diff -Nru qemu-0.9.1/aio.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/aio.c --- qemu-0.9.1/aio.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/aio.c 2008-10-12 22:19:57.000000000 +0100 @@ -0,0 +1,195 @@ +/* + * QEMU aio implementation + * + * Copyright IBM, Corp. 2008 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "qemu-common.h" +#include "block.h" +#include "sys-queue.h" +#include "qemu_socket.h" + +typedef struct AioHandler AioHandler; + +/* The list of registered AIO handlers */ +static LIST_HEAD(, AioHandler) aio_handlers; + +/* This is a simple lock used to protect the aio_handlers list. Specifically, + * it's used to ensure that no callbacks are removed while we're walking and + * dispatching callbacks. + */ +static int walking_handlers; + +struct AioHandler +{ + int fd; + IOHandler *io_read; + IOHandler *io_write; + AioFlushHandler *io_flush; + int deleted; + void *opaque; + LIST_ENTRY(AioHandler) node; +}; + +static AioHandler *find_aio_handler(int fd) +{ + AioHandler *node; + + LIST_FOREACH(node, &aio_handlers, node) { + if (node->fd == fd) + return node; + } + + return NULL; +} + +int qemu_aio_set_fd_handler(int fd, + IOHandler *io_read, + IOHandler *io_write, + AioFlushHandler *io_flush, + void *opaque) +{ + AioHandler *node; + + node = find_aio_handler(fd); + + /* Are we deleting the fd handler? */ + if (!io_read && !io_write) { + if (node) { + /* If the lock is held, just mark the node as deleted */ + if (walking_handlers) + node->deleted = 1; + else { + /* Otherwise, delete it for real. We can't just mark it as + * deleted because deleted nodes are only cleaned up after + * releasing the walking_handlers lock. + */ + LIST_REMOVE(node, node); + qemu_free(node); + } + } + } else { + if (node == NULL) { + /* Alloc and insert if it's not already there */ + node = qemu_mallocz(sizeof(AioHandler)); + if (node == NULL) + return -ENOMEM; + node->fd = fd; + LIST_INSERT_HEAD(&aio_handlers, node, node); + } + /* Update handler with latest information */ + node->io_read = io_read; + node->io_write = io_write; + node->io_flush = io_flush; + node->opaque = opaque; + } + + qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque); + + return 0; +} + +void qemu_aio_flush(void) +{ + AioHandler *node; + int ret; + + do { + ret = 0; + + LIST_FOREACH(node, &aio_handlers, node) { + ret |= node->io_flush(node->opaque); + } + + qemu_aio_wait(); + } while (ret > 0); +} + +void qemu_aio_wait(void) +{ + int ret; + + if (qemu_bh_poll()) + return; + + do { + AioHandler *node; + fd_set rdfds, wrfds; + int max_fd = -1; + + walking_handlers = 1; + + FD_ZERO(&rdfds); + FD_ZERO(&wrfds); + + /* fill fd sets */ + LIST_FOREACH(node, &aio_handlers, node) { + /* If there aren't pending AIO operations, don't invoke callbacks. + * Otherwise, if there are no AIO requests, qemu_aio_wait() would + * wait indefinitely. + */ + if (node->io_flush && node->io_flush(node->opaque) == 0) + continue; + + if (!node->deleted && node->io_read) { + FD_SET(node->fd, &rdfds); + max_fd = MAX(max_fd, node->fd + 1); + } + if (!node->deleted && node->io_write) { + FD_SET(node->fd, &wrfds); + max_fd = MAX(max_fd, node->fd + 1); + } + } + + walking_handlers = 0; + + /* No AIO operations? Get us out of here */ + if (max_fd == -1) + break; + + /* wait until next event */ + ret = select(max_fd, &rdfds, &wrfds, NULL, NULL); + if (ret == -1 && errno == EINTR) + continue; + + /* if we have any readable fds, dispatch event */ + if (ret > 0) { + walking_handlers = 1; + + /* we have to walk very carefully in case + * qemu_aio_set_fd_handler is called while we're walking */ + node = LIST_FIRST(&aio_handlers); + while (node) { + AioHandler *tmp; + + if (!node->deleted && + FD_ISSET(node->fd, &rdfds) && + node->io_read) { + node->io_read(node->opaque); + } + if (!node->deleted && + FD_ISSET(node->fd, &wrfds) && + node->io_write) { + node->io_write(node->opaque); + } + + tmp = node; + node = LIST_NEXT(node, node); + + if (tmp->deleted) { + LIST_REMOVE(tmp, node); + qemu_free(tmp); + } + } + + walking_handlers = 0; + } + } while (ret == 0); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/arm.ld /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/arm.ld --- qemu-0.9.1/arm.ld 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/arm.ld 2008-07-10 18:21:31.000000000 +0100 @@ -63,6 +63,7 @@ . = ALIGN(0x100000) + (. & (0x100000 - 1)); .data : { + *(.gen_code) *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/arm-semi.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/arm-semi.c --- qemu-0.9.1/arm-semi.c 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/arm-semi.c 2008-07-01 17:40:04.000000000 +0100 @@ -362,6 +362,7 @@ return (uint32_t)-1; ret = set_swi_errno(ts, system(s)); unlock_user(s, ARG(0), 0); + return ret; } case SYS_ERRNO: #ifdef CONFIG_USER_ONLY diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/audio/alsaaudio.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/audio/alsaaudio.c --- qemu-0.9.1/audio/alsaaudio.c 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/audio/alsaaudio.c 2008-10-06 19:08:30.000000000 +0100 @@ -58,37 +58,17 @@ int period_size_out_overridden; int verbose; } conf = { -#define DEFAULT_BUFFER_SIZE 1024 -#define DEFAULT_PERIOD_SIZE 256 -#ifdef HIGH_LATENCY - .size_in_usec_in = 1, - .size_in_usec_out = 1, -#endif + .buffer_size_out = 1024, .pcm_name_out = "default", .pcm_name_in = "default", -#ifdef HIGH_LATENCY - .buffer_size_in = 400000, - .period_size_in = 400000 / 4, - .buffer_size_out = 400000, - .period_size_out = 400000 / 4, -#else - .buffer_size_in = DEFAULT_BUFFER_SIZE * 4, - .period_size_in = DEFAULT_PERIOD_SIZE * 4, - .buffer_size_out = DEFAULT_BUFFER_SIZE, - .period_size_out = DEFAULT_PERIOD_SIZE, - .buffer_size_in_overridden = 0, - .buffer_size_out_overridden = 0, - .period_size_in_overridden = 0, - .period_size_out_overridden = 0, -#endif - .threshold = 0, - .verbose = 0 }; struct alsa_params_req { - unsigned int freq; - audfmt_e fmt; - unsigned int nchannels; + int freq; + snd_pcm_format_t fmt; + int nchannels; + int size_in_usec; + int override_mask; unsigned int buffer_size; unsigned int period_size; }; @@ -96,6 +76,7 @@ struct alsa_params_obt { int freq; audfmt_e fmt; + int endianness; int nchannels; snd_pcm_uframes_t samples; }; @@ -143,7 +124,7 @@ return audio_pcm_sw_write (sw, buf, len); } -static int aud_to_alsafmt (audfmt_e fmt) +static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt) { switch (fmt) { case AUD_FMT_S8: @@ -173,7 +154,8 @@ } } -static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness) +static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt, + int *endianness) { switch (alsafmt) { case SND_PCM_FORMAT_S8: @@ -234,7 +216,6 @@ return 0; } -#if defined DEBUG_MISMATCHES || defined DEBUG static void alsa_dump_info (struct alsa_params_req *req, struct alsa_params_obt *obt) { @@ -248,7 +229,6 @@ req->buffer_size, req->period_size); dolog ("obtained: samples %ld\n", obt->samples); } -#endif static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold) { @@ -286,16 +266,16 @@ snd_pcm_t *handle; snd_pcm_hw_params_t *hw_params; int err; + int size_in_usec; unsigned int freq, nchannels; const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out; - unsigned int period_size, buffer_size; snd_pcm_uframes_t obt_buffer_size; const char *typ = in ? "ADC" : "DAC"; + snd_pcm_format_t obtfmt; freq = req->freq; - period_size = req->period_size; - buffer_size = req->buffer_size; nchannels = req->nchannels; + size_in_usec = req->size_in_usec; snd_pcm_hw_params_alloca (&hw_params); @@ -327,9 +307,8 @@ } err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt); - if (err < 0) { + if (err < 0 && conf.verbose) { alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt); - goto err; } err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0); @@ -356,130 +335,79 @@ goto err; } - if (!((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out))) { - if (!buffer_size) { - buffer_size = DEFAULT_BUFFER_SIZE; - period_size= DEFAULT_PERIOD_SIZE; - } - } + if (req->buffer_size) { + unsigned long obt; - if (buffer_size) { - if ((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out)) { - if (period_size) { - err = snd_pcm_hw_params_set_period_time_near ( - handle, - hw_params, - &period_size, - 0 - ); - if (err < 0) { - alsa_logerr2 (err, typ, - "Failed to set period time %d\n", - req->period_size); - goto err; - } - } + if (size_in_usec) { + int dir = 0; + unsigned int btime = req->buffer_size; err = snd_pcm_hw_params_set_buffer_time_near ( handle, hw_params, - &buffer_size, - 0 + &btime, + &dir ); - - if (err < 0) { - alsa_logerr2 (err, typ, - "Failed to set buffer time %d\n", - req->buffer_size); - goto err; - } + obt = btime; } else { - int dir; - snd_pcm_uframes_t minval; + snd_pcm_uframes_t bsize = req->buffer_size; - if (period_size) { - minval = period_size; - dir = 0; - - err = snd_pcm_hw_params_get_period_size_min ( - hw_params, - &minval, - &dir - ); - if (err < 0) { - alsa_logerr ( - err, - "Could not get minmal period size for %s\n", - typ - ); - } - else { - if (period_size < minval) { - if ((in && conf.period_size_in_overridden) - || (!in && conf.period_size_out_overridden)) { - dolog ("%s period size(%d) is less " - "than minmal period size(%ld)\n", - typ, - period_size, - minval); - } - period_size = minval; - } - } + err = snd_pcm_hw_params_set_buffer_size_near ( + handle, + hw_params, + &bsize + ); + obt = bsize; + } + if (err < 0) { + alsa_logerr2 (err, typ, "Failed to set buffer %s to %d\n", + size_in_usec ? "time" : "size", req->buffer_size); + goto err; + } - err = snd_pcm_hw_params_set_period_size ( - handle, - hw_params, - period_size, - 0 - ); - if (err < 0) { - alsa_logerr2 (err, typ, "Failed to set period size %d\n", - req->period_size); - goto err; - } - } + if ((req->override_mask & 2) && (obt - req->buffer_size)) + dolog ("Requested buffer %s %u was rejected, using %lu\n", + size_in_usec ? "time" : "size", req->buffer_size, obt); + } + + if (req->period_size) { + unsigned long obt; + + if (size_in_usec) { + int dir = 0; + unsigned int ptime = req->period_size; - minval = buffer_size; - err = snd_pcm_hw_params_get_buffer_size_min ( + err = snd_pcm_hw_params_set_period_time_near ( + handle, hw_params, - &minval + &ptime, + &dir ); - if (err < 0) { - alsa_logerr (err, "Could not get minmal buffer size for %s\n", - typ); - } - else { - if (buffer_size < minval) { - if ((in && conf.buffer_size_in_overridden) - || (!in && conf.buffer_size_out_overridden)) { - dolog ( - "%s buffer size(%d) is less " - "than minimal buffer size(%ld)\n", - typ, - buffer_size, - minval - ); - } - buffer_size = minval; - } - } + obt = ptime; + } + else { + int dir = 0; + snd_pcm_uframes_t psize = req->period_size; - err = snd_pcm_hw_params_set_buffer_size ( + err = snd_pcm_hw_params_set_period_size_near ( handle, hw_params, - buffer_size + &psize, + &dir ); - if (err < 0) { - alsa_logerr2 (err, typ, "Failed to set buffer size %d\n", - req->buffer_size); - goto err; - } + obt = psize; } - } - else { - dolog ("warning: Buffer size is not set\n"); + + if (err < 0) { + alsa_logerr2 (err, typ, "Failed to set period %s to %d\n", + size_in_usec ? "time" : "size", req->period_size); + goto err; + } + + if ((req->override_mask & 1) && (obt - req->period_size)) + dolog ("Requested period %s %u was rejected, using %lu\n", + size_in_usec ? "time" : "size", req->period_size, obt); } err = snd_pcm_hw_params (handle, hw_params); @@ -494,6 +422,17 @@ goto err; } + err = snd_pcm_hw_params_get_format (hw_params, &obtfmt); + if (err < 0) { + alsa_logerr2 (err, typ, "Failed to get format\n"); + goto err; + } + + if (alsa_to_audfmt (obtfmt, &obt->fmt, &obt->endianness)) { + dolog ("Invalid format was returned %d\n", obtfmt); + goto err; + } + err = snd_pcm_prepare (handle); if (err < 0) { alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle); @@ -504,28 +443,41 @@ snd_pcm_uframes_t threshold; int bytes_per_sec; - bytes_per_sec = freq - << (nchannels == 2) - << (req->fmt == AUD_FMT_S16 || req->fmt == AUD_FMT_U16); + bytes_per_sec = freq << (nchannels == 2); + + switch (obt->fmt) { + case AUD_FMT_S8: + case AUD_FMT_U8: + break; + + case AUD_FMT_S16: + case AUD_FMT_U16: + bytes_per_sec <<= 1; + break; + + case AUD_FMT_S32: + case AUD_FMT_U32: + bytes_per_sec <<= 2; + break; + } threshold = (conf.threshold * bytes_per_sec) / 1000; alsa_set_threshold (handle, threshold); } - obt->fmt = req->fmt; obt->nchannels = nchannels; obt->freq = freq; obt->samples = obt_buffer_size; + *handlep = handle; -#if defined DEBUG_MISMATCHES || defined DEBUG - if (obt->fmt != req->fmt || - obt->nchannels != req->nchannels || - obt->freq != req->freq) { - dolog ("Audio paramters mismatch for %s\n", typ); + if (conf.verbose && + (obt->fmt != req->fmt || + obt->nchannels != req->nchannels || + obt->freq != req->freq)) { + dolog ("Audio paramters for %s\n", typ); alsa_dump_info (req, obt); } -#endif #ifdef DEBUG alsa_dump_info (req, obt); @@ -665,9 +617,6 @@ ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; struct alsa_params_req req; struct alsa_params_obt obt; - audfmt_e effective_fmt; - int endianness; - int err; snd_pcm_t *handle; audsettings_t obt_as; @@ -676,21 +625,18 @@ req.nchannels = as->nchannels; req.period_size = conf.period_size_out; req.buffer_size = conf.buffer_size_out; + req.size_in_usec = conf.size_in_usec_out; + req.override_mask = !!conf.period_size_out_overridden + | (!!conf.buffer_size_out_overridden << 1); if (alsa_open (0, &req, &obt, &handle)) { return -1; } - err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness); - if (err) { - alsa_anal_close (&handle); - return -1; - } - obt_as.freq = obt.freq; obt_as.nchannels = obt.nchannels; - obt_as.fmt = effective_fmt; - obt_as.endianness = endianness; + obt_as.fmt = obt.fmt; + obt_as.endianness = obt.endianness; audio_pcm_init_info (&hw->info, &obt_as); hw->samples = obt.samples; @@ -751,9 +697,6 @@ ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; struct alsa_params_req req; struct alsa_params_obt obt; - int endianness; - int err; - audfmt_e effective_fmt; snd_pcm_t *handle; audsettings_t obt_as; @@ -762,21 +705,18 @@ req.nchannels = as->nchannels; req.period_size = conf.period_size_in; req.buffer_size = conf.buffer_size_in; + req.size_in_usec = conf.size_in_usec_in; + req.override_mask = !!conf.period_size_in_overridden + | (!!conf.buffer_size_in_overridden << 1); if (alsa_open (1, &req, &obt, &handle)) { return -1; } - err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness); - if (err) { - alsa_anal_close (&handle); - return -1; - } - obt_as.freq = obt.freq; obt_as.nchannels = obt.nchannels; - obt_as.fmt = effective_fmt; - obt_as.endianness = endianness; + obt_as.fmt = obt.fmt; + obt_as.endianness = obt.endianness; audio_pcm_init_info (&hw->info, &obt_as); hw->samples = obt.samples; @@ -947,16 +887,20 @@ {"DAC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_out, "DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0}, {"DAC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_out, - "DAC period size", &conf.period_size_out_overridden, 0}, + "DAC period size (0 to go with system default)", + &conf.period_size_out_overridden, 0}, {"DAC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out, - "DAC buffer size", &conf.buffer_size_out_overridden, 0}, + "DAC buffer size (0 to go with system default)", + &conf.buffer_size_out_overridden, 0}, {"ADC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_in, "ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0}, {"ADC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_in, - "ADC period size", &conf.period_size_in_overridden, 0}, + "ADC period size (0 to go with system default)", + &conf.period_size_in_overridden, 0}, {"ADC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in, - "ADC buffer size", &conf.buffer_size_in_overridden, 0}, + "ADC buffer size (0 to go with system default)", + &conf.buffer_size_in_overridden, 0}, {"THRESHOLD", AUD_OPT_INT, &conf.threshold, "(undocumented)", NULL, 0}, diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/audio/audio.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/audio/audio.c --- qemu-0.9.1/audio/audio.c 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/audio/audio.c 2008-11-04 19:15:37.000000000 +0000 @@ -38,24 +38,7 @@ #define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown" static struct audio_driver *drvtab[] = { -#ifdef CONFIG_OSS - &oss_audio_driver, -#endif -#ifdef CONFIG_ALSA - &alsa_audio_driver, -#endif -#ifdef CONFIG_COREAUDIO - &coreaudio_audio_driver, -#endif -#ifdef CONFIG_DSOUND - &dsound_audio_driver, -#endif -#ifdef CONFIG_FMOD - &fmod_audio_driver, -#endif -#ifdef CONFIG_SDL - &sdl_audio_driver, -#endif + AUDIO_DRIVERS &no_audio_driver, &wav_audio_driver }; @@ -101,7 +84,7 @@ } }, - { 0 }, /* period */ + { 250 }, /* period */ 0, /* plive */ 0 /* log_to_monitor */ }; @@ -114,8 +97,8 @@ 1.0, 1.0 #else - UINT_MAX, - UINT_MAX + 1ULL << 32, + 1ULL << 32 #endif }; @@ -228,8 +211,8 @@ size_t i; char *u = r + sizeof (qemu_prefix) - 1; - strcpy (r, qemu_prefix); - strcat (r, s); + pstrcpy (r, len + sizeof (qemu_prefix), qemu_prefix); + pstrcat (r, len + sizeof (qemu_prefix), s); for (i = 0; i < len; ++i) { u[i] = toupper (u[i]); @@ -414,7 +397,7 @@ { audfmt_e *fmtp = opt->valp; printf ( - "format, %s = %s, (one of: U8 S8 U16 S16)\n", + "format, %s = %s, (one of: U8 S8 U16 S16 U32 S32)\n", state, audio_audfmt_to_string (*fmtp) ); @@ -447,7 +430,7 @@ { char *optname; const char qemu_prefix[] = "QEMU_"; - size_t preflen; + size_t preflen, optlen; if (audio_bug (AUDIO_FUNC, !prefix)) { dolog ("prefix = NULL\n"); @@ -475,21 +458,22 @@ /* len of opt->name + len of prefix + size of qemu_prefix * (includes trailing zero) + zero + underscore (on behalf of * sizeof) */ - optname = qemu_malloc (len + preflen + sizeof (qemu_prefix) + 1); + optlen = len + preflen + sizeof (qemu_prefix) + 1; + optname = qemu_malloc (optlen); if (!optname) { dolog ("Could not allocate memory for option name `%s'\n", opt->name); continue; } - strcpy (optname, qemu_prefix); + pstrcpy (optname, optlen, qemu_prefix); /* copy while upper-casing, including trailing zero */ for (i = 0; i <= preflen; ++i) { optname[i + sizeof (qemu_prefix) - 1] = toupper (prefix[i]); } - strcat (optname, "_"); - strcat (optname, opt->name); + pstrcat (optname, optlen, "_"); + pstrcat (optname, optlen, opt->name); def = 1; switch (opt->tag) { @@ -546,6 +530,12 @@ case AUD_FMT_U16: AUD_log (NULL, "U16"); break; + case AUD_FMT_S32: + AUD_log (NULL, "S32"); + break; + case AUD_FMT_U32: + AUD_log (NULL, "U32"); + break; default: AUD_log (NULL, "invalid(%d)", as->fmt); break; @@ -1537,7 +1527,7 @@ "(undocumented)", NULL, 0}, {"LOG_TO_MONITOR", AUD_OPT_BOOL, &conf.log_to_monitor, - "print logging messages to montior instead of stderr", NULL, 0}, + "print logging messages to monitor instead of stderr", NULL, 0}, {NULL, 0, NULL, NULL, NULL, 0} }; @@ -1952,3 +1942,21 @@ } } } + +void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol) +{ + if (sw) { + sw->vol.mute = mute; + sw->vol.l = nominal_volume.l * lvol / 255; + sw->vol.r = nominal_volume.r * rvol / 255; + } +} + +void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol) +{ + if (sw) { + sw->vol.mute = mute; + sw->vol.l = nominal_volume.l * lvol / 255; + sw->vol.r = nominal_volume.r * rvol / 255; + } +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/audio/audio.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/audio/audio.h --- qemu-0.9.1/audio/audio.h 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/audio/audio.h 2008-10-05 11:30:43.000000000 +0100 @@ -124,6 +124,9 @@ void AUD_init_time_stamp_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts); uint64_t AUD_get_elapsed_usec_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts); +void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol); +void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol); + SWVoiceIn *AUD_open_in ( QEMUSoundCard *card, SWVoiceIn *sw, @@ -167,4 +170,7 @@ #define audio_MAX(a, b) ((a)<(b)?(b):(a)) #endif +int wav_start_capture (CaptureState *s, const char *path, int freq, + int bits, int nchannels); + #endif /* audio.h */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/audio/audio_int.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/audio/audio_int.h --- qemu-0.9.1/audio/audio_int.h 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/audio/audio_int.h 2008-10-06 19:08:30.000000000 +0100 @@ -202,6 +202,8 @@ extern struct audio_driver alsa_audio_driver; extern struct audio_driver coreaudio_audio_driver; extern struct audio_driver dsound_audio_driver; +extern struct audio_driver esd_audio_driver; +extern struct audio_driver pa_audio_driver; extern volume_t nominal_volume; void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/audio/audio_pt_int.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/audio/audio_pt_int.c --- qemu-0.9.1/audio/audio_pt_int.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/audio/audio_pt_int.c 2008-01-14 04:24:29.000000000 +0000 @@ -0,0 +1,149 @@ +#include "qemu-common.h" +#include "audio.h" + +#define AUDIO_CAP "audio-pt" + +#include "audio_int.h" +#include "audio_pt_int.h" + +static void logerr (struct audio_pt *pt, int err, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + AUD_vlog (pt->drv, fmt, ap); + va_end (ap); + + AUD_log (NULL, "\n"); + AUD_log (pt->drv, "Reason: %s\n", strerror (err)); +} + +int audio_pt_init (struct audio_pt *p, void *(*func) (void *), + void *opaque, const char *drv, const char *cap) +{ + int err, err2; + const char *efunc; + + p->drv = drv; + + err = pthread_mutex_init (&p->mutex, NULL); + if (err) { + efunc = "pthread_mutex_init"; + goto err0; + } + + err = pthread_cond_init (&p->cond, NULL); + if (err) { + efunc = "pthread_cond_init"; + goto err1; + } + + err = pthread_create (&p->thread, NULL, func, opaque); + if (err) { + efunc = "pthread_create"; + goto err2; + } + + return 0; + + err2: + err2 = pthread_cond_destroy (&p->cond); + if (err2) { + logerr (p, err2, "%s(%s): pthread_cond_destroy failed", cap, AUDIO_FUNC); + } + + err1: + err2 = pthread_mutex_destroy (&p->mutex); + if (err2) { + logerr (p, err2, "%s(%s): pthread_mutex_destroy failed", cap, AUDIO_FUNC); + } + + err0: + logerr (p, err, "%s(%s): %s failed", cap, AUDIO_FUNC, efunc); + return -1; +} + +int audio_pt_fini (struct audio_pt *p, const char *cap) +{ + int err, ret = 0; + + err = pthread_cond_destroy (&p->cond); + if (err) { + logerr (p, err, "%s(%s): pthread_cond_destroy failed", cap, AUDIO_FUNC); + ret = -1; + } + + err = pthread_mutex_destroy (&p->mutex); + if (err) { + logerr (p, err, "%s(%s): pthread_mutex_destroy failed", cap, AUDIO_FUNC); + ret = -1; + } + return ret; +} + +int audio_pt_lock (struct audio_pt *p, const char *cap) +{ + int err; + + err = pthread_mutex_lock (&p->mutex); + if (err) { + logerr (p, err, "%s(%s): pthread_mutex_lock failed", cap, AUDIO_FUNC); + return -1; + } + return 0; +} + +int audio_pt_unlock (struct audio_pt *p, const char *cap) +{ + int err; + + err = pthread_mutex_unlock (&p->mutex); + if (err) { + logerr (p, err, "%s(%s): pthread_mutex_unlock failed", cap, AUDIO_FUNC); + return -1; + } + return 0; +} + +int audio_pt_wait (struct audio_pt *p, const char *cap) +{ + int err; + + err = pthread_cond_wait (&p->cond, &p->mutex); + if (err) { + logerr (p, err, "%s(%s): pthread_cond_wait failed", cap, AUDIO_FUNC); + return -1; + } + return 0; +} + +int audio_pt_unlock_and_signal (struct audio_pt *p, const char *cap) +{ + int err; + + err = pthread_mutex_unlock (&p->mutex); + if (err) { + logerr (p, err, "%s(%s): pthread_mutex_unlock failed", cap, AUDIO_FUNC); + return -1; + } + err = pthread_cond_signal (&p->cond); + if (err) { + logerr (p, err, "%s(%s): pthread_cond_signal failed", cap, AUDIO_FUNC); + return -1; + } + return 0; +} + +int audio_pt_join (struct audio_pt *p, void **arg, const char *cap) +{ + int err; + void *ret; + + err = pthread_join (p->thread, &ret); + if (err) { + logerr (p, err, "%s(%s): pthread_join failed", cap, AUDIO_FUNC); + return -1; + } + *arg = ret; + return 0; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/audio/audio_pt_int.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/audio/audio_pt_int.h --- qemu-0.9.1/audio/audio_pt_int.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/audio/audio_pt_int.h 2008-01-14 04:24:29.000000000 +0000 @@ -0,0 +1,22 @@ +#ifndef QEMU_AUDIO_PT_INT_H +#define QEMU_AUDIO_PT_INT_H + +#include + +struct audio_pt { + const char *drv; + pthread_t thread; + pthread_cond_t cond; + pthread_mutex_t mutex; +}; + +int audio_pt_init (struct audio_pt *, void *(*) (void *), void *, + const char *, const char *); +int audio_pt_fini (struct audio_pt *, const char *); +int audio_pt_lock (struct audio_pt *, const char *); +int audio_pt_unlock (struct audio_pt *, const char *); +int audio_pt_wait (struct audio_pt *, const char *); +int audio_pt_unlock_and_signal (struct audio_pt *, const char *); +int audio_pt_join (struct audio_pt *, void **, const char *); + +#endif /* audio_pt_int.h */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/audio/.cvsignore /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/audio/.cvsignore --- qemu-0.9.1/audio/.cvsignore 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/audio/.cvsignore 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -*.d diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/audio/dsoundaudio.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/audio/dsoundaudio.c --- qemu-0.9.1/audio/dsoundaudio.c 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/audio/dsoundaudio.c 2008-10-06 19:08:30.000000000 +0100 @@ -320,23 +320,22 @@ switch (as->fmt) { case AUD_FMT_S8: - wfx->wBitsPerSample = 8; - break; - case AUD_FMT_U8: wfx->wBitsPerSample = 8; break; case AUD_FMT_S16: + case AUD_FMT_U16: wfx->wBitsPerSample = 16; wfx->nAvgBytesPerSec <<= 1; wfx->nBlockAlign <<= 1; break; - case AUD_FMT_U16: - wfx->wBitsPerSample = 16; - wfx->nAvgBytesPerSec <<= 1; - wfx->nBlockAlign <<= 1; + case AUD_FMT_S32: + case AUD_FMT_U32: + wfx->wBitsPerSample = 32; + wfx->nAvgBytesPerSec <<= 2; + wfx->nBlockAlign <<= 2; break; default: @@ -387,8 +386,13 @@ as->fmt = AUD_FMT_S16; break; + case 32: + as->fmt = AUD_FMT_S32; + break; + default: - dolog ("Invalid wave format, bits per sample is not 8 or 16, but %d\n", + dolog ("Invalid wave format, bits per sample is not " + "8, 16 or 32, but %d\n", wfx->wBitsPerSample); return -1; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/audio/dsound_template.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/audio/dsound_template.h --- qemu-0.9.1/audio/dsound_template.h 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/audio/dsound_template.h 2008-01-17 21:47:25.000000000 +0000 @@ -23,16 +23,20 @@ */ #ifdef DSBTYPE_IN #define NAME "capture buffer" +#define NAME2 "DirectSoundCapture" #define TYPE in #define IFACE IDirectSoundCaptureBuffer #define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER #define FIELD dsound_capture_buffer +#define FIELD2 dsound_capture #else #define NAME "playback buffer" +#define NAME2 "DirectSound" #define TYPE out #define IFACE IDirectSoundBuffer #define BUFPTR LPDIRECTSOUNDBUFFER #define FIELD dsound_buffer +#define FIELD2 dsound #endif static int glue (dsound_unlock_, TYPE) ( @@ -192,6 +196,11 @@ DSBCAPS bc; #endif + if (!s->FIELD2) { + dolog ("Attempt to initialize voice without " NAME2 " object\n"); + return -1; + } + err = waveformat_from_audio_settings (&wfx, as); if (err) { return -1; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/audio/esdaudio.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/audio/esdaudio.c --- qemu-0.9.1/audio/esdaudio.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/audio/esdaudio.c 2008-10-06 19:08:30.000000000 +0100 @@ -0,0 +1,596 @@ +/* + * QEMU ESD audio driver + * + * Copyright (c) 2006 Frederick Reeve (brushed up by malc) + * + * 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 +#include "qemu-common.h" +#include "audio.h" +#include + +#define AUDIO_CAP "esd" +#include "audio_int.h" +#include "audio_pt_int.h" + +typedef struct { + HWVoiceOut hw; + int done; + int live; + int decr; + int rpos; + void *pcm_buf; + int fd; + struct audio_pt pt; +} ESDVoiceOut; + +typedef struct { + HWVoiceIn hw; + int done; + int dead; + int incr; + int wpos; + void *pcm_buf; + int fd; + struct audio_pt pt; +} ESDVoiceIn; + +static struct { + int samples; + int divisor; + char *dac_host; + char *adc_host; +} conf = { + 1024, + 2, + NULL, + NULL +}; + +static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + AUD_vlog (AUDIO_CAP, fmt, ap); + va_end (ap); + + AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err)); +} + +/* playback */ +static void *qesd_thread_out (void *arg) +{ + ESDVoiceOut *esd = arg; + HWVoiceOut *hw = &esd->hw; + int threshold; + + threshold = conf.divisor ? hw->samples / conf.divisor : 0; + + if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { + return NULL; + } + + for (;;) { + int decr, to_mix, rpos; + + for (;;) { + if (esd->done) { + goto exit; + } + + if (esd->live > threshold) { + break; + } + + if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) { + goto exit; + } + } + + decr = to_mix = esd->live; + rpos = hw->rpos; + + if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) { + return NULL; + } + + while (to_mix) { + ssize_t written; + int chunk = audio_MIN (to_mix, hw->samples - rpos); + st_sample_t *src = hw->mix_buf + rpos; + + hw->clip (esd->pcm_buf, src, chunk); + + again: + written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift); + if (written == -1) { + if (errno == EINTR || errno == EAGAIN) { + goto again; + } + qesd_logerr (errno, "write failed\n"); + return NULL; + } + + if (written != chunk << hw->info.shift) { + int wsamples = written >> hw->info.shift; + int wbytes = wsamples << hw->info.shift; + if (wbytes != written) { + dolog ("warning: Misaligned write %d (requested %d), " + "alignment %d\n", + wbytes, written, hw->info.align + 1); + } + to_mix -= wsamples; + rpos = (rpos + wsamples) % hw->samples; + break; + } + + rpos = (rpos + chunk) % hw->samples; + to_mix -= chunk; + } + + if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { + return NULL; + } + + esd->rpos = rpos; + esd->live -= decr; + esd->decr += decr; + } + + exit: + audio_pt_unlock (&esd->pt, AUDIO_FUNC); + return NULL; +} + +static int qesd_run_out (HWVoiceOut *hw) +{ + int live, decr; + ESDVoiceOut *esd = (ESDVoiceOut *) hw; + + if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { + return 0; + } + + live = audio_pcm_hw_get_live_out (hw); + decr = audio_MIN (live, esd->decr); + esd->decr -= decr; + esd->live = live - decr; + hw->rpos = esd->rpos; + if (esd->live > 0) { + audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC); + } + else { + audio_pt_unlock (&esd->pt, AUDIO_FUNC); + } + return decr; +} + +static int qesd_write (SWVoiceOut *sw, void *buf, int len) +{ + return audio_pcm_sw_write (sw, buf, len); +} + +static int qesd_init_out (HWVoiceOut *hw, audsettings_t *as) +{ + ESDVoiceOut *esd = (ESDVoiceOut *) hw; + audsettings_t obt_as = *as; + int esdfmt = ESD_STREAM | ESD_PLAY; + int err; + sigset_t set, old_set; + + sigfillset (&set); + + esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO; + switch (as->fmt) { + case AUD_FMT_S8: + case AUD_FMT_U8: + esdfmt |= ESD_BITS8; + obt_as.fmt = AUD_FMT_U8; + break; + + case AUD_FMT_S32: + case AUD_FMT_U32: + dolog ("Will use 16 instead of 32 bit samples\n"); + + case AUD_FMT_S16: + case AUD_FMT_U16: + deffmt: + esdfmt |= ESD_BITS16; + obt_as.fmt = AUD_FMT_S16; + break; + + default: + dolog ("Internal logic error: Bad audio format %d\n", as->fmt); + goto deffmt; + + } + obt_as.endianness = AUDIO_HOST_ENDIANNESS; + + audio_pcm_init_info (&hw->info, &obt_as); + + hw->samples = conf.samples; + esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); + if (!esd->pcm_buf) { + dolog ("Could not allocate buffer (%d bytes)\n", + hw->samples << hw->info.shift); + return -1; + } + + esd->fd = -1; + err = pthread_sigmask (SIG_BLOCK, &set, &old_set); + if (err) { + qesd_logerr (err, "pthread_sigmask failed\n"); + goto fail1; + } + + esd->fd = esd_play_stream (esdfmt, as->freq, conf.dac_host, NULL); + if (esd->fd < 0) { + qesd_logerr (errno, "esd_play_stream failed\n"); + goto fail2; + } + + if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) { + goto fail3; + } + + err = pthread_sigmask (SIG_SETMASK, &old_set, NULL); + if (err) { + qesd_logerr (err, "pthread_sigmask(restore) failed\n"); + } + + return 0; + + fail3: + if (close (esd->fd)) { + qesd_logerr (errno, "%s: close on esd socket(%d) failed\n", + AUDIO_FUNC, esd->fd); + } + esd->fd = -1; + + fail2: + err = pthread_sigmask (SIG_SETMASK, &old_set, NULL); + if (err) { + qesd_logerr (err, "pthread_sigmask(restore) failed\n"); + } + + fail1: + qemu_free (esd->pcm_buf); + esd->pcm_buf = NULL; + return -1; +} + +static void qesd_fini_out (HWVoiceOut *hw) +{ + void *ret; + ESDVoiceOut *esd = (ESDVoiceOut *) hw; + + audio_pt_lock (&esd->pt, AUDIO_FUNC); + esd->done = 1; + audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC); + audio_pt_join (&esd->pt, &ret, AUDIO_FUNC); + + if (esd->fd >= 0) { + if (close (esd->fd)) { + qesd_logerr (errno, "failed to close esd socket\n"); + } + esd->fd = -1; + } + + audio_pt_fini (&esd->pt, AUDIO_FUNC); + + qemu_free (esd->pcm_buf); + esd->pcm_buf = NULL; +} + +static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...) +{ + (void) hw; + (void) cmd; + return 0; +} + +/* capture */ +static void *qesd_thread_in (void *arg) +{ + ESDVoiceIn *esd = arg; + HWVoiceIn *hw = &esd->hw; + int threshold; + + threshold = conf.divisor ? hw->samples / conf.divisor : 0; + + if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { + return NULL; + } + + for (;;) { + int incr, to_grab, wpos; + + for (;;) { + if (esd->done) { + goto exit; + } + + if (esd->dead > threshold) { + break; + } + + if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) { + goto exit; + } + } + + incr = to_grab = esd->dead; + wpos = hw->wpos; + + if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) { + return NULL; + } + + while (to_grab) { + ssize_t nread; + int chunk = audio_MIN (to_grab, hw->samples - wpos); + void *buf = advance (esd->pcm_buf, wpos); + + again: + nread = read (esd->fd, buf, chunk << hw->info.shift); + if (nread == -1) { + if (errno == EINTR || errno == EAGAIN) { + goto again; + } + qesd_logerr (errno, "read failed\n"); + return NULL; + } + + if (nread != chunk << hw->info.shift) { + int rsamples = nread >> hw->info.shift; + int rbytes = rsamples << hw->info.shift; + if (rbytes != nread) { + dolog ("warning: Misaligned write %d (requested %d), " + "alignment %d\n", + rbytes, nread, hw->info.align + 1); + } + to_grab -= rsamples; + wpos = (wpos + rsamples) % hw->samples; + break; + } + + hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift, + &nominal_volume); + wpos = (wpos + chunk) % hw->samples; + to_grab -= chunk; + } + + if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { + return NULL; + } + + esd->wpos = wpos; + esd->dead -= incr; + esd->incr += incr; + } + + exit: + audio_pt_unlock (&esd->pt, AUDIO_FUNC); + return NULL; +} + +static int qesd_run_in (HWVoiceIn *hw) +{ + int live, incr, dead; + ESDVoiceIn *esd = (ESDVoiceIn *) hw; + + if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { + return 0; + } + + live = audio_pcm_hw_get_live_in (hw); + dead = hw->samples - live; + incr = audio_MIN (dead, esd->incr); + esd->incr -= incr; + esd->dead = dead - incr; + hw->wpos = esd->wpos; + if (esd->dead > 0) { + audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC); + } + else { + audio_pt_unlock (&esd->pt, AUDIO_FUNC); + } + return incr; +} + +static int qesd_read (SWVoiceIn *sw, void *buf, int len) +{ + return audio_pcm_sw_read (sw, buf, len); +} + +static int qesd_init_in (HWVoiceIn *hw, audsettings_t *as) +{ + ESDVoiceIn *esd = (ESDVoiceIn *) hw; + audsettings_t obt_as = *as; + int esdfmt = ESD_STREAM | ESD_RECORD; + int err; + sigset_t set, old_set; + + sigfillset (&set); + + esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO; + switch (as->fmt) { + case AUD_FMT_S8: + case AUD_FMT_U8: + esdfmt |= ESD_BITS8; + obt_as.fmt = AUD_FMT_U8; + break; + + case AUD_FMT_S16: + case AUD_FMT_U16: + esdfmt |= ESD_BITS16; + obt_as.fmt = AUD_FMT_S16; + break; + + case AUD_FMT_S32: + case AUD_FMT_U32: + dolog ("Will use 16 instead of 32 bit samples\n"); + esdfmt |= ESD_BITS16; + obt_as.fmt = AUD_FMT_S16; + break; + } + obt_as.endianness = AUDIO_HOST_ENDIANNESS; + + audio_pcm_init_info (&hw->info, &obt_as); + + hw->samples = conf.samples; + esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); + if (!esd->pcm_buf) { + dolog ("Could not allocate buffer (%d bytes)\n", + hw->samples << hw->info.shift); + return -1; + } + + esd->fd = -1; + + err = pthread_sigmask (SIG_BLOCK, &set, &old_set); + if (err) { + qesd_logerr (err, "pthread_sigmask failed\n"); + goto fail1; + } + + esd->fd = esd_record_stream (esdfmt, as->freq, conf.adc_host, NULL); + if (esd->fd < 0) { + qesd_logerr (errno, "esd_record_stream failed\n"); + goto fail2; + } + + if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) { + goto fail3; + } + + err = pthread_sigmask (SIG_SETMASK, &old_set, NULL); + if (err) { + qesd_logerr (err, "pthread_sigmask(restore) failed\n"); + } + + return 0; + + fail3: + if (close (esd->fd)) { + qesd_logerr (errno, "%s: close on esd socket(%d) failed\n", + AUDIO_FUNC, esd->fd); + } + esd->fd = -1; + + fail2: + err = pthread_sigmask (SIG_SETMASK, &old_set, NULL); + if (err) { + qesd_logerr (err, "pthread_sigmask(restore) failed\n"); + } + + fail1: + qemu_free (esd->pcm_buf); + esd->pcm_buf = NULL; + return -1; +} + +static void qesd_fini_in (HWVoiceIn *hw) +{ + void *ret; + ESDVoiceIn *esd = (ESDVoiceIn *) hw; + + audio_pt_lock (&esd->pt, AUDIO_FUNC); + esd->done = 1; + audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC); + audio_pt_join (&esd->pt, &ret, AUDIO_FUNC); + + if (esd->fd >= 0) { + if (close (esd->fd)) { + qesd_logerr (errno, "failed to close esd socket\n"); + } + esd->fd = -1; + } + + audio_pt_fini (&esd->pt, AUDIO_FUNC); + + qemu_free (esd->pcm_buf); + esd->pcm_buf = NULL; +} + +static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...) +{ + (void) hw; + (void) cmd; + return 0; +} + +/* common */ +static void *qesd_audio_init (void) +{ + return &conf; +} + +static void qesd_audio_fini (void *opaque) +{ + (void) opaque; + ldebug ("esd_fini"); +} + +struct audio_option qesd_options[] = { + {"SAMPLES", AUD_OPT_INT, &conf.samples, + "buffer size in samples", NULL, 0}, + + {"DIVISOR", AUD_OPT_INT, &conf.divisor, + "threshold divisor", NULL, 0}, + + {"DAC_HOST", AUD_OPT_STR, &conf.dac_host, + "playback host", NULL, 0}, + + {"ADC_HOST", AUD_OPT_STR, &conf.adc_host, + "capture host", NULL, 0}, + + {NULL, 0, NULL, NULL, NULL, 0} +}; + +static struct audio_pcm_ops qesd_pcm_ops = { + qesd_init_out, + qesd_fini_out, + qesd_run_out, + qesd_write, + qesd_ctl_out, + + qesd_init_in, + qesd_fini_in, + qesd_run_in, + qesd_read, + qesd_ctl_in, +}; + +struct audio_driver esd_audio_driver = { + INIT_FIELD (name = ) "esd", + INIT_FIELD (descr = ) + "http://en.wikipedia.org/wiki/Esound", + INIT_FIELD (options = ) qesd_options, + INIT_FIELD (init = ) qesd_audio_init, + INIT_FIELD (fini = ) qesd_audio_fini, + INIT_FIELD (pcm_ops = ) &qesd_pcm_ops, + INIT_FIELD (can_be_default = ) 0, + INIT_FIELD (max_voices_out = ) INT_MAX, + INIT_FIELD (max_voices_in = ) INT_MAX, + INIT_FIELD (voice_size_out = ) sizeof (ESDVoiceOut), + INIT_FIELD (voice_size_in = ) sizeof (ESDVoiceIn) +}; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/audio/mixeng.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/audio/mixeng.c --- qemu-0.9.1/audio/mixeng.c 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/audio/mixeng.c 2008-06-23 19:33:30.000000000 +0100 @@ -28,8 +28,6 @@ #define AUDIO_CAP "mixeng" #include "audio_int.h" -#define NOVOL - /* 8 bit */ #define ENDIAN_CONVERSION natural #define ENDIAN_CONVERT(v) (v) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/audio/mixeng_template.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/audio/mixeng_template.h --- qemu-0.9.1/audio/mixeng_template.h 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/audio/mixeng_template.h 2008-06-23 19:33:30.000000000 +0100 @@ -31,14 +31,14 @@ #define HALF (IN_MAX >> 1) #endif -#ifdef NOVOL -#define VOL(a, b) a -#else +#ifdef CONFIG_MIXEMU #ifdef FLOAT_MIXENG #define VOL(a, b) ((a) * (b)) #else #define VOL(a, b) ((a) * (b)) >> 32 #endif +#else +#define VOL(a, b) a #endif #define ET glue (ENDIAN_CONVERSION, glue (_, IN_T)) @@ -113,7 +113,7 @@ { st_sample_t *out = dst; IN_T *in = (IN_T *) src; -#ifndef NOVOL +#ifdef CONFIG_MIXEMU if (vol->mute) { mixeng_clear (dst, samples); return; @@ -133,7 +133,7 @@ { st_sample_t *out = dst; IN_T *in = (IN_T *) src; -#ifndef NOVOL +#ifdef CONFIG_MIXEMU if (vol->mute) { mixeng_clear (dst, samples); return; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/audio/ossaudio.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/audio/ossaudio.c --- qemu-0.9.1/audio/ossaudio.c 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/audio/ossaudio.c 2008-10-06 19:08:30.000000000 +0100 @@ -150,7 +150,7 @@ { switch (ossfmt) { case AFMT_S8: - *endianness =0; + *endianness = 0; *fmt = AUD_FMT_S8; break; @@ -237,7 +237,7 @@ goto err; } - if (ioctl (fd, SNDCTL_DSP_NONBLOCK)) { + if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) { oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n"); goto err; } @@ -254,6 +254,12 @@ goto err; } + if (!abinfo.fragstotal || !abinfo.fragsize) { + AUD_log (AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n", + abinfo.fragstotal, abinfo.fragsize, typ); + goto err; + } + obt->fmt = fmt; obt->nchannels = nchannels; obt->freq = freq; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/audio/paaudio.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/audio/paaudio.c --- qemu-0.9.1/audio/paaudio.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/audio/paaudio.c 2008-10-06 19:08:30.000000000 +0100 @@ -0,0 +1,515 @@ +/* public domain */ +#include "qemu-common.h" +#include "audio.h" + +#include +#include + +#define AUDIO_CAP "pulseaudio" +#include "audio_int.h" +#include "audio_pt_int.h" + +typedef struct { + HWVoiceOut hw; + int done; + int live; + int decr; + int rpos; + pa_simple *s; + void *pcm_buf; + struct audio_pt pt; +} PAVoiceOut; + +typedef struct { + HWVoiceIn hw; + int done; + int dead; + int incr; + int wpos; + pa_simple *s; + void *pcm_buf; + struct audio_pt pt; +} PAVoiceIn; + +static struct { + int samples; + int divisor; + char *server; + char *sink; + char *source; +} conf = { + 1024, + 2, + NULL, + NULL, + NULL +}; + +static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + AUD_vlog (AUDIO_CAP, fmt, ap); + va_end (ap); + + AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err)); +} + +static void *qpa_thread_out (void *arg) +{ + PAVoiceOut *pa = arg; + HWVoiceOut *hw = &pa->hw; + int threshold; + + threshold = conf.divisor ? hw->samples / conf.divisor : 0; + + if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { + return NULL; + } + + for (;;) { + int decr, to_mix, rpos; + + for (;;) { + if (pa->done) { + goto exit; + } + + if (pa->live > threshold) { + break; + } + + if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) { + goto exit; + } + } + + decr = to_mix = pa->live; + rpos = hw->rpos; + + if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) { + return NULL; + } + + while (to_mix) { + int error; + int chunk = audio_MIN (to_mix, hw->samples - rpos); + st_sample_t *src = hw->mix_buf + rpos; + + hw->clip (pa->pcm_buf, src, chunk); + + if (pa_simple_write (pa->s, pa->pcm_buf, + chunk << hw->info.shift, &error) < 0) { + qpa_logerr (error, "pa_simple_write failed\n"); + return NULL; + } + + rpos = (rpos + chunk) % hw->samples; + to_mix -= chunk; + } + + if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { + return NULL; + } + + pa->rpos = rpos; + pa->live -= decr; + pa->decr += decr; + } + + exit: + audio_pt_unlock (&pa->pt, AUDIO_FUNC); + return NULL; +} + +static int qpa_run_out (HWVoiceOut *hw) +{ + int live, decr; + PAVoiceOut *pa = (PAVoiceOut *) hw; + + if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { + return 0; + } + + live = audio_pcm_hw_get_live_out (hw); + decr = audio_MIN (live, pa->decr); + pa->decr -= decr; + pa->live = live - decr; + hw->rpos = pa->rpos; + if (pa->live > 0) { + audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); + } + else { + audio_pt_unlock (&pa->pt, AUDIO_FUNC); + } + return decr; +} + +static int qpa_write (SWVoiceOut *sw, void *buf, int len) +{ + return audio_pcm_sw_write (sw, buf, len); +} + +/* capture */ +static void *qpa_thread_in (void *arg) +{ + PAVoiceIn *pa = arg; + HWVoiceIn *hw = &pa->hw; + int threshold; + + threshold = conf.divisor ? hw->samples / conf.divisor : 0; + + if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { + return NULL; + } + + for (;;) { + int incr, to_grab, wpos; + + for (;;) { + if (pa->done) { + goto exit; + } + + if (pa->dead > threshold) { + break; + } + + if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) { + goto exit; + } + } + + incr = to_grab = pa->dead; + wpos = hw->wpos; + + if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) { + return NULL; + } + + while (to_grab) { + int error; + int chunk = audio_MIN (to_grab, hw->samples - wpos); + void *buf = advance (pa->pcm_buf, wpos); + + if (pa_simple_read (pa->s, buf, + chunk << hw->info.shift, &error) < 0) { + qpa_logerr (error, "pa_simple_read failed\n"); + return NULL; + } + + hw->conv (hw->conv_buf + wpos, buf, chunk, &nominal_volume); + wpos = (wpos + chunk) % hw->samples; + to_grab -= chunk; + } + + if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { + return NULL; + } + + pa->wpos = wpos; + pa->dead -= incr; + pa->incr += incr; + } + + exit: + audio_pt_unlock (&pa->pt, AUDIO_FUNC); + return NULL; +} + +static int qpa_run_in (HWVoiceIn *hw) +{ + int live, incr, dead; + PAVoiceIn *pa = (PAVoiceIn *) hw; + + if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { + return 0; + } + + live = audio_pcm_hw_get_live_in (hw); + dead = hw->samples - live; + incr = audio_MIN (dead, pa->incr); + pa->incr -= incr; + pa->dead = dead - incr; + hw->wpos = pa->wpos; + if (pa->dead > 0) { + audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); + } + else { + audio_pt_unlock (&pa->pt, AUDIO_FUNC); + } + return incr; +} + +static int qpa_read (SWVoiceIn *sw, void *buf, int len) +{ + return audio_pcm_sw_read (sw, buf, len); +} + +static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness) +{ + int format; + + switch (afmt) { + case AUD_FMT_S8: + case AUD_FMT_U8: + format = PA_SAMPLE_U8; + break; + case AUD_FMT_S16: + case AUD_FMT_U16: + format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE; + break; + case AUD_FMT_S32: + case AUD_FMT_U32: + format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE; + break; + default: + dolog ("Internal logic error: Bad audio format %d\n", afmt); + format = PA_SAMPLE_U8; + break; + } + return format; +} + +static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness) +{ + switch (fmt) { + case PA_SAMPLE_U8: + return AUD_FMT_U8; + case PA_SAMPLE_S16BE: + *endianness = 1; + return AUD_FMT_S16; + case PA_SAMPLE_S16LE: + *endianness = 0; + return AUD_FMT_S16; + case PA_SAMPLE_S32BE: + *endianness = 1; + return AUD_FMT_S32; + case PA_SAMPLE_S32LE: + *endianness = 0; + return AUD_FMT_S32; + default: + dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt); + return AUD_FMT_U8; + } +} + +static int qpa_init_out (HWVoiceOut *hw, audsettings_t *as) +{ + int error; + static pa_sample_spec ss; + audsettings_t obt_as = *as; + PAVoiceOut *pa = (PAVoiceOut *) hw; + + ss.format = audfmt_to_pa (as->fmt, as->endianness); + ss.channels = as->nchannels; + ss.rate = as->freq; + + obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); + + pa->s = pa_simple_new ( + conf.server, + "qemu", + PA_STREAM_PLAYBACK, + conf.sink, + "pcm.playback", + &ss, + NULL, /* channel map */ + NULL, /* buffering attributes */ + &error + ); + if (!pa->s) { + qpa_logerr (error, "pa_simple_new for playback failed\n"); + goto fail1; + } + + audio_pcm_init_info (&hw->info, &obt_as); + hw->samples = conf.samples; + pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); + if (!pa->pcm_buf) { + dolog ("Could not allocate buffer (%d bytes)\n", + hw->samples << hw->info.shift); + goto fail2; + } + + if (audio_pt_init (&pa->pt, qpa_thread_out, hw, AUDIO_CAP, AUDIO_FUNC)) { + goto fail3; + } + + return 0; + + fail3: + free (pa->pcm_buf); + pa->pcm_buf = NULL; + fail2: + pa_simple_free (pa->s); + pa->s = NULL; + fail1: + return -1; +} + +static int qpa_init_in (HWVoiceIn *hw, audsettings_t *as) +{ + int error; + static pa_sample_spec ss; + audsettings_t obt_as = *as; + PAVoiceIn *pa = (PAVoiceIn *) hw; + + ss.format = audfmt_to_pa (as->fmt, as->endianness); + ss.channels = as->nchannels; + ss.rate = as->freq; + + obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); + + pa->s = pa_simple_new ( + conf.server, + "qemu", + PA_STREAM_RECORD, + conf.source, + "pcm.capture", + &ss, + NULL, /* channel map */ + NULL, /* buffering attributes */ + &error + ); + if (!pa->s) { + qpa_logerr (error, "pa_simple_new for capture failed\n"); + goto fail1; + } + + audio_pcm_init_info (&hw->info, &obt_as); + hw->samples = conf.samples; + pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); + if (!pa->pcm_buf) { + dolog ("Could not allocate buffer (%d bytes)\n", + hw->samples << hw->info.shift); + goto fail2; + } + + if (audio_pt_init (&pa->pt, qpa_thread_in, hw, AUDIO_CAP, AUDIO_FUNC)) { + goto fail3; + } + + return 0; + + fail3: + free (pa->pcm_buf); + pa->pcm_buf = NULL; + fail2: + pa_simple_free (pa->s); + pa->s = NULL; + fail1: + return -1; +} + +static void qpa_fini_out (HWVoiceOut *hw) +{ + void *ret; + PAVoiceOut *pa = (PAVoiceOut *) hw; + + audio_pt_lock (&pa->pt, AUDIO_FUNC); + pa->done = 1; + audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); + audio_pt_join (&pa->pt, &ret, AUDIO_FUNC); + + if (pa->s) { + pa_simple_free (pa->s); + pa->s = NULL; + } + + audio_pt_fini (&pa->pt, AUDIO_FUNC); + qemu_free (pa->pcm_buf); + pa->pcm_buf = NULL; +} + +static void qpa_fini_in (HWVoiceIn *hw) +{ + void *ret; + PAVoiceIn *pa = (PAVoiceIn *) hw; + + audio_pt_lock (&pa->pt, AUDIO_FUNC); + pa->done = 1; + audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); + audio_pt_join (&pa->pt, &ret, AUDIO_FUNC); + + if (pa->s) { + pa_simple_free (pa->s); + pa->s = NULL; + } + + audio_pt_fini (&pa->pt, AUDIO_FUNC); + qemu_free (pa->pcm_buf); + pa->pcm_buf = NULL; +} + +static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) +{ + (void) hw; + (void) cmd; + return 0; +} + +static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) +{ + (void) hw; + (void) cmd; + return 0; +} + +/* common */ +static void *qpa_audio_init (void) +{ + return &conf; +} + +static void qpa_audio_fini (void *opaque) +{ + (void) opaque; +} + +struct audio_option qpa_options[] = { + {"SAMPLES", AUD_OPT_INT, &conf.samples, + "buffer size in samples", NULL, 0}, + + {"DIVISOR", AUD_OPT_INT, &conf.divisor, + "threshold divisor", NULL, 0}, + + {"SERVER", AUD_OPT_STR, &conf.server, + "server address", NULL, 0}, + + {"SINK", AUD_OPT_STR, &conf.sink, + "sink device name", NULL, 0}, + + {"SOURCE", AUD_OPT_STR, &conf.source, + "source device name", NULL, 0}, + + {NULL, 0, NULL, NULL, NULL, 0} +}; + +static struct audio_pcm_ops qpa_pcm_ops = { + qpa_init_out, + qpa_fini_out, + qpa_run_out, + qpa_write, + qpa_ctl_out, + qpa_init_in, + qpa_fini_in, + qpa_run_in, + qpa_read, + qpa_ctl_in +}; + +struct audio_driver pa_audio_driver = { + INIT_FIELD (name = ) "pa", + INIT_FIELD (descr = ) "http://www.pulseaudio.org/", + INIT_FIELD (options = ) qpa_options, + INIT_FIELD (init = ) qpa_audio_init, + INIT_FIELD (fini = ) qpa_audio_fini, + INIT_FIELD (pcm_ops = ) &qpa_pcm_ops, + INIT_FIELD (can_be_default = ) 0, + INIT_FIELD (max_voices_out = ) INT_MAX, + INIT_FIELD (max_voices_in = ) INT_MAX, + INIT_FIELD (voice_size_out = ) sizeof (PAVoiceOut), + INIT_FIELD (voice_size_in = ) sizeof (PAVoiceIn) +}; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/audio/sdlaudio.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/audio/sdlaudio.c --- qemu-0.9.1/audio/sdlaudio.c 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/audio/sdlaudio.c 2008-10-26 13:43:07.000000000 +0000 @@ -29,6 +29,8 @@ #ifndef _WIN32 #ifdef __sun__ #define _POSIX_PTHREAD_SEMANTICS 1 +#elif defined(__OpenBSD__) || defined(__FreeBSD__) +#include #endif #include #endif @@ -49,7 +51,7 @@ 1024 }; -struct SDLAudioState { +static struct SDLAudioState { int exit; SDL_mutex *mutex; SDL_sem *sem; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/audio/sys-queue.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/audio/sys-queue.h --- qemu-0.9.1/audio/sys-queue.h 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/audio/sys-queue.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,241 +0,0 @@ -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)queue.h 8.3 (Berkeley) 12/13/93 - */ - -#ifndef _SYS_QUEUE_H -#define _SYS_QUEUE_H 1 - -/* - * This file defines three types of data structures: lists, tail queues, - * and circular queues. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list after - * an existing element or at the head of the list. A list may only be - * traversed in the forward direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list after - * an existing element, at the head of the list, or at the end of the - * list. A tail queue may only be traversed in the forward direction. - * - * A circle queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or after - * an existing element, at the head of the list, or at the end of the list. - * A circle queue may be traversed in either direction, but has a more - * complex end of list detection. - * - * For details on the use of these macros, see the queue(3) manual page. - */ - -/* - * List definitions. - */ -#define LIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ -} - -#define LIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ -} - -/* - * List functions. - */ -#define LIST_INIT(head) { \ - (head)->lh_first = NULL; \ -} - -#define LIST_INSERT_AFTER(listelm, elm, field) { \ - if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ - (listelm)->field.le_next->field.le_prev = \ - &(elm)->field.le_next; \ - (listelm)->field.le_next = (elm); \ - (elm)->field.le_prev = &(listelm)->field.le_next; \ -} - -#define LIST_INSERT_HEAD(head, elm, field) { \ - if (((elm)->field.le_next = (head)->lh_first) != NULL) \ - (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ - (head)->lh_first = (elm); \ - (elm)->field.le_prev = &(head)->lh_first; \ -} - -#define LIST_REMOVE(elm, field) { \ - if ((elm)->field.le_next != NULL) \ - (elm)->field.le_next->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = (elm)->field.le_next; \ -} - -/* - * Tail queue definitions. - */ -#define TAILQ_HEAD(name, type) \ -struct name { \ - struct type *tqh_first; /* first element */ \ - struct type **tqh_last; /* addr of last next element */ \ -} - -#define TAILQ_ENTRY(type) \ -struct { \ - struct type *tqe_next; /* next element */ \ - struct type **tqe_prev; /* address of previous next element */ \ -} - -/* - * Tail queue functions. - */ -#define TAILQ_INIT(head) { \ - (head)->tqh_first = NULL; \ - (head)->tqh_last = &(head)->tqh_first; \ -} - -#define TAILQ_INSERT_HEAD(head, elm, field) { \ - if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ - (elm)->field.tqe_next->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (head)->tqh_first = (elm); \ - (elm)->field.tqe_prev = &(head)->tqh_first; \ -} - -#define TAILQ_INSERT_TAIL(head, elm, field) { \ - (elm)->field.tqe_next = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &(elm)->field.tqe_next; \ -} - -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) { \ - if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ - (elm)->field.tqe_next->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (listelm)->field.tqe_next = (elm); \ - (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ -} - -#define TAILQ_REMOVE(head, elm, field) { \ - if (((elm)->field.tqe_next) != NULL) \ - (elm)->field.tqe_next->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ -} - -/* - * Circular queue definitions. - */ -#define CIRCLEQ_HEAD(name, type) \ -struct name { \ - struct type *cqh_first; /* first element */ \ - struct type *cqh_last; /* last element */ \ -} - -#define CIRCLEQ_ENTRY(type) \ -struct { \ - struct type *cqe_next; /* next element */ \ - struct type *cqe_prev; /* previous element */ \ -} - -/* - * Circular queue functions. - */ -#define CIRCLEQ_INIT(head) { \ - (head)->cqh_first = (void *)(head); \ - (head)->cqh_last = (void *)(head); \ -} - -#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) { \ - (elm)->field.cqe_next = (listelm)->field.cqe_next; \ - (elm)->field.cqe_prev = (listelm); \ - if ((listelm)->field.cqe_next == (void *)(head)) \ - (head)->cqh_last = (elm); \ - else \ - (listelm)->field.cqe_next->field.cqe_prev = (elm); \ - (listelm)->field.cqe_next = (elm); \ -} - -#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) { \ - (elm)->field.cqe_next = (listelm); \ - (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ - if ((listelm)->field.cqe_prev == (void *)(head)) \ - (head)->cqh_first = (elm); \ - else \ - (listelm)->field.cqe_prev->field.cqe_next = (elm); \ - (listelm)->field.cqe_prev = (elm); \ -} - -#define CIRCLEQ_INSERT_HEAD(head, elm, field) { \ - (elm)->field.cqe_next = (head)->cqh_first; \ - (elm)->field.cqe_prev = (void *)(head); \ - if ((head)->cqh_last == (void *)(head)) \ - (head)->cqh_last = (elm); \ - else \ - (head)->cqh_first->field.cqe_prev = (elm); \ - (head)->cqh_first = (elm); \ -} - -#define CIRCLEQ_INSERT_TAIL(head, elm, field) { \ - (elm)->field.cqe_next = (void *)(head); \ - (elm)->field.cqe_prev = (head)->cqh_last; \ - if ((head)->cqh_first == (void *)(head)) \ - (head)->cqh_first = (elm); \ - else \ - (head)->cqh_last->field.cqe_next = (elm); \ - (head)->cqh_last = (elm); \ -} - -#define CIRCLEQ_REMOVE(head, elm, field) { \ - if ((elm)->field.cqe_next == (void *)(head)) \ - (head)->cqh_last = (elm)->field.cqe_prev; \ - else \ - (elm)->field.cqe_next->field.cqe_prev = \ - (elm)->field.cqe_prev; \ - if ((elm)->field.cqe_prev == (void *)(head)) \ - (head)->cqh_first = (elm)->field.cqe_next; \ - else \ - (elm)->field.cqe_prev->field.cqe_next = \ - (elm)->field.cqe_next; \ -} -#endif /* sys/queue.h */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/audio/wavaudio.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/audio/wavaudio.c --- qemu-0.9.1/audio/wavaudio.c 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/audio/wavaudio.c 2008-10-06 19:08:30.000000000 +0100 @@ -44,7 +44,7 @@ 44100, 2, AUD_FMT_S16, - AUDIO_HOST_ENDIANNESS + 0 }, "qemu.wav" }; @@ -218,7 +218,7 @@ ldebug ("wav_fini"); } -struct audio_option wav_options[] = { +static struct audio_option wav_options[] = { {"FREQUENCY", AUD_OPT_INT, &conf.settings.freq, "Frequency", NULL, 0}, @@ -233,7 +233,7 @@ {NULL, 0, NULL, NULL, NULL, 0} }; -struct audio_pcm_ops wav_pcm_ops = { +static struct audio_pcm_ops wav_pcm_ops = { wav_init_out, wav_fini_out, wav_run_out, diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/block.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/block.c --- qemu-0.9.1/block.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/block.c 2008-11-08 16:27:07.000000000 +0000 @@ -22,9 +22,7 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#ifndef QEMU_IMG #include "console.h" -#endif #include "block_int.h" #ifdef _BSD @@ -57,6 +55,7 @@ const uint8_t *buf, int nb_sectors); BlockDriverState *bdrv_first; + static BlockDriver *first_drv; int path_is_absolute(const char *path) @@ -191,8 +190,12 @@ void get_tmp_filename(char *filename, int size) { int fd; + const char *tmpdir; /* XXX: race condition possible */ - pstrcpy(filename, size, "/tmp/vl.XXXXXX"); + tmpdir = getenv("TMPDIR"); + if (!tmpdir) + tmpdir = "/tmp"; + snprintf(filename, size, "%s/vl.XXXXXX", tmpdir); fd = mkstemp(filename); close(fd); } @@ -335,6 +338,7 @@ if (flags & BDRV_O_SNAPSHOT) { BlockDriverState *bs1; int64_t total_size; + int is_protocol = 0; /* if snapshot, we create a temporary backing file and open it instead of opening 'filename' directly */ @@ -349,10 +353,21 @@ return -1; } total_size = bdrv_getlength(bs1) >> SECTOR_BITS; + + if (bs1->drv && bs1->drv->protocol_name) + is_protocol = 1; + bdrv_delete(bs1); get_tmp_filename(tmp_filename, sizeof(tmp_filename)); - realpath(filename, backing_filename); + + /* Real path is meaningless for protocols */ + if (is_protocol) + snprintf(backing_filename, sizeof(backing_filename), + "%s", filename); + else + realpath(filename, backing_filename); + if (bdrv_create(&bdrv_qcow2, tmp_filename, total_size, backing_filename, 0) < 0) { return -1; @@ -380,12 +395,12 @@ /* Note: for compatibility, we open disk image files as RDWR, and RDONLY as fallback */ if (!(flags & BDRV_O_FILE)) - open_flags = BDRV_O_RDWR | (flags & BDRV_O_DIRECT); + open_flags = BDRV_O_RDWR | (flags & BDRV_O_CACHE_MASK); else open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT); ret = drv->bdrv_open(bs, filename, open_flags); - if (ret == -EACCES && !(flags & BDRV_O_FILE)) { - ret = drv->bdrv_open(bs, filename, BDRV_O_RDONLY); + if ((ret == -EACCES || ret == -EPERM) && !(flags & BDRV_O_FILE)) { + ret = drv->bdrv_open(bs, filename, open_flags & ~BDRV_O_RDWR); bs->read_only = 1; } if (ret < 0) { @@ -412,7 +427,7 @@ } path_combine(backing_filename, sizeof(backing_filename), filename, bs->backing_file); - if (bdrv_open(bs->backing_hd, backing_filename, 0) < 0) + if (bdrv_open(bs->backing_hd, backing_filename, open_flags) < 0) goto fail; } @@ -448,7 +463,14 @@ void bdrv_delete(BlockDriverState *bs) { - /* XXX: remove the driver list */ + BlockDriverState **pbs; + + pbs = &bdrv_first; + while (*pbs != bs && *pbs != NULL) + pbs = &(*pbs)->next; + if (*pbs == bs) + *pbs = bs->next; + bdrv_close(bs); qemu_free(bs); } @@ -505,14 +527,6 @@ if (!drv) return -ENOMEDIUM; - if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { - memcpy(buf, bs->boot_sector_data, 512); - sector_num++; - nb_sectors--; - buf += 512; - if (nb_sectors == 0) - return 0; - } if (drv->bdrv_pread) { int ret, len; len = nb_sectors * 512; @@ -545,9 +559,6 @@ return -ENOMEDIUM; if (bs->read_only) return -EACCES; - if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { - memcpy(bs->boot_sector_data, buf, 512); - } if (drv->bdrv_pwrite) { int ret, len; len = nb_sectors * 512; @@ -728,16 +739,6 @@ *nb_sectors_ptr = length; } -/* force a given boot sector. */ -void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size) -{ - bs->boot_sector_enabled = 1; - if (size > 512) - size = 512; - memcpy(bs->boot_sector_data, data, size); - memset(bs->boot_sector_data + size, 0, 512 - size); -} - void bdrv_set_geometry_hint(BlockDriverState *bs, int cyls, int heads, int secs) { @@ -873,7 +874,43 @@ bdrv_flush(bs->backing_hd); } -#ifndef QEMU_IMG +void bdrv_flush_all(void) +{ + BlockDriverState *bs; + + for (bs = bdrv_first; bs != NULL; bs = bs->next) + if (bs->drv && !bdrv_is_read_only(bs) && + (!bdrv_is_removable(bs) || bdrv_is_inserted(bs))) + bdrv_flush(bs); +} + +/* + * Returns true iff the specified sector is present in the disk image. Drivers + * not implementing the functionality are assumed to not support backing files, + * hence all their sectors are reported as allocated. + * + * 'pnum' is set to the number of sectors (including and immediately following + * the specified sector) that are known to be in the same + * allocated/unallocated state. + * + * 'nb_sectors' is the max value 'pnum' should be set to. + */ +int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, + int *pnum) +{ + int64_t n; + if (!bs->drv->bdrv_is_allocated) { + if (sector_num >= bs->total_sectors) { + *pnum = 0; + return 0; + } + n = bs->total_sectors - sector_num; + *pnum = (n < nb_sectors) ? (n) : (nb_sectors); + return 1; + } + return bs->drv->bdrv_is_allocated(bs, sector_num, nb_sectors, pnum); +} + void bdrv_info(void) { BlockDriverState *bs; @@ -931,7 +968,6 @@ bs->rd_ops, bs->wr_ops); } } -#endif void bdrv_get_backing_filename(BlockDriverState *bs, char *filename, int filename_size) @@ -1098,14 +1134,6 @@ if (!drv) return NULL; - /* XXX: we assume that nb_sectors == 0 is suppored by the async read */ - if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { - memcpy(buf, bs->boot_sector_data, 512); - sector_num++; - nb_sectors--; - buf += 512; - } - ret = drv->bdrv_aio_read(bs, sector_num, buf, nb_sectors, cb, opaque); if (ret) { @@ -1128,9 +1156,6 @@ return NULL; if (bs->read_only) return NULL; - if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { - memcpy(bs->boot_sector_data, buf, 512); - } ret = drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque); @@ -1154,31 +1179,6 @@ /**************************************************************/ /* async block device emulation */ -#ifdef QEMU_IMG -static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs, - int64_t sector_num, uint8_t *buf, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque) -{ - int ret; - ret = bdrv_read(bs, sector_num, buf, nb_sectors); - cb(opaque, ret); - return NULL; -} - -static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs, - int64_t sector_num, const uint8_t *buf, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque) -{ - int ret; - ret = bdrv_write(bs, sector_num, buf, nb_sectors); - cb(opaque, ret); - return NULL; -} - -static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb) -{ -} -#else static void bdrv_aio_bh_cb(void *opaque) { BlockDriverAIOCBSync *acb = opaque; @@ -1224,7 +1224,6 @@ qemu_bh_cancel(acb->bh); qemu_aio_release(acb); } -#endif /* !QEMU_IMG */ /**************************************************************/ /* sync block device emulation */ @@ -1243,17 +1242,15 @@ BlockDriverAIOCB *acb; async_ret = NOT_DONE; - qemu_aio_wait_start(); acb = bdrv_aio_read(bs, sector_num, buf, nb_sectors, bdrv_rw_em_cb, &async_ret); - if (acb == NULL) { - qemu_aio_wait_end(); + if (acb == NULL) return -1; - } + while (async_ret == NOT_DONE) { qemu_aio_wait(); } - qemu_aio_wait_end(); + return async_ret; } @@ -1264,17 +1261,13 @@ BlockDriverAIOCB *acb; async_ret = NOT_DONE; - qemu_aio_wait_start(); acb = bdrv_aio_write(bs, sector_num, buf, nb_sectors, bdrv_rw_em_cb, &async_ret); - if (acb == NULL) { - qemu_aio_wait_end(); + if (acb == NULL) return -1; - } while (async_ret == NOT_DONE) { qemu_aio_wait(); } - qemu_aio_wait_end(); return async_ret; } @@ -1294,6 +1287,7 @@ bdrv_register(&bdrv_vvfat); bdrv_register(&bdrv_qcow2); bdrv_register(&bdrv_parallels); + bdrv_register(&bdrv_nbd); } void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb, diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/block-dmg.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/block-dmg.c --- qemu-0.9.1/block-dmg.c 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/block-dmg.c 2008-08-06 09:37:17.000000000 +0100 @@ -125,11 +125,11 @@ goto dmg_close; chunk_count = (count-204)/40; new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count); - s->types = realloc(s->types, new_size/2); - s->offsets = realloc(s->offsets, new_size); - s->lengths = realloc(s->lengths, new_size); - s->sectors = realloc(s->sectors, new_size); - s->sectorcounts = realloc(s->sectorcounts, new_size); + s->types = qemu_realloc(s->types, new_size/2); + s->offsets = qemu_realloc(s->offsets, new_size); + s->lengths = qemu_realloc(s->lengths, new_size); + s->sectors = qemu_realloc(s->sectors, new_size); + s->sectorcounts = qemu_realloc(s->sectorcounts, new_size); for(i=s->n_chunks;in_chunks+chunk_count;i++) { s->types[i] = read_uint32(s->fd); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/block.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/block.h --- qemu-0.9.1/block.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/block.h 2008-11-08 16:27:07.000000000 +0000 @@ -1,6 +1,8 @@ #ifndef BLOCK_H #define BLOCK_H +#include "qemu-aio.h" + /* block.c */ typedef struct BlockDriver BlockDriver; @@ -16,6 +18,7 @@ extern BlockDriver bdrv_vvfat; extern BlockDriver bdrv_qcow2; extern BlockDriver bdrv_parallels; +extern BlockDriver bdrv_nbd; typedef struct BlockDriverInfo { /* in bytes, 0 if irrelevant */ @@ -44,12 +47,13 @@ use a disk image format on top of it (default for bdrv_file_open()) */ -#define BDRV_O_DIRECT 0x0020 +#define BDRV_O_NOCACHE 0x0020 /* do not use the host page cache */ +#define BDRV_O_CACHE_WB 0x0040 /* use write-back caching */ + +#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB) -#ifndef QEMU_IMG void bdrv_info(void); void bdrv_info_stats(void); -#endif void bdrv_init(void); BlockDriver *bdrv_find_format(const char *format_name); @@ -75,7 +79,6 @@ int64_t bdrv_getlength(BlockDriverState *bs); void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); int bdrv_commit(BlockDriverState *bs); -void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size); /* async block I/O */ typedef struct BlockDriverAIOCB BlockDriverAIOCB; typedef void BlockDriverCompletionFunc(void *opaque, int ret); @@ -88,17 +91,14 @@ BlockDriverCompletionFunc *cb, void *opaque); void bdrv_aio_cancel(BlockDriverAIOCB *acb); -void qemu_aio_init(void); -void qemu_aio_poll(void); -void qemu_aio_flush(void); -void qemu_aio_wait_start(void); -void qemu_aio_wait(void); -void qemu_aio_wait_end(void); - int qemu_key_check(BlockDriverState *bs, const char *name); /* Ensure contents are flushed to disk. */ void bdrv_flush(BlockDriverState *bs); +void bdrv_flush_all(void); + +int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, + int *pnum); #define BDRV_TYPE_HD 0 #define BDRV_TYPE_CDROM 1 diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/block_int.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/block_int.h --- qemu-0.9.1/block_int.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/block_int.h 2008-11-08 16:27:07.000000000 +0000 @@ -104,9 +104,6 @@ BlockDriver *drv; /* NULL means no media */ void *opaque; - int boot_sector_enabled; - uint8_t boot_sector_data[512]; - char filename[1024]; char backing_file[1024]; /* if non zero, the image is a diff of this file image */ @@ -145,6 +142,6 @@ void *opaque); void qemu_aio_release(void *p); -BlockDriverState *bdrv_first; +extern BlockDriverState *bdrv_first; #endif /* BLOCK_INT_H */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/block-nbd.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/block-nbd.c --- qemu-0.9.1/block-nbd.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/block-nbd.c 2008-08-19 20:10:38.000000000 +0100 @@ -0,0 +1,189 @@ +/* + * QEMU Block driver for NBD + * + * Copyright (C) 2008 Bull S.A.S. + * Author: Laurent Vivier + * + * Some parts: + * Copyright (C) 2007 Anthony Liguori + * + * 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 "qemu-common.h" +#include "nbd.h" + +#include +#include + +typedef struct BDRVNBDState { + int sock; + off_t size; + size_t blocksize; +} BDRVNBDState; + +static int nbd_open(BlockDriverState *bs, const char* filename, int flags) +{ + BDRVNBDState *s = bs->opaque; + const char *host; + const char *unixpath; + int sock; + off_t size; + size_t blocksize; + int ret; + + if ((flags & BDRV_O_CREAT)) + return -EINVAL; + + if (!strstart(filename, "nbd:", &host)) + return -EINVAL; + + if (strstart(host, "unix:", &unixpath)) { + + if (unixpath[0] != '/') + return -EINVAL; + + sock = unix_socket_outgoing(unixpath); + + } else { + uint16_t port; + char *p, *r; + char hostname[128]; + + pstrcpy(hostname, 128, host); + + p = strchr(hostname, ':'); + if (p == NULL) + return -EINVAL; + + *p = '\0'; + p++; + + port = strtol(p, &r, 0); + if (r == p) + return -EINVAL; + sock = tcp_socket_outgoing(hostname, port); + } + + if (sock == -1) + return -errno; + + ret = nbd_receive_negotiate(sock, &size, &blocksize); + if (ret == -1) + return -errno; + + s->sock = sock; + s->size = size; + s->blocksize = blocksize; + + return 0; +} + +static int nbd_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + BDRVNBDState *s = bs->opaque; + struct nbd_request request; + struct nbd_reply reply; + + request.type = NBD_CMD_READ; + request.handle = (uint64_t)(intptr_t)bs; + request.from = sector_num * 512;; + request.len = nb_sectors * 512; + + if (nbd_send_request(s->sock, &request) == -1) + return -errno; + + if (nbd_receive_reply(s->sock, &reply) == -1) + return -errno; + + if (reply.error !=0) + return -reply.error; + + if (reply.handle != request.handle) + return -EIO; + + if (nbd_wr_sync(s->sock, buf, request.len, 1) != request.len) + return -EIO; + + return 0; +} + +static int nbd_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + BDRVNBDState *s = bs->opaque; + struct nbd_request request; + struct nbd_reply reply; + + request.type = NBD_CMD_WRITE; + request.handle = (uint64_t)(intptr_t)bs; + request.from = sector_num * 512;; + request.len = nb_sectors * 512; + + if (nbd_send_request(s->sock, &request) == -1) + return -errno; + + if (nbd_wr_sync(s->sock, (uint8_t*)buf, request.len, 0) != request.len) + return -EIO; + + if (nbd_receive_reply(s->sock, &reply) == -1) + return -errno; + + if (reply.error !=0) + return -reply.error; + + if (reply.handle != request.handle) + return -EIO; + + return 0; +} + +static void nbd_close(BlockDriverState *bs) +{ + BDRVNBDState *s = bs->opaque; + struct nbd_request request; + + request.type = NBD_CMD_DISC; + request.handle = (uint64_t)(intptr_t)bs; + request.from = 0; + request.len = 0; + nbd_send_request(s->sock, &request); + + close(s->sock); +} + +static int64_t nbd_getlength(BlockDriverState *bs) +{ + BDRVNBDState *s = bs->opaque; + + return s->size; +} + +BlockDriver bdrv_nbd = { + "nbd", + sizeof(BDRVNBDState), + NULL, /* no probe for protocols */ + nbd_open, + nbd_read, + nbd_write, + nbd_close, + .bdrv_getlength = nbd_getlength, + .protocol_name = "nbd", +}; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/block-qcow2.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/block-qcow2.c --- qemu-0.9.1/block-qcow2.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/block-qcow2.c 2008-10-31 17:28:00.000000000 +0000 @@ -52,6 +52,8 @@ #define QCOW_CRYPT_NONE 0 #define QCOW_CRYPT_AES 1 +#define QCOW_MAX_CRYPT_CLUSTERS 32 + /* indicate that the refcount of the referenced cluster is exactly one. */ #define QCOW_OFLAG_COPIED (1LL << 63) /* indicate that the cluster is compressed (they never have the copied flag) */ @@ -59,10 +61,6 @@ #define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */ -#ifndef offsetof -#define offsetof(type, field) ((size_t) &((type *)0)->field) -#endif - typedef struct QCowHeader { uint32_t magic; uint32_t version; @@ -263,7 +261,8 @@ if (!s->cluster_cache) goto fail; /* one more sector for decompressed data alignment */ - s->cluster_data = qemu_malloc(s->cluster_size + 512); + s->cluster_data = qemu_malloc(QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size + + 512); if (!s->cluster_data) goto fail; s->cluster_cache_offset = -1; @@ -480,169 +479,535 @@ return -EIO; } -/* 'allocate' is: +/* + * seek_l2_table + * + * seek l2_offset in the l2_cache table + * if not found, return NULL, + * if found, + * increments the l2 cache hit count of the entry, + * if counter overflow, divide by two all counters + * return the pointer to the l2 cache entry + * + */ + +static uint64_t *seek_l2_table(BDRVQcowState *s, uint64_t l2_offset) +{ + int i, j; + + for(i = 0; i < L2_CACHE_SIZE; i++) { + if (l2_offset == s->l2_cache_offsets[i]) { + /* increment the hit count */ + if (++s->l2_cache_counts[i] == 0xffffffff) { + for(j = 0; j < L2_CACHE_SIZE; j++) { + s->l2_cache_counts[j] >>= 1; + } + } + return s->l2_cache + (i << s->l2_bits); + } + } + return NULL; +} + +/* + * l2_load + * + * Loads a L2 table into memory. If the table is in the cache, the cache + * is used; otherwise the L2 table is loaded from the image file. + * + * Returns a pointer to the L2 table on success, or NULL if the read from + * the image file failed. + */ + +static uint64_t *l2_load(BlockDriverState *bs, uint64_t l2_offset) +{ + BDRVQcowState *s = bs->opaque; + int min_index; + uint64_t *l2_table; + + /* seek if the table for the given offset is in the cache */ + + l2_table = seek_l2_table(s, l2_offset); + if (l2_table != NULL) + return l2_table; + + /* not found: load a new entry in the least used one */ + + min_index = l2_cache_new_entry(bs); + l2_table = s->l2_cache + (min_index << s->l2_bits); + if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != + s->l2_size * sizeof(uint64_t)) + return NULL; + s->l2_cache_offsets[min_index] = l2_offset; + s->l2_cache_counts[min_index] = 1; + + return l2_table; +} + +/* + * l2_allocate + * + * Allocate a new l2 entry in the file. If l1_index points to an already + * used entry in the L2 table (i.e. we are doing a copy on write for the L2 + * table) copy the contents of the old L2 table into the newly allocated one. + * Otherwise the new table is initialized with zeros. + * + */ + +static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index) +{ + BDRVQcowState *s = bs->opaque; + int min_index; + uint64_t old_l2_offset, tmp; + uint64_t *l2_table, l2_offset; + + old_l2_offset = s->l1_table[l1_index]; + + /* allocate a new l2 entry */ + + l2_offset = alloc_clusters(bs, s->l2_size * sizeof(uint64_t)); + + /* update the L1 entry */ + + s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED; + + tmp = cpu_to_be64(l2_offset | QCOW_OFLAG_COPIED); + if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp), + &tmp, sizeof(tmp)) != sizeof(tmp)) + return NULL; + + /* allocate a new entry in the l2 cache */ + + min_index = l2_cache_new_entry(bs); + l2_table = s->l2_cache + (min_index << s->l2_bits); + + if (old_l2_offset == 0) { + /* if there was no old l2 table, clear the new table */ + memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); + } else { + /* if there was an old l2 table, read it from the disk */ + if (bdrv_pread(s->hd, old_l2_offset, + l2_table, s->l2_size * sizeof(uint64_t)) != + s->l2_size * sizeof(uint64_t)) + return NULL; + } + /* write the l2 table to the file */ + if (bdrv_pwrite(s->hd, l2_offset, + l2_table, s->l2_size * sizeof(uint64_t)) != + s->l2_size * sizeof(uint64_t)) + return NULL; + + /* update the l2 cache entry */ + + s->l2_cache_offsets[min_index] = l2_offset; + s->l2_cache_counts[min_index] = 1; + + return l2_table; +} + +/* + * get_cluster_offset + * + * For a given offset of the disk image, return cluster offset in + * qcow2 file. * - * 0 not to allocate. + * on entry, *num is the number of contiguous clusters we'd like to + * access following offset. * - * 1 to allocate a normal cluster (for sector indexes 'n_start' to - * 'n_end') + * on exit, *num is the number of contiguous clusters we can read. * - * 2 to allocate a compressed cluster of size - * 'compressed_size'. 'compressed_size' must be > 0 and < - * cluster_size + * Return 1, if the offset is found + * Return 0, otherwise. * - * return 0 if not allocated. */ + static uint64_t get_cluster_offset(BlockDriverState *bs, - uint64_t offset, int allocate, - int compressed_size, - int n_start, int n_end) + uint64_t offset, int *num) { BDRVQcowState *s = bs->opaque; - int min_index, i, j, l1_index, l2_index, ret; - uint64_t l2_offset, *l2_table, cluster_offset, tmp, old_l2_offset; + int l1_index, l2_index; + uint64_t l2_offset, *l2_table, cluster_offset, next; + int l1_bits; + int index_in_cluster, nb_available, nb_needed; + + index_in_cluster = (offset >> 9) & (s->cluster_sectors - 1); + nb_needed = *num + index_in_cluster; + + l1_bits = s->l2_bits + s->cluster_bits; + + /* compute how many bytes there are between the offset and + * and the end of the l1 entry + */ + + nb_available = (1 << l1_bits) - (offset & ((1 << l1_bits) - 1)); + + /* compute the number of available sectors */ + + nb_available = (nb_available >> 9) + index_in_cluster; + + cluster_offset = 0; + + /* seek the the l2 offset in the l1 table */ + + l1_index = offset >> l1_bits; + if (l1_index >= s->l1_size) + goto out; + + l2_offset = s->l1_table[l1_index]; + + /* seek the l2 table of the given l2 offset */ + + if (!l2_offset) + goto out; + + /* load the l2 table in memory */ + + l2_offset &= ~QCOW_OFLAG_COPIED; + l2_table = l2_load(bs, l2_offset); + if (l2_table == NULL) + return 0; + + /* find the cluster offset for the given disk offset */ + + l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); + cluster_offset = be64_to_cpu(l2_table[l2_index]); + nb_available = s->cluster_sectors; + l2_index++; + + if (!cluster_offset) { + + /* how many empty clusters ? */ + + while (nb_available < nb_needed && !l2_table[l2_index]) { + l2_index++; + nb_available += s->cluster_sectors; + } + } else { + + /* how many allocated clusters ? */ + + cluster_offset &= ~QCOW_OFLAG_COPIED; + while (nb_available < nb_needed) { + next = be64_to_cpu(l2_table[l2_index]) & ~QCOW_OFLAG_COPIED; + if (next != cluster_offset + (nb_available << 9)) + break; + l2_index++; + nb_available += s->cluster_sectors; + } + } + +out: + if (nb_available > nb_needed) + nb_available = nb_needed; + + *num = nb_available - index_in_cluster; + + return cluster_offset; +} + +/* + * free_any_clusters + * + * free clusters according to its type: compressed or not + * + */ + +static void free_any_clusters(BlockDriverState *bs, + uint64_t cluster_offset, int nb_clusters) +{ + BDRVQcowState *s = bs->opaque; + + /* free the cluster */ + + if (cluster_offset & QCOW_OFLAG_COMPRESSED) { + int nb_csectors; + nb_csectors = ((cluster_offset >> s->csize_shift) & + s->csize_mask) + 1; + free_clusters(bs, (cluster_offset & s->cluster_offset_mask) & ~511, + nb_csectors * 512); + return; + } + + free_clusters(bs, cluster_offset, nb_clusters << s->cluster_bits); + + return; +} + +/* + * get_cluster_table + * + * for a given disk offset, load (and allocate if needed) + * the l2 table. + * + * the l2 table offset in the qcow2 file and the cluster index + * in the l2 table are given to the caller. + * + */ + +static int get_cluster_table(BlockDriverState *bs, uint64_t offset, + uint64_t **new_l2_table, + uint64_t *new_l2_offset, + int *new_l2_index) +{ + BDRVQcowState *s = bs->opaque; + int l1_index, l2_index, ret; + uint64_t l2_offset, *l2_table; + + /* seek the the l2 offset in the l1 table */ l1_index = offset >> (s->l2_bits + s->cluster_bits); if (l1_index >= s->l1_size) { - /* outside l1 table is allowed: we grow the table if needed */ - if (!allocate) - return 0; - if (grow_l1_table(bs, l1_index + 1) < 0) + ret = grow_l1_table(bs, l1_index + 1); + if (ret < 0) return 0; } l2_offset = s->l1_table[l1_index]; - if (!l2_offset) { - if (!allocate) - return 0; - l2_allocate: - old_l2_offset = l2_offset; - /* allocate a new l2 entry */ - l2_offset = alloc_clusters(bs, s->l2_size * sizeof(uint64_t)); - /* update the L1 entry */ - s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED; - tmp = cpu_to_be64(l2_offset | QCOW_OFLAG_COPIED); - if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp), - &tmp, sizeof(tmp)) != sizeof(tmp)) - return 0; - min_index = l2_cache_new_entry(bs); - l2_table = s->l2_cache + (min_index << s->l2_bits); - if (old_l2_offset == 0) { - memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); - } else { - if (bdrv_pread(s->hd, old_l2_offset, - l2_table, s->l2_size * sizeof(uint64_t)) != - s->l2_size * sizeof(uint64_t)) - return 0; - } - if (bdrv_pwrite(s->hd, l2_offset, - l2_table, s->l2_size * sizeof(uint64_t)) != - s->l2_size * sizeof(uint64_t)) + /* seek the l2 table of the given l2 offset */ + + if (l2_offset & QCOW_OFLAG_COPIED) { + /* load the l2 table in memory */ + l2_offset &= ~QCOW_OFLAG_COPIED; + l2_table = l2_load(bs, l2_offset); + if (l2_table == NULL) return 0; } else { - if (!(l2_offset & QCOW_OFLAG_COPIED)) { - if (allocate) { - free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t)); - goto l2_allocate; - } - } else { - l2_offset &= ~QCOW_OFLAG_COPIED; - } - for(i = 0; i < L2_CACHE_SIZE; i++) { - if (l2_offset == s->l2_cache_offsets[i]) { - /* increment the hit count */ - if (++s->l2_cache_counts[i] == 0xffffffff) { - for(j = 0; j < L2_CACHE_SIZE; j++) { - s->l2_cache_counts[j] >>= 1; - } - } - l2_table = s->l2_cache + (i << s->l2_bits); - goto found; - } - } - /* not found: load a new entry in the least used one */ - min_index = l2_cache_new_entry(bs); - l2_table = s->l2_cache + (min_index << s->l2_bits); - if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != - s->l2_size * sizeof(uint64_t)) + if (l2_offset) + free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t)); + l2_table = l2_allocate(bs, l1_index); + if (l2_table == NULL) return 0; + l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED; } - s->l2_cache_offsets[min_index] = l2_offset; - s->l2_cache_counts[min_index] = 1; - found: + + /* find the cluster offset for the given disk offset */ + l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); + + *new_l2_table = l2_table; + *new_l2_offset = l2_offset; + *new_l2_index = l2_index; + + return 1; +} + +/* + * alloc_compressed_cluster_offset + * + * For a given offset of the disk image, return cluster offset in + * qcow2 file. + * + * If the offset is not found, allocate a new compressed cluster. + * + * Return the cluster offset if successful, + * Return 0, otherwise. + * + */ + +static uint64_t alloc_compressed_cluster_offset(BlockDriverState *bs, + uint64_t offset, + int compressed_size) +{ + BDRVQcowState *s = bs->opaque; + int l2_index, ret; + uint64_t l2_offset, *l2_table, cluster_offset; + int nb_csectors; + + ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index); + if (ret == 0) + return 0; + cluster_offset = be64_to_cpu(l2_table[l2_index]); - if (!cluster_offset) { - if (!allocate) - return cluster_offset; - } else if (!(cluster_offset & QCOW_OFLAG_COPIED)) { - if (!allocate) - return cluster_offset; - /* free the cluster */ - if (cluster_offset & QCOW_OFLAG_COMPRESSED) { - int nb_csectors; - nb_csectors = ((cluster_offset >> s->csize_shift) & - s->csize_mask) + 1; - free_clusters(bs, (cluster_offset & s->cluster_offset_mask) & ~511, - nb_csectors * 512); - } else { - free_clusters(bs, cluster_offset, s->cluster_size); + if (cluster_offset & QCOW_OFLAG_COPIED) + return cluster_offset & ~QCOW_OFLAG_COPIED; + + if (cluster_offset) + free_any_clusters(bs, cluster_offset, 1); + + cluster_offset = alloc_bytes(bs, compressed_size); + nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) - + (cluster_offset >> 9); + + cluster_offset |= QCOW_OFLAG_COMPRESSED | + ((uint64_t)nb_csectors << s->csize_shift); + + /* update L2 table */ + + /* compressed clusters never have the copied flag */ + + l2_table[l2_index] = cpu_to_be64(cluster_offset); + if (bdrv_pwrite(s->hd, + l2_offset + l2_index * sizeof(uint64_t), + l2_table + l2_index, + sizeof(uint64_t)) != sizeof(uint64_t)) + return 0; + + return cluster_offset; +} + +/* + * alloc_cluster_offset + * + * For a given offset of the disk image, return cluster offset in + * qcow2 file. + * + * If the offset is not found, allocate a new cluster. + * + * Return the cluster offset if successful, + * Return 0, otherwise. + * + */ + +static uint64_t alloc_cluster_offset(BlockDriverState *bs, + uint64_t offset, + int n_start, int n_end, + int *num) +{ + BDRVQcowState *s = bs->opaque; + int l2_index, ret; + uint64_t l2_offset, *l2_table, cluster_offset; + int nb_available, nb_clusters, i, j; + uint64_t start_sect, current; + + ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index); + if (ret == 0) + return 0; + + nb_clusters = ((n_end << 9) + s->cluster_size - 1) >> + s->cluster_bits; + if (nb_clusters > s->l2_size - l2_index) + nb_clusters = s->l2_size - l2_index; + + cluster_offset = be64_to_cpu(l2_table[l2_index]); + + /* We keep all QCOW_OFLAG_COPIED clusters */ + + if (cluster_offset & QCOW_OFLAG_COPIED) { + + for (i = 1; i < nb_clusters; i++) { + current = be64_to_cpu(l2_table[l2_index + i]); + if (cluster_offset + (i << s->cluster_bits) != current) + break; } - } else { + nb_clusters = i; + + nb_available = nb_clusters << (s->cluster_bits - 9); + if (nb_available > n_end) + nb_available = n_end; + cluster_offset &= ~QCOW_OFLAG_COPIED; - return cluster_offset; + + goto out; } - if (allocate == 1) { - /* allocate a new cluster */ - cluster_offset = alloc_clusters(bs, s->cluster_size); - - /* we must initialize the cluster content which won't be - written */ - if ((n_end - n_start) < s->cluster_sectors) { - uint64_t start_sect; - - start_sect = (offset & ~(s->cluster_size - 1)) >> 9; - ret = copy_sectors(bs, start_sect, - cluster_offset, 0, n_start); - if (ret < 0) - return 0; - ret = copy_sectors(bs, start_sect, - cluster_offset, n_end, s->cluster_sectors); - if (ret < 0) - return 0; + + /* for the moment, multiple compressed clusters are not managed */ + + if (cluster_offset & QCOW_OFLAG_COMPRESSED) + nb_clusters = 1; + + /* how many available clusters ? */ + + i = 0; + while (i < nb_clusters) { + + i++; + + if (!cluster_offset) { + + /* how many free clusters ? */ + + while (i < nb_clusters) { + cluster_offset = be64_to_cpu(l2_table[l2_index + i]); + if (cluster_offset != 0) + break; + i++; + } + + if ((cluster_offset & QCOW_OFLAG_COPIED) || + (cluster_offset & QCOW_OFLAG_COMPRESSED)) + break; + + } else { + + /* how many contiguous clusters ? */ + + j = 1; + current = 0; + while (i < nb_clusters) { + current = be64_to_cpu(l2_table[l2_index + i]); + if (cluster_offset + (j << s->cluster_bits) != current) + break; + + i++; + j++; + } + + free_any_clusters(bs, cluster_offset, j); + if (current) + break; + cluster_offset = current; } - tmp = cpu_to_be64(cluster_offset | QCOW_OFLAG_COPIED); - } else { - int nb_csectors; - cluster_offset = alloc_bytes(bs, compressed_size); - nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) - - (cluster_offset >> 9); - cluster_offset |= QCOW_OFLAG_COMPRESSED | - ((uint64_t)nb_csectors << s->csize_shift); - /* compressed clusters never have the copied flag */ - tmp = cpu_to_be64(cluster_offset); } + nb_clusters = i; + + /* allocate a new cluster */ + + cluster_offset = alloc_clusters(bs, nb_clusters * s->cluster_size); + + /* we must initialize the cluster content which won't be + written */ + + nb_available = nb_clusters << (s->cluster_bits - 9); + if (nb_available > n_end) + nb_available = n_end; + + /* copy content of unmodified sectors */ + + start_sect = (offset & ~(s->cluster_size - 1)) >> 9; + if (n_start) { + ret = copy_sectors(bs, start_sect, cluster_offset, 0, n_start); + if (ret < 0) + return 0; + } + + if (nb_available & (s->cluster_sectors - 1)) { + uint64_t end = nb_available & ~(uint64_t)(s->cluster_sectors - 1); + ret = copy_sectors(bs, start_sect + end, + cluster_offset + (end << 9), + nb_available - end, + s->cluster_sectors); + if (ret < 0) + return 0; + } + /* update L2 table */ - l2_table[l2_index] = tmp; + + for (i = 0; i < nb_clusters; i++) + l2_table[l2_index + i] = cpu_to_be64((cluster_offset + + (i << s->cluster_bits)) | + QCOW_OFLAG_COPIED); + if (bdrv_pwrite(s->hd, - l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp)) + l2_offset + l2_index * sizeof(uint64_t), + l2_table + l2_index, + nb_clusters * sizeof(uint64_t)) != + nb_clusters * sizeof(uint64_t)) return 0; + +out: + *num = nb_available - n_start; + return cluster_offset; } static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum) { - BDRVQcowState *s = bs->opaque; - int index_in_cluster, n; uint64_t cluster_offset; - cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0); - index_in_cluster = sector_num & (s->cluster_sectors - 1); - n = s->cluster_sectors - index_in_cluster; - if (n > nb_sectors) - n = nb_sectors; - *pnum = n; + *pnum = nb_sectors; + cluster_offset = get_cluster_offset(bs, sector_num << 9, pnum); + return (cluster_offset != 0); } @@ -719,11 +1084,9 @@ uint64_t cluster_offset; while (nb_sectors > 0) { - cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0); + n = nb_sectors; + cluster_offset = get_cluster_offset(bs, sector_num << 9, &n); index_in_cluster = sector_num & (s->cluster_sectors - 1); - n = s->cluster_sectors - index_in_cluster; - if (n > nb_sectors) - n = nb_sectors; if (!cluster_offset) { if (bs->backing_hd) { /* read from the base image */ @@ -762,15 +1125,17 @@ BDRVQcowState *s = bs->opaque; int ret, index_in_cluster, n; uint64_t cluster_offset; + int n_end; while (nb_sectors > 0) { index_in_cluster = sector_num & (s->cluster_sectors - 1); - n = s->cluster_sectors - index_in_cluster; - if (n > nb_sectors) - n = nb_sectors; - cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0, - index_in_cluster, - index_in_cluster + n); + n_end = index_in_cluster + nb_sectors; + if (s->crypt_method && + n_end > QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors) + n_end = QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors; + cluster_offset = alloc_cluster_offset(bs, sector_num << 9, + index_in_cluster, + n_end, &n); if (!cluster_offset) return -1; if (s->crypt_method) { @@ -800,8 +1165,18 @@ uint64_t cluster_offset; uint8_t *cluster_data; BlockDriverAIOCB *hd_aiocb; + QEMUBH *bh; } QCowAIOCB; +static void qcow_aio_read_cb(void *opaque, int ret); +static void qcow_aio_read_bh(void *opaque) +{ + QCowAIOCB *acb = opaque; + qemu_bh_delete(acb->bh); + acb->bh = NULL; + qcow_aio_read_cb(opaque, 0); +} + static void qcow_aio_read_cb(void *opaque, int ret) { QCowAIOCB *acb = opaque; @@ -817,7 +1192,6 @@ return; } - redo: /* post process the read buffer */ if (!acb->cluster_offset) { /* nothing to do */ @@ -843,12 +1217,9 @@ } /* prepare next AIO request */ - acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, - 0, 0, 0, 0); + acb->n = acb->nb_sectors; + acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, &acb->n); index_in_cluster = acb->sector_num & (s->cluster_sectors - 1); - acb->n = s->cluster_sectors - index_in_cluster; - if (acb->n > acb->nb_sectors) - acb->n = acb->nb_sectors; if (!acb->cluster_offset) { if (bs->backing_hd) { @@ -861,12 +1232,30 @@ if (acb->hd_aiocb == NULL) goto fail; } else { - goto redo; + if (acb->bh) { + ret = -EIO; + goto fail; + } + acb->bh = qemu_bh_new(qcow_aio_read_bh, acb); + if (!acb->bh) { + ret = -EIO; + goto fail; + } + qemu_bh_schedule(acb->bh); } } else { /* Note: in this case, no need to wait */ memset(acb->buf, 0, 512 * acb->n); - goto redo; + if (acb->bh) { + ret = -EIO; + goto fail; + } + acb->bh = qemu_bh_new(qcow_aio_read_bh, acb); + if (!acb->bh) { + ret = -EIO; + goto fail; + } + qemu_bh_schedule(acb->bh); } } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) { /* add AIO support for compressed blocks ? */ @@ -874,7 +1263,16 @@ goto fail; memcpy(acb->buf, s->cluster_cache + index_in_cluster * 512, 512 * acb->n); - goto redo; + if (acb->bh) { + ret = -EIO; + goto fail; + } + acb->bh = qemu_bh_new(qcow_aio_read_bh, acb); + if (!acb->bh) { + ret = -EIO; + goto fail; + } + qemu_bh_schedule(acb->bh); } else { if ((acb->cluster_offset & 511) != 0) { ret = -EIO; @@ -928,6 +1326,7 @@ int index_in_cluster; uint64_t cluster_offset; const uint8_t *src_buf; + int n_end; acb->hd_aiocb = NULL; @@ -950,19 +1349,22 @@ } index_in_cluster = acb->sector_num & (s->cluster_sectors - 1); - acb->n = s->cluster_sectors - index_in_cluster; - if (acb->n > acb->nb_sectors) - acb->n = acb->nb_sectors; - cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0, - index_in_cluster, - index_in_cluster + acb->n); + n_end = index_in_cluster + acb->nb_sectors; + if (s->crypt_method && + n_end > QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors) + n_end = QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors; + + cluster_offset = alloc_cluster_offset(bs, acb->sector_num << 9, + index_in_cluster, + n_end, &acb->n); if (!cluster_offset || (cluster_offset & 511) != 0) { ret = -EIO; goto fail; } if (s->crypt_method) { if (!acb->cluster_data) { - acb->cluster_data = qemu_mallocz(s->cluster_size); + acb->cluster_data = qemu_mallocz(QCOW_MAX_CRYPT_CLUSTERS * + s->cluster_size); if (!acb->cluster_data) { ret = -ENOMEM; goto fail; @@ -1215,8 +1617,10 @@ /* could not compress: write normal cluster */ qcow_write(bs, sector_num, buf, s->cluster_sectors); } else { - cluster_offset = get_cluster_offset(bs, sector_num << 9, 2, - out_len, 0, 0); + cluster_offset = alloc_compressed_cluster_offset(bs, sector_num << 9, + out_len); + if (!cluster_offset) + return -1; cluster_offset &= s->cluster_offset_mask; if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) { qemu_free(out_buf); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/block-qcow.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/block-qcow.c --- qemu-0.9.1/block-qcow.c 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/block-qcow.c 2008-06-05 23:00:45.000000000 +0100 @@ -339,33 +339,28 @@ return -1; } else { cluster_offset = bdrv_getlength(s->hd); - if (allocate == 1) { - /* round to cluster size */ - cluster_offset = (cluster_offset + s->cluster_size - 1) & - ~(s->cluster_size - 1); - bdrv_truncate(s->hd, cluster_offset + s->cluster_size); - /* if encrypted, we must initialize the cluster - content which won't be written */ - if (s->crypt_method && - (n_end - n_start) < s->cluster_sectors) { - uint64_t start_sect; - start_sect = (offset & ~(s->cluster_size - 1)) >> 9; - memset(s->cluster_data + 512, 0x00, 512); - for(i = 0; i < s->cluster_sectors; i++) { - if (i < n_start || i >= n_end) { - encrypt_sectors(s, start_sect + i, - s->cluster_data, - s->cluster_data + 512, 1, 1, - &s->aes_encrypt_key); - if (bdrv_pwrite(s->hd, cluster_offset + i * 512, - s->cluster_data, 512) != 512) - return -1; - } + /* round to cluster size */ + cluster_offset = (cluster_offset + s->cluster_size - 1) & + ~(s->cluster_size - 1); + bdrv_truncate(s->hd, cluster_offset + s->cluster_size); + /* if encrypted, we must initialize the cluster + content which won't be written */ + if (s->crypt_method && + (n_end - n_start) < s->cluster_sectors) { + uint64_t start_sect; + start_sect = (offset & ~(s->cluster_size - 1)) >> 9; + memset(s->cluster_data + 512, 0x00, 512); + for(i = 0; i < s->cluster_sectors; i++) { + if (i < n_start || i >= n_end) { + encrypt_sectors(s, start_sect + i, + s->cluster_data, + s->cluster_data + 512, 1, 1, + &s->aes_encrypt_key); + if (bdrv_pwrite(s->hd, cluster_offset + i * 512, + s->cluster_data, 512) != 512) + return -1; } } - } else { - cluster_offset |= QCOW_OFLAG_COMPRESSED | - (uint64_t)compressed_size << (63 - s->cluster_bits); } } /* update L2 table */ @@ -752,11 +747,15 @@ header_size = sizeof(header); backing_filename_len = 0; if (backing_file) { - header.backing_file_offset = cpu_to_be64(header_size); - backing_filename_len = strlen(backing_file); - header.backing_file_size = cpu_to_be32(backing_filename_len); - header_size += backing_filename_len; - header.mtime = cpu_to_be32(0); + if (strcmp(backing_file, "fat:")) { + header.backing_file_offset = cpu_to_be64(header_size); + backing_filename_len = strlen(backing_file); + header.backing_file_size = cpu_to_be32(backing_filename_len); + header_size += backing_filename_len; + } else { + /* special backing file for vvfat */ + backing_file = NULL; + } header.cluster_bits = 9; /* 512 byte cluster to avoid copying unmodifyed sectors */ header.l2_bits = 12; /* 32 KB L2 tables */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/block-raw-posix.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/block-raw-posix.c --- qemu-0.9.1/block-raw-posix.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/block-raw-posix.c 2008-10-14 19:14:47.000000000 +0100 @@ -22,13 +22,13 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#ifndef QEMU_IMG #include "qemu-timer.h" -#include "exec-all.h" -#endif +#include "qemu-char.h" #include "block_int.h" #include +#ifdef CONFIG_AIO #include +#endif #ifdef CONFIG_COCOA #include @@ -53,31 +53,56 @@ #include #endif #ifdef __FreeBSD__ +#include #include #endif +#ifdef __OpenBSD__ +#include +#include +#include +#endif + //#define DEBUG_FLOPPY //#define DEBUG_BLOCK -#if defined(DEBUG_BLOCK) && !defined(QEMU_IMG) +#if defined(DEBUG_BLOCK) #define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0) \ { fprintf(logfile, formatCstr, ##args); fflush(logfile); } } while (0) #else #define DEBUG_BLOCK_PRINT(formatCstr, args...) #endif +/* OS X does not have O_DSYNC */ +#ifndef O_DSYNC +#define O_DSYNC O_SYNC +#endif + +/* Approximate O_DIRECT with O_DSYNC if O_DIRECT isn't available */ +#ifndef O_DIRECT +#define O_DIRECT O_DSYNC +#endif + #define FTYPE_FILE 0 #define FTYPE_CD 1 #define FTYPE_FD 2 +#define ALIGNED_BUFFER_SIZE (32 * 512) + /* if the FD is not accessed during that time (in ms), we try to reopen it to see if the disk has been changed */ #define FD_OPEN_TIMEOUT 1000 +/* posix-aio doesn't allow multiple outstanding requests to a single file + * descriptor. we implement a pool of dup()'d file descriptors to work + * around this */ +#define RAW_FD_POOL_SIZE 64 + typedef struct BDRVRawState { int fd; int type; unsigned int lseek_err_cnt; + int fd_pool[RAW_FD_POOL_SIZE]; #if defined(__linux__) /* linux floppy specific */ int fd_open_flags; @@ -86,14 +111,20 @@ int fd_got_error; int fd_media_changed; #endif + uint8_t* aligned_buf; } BDRVRawState; +static int posix_aio_init(void); + static int fd_open(BlockDriverState *bs); static int raw_open(BlockDriverState *bs, const char *filename, int flags) { BDRVRawState *s = bs->opaque; int fd, open_flags, ret; + int i; + + posix_aio_init(); s->lseek_err_cnt = 0; @@ -106,10 +137,13 @@ } if (flags & BDRV_O_CREAT) open_flags |= O_CREAT | O_TRUNC; -#ifdef O_DIRECT - if (flags & BDRV_O_DIRECT) + + /* Use O_DSYNC for write-through caching, no flags for write-back caching, + * and O_DIRECT for no caching. */ + if ((flags & BDRV_O_NOCACHE)) open_flags |= O_DIRECT; -#endif + else if (!(flags & BDRV_O_CACHE_WB)) + open_flags |= O_DSYNC; s->type = FTYPE_FILE; @@ -121,6 +155,17 @@ return ret; } s->fd = fd; + for (i = 0; i < RAW_FD_POOL_SIZE; i++) + s->fd_pool[i] = -1; + s->aligned_buf = NULL; + if ((flags & BDRV_O_NOCACHE)) { + s->aligned_buf = qemu_memalign(512, ALIGNED_BUFFER_SIZE); + if (s->aligned_buf == NULL) { + ret = -errno; + close(fd); + return ret; + } + } return 0; } @@ -141,7 +186,14 @@ #endif */ -static int raw_pread(BlockDriverState *bs, int64_t offset, +/* + * offset and count are in bytes, but must be multiples of 512 for files + * opened with O_DIRECT. buf must be aligned to 512 bytes then. + * + * This function may be called without alignment if the caller ensures + * that O_DIRECT is not in effect. + */ +static int raw_pread_aligned(BlockDriverState *bs, int64_t offset, uint8_t *buf, int count) { BDRVRawState *s = bs->opaque; @@ -194,7 +246,14 @@ return ret; } -static int raw_pwrite(BlockDriverState *bs, int64_t offset, +/* + * offset and count are in bytes, but must be multiples of 512 for files + * opened with O_DIRECT. buf must be aligned to 512 bytes then. + * + * This function may be called without alignment if the caller ensures + * that O_DIRECT is not in effect. + */ +static int raw_pwrite_aligned(BlockDriverState *bs, int64_t offset, const uint8_t *buf, int count) { BDRVRawState *s = bs->opaque; @@ -230,67 +289,226 @@ return ret; } + +/* + * offset and count are in bytes and possibly not aligned. For files opened + * with O_DIRECT, necessary alignments are ensured before calling + * raw_pread_aligned to do the actual read. + */ +static int raw_pread(BlockDriverState *bs, int64_t offset, + uint8_t *buf, int count) +{ + BDRVRawState *s = bs->opaque; + int size, ret, shift, sum; + + sum = 0; + + if (s->aligned_buf != NULL) { + + if (offset & 0x1ff) { + /* align offset on a 512 bytes boundary */ + + shift = offset & 0x1ff; + size = (shift + count + 0x1ff) & ~0x1ff; + if (size > ALIGNED_BUFFER_SIZE) + size = ALIGNED_BUFFER_SIZE; + ret = raw_pread_aligned(bs, offset - shift, s->aligned_buf, size); + if (ret < 0) + return ret; + + size = 512 - shift; + if (size > count) + size = count; + memcpy(buf, s->aligned_buf + shift, size); + + buf += size; + offset += size; + count -= size; + sum += size; + + if (count == 0) + return sum; + } + if (count & 0x1ff || (uintptr_t) buf & 0x1ff) { + + /* read on aligned buffer */ + + while (count) { + + size = (count + 0x1ff) & ~0x1ff; + if (size > ALIGNED_BUFFER_SIZE) + size = ALIGNED_BUFFER_SIZE; + + ret = raw_pread_aligned(bs, offset, s->aligned_buf, size); + if (ret < 0) + return ret; + + size = ret; + if (size > count) + size = count; + + memcpy(buf, s->aligned_buf, size); + + buf += size; + offset += size; + count -= size; + sum += size; + } + + return sum; + } + } + + return raw_pread_aligned(bs, offset, buf, count) + sum; +} + +/* + * offset and count are in bytes and possibly not aligned. For files opened + * with O_DIRECT, necessary alignments are ensured before calling + * raw_pwrite_aligned to do the actual write. + */ +static int raw_pwrite(BlockDriverState *bs, int64_t offset, + const uint8_t *buf, int count) +{ + BDRVRawState *s = bs->opaque; + int size, ret, shift, sum; + + sum = 0; + + if (s->aligned_buf != NULL) { + + if (offset & 0x1ff) { + /* align offset on a 512 bytes boundary */ + shift = offset & 0x1ff; + ret = raw_pread_aligned(bs, offset - shift, s->aligned_buf, 512); + if (ret < 0) + return ret; + + size = 512 - shift; + if (size > count) + size = count; + memcpy(s->aligned_buf + shift, buf, size); + + ret = raw_pwrite_aligned(bs, offset - shift, s->aligned_buf, 512); + if (ret < 0) + return ret; + + buf += size; + offset += size; + count -= size; + sum += size; + + if (count == 0) + return sum; + } + if (count & 0x1ff || (uintptr_t) buf & 0x1ff) { + + while ((size = (count & ~0x1ff)) != 0) { + + if (size > ALIGNED_BUFFER_SIZE) + size = ALIGNED_BUFFER_SIZE; + + memcpy(s->aligned_buf, buf, size); + + ret = raw_pwrite_aligned(bs, offset, s->aligned_buf, size); + if (ret < 0) + return ret; + + buf += ret; + offset += ret; + count -= ret; + sum += ret; + } + /* here, count < 512 because (count & ~0x1ff) == 0 */ + if (count) { + ret = raw_pread_aligned(bs, offset, s->aligned_buf, 512); + if (ret < 0) + return ret; + memcpy(s->aligned_buf, buf, count); + + ret = raw_pwrite_aligned(bs, offset, s->aligned_buf, 512); + if (ret < 0) + return ret; + if (count < ret) + ret = count; + + sum += ret; + } + return sum; + } + } + return raw_pwrite_aligned(bs, offset, buf, count) + sum; +} + +#ifdef CONFIG_AIO /***********************************************************/ /* Unix AIO using POSIX AIO */ typedef struct RawAIOCB { BlockDriverAIOCB common; + int fd; struct aiocb aiocb; struct RawAIOCB *next; + int ret; } RawAIOCB; -static int aio_sig_num = SIGUSR2; -static RawAIOCB *first_aio; /* AIO issued */ -static int aio_initialized = 0; +typedef struct PosixAioState +{ + int rfd, wfd; + RawAIOCB *first_aio; +} PosixAioState; -static void aio_signal_handler(int signum) +static int raw_fd_pool_get(BDRVRawState *s) { -#ifndef QEMU_IMG - CPUState *env = cpu_single_env; - if (env) { - /* stop the currently executing cpu because a timer occured */ - cpu_interrupt(env, CPU_INTERRUPT_EXIT); -#ifdef USE_KQEMU - if (env->kqemu_enabled) { - kqemu_cpu_interrupt(env); - } -#endif + int i; + + for (i = 0; i < RAW_FD_POOL_SIZE; i++) { + /* already in use */ + if (s->fd_pool[i] != -1) + continue; + + /* try to dup file descriptor */ + s->fd_pool[i] = dup(s->fd); + if (s->fd_pool[i] != -1) + return s->fd_pool[i]; } -#endif + + /* we couldn't dup the file descriptor so just use the main one */ + return s->fd; } -void qemu_aio_init(void) +static void raw_fd_pool_put(RawAIOCB *acb) { - struct sigaction act; - - aio_initialized = 1; + BDRVRawState *s = acb->common.bs->opaque; + int i; - sigfillset(&act.sa_mask); - act.sa_flags = 0; /* do not restart syscalls to interrupt select() */ - act.sa_handler = aio_signal_handler; - sigaction(aio_sig_num, &act, NULL); - -#if defined(__GLIBC__) && defined(__linux__) - { - /* XXX: aio thread exit seems to hang on RedHat 9 and this init - seems to fix the problem. */ - struct aioinit ai; - memset(&ai, 0, sizeof(ai)); - ai.aio_threads = 1; - ai.aio_num = 1; - ai.aio_idle_time = 365 * 100000; - aio_init(&ai); + for (i = 0; i < RAW_FD_POOL_SIZE; i++) { + if (s->fd_pool[i] == acb->fd) { + close(s->fd_pool[i]); + s->fd_pool[i] = -1; + } } -#endif } -void qemu_aio_poll(void) +static void posix_aio_read(void *opaque) { + PosixAioState *s = opaque; RawAIOCB *acb, **pacb; int ret; + ssize_t len; + + do { + char byte; + + len = read(s->rfd, &byte, 1); + if (len == -1 && errno == EINTR) + continue; + if (len == -1 && errno == EAGAIN) + break; + } while (len == -1); for(;;) { - pacb = &first_aio; + pacb = &s->first_aio; for(;;) { acb = *pacb; if (!acb) @@ -299,6 +517,7 @@ if (ret == ECANCELED) { /* remove the request */ *pacb = acb->next; + raw_fd_pool_put(acb); qemu_aio_release(acb); } else if (ret != EINPROGRESS) { /* end of aio */ @@ -315,6 +534,7 @@ *pacb = acb->next; /* call the callback */ acb->common.cb(acb->common.opaque, ret); + raw_fd_pool_put(acb); qemu_aio_release(acb); break; } else { @@ -325,49 +545,77 @@ the_end: ; } -/* Wait for all IO requests to complete. */ -void qemu_aio_flush(void) +static int posix_aio_flush(void *opaque) { - qemu_aio_wait_start(); - qemu_aio_poll(); - while (first_aio) { - qemu_aio_wait(); - } - qemu_aio_wait_end(); + PosixAioState *s = opaque; + return !!s->first_aio; } -/* wait until at least one AIO was handled */ -static sigset_t wait_oset; +static PosixAioState *posix_aio_state; -void qemu_aio_wait_start(void) +static void aio_signal_handler(int signum) { - sigset_t set; + if (posix_aio_state) { + char byte = 0; - if (!aio_initialized) - qemu_aio_init(); - sigemptyset(&set); - sigaddset(&set, aio_sig_num); - sigprocmask(SIG_BLOCK, &set, &wait_oset); + write(posix_aio_state->wfd, &byte, sizeof(byte)); + } + + qemu_service_io(); } -void qemu_aio_wait(void) +static int posix_aio_init(void) { - sigset_t set; - int nb_sigs; + struct sigaction act; + PosixAioState *s; + int fds[2]; + + if (posix_aio_state) + return 0; + + s = qemu_malloc(sizeof(PosixAioState)); + if (s == NULL) + return -ENOMEM; + + sigfillset(&act.sa_mask); + act.sa_flags = 0; /* do not restart syscalls to interrupt select() */ + act.sa_handler = aio_signal_handler; + sigaction(SIGUSR2, &act, NULL); + + s->first_aio = NULL; + if (pipe(fds) == -1) { + fprintf(stderr, "failed to create pipe\n"); + return -errno; + } + + s->rfd = fds[0]; + s->wfd = fds[1]; + + fcntl(s->wfd, F_SETFL, O_NONBLOCK); + + qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush, s); -#ifndef QEMU_IMG - if (qemu_bh_poll()) - return; +#if defined(__linux__) + { + struct aioinit ai; + + memset(&ai, 0, sizeof(ai)); +#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 4) + ai.aio_threads = 64; + ai.aio_num = 64; +#else + /* XXX: aio thread exit seems to hang on RedHat 9 and this init + seems to fix the problem. */ + ai.aio_threads = 1; + ai.aio_num = 1; + ai.aio_idle_time = 365 * 100000; #endif - sigemptyset(&set); - sigaddset(&set, aio_sig_num); - sigwait(&set, &nb_sigs); - qemu_aio_poll(); -} + aio_init(&ai); + } +#endif + posix_aio_state = s; -void qemu_aio_wait_end(void) -{ - sigprocmask(SIG_SETMASK, &wait_oset, NULL); + return 0; } static RawAIOCB *raw_aio_setup(BlockDriverState *bs, @@ -383,8 +631,9 @@ acb = qemu_aio_get(bs, cb, opaque); if (!acb) return NULL; - acb->aiocb.aio_fildes = s->fd; - acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num; + acb->fd = raw_fd_pool_get(s); + acb->aiocb.aio_fildes = acb->fd; + acb->aiocb.aio_sigevent.sigev_signo = SIGUSR2; acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL; acb->aiocb.aio_buf = buf; if (nb_sectors < 0) @@ -392,17 +641,39 @@ else acb->aiocb.aio_nbytes = nb_sectors * 512; acb->aiocb.aio_offset = sector_num * 512; - acb->next = first_aio; - first_aio = acb; + acb->next = posix_aio_state->first_aio; + posix_aio_state->first_aio = acb; return acb; } +static void raw_aio_em_cb(void* opaque) +{ + RawAIOCB *acb = opaque; + acb->common.cb(acb->common.opaque, acb->ret); + qemu_aio_release(acb); +} + static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque) { RawAIOCB *acb; + /* + * If O_DIRECT is used and the buffer is not aligned fall back + * to synchronous IO. + */ + BDRVRawState *s = bs->opaque; + + if (unlikely(s->aligned_buf != NULL && ((uintptr_t) buf % 512))) { + QEMUBH *bh; + acb = qemu_aio_get(bs, cb, opaque); + acb->ret = raw_pread(bs, 512 * sector_num, buf, 512 * nb_sectors); + bh = qemu_bh_new(raw_aio_em_cb, acb); + qemu_bh_schedule(bh); + return &acb->common; + } + acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque); if (!acb) return NULL; @@ -419,6 +690,21 @@ { RawAIOCB *acb; + /* + * If O_DIRECT is used and the buffer is not aligned fall back + * to synchronous IO. + */ + BDRVRawState *s = bs->opaque; + + if (unlikely(s->aligned_buf != NULL && ((uintptr_t) buf % 512))) { + QEMUBH *bh; + acb = qemu_aio_get(bs, cb, opaque); + acb->ret = raw_pwrite(bs, 512 * sector_num, buf, 512 * nb_sectors); + bh = qemu_bh_new(raw_aio_em_cb, acb); + qemu_bh_schedule(bh); + return &acb->common; + } + acb = raw_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque); if (!acb) return NULL; @@ -443,12 +729,13 @@ } /* remove the callback from the queue */ - pacb = &first_aio; + pacb = &posix_aio_state->first_aio; for(;;) { if (*pacb == NULL) { break; } else if (*pacb == acb) { *pacb = acb->next; + raw_fd_pool_put(acb); qemu_aio_release(acb); break; } @@ -456,13 +743,35 @@ } } +#else /* CONFIG_AIO */ +static int posix_aio_init(void) +{ + return 0; +} +#endif /* CONFIG_AIO */ + +static void raw_close_fd_pool(BDRVRawState *s) +{ + int i; + + for (i = 0; i < RAW_FD_POOL_SIZE; i++) { + if (s->fd_pool[i] != -1) { + close(s->fd_pool[i]); + s->fd_pool[i] = -1; + } + } +} + static void raw_close(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; if (s->fd >= 0) { close(s->fd); s->fd = -1; + if (s->aligned_buf != NULL) + qemu_free(s->aligned_buf); } + raw_close_fd_pool(s); } static int raw_truncate(BlockDriverState *bs, int64_t offset) @@ -475,6 +784,26 @@ return 0; } +#ifdef __OpenBSD__ +static int64_t raw_getlength(BlockDriverState *bs) +{ + BDRVRawState *s = bs->opaque; + int fd = s->fd; + struct stat st; + + if (fstat(fd, &st)) + return -1; + if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) { + struct disklabel dl; + + if (ioctl(fd, DIOCGDINFO, &dl)) + return -1; + return (uint64_t)dl.d_secsize * + dl.d_partitions[DISKPART(st.st_rdev)].p_size; + } else + return st.st_size; +} +#else /* !__OpenBSD__ */ static int64_t raw_getlength(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; @@ -521,6 +850,7 @@ } return size; } +#endif static int raw_create(const char *filename, int64_t total_size, const char *backing_file, int flags) @@ -556,11 +886,12 @@ raw_create, raw_flush, +#ifdef CONFIG_AIO .bdrv_aio_read = raw_aio_read, .bdrv_aio_write = raw_aio_write, .bdrv_aio_cancel = raw_aio_cancel, .aiocb_size = sizeof(RawAIOCB), - .protocol_name = "file", +#endif .bdrv_pread = raw_pread, .bdrv_pwrite = raw_pwrite, .bdrv_truncate = raw_truncate, @@ -631,7 +962,9 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) { BDRVRawState *s = bs->opaque; - int fd, open_flags, ret; + int fd, open_flags, ret, i; + + posix_aio_init(); #ifdef CONFIG_COCOA if (strstart(filename, "/dev/cdrom", NULL)) { @@ -666,10 +999,12 @@ open_flags |= O_RDONLY; bs->read_only = 1; } -#ifdef O_DIRECT - if (flags & BDRV_O_DIRECT) + /* Use O_DSYNC for write-through caching, no flags for write-back caching, + * and O_DIRECT for no caching. */ + if ((flags & BDRV_O_NOCACHE)) open_flags |= O_DIRECT; -#endif + else if (!(flags & BDRV_O_CACHE_WB)) + open_flags |= O_DSYNC; s->type = FTYPE_FILE; #if defined(__linux__) @@ -694,6 +1029,8 @@ return ret; } s->fd = fd; + for (i = 0; i < RAW_FD_POOL_SIZE; i++) + s->fd_pool[i] = -1; #if defined(__linux__) /* close fd so that we can reopen it as needed */ if (s->type == FTYPE_FD) { @@ -705,8 +1042,7 @@ return 0; } -#if defined(__linux__) && !defined(QEMU_IMG) - +#if defined(__linux__) /* Note: we do not have a reliable method to detect if the floppy is present. The current method is to try to open the floppy at every I/O and to keep it opened during a few hundreds of ms. */ @@ -722,6 +1058,7 @@ (qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) { close(s->fd); s->fd = -1; + raw_close_fd_pool(s); #ifdef DEBUG_FLOPPY printf("Floppy closed\n"); #endif @@ -755,14 +1092,6 @@ s->fd_got_error = 0; return 0; } -#else -static int fd_open(BlockDriverState *bs) -{ - return 0; -} -#endif - -#if defined(__linux__) static int raw_is_inserted(BlockDriverState *bs) { @@ -830,6 +1159,7 @@ if (s->fd >= 0) { close(s->fd); s->fd = -1; + raw_close_fd_pool(s); } fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK); if (fd >= 0) { @@ -871,6 +1201,11 @@ } #else +static int fd_open(BlockDriverState *bs) +{ + return 0; +} + static int raw_is_inserted(BlockDriverState *bs) { return 1; @@ -908,10 +1243,12 @@ NULL, raw_flush, +#ifdef CONFIG_AIO .bdrv_aio_read = raw_aio_read, .bdrv_aio_write = raw_aio_write, .bdrv_aio_cancel = raw_aio_cancel, .aiocb_size = sizeof(RawAIOCB), +#endif .bdrv_pread = raw_pread, .bdrv_pwrite = raw_pwrite, .bdrv_getlength = raw_getlength, diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/block-raw-win32.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/block-raw-win32.c --- qemu-0.9.1/block-raw-win32.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/block-raw-win32.c 2008-10-14 15:42:54.000000000 +0100 @@ -22,14 +22,13 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#ifndef QEMU_IMG #include "qemu-timer.h" -#include "exec-all.h" -#endif #include "block_int.h" #include #include +//#define WIN32_AIO + #define FTYPE_FILE 0 #define FTYPE_CD 1 #define FTYPE_HARDDISK 2 @@ -100,13 +99,15 @@ } else { create_flags = OPEN_EXISTING; } -#ifdef QEMU_IMG - overlapped = FILE_ATTRIBUTE_NORMAL; -#else +#ifdef WIN32_AIO overlapped = FILE_FLAG_OVERLAPPED; +#else + overlapped = FILE_ATTRIBUTE_NORMAL; #endif - if (flags & BDRV_O_DIRECT) + if ((flags & BDRV_O_NOCACHE)) overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH; + else if (!(flags & BDRV_O_CACHE_WB)) + overlapped |= FILE_FLAG_WRITE_THROUGH; s->hfile = CreateFile(filename, access_flags, FILE_SHARE_READ, NULL, create_flags, overlapped, NULL); @@ -133,10 +134,12 @@ ov.OffsetHigh = offset >> 32; ret = ReadFile(s->hfile, buf, count, &ret_count, &ov); if (!ret) { +#ifdef WIN32_AIO ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE); if (!ret) return -EIO; else +#endif return ret_count; } return ret_count; @@ -155,17 +158,18 @@ ov.OffsetHigh = offset >> 32; ret = WriteFile(s->hfile, buf, count, &ret_count, &ov); if (!ret) { +#ifdef WIN32_AIO ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE); if (!ret) return -EIO; else +#endif return ret_count; } return ret_count; } -#if 0 -#ifndef QEMU_IMG +#ifdef WIN32_AIO static void raw_aio_cb(void *opaque) { RawAIOCB *acb = opaque; @@ -181,7 +185,6 @@ acb->common.cb(acb->common.opaque, 0); } } -#endif static RawAIOCB *raw_aio_setup(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors, @@ -204,9 +207,7 @@ acb->ov.OffsetHigh = offset >> 32; acb->ov.hEvent = acb->hEvent; acb->count = nb_sectors * 512; -#ifndef QEMU_IMG qemu_add_wait_object(acb->ov.hEvent, raw_aio_cb, acb); -#endif return acb; } @@ -226,9 +227,7 @@ qemu_aio_release(acb); return NULL; } -#ifdef QEMU_IMG qemu_aio_release(acb); -#endif return (BlockDriverAIOCB *)acb; } @@ -248,15 +247,12 @@ qemu_aio_release(acb); return NULL; } -#ifdef QEMU_IMG qemu_aio_release(acb); -#endif return (BlockDriverAIOCB *)acb; } static void raw_aio_cancel(BlockDriverAIOCB *blockacb) { -#ifndef QEMU_IMG RawAIOCB *acb = (RawAIOCB *)blockacb; BlockDriverState *bs = acb->common.bs; BDRVRawState *s = bs->opaque; @@ -265,9 +261,8 @@ /* XXX: if more than one async I/O it is not correct */ CancelIo(s->hfile); qemu_aio_release(acb); -#endif } -#endif /* #if 0 */ +#endif /* #if WIN32_AIO */ static void raw_flush(BlockDriverState *bs) { @@ -346,33 +341,6 @@ return 0; } -void qemu_aio_init(void) -{ -} - -void qemu_aio_poll(void) -{ -} - -void qemu_aio_flush(void) -{ -} - -void qemu_aio_wait_start(void) -{ -} - -void qemu_aio_wait(void) -{ -#ifndef QEMU_IMG - qemu_bh_poll(); -#endif -} - -void qemu_aio_wait_end(void) -{ -} - BlockDriver bdrv_raw = { "raw", sizeof(BDRVRawState), @@ -384,13 +352,12 @@ raw_create, raw_flush, -#if 0 +#ifdef WIN32_AIO .bdrv_aio_read = raw_aio_read, .bdrv_aio_write = raw_aio_write, .bdrv_aio_cancel = raw_aio_cancel, .aiocb_size = sizeof(RawAIOCB); #endif - .protocol_name = "file", .bdrv_pread = raw_pread, .bdrv_pwrite = raw_pwrite, .bdrv_truncate = raw_truncate, @@ -470,13 +437,15 @@ } create_flags = OPEN_EXISTING; -#ifdef QEMU_IMG - overlapped = FILE_ATTRIBUTE_NORMAL; -#else +#ifdef WIN32_AIO overlapped = FILE_FLAG_OVERLAPPED; +#else + overlapped = FILE_ATTRIBUTE_NORMAL; #endif - if (flags & BDRV_O_DIRECT) + if ((flags & BDRV_O_NOCACHE)) overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH; + else if (!(flags & BDRV_O_CACHE_WB)) + overlapped |= FILE_FLAG_WRITE_THROUGH; s->hfile = CreateFile(filename, access_flags, FILE_SHARE_READ, NULL, create_flags, overlapped, NULL); @@ -536,7 +505,7 @@ NULL, raw_flush, -#if 0 +#ifdef WIN32_AIO .bdrv_aio_read = raw_aio_read, .bdrv_aio_write = raw_aio_write, .bdrv_aio_cancel = raw_aio_cancel, diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/block-vmdk.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/block-vmdk.c --- qemu-0.9.1/block-vmdk.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/block-vmdk.c 2008-10-28 14:08:49.000000000 +0000 @@ -119,7 +119,7 @@ BDRVVmdkState *s = bs->opaque; char desc[DESC_SIZE]; uint32_t cid; - char *p_name, *cid_str; + const char *p_name, *cid_str; size_t cid_str_size; /* the descriptor offset = 0x200 */ @@ -153,11 +153,11 @@ return -1; tmp_str = strstr(desc,"parentCID"); - strcpy(tmp_desc, tmp_str); + pstrcpy(tmp_desc, sizeof(tmp_desc), tmp_str); if ((p_name = strstr(desc,"CID")) != 0) { p_name += sizeof("CID"); - sprintf(p_name,"%x\n",cid); - strcat(desc,tmp_desc); + snprintf(p_name, sizeof(desc) - (p_name - desc), "%x\n", cid); + pstrcat(desc, sizeof(desc), tmp_desc); } if (bdrv_pwrite(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE) @@ -193,7 +193,7 @@ uint32_t gde_entries, gd_size; int64_t gd_offset, rgd_offset, capacity, gt_size; char p_desc[DESC_SIZE], s_desc[DESC_SIZE], hdr[HEADER_SIZE]; - char *desc_template = + static const char desc_template[] = "# Disk DescriptorFile\n" "version=1\n" "CID=%x\n" @@ -202,7 +202,7 @@ "parentFileNameHint=\"%s\"\n" "\n" "# Extent description\n" - "RW %lu SPARSE \"%s\"\n" + "RW %u SPARSE \"%s\"\n" "\n" "# The Disk Data Base \n" "#DDB\n" @@ -252,8 +252,8 @@ if ((temp_str = strrchr(real_filename, ':')) != NULL) real_filename = temp_str + 1; - sprintf(s_desc, desc_template, p_cid, p_cid, backing_file - , (uint32_t)header.capacity, real_filename); + snprintf(s_desc, sizeof(s_desc), desc_template, p_cid, p_cid, backing_file, + (uint32_t)header.capacity, real_filename); /* write the descriptor */ if (lseek(snp_fd, 0x200, SEEK_SET) == -1) @@ -322,7 +322,7 @@ bdrv_close(bs->backing_hd); } -int parent_open = 0; +static int parent_open = 0; static int vmdk_parent_open(BlockDriverState *bs, const char * filename) { BDRVVmdkState *s = bs->opaque; @@ -341,13 +341,16 @@ p_name += sizeof("parentFileNameHint") + 1; if ((end_name = strchr(p_name,'\"')) == 0) return -1; + if ((end_name - p_name) > sizeof (s->hd->backing_file) - 1) + return -1; - strncpy(s->hd->backing_file, p_name, end_name - p_name); + pstrcpy(s->hd->backing_file, end_name - p_name + 1, p_name); if (stat(s->hd->backing_file, &file_buf) != 0) { path_combine(parent_img_name, sizeof(parent_img_name), filename, s->hd->backing_file); } else { - strcpy(parent_img_name, s->hd->backing_file); + pstrcpy(parent_img_name, sizeof(parent_img_name), + s->hd->backing_file); } s->hd->backing_hd = bdrv_new(""); @@ -374,7 +377,6 @@ if (parent_open) // Parent must be opened as RO. flags = BDRV_O_RDONLY; - fprintf(stderr, "(VMDK) image open: flags=0x%x filename=%s\n", flags, bs->filename); ret = bdrv_file_open(&s->hd, filename, flags); if (ret < 0) @@ -700,7 +702,7 @@ int fd, i; VMDK4Header header; uint32_t tmp, magic, grains, gd_size, gt_size, gt_count; - char *desc_template = + static const char desc_template[] = "# Disk DescriptorFile\n" "version=1\n" "CID=%x\n" @@ -708,13 +710,13 @@ "createType=\"monolithicSparse\"\n" "\n" "# Extent description\n" - "RW %lu SPARSE \"%s\"\n" + "RW %" PRId64 " SPARSE \"%s\"\n" "\n" "# The Disk Data Base \n" "#DDB\n" "\n" "ddb.virtualHWVersion = \"%d\"\n" - "ddb.geometry.cylinders = \"%lu\"\n" + "ddb.geometry.cylinders = \"%" PRId64 "\"\n" "ddb.geometry.heads = \"16\"\n" "ddb.geometry.sectors = \"63\"\n" "ddb.adapterType = \"ide\"\n"; @@ -789,8 +791,10 @@ real_filename = temp_str + 1; if ((temp_str = strrchr(real_filename, ':')) != NULL) real_filename = temp_str + 1; - sprintf(desc, desc_template, time(NULL), (unsigned long)total_size, - real_filename, (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), total_size / (63 * 16)); + snprintf(desc, sizeof(desc), desc_template, (unsigned int)time(NULL), + total_size, real_filename, + (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), + total_size / (int64_t)(63 * 16)); /* write the descriptor */ lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET); @@ -806,9 +810,9 @@ qemu_free(s->l1_table); qemu_free(s->l2_cache); - bdrv_delete(s->hd); // try to close parent image, if exist vmdk_parent_close(s->hd); + bdrv_delete(s->hd); } static void vmdk_flush(BlockDriverState *bs) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/block-vvfat.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/block-vvfat.c --- qemu-0.9.1/block-vvfat.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/block-vvfat.c 2008-11-10 01:34:27.000000000 +0000 @@ -53,7 +53,7 @@ #define stderr STDERR FILE* stderr = NULL; -static void checkpoint(); +static void checkpoint(void); #ifdef __MINGW32__ void nonono(const char* file, int line, const char* msg) { @@ -93,7 +93,6 @@ /* does not automatically grow */ static inline void* array_get(array_t* array,unsigned int index) { - assert(index >= 0); assert(index < array->next); return array->pointer + index * array->item_size; } @@ -102,7 +101,7 @@ { if((index + 1) * array->item_size > array->size) { int new_size = (index + 32) * array->item_size; - array->pointer = realloc(array->pointer, new_size); + array->pointer = qemu_realloc(array->pointer, new_size); if (!array->pointer) return -1; array->size = new_size; @@ -128,7 +127,7 @@ static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) { if((array->next+count)*array->item_size>array->size) { int increment=count*array->item_size; - array->pointer=realloc(array->pointer,array->size+increment); + array->pointer=qemu_realloc(array->pointer,array->size+increment); if(!array->pointer) return 0; array->size+=increment; @@ -195,7 +194,6 @@ static int array_index(array_t* array, void* pointer) { size_t offset = (char*)pointer - array->pointer; - assert(offset >= 0); assert((offset % array->item_size) == 0); assert(offset/array->item_size < array->next); return offset/array->item_size; @@ -454,8 +452,7 @@ static char is_free(const direntry_t* direntry) { - /* return direntry->name[0]==0 ; */ - return direntry->attributes == 0 || direntry->name[0]==0xe5; + return direntry->name[0]==0xe5 || direntry->name[0]==0x00; } static char is_volume_label(const direntry_t* direntry) @@ -628,7 +625,7 @@ entry=array_get_next(&(s->directory)); memset(entry->name,0x20,11); - strncpy((char*)entry->name,filename,i); + memcpy(entry->name, filename, i); if(j > 0) for (i = 0; i < 3 && filename[j+1+i]; i++) @@ -893,7 +890,6 @@ s->path = mapping->path; for (i = 0, cluster = 0; i < s->mapping.next; i++) { - int j; /* MS-DOS expects the FAT to be 0 for the root directory * (except for the media byte). */ /* LATER TODO: still true for FAT32? */ @@ -926,20 +922,25 @@ assert(mapping->begin < mapping->end); + /* next free cluster */ + cluster = mapping->end; + + if(cluster > s->cluster_count) { + fprintf(stderr,"Directory does not fit in FAT%d (capacity %s)\n", + s->fat_type, + s->fat_type == 12 ? s->sector_count == 2880 ? "1.44 MB" + : "2.88 MB" + : "504MB"); + return -EINVAL; + } + /* fix fat for entry */ if (fix_fat) { + int j; for(j = mapping->begin; j < mapping->end - 1; j++) fat_set(s, j, j+1); fat_set(s, mapping->end - 1, s->max_fat_value); } - - /* next free cluster */ - cluster = mapping->end; - - if(cluster > s->cluster_count) { - fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type); - return -1; - } } mapping = array_get(&(s->mapping), 0); @@ -1411,7 +1412,12 @@ } typedef struct { - unsigned char name[1024]; + /* + * Since the sequence number is at most 0x3f, and the filename + * length is at most 13 times the sequence number, the maximal + * filename length is 0x3f * 13 bytes. + */ + unsigned char name[0x3f * 13 + 1]; int checksum, len; int sequence_number; } long_file_name; @@ -1436,6 +1442,7 @@ lfn->sequence_number = pointer[0] & 0x3f; lfn->checksum = pointer[13]; lfn->name[0] = 0; + lfn->name[lfn->sequence_number * 13] = 0; } else if ((pointer[0] & 0x3f) != --lfn->sequence_number) return -1; else if (pointer[13] != lfn->checksum) @@ -1730,7 +1737,7 @@ char path2[PATH_MAX]; assert(path_len < PATH_MAX); /* len was tested before! */ - strcpy(path2, path); + pstrcpy(path2, sizeof(path2), path); path2[path_len] = '/'; path2[path_len + 1] = '\0'; @@ -1804,7 +1811,8 @@ fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name); goto fail; } - strcpy(path2 + path_len + 1, (char*)lfn.name); + pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1, + (char*)lfn.name); if (is_directory(direntries + i)) { if (begin_of_direntry(direntries + i) == 0) { @@ -2233,7 +2241,6 @@ assert((size - offset == 0 && fat_eof(s, c)) || (size > offset && c >=2 && !fat_eof(s, c))); - assert(size >= 0); ret = vvfat_read(s->bs, cluster2sector(s, c), (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200); @@ -2370,8 +2377,9 @@ assert(!strncmp(m->path, mapping->path, l2)); - strcpy(new_path, mapping->path); - strcpy(new_path + l1, m->path + l2); + pstrcpy(new_path, l + diff + 1, mapping->path); + pstrcpy(new_path + l1, l + diff + 1 - l1, + m->path + l2); schedule_rename(s, m->begin, new_path); } @@ -2813,7 +2821,7 @@ }; #ifdef DEBUG -static void checkpoint() { +static void checkpoint(void) { assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2); check1(vvv); check2(vvv); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/bsdload.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/bsdload.c --- qemu-0.9.1/bsd-user/bsdload.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/bsdload.c 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,204 @@ +/* Code for loading BSD executables. Mostly linux kernel code. */ + +#include +#include +#include +#include +#include +#include +#include + +#include "qemu.h" + +#define NGROUPS 32 + +/* ??? This should really be somewhere else. */ +abi_long memcpy_to_target(abi_ulong dest, const void *src, + unsigned long len) +{ + void *host_ptr; + + host_ptr = lock_user(VERIFY_WRITE, dest, len, 0); + if (!host_ptr) + return -TARGET_EFAULT; + memcpy(host_ptr, src, len); + unlock_user(host_ptr, dest, 1); + return 0; +} + +static int in_group_p(gid_t g) +{ + /* return TRUE if we're in the specified group, FALSE otherwise */ + int ngroup; + int i; + gid_t grouplist[NGROUPS]; + + ngroup = getgroups(NGROUPS, grouplist); + for(i = 0; i < ngroup; i++) { + if(grouplist[i] == g) { + return 1; + } + } + return 0; +} + +static int count(char ** vec) +{ + int i; + + for(i = 0; *vec; i++) { + vec++; + } + + return(i); +} + +static int prepare_binprm(struct linux_binprm *bprm) +{ + struct stat st; + int mode; + int retval, id_change; + + if(fstat(bprm->fd, &st) < 0) { + return(-errno); + } + + mode = st.st_mode; + if(!S_ISREG(mode)) { /* Must be regular file */ + return(-EACCES); + } + if(!(mode & 0111)) { /* Must have at least one execute bit set */ + return(-EACCES); + } + + bprm->e_uid = geteuid(); + bprm->e_gid = getegid(); + id_change = 0; + + /* Set-uid? */ + if(mode & S_ISUID) { + bprm->e_uid = st.st_uid; + if(bprm->e_uid != geteuid()) { + id_change = 1; + } + } + + /* Set-gid? */ + /* + * If setgid is set but no group execute bit then this + * is a candidate for mandatory locking, not a setgid + * executable. + */ + if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { + bprm->e_gid = st.st_gid; + if (!in_group_p(bprm->e_gid)) { + id_change = 1; + } + } + + memset(bprm->buf, 0, sizeof(bprm->buf)); + retval = lseek(bprm->fd, 0L, SEEK_SET); + if(retval >= 0) { + retval = read(bprm->fd, bprm->buf, 128); + } + if(retval < 0) { + perror("prepare_binprm"); + exit(-1); + /* return(-errno); */ + } + else { + return(retval); + } +} + +/* Construct the envp and argv tables on the target stack. */ +abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, + abi_ulong stringp, int push_ptr) +{ + int n = sizeof(abi_ulong); + abi_ulong envp; + abi_ulong argv; + + sp -= (envc + 1) * n; + envp = sp; + sp -= (argc + 1) * n; + argv = sp; + if (push_ptr) { + /* FIXME - handle put_user() failures */ + sp -= n; + put_user_ual(envp, sp); + sp -= n; + put_user_ual(argv, sp); + } + sp -= n; + /* FIXME - handle put_user() failures */ + put_user_ual(argc, sp); + + while (argc-- > 0) { + /* FIXME - handle put_user() failures */ + put_user_ual(stringp, argv); + argv += n; + stringp += target_strlen(stringp) + 1; + } + /* FIXME - handle put_user() failures */ + put_user_ual(0, argv); + while (envc-- > 0) { + /* FIXME - handle put_user() failures */ + put_user_ual(stringp, envp); + envp += n; + stringp += target_strlen(stringp) + 1; + } + /* FIXME - handle put_user() failures */ + put_user_ual(0, envp); + + return sp; +} + +int loader_exec(const char * filename, char ** argv, char ** envp, + struct target_pt_regs * regs, struct image_info *infop) +{ + struct linux_binprm bprm; + int retval; + int i; + + bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); + for (i=0 ; ihost_argv = argv; + + if(retval>=0) { + if (bprm.buf[0] == 0x7f + && bprm.buf[1] == 'E' + && bprm.buf[2] == 'L' + && bprm.buf[3] == 'F') { + retval = load_elf_binary(&bprm,regs,infop); + } else { + fprintf(stderr, "Unknown binary format\n"); + return -1; + } + } + + if(retval>=0) { + /* success. Initialize important registers */ + do_init_thread(regs, infop); + return retval; + } + + /* Something went wrong, return the inode and free the argument pages*/ + for (i=0 ; i +#include +#include +#include +#include +#include +#include +#include + +#include "qemu.h" +#include "disas.h" + +#ifdef __powerpc64__ +#undef ARCH_DLINFO +#undef ELF_PLATFORM +#undef ELF_HWCAP +#undef ELF_CLASS +#undef ELF_DATA +#undef ELF_ARCH +#endif + +/* from personality.h */ + +/* + * Flags for bug emulation. + * + * These occupy the top three bytes. + */ +enum { + ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization of VA space */ + FDPIC_FUNCPTRS = 0x0080000, /* userspace function ptrs point to descriptors + * (signal handling) + */ + MMAP_PAGE_ZERO = 0x0100000, + ADDR_COMPAT_LAYOUT = 0x0200000, + READ_IMPLIES_EXEC = 0x0400000, + ADDR_LIMIT_32BIT = 0x0800000, + SHORT_INODE = 0x1000000, + WHOLE_SECONDS = 0x2000000, + STICKY_TIMEOUTS = 0x4000000, + ADDR_LIMIT_3GB = 0x8000000, +}; + +/* + * Personality types. + * + * These go in the low byte. Avoid using the top bit, it will + * conflict with error returns. + */ +enum { + PER_LINUX = 0x0000, + PER_LINUX_32BIT = 0x0000 | ADDR_LIMIT_32BIT, + PER_LINUX_FDPIC = 0x0000 | FDPIC_FUNCPTRS, + PER_SVR4 = 0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, + PER_SVR3 = 0x0002 | STICKY_TIMEOUTS | SHORT_INODE, + PER_SCOSVR3 = 0x0003 | STICKY_TIMEOUTS | + WHOLE_SECONDS | SHORT_INODE, + PER_OSR5 = 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS, + PER_WYSEV386 = 0x0004 | STICKY_TIMEOUTS | SHORT_INODE, + PER_ISCR4 = 0x0005 | STICKY_TIMEOUTS, + PER_BSD = 0x0006, + PER_SUNOS = 0x0006 | STICKY_TIMEOUTS, + PER_XENIX = 0x0007 | STICKY_TIMEOUTS | SHORT_INODE, + PER_LINUX32 = 0x0008, + PER_LINUX32_3GB = 0x0008 | ADDR_LIMIT_3GB, + PER_IRIX32 = 0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */ + PER_IRIXN32 = 0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */ + PER_IRIX64 = 0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */ + PER_RISCOS = 0x000c, + PER_SOLARIS = 0x000d | STICKY_TIMEOUTS, + PER_UW7 = 0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, + PER_OSF4 = 0x000f, /* OSF/1 v4 */ + PER_HPUX = 0x0010, + PER_MASK = 0x00ff, +}; + +/* + * Return the base personality without flags. + */ +#define personality(pers) (pers & PER_MASK) + +/* this flag is uneffective under linux too, should be deleted */ +#ifndef MAP_DENYWRITE +#define MAP_DENYWRITE 0 +#endif + +/* should probably go in elf.h */ +#ifndef ELIBBAD +#define ELIBBAD 80 +#endif + +#ifdef TARGET_I386 + +#define ELF_PLATFORM get_elf_platform() + +static const char *get_elf_platform(void) +{ + static char elf_platform[] = "i386"; + int family = (thread_env->cpuid_version >> 8) & 0xff; + if (family > 6) + family = 6; + if (family >= 3) + elf_platform[1] = '0' + family; + return elf_platform; +} + +#define ELF_HWCAP get_elf_hwcap() + +static uint32_t get_elf_hwcap(void) +{ + return thread_env->cpuid_features; +} + +#ifdef TARGET_X86_64 +#define ELF_START_MMAP 0x2aaaaab000ULL +#define elf_check_arch(x) ( ((x) == ELF_ARCH) ) + +#define ELF_CLASS ELFCLASS64 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_X86_64 + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->rax = 0; + regs->rsp = infop->start_stack; + regs->rip = infop->entry; +} + +#else + +#define ELF_START_MMAP 0x80000000 + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) ) + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_386 + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->esp = infop->start_stack; + regs->eip = infop->entry; + + /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program + starts %edx contains a pointer to a function which might be + registered using `atexit'. This provides a mean for the + dynamic linker to call DT_FINI functions for shared libraries + that have been loaded before the code runs. + + A value of 0 tells we have no such handler. */ + regs->edx = 0; +} +#endif + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#endif + +#ifdef TARGET_ARM + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_ARM ) + +#define ELF_CLASS ELFCLASS32 +#ifdef TARGET_WORDS_BIGENDIAN +#define ELF_DATA ELFDATA2MSB +#else +#define ELF_DATA ELFDATA2LSB +#endif +#define ELF_ARCH EM_ARM + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + abi_long stack = infop->start_stack; + memset(regs, 0, sizeof(*regs)); + regs->ARM_cpsr = 0x10; + if (infop->entry & 1) + regs->ARM_cpsr |= CPSR_T; + regs->ARM_pc = infop->entry & 0xfffffffe; + regs->ARM_sp = infop->start_stack; + /* FIXME - what to for failure of get_user()? */ + get_user_ual(regs->ARM_r2, stack + 8); /* envp */ + get_user_ual(regs->ARM_r1, stack + 4); /* envp */ + /* XXX: it seems that r0 is zeroed after ! */ + regs->ARM_r0 = 0; + /* For uClinux PIC binaries. */ + /* XXX: Linux does this only on ARM with no MMU (do we care ?) */ + regs->ARM_r10 = infop->start_data; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +enum +{ + ARM_HWCAP_ARM_SWP = 1 << 0, + ARM_HWCAP_ARM_HALF = 1 << 1, + ARM_HWCAP_ARM_THUMB = 1 << 2, + ARM_HWCAP_ARM_26BIT = 1 << 3, + ARM_HWCAP_ARM_FAST_MULT = 1 << 4, + ARM_HWCAP_ARM_FPA = 1 << 5, + ARM_HWCAP_ARM_VFP = 1 << 6, + ARM_HWCAP_ARM_EDSP = 1 << 7, +}; + +#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF \ + | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT \ + | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP) + +#endif + +#ifdef TARGET_SPARC +#ifdef TARGET_SPARC64 + +#define ELF_START_MMAP 0x80000000 + +#ifndef TARGET_ABI32 +#define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS ) +#else +#define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC ) +#endif + +#define ELF_CLASS ELFCLASS64 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_SPARCV9 + +#define STACK_BIAS 2047 + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ +#ifndef TARGET_ABI32 + regs->tstate = 0; +#endif + regs->pc = infop->entry; + regs->npc = regs->pc + 4; + regs->y = 0; +#ifdef TARGET_ABI32 + regs->u_regs[14] = infop->start_stack - 16 * 4; +#else + if (personality(infop->personality) == PER_LINUX32) + regs->u_regs[14] = infop->start_stack - 16 * 4; + else + regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS; +#endif +} + +#else +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_SPARC ) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_SPARC + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->psr = 0; + regs->pc = infop->entry; + regs->npc = regs->pc + 4; + regs->y = 0; + regs->u_regs[14] = infop->start_stack - 16 * 4; +} + +#endif +#endif + +#ifdef TARGET_PPC + +#define ELF_START_MMAP 0x80000000 + +#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) + +#define elf_check_arch(x) ( (x) == EM_PPC64 ) + +#define ELF_CLASS ELFCLASS64 + +#else + +#define elf_check_arch(x) ( (x) == EM_PPC ) + +#define ELF_CLASS ELFCLASS32 + +#endif + +#ifdef TARGET_WORDS_BIGENDIAN +#define ELF_DATA ELFDATA2MSB +#else +#define ELF_DATA ELFDATA2LSB +#endif +#define ELF_ARCH EM_PPC + +/* + * We need to put in some extra aux table entries to tell glibc what + * the cache block size is, so it can use the dcbz instruction safely. + */ +#define AT_DCACHEBSIZE 19 +#define AT_ICACHEBSIZE 20 +#define AT_UCACHEBSIZE 21 +/* A special ignored type value for PPC, for glibc compatibility. */ +#define AT_IGNOREPPC 22 +/* + * The requirements here are: + * - keep the final alignment of sp (sp & 0xf) + * - make sure the 32-bit value at the first 16 byte aligned position of + * AUXV is greater than 16 for glibc compatibility. + * AT_IGNOREPPC is used for that. + * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, + * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. + */ +#define DLINFO_ARCH_ITEMS 5 +#define ARCH_DLINFO \ +do { \ + NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20); \ + NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20); \ + NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \ + /* \ + * Now handle glibc compatibility. \ + */ \ + NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ + NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ + } while (0) + +static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) +{ + abi_ulong pos = infop->start_stack; + abi_ulong tmp; +#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) + abi_ulong entry, toc; +#endif + + _regs->gpr[1] = infop->start_stack; +#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) + entry = ldq_raw(infop->entry) + infop->load_addr; + toc = ldq_raw(infop->entry + 8) + infop->load_addr; + _regs->gpr[2] = toc; + infop->entry = entry; +#endif + _regs->nip = infop->entry; + /* Note that isn't exactly what regular kernel does + * but this is what the ABI wants and is needed to allow + * execution of PPC BSD programs. + */ + /* FIXME - what to for failure of get_user()? */ + get_user_ual(_regs->gpr[3], pos); + pos += sizeof(abi_ulong); + _regs->gpr[4] = pos; + for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong)) + tmp = ldl(pos); + _regs->gpr[5] = pos; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#endif + +#ifdef TARGET_MIPS + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_MIPS ) + +#ifdef TARGET_MIPS64 +#define ELF_CLASS ELFCLASS64 +#else +#define ELF_CLASS ELFCLASS32 +#endif +#ifdef TARGET_WORDS_BIGENDIAN +#define ELF_DATA ELFDATA2MSB +#else +#define ELF_DATA ELFDATA2LSB +#endif +#define ELF_ARCH EM_MIPS + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->cp0_status = 2 << CP0St_KSU; + regs->cp0_epc = infop->entry; + regs->regs[29] = infop->start_stack; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#endif /* TARGET_MIPS */ + +#ifdef TARGET_SH4 + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_SH ) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_SH + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + /* Check other registers XXXXX */ + regs->pc = infop->entry; + regs->regs[15] = infop->start_stack; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#endif + +#ifdef TARGET_CRIS + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_CRIS ) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_CRIS + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->erp = infop->entry; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 8192 + +#endif + +#ifdef TARGET_M68K + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_68K ) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_68K + +/* ??? Does this need to do anything? +#define ELF_PLAT_INIT(_r) */ + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->usp = infop->start_stack; + regs->sr = 0; + regs->pc = infop->entry; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 8192 + +#endif + +#ifdef TARGET_ALPHA + +#define ELF_START_MMAP (0x30000000000ULL) + +#define elf_check_arch(x) ( (x) == ELF_ARCH ) + +#define ELF_CLASS ELFCLASS64 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_ALPHA + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->pc = infop->entry; + regs->ps = 8; + regs->usp = infop->start_stack; + regs->unique = infop->start_data; /* ? */ + printf("Set unique value to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", + regs->unique, infop->start_data); +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 8192 + +#endif /* TARGET_ALPHA */ + +#ifndef ELF_PLATFORM +#define ELF_PLATFORM (NULL) +#endif + +#ifndef ELF_HWCAP +#define ELF_HWCAP 0 +#endif + +#ifdef TARGET_ABI32 +#undef ELF_CLASS +#define ELF_CLASS ELFCLASS32 +#undef bswaptls +#define bswaptls(ptr) bswap32s(ptr) +#endif + +#include "elf.h" + +struct exec +{ + unsigned int a_info; /* Use macros N_MAGIC, etc for access */ + unsigned int a_text; /* length of text, in bytes */ + unsigned int a_data; /* length of data, in bytes */ + unsigned int a_bss; /* length of uninitialized data area, in bytes */ + unsigned int a_syms; /* length of symbol table data in file, in bytes */ + unsigned int a_entry; /* start address */ + unsigned int a_trsize; /* length of relocation info for text, in bytes */ + unsigned int a_drsize; /* length of relocation info for data, in bytes */ +}; + + +#define N_MAGIC(exec) ((exec).a_info & 0xffff) +#define OMAGIC 0407 +#define NMAGIC 0410 +#define ZMAGIC 0413 +#define QMAGIC 0314 + +/* max code+data+bss space allocated to elf interpreter */ +#define INTERP_MAP_SIZE (32 * 1024 * 1024) + +/* max code+data+bss+brk space allocated to ET_DYN executables */ +#define ET_DYN_MAP_SIZE (128 * 1024 * 1024) + +/* Necessary parameters */ +#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE +#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) +#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1)) + +#define INTERPRETER_NONE 0 +#define INTERPRETER_AOUT 1 +#define INTERPRETER_ELF 2 + +#define DLINFO_ITEMS 12 + +static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) +{ + memcpy(to, from, n); +} + +extern unsigned long x86_stack_size; + +static int load_aout_interp(void * exptr, int interp_fd); + +#ifdef BSWAP_NEEDED +static void bswap_ehdr(struct elfhdr *ehdr) +{ + bswap16s(&ehdr->e_type); /* Object file type */ + bswap16s(&ehdr->e_machine); /* Architecture */ + bswap32s(&ehdr->e_version); /* Object file version */ + bswaptls(&ehdr->e_entry); /* Entry point virtual address */ + bswaptls(&ehdr->e_phoff); /* Program header table file offset */ + bswaptls(&ehdr->e_shoff); /* Section header table file offset */ + bswap32s(&ehdr->e_flags); /* Processor-specific flags */ + bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ + bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ + bswap16s(&ehdr->e_phnum); /* Program header table entry count */ + bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ + bswap16s(&ehdr->e_shnum); /* Section header table entry count */ + bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ +} + +static void bswap_phdr(struct elf_phdr *phdr) +{ + bswap32s(&phdr->p_type); /* Segment type */ + bswaptls(&phdr->p_offset); /* Segment file offset */ + bswaptls(&phdr->p_vaddr); /* Segment virtual address */ + bswaptls(&phdr->p_paddr); /* Segment physical address */ + bswaptls(&phdr->p_filesz); /* Segment size in file */ + bswaptls(&phdr->p_memsz); /* Segment size in memory */ + bswap32s(&phdr->p_flags); /* Segment flags */ + bswaptls(&phdr->p_align); /* Segment alignment */ +} + +static void bswap_shdr(struct elf_shdr *shdr) +{ + bswap32s(&shdr->sh_name); + bswap32s(&shdr->sh_type); + bswaptls(&shdr->sh_flags); + bswaptls(&shdr->sh_addr); + bswaptls(&shdr->sh_offset); + bswaptls(&shdr->sh_size); + bswap32s(&shdr->sh_link); + bswap32s(&shdr->sh_info); + bswaptls(&shdr->sh_addralign); + bswaptls(&shdr->sh_entsize); +} + +static void bswap_sym(struct elf_sym *sym) +{ + bswap32s(&sym->st_name); + bswaptls(&sym->st_value); + bswaptls(&sym->st_size); + bswap16s(&sym->st_shndx); +} +#endif + +/* + * 'copy_elf_strings()' copies argument/envelope strings from user + * memory to free pages in kernel mem. These are in a format ready + * to be put directly into the top of new user memory. + * + */ +static abi_ulong copy_elf_strings(int argc,char ** argv, void **page, + abi_ulong p) +{ + char *tmp, *tmp1, *pag = NULL; + int len, offset = 0; + + if (!p) { + return 0; /* bullet-proofing */ + } + while (argc-- > 0) { + tmp = argv[argc]; + if (!tmp) { + fprintf(stderr, "VFS: argc is wrong"); + exit(-1); + } + tmp1 = tmp; + while (*tmp++); + len = tmp - tmp1; + if (p < len) { /* this shouldn't happen - 128kB */ + return 0; + } + while (len) { + --p; --tmp; --len; + if (--offset < 0) { + offset = p % TARGET_PAGE_SIZE; + pag = (char *)page[p/TARGET_PAGE_SIZE]; + if (!pag) { + pag = (char *)malloc(TARGET_PAGE_SIZE); + memset(pag, 0, TARGET_PAGE_SIZE); + page[p/TARGET_PAGE_SIZE] = pag; + if (!pag) + return 0; + } + } + if (len == 0 || offset == 0) { + *(pag + offset) = *tmp; + } + else { + int bytes_to_copy = (len > offset) ? offset : len; + tmp -= bytes_to_copy; + p -= bytes_to_copy; + offset -= bytes_to_copy; + len -= bytes_to_copy; + memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1); + } + } + } + return p; +} + +static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, + struct image_info *info) +{ + abi_ulong stack_base, size, error; + int i; + + /* Create enough stack to hold everything. If we don't use + * it for args, we'll use it for something else... + */ + size = x86_stack_size; + if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) + size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; + error = target_mmap(0, + size + qemu_host_page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, + -1, 0); + if (error == -1) { + perror("stk mmap"); + exit(-1); + } + /* we reserve one extra page at the top of the stack as guard */ + target_mprotect(error + size, qemu_host_page_size, PROT_NONE); + + stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; + p += stack_base; + + for (i = 0 ; i < MAX_ARG_PAGES ; i++) { + if (bprm->page[i]) { + info->rss++; + /* FIXME - check return value of memcpy_to_target() for failure */ + memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE); + free(bprm->page[i]); + } + stack_base += TARGET_PAGE_SIZE; + } + return p; +} + +static void set_brk(abi_ulong start, abi_ulong end) +{ + /* page-align the start and end addresses... */ + start = HOST_PAGE_ALIGN(start); + end = HOST_PAGE_ALIGN(end); + if (end <= start) + return; + if(target_mmap(start, end - start, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0) == -1) { + perror("cannot mmap brk"); + exit(-1); + } +} + + +/* We need to explicitly zero any fractional pages after the data + section (i.e. bss). This would contain the junk from the file that + should not be in memory. */ +static void padzero(abi_ulong elf_bss, abi_ulong last_bss) +{ + abi_ulong nbyte; + + if (elf_bss >= last_bss) + return; + + /* XXX: this is really a hack : if the real host page size is + smaller than the target page size, some pages after the end + of the file may not be mapped. A better fix would be to + patch target_mmap(), but it is more complicated as the file + size must be known */ + if (qemu_real_host_page_size < qemu_host_page_size) { + abi_ulong end_addr, end_addr1; + end_addr1 = (elf_bss + qemu_real_host_page_size - 1) & + ~(qemu_real_host_page_size - 1); + end_addr = HOST_PAGE_ALIGN(elf_bss); + if (end_addr1 < end_addr) { + mmap((void *)g2h(end_addr1), end_addr - end_addr1, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0); + } + } + + nbyte = elf_bss & (qemu_host_page_size-1); + if (nbyte) { + nbyte = qemu_host_page_size - nbyte; + do { + /* FIXME - what to do if put_user() fails? */ + put_user_u8(0, elf_bss); + elf_bss++; + } while (--nbyte); + } +} + + +static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, + struct elfhdr * exec, + abi_ulong load_addr, + abi_ulong load_bias, + abi_ulong interp_load_addr, int ibcs, + struct image_info *info) +{ + abi_ulong sp; + int size; + abi_ulong u_platform; + const char *k_platform; + const int n = sizeof(elf_addr_t); + + sp = p; + u_platform = 0; + k_platform = ELF_PLATFORM; + if (k_platform) { + size_t len = strlen(k_platform) + 1; + sp -= (len + n - 1) & ~(n - 1); + u_platform = sp; + /* FIXME - check return value of memcpy_to_target() for failure */ + memcpy_to_target(sp, k_platform, len); + } + /* + * Force 16 byte _final_ alignment here for generality. + */ + sp = sp &~ (abi_ulong)15; + size = (DLINFO_ITEMS + 1) * 2; + if (k_platform) + size += 2; +#ifdef DLINFO_ARCH_ITEMS + size += DLINFO_ARCH_ITEMS * 2; +#endif + size += envc + argc + 2; + size += (!ibcs ? 3 : 1); /* argc itself */ + size *= n; + if (size & 15) + sp -= 16 - (size & 15); + + /* This is correct because Linux defines + * elf_addr_t as Elf32_Off / Elf64_Off + */ +#define NEW_AUX_ENT(id, val) do { \ + sp -= n; put_user_ual(val, sp); \ + sp -= n; put_user_ual(id, sp); \ + } while(0) + + NEW_AUX_ENT (AT_NULL, 0); + + /* There must be exactly DLINFO_ITEMS entries here. */ + NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff)); + NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr))); + NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum)); + NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE)); + NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr)); + NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0); + NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry); + NEW_AUX_ENT(AT_UID, (abi_ulong) getuid()); + NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid()); + NEW_AUX_ENT(AT_GID, (abi_ulong) getgid()); + NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid()); + NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP); + NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK)); + if (k_platform) + NEW_AUX_ENT(AT_PLATFORM, u_platform); +#ifdef ARCH_DLINFO + /* + * ARCH_DLINFO must come last so platform specific code can enforce + * special alignment requirements on the AUXV if necessary (eg. PPC). + */ + ARCH_DLINFO; +#endif +#undef NEW_AUX_ENT + + sp = loader_build_argptr(envc, argc, sp, p, !ibcs); + return sp; +} + + +static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex, + int interpreter_fd, + abi_ulong *interp_load_addr) +{ + struct elf_phdr *elf_phdata = NULL; + struct elf_phdr *eppnt; + abi_ulong load_addr = 0; + int load_addr_set = 0; + int retval; + abi_ulong last_bss, elf_bss; + abi_ulong error; + int i; + + elf_bss = 0; + last_bss = 0; + error = 0; + +#ifdef BSWAP_NEEDED + bswap_ehdr(interp_elf_ex); +#endif + /* First of all, some simple consistency checks */ + if ((interp_elf_ex->e_type != ET_EXEC && + interp_elf_ex->e_type != ET_DYN) || + !elf_check_arch(interp_elf_ex->e_machine)) { + return ~((abi_ulong)0UL); + } + + + /* Now read in all of the header information */ + + if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) + return ~(abi_ulong)0UL; + + elf_phdata = (struct elf_phdr *) + malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); + + if (!elf_phdata) + return ~((abi_ulong)0UL); + + /* + * If the size of this structure has changed, then punt, since + * we will be doing the wrong thing. + */ + if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { + free(elf_phdata); + return ~((abi_ulong)0UL); + } + + retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); + if(retval >= 0) { + retval = read(interpreter_fd, + (char *) elf_phdata, + sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); + } + if (retval < 0) { + perror("load_elf_interp"); + exit(-1); + free (elf_phdata); + return retval; + } +#ifdef BSWAP_NEEDED + eppnt = elf_phdata; + for (i=0; ie_phnum; i++, eppnt++) { + bswap_phdr(eppnt); + } +#endif + + if (interp_elf_ex->e_type == ET_DYN) { + /* in order to avoid hardcoding the interpreter load + address in qemu, we allocate a big enough memory zone */ + error = target_mmap(0, INTERP_MAP_SIZE, + PROT_NONE, MAP_PRIVATE | MAP_ANON, + -1, 0); + if (error == -1) { + perror("mmap"); + exit(-1); + } + load_addr = error; + load_addr_set = 1; + } + + eppnt = elf_phdata; + for(i=0; ie_phnum; i++, eppnt++) + if (eppnt->p_type == PT_LOAD) { + int elf_type = MAP_PRIVATE | MAP_DENYWRITE; + int elf_prot = 0; + abi_ulong vaddr = 0; + abi_ulong k; + + if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; + if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; + if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; + if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { + elf_type |= MAP_FIXED; + vaddr = eppnt->p_vaddr; + } + error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr), + eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr), + elf_prot, + elf_type, + interpreter_fd, + eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); + + if (error == -1) { + /* Real error */ + close(interpreter_fd); + free(elf_phdata); + return ~((abi_ulong)0UL); + } + + if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { + load_addr = error; + load_addr_set = 1; + } + + /* + * Find the end of the file mapping for this phdr, and keep + * track of the largest address we see for this. + */ + k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; + if (k > elf_bss) elf_bss = k; + + /* + * Do the same thing for the memory mapping - between + * elf_bss and last_bss is the bss section. + */ + k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; + if (k > last_bss) last_bss = k; + } + + /* Now use mmap to map the library into memory. */ + + close(interpreter_fd); + + /* + * Now fill out the bss section. First pad the last page up + * to the page boundary, and then perform a mmap to make sure + * that there are zeromapped pages up to and including the last + * bss page. + */ + padzero(elf_bss, last_bss); + elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */ + + /* Map the last of the bss segment */ + if (last_bss > elf_bss) { + target_mmap(elf_bss, last_bss-elf_bss, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0); + } + free(elf_phdata); + + *interp_load_addr = load_addr; + return ((abi_ulong) interp_elf_ex->e_entry) + load_addr; +} + +static int symfind(const void *s0, const void *s1) +{ + struct elf_sym *key = (struct elf_sym *)s0; + struct elf_sym *sym = (struct elf_sym *)s1; + int result = 0; + if (key->st_value < sym->st_value) { + result = -1; + } else if (key->st_value > sym->st_value + sym->st_size) { + result = 1; + } + return result; +} + +static const char *lookup_symbolxx(struct syminfo *s, target_ulong orig_addr) +{ +#if ELF_CLASS == ELFCLASS32 + struct elf_sym *syms = s->disas_symtab.elf32; +#else + struct elf_sym *syms = s->disas_symtab.elf64; +#endif + + // binary search + struct elf_sym key; + struct elf_sym *sym; + + key.st_value = orig_addr; + + sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), symfind); + if (sym != 0) { + return s->disas_strtab + sym->st_name; + } + + return ""; +} + +/* FIXME: This should use elf_ops.h */ +static int symcmp(const void *s0, const void *s1) +{ + struct elf_sym *sym0 = (struct elf_sym *)s0; + struct elf_sym *sym1 = (struct elf_sym *)s1; + return (sym0->st_value < sym1->st_value) + ? -1 + : ((sym0->st_value > sym1->st_value) ? 1 : 0); +} + +/* Best attempt to load symbols from this ELF object. */ +static void load_symbols(struct elfhdr *hdr, int fd) +{ + unsigned int i, nsyms; + struct elf_shdr sechdr, symtab, strtab; + char *strings; + struct syminfo *s; + struct elf_sym *syms; + + lseek(fd, hdr->e_shoff, SEEK_SET); + for (i = 0; i < hdr->e_shnum; i++) { + if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) + return; +#ifdef BSWAP_NEEDED + bswap_shdr(&sechdr); +#endif + if (sechdr.sh_type == SHT_SYMTAB) { + symtab = sechdr; + lseek(fd, hdr->e_shoff + + sizeof(sechdr) * sechdr.sh_link, SEEK_SET); + if (read(fd, &strtab, sizeof(strtab)) + != sizeof(strtab)) + return; +#ifdef BSWAP_NEEDED + bswap_shdr(&strtab); +#endif + goto found; + } + } + return; /* Shouldn't happen... */ + + found: + /* Now know where the strtab and symtab are. Snarf them. */ + s = malloc(sizeof(*s)); + syms = malloc(symtab.sh_size); + if (!syms) + return; + s->disas_strtab = strings = malloc(strtab.sh_size); + if (!s->disas_strtab) + return; + + lseek(fd, symtab.sh_offset, SEEK_SET); + if (read(fd, syms, symtab.sh_size) != symtab.sh_size) + return; + + nsyms = symtab.sh_size / sizeof(struct elf_sym); + + i = 0; + while (i < nsyms) { +#ifdef BSWAP_NEEDED + bswap_sym(syms + i); +#endif + // Throw away entries which we do not need. + if (syms[i].st_shndx == SHN_UNDEF || + syms[i].st_shndx >= SHN_LORESERVE || + ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) { + nsyms--; + if (i < nsyms) { + syms[i] = syms[nsyms]; + } + continue; + } +#if defined(TARGET_ARM) || defined (TARGET_MIPS) + /* The bottom address bit marks a Thumb or MIPS16 symbol. */ + syms[i].st_value &= ~(target_ulong)1; +#endif + i++; + } + syms = realloc(syms, nsyms * sizeof(*syms)); + + qsort(syms, nsyms, sizeof(*syms), symcmp); + + lseek(fd, strtab.sh_offset, SEEK_SET); + if (read(fd, strings, strtab.sh_size) != strtab.sh_size) + return; + s->disas_num_syms = nsyms; +#if ELF_CLASS == ELFCLASS32 + s->disas_symtab.elf32 = syms; + s->lookup_symbol = lookup_symbolxx; +#else + s->disas_symtab.elf64 = syms; + s->lookup_symbol = lookup_symbolxx; +#endif + s->next = syminfos; + syminfos = s; +} + +int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info) +{ + struct elfhdr elf_ex; + struct elfhdr interp_elf_ex; + struct exec interp_ex; + int interpreter_fd = -1; /* avoid warning */ + abi_ulong load_addr, load_bias; + int load_addr_set = 0; + unsigned int interpreter_type = INTERPRETER_NONE; + unsigned char ibcs2_interpreter; + int i; + abi_ulong mapped_addr; + struct elf_phdr * elf_ppnt; + struct elf_phdr *elf_phdata; + abi_ulong elf_bss, k, elf_brk; + int retval; + char * elf_interpreter; + abi_ulong elf_entry, interp_load_addr = 0; + int status; + abi_ulong start_code, end_code, start_data, end_data; + abi_ulong reloc_func_desc = 0; + abi_ulong elf_stack; + char passed_fileno[6]; + + ibcs2_interpreter = 0; + status = 0; + load_addr = 0; + load_bias = 0; + elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ +#ifdef BSWAP_NEEDED + bswap_ehdr(&elf_ex); +#endif + + /* First of all, some simple consistency checks */ + if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || + (! elf_check_arch(elf_ex.e_machine))) { + return -ENOEXEC; + } + + bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); + bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); + bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); + if (!bprm->p) { + retval = -E2BIG; + } + + /* Now read in all of the header information */ + elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum); + if (elf_phdata == NULL) { + return -ENOMEM; + } + + retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); + if(retval > 0) { + retval = read(bprm->fd, (char *) elf_phdata, + elf_ex.e_phentsize * elf_ex.e_phnum); + } + + if (retval < 0) { + perror("load_elf_binary"); + exit(-1); + free (elf_phdata); + return -errno; + } + +#ifdef BSWAP_NEEDED + elf_ppnt = elf_phdata; + for (i=0; ip_type == PT_INTERP) { + if ( elf_interpreter != NULL ) + { + free (elf_phdata); + free(elf_interpreter); + close(bprm->fd); + return -EINVAL; + } + + /* This is the program interpreter used for + * shared libraries - for now assume that this + * is an a.out format binary + */ + + elf_interpreter = (char *)malloc(elf_ppnt->p_filesz); + + if (elf_interpreter == NULL) { + free (elf_phdata); + close(bprm->fd); + return -ENOMEM; + } + + retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); + if(retval >= 0) { + retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz); + } + if(retval < 0) { + perror("load_elf_binary2"); + exit(-1); + } + + /* If the program interpreter is one of these two, + then assume an iBCS2 image. Otherwise assume + a native linux image. */ + + /* JRP - Need to add X86 lib dir stuff here... */ + + if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || + strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) { + ibcs2_interpreter = 1; + } + +#if 0 + printf("Using ELF interpreter %s\n", elf_interpreter); +#endif + if (retval >= 0) { + retval = open(path(elf_interpreter), O_RDONLY); + if(retval >= 0) { + interpreter_fd = retval; + } + else { + perror(elf_interpreter); + exit(-1); + /* retval = -errno; */ + } + } + + if (retval >= 0) { + retval = lseek(interpreter_fd, 0, SEEK_SET); + if(retval >= 0) { + retval = read(interpreter_fd,bprm->buf,128); + } + } + if (retval >= 0) { + interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */ + interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */ + } + if (retval < 0) { + perror("load_elf_binary3"); + exit(-1); + free (elf_phdata); + free(elf_interpreter); + close(bprm->fd); + return retval; + } + } + elf_ppnt++; + } + + /* Some simple consistency checks for the interpreter */ + if (elf_interpreter){ + interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; + + /* Now figure out which format our binary is */ + if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && + (N_MAGIC(interp_ex) != QMAGIC)) { + interpreter_type = INTERPRETER_ELF; + } + + if (interp_elf_ex.e_ident[0] != 0x7f || + strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) { + interpreter_type &= ~INTERPRETER_ELF; + } + + if (!interpreter_type) { + free(elf_interpreter); + free(elf_phdata); + close(bprm->fd); + return -ELIBBAD; + } + } + + /* OK, we are done with that, now set up the arg stuff, + and then start this sucker up */ + + { + char * passed_p; + + if (interpreter_type == INTERPRETER_AOUT) { + snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd); + passed_p = passed_fileno; + + if (elf_interpreter) { + bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p); + bprm->argc++; + } + } + if (!bprm->p) { + if (elf_interpreter) { + free(elf_interpreter); + } + free (elf_phdata); + close(bprm->fd); + return -E2BIG; + } + } + + /* OK, This is the point of no return */ + info->end_data = 0; + info->end_code = 0; + info->start_mmap = (abi_ulong)ELF_START_MMAP; + info->mmap = 0; + elf_entry = (abi_ulong) elf_ex.e_entry; + + /* Do this so that we can load the interpreter, if need be. We will + change some of these later */ + info->rss = 0; + bprm->p = setup_arg_pages(bprm->p, bprm, info); + info->start_stack = bprm->p; + + /* Now we do a little grungy work by mmaping the ELF image into + * the correct location in memory. At this point, we assume that + * the image should be loaded at fixed address, not at a variable + * address. + */ + + for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { + int elf_prot = 0; + int elf_flags = 0; + abi_ulong error; + + if (elf_ppnt->p_type != PT_LOAD) + continue; + + if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; + if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; + if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; + elf_flags = MAP_PRIVATE | MAP_DENYWRITE; + if (elf_ex.e_type == ET_EXEC || load_addr_set) { + elf_flags |= MAP_FIXED; + } else if (elf_ex.e_type == ET_DYN) { + /* Try and get dynamic programs out of the way of the default mmap + base, as well as whatever program they might try to exec. This + is because the brk will follow the loader, and is not movable. */ + /* NOTE: for qemu, we do a big mmap to get enough space + without hardcoding any address */ + error = target_mmap(0, ET_DYN_MAP_SIZE, + PROT_NONE, MAP_PRIVATE | MAP_ANON, + -1, 0); + if (error == -1) { + perror("mmap"); + exit(-1); + } + load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr); + } + + error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), + (elf_ppnt->p_filesz + + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), + elf_prot, + (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), + bprm->fd, + (elf_ppnt->p_offset - + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); + if (error == -1) { + perror("mmap"); + exit(-1); + } + +#ifdef LOW_ELF_STACK + if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) + elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr); +#endif + + if (!load_addr_set) { + load_addr_set = 1; + load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; + if (elf_ex.e_type == ET_DYN) { + load_bias += error - + TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); + load_addr += load_bias; + reloc_func_desc = load_bias; + } + } + k = elf_ppnt->p_vaddr; + if (k < start_code) + start_code = k; + if (start_data < k) + start_data = k; + k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; + if (k > elf_bss) + elf_bss = k; + if ((elf_ppnt->p_flags & PF_X) && end_code < k) + end_code = k; + if (end_data < k) + end_data = k; + k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; + if (k > elf_brk) elf_brk = k; + } + + elf_entry += load_bias; + elf_bss += load_bias; + elf_brk += load_bias; + start_code += load_bias; + end_code += load_bias; + start_data += load_bias; + end_data += load_bias; + + if (elf_interpreter) { + if (interpreter_type & 1) { + elf_entry = load_aout_interp(&interp_ex, interpreter_fd); + } + else if (interpreter_type & 2) { + elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, + &interp_load_addr); + } + reloc_func_desc = interp_load_addr; + + close(interpreter_fd); + free(elf_interpreter); + + if (elf_entry == ~((abi_ulong)0UL)) { + printf("Unable to load interpreter\n"); + free(elf_phdata); + exit(-1); + return 0; + } + } + + free(elf_phdata); + + if (loglevel) + load_symbols(&elf_ex, bprm->fd); + + if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd); + info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); + +#ifdef LOW_ELF_STACK + info->start_stack = bprm->p = elf_stack - 4; +#endif + bprm->p = create_elf_tables(bprm->p, + bprm->argc, + bprm->envc, + &elf_ex, + load_addr, load_bias, + interp_load_addr, + (interpreter_type == INTERPRETER_AOUT ? 0 : 1), + info); + info->load_addr = reloc_func_desc; + info->start_brk = info->brk = elf_brk; + info->end_code = end_code; + info->start_code = start_code; + info->start_data = start_data; + info->end_data = end_data; + info->start_stack = bprm->p; + + /* Calling set_brk effectively mmaps the pages that we need for the bss and break + sections */ + set_brk(elf_bss, elf_brk); + + padzero(elf_bss, elf_brk); + +#if 0 + printf("(start_brk) %x\n" , info->start_brk); + printf("(end_code) %x\n" , info->end_code); + printf("(start_code) %x\n" , info->start_code); + printf("(end_data) %x\n" , info->end_data); + printf("(start_stack) %x\n" , info->start_stack); + printf("(brk) %x\n" , info->brk); +#endif + + if ( info->personality == PER_SVR4 ) + { + /* Why this, you ask??? Well SVr4 maps page 0 as read-only, + and some applications "depend" upon this behavior. + Since we do not have the power to recompile these, we + emulate the SVr4 behavior. Sigh. */ + mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, -1, 0); + } + + info->entry = elf_entry; + + return 0; +} + +static int load_aout_interp(void * exptr, int interp_fd) +{ + printf("a.out interpreter not yet supported\n"); + return(0); +} + +void do_init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + init_thread(regs, infop); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/errno_defs.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/errno_defs.h --- qemu-0.9.1/bsd-user/errno_defs.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/errno_defs.h 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,149 @@ +/* $OpenBSD: errno.h,v 1.20 2007/09/03 14:37:52 millert Exp $ */ +/* $NetBSD: errno.h,v 1.10 1996/01/20 01:33:53 jtc Exp $ */ + +/* + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)errno.h 8.5 (Berkeley) 1/21/94 + */ + +#define TARGET_EPERM 1 /* Operation not permitted */ +#define TARGET_ENOENT 2 /* No such file or directory */ +#define TARGET_ESRCH 3 /* No such process */ +#define TARGET_EINTR 4 /* Interrupted system call */ +#define TARGET_EIO 5 /* Input/output error */ +#define TARGET_ENXIO 6 /* Device not configured */ +#define TARGET_E2BIG 7 /* Argument list too long */ +#define TARGET_ENOEXEC 8 /* Exec format error */ +#define TARGET_EBADF 9 /* Bad file descriptor */ +#define TARGET_ECHILD 10 /* No child processes */ +#define TARGET_EDEADLK 11 /* Resource deadlock avoided */ + /* 11 was EAGAIN */ +#define TARGET_ENOMEM 12 /* Cannot allocate memory */ +#define TARGET_EACCES 13 /* Permission denied */ +#define TARGET_EFAULT 14 /* Bad address */ +#define TARGET_ENOTBLK 15 /* Block device required */ +#define TARGET_EBUSY 16 /* Device busy */ +#define TARGET_EEXIST 17 /* File exists */ +#define TARGET_EXDEV 18 /* Cross-device link */ +#define TARGET_ENODEV 19 /* Operation not supported by device */ +#define TARGET_ENOTDIR 20 /* Not a directory */ +#define TARGET_EISDIR 21 /* Is a directory */ +#define TARGET_EINVAL 22 /* Invalid argument */ +#define TARGET_ENFILE 23 /* Too many open files in system */ +#define TARGET_EMFILE 24 /* Too many open files */ +#define TARGET_ENOTTY 25 /* Inappropriate ioctl for device */ +#define TARGET_ETXTBSY 26 /* Text file busy */ +#define TARGET_EFBIG 27 /* File too large */ +#define TARGET_ENOSPC 28 /* No space left on device */ +#define TARGET_ESPIPE 29 /* Illegal seek */ +#define TARGET_EROFS 30 /* Read-only file system */ +#define TARGET_EMLINK 31 /* Too many links */ +#define TARGET_EPIPE 32 /* Broken pipe */ + +/* math software */ +#define TARGET_EDOM 33 /* Numerical argument out of domain */ +#define TARGET_ERANGE 34 /* Result too large */ + +/* non-blocking and interrupt i/o */ +#define TARGET_EAGAIN 35 /* Resource temporarily unavailable */ +#define TARGET_EWOULDBLOCK EAGAIN /* Operation would block */ +#define TARGET_EINPROGRESS 36 /* Operation now in progress */ +#define TARGET_EALREADY 37 /* Operation already in progress */ + +/* ipc/network software -- argument errors */ +#define TARGET_ENOTSOCK 38 /* Socket operation on non-socket */ +#define TARGET_EDESTADDRREQ 39 /* Destination address required */ +#define TARGET_EMSGSIZE 40 /* Message too long */ +#define TARGET_EPROTOTYPE 41 /* Protocol wrong type for socket */ +#define TARGET_ENOPROTOOPT 42 /* Protocol not available */ +#define TARGET_EPROTONOSUPPORT 43 /* Protocol not supported */ +#define TARGET_ESOCKTNOSUPPORT 44 /* Socket type not supported */ +#define TARGET_EOPNOTSUPP 45 /* Operation not supported */ +#define TARGET_EPFNOSUPPORT 46 /* Protocol family not supported */ +#define TARGET_EAFNOSUPPORT 47 /* Address family not supported by protocol family */ +#define TARGET_EADDRINUSE 48 /* Address already in use */ +#define TARGET_EADDRNOTAVAIL 49 /* Can't assign requested address */ + +/* ipc/network software -- operational errors */ +#define TARGET_ENETDOWN 50 /* Network is down */ +#define TARGET_ENETUNREACH 51 /* Network is unreachable */ +#define TARGET_ENETRESET 52 /* Network dropped connection on reset */ +#define TARGET_ECONNABORTED 53 /* Software caused connection abort */ +#define TARGET_ECONNRESET 54 /* Connection reset by peer */ +#define TARGET_ENOBUFS 55 /* No buffer space available */ +#define TARGET_EISCONN 56 /* Socket is already connected */ +#define TARGET_ENOTCONN 57 /* Socket is not connected */ +#define TARGET_ESHUTDOWN 58 /* Can't send after socket shutdown */ +#define TARGET_ETOOMANYREFS 59 /* Too many references: can't splice */ +#define TARGET_ETIMEDOUT 60 /* Operation timed out */ +#define TARGET_ECONNREFUSED 61 /* Connection refused */ + +#define TARGET_ELOOP 62 /* Too many levels of symbolic links */ +#define TARGET_ENAMETOOLONG 63 /* File name too long */ + +/* should be rearranged */ +#define TARGET_EHOSTDOWN 64 /* Host is down */ +#define TARGET_EHOSTUNREACH 65 /* No route to host */ +#define TARGET_ENOTEMPTY 66 /* Directory not empty */ + +/* quotas & mush */ +#define TARGET_EPROCLIM 67 /* Too many processes */ +#define TARGET_EUSERS 68 /* Too many users */ +#define TARGET_EDQUOT 69 /* Disk quota exceeded */ + +/* Network File System */ +#define TARGET_ESTALE 70 /* Stale NFS file handle */ +#define TARGET_EREMOTE 71 /* Too many levels of remote in path */ +#define TARGET_EBADRPC 72 /* RPC struct is bad */ +#define TARGET_ERPCMISMATCH 73 /* RPC version wrong */ +#define TARGET_EPROGUNAVAIL 74 /* RPC prog. not avail */ +#define TARGET_EPROGMISMATCH 75 /* Program version wrong */ +#define TARGET_EPROCUNAVAIL 76 /* Bad procedure for program */ + +#define TARGET_ENOLCK 77 /* No locks available */ +#define TARGET_ENOSYS 78 /* Function not implemented */ + +#define TARGET_EFTYPE 79 /* Inappropriate file type or format */ +#define TARGET_EAUTH 80 /* Authentication error */ +#define TARGET_ENEEDAUTH 81 /* Need authenticator */ +#define TARGET_EIPSEC 82 /* IPsec processing failure */ +#define TARGET_ENOATTR 83 /* Attribute not found */ +#define TARGET_EILSEQ 84 /* Illegal byte sequence */ +#define TARGET_ENOMEDIUM 85 /* No medium found */ +#define TARGET_EMEDIUMTYPE 86 /* Wrong Medium Type */ +#define TARGET_EOVERFLOW 87 /* Conversion overflow */ +#define TARGET_ECANCELED 88 /* Operation canceled */ +#define TARGET_EIDRM 89 /* Identifier removed */ +#define TARGET_ENOMSG 90 /* No message of desired type */ +#define TARGET_ELAST 90 /* Must be equal largest errno */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/freebsd/strace.list /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/freebsd/strace.list --- qemu-0.9.1/bsd-user/freebsd/strace.list 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/freebsd/strace.list 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,170 @@ +{ TARGET_FREEBSD_NR___getcwd, "__getcwd", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR___semctl, "__semctl", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR___syscall, "__syscall", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR___sysctl, "__sysctl", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_accept, "accept", "%s(%d,%#x,%#x)", NULL, NULL }, +{ TARGET_FREEBSD_NR_access, "access", "%s(\"%s\",%#o)", NULL, NULL }, +{ TARGET_FREEBSD_NR_acct, "acct", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_adjtime, "adjtime", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_bind, "bind", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_break, "break", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_chdir, "chdir", "%s(\"%s\")", NULL, NULL }, +{ TARGET_FREEBSD_NR_chflags, "chflags", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_chmod, "chmod", "%s(\"%s\",%#o)", NULL, NULL }, +{ TARGET_FREEBSD_NR_chown, "chown", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_chroot, "chroot", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_clock_getres, "clock_getres", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_clock_gettime, "clock_gettime", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_clock_settime, "clock_settime", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_close, "close", "%s(%d)", NULL, NULL }, +{ TARGET_FREEBSD_NR_connect, "connect", "%s(%d,%#x,%d)", NULL, NULL }, +{ TARGET_FREEBSD_NR_dup, "dup", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_dup2, "dup2", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_execve, "execve", NULL, print_execve, NULL }, +{ TARGET_FREEBSD_NR_exit, "exit", "%s(%d)\n", NULL, NULL }, +{ TARGET_FREEBSD_NR_fchdir, "fchdir", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_fchflags, "fchflags", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_fchmod, "fchmod", "%s(%d,%#o)", NULL, NULL }, +{ TARGET_FREEBSD_NR_fchown, "fchown", "%s(\"%s\",%d,%d)", NULL, NULL }, +{ TARGET_FREEBSD_NR_fcntl, "fcntl", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_fhopen, "fhopen", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_fhstat, "fhstat", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_fhstatfs, "fhstatfs", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_flock, "flock", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_fork, "fork", "%s()", NULL, NULL }, +{ TARGET_FREEBSD_NR_fpathconf, "fpathconf", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_fstat, "fstat", "%s(%d,%p)", NULL, NULL }, +{ TARGET_FREEBSD_NR_fstatfs, "fstatfs", "%s(%d,%p)", NULL, NULL }, +{ TARGET_FREEBSD_NR_fsync, "fsync", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_futimes, "futimes", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_getdirentries, "getdirentries", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_getegid, "getegid", "%s()", NULL, NULL }, +{ TARGET_FREEBSD_NR_geteuid, "geteuid", "%s()", NULL, NULL }, +{ TARGET_FREEBSD_NR_getfh, "getfh", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_getfsstat, "getfsstat", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_getgid, "getgid", "%s()", NULL, NULL }, +{ TARGET_FREEBSD_NR_getgroups, "getgroups", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_getitimer, "getitimer", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_getlogin, "getlogin", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_getpeername, "getpeername", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_getpgid, "getpgid", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_getpgrp, "getpgrp", "%s()", NULL, NULL }, +{ TARGET_FREEBSD_NR_getpid, "getpid", "%s()", NULL, NULL }, +{ TARGET_FREEBSD_NR_getppid, "getppid", "%s()", NULL, NULL }, +{ TARGET_FREEBSD_NR_getpriority, "getpriority", "%s(%#x,%#x)", NULL, NULL }, +{ TARGET_FREEBSD_NR_getresgid, "getresgid", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_getresuid, "getresuid", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_getrlimit, "getrlimit", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_getrusage, "getrusage", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_getsid, "getsid", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_getsockname, "getsockname", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_getsockopt, "getsockopt", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_gettimeofday, "gettimeofday", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_getuid, "getuid", "%s()", NULL, NULL }, +{ TARGET_FREEBSD_NR_ioctl, "ioctl", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_issetugid, "issetugid", "%s()", NULL, NULL }, +{ TARGET_FREEBSD_NR_kevent, "kevent", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_kill, "kill", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_kqueue, "kqueue", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_ktrace, "ktrace", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_lchown, "lchown", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_link, "link", "%s(\"%s\",\"%s\")", NULL, NULL }, +{ TARGET_FREEBSD_NR_listen, "listen", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_lseek, "lseek", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_lstat, "lstat", "%s(\"%s\",%p)", NULL, NULL }, +{ TARGET_FREEBSD_NR_madvise, "madvise", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_mincore, "mincore", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_minherit, "minherit", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_mkdir, "mkdir", "%s(\"%s\",%#o)", NULL, NULL }, +{ TARGET_FREEBSD_NR_mkfifo, "mkfifo", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_mknod, "mknod", "%s(\"%s\",%#o,%#x)", NULL, NULL }, +{ TARGET_FREEBSD_NR_mlock, "mlock", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_mlockall, "mlockall", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_mmap, "mmap", NULL, NULL, print_syscall_ret_addr }, +{ TARGET_FREEBSD_NR_mount, "mount", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_mprotect, "mprotect", "%s(%#x,%#x,%d)", NULL, NULL }, +{ TARGET_FREEBSD_NR_msgctl, "msgctl", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_msgget, "msgget", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_msgrcv, "msgrcv", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_msgsnd, "msgsnd", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_msync, "msync", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_munlock, "munlock", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_munlockall, "munlockall", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_munmap, "munmap", "%s(%p,%d)", NULL, NULL }, +{ TARGET_FREEBSD_NR_nanosleep, "nanosleep", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_nfssvc, "nfssvc", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_open, "open", "%s(\"%s\",%#x,%#o)", NULL, NULL }, +{ TARGET_FREEBSD_NR_pathconf, "pathconf", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_pipe, "pipe", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_poll, "poll", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_pread, "pread", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_preadv, "preadv", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_profil, "profil", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_ptrace, "ptrace", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_pwrite, "pwrite", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_pwritev, "pwritev", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_quotactl, "quotactl", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_read, "read", "%s(%d,%#x,%d)", NULL, NULL }, +{ TARGET_FREEBSD_NR_readlink, "readlink", "%s(\"%s\",%p,%d)", NULL, NULL }, +{ TARGET_FREEBSD_NR_readv, "readv", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_reboot, "reboot", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_recvfrom, "recvfrom", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_recvmsg, "recvmsg", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_rename, "rename", "%s(\"%s\",\"%s\")", NULL, NULL }, +{ TARGET_FREEBSD_NR_revoke, "revoke", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_rfork, "rfork", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_rmdir, "rmdir", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_sbrk, "sbrk", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_sched_yield, "sched_yield", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_select, "select", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_semget, "semget", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_semop, "semop", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_sendmsg, "sendmsg", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_sendto, "sendto", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_setegid, "setegid", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_seteuid, "seteuid", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_setgid, "setgid", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_setgroups, "setgroups", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_setitimer, "setitimer", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_setlogin, "setlogin", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_setpgid, "setpgid", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_setpriority, "setpriority", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_setregid, "setregid", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_setresgid, "setresgid", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_setresuid, "setresuid", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_setreuid, "setreuid", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_setrlimit, "setrlimit", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_setsid, "setsid", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_setsockopt, "setsockopt", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_settimeofday, "settimeofday", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_setuid, "setuid", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_shmat, "shmat", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_shmctl, "shmctl", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_shmdt, "shmdt", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_shmget, "shmget", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_shutdown, "shutdown", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_sigaction, "sigaction", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_sigaltstack, "sigaltstack", "%s(%p,%p)", NULL, NULL }, +{ TARGET_FREEBSD_NR_sigpending, "sigpending", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_sigprocmask, "sigprocmask", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_sigreturn, "sigreturn", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_sigsuspend, "sigsuspend", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_socket, "socket", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_socketpair, "socketpair", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_sstk, "sstk", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_stat, "stat", "%s(\"%s\",%p)", NULL, NULL }, +{ TARGET_FREEBSD_NR_statfs, "statfs", "%s(\"%s\",%p)", NULL, NULL }, +{ TARGET_FREEBSD_NR_symlink, "symlink", "%s(\"%s\",\"%s\")", NULL, NULL }, +{ TARGET_FREEBSD_NR_sync, "sync", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_sysarch, "sysarch", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_syscall, "syscall", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_truncate, "truncate", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_umask, "umask", "%s(%#o)", NULL, NULL }, +{ TARGET_FREEBSD_NR_unlink, "unlink", "%s(\"%s\")", NULL, NULL }, +{ TARGET_FREEBSD_NR_unmount, "unmount", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_utimes, "utimes", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_vfork, "vfork", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_wait4, "wait4", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_write, "write", "%s(%d,%#x,%d)", NULL, NULL }, +{ TARGET_FREEBSD_NR_writev, "writev", "%s(%d,%p,%#x)", NULL, NULL }, diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/freebsd/syscall_nr.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/freebsd/syscall_nr.h --- qemu-0.9.1/bsd-user/freebsd/syscall_nr.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/freebsd/syscall_nr.h 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,373 @@ +/* + * System call numbers. + * + * $FreeBSD: src/sys/sys/syscall.h,v 1.224 2008/08/24 21:23:08 rwatson Exp $ + * created from FreeBSD: head/sys/kern/syscalls.master 182123 2008-08-24 21:20:35Z rwatson + */ + +#define TARGET_FREEBSD_NR_syscall 0 +#define TARGET_FREEBSD_NR_exit 1 +#define TARGET_FREEBSD_NR_fork 2 +#define TARGET_FREEBSD_NR_read 3 +#define TARGET_FREEBSD_NR_write 4 +#define TARGET_FREEBSD_NR_open 5 +#define TARGET_FREEBSD_NR_close 6 +#define TARGET_FREEBSD_NR_wait4 7 +#define TARGET_FREEBSD_NR_link 9 +#define TARGET_FREEBSD_NR_unlink 10 +#define TARGET_FREEBSD_NR_chdir 12 +#define TARGET_FREEBSD_NR_fchdir 13 +#define TARGET_FREEBSD_NR_mknod 14 +#define TARGET_FREEBSD_NR_chmod 15 +#define TARGET_FREEBSD_NR_chown 16 +#define TARGET_FREEBSD_NR_break 17 +#define TARGET_FREEBSD_NR_freebsd4_getfsstat 18 +#define TARGET_FREEBSD_NR_getpid 20 +#define TARGET_FREEBSD_NR_mount 21 +#define TARGET_FREEBSD_NR_unmount 22 +#define TARGET_FREEBSD_NR_setuid 23 +#define TARGET_FREEBSD_NR_getuid 24 +#define TARGET_FREEBSD_NR_geteuid 25 +#define TARGET_FREEBSD_NR_ptrace 26 +#define TARGET_FREEBSD_NR_recvmsg 27 +#define TARGET_FREEBSD_NR_sendmsg 28 +#define TARGET_FREEBSD_NR_recvfrom 29 +#define TARGET_FREEBSD_NR_accept 30 +#define TARGET_FREEBSD_NR_getpeername 31 +#define TARGET_FREEBSD_NR_getsockname 32 +#define TARGET_FREEBSD_NR_access 33 +#define TARGET_FREEBSD_NR_chflags 34 +#define TARGET_FREEBSD_NR_fchflags 35 +#define TARGET_FREEBSD_NR_sync 36 +#define TARGET_FREEBSD_NR_kill 37 +#define TARGET_FREEBSD_NR_getppid 39 +#define TARGET_FREEBSD_NR_dup 41 +#define TARGET_FREEBSD_NR_pipe 42 +#define TARGET_FREEBSD_NR_getegid 43 +#define TARGET_FREEBSD_NR_profil 44 +#define TARGET_FREEBSD_NR_ktrace 45 +#define TARGET_FREEBSD_NR_getgid 47 +#define TARGET_FREEBSD_NR_getlogin 49 +#define TARGET_FREEBSD_NR_setlogin 50 +#define TARGET_FREEBSD_NR_acct 51 +#define TARGET_FREEBSD_NR_sigaltstack 53 +#define TARGET_FREEBSD_NR_ioctl 54 +#define TARGET_FREEBSD_NR_reboot 55 +#define TARGET_FREEBSD_NR_revoke 56 +#define TARGET_FREEBSD_NR_symlink 57 +#define TARGET_FREEBSD_NR_readlink 58 +#define TARGET_FREEBSD_NR_execve 59 +#define TARGET_FREEBSD_NR_umask 60 +#define TARGET_FREEBSD_NR_chroot 61 +#define TARGET_FREEBSD_NR_msync 65 +#define TARGET_FREEBSD_NR_vfork 66 +#define TARGET_FREEBSD_NR_sbrk 69 +#define TARGET_FREEBSD_NR_sstk 70 +#define TARGET_FREEBSD_NR_vadvise 72 +#define TARGET_FREEBSD_NR_munmap 73 +#define TARGET_FREEBSD_NR_mprotect 74 +#define TARGET_FREEBSD_NR_madvise 75 +#define TARGET_FREEBSD_NR_mincore 78 +#define TARGET_FREEBSD_NR_getgroups 79 +#define TARGET_FREEBSD_NR_setgroups 80 +#define TARGET_FREEBSD_NR_getpgrp 81 +#define TARGET_FREEBSD_NR_setpgid 82 +#define TARGET_FREEBSD_NR_setitimer 83 +#define TARGET_FREEBSD_NR_swapon 85 +#define TARGET_FREEBSD_NR_getitimer 86 +#define TARGET_FREEBSD_NR_getdtablesize 89 +#define TARGET_FREEBSD_NR_dup2 90 +#define TARGET_FREEBSD_NR_fcntl 92 +#define TARGET_FREEBSD_NR_select 93 +#define TARGET_FREEBSD_NR_fsync 95 +#define TARGET_FREEBSD_NR_setpriority 96 +#define TARGET_FREEBSD_NR_socket 97 +#define TARGET_FREEBSD_NR_connect 98 +#define TARGET_FREEBSD_NR_getpriority 100 +#define TARGET_FREEBSD_NR_bind 104 +#define TARGET_FREEBSD_NR_setsockopt 105 +#define TARGET_FREEBSD_NR_listen 106 +#define TARGET_FREEBSD_NR_gettimeofday 116 +#define TARGET_FREEBSD_NR_getrusage 117 +#define TARGET_FREEBSD_NR_getsockopt 118 +#define TARGET_FREEBSD_NR_readv 120 +#define TARGET_FREEBSD_NR_writev 121 +#define TARGET_FREEBSD_NR_settimeofday 122 +#define TARGET_FREEBSD_NR_fchown 123 +#define TARGET_FREEBSD_NR_fchmod 124 +#define TARGET_FREEBSD_NR_setreuid 126 +#define TARGET_FREEBSD_NR_setregid 127 +#define TARGET_FREEBSD_NR_rename 128 +#define TARGET_FREEBSD_NR_flock 131 +#define TARGET_FREEBSD_NR_mkfifo 132 +#define TARGET_FREEBSD_NR_sendto 133 +#define TARGET_FREEBSD_NR_shutdown 134 +#define TARGET_FREEBSD_NR_socketpair 135 +#define TARGET_FREEBSD_NR_mkdir 136 +#define TARGET_FREEBSD_NR_rmdir 137 +#define TARGET_FREEBSD_NR_utimes 138 +#define TARGET_FREEBSD_NR_adjtime 140 +#define TARGET_FREEBSD_NR_setsid 147 +#define TARGET_FREEBSD_NR_quotactl 148 +#define TARGET_FREEBSD_NR_nlm_syscall 154 +#define TARGET_FREEBSD_NR_nfssvc 155 +#define TARGET_FREEBSD_NR_freebsd4_statfs 157 +#define TARGET_FREEBSD_NR_freebsd4_fstatfs 158 +#define TARGET_FREEBSD_NR_lgetfh 160 +#define TARGET_FREEBSD_NR_getfh 161 +#define TARGET_FREEBSD_NR_getdomainname 162 +#define TARGET_FREEBSD_NR_setdomainname 163 +#define TARGET_FREEBSD_NR_uname 164 +#define TARGET_FREEBSD_NR_sysarch 165 +#define TARGET_FREEBSD_NR_rtprio 166 +#define TARGET_FREEBSD_NR_semsys 169 +#define TARGET_FREEBSD_NR_msgsys 170 +#define TARGET_FREEBSD_NR_shmsys 171 +#define TARGET_FREEBSD_NR_freebsd6_pread 173 +#define TARGET_FREEBSD_NR_freebsd6_pwrite 174 +#define TARGET_FREEBSD_NR_setfib 175 +#define TARGET_FREEBSD_NR_ntp_adjtime 176 +#define TARGET_FREEBSD_NR_setgid 181 +#define TARGET_FREEBSD_NR_setegid 182 +#define TARGET_FREEBSD_NR_seteuid 183 +#define TARGET_FREEBSD_NR_stat 188 +#define TARGET_FREEBSD_NR_fstat 189 +#define TARGET_FREEBSD_NR_lstat 190 +#define TARGET_FREEBSD_NR_pathconf 191 +#define TARGET_FREEBSD_NR_fpathconf 192 +#define TARGET_FREEBSD_NR_getrlimit 194 +#define TARGET_FREEBSD_NR_setrlimit 195 +#define TARGET_FREEBSD_NR_getdirentries 196 +#define TARGET_FREEBSD_NR_freebsd6_mmap 197 +#define TARGET_FREEBSD_NR___syscall 198 +#define TARGET_FREEBSD_NR_freebsd6_lseek 199 +#define TARGET_FREEBSD_NR_freebsd6_truncate 200 +#define TARGET_FREEBSD_NR_freebsd6_ftruncate 201 +#define TARGET_FREEBSD_NR___sysctl 202 +#define TARGET_FREEBSD_NR_mlock 203 +#define TARGET_FREEBSD_NR_munlock 204 +#define TARGET_FREEBSD_NR_undelete 205 +#define TARGET_FREEBSD_NR_futimes 206 +#define TARGET_FREEBSD_NR_getpgid 207 +#define TARGET_FREEBSD_NR_poll 209 +#define TARGET_FREEBSD_NR___semctl 220 +#define TARGET_FREEBSD_NR_semget 221 +#define TARGET_FREEBSD_NR_semop 222 +#define TARGET_FREEBSD_NR_msgctl 224 +#define TARGET_FREEBSD_NR_msgget 225 +#define TARGET_FREEBSD_NR_msgsnd 226 +#define TARGET_FREEBSD_NR_msgrcv 227 +#define TARGET_FREEBSD_NR_shmat 228 +#define TARGET_FREEBSD_NR_shmctl 229 +#define TARGET_FREEBSD_NR_shmdt 230 +#define TARGET_FREEBSD_NR_shmget 231 +#define TARGET_FREEBSD_NR_clock_gettime 232 +#define TARGET_FREEBSD_NR_clock_settime 233 +#define TARGET_FREEBSD_NR_clock_getres 234 +#define TARGET_FREEBSD_NR_ktimer_create 235 +#define TARGET_FREEBSD_NR_ktimer_delete 236 +#define TARGET_FREEBSD_NR_ktimer_settime 237 +#define TARGET_FREEBSD_NR_ktimer_gettime 238 +#define TARGET_FREEBSD_NR_ktimer_getoverrun 239 +#define TARGET_FREEBSD_NR_nanosleep 240 +#define TARGET_FREEBSD_NR_ntp_gettime 248 +#define TARGET_FREEBSD_NR_minherit 250 +#define TARGET_FREEBSD_NR_rfork 251 +#define TARGET_FREEBSD_NR_openbsd_poll 252 +#define TARGET_FREEBSD_NR_issetugid 253 +#define TARGET_FREEBSD_NR_lchown 254 +#define TARGET_FREEBSD_NR_aio_read 255 +#define TARGET_FREEBSD_NR_aio_write 256 +#define TARGET_FREEBSD_NR_lio_listio 257 +#define TARGET_FREEBSD_NR_getdents 272 +#define TARGET_FREEBSD_NR_lchmod 274 +#define TARGET_FREEBSD_NR_netbsd_lchown 275 +#define TARGET_FREEBSD_NR_lutimes 276 +#define TARGET_FREEBSD_NR_netbsd_msync 277 +#define TARGET_FREEBSD_NR_nstat 278 +#define TARGET_FREEBSD_NR_nfstat 279 +#define TARGET_FREEBSD_NR_nlstat 280 +#define TARGET_FREEBSD_NR_preadv 289 +#define TARGET_FREEBSD_NR_pwritev 290 +#define TARGET_FREEBSD_NR_freebsd4_fhstatfs 297 +#define TARGET_FREEBSD_NR_fhopen 298 +#define TARGET_FREEBSD_NR_fhstat 299 +#define TARGET_FREEBSD_NR_modnext 300 +#define TARGET_FREEBSD_NR_modstat 301 +#define TARGET_FREEBSD_NR_modfnext 302 +#define TARGET_FREEBSD_NR_modfind 303 +#define TARGET_FREEBSD_NR_kldload 304 +#define TARGET_FREEBSD_NR_kldunload 305 +#define TARGET_FREEBSD_NR_kldfind 306 +#define TARGET_FREEBSD_NR_kldnext 307 +#define TARGET_FREEBSD_NR_kldstat 308 +#define TARGET_FREEBSD_NR_kldfirstmod 309 +#define TARGET_FREEBSD_NR_getsid 310 +#define TARGET_FREEBSD_NR_setresuid 311 +#define TARGET_FREEBSD_NR_setresgid 312 +#define TARGET_FREEBSD_NR_aio_return 314 +#define TARGET_FREEBSD_NR_aio_suspend 315 +#define TARGET_FREEBSD_NR_aio_cancel 316 +#define TARGET_FREEBSD_NR_aio_error 317 +#define TARGET_FREEBSD_NR_oaio_read 318 +#define TARGET_FREEBSD_NR_oaio_write 319 +#define TARGET_FREEBSD_NR_olio_listio 320 +#define TARGET_FREEBSD_NR_yield 321 +#define TARGET_FREEBSD_NR_mlockall 324 +#define TARGET_FREEBSD_NR_munlockall 325 +#define TARGET_FREEBSD_NR___getcwd 326 +#define TARGET_FREEBSD_NR_sched_setparam 327 +#define TARGET_FREEBSD_NR_sched_getparam 328 +#define TARGET_FREEBSD_NR_sched_setscheduler 329 +#define TARGET_FREEBSD_NR_sched_getscheduler 330 +#define TARGET_FREEBSD_NR_sched_yield 331 +#define TARGET_FREEBSD_NR_sched_get_priority_max 332 +#define TARGET_FREEBSD_NR_sched_get_priority_min 333 +#define TARGET_FREEBSD_NR_sched_rr_get_interval 334 +#define TARGET_FREEBSD_NR_utrace 335 +#define TARGET_FREEBSD_NR_freebsd4_sendfile 336 +#define TARGET_FREEBSD_NR_kldsym 337 +#define TARGET_FREEBSD_NR_jail 338 +#define TARGET_FREEBSD_NR_sigprocmask 340 +#define TARGET_FREEBSD_NR_sigsuspend 341 +#define TARGET_FREEBSD_NR_freebsd4_sigaction 342 +#define TARGET_FREEBSD_NR_sigpending 343 +#define TARGET_FREEBSD_NR_freebsd4_sigreturn 344 +#define TARGET_FREEBSD_NR_sigtimedwait 345 +#define TARGET_FREEBSD_NR_sigwaitinfo 346 +#define TARGET_FREEBSD_NR___acl_get_file 347 +#define TARGET_FREEBSD_NR___acl_set_file 348 +#define TARGET_FREEBSD_NR___acl_get_fd 349 +#define TARGET_FREEBSD_NR___acl_set_fd 350 +#define TARGET_FREEBSD_NR___acl_delete_file 351 +#define TARGET_FREEBSD_NR___acl_delete_fd 352 +#define TARGET_FREEBSD_NR___acl_aclcheck_file 353 +#define TARGET_FREEBSD_NR___acl_aclcheck_fd 354 +#define TARGET_FREEBSD_NR_extattrctl 355 +#define TARGET_FREEBSD_NR_extattr_set_file 356 +#define TARGET_FREEBSD_NR_extattr_get_file 357 +#define TARGET_FREEBSD_NR_extattr_delete_file 358 +#define TARGET_FREEBSD_NR_aio_waitcomplete 359 +#define TARGET_FREEBSD_NR_getresuid 360 +#define TARGET_FREEBSD_NR_getresgid 361 +#define TARGET_FREEBSD_NR_kqueue 362 +#define TARGET_FREEBSD_NR_kevent 363 +#define TARGET_FREEBSD_NR_extattr_set_fd 371 +#define TARGET_FREEBSD_NR_extattr_get_fd 372 +#define TARGET_FREEBSD_NR_extattr_delete_fd 373 +#define TARGET_FREEBSD_NR___setugid 374 +#define TARGET_FREEBSD_NR_nfsclnt 375 +#define TARGET_FREEBSD_NR_eaccess 376 +#define TARGET_FREEBSD_NR_nmount 378 +#define TARGET_FREEBSD_NR___mac_get_proc 384 +#define TARGET_FREEBSD_NR___mac_set_proc 385 +#define TARGET_FREEBSD_NR___mac_get_fd 386 +#define TARGET_FREEBSD_NR___mac_get_file 387 +#define TARGET_FREEBSD_NR___mac_set_fd 388 +#define TARGET_FREEBSD_NR___mac_set_file 389 +#define TARGET_FREEBSD_NR_kenv 390 +#define TARGET_FREEBSD_NR_lchflags 391 +#define TARGET_FREEBSD_NR_uuidgen 392 +#define TARGET_FREEBSD_NR_sendfile 393 +#define TARGET_FREEBSD_NR_mac_syscall 394 +#define TARGET_FREEBSD_NR_getfsstat 395 +#define TARGET_FREEBSD_NR_statfs 396 +#define TARGET_FREEBSD_NR_fstatfs 397 +#define TARGET_FREEBSD_NR_fhstatfs 398 +#define TARGET_FREEBSD_NR_ksem_close 400 +#define TARGET_FREEBSD_NR_ksem_post 401 +#define TARGET_FREEBSD_NR_ksem_wait 402 +#define TARGET_FREEBSD_NR_ksem_trywait 403 +#define TARGET_FREEBSD_NR_ksem_init 404 +#define TARGET_FREEBSD_NR_ksem_open 405 +#define TARGET_FREEBSD_NR_ksem_unlink 406 +#define TARGET_FREEBSD_NR_ksem_getvalue 407 +#define TARGET_FREEBSD_NR_ksem_destroy 408 +#define TARGET_FREEBSD_NR___mac_get_pid 409 +#define TARGET_FREEBSD_NR___mac_get_link 410 +#define TARGET_FREEBSD_NR___mac_set_link 411 +#define TARGET_FREEBSD_NR_extattr_set_link 412 +#define TARGET_FREEBSD_NR_extattr_get_link 413 +#define TARGET_FREEBSD_NR_extattr_delete_link 414 +#define TARGET_FREEBSD_NR___mac_execve 415 +#define TARGET_FREEBSD_NR_sigaction 416 +#define TARGET_FREEBSD_NR_sigreturn 417 +#define TARGET_FREEBSD_NR_getcontext 421 +#define TARGET_FREEBSD_NR_setcontext 422 +#define TARGET_FREEBSD_NR_swapcontext 423 +#define TARGET_FREEBSD_NR_swapoff 424 +#define TARGET_FREEBSD_NR___acl_get_link 425 +#define TARGET_FREEBSD_NR___acl_set_link 426 +#define TARGET_FREEBSD_NR___acl_delete_link 427 +#define TARGET_FREEBSD_NR___acl_aclcheck_link 428 +#define TARGET_FREEBSD_NR_sigwait 429 +#define TARGET_FREEBSD_NR_thr_create 430 +#define TARGET_FREEBSD_NR_thr_exit 431 +#define TARGET_FREEBSD_NR_thr_self 432 +#define TARGET_FREEBSD_NR_thr_kill 433 +#define TARGET_FREEBSD_NR__umtx_lock 434 +#define TARGET_FREEBSD_NR__umtx_unlock 435 +#define TARGET_FREEBSD_NR_jail_attach 436 +#define TARGET_FREEBSD_NR_extattr_list_fd 437 +#define TARGET_FREEBSD_NR_extattr_list_file 438 +#define TARGET_FREEBSD_NR_extattr_list_link 439 +#define TARGET_FREEBSD_NR_ksem_timedwait 441 +#define TARGET_FREEBSD_NR_thr_suspend 442 +#define TARGET_FREEBSD_NR_thr_wake 443 +#define TARGET_FREEBSD_NR_kldunloadf 444 +#define TARGET_FREEBSD_NR_audit 445 +#define TARGET_FREEBSD_NR_auditon 446 +#define TARGET_FREEBSD_NR_getauid 447 +#define TARGET_FREEBSD_NR_setauid 448 +#define TARGET_FREEBSD_NR_getaudit 449 +#define TARGET_FREEBSD_NR_setaudit 450 +#define TARGET_FREEBSD_NR_getaudit_addr 451 +#define TARGET_FREEBSD_NR_setaudit_addr 452 +#define TARGET_FREEBSD_NR_auditctl 453 +#define TARGET_FREEBSD_NR__umtx_op 454 +#define TARGET_FREEBSD_NR_thr_new 455 +#define TARGET_FREEBSD_NR_sigqueue 456 +#define TARGET_FREEBSD_NR_kmq_open 457 +#define TARGET_FREEBSD_NR_kmq_setattr 458 +#define TARGET_FREEBSD_NR_kmq_timedreceive 459 +#define TARGET_FREEBSD_NR_kmq_timedsend 460 +#define TARGET_FREEBSD_NR_kmq_notify 461 +#define TARGET_FREEBSD_NR_kmq_unlink 462 +#define TARGET_FREEBSD_NR_abort2 463 +#define TARGET_FREEBSD_NR_thr_set_name 464 +#define TARGET_FREEBSD_NR_aio_fsync 465 +#define TARGET_FREEBSD_NR_rtprio_thread 466 +#define TARGET_FREEBSD_NR_sctp_peeloff 471 +#define TARGET_FREEBSD_NR_sctp_generic_sendmsg 472 +#define TARGET_FREEBSD_NR_sctp_generic_sendmsg_iov 473 +#define TARGET_FREEBSD_NR_sctp_generic_recvmsg 474 +#define TARGET_FREEBSD_NR_pread 475 +#define TARGET_FREEBSD_NR_pwrite 476 +#define TARGET_FREEBSD_NR_mmap 477 +#define TARGET_FREEBSD_NR_lseek 478 +#define TARGET_FREEBSD_NR_truncate 479 +#define TARGET_FREEBSD_NR_ftruncate 480 +#define TARGET_FREEBSD_NR_thr_kill2 481 +#define TARGET_FREEBSD_NR_shm_open 482 +#define TARGET_FREEBSD_NR_shm_unlink 483 +#define TARGET_FREEBSD_NR_cpuset 484 +#define TARGET_FREEBSD_NR_cpuset_setid 485 +#define TARGET_FREEBSD_NR_cpuset_getid 486 +#define TARGET_FREEBSD_NR_cpuset_getaffinity 487 +#define TARGET_FREEBSD_NR_cpuset_setaffinity 488 +#define TARGET_FREEBSD_NR_faccessat 489 +#define TARGET_FREEBSD_NR_fchmodat 490 +#define TARGET_FREEBSD_NR_fchownat 491 +#define TARGET_FREEBSD_NR_fexecve 492 +#define TARGET_FREEBSD_NR_fstatat 493 +#define TARGET_FREEBSD_NR_futimesat 494 +#define TARGET_FREEBSD_NR_linkat 495 +#define TARGET_FREEBSD_NR_mkdirat 496 +#define TARGET_FREEBSD_NR_mkfifoat 497 +#define TARGET_FREEBSD_NR_mknodat 498 +#define TARGET_FREEBSD_NR_openat 499 +#define TARGET_FREEBSD_NR_readlinkat 500 +#define TARGET_FREEBSD_NR_renameat 501 +#define TARGET_FREEBSD_NR_symlinkat 502 +#define TARGET_FREEBSD_NR_unlinkat 503 +#define TARGET_FREEBSD_NR_posix_openpt 504 diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/main.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/main.c --- qemu-0.9.1/bsd-user/main.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/main.c 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,576 @@ +/* + * qemu user main + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "qemu.h" +#include "qemu-common.h" +/* For tb_lock */ +#include "exec-all.h" + +#define DEBUG_LOGFILE "/tmp/qemu.log" + +static const char *interp_prefix = CONFIG_QEMU_PREFIX; +const char *qemu_uname_release = CONFIG_UNAME_RELEASE; +extern char **environ; + +/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so + we allocate a bigger stack. Need a better solution, for example + by remapping the process stack directly at the right place */ +unsigned long x86_stack_size = 512 * 1024; + +void gemu_log(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} +#ifdef TARGET_SPARC +#define SPARC64_STACK_BIAS 2047 + +//#define DEBUG_WIN +/* WARNING: dealing with register windows _is_ complicated. More info + can be found at http://www.sics.se/~psm/sparcstack.html */ +static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) +{ + index = (index + cwp * 16) % (16 * env->nwindows); + /* wrap handling : if cwp is on the last window, then we use the + registers 'after' the end */ + if (index < 8 && env->cwp == env->nwindows - 1) + index += 16 * env->nwindows; + return index; +} + +/* save the register window 'cwp1' */ +static inline void save_window_offset(CPUSPARCState *env, int cwp1) +{ + unsigned int i; + abi_ulong sp_ptr; + + sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; +#ifdef TARGET_SPARC64 + if (sp_ptr & 3) + sp_ptr += SPARC64_STACK_BIAS; +#endif +#if defined(DEBUG_WIN) + printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n", + sp_ptr, cwp1); +#endif + for(i = 0; i < 16; i++) { + /* FIXME - what to do if put_user() fails? */ + put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); + sp_ptr += sizeof(abi_ulong); + } +} + +static void save_window(CPUSPARCState *env) +{ +#ifndef TARGET_SPARC64 + unsigned int new_wim; + new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) & + ((1LL << env->nwindows) - 1); + save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2)); + env->wim = new_wim; +#else + save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2)); + env->cansave++; + env->canrestore--; +#endif +} + +static void restore_window(CPUSPARCState *env) +{ +#ifndef TARGET_SPARC64 + unsigned int new_wim; +#endif + unsigned int i, cwp1; + abi_ulong sp_ptr; + +#ifndef TARGET_SPARC64 + new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) & + ((1LL << env->nwindows) - 1); +#endif + + /* restore the invalid window */ + cwp1 = cpu_cwp_inc(env, env->cwp + 1); + sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; +#ifdef TARGET_SPARC64 + if (sp_ptr & 3) + sp_ptr += SPARC64_STACK_BIAS; +#endif +#if defined(DEBUG_WIN) + printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n", + sp_ptr, cwp1); +#endif + for(i = 0; i < 16; i++) { + /* FIXME - what to do if get_user() fails? */ + get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); + sp_ptr += sizeof(abi_ulong); + } +#ifdef TARGET_SPARC64 + env->canrestore++; + if (env->cleanwin < env->nwindows - 1) + env->cleanwin++; + env->cansave--; +#else + env->wim = new_wim; +#endif +} + +static void flush_windows(CPUSPARCState *env) +{ + int offset, cwp1; + + offset = 1; + for(;;) { + /* if restore would invoke restore_window(), then we can stop */ + cwp1 = cpu_cwp_inc(env, env->cwp + offset); +#ifndef TARGET_SPARC64 + if (env->wim & (1 << cwp1)) + break; +#else + if (env->canrestore == 0) + break; + env->cansave++; + env->canrestore--; +#endif + save_window_offset(env, cwp1); + offset++; + } + cwp1 = cpu_cwp_inc(env, env->cwp + 1); +#ifndef TARGET_SPARC64 + /* set wim so that restore will reload the registers */ + env->wim = 1 << cwp1; +#endif +#if defined(DEBUG_WIN) + printf("flush_windows: nb=%d\n", offset - 1); +#endif +} + +void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type) +{ + int trapnr, ret, syscall_nr; + //target_siginfo_t info; + + while (1) { + trapnr = cpu_sparc_exec (env); + + switch (trapnr) { + case 0x100: + syscall_nr = env->gregs[1]; +#if defined(TARGET_SPARC) + syscall_nr &= ~(SYSCALL_G7RFLAG | SYSCALL_G2RFLAG); +#endif + if (bsd_type == target_freebsd) + ret = do_freebsd_syscall(env, syscall_nr, + env->regwptr[0], env->regwptr[1], + env->regwptr[2], env->regwptr[3], + env->regwptr[4], env->regwptr[5]); + else if (bsd_type == target_netbsd) + ret = do_netbsd_syscall(env, syscall_nr, + env->regwptr[0], env->regwptr[1], + env->regwptr[2], env->regwptr[3], + env->regwptr[4], env->regwptr[5]); + else //if (bsd_type == target_openbsd) + ret = do_openbsd_syscall(env, syscall_nr, + env->regwptr[0], env->regwptr[1], + env->regwptr[2], env->regwptr[3], + env->regwptr[4], env->regwptr[5]); + if ((unsigned int)ret >= (unsigned int)(-515)) { +#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) + env->xcc |= PSR_CARRY; +#else + env->psr |= PSR_CARRY; +#endif + } else { +#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) + env->xcc &= ~PSR_CARRY; +#else + env->psr &= ~PSR_CARRY; +#endif + } + env->regwptr[0] = ret; + /* next instruction */ +#if defined(TARGET_SPARC) + if (env->gregs[1] & SYSCALL_G2RFLAG) { + env->pc = env->gregs[2]; + env->npc = env->pc + 4; + } else if (env->gregs[1] & SYSCALL_G7RFLAG) { + env->pc = env->gregs[7]; + env->npc = env->pc + 4; + } else { + env->pc = env->npc; + env->npc = env->npc + 4; + } +#else + env->pc = env->npc; + env->npc = env->npc + 4; +#endif + break; + case 0x83: /* flush windows */ +#ifdef TARGET_ABI32 + case 0x103: +#endif + flush_windows(env); + /* next instruction */ + env->pc = env->npc; + env->npc = env->npc + 4; + break; +#ifndef TARGET_SPARC64 + case TT_WIN_OVF: /* window overflow */ + save_window(env); + break; + case TT_WIN_UNF: /* window underflow */ + restore_window(env); + break; + case TT_TFAULT: + case TT_DFAULT: +#if 0 + { + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* XXX: check env->error_code */ + info.si_code = TARGET_SEGV_MAPERR; + info._sifields._sigfault._addr = env->mmuregs[4]; + queue_signal(env, info.si_signo, &info); + } +#endif + break; +#else + case TT_SPILL: /* window overflow */ + save_window(env); + break; + case TT_FILL: /* window underflow */ + restore_window(env); + break; + case TT_TFAULT: + case TT_DFAULT: +#if 0 + { + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* XXX: check env->error_code */ + info.si_code = TARGET_SEGV_MAPERR; + if (trapnr == TT_DFAULT) + info._sifields._sigfault._addr = env->dmmuregs[4]; + else + info._sifields._sigfault._addr = env->tsptr->tpc; + //queue_signal(env, info.si_signo, &info); + } +#endif + break; +#endif + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig (env, TARGET_SIGTRAP); +#if 0 + if (sig) + { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + //queue_signal(env, info.si_signo, &info); + } +#endif + } + break; + default: + printf ("Unhandled trap: 0x%x\n", trapnr); + cpu_dump_state(env, stderr, fprintf, 0); + exit (1); + } + process_pending_signals (env); + } +} + +#endif + +static void usage(void) +{ + printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n" + "usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n" + "BSD CPU emulator (compiled for %s emulation)\n" + "\n" + "Standard options:\n" + "-h print this help\n" + "-g port wait gdb connection to port\n" + "-L path set the elf interpreter prefix (default=%s)\n" + "-s size set the stack size in bytes (default=%ld)\n" + "-cpu model select CPU (-cpu ? for list)\n" + "-drop-ld-preload drop LD_PRELOAD for target process\n" + "-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n" + "\n" + "Debug options:\n" + "-d options activate log (logfile=%s)\n" + "-p pagesize set the host page size to 'pagesize'\n" + "-strace log system calls\n" + "\n" + "Environment variables:\n" + "QEMU_STRACE Print system calls and arguments similar to the\n" + " 'strace' program. Enable by setting to any value.\n" + , + TARGET_ARCH, + interp_prefix, + x86_stack_size, + DEBUG_LOGFILE); + _exit(1); +} + +THREAD CPUState *thread_env; + +/* Assumes contents are already zeroed. */ +void init_task_state(TaskState *ts) +{ + int i; + + ts->used = 1; + ts->first_free = ts->sigqueue_table; + for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) { + ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1]; + } + ts->sigqueue_table[i].next = NULL; +} + +int main(int argc, char **argv) +{ + const char *filename; + const char *cpu_model; + struct target_pt_regs regs1, *regs = ®s1; + struct image_info info1, *info = &info1; + TaskState ts1, *ts = &ts1; + CPUState *env; + int optind; + const char *r; + int gdbstub_port = 0; + int drop_ld_preload = 0, environ_count = 0; + char **target_environ, **wrk, **dst; + enum BSDType bsd_type = target_openbsd; + + if (argc <= 1) + usage(); + + /* init debug */ + cpu_set_log_filename(DEBUG_LOGFILE); + + cpu_model = NULL; + optind = 1; + for(;;) { + if (optind >= argc) + break; + r = argv[optind]; + if (r[0] != '-') + break; + optind++; + r++; + if (!strcmp(r, "-")) { + break; + } else if (!strcmp(r, "d")) { + int mask; + const CPULogItem *item; + + if (optind >= argc) + break; + + r = argv[optind++]; + mask = cpu_str_to_log_mask(r); + if (!mask) { + printf("Log items (comma separated):\n"); + for(item = cpu_log_items; item->mask != 0; item++) { + printf("%-10s %s\n", item->name, item->help); + } + exit(1); + } + cpu_set_log(mask); + } else if (!strcmp(r, "s")) { + r = argv[optind++]; + x86_stack_size = strtol(r, (char **)&r, 0); + if (x86_stack_size <= 0) + usage(); + if (*r == 'M') + x86_stack_size *= 1024 * 1024; + else if (*r == 'k' || *r == 'K') + x86_stack_size *= 1024; + } else if (!strcmp(r, "L")) { + interp_prefix = argv[optind++]; + } else if (!strcmp(r, "p")) { + qemu_host_page_size = atoi(argv[optind++]); + if (qemu_host_page_size == 0 || + (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) { + fprintf(stderr, "page size must be a power of two\n"); + exit(1); + } + } else if (!strcmp(r, "g")) { + gdbstub_port = atoi(argv[optind++]); + } else if (!strcmp(r, "r")) { + qemu_uname_release = argv[optind++]; + } else if (!strcmp(r, "cpu")) { + cpu_model = argv[optind++]; + if (strcmp(cpu_model, "?") == 0) { +/* XXX: implement xxx_cpu_list for targets that still miss it */ +#if defined(cpu_list) + cpu_list(stdout, &fprintf); +#endif + _exit(1); + } + } else if (!strcmp(r, "drop-ld-preload")) { + drop_ld_preload = 1; + } else if (!strcmp(r, "bsd")) { + if (!strcasecmp(argv[optind], "freebsd")) { + bsd_type = target_freebsd; + } else if (!strcasecmp(argv[optind], "netbsd")) { + bsd_type = target_netbsd; + } else if (!strcasecmp(argv[optind], "openbsd")) { + bsd_type = target_openbsd; + } else { + usage(); + } + optind++; + } else if (!strcmp(r, "strace")) { + do_strace = 1; + } else + { + usage(); + } + } + if (optind >= argc) + usage(); + filename = argv[optind]; + + /* Zero out regs */ + memset(regs, 0, sizeof(struct target_pt_regs)); + + /* Zero out image_info */ + memset(info, 0, sizeof(struct image_info)); + + /* Scan interp_prefix dir for replacement files. */ + init_paths(interp_prefix); + + if (cpu_model == NULL) { +#if defined(TARGET_SPARC) +#ifdef TARGET_SPARC64 + cpu_model = "TI UltraSparc II"; +#else + cpu_model = "Fujitsu MB86904"; +#endif +#else + cpu_model = "any"; +#endif + } + cpu_exec_init_all(0); + /* NOTE: we need to init the CPU at this stage to get + qemu_host_page_size */ + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + thread_env = env; + + if (getenv("QEMU_STRACE")) { + do_strace = 1; + } + + wrk = environ; + while (*(wrk++)) + environ_count++; + + target_environ = malloc((environ_count + 1) * sizeof(char *)); + if (!target_environ) + abort(); + for (wrk = environ, dst = target_environ; *wrk; wrk++) { + if (drop_ld_preload && !strncmp(*wrk, "LD_PRELOAD=", 11)) + continue; + *(dst++) = strdup(*wrk); + } + *dst = NULL; /* NULL terminate target_environ */ + + if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) { + printf("Error loading %s\n", filename); + _exit(1); + } + + for (wrk = target_environ; *wrk; wrk++) { + free(*wrk); + } + + free(target_environ); + + if (loglevel) { + page_dump(logfile); + + fprintf(logfile, "start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk); + fprintf(logfile, "end_code 0x" TARGET_ABI_FMT_lx "\n", info->end_code); + fprintf(logfile, "start_code 0x" TARGET_ABI_FMT_lx "\n", + info->start_code); + fprintf(logfile, "start_data 0x" TARGET_ABI_FMT_lx "\n", + info->start_data); + fprintf(logfile, "end_data 0x" TARGET_ABI_FMT_lx "\n", info->end_data); + fprintf(logfile, "start_stack 0x" TARGET_ABI_FMT_lx "\n", + info->start_stack); + fprintf(logfile, "brk 0x" TARGET_ABI_FMT_lx "\n", info->brk); + fprintf(logfile, "entry 0x" TARGET_ABI_FMT_lx "\n", info->entry); + } + + target_set_brk(info->brk); + syscall_init(); + signal_init(); + + /* build Task State */ + memset(ts, 0, sizeof(TaskState)); + init_task_state(ts); + ts->info = info; + env->opaque = ts; + env->user_mode_only = 1; + +#if defined(TARGET_SPARC) + { + int i; + env->pc = regs->pc; + env->npc = regs->npc; + env->y = regs->y; + for(i = 0; i < 8; i++) + env->gregs[i] = regs->u_regs[i]; + for(i = 0; i < 8; i++) + env->regwptr[i] = regs->u_regs[i + 8]; + } +#else +#error unsupported target CPU +#endif + + if (gdbstub_port) { + gdbserver_start (gdbstub_port); + gdb_handlesig(env, 0); + } + cpu_loop(env, bsd_type); + /* never exits */ + return 0; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/mmap.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/mmap.c --- qemu-0.9.1/bsd-user/mmap.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/mmap.c 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,545 @@ +/* + * mmap support for qemu + * + * Copyright (c) 2003 - 2008 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "qemu.h" +#include "qemu-common.h" + +//#define DEBUG_MMAP + +#if defined(USE_NPTL) +pthread_mutex_t mmap_mutex; +static int __thread mmap_lock_count; + +void mmap_lock(void) +{ + if (mmap_lock_count++ == 0) { + pthread_mutex_lock(&mmap_mutex); + } +} + +void mmap_unlock(void) +{ + if (--mmap_lock_count == 0) { + pthread_mutex_unlock(&mmap_mutex); + } +} + +/* Grab lock to make sure things are in a consistent state after fork(). */ +void mmap_fork_start(void) +{ + if (mmap_lock_count) + abort(); + pthread_mutex_lock(&mmap_mutex); +} + +void mmap_fork_end(int child) +{ + if (child) + pthread_mutex_init(&mmap_mutex, NULL); + else + pthread_mutex_unlock(&mmap_mutex); +} +#else +/* We aren't threadsafe to start with, so no need to worry about locking. */ +void mmap_lock(void) +{ +} + +void mmap_unlock(void) +{ +} +#endif + +void *qemu_vmalloc(size_t size) +{ + void *p; + unsigned long addr; + mmap_lock(); + /* Use map and mark the pages as used. */ + p = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + + addr = (unsigned long)p; + if (addr == (target_ulong) addr) { + /* Allocated region overlaps guest address space. + This may recurse. */ + page_set_flags(addr & TARGET_PAGE_MASK, TARGET_PAGE_ALIGN(addr + size), + PAGE_RESERVED); + } + + mmap_unlock(); + return p; +} + +void *qemu_malloc(size_t size) +{ + char * p; + size += 16; + p = qemu_vmalloc(size); + *(size_t *)p = size; + return p + 16; +} + +/* We use map, which is always zero initialized. */ +void * qemu_mallocz(size_t size) +{ + return qemu_malloc(size); +} + +void qemu_free(void *ptr) +{ + /* FIXME: We should unmark the reserved pages here. However this gets + complicated when one target page spans multiple host pages, so we + don't bother. */ + size_t *p; + p = (size_t *)((char *)ptr - 16); + munmap(p, *p); +} + +/* NOTE: all the constants are the HOST ones, but addresses are target. */ +int target_mprotect(abi_ulong start, abi_ulong len, int prot) +{ + abi_ulong end, host_start, host_end, addr; + int prot1, ret; + +#ifdef DEBUG_MMAP + printf("mprotect: start=0x" TARGET_FMT_lx + " len=0x" TARGET_FMT_lx " prot=%c%c%c\n", start, len, + prot & PROT_READ ? 'r' : '-', + prot & PROT_WRITE ? 'w' : '-', + prot & PROT_EXEC ? 'x' : '-'); +#endif + + if ((start & ~TARGET_PAGE_MASK) != 0) + return -EINVAL; + len = TARGET_PAGE_ALIGN(len); + end = start + len; + if (end < start) + return -EINVAL; + prot &= PROT_READ | PROT_WRITE | PROT_EXEC; + if (len == 0) + return 0; + + mmap_lock(); + host_start = start & qemu_host_page_mask; + host_end = HOST_PAGE_ALIGN(end); + if (start > host_start) { + /* handle host page containing start */ + prot1 = prot; + for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { + prot1 |= page_get_flags(addr); + } + if (host_end == host_start + qemu_host_page_size) { + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + prot1 |= page_get_flags(addr); + } + end = host_end; + } + ret = mprotect(g2h(host_start), qemu_host_page_size, prot1 & PAGE_BITS); + if (ret != 0) + goto error; + host_start += qemu_host_page_size; + } + if (end < host_end) { + prot1 = prot; + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + prot1 |= page_get_flags(addr); + } + ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size, + prot1 & PAGE_BITS); + if (ret != 0) + goto error; + host_end -= qemu_host_page_size; + } + + /* handle the pages in the middle */ + if (host_start < host_end) { + ret = mprotect(g2h(host_start), host_end - host_start, prot); + if (ret != 0) + goto error; + } + page_set_flags(start, start + len, prot | PAGE_VALID); + mmap_unlock(); + return 0; +error: + mmap_unlock(); + return ret; +} + +/* map an incomplete host page */ +static int mmap_frag(abi_ulong real_start, + abi_ulong start, abi_ulong end, + int prot, int flags, int fd, abi_ulong offset) +{ + abi_ulong real_end, addr; + void *host_start; + int prot1, prot_new; + + real_end = real_start + qemu_host_page_size; + host_start = g2h(real_start); + + /* get the protection of the target pages outside the mapping */ + prot1 = 0; + for(addr = real_start; addr < real_end; addr++) { + if (addr < start || addr >= end) + prot1 |= page_get_flags(addr); + } + + if (prot1 == 0) { + /* no page was there, so we allocate one */ + void *p = mmap(host_start, qemu_host_page_size, prot, + flags | MAP_ANON, -1, 0); + if (p == MAP_FAILED) + return -1; + prot1 = prot; + } + prot1 &= PAGE_BITS; + + prot_new = prot | prot1; + if (!(flags & MAP_ANON)) { + /* msync() won't work here, so we return an error if write is + possible while it is a shared mapping */ + if ((flags & MAP_FLAGMASK) == MAP_SHARED && + (prot & PROT_WRITE)) + return -EINVAL; + + /* adjust protection to be able to read */ + if (!(prot1 & PROT_WRITE)) + mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE); + + /* read the corresponding file data */ + pread(fd, g2h(start), end - start, offset); + + /* put final protection */ + if (prot_new != (prot1 | PROT_WRITE)) + mprotect(host_start, qemu_host_page_size, prot_new); + } else { + /* just update the protection */ + if (prot_new != prot1) { + mprotect(host_start, qemu_host_page_size, prot_new); + } + } + return 0; +} + +#if defined(__CYGWIN__) +/* Cygwin doesn't have a whole lot of address space. */ +static abi_ulong mmap_next_start = 0x18000000; +#else +static abi_ulong mmap_next_start = 0x40000000; +#endif + +unsigned long last_brk; + +/* find a free memory area of size 'size'. The search starts at + 'start'. If 'start' == 0, then a default start address is used. + Return -1 if error. +*/ +/* page_init() marks pages used by the host as reserved to be sure not + to use them. */ +static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) +{ + abi_ulong addr, addr1, addr_start; + int prot; + unsigned long new_brk; + + new_brk = (unsigned long)sbrk(0); + if (last_brk && last_brk < new_brk && last_brk == (target_ulong)last_brk) { + /* This is a hack to catch the host allocating memory with brk(). + If it uses mmap then we loose. + FIXME: We really want to avoid the host allocating memory in + the first place, and maybe leave some slack to avoid switching + to mmap. */ + page_set_flags(last_brk & TARGET_PAGE_MASK, + TARGET_PAGE_ALIGN(new_brk), + PAGE_RESERVED); + } + last_brk = new_brk; + + size = HOST_PAGE_ALIGN(size); + start = start & qemu_host_page_mask; + addr = start; + if (addr == 0) + addr = mmap_next_start; + addr_start = addr; + for(;;) { + prot = 0; + for(addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) { + prot |= page_get_flags(addr1); + } + if (prot == 0) + break; + addr += qemu_host_page_size; + /* we found nothing */ + if (addr == addr_start) + return (abi_ulong)-1; + } + if (start == 0) + mmap_next_start = addr + size; + return addr; +} + +/* NOTE: all the constants are the HOST ones */ +abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, + int flags, int fd, abi_ulong offset) +{ + abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; + unsigned long host_start; + + mmap_lock(); +#ifdef DEBUG_MMAP + { + printf("mmap: start=0x" TARGET_FMT_lx + " len=0x" TARGET_FMT_lx " prot=%c%c%c flags=", + start, len, + prot & PROT_READ ? 'r' : '-', + prot & PROT_WRITE ? 'w' : '-', + prot & PROT_EXEC ? 'x' : '-'); + if (flags & MAP_FIXED) + printf("MAP_FIXED "); + if (flags & MAP_ANON) + printf("MAP_ANON "); + switch(flags & MAP_FLAGMASK) { + case MAP_PRIVATE: + printf("MAP_PRIVATE "); + break; + case MAP_SHARED: + printf("MAP_SHARED "); + break; + default: + printf("[MAP_FLAGMASK=0x%x] ", flags & MAP_FLAGMASK); + break; + } + printf("fd=%d offset=" TARGET_FMT_lx "\n", fd, offset); + } +#endif + + if (offset & ~TARGET_PAGE_MASK) { + errno = EINVAL; + goto fail; + } + + len = TARGET_PAGE_ALIGN(len); + if (len == 0) + goto the_end; + real_start = start & qemu_host_page_mask; + + if (!(flags & MAP_FIXED)) { + abi_ulong mmap_start; + void *p; + host_offset = offset & qemu_host_page_mask; + host_len = len + offset - host_offset; + host_len = HOST_PAGE_ALIGN(host_len); + mmap_start = mmap_find_vma(real_start, host_len); + if (mmap_start == (abi_ulong)-1) { + errno = ENOMEM; + goto fail; + } + /* Note: we prefer to control the mapping address. It is + especially important if qemu_host_page_size > + qemu_real_host_page_size */ + p = mmap(g2h(mmap_start), + host_len, prot, flags | MAP_FIXED, fd, host_offset); + if (p == MAP_FAILED) + goto fail; + /* update start so that it points to the file position at 'offset' */ + host_start = (unsigned long)p; + if (!(flags & MAP_ANON)) + host_start += offset - host_offset; + start = h2g(host_start); + } else { + int flg; + target_ulong addr; + + if (start & ~TARGET_PAGE_MASK) { + errno = EINVAL; + goto fail; + } + end = start + len; + real_end = HOST_PAGE_ALIGN(end); + + for(addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) { + flg = page_get_flags(addr); + if (flg & PAGE_RESERVED) { + errno = ENXIO; + goto fail; + } + } + + /* worst case: we cannot map the file because the offset is not + aligned, so we read it */ + if (!(flags & MAP_ANON) && + (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) { + /* msync() won't work here, so we return an error if write is + possible while it is a shared mapping */ + if ((flags & MAP_FLAGMASK) == MAP_SHARED && + (prot & PROT_WRITE)) { + errno = EINVAL; + goto fail; + } + retaddr = target_mmap(start, len, prot | PROT_WRITE, + MAP_FIXED | MAP_PRIVATE | MAP_ANON, + -1, 0); + if (retaddr == -1) + goto fail; + pread(fd, g2h(start), len, offset); + if (!(prot & PROT_WRITE)) { + ret = target_mprotect(start, len, prot); + if (ret != 0) { + start = ret; + goto the_end; + } + } + goto the_end; + } + + /* handle the start of the mapping */ + if (start > real_start) { + if (real_end == real_start + qemu_host_page_size) { + /* one single host page */ + ret = mmap_frag(real_start, start, end, + prot, flags, fd, offset); + if (ret == -1) + goto fail; + goto the_end1; + } + ret = mmap_frag(real_start, start, real_start + qemu_host_page_size, + prot, flags, fd, offset); + if (ret == -1) + goto fail; + real_start += qemu_host_page_size; + } + /* handle the end of the mapping */ + if (end < real_end) { + ret = mmap_frag(real_end - qemu_host_page_size, + real_end - qemu_host_page_size, real_end, + prot, flags, fd, + offset + real_end - qemu_host_page_size - start); + if (ret == -1) + goto fail; + real_end -= qemu_host_page_size; + } + + /* map the middle (easier) */ + if (real_start < real_end) { + void *p; + unsigned long offset1; + if (flags & MAP_ANON) + offset1 = 0; + else + offset1 = offset + real_start - start; + p = mmap(g2h(real_start), real_end - real_start, + prot, flags, fd, offset1); + if (p == MAP_FAILED) + goto fail; + } + } + the_end1: + page_set_flags(start, start + len, prot | PAGE_VALID); + the_end: +#ifdef DEBUG_MMAP + printf("ret=0x" TARGET_FMT_lx "\n", start); + page_dump(stdout); + printf("\n"); +#endif + mmap_unlock(); + return start; +fail: + mmap_unlock(); + return -1; +} + +int target_munmap(abi_ulong start, abi_ulong len) +{ + abi_ulong end, real_start, real_end, addr; + int prot, ret; + +#ifdef DEBUG_MMAP + printf("munmap: start=0x%lx len=0x%lx\n", start, len); +#endif + if (start & ~TARGET_PAGE_MASK) + return -EINVAL; + len = TARGET_PAGE_ALIGN(len); + if (len == 0) + return -EINVAL; + mmap_lock(); + end = start + len; + real_start = start & qemu_host_page_mask; + real_end = HOST_PAGE_ALIGN(end); + + if (start > real_start) { + /* handle host page containing start */ + prot = 0; + for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) { + prot |= page_get_flags(addr); + } + if (real_end == real_start + qemu_host_page_size) { + for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { + prot |= page_get_flags(addr); + } + end = real_end; + } + if (prot != 0) + real_start += qemu_host_page_size; + } + if (end < real_end) { + prot = 0; + for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { + prot |= page_get_flags(addr); + } + if (prot != 0) + real_end -= qemu_host_page_size; + } + + ret = 0; + /* unmap what we can */ + if (real_start < real_end) { + ret = munmap(g2h(real_start), real_end - real_start); + } + + if (ret == 0) + page_set_flags(start, start + len, 0); + mmap_unlock(); + return ret; +} + +int target_msync(abi_ulong start, abi_ulong len, int flags) +{ + abi_ulong end; + + if (start & ~TARGET_PAGE_MASK) + return -EINVAL; + len = TARGET_PAGE_ALIGN(len); + end = start + len; + if (end < start) + return -EINVAL; + if (end == start) + return 0; + + start &= qemu_host_page_mask; + return msync(g2h(start), end - start, flags); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/netbsd/strace.list /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/netbsd/strace.list --- qemu-0.9.1/bsd-user/netbsd/strace.list 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/netbsd/strace.list 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,145 @@ +{ TARGET_NETBSD_NR___getcwd, "__getcwd", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR___syscall, "__syscall", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR___sysctl, "__sysctl", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_accept, "accept", "%s(%d,%#x,%#x)", NULL, NULL }, +{ TARGET_NETBSD_NR_access, "access", "%s(\"%s\",%#o)", NULL, NULL }, +{ TARGET_NETBSD_NR_acct, "acct", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_adjtime, "adjtime", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_bind, "bind", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_break, "break", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_chdir, "chdir", "%s(\"%s\")", NULL, NULL }, +{ TARGET_NETBSD_NR_chflags, "chflags", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_chmod, "chmod", "%s(\"%s\",%#o)", NULL, NULL }, +{ TARGET_NETBSD_NR_chown, "chown", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_chroot, "chroot", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_clock_getres, "clock_getres", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_clock_gettime, "clock_gettime", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_clock_settime, "clock_settime", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_close, "close", "%s(%d)", NULL, NULL }, +{ TARGET_NETBSD_NR_connect, "connect", "%s(%d,%#x,%d)", NULL, NULL }, +{ TARGET_NETBSD_NR_dup, "dup", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_dup2, "dup2", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_execve, "execve", NULL, print_execve, NULL }, +{ TARGET_NETBSD_NR_exit, "exit", "%s(%d)\n", NULL, NULL }, +{ TARGET_NETBSD_NR_fchdir, "fchdir", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_fchflags, "fchflags", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_fchmod, "fchmod", "%s(%d,%#o)", NULL, NULL }, +{ TARGET_NETBSD_NR_fchown, "fchown", "%s(\"%s\",%d,%d)", NULL, NULL }, +{ TARGET_NETBSD_NR_fcntl, "fcntl", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_flock, "flock", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_fork, "fork", "%s()", NULL, NULL }, +{ TARGET_NETBSD_NR_fpathconf, "fpathconf", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_fsync, "fsync", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_futimes, "futimes", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_getegid, "getegid", "%s()", NULL, NULL }, +{ TARGET_NETBSD_NR_geteuid, "geteuid", "%s()", NULL, NULL }, +{ TARGET_NETBSD_NR_getgid, "getgid", "%s()", NULL, NULL }, +{ TARGET_NETBSD_NR_getgroups, "getgroups", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_getitimer, "getitimer", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_getpeername, "getpeername", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_getpgid, "getpgid", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_getpgrp, "getpgrp", "%s()", NULL, NULL }, +{ TARGET_NETBSD_NR_getpid, "getpid", "%s()", NULL, NULL }, +{ TARGET_NETBSD_NR_getppid, "getppid", "%s()", NULL, NULL }, +{ TARGET_NETBSD_NR_getpriority, "getpriority", "%s(%#x,%#x)", NULL, NULL }, +{ TARGET_NETBSD_NR_getrlimit, "getrlimit", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_getrusage, "getrusage", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_getsid, "getsid", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_getsockname, "getsockname", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_getsockopt, "getsockopt", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_gettimeofday, "gettimeofday", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_getuid, "getuid", "%s()", NULL, NULL }, +{ TARGET_NETBSD_NR_ioctl, "ioctl", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_issetugid, "issetugid", "%s()", NULL, NULL }, +{ TARGET_NETBSD_NR_kevent, "kevent", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_kill, "kill", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_kqueue, "kqueue", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_ktrace, "ktrace", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_lchown, "lchown", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_lfs_bmapv, "lfs_bmapv", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_lfs_markv, "lfs_markv", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_lfs_segclean, "lfs_segclean", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_lfs_segwait, "lfs_segwait", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_link, "link", "%s(\"%s\",\"%s\")", NULL, NULL }, +{ TARGET_NETBSD_NR_listen, "listen", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_lseek, "lseek", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_madvise, "madvise", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_mincore, "mincore", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_minherit, "minherit", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_mkdir, "mkdir", "%s(\"%s\",%#o)", NULL, NULL }, +{ TARGET_NETBSD_NR_mkfifo, "mkfifo", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_mknod, "mknod", "%s(\"%s\",%#o,%#x)", NULL, NULL }, +{ TARGET_NETBSD_NR_mlock, "mlock", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_mlockall, "mlockall", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_mmap, "mmap", NULL, NULL, print_syscall_ret_addr }, +{ TARGET_NETBSD_NR_mprotect, "mprotect", "%s(%#x,%#x,%d)", NULL, NULL }, +{ TARGET_NETBSD_NR_msgget, "msgget", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_msgrcv, "msgrcv", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_msgsnd, "msgsnd", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_munlock, "munlock", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_munlockall, "munlockall", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_munmap, "munmap", "%s(%p,%d)", NULL, NULL }, +{ TARGET_NETBSD_NR_nanosleep, "nanosleep", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_nfssvc, "nfssvc", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_open, "open", "%s(\"%s\",%#x,%#o)", NULL, NULL }, +{ TARGET_NETBSD_NR_pathconf, "pathconf", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_pipe, "pipe", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_poll, "poll", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_pread, "pread", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_preadv, "preadv", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_profil, "profil", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_ptrace, "ptrace", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_pwrite, "pwrite", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_pwritev, "pwritev", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_quotactl, "quotactl", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_read, "read", "%s(%d,%#x,%d)", NULL, NULL }, +{ TARGET_NETBSD_NR_readlink, "readlink", "%s(\"%s\",%p,%d)", NULL, NULL }, +{ TARGET_NETBSD_NR_readv, "readv", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_reboot, "reboot", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_recvfrom, "recvfrom", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_recvmsg, "recvmsg", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_rename, "rename", "%s(\"%s\",\"%s\")", NULL, NULL }, +{ TARGET_NETBSD_NR_revoke, "revoke", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_rmdir, "rmdir", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_sbrk, "sbrk", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_sched_yield, "sched_yield", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_select, "select", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_semget, "semget", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_semop, "semop", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_sendmsg, "sendmsg", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_sendto, "sendto", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_setegid, "setegid", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_seteuid, "seteuid", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_setgid, "setgid", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_setgroups, "setgroups", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_setitimer, "setitimer", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_setpgid, "setpgid", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_setpriority, "setpriority", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_setregid, "setregid", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_setreuid, "setreuid", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_setrlimit, "setrlimit", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_setsid, "setsid", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_setsockopt, "setsockopt", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_settimeofday, "settimeofday", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_setuid, "setuid", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_shmat, "shmat", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_shmdt, "shmdt", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_shmget, "shmget", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_shutdown, "shutdown", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_socketpair, "socketpair", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_sstk, "sstk", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_swapctl, "swapctl", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_symlink, "symlink", "%s(\"%s\",\"%s\")", NULL, NULL }, +{ TARGET_NETBSD_NR_sync, "sync", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_sysarch, "sysarch", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_syscall, "syscall", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_truncate, "truncate", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_umask, "umask", "%s(%#o)", NULL, NULL }, +{ TARGET_NETBSD_NR_unlink, "unlink", "%s(\"%s\")", NULL, NULL }, +{ TARGET_NETBSD_NR_unmount, "unmount", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_utimes, "utimes", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_vfork, "vfork", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_wait4, "wait4", NULL, NULL, NULL }, +{ TARGET_NETBSD_NR_write, "write", "%s(%d,%#x,%d)", NULL, NULL }, +{ TARGET_NETBSD_NR_writev, "writev", "%s(%d,%p,%#x)", NULL, NULL }, diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/netbsd/syscall_nr.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/netbsd/syscall_nr.h --- qemu-0.9.1/bsd-user/netbsd/syscall_nr.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/netbsd/syscall_nr.h 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,373 @@ +/* $NetBSD: syscall.h,v 1.215 2008/06/17 16:07:57 tsutsui Exp $ */ + +/* + * System call numbers. + * + * created from NetBSD: syscalls.master,v 1.204 2008/06/17 16:05:23 tsutsui Exp + */ + +#define TARGET_NETBSD_NR_syscall 0 +#define TARGET_NETBSD_NR_exit 1 +#define TARGET_NETBSD_NR_fork 2 +#define TARGET_NETBSD_NR_read 3 +#define TARGET_NETBSD_NR_write 4 +#define TARGET_NETBSD_NR_open 5 +#define TARGET_NETBSD_NR_close 6 +#define TARGET_NETBSD_NR_wait4 7 +#define TARGET_NETBSD_NR_compat_43_ocreat 8 +#define TARGET_NETBSD_NR_link 9 +#define TARGET_NETBSD_NR_unlink 10 +#define TARGET_NETBSD_NR_chdir 12 +#define TARGET_NETBSD_NR_fchdir 13 +#define TARGET_NETBSD_NR_mknod 14 +#define TARGET_NETBSD_NR_chmod 15 +#define TARGET_NETBSD_NR_chown 16 +#define TARGET_NETBSD_NR_break 17 +#define TARGET_NETBSD_NR_compat_20_getfsstat 18 +#define TARGET_NETBSD_NR_compat_43_olseek 19 +#define TARGET_NETBSD_NR_getpid 20 +#define TARGET_NETBSD_NR_getpid 20 +#define TARGET_NETBSD_NR_compat_40_mount 21 +#define TARGET_NETBSD_NR_unmount 22 +#define TARGET_NETBSD_NR_setuid 23 +#define TARGET_NETBSD_NR_getuid 24 +#define TARGET_NETBSD_NR_getuid 24 +#define TARGET_NETBSD_NR_geteuid 25 +#define TARGET_NETBSD_NR_ptrace 26 +#define TARGET_NETBSD_NR_recvmsg 27 +#define TARGET_NETBSD_NR_sendmsg 28 +#define TARGET_NETBSD_NR_recvfrom 29 +#define TARGET_NETBSD_NR_accept 30 +#define TARGET_NETBSD_NR_getpeername 31 +#define TARGET_NETBSD_NR_getsockname 32 +#define TARGET_NETBSD_NR_access 33 +#define TARGET_NETBSD_NR_chflags 34 +#define TARGET_NETBSD_NR_fchflags 35 +#define TARGET_NETBSD_NR_sync 36 +#define TARGET_NETBSD_NR_kill 37 +#define TARGET_NETBSD_NR_compat_43_stat43 38 +#define TARGET_NETBSD_NR_getppid 39 +#define TARGET_NETBSD_NR_compat_43_lstat43 40 +#define TARGET_NETBSD_NR_dup 41 +#define TARGET_NETBSD_NR_pipe 42 +#define TARGET_NETBSD_NR_getegid 43 +#define TARGET_NETBSD_NR_profil 44 +#define TARGET_NETBSD_NR_ktrace 45 +#define TARGET_NETBSD_NR_compat_13_sigaction13 46 +#define TARGET_NETBSD_NR_getgid 47 +#define TARGET_NETBSD_NR_getgid 47 +#define TARGET_NETBSD_NR_compat_13_sigprocmask13 48 +#define TARGET_NETBSD_NR___getlogin 49 +#define TARGET_NETBSD_NR___setlogin 50 +#define TARGET_NETBSD_NR_acct 51 +#define TARGET_NETBSD_NR_compat_13_sigpending13 52 +#define TARGET_NETBSD_NR_compat_13_sigaltstack13 53 +#define TARGET_NETBSD_NR_ioctl 54 +#define TARGET_NETBSD_NR_compat_12_oreboot 55 +#define TARGET_NETBSD_NR_revoke 56 +#define TARGET_NETBSD_NR_symlink 57 +#define TARGET_NETBSD_NR_readlink 58 +#define TARGET_NETBSD_NR_execve 59 +#define TARGET_NETBSD_NR_umask 60 +#define TARGET_NETBSD_NR_chroot 61 +#define TARGET_NETBSD_NR_compat_43_fstat43 62 +#define TARGET_NETBSD_NR_compat_43_ogetkerninfo 63 +#define TARGET_NETBSD_NR_compat_43_ogetpagesize 64 +#define TARGET_NETBSD_NR_compat_12_msync 65 +#define TARGET_NETBSD_NR_vfork 66 +#define TARGET_NETBSD_NR_sbrk 69 +#define TARGET_NETBSD_NR_sstk 70 +#define TARGET_NETBSD_NR_compat_43_ommap 71 +#define TARGET_NETBSD_NR_vadvise 72 +#define TARGET_NETBSD_NR_munmap 73 +#define TARGET_NETBSD_NR_mprotect 74 +#define TARGET_NETBSD_NR_madvise 75 +#define TARGET_NETBSD_NR_mincore 78 +#define TARGET_NETBSD_NR_getgroups 79 +#define TARGET_NETBSD_NR_setgroups 80 +#define TARGET_NETBSD_NR_getpgrp 81 +#define TARGET_NETBSD_NR_setpgid 82 +#define TARGET_NETBSD_NR_setitimer 83 +#define TARGET_NETBSD_NR_compat_43_owait 84 +#define TARGET_NETBSD_NR_compat_12_oswapon 85 +#define TARGET_NETBSD_NR_getitimer 86 +#define TARGET_NETBSD_NR_compat_43_ogethostname 87 +#define TARGET_NETBSD_NR_compat_43_osethostname 88 +#define TARGET_NETBSD_NR_compat_43_ogetdtablesize 89 +#define TARGET_NETBSD_NR_dup2 90 +#define TARGET_NETBSD_NR_fcntl 92 +#define TARGET_NETBSD_NR_select 93 +#define TARGET_NETBSD_NR_fsync 95 +#define TARGET_NETBSD_NR_setpriority 96 +#define TARGET_NETBSD_NR_compat_30_socket 97 +#define TARGET_NETBSD_NR_connect 98 +#define TARGET_NETBSD_NR_compat_43_oaccept 99 +#define TARGET_NETBSD_NR_getpriority 100 +#define TARGET_NETBSD_NR_compat_43_osend 101 +#define TARGET_NETBSD_NR_compat_43_orecv 102 +#define TARGET_NETBSD_NR_compat_13_sigreturn13 103 +#define TARGET_NETBSD_NR_bind 104 +#define TARGET_NETBSD_NR_setsockopt 105 +#define TARGET_NETBSD_NR_listen 106 +#define TARGET_NETBSD_NR_compat_43_osigvec 108 +#define TARGET_NETBSD_NR_compat_43_osigblock 109 +#define TARGET_NETBSD_NR_compat_43_osigsetmask 110 +#define TARGET_NETBSD_NR_compat_13_sigsuspend13 111 +#define TARGET_NETBSD_NR_compat_43_osigstack 112 +#define TARGET_NETBSD_NR_compat_43_orecvmsg 113 +#define TARGET_NETBSD_NR_compat_43_osendmsg 114 +#define TARGET_NETBSD_NR_gettimeofday 116 +#define TARGET_NETBSD_NR_getrusage 117 +#define TARGET_NETBSD_NR_getsockopt 118 +#define TARGET_NETBSD_NR_readv 120 +#define TARGET_NETBSD_NR_writev 121 +#define TARGET_NETBSD_NR_settimeofday 122 +#define TARGET_NETBSD_NR_fchown 123 +#define TARGET_NETBSD_NR_fchmod 124 +#define TARGET_NETBSD_NR_compat_43_orecvfrom 125 +#define TARGET_NETBSD_NR_setreuid 126 +#define TARGET_NETBSD_NR_setregid 127 +#define TARGET_NETBSD_NR_rename 128 +#define TARGET_NETBSD_NR_compat_43_otruncate 129 +#define TARGET_NETBSD_NR_compat_43_oftruncate 130 +#define TARGET_NETBSD_NR_flock 131 +#define TARGET_NETBSD_NR_mkfifo 132 +#define TARGET_NETBSD_NR_sendto 133 +#define TARGET_NETBSD_NR_shutdown 134 +#define TARGET_NETBSD_NR_socketpair 135 +#define TARGET_NETBSD_NR_mkdir 136 +#define TARGET_NETBSD_NR_rmdir 137 +#define TARGET_NETBSD_NR_utimes 138 +#define TARGET_NETBSD_NR_adjtime 140 +#define TARGET_NETBSD_NR_compat_43_ogetpeername 141 +#define TARGET_NETBSD_NR_compat_43_ogethostid 142 +#define TARGET_NETBSD_NR_compat_43_osethostid 143 +#define TARGET_NETBSD_NR_compat_43_ogetrlimit 144 +#define TARGET_NETBSD_NR_compat_43_osetrlimit 145 +#define TARGET_NETBSD_NR_compat_43_okillpg 146 +#define TARGET_NETBSD_NR_setsid 147 +#define TARGET_NETBSD_NR_quotactl 148 +#define TARGET_NETBSD_NR_compat_43_oquota 149 +#define TARGET_NETBSD_NR_compat_43_ogetsockname 150 +#define TARGET_NETBSD_NR_nfssvc 155 +#define TARGET_NETBSD_NR_compat_43_ogetdirentries 156 +#define TARGET_NETBSD_NR_compat_20_statfs 157 +#define TARGET_NETBSD_NR_compat_20_fstatfs 158 +#define TARGET_NETBSD_NR_compat_30_getfh 161 +#define TARGET_NETBSD_NR_compat_09_ogetdomainname 162 +#define TARGET_NETBSD_NR_compat_09_osetdomainname 163 +#define TARGET_NETBSD_NR_compat_09_ouname 164 +#define TARGET_NETBSD_NR_sysarch 165 +#define TARGET_NETBSD_NR_compat_10_osemsys 169 +#define TARGET_NETBSD_NR_compat_10_omsgsys 170 +#define TARGET_NETBSD_NR_compat_10_oshmsys 171 +#define TARGET_NETBSD_NR_pread 173 +#define TARGET_NETBSD_NR_pwrite 174 +#define TARGET_NETBSD_NR_compat_30_ntp_gettime 175 +#define TARGET_NETBSD_NR_ntp_adjtime 176 +#define TARGET_NETBSD_NR_setgid 181 +#define TARGET_NETBSD_NR_setegid 182 +#define TARGET_NETBSD_NR_seteuid 183 +#define TARGET_NETBSD_NR_lfs_bmapv 184 +#define TARGET_NETBSD_NR_lfs_markv 185 +#define TARGET_NETBSD_NR_lfs_segclean 186 +#define TARGET_NETBSD_NR_lfs_segwait 187 +#define TARGET_NETBSD_NR_compat_12_stat12 188 +#define TARGET_NETBSD_NR_compat_12_fstat12 189 +#define TARGET_NETBSD_NR_compat_12_lstat12 190 +#define TARGET_NETBSD_NR_pathconf 191 +#define TARGET_NETBSD_NR_fpathconf 192 +#define TARGET_NETBSD_NR_getrlimit 194 +#define TARGET_NETBSD_NR_setrlimit 195 +#define TARGET_NETBSD_NR_compat_12_getdirentries 196 +#define TARGET_NETBSD_NR_mmap 197 +#define TARGET_NETBSD_NR___syscall 198 +#define TARGET_NETBSD_NR_lseek 199 +#define TARGET_NETBSD_NR_truncate 200 +#define TARGET_NETBSD_NR_ftruncate 201 +#define TARGET_NETBSD_NR___sysctl 202 +#define TARGET_NETBSD_NR_mlock 203 +#define TARGET_NETBSD_NR_munlock 204 +#define TARGET_NETBSD_NR_undelete 205 +#define TARGET_NETBSD_NR_futimes 206 +#define TARGET_NETBSD_NR_getpgid 207 +#define TARGET_NETBSD_NR_reboot 208 +#define TARGET_NETBSD_NR_poll 209 +#define TARGET_NETBSD_NR_compat_14___semctl 220 +#define TARGET_NETBSD_NR_semget 221 +#define TARGET_NETBSD_NR_semop 222 +#define TARGET_NETBSD_NR_semconfig 223 +#define TARGET_NETBSD_NR_compat_14_msgctl 224 +#define TARGET_NETBSD_NR_msgget 225 +#define TARGET_NETBSD_NR_msgsnd 226 +#define TARGET_NETBSD_NR_msgrcv 227 +#define TARGET_NETBSD_NR_shmat 228 +#define TARGET_NETBSD_NR_compat_14_shmctl 229 +#define TARGET_NETBSD_NR_shmdt 230 +#define TARGET_NETBSD_NR_shmget 231 +#define TARGET_NETBSD_NR_clock_gettime 232 +#define TARGET_NETBSD_NR_clock_settime 233 +#define TARGET_NETBSD_NR_clock_getres 234 +#define TARGET_NETBSD_NR_timer_create 235 +#define TARGET_NETBSD_NR_timer_delete 236 +#define TARGET_NETBSD_NR_timer_settime 237 +#define TARGET_NETBSD_NR_timer_gettime 238 +#define TARGET_NETBSD_NR_timer_getoverrun 239 +#define TARGET_NETBSD_NR_nanosleep 240 +#define TARGET_NETBSD_NR_fdatasync 241 +#define TARGET_NETBSD_NR_mlockall 242 +#define TARGET_NETBSD_NR_munlockall 243 +#define TARGET_NETBSD_NR___sigtimedwait 244 +#define TARGET_NETBSD_NR_modctl 246 +#define TARGET_NETBSD_NR__ksem_init 247 +#define TARGET_NETBSD_NR__ksem_open 248 +#define TARGET_NETBSD_NR__ksem_unlink 249 +#define TARGET_NETBSD_NR__ksem_close 250 +#define TARGET_NETBSD_NR__ksem_post 251 +#define TARGET_NETBSD_NR__ksem_wait 252 +#define TARGET_NETBSD_NR__ksem_trywait 253 +#define TARGET_NETBSD_NR__ksem_getvalue 254 +#define TARGET_NETBSD_NR__ksem_destroy 255 +#define TARGET_NETBSD_NR_mq_open 257 +#define TARGET_NETBSD_NR_mq_close 258 +#define TARGET_NETBSD_NR_mq_unlink 259 +#define TARGET_NETBSD_NR_mq_getattr 260 +#define TARGET_NETBSD_NR_mq_setattr 261 +#define TARGET_NETBSD_NR_mq_notify 262 +#define TARGET_NETBSD_NR_mq_send 263 +#define TARGET_NETBSD_NR_mq_receive 264 +#define TARGET_NETBSD_NR_mq_timedsend 265 +#define TARGET_NETBSD_NR_mq_timedreceive 266 +#define TARGET_NETBSD_NR___posix_rename 270 +#define TARGET_NETBSD_NR_swapctl 271 +#define TARGET_NETBSD_NR_compat_30_getdents 272 +#define TARGET_NETBSD_NR_minherit 273 +#define TARGET_NETBSD_NR_lchmod 274 +#define TARGET_NETBSD_NR_lchown 275 +#define TARGET_NETBSD_NR_lutimes 276 +#define TARGET_NETBSD_NR___msync13 277 +#define TARGET_NETBSD_NR_compat_30___stat13 278 +#define TARGET_NETBSD_NR_compat_30___fstat13 279 +#define TARGET_NETBSD_NR_compat_30___lstat13 280 +#define TARGET_NETBSD_NR___sigaltstack14 281 +#define TARGET_NETBSD_NR___vfork14 282 +#define TARGET_NETBSD_NR___posix_chown 283 +#define TARGET_NETBSD_NR___posix_fchown 284 +#define TARGET_NETBSD_NR___posix_lchown 285 +#define TARGET_NETBSD_NR_getsid 286 +#define TARGET_NETBSD_NR___clone 287 +#define TARGET_NETBSD_NR_fktrace 288 +#define TARGET_NETBSD_NR_preadv 289 +#define TARGET_NETBSD_NR_pwritev 290 +#define TARGET_NETBSD_NR_compat_16___sigaction14 291 +#define TARGET_NETBSD_NR___sigpending14 292 +#define TARGET_NETBSD_NR___sigprocmask14 293 +#define TARGET_NETBSD_NR___sigsuspend14 294 +#define TARGET_NETBSD_NR_compat_16___sigreturn14 295 +#define TARGET_NETBSD_NR___getcwd 296 +#define TARGET_NETBSD_NR_fchroot 297 +#define TARGET_NETBSD_NR_compat_30_fhopen 298 +#define TARGET_NETBSD_NR_compat_30_fhstat 299 +#define TARGET_NETBSD_NR_compat_20_fhstatfs 300 +#define TARGET_NETBSD_NR_____semctl13 301 +#define TARGET_NETBSD_NR___msgctl13 302 +#define TARGET_NETBSD_NR___shmctl13 303 +#define TARGET_NETBSD_NR_lchflags 304 +#define TARGET_NETBSD_NR_issetugid 305 +#define TARGET_NETBSD_NR_utrace 306 +#define TARGET_NETBSD_NR_getcontext 307 +#define TARGET_NETBSD_NR_setcontext 308 +#define TARGET_NETBSD_NR__lwp_create 309 +#define TARGET_NETBSD_NR__lwp_exit 310 +#define TARGET_NETBSD_NR__lwp_self 311 +#define TARGET_NETBSD_NR__lwp_wait 312 +#define TARGET_NETBSD_NR__lwp_suspend 313 +#define TARGET_NETBSD_NR__lwp_continue 314 +#define TARGET_NETBSD_NR__lwp_wakeup 315 +#define TARGET_NETBSD_NR__lwp_getprivate 316 +#define TARGET_NETBSD_NR__lwp_setprivate 317 +#define TARGET_NETBSD_NR__lwp_kill 318 +#define TARGET_NETBSD_NR__lwp_detach 319 +#define TARGET_NETBSD_NR__lwp_park 320 +#define TARGET_NETBSD_NR__lwp_unpark 321 +#define TARGET_NETBSD_NR__lwp_unpark_all 322 +#define TARGET_NETBSD_NR__lwp_setname 323 +#define TARGET_NETBSD_NR__lwp_getname 324 +#define TARGET_NETBSD_NR__lwp_ctl 325 +#define TARGET_NETBSD_NR_sa_register 330 +#define TARGET_NETBSD_NR_sa_stacks 331 +#define TARGET_NETBSD_NR_sa_enable 332 +#define TARGET_NETBSD_NR_sa_setconcurrency 333 +#define TARGET_NETBSD_NR_sa_yield 334 +#define TARGET_NETBSD_NR_sa_preempt 335 +#define TARGET_NETBSD_NR_sa_unblockyield 336 +#define TARGET_NETBSD_NR___sigaction_sigtramp 340 +#define TARGET_NETBSD_NR_pmc_get_info 341 +#define TARGET_NETBSD_NR_pmc_control 342 +#define TARGET_NETBSD_NR_rasctl 343 +#define TARGET_NETBSD_NR_kqueue 344 +#define TARGET_NETBSD_NR_kevent 345 +#define TARGET_NETBSD_NR__sched_setparam 346 +#define TARGET_NETBSD_NR__sched_getparam 347 +#define TARGET_NETBSD_NR__sched_setaffinity 348 +#define TARGET_NETBSD_NR__sched_getaffinity 349 +#define TARGET_NETBSD_NR_sched_yield 350 +#define TARGET_NETBSD_NR_fsync_range 354 +#define TARGET_NETBSD_NR_uuidgen 355 +#define TARGET_NETBSD_NR_getvfsstat 356 +#define TARGET_NETBSD_NR_statvfs1 357 +#define TARGET_NETBSD_NR_fstatvfs1 358 +#define TARGET_NETBSD_NR_compat_30_fhstatvfs1 359 +#define TARGET_NETBSD_NR_extattrctl 360 +#define TARGET_NETBSD_NR_extattr_set_file 361 +#define TARGET_NETBSD_NR_extattr_get_file 362 +#define TARGET_NETBSD_NR_extattr_delete_file 363 +#define TARGET_NETBSD_NR_extattr_set_fd 364 +#define TARGET_NETBSD_NR_extattr_get_fd 365 +#define TARGET_NETBSD_NR_extattr_delete_fd 366 +#define TARGET_NETBSD_NR_extattr_set_link 367 +#define TARGET_NETBSD_NR_extattr_get_link 368 +#define TARGET_NETBSD_NR_extattr_delete_link 369 +#define TARGET_NETBSD_NR_extattr_list_fd 370 +#define TARGET_NETBSD_NR_extattr_list_file 371 +#define TARGET_NETBSD_NR_extattr_list_link 372 +#define TARGET_NETBSD_NR_pselect 373 +#define TARGET_NETBSD_NR_pollts 374 +#define TARGET_NETBSD_NR_setxattr 375 +#define TARGET_NETBSD_NR_lsetxattr 376 +#define TARGET_NETBSD_NR_fsetxattr 377 +#define TARGET_NETBSD_NR_getxattr 378 +#define TARGET_NETBSD_NR_lgetxattr 379 +#define TARGET_NETBSD_NR_fgetxattr 380 +#define TARGET_NETBSD_NR_listxattr 381 +#define TARGET_NETBSD_NR_llistxattr 382 +#define TARGET_NETBSD_NR_flistxattr 383 +#define TARGET_NETBSD_NR_removexattr 384 +#define TARGET_NETBSD_NR_lremovexattr 385 +#define TARGET_NETBSD_NR_fremovexattr 386 +#define TARGET_NETBSD_NR___stat30 387 +#define TARGET_NETBSD_NR___fstat30 388 +#define TARGET_NETBSD_NR___lstat30 389 +#define TARGET_NETBSD_NR___getdents30 390 +#define TARGET_NETBSD_NR_compat_30___fhstat30 392 +#define TARGET_NETBSD_NR___ntp_gettime30 393 +#define TARGET_NETBSD_NR___socket30 394 +#define TARGET_NETBSD_NR___getfh30 395 +#define TARGET_NETBSD_NR___fhopen40 396 +#define TARGET_NETBSD_NR___fhstatvfs140 397 +#define TARGET_NETBSD_NR___fhstat40 398 +#define TARGET_NETBSD_NR_aio_cancel 399 +#define TARGET_NETBSD_NR_aio_error 400 +#define TARGET_NETBSD_NR_aio_fsync 401 +#define TARGET_NETBSD_NR_aio_read 402 +#define TARGET_NETBSD_NR_aio_return 403 +#define TARGET_NETBSD_NR_aio_suspend 404 +#define TARGET_NETBSD_NR_aio_write 405 +#define TARGET_NETBSD_NR_lio_listio 406 +#define TARGET_NETBSD_NR___mount50 410 +#define TARGET_NETBSD_NR_mremap 411 +#define TARGET_NETBSD_NR_pset_create 412 +#define TARGET_NETBSD_NR_pset_destroy 413 +#define TARGET_NETBSD_NR_pset_assign 414 +#define TARGET_NETBSD_NR__pset_bind 415 +#define TARGET_NETBSD_NR___posix_fadvise50 416 diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/openbsd/strace.list /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/openbsd/strace.list --- qemu-0.9.1/bsd-user/openbsd/strace.list 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/openbsd/strace.list 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,187 @@ +{ TARGET_OPENBSD_NR___getcwd, "__getcwd", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR___semctl, "__semctl", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR___syscall, "__syscall", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR___sysctl, "__sysctl", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_accept, "accept", "%s(%d,%#x,%#x)", NULL, NULL }, +{ TARGET_OPENBSD_NR_access, "access", "%s(\"%s\",%#o)", NULL, NULL }, +{ TARGET_OPENBSD_NR_acct, "acct", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_adjfreq, "adjfreq", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_adjtime, "adjtime", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_bind, "bind", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_break, "break", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_chdir, "chdir", "%s(\"%s\")", NULL, NULL }, +{ TARGET_OPENBSD_NR_chflags, "chflags", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_chmod, "chmod", "%s(\"%s\",%#o)", NULL, NULL }, +{ TARGET_OPENBSD_NR_chown, "chown", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_chroot, "chroot", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_clock_getres, "clock_getres", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_clock_gettime, "clock_gettime", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_clock_settime, "clock_settime", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_close, "close", "%s(%d)", NULL, NULL }, +{ TARGET_OPENBSD_NR_closefrom, "closefrom", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_connect, "connect", "%s(%d,%#x,%d)", NULL, NULL }, +{ TARGET_OPENBSD_NR_dup, "dup", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_dup2, "dup2", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_execve, "execve", NULL, print_execve, NULL }, +{ TARGET_OPENBSD_NR_exit, "exit", "%s(%d)\n", NULL, NULL }, +{ TARGET_OPENBSD_NR_fchdir, "fchdir", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_fchflags, "fchflags", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_fchmod, "fchmod", "%s(%d,%#o)", NULL, NULL }, +{ TARGET_OPENBSD_NR_fchown, "fchown", "%s(\"%s\",%d,%d)", NULL, NULL }, +{ TARGET_OPENBSD_NR_fcntl, "fcntl", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_fhopen, "fhopen", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_fhstat, "fhstat", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_fhstatfs, "fhstatfs", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_flock, "flock", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_fork, "fork", "%s()", NULL, NULL }, +{ TARGET_OPENBSD_NR_fpathconf, "fpathconf", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_fstat, "fstat", "%s(%d,%p)", NULL, NULL }, +{ TARGET_OPENBSD_NR_fstatfs, "fstatfs", "%s(%d,%p)", NULL, NULL }, +{ TARGET_OPENBSD_NR_fsync, "fsync", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_futimes, "futimes", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_getdirentries, "getdirentries", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_getegid, "getegid", "%s()", NULL, NULL }, +{ TARGET_OPENBSD_NR_geteuid, "geteuid", "%s()", NULL, NULL }, +{ TARGET_OPENBSD_NR_getfh, "getfh", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_getfsstat, "getfsstat", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_getgid, "getgid", "%s()", NULL, NULL }, +{ TARGET_OPENBSD_NR_getgroups, "getgroups", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_getitimer, "getitimer", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_getlogin, "getlogin", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_getpeereid, "getpeereid", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_getpeername, "getpeername", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_getpgid, "getpgid", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_getpgrp, "getpgrp", "%s()", NULL, NULL }, +{ TARGET_OPENBSD_NR_getpid, "getpid", "%s()", NULL, NULL }, +{ TARGET_OPENBSD_NR_getppid, "getppid", "%s()", NULL, NULL }, +{ TARGET_OPENBSD_NR_getpriority, "getpriority", "%s(%#x,%#x)", NULL, NULL }, +{ TARGET_OPENBSD_NR_getresgid, "getresgid", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_getresuid, "getresuid", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_getrlimit, "getrlimit", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_getrusage, "getrusage", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_getsid, "getsid", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_getsockname, "getsockname", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_getsockopt, "getsockopt", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_getthrid, "getthrid", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_gettimeofday, "gettimeofday", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_getuid, "getuid", "%s()", NULL, NULL }, +{ TARGET_OPENBSD_NR_ioctl, "ioctl", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_issetugid, "issetugid", "%s()", NULL, NULL }, +{ TARGET_OPENBSD_NR_kevent, "kevent", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_kill, "kill", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_kqueue, "kqueue", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_ktrace, "ktrace", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_lchown, "lchown", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_lfs_bmapv, "lfs_bmapv", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_lfs_markv, "lfs_markv", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_lfs_segclean, "lfs_segclean", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_lfs_segwait, "lfs_segwait", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_link, "link", "%s(\"%s\",\"%s\")", NULL, NULL }, +{ TARGET_OPENBSD_NR_listen, "listen", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_lseek, "lseek", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_lstat, "lstat", "%s(\"%s\",%p)", NULL, NULL }, +{ TARGET_OPENBSD_NR_madvise, "madvise", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_mincore, "mincore", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_minherit, "minherit", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_mkdir, "mkdir", "%s(\"%s\",%#o)", NULL, NULL }, +{ TARGET_OPENBSD_NR_mkfifo, "mkfifo", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_mknod, "mknod", "%s(\"%s\",%#o,%#x)", NULL, NULL }, +{ TARGET_OPENBSD_NR_mlock, "mlock", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_mlockall, "mlockall", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_mmap, "mmap", NULL, NULL, print_syscall_ret_addr }, +{ TARGET_OPENBSD_NR_mount, "mount", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_mprotect, "mprotect", "%s(%#x,%#x,%d)", NULL, NULL }, +{ TARGET_OPENBSD_NR_mquery, "mquery", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_msgctl, "msgctl", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_msgget, "msgget", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_msgrcv, "msgrcv", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_msgsnd, "msgsnd", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_msync, "msync", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_munlock, "munlock", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_munlockall, "munlockall", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_munmap, "munmap", "%s(%p,%d)", NULL, NULL }, +{ TARGET_OPENBSD_NR_nanosleep, "nanosleep", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_nfssvc, "nfssvc", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_open, "open", "%s(\"%s\",%#x,%#o)", NULL, NULL }, +{ TARGET_OPENBSD_NR_opipe, "opipe", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_osigaltstack, "osigaltstack", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_pathconf, "pathconf", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_pipe, "pipe", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_poll, "poll", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_pread, "pread", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_preadv, "preadv", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_profil, "profil", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_ptrace, "ptrace", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_pwrite, "pwrite", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_pwritev, "pwritev", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_quotactl, "quotactl", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_read, "read", "%s(%d,%#x,%d)", NULL, NULL }, +{ TARGET_OPENBSD_NR_readlink, "readlink", "%s(\"%s\",%p,%d)", NULL, NULL }, +{ TARGET_OPENBSD_NR_readv, "readv", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_reboot, "reboot", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_recvfrom, "recvfrom", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_recvmsg, "recvmsg", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_rename, "rename", "%s(\"%s\",\"%s\")", NULL, NULL }, +{ TARGET_OPENBSD_NR_revoke, "revoke", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_rfork, "rfork", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_rmdir, "rmdir", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_sbrk, "sbrk", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_sched_yield, "sched_yield", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_select, "select", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_semget, "semget", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_semop, "semop", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_sendmsg, "sendmsg", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_sendto, "sendto", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_setegid, "setegid", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_seteuid, "seteuid", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_setgid, "setgid", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_setgroups, "setgroups", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_setitimer, "setitimer", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_setlogin, "setlogin", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_setpgid, "setpgid", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_setpriority, "setpriority", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_setregid, "setregid", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_setresgid, "setresgid", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_setresuid, "setresuid", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_setreuid, "setreuid", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_setrlimit, "setrlimit", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_setsid, "setsid", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_setsockopt, "setsockopt", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_settimeofday, "settimeofday", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_setuid, "setuid", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_shmat, "shmat", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_shmctl, "shmctl", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_shmdt, "shmdt", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_shmget, "shmget", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_shutdown, "shutdown", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_sigaction, "sigaction", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_sigaltstack, "sigaltstack", "%s(%p,%p)", NULL, NULL }, +{ TARGET_OPENBSD_NR_sigpending, "sigpending", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_sigprocmask, "sigprocmask", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_sigreturn, "sigreturn", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_sigsuspend, "sigsuspend", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_socket, "socket", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_socketpair, "socketpair", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_sstk, "sstk", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_stat, "stat", "%s(\"%s\",%p)", NULL, NULL }, +{ TARGET_OPENBSD_NR_statfs, "statfs", "%s(\"%s\",%p)", NULL, NULL }, +{ TARGET_OPENBSD_NR_swapctl, "swapctl", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_symlink, "symlink", "%s(\"%s\",\"%s\")", NULL, NULL }, +{ TARGET_OPENBSD_NR_sync, "sync", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_sysarch, "sysarch", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_syscall, "syscall", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_threxit, "threxit", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_thrsigdivert, "thrsigdivert", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_thrsleep, "thrsleep", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_thrwakeup, "thrwakeup", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_truncate, "truncate", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_umask, "umask", "%s(%#o)", NULL, NULL }, +{ TARGET_OPENBSD_NR_unlink, "unlink", "%s(\"%s\")", NULL, NULL }, +{ TARGET_OPENBSD_NR_unmount, "unmount", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_utimes, "utimes", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_vfork, "vfork", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_wait4, "wait4", NULL, NULL, NULL }, +{ TARGET_OPENBSD_NR_write, "write", "%s(%d,%#x,%d)", NULL, NULL }, +{ TARGET_OPENBSD_NR_writev, "writev", "%s(%d,%p,%#x)", NULL, NULL }, +{ TARGET_OPENBSD_NR_xfspioctl, "xfspioctl", NULL, NULL, NULL }, diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/openbsd/syscall_nr.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/openbsd/syscall_nr.h --- qemu-0.9.1/bsd-user/openbsd/syscall_nr.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/openbsd/syscall_nr.h 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,195 @@ +/* $OpenBSD: syscall.h,v 1.101 2008/03/16 19:43:41 otto Exp $ */ + +/* + * System call numbers. + * + * created from; OpenBSD: syscalls.master,v 1.90 2008/03/16 19:42:57 otto Exp + */ + +#define TARGET_OPENBSD_NR_syscall 0 +#define TARGET_OPENBSD_NR_exit 1 +#define TARGET_OPENBSD_NR_fork 2 +#define TARGET_OPENBSD_NR_read 3 +#define TARGET_OPENBSD_NR_write 4 +#define TARGET_OPENBSD_NR_open 5 +#define TARGET_OPENBSD_NR_close 6 +#define TARGET_OPENBSD_NR_wait4 7 +#define TARGET_OPENBSD_NR_link 9 +#define TARGET_OPENBSD_NR_unlink 10 +#define TARGET_OPENBSD_NR_chdir 12 +#define TARGET_OPENBSD_NR_fchdir 13 +#define TARGET_OPENBSD_NR_mknod 14 +#define TARGET_OPENBSD_NR_chmod 15 +#define TARGET_OPENBSD_NR_chown 16 +#define TARGET_OPENBSD_NR_break 17 +#define TARGET_OPENBSD_NR_getpid 20 +#define TARGET_OPENBSD_NR_mount 21 +#define TARGET_OPENBSD_NR_unmount 22 +#define TARGET_OPENBSD_NR_setuid 23 +#define TARGET_OPENBSD_NR_getuid 24 +#define TARGET_OPENBSD_NR_geteuid 25 +#define TARGET_OPENBSD_NR_ptrace 26 +#define TARGET_OPENBSD_NR_recvmsg 27 +#define TARGET_OPENBSD_NR_sendmsg 28 +#define TARGET_OPENBSD_NR_recvfrom 29 +#define TARGET_OPENBSD_NR_accept 30 +#define TARGET_OPENBSD_NR_getpeername 31 +#define TARGET_OPENBSD_NR_getsockname 32 +#define TARGET_OPENBSD_NR_access 33 +#define TARGET_OPENBSD_NR_chflags 34 +#define TARGET_OPENBSD_NR_fchflags 35 +#define TARGET_OPENBSD_NR_sync 36 +#define TARGET_OPENBSD_NR_kill 37 +#define TARGET_OPENBSD_NR_getppid 39 +#define TARGET_OPENBSD_NR_dup 41 +#define TARGET_OPENBSD_NR_opipe 42 +#define TARGET_OPENBSD_NR_getegid 43 +#define TARGET_OPENBSD_NR_profil 44 +#define TARGET_OPENBSD_NR_ktrace 45 +#define TARGET_OPENBSD_NR_sigaction 46 +#define TARGET_OPENBSD_NR_getgid 47 +#define TARGET_OPENBSD_NR_sigprocmask 48 +#define TARGET_OPENBSD_NR_getlogin 49 +#define TARGET_OPENBSD_NR_setlogin 50 +#define TARGET_OPENBSD_NR_acct 51 +#define TARGET_OPENBSD_NR_sigpending 52 +#define TARGET_OPENBSD_NR_osigaltstack 53 +#define TARGET_OPENBSD_NR_ioctl 54 +#define TARGET_OPENBSD_NR_reboot 55 +#define TARGET_OPENBSD_NR_revoke 56 +#define TARGET_OPENBSD_NR_symlink 57 +#define TARGET_OPENBSD_NR_readlink 58 +#define TARGET_OPENBSD_NR_execve 59 +#define TARGET_OPENBSD_NR_umask 60 +#define TARGET_OPENBSD_NR_chroot 61 +#define TARGET_OPENBSD_NR_vfork 66 +#define TARGET_OPENBSD_NR_sbrk 69 +#define TARGET_OPENBSD_NR_sstk 70 +#define TARGET_OPENBSD_NR_munmap 73 +#define TARGET_OPENBSD_NR_mprotect 74 +#define TARGET_OPENBSD_NR_madvise 75 +#define TARGET_OPENBSD_NR_mincore 78 +#define TARGET_OPENBSD_NR_getgroups 79 +#define TARGET_OPENBSD_NR_setgroups 80 +#define TARGET_OPENBSD_NR_getpgrp 81 +#define TARGET_OPENBSD_NR_setpgid 82 +#define TARGET_OPENBSD_NR_setitimer 83 +#define TARGET_OPENBSD_NR_getitimer 86 +#define TARGET_OPENBSD_NR_dup2 90 +#define TARGET_OPENBSD_NR_fcntl 92 +#define TARGET_OPENBSD_NR_select 93 +#define TARGET_OPENBSD_NR_fsync 95 +#define TARGET_OPENBSD_NR_setpriority 96 +#define TARGET_OPENBSD_NR_socket 97 +#define TARGET_OPENBSD_NR_connect 98 +#define TARGET_OPENBSD_NR_getpriority 100 +#define TARGET_OPENBSD_NR_sigreturn 103 +#define TARGET_OPENBSD_NR_bind 104 +#define TARGET_OPENBSD_NR_setsockopt 105 +#define TARGET_OPENBSD_NR_listen 106 +#define TARGET_OPENBSD_NR_sigsuspend 111 +#define TARGET_OPENBSD_NR_gettimeofday 116 +#define TARGET_OPENBSD_NR_getrusage 117 +#define TARGET_OPENBSD_NR_getsockopt 118 +#define TARGET_OPENBSD_NR_readv 120 +#define TARGET_OPENBSD_NR_writev 121 +#define TARGET_OPENBSD_NR_settimeofday 122 +#define TARGET_OPENBSD_NR_fchown 123 +#define TARGET_OPENBSD_NR_fchmod 124 +#define TARGET_OPENBSD_NR_setreuid 126 +#define TARGET_OPENBSD_NR_setregid 127 +#define TARGET_OPENBSD_NR_rename 128 +#define TARGET_OPENBSD_NR_flock 131 +#define TARGET_OPENBSD_NR_mkfifo 132 +#define TARGET_OPENBSD_NR_sendto 133 +#define TARGET_OPENBSD_NR_shutdown 134 +#define TARGET_OPENBSD_NR_socketpair 135 +#define TARGET_OPENBSD_NR_mkdir 136 +#define TARGET_OPENBSD_NR_rmdir 137 +#define TARGET_OPENBSD_NR_utimes 138 +#define TARGET_OPENBSD_NR_adjtime 140 +#define TARGET_OPENBSD_NR_setsid 147 +#define TARGET_OPENBSD_NR_quotactl 148 +#define TARGET_OPENBSD_NR_nfssvc 155 +#define TARGET_OPENBSD_NR_getfh 161 +#define TARGET_OPENBSD_NR_sysarch 165 +#define TARGET_OPENBSD_NR_pread 173 +#define TARGET_OPENBSD_NR_pwrite 174 +#define TARGET_OPENBSD_NR_setgid 181 +#define TARGET_OPENBSD_NR_setegid 182 +#define TARGET_OPENBSD_NR_seteuid 183 +#define TARGET_OPENBSD_NR_lfs_bmapv 184 +#define TARGET_OPENBSD_NR_lfs_markv 185 +#define TARGET_OPENBSD_NR_lfs_segclean 186 +#define TARGET_OPENBSD_NR_lfs_segwait 187 +#define TARGET_OPENBSD_NR_pathconf 191 +#define TARGET_OPENBSD_NR_fpathconf 192 +#define TARGET_OPENBSD_NR_swapctl 193 +#define TARGET_OPENBSD_NR_getrlimit 194 +#define TARGET_OPENBSD_NR_setrlimit 195 +#define TARGET_OPENBSD_NR_getdirentries 196 +#define TARGET_OPENBSD_NR_mmap 197 +#define TARGET_OPENBSD_NR___syscall 198 +#define TARGET_OPENBSD_NR_lseek 199 +#define TARGET_OPENBSD_NR_truncate 200 +#define TARGET_OPENBSD_NR_ftruncate 201 +#define TARGET_OPENBSD_NR___sysctl 202 +#define TARGET_OPENBSD_NR_mlock 203 +#define TARGET_OPENBSD_NR_munlock 204 +#define TARGET_OPENBSD_NR_futimes 206 +#define TARGET_OPENBSD_NR_getpgid 207 +#define TARGET_OPENBSD_NR_xfspioctl 208 +#define TARGET_OPENBSD_NR_semget 221 +#define TARGET_OPENBSD_NR_msgget 225 +#define TARGET_OPENBSD_NR_msgsnd 226 +#define TARGET_OPENBSD_NR_msgrcv 227 +#define TARGET_OPENBSD_NR_shmat 228 +#define TARGET_OPENBSD_NR_shmdt 230 +#define TARGET_OPENBSD_NR_clock_gettime 232 +#define TARGET_OPENBSD_NR_clock_settime 233 +#define TARGET_OPENBSD_NR_clock_getres 234 +#define TARGET_OPENBSD_NR_nanosleep 240 +#define TARGET_OPENBSD_NR_minherit 250 +#define TARGET_OPENBSD_NR_rfork 251 +#define TARGET_OPENBSD_NR_poll 252 +#define TARGET_OPENBSD_NR_issetugid 253 +#define TARGET_OPENBSD_NR_lchown 254 +#define TARGET_OPENBSD_NR_getsid 255 +#define TARGET_OPENBSD_NR_msync 256 +#define TARGET_OPENBSD_NR_pipe 263 +#define TARGET_OPENBSD_NR_fhopen 264 +#define TARGET_OPENBSD_NR_preadv 267 +#define TARGET_OPENBSD_NR_pwritev 268 +#define TARGET_OPENBSD_NR_kqueue 269 +#define TARGET_OPENBSD_NR_kevent 270 +#define TARGET_OPENBSD_NR_mlockall 271 +#define TARGET_OPENBSD_NR_munlockall 272 +#define TARGET_OPENBSD_NR_getpeereid 273 +#define TARGET_OPENBSD_NR_getresuid 281 +#define TARGET_OPENBSD_NR_setresuid 282 +#define TARGET_OPENBSD_NR_getresgid 283 +#define TARGET_OPENBSD_NR_setresgid 284 +#define TARGET_OPENBSD_NR_mquery 286 +#define TARGET_OPENBSD_NR_closefrom 287 +#define TARGET_OPENBSD_NR_sigaltstack 288 +#define TARGET_OPENBSD_NR_shmget 289 +#define TARGET_OPENBSD_NR_semop 290 +#define TARGET_OPENBSD_NR_stat 291 +#define TARGET_OPENBSD_NR_fstat 292 +#define TARGET_OPENBSD_NR_lstat 293 +#define TARGET_OPENBSD_NR_fhstat 294 +#define TARGET_OPENBSD_NR___semctl 295 +#define TARGET_OPENBSD_NR_shmctl 296 +#define TARGET_OPENBSD_NR_msgctl 297 +#define TARGET_OPENBSD_NR_sched_yield 298 +#define TARGET_OPENBSD_NR_getthrid 299 +#define TARGET_OPENBSD_NR_thrsleep 300 +#define TARGET_OPENBSD_NR_thrwakeup 301 +#define TARGET_OPENBSD_NR_threxit 302 +#define TARGET_OPENBSD_NR_thrsigdivert 303 +#define TARGET_OPENBSD_NR___getcwd 304 +#define TARGET_OPENBSD_NR_adjfreq 305 +#define TARGET_OPENBSD_NR_getfsstat 306 +#define TARGET_OPENBSD_NR_statfs 307 +#define TARGET_OPENBSD_NR_fstatfs 308 +#define TARGET_OPENBSD_NR_fhstatfs 309 diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/path.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/path.c --- qemu-0.9.1/bsd-user/path.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/path.c 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,163 @@ +/* Code to mangle pathnames into those matching a given prefix. + eg. open("/lib/foo.so") => open("/usr/gnemul/i386-linux/lib/foo.so"); + + The assumption is that this area does not change. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include "qemu.h" +#include "qemu-common.h" + +struct pathelem +{ + /* Name of this, eg. lib */ + char *name; + /* Full path name, eg. /usr/gnemul/x86-linux/lib. */ + char *pathname; + struct pathelem *parent; + /* Children */ + unsigned int num_entries; + struct pathelem *entries[0]; +}; + +static struct pathelem *base; + +/* First N chars of S1 match S2, and S2 is N chars long. */ +static int strneq(const char *s1, unsigned int n, const char *s2) +{ + unsigned int i; + + for (i = 0; i < n; i++) + if (s1[i] != s2[i]) + return 0; + return s2[i] == 0; +} + +static struct pathelem *add_entry(struct pathelem *root, const char *name); + +static struct pathelem *new_entry(const char *root, + struct pathelem *parent, + const char *name) +{ + struct pathelem *new = malloc(sizeof(*new)); + new->name = strdup(name); + asprintf(&new->pathname, "%s/%s", root, name); + new->num_entries = 0; + return new; +} + +#define streq(a,b) (strcmp((a), (b)) == 0) + +static struct pathelem *add_dir_maybe(struct pathelem *path) +{ + DIR *dir; + + if ((dir = opendir(path->pathname)) != NULL) { + struct dirent *dirent; + + while ((dirent = readdir(dir)) != NULL) { + if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){ + path = add_entry(path, dirent->d_name); + } + } + closedir(dir); + } + return path; +} + +static struct pathelem *add_entry(struct pathelem *root, const char *name) +{ + root->num_entries++; + + root = realloc(root, sizeof(*root) + + sizeof(root->entries[0])*root->num_entries); + + root->entries[root->num_entries-1] = new_entry(root->pathname, root, name); + root->entries[root->num_entries-1] + = add_dir_maybe(root->entries[root->num_entries-1]); + return root; +} + +/* This needs to be done after tree is stabilized (ie. no more reallocs!). */ +static void set_parents(struct pathelem *child, struct pathelem *parent) +{ + unsigned int i; + + child->parent = parent; + for (i = 0; i < child->num_entries; i++) + set_parents(child->entries[i], child); +} + +/* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */ +static const char * +follow_path(const struct pathelem *cursor, const char *name) +{ + unsigned int i, namelen; + + name += strspn(name, "/"); + namelen = strcspn(name, "/"); + + if (namelen == 0) + return cursor->pathname; + + if (strneq(name, namelen, "..")) + return follow_path(cursor->parent, name + namelen); + + if (strneq(name, namelen, ".")) + return follow_path(cursor, name + namelen); + + for (i = 0; i < cursor->num_entries; i++) + if (strneq(name, namelen, cursor->entries[i]->name)) + return follow_path(cursor->entries[i], name + namelen); + + /* Not found */ + return NULL; +} + +void init_paths(const char *prefix) +{ + char pref_buf[PATH_MAX]; + + if (prefix[0] == '\0' || + !strcmp(prefix, "/")) + return; + + if (prefix[0] != '/') { + char *cwd = getcwd(NULL, 0); + size_t pref_buf_len = sizeof(pref_buf); + + if (!cwd) + abort(); + pstrcpy(pref_buf, sizeof(pref_buf), cwd); + pstrcat(pref_buf, pref_buf_len, "/"); + pstrcat(pref_buf, pref_buf_len, prefix); + free(cwd); + } else + pstrcpy(pref_buf, sizeof(pref_buf), prefix + 1); + + base = new_entry("", NULL, pref_buf); + base = add_dir_maybe(base); + if (base->num_entries == 0) { + free (base); + base = NULL; + } else { + set_parents(base, base); + } +} + +/* Look for path in emulation dir, otherwise return name. */ +const char *path(const char *name) +{ + /* Only do absolute paths: quick and dirty, but should mostly be OK. + Could do relative by tracking cwd. */ + if (!base || name[0] != '/') + return name; + + return follow_path(base, name) ?: name; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/qemu.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/qemu.h --- qemu-0.9.1/bsd-user/qemu.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/qemu.h 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,405 @@ +#ifndef QEMU_H +#define QEMU_H + +#include +#include + +#include "cpu.h" + +#undef DEBUG_REMAP +#ifdef DEBUG_REMAP +#include +#endif /* DEBUG_REMAP */ + +#ifdef TARGET_ABI32 +typedef uint32_t abi_ulong; +typedef int32_t abi_long; +#define TARGET_ABI_FMT_lx "%08x" +#define TARGET_ABI_FMT_ld "%d" +#define TARGET_ABI_FMT_lu "%u" +#define TARGET_ABI_BITS 32 +#else +typedef target_ulong abi_ulong; +typedef target_long abi_long; +#define TARGET_ABI_FMT_lx TARGET_FMT_lx +#define TARGET_ABI_FMT_ld TARGET_FMT_ld +#define TARGET_ABI_FMT_lu TARGET_FMT_lu +#define TARGET_ABI_BITS TARGET_LONG_BITS +/* for consistency, define ABI32 too */ +#if TARGET_ABI_BITS == 32 +#define TARGET_ABI32 1 +#endif +#endif + +enum BSDType { + target_freebsd, + target_netbsd, + target_openbsd, +}; + +#include "syscall_defs.h" +#include "syscall.h" +#include "target_signal.h" +#include "gdbstub.h" + +#if defined(USE_NPTL) +#define THREAD __thread +#else +#define THREAD +#endif + +/* This struct is used to hold certain information about the image. + * Basically, it replicates in user space what would be certain + * task_struct fields in the kernel + */ +struct image_info { + abi_ulong load_addr; + abi_ulong start_code; + abi_ulong end_code; + abi_ulong start_data; + abi_ulong end_data; + abi_ulong start_brk; + abi_ulong brk; + abi_ulong start_mmap; + abi_ulong mmap; + abi_ulong rss; + abi_ulong start_stack; + abi_ulong entry; + abi_ulong code_offset; + abi_ulong data_offset; + char **host_argv; + int personality; +}; + +#define MAX_SIGQUEUE_SIZE 1024 + +struct sigqueue { + struct sigqueue *next; + //target_siginfo_t info; +}; + +struct emulated_sigtable { + int pending; /* true if signal is pending */ + struct sigqueue *first; + struct sigqueue info; /* in order to always have memory for the + first signal, we put it here */ +}; + +/* NOTE: we force a big alignment so that the stack stored after is + aligned too */ +typedef struct TaskState { + struct TaskState *next; + int used; /* non zero if used */ + struct image_info *info; + + struct emulated_sigtable sigtab[TARGET_NSIG]; + struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ + struct sigqueue *first_free; /* first free siginfo queue entry */ + int signal_pending; /* non zero if a signal may be pending */ + + uint8_t stack[0]; +} __attribute__((aligned(16))) TaskState; + +void init_task_state(TaskState *ts); +extern const char *qemu_uname_release; + +/* ??? See if we can avoid exposing so much of the loader internals. */ +/* + * MAX_ARG_PAGES defines the number of pages allocated for arguments + * and envelope for the new program. 32 should suffice, this gives + * a maximum env+arg of 128kB w/4KB pages! + */ +#define MAX_ARG_PAGES 32 + +/* + * This structure is used to hold the arguments that are + * used when loading binaries. + */ +struct linux_binprm { + char buf[128]; + void *page[MAX_ARG_PAGES]; + abi_ulong p; + int fd; + int e_uid, e_gid; + int argc, envc; + char **argv; + char **envp; + char * filename; /* Name of binary */ +}; + +void do_init_thread(struct target_pt_regs *regs, struct image_info *infop); +abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, + abi_ulong stringp, int push_ptr); +int loader_exec(const char * filename, char ** argv, char ** envp, + struct target_pt_regs * regs, struct image_info *infop); + +int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info); +int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info); + +abi_long memcpy_to_target(abi_ulong dest, const void *src, + unsigned long len); +void target_set_brk(abi_ulong new_brk); +abi_long do_brk(abi_ulong new_brk); +void syscall_init(void); +abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, + abi_long arg5, abi_long arg6); +abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, + abi_long arg5, abi_long arg6); +abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, + abi_long arg5, abi_long arg6); +void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); +extern THREAD CPUState *thread_env; +void cpu_loop(CPUState *env, enum BSDType bsd_type); +void init_paths(const char *prefix); +const char *path(const char *pathname); +char *target_strerror(int err); +int get_osversion(void); +void fork_start(void); +void fork_end(int child); + +#include "qemu-log.h" + +/* strace.c */ +void +print_freebsd_syscall(int num, + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6); +void print_freebsd_syscall_ret(int num, abi_long ret); +void +print_netbsd_syscall(int num, + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6); +void print_netbsd_syscall_ret(int num, abi_long ret); +void +print_openbsd_syscall(int num, + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6); +void print_openbsd_syscall_ret(int num, abi_long ret); +extern int do_strace; + +/* signal.c */ +void process_pending_signals(CPUState *cpu_env); +void signal_init(void); +//int queue_signal(CPUState *env, int sig, target_siginfo_t *info); +//void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); +//void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); +long do_sigreturn(CPUState *env); +long do_rt_sigreturn(CPUState *env); +abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp); + +/* mmap.c */ +int target_mprotect(abi_ulong start, abi_ulong len, int prot); +abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, + int flags, int fd, abi_ulong offset); +int target_munmap(abi_ulong start, abi_ulong len); +abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, + abi_ulong new_size, unsigned long flags, + abi_ulong new_addr); +int target_msync(abi_ulong start, abi_ulong len, int flags); +extern unsigned long last_brk; +void mmap_lock(void); +void mmap_unlock(void); +#if defined(USE_NPTL) +void mmap_fork_start(void); +void mmap_fork_end(int child); +#endif + +/* user access */ + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 /* implies read access */ + +static inline int access_ok(int type, abi_ulong addr, abi_ulong size) +{ + return page_check_range((target_ulong)addr, size, + (type == VERIFY_READ) ? PAGE_READ : (PAGE_READ | PAGE_WRITE)) == 0; +} + +/* NOTE __get_user and __put_user use host pointers and don't check access. */ +/* These are usually used to access struct data members once the + * struct has been locked - usually with lock_user_struct(). + */ +#define __put_user(x, hptr)\ +({\ + int size = sizeof(*hptr);\ + switch(size) {\ + case 1:\ + *(uint8_t *)(hptr) = (uint8_t)(typeof(*hptr))(x);\ + break;\ + case 2:\ + *(uint16_t *)(hptr) = tswap16((typeof(*hptr))(x));\ + break;\ + case 4:\ + *(uint32_t *)(hptr) = tswap32((typeof(*hptr))(x));\ + break;\ + case 8:\ + *(uint64_t *)(hptr) = tswap64((typeof(*hptr))(x));\ + break;\ + default:\ + abort();\ + }\ + 0;\ +}) + +#define __get_user(x, hptr) \ +({\ + int size = sizeof(*hptr);\ + switch(size) {\ + case 1:\ + x = (typeof(*hptr))*(uint8_t *)(hptr);\ + break;\ + case 2:\ + x = (typeof(*hptr))tswap16(*(uint16_t *)(hptr));\ + break;\ + case 4:\ + x = (typeof(*hptr))tswap32(*(uint32_t *)(hptr));\ + break;\ + case 8:\ + x = (typeof(*hptr))tswap64(*(uint64_t *)(hptr));\ + break;\ + default:\ + /* avoid warning */\ + x = 0;\ + abort();\ + }\ + 0;\ +}) + +/* put_user()/get_user() take a guest address and check access */ +/* These are usually used to access an atomic data type, such as an int, + * that has been passed by address. These internally perform locking + * and unlocking on the data type. + */ +#define put_user(x, gaddr, target_type) \ +({ \ + abi_ulong __gaddr = (gaddr); \ + target_type *__hptr; \ + abi_long __ret; \ + if ((__hptr = lock_user(VERIFY_WRITE, __gaddr, sizeof(target_type), 0))) { \ + __ret = __put_user((x), __hptr); \ + unlock_user(__hptr, __gaddr, sizeof(target_type)); \ + } else \ + __ret = -TARGET_EFAULT; \ + __ret; \ +}) + +#define get_user(x, gaddr, target_type) \ +({ \ + abi_ulong __gaddr = (gaddr); \ + target_type *__hptr; \ + abi_long __ret; \ + if ((__hptr = lock_user(VERIFY_READ, __gaddr, sizeof(target_type), 1))) { \ + __ret = __get_user((x), __hptr); \ + unlock_user(__hptr, __gaddr, 0); \ + } else { \ + /* avoid warning */ \ + (x) = 0; \ + __ret = -TARGET_EFAULT; \ + } \ + __ret; \ +}) + +#define put_user_ual(x, gaddr) put_user((x), (gaddr), abi_ulong) +#define put_user_sal(x, gaddr) put_user((x), (gaddr), abi_long) +#define put_user_u64(x, gaddr) put_user((x), (gaddr), uint64_t) +#define put_user_s64(x, gaddr) put_user((x), (gaddr), int64_t) +#define put_user_u32(x, gaddr) put_user((x), (gaddr), uint32_t) +#define put_user_s32(x, gaddr) put_user((x), (gaddr), int32_t) +#define put_user_u16(x, gaddr) put_user((x), (gaddr), uint16_t) +#define put_user_s16(x, gaddr) put_user((x), (gaddr), int16_t) +#define put_user_u8(x, gaddr) put_user((x), (gaddr), uint8_t) +#define put_user_s8(x, gaddr) put_user((x), (gaddr), int8_t) + +#define get_user_ual(x, gaddr) get_user((x), (gaddr), abi_ulong) +#define get_user_sal(x, gaddr) get_user((x), (gaddr), abi_long) +#define get_user_u64(x, gaddr) get_user((x), (gaddr), uint64_t) +#define get_user_s64(x, gaddr) get_user((x), (gaddr), int64_t) +#define get_user_u32(x, gaddr) get_user((x), (gaddr), uint32_t) +#define get_user_s32(x, gaddr) get_user((x), (gaddr), int32_t) +#define get_user_u16(x, gaddr) get_user((x), (gaddr), uint16_t) +#define get_user_s16(x, gaddr) get_user((x), (gaddr), int16_t) +#define get_user_u8(x, gaddr) get_user((x), (gaddr), uint8_t) +#define get_user_s8(x, gaddr) get_user((x), (gaddr), int8_t) + +/* copy_from_user() and copy_to_user() are usually used to copy data + * buffers between the target and host. These internally perform + * locking/unlocking of the memory. + */ +abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len); +abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len); + +/* Functions for accessing guest memory. The tget and tput functions + read/write single values, byteswapping as neccessary. The lock_user + gets a pointer to a contiguous area of guest memory, but does not perform + and byteswapping. lock_user may return either a pointer to the guest + memory, or a temporary buffer. */ + +/* Lock an area of guest memory into the host. If copy is true then the + host area will have the same contents as the guest. */ +static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy) +{ + if (!access_ok(type, guest_addr, len)) + return NULL; +#ifdef DEBUG_REMAP + { + void *addr; + addr = malloc(len); + if (copy) + memcpy(addr, g2h(guest_addr), len); + else + memset(addr, 0, len); + return addr; + } +#else + return g2h(guest_addr); +#endif +} + +/* Unlock an area of guest memory. The first LEN bytes must be + flushed back to guest memory. host_ptr = NULL is explicitly + allowed and does nothing. */ +static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, + long len) +{ + +#ifdef DEBUG_REMAP + if (!host_ptr) + return; + if (host_ptr == g2h(guest_addr)) + return; + if (len > 0) + memcpy(g2h(guest_addr), host_ptr, len); + free(host_ptr); +#endif +} + +/* Return the length of a string in target memory or -TARGET_EFAULT if + access error. */ +abi_long target_strlen(abi_ulong gaddr); + +/* Like lock_user but for null terminated strings. */ +static inline void *lock_user_string(abi_ulong guest_addr) +{ + abi_long len; + len = target_strlen(guest_addr); + if (len < 0) + return NULL; + return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1); +} + +/* Helper macros for locking/ulocking a target struct. */ +#define lock_user_struct(type, host_ptr, guest_addr, copy) \ + (host_ptr = lock_user(type, guest_addr, sizeof(*host_ptr), copy)) +#define unlock_user_struct(host_ptr, guest_addr, copy) \ + unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0) + +#if defined(USE_NPTL) +#include +#endif + +#endif /* QEMU_H */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/signal.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/signal.c --- qemu-0.9.1/bsd-user/signal.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/signal.c 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * Emulation of BSD signals + * + * Copyright (c) 2003 - 2008 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "qemu.h" +#include "target_signal.h" + +//#define DEBUG_SIGNAL + +void signal_init(void) +{ +} + +void process_pending_signals(CPUState *cpu_env) +{ +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/sparc/syscall.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/sparc/syscall.h --- qemu-0.9.1/bsd-user/sparc/syscall.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/sparc/syscall.h 2008-11-09 09:31:37.000000000 +0000 @@ -0,0 +1,9 @@ +struct target_pt_regs { + abi_ulong psr; + abi_ulong pc; + abi_ulong npc; + abi_ulong y; + abi_ulong u_regs[16]; +}; + +#define UNAME_MACHINE "sun4" diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/sparc/target_signal.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/sparc/target_signal.h --- qemu-0.9.1/bsd-user/sparc/target_signal.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/sparc/target_signal.h 2008-11-09 09:31:37.000000000 +0000 @@ -0,0 +1,27 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + abi_ulong ss_sp; + abi_long ss_flags; + abi_ulong ss_size; +} target_stack_t; + + +#ifndef UREG_I6 +#define UREG_I6 6 +#endif +#ifndef UREG_FP +#define UREG_FP UREG_I6 +#endif + +static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) +{ + return state->regwptr[UREG_FP]; +} + +#endif /* TARGET_SIGNAL_H */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/sparc64/syscall.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/sparc64/syscall.h --- qemu-0.9.1/bsd-user/sparc64/syscall.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/sparc64/syscall.h 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,10 @@ +struct target_pt_regs { + abi_ulong u_regs[16]; + abi_ulong tstate; + abi_ulong pc; + abi_ulong npc; + abi_ulong y; + abi_ulong fprs; +}; + +#define UNAME_MACHINE "sun4u" diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/sparc64/target_signal.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/sparc64/target_signal.h --- qemu-0.9.1/bsd-user/sparc64/target_signal.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/sparc64/target_signal.h 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,27 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + abi_ulong ss_sp; + abi_long ss_flags; + abi_ulong ss_size; +} target_stack_t; + + +#ifndef UREG_I6 +#define UREG_I6 6 +#endif +#ifndef UREG_FP +#define UREG_FP UREG_I6 +#endif + +static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) +{ + return state->regwptr[UREG_FP]; +} + +#endif /* TARGET_SIGNAL_H */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/strace.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/strace.c --- qemu-0.9.1/bsd-user/strace.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/strace.c 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,191 @@ +#include +#include +#include +#include +#include +#include +#include "qemu.h" + +int do_strace=0; + +struct syscallname { + int nr; + const char *name; + const char *format; + void (*call)(const struct syscallname *, + abi_long, abi_long, abi_long, + abi_long, abi_long, abi_long); + void (*result)(const struct syscallname *, abi_long); +}; + +/* + * Utility functions + */ + +static void +print_execve(const struct syscallname *name, + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6) +{ + abi_ulong arg_ptr_addr; + char *s; + + if (!(s = lock_user_string(arg1))) + return; + gemu_log("%s(\"%s\",{", name->name, s); + unlock_user(s, arg1, 0); + + for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) { + abi_ulong *arg_ptr, arg_addr, s_addr; + + arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1); + if (!arg_ptr) + return; + arg_addr = tswapl(*arg_ptr); + unlock_user(arg_ptr, arg_ptr_addr, 0); + if (!arg_addr) + break; + if ((s = lock_user_string(arg_addr))) { + gemu_log("\"%s\",", s); + unlock_user(s, s_addr, 0); + } + } + + gemu_log("NULL})"); +} + +/* + * Variants for the return value output function + */ + +static void +print_syscall_ret_addr(const struct syscallname *name, abi_long ret) +{ +if( ret == -1 ) { + gemu_log(" = -1 errno=%d (%s)\n", errno, strerror(errno)); + } else { + gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); + } +} + +#if 0 /* currently unused */ +static void +print_syscall_ret_raw(struct syscallname *name, abi_long ret) +{ + gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); +} +#endif + +/* + * An array of all of the syscalls we know about + */ + +static const struct syscallname freebsd_scnames[] = { +#include "freebsd/strace.list" +}; +static const struct syscallname netbsd_scnames[] = { +#include "netbsd/strace.list" +}; +static const struct syscallname openbsd_scnames[] = { +#include "openbsd/strace.list" +}; + +static void +print_syscall(int num, const struct syscallname *scnames, unsigned int nscnames, + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6) +{ + unsigned int i; + const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," + TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," + TARGET_ABI_FMT_ld ")"; + + gemu_log("%d ", getpid() ); + + for (i = 0; i < nscnames; i++) + if (scnames[i].nr == num) { + if (scnames[i].call != NULL) { + scnames[i].call(&scnames[i], arg1, arg2, arg3, arg4, arg5, + arg6); + } else { + /* XXX: this format system is broken because it uses + host types and host pointers for strings */ + if (scnames[i].format != NULL) + format = scnames[i].format; + gemu_log(format, scnames[i].name, arg1, arg2, arg3, arg4, + arg5, arg6); + } + return; + } + gemu_log("Unknown syscall %d\n", num); +} + +static void +print_syscall_ret(int num, abi_long ret, const struct syscallname *scnames, + unsigned int nscnames) +{ + unsigned int i; + + for (i = 0; i < nscnames; i++) + if (scnames[i].nr == num) { + if (scnames[i].result != NULL) { + scnames[i].result(&scnames[i], ret); + } else { + if( ret < 0 ) { + gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret, + strerror(-ret)); + } else { + gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret); + } + } + break; + } +} + +/* + * The public interface to this module. + */ +void +print_freebsd_syscall(int num, + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6) +{ + print_syscall(num, freebsd_scnames, ARRAY_SIZE(freebsd_scnames), + arg1, arg2, arg3, arg4, arg5, arg6); +} + +void +print_freebsd_syscall_ret(int num, abi_long ret) +{ + print_syscall_ret(num, ret, freebsd_scnames, ARRAY_SIZE(freebsd_scnames)); +} + +void +print_netbsd_syscall(int num, + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6) +{ + print_syscall(num, netbsd_scnames, ARRAY_SIZE(netbsd_scnames), + arg1, arg2, arg3, arg4, arg5, arg6); +} + +void +print_netbsd_syscall_ret(int num, abi_long ret) +{ + print_syscall_ret(num, ret, netbsd_scnames, ARRAY_SIZE(netbsd_scnames)); +} + +void +print_openbsd_syscall(int num, + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6) +{ + print_syscall(num, openbsd_scnames, ARRAY_SIZE(openbsd_scnames), + arg1, arg2, arg3, arg4, arg5, arg6); +} + +void +print_openbsd_syscall_ret(int num, abi_long ret) +{ + print_syscall_ret(num, ret, openbsd_scnames, ARRAY_SIZE(openbsd_scnames)); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/syscall.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/syscall.c --- qemu-0.9.1/bsd-user/syscall.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/syscall.c 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,273 @@ +/* + * BSD syscalls + * + * Copyright (c) 2003 - 2008 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qemu.h" +#include "qemu-common.h" + +//#define DEBUG + +static abi_ulong target_brk; +static abi_ulong target_original_brk; + +#define get_errno(x) (x) +#define target_to_host_bitmask(x, tbl) (x) + +void target_set_brk(abi_ulong new_brk) +{ + target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk); +} + +/* do_syscall() should always have a single exit point at the end so + that actions, such as logging of syscall results, can be performed. + All errnos that do_syscall() returns must be -TARGET_. */ +abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, + abi_long arg5, abi_long arg6) +{ + abi_long ret; + void *p; + +#ifdef DEBUG + gemu_log("freebsd syscall %d\n", num); +#endif + if(do_strace) + print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); + + switch(num) { + case TARGET_FREEBSD_NR_exit: +#ifdef HAVE_GPROF + _mcleanup(); +#endif + gdb_exit(cpu_env, arg1); + /* XXX: should free thread stack and CPU env */ + _exit(arg1); + ret = 0; /* avoid warning */ + break; + case TARGET_FREEBSD_NR_read: + if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) + goto efault; + ret = get_errno(read(arg1, p, arg3)); + unlock_user(p, arg2, ret); + break; + case TARGET_FREEBSD_NR_write: + if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) + goto efault; + ret = get_errno(write(arg1, p, arg3)); + unlock_user(p, arg2, 0); + break; + case TARGET_FREEBSD_NR_open: + if (!(p = lock_user_string(arg1))) + goto efault; + ret = get_errno(open(path(p), + target_to_host_bitmask(arg2, fcntl_flags_tbl), + arg3)); + unlock_user(p, arg1, 0); + break; + case TARGET_FREEBSD_NR_mmap: + ret = get_errno(target_mmap(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), + arg5, + arg6)); + break; + case TARGET_FREEBSD_NR_mprotect: + ret = get_errno(target_mprotect(arg1, arg2, arg3)); + break; + case TARGET_FREEBSD_NR_syscall: + case TARGET_FREEBSD_NR___syscall: + ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0); + break; + default: + ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); + break; + } + fail: +#ifdef DEBUG + gemu_log(" = %ld\n", ret); +#endif + if (do_strace) + print_freebsd_syscall_ret(num, ret); + return ret; + efault: + ret = -TARGET_EFAULT; + goto fail; +} + +abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, + abi_long arg5, abi_long arg6) +{ + abi_long ret; + void *p; + +#ifdef DEBUG + gemu_log("netbsd syscall %d\n", num); +#endif + if(do_strace) + print_netbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); + + switch(num) { + case TARGET_NETBSD_NR_exit: +#ifdef HAVE_GPROF + _mcleanup(); +#endif + gdb_exit(cpu_env, arg1); + /* XXX: should free thread stack and CPU env */ + _exit(arg1); + ret = 0; /* avoid warning */ + break; + case TARGET_NETBSD_NR_read: + if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) + goto efault; + ret = get_errno(read(arg1, p, arg3)); + unlock_user(p, arg2, ret); + break; + case TARGET_NETBSD_NR_write: + if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) + goto efault; + ret = get_errno(write(arg1, p, arg3)); + unlock_user(p, arg2, 0); + break; + case TARGET_NETBSD_NR_open: + if (!(p = lock_user_string(arg1))) + goto efault; + ret = get_errno(open(path(p), + target_to_host_bitmask(arg2, fcntl_flags_tbl), + arg3)); + unlock_user(p, arg1, 0); + break; + case TARGET_NETBSD_NR_mmap: + ret = get_errno(target_mmap(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), + arg5, + arg6)); + break; + case TARGET_NETBSD_NR_mprotect: + ret = get_errno(target_mprotect(arg1, arg2, arg3)); + break; + case TARGET_NETBSD_NR_syscall: + case TARGET_NETBSD_NR___syscall: + ret = do_netbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0); + break; + default: + ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); + break; + } + fail: +#ifdef DEBUG + gemu_log(" = %ld\n", ret); +#endif + if (do_strace) + print_netbsd_syscall_ret(num, ret); + return ret; + efault: + ret = -TARGET_EFAULT; + goto fail; +} + +abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, + abi_long arg5, abi_long arg6) +{ + abi_long ret; + void *p; + +#ifdef DEBUG + gemu_log("openbsd syscall %d\n", num); +#endif + if(do_strace) + print_openbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); + + switch(num) { + case TARGET_OPENBSD_NR_exit: +#ifdef HAVE_GPROF + _mcleanup(); +#endif + gdb_exit(cpu_env, arg1); + /* XXX: should free thread stack and CPU env */ + _exit(arg1); + ret = 0; /* avoid warning */ + break; + case TARGET_OPENBSD_NR_read: + if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) + goto efault; + ret = get_errno(read(arg1, p, arg3)); + unlock_user(p, arg2, ret); + break; + case TARGET_OPENBSD_NR_write: + if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) + goto efault; + ret = get_errno(write(arg1, p, arg3)); + unlock_user(p, arg2, 0); + break; + case TARGET_OPENBSD_NR_open: + if (!(p = lock_user_string(arg1))) + goto efault; + ret = get_errno(open(path(p), + target_to_host_bitmask(arg2, fcntl_flags_tbl), + arg3)); + unlock_user(p, arg1, 0); + break; + case TARGET_OPENBSD_NR_mmap: + ret = get_errno(target_mmap(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), + arg5, + arg6)); + break; + case TARGET_OPENBSD_NR_mprotect: + ret = get_errno(target_mprotect(arg1, arg2, arg3)); + break; + case TARGET_OPENBSD_NR_syscall: + case TARGET_OPENBSD_NR___syscall: + ret = do_openbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0); + break; + default: + ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); + break; + } + fail: +#ifdef DEBUG + gemu_log(" = %ld\n", ret); +#endif + if (do_strace) + print_openbsd_syscall_ret(num, ret); + return ret; + efault: + ret = -TARGET_EFAULT; + goto fail; +} + +void syscall_init(void) +{ +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/syscall_defs.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/syscall_defs.h --- qemu-0.9.1/bsd-user/syscall_defs.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/syscall_defs.h 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,108 @@ +/* $OpenBSD: signal.h,v 1.19 2006/01/08 14:20:16 millert Exp $ */ +/* $NetBSD: signal.h,v 1.21 1996/02/09 18:25:32 christos Exp $ */ + +/* + * Copyright (c) 1982, 1986, 1989, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)signal.h 8.2 (Berkeley) 1/21/94 + */ + +#define TARGET_NSIG 32 /* counting 0; could be 33 (mask is 1-32) */ + +#define TARGET_SIGHUP 1 /* hangup */ +#define TARGET_SIGINT 2 /* interrupt */ +#define TARGET_SIGQUIT 3 /* quit */ +#define TARGET_SIGILL 4 /* illegal instruction (not reset when caught) */ +#define TARGET_SIGTRAP 5 /* trace trap (not reset when caught) */ +#define TARGET_SIGABRT 6 /* abort() */ +#define TARGET_SIGIOT SIGABRT /* compatibility */ +#define TARGET_SIGEMT 7 /* EMT instruction */ +#define TARGET_SIGFPE 8 /* floating point exception */ +#define TARGET_SIGKILL 9 /* kill (cannot be caught or ignored) */ +#define TARGET_SIGBUS 10 /* bus error */ +#define TARGET_SIGSEGV 11 /* segmentation violation */ +#define TARGET_SIGSYS 12 /* bad argument to system call */ +#define TARGET_SIGPIPE 13 /* write on a pipe with no one to read it */ +#define TARGET_SIGALRM 14 /* alarm clock */ +#define TARGET_SIGTERM 15 /* software termination signal from kill */ +#define TARGET_SIGURG 16 /* urgent condition on IO channel */ +#define TARGET_SIGSTOP 17 /* sendable stop signal not from tty */ +#define TARGET_SIGTSTP 18 /* stop signal from tty */ +#define TARGET_SIGCONT 19 /* continue a stopped process */ +#define TARGET_SIGCHLD 20 /* to parent on child stop or exit */ +#define TARGET_SIGTTIN 21 /* to readers pgrp upon background tty read */ +#define TARGET_SIGTTOU 22 /* like TTIN for output if (tp->t_local<OSTOP) */ +#define TARGET_SIGIO 23 /* input/output possible signal */ +#define TARGET_SIGXCPU 24 /* exceeded CPU time limit */ +#define TARGET_SIGXFSZ 25 /* exceeded file size limit */ +#define TARGET_SIGVTALRM 26 /* virtual time alarm */ +#define TARGET_SIGPROF 27 /* profiling time alarm */ +#define TARGET_SIGWINCH 28 /* window size changes */ +#define TARGET_SIGINFO 29 /* information request */ +#define TARGET_SIGUSR1 30 /* user defined signal 1 */ +#define TARGET_SIGUSR2 31 /* user defined signal 2 */ + +/* + * Language spec says we must list exactly one parameter, even though we + * actually supply three. Ugh! + */ +#define TARGET_SIG_DFL (void (*)(int))0 +#define TARGET_SIG_IGN (void (*)(int))1 +#define TARGET_SIG_ERR (void (*)(int))-1 + +#define TARGET_SA_ONSTACK 0x0001 /* take signal on signal stack */ +#define TARGET_SA_RESTART 0x0002 /* restart system on signal return */ +#define TARGET_SA_RESETHAND 0x0004 /* reset to SIG_DFL when taking signal */ +#define TARGET_SA_NODEFER 0x0010 /* don't mask the signal we're delivering */ +#define TARGET_SA_NOCLDWAIT 0x0020 /* don't create zombies (assign to pid 1) */ +#define TARGET_SA_USERTRAMP 0x0100 /* do not bounce off kernel's sigtramp */ +#define TARGET_SA_NOCLDSTOP 0x0008 /* do not generate SIGCHLD on child stop */ +#define TARGET_SA_SIGINFO 0x0040 /* generate siginfo_t */ + +/* + * Flags for sigprocmask: + */ +#define TARGET_SIG_BLOCK 1 /* block specified signal set */ +#define TARGET_SIG_UNBLOCK 2 /* unblock specified signal set */ +#define TARGET_SIG_SETMASK 3 /* set specified signal set */ + +#define TARGET_BADSIG SIG_ERR + +#define TARGET_SS_ONSTACK 0x0001 /* take signals on alternate stack */ +#define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate stack */ + +#include "errno_defs.h" + +#include "freebsd/syscall_nr.h" +#include "netbsd/syscall_nr.h" +#include "openbsd/syscall_nr.h" diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bsd-user/uaccess.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bsd-user/uaccess.c --- qemu-0.9.1/bsd-user/uaccess.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bsd-user/uaccess.c 2008-10-26 20:33:16.000000000 +0000 @@ -0,0 +1,76 @@ +/* User memory access */ +#include +#include + +#include "qemu.h" + +/* copy_from_user() and copy_to_user() are usually used to copy data + * buffers between the target and host. These internally perform + * locking/unlocking of the memory. + */ +abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len) +{ + abi_long ret = 0; + void *ghptr; + + if ((ghptr = lock_user(VERIFY_READ, gaddr, len, 1))) { + memcpy(hptr, ghptr, len); + unlock_user(ghptr, gaddr, 0); + } else + ret = -TARGET_EFAULT; + + return ret; +} + + +abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len) +{ + abi_long ret = 0; + void *ghptr; + + if ((ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0))) { + memcpy(ghptr, hptr, len); + unlock_user(ghptr, gaddr, len); + } else + ret = -TARGET_EFAULT; + + return ret; +} + +/* XXX: use host strnlen if available ? */ +static int qemu_strnlen(const char *s, int max_len) +{ + int i; + for(i = 0; i < max_len; i++) { + if (s[i] == '\0') + break; + } + return i; +} + +/* Return the length of a string in target memory or -TARGET_EFAULT if + access error */ +abi_long target_strlen(abi_ulong guest_addr1) +{ + uint8_t *ptr; + abi_ulong guest_addr; + int max_len, len; + + guest_addr = guest_addr1; + for(;;) { + max_len = TARGET_PAGE_SIZE - (guest_addr & ~TARGET_PAGE_MASK); + ptr = lock_user(VERIFY_READ, guest_addr, max_len, 1); + if (!ptr) + return -TARGET_EFAULT; + len = qemu_strnlen(ptr, max_len); + unlock_user(ptr, guest_addr, 0); + guest_addr += len; + /* we don't allow wrapping or integer overflow */ + if (guest_addr == 0 || + (guest_addr - guest_addr1) > 0x7fffffff) + return -TARGET_EFAULT; + if (len != max_len) + break; + } + return guest_addr - guest_addr1; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bswap.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bswap.h --- qemu-0.9.1/bswap.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/bswap.h 2008-03-28 22:30:48.000000000 +0000 @@ -132,6 +132,7 @@ #define cpu_to_le32wu(p, v) cpu_to_le32w(p, v) #define le16_to_cpupu(p) le16_to_cpup(p) #define le32_to_cpupu(p) le32_to_cpup(p) +#define be32_to_cpupu(p) be32_to_cpup(p) #define cpu_to_be16wu(p, v) cpu_to_be16w(p, v) #define cpu_to_be32wu(p, v) cpu_to_be32w(p, v) @@ -168,6 +169,12 @@ return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24); } +static inline uint32_t be32_to_cpupu(const uint32_t *p) +{ + const uint8_t *p1 = (const uint8_t *)p; + return p1[3] | (p1[2] << 8) | (p1[1] << 16) | (p1[0] << 24); +} + static inline void cpu_to_be16wu(uint16_t *p, uint16_t v) { uint8_t *p1 = (uint8_t *)p; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bt-host.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bt-host.c --- qemu-0.9.1/bt-host.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bt-host.c 2008-11-06 09:38:51.000000000 +0000 @@ -0,0 +1,207 @@ +/* + * Wrap a host Bluetooth HCI socket in a struct HCIInfo. + * + * Copyright (C) 2008 Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "qemu-common.h" +#include "qemu-char.h" +#include "sysemu.h" +#include "net.h" + +#ifndef _WIN32 +# include +# include +# include +# ifdef CONFIG_BLUEZ +# include +# include +# include +# else +# include "hw/bt.h" +# define HCI_MAX_FRAME_SIZE 1028 +# endif + +struct bt_host_hci_s { + struct HCIInfo hci; + int fd; + + uint8_t hdr[HCI_MAX_FRAME_SIZE]; + int len; +}; + +static void bt_host_send(struct HCIInfo *hci, + int type, const uint8_t *data, int len) +{ + struct bt_host_hci_s *s = (struct bt_host_hci_s *) hci; + uint8_t pkt = type; + struct iovec iv[2]; + int ret; + + iv[0].iov_base = &pkt; + iv[0].iov_len = 1; + iv[1].iov_base = (void *) data; + iv[1].iov_len = len; + + while ((ret = writev(s->fd, iv, 2)) < 0) + if (errno != EAGAIN && errno != EINTR) { + fprintf(stderr, "qemu: error %i writing bluetooth packet.\n", + errno); + return; + } +} + +static void bt_host_cmd(struct HCIInfo *hci, const uint8_t *data, int len) +{ + bt_host_send(hci, HCI_COMMAND_PKT, data, len); +} + +static void bt_host_acl(struct HCIInfo *hci, const uint8_t *data, int len) +{ + bt_host_send(hci, HCI_ACLDATA_PKT, data, len); +} + +static void bt_host_sco(struct HCIInfo *hci, const uint8_t *data, int len) +{ + bt_host_send(hci, HCI_SCODATA_PKT, data, len); +} + +static int bt_host_read_poll(void *opaque) +{ + struct bt_host_hci_s *s = (struct bt_host_hci_s *) opaque; + + return !!s->hci.evt_recv; +} + +static void bt_host_read(void *opaque) +{ + struct bt_host_hci_s *s = (struct bt_host_hci_s *) opaque; + uint8_t *pkt; + int pktlen; + + /* Seems that we can't read only the header first and then the amount + * of data indicated in the header because Linux will discard everything + * that's not been read in one go. */ + s->len = read(s->fd, s->hdr, sizeof(s->hdr)); + + if (s->len < 0) { + fprintf(stderr, "qemu: error %i reading HCI frame\n", errno); + return; + } + + pkt = s->hdr; + while (s->len --) + switch (*pkt ++) { + case HCI_EVENT_PKT: + if (s->len < 2) + goto bad_pkt; + + pktlen = MIN(pkt[1] + 2, s->len); + s->hci.evt_recv(s->hci.opaque, pkt, pktlen); + s->len -= pktlen; + pkt += pktlen; + + /* TODO: if this is an Inquiry Result event, it's also + * interpreted by Linux kernel before we received it, possibly + * we should clean the kernel Inquiry cache through + * ioctl(s->fd, HCI_INQUIRY, ...). */ + break; + + case HCI_ACLDATA_PKT: + if (s->len < 4) + goto bad_pkt; + + pktlen = MIN(((pkt[3] << 8) | pkt[2]) + 4, s->len); + s->hci.acl_recv(s->hci.opaque, pkt, pktlen); + s->len -= pktlen; + pkt += pktlen; + break; + + case HCI_SCODATA_PKT: + if (s->len < 3) + goto bad_pkt; + + pktlen = MIN(pkt[2] + 3, s->len); + s->len -= pktlen; + pkt += pktlen; + + default: + bad_pkt: + fprintf(stderr, "qemu: bad HCI packet type %02x\n", pkt[-1]); + } +} + +static int bt_host_bdaddr_set(struct HCIInfo *hci, const uint8_t *bd_addr) +{ + return -ENOTSUP; +} + +struct HCIInfo *bt_host_hci(const char *id) +{ + struct bt_host_hci_s *s; + int fd = -1; +# ifdef CONFIG_BLUEZ + int dev_id = hci_devid(id); + struct hci_filter flt; + + if (dev_id < 0) { + fprintf(stderr, "qemu: `%s' not available\n", id); + return 0; + } + + fd = hci_open_dev(dev_id); + + /* XXX: can we ensure nobody else has the device opened? */ +# endif + + if (fd < 0) { + fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n", + id, strerror(errno), errno); + return 0; + } + +# ifdef CONFIG_BLUEZ + hci_filter_clear(&flt); + hci_filter_all_ptypes(&flt); + hci_filter_all_events(&flt); + + if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { + fprintf(stderr, "qemu: Can't set HCI filter on socket (%i)\n", errno); + return 0; + } +# endif + + s = qemu_mallocz(sizeof(struct bt_host_hci_s)); + s->fd = fd; + s->hci.cmd_send = bt_host_cmd; + s->hci.sco_send = bt_host_sco; + s->hci.acl_send = bt_host_acl; + s->hci.bdaddr_set = bt_host_bdaddr_set; + + qemu_set_fd_handler2(s->fd, bt_host_read_poll, bt_host_read, 0, s); + + return &s->hci; +} +#else +struct HCIInfo *bt_host_hci(const char *id) +{ + fprintf(stderr, "qemu: bluetooth passthrough not supported (yet)\n"); + + return 0; +} +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/bt-vhci.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/bt-vhci.c --- qemu-0.9.1/bt-vhci.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/bt-vhci.c 2008-10-01 00:31:35.000000000 +0100 @@ -0,0 +1,170 @@ +/* + * Support for host VHCIs inside qemu scatternets. + * + * Copyright (C) 2008 Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "qemu-common.h" +#include "qemu-char.h" +#include "sysemu.h" +#include "net.h" +#include "hw/bt.h" + +#define VHCI_DEV "/dev/vhci" +#define VHCI_UDEV "/dev/hci_vhci" + +struct bt_vhci_s { + int fd; + struct HCIInfo *info; + + uint8_t hdr[4096]; + int len; +}; + +static void vhci_read(void *opaque) +{ + struct bt_vhci_s *s = (struct bt_vhci_s *) opaque; + uint8_t *pkt; + int pktlen; + + /* Seems that we can't read only the header first and then the amount + * of data indicated in the header because Linux will discard everything + * that's not been read in one go. */ + s->len = read(s->fd, s->hdr, sizeof(s->hdr)); + + if (s->len < 0) { + fprintf(stderr, "qemu: error %i reading the PDU\n", errno); + return; + } + + pkt = s->hdr; + while (s->len --) + switch (*pkt ++) { + case HCI_COMMAND_PKT: + if (s->len < 3) + goto bad_pkt; + + pktlen = MIN(pkt[2] + 3, s->len); + s->info->cmd_send(s->info, pkt, pktlen); + s->len -= pktlen; + pkt += pktlen; + break; + + case HCI_ACLDATA_PKT: + if (s->len < 4) + goto bad_pkt; + + pktlen = MIN(((pkt[3] << 8) | pkt[2]) + 4, s->len); + s->info->acl_send(s->info, pkt, pktlen); + s->len -= pktlen; + pkt += pktlen; + break; + + case HCI_SCODATA_PKT: + if (s->len < 3) + goto bad_pkt; + + pktlen = MIN(pkt[2] + 3, s->len); + s->info->sco_send(s->info, pkt, pktlen); + s->len -= pktlen; + pkt += pktlen; + break; + + default: + bad_pkt: + fprintf(stderr, "qemu: bad HCI packet type %02x\n", pkt[-1]); + } +} + +static void vhci_host_send(void *opaque, + int type, const uint8_t *data, int len) +{ + struct bt_vhci_s *s = (struct bt_vhci_s *) opaque; +#if 0 + uint8_t pkt = type; + struct iovec iv[2]; + + iv[0].iov_base = &pkt; + iv[0].iov_len = 1; + iv[1].iov_base = (void *) data; + iv[1].iov_len = len; + + while (writev(s->fd, iv, 2) < 0) + if (errno != EAGAIN && errno != EINTR) { + fprintf(stderr, "qemu: error %i writing bluetooth packet.\n", + errno); + return; + } +#else + /* Apparently VHCI wants us to write everything in one chunk :-( */ + static uint8_t buf[4096]; + + buf[0] = type; + memcpy(buf + 1, data, len); + + while (write(s->fd, buf, len + 1) < 0) + if (errno != EAGAIN && errno != EINTR) { + fprintf(stderr, "qemu: error %i writing bluetooth packet.\n", + errno); + return; + } +#endif +} + +static void vhci_out_hci_packet_event(void *opaque, + const uint8_t *data, int len) +{ + vhci_host_send(opaque, HCI_EVENT_PKT, data, len); +} + +static void vhci_out_hci_packet_acl(void *opaque, + const uint8_t *data, int len) +{ + vhci_host_send(opaque, HCI_ACLDATA_PKT, data, len); +} + +void bt_vhci_init(struct HCIInfo *info) +{ + struct bt_vhci_s *s; + int err[2]; + int fd; + + fd = open(VHCI_DEV, O_RDWR); + err[0] = errno; + if (fd < 0) { + fd = open(VHCI_UDEV, O_RDWR); + err[1] = errno; + } + + if (fd < 0) { + fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n", + VHCI_DEV, strerror(err[0]), err[0]); + fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n", + VHCI_UDEV, strerror(err[1]), err[1]); + exit(-1); + } + + s = qemu_mallocz(sizeof(struct bt_vhci_s)); + s->fd = fd; + s->info = info ?: qemu_next_hci(); + s->info->opaque = s; + s->info->evt_recv = vhci_out_hci_packet_event; + s->info->acl_recv = vhci_out_hci_packet_acl; + + qemu_set_fd_handler(s->fd, vhci_read, 0, s); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/buffered_file.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/buffered_file.c --- qemu-0.9.1/buffered_file.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/buffered_file.c 2008-10-13 04:10:22.000000000 +0100 @@ -0,0 +1,250 @@ +/* + * QEMU buffered QEMUFile + * + * Copyright IBM, Corp. 2008 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "qemu-common.h" +#include "hw/hw.h" +#include "qemu-timer.h" +#include "sysemu.h" +#include "qemu-char.h" +#include "buffered_file.h" + +//#define DEBUG_BUFFERED_FILE + +typedef struct QEMUFileBuffered +{ + BufferedPutFunc *put_buffer; + BufferedPutReadyFunc *put_ready; + BufferedWaitForUnfreezeFunc *wait_for_unfreeze; + BufferedCloseFunc *close; + void *opaque; + QEMUFile *file; + int has_error; + int freeze_output; + size_t bytes_xfer; + size_t xfer_limit; + uint8_t *buffer; + size_t buffer_size; + size_t buffer_capacity; + QEMUTimer *timer; +} QEMUFileBuffered; + +#ifdef DEBUG_BUFFERED_FILE +#define dprintf(fmt, ...) \ + do { printf("buffered-file: " fmt, ## __VA_ARGS__); } while (0) +#else +#define dprintf(fmt, ...) \ + do { } while (0) +#endif + +static void buffered_append(QEMUFileBuffered *s, + const uint8_t *buf, size_t size) +{ + if (size > (s->buffer_capacity - s->buffer_size)) { + void *tmp; + + dprintf("increasing buffer capacity from %ld by %ld\n", + s->buffer_capacity, size + 1024); + + s->buffer_capacity += size + 1024; + + tmp = qemu_realloc(s->buffer, s->buffer_capacity); + if (tmp == NULL) { + fprintf(stderr, "qemu file buffer expansion failed\n"); + exit(1); + } + + s->buffer = tmp; + } + + memcpy(s->buffer + s->buffer_size, buf, size); + s->buffer_size += size; +} + +static void buffered_flush(QEMUFileBuffered *s) +{ + size_t offset = 0; + + if (s->has_error) { + dprintf("flush when error, bailing\n"); + return; + } + + dprintf("flushing %ld byte(s) of data\n", s->buffer_size); + + while (offset < s->buffer_size) { + ssize_t ret; + + ret = s->put_buffer(s->opaque, s->buffer + offset, + s->buffer_size - offset); + if (ret == -EAGAIN) { + dprintf("backend not ready, freezing\n"); + s->freeze_output = 1; + break; + } + + if (ret <= 0) { + dprintf("error flushing data, %ld\n", ret); + s->has_error = 1; + break; + } else { + dprintf("flushed %ld byte(s)\n", ret); + offset += ret; + } + } + + dprintf("flushed %ld of %ld byte(s)\n", offset, s->buffer_size); + memmove(s->buffer, s->buffer + offset, s->buffer_size - offset); + s->buffer_size -= offset; +} + +static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) +{ + QEMUFileBuffered *s = opaque; + int offset = 0; + ssize_t ret; + + dprintf("putting %ld bytes at %Ld\n", size, pos); + + if (s->has_error) { + dprintf("flush when error, bailing\n"); + return -EINVAL; + } + + dprintf("unfreezing output\n"); + s->freeze_output = 0; + + buffered_flush(s); + + while (!s->freeze_output && offset < size) { + if (s->bytes_xfer > s->xfer_limit) { + dprintf("transfer limit exceeded when putting\n"); + break; + } + + ret = s->put_buffer(s->opaque, buf + offset, size - offset); + if (ret == -EAGAIN) { + dprintf("backend not ready, freezing\n"); + s->freeze_output = 1; + break; + } + + if (ret <= 0) { + dprintf("error putting\n"); + s->has_error = 1; + offset = -EINVAL; + break; + } + + dprintf("put %ld byte(s)\n", ret); + offset += ret; + s->bytes_xfer += ret; + } + + if (offset >= 0) { + dprintf("buffering %ld bytes\n", size - offset); + buffered_append(s, buf + offset, size - offset); + offset = size; + } + + return offset; +} + +static int buffered_close(void *opaque) +{ + QEMUFileBuffered *s = opaque; + int ret; + + dprintf("closing\n"); + + while (!s->has_error && s->buffer_size) { + buffered_flush(s); + if (s->freeze_output) + s->wait_for_unfreeze(s); + } + + ret = s->close(s->opaque); + + qemu_del_timer(s->timer); + qemu_free_timer(s->timer); + qemu_free(s->buffer); + qemu_free(s); + + return ret; +} + +static int buffered_rate_limit(void *opaque) +{ + QEMUFileBuffered *s = opaque; + + if (s->has_error) + return 0; + + if (s->freeze_output) + return 1; + + if (s->bytes_xfer > s->xfer_limit) + return 1; + + return 0; +} + +static void buffered_rate_tick(void *opaque) +{ + QEMUFileBuffered *s = opaque; + + if (s->has_error) + return; + + qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 100); + + if (s->freeze_output) + return; + + s->bytes_xfer = 0; + + buffered_flush(s); + + /* Add some checks around this */ + s->put_ready(s->opaque); +} + +QEMUFile *qemu_fopen_ops_buffered(void *opaque, + size_t bytes_per_sec, + BufferedPutFunc *put_buffer, + BufferedPutReadyFunc *put_ready, + BufferedWaitForUnfreezeFunc *wait_for_unfreeze, + BufferedCloseFunc *close) +{ + QEMUFileBuffered *s; + + s = qemu_mallocz(sizeof(*s)); + if (s == NULL) + return NULL; + + s->opaque = opaque; + s->xfer_limit = bytes_per_sec / 10; + s->put_buffer = put_buffer; + s->put_ready = put_ready; + s->wait_for_unfreeze = wait_for_unfreeze; + s->close = close; + + s->file = qemu_fopen_ops(s, buffered_put_buffer, NULL, + buffered_close, buffered_rate_limit); + + s->timer = qemu_new_timer(rt_clock, buffered_rate_tick, s); + + qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 100); + + return s->file; +} + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/buffered_file.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/buffered_file.h --- qemu-0.9.1/buffered_file.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/buffered_file.h 2008-10-13 04:10:22.000000000 +0100 @@ -0,0 +1,30 @@ +/* + * QEMU buffered QEMUFile + * + * Copyright IBM, Corp. 2008 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_BUFFERED_FILE_H +#define QEMU_BUFFERED_FILE_H + +#include "hw/hw.h" + +typedef ssize_t (BufferedPutFunc)(void *opaque, const void *data, size_t size); +typedef void (BufferedPutReadyFunc)(void *opaque); +typedef void (BufferedWaitForUnfreezeFunc)(void *opaque); +typedef int (BufferedCloseFunc)(void *opaque); + +QEMUFile *qemu_fopen_ops_buffered(void *opaque, size_t xfer_limit, + BufferedPutFunc *put_buffer, + BufferedPutReadyFunc *put_ready, + BufferedWaitForUnfreezeFunc *wait_for_unfreeze, + BufferedCloseFunc *close); + +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/build-jaunty-20081123-2159.uJzmm8.log /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/build-jaunty-20081123-2159.uJzmm8.log --- qemu-0.9.1/build-jaunty-20081123-2159.uJzmm8.log 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/build-jaunty-20081123-2159.uJzmm8.log 2008-11-23 23:12:07.000000000 +0000 @@ -0,0 +1,2 @@ +Invalid source: qemu_0.9.1+svn20081112-1ubuntu1.dsc +Skipping qemu diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/Changelog /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/Changelog --- qemu-0.9.1/Changelog 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/Changelog 2008-06-08 02:55:07.000000000 +0100 @@ -1,3 +1,10 @@ + - MIPS Magnum R4000 machine (Hervé Poussineau) + - Braille support (Samuel Thibault) + - Freecom MusicPal system emulation (Jan Kiszka) + - OMAP242x and Nokia N800, N810 machines (Andrzej Zaborowski) + - EsounD audio driver (Frederick Reeve) + - Gravis Ultrasound GF1 sound card (Tibor "TS" Schütz) + version 0.9.1: - TFTP booting from host directory (Anthony Liguori, Erwan Velu) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/cocoa.m /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/cocoa.m --- qemu-0.9.1/cocoa.m 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/cocoa.m 2008-03-10 19:34:27.000000000 +0000 @@ -1,8 +1,7 @@ /* - * QEMU Cocoa display driver + * QEMU Cocoa CG display driver * - * Copyright (c) 2005 Pierre d'Herbemont - * many code/inspiration from SDL 1.2 code (LGPL) + * Copyright (c) 2008 Mike Kronenberg * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,18 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -/* - Todo : x miniaturize window - x center the window - - save window position - - handle keyboard event - - handle mouse event - - non 32 bpp support - - full screen - - mouse focus - x simple graphical prompt to demo - - better graphical prompt -*/ #import @@ -41,146 +28,41 @@ #include "console.h" #include "sysemu.h" -NSWindow *window = NULL; -NSQuickDrawView *qd_view = NULL; - - -int gArgc; -char **gArgv; -DisplayState current_ds; - -int grab = 0; -int modifiers_state[256]; - -/* main defined in qemu/vl.c */ -int qemu_main(int argc, char **argv); - -/* To deal with miniaturization */ -@interface QemuWindow : NSWindow -{ } -@end - - -/* - ------------------------------------------------------ - Qemu Video Driver - ------------------------------------------------------ -*/ - -/* - ------------------------------------------------------ - cocoa_update - ------------------------------------------------------ -*/ -static void cocoa_update(DisplayState *ds, int x, int y, int w, int h) -{ - //printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h); - - /* Use QDFlushPortBuffer() to flush content to display */ - RgnHandle dirty = NewRgn (); - RgnHandle temp = NewRgn (); - - SetEmptyRgn (dirty); - - /* Build the region of dirty rectangles */ - MacSetRectRgn (temp, x, y, - x + w, y + h); - MacUnionRgn (dirty, temp, dirty); - - /* Flush the dirty region */ - QDFlushPortBuffer ( [ qd_view qdPort ], dirty ); - DisposeRgn (dirty); - DisposeRgn (temp); -} - -/* - ------------------------------------------------------ - cocoa_resize - ------------------------------------------------------ -*/ -static void cocoa_resize(DisplayState *ds, int w, int h) -{ - const int device_bpp = 32; - static void *screen_pixels; - static int screen_pitch; - NSRect contentRect; - - //printf("resizing to %d %d\n", w, h); - - contentRect = NSMakeRect (0, 0, w, h); - if(window) - { - [window close]; - [window release]; - } - window = [ [ QemuWindow alloc ] initWithContentRect:contentRect - styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask - backing:NSBackingStoreBuffered defer:NO]; - if(!window) - { - fprintf(stderr, "(cocoa) can't create window\n"); - exit(1); - } - - if(qd_view) - [qd_view release]; - qd_view = [ [ NSQuickDrawView alloc ] initWithFrame:contentRect ]; +//#define DEBUG - if(!qd_view) - { - fprintf(stderr, "(cocoa) can't create qd_view\n"); - exit(1); - } - - [ window setAcceptsMouseMovedEvents:YES ]; - [ window setTitle:@"Qemu" ]; - [ window setReleasedWhenClosed:NO ]; - - /* Set screen to black */ - [ window setBackgroundColor: [NSColor blackColor] ]; - - /* set window position */ - [ window center ]; - - [ qd_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ]; - [ [ window contentView ] addSubview:qd_view ]; - [ qd_view release ]; - [ window makeKeyAndOrderFront:nil ]; - - /* Careful here, the window seems to have to be onscreen to do that */ - LockPortBits ( [ qd_view qdPort ] ); - screen_pixels = GetPixBaseAddr ( GetPortPixMap ( [ qd_view qdPort ] ) ); - screen_pitch = GetPixRowBytes ( GetPortPixMap ( [ qd_view qdPort ] ) ); - UnlockPortBits ( [ qd_view qdPort ] ); - { - int vOffset = [ window frame ].size.height - - [ qd_view frame ].size.height - [ qd_view frame ].origin.y; - - int hOffset = [ qd_view frame ].origin.x; - - screen_pixels += (vOffset * screen_pitch) + hOffset * (device_bpp/8); - } - ds->data = screen_pixels; - ds->linesize = screen_pitch; - ds->depth = device_bpp; - ds->width = w; - ds->height = h; -#ifdef __LITTLE_ENDIAN__ - ds->bgr = 1; +#ifdef DEBUG +#define COCOA_DEBUG(...) { (void) fprintf (stdout, __VA_ARGS__); } #else - ds->bgr = 0; +#define COCOA_DEBUG(...) ((void) 0) #endif - current_ds = *ds; -} +#define cgrect(nsrect) (*(CGRect *)&(nsrect)) +#define COCOA_MOUSE_EVENT \ + if (isTabletEnabled) { \ + kbd_mouse_event((int)(p.x * 0x7FFF / (screen.width - 1)), (int)((screen.height - p.y) * 0x7FFF / (screen.height - 1)), 0, buttons); \ + } else if (isMouseGrabed) { \ + kbd_mouse_event((int)[event deltaX], (int)[event deltaY], 0, buttons); \ + } else { \ + [NSApp sendEvent:event]; \ + } -/* - ------------------------------------------------------ - keymap conversion - ------------------------------------------------------ -*/ +typedef struct { + int width; + int height; + int bitsPerComponent; + int bitsPerPixel; +} QEMUScreen; + +int qemu_main(int argc, char **argv); // main defined in qemu/vl.c +NSWindow *normalWindow; +id cocoaView; +static void *screenBuffer; + +int gArgc; +char **gArgv; +// keymap conversion int keymap[] = { // SdlI macI macH SdlH 104xtH 104xtC sdl @@ -289,7 +171,7 @@ 0, // 102 0x66 Undefined 87, // 103 0x67 0x57 F11 QZ_F11 0, // 104 0x68 Undefined - 183,// 105 0x69 0xb7 QZ_PRINT + 183,// 105 0x69 0xb7 QZ_PRINT 0, // 106 0x6A Undefined 70, // 107 0x6B 0x46 SCROLL QZ_SCROLLOCK 0, // 108 0x6C Undefined @@ -357,430 +239,566 @@ return keymap[keycode]; } + + /* ------------------------------------------------------ - cocoa_refresh + QemuCocoaView ------------------------------------------------------ */ -static void cocoa_refresh(DisplayState *ds) +@interface QemuCocoaView : NSView { - //printf("cocoa_refresh \n"); - NSDate *distantPast; - NSEvent *event; - NSAutoreleasePool *pool; - - pool = [ [ NSAutoreleasePool alloc ] init ]; - distantPast = [ NSDate distantPast ]; - - vga_hw_update(); - - do { - event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast - inMode: NSDefaultRunLoopMode dequeue:YES ]; - if (event != nil) { - switch ([event type]) { - case NSFlagsChanged: - { - int keycode = cocoa_keycode_to_qemu([event keyCode]); - - if (keycode) - { - if (keycode == 58 || keycode == 69) { - /* emulate caps lock and num lock keydown and keyup */ - kbd_put_keycode(keycode); - kbd_put_keycode(keycode | 0x80); - } else if (is_graphic_console()) { - if (keycode & 0x80) - kbd_put_keycode(0xe0); - if (modifiers_state[keycode] == 0) { - /* keydown */ - kbd_put_keycode(keycode & 0x7f); - modifiers_state[keycode] = 1; - } else { - /* keyup */ - kbd_put_keycode(keycode | 0x80); - modifiers_state[keycode] = 0; - } - } - } - - /* release Mouse grab when pressing ctrl+alt */ - if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) - { - [window setTitle: @"QEMU"]; - [NSCursor unhide]; - CGAssociateMouseAndMouseCursorPosition ( TRUE ); - grab = 0; - } - } - break; - - case NSKeyDown: - { - int keycode = cocoa_keycode_to_qemu([event keyCode]); - - /* handle command Key Combos */ - if ([event modifierFlags] & NSCommandKeyMask) { - switch ([event keyCode]) { - /* quit */ - case 12: /* q key */ - /* switch to windowed View */ - exit(0); - return; - } - } - - /* handle control + alt Key Combos */ - if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) { - switch (keycode) { - /* toggle Monitor */ - case 0x02 ... 0x0a: /* '1' to '9' keys */ - console_select(keycode - 0x02); - break; - } - } else { - /* handle standard key events */ - if (is_graphic_console()) { - if (keycode & 0x80) //check bit for e0 in front - kbd_put_keycode(0xe0); - kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front - /* handle monitor key events */ - } else { - int keysym = 0; - - switch([event keyCode]) { - case 115: - keysym = QEMU_KEY_HOME; - break; - case 117: - keysym = QEMU_KEY_DELETE; - break; - case 119: - keysym = QEMU_KEY_END; - break; - case 123: - keysym = QEMU_KEY_LEFT; - break; - case 124: - keysym = QEMU_KEY_RIGHT; - break; - case 125: - keysym = QEMU_KEY_DOWN; - break; - case 126: - keysym = QEMU_KEY_UP; - break; - default: - { - NSString *ks = [event characters]; - - if ([ks length] > 0) - keysym = [ks characterAtIndex:0]; - } - } - if (keysym) - kbd_put_keysym(keysym); - } - } - } - break; - - case NSKeyUp: - { - int keycode = cocoa_keycode_to_qemu([event keyCode]); - if (is_graphic_console()) { - if (keycode & 0x80) - kbd_put_keycode(0xe0); - kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key - } - } - break; + QEMUScreen screen; + NSWindow *fullScreenWindow; + float cx,cy,cw,ch,cdx,cdy; + CGDataProviderRef dataProviderRef; + int modifiers_state[256]; + BOOL isMouseGrabed; + BOOL isFullscreen; + BOOL isAbsoluteEnabled; + BOOL isTabletEnabled; +} +- (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds; +- (void) grabMouse; +- (void) ungrabMouse; +- (void) toggleFullScreen:(id)sender; +- (void) handleEvent:(NSEvent *)event; +- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled; +- (BOOL) isMouseGrabed; +- (BOOL) isAbsoluteEnabled; +- (float) cdx; +- (float) cdy; +- (QEMUScreen) gscreen; +@end - case NSMouseMoved: - if (grab) { - int dx = [event deltaX]; - int dy = [event deltaY]; - int dz = [event deltaZ]; - int buttons = 0; - kbd_mouse_event(dx, dy, dz, buttons); - } - break; +@implementation QemuCocoaView +- (id)initWithFrame:(NSRect)frameRect +{ + COCOA_DEBUG("QemuCocoaView: initWithFrame\n"); - case NSLeftMouseDown: - if (grab) { - int buttons = 0; - - /* leftclick+command simulates rightclick */ - if ([event modifierFlags] & NSCommandKeyMask) { - buttons |= MOUSE_EVENT_RBUTTON; - } else { - buttons |= MOUSE_EVENT_LBUTTON; - } - kbd_mouse_event(0, 0, 0, buttons); - } else { - [NSApp sendEvent: event]; - } - break; + self = [super initWithFrame:frameRect]; + if (self) { - case NSLeftMouseDragged: - if (grab) { - int dx = [event deltaX]; - int dy = [event deltaY]; - int dz = [event deltaZ]; - int buttons = 0; - if ([[NSApp currentEvent] modifierFlags] & NSCommandKeyMask) { //leftclick+command simulates rightclick - buttons |= MOUSE_EVENT_RBUTTON; - } else { - buttons |= MOUSE_EVENT_LBUTTON; - } - kbd_mouse_event(dx, dy, dz, buttons); - } - break; + screen.bitsPerComponent = 8; + screen.bitsPerPixel = 32; + screen.width = frameRect.size.width; + screen.height = frameRect.size.height; - case NSLeftMouseUp: - if (grab) { - kbd_mouse_event(0, 0, 0, 0); - } else { - [window setTitle: @"QEMU (Press ctrl + alt to release Mouse)"]; - [NSCursor hide]; - CGAssociateMouseAndMouseCursorPosition ( FALSE ); - grab = 1; - //[NSApp sendEvent: event]; - } - break; + } + return self; +} - case NSRightMouseDown: - if (grab) { - int buttons = 0; - - buttons |= MOUSE_EVENT_RBUTTON; - kbd_mouse_event(0, 0, 0, buttons); - } else { - [NSApp sendEvent: event]; - } - break; +- (void) dealloc +{ + COCOA_DEBUG("QemuCocoaView: dealloc\n"); - case NSRightMouseDragged: - if (grab) { - int dx = [event deltaX]; - int dy = [event deltaY]; - int dz = [event deltaZ]; - int buttons = 0; - buttons |= MOUSE_EVENT_RBUTTON; - kbd_mouse_event(dx, dy, dz, buttons); - } - break; + if (screenBuffer) + free(screenBuffer); - case NSRightMouseUp: - if (grab) { - kbd_mouse_event(0, 0, 0, 0); - } else { - [NSApp sendEvent: event]; - } - break; + if (dataProviderRef) + CGDataProviderRelease(dataProviderRef); - case NSOtherMouseDragged: - if (grab) { - int dx = [event deltaX]; - int dy = [event deltaY]; - int dz = [event deltaZ]; - int buttons = 0; - buttons |= MOUSE_EVENT_MBUTTON; - kbd_mouse_event(dx, dy, dz, buttons); - } - break; + [super dealloc]; +} - case NSOtherMouseDown: - if (grab) { - int buttons = 0; - buttons |= MOUSE_EVENT_MBUTTON; - kbd_mouse_event(0, 0, 0, buttons); - } else { - [NSApp sendEvent:event]; - } - break; +- (void) drawRect:(NSRect) rect +{ + COCOA_DEBUG("QemuCocoaView: drawRect\n"); - case NSOtherMouseUp: - if (grab) { - kbd_mouse_event(0, 0, 0, 0); - } else { - [NSApp sendEvent: event]; - } - break; + if ((int)screenBuffer == -1) + return; - case NSScrollWheel: - if (grab) { - int dz = [event deltaY]; - kbd_mouse_event(0, 0, -dz, 0); - } - break; + // get CoreGraphic context + CGContextRef viewContextRef = [[NSGraphicsContext currentContext] graphicsPort]; + CGContextSetInterpolationQuality (viewContextRef, kCGInterpolationNone); + CGContextSetShouldAntialias (viewContextRef, NO); - default: [NSApp sendEvent:event]; + // draw screen bitmap directly to Core Graphics context + if (dataProviderRef) { + CGImageRef imageRef = CGImageCreate( + screen.width, //width + screen.height, //height + screen.bitsPerComponent, //bitsPerComponent + screen.bitsPerPixel, //bitsPerPixel + (screen.width * 4), //bytesPerRow +#if __LITTLE_ENDIAN__ + CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), //colorspace for OS X >= 10.4 + kCGImageAlphaNoneSkipLast, +#else + CGColorSpaceCreateDeviceRGB(), //colorspace for OS X < 10.4 (actually ppc) + kCGImageAlphaNoneSkipFirst, //bitmapInfo +#endif + dataProviderRef, //provider + NULL, //decode + 0, //interpolate + kCGRenderingIntentDefault //intent + ); +// test if host support "CGImageCreateWithImageInRect" at compiletime +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) + if (CGImageCreateWithImageInRect == NULL) { // test if "CGImageCreateWithImageInRect" is supported on host at runtime +#endif + // compatibility drawing code (draws everything) (OS X < 10.4) + CGContextDrawImage (viewContextRef, CGRectMake(0, 0, [self bounds].size.width, [self bounds].size.height), imageRef); +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) + } else { + // selective drawing code (draws only dirty rectangles) (OS X >= 10.4) + const NSRect *rectList; + int rectCount; + int i; + CGImageRef clipImageRef; + CGRect clipRect; + + [self getRectsBeingDrawn:&rectList count:&rectCount]; + for (i = 0; i < rectCount; i++) { + clipRect.origin.x = rectList[i].origin.x / cdx; + clipRect.origin.y = (float)screen.height - (rectList[i].origin.y + rectList[i].size.height) / cdy; + clipRect.size.width = rectList[i].size.width / cdx; + clipRect.size.height = rectList[i].size.height / cdy; + clipImageRef = CGImageCreateWithImageInRect( + imageRef, + clipRect + ); + CGContextDrawImage (viewContextRef, cgrect(rectList[i]), clipImageRef); + CGImageRelease (clipImageRef); } } - } while(event != nil); +#endif + CGImageRelease (imageRef); + } } -/* - ------------------------------------------------------ - cocoa_cleanup - ------------------------------------------------------ -*/ - -static void cocoa_cleanup(void) +- (void) setContentDimensions { + COCOA_DEBUG("QemuCocoaView: setContentDimensions\n"); + if (isFullscreen) { + cdx = [[NSScreen mainScreen] frame].size.width / (float)screen.width; + cdy = [[NSScreen mainScreen] frame].size.height / (float)screen.height; + cw = screen.width * cdx; + ch = screen.height * cdy; + cx = ([[NSScreen mainScreen] frame].size.width - cw) / 2.0; + cy = ([[NSScreen mainScreen] frame].size.height - ch) / 2.0; + } else { + cx = 0; + cy = 0; + cw = screen.width; + ch = screen.height; + cdx = 1.0; + cdy = 1.0; + } } -/* - ------------------------------------------------------ - cocoa_display_init - ------------------------------------------------------ -*/ - -void cocoa_display_init(DisplayState *ds, int full_screen) +- (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds { - ds->dpy_update = cocoa_update; - ds->dpy_resize = cocoa_resize; - ds->dpy_refresh = cocoa_refresh; + COCOA_DEBUG("QemuCocoaView: resizeContent\n"); - cocoa_resize(ds, 640, 400); + // update screenBuffer + if (dataProviderRef) + CGDataProviderRelease(dataProviderRef); + if (screenBuffer) + free(screenBuffer); + screenBuffer = malloc( w * 4 * h ); + + ds->data = screenBuffer; + ds->linesize = (w * 4); + ds->depth = 32; + ds->width = w; + ds->height = h; +#ifdef __LITTLE_ENDIAN__ + ds->bgr = 1; +#else + ds->bgr = 0; +#endif - atexit(cocoa_cleanup); + dataProviderRef = CGDataProviderCreateWithData(NULL, screenBuffer, w * 4 * h, NULL); + + // update windows + if (isFullscreen) { + [[fullScreenWindow contentView] setFrame:[[NSScreen mainScreen] frame]]; + [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:NO animate:NO]; + } else { + if (qemu_name) + [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]]; + [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:YES animate:YES]; + } + screen.width = w; + screen.height = h; + [self setContentDimensions]; + [self setFrame:NSMakeRect(cx, cy, cw, ch)]; +} + +- (void) toggleFullScreen:(id)sender +{ + COCOA_DEBUG("QemuCocoaView: toggleFullScreen\n"); + + if (isFullscreen) { // switch from fullscreen to desktop + isFullscreen = FALSE; + [self ungrabMouse]; + [self setContentDimensions]; +// test if host support "enterFullScreenMode:withOptions" at compiletime +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) + if ([NSView respondsToSelector:@selector(exitFullScreenModeWithOptions:)]) { // test if "exitFullScreenModeWithOptions" is supported on host at runtime + [self exitFullScreenModeWithOptions:nil]; + } else { +#endif + [fullScreenWindow close]; + [normalWindow setContentView: self]; + [normalWindow makeKeyAndOrderFront: self]; + [NSMenu setMenuBarVisible:YES]; +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) + } +#endif + } else { // switch from desktop to fullscreen + isFullscreen = TRUE; + [self grabMouse]; + [self setContentDimensions]; +// test if host support "enterFullScreenMode:withOptions" at compiletime +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) + if ([NSView respondsToSelector:@selector(enterFullScreenMode:withOptions:)]) { // test if "enterFullScreenMode:withOptions" is supported on host at runtime + [self enterFullScreenMode:[NSScreen mainScreen] withOptions:[NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:NO], NSFullScreenModeAllScreens, + [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], kCGDisplayModeIsStretched, nil], NSFullScreenModeSetting, + nil]]; + } else { +#endif + [NSMenu setMenuBarVisible:NO]; + fullScreenWindow = [[NSWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame] + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO]; + [fullScreenWindow setHasShadow:NO]; + [fullScreenWindow setContentView:self]; + [fullScreenWindow makeKeyAndOrderFront:self]; +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) + } +#endif + } } -/* - ------------------------------------------------------ - Interface with Cocoa - ------------------------------------------------------ -*/ +- (void) handleEvent:(NSEvent *)event +{ + COCOA_DEBUG("QemuCocoaView: handleEvent\n"); + int buttons = 0; + int keycode; + NSPoint p = [event locationInWindow]; + + switch ([event type]) { + case NSFlagsChanged: + keycode = cocoa_keycode_to_qemu([event keyCode]); + if (keycode) { + if (keycode == 58 || keycode == 69) { // emulate caps lock and num lock keydown and keyup + kbd_put_keycode(keycode); + kbd_put_keycode(keycode | 0x80); + } else if (is_graphic_console()) { + if (keycode & 0x80) + kbd_put_keycode(0xe0); + if (modifiers_state[keycode] == 0) { // keydown + kbd_put_keycode(keycode & 0x7f); + modifiers_state[keycode] = 1; + } else { // keyup + kbd_put_keycode(keycode | 0x80); + modifiers_state[keycode] = 0; + } + } + } -/* - ------------------------------------------------------ - QemuWindow - Some trick from SDL to use miniwindow - ------------------------------------------------------ -*/ -static void QZ_SetPortAlphaOpaque () -{ - /* Assume 32 bit if( bpp == 32 )*/ - if ( 1 ) { + // release Mouse grab when pressing ctrl+alt + if (!isFullscreen && ([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) { + [self ungrabMouse]; + } + break; + case NSKeyDown: - uint32_t *pixels = (uint32_t*) current_ds.data; - uint32_t rowPixels = current_ds.linesize / 4; - uint32_t i, j; + // forward command Key Combos + if ([event modifierFlags] & NSCommandKeyMask) { + [NSApp sendEvent:event]; + return; + } - for (i = 0; i < current_ds.height; i++) - for (j = 0; j < current_ds.width; j++) { + // default + keycode = cocoa_keycode_to_qemu([event keyCode]); - pixels[ (i * rowPixels) + j ] |= 0xFF000000; + // handle control + alt Key Combos (ctrl+alt is reserved for QEMU) + if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) { + switch (keycode) { + + // enable graphic console + case 0x02 ... 0x0a: // '1' to '9' keys + console_select(keycode - 0x02); + break; + } + + // handle keys for graphic console + } else if (is_graphic_console()) { + if (keycode & 0x80) //check bit for e0 in front + kbd_put_keycode(0xe0); + kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front + + // handlekeys for Monitor + } else { + int keysym = 0; + switch([event keyCode]) { + case 115: + keysym = QEMU_KEY_HOME; + break; + case 117: + keysym = QEMU_KEY_DELETE; + break; + case 119: + keysym = QEMU_KEY_END; + break; + case 123: + keysym = QEMU_KEY_LEFT; + break; + case 124: + keysym = QEMU_KEY_RIGHT; + break; + case 125: + keysym = QEMU_KEY_DOWN; + break; + case 126: + keysym = QEMU_KEY_UP; + break; + default: + { + NSString *ks = [event characters]; + if ([ks length] > 0) + keysym = [ks characterAtIndex:0]; + } + } + if (keysym) + kbd_put_keysym(keysym); + } + break; + case NSKeyUp: + keycode = cocoa_keycode_to_qemu([event keyCode]); + if (is_graphic_console()) { + if (keycode & 0x80) + kbd_put_keycode(0xe0); + kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key } + break; + case NSMouseMoved: + if (isAbsoluteEnabled) { + if (p.x < 0 || p.x > screen.width || p.y < 0 || p.y > screen.height || ![[self window] isKeyWindow]) { + if (isTabletEnabled) { // if we leave the window, deactivate the tablet + [NSCursor unhide]; + isTabletEnabled = FALSE; + } + } else { + if (!isTabletEnabled) { // if we enter the window, activate the tablet + [NSCursor hide]; + isTabletEnabled = TRUE; + } + } + } + COCOA_MOUSE_EVENT + break; + case NSLeftMouseDown: + if ([event modifierFlags] & NSCommandKeyMask) { + buttons |= MOUSE_EVENT_RBUTTON; + } else { + buttons |= MOUSE_EVENT_LBUTTON; + } + COCOA_MOUSE_EVENT + break; + case NSRightMouseDown: + buttons |= MOUSE_EVENT_RBUTTON; + COCOA_MOUSE_EVENT + break; + case NSOtherMouseDown: + buttons |= MOUSE_EVENT_MBUTTON; + COCOA_MOUSE_EVENT + break; + case NSLeftMouseDragged: + if ([event modifierFlags] & NSCommandKeyMask) { + buttons |= MOUSE_EVENT_RBUTTON; + } else { + buttons |= MOUSE_EVENT_LBUTTON; + } + COCOA_MOUSE_EVENT + break; + case NSRightMouseDragged: + buttons |= MOUSE_EVENT_RBUTTON; + COCOA_MOUSE_EVENT + break; + case NSOtherMouseDragged: + buttons |= MOUSE_EVENT_MBUTTON; + COCOA_MOUSE_EVENT + break; + case NSLeftMouseUp: + if (isTabletEnabled) { + COCOA_MOUSE_EVENT + } else if (!isMouseGrabed) { + if (p.x > -1 && p.x < screen.width && p.y > -1 && p.y < screen.height) { + [self grabMouse]; + } else { + [NSApp sendEvent:event]; + } + } else { + COCOA_MOUSE_EVENT + } + break; + case NSRightMouseUp: + COCOA_MOUSE_EVENT + break; + case NSOtherMouseUp: + COCOA_MOUSE_EVENT + break; + case NSScrollWheel: + if (isTabletEnabled || isMouseGrabed) { + kbd_mouse_event(0, 0, -[event deltaY], 0); + } else { + [NSApp sendEvent:event]; + } + break; + default: + [NSApp sendEvent:event]; } } -@implementation QemuWindow -- (void)miniaturize:(id)sender +- (void) grabMouse { + COCOA_DEBUG("QemuCocoaView: grabMouse\n"); - /* make the alpha channel opaque so anim won't have holes in it */ - QZ_SetPortAlphaOpaque (); - - [ super miniaturize:sender ]; - + if (!isFullscreen) { + if (qemu_name) + [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s - (Press ctrl + alt to release Mouse)", qemu_name]]; + else + [normalWindow setTitle:@"QEMU - (Press ctrl + alt to release Mouse)"]; + } + [NSCursor hide]; + CGAssociateMouseAndMouseCursorPosition(FALSE); + isMouseGrabed = TRUE; // while isMouseGrabed = TRUE, QemuCocoaApp sends all events to [cocoaView handleEvent:] } -- (void)display -{ - /* - This method fires just before the window deminaturizes from the Dock. - - We'll save the current visible surface, let the window manager redraw any - UI elements, and restore the SDL surface. This way, no expose event - is required, and the deminiaturize works perfectly. - */ - - /* make sure pixels are fully opaque */ - QZ_SetPortAlphaOpaque (); - - /* save current visible SDL surface */ - [ self cacheImageInRect:[ qd_view frame ] ]; - /* let the window manager redraw controls, border, etc */ - [ super display ]; +- (void) ungrabMouse +{ + COCOA_DEBUG("QemuCocoaView: ungrabMouse\n"); - /* restore visible SDL surface */ - [ self restoreCachedImage ]; + if (!isFullscreen) { + if (qemu_name) + [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]]; + else + [normalWindow setTitle:@"QEMU"]; + } + [NSCursor unhide]; + CGAssociateMouseAndMouseCursorPosition(TRUE); + isMouseGrabed = FALSE; } +- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {isAbsoluteEnabled = tIsAbsoluteEnabled;} +- (BOOL) isMouseGrabed {return isMouseGrabed;} +- (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;} +- (float) cdx {return cdx;} +- (float) cdy {return cdy;} +- (QEMUScreen) gscreen {return screen;} @end + /* ------------------------------------------------------ - QemuCocoaGUIController - NSApp's delegate - indeed main object + QemuCocoaAppController ------------------------------------------------------ */ - -@interface QemuCocoaGUIController : NSObject +@interface QemuCocoaAppController : NSObject { } -- (void)applicationDidFinishLaunching: (NSNotification *) note; -- (void)applicationWillTerminate:(NSNotification *)aNotification; - -- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo; - - (void)startEmulationWithArgc:(int)argc argv:(char**)argv; +- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo; +- (void)toggleFullScreen:(id)sender; +- (void)showQEMUDoc:(id)sender; +- (void)showQEMUTec:(id)sender; @end -@implementation QemuCocoaGUIController -/* Called when the internal event loop has just started running */ -- (void)applicationDidFinishLaunching: (NSNotification *) note +@implementation QemuCocoaAppController +- (id) init { + COCOA_DEBUG("QemuCocoaAppController: init\n"); - /* Display an open dialog box if no argument were passed or - if qemu was launched from the finder ( the Finder passes "-psn" ) */ + self = [super init]; + if (self) { - if( gArgc <= 1 || strncmp (gArgv[1], "-psn", 4) == 0) - { - NSOpenPanel *op = [[NSOpenPanel alloc] init]; + // create a view and add it to the window + cocoaView = [[QemuCocoaView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 640.0, 480.0)]; + if(!cocoaView) { + fprintf(stderr, "(cocoa) can't create a view\n"); + exit(1); + } - cocoa_resize(¤t_ds, 640, 400); + // create a window + normalWindow = [[NSWindow alloc] initWithContentRect:[cocoaView frame] + styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask + backing:NSBackingStoreBuffered defer:NO]; + if(!normalWindow) { + fprintf(stderr, "(cocoa) can't create window\n"); + exit(1); + } + [normalWindow setAcceptsMouseMovedEvents:YES]; + [normalWindow setTitle:[NSString stringWithFormat:@"QEMU"]]; + [normalWindow setContentView:cocoaView]; + [normalWindow makeKeyAndOrderFront:self]; - [op setPrompt:@"Boot image"]; + } + return self; +} - [op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"]; +- (void) dealloc +{ + COCOA_DEBUG("QemuCocoaAppController: dealloc\n"); + + if (cocoaView) + [cocoaView release]; + [super dealloc]; +} + +- (void)applicationDidFinishLaunching: (NSNotification *) note +{ + COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching\n"); + // Display an open dialog box if no argument were passed or + // if qemu was launched from the finder ( the Finder passes "-psn" ) + if( gArgc <= 1 || strncmp ((char *)gArgv[1], "-psn", 4) == 0) { + NSOpenPanel *op = [[NSOpenPanel alloc] init]; + [op setPrompt:@"Boot image"]; + [op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"]; [op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil] - modalForWindow:window modalDelegate:self + modalForWindow:normalWindow modalDelegate:self didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL]; - } - else - { - /* or Launch Qemu, with the global args */ - [self startEmulationWithArgc:gArgc argv:gArgv]; + } else { + // or Launch Qemu, with the global args + [self startEmulationWithArgc:gArgc argv:(char **)gArgv]; } } - (void)applicationWillTerminate:(NSNotification *)aNotification { - printf("Application will terminate\n"); + COCOA_DEBUG("QemuCocoaAppController: applicationWillTerminate\n"); + qemu_system_shutdown_request(); - /* In order to avoid a crash */ exit(0); } +- (void)startEmulationWithArgc:(int)argc argv:(char**)argv +{ + COCOA_DEBUG("QemuCocoaAppController: startEmulationWithArgc\n"); + + int status; + status = qemu_main(argc, argv); + exit(status); +} + - (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo { - if(returnCode == NSCancelButton) - { - exit(0); - } + COCOA_DEBUG("QemuCocoaAppController: openPanelDidEnd\n"); - if(returnCode == NSOKButton) - { + if(returnCode == NSCancelButton) { + exit(0); + } else if(returnCode == NSOKButton) { char *bin = "qemu"; - char *img = (char*)[ [ sheet filename ] cString]; + char *img = (char*)[ [ sheet filename ] cStringUsingEncoding:NSASCIIStringEncoding]; char **argv = (char**)malloc( sizeof(char*)*3 ); @@ -793,24 +811,33 @@ [self startEmulationWithArgc:3 argv:(char**)argv]; } } +- (void)toggleFullScreen:(id)sender +{ + COCOA_DEBUG("QemuCocoaAppController: toggleFullScreen\n"); -- (void)startEmulationWithArgc:(int)argc argv:(char**)argv + [cocoaView toggleFullScreen:sender]; +} + +- (void)showQEMUDoc:(id)sender { - int status; - /* Launch Qemu */ - printf("starting qemu...\n"); - status = qemu_main (argc, argv); - exit(status); + COCOA_DEBUG("QemuCocoaAppController: showQEMUDoc\n"); + + [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-doc.html", + [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"]; +} + +- (void)showQEMUTec:(id)sender +{ + COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n"); + + [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-tech.html", + [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"]; } @end -/* - ------------------------------------------------------ - Application Creation - ------------------------------------------------------ -*/ -/* Dock Connection */ + +// Dock Connection typedef struct CPSProcessSerNum { UInt32 lo; @@ -821,114 +848,148 @@ extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); -/* Menu Creation */ -static void setApplicationMenu(void) -{ - /* warning: this code is very odd */ - NSMenu *appleMenu; - NSMenuItem *menuItem; - NSString *title; - NSString *appName; - - appName = @"Qemu"; - appleMenu = [[NSMenu alloc] initWithTitle:@""]; +int main (int argc, const char * argv[]) { - /* Add menu items */ - title = [@"About " stringByAppendingString:appName]; - [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; + gArgc = argc; + gArgv = (char **)argv; + CPSProcessSerNum PSN; - [appleMenu addItem:[NSMenuItem separatorItem]]; + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + [NSApplication sharedApplication]; - title = [@"Hide " stringByAppendingString:appName]; - [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; + if (!CPSGetCurrentProcess(&PSN)) + if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) + if (!CPSSetFrontProcess(&PSN)) + [NSApplication sharedApplication]; - menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; - [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; + // Add menus + NSMenu *menu; + NSMenuItem *menuItem; - [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; + [NSApp setMainMenu:[[NSMenu alloc] init]]; - [appleMenu addItem:[NSMenuItem separatorItem]]; + // Application menu + menu = [[NSMenu alloc] initWithTitle:@""]; + [menu addItemWithTitle:@"About QEMU" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; // About QEMU + [menu addItem:[NSMenuItem separatorItem]]; //Separator + [menu addItemWithTitle:@"Hide QEMU" action:@selector(hide:) keyEquivalent:@"h"]; //Hide QEMU + menuItem = (NSMenuItem *)[menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; // Hide Others + [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; + [menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; // Show All + [menu addItem:[NSMenuItem separatorItem]]; //Separator + [menu addItemWithTitle:@"Quit QEMU" action:@selector(terminate:) keyEquivalent:@"q"]; + menuItem = [[NSMenuItem alloc] initWithTitle:@"Apple" action:nil keyEquivalent:@""]; + [menuItem setSubmenu:menu]; + [[NSApp mainMenu] addItem:menuItem]; + [NSApp performSelector:@selector(setAppleMenu:) withObject:menu]; // Workaround (this method is private since 10.4+) - title = [@"Quit " stringByAppendingString:appName]; - [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; + // View menu + menu = [[NSMenu alloc] initWithTitle:@"View"]; + [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Enter Fullscreen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"] autorelease]]; // Fullscreen + menuItem = [[[NSMenuItem alloc] initWithTitle:@"View" action:nil keyEquivalent:@""] autorelease]; + [menuItem setSubmenu:menu]; + [[NSApp mainMenu] addItem:menuItem]; + // Window menu + menu = [[NSMenu alloc] initWithTitle:@"Window"]; + [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"] autorelease]]; // Miniaturize + menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease]; + [menuItem setSubmenu:menu]; + [[NSApp mainMenu] addItem:menuItem]; + [NSApp setWindowsMenu:menu]; - /* Put menu into the menubar */ - menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; - [menuItem setSubmenu:appleMenu]; + // Help menu + menu = [[NSMenu alloc] initWithTitle:@"Help"]; + [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Documentation" action:@selector(showQEMUDoc:) keyEquivalent:@"?"] autorelease]]; // QEMU Help + [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Technology" action:@selector(showQEMUTec:) keyEquivalent:@""] autorelease]]; // QEMU Help + menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease]; + [menuItem setSubmenu:menu]; [[NSApp mainMenu] addItem:menuItem]; - /* Tell the application object that this is now the application menu */ - [NSApp setAppleMenu:appleMenu]; + // Create an Application controller + QemuCocoaAppController *appController = [[QemuCocoaAppController alloc] init]; + [NSApp setDelegate:appController]; - /* Finally give up our references to the objects */ - [appleMenu release]; - [menuItem release]; -} + // Start the main event loop + [NSApp run]; -/* Create a window menu */ -static void setupWindowMenu(void) -{ - NSMenu *windowMenu; - NSMenuItem *windowMenuItem; - NSMenuItem *menuItem; + [appController release]; + [pool release]; - windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; + return 0; +} - /* "Minimize" item */ - menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; - [windowMenu addItem:menuItem]; - [menuItem release]; - /* Put menu into the menubar */ - windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; - [windowMenuItem setSubmenu:windowMenu]; - [[NSApp mainMenu] addItem:windowMenuItem]; - /* Tell the application object that this is now the window menu */ - [NSApp setWindowsMenu:windowMenu]; +#pragma mark qemu +static void cocoa_update(DisplayState *ds, int x, int y, int w, int h) +{ + COCOA_DEBUG("qemu_cocoa: cocoa_update\n"); - /* Finally give up our references to the objects */ - [windowMenu release]; - [windowMenuItem release]; + NSRect rect; + if ([cocoaView cdx] == 1.0) { + rect = NSMakeRect(x, [cocoaView gscreen].height - y - h, w, h); + } else { + rect = NSMakeRect( + x * [cocoaView cdx], + ([cocoaView gscreen].height - y - h) * [cocoaView cdy], + w * [cocoaView cdx], + h * [cocoaView cdy]); + } + [cocoaView displayRect:rect]; } -static void CustomApplicationMain(void) +static void cocoa_resize(DisplayState *ds, int w, int h) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - QemuCocoaGUIController *gui_controller; - CPSProcessSerNum PSN; + COCOA_DEBUG("qemu_cocoa: cocoa_resize\n"); - [NSApplication sharedApplication]; + [cocoaView resizeContentToWidth:w height:h displayState:ds]; +} - if (!CPSGetCurrentProcess(&PSN)) - if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) - if (!CPSSetFrontProcess(&PSN)) - [NSApplication sharedApplication]; +static void cocoa_refresh(DisplayState *ds) +{ + COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n"); - /* Set up the menubar */ - [NSApp setMainMenu:[[NSMenu alloc] init]]; - setApplicationMenu(); - setupWindowMenu(); + if (kbd_mouse_is_absolute()) { + if (![cocoaView isAbsoluteEnabled]) { + if ([cocoaView isMouseGrabed]) { + [cocoaView ungrabMouse]; + } + } + [cocoaView setAbsoluteEnabled:YES]; + } - /* Create SDLMain and make it the app delegate */ - gui_controller = [[QemuCocoaGUIController alloc] init]; - [NSApp setDelegate:gui_controller]; + NSDate *distantPast; + NSEvent *event; + distantPast = [NSDate distantPast]; + do { + event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast + inMode: NSDefaultRunLoopMode dequeue:YES]; + if (event != nil) { + [cocoaView handleEvent:event]; + } + } while(event != nil); + vga_hw_update(); +} - /* Start the main event loop */ - [NSApp run]; +static void cocoa_cleanup(void) +{ + COCOA_DEBUG("qemu_cocoa: cocoa_cleanup\n"); - [gui_controller release]; - [pool release]; } -/* Real main of qemu-cocoa */ -int main(int argc, char **argv) +void cocoa_display_init(DisplayState *ds, int full_screen) { - gArgc = argc; - gArgv = argv; + COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n"); - CustomApplicationMain(); + // register vga outpu callbacks + ds->dpy_update = cocoa_update; + ds->dpy_resize = cocoa_resize; + ds->dpy_refresh = cocoa_refresh; - return 0; + // give window a initial Size + cocoa_resize(ds, 640, 400); + + // register cleanup function + atexit(cocoa_cleanup); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/configure /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/configure --- qemu-0.9.1/configure 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/configure 2008-11-05 19:59:25.000000000 +0000 @@ -15,6 +15,7 @@ TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o" TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}" TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S" +TMPI="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.i" # default parameters prefix="" @@ -24,6 +25,8 @@ cc="gcc" gcc3_search="yes" gcc3_list="gcc-3.4.6 gcc-3.4 gcc34 gcc-3.3.6 gcc-3.3 gcc33 gcc-3.2 gcc32" +audio_drv_list="" +audio_card_list="" host_cc="gcc" ar="ar" make="make" @@ -35,17 +38,29 @@ i386|i486|i586|i686|i86pc|BePC) cpu="i386" ;; + x86_64|amd64) + cpu="x86_64" + ;; + alpha) + cpu="alpha" + ;; armv*b) cpu="armv4b" ;; armv*l) cpu="armv4l" ;; - alpha) - cpu="alpha" + cris) + cpu="cris" ;; - "Power Macintosh"|ppc|ppc64) - cpu="powerpc" + parisc|parisc64) + cpu="hppa" + ;; + ia64) + cpu="ia64" + ;; + m68k) + cpu="m68k" ;; mips) cpu="mips" @@ -53,8 +68,8 @@ mips64) cpu="mips64" ;; - cris) - cpu="cris" + "Power Macintosh"|ppc|ppc64) + cpu="powerpc" ;; s390*) cpu="s390" @@ -65,36 +80,25 @@ sparc64) cpu="sparc64" ;; - ia64) - cpu="ia64" - ;; - m68k) - cpu="m68k" - ;; - x86_64|amd64) - cpu="x86_64" - ;; *) cpu="unknown" ;; esac gprof="no" +sparse="no" bigendian="no" mingw32="no" EXESUF="" gdbstub="yes" slirp="yes" -adlib="no" -oss="no" -dsound="no" -coreaudio="no" -alsa="no" -fmod="no" +vde="yes" fmod_lib="" fmod_inc="" +oss_lib="" vnc_tls="yes" bsd="no" linux="no" +solaris="no" kqemu="no" profiler="no" cocoa="no" @@ -103,8 +107,16 @@ softmmu="yes" linux_user="no" darwin_user="no" +bsd_user="no" build_docs="no" uname_release="" +curses="yes" +aio="yes" +nptl="yes" +mixemu="no" +bluez="yes" +kvm="yes" +kerneldir="" # OS specific targetos=`uname -s` @@ -112,45 +124,54 @@ CYGWIN*) mingw32="yes" OS_CFLAGS="-mno-cygwin" -VL_OS_LDFLAGS="-mno-cygwin" if [ "$cpu" = "i386" ] ; then kqemu="yes" fi +audio_possible_drivers="sdl" ;; MINGW32*) mingw32="yes" if [ "$cpu" = "i386" ] ; then kqemu="yes" fi +audio_possible_drivers="dsound sdl fmod" ;; GNU/kFreeBSD) -oss="yes" +audio_drv_list="oss" +audio_possible_drivers="oss sdl esd pa" if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then kqemu="yes" fi ;; FreeBSD) bsd="yes" -oss="yes" +audio_drv_list="oss" +audio_possible_drivers="oss sdl esd pa" if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then kqemu="yes" fi ;; NetBSD) bsd="yes" -oss="yes" +audio_drv_list="oss" +audio_possible_drivers="oss sdl esd" ;; OpenBSD) bsd="yes" -oss="yes" +openbsd="yes" +audio_drv_list="oss" +audio_possible_drivers="oss sdl esd" +oss_lib="-lossaudio" ;; Darwin) bsd="yes" darwin="yes" darwin_user="yes" cocoa="yes" -coreaudio="yes" +audio_drv_list="coreaudio" +audio_possible_drivers="coreaudio sdl fmod" OS_CFLAGS="-mdynamic-no-pic" +OS_LDFLAGS="-framework CoreFoundation -framework IOKit" ;; SunOS) solaris="yes" @@ -181,15 +202,18 @@ fi fi if test -f /usr/include/sys/soundcard.h ; then - oss=yes + audio_drv_list="oss" fi + audio_possible_drivers="oss sdl" ;; *) -oss="yes" +audio_drv_list="oss" +audio_possible_drivers="oss alsa sdl esd pa" linux="yes" linux_user="yes" if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then kqemu="yes" + audio_possible_drivers="$audio_possible_drivers fmod" fi ;; esac @@ -198,20 +222,19 @@ if [ "$darwin" != "yes" ] ; then make="gmake" fi + bsd_user="yes" fi # find source path source_path=`dirname "$0"` +source_path_used="no" +workdir=`pwd` if [ -z "$source_path" ]; then - source_path=`pwd` + source_path=$workdir else source_path=`cd "$source_path"; pwd` fi -if test "$source_path" = `pwd` ; then - source_path_used="no" -else - source_path_used="yes" -fi +[ -f "$workdir/vl.c" ] || source_path_used="yes" werror="no" # generate compile errors on warnings for development builds @@ -256,31 +279,40 @@ ;; --disable-sdl) sdl="no" ;; - --enable-coreaudio) coreaudio="yes" + --fmod-lib=*) fmod_lib="$optarg" ;; - --enable-alsa) alsa="yes" + --fmod-inc=*) fmod_inc="$optarg" ;; - --enable-dsound) dsound="yes" + --oss-lib=*) oss_lib="$optarg" ;; - --enable-fmod) fmod="yes" + --audio-card-list=*) audio_card_list=`echo "$optarg" | sed -e 's/,/ /g'` ;; - --fmod-lib=*) fmod_lib="$optarg" + --audio-drv-list=*) audio_drv_list="$optarg" ;; - --fmod-inc=*) fmod_inc="$optarg" + --enable-sparse) sparse="yes" ;; - --disable-vnc-tls) vnc_tls="no" + --disable-sparse) sparse="no" ;; - --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; linux_user="no" + --disable-vnc-tls) vnc_tls="no" ;; --disable-slirp) slirp="no" ;; - --enable-adlib) adlib="yes" + --disable-vde) vde="no" ;; --disable-kqemu) kqemu="no" ;; + --disable-brlapi) brlapi="no" + ;; + --disable-bluez) bluez="no" + ;; + --disable-kvm) kvm="no" + ;; --enable-profiler) profiler="yes" ;; - --enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no" + --enable-cocoa) + cocoa="yes" ; + sdl="no" ; + audio_drv_list="coreaudio `echo $audio_drv_list | sed s,coreaudio,,g`" ;; --disable-gfx-check) check_gfx="no" ;; @@ -298,6 +330,10 @@ ;; --enable-darwin-user) darwin_user="yes" ;; + --disable-bsd-user) bsd_user="no" + ;; + --enable-bsd-user) bsd_user="yes" + ;; --enable-uname-release=*) uname_release="$optarg" ;; --sparc_cpu=*) @@ -316,30 +352,40 @@ ;; --disable-werror) werror="no" ;; + --disable-curses) curses="no" + ;; + --disable-nptl) nptl="no" + ;; + --enable-mixemu) mixemu="yes" + ;; + --disable-aio) aio="no" + ;; + --kerneldir=*) kerneldir="$optarg" + ;; *) echo "ERROR: unknown option $opt"; show_help="yes" ;; esac done -if [ "$bsd" = "yes" -o "$darwin" = "yes" -o "$mingw32" = "yes" ] ; then - AIOLIBS= -else - # Some Linux architectures (e.g. s390) don't imply -lpthread automatically. - AIOLIBS="-lrt -lpthread" -fi - # default flags for all hosts -CFLAGS="$CFLAGS -Wall -O2 -g -fno-strict-aliasing" +CFLAGS="$CFLAGS -O2 -g -fno-strict-aliasing" +CFLAGS="$CFLAGS -Wall -Wundef -Wendif-labels -Wwrite-strings" LDFLAGS="$LDFLAGS -g" if test "$werror" = "yes" ; then CFLAGS="$CFLAGS -Werror" fi +if test "$solaris" = "no" ; then + if ld --version 2>/dev/null | grep "GNU ld" >/dev/null 2>/dev/null ; then + LDFLAGS="$LDFLAGS -Wl,--warn-common" + fi +fi + # # If cpu ~= sparc and sparc_cpu hasn't been defined, plug in the right # ARCH_CFLAGS/ARCH_LDFLAGS (assume sparc_v8plus for 32-bit and sparc_v9 for 64-bit) # -case $cpu in +case "$cpu" in sparc) if test -z "$sparc_cpu" ; then ARCH_CFLAGS="-m32 -mcpu=ultrasparc -D__sparc_v8plus__" ARCH_LDFLAGS="-m32" @@ -359,19 +405,16 @@ s390) ARCH_CFLAGS="-march=z900" ;; + i386) + ARCH_CFLAGS="-m32" + ARCH_LDFLAGS="-m32" + ;; + x86_64) + ARCH_CFLAGS="-m64" + ARCH_LDFLAGS="-m64" + ;; esac -if [ "$solaris" = "yes" -a "$cpu" = "x86_64" ] ; then - CFLAGS="${CFLAGS} -m64" - OS_CFLAGS="${OS_CFLAGS} -m64" - OS_LDFLAGS="${OS_LDFLAGS} -m64" -fi - -if [ "$solaris" = "yes" -a "$cpu" = "i386" ] ; then - CFLAGS="${CFLAGS} -m32" - OS_CFLAGS="${OS_CFLAGS} -m32" -fi - if test x"$show_help" = x"yes" ; then cat << EOF @@ -397,26 +440,38 @@ echo " --make=MAKE use specified make [$make]" echo " --install=INSTALL use specified install [$install]" echo " --static enable static build [$static]" +echo " --enable-sparse enable sparse checker" +echo " --disable-sparse disable sparse checker (default)" echo " --disable-werror disable compilation abort on warning" echo " --disable-sdl disable SDL" echo " --enable-cocoa enable COCOA (Mac OS X only)" -echo " --enable-mingw32 enable Win32 cross compilation with mingw32" -echo " --enable-adlib enable Adlib emulation" -echo " --enable-coreaudio enable Coreaudio audio driver" -echo " --enable-alsa enable ALSA audio driver" -echo " --enable-fmod enable FMOD audio driver" -echo " --enable-dsound enable DirectSound audio driver" +echo " --audio-drv-list=LIST set audio drivers list:" +echo " Available drivers: $audio_possible_drivers" +echo " --audio-card-list=LIST set list of additional emulated audio cards" +echo " Available cards: ac97 adlib cs4231a gus" +echo " --enable-mixemu enable mixer emulation" +echo " --disable-brlapi disable BrlAPI" echo " --disable-vnc-tls disable TLS encryption for VNC server" +echo " --disable-curses disable curses output" +echo " --disable-bluez disable bluez stack connectivity" +echo " --disable-kvm disable KVM acceleration support" +echo " --disable-nptl disable usermode NPTL support" echo " --enable-system enable all system emulation targets" echo " --disable-system disable all system emulation targets" echo " --enable-linux-user enable all linux usermode emulation targets" echo " --disable-linux-user disable all linux usermode emulation targets" echo " --enable-darwin-user enable all darwin usermode emulation targets" echo " --disable-darwin-user disable all darwin usermode emulation targets" +echo " --enable-bsd-user enable all BSD usermode emulation targets" +echo " --disable-bsd-user disable all BSD usermode emulation targets" echo " --fmod-lib path to FMOD library" echo " --fmod-inc path to FMOD includes" +echo " --oss-lib path to OSS library" echo " --enable-uname-release=R Return R for uname -r in usermode emulation" echo " --sparc_cpu=V Build qemu for Sparc architecture v7, v8, v8plus, v8plusa, v9" +echo " --disable-vde disable support for vde network" +echo " --disable-aio disable AIO support" +echo " --kerneldir=PATH look for kernel includes in PATH" echo "" echo "NOTE: The object files are built at the place where configure is launched" exit 1 @@ -431,17 +486,41 @@ int main(void) {} EOF -if $cc -c -o $TMPO $TMPC 2> /dev/null ; then +if $cc $ARCH_CFLAGS -c -o $TMPO $TMPC 2> /dev/null ; then : C compiler works ok else echo "ERROR: \"$cc\" either does not exist or does not work" exit 1 fi +# check compiler to see if we're on mingw32 +cat > $TMPC < +#ifndef _WIN32 +#error not windows +#endif +int main(void) {} +EOF + +if $cc $ARCH_CFLAGS -c -o $TMPO $TMPC 2> /dev/null ; then + mingw32="yes" +fi + if test "$mingw32" = "yes" ; then linux="no" EXESUF=".exe" oss="no" + linux_user="no" + bsd_user="no" +fi + +if [ "$darwin" = "yes" -o "$mingw32" = "yes" ] ; then + AIOLIBS= +elif [ "$bsd" = "yes" ]; then + AIOLIBS="-lpthread" +else + # Some Linux architectures (e.g. s390) don't imply -lpthread automatically. + AIOLIBS="-lrt -lpthread" fi # Check for gcc4, error if pre-gcc4 @@ -452,7 +531,7 @@ #endif int main(){return 0;} EOF - if "$cc" -o $TMPE $TMPC 2> /dev/null ; then + if "$cc" $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then echo "WARNING: \"$cc\" looks like gcc 4.x" found_compat_cc="no" if test "$gcc3_search" = "yes" ; then @@ -478,6 +557,10 @@ fi fi +if test ! -x "$(which cgcc 2>/dev/null)"; then + sparse="no" +fi + # # Solaris specific configure tool chain decisions # @@ -522,15 +605,55 @@ if test -z "$target_list" ; then # these targets are portable if [ "$softmmu" = "yes" ] ; then - target_list="i386-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc-softmmu ppcemb-softmmu ppc64-softmmu m68k-softmmu sh4-softmmu sh4eb-softmmu cris-softmmu" + target_list="\ +i386-softmmu \ +x86_64-softmmu \ +arm-softmmu \ +cris-softmmu \ +m68k-softmmu \ +mips-softmmu \ +mipsel-softmmu \ +mips64-softmmu \ +mips64el-softmmu \ +ppc-softmmu \ +ppcemb-softmmu \ +ppc64-softmmu \ +sh4-softmmu \ +sh4eb-softmmu \ +sparc-softmmu \ +" fi # the following are Linux specific if [ "$linux_user" = "yes" ] ; then - target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user sparc64-linux-user sparc32plus-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user sh4-linux-user sh4eb-linux-user ppc-linux-user ppc64-linux-user ppc64abi32-linux-user x86_64-linux-user cris-linux-user $target_list" + target_list="${target_list}\ +i386-linux-user \ +x86_64-linux-user \ +alpha-linux-user \ +arm-linux-user \ +armeb-linux-user \ +cris-linux-user \ +m68k-linux-user \ +mips-linux-user \ +mipsel-linux-user \ +ppc-linux-user \ +ppc64-linux-user \ +ppc64abi32-linux-user \ +sh4-linux-user \ +sh4eb-linux-user \ +sparc-linux-user \ +sparc64-linux-user \ +sparc32plus-linux-user \ +" fi # the following are Darwin specific if [ "$darwin_user" = "yes" ] ; then - target_list="i386-darwin-user ppc-darwin-user $target_list" + target_list="$target_list i386-darwin-user ppc-darwin-user" + fi +# the following are BSD specific + if [ "$bsd_user" = "yes" ] ; then + target_list="${target_list}\ +sparc64-bsd-user \ +" fi else target_list=`echo "$target_list" | sed -e 's/,/ /g'` @@ -552,7 +675,7 @@ } EOF -if $cc -o $TMPE $TMPC 2> /dev/null ; then +if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then $TMPE && bigendian="yes" else echo big/little test failed @@ -561,7 +684,15 @@ else # if cross compiling, cannot launch a program, so make a static guess -if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "mips64" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k" -o "$cpu" = "armv4b"; then +if test "$cpu" = "armv4b" \ + -o "$cpu" = "hppa" \ + -o "$cpu" = "m68k" \ + -o "$cpu" = "mips" \ + -o "$cpu" = "mips64" \ + -o "$cpu" = "powerpc" \ + -o "$cpu" = "s390" \ + -o "$cpu" = "sparc" \ + -o "$cpu" = "sparc64"; then bigendian="yes" fi @@ -569,16 +700,64 @@ # host long bits test hostlongbits="32" -if test "$cpu" = "sparc64" -o "$cpu" = "ia64" -o "$cpu" = "x86_64" -o "$cpu" = "alpha"; then +if test "$cpu" = "x86_64" \ + -o "$cpu" = "alpha" \ + -o "$cpu" = "ia64" \ + -o "$cpu" = "sparc64"; then hostlongbits="64" fi +# ppc specific hostlongbits selection +if test "$cpu" = "powerpc" ; then + if $cc $ARCH_CFLAGS -dM -E - -o $TMPI 2>/dev/null $TMPC < $TMPC < +#include +void foo() +{ +#if !defined(CLONE_SETTLS) || !defined(FUTEX_WAIT) +#error bork +#endif +} +EOF + +if $cc $ARCH_CFLAGS -c -o $TMPO $TMPC 2> /dev/null ; then + : +else + nptl="no" +fi + +########################################## +# zlib check + +cat > $TMPC << EOF +#include +int main(void) { zlibVersion(); return 0; } +EOF +if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $TMPC -lz 2> /dev/null ; then + : +else + echo + echo "Error: zlib check failed" + echo "Make sure to have the zlib libs and headers installed." + echo + exit 1 +fi + ########################################## # SDL probe @@ -589,76 +768,233 @@ sdl=no sdl_static=no - if test "$mingw32" = "yes" -a ! -z "$cross_prefix" ; then - # win32 cross compilation case - sdl_config="i386-mingw32msvc-sdl-config" - sdl=yes - else - # normal SDL probe cat > $TMPC << EOF #include #undef main /* We don't want SDL to override our main() */ int main( void ) { return SDL_Init (SDL_INIT_VIDEO); } EOF - if $cc -o $TMPE ${OS_CFLAGS} `$sdl_config --cflags 2> /dev/null` $TMPC `$sdl_config --libs 2> /dev/null` 2> /tmp/qemu-$$-sdl-config.log ; then - _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'` - if test "$_sdlversion" -lt 121 ; then - sdl_too_old=yes - else - if test "$cocoa" = "no" ; then - sdl=yes - fi + if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} `$sdl_config --cflags 2> /dev/null` $TMPC `$sdl_config --libs 2> /dev/null` 2> /tmp/qemu-$$-sdl-config.log ; then + _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'` + if test "$_sdlversion" -lt 121 ; then + sdl_too_old=yes + else + if test "$cocoa" = "no" ; then + sdl=yes fi + fi - # static link with sdl ? - if test "$sdl" = "yes" ; then - aa="no" - `$sdl_config --static-libs 2>/dev/null | grep \\\-laa > /dev/null` && aa="yes" - sdl_static_libs=`$sdl_config --static-libs 2>/dev/null` - if [ "$aa" = "yes" ] ; then - sdl_static_libs="$sdl_static_libs `aalib-config --static-libs`" - fi - - if $cc -o $TMPE ${OS_CFLAGS} `$sdl_config --cflags 2> /dev/null` $TMPC $sdl_static_libs 2> /dev/null; then - sdl_static=yes - fi - fi # static link - fi # sdl compile test - fi # cross compilation + # static link with sdl ? + if test "$sdl" = "yes" ; then + aa="no" + `$sdl_config --static-libs 2>/dev/null | grep \\\-laa > /dev/null` && aa="yes" + sdl_static_libs=`$sdl_config --static-libs 2>/dev/null` + if [ "$aa" = "yes" ] ; then + sdl_static_libs="$sdl_static_libs `aalib-config --static-libs`" + fi + + if $cc -o $TMPE ${OS_CFLAGS} `$sdl_config --cflags 2> /dev/null` $TMPC $sdl_static_libs 2> /dev/null; then + sdl_static=yes + fi + fi # static link + fi # sdl compile test else # Make sure to disable cocoa if sdl was set if test "$sdl" = "yes" ; then cocoa="no" - coreaudio="no" + audio_drv_list="`echo $audio_drv_list | sed s,coreaudio,,g`" fi fi # -z $sdl ########################################## # VNC TLS detection if test "$vnc_tls" = "yes" ; then - `pkg-config gnutls` || vnc_tls="no" +cat > $TMPC < +int main(void) { gnutls_session_t s; gnutls_init(&s, GNUTLS_SERVER); return 0; } +EOF + vnc_tls_cflags=`pkg-config --cflags gnutls 2> /dev/null` + vnc_tls_libs=`pkg-config --libs gnutls 2> /dev/null` + if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $vnc_tls_cflags $TMPC \ + $vnc_tls_libs 2> /dev/null ; then + : + else + vnc_tls="no" + fi fi -if test "$vnc_tls" = "yes" ; then - vnc_tls_cflags=`pkg-config --cflags gnutls` - vnc_tls_libs=`pkg-config --libs gnutls` + +########################################## +# vde libraries probe +if test "$vde" = "yes" ; then + cat > $TMPC << EOF +#include +int main(void) +{ + struct vde_open_args a = {0, 0, 0}; + vde_open("", "", &a); + return 0; +} +EOF + if $cc $ARCH_CFLAGS -o $TMPE $TMPC -lvdeplug 2> /dev/null ; then + : + else + vde="no" + fi fi ########################################## -# alsa sound support libraries +# Sound support libraries probe + +audio_drv_probe() +{ + drv=$1 + hdr=$2 + lib=$3 + exp=$4 + cfl=$5 + cat > $TMPC << EOF +#include <$hdr> +int main(void) { $exp } +EOF + if $cc $ARCH_CFLAGS $cfl -o $TMPE $TMPC $lib 2> /dev/null ; then + : + else + echo + echo "Error: $drv check failed" + echo "Make sure to have the $drv libs and headers installed." + echo + exit 1 + fi +} + +audio_drv_list=`echo "$audio_drv_list" | sed -e 's/,/ /g'` +for drv in $audio_drv_list; do + case $drv in + alsa) + audio_drv_probe $drv alsa/asoundlib.h -lasound \ + "snd_pcm_t **handle; return snd_pcm_close(*handle);" + ;; + + fmod) + if test -z $fmod_lib || test -z $fmod_inc; then + echo + echo "Error: You must specify path to FMOD library and headers" + echo "Example: --fmod-inc=/path/include/fmod --fmod-lib=/path/lib/libfmod-3.74.so" + echo + exit 1 + fi + audio_drv_probe $drv fmod.h $fmod_lib "return FSOUND_GetVersion();" "-I $fmod_inc" + ;; + + esd) + audio_drv_probe $drv esd.h -lesd 'return esd_play_stream(0, 0, "", 0);' + ;; + + pa) + audio_drv_probe $drv pulse/simple.h -lpulse-simple \ + "pa_simple *s = NULL; pa_simple_free(s); return 0;" + ;; + + oss|sdl|core|wav|dsound) + # XXX: Probes for CoreAudio, DirectSound, SDL(?) + ;; + + *) + echo "$audio_possible_drivers" | grep -q "\<$drv\>" || { + echo + echo "Error: Unknown driver '$drv' selected" + echo "Possible drivers are: $audio_possible_drivers" + echo + exit 1 + } + ;; + esac +done + +########################################## +# BrlAPI probe -if test "$alsa" = "yes" ; then +if test -z "$brlapi" ; then + brlapi=no +cat > $TMPC << EOF +#include +int main( void ) { return brlapi__openConnection (NULL, NULL, NULL); } +EOF + if $cc ${ARCH_CFLAGS} -o $TMPE ${OS_CFLAGS} $TMPC -lbrlapi 2> /dev/null ; then + brlapi=yes + fi # brlapi compile test +fi # -z $brlapi + +########################################## +# curses probe + +if test "$curses" = "yes" ; then + curses=no cat > $TMPC << EOF -#include -int main(void) { snd_pcm_t **handle; return snd_pcm_close(*handle); } +#include +int main(void) { return curses_version(); } EOF - if $cc -o $TMPE $TMPC -lasound 2> /dev/null ; then + if $cc $ARCH_CFLAGS -o $TMPE $TMPC -lcurses 2> /dev/null ; then + curses=yes + fi +fi # test "$curses" + +########################################## +# bluez support probe +if test "$bluez" = "yes" ; then + `pkg-config bluez` || bluez="no" +fi +if test "$bluez" = "yes" ; then + cat > $TMPC << EOF +#include +int main(void) { return bt_error(0); } +EOF + bluez_cflags=`pkg-config --cflags bluez` + bluez_libs=`pkg-config --libs bluez` + if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $bluez_cflags $TMPC \ + $bluez_libs 2> /dev/null ; then : else - echo - echo "Error: Could not find alsa" - echo "Make sure to have the alsa libs and headers installed." - echo - exit 1 + bluez="no" + fi +fi + +########################################## +# kvm probe +if test "$kvm" = "yes" ; then + cat > $TMPC < +#if !defined(KVM_API_VERSION) || \ + KVM_API_VERSION < 12 || \ + KVM_API_VERSION > 12 || \ + !defined(KVM_CAP_USER_MEMORY) || \ + !defined(KVM_CAP_SET_TSS_ADDR) +#error Invalid KVM version +#endif +int main(void) { return 0; } +EOF + if test "$kerneldir" != "" ; then + kvm_cflags=-I"$kerneldir"/include + else + kvm_cflags="" + fi + if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $kvm_cflags $TMPC \ + 2>/dev/null ; then + : + else + kvm="no" + fi +fi + +########################################## +# AIO probe +if test "$aio" = "yes" ; then + aio=no + cat > $TMPC << EOF +#include +int main(void) { return aio_write(NULL); } +EOF + if $cc $ARCH_CFLAGS -o $TMPE $AIOLIBS $TMPC 2> /dev/null ; then + aio=yes fi fi @@ -670,7 +1006,7 @@ if test "$mingw32" = "yes" ; then if test -z "$prefix" ; then - prefix="/c/Program Files/Qemu" + prefix="c:\\\\Program Files\\\\Qemu" fi mansuffix="" datasuffix="" @@ -696,12 +1032,14 @@ echo "Source path $source_path" echo "C compiler $cc" echo "Host C compiler $host_cc" +echo "ARCH_CFLAGS $ARCH_CFLAGS" echo "make $make" echo "install $install" echo "host CPU $cpu" echo "host big endian $bigendian" echo "target list $target_list" echo "gprof enabled $gprof" +echo "sparse enabled $sparse" echo "profiler $profiler" echo "static build $static" echo "-Werror enabled $werror" @@ -712,25 +1050,11 @@ if test "$sdl" != "no" ; then echo "SDL static link $sdl_static" fi +echo "curses support $curses" echo "mingw32 support $mingw32" -echo "Adlib support $adlib" -echo "CoreAudio support $coreaudio" -echo "ALSA support $alsa" -echo "DSound support $dsound" -if test "$fmod" = "yes"; then - if test -z $fmod_lib || test -z $fmod_inc; then - echo - echo "Error: You must specify path to FMOD library and headers" - echo "Example: --fmod-inc=/path/include/fmod --fmod-lib=/path/lib/libfmod-3.74.so" - echo - exit 1 - fi - fmod_support=" (lib='$fmod_lib' include='$fmod_inc')" -else - fmod_support="" -fi -echo "FMOD support $fmod $fmod_support" -echo "OSS support $oss" +echo "Audio drivers $audio_drv_list" +echo "Extra audio cards $audio_card_list" +echo "Mixer emulation $mixemu" echo "VNC TLS support $vnc_tls" if test "$vnc_tls" = "yes" ; then echo " TLS CFLAGS $vnc_tls_cflags" @@ -740,9 +1064,14 @@ echo "Target Sparc Arch $sparc_cpu" fi echo "kqemu support $kqemu" +echo "brlapi support $brlapi" echo "Documentation $build_docs" [ ! -z "$uname_release" ] && \ echo "uname -r $uname_release" +echo "NPTL support $nptl" +echo "vde support $vde" +echo "AIO support $aio" +echo "KVM support $kvm" if test $sdl_too_old = "yes"; then echo "-> Your SDL version is too old - please upgrade to have SDL support" @@ -778,60 +1107,92 @@ echo "HOST_CC=$host_cc" >> $config_mak echo "AR=$ar" >> $config_mak echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak +# XXX: only use CFLAGS and LDFLAGS ? +# XXX: should export HOST_CFLAGS and HOST_LDFLAGS for cross +# compilation of dyngen tool (useful for win32 build on Linux host) echo "OS_CFLAGS=$OS_CFLAGS" >> $config_mak echo "OS_LDFLAGS=$OS_LDFLAGS" >> $config_mak -echo "VL_OS_LDFLAGS=$VL_OS_LDFLAGS" >> $config_mak echo "ARCH_CFLAGS=$ARCH_CFLAGS" >> $config_mak echo "ARCH_LDFLAGS=$ARCH_LDFLAGS" >> $config_mak echo "CFLAGS=$CFLAGS" >> $config_mak echo "LDFLAGS=$LDFLAGS" >> $config_mak echo "EXESUF=$EXESUF" >> $config_mak echo "AIOLIBS=$AIOLIBS" >> $config_mak -if test "$cpu" = "i386" ; then - echo "ARCH=i386" >> $config_mak - echo "#define HOST_I386 1" >> $config_h -elif test "$cpu" = "x86_64" ; then - echo "ARCH=x86_64" >> $config_mak - echo "#define HOST_X86_64 1" >> $config_h -elif test "$cpu" = "armv4b" ; then - echo "ARCH=arm" >> $config_mak - echo "#define HOST_ARM 1" >> $config_h -elif test "$cpu" = "armv4l" ; then - echo "ARCH=arm" >> $config_mak - echo "#define HOST_ARM 1" >> $config_h -elif test "$cpu" = "powerpc" ; then - echo "ARCH=ppc" >> $config_mak - echo "#define HOST_PPC 1" >> $config_h -elif test "$cpu" = "mips" ; then - echo "ARCH=mips" >> $config_mak - echo "#define HOST_MIPS 1" >> $config_h -elif test "$cpu" = "mips64" ; then - echo "ARCH=mips64" >> $config_mak - echo "#define HOST_MIPS64 1" >> $config_h -elif test "$cpu" = "cris" ; then - echo "ARCH=cris" >> $config_mak - echo "#define HOST_CRIS 1" >> $config_h -elif test "$cpu" = "s390" ; then - echo "ARCH=s390" >> $config_mak - echo "#define HOST_S390 1" >> $config_h -elif test "$cpu" = "alpha" ; then - echo "ARCH=alpha" >> $config_mak - echo "#define HOST_ALPHA 1" >> $config_h -elif test "$cpu" = "sparc" ; then - echo "ARCH=sparc" >> $config_mak - echo "#define HOST_SPARC 1" >> $config_h -elif test "$cpu" = "sparc64" ; then - echo "ARCH=sparc64" >> $config_mak - echo "#define HOST_SPARC64 1" >> $config_h -elif test "$cpu" = "ia64" ; then - echo "ARCH=ia64" >> $config_mak - echo "#define HOST_IA64 1" >> $config_h -elif test "$cpu" = "m68k" ; then - echo "ARCH=m68k" >> $config_mak - echo "#define HOST_M68K 1" >> $config_h -else - echo "Unsupported CPU = $cpu" - exit 1 +case "$cpu" in + i386) + echo "ARCH=i386" >> $config_mak + echo "#define HOST_I386 1" >> $config_h + ;; + x86_64) + echo "ARCH=x86_64" >> $config_mak + echo "#define HOST_X86_64 1" >> $config_h + ;; + alpha) + echo "ARCH=alpha" >> $config_mak + echo "#define HOST_ALPHA 1" >> $config_h + ;; + armv4b) + echo "ARCH=arm" >> $config_mak + echo "#define HOST_ARM 1" >> $config_h + ;; + armv4l) + echo "ARCH=arm" >> $config_mak + echo "#define HOST_ARM 1" >> $config_h + ;; + cris) + echo "ARCH=cris" >> $config_mak + echo "#define HOST_CRIS 1" >> $config_h + ;; + hppa) + echo "ARCH=hppa" >> $config_mak + echo "#define HOST_HPPA 1" >> $config_h + ;; + ia64) + echo "ARCH=ia64" >> $config_mak + echo "#define HOST_IA64 1" >> $config_h + ;; + m68k) + echo "ARCH=m68k" >> $config_mak + echo "#define HOST_M68K 1" >> $config_h + ;; + mips) + echo "ARCH=mips" >> $config_mak + echo "#define HOST_MIPS 1" >> $config_h + ;; + mips64) + echo "ARCH=mips64" >> $config_mak + echo "#define HOST_MIPS64 1" >> $config_h + ;; + powerpc) + if test "$hostlongbits" = "32"; then + echo "ARCH=ppc" >> $config_mak + echo "#define HOST_PPC 1" >> $config_h + else + echo "ARCH=ppc64" >> $config_mak + echo "#define HOST_PPC64 1" >> $config_h + fi + ;; + s390) + echo "ARCH=s390" >> $config_mak + echo "#define HOST_S390 1" >> $config_h + ;; + sparc) + echo "ARCH=sparc" >> $config_mak + echo "#define HOST_SPARC 1" >> $config_h + ;; + sparc64) + echo "ARCH=sparc64" >> $config_mak + echo "#define HOST_SPARC64 1" >> $config_h + ;; + *) + echo "Unsupported CPU = $cpu" + exit 1 + ;; +esac +if test "$sparse" = "yes" ; then + echo "CC := REAL_CC=\"\$(CC)\" cgcc" >> $config_mak + echo "HOST_CC := REAL_CC=\"\$(HOST_CC)\" cgcc" >> $config_mak + echo "CFLAGS += -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_mak fi if test "$bigendian" = "yes" ; then echo "WORDS_BIGENDIAN=yes" >> $config_mak @@ -846,10 +1207,15 @@ #include int main(void) { return bswap_32(0); } EOF - if $cc -o $TMPE $TMPC 2> /dev/null ; then + if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then echo "#define HAVE_BYTESWAP_H 1" >> $config_h fi fi + +if [ "$openbsd" = "yes" ] ; then + echo "#define ENOTSUP 4096" >> $config_h +fi + if test "$darwin" = "yes" ; then echo "CONFIG_DARWIN=yes" >> $config_mak echo "#define CONFIG_DARWIN 1" >> $config_h @@ -885,31 +1251,32 @@ echo "CONFIG_SLIRP=yes" >> $config_mak echo "#define CONFIG_SLIRP 1" >> $config_h fi -if test "$adlib" = "yes" ; then - echo "CONFIG_ADLIB=yes" >> $config_mak - echo "#define CONFIG_ADLIB 1" >> $config_h -fi -if test "$oss" = "yes" ; then - echo "CONFIG_OSS=yes" >> $config_mak - echo "#define CONFIG_OSS 1" >> $config_h -fi -if test "$coreaudio" = "yes" ; then - echo "CONFIG_COREAUDIO=yes" >> $config_mak - echo "#define CONFIG_COREAUDIO 1" >> $config_h -fi -if test "$alsa" = "yes" ; then - echo "CONFIG_ALSA=yes" >> $config_mak - echo "#define CONFIG_ALSA 1" >> $config_h -fi -if test "$dsound" = "yes" ; then - echo "CONFIG_DSOUND=yes" >> $config_mak - echo "#define CONFIG_DSOUND 1" >> $config_h -fi -if test "$fmod" = "yes" ; then - echo "CONFIG_FMOD=yes" >> $config_mak - echo "CONFIG_FMOD_LIB=$fmod_lib" >> $config_mak - echo "CONFIG_FMOD_INC=$fmod_inc" >> $config_mak - echo "#define CONFIG_FMOD 1" >> $config_h +if test "$vde" = "yes" ; then + echo "CONFIG_VDE=yes" >> $config_mak + echo "#define CONFIG_VDE 1" >> $config_h + echo "VDE_LIBS=-lvdeplug" >> $config_mak +fi +for card in $audio_card_list; do + def=CONFIG_`echo $card | tr '[:lower:]' '[:upper:]'` + echo "$def=yes" >> $config_mak + echo "#define $def 1" >> $config_h +done +echo "#define AUDIO_DRIVERS \\" >> $config_h +for drv in $audio_drv_list; do + echo " &${drv}_audio_driver, \\" >>$config_h + def=CONFIG_`echo $drv | tr '[:lower:]' '[:upper:]'` + echo "$def=yes" >> $config_mak + if test "$drv" = "fmod"; then + echo "CONFIG_FMOD_LIB=$fmod_lib" >> $config_mak + echo "CONFIG_FMOD_INC=$fmod_inc" >> $config_mak + elif test "$drv" = "oss"; then + echo "CONFIG_OSS_LIB=$oss_lib" >> $config_mak + fi +done +echo "" >>$config_h +if test "$mixemu" = "yes" ; then + echo "CONFIG_MIXEMU=yes" >> $config_mak + echo "#define CONFIG_MIXEMU 1" >> $config_h fi if test "$vnc_tls" = "yes" ; then echo "CONFIG_VNC_TLS=yes" >> $config_mak @@ -949,8 +1316,28 @@ fi fi if test "$cocoa" = "yes" ; then - echo "#define CONFIG_COCOA 1" >> $config_h - echo "CONFIG_COCOA=yes" >> $config_mak + echo "#define CONFIG_COCOA 1" >> $config_h + echo "CONFIG_COCOA=yes" >> $config_mak +fi +if test "$curses" = "yes" ; then + echo "#define CONFIG_CURSES 1" >> $config_h + echo "CONFIG_CURSES=yes" >> $config_mak + echo "CURSES_LIBS=-lcurses" >> $config_mak +fi +if test "$brlapi" = "yes" ; then + echo "CONFIG_BRLAPI=yes" >> $config_mak + echo "#define CONFIG_BRLAPI 1" >> $config_h + echo "BRLAPI_LIBS=-lbrlapi" >> $config_mak +fi +if test "$bluez" = "yes" ; then + echo "CONFIG_BLUEZ=yes" >> $config_mak + echo "CONFIG_BLUEZ_CFLAGS=$bluez_cflags" >> $config_mak + echo "CONFIG_BLUEZ_LIBS=$bluez_libs" >> $config_mak + echo "#define CONFIG_BLUEZ 1" >> $config_h +fi +if test "$aio" = "yes" ; then + echo "#define CONFIG_AIO 1" >> $config_h + echo "CONFIG_AIO=yes" >> $config_mak fi # XXX: suppress that @@ -965,6 +1352,9 @@ tools= if test `expr "$target_list" : ".*softmmu.*"` != 0 ; then tools="qemu-img\$(EXESUF) $tools" + if [ "$linux" = "yes" ] ; then + tools="qemu-nbd\$(EXESUF) $tools" + fi fi echo "TOOLS=$tools" >> $config_mak @@ -977,22 +1367,23 @@ target_cpu=`echo $target | cut -d '-' -f 1` target_bigendian="no" [ "$target_cpu" = "armeb" ] && target_bigendian=yes -[ "$target_cpu" = "sparc" ] && target_bigendian=yes -[ "$target_cpu" = "sparc64" ] && target_bigendian=yes -[ "$target_cpu" = "sparc32plus" ] && target_bigendian=yes +[ "$target_cpu" = "m68k" ] && target_bigendian=yes +[ "$target_cpu" = "mips" ] && target_bigendian=yes +[ "$target_cpu" = "mipsn32" ] && target_bigendian=yes +[ "$target_cpu" = "mips64" ] && target_bigendian=yes [ "$target_cpu" = "ppc" ] && target_bigendian=yes [ "$target_cpu" = "ppcemb" ] && target_bigendian=yes [ "$target_cpu" = "ppc64" ] && target_bigendian=yes [ "$target_cpu" = "ppc64abi32" ] && target_bigendian=yes -[ "$target_cpu" = "mips" ] && target_bigendian=yes -[ "$target_cpu" = "mipsn32" ] && target_bigendian=yes -[ "$target_cpu" = "mips64" ] && target_bigendian=yes [ "$target_cpu" = "sh4eb" ] && target_bigendian=yes -[ "$target_cpu" = "m68k" ] && target_bigendian=yes +[ "$target_cpu" = "sparc" ] && target_bigendian=yes +[ "$target_cpu" = "sparc64" ] && target_bigendian=yes +[ "$target_cpu" = "sparc32plus" ] && target_bigendian=yes target_softmmu="no" target_user_only="no" target_linux_user="no" target_darwin_user="no" +target_bsd_user="no" case "$target" in ${target_cpu}-softmmu) target_softmmu="yes" @@ -1005,6 +1396,10 @@ target_user_only="yes" target_darwin_user="yes" ;; + ${target_cpu}-bsd-user) + target_user_only="yes" + target_bsd_user="yes" + ;; *) echo "ERROR: Target '$target' not recognised" exit 1 @@ -1015,7 +1410,8 @@ -a "$sdl" = "no" -a "$cocoa" = "no" ; then echo "ERROR: QEMU requires SDL or Cocoa for graphical output" echo "To build QEMU without graphical output configure with --disable-gfx-check" - echo "Note that this will disable all output from the virtual graphics card." + echo "Note that this will disable all output from the virtual graphics card" + echo "except through VNC or curses." exit 1; fi @@ -1025,7 +1421,8 @@ mkdir -p $target_dir mkdir -p $target_dir/fpu -if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" ; then +mkdir -p $target_dir/tcg +if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" -o "$target" = "arm-bsd-user" -o "$target" = "armeb-bsd-user" ; then mkdir -p $target_dir/nwfpe fi @@ -1045,111 +1442,172 @@ bflt="no" elfload32="no" +target_nptl="no" interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"` echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h +gdb_xml_files="" -if test "$target_cpu" = "i386" ; then - echo "TARGET_ARCH=i386" >> $config_mak - echo "#define TARGET_ARCH \"i386\"" >> $config_h - echo "#define TARGET_I386 1" >> $config_h - if test $kqemu = "yes" -a "$target_softmmu" = "yes" -a $cpu = "i386" ; then - echo "#define USE_KQEMU 1" >> $config_h - fi -elif test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then - echo "TARGET_ARCH=arm" >> $config_mak - echo "#define TARGET_ARCH \"arm\"" >> $config_h - echo "#define TARGET_ARM 1" >> $config_h - bflt="yes" -elif test "$target_cpu" = "sparc" ; then - echo "TARGET_ARCH=sparc" >> $config_mak - echo "#define TARGET_ARCH \"sparc\"" >> $config_h - echo "#define TARGET_SPARC 1" >> $config_h -elif test "$target_cpu" = "sparc64" ; then - echo "TARGET_ARCH=sparc64" >> $config_mak - echo "#define TARGET_ARCH \"sparc64\"" >> $config_h - echo "#define TARGET_SPARC 1" >> $config_h - echo "#define TARGET_SPARC64 1" >> $config_h - elfload32="yes" -elif test "$target_cpu" = "sparc32plus" ; then - echo "TARGET_ARCH=sparc64" >> $config_mak - echo "TARGET_ABI_DIR=sparc" >> $config_mak - echo "TARGET_ARCH2=sparc32plus" >> $config_mak - echo "#define TARGET_ARCH \"sparc64\"" >> $config_h - echo "#define TARGET_SPARC 1" >> $config_h - echo "#define TARGET_SPARC64 1" >> $config_h - echo "#define TARGET_ABI32 1" >> $config_h -elif test "$target_cpu" = "ppc" ; then - echo "TARGET_ARCH=ppc" >> $config_mak - echo "#define TARGET_ARCH \"ppc\"" >> $config_h - echo "#define TARGET_PPC 1" >> $config_h -elif test "$target_cpu" = "ppcemb" ; then - echo "TARGET_ARCH=ppcemb" >> $config_mak - echo "TARGET_ABI_DIR=ppc" >> $config_mak - echo "#define TARGET_ARCH \"ppcemb\"" >> $config_h - echo "#define TARGET_PPC 1" >> $config_h - echo "#define TARGET_PPCEMB 1" >> $config_h -elif test "$target_cpu" = "ppc64" ; then - echo "TARGET_ARCH=ppc64" >> $config_mak - echo "TARGET_ABI_DIR=ppc" >> $config_mak - echo "#define TARGET_ARCH \"ppc64\"" >> $config_h - echo "#define TARGET_PPC 1" >> $config_h - echo "#define TARGET_PPC64 1" >> $config_h -elif test "$target_cpu" = "ppc64abi32" ; then - echo "TARGET_ARCH=ppc64" >> $config_mak - echo "TARGET_ABI_DIR=ppc" >> $config_mak - echo "TARGET_ARCH2=ppc64abi32" >> $config_mak - echo "#define TARGET_ARCH \"ppc64\"" >> $config_h - echo "#define TARGET_PPC 1" >> $config_h - echo "#define TARGET_PPC64 1" >> $config_h - echo "#define TARGET_ABI32 1" >> $config_h -elif test "$target_cpu" = "x86_64" ; then - echo "TARGET_ARCH=x86_64" >> $config_mak - echo "#define TARGET_ARCH \"x86_64\"" >> $config_h - echo "#define TARGET_I386 1" >> $config_h - echo "#define TARGET_X86_64 1" >> $config_h - if test $kqemu = "yes" -a "$target_softmmu" = "yes" -a $cpu = "x86_64" ; then - echo "#define USE_KQEMU 1" >> $config_h - fi -elif test "$target_cpu" = "mips" -o "$target_cpu" = "mipsel" ; then - echo "TARGET_ARCH=mips" >> $config_mak - echo "#define TARGET_ARCH \"mips\"" >> $config_h - echo "#define TARGET_MIPS 1" >> $config_h - echo "#define TARGET_ABI_MIPSO32 1" >> $config_h -elif test "$target_cpu" = "mipsn32" -o "$target_cpu" = "mipsn32el" ; then - echo "TARGET_ARCH=mipsn32" >> $config_mak - echo "#define TARGET_ARCH \"mipsn32\"" >> $config_h - echo "#define TARGET_MIPS 1" >> $config_h - echo "#define TARGET_ABI_MIPSN32 1" >> $config_h -elif test "$target_cpu" = "mips64" -o "$target_cpu" = "mips64el" ; then - echo "TARGET_ARCH=mips64" >> $config_mak - echo "#define TARGET_ARCH \"mips64\"" >> $config_h - echo "#define TARGET_MIPS 1" >> $config_h - echo "#define TARGET_MIPS64 1" >> $config_h - echo "#define TARGET_ABI_MIPSN64 1" >> $config_h -elif test "$target_cpu" = "cris" ; then - echo "TARGET_ARCH=cris" >> $config_mak - echo "#define TARGET_ARCH \"cris\"" >> $config_h - echo "#define TARGET_CRIS 1" >> $config_h - echo "CONFIG_SOFTFLOAT=yes" >> $config_mak - echo "#define CONFIG_SOFTFLOAT 1" >> $config_h -elif test "$target_cpu" = "sh4" -o "$target_cpu" = "sh4eb" ; then - echo "TARGET_ARCH=sh4" >> $config_mak - echo "#define TARGET_ARCH \"sh4\"" >> $config_h - echo "#define TARGET_SH4 1" >> $config_h - bflt="yes" -elif test "$target_cpu" = "m68k" ; then - echo "TARGET_ARCH=m68k" >> $config_mak - echo "#define TARGET_ARCH \"m68k\"" >> $config_h - echo "#define TARGET_M68K 1" >> $config_h - bflt="yes" -elif test "$target_cpu" = "alpha" ; then - echo "TARGET_ARCH=alpha" >> $config_mak - echo "#define TARGET_ARCH \"alpha\"" >> $config_h - echo "#define TARGET_ALPHA 1" >> $config_h -else - echo "Unsupported target CPU" - exit 1 -fi +# Make sure the target and host cpus are compatible +if test "$kvm" = "yes" -a ! \( "$target_cpu" = "$cpu" -o \ + \( "$target_cpu" = "x86_64" -a "$cpu" = "i386" \) -o \ + \( "$target_cpu" = "i386" -a "$cpu" = "x86_64" \) \) ; then + kvm="no" +fi +# Disable KVM for linux-user +if test "$kvm" = "yes" -a "$target_softmmu" = "no" ; then + kvm="no" +fi + +case "$target_cpu" in + i386) + echo "TARGET_ARCH=i386" >> $config_mak + echo "#define TARGET_ARCH \"i386\"" >> $config_h + echo "#define TARGET_I386 1" >> $config_h + if test $kqemu = "yes" -a "$target_softmmu" = "yes" + then + echo "#define USE_KQEMU 1" >> $config_h + fi + if test "$kvm" = "yes" ; then + echo "CONFIG_KVM=yes" >> $config_mak + echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak + echo "#define CONFIG_KVM 1" >> $config_h + fi + gcc3minver=`$cc --version 2> /dev/null| fgrep "(GCC) 3." | awk '{ print $3 }' | cut -f2 -d.` + if test -n "$gcc3minver" && test $gcc3minver -gt 3 + then + echo "HAVE_GT_GCC_3_3=true" >> $config_mak + else + echo "HAVE_GT_GCC_3_3=false" >> $config_mak + fi + ;; + x86_64) + echo "TARGET_ARCH=x86_64" >> $config_mak + echo "#define TARGET_ARCH \"x86_64\"" >> $config_h + echo "#define TARGET_I386 1" >> $config_h + echo "#define TARGET_X86_64 1" >> $config_h + if test $kqemu = "yes" -a "$target_softmmu" = "yes" -a $cpu = "x86_64" + then + echo "#define USE_KQEMU 1" >> $config_h + fi + if test "$kvm" = "yes" ; then + echo "CONFIG_KVM=yes" >> $config_mak + echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak + echo "#define CONFIG_KVM 1" >> $config_h + fi + ;; + alpha) + echo "TARGET_ARCH=alpha" >> $config_mak + echo "#define TARGET_ARCH \"alpha\"" >> $config_h + echo "#define TARGET_ALPHA 1" >> $config_h + ;; + arm|armeb) + echo "TARGET_ARCH=arm" >> $config_mak + echo "#define TARGET_ARCH \"arm\"" >> $config_h + echo "#define TARGET_ARM 1" >> $config_h + bflt="yes" + target_nptl="yes" + gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml" + ;; + cris) + echo "TARGET_ARCH=cris" >> $config_mak + echo "#define TARGET_ARCH \"cris\"" >> $config_h + echo "#define TARGET_CRIS 1" >> $config_h + ;; + m68k) + echo "TARGET_ARCH=m68k" >> $config_mak + echo "#define TARGET_ARCH \"m68k\"" >> $config_h + echo "#define TARGET_M68K 1" >> $config_h + bflt="yes" + gdb_xml_files="cf-core.xml cf-fp.xml" + ;; + mips|mipsel) + echo "TARGET_ARCH=mips" >> $config_mak + echo "#define TARGET_ARCH \"mips\"" >> $config_h + echo "#define TARGET_MIPS 1" >> $config_h + echo "#define TARGET_ABI_MIPSO32 1" >> $config_h + ;; + mipsn32|mipsn32el) + echo "TARGET_ARCH=mipsn32" >> $config_mak + echo "#define TARGET_ARCH \"mipsn32\"" >> $config_h + echo "#define TARGET_MIPS 1" >> $config_h + echo "#define TARGET_ABI_MIPSN32 1" >> $config_h + ;; + mips64|mips64el) + echo "TARGET_ARCH=mips64" >> $config_mak + echo "#define TARGET_ARCH \"mips64\"" >> $config_h + echo "#define TARGET_MIPS 1" >> $config_h + echo "#define TARGET_MIPS64 1" >> $config_h + echo "#define TARGET_ABI_MIPSN64 1" >> $config_h + ;; + ppc) + echo "TARGET_ARCH=ppc" >> $config_mak + echo "CONFIG_DYNGEN_OP=yes" >> $config_mak + echo "#define TARGET_ARCH \"ppc\"" >> $config_h + echo "#define TARGET_PPC 1" >> $config_h + echo "#define CONFIG_DYNGEN_OP 1" >> $config_h + ;; + ppcemb) + echo "TARGET_ARCH=ppcemb" >> $config_mak + echo "TARGET_ABI_DIR=ppc" >> $config_mak + echo "CONFIG_DYNGEN_OP=yes" >> $config_mak + echo "#define TARGET_ARCH \"ppcemb\"" >> $config_h + echo "#define TARGET_PPC 1" >> $config_h + echo "#define TARGET_PPCEMB 1" >> $config_h + echo "#define CONFIG_DYNGEN_OP 1" >> $config_h + ;; + ppc64) + echo "TARGET_ARCH=ppc64" >> $config_mak + echo "TARGET_ABI_DIR=ppc" >> $config_mak + echo "CONFIG_DYNGEN_OP=yes" >> $config_mak + echo "#define TARGET_ARCH \"ppc64\"" >> $config_h + echo "#define TARGET_PPC 1" >> $config_h + echo "#define TARGET_PPC64 1" >> $config_h + echo "#define CONFIG_DYNGEN_OP 1" >> $config_h + ;; + ppc64abi32) + echo "TARGET_ARCH=ppc64" >> $config_mak + echo "TARGET_ABI_DIR=ppc" >> $config_mak + echo "TARGET_ARCH2=ppc64abi32" >> $config_mak + echo "CONFIG_DYNGEN_OP=yes" >> $config_mak + echo "#define TARGET_ARCH \"ppc64\"" >> $config_h + echo "#define TARGET_PPC 1" >> $config_h + echo "#define TARGET_PPC64 1" >> $config_h + echo "#define TARGET_ABI32 1" >> $config_h + echo "#define CONFIG_DYNGEN_OP 1" >> $config_h + ;; + sh4|sh4eb) + echo "TARGET_ARCH=sh4" >> $config_mak + echo "#define TARGET_ARCH \"sh4\"" >> $config_h + echo "#define TARGET_SH4 1" >> $config_h + bflt="yes" + target_nptl="yes" + ;; + sparc) + echo "TARGET_ARCH=sparc" >> $config_mak + echo "#define TARGET_ARCH \"sparc\"" >> $config_h + echo "#define TARGET_SPARC 1" >> $config_h + ;; + sparc64) + echo "TARGET_ARCH=sparc64" >> $config_mak + echo "#define TARGET_ARCH \"sparc64\"" >> $config_h + echo "#define TARGET_SPARC 1" >> $config_h + echo "#define TARGET_SPARC64 1" >> $config_h + elfload32="yes" + ;; + sparc32plus) + echo "TARGET_ARCH=sparc64" >> $config_mak + echo "TARGET_ABI_DIR=sparc" >> $config_mak + echo "TARGET_ARCH2=sparc32plus" >> $config_mak + echo "#define TARGET_ARCH \"sparc64\"" >> $config_h + echo "#define TARGET_SPARC 1" >> $config_h + echo "#define TARGET_SPARC64 1" >> $config_h + echo "#define TARGET_ABI32 1" >> $config_h + ;; + *) + echo "Unsupported target CPU" + exit 1 + ;; +esac if test "$target_bigendian" = "yes" ; then echo "TARGET_WORDS_BIGENDIAN=yes" >> $config_mak echo "#define TARGET_WORDS_BIGENDIAN 1" >> $config_h @@ -1170,8 +1628,26 @@ echo "CONFIG_DARWIN_USER=yes" >> $config_mak echo "#define CONFIG_DARWIN_USER 1" >> $config_h fi - -if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64" -o "$target_cpu" = "sparc32plus" -o "$target_cpu" = "m68k" -o "$target_cpu" = "mips" -o "$target_cpu" = "mipsel" -o "$target_cpu" = "mipsn32" -o "$target_cpu" = "mipsn32el" -o "$target_cpu" = "mips64" -o "$target_cpu" = "mips64el"; then +list="" +if test ! -z "$gdb_xml_files" ; then + for x in $gdb_xml_files; do + list="$list $source_path/gdb-xml/$x" + done +fi +echo "TARGET_XML_FILES=$list" >> $config_mak + +if test "$target_cpu" = "arm" \ + -o "$target_cpu" = "armeb" \ + -o "$target_cpu" = "m68k" \ + -o "$target_cpu" = "mips" \ + -o "$target_cpu" = "mipsel" \ + -o "$target_cpu" = "mipsn32" \ + -o "$target_cpu" = "mipsn32el" \ + -o "$target_cpu" = "mips64" \ + -o "$target_cpu" = "mips64el" \ + -o "$target_cpu" = "sparc" \ + -o "$target_cpu" = "sparc64" \ + -o "$target_cpu" = "sparc32plus"; then echo "CONFIG_SOFTFLOAT=yes" >> $config_mak echo "#define CONFIG_SOFTFLOAT 1" >> $config_h fi @@ -1179,11 +1655,19 @@ echo "TARGET_HAS_BFLT=yes" >> $config_mak echo "#define TARGET_HAS_BFLT 1" >> $config_h fi +if test "$target_user_only" = "yes" \ + -a "$nptl" = "yes" -a "$target_nptl" = "yes"; then + echo "#define USE_NPTL 1" >> $config_h +fi # 32 bit ELF loader in addition to native 64 bit loader? if test "$target_user_only" = "yes" -a "$elfload32" = "yes"; then echo "TARGET_HAS_ELFLOAD32=yes" >> $config_mak echo "#define TARGET_HAS_ELFLOAD32 1" >> $config_h fi +if test "$target_bsd_user" = "yes" ; then + echo "CONFIG_BSD_USER=yes" >> $config_mak + echo "#define CONFIG_BSD_USER 1" >> $config_h +fi test -f ${config_h}~ && cmp -s $config_h ${config_h}~ && mv ${config_h}~ $config_h @@ -1194,6 +1678,7 @@ DIRS="tests tests/cris slirp audio" FILES="Makefile tests/Makefile" FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit" + FILES="$FILES tests/test-mmap.c" for dir in $DIRS ; do mkdir -p $dir done @@ -1204,4 +1689,4 @@ done fi -rm -f $TMPO $TMPC $TMPE $TMPS +rm -f $TMPO $TMPC $TMPE $TMPS $TMPI diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/console.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/console.c --- qemu-0.9.1/console.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/console.c 2008-09-24 04:32:33.000000000 +0100 @@ -28,6 +28,7 @@ //#define DEBUG_CONSOLE #define DEFAULT_BACKSCROLL 512 #define MAX_CONSOLES 12 +#define DEFAULT_MONITOR_SIZE "800x600" #define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) #define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff) @@ -121,6 +122,7 @@ vga_hw_update_ptr hw_update; vga_hw_invalidate_ptr hw_invalidate; vga_hw_screen_dump_ptr hw_screen_dump; + vga_hw_text_update_ptr hw_text_update; void *hw; int g_width, g_height; @@ -135,6 +137,7 @@ TextAttributes t_attrib_default; /* default text attributes */ TextAttributes t_attrib; /* currently active text attributes */ TextCell *cells; + int text_x[2], text_y[2], cursor_invalidate; enum TTYState state; int esc_params[MAX_ESC_PARAMS]; @@ -165,10 +168,21 @@ void vga_hw_screen_dump(const char *filename) { - /* There is currently no was of specifying which screen we want to dump, - so always dump the dirst one. */ + TextConsole *previous_active_console; + + previous_active_console = active_console; + active_console = consoles[0]; + /* There is currently no way of specifying which screen we want to dump, + so always dump the first one. */ if (consoles[0]->hw_screen_dump) consoles[0]->hw_screen_dump(consoles[0]->hw, filename); + active_console = previous_active_console; +} + +void vga_hw_text_update(console_ch_t *chardata) +{ + if (active_console && active_console->hw_text_update) + active_console->hw_text_update(active_console->hw, chardata); } /* convert a RGBA color to a color index usable in graphic primitives */ @@ -515,12 +529,25 @@ s->cells = cells; } +static inline void text_update_xy(TextConsole *s, int x, int y) +{ + s->text_x[0] = MIN(s->text_x[0], x); + s->text_x[1] = MAX(s->text_x[1], x); + s->text_y[0] = MIN(s->text_y[0], y); + s->text_y[1] = MAX(s->text_y[1], y); +} + static void update_xy(TextConsole *s, int x, int y) { TextCell *c; int y1, y2; if (s == active_console) { + if (!s->ds->depth) { + text_update_xy(s, x, y); + return; + } + y1 = (s->y_base + y) % s->total_height; y2 = y1 - s->y_displayed; if (y2 < 0) @@ -542,6 +569,12 @@ if (s == active_console) { int x = s->x; + + if (!s->ds->depth) { + s->cursor_invalidate = 1; + return; + } + if (x >= s->width) { x = s->width - 1; } @@ -571,6 +604,14 @@ if (s != active_console) return; + if (!s->ds->depth) { + s->text_x[0] = 0; + s->text_y[0] = 0; + s->text_x[1] = s->width - 1; + s->text_y[1] = s->height - 1; + s->cursor_invalidate = 1; + return; + } vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height, color_table[0][COLOR_BLACK]); @@ -648,6 +689,14 @@ c++; } if (s == active_console && s->y_displayed == s->y_base) { + if (!s->ds->depth) { + s->text_x[0] = 0; + s->text_y[0] = 0; + s->text_x[1] = s->width - 1; + s->text_y[1] = s->height - 1; + return; + } + vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, s->width * FONT_WIDTH, (s->height - 1) * FONT_HEIGHT); @@ -998,21 +1047,10 @@ s = consoles[index]; if (s) { active_console = s; - if (s->console_type != GRAPHIC_CONSOLE) { - if (s->g_width != s->ds->width || - s->g_height != s->ds->height) { - if (s->console_type == TEXT_CONSOLE_FIXED_SIZE) { - dpy_resize(s->ds, s->g_width, s->g_height); - } else { - s->g_width = s->ds->width; - s->g_height = s->ds->height; - text_console_resize(s); - } - } - console_refresh(s); - } else { - vga_hw_invalidate(); - } + if (s->console_type != TEXT_CONSOLE && s->g_width && s->g_height + && (s->g_width != s->ds->width || s->g_height != s->ds->height)) + dpy_resize(s->ds, s->g_width, s->g_height); + vga_hw_invalidate(); } } @@ -1116,6 +1154,49 @@ } } +static void text_console_invalidate(void *opaque) +{ + TextConsole *s = (TextConsole *) opaque; + + if (s->g_width != s->ds->width || s->g_height != s->ds->height) { + if (s->console_type == TEXT_CONSOLE_FIXED_SIZE) + dpy_resize(s->ds, s->g_width, s->g_height); + else { + s->g_width = s->ds->width; + s->g_height = s->ds->height; + text_console_resize(s); + } + } + console_refresh(s); +} + +static void text_console_update(void *opaque, console_ch_t *chardata) +{ + TextConsole *s = (TextConsole *) opaque; + int i, j, src; + + if (s->text_x[0] <= s->text_x[1]) { + src = (s->y_base + s->text_y[0]) * s->width; + chardata += s->text_y[0] * s->width; + for (i = s->text_y[0]; i <= s->text_y[1]; i ++) + for (j = 0; j < s->width; j ++, src ++) + console_write_ch(chardata ++, s->cells[src].ch | + (s->cells[src].t_attrib.fgcol << 12) | + (s->cells[src].t_attrib.bgcol << 8) | + (s->cells[src].t_attrib.bold << 21)); + dpy_update(s->ds, s->text_x[0], s->text_y[0], + s->text_x[1] - s->text_x[0], i - s->text_y[0]); + s->text_x[0] = s->width; + s->text_y[0] = s->height; + s->text_x[1] = 0; + s->text_y[1] = 0; + } + if (s->cursor_invalidate) { + dpy_cursor(s->ds, s->x, s->y); + s->cursor_invalidate = 0; + } +} + static TextConsole *new_console(DisplayState *ds, console_type_t console_type) { TextConsole *s; @@ -1150,6 +1231,7 @@ TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update, vga_hw_invalidate_ptr invalidate, vga_hw_screen_dump_ptr screen_dump, + vga_hw_text_update_ptr text_update, void *opaque) { TextConsole *s; @@ -1160,13 +1242,19 @@ s->hw_update = update; s->hw_invalidate = invalidate; s->hw_screen_dump = screen_dump; + s->hw_text_update = text_update; s->hw = opaque; return s; } int is_graphic_console(void) { - return active_console->console_type == GRAPHIC_CONSOLE; + return active_console && active_console->console_type == GRAPHIC_CONSOLE; +} + +int is_fixedsize_console(void) +{ + return active_console && active_console->console_type != TEXT_CONSOLE; } void console_color_init(DisplayState *ds) @@ -1234,6 +1322,10 @@ s->g_width = width; s->g_height = height; + s->hw_invalidate = text_console_invalidate; + s->hw_text_update = text_console_update; + s->hw = s; + /* Set text attribute defaults */ s->t_attrib_default.bold = 0; s->t_attrib_default.uline = 0; @@ -1251,3 +1343,29 @@ return chr; } + +void qemu_console_resize(QEMUConsole *console, int width, int height) +{ + if (console->g_width != width || console->g_height != height + || !console->ds->data) { + console->g_width = width; + console->g_height = height; + if (active_console == console) { + dpy_resize(console->ds, width, height); + } + } +} + +void qemu_console_copy(QEMUConsole *console, int src_x, int src_y, + int dst_x, int dst_y, int w, int h) +{ + if (active_console == console) { + if (console->ds->dpy_copy) + console->ds->dpy_copy(console->ds, + src_x, src_y, dst_x, dst_y, w, h); + else { + /* TODO */ + console->ds->dpy_update(console->ds, dst_x, dst_y, w, h); + } + } +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/console.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/console.h --- qemu-0.9.1/console.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/console.h 2008-10-06 14:52:44.000000000 +0100 @@ -9,6 +9,9 @@ #define MOUSE_EVENT_RBUTTON 0x02 #define MOUSE_EVENT_MBUTTON 0x04 +/* in ms */ +#define GUI_REFRESH_INTERVAL 30 + typedef void QEMUPutKBDEvent(void *opaque, int keycode); typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state); @@ -32,6 +35,14 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); int kbd_mouse_is_absolute(void); +struct mouse_transform_info_s { + /* Touchscreen resolution */ + int x; + int y; + /* Calibration values as used/generated by tslib */ + int a[7]; +}; + void do_info_mice(void); void do_mouse_set(int index); @@ -71,6 +82,8 @@ int height; void *opaque; struct QEMUTimer *gui_timer; + uint64_t gui_timer_interval; + int idle; /* there is nothing to update (window invisible), set by vnc/sdl */ void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h); void (*dpy_resize)(struct DisplayState *s, int w, int h); @@ -79,6 +92,7 @@ int dst_x, int dst_y, int w, int h); void (*dpy_fill)(struct DisplayState *s, int x, int y, int w, int h, uint32_t c); + void (*dpy_text_cursor)(struct DisplayState *s, int x, int y); void (*mouse_set)(int x, int y, int on); void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y, uint8_t *image, uint8_t *mask); @@ -94,22 +108,41 @@ s->dpy_resize(s, w, h); } +static inline void dpy_cursor(DisplayState *s, int x, int y) +{ + if (s->dpy_text_cursor) + s->dpy_text_cursor(s, x, y); +} + +typedef unsigned long console_ch_t; +static inline void console_write_ch(console_ch_t *dest, uint32_t ch) +{ + cpu_to_le32wu((uint32_t *) dest, ch); +} + typedef void (*vga_hw_update_ptr)(void *); typedef void (*vga_hw_invalidate_ptr)(void *); typedef void (*vga_hw_screen_dump_ptr)(void *, const char *); +typedef void (*vga_hw_text_update_ptr)(void *, console_ch_t *); TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update, vga_hw_invalidate_ptr invalidate, vga_hw_screen_dump_ptr screen_dump, + vga_hw_text_update_ptr text_update, void *opaque); void vga_hw_update(void); void vga_hw_invalidate(void); void vga_hw_screen_dump(const char *filename); +void vga_hw_text_update(console_ch_t *chardata); int is_graphic_console(void); +int is_fixedsize_console(void); CharDriverState *text_console_init(DisplayState *ds, const char *p); void console_select(unsigned int index); void console_color_init(DisplayState *ds); +void qemu_console_resize(QEMUConsole *console, int width, int height); +void qemu_console_copy(QEMUConsole *console, int src_x, int src_y, + int dst_x, int dst_y, int w, int h); /* sdl.c */ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame); @@ -124,6 +157,9 @@ int vnc_display_password(DisplayState *ds, const char *password); void do_info_vnc(void); +/* curses.c */ +void curses_display_init(DisplayState *ds, int full_screen); + /* x_keymap.c */ extern uint8_t _translate_keycode(const int key); @@ -139,6 +175,8 @@ void term_print_help(void); void monitor_readline(const char *prompt, int is_password, char *buf, int buf_size); +void monitor_suspend(void); +void monitor_resume(void); /* readline.c */ typedef void ReadLineFunc(void *opaque, const char *str); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/COPYING /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/COPYING --- qemu-0.9.1/COPYING 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/COPYING 2008-10-12 18:54:42.000000000 +0100 @@ -1,8 +1,8 @@ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -15,7 +15,7 @@ General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to +the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not @@ -291,7 +291,7 @@ the "copyright" line and a pointer to where the full notice is found. - Copyright (C) 19yy + Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -303,16 +303,16 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. @@ -335,5 +335,5 @@ This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General +library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/cpu-all.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/cpu-all.h --- qemu-0.9.1/cpu-all.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/cpu-all.h 2008-10-06 15:02:03.000000000 +0100 @@ -20,7 +20,7 @@ #ifndef CPU_ALL_H #define CPU_ALL_H -#if defined(__arm__) || defined(__sparc__) || defined(__mips__) +#if defined(__arm__) || defined(__sparc__) || defined(__mips__) || defined(__hppa__) #define WORDS_ALIGNED #endif @@ -38,6 +38,7 @@ */ #include "bswap.h" +#include "softfloat.h" #if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) #define BSWAP_NEEDED @@ -116,6 +117,11 @@ #define bswaptls(s) bswap64s(s) #endif +typedef union { + float32 f; + uint32_t l; +} CPU_FloatU; + /* NOTE: arm FPA is horrible as double 32 bit words are stored in big endian ! */ typedef union { @@ -446,7 +452,7 @@ { uint32_t a,b; a = ldl_be_p(ptr); - b = ldl_be_p(ptr+4); + b = ldl_be_p((uint8_t *)ptr + 4); return (((uint64_t)a<<32)|b); } @@ -483,7 +489,7 @@ static inline void stq_be_p(void *ptr, uint64_t v) { stl_be_p(ptr, v >> 32); - stl_be_p(ptr + 4, v); + stl_be_p((uint8_t *)ptr + 4, v); } /* float access */ @@ -512,7 +518,7 @@ { CPU_DoubleU u; u.l.upper = ldl_be_p(ptr); - u.l.lower = ldl_be_p(ptr + 4); + u.l.lower = ldl_be_p((uint8_t *)ptr + 4); return u.d; } @@ -521,7 +527,7 @@ CPU_DoubleU u; u.d = v; stl_be_p(ptr, u.l.upper); - stl_be_p(ptr + 4, u.l.lower); + stl_be_p((uint8_t *)ptr + 4, u.l.lower); } #else @@ -623,7 +629,7 @@ /* All direct uses of g2h and h2g need to go away for usermode softmmu. */ #define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE)) -#define h2g(x) ((target_ulong)(x - GUEST_BASE)) +#define h2g(x) ((target_ulong)((unsigned long)(x) - GUEST_BASE)) #define saddr(x) g2h(x) #define laddr(x) g2h(x) @@ -723,6 +729,7 @@ void page_set_flags(target_ulong start, target_ulong end, int flags); int page_check_range(target_ulong start, target_ulong len, int flags); +void cpu_exec_init_all(unsigned long tb_size); CPUState *cpu_copy(CPUState *env); void cpu_dump_state(CPUState *env, FILE *f, @@ -737,7 +744,8 @@ __attribute__ ((__noreturn__)); extern CPUState *first_cpu; extern CPUState *cpu_single_env; -extern int code_copy_enabled; +extern int64_t qemu_icount; +extern int use_icount; #define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */ #define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */ @@ -748,14 +756,22 @@ #define CPU_INTERRUPT_SMI 0x40 /* (x86 only) SMI interrupt pending */ #define CPU_INTERRUPT_DEBUG 0x80 /* Debug event occured. */ #define CPU_INTERRUPT_VIRQ 0x100 /* virtual interrupt pending. */ +#define CPU_INTERRUPT_NMI 0x200 /* NMI pending. */ void cpu_interrupt(CPUState *s, int mask); void cpu_reset_interrupt(CPUState *env, int mask); -int cpu_watchpoint_insert(CPUState *env, target_ulong addr); +int cpu_watchpoint_insert(CPUState *env, target_ulong addr, int type); int cpu_watchpoint_remove(CPUState *env, target_ulong addr); +void cpu_watchpoint_remove_all(CPUState *env); int cpu_breakpoint_insert(CPUState *env, target_ulong pc); int cpu_breakpoint_remove(CPUState *env, target_ulong pc); +void cpu_breakpoint_remove_all(CPUState *env); + +#define SSTEP_ENABLE 0x1 /* Enable simulated HW single stepping */ +#define SSTEP_NOIRQ 0x2 /* Do not use IRQ while single stepping */ +#define SSTEP_NOTIMER 0x4 /* Do not Timers while single stepping */ + void cpu_single_step(CPUState *env, int enabled); void cpu_reset(CPUState *s); @@ -781,7 +797,7 @@ const char *help; } CPULogItem; -extern CPULogItem cpu_log_items[]; +extern const CPULogItem cpu_log_items[]; void cpu_set_log(int log_flags); void cpu_set_log_filename(const char *filename); @@ -800,37 +816,58 @@ int cpu_inl(CPUState *env, int addr); #endif +/* address in the RAM (different from a physical address) */ +#ifdef USE_KQEMU +typedef uint32_t ram_addr_t; +#else +typedef unsigned long ram_addr_t; +#endif + /* memory API */ -extern int phys_ram_size; +extern ram_addr_t phys_ram_size; extern int phys_ram_fd; extern uint8_t *phys_ram_base; extern uint8_t *phys_ram_dirty; +extern ram_addr_t ram_size; /* physical memory access */ -#define TLB_INVALID_MASK (1 << 3) -#define IO_MEM_SHIFT 4 + +/* MMIO pages are identified by a combination of an IO device index and + 3 flags. The ROMD code stores the page ram offset in iotlb entry, + so only a limited number of ids are avaiable. */ + +#define IO_MEM_SHIFT 3 #define IO_MEM_NB_ENTRIES (1 << (TARGET_PAGE_BITS - IO_MEM_SHIFT)) #define IO_MEM_RAM (0 << IO_MEM_SHIFT) /* hardcoded offset */ #define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */ #define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT) -#define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */ -/* acts like a ROM when read and like a device when written. As an - exception, the write memory callback gets the ram offset instead of - the physical address */ +#define IO_MEM_NOTDIRTY (3 << IO_MEM_SHIFT) + +/* Acts like a ROM when read and like a device when written. */ #define IO_MEM_ROMD (1) #define IO_MEM_SUBPAGE (2) #define IO_MEM_SUBWIDTH (4) +/* Flags stored in the low bits of the TLB virtual address. These are + defined so that fast path ram access is all zeros. */ +/* Zero if TLB entry is valid. */ +#define TLB_INVALID_MASK (1 << 3) +/* Set if TLB entry references a clean RAM page. The iotlb entry will + contain the page physical address. */ +#define TLB_NOTDIRTY (1 << 4) +/* Set if TLB entry is an IO callback. */ +#define TLB_MMIO (1 << 5) + typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value); typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr); void cpu_register_physical_memory(target_phys_addr_t start_addr, - unsigned long size, - unsigned long phys_offset); -uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr); -ram_addr_t qemu_ram_alloc(unsigned int size); + ram_addr_t size, + ram_addr_t phys_offset); +ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr); +ram_addr_t qemu_ram_alloc(ram_addr_t); void qemu_ram_free(ram_addr_t addr); int cpu_register_io_memory(int io_index, CPUReadMemoryFunc **mem_read, @@ -867,8 +904,10 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr, uint8_t *buf, int len, int is_write); -#define VGA_DIRTY_FLAG 0x01 -#define CODE_DIRTY_FLAG 0x02 +#define VGA_DIRTY_FLAG 0x01 +#define CODE_DIRTY_FLAG 0x02 +#define KQEMU_DIRTY_FLAG 0x04 +#define MIGRATION_DIRTY_FLAG 0x08 /* read dirty bit (return 0 or 1) */ static inline int cpu_physical_memory_is_dirty(ram_addr_t addr) @@ -891,6 +930,10 @@ int dirty_flags); void cpu_tlb_update_dirty(CPUState *env); +int cpu_physical_memory_set_dirty_tracking(int enable); + +int cpu_physical_memory_get_dirty_tracking(void); + void dump_exec_info(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); @@ -947,6 +990,15 @@ return val; } +#elif defined(__hppa__) + +static inline int64_t cpu_get_real_ticks(void) +{ + int val; + asm volatile ("mfctl %%cr16, %0" : "=r"(val)); + return val; +} + #elif defined(__ia64) static inline int64_t cpu_get_real_ticks(void) @@ -1033,7 +1085,6 @@ extern int64_t kqemu_ret_int_count; extern int64_t kqemu_ret_excp_count; extern int64_t kqemu_ret_intr_count; - #endif #endif /* CPU_ALL_H */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/cpu-defs.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/cpu-defs.h --- qemu-0.9.1/cpu-defs.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/cpu-defs.h 2008-11-05 16:04:33.000000000 +0000 @@ -76,9 +76,6 @@ #error TARGET_PHYS_ADDR_BITS undefined #endif -/* address in the RAM (different from a physical address) */ -typedef unsigned long ram_addr_t; - #define HOST_LONG_SIZE (HOST_LONG_BITS / 8) #define EXCP_INTERRUPT 0x10000 /* async interruption */ @@ -102,33 +99,81 @@ #define CPU_TLB_BITS 8 #define CPU_TLB_SIZE (1 << CPU_TLB_BITS) +#if TARGET_PHYS_ADDR_BITS == 32 && TARGET_LONG_BITS == 32 +#define CPU_TLB_ENTRY_BITS 4 +#else +#define CPU_TLB_ENTRY_BITS 5 +#endif + typedef struct CPUTLBEntry { - /* bit 31 to TARGET_PAGE_BITS : virtual address - bit TARGET_PAGE_BITS-1..IO_MEM_SHIFT : if non zero, memory io - zone number + /* bit TARGET_LONG_BITS to TARGET_PAGE_BITS : virtual address + bit TARGET_PAGE_BITS-1..4 : Nonzero for accesses that should not + go directly to ram. bit 3 : indicates that the entry is invalid bit 2..0 : zero */ target_ulong addr_read; target_ulong addr_write; target_ulong addr_code; - /* addend to virtual address to get physical address */ + /* Addend to virtual address to get physical address. IO accesses + use the correcponding iotlb value. */ +#if TARGET_PHYS_ADDR_BITS == 64 + /* on i386 Linux make sure it is aligned */ + target_phys_addr_t addend __attribute__((aligned(8))); +#else target_phys_addr_t addend; +#endif + /* padding to get a power of two size */ + uint8_t dummy[(1 << CPU_TLB_ENTRY_BITS) - + (sizeof(target_ulong) * 3 + + ((-sizeof(target_ulong) * 3) & (sizeof(target_phys_addr_t) - 1)) + + sizeof(target_phys_addr_t))]; } CPUTLBEntry; +#ifdef WORDS_BIGENDIAN +typedef struct icount_decr_u16 { + uint16_t high; + uint16_t low; +} icount_decr_u16; +#else +typedef struct icount_decr_u16 { + uint16_t low; + uint16_t high; +} icount_decr_u16; +#endif + +struct kvm_run; +struct KVMState; + +#define CPU_TEMP_BUF_NLONGS 128 #define CPU_COMMON \ struct TranslationBlock *current_tb; /* currently executing TB */ \ /* soft mmu support */ \ - /* in order to avoid passing too many arguments to the memory \ - write helpers, we store some rarely used information in the CPU \ + /* in order to avoid passing too many arguments to the MMIO \ + helpers, we store some rarely used information in the CPU \ context) */ \ - unsigned long mem_write_pc; /* host pc at which the memory was \ - written */ \ - target_ulong mem_write_vaddr; /* target virtual addr at which the \ - memory was written */ \ + unsigned long mem_io_pc; /* host pc at which the memory was \ + accessed */ \ + target_ulong mem_io_vaddr; /* target virtual addr at which the \ + memory was accessed */ \ + uint32_t halted; /* Nonzero if the CPU is in suspend state */ \ + uint32_t interrupt_request; \ /* The meaning of the MMU modes is defined in the target code. */ \ CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \ + target_phys_addr_t iotlb[NB_MMU_MODES][CPU_TLB_SIZE]; \ struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \ + /* buffer for temporaries in the code generator */ \ + long temp_buf[CPU_TEMP_BUF_NLONGS]; \ + \ + int64_t icount_extra; /* Instructions until next timer event. */ \ + /* Number of cycles left, with interrupt flag in high bit. \ + This allows a single read-compare-cbranch-write sequence to test \ + for both decrementer underflow and exceptions. */ \ + union { \ + uint32_t u32; \ + icount_decr_u16 u16; \ + } icount_decr; \ + uint32_t can_do_io; /* nonzero if memory mapped IO is safe. */ \ \ /* from this point: preserved by CPU reset */ \ /* ice debug support */ \ @@ -138,16 +183,28 @@ \ struct { \ target_ulong vaddr; \ - target_phys_addr_t addend; \ + int type; /* PAGE_READ/PAGE_WRITE */ \ } watchpoint[MAX_WATCHPOINTS]; \ int nb_watchpoints; \ int watchpoint_hit; \ \ + struct GDBRegisterState *gdb_regs; \ + \ + /* Core interrupt code */ \ + jmp_buf jmp_env; \ + int exception_index; \ + \ + int user_mode_only; \ + \ void *next_cpu; /* next CPU sharing TB cache */ \ int cpu_index; /* CPU index (informative) */ \ + int running; /* Nonzero if cpu is currently running(usermode). */ \ /* user data */ \ void *opaque; \ \ - const char *cpu_model_str; + const char *cpu_model_str; \ + struct KVMState *kvm_state; \ + struct kvm_run *kvm_run; \ + int kvm_fd; #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/cpu-exec.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/cpu-exec.c --- qemu-0.9.1/cpu-exec.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/cpu-exec.c 2008-11-10 15:55:14.000000000 +0000 @@ -18,8 +18,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" +#define CPU_NO_GLOBAL_REGS #include "exec.h" #include "disas.h" +#include "tcg.h" +#include "kvm.h" #if !defined(CONFIG_SOFTMMU) #undef EAX @@ -32,59 +35,21 @@ #undef EDI #undef EIP #include +#ifdef __linux__ #include #endif - -int tb_invalidated_flag; - -//#define DEBUG_EXEC -//#define DEBUG_SIGNAL - -#define SAVE_GLOBALS() -#define RESTORE_GLOBALS() +#endif #if defined(__sparc__) && !defined(HOST_SOLARIS) -#include -#if defined(__GLIBC__) && ((__GLIBC__ < 2) || \ - ((__GLIBC__ == 2) && (__GLIBC_MINOR__ <= 90))) // Work around ugly bugs in glibc that mangle global register contents +#undef env +#define env cpu_single_env +#endif -static volatile void *saved_env; -static volatile unsigned long saved_t0, saved_i7; -#undef SAVE_GLOBALS -#define SAVE_GLOBALS() do { \ - saved_env = env; \ - saved_t0 = T0; \ - asm volatile ("st %%i7, [%0]" : : "r" (&saved_i7)); \ - } while(0) - -#undef RESTORE_GLOBALS -#define RESTORE_GLOBALS() do { \ - env = (void *)saved_env; \ - T0 = saved_t0; \ - asm volatile ("ld [%0], %%i7" : : "r" (&saved_i7)); \ - } while(0) - -static int sparc_setjmp(jmp_buf buf) -{ - int ret; - - SAVE_GLOBALS(); - ret = setjmp(buf); - RESTORE_GLOBALS(); - return ret; -} -#undef setjmp -#define setjmp(jmp_buf) sparc_setjmp(jmp_buf) +int tb_invalidated_flag; -static void sparc_longjmp(jmp_buf buf, int val) -{ - SAVE_GLOBALS(); - longjmp(buf, val); -} -#define longjmp(jmp_buf, val) sparc_longjmp(jmp_buf, val) -#endif -#endif +//#define DEBUG_EXEC +//#define DEBUG_SIGNAL void cpu_loop_exit(void) { @@ -94,17 +59,17 @@ longjmp(env->jmp_env, 1); } -#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K)) -#define reg_T2 -#endif - /* exit the current TB from a signal handler. The host registers are restored in a state compatible with the CPU emulator */ void cpu_resume_from_signal(CPUState *env1, void *puc) { #if !defined(CONFIG_SOFTMMU) +#ifdef __linux__ struct ucontext *uc = puc; +#elif defined(__OpenBSD__) + struct sigcontext *uc = puc; +#endif #endif env = env1; @@ -114,24 +79,50 @@ #if !defined(CONFIG_SOFTMMU) if (puc) { /* XXX: use siglongjmp ? */ +#ifdef __linux__ sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL); +#elif defined(__OpenBSD__) + sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL); +#endif } #endif longjmp(env->jmp_env, 1); } +/* Execute the code without caching the generated code. An interpreter + could be used if available. */ +static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb) +{ + unsigned long next_tb; + TranslationBlock *tb; + + /* Should never happen. + We only end up here when an existing TB is too long. */ + if (max_cycles > CF_COUNT_MASK) + max_cycles = CF_COUNT_MASK; + + tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags, + max_cycles); + env->current_tb = tb; + /* execute the generated code */ + next_tb = tcg_qemu_tb_exec(tb->tc_ptr); + + if ((next_tb & 3) == 2) { + /* Restore PC. This may happen if async event occurs before + the TB starts executing. */ + CPU_PC_FROM_TB(env, tb); + } + tb_phys_invalidate(tb, -1); + tb_free(tb); +} static TranslationBlock *tb_find_slow(target_ulong pc, target_ulong cs_base, uint64_t flags) { TranslationBlock *tb, **ptb1; - int code_gen_size; unsigned int h; target_ulong phys_pc, phys_page1, phys_page2, virt_page2; - uint8_t *tc_ptr; - - spin_lock(&tb_lock); tb_invalidated_flag = 0; @@ -165,37 +156,12 @@ ptb1 = &tb->phys_hash_next; } not_found: - /* if no translated code available, then translate it now */ - tb = tb_alloc(pc); - if (!tb) { - /* flush must be done */ - tb_flush(env); - /* cannot fail at this point */ - tb = tb_alloc(pc); - /* don't forget to invalidate previous TB info */ - tb_invalidated_flag = 1; - } - tc_ptr = code_gen_ptr; - tb->tc_ptr = tc_ptr; - tb->cs_base = cs_base; - tb->flags = flags; - SAVE_GLOBALS(); - cpu_gen_code(env, tb, &code_gen_size); - RESTORE_GLOBALS(); - code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); - - /* check next page if needed */ - virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK; - phys_page2 = -1; - if ((pc & TARGET_PAGE_MASK) != virt_page2) { - phys_page2 = get_phys_addr_code(env, virt_page2); - } - tb_link_phys(tb, phys_pc, phys_page2); + /* if no translated code available, then translate it now */ + tb = tb_gen_code(env, pc, cs_base, flags, 0); found: /* we add the TB in the virtual pc hash table */ env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb; - spin_unlock(&tb_lock); return tb; } @@ -211,7 +177,6 @@ #if defined(TARGET_I386) flags = env->hflags; flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)); - flags |= env->intercept; cs_base = env->segs[R_CS].base; pc = cs_base + env->eip; #elif defined(TARGET_ARM) @@ -226,8 +191,9 @@ pc = env->regs[15]; #elif defined(TARGET_SPARC) #ifdef TARGET_SPARC64 - // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled - flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2)) + // AM . Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled + flags = ((env->pstate & PS_AM) << 2) + | (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2)) | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2); #else // FPU enable . Supervisor @@ -242,7 +208,7 @@ #elif defined(TARGET_MIPS) flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK); cs_base = 0; - pc = env->PC[env->current_tc]; + pc = env->active_tc.PC; #elif defined(TARGET_M68K) flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */ | (env->sr & SR_S) /* Bit 13 */ @@ -250,7 +216,10 @@ cs_base = 0; pc = env->pc; #elif defined(TARGET_SH4) - flags = env->flags; + flags = (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL + | DELAY_SLOT_TRUE | DELAY_SLOT_CLEARME)) /* Bits 0- 3 */ + | (env->fpscr & (FPSCR_FR | FPSCR_SZ | FPSCR_PR)) /* Bits 19-21 */ + | (env->sr & (SR_MD | SR_RB)); /* Bits 29-30 */ cs_base = 0; pc = env->pc; #elif defined(TARGET_ALPHA) @@ -258,45 +227,31 @@ cs_base = 0; pc = env->pc; #elif defined(TARGET_CRIS) - flags = 0; + flags = env->pregs[PR_CCS] & (S_FLAG | P_FLAG | U_FLAG | X_FLAG); + flags |= env->dslot; cs_base = 0; pc = env->pc; #else #error unsupported CPU #endif tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)]; - if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base || - tb->flags != flags, 0)) { + if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base || + tb->flags != flags)) { tb = tb_find_slow(pc, cs_base, flags); - /* Note: we do it here to avoid a gcc bug on Mac OS X when - doing it in tb_find_slow */ - if (tb_invalidated_flag) { - /* as some TB could have been invalidated because - of memory exceptions while generating the code, we - must recompute the hash index here */ - T0 = 0; - } } return tb; } -#define BREAK_CHAIN T0 = 0 - /* main execution loop */ int cpu_exec(CPUState *env1) { #define DECLARE_HOST_REGS 1 #include "hostregs_helper.h" -#if defined(TARGET_SPARC) -#if defined(reg_REGWPTR) - uint32_t *saved_regwptr; -#endif -#endif int ret, interrupt_request; - void (*gen_func)(void); TranslationBlock *tb; uint8_t *tc_ptr; + unsigned long next_tb; if (cpu_halted(env1) == EXCP_HALTED) return EXCP_HALTED; @@ -307,7 +262,6 @@ #define SAVE_HOST_REGS 1 #include "hostregs_helper.h" env = env1; - SAVE_GLOBALS(); env_to_regs(); #if defined(TARGET_I386) @@ -317,9 +271,6 @@ CC_OP = CC_OP_EFLAGS; env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); #elif defined(TARGET_SPARC) -#if defined(reg_REGWPTR) - saved_regwptr = REGWPTR; -#endif #elif defined(TARGET_M68K) env->cc_op = CC_OP_FLAGS; env->cc_dest = env->sr & 0xf; @@ -355,6 +306,8 @@ env->exception_is_int, env->error_code, env->exception_next_eip); + /* successfully delivered */ + env->old_exception = -1; #endif ret = env->exception_index; break; @@ -374,7 +327,7 @@ #elif defined(TARGET_MIPS) do_interrupt(env); #elif defined(TARGET_SPARC) - do_interrupt(env->exception_index); + do_interrupt(env); #elif defined(TARGET_ARM) do_interrupt(env); #elif defined(TARGET_SH4) @@ -415,15 +368,22 @@ } #endif - T0 = 0; /* force lookup of first TB */ + if (kvm_enabled()) { + kvm_cpu_exec(env); + longjmp(env->jmp_env, 1); + } + + next_tb = 0; /* force lookup of first TB */ for(;;) { - SAVE_GLOBALS(); interrupt_request = env->interrupt_request; - if (__builtin_expect(interrupt_request, 0) -#if defined(TARGET_I386) - && env->hflags & HF_GIF_MASK -#endif - ) { + if (unlikely(interrupt_request)) { + if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) { + /* Mask out external interrupts for this step. */ + interrupt_request &= ~(CPU_INTERRUPT_HARD | + CPU_INTERRUPT_FIQ | + CPU_INTERRUPT_SMI | + CPU_INTERRUPT_NMI); + } if (interrupt_request & CPU_INTERRUPT_DEBUG) { env->interrupt_request &= ~CPU_INTERRUPT_DEBUG; env->exception_index = EXCP_DEBUG; @@ -439,41 +399,51 @@ } #endif #if defined(TARGET_I386) - if ((interrupt_request & CPU_INTERRUPT_SMI) && - !(env->hflags & HF_SMM_MASK)) { - svm_check_intercept(SVM_EXIT_SMI); - env->interrupt_request &= ~CPU_INTERRUPT_SMI; - do_smm_enter(); - BREAK_CHAIN; - } else if ((interrupt_request & CPU_INTERRUPT_HARD) && - (env->eflags & IF_MASK || env->hflags & HF_HIF_MASK) && - !(env->hflags & HF_INHIBIT_IRQ_MASK)) { - int intno; - svm_check_intercept(SVM_EXIT_INTR); - env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ); - intno = cpu_get_pic_interrupt(env); - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno); - } - do_interrupt(intno, 0, 0, 0, 1); - /* ensure that no TB jump will be modified as - the program flow was changed */ - BREAK_CHAIN; + if (env->hflags2 & HF2_GIF_MASK) { + if ((interrupt_request & CPU_INTERRUPT_SMI) && + !(env->hflags & HF_SMM_MASK)) { + svm_check_intercept(SVM_EXIT_SMI); + env->interrupt_request &= ~CPU_INTERRUPT_SMI; + do_smm_enter(); + next_tb = 0; + } else if ((interrupt_request & CPU_INTERRUPT_NMI) && + !(env->hflags2 & HF2_NMI_MASK)) { + env->interrupt_request &= ~CPU_INTERRUPT_NMI; + env->hflags2 |= HF2_NMI_MASK; + do_interrupt(EXCP02_NMI, 0, 0, 0, 1); + next_tb = 0; + } else if ((interrupt_request & CPU_INTERRUPT_HARD) && + (((env->hflags2 & HF2_VINTR_MASK) && + (env->hflags2 & HF2_HIF_MASK)) || + (!(env->hflags2 & HF2_VINTR_MASK) && + (env->eflags & IF_MASK && + !(env->hflags & HF_INHIBIT_IRQ_MASK))))) { + int intno; + svm_check_intercept(SVM_EXIT_INTR); + env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ); + intno = cpu_get_pic_interrupt(env); + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno); + } + do_interrupt(intno, 0, 0, 0, 1); + /* ensure that no TB jump will be modified as + the program flow was changed */ + next_tb = 0; #if !defined(CONFIG_USER_ONLY) - } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) && - (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) { - int intno; - /* FIXME: this should respect TPR */ - env->interrupt_request &= ~CPU_INTERRUPT_VIRQ; - svm_check_intercept(SVM_EXIT_VINTR); - intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector)); - if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno); - do_interrupt(intno, 0, 0, -1, 1); - stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), - ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK); - BREAK_CHAIN; + } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) && + (env->eflags & IF_MASK) && + !(env->hflags & HF_INHIBIT_IRQ_MASK)) { + int intno; + /* FIXME: this should respect TPR */ + svm_check_intercept(SVM_EXIT_VINTR); + env->interrupt_request &= ~CPU_INTERRUPT_VIRQ; + intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector)); + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno); + do_interrupt(intno, 0, 0, 0, 1); + next_tb = 0; #endif + } } #elif defined(TARGET_PPC) #if 0 @@ -485,7 +455,7 @@ ppc_hw_interrupt(env); if (env->pending_interrupts == 0) env->interrupt_request &= ~CPU_INTERRUPT_HARD; - BREAK_CHAIN; + next_tb = 0; } #elif defined(TARGET_MIPS) if ((interrupt_request & CPU_INTERRUPT_HARD) && @@ -498,7 +468,7 @@ env->exception_index = EXCP_EXT_INTERRUPT; env->error_code = 0; do_interrupt(env); - BREAK_CHAIN; + next_tb = 0; } #elif defined(TARGET_SPARC) if ((interrupt_request & CPU_INTERRUPT_HARD) && @@ -510,12 +480,13 @@ (pil == 15 || pil > env->psrpil)) || type != TT_EXTINT) { env->interrupt_request &= ~CPU_INTERRUPT_HARD; - do_interrupt(env->interrupt_index); + env->exception_index = env->interrupt_index; + do_interrupt(env); env->interrupt_index = 0; #if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) cpu_check_irqs(env); #endif - BREAK_CHAIN; + next_tb = 0; } } else if (interrupt_request & CPU_INTERRUPT_TIMER) { //do_interrupt(0, 0, 0, 0, 0); @@ -526,7 +497,7 @@ && !(env->uncached_cpsr & CPSR_F)) { env->exception_index = EXCP_FIQ; do_interrupt(env); - BREAK_CHAIN; + next_tb = 0; } /* ARMv7-M interrupt return works by loading a magic value into the PC. On real hardware the load causes the @@ -542,23 +513,30 @@ || !(env->uncached_cpsr & CPSR_I))) { env->exception_index = EXCP_IRQ; do_interrupt(env); - BREAK_CHAIN; + next_tb = 0; } #elif defined(TARGET_SH4) if (interrupt_request & CPU_INTERRUPT_HARD) { do_interrupt(env); - BREAK_CHAIN; + next_tb = 0; } #elif defined(TARGET_ALPHA) if (interrupt_request & CPU_INTERRUPT_HARD) { do_interrupt(env); - BREAK_CHAIN; + next_tb = 0; } #elif defined(TARGET_CRIS) - if (interrupt_request & CPU_INTERRUPT_HARD) { + if (interrupt_request & CPU_INTERRUPT_HARD + && (env->pregs[PR_CCS] & I_FLAG)) { + env->exception_index = EXCP_IRQ; + do_interrupt(env); + next_tb = 0; + } + if (interrupt_request & CPU_INTERRUPT_NMI + && (env->pregs[PR_CCS] & M_FLAG)) { + env->exception_index = EXCP_NMI; do_interrupt(env); - env->interrupt_request &= ~CPU_INTERRUPT_HARD; - BREAK_CHAIN; + next_tb = 0; } #elif defined(TARGET_M68K) if (interrupt_request & CPU_INTERRUPT_HARD @@ -571,7 +549,7 @@ first signalled. */ env->exception_index = env->pending_vector; do_interrupt(1); - BREAK_CHAIN; + next_tb = 0; } #endif /* Don't use the cached interupt_request value, @@ -580,7 +558,7 @@ env->interrupt_request &= ~CPU_INTERRUPT_EXITTB; /* ensure that no TB jump will be modified as the program flow was changed */ - BREAK_CHAIN; + next_tb = 0; } if (interrupt_request & CPU_INTERRUPT_EXIT) { env->interrupt_request &= ~CPU_INTERRUPT_EXIT; @@ -599,8 +577,6 @@ #elif defined(TARGET_ARM) cpu_dump_state(env, logfile, fprintf, 0); #elif defined(TARGET_SPARC) - REGWPTR = env->regbase + (env->cwp * 16); - env->regwptr = REGWPTR; cpu_dump_state(env, logfile, fprintf, 0); #elif defined(TARGET_PPC) cpu_dump_state(env, logfile, fprintf, 0); @@ -623,7 +599,17 @@ #endif } #endif + spin_lock(&tb_lock); tb = tb_find_fast(); + /* Note: we do it here to avoid a gcc bug on Mac OS X when + doing it in tb_find_slow */ + if (tb_invalidated_flag) { + /* as some TB could have been invalidated because + of memory exceptions while generating the code, we + must recompute the hash index here */ + next_tb = 0; + tb_invalidated_flag = 0; + } #ifdef DEBUG_EXEC if ((loglevel & CPU_LOG_EXEC)) { fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n", @@ -631,63 +617,68 @@ lookup_symbol(tb->pc)); } #endif - RESTORE_GLOBALS(); /* see if we can patch the calling TB. When the TB spans two pages, we cannot safely do a direct jump. */ { - if (T0 != 0 && -#if USE_KQEMU + if (next_tb != 0 && +#ifdef USE_KQEMU (env->kqemu_enabled != 2) && #endif tb->page_addr[1] == -1) { - spin_lock(&tb_lock); - tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb); - spin_unlock(&tb_lock); + tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb); } } - tc_ptr = tb->tc_ptr; + spin_unlock(&tb_lock); env->current_tb = tb; + + /* cpu_interrupt might be called while translating the + TB, but before it is linked into a potentially + infinite loop and becomes env->current_tb. Avoid + starting execution if there is a pending interrupt. */ + if (unlikely (env->interrupt_request & CPU_INTERRUPT_EXIT)) + env->current_tb = NULL; + + while (env->current_tb) { + tc_ptr = tb->tc_ptr; /* execute the generated code */ - gen_func = (void *)tc_ptr; -#if defined(__sparc__) - __asm__ __volatile__("call %0\n\t" - "mov %%o7,%%i0" - : /* no outputs */ - : "r" (gen_func) - : "i0", "i1", "i2", "i3", "i4", "i5", - "o0", "o1", "o2", "o3", "o4", "o5", - "l0", "l1", "l2", "l3", "l4", "l5", - "l6", "l7"); -#elif defined(__arm__) - asm volatile ("mov pc, %0\n\t" - ".global exec_loop\n\t" - "exec_loop:\n\t" - : /* no outputs */ - : "r" (gen_func) - : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14"); -#elif defined(__ia64) - struct fptr { - void *ip; - void *gp; - } fp; - - fp.ip = tc_ptr; - fp.gp = code_gen_buffer + 2 * (1 << 20); - (*(void (*)(void)) &fp)(); -#else - gen_func(); -#endif - env->current_tb = NULL; +#if defined(__sparc__) && !defined(HOST_SOLARIS) +#undef env + env = cpu_single_env; +#define env cpu_single_env +#endif + next_tb = tcg_qemu_tb_exec(tc_ptr); + env->current_tb = NULL; + if ((next_tb & 3) == 2) { + /* Instruction counter expired. */ + int insns_left; + tb = (TranslationBlock *)(long)(next_tb & ~3); + /* Restore PC. */ + CPU_PC_FROM_TB(env, tb); + insns_left = env->icount_decr.u32; + if (env->icount_extra && insns_left >= 0) { + /* Refill decrementer and continue execution. */ + env->icount_extra += insns_left; + if (env->icount_extra > 0xffff) { + insns_left = 0xffff; + } else { + insns_left = env->icount_extra; + } + env->icount_extra -= insns_left; + env->icount_decr.u16.low = insns_left; + } else { + if (insns_left > 0) { + /* Execute remaining instructions. */ + cpu_exec_nocache(insns_left, tb); + } + env->exception_index = EXCP_INTERRUPT; + next_tb = 0; + cpu_loop_exit(); + } + } + } /* reset soft MMU for next block (it can currently only be set by a memory fault) */ -#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU) - if (env->hflags & HF_SOFTMMU_MASK) { - env->hflags &= ~HF_SOFTMMU_MASK; - /* do not allow linking to another block */ - T0 = 0; - } -#endif #if defined(USE_KQEMU) #define MIN_CYCLE_BEFORE_SWITCH (100 * 1000) if (kqemu_is_ok(env) && @@ -708,9 +699,6 @@ #elif defined(TARGET_ARM) /* XXX: Save/restore host fpu exception state?. */ #elif defined(TARGET_SPARC) -#if defined(reg_REGWPTR) - REGWPTR = saved_regwptr; -#endif #elif defined(TARGET_PPC) #elif defined(TARGET_M68K) cpu_m68k_flush_flags(env, env->cc_op); @@ -727,7 +715,6 @@ #endif /* restore global registers */ - RESTORE_GLOBALS(); #include "hostregs_helper.h" /* fail safe : never use cpu_single_env outside cpu_exec() */ @@ -761,7 +748,7 @@ cpu_x86_load_seg_cache(env, seg_reg, selector, (selector << 4), 0xffff, 0); } else { - load_seg(seg_reg, selector); + helper_load_seg(seg_reg, selector); } env = saved_env; } @@ -884,6 +871,8 @@ do it (XXX: use sigsetjmp) */ sigprocmask(SIG_SETMASK, old_set, NULL); cpu_loop_exit(); + /* never comes here */ + return 1; } #elif defined(TARGET_SPARC) static inline int handle_cpu_signal(unsigned long pc, unsigned long address, @@ -920,6 +909,8 @@ do it (XXX: use sigsetjmp) */ sigprocmask(SIG_SETMASK, old_set, NULL); cpu_loop_exit(); + /* never comes here */ + return 1; } #elif defined (TARGET_PPC) static inline int handle_cpu_signal(unsigned long pc, unsigned long address, @@ -1182,10 +1173,6 @@ a virtual CPU fault */ cpu_restore_state(tb, env, pc, puc); } -#if 0 - printf("PF exception: NIP=0x%08x error=0x%x %p\n", - env->nip, env->error_code, tb); -#endif /* we restore the process signal mask as the sigreturn should do it (XXX: use sigsetjmp) */ sigprocmask(SIG_SETMASK, old_set, NULL); @@ -1359,14 +1346,25 @@ void *puc) { siginfo_t *info = pinfo; - uint32_t *regs = (uint32_t *)(info + 1); - void *sigmask = (regs + 20); - unsigned long pc; int is_write; uint32_t insn; - +#if !defined(__arch64__) || defined(HOST_SOLARIS) + uint32_t *regs = (uint32_t *)(info + 1); + void *sigmask = (regs + 20); /* XXX: is there a standard glibc define ? */ - pc = regs[1]; + unsigned long pc = regs[1]; +#else +#ifdef __linux__ + struct sigcontext *sc = puc; + unsigned long pc = sc->sigc_regs.tpc; + void *sigmask = (void *)sc->sigc_mask; +#elif defined(__OpenBSD__) + struct sigcontext *uc = puc; + unsigned long pc = uc->sc_pc; + void *sigmask = (void *)(long)uc->sc_mask; +#endif +#endif + /* XXX: need kernel patch to get write flag faster */ is_write = 0; insn = *(uint32_t *)pc; @@ -1397,7 +1395,11 @@ unsigned long pc; int is_write; +#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) pc = uc->uc_mcontext.gregs[R15]; +#else + pc = uc->uc_mcontext.arm_pc; +#endif /* XXX: compute is_write */ is_write = 0; return handle_cpu_signal(pc, (unsigned long)info->si_addr, @@ -1490,6 +1492,24 @@ is_write, &uc->uc_sigmask, puc); } +#elif defined(__hppa__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + struct siginfo *info = pinfo; + struct ucontext *uc = puc; + unsigned long pc; + int is_write; + + pc = uc->uc_mcontext.sc_iaoq[0]; + /* FIXME: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, + &uc->uc_sigmask, puc); +} + #else #error host CPU specific signal handler needed diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/cris-dis.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/cris-dis.c --- qemu-0.9.1/cris-dis.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/cris-dis.c 2008-05-06 09:45:10.000000000 +0100 @@ -2625,12 +2625,10 @@ If we can't get any data, or we do not get enough data, we print the error message. */ - for (nbytes = MAX_BYTES_PER_CRIS_INSN; nbytes > 0; nbytes -= 2) - { - status = (*info->read_memory_func) (memaddr, buffer, nbytes, info); - if (status == 0) - break; - } + nbytes = info->buffer_length; + if (nbytes > MAX_BYTES_PER_CRIS_INSN) + nbytes = MAX_BYTES_PER_CRIS_INSN; + status = (*info->read_memory_func) (memaddr, buffer, nbytes, info); /* If we did not get all we asked for, then clear the rest. Hopefully this makes a reproducible result in case of errors. */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/curses.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/curses.c --- qemu-0.9.1/curses.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/curses.c 2008-09-24 04:32:33.000000000 +0100 @@ -0,0 +1,374 @@ +/* + * QEMU curses/ncurses display driver + * + * Copyright (c) 2005 Andrzej Zaborowski + * + * 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 "qemu-common.h" +#include "console.h" +#include "sysemu.h" + +#include + +#ifndef _WIN32 +#include +#include +#include +#endif + +#ifdef __OpenBSD__ +#define resize_term resizeterm +#endif + +#define FONT_HEIGHT 16 +#define FONT_WIDTH 8 + +static console_ch_t screen[160 * 100]; +static WINDOW *screenpad = NULL; +static int width, height, gwidth, gheight, invalidate; +static int px, py, sminx, sminy, smaxx, smaxy; + +static void curses_update(DisplayState *ds, int x, int y, int w, int h) +{ + chtype *line; + + line = ((chtype *) screen) + y * width; + for (h += y; y < h; y ++, line += width) + mvwaddchnstr(screenpad, y, 0, line, width); + + pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1); + refresh(); +} + +static void curses_calc_pad(void) +{ + if (is_fixedsize_console()) { + width = gwidth; + height = gheight; + } else { + width = COLS; + height = LINES; + } + + if (screenpad) + delwin(screenpad); + + clear(); + refresh(); + + screenpad = newpad(height, width); + + if (width > COLS) { + px = (width - COLS) / 2; + sminx = 0; + smaxx = COLS; + } else { + px = 0; + sminx = (COLS - width) / 2; + smaxx = sminx + width; + } + + if (height > LINES) { + py = (height - LINES) / 2; + sminy = 0; + smaxy = LINES; + } else { + py = 0; + sminy = (LINES - height) / 2; + smaxy = sminy + height; + } +} + +static void curses_resize(DisplayState *ds, int w, int h) +{ + if (w == gwidth && h == gheight) + return; + + gwidth = w; + gheight = h; + + curses_calc_pad(); +} + +#ifndef _WIN32 +#if defined(SIGWINCH) && defined(KEY_RESIZE) +static void curses_winch_handler(int signum) +{ + struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; /* unused */ + unsigned short ws_ypixel; /* unused */ + } ws; + + /* terminal size changed */ + if (ioctl(1, TIOCGWINSZ, &ws) == -1) + return; + + resize_term(ws.ws_row, ws.ws_col); + curses_calc_pad(); + invalidate = 1; + + /* some systems require this */ + signal(SIGWINCH, curses_winch_handler); +} +#endif +#endif + +static void curses_cursor_position(DisplayState *ds, int x, int y) +{ + if (x >= 0) { + x = sminx + x - px; + y = sminy + y - py; + + if (x >= 0 && y >= 0 && x < COLS && y < LINES) { + move(y, x); + curs_set(1); + /* it seems that curs_set(1) must always be called before + * curs_set(2) for the latter to have effect */ + if (!is_graphic_console()) + curs_set(2); + return; + } + } + + curs_set(0); +} + +/* generic keyboard conversion */ + +#include "curses_keys.h" +#include "keymaps.c" + +static kbd_layout_t *kbd_layout = 0; +static int keycode2keysym[CURSES_KEYS]; + +static void curses_refresh(DisplayState *ds) +{ + int chr, nextchr, keysym, keycode; + + if (invalidate) { + clear(); + refresh(); + curses_calc_pad(); + ds->width = FONT_WIDTH * width; + ds->height = FONT_HEIGHT * height; + vga_hw_invalidate(); + invalidate = 0; + } + + vga_hw_text_update(screen); + + nextchr = ERR; + while (1) { + /* while there are any pending key strokes to process */ + if (nextchr == ERR) + chr = getch(); + else { + chr = nextchr; + nextchr = ERR; + } + + if (chr == ERR) + break; + +#ifdef KEY_RESIZE + /* this shouldn't occur when we use a custom SIGWINCH handler */ + if (chr == KEY_RESIZE) { + clear(); + refresh(); + curses_calc_pad(); + curses_update(ds, 0, 0, width, height); + ds->width = FONT_WIDTH * width; + ds->height = FONT_HEIGHT * height; + continue; + } +#endif + + keycode = curses2keycode[chr]; + if (keycode == -1) + continue; + + /* alt key */ + if (keycode == 1) { + nextchr = getch(); + + if (nextchr != ERR) { + keycode = curses2keycode[nextchr]; + nextchr = ERR; + if (keycode == -1) + continue; + + keycode |= ALT; + + /* process keys reserved for qemu */ + if (keycode >= QEMU_KEY_CONSOLE0 && + keycode < QEMU_KEY_CONSOLE0 + 9) { + erase(); + wnoutrefresh(stdscr); + console_select(keycode - QEMU_KEY_CONSOLE0); + + invalidate = 1; + continue; + } + } + } + + if (kbd_layout && !(keycode & GREY)) { + keysym = keycode2keysym[keycode & KEY_MASK]; + if (keysym == -1) + keysym = chr; + + keycode &= ~KEY_MASK; + keycode |= keysym2scancode(kbd_layout, keysym); + } + + if (is_graphic_console()) { + /* since terminals don't know about key press and release + * events, we need to emit both for each key received */ + if (keycode & SHIFT) + kbd_put_keycode(SHIFT_CODE); + if (keycode & CNTRL) + kbd_put_keycode(CNTRL_CODE); + if (keycode & ALT) + kbd_put_keycode(ALT_CODE); + if (keycode & GREY) + kbd_put_keycode(GREY_CODE); + kbd_put_keycode(keycode & KEY_MASK); + if (keycode & GREY) + kbd_put_keycode(GREY_CODE); + kbd_put_keycode((keycode & KEY_MASK) | KEY_RELEASE); + if (keycode & ALT) + kbd_put_keycode(ALT_CODE | KEY_RELEASE); + if (keycode & CNTRL) + kbd_put_keycode(CNTRL_CODE | KEY_RELEASE); + if (keycode & SHIFT) + kbd_put_keycode(SHIFT_CODE | KEY_RELEASE); + } else { + keysym = curses2keysym[chr]; + if (keysym == -1) + keysym = chr; + + kbd_put_keysym(keysym); + } + } +} + +static void curses_cleanup(void *opaque) +{ + endwin(); +} + +static void curses_atexit(void) +{ + curses_cleanup(NULL); +} + +static void curses_setup(void) +{ + int i, colour_default[8] = { + COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, + COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE, + }; + + /* input as raw as possible, let everything be interpreted + * by the guest system */ + initscr(); noecho(); intrflush(stdscr, FALSE); + nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE); + start_color(); raw(); scrollok(stdscr, FALSE); + + for (i = 0; i < 64; i ++) + init_pair(i, colour_default[i & 7], colour_default[i >> 3]); +} + +static void curses_keyboard_setup(void) +{ + int i, keycode, keysym; + +#if defined(__APPLE__) + /* always use generic keymaps */ + if (!keyboard_layout) + keyboard_layout = "en-us"; +#endif + if(keyboard_layout) { + kbd_layout = init_keyboard_layout(keyboard_layout); + if (!kbd_layout) + exit(1); + } + + for (i = 0; i < CURSES_KEYS; i ++) + keycode2keysym[i] = -1; + + for (i = 0; i < CURSES_KEYS; i ++) { + if (curses2keycode[i] == -1) + continue; + + keycode = curses2keycode[i] & KEY_MASK; + if (keycode2keysym[keycode] >= 0) + continue; + + for (keysym = 0; keysym < CURSES_KEYS; keysym ++) + if (curses2keycode[keysym] == keycode) { + keycode2keysym[keycode] = keysym; + break; + } + + if (keysym >= CURSES_KEYS) + keycode2keysym[keycode] = i; + } +} + +void curses_display_init(DisplayState *ds, int full_screen) +{ +#ifndef _WIN32 + if (!isatty(1)) { + fprintf(stderr, "We need a terminal output\n"); + exit(1); + } +#endif + + curses_setup(); + curses_keyboard_setup(); + atexit(curses_atexit); + +#ifndef _WIN32 +#if defined(SIGWINCH) && defined(KEY_RESIZE) + /* some curses implementations provide a handler, but we + * want to be sure this is handled regardless of the library */ + signal(SIGWINCH, curses_winch_handler); +#endif +#endif + + ds->data = (void *) screen; + ds->linesize = 0; + ds->depth = 0; + ds->width = 640; + ds->height = 400; + ds->dpy_update = curses_update; + ds->dpy_resize = curses_resize; + ds->dpy_refresh = curses_refresh; + ds->dpy_text_cursor = curses_cursor_position; + + invalidate = 1; + + /* Standard VGA initial text mode dimensions */ + curses_resize(ds, 80, 25); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/curses_keys.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/curses_keys.h --- qemu-0.9.1/curses_keys.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/curses_keys.h 2008-10-28 00:11:06.000000000 +0000 @@ -0,0 +1,484 @@ +/* + * Keycode and keysyms conversion tables for curses + * + * Copyright (c) 2005 Andrzej Zaborowski + * + * 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. + */ +#define KEY_RELEASE 0x80 +#define KEY_MASK 0x7f +#define SHIFT_CODE 0x2a +#define SHIFT 0x0080 +#define GREY_CODE 0xe0 +#define GREY 0x0100 +#define CNTRL_CODE 0x1d +#define CNTRL 0x0200 +#define ALT_CODE 0x38 +#define ALT 0x0400 + +/* curses won't detect a Control + Alt + 1, so use Alt + 1 */ +#define QEMU_KEY_CONSOLE0 (2 | ALT) /* (curses2keycode['1'] | ALT) */ + +#define CURSES_KEYS KEY_MAX /* KEY_MAX defined in */ + +static const int curses2keycode[CURSES_KEYS] = { + [0 ... (CURSES_KEYS - 1)] = -1, + + [0x01b] = 1, /* Escape */ + ['1'] = 2, + ['2'] = 3, + ['3'] = 4, + ['4'] = 5, + ['5'] = 6, + ['6'] = 7, + ['7'] = 8, + ['8'] = 9, + ['9'] = 10, + ['0'] = 11, + ['-'] = 12, + ['='] = 13, + [0x07f] = 14, /* Backspace */ + [0x107] = 14, /* Backspace */ + + ['\t'] = 15, /* Tab */ + ['q'] = 16, + ['w'] = 17, + ['e'] = 18, + ['r'] = 19, + ['t'] = 20, + ['y'] = 21, + ['u'] = 22, + ['i'] = 23, + ['o'] = 24, + ['p'] = 25, + ['['] = 26, + [']'] = 27, + ['\n'] = 28, /* Return */ + ['\r'] = 28, /* Return */ + [0x157] = 28, /* Return */ + + ['a'] = 30, + ['s'] = 31, + ['d'] = 32, + ['f'] = 33, + ['g'] = 34, + ['h'] = 35, + ['j'] = 36, + ['k'] = 37, + ['l'] = 38, + [';'] = 39, + ['\''] = 40, /* Single quote */ + ['`'] = 41, + ['\\'] = 43, /* Backslash */ + + ['z'] = 44, + ['x'] = 45, + ['c'] = 46, + ['v'] = 47, + ['b'] = 48, + ['n'] = 49, + ['m'] = 50, + [','] = 51, + ['.'] = 52, + ['/'] = 53, + + [' '] = 57, + + [0x109] = 59, /* Function Key 1 */ + [0x10a] = 60, /* Function Key 2 */ + [0x10b] = 61, /* Function Key 3 */ + [0x10c] = 62, /* Function Key 4 */ + [0x10d] = 63, /* Function Key 5 */ + [0x10e] = 64, /* Function Key 6 */ + [0x10f] = 65, /* Function Key 7 */ + [0x110] = 66, /* Function Key 8 */ + [0x111] = 67, /* Function Key 9 */ + [0x112] = 68, /* Function Key 10 */ + [0x113] = 87, /* Function Key 11 */ + [0x114] = 88, /* Function Key 12 */ + + [0x106] = 71 | GREY, /* Home */ + [0x103] = 72 | GREY, /* Up Arrow */ + [0x153] = 73 | GREY, /* Page Up */ + [0x104] = 75 | GREY, /* Left Arrow */ + [0x105] = 77 | GREY, /* Right Arrow */ + [0x168] = 79 | GREY, /* End */ + [0x102] = 80 | GREY, /* Down Arrow */ + [0x152] = 81 | GREY, /* Page Down */ + [0x14b] = 82 | GREY, /* Insert */ + [0x14a] = 83 | GREY, /* Delete */ + + ['!'] = 2 | SHIFT, + ['@'] = 3 | SHIFT, + ['#'] = 4 | SHIFT, + ['$'] = 5 | SHIFT, + ['%'] = 6 | SHIFT, + ['^'] = 7 | SHIFT, + ['&'] = 8 | SHIFT, + ['*'] = 9 | SHIFT, + ['('] = 10 | SHIFT, + [')'] = 11 | SHIFT, + ['_'] = 12 | SHIFT, + ['+'] = 13 | SHIFT, + + [0x161] = 15 | SHIFT, /* Shift + Tab */ + ['Q'] = 16 | SHIFT, + ['W'] = 17 | SHIFT, + ['E'] = 18 | SHIFT, + ['R'] = 19 | SHIFT, + ['T'] = 20 | SHIFT, + ['Y'] = 21 | SHIFT, + ['U'] = 22 | SHIFT, + ['I'] = 23 | SHIFT, + ['O'] = 24 | SHIFT, + ['P'] = 25 | SHIFT, + ['{'] = 26 | SHIFT, + ['}'] = 27 | SHIFT, + + ['A'] = 30 | SHIFT, + ['S'] = 31 | SHIFT, + ['D'] = 32 | SHIFT, + ['F'] = 33 | SHIFT, + ['G'] = 34 | SHIFT, + ['H'] = 35 | SHIFT, + ['J'] = 36 | SHIFT, + ['K'] = 37 | SHIFT, + ['L'] = 38 | SHIFT, + [':'] = 39 | SHIFT, + ['"'] = 40 | SHIFT, + ['~'] = 41 | SHIFT, + ['|'] = 43 | SHIFT, + + ['Z'] = 44 | SHIFT, + ['X'] = 45 | SHIFT, + ['C'] = 46 | SHIFT, + ['V'] = 47 | SHIFT, + ['B'] = 48 | SHIFT, + ['N'] = 49 | SHIFT, + ['M'] = 50 | SHIFT, + ['<'] = 51 | SHIFT, + ['>'] = 52 | SHIFT, + ['?'] = 53 | SHIFT, + + [0x115] = 59 | SHIFT, /* Shift + Function Key 1 */ + [0x116] = 60 | SHIFT, /* Shift + Function Key 2 */ + [0x117] = 61 | SHIFT, /* Shift + Function Key 3 */ + [0x118] = 62 | SHIFT, /* Shift + Function Key 4 */ + [0x119] = 63 | SHIFT, /* Shift + Function Key 5 */ + [0x11a] = 64 | SHIFT, /* Shift + Function Key 6 */ + [0x11b] = 65 | SHIFT, /* Shift + Function Key 7 */ + [0x11c] = 66 | SHIFT, /* Shift + Function Key 8 */ + + [0x011] = 16 | CNTRL, /* Control + q */ + [0x017] = 17 | CNTRL, /* Control + w */ + [0x005] = 18 | CNTRL, /* Control + e */ + [0x012] = 19 | CNTRL, /* Control + r */ + [0x014] = 20 | CNTRL, /* Control + t */ + [0x019] = 21 | CNTRL, /* Control + y */ + [0x015] = 22 | CNTRL, /* Control + u */ + /* Control + i collides with Tab */ + [0x00f] = 24 | CNTRL, /* Control + o */ + [0x010] = 25 | CNTRL, /* Control + p */ + + [0x001] = 30 | CNTRL, /* Control + a */ + [0x013] = 31 | CNTRL, /* Control + s */ + [0x004] = 32 | CNTRL, /* Control + d */ + [0x006] = 33 | CNTRL, /* Control + f */ + [0x007] = 34 | CNTRL, /* Control + g */ + [0x008] = 35 | CNTRL, /* Control + h */ + [0x00a] = 36 | CNTRL, /* Control + j */ + [0x00b] = 37 | CNTRL, /* Control + k */ + [0x00c] = 38 | CNTRL, /* Control + l */ + + [0x01a] = 44 | CNTRL, /* Control + z */ + [0x018] = 45 | CNTRL, /* Control + x */ + [0x003] = 46 | CNTRL, /* Control + c */ + [0x016] = 47 | CNTRL, /* Control + v */ + [0x002] = 48 | CNTRL, /* Control + b */ + [0x00e] = 49 | CNTRL, /* Control + n */ + /* Control + m collides with the keycode for Enter */ + +}; + +static const int curses2keysym[CURSES_KEYS] = { + [0 ... (CURSES_KEYS - 1)] = -1, + + ['\n'] = '\n', + ['\r'] = '\n', + + [0x07f] = QEMU_KEY_BACKSPACE, + + [0x102] = QEMU_KEY_DOWN, + [0x103] = QEMU_KEY_UP, + [0x104] = QEMU_KEY_LEFT, + [0x105] = QEMU_KEY_RIGHT, + [0x106] = QEMU_KEY_HOME, + [0x107] = QEMU_KEY_BACKSPACE, + + [0x14a] = QEMU_KEY_DELETE, + [0x152] = QEMU_KEY_PAGEDOWN, + [0x153] = QEMU_KEY_PAGEUP, + [0x157] = '\n', + [0x168] = QEMU_KEY_END, + +}; + +typedef struct { + const char* name; + int keysym; +} name2keysym_t; + +static const name2keysym_t name2keysym[] = { + /* Plain ASCII */ + { "space", 0x020 }, + { "exclam", 0x021 }, + { "quotedbl", 0x022 }, + { "numbersign", 0x023 }, + { "dollar", 0x024 }, + { "percent", 0x025 }, + { "ampersand", 0x026 }, + { "apostrophe", 0x027 }, + { "parenleft", 0x028 }, + { "parenright", 0x029 }, + { "asterisk", 0x02a }, + { "plus", 0x02b }, + { "comma", 0x02c }, + { "minus", 0x02d }, + { "period", 0x02e }, + { "slash", 0x02f }, + { "0", 0x030 }, + { "1", 0x031 }, + { "2", 0x032 }, + { "3", 0x033 }, + { "4", 0x034 }, + { "5", 0x035 }, + { "6", 0x036 }, + { "7", 0x037 }, + { "8", 0x038 }, + { "9", 0x039 }, + { "colon", 0x03a }, + { "semicolon", 0x03b }, + { "less", 0x03c }, + { "equal", 0x03d }, + { "greater", 0x03e }, + { "question", 0x03f }, + { "at", 0x040 }, + { "A", 0x041 }, + { "B", 0x042 }, + { "C", 0x043 }, + { "D", 0x044 }, + { "E", 0x045 }, + { "F", 0x046 }, + { "G", 0x047 }, + { "H", 0x048 }, + { "I", 0x049 }, + { "J", 0x04a }, + { "K", 0x04b }, + { "L", 0x04c }, + { "M", 0x04d }, + { "N", 0x04e }, + { "O", 0x04f }, + { "P", 0x050 }, + { "Q", 0x051 }, + { "R", 0x052 }, + { "S", 0x053 }, + { "T", 0x054 }, + { "U", 0x055 }, + { "V", 0x056 }, + { "W", 0x057 }, + { "X", 0x058 }, + { "Y", 0x059 }, + { "Z", 0x05a }, + { "bracketleft", 0x05b }, + { "backslash", 0x05c }, + { "bracketright", 0x05d }, + { "asciicircum", 0x05e }, + { "underscore", 0x05f }, + { "grave", 0x060 }, + { "a", 0x061 }, + { "b", 0x062 }, + { "c", 0x063 }, + { "d", 0x064 }, + { "e", 0x065 }, + { "f", 0x066 }, + { "g", 0x067 }, + { "h", 0x068 }, + { "i", 0x069 }, + { "j", 0x06a }, + { "k", 0x06b }, + { "l", 0x06c }, + { "m", 0x06d }, + { "n", 0x06e }, + { "o", 0x06f }, + { "p", 0x070 }, + { "q", 0x071 }, + { "r", 0x072 }, + { "s", 0x073 }, + { "t", 0x074 }, + { "u", 0x075 }, + { "v", 0x076 }, + { "w", 0x077 }, + { "x", 0x078 }, + { "y", 0x079 }, + { "z", 0x07a }, + { "braceleft", 0x07b }, + { "bar", 0x07c }, + { "braceright", 0x07d }, + { "asciitilde", 0x07e }, + + /* Latin-1 extensions */ + { "nobreakspace", 0x0a0 }, + { "exclamdown", 0x0a1 }, + { "cent", 0x0a2 }, + { "sterling", 0x0a3 }, + { "currency", 0x0a4 }, + { "yen", 0x0a5 }, + { "brokenbar", 0x0a6 }, + { "section", 0x0a7 }, + { "diaeresis", 0x0a8 }, + { "copyright", 0x0a9 }, + { "ordfeminine", 0x0aa }, + { "guillemotleft", 0x0ab }, + { "notsign", 0x0ac }, + { "hyphen", 0x0ad }, + { "registered", 0x0ae }, + { "macron", 0x0af }, + { "degree", 0x0b0 }, + { "plusminus", 0x0b1 }, + { "twosuperior", 0x0b2 }, + { "threesuperior", 0x0b3 }, + { "acute", 0x0b4 }, + { "mu", 0x0b5 }, + { "paragraph", 0x0b6 }, + { "periodcentered", 0x0b7 }, + { "cedilla", 0x0b8 }, + { "onesuperior", 0x0b9 }, + { "masculine", 0x0ba }, + { "guillemotright", 0x0bb }, + { "onequarter", 0x0bc }, + { "onehalf", 0x0bd }, + { "threequarters", 0x0be }, + { "questiondown", 0x0bf }, + { "Agrave", 0x0c0 }, + { "Aacute", 0x0c1 }, + { "Acircumflex", 0x0c2 }, + { "Atilde", 0x0c3 }, + { "Adiaeresis", 0x0c4 }, + { "Aring", 0x0c5 }, + { "AE", 0x0c6 }, + { "Ccedilla", 0x0c7 }, + { "Egrave", 0x0c8 }, + { "Eacute", 0x0c9 }, + { "Ecircumflex", 0x0ca }, + { "Ediaeresis", 0x0cb }, + { "Igrave", 0x0cc }, + { "Iacute", 0x0cd }, + { "Icircumflex", 0x0ce }, + { "Idiaeresis", 0x0cf }, + { "ETH", 0x0d0 }, + { "Eth", 0x0d0 }, + { "Ntilde", 0x0d1 }, + { "Ograve", 0x0d2 }, + { "Oacute", 0x0d3 }, + { "Ocircumflex", 0x0d4 }, + { "Otilde", 0x0d5 }, + { "Odiaeresis", 0x0d6 }, + { "multiply", 0x0d7 }, + { "Ooblique", 0x0d8 }, + { "Oslash", 0x0d8 }, + { "Ugrave", 0x0d9 }, + { "Uacute", 0x0da }, + { "Ucircumflex", 0x0db }, + { "Udiaeresis", 0x0dc }, + { "Yacute", 0x0dd }, + { "THORN", 0x0de }, + { "Thorn", 0x0de }, + { "ssharp", 0x0df }, + { "agrave", 0x0e0 }, + { "aacute", 0x0e1 }, + { "acircumflex", 0x0e2 }, + { "atilde", 0x0e3 }, + { "adiaeresis", 0x0e4 }, + { "aring", 0x0e5 }, + { "ae", 0x0e6 }, + { "ccedilla", 0x0e7 }, + { "egrave", 0x0e8 }, + { "eacute", 0x0e9 }, + { "ecircumflex", 0x0ea }, + { "ediaeresis", 0x0eb }, + { "igrave", 0x0ec }, + { "iacute", 0x0ed }, + { "icircumflex", 0x0ee }, + { "idiaeresis", 0x0ef }, + { "eth", 0x0f0 }, + { "ntilde", 0x0f1 }, + { "ograve", 0x0f2 }, + { "oacute", 0x0f3 }, + { "ocircumflex", 0x0f4 }, + { "otilde", 0x0f5 }, + { "odiaeresis", 0x0f6 }, + { "division", 0x0f7 }, + { "oslash", 0x0f8 }, + { "ooblique", 0x0f8 }, + { "ugrave", 0x0f9 }, + { "uacute", 0x0fa }, + { "ucircumflex", 0x0fb }, + { "udiaeresis", 0x0fc }, + { "yacute", 0x0fd }, + { "thorn", 0x0fe }, + { "ydiaeresis", 0x0ff }, + + /* Special keys */ + { "BackSpace", 0x07f }, + { "Tab", '\t' }, + { "Return", '\r' }, + { "Right", 0x105 }, + { "Left", 0x104 }, + { "Up", 0x103 }, + { "Down", 0x102 }, + { "Page_Down", 0x152 }, + { "Page_Up", 0x153 }, + { "Insert", 0x14b }, + { "Delete", 0x14a }, + { "Home", 0x106 }, + { "End", 0x168 }, + { "F1", 0x109 }, + { "F2", 0x10a }, + { "F3", 0x10b }, + { "F4", 0x10c }, + { "F5", 0x10d }, + { "F6", 0x10e }, + { "F7", 0x10f }, + { "F8", 0x110 }, + { "F9", 0x111 }, + { "F10", 0x112 }, + { "F11", 0x113 }, + { "F12", 0x114 }, + { "F13", 0x115 }, + { "F14", 0x116 }, + { "F15", 0x117 }, + { "F16", 0x118 }, + { "F17", 0x119 }, + { "F18", 0x11a }, + { "F19", 0x11b }, + { "F20", 0x11c }, + { "Escape", 27 }, + + { 0, 0 }, +}; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/.cvsignore /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/.cvsignore --- qemu-0.9.1/.cvsignore 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/.cvsignore 1970-01-01 01:00:00.000000000 +0100 @@ -1,27 +0,0 @@ -config-host.* -dyngen -i386 -*-softmmu -*-darwin-user -*-linux-user -qemu-doc.html -qemu-tech.html -qemu-doc.info -qemu-tech.info -qemu.1 -qemu.pod -qemu-img.1 -qemu-img.pod -qemu-img -.gdbinit -*.aux -*.cp -*.dvi -*.fn -*.ky -*.log -*.pg -*.toc -*.tp -*.vr -*.d diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/d3des.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/d3des.c --- qemu-0.9.1/d3des.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/d3des.c 2008-10-27 19:49:12.000000000 +0000 @@ -35,10 +35,10 @@ static unsigned long KnL[32] = { 0L }; -static unsigned short bytebit[8] = { +static const unsigned short bytebit[8] = { 01, 02, 04, 010, 020, 040, 0100, 0200 }; -static unsigned long bigbyte[24] = { +static const unsigned long bigbyte[24] = { 0x800000L, 0x400000L, 0x200000L, 0x100000L, 0x80000L, 0x40000L, 0x20000L, 0x10000L, 0x8000L, 0x4000L, 0x2000L, 0x1000L, @@ -48,24 +48,23 @@ /* Use the key schedule specified in the Standard (ANSI X3.92-1981). */ -static unsigned char pc1[56] = { +static const unsigned char pc1[56] = { 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 }; -static unsigned char totrot[16] = { +static const unsigned char totrot[16] = { 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 }; -static unsigned char pc2[48] = { +static const unsigned char pc2[48] = { 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 }; -void deskey(key, edf) /* Thanks to James Gillogly & Phil Karn! */ -unsigned char *key; -int edf; +/* Thanks to James Gillogly & Phil Karn! */ +void deskey(unsigned char *key, int edf) { register int i, j, l, m, n; unsigned char pc1m[56], pcr[56]; @@ -100,8 +99,7 @@ return; } -static void cookey(raw1) -register unsigned long *raw1; +static void cookey(register unsigned long *raw1) { register unsigned long *cook, *raw0; unsigned long dough[32]; @@ -123,8 +121,7 @@ return; } -void cpkey(into) -register unsigned long *into; +void cpkey(register unsigned long *into) { register unsigned long *from, *endp; @@ -133,8 +130,7 @@ return; } -void usekey(from) -register unsigned long *from; +void usekey(register unsigned long *from) { register unsigned long *to, *endp; @@ -143,8 +139,7 @@ return; } -void des(inblock, outblock) -unsigned char *inblock, *outblock; +void des(unsigned char *inblock, unsigned char *outblock) { unsigned long work[2]; @@ -154,9 +149,7 @@ return; } -static void scrunch(outof, into) -register unsigned char *outof; -register unsigned long *into; +static void scrunch(register unsigned char *outof, register unsigned long *into) { *into = (*outof++ & 0xffL) << 24; *into |= (*outof++ & 0xffL) << 16; @@ -169,9 +162,7 @@ return; } -static void unscrun(outof, into) -register unsigned long *outof; -register unsigned char *into; +static void unscrun(register unsigned long *outof, register unsigned char *into) { *into++ = (unsigned char)((*outof >> 24) & 0xffL); *into++ = (unsigned char)((*outof >> 16) & 0xffL); @@ -184,7 +175,7 @@ return; } -static unsigned long SP1[64] = { +static const unsigned long SP1[64] = { 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L, 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L, 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L, @@ -202,7 +193,7 @@ 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L, 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L }; -static unsigned long SP2[64] = { +static const unsigned long SP2[64] = { 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L, 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L, 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L, @@ -220,7 +211,7 @@ 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L, 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L }; -static unsigned long SP3[64] = { +static const unsigned long SP3[64] = { 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L, 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L, 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L, @@ -238,7 +229,7 @@ 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L, 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L }; -static unsigned long SP4[64] = { +static const unsigned long SP4[64] = { 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L, 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L, @@ -256,7 +247,7 @@ 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L, 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L }; -static unsigned long SP5[64] = { +static const unsigned long SP5[64] = { 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L, 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L, 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L, @@ -274,7 +265,7 @@ 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L, 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L }; -static unsigned long SP6[64] = { +static const unsigned long SP6[64] = { 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L, 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L, 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L, @@ -292,7 +283,7 @@ 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L, 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L }; -static unsigned long SP7[64] = { +static const unsigned long SP7[64] = { 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L, 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L, 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L, @@ -310,7 +301,7 @@ 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L, 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L }; -static unsigned long SP8[64] = { +static const unsigned long SP8[64] = { 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L, 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L, 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L, @@ -328,8 +319,7 @@ 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L, 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L }; -static void desfunc(block, keys) -register unsigned long *block, *keys; +static void desfunc(register unsigned long *block, register unsigned long *keys) { register unsigned long fval, work, right, leftt; register int round; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/darwin-user/main.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/darwin-user/main.c --- qemu-0.9.1/darwin-user/main.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/darwin-user/main.c 2008-05-28 13:30:31.000000000 +0100 @@ -873,6 +873,7 @@ #endif } + cpu_exec_init_all(0); /* NOTE: we need to init the CPU at this stage to get qemu_host_page_size */ env = cpu_init(cpu_model); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/darwin-user/qemu.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/darwin-user/qemu.h --- qemu-0.9.1/darwin-user/qemu.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/darwin-user/qemu.h 2008-10-04 08:20:07.000000000 +0100 @@ -109,11 +109,10 @@ void init_paths(const char *prefix); const char *path(const char *pathname); -extern int loglevel; -extern FILE *logfile; +#include "qemu-log.h" /* commpage.c */ -void commpage_init(); +void commpage_init(void); void do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/darwin-user/signal.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/darwin-user/signal.c --- qemu-0.9.1/darwin-user/signal.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/darwin-user/signal.c 2008-10-05 12:09:37.000000000 +0100 @@ -54,7 +54,7 @@ first signal, we put it here */ }; -struct sigaltstack target_sigaltstack_used = { +static struct sigaltstack target_sigaltstack_used = { 0, 0, SA_DISABLE }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/darwin-user/syscall.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/darwin-user/syscall.c --- qemu-0.9.1/darwin-user/syscall.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/darwin-user/syscall.c 2008-10-05 11:52:52.000000000 +0100 @@ -417,7 +417,7 @@ uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8) { - extern uint32_t mach_reply_port(); + extern uint32_t mach_reply_port(void); long ret = 0; @@ -551,7 +551,7 @@ uint32_t arg8) { extern uint32_t cthread_set_self(uint32_t); - extern uint32_t processor_facilities_used(); + extern uint32_t processor_facilities_used(void); long ret = 0; arg1 = tswap32(arg1); @@ -654,7 +654,7 @@ #define MAX_STRUCT_SIZE 4096 -IOCTLEntry ioctl_entries[] = { +static IOCTLEntry ioctl_entries[] = { #define IOCTL(cmd, access, types...) \ { cmd, cmd, #cmd, access, { types } }, #include "ioctls.h" @@ -830,7 +830,7 @@ } long do_unix_syscall_indirect(void *cpu_env, int num); -long do_sync(); +long do_sync(void); long do_exit(uint32_t arg1); long do_getlogin(char *out, uint32_t size); long do_open(char * arg1, uint32_t arg2, uint32_t arg3); @@ -996,7 +996,7 @@ return -1; } -long do_sync() +long do_sync(void) { sync(); return 0; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/changelog /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/changelog --- qemu-0.9.1/debian/changelog 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/changelog 2008-11-23 23:12:07.000000000 +0000 @@ -1,36 +1,165 @@ -qemu (0.9.1-7ubuntu1) jaunty; urgency=low +qemu (0.9.1+svn20081112-1ubuntu1) jaunty; urgency=low * Merge from debian unstable, remaining changes: - debian/control: add lpia to the Architectures list; move proll, openhackware, and openbios-sparc from Depends to Recommends - - debian/patches/91_vmdk_compat6_scsi: add support for multiple - compatiblity levels and scsi disks to vmdk images + - debian/patches/91_vmdk_compat6_scsi: add support for scsi disks to + vmdk images - debian/patches/95_evdev_keycode_map.patch: ported the gtk-vnc patch that fixes evdev keycode mapping - - debian/patches/96_dirent.patch: fix FTBFS error, including the wrong - dirent.h, matches qemu SVN - -- Dustin Kirkland Thu, 20 Nov 2008 18:10:36 -0600 + -- Soren Hansen Sun, 23 Nov 2008 21:55:46 +0100 + +qemu (0.9.1+svn20081112-1) experimental; urgency=low + + [ Aurelien Jarno ] + * New upstream snapshot. + - does not need a disk image anymore (Closes: bug#260935). + - 53_openbios_size.patch: drop (merged upstream). + - 90_security: update. + * debian/control: depend on openbios-sparc (>= 1.0~alpha2+20081109) + (Closes: bug#502411, bug#502414). + + -- Aurelien Jarno Sun, 09 Nov 2008 14:42:37 +0100 + +qemu (0.9.1+svn20081101-1) experimental; urgency=low + + [ Aurelien Jarno ] + * New upstream snapshot. + - fix a heap overflow in Cirrus emulation (CVE-2008-4539). + - 50_linuxbios_isa_bios_ram.patch: update. + - 90_security.patch: update. + + -- Aurelien Jarno Sat, 01 Nov 2008 09:26:45 +0100 + +qemu (0.9.1+svn20081023-1) experimental; urgency=low + + [ Aurelien Jarno ] + * New upstream snapshot. + - 12_signal_powerpc_support.patch: update. + - 50_linuxbios_isa_bios_ram.patch: update. + + -- Aurelien Jarno Thu, 23 Oct 2008 21:34:26 +0200 -qemu (0.9.1-7) unstable; urgency=low +qemu (0.9.1+svn20081016-1) experimental; urgency=low + [ Aurelien Jarno ] + * New upstream snapshot. + * patches/31_syscalls.patch: remove parts merged upstream. * debian/qemu-make-debian-root: - Fix bug introduced when fixing bug#496394 (Closes: bug#502325). - -- Aurelien Jarno Thu, 16 Oct 2008 22:18:39 +0200 + -- Aurelien Jarno Mon, 13 Oct 2008 23:11:15 +0200 -qemu (0.9.1-6) unstable; urgency=high +qemu (0.9.1+svn20081012-1) experimental; urgency=low + + [ Riku Voipio ] + * Add a bunch of patches from scratchbox + - 44_socklen_t_check work better with badbehavin net apps + - 48_signal_terminate make qemu binary terminate on signals as expected + - 49_null_checks don't bother some syscalls when null/zero is passed [ Aurelien Jarno ] - * debian/control: - - Update list of supported targets (Closes: bug#488339). + * New upstream snapshot. + - alpha is now a TCG target. + - comma has been added to sendkey (closes: bug#414342). + * patches/31_syscalls.patch: remove parts merged upstream. + * patches/39_syscall_fadvise64.patch: remove (merged upstream). + * patches/90_security.patch: remove parts merged upstream. + * debian/control: build-depends on libbluetooth-dev. + + -- Aurelien Jarno Sun, 12 Oct 2008 18:46:54 +0200 + +qemu (0.9.1+svn20080905-1) experimental; urgency=low + + * New upstream snapshot. + - SH4 is now a TCG target. + * debian/watch: update URL location. + + -- Aurelien Jarno Tue, 02 Sep 2008 01:43:24 +0200 + +qemu (0.9.1+svn20080826-1) experimental; urgency=low + + * New upstream snapshot. * debian/qemu-make-debian-root: - Use mktemp instead of $$ to create temporary directories (Closes: bug#496394). + * Ship a libqemu-dev package (Closes: bug#451618). + + -- Aurelien Jarno Tue, 26 Aug 2008 09:55:36 +0200 + +qemu (0.9.1+svn20080822-1) experimental; urgency=low + + * New upstream snapshot. + - Focus to monitor to ask password (Closes: bug#473240). + - TCG SPARC host support (Closes: bug#450817). + - Check KQEMU availability before allocating memory (Closes: bug#414566). + - Fix dead keys (Closes: bug#489594). + - Fix ES1370 emulation (Closes: bug#494462). + - New USB UHCI implemnation (Closes: bug#457651). + - Add debian/patches/00_bios.patch. + - Remove debian/patches/02_snapshot_use_tmpdir.patch (merged). + - Remove debian/patches/04_do_not_print_rtc_freq_if_ok.patch (merged). + - Remove patches/05_non-fatal_if_linux_hd_missing.patch (merged). + - Update debian/patches/07_i386_exec_name.patch + - Update debian/patches/12_signal_powerpc_support.patch + - Remove debian/patches/33_syscall_ppc_clone.patch (merged differently). + - Remove debian/patches/41_arm_fpa_sigfpe.patch (merged). + - Remove debian/patches/42_arm_tls.patch (merged differently). + - Update debian/patches/55_unmux_socketcall.patch. + - Remove debian/patches/63_sparc_build.patch (useless). + - Update debian/patches/65_kfreebsd.patch. + - Update debian/patches/66_tls_ld.patch. + - Remove debian/patches/70_manpage.patch (merged). + - Remove debian/patches/71_doc.patch (merged). + - Remove debian/patches/80_ui_curses.patch (merged). + - Remove debian/patches/81_mips32r2_fpu.patch (merged). + - Remove debian/patches/82_mips_abs.patch (merged). + - Remove debian/patches/83_usb-serial.patch (merged). + - Remove debian/patches/84_rtl8139.patch (merged). + - Remove debian/patches/85_vvfat.patch (merged). + - Remove debian/patches/86_df.patch (merged). + - Remove debian/patches/87_eoi.patch (merged). + - Remove debian/patches/88_dma.patch (merged). + - Remove debian/patches/89_braille.patch (merged). + - Remove debian/patches/92_no_shutdown.patch (merged). + - Remove debian/patches/93_tmpfs.patch (merged). + - Remove debian/patches/94_security.patch (merged). + * debian/README.source: new file. + * debian/patches/*: convert to patchlevel 1 (Closes: bug#484963). + * debian/control: + - Add build-depends on libesd0-dev. + - Add build-depends on libpulse-dev. + - Add build-depends on libvdeplug2-dev. + - Add build-depends on etherboot. + - Update list of supported targets (Closes: bug#488339). + - Suggests kqemu-source. + - Bump Standards-Version to 3.8.0. * debian/links: - - Add missing links to manpages. + - Add missing manpage symlinks. + * debian/rules: + - Enable audio drivers depending on the system. + - Enable DYNGEN targets depending on the system. + - Install PXE bios from etherboot (Closes: bug#412010). + - Don't ignore make clean errors. + - Don't build DYNGEN targets on kfreebsd-amd64 (Closes: bug#494353). + * debian/patches/22_net_tuntap_stall.patch: remove (outdated). + + -- Aurelien Jarno Fri, 22 Aug 2008 01:00:54 +0200 - -- Aurelien Jarno Mon, 25 Aug 2008 04:38:35 +0200 +qemu (0.9.1-7ubuntu1) jaunty; urgency=low + + * Merge from debian unstable, remaining changes: + - debian/control: add lpia to the Architectures list; + move proll, openhackware, and openbios-sparc from Depends to Recommends + - debian/patches/91_vmdk_compat6_scsi: add support for multiple + compatiblity levels and scsi disks to vmdk images + - debian/patches/95_evdev_keycode_map.patch: ported the + gtk-vnc patch that fixes evdev keycode mapping + - debian/patches/96_dirent.patch: fix FTBFS error, including the wrong + dirent.h, matches qemu SVN + + -- Dustin Kirkland Thu, 20 Nov 2008 18:10:36 -0600 qemu (0.9.1-5ubuntu3) intrepid; urgency=low diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/control /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/control --- qemu-0.9.1/debian/control 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/control 2008-11-23 23:12:07.000000000 +0000 @@ -6,20 +6,24 @@ Uploaders: Aurelien Jarno , Riku Voipio , Josh Triplett Build-Depends: debhelper (>= 5), quilt (>= 0.40), binutils (>= 2.16), nasm, - gcc-3.4, libx11-dev, libsdl1.2-dev (>> 1.2.1), libncurses5-dev, zlib1g-dev, - texi2html, sharutils, libgnutls-dev, libfreebsd-dev [kfreebsd-i386 kfreebsd-amd64], - libasound2-dev [!kfreebsd-i386 !kfreebsd-amd64 !hurd-i386], - libgpmg1-dev [amd64 i386 powerpc alpha sparc arm armeb armel s390], libbrlapi-dev -Standards-Version: 3.7.3 + libx11-dev, libsdl1.2-dev (>> 1.2.1), libncurses5-dev, zlib1g-dev, + texi2html, sharutils, libgnutls-dev, libesd0-dev, libbrlapi-dev, etherboot, + libpulse-dev, gcc-3.4 [amd64 i386 powerpc kfreebsd-i386], + libvdeplug2-dev [!kfreebsd-i386 !kfreebsd-amd64], + libfreebsd-dev [kfreebsd-i386 kfreebsd-amd64], + libasound2-dev [!kfreebsd-i386 !kfreebsd-amd64], + libbluetooth-dev [!kfreebsd-i386 !kfreebsd-amd64], + libgpmg1-dev [amd64 arm armel hppa i386 powerpc sparc ppc64] +Standards-Version: 3.8.0 Homepage: http://www.qemu.org/ XS-Debian-Vcs-Browser: http://svn.debian.org/wsvn/pkg-qemu/ XS-Debian-Vcs-Svn: svn://svn.debian.org/pkg-qemu/trunk/ Package: qemu -Architecture: amd64 i386 powerpc alpha sparc arm armeb armel s390 kfreebsd-i386 kfreebsd-amd64 lpia -Depends: ${shlibs:Depends}, vgabios (>= 0.5a-1), bochsbios-qemu (>= 2.3.5-1ubuntu1) | bochsbios (>= 2.3.6-2ubuntu1) -Recommends: debootstrap, sharutils, vde2, proll, openhackware, openbios-sparc -Suggests: sudo, samba +Architecture: amd64 arm armel hppa i386 powerpc sparc kfreebsd-i386 kfreebsd-amd64 ppc64 lpia +Depends: ${shlibs:Depends}, vgabios (>= 0.5a-1), bochsbios-qemu (>= 2.3.5-1ubuntu1) | bochsbios (>= 2.3.6-2ubuntu1), +Recommends: debootstrap, sharutils, vde2, proll, openhackware, openbios-sparc (>= 1.0~alpha2+20081109) +Suggests: sudo, samba, kqemu-source Description: fast processor emulator QEMU is a fast processor emulator: currently the package supports ARM, CRIS, i386, M68k (ColdFire), MIPS, PowerPC, SH4, SPARc and x86-64 @@ -36,3 +40,15 @@ As QEMU requires no host kernel patches to run, it is very safe and easy to use. +Package: libqemu-dev +Architecture: amd64 arm armel hppa i386 powerpc sparc kfreebsd-i386 kfreebsd-amd64 ppc64 +Section: libdevel +Depends: ${shlibs:Depends} +Description: static libraries and headers for QEMU + QEMU is a fast processor emulator: currently the package supports + ARM, CRIS, i386, M68k (ColdFire), MIPS, PowerPC, SH4, SPARc and x86-64 + emulation. By using dynamic translation it achieves reasonable speed + while being easy to port on new host CPUs. + . + This package provides header files and static libraries suitable to + emulate the various CPU supported by QEMU directly in an application. diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/docs /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/docs --- qemu-0.9.1/debian/docs 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/docs 1970-01-01 01:00:00.000000000 +0100 @@ -1,4 +0,0 @@ -README -TODO -qemu-doc.html -debian/tundev.c diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/install /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/install --- qemu-0.9.1/debian/install 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/install 1970-01-01 01:00:00.000000000 +0100 @@ -1,3 +0,0 @@ -debian/qemu-ifup etc/ -debian/qemu-make-debian-root usr/sbin/ -debian/overrides/qemu usr/share/lintian/overrides/ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/libqemu-dev.dirs /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/libqemu-dev.dirs --- qemu-0.9.1/debian/libqemu-dev.dirs 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/debian/libqemu-dev.dirs 2008-11-23 23:12:07.000000000 +0000 @@ -0,0 +1,47 @@ +usr/include/qemu/audio/ +usr/include/qemu/fpu/ +usr/include/qemu/hw/ + +usr/include/qemu/target-alpha/ +usr/include/qemu/target-arm/ +usr/include/qemu/target-cris/ +usr/include/qemu/target-i386/ +usr/include/qemu/target-m68k/ +usr/include/qemu/target-mips/ +usr/include/qemu/target-ppc/ +usr/include/qemu/target-sh4/ +usr/include/qemu/target-sparc/ + +usr/include/qemu/arm-softmmu/ +usr/include/qemu/cris-softmmu/ +usr/include/qemu/i386-softmmu/ +usr/include/qemu/m68k-softmmu/ +usr/include/qemu/mips-softmmu/ +usr/include/qemu/mips64-softmmu/ +usr/include/qemu/mips64el-softmmu/ +usr/include/qemu/mipsel-softmmu/ +usr/include/qemu/ppc-softmmu/ +usr/include/qemu/ppc64-softmmu/ +usr/include/qemu/ppcemb-softmmu/ +usr/include/qemu/sh4-softmmu/ +usr/include/qemu/sh4eb-softmmu/ +usr/include/qemu/sparc-softmmu/ +usr/include/qemu/sparc64-softmmu/ +usr/include/qemu/x86_64-softmmu/ + +usr/lib/qemu/arm-softmmu/ +usr/lib/qemu/cris-softmmu/ +usr/lib/qemu/i386-softmmu/ +usr/lib/qemu/m68k-softmmu/ +usr/lib/qemu/mips-softmmu/ +usr/lib/qemu/mips64-softmmu/ +usr/lib/qemu/mips64el-softmmu/ +usr/lib/qemu/mipsel-softmmu/ +usr/lib/qemu/ppc-softmmu/ +usr/lib/qemu/ppc64-softmmu/ +usr/lib/qemu/ppcemb-softmmu/ +usr/lib/qemu/sh4-softmmu/ +usr/lib/qemu/sh4eb-softmmu/ +usr/lib/qemu/sparc-softmmu/ +usr/lib/qemu/sparc64-softmmu/ +usr/lib/qemu/x86_64-softmmu/ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/libqemu-dev.install /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/libqemu-dev.install --- qemu-0.9.1/debian/libqemu-dev.install 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/debian/libqemu-dev.install 2008-11-23 23:12:07.000000000 +0000 @@ -0,0 +1,14 @@ +*.h usr/include/qemu/ +audio/*.h usr/include/qemu/audio/ +fpu/*.h usr/include/qemu/fpu/ +hw/*.h usr/include/qemu/hw/ + +target-alpha/*.h usr/include/qemu/target-alpha/ +target-arm/*.h usr/include/qemu/target-arm +target-cris/*.h usr/include/qemu/target-cris +target-i386/*.h usr/include/qemu/target-i386 +target-m68k/*.h usr/include/qemu/target-m68k +target-mips/*.h usr/include/qemu/target-mips +target-ppc/*.h usr/include/qemu/target-ppc +target-sh4/*.h usr/include/qemu/target-sh4 +target-sparc/*.h usr/include/qemu/target-sparc diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/links /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/links --- qemu-0.9.1/debian/links 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/links 1970-01-01 01:00:00.000000000 +0100 @@ -1,40 +0,0 @@ -usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-alpha.1 -usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-cris.1 -usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-arm.1 -usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-armeb.1 -usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-i386.1 -usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-m68k.1 -usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-mips.1 -usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-mipsel.1 -usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-ppc.1 -usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-ppc64.1 -usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-ppc64abi32.1 -usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-sh4.1 -usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-sh4eb.1 -usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-sparc.1 -usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-sparc32plus.1 -usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-sparc64.1 -usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-x86_64.1 -usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-arm.1 -usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-cris.1 -usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-i386.1 -usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-m68k.1 -usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-mips.1 -usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-mips64.1 -usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-mips64el.1 -usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-mipsel.1 -usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-ppc.1 -usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-ppc64.1 -usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-ppcemb.1 -usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-sh4.1 -usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-sh4eb.1 -usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-sparc.1 -usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-sparc64.1 -usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-x86_64.1 -usr/share/bochs/BIOS-qemu-latest usr/share/qemu/bios.bin -usr/share/vgabios/vgabios.bin usr/share/qemu/vgabios.bin -usr/share/vgabios/vgabios.cirrus.bin usr/share/qemu/vgabios-cirrus.bin -usr/share/proll/proll-qemu.elf usr/share/qemu/proll.elf -usr/share/openhackware/ppc_rom.bin usr/share/qemu/ppc_rom.bin -usr/share/openbios/openbios-sparc32 usr/share/qemu/openbios-sparc32 -usr/share/openbios/openbios-sparc64 usr/share/qemu/openbios-sparc64 diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/manpages /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/manpages --- qemu-0.9.1/debian/manpages 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/manpages 1970-01-01 01:00:00.000000000 +0100 @@ -1,2 +0,0 @@ -debian/qemu-make-debian-root.8 -debian/qemu-user.1 diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/00_bios.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/00_bios.patch --- qemu-0.9.1/debian/patches/00_bios.patch 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/debian/patches/00_bios.patch 2008-11-23 23:12:07.000000000 +0000 @@ -0,0 +1,15 @@ +--- a/Makefile ++++ b/Makefile +@@ -232,12 +232,6 @@ + ifneq ($(TOOLS),) + $(INSTALL) -m 755 $(TOOLS) "$(DESTDIR)$(bindir)" + endif +- mkdir -p "$(DESTDIR)$(datadir)" +- set -e; for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \ +- video.x openbios-sparc32 openbios-sparc64 pxe-ne2k_pci.bin \ +- pxe-rtl8139.bin pxe-pcnet.bin pxe-e1000.bin; do \ +- $(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \ +- done + ifndef CONFIG_WIN32 + mkdir -p "$(DESTDIR)$(datadir)/keymaps" + set -e; for x in $(KEYMAPS); do \ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/01_nostrip.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/01_nostrip.patch --- qemu-0.9.1/debian/patches/01_nostrip.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/01_nostrip.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,21 +1,21 @@ -Index: qemu-0.9.1/Makefile +Index: qemu-0.9.1+svn20081012/Makefile =================================================================== ---- qemu-0.9.1.orig/Makefile 2008-01-06 20:38:41.000000000 +0100 -+++ qemu-0.9.1/Makefile 2008-04-14 11:27:19.000000000 +0200 -@@ -174,7 +174,7 @@ +--- qemu-0.9.1+svn20081012.orig/Makefile 2008-10-12 18:54:50.000000000 +0200 ++++ qemu-0.9.1+svn20081012/Makefile 2008-10-12 18:54:50.000000000 +0200 +@@ -230,7 +230,7 @@ install: all $(if $(BUILD_DOCS),install-doc) mkdir -p "$(DESTDIR)$(bindir)" ifneq ($(TOOLS),) - $(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)" + $(INSTALL) -m 755 $(TOOLS) "$(DESTDIR)$(bindir)" endif - mkdir -p "$(DESTDIR)$(datadir)" - for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \ -Index: qemu-0.9.1/Makefile.target + ifndef CONFIG_WIN32 + mkdir -p "$(DESTDIR)$(datadir)/keymaps" +Index: qemu-0.9.1+svn20081012/Makefile.target =================================================================== ---- qemu-0.9.1.orig/Makefile.target 2008-01-06 20:38:41.000000000 +0100 -+++ qemu-0.9.1/Makefile.target 2008-04-14 11:27:38.000000000 +0200 -@@ -632,7 +632,7 @@ +--- qemu-0.9.1+svn20081012.orig/Makefile.target 2008-10-11 19:55:29.000000000 +0200 ++++ qemu-0.9.1+svn20081012/Makefile.target 2008-10-12 18:58:27.000000000 +0200 +@@ -694,7 +694,7 @@ install: all ifneq ($(PROGS),) @@ -23,4 +23,4 @@ + $(INSTALL) -m 755 $(PROGS) "$(DESTDIR)$(bindir)" endif - ifneq ($(wildcard .depend),) + # Include automatically generated dependency files diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/02_snapshot_use_tmpdir.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/02_snapshot_use_tmpdir.patch --- qemu-0.9.1/debian/patches/02_snapshot_use_tmpdir.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/02_snapshot_use_tmpdir.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,18 +0,0 @@ -Index: block.c -=================================================================== ---- block.c.orig 2008-01-06 20:38:42.000000000 +0100 -+++ block.c 2008-04-14 11:27:17.000000000 +0200 -@@ -191,8 +191,12 @@ - void get_tmp_filename(char *filename, int size) - { - int fd; -+ char *tmpdir; - /* XXX: race condition possible */ -- pstrcpy(filename, size, "/tmp/vl.XXXXXX"); -+ tmpdir = getenv("TMPDIR"); -+ if (!tmpdir) -+ tmpdir = "/tmp"; -+ snprintf(filename, size, "%s/vl.XXXXXX", tmpdir); - fd = mkstemp(filename); - close(fd); - } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/04_do_not_print_rtc_freq_if_ok.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/04_do_not_print_rtc_freq_if_ok.patch --- qemu-0.9.1/debian/patches/04_do_not_print_rtc_freq_if_ok.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/04_do_not_print_rtc_freq_if_ok.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,20 +0,0 @@ -Index: qemu-0.9.1/vl.c -=================================================================== ---- qemu-0.9.1.orig/vl.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/vl.c 2008-04-14 11:27:38.000000000 +0200 -@@ -1302,11 +1302,14 @@ - static int rtc_start_timer(struct qemu_alarm_timer *t) - { - int rtc_fd; -+ unsigned long current_rtc_freq = 0; - - TFR(rtc_fd = open("/dev/rtc", O_RDONLY)); - if (rtc_fd < 0) - return -1; -- if (ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) { -+ ioctl(rtc_fd, RTC_IRQP_READ, ¤t_rtc_freq); -+ if (current_rtc_freq != RTC_FREQ && -+ ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) { - fprintf(stderr, "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n" - "error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n" - "type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n"); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/05_non-fatal_if_linux_hd_missing.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/05_non-fatal_if_linux_hd_missing.patch --- qemu-0.9.1/debian/patches/05_non-fatal_if_linux_hd_missing.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/05_non-fatal_if_linux_hd_missing.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,13 +0,0 @@ -Index: qemu-0.9.1/hw/pc.c -=================================================================== ---- qemu-0.9.1.orig/hw/pc.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/pc.c 2008-04-14 11:27:35.000000000 +0200 -@@ -388,7 +388,7 @@ - hda = drive_get_index(IF_IDE, 0, 0); - if (hda == -1) { - fprintf(stderr, "A disk image must be given for 'hda' when booting " -- "a Linux kernel\n"); -+ "a Linux kernel\n(if you really don't want it, use /dev/zero)\n"); - exit(1); - } - diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/06_exit_segfault.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/06_exit_segfault.patch --- qemu-0.9.1/debian/patches/06_exit_segfault.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/06_exit_segfault.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,8 +1,8 @@ -Index: linux-user/main.c +Index: qemu-0.9.1+svn20081012/linux-user/main.c =================================================================== ---- linux-user/main.c.orig 2008-01-06 20:38:42.000000000 +0100 -+++ linux-user/main.c 2008-04-14 11:27:36.000000000 +0200 -@@ -714,7 +714,7 @@ +--- qemu-0.9.1+svn20081012.orig/linux-user/main.c 2008-10-08 16:26:58.000000000 +0200 ++++ qemu-0.9.1+svn20081012/linux-user/main.c 2008-10-12 18:54:50.000000000 +0200 +@@ -995,7 +995,7 @@ default: printf ("Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); @@ -11,7 +11,7 @@ } process_pending_signals (env); } -@@ -1646,7 +1646,7 @@ +@@ -1927,7 +1927,7 @@ default: printf ("Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); @@ -20,7 +20,7 @@ } process_pending_signals (env); } -@@ -1972,7 +1972,7 @@ +@@ -2263,7 +2263,7 @@ for(item = cpu_log_items; item->mask != 0; item++) { printf("%-10s %s\n", item->name, item->help); } @@ -29,7 +29,7 @@ } cpu_set_log(mask); } else if (!strcmp(r, "s")) { -@@ -1991,7 +1991,7 @@ +@@ -2282,7 +2282,7 @@ if (qemu_host_page_size == 0 || (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) { fprintf(stderr, "page size must be a power of two\n"); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/07_i386_exec_name.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/07_i386_exec_name.patch --- qemu-0.9.1/debian/patches/07_i386_exec_name.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/07_i386_exec_name.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,20 +1,21 @@ -Index: qemu-0.9.1/Makefile.target +Index: qemu-0.9.1+svn20081012/Makefile.target =================================================================== ---- qemu-0.9.1.orig/Makefile.target 2008-04-14 11:26:13.000000000 +0200 -+++ qemu-0.9.1/Makefile.target 2008-04-14 11:27:37.000000000 +0200 -@@ -74,11 +74,7 @@ - QEMU_USER=qemu-$(TARGET_ARCH2) +--- qemu-0.9.1+svn20081012.orig/Makefile.target 2008-10-12 18:54:50.000000000 +0200 ++++ qemu-0.9.1+svn20081012/Makefile.target 2008-10-12 18:58:15.000000000 +0200 +@@ -63,12 +63,8 @@ + QEMU_PROG=qemu-$(TARGET_ARCH2) + else # system emulator name - ifdef CONFIG_SOFTMMU -ifeq ($(TARGET_ARCH), i386) --QEMU_SYSTEM=qemu$(EXESUF) +-QEMU_PROG=qemu$(EXESUF) -else - QEMU_SYSTEM=qemu-system-$(TARGET_ARCH2)$(EXESUF) --endif - else - QEMU_SYSTEM=qemu-fast + QEMU_PROG=qemu-system-$(TARGET_ARCH2)$(EXESUF) endif -@@ -634,6 +630,9 @@ +-endif + + PROGS=$(QEMU_PROG) + +@@ -696,6 +692,9 @@ ifneq ($(PROGS),) $(INSTALL) -m 755 $(PROGS) "$(DESTDIR)$(bindir)" endif @@ -22,5 +23,5 @@ + ln -sf qemu-system-i386$(EXESUF) "$(DESTDIR)$(bindir)/qemu$(EXESUF)" +endif - ifneq ($(wildcard .depend),) - include .depend + # Include automatically generated dependency files + -include $(wildcard *.d */*.d) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/10_signal_jobs.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/10_signal_jobs.patch --- qemu-0.9.1/debian/patches/10_signal_jobs.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/10_signal_jobs.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,10 +1,10 @@ -Index: linux-user/signal.c +Index: qemu-0.9.1+svn20081012/linux-user/signal.c =================================================================== ---- linux-user/signal.c.orig 2008-01-06 20:38:42.000000000 +0100 -+++ linux-user/signal.c 2008-04-14 11:27:38.000000000 +0200 -@@ -364,10 +364,15 @@ - k = &sigact_table[sig - 1]; - handler = k->sa._sa_handler; +--- qemu-0.9.1+svn20081012.orig/linux-user/signal.c 2008-10-08 16:39:08.000000000 +0200 ++++ qemu-0.9.1+svn20081012/linux-user/signal.c 2008-10-12 18:58:23.000000000 +0200 +@@ -361,10 +361,15 @@ + k = &ts->sigtab[sig - 1]; + handler = sigact_table[sig - 1]._sa_handler; if (handler == TARGET_SIG_DFL) { + if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) { + kill(getpid(),SIGSTOP); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/11_signal_sigaction.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/11_signal_sigaction.patch --- qemu-0.9.1/debian/patches/11_signal_sigaction.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/11_signal_sigaction.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,8 +1,8 @@ -Index: linux-user/signal.c +Index: qemu-0.9.1+svn20081012/linux-user/signal.c =================================================================== ---- linux-user/signal.c.orig 2008-04-14 11:26:14.000000000 +0200 -+++ linux-user/signal.c 2008-04-14 11:27:38.000000000 +0200 -@@ -512,6 +512,11 @@ +--- qemu-0.9.1+svn20081012.orig/linux-user/signal.c 2008-10-12 18:54:50.000000000 +0200 ++++ qemu-0.9.1+svn20081012/linux-user/signal.c 2008-10-12 18:58:20.000000000 +0200 +@@ -509,6 +509,11 @@ if (sig < 1 || sig > TARGET_NSIG || sig == SIGKILL || sig == SIGSTOP) return -EINVAL; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/12_signal_powerpc_support.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/12_signal_powerpc_support.patch --- qemu-0.9.1/debian/patches/12_signal_powerpc_support.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/12_signal_powerpc_support.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,7 +1,7 @@ -Index: linux-user/signal.c +Index: qemu-0.9.1+svn20081012/linux-user/signal.c =================================================================== ---- linux-user/signal.c.orig 2008-04-14 11:26:14.000000000 +0200 -+++ linux-user/signal.c 2008-04-14 11:26:14.000000000 +0200 +--- qemu-0.9.1+svn20081012.orig/linux-user/signal.c 2008-10-12 18:54:50.000000000 +0200 ++++ qemu-0.9.1+svn20081012/linux-user/signal.c 2008-10-12 18:58:07.000000000 +0200 @@ -2,6 +2,7 @@ * Emulation of Linux signals * @@ -23,8 +23,8 @@ */ #include #include -@@ -2717,6 +2724,370 @@ - return 0; +@@ -3046,6 +3053,369 @@ + return -TARGET_ENOSYS; } +#elif defined(TARGET_PPC) @@ -118,7 +118,7 @@ + /* FIXME: || __put_user(orig_gpr3, &frame->mc_gregs[34]) */ + || __put_user(env->ctr, &frame->mc_gregs[35]) + || __put_user(env->lr, &frame->mc_gregs[36]) -+ || __put_user(ppc_load_xer(env), &frame->mc_gregs[37]) ++ || __put_user(env->xer, &frame->mc_gregs[37]) + || __put_user(ppc_load_cr(env), &frame->mc_gregs[38]) + || __put_user(env->spr[SPR_MQ], &frame->mc_gregs[39]) + /* FIXME: || __put_user(trap, &frame->mc_gregs[40]) */ @@ -177,8 +177,8 @@ + + if (sigret) { + /* Set up the sigreturn trampoline: li r0,sigret; sc */ -+ if (__put_user(0x38000000UL + sigret, &frame->tramp[0]) -+ || __put_user(0x44000002UL, &frame->tramp[1])) ++ if (__put_user(0x38000000 + sigret, &frame->tramp[0]) ++ || __put_user(0x44000002, &frame->tramp[1])) + return 1; +#if 0 + flush_icache_range((unsigned long) &frame->tramp[0], @@ -215,7 +215,7 @@ + /* FIXME: || __get_user(orig_gpr3, &sr->mc_gregs[34]) */ + || __get_user(env->ctr, &sr->mc_gregs[35]) + || __get_user(env->lr, &sr->mc_gregs[36]) -+ || __get_user(saved_xer, &sr->mc_gregs[37]) ++ || __get_user(env->xer, &sr->mc_gregs[37]) + || __get_user(saved_cr, &sr->mc_gregs[38]) + || __get_user(env->spr[SPR_MQ], &sr->mc_gregs[39]) + /* FIXME: || __get_user(trap, &sr->mc_gregs[40]) */ @@ -223,7 +223,6 @@ + || __get_user(env->spr[SPR_DSISR], &sr->mc_gregs[42]) + /* FIXME: || __get_user(result, &sr->mc_gregs[43]) */) + return 1; -+ ppc_store_xer(env, saved_xer); + ppc_store_cr(env, saved_cr, 0xFF); + + if (!sig) @@ -289,7 +288,7 @@ + return 0; +} + -+static void setup_frame(int sig, struct emulated_sigaction *ka, ++static void setup_frame(int sig, struct target_sigaction *ka, + target_sigset_t *oldset, CPUState *env) +{ + struct target_sigcontext *sc; @@ -314,7 +313,7 @@ +#if TARGET_NSIG != 64 +#error "Please adjust handle_signal()" +#endif -+ if (__put_user((target_ulong) ka->sa._sa_handler, &sc->handler) ++ if (__put_user((target_ulong) ka->_sa_handler, &sc->handler) + || __put_user(oldset->sig[0], &sc->oldmask) + || __put_user(oldset->sig[1], &sc->_unused[3]) + || __put_user(frame, (target_ulong *)&sc->regs) @@ -329,7 +328,7 @@ + env->gpr[1] = newsp; + env->gpr[3] = sig; + env->gpr[4] = (unsigned long) sc; -+ env->nip = (unsigned long) ka->sa._sa_handler; ++ env->nip = (unsigned long) ka->_sa_handler; + env->lr = (unsigned long) frame->mctx.tramp; + /* FIXME: env->trap = 0; */ + @@ -344,7 +343,7 @@ + force_sig(TARGET_SIGSEGV); +} + -+static void setup_rt_frame(int sig, struct emulated_sigaction *ka, ++static void setup_rt_frame(int sig, struct target_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ @@ -393,12 +392,12 @@ + #else - static void setup_frame(int sig, struct emulated_sigaction *ka, -Index: target-ppc/cpu.h + static void setup_frame(int sig, struct target_sigaction *ka, +Index: qemu-0.9.1+svn20081012/target-ppc/cpu.h =================================================================== ---- target-ppc/cpu.h.orig 2008-01-06 20:38:45.000000000 +0100 -+++ target-ppc/cpu.h 2008-04-14 11:26:14.000000000 +0200 -@@ -742,6 +742,10 @@ +--- qemu-0.9.1+svn20081012.orig/target-ppc/cpu.h 2008-09-20 10:07:15.000000000 +0200 ++++ qemu-0.9.1+svn20081012/target-ppc/cpu.h 2008-10-12 18:54:50.000000000 +0200 +@@ -728,6 +728,10 @@ target_ulong ppc_load_xer (CPUPPCState *env); void ppc_store_xer (CPUPPCState *env, target_ulong value); void ppc_store_msr (CPUPPCState *env, target_ulong value); @@ -409,11 +408,11 @@ void cpu_ppc_reset (void *opaque); -Index: target-ppc/helper.c +Index: qemu-0.9.1+svn20081012/target-ppc/helper.c =================================================================== ---- target-ppc/helper.c.orig 2008-01-06 20:38:45.000000000 +0100 -+++ target-ppc/helper.c 2008-04-14 11:26:14.000000000 +0200 -@@ -2139,6 +2139,60 @@ +--- qemu-0.9.1+svn20081012.orig/target-ppc/helper.c 2008-06-29 03:03:05.000000000 +0200 ++++ qemu-0.9.1+svn20081012/target-ppc/helper.c 2008-10-12 18:54:50.000000000 +0200 +@@ -2140,6 +2140,60 @@ hreg_store_msr(env, value, 0); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/21_net_soopts.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/21_net_soopts.patch --- qemu-0.9.1/debian/patches/21_net_soopts.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/21_net_soopts.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,8 +1,8 @@ -Index: linux-user/syscall.c +Index: qemu-0.9.1+svn20081012/linux-user/syscall.c =================================================================== ---- linux-user/syscall.c.orig 2008-01-06 20:38:42.000000000 +0100 -+++ linux-user/syscall.c 2008-04-14 11:27:37.000000000 +0200 -@@ -785,6 +785,28 @@ +--- qemu-0.9.1+svn20081012.orig/linux-user/syscall.c 2008-10-05 13:45:25.000000000 +0200 ++++ qemu-0.9.1+svn20081012/linux-user/syscall.c 2008-10-12 18:58:17.000000000 +0200 +@@ -828,6 +828,28 @@ return 0; } @@ -31,7 +31,7 @@ /* do_setsockopt() Must return target values and target errnos. */ static abi_long do_setsockopt(int sockfd, int level, int optname, abi_ulong optval_addr, socklen_t optlen) -@@ -835,7 +857,6 @@ +@@ -878,7 +900,6 @@ break; case TARGET_SOL_SOCKET: switch (optname) { @@ -39,7 +39,7 @@ case TARGET_SO_DEBUG: optname = SO_DEBUG; break; -@@ -892,17 +913,48 @@ +@@ -935,17 +956,48 @@ case TARGET_SO_SNDTIMEO: optname = SO_SNDTIMEO; break; @@ -93,7 +93,7 @@ default: unimplemented: gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname); -@@ -922,13 +974,57 @@ +@@ -966,13 +1018,57 @@ case TARGET_SOL_SOCKET: level = SOL_SOCKET; switch (optname) { @@ -154,7 +154,7 @@ default: goto int_case; } -@@ -1171,16 +1267,23 @@ +@@ -1220,16 +1316,23 @@ void *addr; abi_long ret; @@ -186,10 +186,10 @@ } return ret; } -Index: linux-user/syscall_defs.h +Index: qemu-0.9.1+svn20081012/linux-user/syscall_defs.h =================================================================== ---- linux-user/syscall_defs.h.orig 2008-01-06 20:38:42.000000000 +0100 -+++ linux-user/syscall_defs.h 2008-04-14 11:26:14.000000000 +0200 +--- qemu-0.9.1+svn20081012.orig/linux-user/syscall_defs.h 2008-09-29 19:23:09.000000000 +0200 ++++ qemu-0.9.1+svn20081012/linux-user/syscall_defs.h 2008-10-12 18:54:50.000000000 +0200 @@ -114,6 +114,11 @@ abi_long tv_nsec; }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/22_net_tuntap_stall.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/22_net_tuntap_stall.patch --- qemu-0.9.1/debian/patches/22_net_tuntap_stall.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/22_net_tuntap_stall.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,13 +0,0 @@ -Index: vl.c -=================================================================== ---- vl.c.orig 2008-04-14 11:26:13.000000000 +0200 -+++ vl.c 2008-04-14 11:27:19.000000000 +0200 -@@ -4085,7 +4085,7 @@ - return -1; - } - memset(&ifr, 0, sizeof(ifr)); -- ifr.ifr_flags = IFF_TAP | IFF_NO_PI; -+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE; - if (ifname[0] != '\0') - pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname); - else diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/30_syscall_ipc.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/30_syscall_ipc.patch --- qemu-0.9.1/debian/patches/30_syscall_ipc.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/30_syscall_ipc.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,8 +1,8 @@ -Index: linux-user/syscall.c +Index: qemu-0.9.1+svn20081012/linux-user/syscall.c =================================================================== ---- linux-user/syscall.c.orig 2008-04-14 11:26:14.000000000 +0200 -+++ linux-user/syscall.c 2008-04-14 11:27:37.000000000 +0200 -@@ -44,8 +44,10 @@ +--- qemu-0.9.1+svn20081012.orig/linux-user/syscall.c 2008-10-12 18:54:50.000000000 +0200 ++++ qemu-0.9.1+svn20081012/linux-user/syscall.c 2008-10-12 18:58:15.000000000 +0200 +@@ -46,8 +46,10 @@ #include #include #include @@ -13,7 +13,7 @@ #include #include #include -@@ -2149,7 +2151,8 @@ +@@ -2198,7 +2200,8 @@ ret = get_errno(shmctl(first, second, NULL)); break; default: diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/31_syscalls.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/31_syscalls.patch --- qemu-0.9.1/debian/patches/31_syscalls.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/31_syscalls.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,16 +1,16 @@ -Index: qemu-0.9.1/linux-user/syscall.c +Index: qemu-0.9.1+svn20081012/linux-user/syscall.c =================================================================== ---- qemu-0.9.1.orig/linux-user/syscall.c 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/linux-user/syscall.c 2008-04-14 11:27:37.000000000 +0200 -@@ -252,6 +252,7 @@ - extern int setresgid(gid_t, gid_t, gid_t); - extern int getresgid(gid_t *, gid_t *, gid_t *); +--- qemu-0.9.1+svn20081012.orig/linux-user/syscall.c 2008-10-12 18:54:50.000000000 +0200 ++++ qemu-0.9.1+svn20081012/linux-user/syscall.c 2008-10-12 18:58:14.000000000 +0200 +@@ -296,6 +296,7 @@ + extern int setfsuid(int); + extern int setfsgid(int); extern int setgroups(int, gid_t *); +extern int uselib(const char*); #define ERRNO_TABLE_SIZE 1200 -@@ -4139,7 +4140,8 @@ +@@ -4437,7 +4438,8 @@ #endif #ifdef TARGET_NR_uselib case TARGET_NR_uselib: @@ -20,36 +20,16 @@ #endif #ifdef TARGET_NR_swapon case TARGET_NR_swapon: -@@ -5406,7 +5408,8 @@ - goto unimplemented; - #ifdef TARGET_NR_mincore - case TARGET_NR_mincore: -- goto unimplemented; -+ ret = get_errno(mincore((void*)arg1, (size_t)arg2, (unsigned char*)arg3)); -+ break; - #endif - #ifdef TARGET_NR_madvise - case TARGET_NR_madvise: -@@ -5546,7 +5549,8 @@ - break; - #ifdef TARGET_NR_readahead - case TARGET_NR_readahead: -- goto unimplemented; -+ ret = get_errno(readahead((int)arg1, (off64_t)arg2, (size_t)arg3)); -+ break; - #endif - #ifdef TARGET_NR_setxattr - case TARGET_NR_setxattr: -Index: qemu-0.9.1/Makefile.target +Index: qemu-0.9.1+svn20081012/Makefile.target =================================================================== ---- qemu-0.9.1.orig/Makefile.target 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/Makefile.target 2008-04-14 11:27:19.000000000 +0200 -@@ -228,7 +228,7 @@ - ######################################################### +--- qemu-0.9.1+svn20081012.orig/Makefile.target 2008-10-12 18:54:50.000000000 +0200 ++++ qemu-0.9.1+svn20081012/Makefile.target 2008-10-12 18:54:50.000000000 +0200 +@@ -165,7 +165,7 @@ + OP_CFLAGS+=$(OS_CFLAGS) $(ARCH_CFLAGS) CPPFLAGS+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -LIBS+=-lm +LIBS+=-lm -lrt - ifndef CONFIG_USER_ONLY - LIBS+=-lz + ifdef CONFIG_WIN32 + LIBS+=-lwinmm -lws2_32 -liphlpapi endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/32_syscall_sysctl.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/32_syscall_sysctl.patch --- qemu-0.9.1/debian/patches/32_syscall_sysctl.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/32_syscall_sysctl.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,16 +1,16 @@ -Index: linux-user/syscall.c +Index: qemu-0.9.1+svn20081012/linux-user/syscall.c =================================================================== ---- linux-user/syscall.c.orig 2008-04-14 11:26:14.000000000 +0200 -+++ linux-user/syscall.c 2008-04-14 11:27:37.000000000 +0200 -@@ -54,6 +54,7 @@ +--- qemu-0.9.1+svn20081012.orig/linux-user/syscall.c 2008-10-12 18:54:50.000000000 +0200 ++++ qemu-0.9.1+svn20081012/linux-user/syscall.c 2008-10-12 18:58:12.000000000 +0200 +@@ -56,6 +56,7 @@ //#include #include #include +#include + #include #define termios host_termios - #define winsize host_winsize -@@ -4856,9 +4857,34 @@ +@@ -5158,9 +5159,34 @@ break; #endif case TARGET_NR__sysctl: diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/33_syscall_ppc_clone.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/33_syscall_ppc_clone.patch --- qemu-0.9.1/debian/patches/33_syscall_ppc_clone.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/33_syscall_ppc_clone.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,17 +0,0 @@ -Index: linux-user/syscall.c -=================================================================== ---- linux-user/syscall.c.orig 2008-04-14 11:26:14.000000000 +0200 -+++ linux-user/syscall.c 2008-04-14 11:27:37.000000000 +0200 -@@ -2861,11 +2861,7 @@ - if (!newsp) - newsp = env->gpr[1]; - new_env->gpr[1] = newsp; -- { -- int i; -- for (i = 7; i < 32; i++) -- new_env->gpr[i] = 0; -- } -+ new_env->gpr[3] = 0; - #elif defined(TARGET_SH4) - if (!newsp) - newsp = env->gregs[15]; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/35_syscall_sockaddr.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/35_syscall_sockaddr.patch --- qemu-0.9.1/debian/patches/35_syscall_sockaddr.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/35_syscall_sockaddr.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,16 +1,16 @@ -Index: qemu-0.9.1/linux-user/syscall.c +Index: qemu-0.9.1+svn20081012/linux-user/syscall.c =================================================================== ---- qemu-0.9.1.orig/linux-user/syscall.c 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/linux-user/syscall.c 2008-04-14 11:27:36.000000000 +0200 -@@ -54,6 +54,7 @@ +--- qemu-0.9.1+svn20081012.orig/linux-user/syscall.c 2008-10-12 18:57:43.000000000 +0200 ++++ qemu-0.9.1+svn20081012/linux-user/syscall.c 2008-10-12 18:58:10.000000000 +0200 +@@ -56,6 +56,7 @@ //#include #include #include +#include #include + #include - #define termios host_termios -@@ -646,14 +647,17 @@ +@@ -689,14 +690,17 @@ static inline abi_long target_to_host_sockaddr(struct sockaddr *addr, abi_ulong target_addr, @@ -31,7 +31,7 @@ addr->sa_family = tswap16(target_saddr->sa_family); unlock_user(target_saddr, target_addr, 0); -@@ -1198,7 +1202,7 @@ +@@ -1247,7 +1251,7 @@ { void *addr = alloca(addrlen); @@ -40,7 +40,7 @@ return get_errno(bind(sockfd, addr, addrlen)); } -@@ -1208,7 +1212,7 @@ +@@ -1257,7 +1261,7 @@ { void *addr = alloca(addrlen); @@ -49,7 +49,7 @@ return get_errno(connect(sockfd, addr, addrlen)); } -@@ -1233,7 +1237,7 @@ +@@ -1282,7 +1286,7 @@ msg.msg_namelen = tswap32(msgp->msg_namelen); msg.msg_name = alloca(msg.msg_namelen); target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name), @@ -58,7 +58,7 @@ } else { msg.msg_name = NULL; msg.msg_namelen = 0; -@@ -1365,7 +1369,7 @@ +@@ -1414,7 +1418,7 @@ return -TARGET_EFAULT; if (target_addr) { addr = alloca(addrlen); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/39_syscall_fadvise64.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/39_syscall_fadvise64.patch --- qemu-0.9.1/debian/patches/39_syscall_fadvise64.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/39_syscall_fadvise64.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,29 +0,0 @@ -Index: linux-user/arm/syscall_nr.h -=================================================================== ---- linux-user/arm/syscall_nr.h.orig 2008-01-06 20:38:43.000000000 +0100 -+++ linux-user/arm/syscall_nr.h 2008-04-14 11:27:21.000000000 +0200 -@@ -273,6 +273,7 @@ - #define TARGET_NR_fstatfs64 267 - #define TARGET_NR_tgkill 268 - #define TARGET_NR_utimes 269 -+#define TARGET_NR_fadvise64_64 270 - #define TARGET_NR_arm_fadvise64_64 270 - #define TARGET_NR_pciconfig_iobase 271 - #define TARGET_NR_pciconfig_read 272 -Index: linux-user/syscall.c -=================================================================== ---- linux-user/syscall.c.orig 2008-04-14 11:26:14.000000000 +0200 -+++ linux-user/syscall.c 2008-04-14 11:27:36.000000000 +0200 -@@ -5437,6 +5437,12 @@ - ret = get_errno(mincore((void*)arg1, (size_t)arg2, (unsigned char*)arg3)); - break; - #endif -+#ifdef TARGET_NR_fadvise64_64 -+ case TARGET_NR_fadvise64_64: -+ /* Just return success */ -+ ret = get_errno(0); -+ break; -+#endif - #ifdef TARGET_NR_madvise - case TARGET_NR_madvise: - /* A straight passthrough may not be safe because qemu sometimes diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/41_arm_fpa_sigfpe.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/41_arm_fpa_sigfpe.patch --- qemu-0.9.1/debian/patches/41_arm_fpa_sigfpe.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/41_arm_fpa_sigfpe.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,100 +0,0 @@ -Index: linux-user/main.c -=================================================================== ---- linux-user/main.c.orig 2008-04-14 11:26:14.000000000 +0200 -+++ linux-user/main.c 2008-04-14 11:27:36.000000000 +0200 -@@ -377,19 +377,68 @@ - { - TaskState *ts = env->opaque; - uint32_t opcode; -+ int rc; - - /* we handle the FPU emulation here, as Linux */ - /* we get the opcode */ - /* FIXME - what to do if get_user() fails? */ - get_user_u32(opcode, env->regs[15]); - -- if (EmulateAll(opcode, &ts->fpa, env) == 0) { -+ rc = EmulateAll(opcode, &ts->fpa, env); -+ if (rc == 0) { /* illegal instruction */ - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = TARGET_ILL_ILLOPN; - info._sifields._sigfault._addr = env->regs[15]; - queue_signal(info.si_signo, &info); -- } else { -+ } else if (rc < 0) { /* FP exception */ -+ int arm_fpe=0; -+ -+ /* translate softfloat flags to FPSR flags */ -+ if (-rc & float_flag_invalid) -+ arm_fpe |= BIT_IOC; -+ if (-rc & float_flag_divbyzero) -+ arm_fpe |= BIT_DZC; -+ if (-rc & float_flag_overflow) -+ arm_fpe |= BIT_OFC; -+ if (-rc & float_flag_underflow) -+ arm_fpe |= BIT_UFC; -+ if (-rc & float_flag_inexact) -+ arm_fpe |= BIT_IXC; -+ -+ FPSR fpsr = ts->fpa.fpsr; -+ //printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe); -+ -+ if (fpsr & (arm_fpe << 16)) { /* exception enabled? */ -+ info.si_signo = SIGFPE; -+ info.si_errno = 0; -+ -+ /* ordered by priority, least first */ -+ if (arm_fpe & BIT_IXC) info.si_code = TARGET_FPE_FLTRES; -+ if (arm_fpe & BIT_UFC) info.si_code = TARGET_FPE_FLTUND; -+ if (arm_fpe & BIT_OFC) info.si_code = TARGET_FPE_FLTOVF; -+ if (arm_fpe & BIT_DZC) info.si_code = TARGET_FPE_FLTDIV; -+ if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV; -+ -+ info._sifields._sigfault._addr = env->regs[15]; -+ queue_signal(info.si_signo, &info); -+ } else { -+ env->regs[15] += 4; -+ } -+ -+ /* accumulate unenabled exceptions */ -+ if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC)) -+ fpsr |= BIT_IXC; -+ if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC)) -+ fpsr |= BIT_UFC; -+ if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC)) -+ fpsr |= BIT_OFC; -+ if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC)) -+ fpsr |= BIT_DZC; -+ if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC)) -+ fpsr |= BIT_IOC; -+ ts->fpa.fpsr=fpsr; -+ } else { /* everything OK */ - /* increment PC */ - env->regs[15] += 4; - } -Index: target-arm/nwfpe/fpa11.c -=================================================================== ---- target-arm/nwfpe/fpa11.c.orig 2008-01-06 20:38:44.000000000 +0100 -+++ target-arm/nwfpe/fpa11.c 2008-04-14 11:26:14.000000000 +0200 -@@ -162,6 +162,8 @@ - fpa11->initflag = 1; - } - -+ set_float_exception_flags(0, &fpa11->fp_status); -+ - if (TEST_OPCODE(opcode,MASK_CPRT)) - { - //fprintf(stderr,"emulating CPRT\n"); -@@ -191,6 +193,11 @@ - } - - // restore_flags(flags); -+ if(nRc == 1 && get_float_exception_flags(&fpa11->fp_status)) -+ { -+ //printf("fef 0x%x\n",float_exception_flags); -+ nRc=-get_float_exception_flags(&fpa11->fp_status); -+ } - - //printf("returning %d\n",nRc); - return(nRc); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/42_arm_tls.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/42_arm_tls.patch --- qemu-0.9.1/debian/patches/42_arm_tls.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/42_arm_tls.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,831 +0,0 @@ -Index: qemu-0.9.1/configure -=================================================================== ---- qemu-0.9.1.orig/configure 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/configure 2008-04-14 11:27:20.000000000 +0200 -@@ -105,6 +105,7 @@ - darwin_user="no" - build_docs="no" - uname_release="" -+nptl="yes" - - # OS specific - targetos=`uname -s` -@@ -318,6 +319,8 @@ - ;; - *) echo "ERROR: unknown option $opt"; show_help="yes" - ;; -+ --disable-nptl) nptl="no" -+ ;; - esac - done - -@@ -413,6 +416,7 @@ - echo " --disable-linux-user disable all linux usermode emulation targets" - echo " --enable-darwin-user enable all darwin usermode emulation targets" - echo " --disable-darwin-user disable all darwin usermode emulation targets" -+echo " --disable-nptl disable usermode NPTL guest support" - echo " --fmod-lib path to FMOD library" - echo " --fmod-inc path to FMOD includes" - echo " --enable-uname-release=R Return R for uname -r in usermode emulation" -@@ -579,6 +583,23 @@ - } - EOF - -+# check NPTL support -+cat > $TMPC < -+void foo() -+{ -+#ifndef CLONE_SETTLS -+#error bork -+#endif -+} -+EOF -+ -+if $cc -c -o $TMPO $TMPC 2> /dev/null ; then -+ : -+else -+ nptl="no" -+fi -+ - ########################################## - # SDL probe - -@@ -743,6 +764,7 @@ - echo "Documentation $build_docs" - [ ! -z "$uname_release" ] && \ - echo "uname -r $uname_release" -+echo "NPTL support $nptl" - - if test $sdl_too_old = "yes"; then - echo "-> Your SDL version is too old - please upgrade to have SDL support" -@@ -947,6 +969,14 @@ - else - echo "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak - fi -+else -+ if test "$nptl" = "yes" ; then -+ case "$target_cpu" in -+ arm | armeb) -+ echo "#define USE_NPTL 1" >> $config_h -+ ;; -+ esac -+ fi - fi - if test "$cocoa" = "yes" ; then - echo "#define CONFIG_COCOA 1" >> $config_h -Index: qemu-0.9.1/exec-all.h -=================================================================== ---- qemu-0.9.1.orig/exec-all.h 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/exec-all.h 2008-04-14 11:26:14.000000000 +0200 -@@ -340,170 +340,7 @@ - extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; - extern void *io_mem_opaque[IO_MEM_NB_ENTRIES]; - --#if defined(__powerpc__) --static inline int testandset (int *p) --{ -- int ret; -- __asm__ __volatile__ ( -- "0: lwarx %0,0,%1\n" -- " xor. %0,%3,%0\n" -- " bne 1f\n" -- " stwcx. %2,0,%1\n" -- " bne- 0b\n" -- "1: " -- : "=&r" (ret) -- : "r" (p), "r" (1), "r" (0) -- : "cr0", "memory"); -- return ret; --} --#elif defined(__i386__) --static inline int testandset (int *p) --{ -- long int readval = 0; -- -- __asm__ __volatile__ ("lock; cmpxchgl %2, %0" -- : "+m" (*p), "+a" (readval) -- : "r" (1) -- : "cc"); -- return readval; --} --#elif defined(__x86_64__) --static inline int testandset (int *p) --{ -- long int readval = 0; -- -- __asm__ __volatile__ ("lock; cmpxchgl %2, %0" -- : "+m" (*p), "+a" (readval) -- : "r" (1) -- : "cc"); -- return readval; --} --#elif defined(__s390__) --static inline int testandset (int *p) --{ -- int ret; -- -- __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n" -- " jl 0b" -- : "=&d" (ret) -- : "r" (1), "a" (p), "0" (*p) -- : "cc", "memory" ); -- return ret; --} --#elif defined(__alpha__) --static inline int testandset (int *p) --{ -- int ret; -- unsigned long one; -- -- __asm__ __volatile__ ("0: mov 1,%2\n" -- " ldl_l %0,%1\n" -- " stl_c %2,%1\n" -- " beq %2,1f\n" -- ".subsection 2\n" -- "1: br 0b\n" -- ".previous" -- : "=r" (ret), "=m" (*p), "=r" (one) -- : "m" (*p)); -- return ret; --} --#elif defined(__sparc__) --static inline int testandset (int *p) --{ -- int ret; -- -- __asm__ __volatile__("ldstub [%1], %0" -- : "=r" (ret) -- : "r" (p) -- : "memory"); -- -- return (ret ? 1 : 0); --} --#elif defined(__arm__) --static inline int testandset (int *spinlock) --{ -- register unsigned int ret; -- __asm__ __volatile__("swp %0, %1, [%2]" -- : "=r"(ret) -- : "0"(1), "r"(spinlock)); -- -- return ret; --} --#elif defined(__mc68000) --static inline int testandset (int *p) --{ -- char ret; -- __asm__ __volatile__("tas %1; sne %0" -- : "=r" (ret) -- : "m" (p) -- : "cc","memory"); -- return ret; --} --#elif defined(__ia64) -- --#include -- --static inline int testandset (int *p) --{ -- return __sync_lock_test_and_set (p, 1); --} --#elif defined(__mips__) --static inline int testandset (int *p) --{ -- int ret; -- -- __asm__ __volatile__ ( -- " .set push \n" -- " .set noat \n" -- " .set mips2 \n" -- "1: li $1, 1 \n" -- " ll %0, %1 \n" -- " sc $1, %1 \n" -- " beqz $1, 1b \n" -- " .set pop " -- : "=r" (ret), "+R" (*p) -- : -- : "memory"); -- -- return ret; --} --#else --#error unimplemented CPU support --#endif -- --typedef int spinlock_t; -- --#define SPIN_LOCK_UNLOCKED 0 -- --#if defined(CONFIG_USER_ONLY) --static inline void spin_lock(spinlock_t *lock) --{ -- while (testandset(lock)); --} -- --static inline void spin_unlock(spinlock_t *lock) --{ -- *lock = 0; --} -- --static inline int spin_trylock(spinlock_t *lock) --{ -- return !testandset(lock); --} --#else --static inline void spin_lock(spinlock_t *lock) --{ --} -- --static inline void spin_unlock(spinlock_t *lock) --{ --} -- --static inline int spin_trylock(spinlock_t *lock) --{ -- return 1; --} --#endif -+#include "spinlock.h" - - extern spinlock_t tb_lock; - -Index: qemu-0.9.1/linux-user/arm/syscall.h -=================================================================== ---- qemu-0.9.1.orig/linux-user/arm/syscall.h 2008-01-06 20:38:43.000000000 +0100 -+++ qemu-0.9.1/linux-user/arm/syscall.h 2008-04-14 11:26:14.000000000 +0200 -@@ -28,7 +28,9 @@ - #define ARM_SYSCALL_BASE 0x900000 - #define ARM_THUMB_SYSCALL 0 - --#define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2) -+#define ARM_NR_BASE 0xf0000 -+#define ARM_NR_cacheflush (ARM_NR_BASE + 2) -+#define ARM_NR_set_tls (ARM_NR_BASE + 5) - - #define ARM_NR_semihosting 0x123456 - #define ARM_NR_thumb_semihosting 0xAB -Index: qemu-0.9.1/linux-user/main.c -=================================================================== ---- qemu-0.9.1.orig/linux-user/main.c 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/linux-user/main.c 2008-04-14 11:26:14.000000000 +0200 -@@ -363,6 +363,50 @@ - } - } - -+/* Handle a jump to the kernel code page. */ -+static int -+do_kernel_trap(CPUARMState *env) -+{ -+ uint32_t addr; -+ uint32_t *ptr; -+ uint32_t cpsr; -+ -+ switch (env->regs[15]) { -+ case 0xffff0fc0: /* __kernel_cmpxchg */ -+ /* XXX: This only works between threads, not between processes. -+ Use native atomic operations. */ -+ /* ??? This probably breaks horribly if the access segfaults. */ -+ cpu_lock(); -+ ptr = (uint32_t *)env->regs[2]; -+ cpsr = cpsr_read(env); -+ if (*ptr == env->regs[0]) { -+ *ptr = env->regs[1]; -+ env->regs[0] = 0; -+ cpsr |= CPSR_C; -+ } else { -+ env->regs[0] = -1; -+ cpsr &= ~CPSR_C; -+ } -+ cpsr_write(env, cpsr, CPSR_C); -+ cpu_unlock(); -+ break; -+ case 0xffff0fe0: /* __kernel_get_tls */ -+ env->regs[0] = env->cp15.c13_tls2; -+ break; -+ default: -+ return 1; -+ } -+ /* Jump back to the caller. */ -+ addr = env->regs[14]; -+ if (addr & 1) { -+ env->thumb = 1; -+ addr &= ~1; -+ } -+ env->regs[15] = addr; -+ -+ return 0; -+} -+ - void cpu_loop(CPUARMState *env) - { - int trapnr; -@@ -473,10 +517,8 @@ - } - } - -- if (n == ARM_NR_cacheflush) { -- arm_cache_flush(env->regs[0], env->regs[1]); -- } else if (n == ARM_NR_semihosting -- || n == ARM_NR_thumb_semihosting) { -+ if (n == ARM_NR_semihosting -+ || n == ARM_NR_thumb_semihosting) { - env->regs[0] = do_arm_semihosting (env); - } else if (n == 0 || n >= ARM_SYSCALL_BASE - || (env->thumb && n == ARM_THUMB_SYSCALL)) { -@@ -487,14 +529,35 @@ - n -= ARM_SYSCALL_BASE; - env->eabi = 0; - } -- env->regs[0] = do_syscall(env, -- n, -- env->regs[0], -- env->regs[1], -- env->regs[2], -- env->regs[3], -- env->regs[4], -- env->regs[5]); -+ if (n > ARM_NR_BASE) { -+ switch (n) -+ { -+ case ARM_NR_cacheflush: -+ arm_cache_flush(env->regs[0], env->regs[1]); -+ break; -+#ifdef USE_NPTL -+ case ARM_NR_set_tls: -+ cpu_set_tls(env, env->regs[0]); -+ env->regs[0] = 0; -+ break; -+#endif -+ default: -+ printf ("Error: Bad syscall: %x\n", n); -+ env->regs[0] = -ENOSYS; -+ goto error; -+ } -+ } -+ else -+ { -+ env->regs[0] = do_syscall(env, -+ n, -+ env->regs[0], -+ env->regs[1], -+ env->regs[2], -+ env->regs[3], -+ env->regs[4], -+ env->regs[5]); -+ } - } else { - goto error; - } -@@ -533,6 +596,10 @@ - } - } - break; -+ case EXCP_KERNEL_TRAP: -+ if (do_kernel_trap(env)) -+ goto error; -+ break; - default: - error: - fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", -@@ -2398,6 +2465,10 @@ - ts->heap_base = info->brk; - /* This will be filled in on the first SYS_HEAPINFO call. */ - ts->heap_limit = 0; -+ /* Register the magic kernel code page. The cpu will generate a -+ special exception when it tries to execute code here. We can't -+ put real code here because it may be in use by the host kernel. */ -+ page_set_flags(0xffff0000, 0xffff0fff, 0); - #endif - - if (gdbstub_port) { -Index: qemu-0.9.1/linux-user/qemu.h -=================================================================== ---- qemu-0.9.1.orig/linux-user/qemu.h 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/linux-user/qemu.h 2008-04-14 11:26:14.000000000 +0200 -@@ -109,6 +109,9 @@ - #endif - int used; /* non zero if used */ - struct image_info *info; -+#ifdef USE_NPTL -+ uint32_t *child_tidptr; -+#endif - uint8_t stack[0]; - } __attribute__((aligned(16))) TaskState; - -Index: qemu-0.9.1/linux-user/syscall.c -=================================================================== ---- qemu-0.9.1.orig/linux-user/syscall.c 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/linux-user/syscall.c 2008-04-14 11:27:21.000000000 +0200 -@@ -74,9 +74,18 @@ - #include - - #include "qemu.h" -+#include "spinlock.h" - - //#define DEBUG - -+#ifdef USE_NPTL -+#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \ -+ CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID) -+#else -+/* XXX: Hardcode the above values. */ -+#define CLONE_NPTL_FLAGS2 0 -+#endif -+ - #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \ - || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS) - /* 16 bit uid wrappers emulation */ -@@ -2807,9 +2816,19 @@ - thread/process */ - #define NEW_STACK_SIZE 8192 - -+#ifdef USE_NPTL -+static spinlock_t nptl_lock = SPIN_LOCK_UNLOCKED; -+#endif -+ - static int clone_func(void *arg) - { - CPUState *env = arg; -+#ifdef HAVE_NPTL -+ /* Wait until the parent has finshed initializing the tls state. */ -+ while (!spin_trylock(&nptl_lock)) -+ usleep(1); -+ spin_unlock(&nptl_lock); -+#endif - cpu_loop(env); - /* never exits */ - return 0; -@@ -2817,12 +2836,20 @@ - - /* do_fork() Must return host values and target errnos (unlike most - do_*() functions). */ --int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp) -+int do_fork(CPUState *env, unsigned int flags, unsigned long newsp, -+ uint32_t *parent_tidptr, void *newtls, -+ uint32_t *child_tidptr) - { - int ret; - TaskState *ts; - uint8_t *new_stack; - CPUState *new_env; -+#ifdef USE_NPTL -+ unsigned int nptl_flags; -+ -+ if (flags & CLONE_PARENT_SETTID) -+ *parent_tidptr = gettid(); -+#endif - - if (flags & CLONE_VM) { - ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE); -@@ -2889,16 +2916,64 @@ - #error unsupported target CPU - #endif - new_env->opaque = ts; -+#ifdef USE_NPTL -+ nptl_flags = flags; -+ flags &= ~CLONE_NPTL_FLAGS2; -+ -+ if (nptl_flags & CLONE_CHILD_CLEARTID) { -+ ts->child_tidptr = child_tidptr; -+ } -+ -+ if (nptl_flags & CLONE_SETTLS) -+ cpu_set_tls (new_env, newtls); -+ -+ /* Grab the global cpu lock so that the thread setup appears -+ atomic. */ -+ if (nptl_flags & CLONE_CHILD_SETTID) -+ spin_lock(&nptl_lock); -+ -+#else -+ if (flags & CLONE_NPTL_FLAGS2) -+ return -EINVAL; -+#endif - #ifdef __ia64__ - ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); - #else - ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); - #endif -+#ifdef USE_NPTL -+ if (ret != -1) { -+ if (nptl_flags & CLONE_CHILD_SETTID) -+ *child_tidptr = ret; -+ } -+ -+ /* Allow the child to continue. */ -+ if (nptl_flags & CLONE_CHILD_SETTID) -+ spin_unlock(&nptl_lock); -+#endif - } else { - /* if no CLONE_VM, we consider it is a fork */ -- if ((flags & ~CSIGNAL) != 0) -+ if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) - return -EINVAL; - ret = fork(); -+#ifdef USE_NPTL -+ /* There is a race condition here. The parent process could -+ theoretically read the TID in the child process before the child -+ tid is set. This would require using either ptrace -+ (not implemented) or having *_tidptr to point at a shared memory -+ mapping. We can't repeat the spinlock hack used above because -+ the child process gets its own copy of the lock. */ -+ if (ret == 0) { -+ /* Child Process. */ -+ if (flags & CLONE_CHILD_SETTID) -+ *child_tidptr = gettid(); -+ ts = (TaskState *)env->opaque; -+ if (flags & CLONE_CHILD_CLEARTID) -+ ts->child_tidptr = child_tidptr; -+ if (flags & CLONE_SETTLS) -+ cpu_set_tls (env, newtls); -+ } -+#endif - } - return ret; - } -@@ -3223,7 +3298,7 @@ - ret = do_brk(arg1); - break; - case TARGET_NR_fork: -- ret = get_errno(do_fork(cpu_env, SIGCHLD, 0)); -+ ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, NULL, NULL, NULL)); - break; - #ifdef TARGET_NR_waitpid - case TARGET_NR_waitpid: -@@ -4586,7 +4661,8 @@ - ret = get_errno(fsync(arg1)); - break; - case TARGET_NR_clone: -- ret = get_errno(do_fork(cpu_env, arg1, arg2)); -+ ret = get_errno(do_fork(cpu_env, arg1, arg2, (uint32_t *)arg3, -+ (void *)arg4, (uint32_t *)arg5)); - break; - #ifdef __NR_exit_group - /* new thread calls */ -@@ -5031,7 +5107,8 @@ - #endif - #ifdef TARGET_NR_vfork - case TARGET_NR_vfork: -- ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0)); -+ ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0, -+ NULL, NULL, NULL)); - break; - #endif - #ifdef TARGET_NR_ugetrlimit -Index: qemu-0.9.1/spinlock.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ qemu-0.9.1/spinlock.h 2008-04-14 11:26:14.000000000 +0200 -@@ -0,0 +1,188 @@ -+/* -+ * Atomic operation helper include -+ * -+ * Copyright (c) 2005 Fabrice Bellard -+ * -+ * 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 -+ */ -+#ifndef SPINLOCK_H -+#define SPINLOCK_H -+ -+#if defined(__powerpc__) -+static inline int testandset (int *p) -+{ -+ int ret; -+ __asm__ __volatile__ ( -+ "0: lwarx %0,0,%1\n" -+ " xor. %0,%3,%0\n" -+ " bne 1f\n" -+ " stwcx. %2,0,%1\n" -+ " bne- 0b\n" -+ "1: " -+ : "=&r" (ret) -+ : "r" (p), "r" (1), "r" (0) -+ : "cr0", "memory"); -+ return ret; -+} -+#elif defined(__i386__) -+static inline int testandset (int *p) -+{ -+ long int readval = 0; -+ -+ __asm__ __volatile__ ("lock; cmpxchgl %2, %0" -+ : "+m" (*p), "+a" (readval) -+ : "r" (1) -+ : "cc"); -+ return readval; -+} -+#elif defined(__x86_64__) -+static inline int testandset (int *p) -+{ -+ long int readval = 0; -+ -+ __asm__ __volatile__ ("lock; cmpxchgl %2, %0" -+ : "+m" (*p), "+a" (readval) -+ : "r" (1) -+ : "cc"); -+ return readval; -+} -+#elif defined(__s390__) -+static inline int testandset (int *p) -+{ -+ int ret; -+ -+ __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n" -+ " jl 0b" -+ : "=&d" (ret) -+ : "r" (1), "a" (p), "0" (*p) -+ : "cc", "memory" ); -+ return ret; -+} -+#elif defined(__alpha__) -+static inline int testandset (int *p) -+{ -+ int ret; -+ unsigned long one; -+ -+ __asm__ __volatile__ ("0: mov 1,%2\n" -+ " ldl_l %0,%1\n" -+ " stl_c %2,%1\n" -+ " beq %2,1f\n" -+ ".subsection 2\n" -+ "1: br 0b\n" -+ ".previous" -+ : "=r" (ret), "=m" (*p), "=r" (one) -+ : "m" (*p)); -+ return ret; -+} -+#elif defined(__sparc__) -+static inline int testandset (int *p) -+{ -+ int ret; -+ -+ __asm__ __volatile__("ldstub [%1], %0" -+ : "=r" (ret) -+ : "r" (p) -+ : "memory"); -+ -+ return (ret ? 1 : 0); -+} -+#elif defined(__arm__) -+static inline int testandset (int *spinlock) -+{ -+ register unsigned int ret; -+ __asm__ __volatile__("swp %0, %1, [%2]" -+ : "=r"(ret) -+ : "0"(1), "r"(spinlock)); -+ -+ return ret; -+} -+#elif defined(__mc68000) -+static inline int testandset (int *p) -+{ -+ char ret; -+ __asm__ __volatile__("tas %1; sne %0" -+ : "=r" (ret) -+ : "m" (p) -+ : "cc","memory"); -+ return ret; -+} -+#elif defined(__ia64) -+ -+#include -+ -+static inline int testandset (int *p) -+{ -+ return __sync_lock_test_and_set (p, 1); -+} -+#elif defined(__mips__) -+static inline int testandset (int *p) -+{ -+ int ret; -+ -+ __asm__ __volatile__ ( -+ " .set push \n" -+ " .set noat \n" -+ " .set mips2 \n" -+ "1: li $1, 1 \n" -+ " ll %0, %1 \n" -+ " sc $1, %1 \n" -+ " beqz $1, 1b \n" -+ " .set pop " -+ : "=r" (ret), "+R" (*p) -+ : -+ : "memory"); -+ -+ return ret; -+} -+#else -+#error unimplemented CPU support -+#endif -+ -+typedef int spinlock_t; -+ -+#define SPIN_LOCK_UNLOCKED 0 -+ -+#if defined(CONFIG_USER_ONLY) -+static inline void spin_lock(spinlock_t *lock) -+{ -+ while (testandset(lock)); -+} -+ -+static inline void spin_unlock(spinlock_t *lock) -+{ -+ *lock = 0; -+} -+ -+static inline int spin_trylock(spinlock_t *lock) -+{ -+ return !testandset(lock); -+} -+#else -+static inline void spin_lock(spinlock_t *lock) -+{ -+} -+ -+static inline void spin_unlock(spinlock_t *lock) -+{ -+} -+ -+static inline int spin_trylock(spinlock_t *lock) -+{ -+ return 1; -+} -+#endif -+ -+#endif -Index: qemu-0.9.1/target-arm/cpu.h -=================================================================== ---- qemu-0.9.1.orig/target-arm/cpu.h 2008-01-06 20:38:44.000000000 +0100 -+++ qemu-0.9.1/target-arm/cpu.h 2008-04-14 11:26:14.000000000 +0200 -@@ -38,6 +38,7 @@ - #define EXCP_FIQ 6 - #define EXCP_BKPT 7 - #define EXCP_EXCEPTION_EXIT 8 /* Return from v7M exception. */ -+#define EXCP_KERNEL_TRAP 9 /* Jumped to kernel code page. */ - - #define ARMV7M_EXCP_RESET 1 - #define ARMV7M_EXCP_NMI 2 -@@ -222,6 +223,15 @@ - void cpu_lock(void); - void cpu_unlock(void); - -+void cpu_lock(void); -+void cpu_unlock(void); -+#if defined(USE_NPTL) -+static inline void cpu_set_tls(CPUARMState *env, void *newtls) -+{ -+ env->cp15.c13_tls2 = (uint32_t)(long)newtls; -+} -+#endif -+ - #define CPSR_M (0x1f) - #define CPSR_T (1 << 5) - #define CPSR_F (1 << 6) -Index: qemu-0.9.1/target-arm/op.c -=================================================================== ---- qemu-0.9.1.orig/target-arm/op.c 2008-01-06 20:38:44.000000000 +0100 -+++ qemu-0.9.1/target-arm/op.c 2008-04-14 11:26:14.000000000 +0200 -@@ -1009,6 +1009,12 @@ - cpu_loop_exit(); - } - -+void OPPROTO op_kernel_trap(void) -+{ -+ env->exception_index = EXCP_KERNEL_TRAP; -+ cpu_loop_exit(); -+} -+ - /* VFP support. We follow the convention used for VFP instrunctions: - Single precition routines have a "s" suffix, double precision a - "d" suffix. */ -Index: qemu-0.9.1/target-arm/translate.c -=================================================================== ---- qemu-0.9.1.orig/target-arm/translate.c 2008-01-06 20:38:44.000000000 +0100 -+++ qemu-0.9.1/target-arm/translate.c 2008-04-14 11:26:14.000000000 +0200 -@@ -7519,6 +7519,13 @@ - conditional execution block. */ - gen_op_exception_exit(); - } -+#else -+ /* Intercept jump to the magic kernel page. */ -+ if (dc->pc > 0xffff0000) { -+ gen_op_kernel_trap(); -+ dc->is_jmp = DISAS_UPDATE; -+ break; -+ } - #endif - - if (env->nb_breakpoints > 0) { diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/43_arm_cpustate.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/43_arm_cpustate.patch --- qemu-0.9.1/debian/patches/43_arm_cpustate.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/43_arm_cpustate.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,35 +0,0 @@ -Index: qemu-0.9.1/exec.c -=================================================================== ---- qemu-0.9.1.orig/exec.c 2008-01-28 02:21:46.000000000 +0100 -+++ qemu-0.9.1/exec.c 2008-01-28 02:22:17.000000000 +0100 -@@ -308,24 +308,18 @@ - - void cpu_exec_init(CPUState *env) - { -- CPUState **penv; -- int cpu_index; -- - if (!code_gen_ptr) { - code_gen_ptr = code_gen_buffer; - page_init(); - io_mem_init(); - } -- env->next_cpu = NULL; -- penv = &first_cpu; -- cpu_index = 0; -- while (*penv != NULL) { -- penv = (CPUState **)&(*penv)->next_cpu; -- cpu_index++; -- } -- env->cpu_index = cpu_index; -+ -+ if (first_cpu) -+ env->cpu_index = first_cpu->cpu_index + 1; -+ -+ env->next_cpu = first_cpu; - env->nb_watchpoints = 0; -- *penv = env; -+ first_cpu = env; - } - - static inline void invalidate_page_bitmap(PageDesc *p) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/44_socklen_t_check.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/44_socklen_t_check.patch --- qemu-0.9.1/debian/patches/44_socklen_t_check.patch 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/debian/patches/44_socklen_t_check.patch 2008-11-23 23:12:07.000000000 +0000 @@ -0,0 +1,79 @@ +Index: qemu-0.9.1+svn20081012/linux-user/syscall.c +=================================================================== +--- qemu-0.9.1+svn20081012.orig/linux-user/syscall.c 2008-10-12 18:57:43.000000000 +0200 ++++ qemu-0.9.1+svn20081012/linux-user/syscall.c 2008-10-12 18:57:43.000000000 +0200 +@@ -1245,11 +1245,19 @@ + return get_errno(socket(domain, type, protocol)); + } + ++/* MAX_SOCK_ADDR from linux/net/socket.c */ ++#define MAX_SOCK_ADDR 128 ++ + /* do_bind() Must return target values and target errnos. */ + static abi_long do_bind(int sockfd, abi_ulong target_addr, + socklen_t addrlen) + { +- void *addr = alloca(addrlen); ++ void *addr; ++ ++ if (addrlen < 0 || addrlen > MAX_SOCK_ADDR) ++ return -TARGET_EINVAL; ++ ++ addr = alloca(addrlen); + + target_to_host_sockaddr(addr, target_addr, &addrlen); + return get_errno(bind(sockfd, addr, addrlen)); +@@ -1259,7 +1267,12 @@ + static abi_long do_connect(int sockfd, abi_ulong target_addr, + socklen_t addrlen) + { +- void *addr = alloca(addrlen); ++ void *addr; ++ ++ if (addrlen < 0 || addrlen > MAX_SOCK_ADDR) ++ return -TARGET_EINVAL; ++ ++ addr = alloca(addrlen); + + target_to_host_sockaddr(addr, target_addr, &addrlen); + return get_errno(connect(sockfd, addr, addrlen)); +@@ -1328,6 +1341,8 @@ + target_addr != (target_ulong)NULL) { + if (get_user_u32(addrlen, target_addrlen_addr)) + return -TARGET_EFAULT; ++ if (addrlen < 0 || addrlen > MAX_SOCK_ADDR) ++ return -TARGET_EINVAL; + addr = alloca(addrlen); + ret = get_errno(accept(fd, addr, &addrlen)); + } else { +@@ -1378,6 +1393,9 @@ + if (get_user_u32(addrlen, target_addrlen_addr)) + return -TARGET_EFAULT; + ++ if (addrlen < 0 || addrlen > MAX_SOCK_ADDR) ++ return -TARGET_EINVAL; ++ + addr = alloca(addrlen); + + ret = get_errno(getsockname(fd, addr, &addrlen)); +@@ -1413,6 +1431,9 @@ + void *host_msg; + abi_long ret; + ++ if (addrlen < 0 || addrlen > MAX_SOCK_ADDR) ++ return -TARGET_EINVAL; ++ + host_msg = lock_user(VERIFY_READ, msg, len, 1); + if (!host_msg) + return -TARGET_EFAULT; +@@ -1445,6 +1466,10 @@ + ret = -TARGET_EFAULT; + goto fail; + } ++ if (addrlen < 0 || addrlen > MAX_SOCK_ADDR) { ++ ret = -TARGET_EINVAL; ++ goto fail; ++ } + addr = alloca(addrlen); + ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen)); + } else { diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/48_signal_terminate.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/48_signal_terminate.patch --- qemu-0.9.1/debian/patches/48_signal_terminate.patch 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/debian/patches/48_signal_terminate.patch 2008-11-23 23:12:07.000000000 +0000 @@ -0,0 +1,58 @@ +Index: qemu-0.9.1+svn20081012/linux-user/signal.c +=================================================================== +--- qemu-0.9.1+svn20081012.orig/linux-user/signal.c 2008-10-12 18:54:50.000000000 +0200 ++++ qemu-0.9.1+svn20081012/linux-user/signal.c 2008-10-12 18:57:43.000000000 +0200 +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + + #include "qemu.h" +@@ -335,21 +336,33 @@ + static void __attribute((noreturn)) force_sig(int sig) + { + int host_sig; ++ struct sigaction act; + host_sig = target_to_host_signal(sig); + fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n", + sig, strsignal(host_sig)); +-#if 1 +- _exit(-host_sig); +-#else +- { +- struct sigaction act; +- sigemptyset(&act.sa_mask); +- act.sa_flags = SA_SIGINFO; +- act.sa_sigaction = SIG_DFL; +- sigaction(SIGABRT, &act, NULL); +- abort(); +- } +-#endif ++ ++ /* The proper exit code for dieing from an uncaught signal is ++ * -. The kernel doesn't allow exit() or _exit() to pass ++ * a negative value. To get the proper exit code we need to ++ * actually die from an uncaught signal. Here the default signal ++ * handler is installed, we send ourself a signal and we wait for ++ * it to arrive. */ ++ sigfillset(&act.sa_mask); ++ act.sa_handler = SIG_DFL; ++ sigaction(host_sig, &act, NULL); ++ ++ /* For some reason raise(host_sig) doesn't send the signal when ++ * statically linked on x86-64. */ ++ kill(getpid(), host_sig); ++ ++ /* Make sure the signal isn't masked (just reuse the mask inside ++ of act) */ ++ sigdelset(&act.sa_mask, host_sig); ++ sigsuspend(&act.sa_mask); ++ ++ /* unreachable */ ++ assert(0); ++ + } + + /* queue a signal so that it will be send to the virtual CPU as soon diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/49_null_check.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/49_null_check.patch --- qemu-0.9.1/debian/patches/49_null_check.patch 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/debian/patches/49_null_check.patch 2008-11-23 23:12:07.000000000 +0000 @@ -0,0 +1,60 @@ +Index: qemu-0.9.1+svn20081012/linux-user/path.c +=================================================================== +--- qemu-0.9.1+svn20081012.orig/linux-user/path.c 2008-06-03 21:51:57.000000000 +0200 ++++ qemu-0.9.1+svn20081012/linux-user/path.c 2008-10-12 19:08:30.000000000 +0200 +@@ -152,7 +152,7 @@ + { + /* Only do absolute paths: quick and dirty, but should mostly be OK. + Could do relative by tracking cwd. */ +- if (!base || name[0] != '/') ++ if (!base || !name || name[0] != '/') + return name; + + return follow_path(base, name) ?: name; +Index: qemu-0.9.1+svn20081012/linux-user/syscall.c +=================================================================== +--- qemu-0.9.1+svn20081012.orig/linux-user/syscall.c 2008-10-12 19:08:30.000000000 +0200 ++++ qemu-0.9.1+svn20081012/linux-user/syscall.c 2008-10-12 19:08:30.000000000 +0200 +@@ -1369,7 +1369,7 @@ + abi_long ret; + + if (get_user_u32(addrlen, target_addrlen_addr)) +- return -TARGET_EFAULT; ++ return -TARGET_EINVAL; + + addr = alloca(addrlen); + +@@ -3475,10 +3475,14 @@ + ret = 0; /* avoid warning */ + break; + case TARGET_NR_read: +- if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) +- goto efault; +- ret = get_errno(read(arg1, p, arg3)); +- unlock_user(p, arg2, ret); ++ if (!arg3) ++ ret = 0; ++ else { ++ if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) ++ goto efault; ++ ret = get_errno(read(arg1, p, arg3)); ++ unlock_user(p, arg2, ret); ++ } + break; + case TARGET_NR_write: + if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) +@@ -3979,8 +3983,12 @@ + goto unimplemented; + #endif + case TARGET_NR_acct: +- if (!(p = lock_user_string(arg1))) +- goto efault; ++ if (arg1) { ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ } else { ++ p = NULL; ++ } + ret = get_errno(acct(path(p))); + unlock_user(p, arg1, 0); + break; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/50_linuxbios_isa_bios_ram.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/50_linuxbios_isa_bios_ram.patch --- qemu-0.9.1/debian/patches/50_linuxbios_isa_bios_ram.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/50_linuxbios_isa_bios_ram.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,8 +1,16 @@ -Index: hw/pc.c +Index: qemu-0.9.1+svn20081012/hw/pc.c =================================================================== ---- hw/pc.c.orig 2008-04-14 11:26:14.000000000 +0200 -+++ hw/pc.c 2008-04-14 11:27:35.000000000 +0200 -@@ -794,15 +794,13 @@ +--- qemu-0.9.1+svn20081012.orig/hw/pc.c 2008-10-07 22:39:39.000000000 +0200 ++++ qemu-0.9.1+svn20081012/hw/pc.c 2008-10-12 19:08:47.000000000 +0200 +@@ -785,6 +785,7 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size, + * and some bios areas, which will be registered later + */ + ram_addr = qemu_ram_alloc(0x100000 - 0xa0000); ++ cpu_register_physical_memory(0xa0000, 0x100000 - 0xa0000, ram_addr); + ram_addr = qemu_ram_alloc(below_4g_mem_size - 0x100000); + cpu_register_physical_memory(0x100000, + below_4g_mem_size - 0x100000, +@@ -841,15 +842,15 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size, cpu_register_physical_memory(0xc0000, 0x10000, vga_bios_offset | IO_MEM_ROM); @@ -11,8 +19,6 @@ isa_bios_size = bios_size; if (isa_bios_size > (128 * 1024)) isa_bios_size = 128 * 1024; -- cpu_register_physical_memory(0xd0000, (192 * 1024) - isa_bios_size, -- IO_MEM_UNASSIGNED); - cpu_register_physical_memory(0x100000 - isa_bios_size, - isa_bios_size, - (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/51_linuxbios_piix_ram_size.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/51_linuxbios_piix_ram_size.patch --- qemu-0.9.1/debian/patches/51_linuxbios_piix_ram_size.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/51_linuxbios_piix_ram_size.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,8 +1,8 @@ -Index: hw/pc.c +Index: qemu-0.9.1+svn20081012/hw/pc.c =================================================================== ---- hw/pc.c.orig 2008-04-14 11:26:14.000000000 +0200 -+++ hw/pc.c 2008-04-14 11:27:17.000000000 +0200 -@@ -844,7 +844,7 @@ +--- qemu-0.9.1+svn20081012.orig/hw/pc.c 2008-10-12 19:08:30.000000000 +0200 ++++ qemu-0.9.1+svn20081012/hw/pc.c 2008-10-12 19:08:30.000000000 +0200 +@@ -899,7 +899,7 @@ ferr_irq = i8259[13]; if (pci_enabled) { @@ -11,11 +11,11 @@ piix3_devfn = piix3_init(pci_bus, -1); } else { pci_bus = NULL; -Index: hw/pc.h +Index: qemu-0.9.1+svn20081012/hw/pc.h =================================================================== ---- hw/pc.h.orig 2008-01-06 20:38:42.000000000 +0100 -+++ hw/pc.h 2008-04-14 11:26:14.000000000 +0200 -@@ -97,7 +97,7 @@ +--- qemu-0.9.1+svn20081012.orig/hw/pc.h 2008-09-28 02:42:12.000000000 +0200 ++++ qemu-0.9.1+svn20081012/hw/pc.h 2008-10-12 19:08:30.000000000 +0200 +@@ -100,7 +100,7 @@ int pcspk_audio_init(AudioState *, qemu_irq *pic); /* piix_pci.c */ @@ -24,10 +24,10 @@ void i440fx_set_smm(PCIDevice *d, int val); int piix3_init(PCIBus *bus, int devfn); void i440fx_init_memory_mappings(PCIDevice *d); -Index: hw/piix_pci.c +Index: qemu-0.9.1+svn20081012/hw/piix_pci.c =================================================================== ---- hw/piix_pci.c.orig 2008-01-06 20:38:42.000000000 +0100 -+++ hw/piix_pci.c 2008-04-14 11:26:14.000000000 +0200 +--- qemu-0.9.1+svn20081012.orig/hw/piix_pci.c 2008-04-27 23:12:55.000000000 +0200 ++++ qemu-0.9.1+svn20081012/hw/piix_pci.c 2008-10-12 19:08:30.000000000 +0200 @@ -169,7 +169,7 @@ return 0; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/53_openbios_size.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/53_openbios_size.patch --- qemu-0.9.1/debian/patches/53_openbios_size.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/53_openbios_size.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,26 +0,0 @@ -Index: qemu-0.9.1/hw/sun4m.c -=================================================================== ---- qemu-0.9.1.orig/hw/sun4m.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/sun4m.c 2008-04-14 11:26:14.000000000 +0200 -@@ -71,7 +71,7 @@ - #define KERNEL_LOAD_ADDR 0x00004000 - #define CMDLINE_ADDR 0x007ff000 - #define INITRD_LOAD_ADDR 0x00800000 --#define PROM_SIZE_MAX (512 * 1024) -+#define PROM_SIZE_MAX (1024 * 1024) - #define PROM_VADDR 0xffd00000 - #define PROM_FILENAME "openbios-sparc32" - -Index: qemu-0.9.1/hw/sun4u.c -=================================================================== ---- qemu-0.9.1.orig/hw/sun4u.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/sun4u.c 2008-04-14 11:26:14.000000000 +0200 -@@ -35,7 +35,7 @@ - #define KERNEL_LOAD_ADDR 0x00404000 - #define CMDLINE_ADDR 0x003ff000 - #define INITRD_LOAD_ADDR 0x00300000 --#define PROM_SIZE_MAX (512 * 1024) -+#define PROM_SIZE_MAX (1024 * 1024) - #define PROM_ADDR 0x1fff0000000ULL - #define PROM_VADDR 0x000ffd00000ULL - #define APB_SPECIAL_BASE 0x1fe00000000ULL diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/55_unmux_socketcall.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/55_unmux_socketcall.patch --- qemu-0.9.1/debian/patches/55_unmux_socketcall.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/55_unmux_socketcall.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,7 +1,7 @@ -Index: qemu-0.9.1/linux-user/arm/syscall_nr.h +Index: qemu-0.9.1+svn20081012/linux-user/arm/syscall_nr.h =================================================================== ---- qemu-0.9.1.orig/linux-user/arm/syscall_nr.h 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/linux-user/arm/syscall_nr.h 2008-04-14 11:26:14.000000000 +0200 +--- qemu-0.9.1+svn20081012.orig/linux-user/arm/syscall_nr.h 2008-10-12 19:08:30.000000000 +0200 ++++ qemu-0.9.1+svn20081012/linux-user/arm/syscall_nr.h 2008-10-12 19:08:30.000000000 +0200 @@ -256,9 +256,8 @@ #define TARGET_NR_epoll_ctl (251) #define TARGET_NR_epoll_wait (252) @@ -14,19 +14,3 @@ #define TARGET_NR_set_tid_address 256 #define TARGET_NR_timer_create 257 #define TARGET_NR_timer_settime 258 -Index: qemu-0.9.1/linux-user/syscall.c -=================================================================== ---- qemu-0.9.1.orig/linux-user/syscall.c 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/linux-user/syscall.c 2008-04-14 11:26:14.000000000 +0200 -@@ -5701,7 +5701,10 @@ - case TARGET_NR_getdomainname: - goto unimplemented_nowarn; - #endif -- -+#ifdef TARGET_NR_futex -+ case TARGET_NR_futex: -+ goto unimplemented_nowarn; -+#endif - #ifdef TARGET_NR_clock_gettime - case TARGET_NR_clock_gettime: - { diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/60_ppc_ld.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/60_ppc_ld.patch --- qemu-0.9.1/debian/patches/60_ppc_ld.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/60_ppc_ld.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,7 +1,5 @@ -Index: qemu-0.9.1/ppc.ld -=================================================================== ---- qemu-0.9.1.orig/ppc.ld 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/ppc.ld 2008-04-14 11:26:14.000000000 +0200 +--- a/ppc.ld ++++ b/ppc.ld @@ -8,6 +8,7 @@ SECTIONS { diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/63_sparc_build.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/63_sparc_build.patch --- qemu-0.9.1/debian/patches/63_sparc_build.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/63_sparc_build.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,13 +0,0 @@ -Index: sparc.ld -=================================================================== ---- sparc.ld.orig 2008-01-06 20:38:42.000000000 +0100 -+++ sparc.ld 2008-04-14 11:26:14.000000000 +0200 -@@ -6,7 +6,7 @@ - SECTIONS - { - /* Read-only sections, merged into text segment: */ -- . = 0x60000000 + SIZEOF_HEADERS; -+ . = 0x60000000 + 0x400; - .interp : { *(.interp) } - .hash : { *(.hash) } - .dynsym : { *(.dynsym) } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/64_ppc_asm_constraints.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/64_ppc_asm_constraints.patch --- qemu-0.9.1/debian/patches/64_ppc_asm_constraints.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/64_ppc_asm_constraints.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,8 +1,8 @@ -Index: qemu-0.9.1/cpu-all.h +Index: qemu-0.9.1+svn20081012/cpu-all.h =================================================================== ---- qemu-0.9.1.orig/cpu-all.h 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/cpu-all.h 2008-04-14 11:26:14.000000000 +0200 -@@ -280,7 +280,7 @@ +--- qemu-0.9.1+svn20081012.orig/cpu-all.h 2008-10-12 19:13:00.000000000 +0200 ++++ qemu-0.9.1+svn20081012/cpu-all.h 2008-10-12 19:13:07.000000000 +0200 +@@ -286,7 +286,7 @@ static inline void stl_le_p(void *ptr, int v) { #ifdef __powerpc__ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/65_kfreebsd.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/65_kfreebsd.patch --- qemu-0.9.1/debian/patches/65_kfreebsd.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/65_kfreebsd.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,12 +1,12 @@ -Index: qemu-0.9.1/configure +Index: qemu-0.9.1+svn20081012/configure =================================================================== ---- qemu-0.9.1.orig/configure 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/configure 2008-04-14 11:27:19.000000000 +0200 -@@ -126,6 +126,7 @@ - ;; - GNU/kFreeBSD) - oss="yes" -+VL_OS_LDFLAGS="-lfreebsd" +--- qemu-0.9.1+svn20081012.orig/configure 2008-10-12 19:12:59.000000000 +0200 ++++ qemu-0.9.1+svn20081012/configure 2008-10-12 19:13:07.000000000 +0200 +@@ -138,6 +138,7 @@ if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then kqemu="yes" fi ++OS_LDFLAGS="-lfreebsd" + ;; + FreeBSD) + bsd="yes" diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/66_tls_ld.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/66_tls_ld.patch --- qemu-0.9.1/debian/patches/66_tls_ld.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/66_tls_ld.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,32 +1,7 @@ -Index: arm.ld +Index: qemu-0.9.1+svn20081012/i386.ld =================================================================== ---- arm.ld.orig 2008-01-06 20:38:41.000000000 +0100 -+++ arm.ld 2008-04-14 11:26:14.000000000 +0200 -@@ -26,6 +26,10 @@ - { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } - .rela.rodata : - { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } -+ .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } -+ .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } -+ .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } -+ .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.ctors : { *(.rel.ctors) } -@@ -58,6 +62,9 @@ - .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } - __exidx_end = .; - .reginfo : { *(.reginfo) } -+ /* Thread Local Storage sections */ -+ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } -+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. */ - . = ALIGN(0x100000) + (. & (0x100000 - 1)); -Index: i386.ld -=================================================================== ---- i386.ld.orig 2008-01-06 20:38:42.000000000 +0100 -+++ i386.ld 2008-04-14 11:26:14.000000000 +0200 +--- qemu-0.9.1+svn20081012.orig/i386.ld 2008-10-12 19:12:59.000000000 +0200 ++++ qemu-0.9.1+svn20081012/i386.ld 2008-10-12 19:13:07.000000000 +0200 @@ -28,6 +28,10 @@ { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } .rela.rodata : diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/70_manpage.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/70_manpage.patch --- qemu-0.9.1/debian/patches/70_manpage.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/70_manpage.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,33 +0,0 @@ -Index: qemu-doc.texi -=================================================================== ---- qemu-doc.texi.orig 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-doc.texi 2008-04-14 11:27:20.000000000 +0200 -@@ -492,6 +498,28 @@ - - @item -usbdevice @var{devname} - Add the USB device @var{devname}. @xref{usb_devices}. -+ -+@table @code -+ -+@item mouse -+Virtual Mouse. This will override the PS/2 mouse emulation when activated. -+ -+@item tablet -+Pointer device that uses absolute coordinates (like a touchscreen). This -+means qemu is able to report the mouse position without having to grab the -+mouse. Also overrides the PS/2 mouse emulation when activated. -+ -+@item disk:file -+Mass storage device based on file -+ -+@item host:bus.addr -+Pass through the host device identified by bus.addr (Linux only). -+ -+@item host:vendor_id:product_id -+Pass through the host device identified by vendor_id:product_id (Linux only). -+ -+@end table -+ - @end table - - Network options: diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/71_doc.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/71_doc.patch --- qemu-0.9.1/debian/patches/71_doc.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/71_doc.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,21 +0,0 @@ -commit 3bed1834e876c7f922694e0dbfe8f5d2da480b6d -Author: Aurelien Jarno -Date: Sun Mar 16 22:15:30 2008 +0100 - - Documentation update for the monitor change command - - Signed-off-by: Aurelien Jarno - -Index: qemu-0.9.1/qemu-doc.texi -=================================================================== ---- qemu-0.9.1.orig/qemu-doc.texi 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/qemu-doc.texi 2008-04-14 11:27:19.000000000 +0200 -@@ -1046,7 +1046,7 @@ - Change the medium for a removable disk device to point to @var{filename}. eg - - @example --(qemu) change cdrom /path/to/some.iso -+(qemu) change ide1-cd0 /path/to/some.iso - @end example - - @item change vnc @var{display},@var{options} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/80_ui_curses.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/80_ui_curses.patch --- qemu-0.9.1/debian/patches/80_ui_curses.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/80_ui_curses.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,1788 +0,0 @@ -commit ea85a83baf27032c4b7a0a6bb495fa276df2d2ef -Author: balrog -Date: Sun Feb 10 16:33:12 2008 +0000 - - Add an ncurses UI. - -Index: qemu-0.9.1/Makefile -=================================================================== ---- qemu-0.9.1.orig/Makefile 2008-04-14 11:26:13.000000000 +0200 -+++ qemu-0.9.1/Makefile 2008-04-14 11:27:19.000000000 +0200 -@@ -90,6 +90,9 @@ - ifdef CONFIG_SDL - OBJS+=sdl.o x_keymap.o - endif -+ifdef CONFIG_CURSES -+OBJS+=curses.o -+endif - OBJS+=vnc.o d3des.o - - ifdef CONFIG_COCOA -@@ -113,6 +116,9 @@ - vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h d3des.c d3des.h - $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $(CONFIG_VNC_TLS_CFLAGS) -c -o $@ $< - -+curses.o: curses.c keymaps.c curses_keys.h -+ $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< -+ - audio/sdlaudio.o: audio/sdlaudio.c - $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $< - -Index: qemu-0.9.1/Makefile.target -=================================================================== ---- qemu-0.9.1.orig/Makefile.target 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/Makefile.target 2008-04-14 11:27:17.000000000 +0200 -@@ -565,7 +565,7 @@ - endif - - $(QEMU_SYSTEM): $(VL_OBJS) ../libqemu_common.a libqemu.a -- $(CC) $(VL_LDFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS) -+ $(CC) $(VL_LDFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(CURSES_LIBS) $(COCOA_LIBS) $(VL_LIBS) - - depend: $(SRCS) - $(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend -Index: qemu-0.9.1/configure -=================================================================== ---- qemu-0.9.1.orig/configure 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/configure 2008-04-14 11:27:17.000000000 +0200 -@@ -106,6 +106,7 @@ - build_docs="no" - uname_release="" - nptl="yes" -+curses="yes" - - # OS specific - targetos=`uname -s` -@@ -318,6 +319,8 @@ - ;; - --disable-werror) werror="no" - ;; -+ --disable-curses) curses="no" -+ ;; - *) echo "ERROR: unknown option $opt"; show_help="yes" - ;; - --disable-nptl) nptl="no" -@@ -684,6 +687,20 @@ - fi - fi - -+########################################## -+# curses probe -+ -+if test "$curses" = "yes" ; then -+ curses=no -+ cat > $TMPC << EOF -+#include -+int main(void) { return curses_version(); } -+EOF -+ if $cc -o $TMPE $TMPC -lcurses 2> /dev/null ; then -+ curses=yes -+ fi -+fi # test "$curses" -+ - # Check if tools are available to build documentation. - if [ -x "`which texi2html 2>/dev/null`" ] && \ - [ -x "`which pod2man 2>/dev/null`" ]; then -@@ -734,6 +751,7 @@ - if test "$sdl" != "no" ; then - echo "SDL static link $sdl_static" - fi -+echo "curses support $curses" - echo "mingw32 support $mingw32" - echo "Adlib support $adlib" - echo "CoreAudio support $coreaudio" -@@ -980,8 +998,13 @@ - fi - fi - if test "$cocoa" = "yes" ; then -- echo "#define CONFIG_COCOA 1" >> $config_h -- echo "CONFIG_COCOA=yes" >> $config_mak -+ echo "#define CONFIG_COCOA 1" >> $config_h -+ echo "CONFIG_COCOA=yes" >> $config_mak -+fi -+if test "$curses" = "yes" ; then -+ echo "#define CONFIG_CURSES 1" >> $config_h -+ echo "CONFIG_CURSES=yes" >> $config_mak -+ echo "CURSES_LIBS=-lcurses" >> $config_mak - fi - - # XXX: suppress that -@@ -1046,7 +1069,8 @@ - -a "$sdl" = "no" -a "$cocoa" = "no" ; then - echo "ERROR: QEMU requires SDL or Cocoa for graphical output" - echo "To build QEMU without graphical output configure with --disable-gfx-check" -- echo "Note that this will disable all output from the virtual graphics card." -+ echo "Note that this will disable all output from the virtual graphics card" -+ echo "except through VNC or curses." - exit 1; - fi - -Index: qemu-0.9.1/console.c -=================================================================== ---- qemu-0.9.1.orig/console.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/console.c 2008-04-14 11:26:14.000000000 +0200 -@@ -121,6 +121,7 @@ - vga_hw_update_ptr hw_update; - vga_hw_invalidate_ptr hw_invalidate; - vga_hw_screen_dump_ptr hw_screen_dump; -+ vga_hw_text_update_ptr hw_text_update; - void *hw; - - int g_width, g_height; -@@ -135,6 +136,7 @@ - TextAttributes t_attrib_default; /* default text attributes */ - TextAttributes t_attrib; /* currently active text attributes */ - TextCell *cells; -+ int text_x[2], text_y[2], cursor_invalidate; - - enum TTYState state; - int esc_params[MAX_ESC_PARAMS]; -@@ -171,6 +173,12 @@ - consoles[0]->hw_screen_dump(consoles[0]->hw, filename); - } - -+void vga_hw_text_update(console_ch_t *chardata) -+{ -+ if (active_console && active_console->hw_text_update) -+ active_console->hw_text_update(active_console->hw, chardata); -+} -+ - /* convert a RGBA color to a color index usable in graphic primitives */ - static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba) - { -@@ -515,12 +523,25 @@ - s->cells = cells; - } - -+static inline void text_update_xy(TextConsole *s, int x, int y) -+{ -+ s->text_x[0] = MIN(s->text_x[0], x); -+ s->text_x[1] = MAX(s->text_x[1], x); -+ s->text_y[0] = MIN(s->text_y[0], y); -+ s->text_y[1] = MAX(s->text_y[1], y); -+} -+ - static void update_xy(TextConsole *s, int x, int y) - { - TextCell *c; - int y1, y2; - - if (s == active_console) { -+ if (!s->ds->depth) { -+ text_update_xy(s, x, y); -+ return; -+ } -+ - y1 = (s->y_base + y) % s->total_height; - y2 = y1 - s->y_displayed; - if (y2 < 0) -@@ -542,6 +563,12 @@ - - if (s == active_console) { - int x = s->x; -+ -+ if (!s->ds->depth) { -+ s->cursor_invalidate = 1; -+ return; -+ } -+ - if (x >= s->width) { - x = s->width - 1; - } -@@ -571,6 +598,14 @@ - - if (s != active_console) - return; -+ if (!s->ds->depth) { -+ s->text_x[0] = 0; -+ s->text_y[0] = 0; -+ s->text_x[1] = s->width - 1; -+ s->text_y[1] = s->height - 1; -+ s->cursor_invalidate = 1; -+ return; -+ } - - vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height, - color_table[0][COLOR_BLACK]); -@@ -648,6 +683,14 @@ - c++; - } - if (s == active_console && s->y_displayed == s->y_base) { -+ if (!s->ds->depth) { -+ s->text_x[0] = 0; -+ s->text_y[0] = 0; -+ s->text_x[1] = s->width - 1; -+ s->text_y[1] = s->height - 1; -+ return; -+ } -+ - vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, - s->width * FONT_WIDTH, - (s->height - 1) * FONT_HEIGHT); -@@ -998,21 +1041,7 @@ - s = consoles[index]; - if (s) { - active_console = s; -- if (s->console_type != GRAPHIC_CONSOLE) { -- if (s->g_width != s->ds->width || -- s->g_height != s->ds->height) { -- if (s->console_type == TEXT_CONSOLE_FIXED_SIZE) { -- dpy_resize(s->ds, s->g_width, s->g_height); -- } else { -- s->g_width = s->ds->width; -- s->g_height = s->ds->height; -- text_console_resize(s); -- } -- } -- console_refresh(s); -- } else { -- vga_hw_invalidate(); -- } -+ vga_hw_invalidate(); - } - } - -@@ -1116,6 +1145,52 @@ - } - } - -+static void text_console_invalidate(void *opaque) -+{ -+ TextConsole *s = (TextConsole *) opaque; -+ -+ if (s->console_type != GRAPHIC_CONSOLE) { -+ if (s->g_width != s->ds->width || -+ s->g_height != s->ds->height) { -+ if (s->console_type == TEXT_CONSOLE_FIXED_SIZE) -+ dpy_resize(s->ds, s->g_width, s->g_height); -+ else { -+ s->g_width = s->ds->width; -+ s->g_height = s->ds->height; -+ text_console_resize(s); -+ } -+ } -+ } -+ console_refresh(s); -+} -+ -+static void text_console_update(void *opaque, console_ch_t *chardata) -+{ -+ TextConsole *s = (TextConsole *) opaque; -+ int i, j, src; -+ -+ if (s->text_x[0] <= s->text_x[1]) { -+ src = (s->y_base + s->text_y[0]) * s->width; -+ chardata += s->text_y[0] * s->width; -+ for (i = s->text_y[0]; i <= s->text_y[1]; i ++) -+ for (j = 0; j < s->width; j ++, src ++) -+ console_write_ch(chardata ++, s->cells[src].ch | -+ (s->cells[src].t_attrib.fgcol << 12) | -+ (s->cells[src].t_attrib.bgcol << 8) | -+ (s->cells[src].t_attrib.bold << 21)); -+ dpy_update(s->ds, s->text_x[0], s->text_y[0], -+ s->text_x[1] - s->text_x[0], i - s->text_y[0]); -+ s->text_x[0] = s->width; -+ s->text_y[0] = s->height; -+ s->text_x[1] = 0; -+ s->text_y[1] = 0; -+ } -+ if (s->cursor_invalidate) { -+ dpy_cursor(s->ds, s->x, s->y); -+ s->cursor_invalidate = 0; -+ } -+} -+ - static TextConsole *new_console(DisplayState *ds, console_type_t console_type) - { - TextConsole *s; -@@ -1150,6 +1225,7 @@ - TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update, - vga_hw_invalidate_ptr invalidate, - vga_hw_screen_dump_ptr screen_dump, -+ vga_hw_text_update_ptr text_update, - void *opaque) - { - TextConsole *s; -@@ -1160,13 +1236,14 @@ - s->hw_update = update; - s->hw_invalidate = invalidate; - s->hw_screen_dump = screen_dump; -+ s->hw_text_update = text_update; - s->hw = opaque; - return s; - } - - int is_graphic_console(void) - { -- return active_console->console_type == GRAPHIC_CONSOLE; -+ return active_console && active_console->console_type == GRAPHIC_CONSOLE; - } - - void console_color_init(DisplayState *ds) -@@ -1234,6 +1311,10 @@ - s->g_width = width; - s->g_height = height; - -+ s->hw_invalidate = text_console_invalidate; -+ s->hw_text_update = text_console_update; -+ s->hw = s; -+ - /* Set text attribute defaults */ - s->t_attrib_default.bold = 0; - s->t_attrib_default.uline = 0; -Index: qemu-0.9.1/console.h -=================================================================== ---- qemu-0.9.1.orig/console.h 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/console.h 2008-04-14 11:26:14.000000000 +0200 -@@ -79,6 +79,7 @@ - int dst_x, int dst_y, int w, int h); - void (*dpy_fill)(struct DisplayState *s, int x, int y, - int w, int h, uint32_t c); -+ void (*dpy_text_cursor)(struct DisplayState *s, int x, int y); - void (*mouse_set)(int x, int y, int on); - void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y, - uint8_t *image, uint8_t *mask); -@@ -94,17 +95,32 @@ - s->dpy_resize(s, w, h); - } - -+static inline void dpy_cursor(DisplayState *s, int x, int y) -+{ -+ if (s->dpy_text_cursor) -+ s->dpy_text_cursor(s, x, y); -+} -+ -+typedef unsigned long console_ch_t; -+static inline void console_write_ch(console_ch_t *dest, uint32_t ch) -+{ -+ cpu_to_le32wu((uint32_t *) dest, ch); -+} -+ - typedef void (*vga_hw_update_ptr)(void *); - typedef void (*vga_hw_invalidate_ptr)(void *); - typedef void (*vga_hw_screen_dump_ptr)(void *, const char *); -+typedef void (*vga_hw_text_update_ptr)(void *, console_ch_t *); - - TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update, - vga_hw_invalidate_ptr invalidate, - vga_hw_screen_dump_ptr screen_dump, -+ vga_hw_text_update_ptr text_update, - void *opaque); - void vga_hw_update(void); - void vga_hw_invalidate(void); - void vga_hw_screen_dump(const char *filename); -+void vga_hw_text_update(console_ch_t *chardata); - - int is_graphic_console(void); - CharDriverState *text_console_init(DisplayState *ds, const char *p); -@@ -124,6 +140,9 @@ - int vnc_display_password(DisplayState *ds, const char *password); - void do_info_vnc(void); - -+/* curses.c */ -+void curses_display_init(DisplayState *ds, int full_screen); -+ - /* x_keymap.c */ - extern uint8_t _translate_keycode(const int key); - -Index: qemu-0.9.1/curses.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ qemu-0.9.1/curses.c 2008-04-14 11:26:14.000000000 +0200 -@@ -0,0 +1,370 @@ -+/* -+ * QEMU curses/ncurses display driver -+ * -+ * Copyright (c) 2005 Andrzej Zaborowski -+ * -+ * 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 "qemu-common.h" -+#include "console.h" -+#include "sysemu.h" -+ -+#include -+ -+#ifndef _WIN32 -+#include -+#include -+#include -+#endif -+ -+#define FONT_HEIGHT 16 -+#define FONT_WIDTH 8 -+ -+static console_ch_t screen[160 * 100]; -+static WINDOW *screenpad = NULL; -+static int width, height, gwidth, gheight, invalidate; -+static int px, py, sminx, sminy, smaxx, smaxy; -+ -+static void curses_update(DisplayState *ds, int x, int y, int w, int h) -+{ -+ chtype *line; -+ -+ line = ((chtype *) screen) + y * width; -+ for (h += y; y < h; y ++, line += width) -+ mvwaddchnstr(screenpad, y, 0, line, width); -+ -+ pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1); -+ refresh(); -+} -+ -+static void curses_calc_pad(void) -+{ -+ if (is_graphic_console()) { -+ width = gwidth; -+ height = gheight; -+ } else { -+ width = COLS; -+ height = LINES; -+ } -+ -+ if (screenpad) -+ delwin(screenpad); -+ -+ clear(); -+ refresh(); -+ -+ screenpad = newpad(height, width); -+ -+ if (width > COLS) { -+ px = (width - COLS) / 2; -+ sminx = 0; -+ smaxx = COLS; -+ } else { -+ px = 0; -+ sminx = (COLS - width) / 2; -+ smaxx = sminx + width; -+ } -+ -+ if (height > LINES) { -+ py = (height - LINES) / 2; -+ sminy = 0; -+ smaxy = LINES; -+ } else { -+ py = 0; -+ sminy = (LINES - height) / 2; -+ smaxy = sminy + height; -+ } -+} -+ -+static void curses_resize(DisplayState *ds, int w, int h) -+{ -+ if (w == gwidth && h == gheight) -+ return; -+ -+ gwidth = w; -+ gheight = h; -+ -+ curses_calc_pad(); -+} -+ -+#ifndef _WIN32 -+#ifdef SIGWINCH -+static void curses_winch_handler(int signum) -+{ -+ struct winsize { -+ unsigned short ws_row; -+ unsigned short ws_col; -+ unsigned short ws_xpixel; /* unused */ -+ unsigned short ws_ypixel; /* unused */ -+ } ws; -+ -+ /* terminal size changed */ -+ if (ioctl(1, TIOCGWINSZ, &ws) == -1) -+ return; -+ -+ resize_term(ws.ws_row, ws.ws_col); -+ curses_calc_pad(); -+ invalidate = 1; -+ -+ /* some systems require this */ -+ signal(SIGWINCH, curses_winch_handler); -+} -+#endif -+#endif -+ -+static void curses_cursor_position(DisplayState *ds, int x, int y) -+{ -+ if (x >= 0) { -+ x = sminx + x - px; -+ y = sminy + y - py; -+ -+ if (x >= 0 && y >= 0 && x < COLS && y < LINES) { -+ move(y, x); -+ curs_set(1); -+ /* it seems that curs_set(1) must always be called before -+ * curs_set(2) for the latter to have effect */ -+ if (!is_graphic_console()) -+ curs_set(2); -+ return; -+ } -+ } -+ -+ curs_set(0); -+} -+ -+/* generic keyboard conversion */ -+ -+#include "curses_keys.h" -+#include "keymaps.c" -+ -+static kbd_layout_t *kbd_layout = 0; -+static int keycode2keysym[CURSES_KEYS]; -+ -+static void curses_refresh(DisplayState *ds) -+{ -+ int chr, nextchr, keysym, keycode; -+ -+ if (invalidate) { -+ clear(); -+ refresh(); -+ curses_calc_pad(); -+ ds->width = FONT_WIDTH * width; -+ ds->height = FONT_HEIGHT * height; -+ vga_hw_invalidate(); -+ invalidate = 0; -+ } -+ -+ vga_hw_text_update(screen); -+ -+ nextchr = ERR; -+ while (1) { -+ /* while there are any pending key strokes to process */ -+ if (nextchr == ERR) -+ chr = getch(); -+ else { -+ chr = nextchr; -+ nextchr = ERR; -+ } -+ -+ if (chr == ERR) -+ break; -+ -+ /* this shouldn't occur when we use a custom SIGWINCH handler */ -+ if (chr == KEY_RESIZE) { -+ clear(); -+ refresh(); -+ curses_calc_pad(); -+ curses_update(ds, 0, 0, width, height); -+ ds->width = FONT_WIDTH * width; -+ ds->height = FONT_HEIGHT * height; -+ continue; -+ } -+ -+ keycode = curses2keycode[chr]; -+ if (keycode == -1) -+ continue; -+ -+ /* alt key */ -+ if (keycode == 1) { -+ nextchr = getch(); -+ -+ if (nextchr != ERR) { -+ keycode = curses2keycode[nextchr]; -+ nextchr = ERR; -+ if (keycode == -1) -+ continue; -+ -+ keycode |= ALT; -+ -+ /* process keys reserved for qemu */ -+ if (keycode >= QEMU_KEY_CONSOLE0 && -+ keycode < QEMU_KEY_CONSOLE0 + 9) { -+ erase(); -+ wnoutrefresh(stdscr); -+ console_select(keycode - QEMU_KEY_CONSOLE0); -+ -+ invalidate = 1; -+ continue; -+ } -+ } -+ } -+ -+ if (kbd_layout && !(keycode & GREY)) { -+ keysym = keycode2keysym[keycode & KEY_MASK]; -+ if (keysym == -1) -+ keysym = chr; -+ -+ keycode &= ~KEY_MASK; -+ keycode |= keysym2scancode(kbd_layout, keysym); -+ } -+ -+ if (is_graphic_console()) { -+ /* since terminals don't know about key press and release -+ * events, we need to emit both for each key received */ -+ if (keycode & SHIFT) -+ kbd_put_keycode(SHIFT_CODE); -+ if (keycode & CNTRL) -+ kbd_put_keycode(CNTRL_CODE); -+ if (keycode & ALT) -+ kbd_put_keycode(ALT_CODE); -+ if (keycode & GREY) -+ kbd_put_keycode(GREY_CODE); -+ kbd_put_keycode(keycode & KEY_MASK); -+ if (keycode & GREY) -+ kbd_put_keycode(GREY_CODE); -+ kbd_put_keycode((keycode & KEY_MASK) | KEY_RELEASE); -+ if (keycode & ALT) -+ kbd_put_keycode(ALT_CODE | KEY_RELEASE); -+ if (keycode & CNTRL) -+ kbd_put_keycode(CNTRL_CODE | KEY_RELEASE); -+ if (keycode & SHIFT) -+ kbd_put_keycode(SHIFT_CODE | KEY_RELEASE); -+ } else { -+ keysym = curses2keysym[chr]; -+ if (keysym == -1) -+ keysym = chr; -+ -+ kbd_put_keysym(keysym); -+ } -+ } -+} -+ -+static void curses_cleanup(void *opaque) -+{ -+ endwin(); -+} -+ -+static void curses_atexit(void) -+{ -+ curses_cleanup(NULL); -+} -+ -+static void curses_setup(void) -+{ -+ int i, colour_default[8] = { -+ COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, -+ COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE, -+ }; -+ -+ /* input as raw as possible, let everything be interpreted -+ * by the guest system */ -+ initscr(); noecho(); intrflush(stdscr, FALSE); -+ nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE); -+ start_color(); raw(); scrollok(stdscr, FALSE); -+ -+ for (i = 0; i < 64; i ++) -+ init_pair(i, colour_default[i & 7], colour_default[i >> 3]); -+} -+ -+static void curses_keyboard_setup(void) -+{ -+ int i, keycode, keysym; -+ -+#if defined(__APPLE__) -+ /* always use generic keymaps */ -+ if (!keyboard_layout) -+ keyboard_layout = "en-us"; -+#endif -+ if(keyboard_layout) { -+ kbd_layout = init_keyboard_layout(keyboard_layout); -+ if (!kbd_layout) -+ exit(1); -+ } -+ -+ for (i = 0; i < CURSES_KEYS; i ++) -+ keycode2keysym[i] = -1; -+ -+ for (i = 0; i < CURSES_KEYS; i ++) { -+ if (curses2keycode[i] == -1) -+ continue; -+ -+ keycode = curses2keycode[i] & KEY_MASK; -+ if (keycode2keysym[keycode] >= 0) -+ continue; -+ -+ for (keysym = 0; keysym < CURSES_KEYS; keysym ++) -+ if (curses2keycode[keysym] == keycode) { -+ keycode2keysym[keycode] = keysym; -+ break; -+ } -+ -+ if (keysym >= CURSES_KEYS) -+ keycode2keysym[keycode] = i; -+ } -+} -+ -+void curses_display_init(DisplayState *ds, int full_screen) -+{ -+#ifndef _WIN32 -+ if (!isatty(1)) { -+ fprintf(stderr, "We need a terminal output\n"); -+ exit(1); -+ } -+#endif -+ -+ curses_setup(); -+ curses_keyboard_setup(); -+ atexit(curses_atexit); -+ -+#ifndef _WIN32 -+ signal(SIGINT, SIG_DFL); -+ signal(SIGQUIT, SIG_DFL); -+#ifdef SIGWINCH -+ /* some curses implementations provide a handler, but we -+ * want to be sure this is handled regardless of the library */ -+ signal(SIGWINCH, curses_winch_handler); -+#endif -+#endif -+ -+ ds->data = (void *) screen; -+ ds->linesize = 0; -+ ds->depth = 0; -+ ds->width = 640; -+ ds->height = 400; -+ ds->dpy_update = curses_update; -+ ds->dpy_resize = curses_resize; -+ ds->dpy_refresh = curses_refresh; -+ ds->dpy_text_cursor = curses_cursor_position; -+ -+ invalidate = 1; -+ -+ /* Standard VGA initial text mode dimensions */ -+ curses_resize(ds, 80, 25); -+} -Index: qemu-0.9.1/curses_keys.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ qemu-0.9.1/curses_keys.h 2008-04-14 11:26:14.000000000 +0200 -@@ -0,0 +1,484 @@ -+/* -+ * Keycode and keysyms conversion tables for curses -+ * -+ * Copyright (c) 2005 Andrzej Zaborowski -+ * -+ * 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. -+ */ -+#define KEY_RELEASE 0x80 -+#define KEY_MASK 0x7f -+#define SHIFT_CODE 0x2a -+#define SHIFT 0x0080 -+#define GREY_CODE 0xe0 -+#define GREY 0x0100 -+#define CNTRL_CODE 0x1d -+#define CNTRL 0x0200 -+#define ALT_CODE 0x38 -+#define ALT 0x0400 -+ -+/* curses won't detect a Control + Alt + 1, so use Alt + 1 */ -+#define QEMU_KEY_CONSOLE0 (2 | ALT) /* (curses2keycode['1'] | ALT) */ -+ -+#define CURSES_KEYS KEY_MAX /* KEY_MAX defined in */ -+ -+int curses2keycode[CURSES_KEYS] = { -+ [0 ... (CURSES_KEYS - 1)] = -1, -+ -+ [0x01b] = 1, /* Escape */ -+ ['1'] = 2, -+ ['2'] = 3, -+ ['3'] = 4, -+ ['4'] = 5, -+ ['5'] = 6, -+ ['6'] = 7, -+ ['7'] = 8, -+ ['8'] = 9, -+ ['9'] = 10, -+ ['0'] = 11, -+ ['-'] = 12, -+ ['='] = 13, -+ [0x07f] = 14, /* Backspace */ -+ [0x107] = 14, /* Backspace */ -+ -+ ['\t'] = 15, /* Tab */ -+ ['q'] = 16, -+ ['w'] = 17, -+ ['e'] = 18, -+ ['r'] = 19, -+ ['t'] = 20, -+ ['y'] = 21, -+ ['u'] = 22, -+ ['i'] = 23, -+ ['o'] = 24, -+ ['p'] = 25, -+ ['['] = 26, -+ [']'] = 27, -+ ['\n'] = 28, /* Return */ -+ ['\r'] = 28, /* Return */ -+ [0x157] = 28, /* Return */ -+ -+ ['a'] = 30, -+ ['s'] = 31, -+ ['d'] = 32, -+ ['f'] = 33, -+ ['g'] = 34, -+ ['h'] = 35, -+ ['j'] = 36, -+ ['k'] = 37, -+ ['l'] = 38, -+ [';'] = 39, -+ ['\''] = 40, /* Single quote */ -+ ['`'] = 41, -+ ['\\'] = 43, /* Backslash */ -+ -+ ['z'] = 44, -+ ['x'] = 45, -+ ['c'] = 46, -+ ['v'] = 47, -+ ['b'] = 48, -+ ['n'] = 49, -+ ['m'] = 50, -+ [','] = 51, -+ ['.'] = 52, -+ ['/'] = 53, -+ -+ [' '] = 57, -+ -+ [0x109] = 59, /* Function Key 1 */ -+ [0x10a] = 60, /* Function Key 2 */ -+ [0x10b] = 61, /* Function Key 3 */ -+ [0x10c] = 62, /* Function Key 4 */ -+ [0x10d] = 63, /* Function Key 5 */ -+ [0x10e] = 64, /* Function Key 6 */ -+ [0x10f] = 65, /* Function Key 7 */ -+ [0x110] = 66, /* Function Key 8 */ -+ [0x111] = 67, /* Function Key 9 */ -+ [0x112] = 68, /* Function Key 10 */ -+ [0x113] = 87, /* Function Key 11 */ -+ [0x114] = 88, /* Function Key 12 */ -+ -+ [0x106] = 71 | GREY, /* Home */ -+ [0x103] = 72 | GREY, /* Up Arrow */ -+ [0x153] = 73 | GREY, /* Page Up */ -+ [0x104] = 75 | GREY, /* Left Arrow */ -+ [0x105] = 77 | GREY, /* Right Arrow */ -+ [0x168] = 79 | GREY, /* End */ -+ [0x102] = 80 | GREY, /* Down Arrow */ -+ [0x152] = 81 | GREY, /* Page Down */ -+ [0x14b] = 82 | GREY, /* Insert */ -+ [0x14a] = 83 | GREY, /* Delete */ -+ -+ ['!'] = 2 | SHIFT, -+ ['@'] = 3 | SHIFT, -+ ['#'] = 4 | SHIFT, -+ ['$'] = 5 | SHIFT, -+ ['%'] = 6 | SHIFT, -+ ['^'] = 7 | SHIFT, -+ ['&'] = 8 | SHIFT, -+ ['*'] = 9 | SHIFT, -+ ['('] = 10 | SHIFT, -+ [')'] = 11 | SHIFT, -+ ['_'] = 12 | SHIFT, -+ ['+'] = 13 | SHIFT, -+ -+ [0x161] = 15 | SHIFT, /* Shift + Tab */ -+ ['Q'] = 16 | SHIFT, -+ ['W'] = 17 | SHIFT, -+ ['E'] = 18 | SHIFT, -+ ['R'] = 19 | SHIFT, -+ ['T'] = 20 | SHIFT, -+ ['Y'] = 21 | SHIFT, -+ ['U'] = 22 | SHIFT, -+ ['I'] = 23 | SHIFT, -+ ['O'] = 24 | SHIFT, -+ ['P'] = 25 | SHIFT, -+ ['{'] = 26 | SHIFT, -+ ['}'] = 27 | SHIFT, -+ -+ ['A'] = 30 | SHIFT, -+ ['S'] = 31 | SHIFT, -+ ['D'] = 32 | SHIFT, -+ ['F'] = 33 | SHIFT, -+ ['G'] = 34 | SHIFT, -+ ['H'] = 35 | SHIFT, -+ ['J'] = 36 | SHIFT, -+ ['K'] = 37 | SHIFT, -+ ['L'] = 38 | SHIFT, -+ [':'] = 39 | SHIFT, -+ ['"'] = 40 | SHIFT, -+ ['~'] = 41 | SHIFT, -+ ['|'] = 43 | SHIFT, -+ -+ ['Z'] = 44 | SHIFT, -+ ['X'] = 45 | SHIFT, -+ ['C'] = 46 | SHIFT, -+ ['V'] = 47 | SHIFT, -+ ['B'] = 48 | SHIFT, -+ ['N'] = 49 | SHIFT, -+ ['M'] = 50 | SHIFT, -+ ['<'] = 51 | SHIFT, -+ ['>'] = 52 | SHIFT, -+ ['?'] = 53 | SHIFT, -+ -+ [0x115] = 59 | SHIFT, /* Shift + Function Key 1 */ -+ [0x116] = 60 | SHIFT, /* Shift + Function Key 2 */ -+ [0x117] = 61 | SHIFT, /* Shift + Function Key 3 */ -+ [0x118] = 62 | SHIFT, /* Shift + Function Key 4 */ -+ [0x119] = 63 | SHIFT, /* Shift + Function Key 5 */ -+ [0x11a] = 64 | SHIFT, /* Shift + Function Key 6 */ -+ [0x11b] = 65 | SHIFT, /* Shift + Function Key 7 */ -+ [0x11c] = 66 | SHIFT, /* Shift + Function Key 8 */ -+ -+ [0x011] = 16 | CNTRL, /* Control + q */ -+ [0x017] = 17 | CNTRL, /* Control + w */ -+ [0x005] = 18 | CNTRL, /* Control + e */ -+ [0x012] = 19 | CNTRL, /* Control + r */ -+ [0x014] = 20 | CNTRL, /* Control + t */ -+ [0x019] = 21 | CNTRL, /* Control + y */ -+ [0x015] = 22 | CNTRL, /* Control + u */ -+ [0x009] = 23 | CNTRL, /* Control + i */ -+ [0x00f] = 24 | CNTRL, /* Control + o */ -+ [0x010] = 25 | CNTRL, /* Control + p */ -+ -+ [0x001] = 30 | CNTRL, /* Control + a */ -+ [0x013] = 31 | CNTRL, /* Control + s */ -+ [0x004] = 32 | CNTRL, /* Control + d */ -+ [0x006] = 33 | CNTRL, /* Control + f */ -+ [0x007] = 34 | CNTRL, /* Control + g */ -+ [0x008] = 35 | CNTRL, /* Control + h */ -+ [0x00a] = 36 | CNTRL, /* Control + j */ -+ [0x00b] = 37 | CNTRL, /* Control + k */ -+ [0x00c] = 38 | CNTRL, /* Control + l */ -+ -+ [0x01a] = 44 | CNTRL, /* Control + z */ -+ [0x018] = 45 | CNTRL, /* Control + x */ -+ [0x003] = 46 | CNTRL, /* Control + c */ -+ [0x016] = 47 | CNTRL, /* Control + v */ -+ [0x002] = 48 | CNTRL, /* Control + b */ -+ [0x00e] = 49 | CNTRL, /* Control + n */ -+ /* Control + m collides with the keycode for Enter */ -+ -+}; -+ -+int curses2keysym[CURSES_KEYS] = { -+ [0 ... (CURSES_KEYS - 1)] = -1, -+ -+ ['\n'] = '\n', -+ ['\r'] = '\n', -+ -+ [0x07f] = QEMU_KEY_BACKSPACE, -+ -+ [0x102] = QEMU_KEY_DOWN, -+ [0x103] = QEMU_KEY_UP, -+ [0x104] = QEMU_KEY_LEFT, -+ [0x105] = QEMU_KEY_RIGHT, -+ [0x106] = QEMU_KEY_HOME, -+ [0x107] = QEMU_KEY_BACKSPACE, -+ -+ [0x14a] = QEMU_KEY_DELETE, -+ [0x152] = QEMU_KEY_PAGEDOWN, -+ [0x153] = QEMU_KEY_PAGEUP, -+ [0x157] = '\n', -+ [0x168] = QEMU_KEY_END, -+ -+}; -+ -+typedef struct { -+ const char* name; -+ int keysym; -+} name2keysym_t; -+ -+static name2keysym_t name2keysym[] = { -+ /* Plain ASCII */ -+ { "space", 0x020 }, -+ { "exclam", 0x021 }, -+ { "quotedbl", 0x022 }, -+ { "numbersign", 0x023 }, -+ { "dollar", 0x024 }, -+ { "percent", 0x025 }, -+ { "ampersand", 0x026 }, -+ { "apostrophe", 0x027 }, -+ { "parenleft", 0x028 }, -+ { "parenright", 0x029 }, -+ { "asterisk", 0x02a }, -+ { "plus", 0x02b }, -+ { "comma", 0x02c }, -+ { "minus", 0x02d }, -+ { "period", 0x02e }, -+ { "slash", 0x02f }, -+ { "0", 0x030 }, -+ { "1", 0x031 }, -+ { "2", 0x032 }, -+ { "3", 0x033 }, -+ { "4", 0x034 }, -+ { "5", 0x035 }, -+ { "6", 0x036 }, -+ { "7", 0x037 }, -+ { "8", 0x038 }, -+ { "9", 0x039 }, -+ { "colon", 0x03a }, -+ { "semicolon", 0x03b }, -+ { "less", 0x03c }, -+ { "equal", 0x03d }, -+ { "greater", 0x03e }, -+ { "question", 0x03f }, -+ { "at", 0x040 }, -+ { "A", 0x041 }, -+ { "B", 0x042 }, -+ { "C", 0x043 }, -+ { "D", 0x044 }, -+ { "E", 0x045 }, -+ { "F", 0x046 }, -+ { "G", 0x047 }, -+ { "H", 0x048 }, -+ { "I", 0x049 }, -+ { "J", 0x04a }, -+ { "K", 0x04b }, -+ { "L", 0x04c }, -+ { "M", 0x04d }, -+ { "N", 0x04e }, -+ { "O", 0x04f }, -+ { "P", 0x050 }, -+ { "Q", 0x051 }, -+ { "R", 0x052 }, -+ { "S", 0x053 }, -+ { "T", 0x054 }, -+ { "U", 0x055 }, -+ { "V", 0x056 }, -+ { "W", 0x057 }, -+ { "X", 0x058 }, -+ { "Y", 0x059 }, -+ { "Z", 0x05a }, -+ { "bracketleft", 0x05b }, -+ { "backslash", 0x05c }, -+ { "bracketright", 0x05d }, -+ { "asciicircum", 0x05e }, -+ { "underscore", 0x05f }, -+ { "grave", 0x060 }, -+ { "a", 0x061 }, -+ { "b", 0x062 }, -+ { "c", 0x063 }, -+ { "d", 0x064 }, -+ { "e", 0x065 }, -+ { "f", 0x066 }, -+ { "g", 0x067 }, -+ { "h", 0x068 }, -+ { "i", 0x069 }, -+ { "j", 0x06a }, -+ { "k", 0x06b }, -+ { "l", 0x06c }, -+ { "m", 0x06d }, -+ { "n", 0x06e }, -+ { "o", 0x06f }, -+ { "p", 0x070 }, -+ { "q", 0x071 }, -+ { "r", 0x072 }, -+ { "s", 0x073 }, -+ { "t", 0x074 }, -+ { "u", 0x075 }, -+ { "v", 0x076 }, -+ { "w", 0x077 }, -+ { "x", 0x078 }, -+ { "y", 0x079 }, -+ { "z", 0x07a }, -+ { "braceleft", 0x07b }, -+ { "bar", 0x07c }, -+ { "braceright", 0x07d }, -+ { "asciitilde", 0x07e }, -+ -+ /* Latin-1 extensions */ -+ { "nobreakspace", 0x0a0 }, -+ { "exclamdown", 0x0a1 }, -+ { "cent", 0x0a2 }, -+ { "sterling", 0x0a3 }, -+ { "currency", 0x0a4 }, -+ { "yen", 0x0a5 }, -+ { "brokenbar", 0x0a6 }, -+ { "section", 0x0a7 }, -+ { "diaeresis", 0x0a8 }, -+ { "copyright", 0x0a9 }, -+ { "ordfeminine", 0x0aa }, -+ { "guillemotleft", 0x0ab }, -+ { "notsign", 0x0ac }, -+ { "hyphen", 0x0ad }, -+ { "registered", 0x0ae }, -+ { "macron", 0x0af }, -+ { "degree", 0x0b0 }, -+ { "plusminus", 0x0b1 }, -+ { "twosuperior", 0x0b2 }, -+ { "threesuperior", 0x0b3 }, -+ { "acute", 0x0b4 }, -+ { "mu", 0x0b5 }, -+ { "paragraph", 0x0b6 }, -+ { "periodcentered", 0x0b7 }, -+ { "cedilla", 0x0b8 }, -+ { "onesuperior", 0x0b9 }, -+ { "masculine", 0x0ba }, -+ { "guillemotright", 0x0bb }, -+ { "onequarter", 0x0bc }, -+ { "onehalf", 0x0bd }, -+ { "threequarters", 0x0be }, -+ { "questiondown", 0x0bf }, -+ { "Agrave", 0x0c0 }, -+ { "Aacute", 0x0c1 }, -+ { "Acircumflex", 0x0c2 }, -+ { "Atilde", 0x0c3 }, -+ { "Adiaeresis", 0x0c4 }, -+ { "Aring", 0x0c5 }, -+ { "AE", 0x0c6 }, -+ { "Ccedilla", 0x0c7 }, -+ { "Egrave", 0x0c8 }, -+ { "Eacute", 0x0c9 }, -+ { "Ecircumflex", 0x0ca }, -+ { "Ediaeresis", 0x0cb }, -+ { "Igrave", 0x0cc }, -+ { "Iacute", 0x0cd }, -+ { "Icircumflex", 0x0ce }, -+ { "Idiaeresis", 0x0cf }, -+ { "ETH", 0x0d0 }, -+ { "Eth", 0x0d0 }, -+ { "Ntilde", 0x0d1 }, -+ { "Ograve", 0x0d2 }, -+ { "Oacute", 0x0d3 }, -+ { "Ocircumflex", 0x0d4 }, -+ { "Otilde", 0x0d5 }, -+ { "Odiaeresis", 0x0d6 }, -+ { "multiply", 0x0d7 }, -+ { "Ooblique", 0x0d8 }, -+ { "Oslash", 0x0d8 }, -+ { "Ugrave", 0x0d9 }, -+ { "Uacute", 0x0da }, -+ { "Ucircumflex", 0x0db }, -+ { "Udiaeresis", 0x0dc }, -+ { "Yacute", 0x0dd }, -+ { "THORN", 0x0de }, -+ { "Thorn", 0x0de }, -+ { "ssharp", 0x0df }, -+ { "agrave", 0x0e0 }, -+ { "aacute", 0x0e1 }, -+ { "acircumflex", 0x0e2 }, -+ { "atilde", 0x0e3 }, -+ { "adiaeresis", 0x0e4 }, -+ { "aring", 0x0e5 }, -+ { "ae", 0x0e6 }, -+ { "ccedilla", 0x0e7 }, -+ { "egrave", 0x0e8 }, -+ { "eacute", 0x0e9 }, -+ { "ecircumflex", 0x0ea }, -+ { "ediaeresis", 0x0eb }, -+ { "igrave", 0x0ec }, -+ { "iacute", 0x0ed }, -+ { "icircumflex", 0x0ee }, -+ { "idiaeresis", 0x0ef }, -+ { "eth", 0x0f0 }, -+ { "ntilde", 0x0f1 }, -+ { "ograve", 0x0f2 }, -+ { "oacute", 0x0f3 }, -+ { "ocircumflex", 0x0f4 }, -+ { "otilde", 0x0f5 }, -+ { "odiaeresis", 0x0f6 }, -+ { "division", 0x0f7 }, -+ { "oslash", 0x0f8 }, -+ { "ooblique", 0x0f8 }, -+ { "ugrave", 0x0f9 }, -+ { "uacute", 0x0fa }, -+ { "ucircumflex", 0x0fb }, -+ { "udiaeresis", 0x0fc }, -+ { "yacute", 0x0fd }, -+ { "thorn", 0x0fe }, -+ { "ydiaeresis", 0x0ff }, -+ -+ /* Special keys */ -+ { "BackSpace", 0x07f }, -+ { "Tab", '\t' }, -+ { "Return", '\r' }, -+ { "Right", 0x105 }, -+ { "Left", 0x104 }, -+ { "Up", 0x103 }, -+ { "Down", 0x102 }, -+ { "Page_Down", 0x152 }, -+ { "Page_Up", 0x153 }, -+ { "Insert", 0x14b }, -+ { "Delete", 0x14a }, -+ { "Home", 0x106 }, -+ { "End", 0x168 }, -+ { "F1", 0x109 }, -+ { "F2", 0x10a }, -+ { "F3", 0x10b }, -+ { "F4", 0x10c }, -+ { "F5", 0x10d }, -+ { "F6", 0x10e }, -+ { "F7", 0x10f }, -+ { "F8", 0x110 }, -+ { "F9", 0x111 }, -+ { "F10", 0x112 }, -+ { "F11", 0x113 }, -+ { "F12", 0x114 }, -+ { "F13", 0x115 }, -+ { "F14", 0x116 }, -+ { "F15", 0x117 }, -+ { "F16", 0x118 }, -+ { "F17", 0x119 }, -+ { "F18", 0x11a }, -+ { "F19", 0x11b }, -+ { "F20", 0x11c }, -+ { "Escape", 27 }, -+ -+ { 0, 0 }, -+}; -Index: qemu-0.9.1/hw/cirrus_vga.c -=================================================================== ---- qemu-0.9.1.orig/hw/cirrus_vga.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/cirrus_vga.c 2008-04-14 11:27:17.000000000 +0200 -@@ -3257,7 +3257,8 @@ - ds, vga_ram_base, vga_ram_offset, vga_ram_size); - cirrus_init_common(s, device_id, 1); - -- graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); -+ graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, -+ s->text_update, s); - - s->pci_dev = (PCIDevice *)d; - -Index: qemu-0.9.1/hw/jazz_led.c -=================================================================== ---- qemu-0.9.1.orig/hw/jazz_led.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/jazz_led.c 2008-04-14 11:26:14.000000000 +0200 -@@ -285,6 +285,22 @@ - printf("jazz_led_screen_dump() not implemented\n"); - } - -+static void jazz_led_text_update(void *opaque, console_ch_t *chardata) -+{ -+ LedState *s = opaque; -+ char buf[2]; -+ -+ dpy_cursor(s->ds, -1, -1); -+ dpy_resize(s->ds, 2, 1); -+ -+ /* TODO: draw the segments */ -+ snprintf(buf, 2, "%02hhx\n", s->segments); -+ console_write_ch(chardata++, 0x00200100 | buf[0]); -+ console_write_ch(chardata++, 0x00200100 | buf[1]); -+ -+ dpy_update(s->ds, 0, 0, 2, 1); -+} -+ - void jazz_led_init(DisplayState *ds, target_phys_addr_t base) - { - LedState *s; -@@ -301,5 +317,7 @@ - io = cpu_register_io_memory(0, led_read, led_write, s); - cpu_register_physical_memory(s->base, 1, io); - -- graphic_console_init(ds, jazz_led_update_display, jazz_led_invalidate_display, jazz_led_screen_dump, s); -+ graphic_console_init(ds, jazz_led_update_display, -+ jazz_led_invalidate_display, jazz_led_screen_dump, -+ jazz_led_text_update, s); - } -Index: qemu-0.9.1/hw/omap_lcdc.c -=================================================================== ---- qemu-0.9.1.orig/hw/omap_lcdc.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/omap_lcdc.c 2008-04-14 11:26:14.000000000 +0200 -@@ -495,7 +495,7 @@ - cpu_register_physical_memory(s->base, 0x100, iomemtype); - - graphic_console_init(ds, omap_update_display, -- omap_invalidate_display, omap_screen_dump, s); -+ omap_invalidate_display, omap_screen_dump, NULL, s); - - return s; - } -Index: qemu-0.9.1/hw/pl110.c -=================================================================== ---- qemu-0.9.1.orig/hw/pl110.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/pl110.c 2008-04-14 11:26:14.000000000 +0200 -@@ -426,7 +426,7 @@ - s->versatile = versatile; - s->irq = irq; - graphic_console_init(ds, pl110_update_display, pl110_invalidate_display, -- NULL, s); -+ NULL, NULL, s); - /* ??? Save/restore. */ - return s; - } -Index: qemu-0.9.1/hw/pxa2xx_lcd.c -=================================================================== ---- qemu-0.9.1.orig/hw/pxa2xx_lcd.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/pxa2xx_lcd.c 2008-04-14 11:26:14.000000000 +0200 -@@ -1002,7 +1002,7 @@ - cpu_register_physical_memory(base, 0x00100000, iomemtype); - - graphic_console_init(ds, pxa2xx_update_display, -- pxa2xx_invalidate_display, pxa2xx_screen_dump, s); -+ pxa2xx_invalidate_display, pxa2xx_screen_dump, NULL, s); - - switch (s->ds->depth) { - case 0: -Index: qemu-0.9.1/hw/ssd0303.c -=================================================================== ---- qemu-0.9.1.orig/hw/ssd0303.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/ssd0303.c 2008-04-14 11:26:14.000000000 +0200 -@@ -270,6 +270,6 @@ - s->i2c.recv = ssd0303_recv; - s->i2c.send = ssd0303_send; - graphic_console_init(ds, ssd0303_update_display, ssd0303_invalidate_display, -- NULL, s); -+ NULL, NULL, s); - dpy_resize(s->ds, 96 * MAGNIFY, 16 * MAGNIFY); - } -Index: qemu-0.9.1/hw/ssd0323.c -=================================================================== ---- qemu-0.9.1.orig/hw/ssd0323.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/ssd0323.c 2008-04-14 11:26:14.000000000 +0200 -@@ -280,7 +280,7 @@ - s = (ssd0323_state *)qemu_mallocz(sizeof(ssd0323_state)); - s->ds = ds; - graphic_console_init(ds, ssd0323_update_display, ssd0323_invalidate_display, -- NULL, s); -+ NULL, NULL, s); - dpy_resize(s->ds, 128 * MAGNIFY, 64 * MAGNIFY); - s->col_end = 63; - s->row_end = 79; -Index: qemu-0.9.1/hw/tcx.c -=================================================================== ---- qemu-0.9.1.orig/hw/tcx.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/tcx.c 2008-04-14 11:26:14.000000000 +0200 -@@ -537,12 +537,13 @@ - s->cplane_offset = vram_offset; - cpu_register_physical_memory(addr + 0x0a000000ULL, size, vram_offset); - graphic_console_init(s->ds, tcx24_update_display, -- tcx24_invalidate_display, tcx24_screen_dump, s); -+ tcx24_invalidate_display, -+ tcx24_screen_dump, NULL, s); - } else { - cpu_register_physical_memory(addr + 0x00300000ULL, TCX_THC_NREGS_8, - dummy_memory); - graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display, -- tcx_screen_dump, s); -+ tcx_screen_dump, NULL, s); - } - // NetBSD writes here even with 8-bit display - cpu_register_physical_memory(addr + 0x00301000ULL, TCX_THC_NREGS_24, -Index: qemu-0.9.1/hw/vga.c -=================================================================== ---- qemu-0.9.1.orig/hw/vga.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/vga.c 2008-04-14 11:26:14.000000000 +0200 -@@ -1152,7 +1152,7 @@ - } - - if (width != s->last_width || height != s->last_height || -- cw != s->last_cw || cheight != s->last_ch) { -+ cw != s->last_cw || cheight != s->last_ch || s->message_screen) { - s->last_scr_width = width * cw; - s->last_scr_height = height * cheight; - dpy_resize(s->ds, s->last_scr_width, s->last_scr_height); -@@ -1160,6 +1160,7 @@ - s->last_height = height; - s->last_ch = cheight; - s->last_cw = cw; -+ s->message_screen = 0; - full_update = 1; - } - cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr; -@@ -1660,6 +1661,167 @@ - s->graphic_mode = -1; /* force full update */ - } - -+#define TEXTMODE_X(x) ((x) % width) -+#define TEXTMODE_Y(x) ((x) / width) -+#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \ -+ ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1)) -+/* relay text rendering to the display driver -+ * instead of doing a full vga_update_display() */ -+static void vga_update_text(void *opaque, console_ch_t *chardata) -+{ -+ VGAState *s = (VGAState *) opaque; -+ int graphic_mode, i, cursor_offset, cursor_visible; -+ int cw, cheight, width, height, size, c_min, c_max; -+ uint32_t *src; -+ console_ch_t *dst, val; -+ char msg_buffer[80]; -+ int full_update; -+ full_update = 0; -+ -+ if (!(s->ar_index & 0x20)) { -+ graphic_mode = GMODE_BLANK; -+ } else { -+ graphic_mode = s->gr[6] & 1; -+ } -+ if (graphic_mode != s->graphic_mode) { -+ s->graphic_mode = graphic_mode; -+ full_update = 1; -+ } -+ if (s->last_width == -1) { -+ s->last_width = 0; -+ full_update = 1; -+ } -+ -+ switch (graphic_mode) { -+ case GMODE_TEXT: -+ /* TODO: update palette */ -+ full_update |= update_basic_params(s); -+ -+ /* total width & height */ -+ cheight = (s->cr[9] & 0x1f) + 1; -+ cw = 8; -+ if (!(s->sr[1] & 0x01)) -+ cw = 9; -+ if (s->sr[1] & 0x08) -+ cw = 16; /* NOTE: no 18 pixel wide */ -+ width = (s->cr[0x01] + 1); -+ if (s->cr[0x06] == 100) { -+ /* ugly hack for CGA 160x100x16 - explain me the logic */ -+ height = 100; -+ } else { -+ height = s->cr[0x12] | -+ ((s->cr[0x07] & 0x02) << 7) | -+ ((s->cr[0x07] & 0x40) << 3); -+ height = (height + 1) / cheight; -+ } -+ -+ size = (height * width); -+ if (size > CH_ATTR_SIZE) { -+ if (!full_update) -+ return; -+ -+ sprintf(msg_buffer, "%i x %i Text mode", width, height); -+ break; -+ } -+ -+ if (width != s->last_width || height != s->last_height || -+ cw != s->last_cw || cheight != s->last_ch || s->message_screen) { -+ s->last_scr_width = width * cw; -+ s->last_scr_height = height * cheight; -+ dpy_resize(s->ds, width, height); -+ s->last_width = width; -+ s->last_height = height; -+ s->last_ch = cheight; -+ s->last_cw = cw; -+ s->message_screen = 0; -+ full_update = 1; -+ } -+ -+ /* Update "hardware" cursor */ -+ cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr; -+ if (cursor_offset != s->cursor_offset || -+ s->cr[0xa] != s->cursor_start || -+ s->cr[0xb] != s->cursor_end || full_update) { -+ cursor_visible = !(s->cr[0xa] & 0x20); -+ if (cursor_visible && cursor_offset < size && cursor_offset >= 0) -+ dpy_cursor(s->ds, -+ TEXTMODE_X(cursor_offset), -+ TEXTMODE_Y(cursor_offset)); -+ else -+ dpy_cursor(s->ds, -1, -1); -+ s->cursor_offset = cursor_offset; -+ s->cursor_start = s->cr[0xa]; -+ s->cursor_end = s->cr[0xb]; -+ } -+ -+ src = (uint32_t *) s->vram_ptr + s->start_addr; -+ dst = chardata; -+ -+ if (full_update) { -+ for (i = 0; i < size; src ++, dst ++, i ++) -+ console_write_ch(dst, VMEM2CHTYPE(*src)); -+ -+ dpy_update(s->ds, 0, 0, width, height); -+ } else { -+ c_max = 0; -+ -+ for (i = 0; i < size; src ++, dst ++, i ++) { -+ console_write_ch(&val, VMEM2CHTYPE(*src)); -+ if (*dst != val) { -+ *dst = val; -+ c_max = i; -+ break; -+ } -+ } -+ c_min = i; -+ for (; i < size; src ++, dst ++, i ++) { -+ console_write_ch(&val, VMEM2CHTYPE(*src)); -+ if (*dst != val) { -+ *dst = val; -+ c_max = i; -+ } -+ } -+ -+ if (c_min <= c_max) { -+ i = TEXTMODE_Y(c_min); -+ dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1); -+ } -+ } -+ -+ return; -+ case GMODE_GRAPH: -+ if (!full_update) -+ return; -+ -+ s->get_resolution(s, &width, &height); -+ sprintf(msg_buffer, "%i x %i Graphic mode", width, height); -+ break; -+ case GMODE_BLANK: -+ default: -+ if (!full_update) -+ return; -+ -+ sprintf(msg_buffer, "VGA Blank mode"); -+ break; -+ } -+ -+ /* Display a message */ -+ dpy_cursor(s->ds, -1, -1); -+ dpy_resize(s->ds, 60, 3); -+ s->message_screen = 1; -+ -+ for (dst = chardata, i = 0; i < 60 * 3; i ++) -+ console_write_ch(dst ++, ' '); -+ -+ size = strlen(msg_buffer); -+ width = (60 - size) / 2; -+ dst = chardata + 60 + width; -+ for (i = 0; i < size; i ++) -+ console_write_ch(dst ++, 0x00200100 | msg_buffer[i]); -+ -+ dpy_update(s->ds, 0, 0, 60, 3); -+} -+ - static CPUReadMemoryFunc *vga_mem_read[3] = { - vga_mem_readb, - vga_mem_readw, -@@ -1830,6 +1992,7 @@ - s->update = vga_update_display; - s->invalidate = vga_invalidate_display; - s->screen_dump = vga_screen_dump; -+ s->text_update = vga_update_text; - } - - /* used by both ISA and PCI */ -@@ -1971,7 +2134,8 @@ - vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); - vga_init(s); - -- graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); -+ graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, -+ s->text_update, s); - - #ifdef CONFIG_BOCHS_VBE - /* XXX: use optimized standard vga accesses */ -@@ -1995,7 +2159,8 @@ - vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); - vga_mm_init(s, vram_base, ctrl_base, it_shift); - -- graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); -+ graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, -+ s->text_update, s); - - #ifdef CONFIG_BOCHS_VBE - /* XXX: use optimized standard vga accesses */ -@@ -2023,7 +2188,8 @@ - vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); - vga_init(s); - -- graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); -+ graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, -+ s->text_update, s); - - s->pci_dev = &d->dev; - -Index: qemu-0.9.1/hw/vga_int.h -=================================================================== ---- qemu-0.9.1.orig/hw/vga_int.h 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/vga_int.h 2008-04-14 11:26:14.000000000 +0200 -@@ -129,6 +129,7 @@ - uint32_t line_compare; \ - uint32_t start_addr; \ - uint32_t plane_updated; \ -+ int message_screen; \ - uint8_t last_cw, last_ch; \ - uint32_t last_width, last_height; /* in chars or pixels */ \ - uint32_t last_scr_width, last_scr_height; /* in pixels */ \ -@@ -139,6 +140,7 @@ - vga_hw_update_ptr update; \ - vga_hw_invalidate_ptr invalidate; \ - vga_hw_screen_dump_ptr screen_dump; \ -+ vga_hw_text_update_ptr text_update; \ - /* hardware mouse cursor support */ \ - uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32]; \ - void (*cursor_invalidate)(struct VGAState *s); \ -Index: qemu-0.9.1/hw/vmware_vga.c -=================================================================== ---- qemu-0.9.1.orig/hw/vmware_vga.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/vmware_vga.c 2008-04-14 11:26:14.000000000 +0200 -@@ -949,6 +949,14 @@ - } - } - -+static void vmsvga_text_update(void *opaque, console_ch_t *chardata) -+{ -+ struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; -+ -+ if (s->text_update) -+ s->text_update(opaque, chardata); -+} -+ - #ifdef DIRECT_VRAM - static uint32_t vmsvga_vram_readb(void *opaque, target_phys_addr_t addr) - { -@@ -1114,7 +1122,8 @@ - 1, 4, vmsvga_bios_write, s); - - graphic_console_init(ds, vmsvga_update_display, -- vmsvga_invalidate_display, vmsvga_screen_dump, s); -+ vmsvga_invalidate_display, vmsvga_screen_dump, -+ vmsvga_text_update, s); - - #ifdef EMBED_STDVGA - vga_common_init((VGAState *) s, ds, -Index: qemu-0.9.1/monitor.c -=================================================================== ---- qemu-0.9.1.orig/monitor.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/monitor.c 2008-04-14 11:26:14.000000000 +0200 -@@ -824,6 +824,8 @@ - { 0x31, "n" }, - { 0x32, "m" }, - -+ { 0x37, "asterisk" }, -+ - { 0x39, "spc" }, - { 0x3a, "caps_lock" }, - { 0x3b, "f1" }, -Index: qemu-0.9.1/vl.c -=================================================================== ---- qemu-0.9.1.orig/vl.c 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/vl.c 2008-04-14 11:27:19.000000000 +0200 -@@ -172,6 +172,7 @@ - int vga_ram_size; - static DisplayState display_state; - int nographic; -+int curses; - const char* keyboard_layout = NULL; - int64_t ticks_per_sec; - int ram_size; -@@ -7608,6 +7609,9 @@ - " (default is CL-GD5446 PCI VGA)\n" - "-no-acpi disable ACPI\n" - #endif -+#ifdef CONFIG_CURSES -+ "-curses use a curses/ncurses interface instead of SDL\n" -+#endif - "-no-reboot exit instead of rebooting\n" - "-loadvm file start right away with a saved state (loadvm in monitor)\n" - "-vnc display start a VNC server on display\n" -@@ -7712,6 +7716,7 @@ - QEMU_OPTION_smp, - QEMU_OPTION_vnc, - QEMU_OPTION_no_acpi, -+ QEMU_OPTION_curses, - QEMU_OPTION_no_reboot, - QEMU_OPTION_show_cursor, - QEMU_OPTION_daemonize, -@@ -7808,6 +7813,9 @@ - { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, - { "smp", HAS_ARG, QEMU_OPTION_smp }, - { "vnc", HAS_ARG, QEMU_OPTION_vnc }, -+#ifdef CONFIG_CURSES -+ { "curses", 0, QEMU_OPTION_curses }, -+#endif - - /* temporary options */ - { "usb", 0, QEMU_OPTION_usb }, -@@ -8134,6 +8142,7 @@ - #endif - snapshot = 0; - nographic = 0; -+ curses = 0; - kernel_filename = NULL; - kernel_cmdline = ""; - cyls = heads = secs = 0; -@@ -8310,6 +8319,11 @@ - pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); - nographic = 1; - break; -+#ifdef CONFIG_CURSES -+ case QEMU_OPTION_curses: -+ curses = 1; -+ break; -+#endif - case QEMU_OPTION_portrait: - graphic_rotate = 1; - break; -@@ -8850,13 +8864,23 @@ - /* terminal init */ - memset(&display_state, 0, sizeof(display_state)); - if (nographic) { -+ if (curses) { -+ fprintf(stderr, "fatal: -nographic can't be used with -curses\n"); -+ exit(1); -+ } - /* nearly nothing to do */ - dumb_display_init(ds); - } else if (vnc_display != NULL) { - vnc_display_init(ds); - if (vnc_display_open(ds, vnc_display) < 0) - exit(1); -- } else { -+ } else -+#if defined(CONFIG_CURSES) -+ if (curses) { -+ curses_display_init(ds, full_screen); -+ } else -+#endif -+ { - #if defined(CONFIG_SDL) - sdl_display_init(ds, full_screen, no_frame); - #elif defined(CONFIG_COCOA) -Index: qemu-0.9.1/vnc.c -=================================================================== ---- qemu-0.9.1.orig/vnc.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/vnc.c 2008-04-14 11:26:14.000000000 +0200 -@@ -954,6 +954,7 @@ - return; - } - break; -+ case 0x3a: /* CapsLock */ - case 0x45: /* NumLock */ - if (!down) - vs->modifiers_state[keycode] ^= 1; -Index: qemu-0.9.1/qemu-doc.texi -=================================================================== ---- qemu-0.9.1.orig/qemu-doc.texi 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/qemu-doc.texi 2008-04-14 11:27:19.000000000 +0200 -@@ -390,6 +390,12 @@ - the console. Therefore, you can still use QEMU to debug a Linux kernel - with a serial console. - -+@item -curses -+ -+Normally, QEMU uses SDL to display the VGA output. With this option, -+QEMU can display the VGA output when in text mode using a -+curses/ncurses interface. Nothing is displayed in graphical mode. -+ - @item -no-frame - - Do not use decorations for SDL windows and start them using the whole diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/81_mips32r2_fpu.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/81_mips32r2_fpu.patch --- qemu-0.9.1/debian/patches/81_mips32r2_fpu.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/81_mips32r2_fpu.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,19 +0,0 @@ -commit e11972fd3238aa5b3847cdc530afe1c7319ffce2 -Author: ths -Date: Wed Jan 9 12:03:22 2008 +0000 - - Fix typo which broke MIPS32R2 64-bit FPU support. - -Index: qemu-0.9.1/target-mips/exec.h -=================================================================== ---- qemu-0.9.1.orig/target-mips/exec.h 2008-01-06 20:38:45.000000000 +0100 -+++ qemu-0.9.1/target-mips/exec.h 2008-04-14 11:26:14.000000000 +0200 -@@ -258,7 +258,7 @@ - if (env->CP0_Status & (1 << CP0St_FR)) - env->hflags |= MIPS_HFLAG_F64; - if (env->insn_flags & ISA_MIPS32R2) { -- if (env->fpu->fcr0 & FCR0_F64) -+ if (env->fpu->fcr0 & (1 << FCR0_F64)) - env->hflags |= MIPS_HFLAG_COP1X; - } else if (env->insn_flags & ISA_MIPS32) { - if (env->hflags & MIPS_HFLAG_64) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/82_mips_abs.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/82_mips_abs.patch --- qemu-0.9.1/debian/patches/82_mips_abs.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/82_mips_abs.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,24 +0,0 @@ -commit fcb2adefba1ccba4b6eaf27750970d654edd89c8 -Author: ths -Date: Tue Jan 8 18:11:08 2008 +0000 - - Fix broken absoluteness check for cabs.d.*. - - - git-svn-id: svn+ssh://svn.savannah.nongnu.org/qemu/trunk@3900 c046a42c-6fe2-441c-8c8c-71466251a162 - -Index: qemu-0.9.1/target-mips/op_helper.c -=================================================================== ---- qemu-0.9.1.orig/target-mips/op_helper.c 2008-01-06 20:38:45.000000000 +0100 -+++ qemu-0.9.1/target-mips/op_helper.c 2008-04-14 11:26:14.000000000 +0200 -@@ -1250,8 +1250,8 @@ - void do_cmpabs_d_ ## op (long cc) \ - { \ - int c; \ -- FDT0 = float64_chs(FDT0); \ -- FDT1 = float64_chs(FDT1); \ -+ FDT0 = float64_abs(FDT0); \ -+ FDT1 = float64_abs(FDT1); \ - c = cond; \ - update_fcr31(); \ - if (c) \ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/83_usb-serial.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/83_usb-serial.patch --- qemu-0.9.1/debian/patches/83_usb-serial.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/83_usb-serial.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,800 +0,0 @@ -commit c4ca814904a59f51ae30b64de4c62848f300f17e -Author: balrog -Date: Mon Jan 14 03:41:02 2008 +0000 - - USB-to-serial device (Samuel Thibault). - - - git-svn-id: svn+ssh://svn.savannah.nongnu.org/qemu/trunk@3914 c046a42c-6fe2-441c-8c8c-71466251a162 - -Index: qemu-0.9.1/Makefile -=================================================================== ---- qemu-0.9.1.orig/Makefile 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/Makefile 2008-04-14 11:27:17.000000000 +0200 -@@ -57,7 +57,7 @@ - OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o - OBJS+=scsi-disk.o cdrom.o - OBJS+=scsi-generic.o --OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o -+OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o usb-serial.o - OBJS+=sd.o ssi-sd.o - - ifdef CONFIG_WIN32 -Index: qemu-0.9.1/hw/usb-serial.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ qemu-0.9.1/hw/usb-serial.c 2008-04-14 11:26:14.000000000 +0200 -@@ -0,0 +1,549 @@ -+/* -+ * FTDI FT232BM Device emulation -+ * -+ * Copyright (c) 2006 CodeSourcery. -+ * Copyright (c) 2008 Samuel Thibault -+ * Written by Paul Brook, reused for FTDI by Samuel Thibault -+ * -+ * This code is licenced under the LGPL. -+ */ -+ -+#include "qemu-common.h" -+#include "usb.h" -+#include "qemu-char.h" -+ -+//#define DEBUG_Serial -+ -+#ifdef DEBUG_Serial -+#define DPRINTF(fmt, args...) \ -+do { printf("usb-serial: " fmt , ##args); } while (0) -+#else -+#define DPRINTF(fmt, args...) do {} while(0) -+#endif -+ -+#define RECV_BUF 384 -+#define SEND_BUF 128 // Not used for now -+ -+/* Commands */ -+#define FTDI_RESET 0 -+#define FTDI_SET_MDM_CTRL 1 -+#define FTDI_SET_FLOW_CTRL 2 -+#define FTDI_SET_BAUD 3 -+#define FTDI_SET_DATA 4 -+#define FTDI_GET_MDM_ST 5 -+#define FTDI_SET_EVENT_CHR 6 -+#define FTDI_SET_ERROR_CHR 7 -+#define FTDI_SET_LATENCY 9 -+#define FTDI_GET_LATENCY 10 -+ -+#define DeviceOutVendor ((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8) -+#define DeviceInVendor ((USB_DIR_IN |USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8) -+ -+/* RESET */ -+ -+#define FTDI_RESET_SIO 0 -+#define FTDI_RESET_RX 1 -+#define FTDI_RESET_TX 2 -+ -+/* SET_MDM_CTRL */ -+ -+#define FTDI_MDM_CTRL 3 -+#define FTDI_DTR 1 -+#define FTDI_RTS 2 -+ -+/* SET_FLOW_CTRL */ -+ -+#define FTDI_RTS_CTS_HS 1 -+#define FTDI_DTR_DSR_HS 2 -+#define FTDI_XON_XOFF_HS 4 -+ -+/* SET_DATA */ -+ -+#define FTDI_PARITY (0x7 << 8) -+#define FTDI_ODD (0x1 << 8) -+#define FTDI_EVEN (0x2 << 8) -+#define FTDI_MARK (0x3 << 8) -+#define FTDI_SPACE (0x4 << 8) -+ -+#define FTDI_STOP (0x3 << 11) -+#define FTDI_STOP1 (0x0 << 11) -+#define FTDI_STOP15 (0x1 << 11) -+#define FTDI_STOP2 (0x2 << 11) -+ -+/* GET_MDM_ST */ -+/* TODO: should be sent every 40ms */ -+#define FTDI_CTS (1<<4) // CTS line status -+#define FTDI_DSR (1<<5) // DSR line status -+#define FTDI_RI (1<<6) // RI line status -+#define FTDI_RLSD (1<<7) // Receive Line Signal Detect -+ -+/* Status */ -+ -+#define FTDI_DR (1<<0) // Data Ready -+#define FTDI_OE (1<<1) // Overrun Err -+#define FTDI_PE (1<<2) // Parity Err -+#define FTDI_FE (1<<3) // Framing Err -+#define FTDI_BI (1<<4) // Break Interrupt -+#define FTDI_THRE (1<<5) // Transmitter Holding Register -+#define FTDI_TEMT (1<<6) // Transmitter Empty -+#define FTDI_FIFO (1<<7) // Error in FIFO -+ -+typedef struct { -+ USBDevice dev; -+ uint16_t vendorid; -+ uint16_t productid; -+ uint8_t recv_buf[RECV_BUF]; -+ uint8_t recv_ptr; -+ uint8_t recv_used; -+ uint8_t send_buf[SEND_BUF]; -+ uint8_t event_chr; -+ uint8_t error_chr; -+ uint8_t event_trigger; -+ uint8_t lines; -+ QEMUSerialSetParams params; -+ int latency; /* ms */ -+ CharDriverState *cs; -+} USBSerialState; -+ -+static const uint8_t qemu_serial_dev_descriptor[] = { -+ 0x12, /* u8 bLength; */ -+ 0x01, /* u8 bDescriptorType; Device */ -+ 0x00, 0x02, /* u16 bcdUSB; v2.0 */ -+ -+ 0x00, /* u8 bDeviceClass; */ -+ 0x00, /* u8 bDeviceSubClass; */ -+ 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ -+ 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ -+ -+ /* Vendor and product id are arbitrary. */ -+ 0x03, 0x04, /* u16 idVendor; */ -+ 0x00, 0xFF, /* u16 idProduct; */ -+ 0x00, 0x04, /* u16 bcdDevice */ -+ -+ 0x01, /* u8 iManufacturer; */ -+ 0x02, /* u8 iProduct; */ -+ 0x03, /* u8 iSerialNumber; */ -+ 0x01 /* u8 bNumConfigurations; */ -+}; -+ -+static const uint8_t qemu_serial_config_descriptor[] = { -+ -+ /* one configuration */ -+ 0x09, /* u8 bLength; */ -+ 0x02, /* u8 bDescriptorType; Configuration */ -+ 0x20, 0x00, /* u16 wTotalLength; */ -+ 0x01, /* u8 bNumInterfaces; (1) */ -+ 0x01, /* u8 bConfigurationValue; */ -+ 0x00, /* u8 iConfiguration; */ -+ 0x80, /* u8 bmAttributes; -+ Bit 7: must be set, -+ 6: Self-powered, -+ 5: Remote wakeup, -+ 4..0: resvd */ -+ 100/2, /* u8 MaxPower; */ -+ -+ /* one interface */ -+ 0x09, /* u8 if_bLength; */ -+ 0x04, /* u8 if_bDescriptorType; Interface */ -+ 0x00, /* u8 if_bInterfaceNumber; */ -+ 0x00, /* u8 if_bAlternateSetting; */ -+ 0x02, /* u8 if_bNumEndpoints; */ -+ 0xff, /* u8 if_bInterfaceClass; Vendor Specific */ -+ 0xff, /* u8 if_bInterfaceSubClass; Vendor Specific */ -+ 0xff, /* u8 if_bInterfaceProtocol; Vendor Specific */ -+ 0x02, /* u8 if_iInterface; */ -+ -+ /* Bulk-In endpoint */ -+ 0x07, /* u8 ep_bLength; */ -+ 0x05, /* u8 ep_bDescriptorType; Endpoint */ -+ 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ -+ 0x02, /* u8 ep_bmAttributes; Bulk */ -+ 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ -+ 0x00, /* u8 ep_bInterval; */ -+ -+ /* Bulk-Out endpoint */ -+ 0x07, /* u8 ep_bLength; */ -+ 0x05, /* u8 ep_bDescriptorType; Endpoint */ -+ 0x02, /* u8 ep_bEndpointAddress; OUT Endpoint 2 */ -+ 0x02, /* u8 ep_bmAttributes; Bulk */ -+ 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ -+ 0x00 /* u8 ep_bInterval; */ -+}; -+ -+static void usb_serial_reset(USBSerialState *s) -+{ -+ /* TODO: Set flow control to none */ -+ s->event_chr = 0x0d; -+ s->event_trigger = 0; -+ s->recv_ptr = 0; -+ s->recv_used = 0; -+ /* TODO: purge in char driver */ -+ s->lines &= ~(FTDI_DTR|FTDI_RTS); -+} -+ -+static void usb_serial_handle_reset(USBDevice *dev) -+{ -+ USBSerialState *s = (USBSerialState *)dev; -+ -+ DPRINTF("Reset\n"); -+ -+ usb_serial_reset(s); -+ /* TODO: Reset char device, send BREAK? */ -+} -+ -+static int usb_serial_handle_control(USBDevice *dev, int request, int value, -+ int index, int length, uint8_t *data) -+{ -+ USBSerialState *s = (USBSerialState *)dev; -+ int ret = 0; -+ -+ //DPRINTF("got control %x, value %x\n",request, value); -+ switch (request) { -+ case DeviceRequest | USB_REQ_GET_STATUS: -+ data[0] = (0 << USB_DEVICE_SELF_POWERED) | -+ (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); -+ data[1] = 0x00; -+ ret = 2; -+ break; -+ case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: -+ if (value == USB_DEVICE_REMOTE_WAKEUP) { -+ dev->remote_wakeup = 0; -+ } else { -+ goto fail; -+ } -+ ret = 0; -+ break; -+ case DeviceOutRequest | USB_REQ_SET_FEATURE: -+ if (value == USB_DEVICE_REMOTE_WAKEUP) { -+ dev->remote_wakeup = 1; -+ } else { -+ goto fail; -+ } -+ ret = 0; -+ break; -+ case DeviceOutRequest | USB_REQ_SET_ADDRESS: -+ dev->addr = value; -+ ret = 0; -+ break; -+ case DeviceRequest | USB_REQ_GET_DESCRIPTOR: -+ switch(value >> 8) { -+ case USB_DT_DEVICE: -+ memcpy(data, qemu_serial_dev_descriptor, -+ sizeof(qemu_serial_dev_descriptor)); -+ data[8] = s->vendorid & 0xff; -+ data[9] = ((s->vendorid) >> 8) & 0xff; -+ data[10] = s->productid & 0xff; -+ data[11] = ((s->productid) >> 8) & 0xff; -+ ret = sizeof(qemu_serial_dev_descriptor); -+ break; -+ case USB_DT_CONFIG: -+ memcpy(data, qemu_serial_config_descriptor, -+ sizeof(qemu_serial_config_descriptor)); -+ ret = sizeof(qemu_serial_config_descriptor); -+ break; -+ case USB_DT_STRING: -+ switch(value & 0xff) { -+ case 0: -+ /* language ids */ -+ data[0] = 4; -+ data[1] = 3; -+ data[2] = 0x09; -+ data[3] = 0x04; -+ ret = 4; -+ break; -+ case 1: -+ /* vendor description */ -+ ret = set_usb_string(data, "QEMU " QEMU_VERSION); -+ break; -+ case 2: -+ /* product description */ -+ ret = set_usb_string(data, "QEMU USB SERIAL"); -+ break; -+ case 3: -+ /* serial number */ -+ ret = set_usb_string(data, "1"); -+ break; -+ default: -+ goto fail; -+ } -+ break; -+ default: -+ goto fail; -+ } -+ break; -+ case DeviceRequest | USB_REQ_GET_CONFIGURATION: -+ data[0] = 1; -+ ret = 1; -+ break; -+ case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: -+ ret = 0; -+ break; -+ case DeviceRequest | USB_REQ_GET_INTERFACE: -+ data[0] = 0; -+ ret = 1; -+ break; -+ case InterfaceOutRequest | USB_REQ_SET_INTERFACE: -+ ret = 0; -+ break; -+ case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: -+ ret = 0; -+ break; -+ -+ /* Class specific requests. */ -+ case DeviceOutVendor | FTDI_RESET: -+ switch (value) { -+ case FTDI_RESET_SIO: -+ usb_serial_reset(s); -+ break; -+ case FTDI_RESET_RX: -+ s->recv_ptr = 0; -+ s->recv_used = 0; -+ /* TODO: purge from char device */ -+ break; -+ case FTDI_RESET_TX: -+ /* TODO: purge from char device */ -+ break; -+ } -+ break; -+ case DeviceOutVendor | FTDI_SET_MDM_CTRL: -+ s->lines = value & FTDI_MDM_CTRL; -+ break; -+ case DeviceOutVendor | FTDI_SET_FLOW_CTRL: -+ /* TODO: ioctl */ -+ break; -+ case DeviceOutVendor | FTDI_SET_BAUD: { -+ static const int subdivisors8[8] = { 0, 4, 2, 1, 3, 5, 6, 7 }; -+ int subdivisor8 = subdivisors8[((value & 0xc000) >> 14) -+ | ((index & 1) << 2)]; -+ int divisor = value & 0x3fff; -+ -+ /* chip special cases */ -+ if (divisor == 1 && subdivisor8 == 0) -+ subdivisor8 = 4; -+ if (divisor == 0 && subdivisor8 == 0) -+ divisor = 1; -+ -+ s->params.speed = (48000000 / 2) / (8 * divisor + subdivisor8); -+ qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params); -+ break; -+ } -+ case DeviceOutVendor | FTDI_SET_DATA: -+ switch (value & FTDI_PARITY) { -+ case 0: -+ s->params.parity = 'N'; -+ break; -+ case FTDI_ODD: -+ s->params.parity = 'O'; -+ break; -+ case FTDI_EVEN: -+ s->params.parity = 'E'; -+ break; -+ default: -+ DPRINTF("unsupported parity %d\n", value & FTDI_PARITY); -+ goto fail; -+ } -+ switch (value & FTDI_STOP) { -+ case FTDI_STOP1: -+ s->params.stop_bits = 1; -+ break; -+ case FTDI_STOP2: -+ s->params.stop_bits = 2; -+ break; -+ default: -+ DPRINTF("unsupported stop bits %d\n", value & FTDI_STOP); -+ goto fail; -+ } -+ qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params); -+ /* TODO: TX ON/OFF */ -+ break; -+ case DeviceInVendor | FTDI_GET_MDM_ST: -+ /* TODO: return modem status */ -+ data[0] = 0; -+ ret = 1; -+ break; -+ case DeviceOutVendor | FTDI_SET_EVENT_CHR: -+ /* TODO: handle it */ -+ s->event_chr = value; -+ break; -+ case DeviceOutVendor | FTDI_SET_ERROR_CHR: -+ /* TODO: handle it */ -+ s->error_chr = value; -+ break; -+ case DeviceOutVendor | FTDI_SET_LATENCY: -+ s->latency = value; -+ break; -+ case DeviceInVendor | FTDI_GET_LATENCY: -+ data[0] = s->latency; -+ ret = 1; -+ break; -+ default: -+ fail: -+ DPRINTF("got unsupported/bogus control %x, value %x\n", request, value); -+ ret = USB_RET_STALL; -+ break; -+ } -+ return ret; -+} -+ -+static int usb_serial_handle_data(USBDevice *dev, USBPacket *p) -+{ -+ USBSerialState *s = (USBSerialState *)dev; -+ int ret = 0; -+ uint8_t devep = p->devep; -+ uint8_t *data = p->data; -+ int len = p->len; -+ int first_len; -+ -+ switch (p->pid) { -+ case USB_TOKEN_OUT: -+ if (devep != 2) -+ goto fail; -+ qemu_chr_write(s->cs, data, len); -+ break; -+ -+ case USB_TOKEN_IN: -+ if (devep != 1) -+ goto fail; -+ first_len = RECV_BUF - s->recv_ptr; -+ if (len <= 2) { -+ ret = USB_RET_NAK; -+ break; -+ } -+ /* TODO: Report serial line status */ -+ *data++ = 0; -+ *data++ = 0; -+ len -= 2; -+ if (len > s->recv_used) -+ len = s->recv_used; -+ if (!len) { -+ ret = USB_RET_NAK; -+ break; -+ } -+ if (first_len > len) -+ first_len = len; -+ memcpy(data, s->recv_buf + s->recv_ptr, first_len); -+ if (len > first_len) -+ memcpy(data + first_len, s->recv_buf, len - first_len); -+ s->recv_used -= len; -+ s->recv_ptr = (s->recv_ptr + len) % RECV_BUF; -+ ret = len + 2; -+ break; -+ -+ default: -+ DPRINTF("Bad token\n"); -+ fail: -+ ret = USB_RET_STALL; -+ break; -+ } -+ -+ return ret; -+} -+ -+static void usb_serial_handle_destroy(USBDevice *dev) -+{ -+ USBSerialState *s = (USBSerialState *)dev; -+ -+ qemu_chr_close(s->cs); -+ qemu_free(s); -+} -+ -+int usb_serial_can_read(void *opaque) -+{ -+ USBSerialState *s = opaque; -+ return RECV_BUF - s->recv_used; -+} -+ -+void usb_serial_read(void *opaque, const uint8_t *buf, int size) -+{ -+ USBSerialState *s = opaque; -+ int first_size = RECV_BUF - s->recv_ptr; -+ if (first_size > size) -+ first_size = size; -+ memcpy(s->recv_buf + s->recv_ptr + s->recv_used, buf, first_size); -+ if (size > first_size) -+ memcpy(s->recv_buf, buf + first_size, size - first_size); -+ s->recv_used += size; -+} -+ -+void usb_serial_event(void *opaque, int event) -+{ -+ USBSerialState *s = opaque; -+ -+ switch (event) { -+ case CHR_EVENT_BREAK: -+ /* TODO: Send Break to USB */ -+ break; -+ case CHR_EVENT_FOCUS: -+ break; -+ case CHR_EVENT_RESET: -+ usb_serial_reset(s); -+ /* TODO: Reset USB port */ -+ break; -+ } -+} -+ -+USBDevice *usb_serial_init(const char *filename) -+{ -+ USBSerialState *s; -+ CharDriverState *cdrv; -+ unsigned short vendorid = 0x0403, productid = 0x6001; -+ -+ while (*filename && *filename != ':') { -+ const char *p; -+ char *e; -+ if (strstart(filename, "vendorid=", &p)) { -+ vendorid = strtol(p, &e, 16); -+ if (e == p || (*e && *e != ',' && *e != ':')) { -+ printf("bogus vendor ID %s\n", p); -+ return NULL; -+ } -+ filename = e; -+ } else if (strstart(filename, "productid=", &p)) { -+ productid = strtol(p, &e, 16); -+ if (e == p || (*e && *e != ',' && *e != ':')) { -+ printf("bogus product ID %s\n", p); -+ return NULL; -+ } -+ filename = e; -+ } else { -+ printf("unrecognized serial USB option %s\n", filename); -+ return NULL; -+ } -+ while(*filename == ',') -+ filename++; -+ } -+ if (!*filename) { -+ printf("character device specification needed\n"); -+ return NULL; -+ } -+ filename++; -+ s = qemu_mallocz(sizeof(USBSerialState)); -+ if (!s) -+ return NULL; -+ -+ cdrv = qemu_chr_open(filename); -+ if (!cdrv) -+ goto fail; -+ s->cs = cdrv; -+ qemu_chr_add_handlers(cdrv, usb_serial_can_read, usb_serial_read, usb_serial_event, s); -+ -+ s->dev.speed = USB_SPEED_FULL; -+ s->dev.handle_packet = usb_generic_handle_packet; -+ -+ s->dev.handle_reset = usb_serial_handle_reset; -+ s->dev.handle_control = usb_serial_handle_control; -+ s->dev.handle_data = usb_serial_handle_data; -+ s->dev.handle_destroy = usb_serial_handle_destroy; -+ -+ s->vendorid = vendorid; -+ s->productid = productid; -+ -+ snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Serial(%.16s)", -+ filename); -+ -+ usb_serial_handle_reset((USBDevice *)s); -+ return (USBDevice *)s; -+ fail: -+ qemu_free(s); -+ return NULL; -+} -Index: qemu-0.9.1/hw/usb.h -=================================================================== ---- qemu-0.9.1.orig/hw/usb.h 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/usb.h 2008-04-14 11:26:14.000000000 +0200 -@@ -217,6 +217,9 @@ - /* usb-wacom.c */ - USBDevice *usb_wacom_init(void); - -+/* usb-serial.c */ -+USBDevice *usb_serial_init(const char *filename); -+ - /* usb ports of the VM */ - - void qemu_register_usb_port(USBPort *port, void *opaque, int index, -Index: qemu-0.9.1/vl.c -=================================================================== ---- qemu-0.9.1.orig/vl.c 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/vl.c 2008-04-14 11:27:17.000000000 +0200 -@@ -2051,6 +2051,20 @@ - } - } - -+static void fd_chr_close(struct CharDriverState *chr) -+{ -+ FDCharDriver *s = chr->opaque; -+ -+ if (s->fd_in >= 0) { -+ if (nographic && s->fd_in == 0) { -+ } else { -+ qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL); -+ } -+ } -+ -+ qemu_free(s); -+} -+ - /* open a character device to a unix fd */ - static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) - { -@@ -2070,6 +2084,7 @@ - chr->opaque = s; - chr->chr_write = fd_chr_write; - chr->chr_update_read_handler = fd_chr_update_read_handler; -+ chr->chr_close = fd_chr_close; - - qemu_chr_reset(chr); - -@@ -2156,6 +2171,7 @@ - /* init terminal so that we can grab keys */ - static struct termios oldtty; - static int old_fd0_flags; -+static int term_atexit_done; - - static void term_exit(void) - { -@@ -2185,11 +2201,20 @@ - - tcsetattr (0, TCSANOW, &tty); - -- atexit(term_exit); -+ if (!term_atexit_done++) -+ atexit(term_exit); - - fcntl(0, F_SETFL, O_NONBLOCK); - } - -+static void qemu_chr_close_stdio(struct CharDriverState *chr) -+{ -+ term_exit(); -+ stdio_nb_clients--; -+ qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL); -+ fd_chr_close(chr); -+} -+ - static CharDriverState *qemu_chr_open_stdio(void) - { - CharDriverState *chr; -@@ -2197,6 +2222,7 @@ - if (stdio_nb_clients >= STDIO_MAX_CLIENTS) - return NULL; - chr = qemu_chr_open_fd(0, 1); -+ chr->chr_close = qemu_chr_close_stdio; - qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr); - stdio_nb_clients++; - term_init(); -@@ -2241,45 +2267,33 @@ - #endif - tcgetattr (fd, &tty); - -- switch(speed) { -- case 50: -+#define MARGIN 1.1 -+ if (speed <= 50 * MARGIN) - spd = B50; -- break; -- case 75: -+ else if (speed <= 75 * MARGIN) - spd = B75; -- break; -- case 300: -+ else if (speed <= 300 * MARGIN) - spd = B300; -- break; -- case 600: -+ else if (speed <= 600 * MARGIN) - spd = B600; -- break; -- case 1200: -+ else if (speed <= 1200 * MARGIN) - spd = B1200; -- break; -- case 2400: -+ else if (speed <= 2400 * MARGIN) - spd = B2400; -- break; -- case 4800: -+ else if (speed <= 4800 * MARGIN) - spd = B4800; -- break; -- case 9600: -+ else if (speed <= 9600 * MARGIN) - spd = B9600; -- break; -- case 19200: -+ else if (speed <= 19200 * MARGIN) - spd = B19200; -- break; -- case 38400: -+ else if (speed <= 38400 * MARGIN) - spd = B38400; -- break; -- case 57600: -+ else if (speed <= 57600 * MARGIN) - spd = B57600; -- break; -- default: -- case 115200: -+ else if (speed <= 115200 * MARGIN) -+ spd = B115200; -+ else - spd = B115200; -- break; -- } - - cfsetispeed(&tty, spd); - cfsetospeed(&tty, spd); -@@ -3431,6 +3445,7 @@ - { - if (chr->chr_close) - chr->chr_close(chr); -+ qemu_free(chr); - } - - /***********************************************************/ -@@ -5200,6 +5215,8 @@ - dev = usb_msd_init(p); - } else if (!strcmp(devname, "wacom-tablet")) { - dev = usb_wacom_init(); -+ } else if (strstart(devname, "serial:", &p)) { -+ dev = usb_serial_init(p); - } else { - return -1; - } -Index: qemu-0.9.1/qemu-doc.texi -=================================================================== ---- qemu-0.9.1.orig/qemu-doc.texi 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/qemu-doc.texi 2008-04-14 11:27:17.000000000 +0200 -@@ -524,6 +524,10 @@ - @item host:vendor_id:product_id - Pass through the host device identified by vendor_id:product_id (Linux only). - -+@item serial:[vendorid=@var{vendor_id}][,productid=@var{product_id}]:@var{dev} -+Serial converter to host character device @var{dev}, see @code{-serial} for the -+available devices. -+ - @end table - - @end table -@@ -1561,27 +1565,37 @@ - USB devices can be connected with the @option{-usbdevice} commandline option - or the @code{usb_add} monitor command. Available devices are: - --@table @var --@item @code{mouse} -+@table @code -+@item mouse - Virtual Mouse. This will override the PS/2 mouse emulation when activated. --@item @code{tablet} -+@item tablet - Pointer device that uses absolute coordinates (like a touchscreen). - This means qemu is able to report the mouse position without having - to grab the mouse. Also overrides the PS/2 mouse emulation when activated. --@item @code{disk:@var{file}} -+@item disk:@var{file} - Mass storage device based on @var{file} (@pxref{disk_images}) --@item @code{host:@var{bus.addr}} -+@item host:@var{bus.addr} - Pass through the host device identified by @var{bus.addr} - (Linux only) --@item @code{host:@var{vendor_id:product_id}} -+@item host:@var{vendor_id:product_id} - Pass through the host device identified by @var{vendor_id:product_id} - (Linux only) --@item @code{wacom-tablet} -+@item wacom-tablet - Virtual Wacom PenPartner tablet. This device is similar to the @code{tablet} - above but it can be used with the tslib library because in addition to touch - coordinates it reports touch pressure. --@item @code{keyboard} -+@item keyboard - Standard USB keyboard. Will override the PS/2 keyboard (if present). -+@item serial:[vendorid=@var{vendor_id}][,product_id=@var{product_id}]:@var{dev} -+Serial converter. This emulates an FTDI FT232BM chip connected to host character -+device @var{dev}. The available character devices are the same as for the -+@code{-serial} option. The @code{vendorid} and @code{productid} options can be -+used to override the default 0403:6001. For instance, -+@example -+usb_add serial:productid=FA00:tcp:192.168.0.2:4444 -+@end example -+will connect to tcp port 4444 of ip 192.168.0.2, and plug that to the virtual -+serial converter, faking a Matrix Orbital LCD Display (USB ID 0403:FA00). - @end table - - @node host_usb_devices diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/84_rtl8139.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/84_rtl8139.patch --- qemu-0.9.1/debian/patches/84_rtl8139.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/84_rtl8139.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,122 +0,0 @@ -commit 1104c4b774c263da3d9f6e463d20bbc096e72b00 -Author: aurel32 -Date: Thu Mar 13 19:17:40 2008 +0000 - - rtl8139: fix endianness on big endian targets - - On big endian targets with mmio accesses, the values are not always - swapped, depending on the accessed register. The Linux 8139too module - was able to cope with that, but not the 8139cp one. - - - git-svn-id: svn+ssh://svn.savannah.nongnu.org/qemu/trunk@4045 c046a42c-6fe2-441c-8c8c-71466251a162 - -Index: qemu-0.9.1/hw/rtl8139.c -=================================================================== ---- qemu-0.9.1.orig/hw/rtl8139.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/rtl8139.c 2008-04-14 11:26:14.000000000 +0200 -@@ -2735,13 +2735,8 @@ - default: - DEBUG_PRINT(("RTL8139: ioport write(w) addr=0x%x val=0x%04x via write(b)\n", addr, val)); - --#ifdef TARGET_WORDS_BIGENDIAN -- rtl8139_io_writeb(opaque, addr, (val >> 8) & 0xff); -- rtl8139_io_writeb(opaque, addr + 1, val & 0xff); --#else - rtl8139_io_writeb(opaque, addr, val & 0xff); - rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff); --#endif - break; - } - } -@@ -2802,17 +2797,10 @@ - - default: - DEBUG_PRINT(("RTL8139: ioport write(l) addr=0x%x val=0x%08x via write(b)\n", addr, val)); --#ifdef TARGET_WORDS_BIGENDIAN -- rtl8139_io_writeb(opaque, addr, (val >> 24) & 0xff); -- rtl8139_io_writeb(opaque, addr + 1, (val >> 16) & 0xff); -- rtl8139_io_writeb(opaque, addr + 2, (val >> 8) & 0xff); -- rtl8139_io_writeb(opaque, addr + 3, val & 0xff); --#else - rtl8139_io_writeb(opaque, addr, val & 0xff); - rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff); - rtl8139_io_writeb(opaque, addr + 2, (val >> 16) & 0xff); - rtl8139_io_writeb(opaque, addr + 3, (val >> 24) & 0xff); --#endif - break; - } - } -@@ -2958,13 +2946,8 @@ - default: - DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x via read(b)\n", addr)); - --#ifdef TARGET_WORDS_BIGENDIAN -- ret = rtl8139_io_readb(opaque, addr) << 8; -- ret |= rtl8139_io_readb(opaque, addr + 1); --#else - ret = rtl8139_io_readb(opaque, addr); - ret |= rtl8139_io_readb(opaque, addr + 1) << 8; --#endif - - DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x val=0x%04x\n", addr, ret)); - break; -@@ -3031,17 +3014,10 @@ - default: - DEBUG_PRINT(("RTL8139: ioport read(l) addr=0x%x via read(b)\n", addr)); - --#ifdef TARGET_WORDS_BIGENDIAN -- ret = rtl8139_io_readb(opaque, addr) << 24; -- ret |= rtl8139_io_readb(opaque, addr + 1) << 16; -- ret |= rtl8139_io_readb(opaque, addr + 2) << 8; -- ret |= rtl8139_io_readb(opaque, addr + 3); --#else - ret = rtl8139_io_readb(opaque, addr); - ret |= rtl8139_io_readb(opaque, addr + 1) << 8; - ret |= rtl8139_io_readb(opaque, addr + 2) << 16; - ret |= rtl8139_io_readb(opaque, addr + 3) << 24; --#endif - - DEBUG_PRINT(("RTL8139: read(l) addr=0x%x val=%08x\n", addr, ret)); - break; -@@ -3091,11 +3067,17 @@ - - static void rtl8139_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) - { -+#ifdef TARGET_WORDS_BIGENDIAN -+ val = bswap16(val); -+#endif - rtl8139_io_writew(opaque, addr & 0xFF, val); - } - - static void rtl8139_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) - { -+#ifdef TARGET_WORDS_BIGENDIAN -+ val = bswap32(val); -+#endif - rtl8139_io_writel(opaque, addr & 0xFF, val); - } - -@@ -3106,12 +3088,20 @@ - - static uint32_t rtl8139_mmio_readw(void *opaque, target_phys_addr_t addr) - { -- return rtl8139_io_readw(opaque, addr & 0xFF); -+ uint32_t val = rtl8139_io_readw(opaque, addr & 0xFF); -+#ifdef TARGET_WORDS_BIGENDIAN -+ val = bswap16(val); -+#endif -+ return val; - } - - static uint32_t rtl8139_mmio_readl(void *opaque, target_phys_addr_t addr) - { -- return rtl8139_io_readl(opaque, addr & 0xFF); -+ uint32_t val = rtl8139_io_readl(opaque, addr & 0xFF); -+#ifdef TARGET_WORDS_BIGENDIAN -+ val = bswap32(val); -+#endif -+ return val; - } - - /* */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/85_vvfat.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/85_vvfat.patch --- qemu-0.9.1/debian/patches/85_vvfat.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/85_vvfat.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,36 +0,0 @@ -commit 08120e44a2bd9a8b53a2e4610b5d5637c3060d1a -Author: aurel32 -Date: Tue Mar 18 06:52:48 2008 +0000 - - restore rw support for vvfat - - (Carlo Marcelo Arenas) - - - git-svn-id: svn+ssh://svn.savannah.nongnu.org/qemu/trunk@4080 c046a42c-6fe2-441c-8c8c-71466251a162 - -Index: qemu-0.9.1/block-qcow.c -=================================================================== ---- qemu-0.9.1.orig/block-qcow.c 2008-01-06 20:38:41.000000000 +0100 -+++ qemu-0.9.1/block-qcow.c 2008-04-14 11:26:14.000000000 +0200 -@@ -752,11 +752,15 @@ - header_size = sizeof(header); - backing_filename_len = 0; - if (backing_file) { -- header.backing_file_offset = cpu_to_be64(header_size); -- backing_filename_len = strlen(backing_file); -- header.backing_file_size = cpu_to_be32(backing_filename_len); -- header_size += backing_filename_len; -- header.mtime = cpu_to_be32(0); -+ if (strcmp(backing_file, "fat:")) { -+ header.backing_file_offset = cpu_to_be64(header_size); -+ backing_filename_len = strlen(backing_file); -+ header.backing_file_size = cpu_to_be32(backing_filename_len); -+ header_size += backing_filename_len; -+ } else { -+ /* special backing file for vvfat */ -+ backing_file = NULL; -+ } - header.cluster_bits = 9; /* 512 byte cluster to avoid copying - unmodifyed sectors */ - header.l2_bits = 12; /* 32 KB L2 tables */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/86_df.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/86_df.patch --- qemu-0.9.1/debian/patches/86_df.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/86_df.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,23 +0,0 @@ -commit 953d3ae6fbd433d2d6f0402a0de81e32e09023d5 -Author: aurel32 -Date: Fri Mar 28 22:30:30 2008 +0000 - - x86-64: recompute DF after eflags has been modified when emulating SYSCALL - - (Jakub Jermar) - - - git-svn-id: svn+ssh://svn.savannah.nongnu.org/qemu/trunk@4120 c046a42c-6fe2-441c-8c8c-71466251a162 - -Index: qemu-0.9.1/target-i386/helper.c -=================================================================== ---- qemu-0.9.1.orig/target-i386/helper.c 2008-01-06 20:38:45.000000000 +0100 -+++ qemu-0.9.1/target-i386/helper.c 2008-04-14 11:26:14.000000000 +0200 -@@ -1008,6 +1008,7 @@ - DESC_S_MASK | - DESC_W_MASK | DESC_A_MASK); - env->eflags &= ~env->fmask; -+ load_eflags(env->eflags, 0); - if (code64) - env->eip = env->lstar; - else diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/87_eoi.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/87_eoi.patch --- qemu-0.9.1/debian/patches/87_eoi.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/87_eoi.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,25 +0,0 @@ -commit 9127f94b9af96153838091a5409c51843061c8a3 -Author: aurel32 -Date: Fri Mar 28 22:31:36 2008 +0000 - - ignore reads to the EOI register - - (Glauber Costa) - - - git-svn-id: svn+ssh://svn.savannah.nongnu.org/qemu/trunk@4124 c046a42c-6fe2-441c-8c8c-71466251a162 - -Index: qemu-0.9.1/hw/apic.c -=================================================================== ---- qemu-0.9.1.orig/hw/apic.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/apic.c 2008-04-14 11:26:14.000000000 +0200 -@@ -604,6 +604,9 @@ - /* ppr */ - val = apic_get_ppr(s); - break; -+ case 0x0b: -+ val = 0; -+ break; - case 0x0d: - val = s->log_dest << 24; - break; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/88_dma.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/88_dma.patch --- qemu-0.9.1/debian/patches/88_dma.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/88_dma.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,70 +0,0 @@ -commit 43b0a943462c2620569776cc43e5b3fa04a73a3a -Author: aurel32 -Date: Sat Mar 29 12:15:35 2008 +0000 - - IDE: Improve DMA transfers by increasing the buffer size - - (Ian Jackson) - - - git-svn-id: svn+ssh://svn.savannah.nongnu.org/qemu/trunk@4132 c046a42c-6fe2-441c-8c8c-71466251a162 - -Index: qemu-0.9.1/hw/ide.c -=================================================================== ---- qemu-0.9.1.orig/hw/ide.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/ide.c 2008-04-14 11:26:14.000000000 +0200 -@@ -202,6 +202,12 @@ - /* set to 1 set disable mult support */ - #define MAX_MULT_SECTORS 16 - -+#define IDE_DMA_BUF_SECTORS 256 -+ -+#if (IDE_DMA_BUF_SECTORS < MAX_MULT_SECTORS) -+#error "IDE_DMA_BUF_SECTORS must be bigger or equal to MAX_MULT_SECTORS" -+#endif -+ - /* ATAPI defines */ - - #define ATAPI_PACKET_SIZE 12 -@@ -847,8 +853,8 @@ - - /* launch next transfer */ - n = s->nsector; -- if (n > MAX_MULT_SECTORS) -- n = MAX_MULT_SECTORS; -+ if (n > IDE_DMA_BUF_SECTORS) -+ n = IDE_DMA_BUF_SECTORS; - s->io_buffer_index = 0; - s->io_buffer_size = n * 512; - #ifdef DEBUG_AIO -@@ -946,8 +952,8 @@ - - /* launch next transfer */ - n = s->nsector; -- if (n > MAX_MULT_SECTORS) -- n = MAX_MULT_SECTORS; -+ if (n > IDE_DMA_BUF_SECTORS) -+ n = IDE_DMA_BUF_SECTORS; - s->io_buffer_index = 0; - s->io_buffer_size = n * 512; - -@@ -1241,8 +1247,8 @@ - data_offset = 16; - } else { - n = s->packet_transfer_size >> 11; -- if (n > (MAX_MULT_SECTORS / 4)) -- n = (MAX_MULT_SECTORS / 4); -+ if (n > (IDE_DMA_BUF_SECTORS / 4)) -+ n = (IDE_DMA_BUF_SECTORS / 4); - s->io_buffer_size = n * 2048; - data_offset = 0; - } -@@ -2434,7 +2440,7 @@ - - for(i = 0; i < 2; i++) { - s = ide_state + i; -- s->io_buffer = qemu_memalign(512, MAX_MULT_SECTORS*512 + 4); -+ s->io_buffer = qemu_memalign(512, IDE_DMA_BUF_SECTORS*512 + 4); - if (i == 0) - s->bs = hd0; - else diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/89_braille.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/89_braille.patch --- qemu-0.9.1/debian/patches/89_braille.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/89_braille.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,857 +0,0 @@ -commit 4a0163c1e18b1c752bfaf086bf806f0fc7be5c41 -Author: aurel32 -Date: Tue Apr 8 06:01:02 2008 +0000 - - Braille device support - - (Samuel Thibault) - - - git-svn-id: svn+ssh://svn.savannah.nongnu.org/qemu/trunk@4173 c046a42c-6fe2-441c-8c8c-71466251a162 - -Index: qemu-0.9.1/Makefile -=================================================================== ---- qemu-0.9.1.orig/Makefile 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/Makefile 2008-04-14 11:26:14.000000000 +0200 -@@ -60,6 +60,11 @@ - OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o usb-serial.o - OBJS+=sd.o ssi-sd.o - -+ifdef CONFIG_BRLAPI -+OBJS+= baum.o -+LIBS+=-lbrlapi -+endif -+ - ifdef CONFIG_WIN32 - OBJS+=tap-win32.o - endif -Index: qemu-0.9.1/Makefile.target -=================================================================== ---- qemu-0.9.1.orig/Makefile.target 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/Makefile.target 2008-04-14 11:26:14.000000000 +0200 -@@ -565,7 +565,7 @@ - endif - - $(QEMU_SYSTEM): $(VL_OBJS) ../libqemu_common.a libqemu.a -- $(CC) $(VL_LDFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(CURSES_LIBS) $(COCOA_LIBS) $(VL_LIBS) -+ $(CC) $(VL_LDFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(CURSES_LIBS) $(COCOA_LIBS) $(VL_LIBS) $(BRLAPI_LIBS) - - depend: $(SRCS) - $(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend -Index: qemu-0.9.1/configure -=================================================================== ---- qemu-0.9.1.orig/configure 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/configure 2008-04-14 11:26:14.000000000 +0200 -@@ -281,6 +281,8 @@ - ;; - --disable-kqemu) kqemu="no" - ;; -+ --disable-brlapi) brlapi="no" -+ ;; - --enable-profiler) profiler="yes" - ;; - --enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no" -@@ -413,6 +415,7 @@ - echo " --enable-alsa enable ALSA audio driver" - echo " --enable-fmod enable FMOD audio driver" - echo " --enable-dsound enable DirectSound audio driver" -+echo " --disable-brlapi disable BrlAPI" - echo " --disable-vnc-tls disable TLS encryption for VNC server" - echo " --enable-system enable all system emulation targets" - echo " --disable-system disable all system emulation targets" -@@ -688,6 +691,20 @@ - fi - - ########################################## -+# BrlAPI probe -+ -+if test -z "$brlapi" ; then -+ brlapi=no -+cat > $TMPC << EOF -+#include -+int main( void ) { return brlapi__openConnection (NULL, NULL, NULL); } -+EOF -+ if $cc -o $TMPE ${OS_CFLAGS} $TMPC -lbrlapi 2> /tmp/qemu-$$-brlapi.log ; then -+ brlapi=yes -+ fi # brlapi compile test -+fi # -z $brlapi -+ -+########################################## - # curses probe - - if test "$curses" = "yes" ; then -@@ -780,6 +797,7 @@ - echo "Target Sparc Arch $sparc_cpu" - fi - echo "kqemu support $kqemu" -+echo "brlapi support $brlapi" - echo "Documentation $build_docs" - [ ! -z "$uname_release" ] && \ - echo "uname -r $uname_release" -@@ -1006,6 +1024,11 @@ - echo "CONFIG_CURSES=yes" >> $config_mak - echo "CURSES_LIBS=-lcurses" >> $config_mak - fi -+if test "$brlapi" = "yes" ; then -+ echo "CONFIG_BRLAPI=yes" >> $config_mak -+ echo "#define CONFIG_BRLAPI 1" >> $config_h -+ echo "BRLAPI_LIBS=-lbrlapi" >> $config_mak -+fi - - # XXX: suppress that - if [ "$bsd" = "yes" ] ; then -Index: qemu-0.9.1/hw/baum.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ qemu-0.9.1/hw/baum.c 2008-04-14 11:26:14.000000000 +0200 -@@ -0,0 +1,643 @@ -+/* -+ * QEMU Baum Braille Device -+ * -+ * Copyright (c) 2008 Samuel Thibault -+ * -+ * 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 "qemu-common.h" -+#include "qemu-char.h" -+#include "qemu-timer.h" -+#include "usb.h" -+#include -+#include -+#include -+#include -+#ifdef CONFIG_SDL -+#include -+#endif -+ -+#if 0 -+#define DPRINTF(fmt, ...) \ -+ printf(fmt, ## __VA_ARGS__) -+#else -+#define DPRINTF(fmt, ...) -+#endif -+ -+#define ESC 0x1B -+ -+#define BAUM_REQ_DisplayData 0x01 -+#define BAUM_REQ_GetVersionNumber 0x05 -+#define BAUM_REQ_GetKeys 0x08 -+#define BAUM_REQ_SetMode 0x12 -+#define BAUM_REQ_SetProtocol 0x15 -+#define BAUM_REQ_GetDeviceIdentity 0x84 -+#define BAUM_REQ_GetSerialNumber 0x8A -+ -+#define BAUM_RSP_CellCount 0x01 -+#define BAUM_RSP_VersionNumber 0x05 -+#define BAUM_RSP_ModeSetting 0x11 -+#define BAUM_RSP_CommunicationChannel 0x16 -+#define BAUM_RSP_PowerdownSignal 0x17 -+#define BAUM_RSP_HorizontalSensors 0x20 -+#define BAUM_RSP_VerticalSensors 0x21 -+#define BAUM_RSP_RoutingKeys 0x22 -+#define BAUM_RSP_Switches 0x23 -+#define BAUM_RSP_TopKeys 0x24 -+#define BAUM_RSP_HorizontalSensor 0x25 -+#define BAUM_RSP_VerticalSensor 0x26 -+#define BAUM_RSP_RoutingKey 0x27 -+#define BAUM_RSP_FrontKeys6 0x28 -+#define BAUM_RSP_BackKeys6 0x29 -+#define BAUM_RSP_CommandKeys 0x2B -+#define BAUM_RSP_FrontKeys10 0x2C -+#define BAUM_RSP_BackKeys10 0x2D -+#define BAUM_RSP_EntryKeys 0x33 -+#define BAUM_RSP_JoyStick 0x34 -+#define BAUM_RSP_ErrorCode 0x40 -+#define BAUM_RSP_InfoBlock 0x42 -+#define BAUM_RSP_DeviceIdentity 0x84 -+#define BAUM_RSP_SerialNumber 0x8A -+#define BAUM_RSP_BluetoothName 0x8C -+ -+#define BAUM_TL1 0x01 -+#define BAUM_TL2 0x02 -+#define BAUM_TL3 0x04 -+#define BAUM_TR1 0x08 -+#define BAUM_TR2 0x10 -+#define BAUM_TR3 0x20 -+ -+#define BUF_SIZE 256 -+ -+typedef struct { -+ CharDriverState *chr; -+ -+ brlapi_handle_t *brlapi; -+ int brlapi_fd; -+ int x, y; -+ -+ uint8_t in_buf[BUF_SIZE]; -+ uint8_t in_buf_used; -+ uint8_t out_buf[BUF_SIZE]; -+ uint8_t out_buf_used, out_buf_ptr; -+ -+ QEMUTimer *cellCount_timer; -+} BaumDriverState; -+ -+/* Let's assume NABCC by default */ -+static const uint8_t nabcc_translation[256] = { -+ [0] = ' ', -+#ifndef BRLAPI_DOTS -+#define BRLAPI_DOTS(d1,d2,d3,d4,d5,d6,d7,d8) \ -+ ((d1?BRLAPI_DOT1:0)|\ -+ (d2?BRLAPI_DOT2:0)|\ -+ (d3?BRLAPI_DOT3:0)|\ -+ (d4?BRLAPI_DOT4:0)|\ -+ (d5?BRLAPI_DOT5:0)|\ -+ (d6?BRLAPI_DOT6:0)|\ -+ (d7?BRLAPI_DOT7:0)|\ -+ (d8?BRLAPI_DOT8:0)) -+#endif -+ [BRLAPI_DOTS(1,0,0,0,0,0,0,0)] = 'a', -+ [BRLAPI_DOTS(1,1,0,0,0,0,0,0)] = 'b', -+ [BRLAPI_DOTS(1,0,0,1,0,0,0,0)] = 'c', -+ [BRLAPI_DOTS(1,0,0,1,1,0,0,0)] = 'd', -+ [BRLAPI_DOTS(1,0,0,0,1,0,0,0)] = 'e', -+ [BRLAPI_DOTS(1,1,0,1,0,0,0,0)] = 'f', -+ [BRLAPI_DOTS(1,1,0,1,1,0,0,0)] = 'g', -+ [BRLAPI_DOTS(1,1,0,0,1,0,0,0)] = 'h', -+ [BRLAPI_DOTS(0,1,0,1,0,0,0,0)] = 'i', -+ [BRLAPI_DOTS(0,1,0,1,1,0,0,0)] = 'j', -+ [BRLAPI_DOTS(1,0,1,0,0,0,0,0)] = 'k', -+ [BRLAPI_DOTS(1,1,1,0,0,0,0,0)] = 'l', -+ [BRLAPI_DOTS(1,0,1,1,0,0,0,0)] = 'm', -+ [BRLAPI_DOTS(1,0,1,1,1,0,0,0)] = 'n', -+ [BRLAPI_DOTS(1,0,1,0,1,0,0,0)] = 'o', -+ [BRLAPI_DOTS(1,1,1,1,0,0,0,0)] = 'p', -+ [BRLAPI_DOTS(1,1,1,1,1,0,0,0)] = 'q', -+ [BRLAPI_DOTS(1,1,1,0,1,0,0,0)] = 'r', -+ [BRLAPI_DOTS(0,1,1,1,0,0,0,0)] = 's', -+ [BRLAPI_DOTS(0,1,1,1,1,0,0,0)] = 't', -+ [BRLAPI_DOTS(1,0,1,0,0,1,0,0)] = 'u', -+ [BRLAPI_DOTS(1,1,1,0,0,1,0,0)] = 'v', -+ [BRLAPI_DOTS(0,1,0,1,1,1,0,0)] = 'w', -+ [BRLAPI_DOTS(1,0,1,1,0,1,0,0)] = 'x', -+ [BRLAPI_DOTS(1,0,1,1,1,1,0,0)] = 'y', -+ [BRLAPI_DOTS(1,0,1,0,1,1,0,0)] = 'z', -+ -+ [BRLAPI_DOTS(1,0,0,0,0,0,1,0)] = 'A', -+ [BRLAPI_DOTS(1,1,0,0,0,0,1,0)] = 'B', -+ [BRLAPI_DOTS(1,0,0,1,0,0,1,0)] = 'C', -+ [BRLAPI_DOTS(1,0,0,1,1,0,1,0)] = 'D', -+ [BRLAPI_DOTS(1,0,0,0,1,0,1,0)] = 'E', -+ [BRLAPI_DOTS(1,1,0,1,0,0,1,0)] = 'F', -+ [BRLAPI_DOTS(1,1,0,1,1,0,1,0)] = 'G', -+ [BRLAPI_DOTS(1,1,0,0,1,0,1,0)] = 'H', -+ [BRLAPI_DOTS(0,1,0,1,0,0,1,0)] = 'I', -+ [BRLAPI_DOTS(0,1,0,1,1,0,1,0)] = 'J', -+ [BRLAPI_DOTS(1,0,1,0,0,0,1,0)] = 'K', -+ [BRLAPI_DOTS(1,1,1,0,0,0,1,0)] = 'L', -+ [BRLAPI_DOTS(1,0,1,1,0,0,1,0)] = 'M', -+ [BRLAPI_DOTS(1,0,1,1,1,0,1,0)] = 'N', -+ [BRLAPI_DOTS(1,0,1,0,1,0,1,0)] = 'O', -+ [BRLAPI_DOTS(1,1,1,1,0,0,1,0)] = 'P', -+ [BRLAPI_DOTS(1,1,1,1,1,0,1,0)] = 'Q', -+ [BRLAPI_DOTS(1,1,1,0,1,0,1,0)] = 'R', -+ [BRLAPI_DOTS(0,1,1,1,0,0,1,0)] = 'S', -+ [BRLAPI_DOTS(0,1,1,1,1,0,1,0)] = 'T', -+ [BRLAPI_DOTS(1,0,1,0,0,1,1,0)] = 'U', -+ [BRLAPI_DOTS(1,1,1,0,0,1,1,0)] = 'V', -+ [BRLAPI_DOTS(0,1,0,1,1,1,1,0)] = 'W', -+ [BRLAPI_DOTS(1,0,1,1,0,1,1,0)] = 'X', -+ [BRLAPI_DOTS(1,0,1,1,1,1,1,0)] = 'Y', -+ [BRLAPI_DOTS(1,0,1,0,1,1,1,0)] = 'Z', -+ -+ [BRLAPI_DOTS(0,0,1,0,1,1,0,0)] = '0', -+ [BRLAPI_DOTS(0,1,0,0,0,0,0,0)] = '1', -+ [BRLAPI_DOTS(0,1,1,0,0,0,0,0)] = '2', -+ [BRLAPI_DOTS(0,1,0,0,1,0,0,0)] = '3', -+ [BRLAPI_DOTS(0,1,0,0,1,1,0,0)] = '4', -+ [BRLAPI_DOTS(0,1,0,0,0,1,0,0)] = '5', -+ [BRLAPI_DOTS(0,1,1,0,1,0,0,0)] = '6', -+ [BRLAPI_DOTS(0,1,1,0,1,1,0,0)] = '7', -+ [BRLAPI_DOTS(0,1,1,0,0,1,0,0)] = '8', -+ [BRLAPI_DOTS(0,0,1,0,1,0,0,0)] = '9', -+ -+ [BRLAPI_DOTS(0,0,0,1,0,1,0,0)] = '.', -+ [BRLAPI_DOTS(0,0,1,1,0,1,0,0)] = '+', -+ [BRLAPI_DOTS(0,0,1,0,0,1,0,0)] = '-', -+ [BRLAPI_DOTS(1,0,0,0,0,1,0,0)] = '*', -+ [BRLAPI_DOTS(0,0,1,1,0,0,0,0)] = '/', -+ [BRLAPI_DOTS(1,1,1,0,1,1,0,0)] = '(', -+ [BRLAPI_DOTS(0,1,1,1,1,1,0,0)] = ')', -+ -+ [BRLAPI_DOTS(1,1,1,1,0,1,0,0)] = '&', -+ [BRLAPI_DOTS(0,0,1,1,1,1,0,0)] = '#', -+ -+ [BRLAPI_DOTS(0,0,0,0,0,1,0,0)] = ',', -+ [BRLAPI_DOTS(0,0,0,0,1,1,0,0)] = ';', -+ [BRLAPI_DOTS(1,0,0,0,1,1,0,0)] = ':', -+ [BRLAPI_DOTS(0,1,1,1,0,1,0,0)] = '!', -+ [BRLAPI_DOTS(1,0,0,1,1,1,0,0)] = '?', -+ [BRLAPI_DOTS(0,0,0,0,1,0,0,0)] = '"', -+ [BRLAPI_DOTS(0,0,1,0,0,0,0,0)] ='\'', -+ [BRLAPI_DOTS(0,0,0,1,0,0,0,0)] = '`', -+ [BRLAPI_DOTS(0,0,0,1,1,0,1,0)] = '^', -+ [BRLAPI_DOTS(0,0,0,1,1,0,0,0)] = '~', -+ [BRLAPI_DOTS(0,1,0,1,0,1,1,0)] = '[', -+ [BRLAPI_DOTS(1,1,0,1,1,1,1,0)] = ']', -+ [BRLAPI_DOTS(0,1,0,1,0,1,0,0)] = '{', -+ [BRLAPI_DOTS(1,1,0,1,1,1,0,0)] = '}', -+ [BRLAPI_DOTS(1,1,1,1,1,1,0,0)] = '=', -+ [BRLAPI_DOTS(1,1,0,0,0,1,0,0)] = '<', -+ [BRLAPI_DOTS(0,0,1,1,1,0,0,0)] = '>', -+ [BRLAPI_DOTS(1,1,0,1,0,1,0,0)] = '$', -+ [BRLAPI_DOTS(1,0,0,1,0,1,0,0)] = '%', -+ [BRLAPI_DOTS(0,0,0,1,0,0,1,0)] = '@', -+ [BRLAPI_DOTS(1,1,0,0,1,1,0,0)] = '|', -+ [BRLAPI_DOTS(1,1,0,0,1,1,1,0)] ='\\', -+ [BRLAPI_DOTS(0,0,0,1,1,1,0,0)] = '_', -+}; -+ -+/* The serial port can receive more of our data */ -+static void baum_accept_input(struct CharDriverState *chr) -+{ -+ BaumDriverState *baum = chr->opaque; -+ int room, first; -+ -+ if (!baum->out_buf_used) -+ return; -+ room = qemu_chr_can_read(chr); -+ if (!room) -+ return; -+ if (room > baum->out_buf_used) -+ room = baum->out_buf_used; -+ -+ first = BUF_SIZE - baum->out_buf_ptr; -+ if (room > first) { -+ qemu_chr_read(chr, baum->out_buf + baum->out_buf_ptr, first); -+ baum->out_buf_ptr = 0; -+ baum->out_buf_used -= first; -+ room -= first; -+ } -+ qemu_chr_read(chr, baum->out_buf + baum->out_buf_ptr, room); -+ baum->out_buf_ptr += room; -+ baum->out_buf_used -= room; -+} -+ -+/* We want to send a packet */ -+static void baum_write_packet(BaumDriverState *baum, const uint8_t *buf, int len) -+{ -+ uint8_t io_buf[1 + 2 * len], *cur = io_buf; -+ int room; -+ *cur++ = ESC; -+ while (len--) -+ if ((*cur++ = *buf++) == ESC) -+ *cur++ = ESC; -+ room = qemu_chr_can_read(baum->chr); -+ len = cur - io_buf; -+ if (len <= room) { -+ /* Fits */ -+ qemu_chr_read(baum->chr, io_buf, len); -+ } else { -+ int first; -+ uint8_t out; -+ /* Can't fit all, send what can be, and store the rest. */ -+ qemu_chr_read(baum->chr, io_buf, room); -+ len -= room; -+ cur = io_buf + room; -+ if (len > BUF_SIZE - baum->out_buf_used) { -+ /* Can't even store it, drop the previous data... */ -+ assert(len <= BUF_SIZE); -+ baum->out_buf_used = 0; -+ baum->out_buf_ptr = 0; -+ } -+ out = baum->out_buf_ptr; -+ baum->out_buf_used += len; -+ first = BUF_SIZE - baum->out_buf_ptr; -+ if (len > first) { -+ memcpy(baum->out_buf + out, cur, first); -+ out = 0; -+ len -= first; -+ cur += first; -+ } -+ memcpy(baum->out_buf + out, cur, len); -+ } -+} -+ -+/* Called when the other end seems to have a wrong idea of our display size */ -+static void baum_cellCount_timer_cb(void *opaque) -+{ -+ BaumDriverState *baum = opaque; -+ uint8_t cell_count[] = { BAUM_RSP_CellCount, baum->x * baum->y }; -+ DPRINTF("Timeout waiting for DisplayData, sending cell count\n"); -+ baum_write_packet(baum, cell_count, sizeof(cell_count)); -+} -+ -+/* Try to interpret a whole incoming packet */ -+static int baum_eat_packet(BaumDriverState *baum, const uint8_t *buf, int len) -+{ -+ const uint8_t *cur = buf; -+ uint8_t req = 0; -+ -+ if (!len--) -+ return 0; -+ if (*cur++ != ESC) { -+ while (*cur != ESC) { -+ if (!len--) -+ return 0; -+ cur++; -+ } -+ DPRINTF("Dropped %d bytes!\n", cur - buf); -+ } -+ -+#define EAT(c) do {\ -+ if (!len--) \ -+ return 0; \ -+ if ((c = *cur++) == ESC) { \ -+ if (!len--) \ -+ return 0; \ -+ if (*cur++ != ESC) { \ -+ DPRINTF("Broken packet %#2x, tossing\n", req); \ -+ if (qemu_timer_pending(baum->cellCount_timer)) { \ -+ qemu_del_timer(baum->cellCount_timer); \ -+ baum_cellCount_timer_cb(baum); \ -+ } \ -+ return (cur - 2 - buf); \ -+ } \ -+ } \ -+} while (0) -+ -+ EAT(req); -+ switch (req) { -+ case BAUM_REQ_DisplayData: -+ { -+ uint8_t cells[baum->x * baum->y], c; -+ uint8_t text[baum->x * baum->y]; -+ uint8_t zero[baum->x * baum->y]; -+ int cursor = BRLAPI_CURSOR_OFF; -+ int i; -+ -+ /* Allow 100ms to complete the DisplayData packet */ -+ qemu_mod_timer(baum->cellCount_timer, qemu_get_clock(vm_clock) + ticks_per_sec / 10); -+ for (i = 0; i < baum->x * baum->y ; i++) { -+ EAT(c); -+ cells[i] = c; -+ if ((c & (BRLAPI_DOT7|BRLAPI_DOT8)) -+ == (BRLAPI_DOT7|BRLAPI_DOT8)) { -+ cursor = i + 1; -+ c &= ~(BRLAPI_DOT7|BRLAPI_DOT8); -+ } -+ if (!(c = nabcc_translation[c])) -+ c = '?'; -+ text[i] = c; -+ } -+ qemu_del_timer(baum->cellCount_timer); -+ -+ memset(zero, 0, sizeof(zero)); -+ -+ brlapi_writeArguments_t wa = { -+ .displayNumber = BRLAPI_DISPLAY_DEFAULT, -+ .regionBegin = 1, -+ .regionSize = baum->x * baum->y, -+ .text = text, -+ .textSize = baum->x * baum->y, -+ .andMask = zero, -+ .orMask = cells, -+ .cursor = cursor, -+ .charset = "ISO-8859-1", -+ }; -+ -+ if (brlapi__write(baum->brlapi, &wa) == -1) -+ brlapi_perror("baum brlapi_write"); -+ break; -+ } -+ case BAUM_REQ_SetMode: -+ { -+ uint8_t mode, setting; -+ DPRINTF("SetMode\n"); -+ EAT(mode); -+ EAT(setting); -+ /* ignore */ -+ break; -+ } -+ case BAUM_REQ_SetProtocol: -+ { -+ uint8_t protocol; -+ DPRINTF("SetProtocol\n"); -+ EAT(protocol); -+ /* ignore */ -+ break; -+ } -+ case BAUM_REQ_GetDeviceIdentity: -+ { -+ uint8_t identity[17] = { BAUM_RSP_DeviceIdentity, -+ 'B','a','u','m',' ','V','a','r','i','o' }; -+ DPRINTF("GetDeviceIdentity\n"); -+ identity[11] = '0' + baum->x / 10; -+ identity[12] = '0' + baum->x % 10; -+ baum_write_packet(baum, identity, sizeof(identity)); -+ break; -+ } -+ case BAUM_REQ_GetVersionNumber: -+ { -+ uint8_t version[] = { BAUM_RSP_VersionNumber, 1 }; /* ? */ -+ DPRINTF("GetVersionNumber\n"); -+ baum_write_packet(baum, version, sizeof(version)); -+ break; -+ } -+ case BAUM_REQ_GetSerialNumber: -+ { -+ uint8_t serial[] = { BAUM_RSP_SerialNumber, -+ '0','0','0','0','0','0','0','0' }; -+ DPRINTF("GetSerialNumber\n"); -+ baum_write_packet(baum, serial, sizeof(serial)); -+ break; -+ } -+ case BAUM_REQ_GetKeys: -+ { -+ DPRINTF("Get%0#2x\n", req); -+ /* ignore */ -+ break; -+ } -+ default: -+ DPRINTF("unrecognized request %0#2x\n", req); -+ do -+ if (!len--) -+ return 0; -+ while (*cur++ != ESC); -+ cur--; -+ break; -+ } -+ return cur - buf; -+} -+ -+/* The other end is writing some data. Store it and try to interpret */ -+static int baum_write(CharDriverState *chr, const uint8_t *buf, int len) -+{ -+ BaumDriverState *baum = chr->opaque; -+ int tocopy, cur, eaten, orig_len = len; -+ -+ if (!len) -+ return 0; -+ if (!baum->brlapi) -+ return len; -+ -+ while (len) { -+ /* Complete our buffer as much as possible */ -+ tocopy = len; -+ if (tocopy > BUF_SIZE - baum->in_buf_used) -+ tocopy = BUF_SIZE - baum->in_buf_used; -+ -+ memcpy(baum->in_buf + baum->in_buf_used, buf, tocopy); -+ baum->in_buf_used += tocopy; -+ buf += tocopy; -+ len -= tocopy; -+ -+ /* Interpret it as much as possible */ -+ cur = 0; -+ while (cur < baum->in_buf_used && -+ (eaten = baum_eat_packet(baum, baum->in_buf + cur, baum->in_buf_used - cur))) -+ cur += eaten; -+ -+ /* Shift the remainder */ -+ if (cur) { -+ memmove(baum->in_buf, baum->in_buf + cur, baum->in_buf_used - cur); -+ baum->in_buf_used -= cur; -+ } -+ -+ /* And continue if any data left */ -+ } -+ return orig_len; -+} -+ -+/* The other end sent us some event */ -+static void baum_send_event(CharDriverState *chr, int event) -+{ -+ BaumDriverState *baum = chr->opaque; -+ switch (event) { -+ case CHR_EVENT_BREAK: -+ break; -+ case CHR_EVENT_RESET: -+ /* Reset state */ -+ baum->in_buf_used = 0; -+ break; -+ } -+} -+ -+/* Send the key code to the other end */ -+static void baum_send_key(BaumDriverState *baum, uint8_t type, uint8_t value) { -+ uint8_t packet[] = { type, value }; -+ DPRINTF("writing key %x %x\n", type, value); -+ baum_write_packet(baum, packet, sizeof(packet)); -+} -+ -+/* We got some data on the BrlAPI socket */ -+static void baum_chr_read(void *opaque) -+{ -+ BaumDriverState *baum = opaque; -+ brlapi_keyCode_t code; -+ int ret; -+ if (!baum->brlapi) -+ return; -+ while ((ret = brlapi__readKey(baum->brlapi, 0, &code)) == 1) { -+ DPRINTF("got key %"BRLAPI_PRIxKEYCODE"\n", code); -+ /* Emulate */ -+ switch (code & BRLAPI_KEY_TYPE_MASK) { -+ case BRLAPI_KEY_TYPE_CMD: -+ switch (code & BRLAPI_KEY_CMD_BLK_MASK) { -+ case BRLAPI_KEY_CMD_ROUTE: -+ baum_send_key(baum, BAUM_RSP_RoutingKey, (code & BRLAPI_KEY_CMD_ARG_MASK)+1); -+ baum_send_key(baum, BAUM_RSP_RoutingKey, 0); -+ break; -+ case 0: -+ switch (code & BRLAPI_KEY_CMD_ARG_MASK) { -+ case BRLAPI_KEY_CMD_FWINLT: -+ baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2); -+ baum_send_key(baum, BAUM_RSP_TopKeys, 0); -+ break; -+ case BRLAPI_KEY_CMD_FWINRT: -+ baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR2); -+ baum_send_key(baum, BAUM_RSP_TopKeys, 0); -+ break; -+ case BRLAPI_KEY_CMD_LNUP: -+ baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR1); -+ baum_send_key(baum, BAUM_RSP_TopKeys, 0); -+ break; -+ case BRLAPI_KEY_CMD_LNDN: -+ baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR3); -+ baum_send_key(baum, BAUM_RSP_TopKeys, 0); -+ break; -+ case BRLAPI_KEY_CMD_TOP: -+ baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TR1); -+ baum_send_key(baum, BAUM_RSP_TopKeys, 0); -+ break; -+ case BRLAPI_KEY_CMD_BOT: -+ baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL3|BAUM_TR3); -+ baum_send_key(baum, BAUM_RSP_TopKeys, 0); -+ break; -+ case BRLAPI_KEY_CMD_TOP_LEFT: -+ baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1); -+ baum_send_key(baum, BAUM_RSP_TopKeys, 0); -+ break; -+ case BRLAPI_KEY_CMD_BOT_LEFT: -+ baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR3); -+ baum_send_key(baum, BAUM_RSP_TopKeys, 0); -+ break; -+ case BRLAPI_KEY_CMD_HOME: -+ baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1|BAUM_TR3); -+ baum_send_key(baum, BAUM_RSP_TopKeys, 0); -+ break; -+ case BRLAPI_KEY_CMD_PREFMENU: -+ baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TL3|BAUM_TR1); -+ baum_send_key(baum, BAUM_RSP_TopKeys, 0); -+ break; -+ } -+ } -+ break; -+ case BRLAPI_KEY_TYPE_SYM: -+ break; -+ } -+ } -+ if (ret == -1 && (brlapi_errno != BRLAPI_ERROR_LIBCERR || errno != EINTR)) { -+ brlapi_perror("baum: brlapi_readKey"); -+ brlapi__closeConnection(baum->brlapi); -+ free(baum->brlapi); -+ baum->brlapi = NULL; -+ } -+} -+ -+CharDriverState *chr_baum_init(void) -+{ -+ BaumDriverState *baum; -+ CharDriverState *chr; -+ brlapi_handle_t *handle; -+#ifdef CONFIG_SDL -+ SDL_SysWMinfo info; -+#endif -+ int tty; -+ -+ baum = qemu_mallocz(sizeof(BaumDriverState)); -+ if (!baum) -+ return NULL; -+ -+ baum->chr = chr = qemu_mallocz(sizeof(CharDriverState)); -+ if (!chr) -+ goto fail_baum; -+ -+ chr->opaque = baum; -+ chr->chr_write = baum_write; -+ chr->chr_send_event = baum_send_event; -+ chr->chr_accept_input = baum_accept_input; -+ -+ handle = qemu_mallocz(brlapi_getHandleSize()); -+ if (!handle) -+ goto fail_chr; -+ baum->brlapi = handle; -+ -+ baum->brlapi_fd = brlapi__openConnection(handle, NULL, NULL); -+ if (baum->brlapi_fd == -1) { -+ brlapi_perror("baum_init: brlapi_openConnection"); -+ goto fail_handle; -+ } -+ -+ baum->cellCount_timer = qemu_new_timer(vm_clock, baum_cellCount_timer_cb, baum); -+ -+ if (brlapi__getDisplaySize(handle, &baum->x, &baum->y) == -1) { -+ brlapi_perror("baum_init: brlapi_getDisplaySize"); -+ goto fail; -+ } -+ -+#ifdef CONFIG_SDL -+ memset(&info, 0, sizeof(info)); -+ SDL_VERSION(&info.version); -+ if (SDL_GetWMInfo(&info)) -+ tty = info.info.x11.wmwindow; -+ else -+#endif -+ tty = BRLAPI_TTY_DEFAULT; -+ -+ if (brlapi__enterTtyMode(handle, tty, NULL) == -1) { -+ brlapi_perror("baum_init: brlapi_enterTtyMode"); -+ goto fail; -+ } -+ -+ qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum); -+ -+ qemu_chr_reset(chr); -+ -+ return chr; -+ -+fail: -+ qemu_free_timer(baum->cellCount_timer); -+ brlapi__closeConnection(handle); -+fail_handle: -+ free(handle); -+fail_chr: -+ free(chr); -+fail_baum: -+ free(baum); -+ return NULL; -+} -+ -+USBDevice *usb_baum_init(void) -+{ -+ /* USB Product ID of Super Vario 40 */ -+ return usb_serial_init("productid=FE72:braille"); -+} -Index: qemu-0.9.1/hw/baum.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ qemu-0.9.1/hw/baum.h 2008-04-14 11:26:14.000000000 +0200 -@@ -0,0 +1,29 @@ -+/* -+ * QEMU Baum -+ * -+ * Copyright (c) 2008 Samuel Thibault -+ * -+ * 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. -+ */ -+ -+/* usb device */ -+USBDevice *usb_baum_init(void); -+ -+/* char device */ -+CharDriverState *chr_baum_init(void); -Index: qemu-0.9.1/qemu-doc.texi -=================================================================== ---- qemu-0.9.1.orig/qemu-doc.texi 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/qemu-doc.texi 2008-04-14 11:26:14.000000000 +0200 -@@ -528,6 +528,10 @@ - Serial converter to host character device @var{dev}, see @code{-serial} for the - available devices. - -+@item braille -+Braille device. This will use BrlAPI to display the braille output on a real -+or fake device. -+ - @end table - - @end table -@@ -841,6 +845,10 @@ - @item -serial mon:telnet::4444,server,nowait - @end table - -+@item braille -+Braille device. This will use BrlAPI to display the braille output on a real -+or fake device. -+ - @end table - - @item -parallel @var{dev} -@@ -1596,6 +1604,9 @@ - @end example - will connect to tcp port 4444 of ip 192.168.0.2, and plug that to the virtual - serial converter, faking a Matrix Orbital LCD Display (USB ID 0403:FA00). -+@item braille -+Braille device. This will use BrlAPI to display the braille output on a real -+or fake device. - @end table - - @node host_usb_devices -Index: qemu-0.9.1/vl.c -=================================================================== ---- qemu-0.9.1.orig/vl.c 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/vl.c 2008-04-14 11:27:17.000000000 +0200 -@@ -29,6 +29,7 @@ - #include "hw/fdc.h" - #include "hw/audiodev.h" - #include "hw/isa.h" -+#include "hw/baum.h" - #include "net.h" - #include "console.h" - #include "sysemu.h" -@@ -3434,7 +3435,12 @@ - } else - if (strstart(filename, "file:", &p)) { - return qemu_chr_open_win_file_out(p); -- } -+ } else -+#endif -+#ifdef CONFIG_BRLAPI -+ if (!strcmp(filename, "braille")) { -+ return chr_baum_init(); -+ } else - #endif - { - return NULL; -@@ -5217,6 +5223,10 @@ - dev = usb_wacom_init(); - } else if (strstart(devname, "serial:", &p)) { - dev = usb_serial_init(p); -+#ifdef CONFIG_BRLAPI -+ } else if (!strcmp(devname, "braille")) { -+ dev = usb_baum_init(); -+#endif - } else { - return -1; - } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/90_security.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/90_security.patch --- qemu-0.9.1/debian/patches/90_security.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/90_security.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,16 +1,14 @@ -Index: qemu-0.9.1/block.c +Index: qemu-0.9.1+svn20081101/block.c =================================================================== ---- qemu-0.9.1.orig/block.c 2008-04-14 11:26:13.000000000 +0200 -+++ qemu-0.9.1/block.c 2008-04-14 11:26:14.000000000 +0200 -@@ -549,13 +549,21 @@ +diff -Nurd qemu-0.9.1+svn20081112.orig/block.c qemu-0.9.1+svn20081112/block.c +--- qemu-0.9.1+svn20081112.orig/block.c 2008-11-08 17:27:07.000000000 +0100 ++++ qemu-0.9.1+svn20081112/block.c 2008-11-12 11:29:28.000000000 +0100 +@@ -559,10 +559,18 @@ return -ENOMEDIUM; if (bs->read_only) return -EACCES; + if (sector_num < 0) + return -EINVAL; - if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { - memcpy(bs->boot_sector_data, buf, 512); - } if (drv->bdrv_pwrite) { int ret, len; + int64_t ns; @@ -25,196 +23,11 @@ if (ret < 0) return ret; else if (ret != len) -Index: qemu-0.9.1/hw/cirrus_vga.c +Index: qemu-0.9.1+svn20081101/hw/pc.c =================================================================== ---- qemu-0.9.1.orig/hw/cirrus_vga.c 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/hw/cirrus_vga.c 2008-04-14 11:26:15.000000000 +0200 -@@ -220,6 +220,20 @@ - #define CIRRUS_HOOK_NOT_HANDLED 0 - #define CIRRUS_HOOK_HANDLED 1 - -+#define BLTUNSAFE(s) \ -+ ( \ -+ ( /* check dst is within bounds */ \ -+ (s)->cirrus_blt_height * (s)->cirrus_blt_dstpitch \ -+ + ((s)->cirrus_blt_dstaddr & (s)->cirrus_addr_mask) > \ -+ (s)->vram_size \ -+ ) || \ -+ ( /* check src is within bounds */ \ -+ (s)->cirrus_blt_height * (s)->cirrus_blt_srcpitch \ -+ + ((s)->cirrus_blt_srcaddr & (s)->cirrus_addr_mask) > \ -+ (s)->vram_size \ -+ ) \ -+ ) -+ - struct CirrusVGAState; - typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s, - uint8_t * dst, const uint8_t * src, -@@ -639,7 +653,7 @@ - - for (y = 0; y < lines; y++) { - off_cur = off_begin; -- off_cur_end = off_cur + bytesperline; -+ off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask; - off_cur &= TARGET_PAGE_MASK; - while (off_cur < off_cur_end) { - cpu_physical_memory_set_dirty(s->vram_offset + off_cur); -@@ -654,7 +668,11 @@ - { - uint8_t *dst; - -- dst = s->vram_ptr + s->cirrus_blt_dstaddr; -+ dst = s->vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask); -+ -+ if (BLTUNSAFE(s)) -+ return 0; -+ - (*s->cirrus_rop) (s, dst, src, - s->cirrus_blt_dstpitch, 0, - s->cirrus_blt_width, s->cirrus_blt_height); -@@ -670,8 +688,10 @@ - { - cirrus_fill_t rop_func; - -+ if (BLTUNSAFE(s)) -+ return 0; - rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; -- rop_func(s, s->vram_ptr + s->cirrus_blt_dstaddr, -+ rop_func(s, s->vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), - s->cirrus_blt_dstpitch, - s->cirrus_blt_width, s->cirrus_blt_height); - cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, -@@ -690,8 +710,8 @@ - static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s) - { - return cirrus_bitblt_common_patterncopy(s, -- s->vram_ptr + -- (s->cirrus_blt_srcaddr & ~7)); -+ s->vram_ptr + ((s->cirrus_blt_srcaddr & ~7) & -+ s->cirrus_addr_mask)); - } - - static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) -@@ -741,8 +761,10 @@ - if (notify) - vga_hw_update(); - -- (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr, -- s->vram_ptr + s->cirrus_blt_srcaddr, -+ (*s->cirrus_rop) (s, s->vram_ptr + -+ (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), -+ s->vram_ptr + -+ (s->cirrus_blt_srcaddr & s->cirrus_addr_mask), - s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, - s->cirrus_blt_width, s->cirrus_blt_height); - -@@ -768,8 +790,14 @@ - s->cirrus_blt_srcaddr - s->start_addr, - s->cirrus_blt_width, s->cirrus_blt_height); - } else { -- (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr, -- s->vram_ptr + s->cirrus_blt_srcaddr, -+ -+ if (BLTUNSAFE(s)) -+ return 0; -+ -+ (*s->cirrus_rop) (s, s->vram_ptr + -+ (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), -+ s->vram_ptr + -+ (s->cirrus_blt_srcaddr & s->cirrus_addr_mask), - s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, - s->cirrus_blt_width, s->cirrus_blt_height); - -@@ -801,8 +829,9 @@ - } else { - /* at least one scan line */ - do { -- (*s->cirrus_rop)(s, s->vram_ptr + s->cirrus_blt_dstaddr, -- s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1); -+ (*s->cirrus_rop)(s, s->vram_ptr + -+ (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), -+ s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1); - cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0, - s->cirrus_blt_width, 1); - s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch; -@@ -1920,7 +1949,7 @@ - unsigned val = mem_value; - uint8_t *dst; - -- dst = s->vram_ptr + offset; -+ dst = s->vram_ptr + (offset &= s->cirrus_addr_mask); - for (x = 0; x < 8; x++) { - if (val & 0x80) { - *dst = s->cirrus_shadow_gr1; -@@ -1943,7 +1972,7 @@ - unsigned val = mem_value; - uint8_t *dst; - -- dst = s->vram_ptr + offset; -+ dst = s->vram_ptr + (offset &= s->cirrus_addr_mask); - for (x = 0; x < 8; x++) { - if (val & 0x80) { - *dst = s->cirrus_shadow_gr1; -Index: qemu-0.9.1/hw/cirrus_vga_rop.h -=================================================================== ---- qemu-0.9.1.orig/hw/cirrus_vga_rop.h 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/cirrus_vga_rop.h 2008-04-14 11:26:15.000000000 +0200 -@@ -31,6 +31,12 @@ - int x,y; - dstpitch -= bltwidth; - srcpitch -= bltwidth; -+ -+ if (dstpitch < 0 || srcpitch < 0) { -+ /* is 0 valid? srcpitch == 0 could be useful */ -+ return; -+ } -+ - for (y = 0; y < bltheight; y++) { - for (x = 0; x < bltwidth; x++) { - ROP_OP(*dst, *src); -Index: qemu-0.9.1/hw/dma.c -=================================================================== ---- qemu-0.9.1.orig/hw/dma.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/dma.c 2008-04-14 11:26:15.000000000 +0200 -@@ -341,9 +341,11 @@ - #endif - - r = dma_controllers[ncont].regs + ichan; -- n = r->transfer_handler (r->opaque, ichan + (ncont << 2), -- r->now[COUNT], (r->base[COUNT] + 1) << ncont); -- r->now[COUNT] = n; -+ if (r->transfer_handler) { -+ n = r->transfer_handler (r->opaque, ichan + (ncont << 2), -+ r->now[COUNT], (r->base[COUNT] + 1) << ncont); -+ r->now[COUNT] = n; -+ } - ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont); - } - -Index: qemu-0.9.1/hw/fdc.c -=================================================================== ---- qemu-0.9.1.orig/hw/fdc.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/fdc.c 2008-04-14 11:26:15.000000000 +0200 -@@ -1247,7 +1247,13 @@ - len = fdctrl->data_len - fdctrl->data_pos; - if (len > FD_SECTOR_LEN) - len = FD_SECTOR_LEN; -- bdrv_read(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1); -+ if (cur_drv->bs) { -+ bdrv_read(cur_drv->bs, fd_sector(cur_drv), -+ fdctrl->fifo, 1); -+ } else { -+ FLOPPY_ERROR("can't read data from drive\n"); -+ return 0; -+ } - } - } - retval = fdctrl->fifo[pos]; -Index: qemu-0.9.1/hw/pc.c -=================================================================== ---- qemu-0.9.1.orig/hw/pc.c 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/hw/pc.c 2008-04-14 11:26:15.000000000 +0200 -@@ -329,7 +329,8 @@ +--- qemu-0.9.1+svn20081101.orig/hw/pc.c 2008-11-01 09:30:17.000000000 +0100 ++++ qemu-0.9.1+svn20081101/hw/pc.c 2008-11-01 11:04:55.000000000 +0100 +@@ -382,7 +382,8 @@ case 0x400: case 0x401: fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val); @@ -224,7 +37,7 @@ case 0x402: case 0x403: #ifdef DEBUG_BIOS -@@ -352,8 +353,9 @@ +@@ -405,8 +406,9 @@ /* LGPL'ed VGA BIOS messages */ case 0x501: case 0x502: @@ -235,28 +48,11 @@ case 0x500: case 0x503: #ifdef DEBUG_BIOS -Index: qemu-0.9.1/hw/sb16.c -=================================================================== ---- qemu-0.9.1.orig/hw/sb16.c 2008-01-06 20:38:42.000000000 +0100 -+++ qemu-0.9.1/hw/sb16.c 2008-04-14 11:26:15.000000000 +0200 -@@ -1240,8 +1240,10 @@ - s->block_size); - #endif - -- while (s->left_till_irq <= 0) { -- s->left_till_irq = s->block_size + s->left_till_irq; -+ if (s->block_size) { -+ while (s->left_till_irq <= 0) { -+ s->left_till_irq = s->block_size + s->left_till_irq; -+ } - } - - return dma_pos; -Index: qemu-0.9.1/slirp/slirp.c +Index: qemu-0.9.1+svn20081101/slirp/slirp.c =================================================================== ---- qemu-0.9.1.orig/slirp/slirp.c 2008-01-06 20:38:44.000000000 +0100 -+++ qemu-0.9.1/slirp/slirp.c 2008-04-14 11:26:15.000000000 +0200 -@@ -620,6 +620,10 @@ +--- qemu-0.9.1+svn20081101.orig/slirp/slirp.c 2008-10-17 19:31:57.000000000 +0200 ++++ qemu-0.9.1+svn20081101/slirp/slirp.c 2008-11-01 11:04:55.000000000 +0100 +@@ -654,6 +654,10 @@ if (!m) return; /* Note: we add to align the IP header */ @@ -267,19 +63,19 @@ m->m_len = pkt_len + 2; memcpy(m->m_data + 2, pkt, pkt_len); -Index: qemu-0.9.1/target-i386/translate.c +Index: qemu-0.9.1+svn20081101/target-i386/translate.c =================================================================== ---- qemu-0.9.1.orig/target-i386/translate.c 2008-01-06 20:38:45.000000000 +0100 -+++ qemu-0.9.1/target-i386/translate.c 2008-04-14 11:26:15.000000000 +0200 -@@ -5510,6 +5510,7 @@ +--- qemu-0.9.1+svn20081101.orig/target-i386/translate.c 2008-10-04 13:33:52.000000000 +0200 ++++ qemu-0.9.1+svn20081101/target-i386/translate.c 2008-11-01 11:04:55.000000000 +0100 +@@ -6564,6 +6564,7 @@ gen_jmp_im(pc_start - s->cs_base); - gen_op_into(s->pc - pc_start); + tcg_gen_helper_0_1(helper_into, tcg_const_i32(s->pc - pc_start)); break; +#ifdef WANT_ICEBP case 0xf1: /* icebp (undocumented, exits to external debugger) */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_ICEBP)) - break; -@@ -5521,6 +5522,7 @@ + gen_svm_check_intercept(s, pc_start, SVM_EXIT_ICEBP); + #if 1 +@@ -6574,6 +6575,7 @@ cpu_set_log(CPU_LOG_INT | CPU_LOG_TB_IN_ASM); #endif break; @@ -287,11 +83,11 @@ case 0xfa: /* cli */ if (!s->vm86) { if (s->cpl <= s->iopl) { -Index: qemu-0.9.1/vl.c +Index: qemu-0.9.1+svn20081101/net.c =================================================================== ---- qemu-0.9.1.orig/vl.c 2008-04-14 11:26:14.000000000 +0200 -+++ qemu-0.9.1/vl.c 2008-04-14 11:26:54.000000000 +0200 -@@ -4198,8 +4198,8 @@ +--- qemu-0.9.1+svn20081101.orig/net.c 2008-10-31 20:10:00.000000000 +0100 ++++ qemu-0.9.1+svn20081101/net.c 2008-11-01 11:04:55.000000000 +0100 +@@ -949,8 +949,8 @@ VLANClientState *vc; int fd; int state; /* 0 = getting length, 1 = getting data */ @@ -302,7 +98,7 @@ uint8_t buf[4096]; struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */ } NetSocketState; -@@ -4230,7 +4230,8 @@ +@@ -981,7 +981,8 @@ static void net_socket_send(void *opaque) { NetSocketState *s = opaque; @@ -312,7 +108,7 @@ uint8_t buf1[4096]; const uint8_t *buf; -@@ -4269,7 +4270,15 @@ +@@ -1020,7 +1021,15 @@ l = s->packet_len - s->index; if (l > size) l = size; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/91_security.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/91_security.patch --- qemu-0.9.1/debian/patches/91_security.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/91_security.patch 2008-11-23 23:12:07.000000000 +0000 @@ -218,838 +218,3 @@ if (ret < 0) return ret; if (bdrv_pread(s->hd, 0, &magic, sizeof(magic)) != sizeof(magic)) -diff -Nurd qemu-0.9.1.orig/block-vmdk.c.orig qemu-0.9.1/block-vmdk.c.orig ---- qemu-0.9.1.orig/block-vmdk.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ qemu-0.9.1/block-vmdk.c.orig 2008-01-06 20:38:42.000000000 +0100 -@@ -0,0 +1,831 @@ -+/* -+ * Block driver for the VMDK format -+ * -+ * Copyright (c) 2004 Fabrice Bellard -+ * Copyright (c) 2005 Filip Navara -+ * -+ * 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 "qemu-common.h" -+#include "block_int.h" -+ -+#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D') -+#define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V') -+ -+typedef struct { -+ uint32_t version; -+ uint32_t flags; -+ uint32_t disk_sectors; -+ uint32_t granularity; -+ uint32_t l1dir_offset; -+ uint32_t l1dir_size; -+ uint32_t file_sectors; -+ uint32_t cylinders; -+ uint32_t heads; -+ uint32_t sectors_per_track; -+} VMDK3Header; -+ -+typedef struct { -+ uint32_t version; -+ uint32_t flags; -+ int64_t capacity; -+ int64_t granularity; -+ int64_t desc_offset; -+ int64_t desc_size; -+ int32_t num_gtes_per_gte; -+ int64_t rgd_offset; -+ int64_t gd_offset; -+ int64_t grain_offset; -+ char filler[1]; -+ char check_bytes[4]; -+} __attribute__((packed)) VMDK4Header; -+ -+#define L2_CACHE_SIZE 16 -+ -+typedef struct BDRVVmdkState { -+ BlockDriverState *hd; -+ int64_t l1_table_offset; -+ int64_t l1_backup_table_offset; -+ uint32_t *l1_table; -+ uint32_t *l1_backup_table; -+ unsigned int l1_size; -+ uint32_t l1_entry_sectors; -+ -+ unsigned int l2_size; -+ uint32_t *l2_cache; -+ uint32_t l2_cache_offsets[L2_CACHE_SIZE]; -+ uint32_t l2_cache_counts[L2_CACHE_SIZE]; -+ -+ unsigned int cluster_sectors; -+ uint32_t parent_cid; -+ int is_parent; -+} BDRVVmdkState; -+ -+typedef struct VmdkMetaData { -+ uint32_t offset; -+ unsigned int l1_index; -+ unsigned int l2_index; -+ unsigned int l2_offset; -+ int valid; -+} VmdkMetaData; -+ -+typedef struct ActiveBDRVState{ -+ BlockDriverState *hd; // active image handler -+ uint64_t cluster_offset; // current write offset -+}ActiveBDRVState; -+ -+static ActiveBDRVState activeBDRV; -+ -+ -+static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) -+{ -+ uint32_t magic; -+ -+ if (buf_size < 4) -+ return 0; -+ magic = be32_to_cpu(*(uint32_t *)buf); -+ if (magic == VMDK3_MAGIC || -+ magic == VMDK4_MAGIC) -+ return 100; -+ else -+ return 0; -+} -+ -+#define CHECK_CID 1 -+ -+#define SECTOR_SIZE 512 -+#define DESC_SIZE 20*SECTOR_SIZE // 20 sectors of 512 bytes each -+#define HEADER_SIZE 512 // first sector of 512 bytes -+ -+static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent) -+{ -+ BDRVVmdkState *s = bs->opaque; -+ char desc[DESC_SIZE]; -+ uint32_t cid; -+ char *p_name, *cid_str; -+ size_t cid_str_size; -+ -+ /* the descriptor offset = 0x200 */ -+ if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE) -+ return 0; -+ -+ if (parent) { -+ cid_str = "parentCID"; -+ cid_str_size = sizeof("parentCID"); -+ } else { -+ cid_str = "CID"; -+ cid_str_size = sizeof("CID"); -+ } -+ -+ if ((p_name = strstr(desc,cid_str)) != 0) { -+ p_name += cid_str_size; -+ sscanf(p_name,"%x",&cid); -+ } -+ -+ return cid; -+} -+ -+static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid) -+{ -+ BDRVVmdkState *s = bs->opaque; -+ char desc[DESC_SIZE], tmp_desc[DESC_SIZE]; -+ char *p_name, *tmp_str; -+ -+ /* the descriptor offset = 0x200 */ -+ if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE) -+ return -1; -+ -+ tmp_str = strstr(desc,"parentCID"); -+ strcpy(tmp_desc, tmp_str); -+ if ((p_name = strstr(desc,"CID")) != 0) { -+ p_name += sizeof("CID"); -+ sprintf(p_name,"%x\n",cid); -+ strcat(desc,tmp_desc); -+ } -+ -+ if (bdrv_pwrite(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE) -+ return -1; -+ return 0; -+} -+ -+static int vmdk_is_cid_valid(BlockDriverState *bs) -+{ -+#ifdef CHECK_CID -+ BDRVVmdkState *s = bs->opaque; -+ BlockDriverState *p_bs = s->hd->backing_hd; -+ uint32_t cur_pcid; -+ -+ if (p_bs) { -+ cur_pcid = vmdk_read_cid(p_bs,0); -+ if (s->parent_cid != cur_pcid) -+ // CID not valid -+ return 0; -+ } -+#endif -+ // CID valid -+ return 1; -+} -+ -+static int vmdk_snapshot_create(const char *filename, const char *backing_file) -+{ -+ int snp_fd, p_fd; -+ uint32_t p_cid; -+ char *p_name, *gd_buf, *rgd_buf; -+ const char *real_filename, *temp_str; -+ VMDK4Header header; -+ uint32_t gde_entries, gd_size; -+ int64_t gd_offset, rgd_offset, capacity, gt_size; -+ char p_desc[DESC_SIZE], s_desc[DESC_SIZE], hdr[HEADER_SIZE]; -+ char *desc_template = -+ "# Disk DescriptorFile\n" -+ "version=1\n" -+ "CID=%x\n" -+ "parentCID=%x\n" -+ "createType=\"monolithicSparse\"\n" -+ "parentFileNameHint=\"%s\"\n" -+ "\n" -+ "# Extent description\n" -+ "RW %lu SPARSE \"%s\"\n" -+ "\n" -+ "# The Disk Data Base \n" -+ "#DDB\n" -+ "\n"; -+ -+ snp_fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 0644); -+ if (snp_fd < 0) -+ return -1; -+ p_fd = open(backing_file, O_RDONLY | O_BINARY | O_LARGEFILE); -+ if (p_fd < 0) { -+ close(snp_fd); -+ return -1; -+ } -+ -+ /* read the header */ -+ if (lseek(p_fd, 0x0, SEEK_SET) == -1) -+ goto fail; -+ if (read(p_fd, hdr, HEADER_SIZE) != HEADER_SIZE) -+ goto fail; -+ -+ /* write the header */ -+ if (lseek(snp_fd, 0x0, SEEK_SET) == -1) -+ goto fail; -+ if (write(snp_fd, hdr, HEADER_SIZE) == -1) -+ goto fail; -+ -+ memset(&header, 0, sizeof(header)); -+ memcpy(&header,&hdr[4], sizeof(header)); // skip the VMDK4_MAGIC -+ -+ ftruncate(snp_fd, header.grain_offset << 9); -+ /* the descriptor offset = 0x200 */ -+ if (lseek(p_fd, 0x200, SEEK_SET) == -1) -+ goto fail; -+ if (read(p_fd, p_desc, DESC_SIZE) != DESC_SIZE) -+ goto fail; -+ -+ if ((p_name = strstr(p_desc,"CID")) != 0) { -+ p_name += sizeof("CID"); -+ sscanf(p_name,"%x",&p_cid); -+ } -+ -+ real_filename = filename; -+ if ((temp_str = strrchr(real_filename, '\\')) != NULL) -+ real_filename = temp_str + 1; -+ if ((temp_str = strrchr(real_filename, '/')) != NULL) -+ real_filename = temp_str + 1; -+ if ((temp_str = strrchr(real_filename, ':')) != NULL) -+ real_filename = temp_str + 1; -+ -+ sprintf(s_desc, desc_template, p_cid, p_cid, backing_file -+ , (uint32_t)header.capacity, real_filename); -+ -+ /* write the descriptor */ -+ if (lseek(snp_fd, 0x200, SEEK_SET) == -1) -+ goto fail; -+ if (write(snp_fd, s_desc, strlen(s_desc)) == -1) -+ goto fail; -+ -+ gd_offset = header.gd_offset * SECTOR_SIZE; // offset of GD table -+ rgd_offset = header.rgd_offset * SECTOR_SIZE; // offset of RGD table -+ capacity = header.capacity * SECTOR_SIZE; // Extent size -+ /* -+ * Each GDE span 32M disk, means: -+ * 512 GTE per GT, each GTE points to grain -+ */ -+ gt_size = (int64_t)header.num_gtes_per_gte * header.granularity * SECTOR_SIZE; -+ if (!gt_size) -+ goto fail; -+ gde_entries = (uint32_t)(capacity / gt_size); // number of gde/rgde -+ gd_size = gde_entries * sizeof(uint32_t); -+ -+ /* write RGD */ -+ rgd_buf = qemu_malloc(gd_size); -+ if (!rgd_buf) -+ goto fail; -+ if (lseek(p_fd, rgd_offset, SEEK_SET) == -1) -+ goto fail_rgd; -+ if (read(p_fd, rgd_buf, gd_size) != gd_size) -+ goto fail_rgd; -+ if (lseek(snp_fd, rgd_offset, SEEK_SET) == -1) -+ goto fail_rgd; -+ if (write(snp_fd, rgd_buf, gd_size) == -1) -+ goto fail_rgd; -+ qemu_free(rgd_buf); -+ -+ /* write GD */ -+ gd_buf = qemu_malloc(gd_size); -+ if (!gd_buf) -+ goto fail_rgd; -+ if (lseek(p_fd, gd_offset, SEEK_SET) == -1) -+ goto fail_gd; -+ if (read(p_fd, gd_buf, gd_size) != gd_size) -+ goto fail_gd; -+ if (lseek(snp_fd, gd_offset, SEEK_SET) == -1) -+ goto fail_gd; -+ if (write(snp_fd, gd_buf, gd_size) == -1) -+ goto fail_gd; -+ qemu_free(gd_buf); -+ -+ close(p_fd); -+ close(snp_fd); -+ return 0; -+ -+ fail_gd: -+ qemu_free(gd_buf); -+ fail_rgd: -+ qemu_free(rgd_buf); -+ fail: -+ close(p_fd); -+ close(snp_fd); -+ return -1; -+} -+ -+static void vmdk_parent_close(BlockDriverState *bs) -+{ -+ if (bs->backing_hd) -+ bdrv_close(bs->backing_hd); -+} -+ -+int parent_open = 0; -+static int vmdk_parent_open(BlockDriverState *bs, const char * filename) -+{ -+ BDRVVmdkState *s = bs->opaque; -+ char *p_name; -+ char desc[DESC_SIZE]; -+ char parent_img_name[1024]; -+ -+ /* the descriptor offset = 0x200 */ -+ if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE) -+ return -1; -+ -+ if ((p_name = strstr(desc,"parentFileNameHint")) != 0) { -+ char *end_name; -+ struct stat file_buf; -+ -+ p_name += sizeof("parentFileNameHint") + 1; -+ if ((end_name = strchr(p_name,'\"')) == 0) -+ return -1; -+ -+ strncpy(s->hd->backing_file, p_name, end_name - p_name); -+ if (stat(s->hd->backing_file, &file_buf) != 0) { -+ path_combine(parent_img_name, sizeof(parent_img_name), -+ filename, s->hd->backing_file); -+ } else { -+ strcpy(parent_img_name, s->hd->backing_file); -+ } -+ -+ s->hd->backing_hd = bdrv_new(""); -+ if (!s->hd->backing_hd) { -+ failure: -+ bdrv_close(s->hd); -+ return -1; -+ } -+ parent_open = 1; -+ if (bdrv_open(s->hd->backing_hd, parent_img_name, BDRV_O_RDONLY) < 0) -+ goto failure; -+ parent_open = 0; -+ } -+ -+ return 0; -+} -+ -+static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) -+{ -+ BDRVVmdkState *s = bs->opaque; -+ uint32_t magic; -+ int l1_size, i, ret; -+ -+ if (parent_open) -+ // Parent must be opened as RO. -+ flags = BDRV_O_RDONLY; -+ fprintf(stderr, "(VMDK) image open: flags=0x%x filename=%s\n", flags, bs->filename); -+ -+ ret = bdrv_file_open(&s->hd, filename, flags); -+ if (ret < 0) -+ return ret; -+ if (bdrv_pread(s->hd, 0, &magic, sizeof(magic)) != sizeof(magic)) -+ goto fail; -+ -+ magic = be32_to_cpu(magic); -+ if (magic == VMDK3_MAGIC) { -+ VMDK3Header header; -+ -+ if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header)) -+ goto fail; -+ s->cluster_sectors = le32_to_cpu(header.granularity); -+ s->l2_size = 1 << 9; -+ s->l1_size = 1 << 6; -+ bs->total_sectors = le32_to_cpu(header.disk_sectors); -+ s->l1_table_offset = le32_to_cpu(header.l1dir_offset) << 9; -+ s->l1_backup_table_offset = 0; -+ s->l1_entry_sectors = s->l2_size * s->cluster_sectors; -+ } else if (magic == VMDK4_MAGIC) { -+ VMDK4Header header; -+ -+ if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header)) -+ goto fail; -+ bs->total_sectors = le64_to_cpu(header.capacity); -+ s->cluster_sectors = le64_to_cpu(header.granularity); -+ s->l2_size = le32_to_cpu(header.num_gtes_per_gte); -+ s->l1_entry_sectors = s->l2_size * s->cluster_sectors; -+ if (s->l1_entry_sectors <= 0) -+ goto fail; -+ s->l1_size = (bs->total_sectors + s->l1_entry_sectors - 1) -+ / s->l1_entry_sectors; -+ s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9; -+ s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9; -+ -+ if (parent_open) -+ s->is_parent = 1; -+ else -+ s->is_parent = 0; -+ -+ // try to open parent images, if exist -+ if (vmdk_parent_open(bs, filename) != 0) -+ goto fail; -+ // write the CID once after the image creation -+ s->parent_cid = vmdk_read_cid(bs,1); -+ } else { -+ goto fail; -+ } -+ -+ /* read the L1 table */ -+ l1_size = s->l1_size * sizeof(uint32_t); -+ s->l1_table = qemu_malloc(l1_size); -+ if (!s->l1_table) -+ goto fail; -+ if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, l1_size) != l1_size) -+ goto fail; -+ for(i = 0; i < s->l1_size; i++) { -+ le32_to_cpus(&s->l1_table[i]); -+ } -+ -+ if (s->l1_backup_table_offset) { -+ s->l1_backup_table = qemu_malloc(l1_size); -+ if (!s->l1_backup_table) -+ goto fail; -+ if (bdrv_pread(s->hd, s->l1_backup_table_offset, s->l1_backup_table, l1_size) != l1_size) -+ goto fail; -+ for(i = 0; i < s->l1_size; i++) { -+ le32_to_cpus(&s->l1_backup_table[i]); -+ } -+ } -+ -+ s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t)); -+ if (!s->l2_cache) -+ goto fail; -+ return 0; -+ fail: -+ qemu_free(s->l1_backup_table); -+ qemu_free(s->l1_table); -+ qemu_free(s->l2_cache); -+ bdrv_delete(s->hd); -+ return -1; -+} -+ -+static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data, -+ uint64_t offset, int allocate); -+ -+static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset, -+ uint64_t offset, int allocate) -+{ -+ uint64_t parent_cluster_offset; -+ BDRVVmdkState *s = bs->opaque; -+ uint8_t whole_grain[s->cluster_sectors*512]; // 128 sectors * 512 bytes each = grain size 64KB -+ -+ // we will be here if it's first write on non-exist grain(cluster). -+ // try to read from parent image, if exist -+ if (s->hd->backing_hd) { -+ BDRVVmdkState *ps = s->hd->backing_hd->opaque; -+ -+ if (!vmdk_is_cid_valid(bs)) -+ return -1; -+ -+ parent_cluster_offset = get_cluster_offset(s->hd->backing_hd, NULL, offset, allocate); -+ -+ if (parent_cluster_offset) { -+ BDRVVmdkState *act_s = activeBDRV.hd->opaque; -+ -+ if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) != ps->cluster_sectors*512) -+ return -1; -+ -+ //Write grain only into the active image -+ if (bdrv_pwrite(act_s->hd, activeBDRV.cluster_offset << 9, whole_grain, sizeof(whole_grain)) != sizeof(whole_grain)) -+ return -1; -+ } -+ } -+ return 0; -+} -+ -+static int vmdk_L2update(BlockDriverState *bs, VmdkMetaData *m_data) -+{ -+ BDRVVmdkState *s = bs->opaque; -+ -+ /* update L2 table */ -+ if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)), -+ &(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset)) -+ return -1; -+ /* update backup L2 table */ -+ if (s->l1_backup_table_offset != 0) { -+ m_data->l2_offset = s->l1_backup_table[m_data->l1_index]; -+ if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)), -+ &(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset)) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data, -+ uint64_t offset, int allocate) -+{ -+ BDRVVmdkState *s = bs->opaque; -+ unsigned int l1_index, l2_offset, l2_index; -+ int min_index, i, j; -+ uint32_t min_count, *l2_table, tmp = 0; -+ uint64_t cluster_offset; -+ -+ if (m_data) -+ m_data->valid = 0; -+ -+ l1_index = (offset >> 9) / s->l1_entry_sectors; -+ if (l1_index >= s->l1_size) -+ return 0; -+ l2_offset = s->l1_table[l1_index]; -+ if (!l2_offset) -+ return 0; -+ for(i = 0; i < L2_CACHE_SIZE; i++) { -+ if (l2_offset == s->l2_cache_offsets[i]) { -+ /* increment the hit count */ -+ if (++s->l2_cache_counts[i] == 0xffffffff) { -+ for(j = 0; j < L2_CACHE_SIZE; j++) { -+ s->l2_cache_counts[j] >>= 1; -+ } -+ } -+ l2_table = s->l2_cache + (i * s->l2_size); -+ goto found; -+ } -+ } -+ /* not found: load a new entry in the least used one */ -+ min_index = 0; -+ min_count = 0xffffffff; -+ for(i = 0; i < L2_CACHE_SIZE; i++) { -+ if (s->l2_cache_counts[i] < min_count) { -+ min_count = s->l2_cache_counts[i]; -+ min_index = i; -+ } -+ } -+ l2_table = s->l2_cache + (min_index * s->l2_size); -+ if (bdrv_pread(s->hd, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) != -+ s->l2_size * sizeof(uint32_t)) -+ return 0; -+ -+ s->l2_cache_offsets[min_index] = l2_offset; -+ s->l2_cache_counts[min_index] = 1; -+ found: -+ l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size; -+ cluster_offset = le32_to_cpu(l2_table[l2_index]); -+ -+ if (!cluster_offset) { -+ if (!allocate) -+ return 0; -+ // Avoid the L2 tables update for the images that have snapshots. -+ if (!s->is_parent) { -+ cluster_offset = bdrv_getlength(s->hd); -+ bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9)); -+ -+ cluster_offset >>= 9; -+ tmp = cpu_to_le32(cluster_offset); -+ l2_table[l2_index] = tmp; -+ // Save the active image state -+ activeBDRV.cluster_offset = cluster_offset; -+ activeBDRV.hd = bs; -+ } -+ /* First of all we write grain itself, to avoid race condition -+ * that may to corrupt the image. -+ * This problem may occur because of insufficient space on host disk -+ * or inappropriate VM shutdown. -+ */ -+ if (get_whole_cluster(bs, cluster_offset, offset, allocate) == -1) -+ return 0; -+ -+ if (m_data) { -+ m_data->offset = tmp; -+ m_data->l1_index = l1_index; -+ m_data->l2_index = l2_index; -+ m_data->l2_offset = l2_offset; -+ m_data->valid = 1; -+ } -+ } -+ cluster_offset <<= 9; -+ return cluster_offset; -+} -+ -+static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num, -+ int nb_sectors, int *pnum) -+{ -+ BDRVVmdkState *s = bs->opaque; -+ int index_in_cluster, n; -+ uint64_t cluster_offset; -+ -+ cluster_offset = get_cluster_offset(bs, NULL, sector_num << 9, 0); -+ index_in_cluster = sector_num % s->cluster_sectors; -+ n = s->cluster_sectors - index_in_cluster; -+ if (n > nb_sectors) -+ n = nb_sectors; -+ *pnum = n; -+ return (cluster_offset != 0); -+} -+ -+static int vmdk_read(BlockDriverState *bs, int64_t sector_num, -+ uint8_t *buf, int nb_sectors) -+{ -+ BDRVVmdkState *s = bs->opaque; -+ int index_in_cluster, n, ret; -+ uint64_t cluster_offset; -+ -+ while (nb_sectors > 0) { -+ cluster_offset = get_cluster_offset(bs, NULL, sector_num << 9, 0); -+ index_in_cluster = sector_num % s->cluster_sectors; -+ n = s->cluster_sectors - index_in_cluster; -+ if (n > nb_sectors) -+ n = nb_sectors; -+ if (!cluster_offset) { -+ // try to read from parent image, if exist -+ if (s->hd->backing_hd) { -+ if (!vmdk_is_cid_valid(bs)) -+ return -1; -+ ret = bdrv_read(s->hd->backing_hd, sector_num, buf, n); -+ if (ret < 0) -+ return -1; -+ } else { -+ memset(buf, 0, 512 * n); -+ } -+ } else { -+ if(bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512) -+ return -1; -+ } -+ nb_sectors -= n; -+ sector_num += n; -+ buf += n * 512; -+ } -+ return 0; -+} -+ -+static int vmdk_write(BlockDriverState *bs, int64_t sector_num, -+ const uint8_t *buf, int nb_sectors) -+{ -+ BDRVVmdkState *s = bs->opaque; -+ VmdkMetaData m_data; -+ int index_in_cluster, n; -+ uint64_t cluster_offset; -+ static int cid_update = 0; -+ -+ if (sector_num > bs->total_sectors) { -+ fprintf(stderr, -+ "(VMDK) Wrong offset: sector_num=0x%" PRIx64 -+ " total_sectors=0x%" PRIx64 "\n", -+ sector_num, bs->total_sectors); -+ return -1; -+ } -+ -+ while (nb_sectors > 0) { -+ index_in_cluster = sector_num & (s->cluster_sectors - 1); -+ n = s->cluster_sectors - index_in_cluster; -+ if (n > nb_sectors) -+ n = nb_sectors; -+ cluster_offset = get_cluster_offset(bs, &m_data, sector_num << 9, 1); -+ if (!cluster_offset) -+ return -1; -+ -+ if (bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512) -+ return -1; -+ if (m_data.valid) { -+ /* update L2 tables */ -+ if (vmdk_L2update(bs, &m_data) == -1) -+ return -1; -+ } -+ nb_sectors -= n; -+ sector_num += n; -+ buf += n * 512; -+ -+ // update CID on the first write every time the virtual disk is opened -+ if (!cid_update) { -+ vmdk_write_cid(bs, time(NULL)); -+ cid_update++; -+ } -+ } -+ return 0; -+} -+ -+static int vmdk_create(const char *filename, int64_t total_size, -+ const char *backing_file, int flags) -+{ -+ int fd, i; -+ VMDK4Header header; -+ uint32_t tmp, magic, grains, gd_size, gt_size, gt_count; -+ char *desc_template = -+ "# Disk DescriptorFile\n" -+ "version=1\n" -+ "CID=%x\n" -+ "parentCID=ffffffff\n" -+ "createType=\"monolithicSparse\"\n" -+ "\n" -+ "# Extent description\n" -+ "RW %lu SPARSE \"%s\"\n" -+ "\n" -+ "# The Disk Data Base \n" -+ "#DDB\n" -+ "\n" -+ "ddb.virtualHWVersion = \"%d\"\n" -+ "ddb.geometry.cylinders = \"%lu\"\n" -+ "ddb.geometry.heads = \"16\"\n" -+ "ddb.geometry.sectors = \"63\"\n" -+ "ddb.adapterType = \"ide\"\n"; -+ char desc[1024]; -+ const char *real_filename, *temp_str; -+ -+ /* XXX: add support for backing file */ -+ if (backing_file) { -+ return vmdk_snapshot_create(filename, backing_file); -+ } -+ -+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, -+ 0644); -+ if (fd < 0) -+ return -1; -+ magic = cpu_to_be32(VMDK4_MAGIC); -+ memset(&header, 0, sizeof(header)); -+ header.version = cpu_to_le32(1); -+ header.flags = cpu_to_le32(3); /* ?? */ -+ header.capacity = cpu_to_le64(total_size); -+ header.granularity = cpu_to_le64(128); -+ header.num_gtes_per_gte = cpu_to_le32(512); -+ -+ grains = (total_size + header.granularity - 1) / header.granularity; -+ gt_size = ((header.num_gtes_per_gte * sizeof(uint32_t)) + 511) >> 9; -+ gt_count = (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte; -+ gd_size = (gt_count * sizeof(uint32_t) + 511) >> 9; -+ -+ header.desc_offset = 1; -+ header.desc_size = 20; -+ header.rgd_offset = header.desc_offset + header.desc_size; -+ header.gd_offset = header.rgd_offset + gd_size + (gt_size * gt_count); -+ header.grain_offset = -+ ((header.gd_offset + gd_size + (gt_size * gt_count) + -+ header.granularity - 1) / header.granularity) * -+ header.granularity; -+ -+ header.desc_offset = cpu_to_le64(header.desc_offset); -+ header.desc_size = cpu_to_le64(header.desc_size); -+ header.rgd_offset = cpu_to_le64(header.rgd_offset); -+ header.gd_offset = cpu_to_le64(header.gd_offset); -+ header.grain_offset = cpu_to_le64(header.grain_offset); -+ -+ header.check_bytes[0] = 0xa; -+ header.check_bytes[1] = 0x20; -+ header.check_bytes[2] = 0xd; -+ header.check_bytes[3] = 0xa; -+ -+ /* write all the data */ -+ write(fd, &magic, sizeof(magic)); -+ write(fd, &header, sizeof(header)); -+ -+ ftruncate(fd, header.grain_offset << 9); -+ -+ /* write grain directory */ -+ lseek(fd, le64_to_cpu(header.rgd_offset) << 9, SEEK_SET); -+ for (i = 0, tmp = header.rgd_offset + gd_size; -+ i < gt_count; i++, tmp += gt_size) -+ write(fd, &tmp, sizeof(tmp)); -+ -+ /* write backup grain directory */ -+ lseek(fd, le64_to_cpu(header.gd_offset) << 9, SEEK_SET); -+ for (i = 0, tmp = header.gd_offset + gd_size; -+ i < gt_count; i++, tmp += gt_size) -+ write(fd, &tmp, sizeof(tmp)); -+ -+ /* compose the descriptor */ -+ real_filename = filename; -+ if ((temp_str = strrchr(real_filename, '\\')) != NULL) -+ real_filename = temp_str + 1; -+ if ((temp_str = strrchr(real_filename, '/')) != NULL) -+ real_filename = temp_str + 1; -+ if ((temp_str = strrchr(real_filename, ':')) != NULL) -+ real_filename = temp_str + 1; -+ sprintf(desc, desc_template, time(NULL), (unsigned long)total_size, -+ real_filename, (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), total_size / (63 * 16)); -+ -+ /* write the descriptor */ -+ lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET); -+ write(fd, desc, strlen(desc)); -+ -+ close(fd); -+ return 0; -+} -+ -+static void vmdk_close(BlockDriverState *bs) -+{ -+ BDRVVmdkState *s = bs->opaque; -+ -+ qemu_free(s->l1_table); -+ qemu_free(s->l2_cache); -+ bdrv_delete(s->hd); -+ // try to close parent image, if exist -+ vmdk_parent_close(s->hd); -+} -+ -+static void vmdk_flush(BlockDriverState *bs) -+{ -+ BDRVVmdkState *s = bs->opaque; -+ bdrv_flush(s->hd); -+} -+ -+BlockDriver bdrv_vmdk = { -+ "vmdk", -+ sizeof(BDRVVmdkState), -+ vmdk_probe, -+ vmdk_open, -+ vmdk_read, -+ vmdk_write, -+ vmdk_close, -+ vmdk_create, -+ vmdk_flush, -+ vmdk_is_allocated, -+}; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/91_vmdk_compat6_scsi.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/91_vmdk_compat6_scsi.patch --- qemu-0.9.1/debian/patches/91_vmdk_compat6_scsi.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/91_vmdk_compat6_scsi.patch 2008-11-23 23:12:07.000000000 +0000 @@ -1,10 +1,10 @@ === modified file 'block-qcow.c' Index: block-vmdk.c =================================================================== ---- block-vmdk.c.orig 2008-02-13 01:47:53.210756922 +0100 -+++ block-vmdk.c 2008-02-13 01:50:14.622757082 +0100 -@@ -717,7 +717,7 @@ - "ddb.geometry.cylinders = \"%lu\"\n" +--- block-vmdk.c.orig 2008-10-28 15:08:49.000000000 +0100 ++++ block-vmdk.c 2008-11-23 21:53:13.135739816 +0100 +@@ -719,7 +719,7 @@ + "ddb.geometry.cylinders = \"%" PRId64 "\"\n" "ddb.geometry.heads = \"16\"\n" "ddb.geometry.sectors = \"63\"\n" - "ddb.adapterType = \"ide\"\n"; @@ -12,19 +12,20 @@ char desc[1024]; const char *real_filename, *temp_str; -@@ -790,7 +790,7 @@ - if ((temp_str = strrchr(real_filename, ':')) != NULL) - real_filename = temp_str + 1; - sprintf(desc, desc_template, time(NULL), (unsigned long)total_size, -- real_filename, (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), total_size / (63 * 16)); -+ real_filename, (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), total_size / (63 * 16), (flags & BLOCK_FLAG_SCSI ? "lsilogic" : "ide")); +@@ -794,7 +794,8 @@ + snprintf(desc, sizeof(desc), desc_template, (unsigned int)time(NULL), + total_size, real_filename, + (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), +- total_size / (int64_t)(63 * 16)); ++ total_size / (int64_t)(63 * 16), ++ (flags & BLOCK_FLAG_SCSI ? "lsilogic" : "ide")); /* write the descriptor */ lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET); Index: block_int.h =================================================================== ---- block_int.h.orig 2008-02-13 01:47:53.254757343 +0100 -+++ block_int.h 2008-02-13 01:50:14.634756804 +0100 +--- block_int.h.orig 2008-11-08 17:27:07.000000000 +0100 ++++ block_int.h 2008-11-23 21:52:04.315738113 +0100 @@ -29,6 +29,7 @@ #define BLOCK_FLAG_ENCRYPT 1 #define BLOCK_FLAG_COMPRESS 2 @@ -35,21 +36,21 @@ const char *format_name; Index: qemu-img.c =================================================================== ---- qemu-img.c.orig 2008-02-13 01:47:53.286758042 +0100 -+++ qemu-img.c 2008-02-13 01:50:27.554756688 +0100 -@@ -88,9 +88,9 @@ +--- qemu-img.c.orig 2008-08-24 12:30:33.000000000 +0200 ++++ qemu-img.c 2008-11-23 21:54:19.407736815 +0100 +@@ -53,9 +53,9 @@ "QEMU disk image utility\n" "\n" "Command syntax:\n" - " create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n" + " create [-e] [-6] [-s] [-b base_image] [-f fmt] filename [size]\n" " commit [-f fmt] filename\n" -- " convert [-c] [-e] [-6] [-f fmt] filename [filename2 [...]] [-O output_fmt] output_filename\n" -+ " convert [-c] [-e] [-6] [-s] [-f fmt] filename [filename2 [...]] [-O output_fmt] output_filename\n" +- " convert [-c] [-e] [-6] [-f fmt] [-O output_fmt] [-B output_base_image] filename [filename2 [...]] output_filename\n" ++ " convert [-c] [-e] [-6] [-s] [-f fmt] [-O output_fmt] [-B output_base_image] filename [filename2 [...]] output_filename\n" " info [-f fmt] filename\n" "\n" "Command parameters:\n" -@@ -105,6 +105,7 @@ +@@ -74,6 +74,7 @@ " '-c' indicates that target image must be compressed (qcow format only)\n" " '-e' indicates that the target image must be encrypted (qcow format only)\n" " '-6' indicates that the target image must use compatibility level 6 (vmdk format only)\n" @@ -57,7 +58,7 @@ ); printf("\nSupported format:"); bdrv_iterate_format(format_print, NULL); -@@ -242,7 +243,7 @@ +@@ -211,7 +212,7 @@ flags = 0; for(;;) { @@ -66,7 +67,7 @@ if (c == -1) break; switch(c) { -@@ -261,6 +262,9 @@ +@@ -230,6 +231,9 @@ case '6': flags |= BLOCK_FLAG_COMPAT6; break; @@ -76,7 +77,7 @@ } } if (optind >= argc) -@@ -297,6 +301,8 @@ +@@ -266,6 +270,8 @@ printf(", encrypted"); if (flags & BLOCK_FLAG_COMPAT6) printf(", compatibility level=6"); @@ -85,16 +86,7 @@ if (base_filename) { printf(", backing_file=%s", base_filename); -@@ -421,7 +427,7 @@ - out_fmt = "raw"; - flags = 0; - for(;;) { -- c = getopt(argc, argv, "f:O:hce6"); -+ c = getopt(argc, argv, "f:O:hce6s"); - if (c == -1) - break; - switch(c) { -@@ -443,6 +449,9 @@ +@@ -423,6 +429,9 @@ case '6': flags |= BLOCK_FLAG_COMPAT6; break; @@ -106,8 +98,8 @@ Index: qemu-img.texi =================================================================== ---- qemu-img.texi.orig 2008-02-13 01:47:53.294757321 +0100 -+++ qemu-img.texi 2008-02-13 01:50:14.698756750 +0100 +--- qemu-img.texi.orig 2008-06-05 23:53:49.000000000 +0200 ++++ qemu-img.texi 2008-11-23 21:54:45.605828822 +0100 @@ -8,9 +8,9 @@ The following commands are supported: @@ -115,12 +107,12 @@ -@item create [-e] [-6] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}] +@item create [-e] [-6] [-s] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}] @item commit [-f @var{fmt}] @var{filename} --@item convert [-c] [-e] [-6] [-f @var{fmt}] @var{filename} [-O @var{output_fmt}] @var{output_filename} -+@item convert [-c] [-e] [-6] [-s] [-f @var{fmt}] @var{filename} [-O @var{output_fmt}] @var{output_filename} +-@item convert [-c] [-e] [-6] [-f @var{fmt}] [-O @var{output_fmt}] [-B @var{output_base_image}] @var{filename} [@var{filename2} [...]] @var{output_filename} ++@item convert [-c] [-e] [-6] [-s] [-f @var{fmt}] [-O @var{output_fmt}] [-B @var{output_base_image}] @var{filename} [@var{filename2} [...]] @var{output_filename} @item info [-f @var{fmt}] @var{filename} @end table -@@ -69,12 +69,14 @@ +@@ -73,12 +73,14 @@ indicates that the target image must be encrypted (qcow format only) @item -6 indicates that the target image must use compatibility level 6 (vmdk format only) @@ -136,7 +128,7 @@ Create the new disk image @var{filename} of size @var{size} and format @var{fmt}. -@@ -88,7 +90,7 @@ +@@ -92,7 +94,7 @@ Commit the changes recorded in @var{filename} in its base image. diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/92_no_shutdown.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/92_no_shutdown.patch --- qemu-0.9.1/debian/patches/92_no_shutdown.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/92_no_shutdown.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,71 +0,0 @@ -commit dfe25b09e14cc6bdffe7c899f857affc9130309f -Author: aurel32 -Date: Fri Apr 11 21:35:52 2008 +0000 - - Stop before shutdown - - (Eduardo Felipe) - - - git-svn-id: svn+ssh://svn.savannah.nongnu.org/qemu/trunk@4192 c046a42c-6fe2-441c-8c8c-71466251a162 - -Index: qemu-0.9.1/vl.c -=================================================================== ---- qemu-0.9.1.orig/vl.c 2008-04-14 11:26:15.000000000 +0200 -+++ qemu-0.9.1/vl.c 2008-04-14 11:26:15.000000000 +0200 -@@ -216,6 +216,7 @@ - int acpi_enabled = 1; - int fd_bootchk = 1; - int no_reboot = 0; -+int no_shutdown = 0; - int cursor_hide = 1; - int graphic_rotate = 0; - int daemonize = 0; -@@ -7490,7 +7491,12 @@ - - if (shutdown_requested) { - ret = EXCP_INTERRUPT; -- break; -+ if (no_shutdown) { -+ vm_stop(0); -+ no_shutdown = 0; -+ } -+ else -+ break; - } - if (reset_requested) { - reset_requested = 0; -@@ -7649,6 +7655,7 @@ - "-curses use a curses/ncurses interface instead of SDL\n" - #endif - "-no-reboot exit instead of rebooting\n" -+ "-no-shutdown stop before shutdown\n" - "-loadvm file start right away with a saved state (loadvm in monitor)\n" - "-vnc display start a VNC server on display\n" - #ifndef _WIN32 -@@ -7754,6 +7761,7 @@ - QEMU_OPTION_no_acpi, - QEMU_OPTION_curses, - QEMU_OPTION_no_reboot, -+ QEMU_OPTION_no_shutdown, - QEMU_OPTION_show_cursor, - QEMU_OPTION_daemonize, - QEMU_OPTION_option_rom, -@@ -7859,6 +7867,7 @@ - { "vmwarevga", 0, QEMU_OPTION_vmsvga }, - { "no-acpi", 0, QEMU_OPTION_no_acpi }, - { "no-reboot", 0, QEMU_OPTION_no_reboot }, -+ { "no-shutdown", 0, QEMU_OPTION_no_shutdown }, - { "show-cursor", 0, QEMU_OPTION_show_cursor }, - { "daemonize", 0, QEMU_OPTION_daemonize }, - { "option-rom", HAS_ARG, QEMU_OPTION_option_rom }, -@@ -8641,6 +8650,9 @@ - case QEMU_OPTION_no_reboot: - no_reboot = 1; - break; -+ case QEMU_OPTION_no_shutdown: -+ no_shutdown = 1; -+ break; - case QEMU_OPTION_show_cursor: - cursor_hide = 0; - break; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/93_tmpfs.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/93_tmpfs.patch --- qemu-0.9.1/debian/patches/93_tmpfs.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/93_tmpfs.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,24 +0,0 @@ -commit b25b2e302ddaeb3a674892cf9b3f50a92fb8c26c -Author: aurel32 -Date: Sun Apr 20 21:10:41 2008 +0000 - - Use "mount -o remount" instead of "umount" and "mount /dev/shm", - which results in emptying this virtual file system. - - - git-svn-id: svn+ssh://svn.savannah.nongnu.org/qemu/trunk@4228 c046a42c-6fe2-441c-8c8c-71466251a162 - -diff --git a/osdep.c b/osdep.c -index 64bc16e..ae7e3fb 100644 ---- a/osdep.c -+++ b/osdep.c -@@ -107,8 +107,7 @@ static void *kqemu_vmalloc(size_t size) - tmpdir, ram_mb); - if (strcmp(tmpdir, "/dev/shm") == 0) { - fprintf(stderr, "To have more space available provided you have enough RAM and swap, do as root:\n" -- "umount /dev/shm\n" -- "mount -t tmpfs -o size=%dm none /dev/shm\n", -+ "mount -o remount,size=%dm /dev/shm\n", - ram_mb + 16); - } else { - fprintf(stderr, diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/94_security.patch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/94_security.patch --- qemu-0.9.1/debian/patches/94_security.patch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/94_security.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,77 +0,0 @@ -commit 2e095576078414ffd9a918b5dbcdaeb870d20b1f -Author: Aurelien Jarno -Date: Mon Apr 28 21:53:44 2008 +0200 - - add format= to drive options (CVE-2008-2004) - - It is possible for a guest with a raw formatted disk image to write a - header to that disk image describing another format (such as qcow2). - Stopping and subsequent restart of the guest will cause qemu to detect - that format, and could allow the guest to read any host file if qemu is - sufficiently privileged (typical in virt environments). - - The patch defaults to existing behaviour (probing based on file contents), - so it still requires the mgmt app (e.g. libvirt xml) to pass a new - "format=raw" parameter for raw disk images. - - Originally noted by Avi Kivity, patch from Chris Wright. - -diff --git a/qemu-doc.texi b/qemu-doc.texi -index 45c89ce..1f409f4 100644 ---- a/qemu-doc.texi -+++ b/qemu-doc.texi -@@ -261,6 +261,10 @@ These options have the same definition as they have in @option{-hdachs}. - @var{snapshot} is "on" or "off" and allows to enable snapshot for given drive (see @option{-snapshot}). - @item cache=@var{cache} - @var{cache} is "on" or "off" and allows to disable host cache to access data. -+@item format=@var{format} -+Specify which disk @var{format} will be used rather than detecting -+the format. Can be used to specifiy format=raw to avoid interpreting -+an untrusted format header. - @end table - - Instead of @option{-cdrom} you can use: -diff --git a/vl.c b/vl.c -index c30a87f..728e07e 100644 ---- a/vl.c -+++ b/vl.c -@@ -4912,13 +4912,14 @@ - int bus_id, unit_id; - int cyls, heads, secs, translation; - BlockDriverState *bdrv; -+ BlockDriver *drv = NULL; - int max_devs; - int index; - int cache; - int bdrv_flags; - char *params[] = { "bus", "unit", "if", "index", "cyls", "heads", - "secs", "trans", "media", "snapshot", "file", -- "cache", NULL }; -+ "cache", "format", NULL }; - - if (check_params(buf, sizeof(buf), params, str) < 0) { - fprintf(stderr, "qemu: unknowm parameter '%s' in '%s'\n", -@@ -5086,6 +5087,14 @@ - } - } - -+ if (get_param_value(buf, sizeof(buf), "format", str)) { -+ drv = bdrv_find_format(buf); -+ if (!drv) { -+ fprintf(stderr, "qemu: '%s' invalid format\n", buf); -+ return -1; -+ } -+ } -+ - get_param_value(file, sizeof(file), "file", str); - - /* compute bus and unit according index */ -@@ -5185,7 +5194,7 @@ - bdrv_flags |= BDRV_O_SNAPSHOT; - if (!cache) - bdrv_flags |= BDRV_O_DIRECT; -- if (bdrv_open(bdrv, file, bdrv_flags) < 0 || qemu_key_check(bdrv, file)) { -+ if (bdrv_open2(bdrv, file, bdrv_flags, drv) < 0 || qemu_key_check(bdrv, file)) { - fprintf(stderr, "qemu: could not open disk image %s\n", - file); - return -1; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/patches/series /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/patches/series --- qemu-0.9.1/debian/patches/series 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/patches/series 2008-11-23 23:12:07.000000000 +0000 @@ -1,48 +1,25 @@ +00_bios.patch 01_nostrip.patch -02_snapshot_use_tmpdir.patch -p0 -04_do_not_print_rtc_freq_if_ok.patch -05_non-fatal_if_linux_hd_missing.patch -06_exit_segfault.patch -p0 +06_exit_segfault.patch 07_i386_exec_name.patch -10_signal_jobs.patch -p0 -11_signal_sigaction.patch -p0 -12_signal_powerpc_support.patch -p0 -21_net_soopts.patch -p0 -22_net_tuntap_stall.patch -p0 -30_syscall_ipc.patch -p0 +10_signal_jobs.patch +11_signal_sigaction.patch +12_signal_powerpc_support.patch +21_net_soopts.patch +30_syscall_ipc.patch 31_syscalls.patch -32_syscall_sysctl.patch -p0 -33_syscall_ppc_clone.patch -p0 +32_syscall_sysctl.patch 35_syscall_sockaddr.patch -39_syscall_fadvise64.patch -p0 -41_arm_fpa_sigfpe.patch -p0 -42_arm_tls.patch -#43_arm_cpustate.patch -50_linuxbios_isa_bios_ram.patch -p0 -51_linuxbios_piix_ram_size.patch -p0 -53_openbios_size.patch +44_socklen_t_check.patch +48_signal_terminate.patch +49_null_check.patch +50_linuxbios_isa_bios_ram.patch +51_linuxbios_piix_ram_size.patch 55_unmux_socketcall.patch 60_ppc_ld.patch -63_sparc_build.patch -p0 64_ppc_asm_constraints.patch 65_kfreebsd.patch -66_tls_ld.patch -p0 -70_manpage.patch -p0 -71_doc.patch -80_ui_curses.patch -91_vmdk_compat6_scsi.patch -p0 -81_mips32r2_fpu.patch -82_mips_abs.patch -83_usb-serial.patch -84_rtl8139.patch -85_vvfat.patch -86_df.patch -87_eoi.patch -88_dma.patch -89_braille.patch +66_tls_ld.patch 90_security.patch -92_no_shutdown.patch -93_tmpfs.patch -94_security.patch +91_vmdk_compat6_scsi.patch -p0 95_evdev_keycode_map.patch -96_dirent.patch diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/qemu.dirs /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/qemu.dirs --- qemu-0.9.1/debian/qemu.dirs 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/debian/qemu.dirs 2008-11-23 23:12:07.000000000 +0000 @@ -0,0 +1 @@ +usr/share/qemu/ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/qemu.docs /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/qemu.docs --- qemu-0.9.1/debian/qemu.docs 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/debian/qemu.docs 2008-11-23 23:12:07.000000000 +0000 @@ -0,0 +1,4 @@ +README +TODO +qemu-doc.html +debian/tundev.c diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/qemu.install /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/qemu.install --- qemu-0.9.1/debian/qemu.install 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/debian/qemu.install 2008-11-23 23:12:07.000000000 +0000 @@ -0,0 +1,3 @@ +debian/qemu-ifup etc/ +debian/qemu-make-debian-root usr/sbin/ +debian/overrides/qemu usr/share/lintian/overrides/ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/qemu.links /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/qemu.links --- qemu-0.9.1/debian/qemu.links 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/debian/qemu.links 2008-11-23 23:12:07.000000000 +0000 @@ -0,0 +1,40 @@ +usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-alpha.1 +usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-cris.1 +usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-arm.1 +usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-armeb.1 +usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-i386.1 +usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-m68k.1 +usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-mips.1 +usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-mipsel.1 +usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-ppc.1 +usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-ppc64.1 +usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-ppc64abi32.1 +usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-sh4.1 +usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-sh4eb.1 +usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-sparc.1 +usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-sparc32plus.1 +usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-sparc64.1 +usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-x86_64.1 +usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-arm.1 +usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-cris.1 +usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-i386.1 +usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-m68k.1 +usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-mips.1 +usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-mips64.1 +usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-mips64el.1 +usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-mipsel.1 +usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-ppc.1 +usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-ppc64.1 +usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-ppcemb.1 +usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-sh4.1 +usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-sh4eb.1 +usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-sparc.1 +usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-sparc64.1 +usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-x86_64.1 +usr/share/bochs/BIOS-qemu-latest usr/share/qemu/bios.bin +usr/share/vgabios/vgabios.bin usr/share/qemu/vgabios.bin +usr/share/vgabios/vgabios.cirrus.bin usr/share/qemu/vgabios-cirrus.bin +usr/share/proll/proll-qemu.elf usr/share/qemu/proll.elf +usr/share/openhackware/ppc_rom.bin usr/share/qemu/ppc_rom.bin +usr/share/openbios/openbios-sparc32 usr/share/qemu/openbios-sparc32 +usr/share/openbios/openbios-sparc64 usr/share/qemu/openbios-sparc64 diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/qemu-make-debian-root /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/qemu-make-debian-root --- qemu-0.9.1/debian/qemu-make-debian-root 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/qemu-make-debian-root 2008-11-23 23:12:07.000000000 +0000 @@ -1,6 +1,6 @@ #! /bin/sh # -# $Id: qemu-make-debian-root 351 2008-10-16 20:20:49Z aurel32 $ +# $Id: qemu-make-debian-root 353 2008-10-16 20:28:22Z aurel32 $ # # Script to make a debian root image. # diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/qemu-make-debian-root.8 /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/qemu-make-debian-root.8 --- qemu-0.9.1/debian/qemu-make-debian-root.8 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/qemu-make-debian-root.8 2008-11-23 23:12:07.000000000 +0000 @@ -1,4 +1,4 @@ -.\" $Id: qemu-make-debian-root.8 266 2008-01-06 20:29:04Z aurel32 $ +.\" $Id: qemu-make-debian-root.8 325 2008-08-09 21:39:16Z aurel32 $ .TH qemu\-make\-debian\-root 8 2006-05-28 "0.0" Debian .\" Please adjust this date whenever revising the manpage. .\" diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/qemu.manpages /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/qemu.manpages --- qemu-0.9.1/debian/qemu.manpages 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/debian/qemu.manpages 2008-11-23 23:12:07.000000000 +0000 @@ -0,0 +1,2 @@ +debian/qemu-make-debian-root.8 +debian/qemu-user.1 diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/qemu-user.1 /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/qemu-user.1 --- qemu-0.9.1/debian/qemu-user.1 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/qemu-user.1 2008-11-23 23:12:07.000000000 +0000 @@ -1,4 +1,4 @@ -.\" $Id: qemu-user.1 234 2007-02-07 22:57:18Z guillem $ +.\" $Id: qemu-user.1 325 2008-08-09 21:39:16Z aurel32 $ .TH qemu\-user 1 2007-02-08 "0.9.0" Debian .SH NAME qemu\-user \- QEMU User Emulator diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/README.source /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/README.source --- qemu-0.9.1/debian/README.source 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/debian/README.source 2008-11-23 23:12:07.000000000 +0000 @@ -0,0 +1,57 @@ +This package uses quilt to manage all modifications to the upstream +source. Changes are stored in the source package as diffs in +debian/patches and applied during the build. + +To configure quilt to use debian/patches instead of patches, you want +either to export QUILT_PATCHES=debian/patches in your environment +or use this snippet in your ~/.quiltrc: + + for where in ./ ../ ../../ ../../../ ../../../../ ../../../../../; do + if [ -e ${where}debian/rules -a -d ${where}debian/patches ]; then + export QUILT_PATCHES=debian/patches + fi + done + +To get the fully patched source after unpacking the source package, cd to +the root level of the source package and run: + + quilt push -a + +The last patch listed in debian/patches/series will become the current +patch. + +To add a new set of changes, first run quilt push -a, and then run: + + quilt new + +where is a descriptive name for the patch, used as the filename in +debian/patches. Then, for every file that will be modified by this patch, +run: + + quilt add + +before editing those files. You must tell quilt with quilt add what files +will be part of the patch before making changes or quilt will not work +properly. After editing the files, run: + + quilt refresh + +to save the results as a patch. + +Alternately, if you already have an external patch and you just want to +add it to the build system, run quilt push -a and then: + + quilt import -P /path/to/patch + quilt push -a + +(add -p 0 to quilt import if needed). as above is the filename to +use in debian/patches. The last quilt push -a will apply the patch to +make sure it works properly. + +To remove an existing patch from the list of patches that will be applied, +run: + + quilt delete + +You may need to run quilt pop -a to unapply patches first before running +this command. diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/rules /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/rules --- qemu-0.9.1/debian/rules 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/rules 2008-11-23 23:12:07.000000000 +0000 @@ -1,10 +1,8 @@ #!/usr/bin/make -f # -# $Id: rules 320 2008-04-23 00:17:18Z guillem $ +# $Id: rules 348 2008-10-12 16:55:44Z aurel32 $ # -DEB_HOST_ARCH_OS = $(shell dpkg-architecture -qDEB_HOST_ARCH_OS) - # WARNING: Removing no-strict-aliasing will make qemu insta-segfault. CFLAGS = -Wall -g -fno-strict-aliasing @@ -14,29 +12,49 @@ CFLAGS += -O2 endif -ifeq ($(DEB_HOST_ARCH_OS),linux) - conf_arch += --enable-alsa -endif - # Support multiple makes at once ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) NJOBS := -j $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) endif -D = $(CURDIR)/debian/qemu +# Architecture/system specific configuration +DEB_HOST_ARCH = $(shell dpkg-architecture -qDEB_HOST_ARCH) +DEB_HOST_ARCH_OS = $(shell dpkg-architecture -qDEB_HOST_ARCH_OS) +DEB_HOST_ARCH_CPU = $(shell dpkg-architecture -qDEB_HOST_ARCH_CPU) + +TARGET_SYSTEM_TCG = arm-softmmu cris-softmmu i386-softmmu m68k-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu sh4-softmmu sh4eb-softmmu sparc-softmmu sparc64-softmmu x86_64-softmmu +TARGET_SYSTEM_DYNGEN = ppc-softmmu ppcemb-softmmu ppc64-softmmu +TARGET_LINUX_TCG = alpha-linux-user arm-linux-user armeb-linux-user cris-linux-user i386-linux-user m68k-linux-user mips-linux-user mipsel-linux-user sh4-linux-user sh4eb-linux-user sparc-linux-user sparc64-linux-user sparc32plus-linux-user x86_64-linux-user +TARGET_LINUX_DYNGEN = ppc-linux-user ppc64-linux-user ppc64abi32-linux-user -qemu_bios_files = \ - bios.bin \ - vgabios.bin \ - vgabios-cirrus.bin \ - video.x \ - openbios-sparc32 \ - openbios-sparc64 \ - pxe-ne2k_pci.bin \ - pxe-rtl8139.bin \ - pxe-pcnet.bin \ - ppc_rom.bin \ - proll.elf +target_system_list += $(TARGET_SYSTEM_TCG) + +ifneq (,$(filter $(DEB_HOST_ARCH),amd64 i386 powerpc kfreebsd-i386)) + target_system_list += $(TARGET_SYSTEM_DYNGEN) +else + conf_arch += --cc=gcc --disable-gcc-check +endif + +ifeq ($(DEB_HOST_ARCH_OS),linux) + conf_arch += --audio-drv-list=oss,alsa,sdl,esd,pa + target_linux_list += $(TARGET_LINUX_TCG) +endif +ifeq ($(DEB_HOST_ARCH_OS),kfreebsd) + conf_arch += --audio-drv-list=oss,sdl,esd,pa +endif + +ifneq (,$(filter $(DEB_HOST_ARCH),amd64 i386 powerpc)) + target_linux_list += $(TARGET_LINUX_DYNGEN) +endif + +ifeq ($(DEB_HOST_ARCH_CPU),i386) + conf_arch += --cpu=i386 +endif +ifeq ($(DEB_HOST_ARCH_CPU),sparc) + conf_arch += --cpu=sparc +endif + +include /usr/share/quilt/quilt.make qemu_docs = \ qemu-doc.html \ @@ -44,15 +62,13 @@ qemu.1 \ qemu-img.1 -include /usr/share/quilt/quilt.make - config-host.mak: configure dh_testdir CFLAGS="$(CFLAGS)" ./configure \ - --prefix=/usr \ - --enable-adlib \ - $(conf_arch) + --prefix=/usr \ + --target-list="$(target_system_list) $(target_linux_list)" \ + $(conf_arch) setup-source: patch $(MAKE) -f debian/rules config-host.mak @@ -67,8 +83,7 @@ dh_testdir dh_testroot - -$(MAKE) -C pc-bios clean - -$(MAKE) distclean + [ ! -f config-host.mak ] || $(MAKE) distclean rm -f $(qemu_docs) @@ -80,18 +95,18 @@ dh_clean -k dh_installdirs -a - # Make qemu's "make install" happy - for i in $(qemu_bios_files); do \ - touch pc-bios/$$i; \ + $(MAKE) DESTDIR=$(CURDIR)/debian/qemu install + + zcat /usr/share/etherboot/e1000-82540em.zrom.gz > $(CURDIR)/debian/qemu/usr/share/qemu/pxe-e1000.bin + zcat /usr/share/etherboot/rtl8029.zrom.gz > $(CURDIR)/debian/qemu/usr/share/qemu/pxe-ne2k_pci.bin + zcat /usr/share/etherboot/pcnet32.zrom.gz > $(CURDIR)/debian/qemu/usr/share/qemu/pxe-pcnet.bin + zcat /usr/share/etherboot/rtl8139.zrom.gz > $(CURDIR)/debian/qemu/usr/share/qemu/pxe-rtl8139.bin + + for target in $(target_system_list) ; do \ + cp $(CURDIR)/$$target/libqemu.a $(CURDIR)/debian/libqemu-dev/usr/lib/qemu/$$target/ ; \ + cp $(CURDIR)/$$target/*.h $(CURDIR)/debian/libqemu-dev/usr/include/qemu/$$target/ ; \ done - $(MAKE) DESTDIR=$(D) install - - # Clean up the mess - for i in $(qemu_bios_files); do \ - rm -f pc-bios/$$i $(D)/usr/share/qemu/$$i; \ - done - binary-indep: # Nothing to do. @@ -110,7 +125,7 @@ dh_strip -a dh_compress -a dh_fixperms -a - chmod a+x $(D)/etc/qemu-ifup + chmod a+x $(CURDIR)/debian/qemu/etc/qemu-ifup dh_installdeb -a dh_shlibdeps -a dh_gencontrol -a diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/tundev.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/tundev.c --- qemu-0.9.1/debian/tundev.c 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/tundev.c 2008-11-23 23:12:07.000000000 +0000 @@ -1,5 +1,5 @@ /* - * $Id: tundev.c 116 2005-10-30 14:18:08Z guillem $ + * $Id: tundev.c 325 2008-08-09 21:39:16Z aurel32 $ */ #define _GNU_SOURCE /* asprintf */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/debian/watch /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/debian/watch --- qemu-0.9.1/debian/watch 2008-11-23 23:12:07.000000000 +0000 +++ qemu-0.9.1+svn20081112/debian/watch 2008-11-23 23:12:07.000000000 +0000 @@ -1,2 +1,3 @@ version=3 -http://www.qemu.org/download.html qemu-([\d.]*).tar.gz debian uupdate + +http://bellard.org/qemu/download.html qemu-([\d.]*).tar.gz debian uupdate diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/disas.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/disas.c --- qemu-0.9.1/disas.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/disas.c 2008-10-22 16:55:18.000000000 +0100 @@ -14,11 +14,8 @@ /* Get LENGTH bytes from info's buffer, at target address memaddr. Transfer them to myaddr. */ int -buffer_read_memory (memaddr, myaddr, length, info) - bfd_vma memaddr; - bfd_byte *myaddr; - int length; - struct disassemble_info *info; +buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length, + struct disassemble_info *info) { if (memaddr < info->buffer_vma || memaddr + length > info->buffer_vma + info->buffer_length) @@ -46,10 +43,7 @@ /* Print an error message. We can assume that this is in response to an error return from buffer_read_memory. */ void -perror_memory (status, memaddr, info) - int status; - bfd_vma memaddr; - struct disassemble_info *info; +perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info) { if (status != EIO) /* Can't happen. */ @@ -69,9 +63,7 @@ addresses). */ void -generic_print_address (addr, info) - bfd_vma addr; - struct disassemble_info *info; +generic_print_address (bfd_vma addr, struct disassemble_info *info) { (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr); } @@ -79,9 +71,7 @@ /* Just return the given address. */ int -generic_symbol_at_address (addr, info) - bfd_vma addr; - struct disassemble_info * info; +generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info) { return 1; } @@ -279,6 +269,8 @@ print_insn = print_insn_m68k; #elif defined(__s390__) print_insn = print_insn_s390; +#elif defined(__hppa__) + print_insn = print_insn_hppa; #else fprintf(out, "0x%lx: Asm output not supported on this arch\n", (long) code); @@ -301,33 +293,17 @@ /* Look up symbol for debugging purpose. Returns "" if unknown. */ const char *lookup_symbol(target_ulong orig_addr) { - unsigned int i; - /* Hack, because we know this is x86. */ - Elf32_Sym *sym; + const char *symbol = ""; struct syminfo *s; - target_ulong addr; for (s = syminfos; s; s = s->next) { - sym = s->disas_symtab; - for (i = 0; i < s->disas_num_syms; i++) { - if (sym[i].st_shndx == SHN_UNDEF - || sym[i].st_shndx >= SHN_LORESERVE) - continue; - - if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC) - continue; - - addr = sym[i].st_value; -#if defined(TARGET_ARM) || defined (TARGET_MIPS) - /* The bottom address bit marks a Thumb or MIPS16 symbol. */ - addr &= ~(target_ulong)1; -#endif - if (orig_addr >= addr - && orig_addr < addr + sym[i].st_size) - return s->disas_strtab + sym[i].st_name; - } + symbol = s->lookup_symbol(s, orig_addr); + if (symbol[0] != '\0') { + break; + } } - return ""; + + return symbol; } #if !defined(CONFIG_USER_ONLY) @@ -339,11 +315,8 @@ static CPUState *monitor_disas_env; static int -monitor_read_memory (memaddr, myaddr, length, info) - bfd_vma memaddr; - bfd_byte *myaddr; - int length; - struct disassemble_info *info; +monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length, + struct disassemble_info *info) { if (monitor_disas_is_physical) { cpu_physical_memory_rw(memaddr, myaddr, length, 0); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/disas.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/disas.h --- qemu-0.9.1/disas.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/disas.h 2008-10-22 16:11:31.000000000 +0100 @@ -10,12 +10,24 @@ /* Look up symbol for debugging purpose. Returns "" if unknown. */ const char *lookup_symbol(target_ulong orig_addr); -/* Filled in by elfload.c. Simplistic, but will do for now. */ -extern struct syminfo { +struct syminfo; +struct elf32_sym; +struct elf64_sym; + +typedef const char *(*lookup_symbol_t)(struct syminfo *s, target_ulong orig_addr); + +struct syminfo { + lookup_symbol_t lookup_symbol; unsigned int disas_num_syms; - void *disas_symtab; + union { + struct elf32_sym *elf32; + struct elf64_sym *elf64; + } disas_symtab; const char *disas_strtab; struct syminfo *next; -} *syminfos; +}; + +/* Filled in by elfload.c. Simplistic, but will do for now. */ +extern struct syminfo *syminfos; #endif /* _QEMU_DISAS_H */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/dis-asm.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/dis-asm.h --- qemu-0.9.1/dis-asm.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/dis-asm.h 2008-08-21 18:58:08.000000000 +0100 @@ -20,6 +20,7 @@ typedef int64_t bfd_signed_vma; typedef uint8_t bfd_byte; #define sprintf_vma(s,x) sprintf (s, "%0" PRIx64, x) +#define snprintf_vma(s,ss,x) snprintf (s, ss, "%0" PRIx64, x) #define BFD64 @@ -157,6 +158,10 @@ #define bfd_mach_ppc_7400 7400 bfd_arch_rs6000, /* IBM RS/6000 */ bfd_arch_hppa, /* HP PA RISC */ +#define bfd_mach_hppa10 10 +#define bfd_mach_hppa11 11 +#define bfd_mach_hppa20 20 +#define bfd_mach_hppa20w 25 bfd_arch_d10v, /* Mitsubishi D10V */ bfd_arch_z8k, /* Zilog Z8000 */ #define bfd_mach_z8001 1 @@ -392,7 +397,6 @@ extern int print_insn_v850 PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_ppc PARAMS ((bfd_vma, disassemble_info*)); -extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_s390 PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_crisv32 PARAMS ((bfd_vma, disassemble_info*)); @@ -444,6 +448,7 @@ (INFO).stream = (STREAM), \ (INFO).symbols = NULL, \ (INFO).num_symbols = 0, \ + (INFO).private_data = NULL, \ (INFO).buffer = NULL, \ (INFO).buffer_vma = 0, \ (INFO).buffer_length = 0, \ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/dyngen.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/dyngen.c --- qemu-0.9.1/dyngen.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/dyngen.c 2008-08-17 21:26:25.000000000 +0100 @@ -68,6 +68,13 @@ #define elf_check_arch(x) ((x) == EM_PPC) #define ELF_USES_RELOCA +#elif defined(HOST_PPC64) + +#define ELF_CLASS ELFCLASS64 +#define ELF_ARCH EM_PPC64 +#define elf_check_arch(x) ((x) == EM_PPC64) +#define ELF_USES_RELOCA + #elif defined(HOST_S390) #define ELF_CLASS ELFCLASS32 @@ -117,6 +124,13 @@ #define elf_check_arch(x) ((x) == EM_68K) #define ELF_USES_RELOCA +#elif defined(HOST_HPPA) + +#define ELF_CLASS ELFCLASS32 +#define ELF_ARCH EM_PARISC +#define elf_check_arch(x) ((x) == EM_PARISC) +#define ELF_USES_RELOCA + #elif defined(HOST_MIPS) #define ELF_CLASS ELFCLASS32 @@ -258,7 +272,7 @@ return data; } -int strstart(const char *str, const char *val, const char **ptr) +static int strstart(const char *str, const char *val, const char **ptr) { const char *p, *q; p = str; @@ -274,7 +288,7 @@ return 1; } -void pstrcpy(char *buf, int buf_size, const char *str) +static void pstrcpy(char *buf, int buf_size, const char *str) { int c; char *q = buf; @@ -291,32 +305,32 @@ *q = '\0'; } -void swab16s(uint16_t *p) +static void swab16s(uint16_t *p) { *p = bswap16(*p); } -void swab32s(uint32_t *p) +static void swab32s(uint32_t *p) { *p = bswap32(*p); } -void swab32ss(int32_t *p) +static void swab32ss(int32_t *p) { *p = bswap32(*p); } -void swab64s(uint64_t *p) +static void swab64s(uint64_t *p) { *p = bswap64(*p); } -void swab64ss(int64_t *p) +static void swab64ss(int64_t *p) { *p = bswap64(*p); } -uint16_t get16(uint16_t *p) +static uint16_t get16(uint16_t *p) { uint16_t val; val = *p; @@ -325,7 +339,7 @@ return val; } -uint32_t get32(uint32_t *p) +static uint32_t get32(uint32_t *p) { uint32_t val; val = *p; @@ -334,14 +348,14 @@ return val; } -void put16(uint16_t *p, uint16_t val) +static void put16(uint16_t *p, uint16_t val) { if (do_swap) val = bswap16(val); *p = val; } -void put32(uint32_t *p, uint32_t val) +static void put32(uint32_t *p, uint32_t val) { if (do_swap) val = bswap32(val); @@ -364,7 +378,7 @@ struct elfhdr ehdr; char *strtab; -int elf_must_swap(struct elfhdr *h) +static int elf_must_swap(struct elfhdr *h) { union { uint32_t i; @@ -376,7 +390,7 @@ (swaptest.b[0] == 0); } -void elf_swap_ehdr(struct elfhdr *h) +static void elf_swap_ehdr(struct elfhdr *h) { swab16s(&h->e_type); /* Object file type */ swab16s(&h-> e_machine); /* Architecture */ @@ -393,7 +407,7 @@ swab16s(&h-> e_shstrndx); /* Section header string table index */ } -void elf_swap_shdr(struct elf_shdr *h) +static void elf_swap_shdr(struct elf_shdr *h) { swab32s(&h-> sh_name); /* Section name (string tbl index) */ swab32s(&h-> sh_type); /* Section type */ @@ -407,7 +421,7 @@ swabls(&h-> sh_entsize); /* Entry size if section holds table */ } -void elf_swap_phdr(struct elf_phdr *h) +static void elf_swap_phdr(struct elf_phdr *h) { swab32s(&h->p_type); /* Segment type */ swabls(&h->p_offset); /* Segment file offset */ @@ -419,7 +433,7 @@ swabls(&h->p_align); /* Segment alignment */ } -void elf_swap_rel(ELF_RELOC *rel) +static void elf_swap_rel(ELF_RELOC *rel) { swabls(&rel->r_offset); swabls(&rel->r_info); @@ -428,8 +442,8 @@ #endif } -struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr, - const char *name) +static struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, + const char *shstr, const char *name) { int i; const char *shname; @@ -446,7 +460,7 @@ return NULL; } -int find_reloc(int sh_index) +static int find_reloc(int sh_index) { struct elf_shdr *sec; int i; @@ -475,7 +489,7 @@ } /* load an elf object file */ -int load_object(const char *filename) +static int load_object(const char *filename) { int fd; struct elf_shdr *sec, *symtab_sec, *strtab_sec, *text_sec; @@ -1212,16 +1226,18 @@ #endif /* CONFIG_FORMAT_MACH */ -void get_reloc_expr(char *name, int name_size, const char *sym_name) +/* return true if the expression is a label reference */ +static int get_reloc_expr(char *name, int name_size, const char *sym_name) { const char *p; if (strstart(sym_name, "__op_param", &p)) { snprintf(name, name_size, "param%s", p); } else if (strstart(sym_name, "__op_gen_label", &p)) { - snprintf(name, name_size, "gen_labels[param%s]", p); + snprintf(name, name_size, "param%s", p); + return 1; } else { -#ifdef HOST_SPARC +#if defined(HOST_SPARC) || defined(HOST_HPPA) if (sym_name[0] == '.') snprintf(name, name_size, "(long)(&__dot_%s)", @@ -1230,6 +1246,7 @@ #endif snprintf(name, name_size, "(long)(&%s)", sym_name); } + return 0; } #ifdef HOST_IA64 @@ -1274,166 +1291,11 @@ #endif -#ifdef HOST_ARM - -int arm_emit_ldr_info(const char *name, unsigned long start_offset, - FILE *outfile, uint8_t *p_start, uint8_t *p_end, - ELF_RELOC *relocs, int nb_relocs) -{ - uint8_t *p; - uint32_t insn; - int offset, min_offset, pc_offset, data_size, spare, max_pool; - uint8_t data_allocated[1024]; - unsigned int data_index; - int type; - - memset(data_allocated, 0, sizeof(data_allocated)); - - p = p_start; - min_offset = p_end - p_start; - spare = 0x7fffffff; - while (p < p_start + min_offset) { - insn = get32((uint32_t *)p); - /* TODO: Armv5e ldrd. */ - /* TODO: VFP load. */ - if ((insn & 0x0d5f0000) == 0x051f0000) { - /* ldr reg, [pc, #im] */ - offset = insn & 0xfff; - if (!(insn & 0x00800000)) - offset = -offset; - max_pool = 4096; - type = 0; - } else if ((insn & 0x0e5f0f00) == 0x0c1f0100) { - /* FPA ldf. */ - offset = (insn & 0xff) << 2; - if (!(insn & 0x00800000)) - offset = -offset; - max_pool = 1024; - type = 1; - } else if ((insn & 0x0fff0000) == 0x028f0000) { - /* Some gcc load a doubleword immediate with - add regN, pc, #imm - ldmia regN, {regN, regM} - Hope and pray the compiler never generates somethin like - add reg, pc, #imm1; ldr reg, [reg, #-imm2]; */ - int r; - - r = (insn & 0xf00) >> 7; - offset = ((insn & 0xff) >> r) | ((insn & 0xff) << (32 - r)); - max_pool = 1024; - type = 2; - } else { - max_pool = 0; - type = -1; - } - if (type >= 0) { - /* PC-relative load needs fixing up. */ - if (spare > max_pool - offset) - spare = max_pool - offset; - if ((offset & 3) !=0) - error("%s:%04x: pc offset must be 32 bit aligned", - name, start_offset + p - p_start); - if (offset < 0) - error("%s:%04x: Embedded literal value", - name, start_offset + p - p_start); - pc_offset = p - p_start + offset + 8; - if (pc_offset <= (p - p_start) || - pc_offset >= (p_end - p_start)) - error("%s:%04x: pc offset must point inside the function code", - name, start_offset + p - p_start); - if (pc_offset < min_offset) - min_offset = pc_offset; - if (outfile) { - /* The intruction position */ - fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n", - p - p_start); - /* The position of the constant pool data. */ - data_index = ((p_end - p_start) - pc_offset) >> 2; - fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr - %d;\n", - data_index); - fprintf(outfile, " arm_ldr_ptr->type = %d;\n", type); - fprintf(outfile, " arm_ldr_ptr++;\n"); - } - } - p += 4; - } - - /* Copy and relocate the constant pool data. */ - data_size = (p_end - p_start) - min_offset; - if (data_size > 0 && outfile) { - spare += min_offset; - fprintf(outfile, " arm_data_ptr -= %d;\n", data_size >> 2); - fprintf(outfile, " arm_pool_ptr -= %d;\n", data_size); - fprintf(outfile, " if (arm_pool_ptr > gen_code_ptr + %d)\n" - " arm_pool_ptr = gen_code_ptr + %d;\n", - spare, spare); - - data_index = 0; - for (pc_offset = min_offset; - pc_offset < p_end - p_start; - pc_offset += 4) { - - ELF_RELOC *rel; - int i, addend, type; - const char *sym_name; - char relname[1024]; - - /* data value */ - addend = get32((uint32_t *)(p_start + pc_offset)); - relname[0] = '\0'; - for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { - if (rel->r_offset == (pc_offset + start_offset)) { - sym_name = get_rel_sym_name(rel); - /* the compiler leave some unnecessary references to the code */ - get_reloc_expr(relname, sizeof(relname), sym_name); - type = ELF32_R_TYPE(rel->r_info); - if (type != R_ARM_ABS32) - error("%s: unsupported data relocation", name); - break; - } - } - fprintf(outfile, " arm_data_ptr[%d] = 0x%x", - data_index, addend); - if (relname[0] != '\0') - fprintf(outfile, " + %s", relname); - fprintf(outfile, ";\n"); - - data_index++; - } - } - - if (p == p_start) - goto arm_ret_error; - p -= 4; - insn = get32((uint32_t *)p); - /* The last instruction must be an ldm instruction. There are several - forms generated by gcc: - ldmib sp, {..., pc} (implies a sp adjustment of +4) - ldmia sp, {..., pc} - ldmea fp, {..., pc} */ - if ((insn & 0xffff8000) == 0xe99d8000) { - if (outfile) { - fprintf(outfile, - " *(uint32_t *)(gen_code_ptr + %d) = 0xe28dd004;\n", - p - p_start); - } - p += 4; - } else if ((insn & 0xffff8000) != 0xe89d8000 - && (insn & 0xffff8000) != 0xe91b8000) { - arm_ret_error: - if (!outfile) - printf("%s: invalid epilog\n", name); - } - return p - p_start; -} -#endif - - #define MAX_ARGS 3 /* generate op code */ -void gen_code(const char *name, host_ulong offset, host_ulong size, - FILE *outfile, int gen_switch) +static void gen_code(const char *name, host_ulong offset, host_ulong size, + FILE *outfile, int gen_switch) { int copy_size = 0; uint8_t *p_start, *p_end; @@ -1612,36 +1474,17 @@ error("No save at the beginning of %s", name); } +#if 0 /* Skip a preceeding nop, if present. */ if (p > p_start) { skip_insn = get32((uint32_t *)(p - 0x4)); if (skip_insn == 0x01000000) p -= 4; } +#endif copy_size = p - p_start; } -#elif defined(HOST_ARM) - { - uint32_t insn; - - if ((p_end - p_start) <= 16) - error("%s: function too small", name); - if (get32((uint32_t *)p_start) != 0xe1a0c00d || - (get32((uint32_t *)(p_start + 4)) & 0xffff0000) != 0xe92d0000 || - get32((uint32_t *)(p_start + 8)) != 0xe24cb004) - error("%s: invalid prolog", name); - p_start += 12; - start_offset += 12; - insn = get32((uint32_t *)p_start); - if ((insn & 0xffffff00) == 0xe24dd000) { - /* Stack adjustment. Assume op uses the frame pointer. */ - p_start -= 4; - start_offset -= 4; - } - copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end, - relocs, nb_relocs); - } #elif defined(HOST_M68K) { uint8_t *p; @@ -1656,6 +1499,43 @@ error("rts expected at the end of %s", name); copy_size = p - p_start; } +#elif defined(HOST_HPPA) + { + uint8_t *p; + p = p_start; + while (p < p_end) { + uint32_t insn = get32((uint32_t *)p); + if (insn == 0x6bc23fd9 || /* stw rp,-14(sp) */ + insn == 0x08030241 || /* copy r3,r1 */ + insn == 0x081e0243 || /* copy sp,r3 */ + (insn & 0xffffc000) == 0x37de0000 || /* ldo x(sp),sp */ + (insn & 0xffffc000) == 0x6fc10000) /* stwm r1,x(sp) */ + p += 4; + else + break; + } + start_offset += p - p_start; + p_start = p; + p = p_end - 4; + + while (p > p_start) { + uint32_t insn = get32((uint32_t *)p); + if ((insn & 0xffffc000) == 0x347e0000 || /* ldo x(r3),sp */ + (insn & 0xffe0c000) == 0x4fc00000 || /* ldwm x(sp),rx */ + (insn & 0xffffc000) == 0x37de0000 || /* ldo x(sp),sp */ + insn == 0x48623fd9 || /* ldw -14(r3),rp */ + insn == 0xe840c000 || /* bv r0(rp) */ + insn == 0xe840c002) /* bv,n r0(rp) */ + p -= 4; + else + break; + } + p += 4; + if (p <= p_start) + error("empty code for %s", name); + + copy_size = p - p_start; + } #elif defined(HOST_MIPS) || defined(HOST_MIPS64) { #define INSN_RETURN 0x03e00008 @@ -1676,6 +1556,10 @@ } copy_size = p - p_start; } +#elif defined(HOST_ARM) + error("dyngen targets not supported on ARM"); +#elif defined(HOST_PPC64) + error("dyngen targets not supported on PPC64"); #else #error unsupported CPU #endif @@ -1710,7 +1594,36 @@ } if (gen_switch == 2) { - fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size); + +#if defined(HOST_HPPA) + int op_size = copy_size; + int has_stubs = 0; + char relname[256]; + int type, is_label; + + for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { + sym_name = get_rel_sym_name(rel); + sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; + is_label = get_reloc_expr(relname, sizeof(relname), sym_name); + type = ELF32_R_TYPE(rel->r_info); + + if (!is_label && type == R_PARISC_PCREL17F) { + has_stubs = 1; + op_size += 8; /* ldil and be,n instructions */ + } + } + } + + if (has_stubs) + op_size += 4; /* b,l,n instruction, to skip past the stubs */ + + fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, op_size); +#else + fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size); +#endif + } else if (gen_switch == 1) { /* output C code */ @@ -1741,7 +1654,7 @@ !strstart(sym_name, "__op_param", NULL) && !strstart(sym_name, "__op_jmp", NULL) && !strstart(sym_name, "__op_gen_label", NULL)) { -#if defined(HOST_SPARC) +#if defined(HOST_SPARC) || defined(HOST_HPPA) if (sym_name[0] == '.') { fprintf(outfile, "extern char __dot_%s __asm__(\"%s\");\n", @@ -1769,8 +1682,13 @@ } } +#ifdef __hppa__ + fprintf(outfile, " memcpy(gen_code_ptr, (void *)((char *)__canonicalize_funcptr_for_compare(%s)+%d), %d);\n", + name, (int)(start_offset - offset), copy_size); +#else fprintf(outfile, " memcpy(gen_code_ptr, (void *)((char *)&%s+%d), %d);\n", name, (int)(start_offset - offset), copy_size); +#endif /* emit code offset information */ { @@ -1846,7 +1764,7 @@ #if defined(HOST_I386) { char relname[256]; - int type; + int type, is_label; int addend; int reloc_offset; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { @@ -1868,21 +1786,33 @@ continue; } - get_reloc_expr(relname, sizeof(relname), sym_name); + is_label = get_reloc_expr(relname, sizeof(relname), sym_name); addend = get32((uint32_t *)(text + rel->r_offset)); #ifdef CONFIG_FORMAT_ELF type = ELF32_R_TYPE(rel->r_info); - switch(type) { - case R_386_32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - reloc_offset, relname, addend); - break; - case R_386_PC32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", - reloc_offset, relname, reloc_offset, addend); - break; - default: - error("unsupported i386 relocation (%d)", type); + if (is_label) { + switch(type) { + case R_386_32: + case R_386_PC32: + fprintf(outfile, " tcg_out_reloc(s, gen_code_ptr + %d, %d, %s, %d);\n", + reloc_offset, type, relname, addend); + break; + default: + error("unsupported i386 relocation (%d)", type); + } + } else { + switch(type) { + case R_386_32: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", + reloc_offset, relname, addend); + break; + case R_386_PC32: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", + reloc_offset, relname, reloc_offset, addend); + break; + default: + error("unsupported i386 relocation (%d)", type); + } } #elif defined(CONFIG_FORMAT_COFF) { @@ -1899,17 +1829,37 @@ } } type = rel->r_type; - switch(type) { - case DIR32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - reloc_offset, relname, addend); - break; - case DISP32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n", - reloc_offset, relname, reloc_offset, addend); - break; - default: - error("unsupported i386 relocation (%d)", type); + if (is_label) { +/* TCG uses elf relocation constants */ +#define R_386_32 1 +#define R_386_PC32 2 + switch(type) { + case DIR32: + type = R_386_32; + goto do_reloc; + case DISP32: + type = R_386_PC32; + addend -= 4; + do_reloc: + fprintf(outfile, " tcg_out_reloc(s, gen_code_ptr + %d, %d, %s, %d);\n", + reloc_offset, type, relname, addend); + break; + default: + error("unsupported i386 relocation (%d)", type); + } + } else { + switch(type) { + case DIR32: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", + reloc_offset, relname, addend); + break; + case DISP32: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n", + reloc_offset, relname, reloc_offset, addend); + break; + default: + error("unsupported i386 relocation (%d)", type); + } } #else #error unsupport object format @@ -1920,32 +1870,45 @@ #elif defined(HOST_X86_64) { char relname[256]; - int type; + int type, is_label; int addend; int reloc_offset; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; - get_reloc_expr(relname, sizeof(relname), sym_name); + is_label = get_reloc_expr(relname, sizeof(relname), sym_name); type = ELF32_R_TYPE(rel->r_info); addend = rel->r_addend; reloc_offset = rel->r_offset - start_offset; - switch(type) { - case R_X86_64_32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n", - reloc_offset, relname, addend); - break; - case R_X86_64_32S: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n", - reloc_offset, relname, addend); - break; - case R_X86_64_PC32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", - reloc_offset, relname, reloc_offset, addend); - break; - default: - error("unsupported X86_64 relocation (%d)", type); + if (is_label) { + switch(type) { + case R_X86_64_32: + case R_X86_64_32S: + case R_X86_64_PC32: + fprintf(outfile, " tcg_out_reloc(s, gen_code_ptr + %d, %d, %s, %d);\n", + reloc_offset, type, relname, addend); + break; + default: + error("unsupported X86_64 relocation (%d)", type); + } + } else { + switch(type) { + case R_X86_64_32: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n", + reloc_offset, relname, addend); + break; + case R_X86_64_32S: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n", + reloc_offset, relname, addend); + break; + case R_X86_64_PC32: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", + reloc_offset, relname, reloc_offset, addend); + break; + default: + error("unsupported X86_64 relocation (%d)", type); + } } } } @@ -1956,10 +1919,11 @@ char relname[256]; int type; int addend; + int is_label; int reloc_offset; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { if (rel->r_offset >= start_offset && - rel->r_offset < start_offset + copy_size) { + rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; reloc_offset = rel->r_offset - start_offset; if (strstart(sym_name, "__op_jmp", &p)) { @@ -1976,31 +1940,52 @@ get_reloc_expr(relname, sizeof(relname), sym_name); type = ELF32_R_TYPE(rel->r_info); + is_label = get_reloc_expr(relname, sizeof(relname), sym_name); addend = rel->r_addend; - switch(type) { - case R_PPC_ADDR32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - reloc_offset, relname, addend); - break; - case R_PPC_ADDR16_LO: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n", - reloc_offset, relname, addend); - break; - case R_PPC_ADDR16_HI: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n", - reloc_offset, relname, addend); - break; - case R_PPC_ADDR16_HA: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n", - reloc_offset, relname, addend); - break; - case R_PPC_REL24: - /* warning: must be at 32 MB distancy */ - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n", - reloc_offset, reloc_offset, relname, reloc_offset, addend); - break; - default: - error("unsupported powerpc relocation (%d)", type); + if (is_label) { + switch (type) { + case R_PPC_REL24: + fprintf (outfile, " tcg_out_reloc(s, gen_code_ptr + %d, %d, %s, %d);\n", + reloc_offset, type, relname, addend); + break; + default: + error ("unsupported ppc relocation (%d)", type); + } + } + else { + switch(type) { + case R_PPC_ADDR32: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", + reloc_offset, relname, addend); + break; + case R_PPC_ADDR16_LO: + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n", + reloc_offset, relname, addend); + break; + case R_PPC_ADDR16_HI: + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n", + reloc_offset, relname, addend); + break; + case R_PPC_ADDR16_HA: + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n", + reloc_offset, relname, addend); + break; + case R_PPC_REL24: + /* warning: must be at 32 MB distancy */ + fprintf(outfile, "{\n" + " long disp = (%s - (long)(gen_code_ptr + %d) + %d);\n" + " if ((disp << 6) >> 6 != disp) {;\n" + " fprintf(stderr, \"Branch target is too far away\\n\");" + " abort();\n" + " }\n" + "}\n", + relname, reloc_offset, addend); + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n", + reloc_offset, reloc_offset, relname, reloc_offset, addend); + break; + default: + error("unsupported powerpc relocation (%d)", type); + } } } } @@ -2430,74 +2415,6 @@ } } } -#elif defined(HOST_ARM) - { - char relname[256]; - int type; - int addend; - int reloc_offset; - uint32_t insn; - - insn = get32((uint32_t *)(p_start + 4)); - /* If prologue ends in sub sp, sp, #const then assume - op has a stack frame and needs the frame pointer. */ - if ((insn & 0xffffff00) == 0xe24dd000) { - int i; - uint32_t opcode; - opcode = 0xe28db000; /* add fp, sp, #0. */ -#if 0 -/* ??? Need to undo the extra stack adjustment at the end of the op. - For now just leave the stack misaligned and hope it doesn't break anything - too important. */ - if ((insn & 4) != 0) { - /* Preserve doubleword stack alignment. */ - fprintf(outfile, - " *(uint32_t *)(gen_code_ptr + 4)= 0x%x;\n", - insn + 4); - opcode -= 4; - } -#endif - insn = get32((uint32_t *)(p_start - 4)); - /* Calculate the size of the saved registers, - excluding pc. */ - for (i = 0; i < 15; i++) { - if (insn & (1 << i)) - opcode += 4; - } - fprintf(outfile, - " *(uint32_t *)gen_code_ptr = 0x%x;\n", opcode); - } - arm_emit_ldr_info(relname, start_offset, outfile, p_start, p_end, - relocs, nb_relocs); - - for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { - if (rel->r_offset >= start_offset && - rel->r_offset < start_offset + copy_size) { - sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; - /* the compiler leave some unnecessary references to the code */ - if (sym_name[0] == '\0') - continue; - get_reloc_expr(relname, sizeof(relname), sym_name); - type = ELF32_R_TYPE(rel->r_info); - addend = get32((uint32_t *)(text + rel->r_offset)); - reloc_offset = rel->r_offset - start_offset; - switch(type) { - case R_ARM_ABS32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - reloc_offset, relname, addend); - break; - case R_ARM_PC24: - case R_ARM_JUMP24: - case R_ARM_CALL: - fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n", - reloc_offset, addend, relname); - break; - default: - error("unsupported arm relocation (%d)", type); - } - } - } - } #elif defined(HOST_M68K) { char relname[256]; @@ -2531,6 +2448,82 @@ } } } +#elif defined(HOST_HPPA) + { + char relname[256]; + int type, is_label; + int addend; + int reloc_offset; + for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { + sym_name = get_rel_sym_name(rel); + sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; + is_label = get_reloc_expr(relname, sizeof(relname), sym_name); + type = ELF32_R_TYPE(rel->r_info); + addend = rel->r_addend; + reloc_offset = rel->r_offset - start_offset; + + if (is_label) { + switch (type) { + case R_PARISC_PCREL17F: + fprintf(outfile, +" tcg_out_reloc(s, gen_code_ptr + %d, %d, %s, %d);\n", + reloc_offset, type, relname, addend); + break; + default: + error("unsupported hppa label relocation (%d)", type); + } + } else { + switch (type) { + case R_PARISC_DIR21L: + fprintf(outfile, +" hppa_patch21l((uint32_t *)(gen_code_ptr + %d), %s, %d);\n", + reloc_offset, relname, addend); + break; + case R_PARISC_DIR14R: + fprintf(outfile, +" hppa_patch14r((uint32_t *)(gen_code_ptr + %d), %s, %d);\n", + reloc_offset, relname, addend); + break; + case R_PARISC_PCREL17F: + if (strstart(sym_name, "__op_gen_label", NULL)) { + fprintf(outfile, +" hppa_patch17f((uint32_t *)(gen_code_ptr + %d), %s, %d);\n", + reloc_offset, relname, addend); + } else { + fprintf(outfile, +" HPPA_RECORD_BRANCH(hppa_stubs, (uint32_t *)(gen_code_ptr + %d), %s);\n", + reloc_offset, relname); + } + break; + case R_PARISC_DPREL21L: + if (strstart(sym_name, "__op_param", &p)) + fprintf(outfile, +" hppa_load_imm21l((uint32_t *)(gen_code_ptr + %d), param%s, %d);\n", + reloc_offset, p, addend); + else + fprintf(outfile, +" hppa_patch21l_dprel((uint32_t *)(gen_code_ptr + %d), %s, %d);\n", + reloc_offset, relname, addend); + break; + case R_PARISC_DPREL14R: + if (strstart(sym_name, "__op_param", &p)) + fprintf(outfile, +" hppa_load_imm14r((uint32_t *)(gen_code_ptr + %d), param%s, %d);\n", + reloc_offset, p, addend); + else + fprintf(outfile, +" hppa_patch14r_dprel((uint32_t *)(gen_code_ptr + %d), %s, %d);\n", + reloc_offset, relname, addend); + break; + default: + error("unsupported hppa relocation (%d)", type); + } + } + } + } + } #elif defined(HOST_MIPS) || defined(HOST_MIPS64) { for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) { @@ -2606,6 +2599,10 @@ } } } +#elif defined(HOST_ARM) + error("dyngen targets not supported on ARM"); +#elif defined(HOST_PPC64) + error("dyngen targets not supported on PPC64"); #else #error unsupported CPU #endif @@ -2633,17 +2630,12 @@ } } -int gen_file(FILE *outfile, int out_type) +static int gen_file(FILE *outfile, int out_type) { int i; EXE_SYM *sym; if (out_type == OUT_INDEX_OP) { - fprintf(outfile, "DEF(end, 0, 0)\n"); - fprintf(outfile, "DEF(nop, 0, 0)\n"); - fprintf(outfile, "DEF(nop1, 1, 0)\n"); - fprintf(outfile, "DEF(nop2, 2, 0)\n"); - fprintf(outfile, "DEF(nop3, 3, 0)\n"); for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { const char *name; name = get_sym_name(sym); @@ -2653,7 +2645,6 @@ } } else if (out_type == OUT_GEN_OP) { /* generate gen_xxx functions */ - fprintf(outfile, "#include \"dyngen-op.h\"\n"); for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { const char *name; name = get_sym_name(sym); @@ -2670,68 +2661,10 @@ /* generate big code generation switch */ #ifdef HOST_ARM - /* We need to know the size of all the ops so we can figure out when - to emit constant pools. This must be consistent with opc.h. */ -fprintf(outfile, -"static const uint32_t arm_opc_size[] = {\n" -" 0,\n" /* end */ -" 0,\n" /* nop */ -" 0,\n" /* nop1 */ -" 0,\n" /* nop2 */ -" 0,\n"); /* nop3 */ - for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { - const char *name; - name = get_sym_name(sym); - if (strstart(name, OP_PREFIX, NULL)) { - fprintf(outfile, " %d,\n", sym->st_size); - } - } -fprintf(outfile, -"};\n"); -#endif - -fprintf(outfile, -"int dyngen_code(uint8_t *gen_code_buf,\n" -" uint16_t *label_offsets, uint16_t *jmp_offsets,\n" -" const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels)\n" -"{\n" -" uint8_t *gen_code_ptr;\n" -" const uint16_t *opc_ptr;\n" -" const uint32_t *opparam_ptr;\n"); - -#ifdef HOST_ARM -/* Arm is tricky because it uses constant pools for loading immediate values. - We assume (and require) each function is code followed by a constant pool. - All the ops are small so this should be ok. For each op we figure - out how much "spare" range we have in the load instructions. This allows - us to insert subsequent ops in between the op and the constant pool, - eliminating the neeed to jump around the pool. - - We currently generate: - - [ For this example we assume merging would move op1_pool out of range. - In practice we should be able to combine many ops before the offset - limits are reached. ] - op1_code; - op2_code; - goto op3; - op2_pool; - op1_pool; -op3: - op3_code; - ret; - op3_pool; - - Ideally we'd put op1_pool before op2_pool, but that requires two passes. - */ -fprintf(outfile, -" uint8_t *last_gen_code_ptr = gen_code_buf;\n" -" LDREntry *arm_ldr_ptr = arm_ldr_table;\n" -" uint32_t *arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n" -/* Initialise the parmissible pool offset to an arbitary large value. */ -" uint8_t *arm_pool_ptr = gen_code_buf + 0x1000000;\n"); + error("dyngen targets not supported on ARM"); #endif #ifdef HOST_IA64 +#error broken { long addend, not_first = 0; unsigned long sym_idx; @@ -2789,33 +2722,6 @@ } #endif -fprintf(outfile, -"\n" -" gen_code_ptr = gen_code_buf;\n" -" opc_ptr = opc_buf;\n" -" opparam_ptr = opparam_buf;\n"); - - /* Generate prologue, if needed. */ - -fprintf(outfile, -" for(;;) {\n"); - -#ifdef HOST_ARM -/* Generate constant pool if needed */ -fprintf(outfile, -" if (gen_code_ptr + arm_opc_size[*opc_ptr] >= arm_pool_ptr) {\n" -" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, " -"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 1);\n" -" last_gen_code_ptr = gen_code_ptr;\n" -" arm_ldr_ptr = arm_ldr_table;\n" -" arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n" -" arm_pool_ptr = gen_code_ptr + 0x1000000;\n" -" }\n"); -#endif - -fprintf(outfile, -" switch(*opc_ptr++) {\n"); - for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { const char *name; name = get_sym_name(sym); @@ -2831,57 +2737,12 @@ gen_code(name, sym->st_value, sym->st_size, outfile, 1); } } - -fprintf(outfile, -" case INDEX_op_nop:\n" -" break;\n" -" case INDEX_op_nop1:\n" -" opparam_ptr++;\n" -" break;\n" -" case INDEX_op_nop2:\n" -" opparam_ptr += 2;\n" -" break;\n" -" case INDEX_op_nop3:\n" -" opparam_ptr += 3;\n" -" break;\n" -" default:\n" -" goto the_end;\n" -" }\n"); - - -fprintf(outfile, -" }\n" -" the_end:\n" -); -#ifdef HOST_IA64 - fprintf(outfile, - " {\n" - " extern char code_gen_buffer[];\n" - " ia64_apply_fixes(&gen_code_ptr, ltoff_fixes, " - "(uint64_t) code_gen_buffer + 2*(1<<20), plt_fixes,\n\t\t\t" - "sizeof(plt_target)/sizeof(plt_target[0]),\n\t\t\t" - "plt_target, plt_offset);\n }\n"); -#endif - -/* generate some code patching */ -#ifdef HOST_ARM -fprintf(outfile, -"if (arm_data_ptr != arm_data_table + ARM_LDR_TABLE_SIZE)\n" -" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, " -"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 0);\n"); -#endif - /* flush instruction cache */ - fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n"); - - fprintf(outfile, "return gen_code_ptr - gen_code_buf;\n"); - fprintf(outfile, "}\n\n"); - } return 0; } -void usage(void) +static void usage(void) { printf("dyngen (c) 2003 Fabrice Bellard\n" "usage: dyngen [-o outfile] [-c] objfile\n" diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/dyngen-exec.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/dyngen-exec.h --- qemu-0.9.1/dyngen-exec.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/dyngen-exec.h 2008-08-15 19:33:42.000000000 +0100 @@ -32,13 +32,16 @@ host headers do not allow that. */ #include +#ifdef __OpenBSD__ +#include +#else typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; // Linux/Sparc64 defines uint64_t -#if !(defined (__sparc_v9__) && defined(__linux__)) +#if !(defined (__sparc_v9__) && defined(__linux__)) && !(defined(__APPLE__) && defined(__x86_64__)) /* XXX may be done for all 64 bits targets ? */ -#if defined (__x86_64__) || defined(__ia64) || defined(__s390x__) || defined(__alpha__) +#if defined (__x86_64__) || defined(__ia64) || defined(__s390x__) || defined(__alpha__) || defined(__powerpc64__) typedef unsigned long uint64_t; #else typedef unsigned long long uint64_t; @@ -54,13 +57,14 @@ typedef signed short int16_t; typedef signed int int32_t; // Linux/Sparc64 defines int64_t -#if !(defined (__sparc_v9__) && defined(__linux__)) -#if defined (__x86_64__) || defined(__ia64) || defined(__s390x__) || defined(__alpha__) +#if !(defined (__sparc_v9__) && defined(__linux__)) && !(defined(__APPLE__) && defined(__x86_64__)) +#if defined (__x86_64__) || defined(__ia64) || defined(__s390x__) || defined(__alpha__) || defined(__powerpc64__) typedef signed long int64_t; #else typedef signed long long int64_t; #endif #endif +#endif /* XXX: This may be wrong for 64-bit ILP32 hosts. */ typedef void * host_reg_t; @@ -117,13 +121,16 @@ #define AREG10 "r22" #define AREG11 "r23" #endif -#define USE_INT_TO_FLOAT_HELPERS -#define BUGGY_GCC_DIV64 #elif defined(__arm__) #define AREG0 "r7" #define AREG1 "r4" #define AREG2 "r5" #define AREG3 "r6" +#elif defined(__hppa__) +#define AREG0 "r17" +#define AREG1 "r14" +#define AREG2 "r15" +#define AREG3 "r16" #elif defined(__mips__) #define AREG0 "fp" #define AREG1 "s0" @@ -143,10 +150,9 @@ #define AREG4 "g6" #else #ifdef __sparc_v9__ -#define AREG0 "g1" -#define AREG1 "g4" -#define AREG2 "g5" -#define AREG3 "g7" +#define AREG0 "g5" +#define AREG1 "g6" +#define AREG2 "g7" #else #define AREG0 "g6" #define AREG1 "g1" @@ -162,7 +168,6 @@ #define AREG11 "l7" #endif #endif -#define USE_FP_CONVERT #elif defined(__s390__) #define AREG0 "r10" #define AREG1 "r7" @@ -279,8 +284,22 @@ #elif defined(__mips__) #define EXIT_TB() asm volatile ("jr $ra") #define GOTO_LABEL_PARAM(n) asm volatile (".set noat; la $1, " ASM_NAME(__op_gen_label) #n "; jr $1; .set at") +#elif defined(__hppa__) +#define GOTO_LABEL_PARAM(n) asm volatile ("b,n " ASM_NAME(__op_gen_label) #n) #else #error unsupported CPU #endif +/* The return address may point to the start of the next instruction. + Subtracting one gets us the call instruction itself. */ +#if defined(__s390__) +# define GETPC() ((void*)(((unsigned long)__builtin_return_address(0) & 0x7fffffffUL) - 1)) +#elif defined(__arm__) +/* Thumb return addresses have the low bit set, so we need to subtract two. + This is still safe in ARM mode because instructions are 4 bytes. */ +# define GETPC() ((void *)((unsigned long)__builtin_return_address(0) - 2)) +#else +# define GETPC() ((void *)((unsigned long)__builtin_return_address(0) - 1)) +#endif + #endif /* !defined(__DYNGEN_EXEC_H__) */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/dyngen.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/dyngen.h --- qemu-0.9.1/dyngen.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/dyngen.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,449 +0,0 @@ -/* - * dyngen helpers - * - * Copyright (c) 2003 Fabrice Bellard - * - * 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 - */ - -int __op_param1, __op_param2, __op_param3; -#if defined(__sparc__) || defined(__arm__) - void __op_gen_label1(){} - void __op_gen_label2(){} - void __op_gen_label3(){} -#else - int __op_gen_label1, __op_gen_label2, __op_gen_label3; -#endif -int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; - -#if defined(__i386__) || defined(__x86_64__) || defined(__s390__) -static inline void flush_icache_range(unsigned long start, unsigned long stop) -{ -} -#elif defined(__ia64__) -static inline void flush_icache_range(unsigned long start, unsigned long stop) -{ - while (start < stop) { - asm volatile ("fc %0" :: "r"(start)); - start += 32; - } - asm volatile (";;sync.i;;srlz.i;;"); -} -#elif defined(__powerpc__) - -#define MIN_CACHE_LINE_SIZE 8 /* conservative value */ - -static inline void flush_icache_range(unsigned long start, unsigned long stop) -{ - unsigned long p; - - start &= ~(MIN_CACHE_LINE_SIZE - 1); - stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1); - - for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { - asm volatile ("dcbst 0,%0" : : "r"(p) : "memory"); - } - asm volatile ("sync" : : : "memory"); - for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { - asm volatile ("icbi 0,%0" : : "r"(p) : "memory"); - } - asm volatile ("sync" : : : "memory"); - asm volatile ("isync" : : : "memory"); -} -#elif defined(__alpha__) -static inline void flush_icache_range(unsigned long start, unsigned long stop) -{ - asm ("imb"); -} -#elif defined(__sparc__) -static inline void flush_icache_range(unsigned long start, unsigned long stop) -{ - unsigned long p; - - p = start & ~(8UL - 1UL); - stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL); - - for (; p < stop; p += 8) - __asm__ __volatile__("flush\t%0" : : "r" (p)); -} -#elif defined(__arm__) -static inline void flush_icache_range(unsigned long start, unsigned long stop) -{ - register unsigned long _beg __asm ("a1") = start; - register unsigned long _end __asm ("a2") = stop; - register unsigned long _flg __asm ("a3") = 0; - __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); -} -#elif defined(__mc68000) - -# include -static inline void flush_icache_range(unsigned long start, unsigned long stop) -{ - cacheflush(start,FLUSH_SCOPE_LINE,FLUSH_CACHE_BOTH,stop-start+16); -} -#elif defined(__mips__) - -#include -static inline void flush_icache_range(unsigned long start, unsigned long stop) -{ - _flush_cache ((void *)start, stop - start, BCACHE); -} -#else -#error unsupported CPU -#endif - -#ifdef __alpha__ - -register int gp asm("$29"); - -static inline void immediate_ldah(void *p, int val) { - uint32_t *dest = p; - long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff; - - *dest &= ~0xffff; - *dest |= high; - *dest |= 31 << 16; -} -static inline void immediate_lda(void *dest, int val) { - *(uint16_t *) dest = val; -} -void fix_bsr(void *p, int offset) { - uint32_t *dest = p; - *dest &= ~((1 << 21) - 1); - *dest |= (offset >> 2) & ((1 << 21) - 1); -} - -#endif /* __alpha__ */ - -#ifdef __arm__ - -#define ARM_LDR_TABLE_SIZE 1024 - -typedef struct LDREntry { - uint8_t *ptr; - uint32_t *data_ptr; - unsigned type:2; -} LDREntry; - -static LDREntry arm_ldr_table[1024]; -static uint32_t arm_data_table[ARM_LDR_TABLE_SIZE]; - -extern char exec_loop; - -static inline void arm_reloc_pc24(uint32_t *ptr, uint32_t insn, int val) -{ - *ptr = (insn & ~0xffffff) | ((insn + ((val - (int)ptr) >> 2)) & 0xffffff); -} - -static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr, - LDREntry *ldr_start, LDREntry *ldr_end, - uint32_t *data_start, uint32_t *data_end, - int gen_jmp) -{ - LDREntry *le; - uint32_t *ptr; - int offset, data_size, target; - uint8_t *data_ptr; - uint32_t insn; - uint32_t mask; - - data_size = (data_end - data_start) << 2; - - if (gen_jmp) { - /* generate branch to skip the data */ - if (data_size == 0) - return gen_code_ptr; - target = (long)gen_code_ptr + data_size + 4; - arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, target); - gen_code_ptr += 4; - } - - /* copy the data */ - data_ptr = gen_code_ptr; - memcpy(gen_code_ptr, data_start, data_size); - gen_code_ptr += data_size; - - /* patch the ldr to point to the data */ - for(le = ldr_start; le < ldr_end; le++) { - ptr = (uint32_t *)le->ptr; - offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) + - (unsigned long)data_ptr - - (unsigned long)ptr - 8; - if (offset < 0) { - fprintf(stderr, "Negative constant pool offset\n"); - abort(); - } - switch (le->type) { - case 0: /* ldr */ - mask = ~0x00800fff; - if (offset >= 4096) { - fprintf(stderr, "Bad ldr offset\n"); - abort(); - } - break; - case 1: /* ldc */ - mask = ~0x008000ff; - if (offset >= 1024 ) { - fprintf(stderr, "Bad ldc offset\n"); - abort(); - } - break; - case 2: /* add */ - mask = ~0xfff; - if (offset >= 1024 ) { - fprintf(stderr, "Bad add offset\n"); - abort(); - } - break; - default: - fprintf(stderr, "Bad pc relative fixup\n"); - abort(); - } - insn = *ptr & mask; - switch (le->type) { - case 0: /* ldr */ - insn |= offset | 0x00800000; - break; - case 1: /* ldc */ - insn |= (offset >> 2) | 0x00800000; - break; - case 2: /* add */ - insn |= (offset >> 2) | 0xf00; - break; - } - *ptr = insn; - } - return gen_code_ptr; -} - -#endif /* __arm__ */ - -#ifdef __ia64 - -/* Patch instruction with "val" where "mask" has 1 bits. */ -static inline void ia64_patch (uint64_t insn_addr, uint64_t mask, uint64_t val) -{ - uint64_t m0, m1, v0, v1, b0, b1, *b = (uint64_t *) (insn_addr & -16); -# define insn_mask ((1UL << 41) - 1) - unsigned long shift; - - b0 = b[0]; b1 = b[1]; - shift = 5 + 41 * (insn_addr % 16); /* 5 template, 3 x 41-bit insns */ - if (shift >= 64) { - m1 = mask << (shift - 64); - v1 = val << (shift - 64); - } else { - m0 = mask << shift; m1 = mask >> (64 - shift); - v0 = val << shift; v1 = val >> (64 - shift); - b[0] = (b0 & ~m0) | (v0 & m0); - } - b[1] = (b1 & ~m1) | (v1 & m1); -} - -static inline void ia64_patch_imm60 (uint64_t insn_addr, uint64_t val) -{ - ia64_patch(insn_addr, - 0x011ffffe000UL, - ( ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */ - | ((val & 0x00000000000fffffUL) << 13) /* bit 0 -> 13 */)); - ia64_patch(insn_addr - 1, 0x1fffffffffcUL, val >> 18); -} - -static inline void ia64_imm64 (void *insn, uint64_t val) -{ - /* Ignore the slot number of the relocation; GCC and Intel - toolchains differed for some time on whether IMM64 relocs are - against slot 1 (Intel) or slot 2 (GCC). */ - uint64_t insn_addr = (uint64_t) insn & ~3UL; - - ia64_patch(insn_addr + 2, - 0x01fffefe000UL, - ( ((val & 0x8000000000000000UL) >> 27) /* bit 63 -> 36 */ - | ((val & 0x0000000000200000UL) << 0) /* bit 21 -> 21 */ - | ((val & 0x00000000001f0000UL) << 6) /* bit 16 -> 22 */ - | ((val & 0x000000000000ff80UL) << 20) /* bit 7 -> 27 */ - | ((val & 0x000000000000007fUL) << 13) /* bit 0 -> 13 */) - ); - ia64_patch(insn_addr + 1, 0x1ffffffffffUL, val >> 22); -} - -static inline void ia64_imm60b (void *insn, uint64_t val) -{ - /* Ignore the slot number of the relocation; GCC and Intel - toolchains differed for some time on whether IMM64 relocs are - against slot 1 (Intel) or slot 2 (GCC). */ - uint64_t insn_addr = (uint64_t) insn & ~3UL; - - if (val + ((uint64_t) 1 << 59) >= (1UL << 60)) - fprintf(stderr, "%s: value %ld out of IMM60 range\n", - __FUNCTION__, (int64_t) val); - ia64_patch_imm60(insn_addr + 2, val); -} - -static inline void ia64_imm22 (void *insn, uint64_t val) -{ - if (val + (1 << 21) >= (1 << 22)) - fprintf(stderr, "%s: value %li out of IMM22 range\n", - __FUNCTION__, (int64_t)val); - ia64_patch((uint64_t) insn, 0x01fffcfe000UL, - ( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */ - | ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */ - | ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */ - | ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */)); -} - -/* Like ia64_imm22(), but also clear bits 20-21. For addl, this has - the effect of turning "addl rX=imm22,rY" into "addl - rX=imm22,r0". */ -static inline void ia64_imm22_r0 (void *insn, uint64_t val) -{ - if (val + (1 << 21) >= (1 << 22)) - fprintf(stderr, "%s: value %li out of IMM22 range\n", - __FUNCTION__, (int64_t)val); - ia64_patch((uint64_t) insn, 0x01fffcfe000UL | (0x3UL << 20), - ( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */ - | ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */ - | ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */ - | ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */)); -} - -static inline void ia64_imm21b (void *insn, uint64_t val) -{ - if (val + (1 << 20) >= (1 << 21)) - fprintf(stderr, "%s: value %li out of IMM21b range\n", - __FUNCTION__, (int64_t)val); - ia64_patch((uint64_t) insn, 0x11ffffe000UL, - ( ((val & 0x100000UL) << 16) /* bit 20 -> 36 */ - | ((val & 0x0fffffUL) << 13) /* bit 0 -> 13 */)); -} - -static inline void ia64_nop_b (void *insn) -{ - ia64_patch((uint64_t) insn, (1UL << 41) - 1, 2UL << 37); -} - -static inline void ia64_ldxmov(void *insn, uint64_t val) -{ - if (val + (1 << 21) < (1 << 22)) - ia64_patch((uint64_t) insn, 0x1fff80fe000UL, 8UL << 37); -} - -static inline int ia64_patch_ltoff(void *insn, uint64_t val, - int relaxable) -{ - if (relaxable && (val + (1 << 21) < (1 << 22))) { - ia64_imm22_r0(insn, val); - return 0; - } - return 1; -} - -struct ia64_fixup { - struct ia64_fixup *next; - void *addr; /* address that needs to be patched */ - long value; -}; - -#define IA64_PLT(insn, plt_index) \ -do { \ - struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \ - fixup->next = plt_fixes; \ - plt_fixes = fixup; \ - fixup->addr = (insn); \ - fixup->value = (plt_index); \ - plt_offset[(plt_index)] = 1; \ -} while (0) - -#define IA64_LTOFF(insn, val, relaxable) \ -do { \ - if (ia64_patch_ltoff(insn, val, relaxable)) { \ - struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \ - fixup->next = ltoff_fixes; \ - ltoff_fixes = fixup; \ - fixup->addr = (insn); \ - fixup->value = (val); \ - } \ -} while (0) - -static inline void ia64_apply_fixes (uint8_t **gen_code_pp, - struct ia64_fixup *ltoff_fixes, - uint64_t gp, - struct ia64_fixup *plt_fixes, - int num_plts, - unsigned long *plt_target, - unsigned int *plt_offset) -{ - static const uint8_t plt_bundle[] = { - 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; movl r1=GP */ - 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60, - - 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; brl IP */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0 - }; - uint8_t *gen_code_ptr = *gen_code_pp, *plt_start, *got_start; - uint64_t *vp; - struct ia64_fixup *fixup; - unsigned int offset = 0; - struct fdesc { - long ip; - long gp; - } *fdesc; - int i; - - if (plt_fixes) { - plt_start = gen_code_ptr; - - for (i = 0; i < num_plts; ++i) { - if (plt_offset[i]) { - plt_offset[i] = offset; - offset += sizeof(plt_bundle); - - fdesc = (struct fdesc *) plt_target[i]; - memcpy(gen_code_ptr, plt_bundle, sizeof(plt_bundle)); - ia64_imm64 (gen_code_ptr + 0x02, fdesc->gp); - ia64_imm60b(gen_code_ptr + 0x12, - (fdesc->ip - (long) (gen_code_ptr + 0x10)) >> 4); - gen_code_ptr += sizeof(plt_bundle); - } - } - - for (fixup = plt_fixes; fixup; fixup = fixup->next) - ia64_imm21b(fixup->addr, - ((long) plt_start + plt_offset[fixup->value] - - ((long) fixup->addr & ~0xf)) >> 4); - } - - got_start = gen_code_ptr; - - /* First, create the GOT: */ - for (fixup = ltoff_fixes; fixup; fixup = fixup->next) { - /* first check if we already have this value in the GOT: */ - for (vp = (uint64_t *) got_start; vp < (uint64_t *) gen_code_ptr; ++vp) - if (*vp == fixup->value) - break; - if (vp == (uint64_t *) gen_code_ptr) { - /* Nope, we need to put the value in the GOT: */ - *vp = fixup->value; - gen_code_ptr += 8; - } - ia64_imm22(fixup->addr, (long) vp - gp); - } - /* Keep code ptr aligned. */ - if ((long) gen_code_ptr & 15) - gen_code_ptr += 8; - *gen_code_pp = gen_code_ptr; -} - -#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/dyngen-op.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/dyngen-op.h --- qemu-0.9.1/dyngen-op.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/dyngen-op.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,9 +0,0 @@ -static inline int gen_new_label(void) -{ - return nb_gen_labels++; -} - -static inline void gen_set_label(int n) -{ - gen_labels[n] = gen_opc_ptr - gen_opc_buf; -} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/elf.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/elf.h --- qemu-0.9.1/elf.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/elf.h 2008-09-06 18:47:39.000000000 +0100 @@ -1123,6 +1123,7 @@ Elf64_Word n_type; /* Content type */ } Elf64_Nhdr; +#ifdef ELF_CLASS #if ELF_CLASS == ELFCLASS32 #define elfhdr elf32_hdr @@ -1165,5 +1166,7 @@ # endif #endif +#endif /* ELF_CLASS */ + #endif /* _QEMU_ELF_H */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/elf_ops.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/elf_ops.h --- qemu-0.9.1/elf_ops.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/elf_ops.h 2008-10-22 19:20:20.000000000 +0100 @@ -60,13 +60,48 @@ return NULL; } +static int glue(symfind, SZ)(const void *s0, const void *s1) +{ + struct elf_sym *key = (struct elf_sym *)s0; + struct elf_sym *sym = (struct elf_sym *)s1; + int result = 0; + if (key->st_value < sym->st_value) { + result = -1; + } else if (key->st_value > sym->st_value + sym->st_size) { + result = 1; + } + return result; +} + +static const char *glue(lookup_symbol, SZ)(struct syminfo *s, target_ulong orig_addr) +{ + struct elf_sym *syms = glue(s->disas_symtab.elf, SZ); + struct elf_sym key; + struct elf_sym *sym; + + key.st_value = orig_addr; + + sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), glue(symfind, SZ)); + if (sym != 0) { + return s->disas_strtab + sym->st_name; + } + + return ""; +} + +static int glue(symcmp, SZ)(const void *s0, const void *s1) +{ + struct elf_sym *sym0 = (struct elf_sym *)s0; + struct elf_sym *sym1 = (struct elf_sym *)s1; + return (sym0->st_value < sym1->st_value) + ? -1 + : ((sym0->st_value > sym1->st_value) ? 1 : 0); +} + static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) { struct elf_shdr *symtab, *strtab, *shdr_table = NULL; struct elf_sym *syms = NULL; -#if (SZ == 64) - struct elf32_sym *syms32 = NULL; -#endif struct syminfo *s; int nsyms, i; char *str = NULL; @@ -90,21 +125,32 @@ goto fail; nsyms = symtab->sh_size / sizeof(struct elf_sym); -#if (SZ == 64) - syms32 = qemu_mallocz(nsyms * sizeof(struct elf32_sym)); -#endif - for (i = 0; i < nsyms; i++) { + + i = 0; + while (i < nsyms) { if (must_swab) glue(bswap_sym, SZ)(&syms[i]); -#if (SZ == 64) - syms32[i].st_name = syms[i].st_name; - syms32[i].st_info = syms[i].st_info; - syms32[i].st_other = syms[i].st_other; - syms32[i].st_shndx = syms[i].st_shndx; - syms32[i].st_value = syms[i].st_value & 0xffffffff; - syms32[i].st_size = syms[i].st_size & 0xffffffff; + /* We are only interested in function symbols. + Throw everything else away. */ + if (syms[i].st_shndx == SHN_UNDEF || + syms[i].st_shndx >= SHN_LORESERVE || + ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) { + nsyms--; + if (i < nsyms) { + syms[i] = syms[nsyms]; + } + continue; + } +#if defined(TARGET_ARM) || defined (TARGET_MIPS) + /* The bottom address bit marks a Thumb or MIPS16 symbol. */ + syms[i].st_value &= ~(target_ulong)1; #endif + i++; } + syms = qemu_realloc(syms, nsyms * sizeof(*syms)); + + qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ)); + /* String table */ if (symtab->sh_link >= ehdr->e_shnum) goto fail; @@ -112,16 +158,12 @@ str = load_at(fd, strtab->sh_offset, strtab->sh_size); if (!str) - goto fail; + goto fail; /* Commit */ s = qemu_mallocz(sizeof(*s)); -#if (SZ == 64) - s->disas_symtab = syms32; - qemu_free(syms); -#else - s->disas_symtab = syms; -#endif + s->lookup_symbol = glue(lookup_symbol, SZ); + glue(s->disas_symtab.elf, SZ) = syms; s->disas_num_syms = nsyms; s->disas_strtab = str; s->next = syminfos; @@ -129,16 +171,13 @@ qemu_free(shdr_table); return 0; fail: -#if (SZ == 64) - qemu_free(syms32); -#endif qemu_free(syms); qemu_free(str); qemu_free(shdr_table); return -1; } -static int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, +static int glue(load_elf, SZ)(int fd, int64_t address_offset, int must_swab, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr) { @@ -190,7 +229,9 @@ if (read(fd, data, ph->p_filesz) != ph->p_filesz) goto fail; } - addr = ph->p_vaddr + virt_to_phys_addend; + /* address_offset is hack for kernel images that are + linked at the wrong physical address. */ + addr = ph->p_paddr + address_offset; cpu_physical_memory_write_rom(addr, data, mem_size); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/exec-all.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/exec-all.h --- qemu-0.9.1/exec-all.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/exec-all.h 2008-11-11 13:41:01.000000000 +0000 @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef _EXEC_ALL_H_ +#define _EXEC_ALL_H_ /* allow to see translation results - the slowdown should be negligible, so we leave it */ #define DEBUG_DISAS @@ -27,23 +29,28 @@ #define DISAS_UPDATE 2 /* cpu state was modified dynamically */ #define DISAS_TB_JUMP 3 /* only pc was modified statically */ -struct TranslationBlock; +typedef struct TranslationBlock TranslationBlock; /* XXX: make safe guess about sizes */ -#define MAX_OP_PER_INSTR 32 +#define MAX_OP_PER_INSTR 64 +/* A Call op needs up to 6 + 2N parameters (N = number of arguments). */ +#define MAX_OPC_PARAM 10 #define OPC_BUF_SIZE 512 #define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR) -#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3) +/* Maximum size a TCG op can expand to. This is complicated because a + single op may require several host instructions and regirster reloads. + For now take a wild guess at 128 bytes, which should allow at least + a couple of fixup instructions per argument. */ +#define TCG_MAX_OP_SIZE 128 + +#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * MAX_OPC_PARAM) -extern uint16_t gen_opc_buf[OPC_BUF_SIZE]; -extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; -extern long gen_labels[OPC_BUF_SIZE]; -extern int nb_gen_labels; extern target_ulong gen_opc_pc[OPC_BUF_SIZE]; extern target_ulong gen_opc_npc[OPC_BUF_SIZE]; extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; +extern uint16_t gen_opc_icount[OPC_BUF_SIZE]; extern target_ulong gen_opc_jump_pc[2]; extern uint32_t gen_opc_hflags[OPC_BUF_SIZE]; @@ -52,33 +59,31 @@ typedef void (GenOpFunc2)(long, long); typedef void (GenOpFunc3)(long, long, long); -#if defined(TARGET_I386) - -void optimize_flags_init(void); - -#endif +#include "qemu-log.h" -extern FILE *logfile; -extern int loglevel; +void gen_intermediate_code(CPUState *env, struct TranslationBlock *tb); +void gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb); +void gen_pc_load(CPUState *env, struct TranslationBlock *tb, + unsigned long searched_pc, int pc_pos, void *puc); -int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb); -int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb); -void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf); unsigned long code_gen_max_block_size(void); +void cpu_gen_init(void); int cpu_gen_code(CPUState *env, struct TranslationBlock *tb, int *gen_code_size_ptr); int cpu_restore_state(struct TranslationBlock *tb, CPUState *env, unsigned long searched_pc, void *puc); -int cpu_gen_code_copy(CPUState *env, struct TranslationBlock *tb, - int max_code_size, int *gen_code_size_ptr); int cpu_restore_state_copy(struct TranslationBlock *tb, CPUState *env, unsigned long searched_pc, void *puc); void cpu_resume_from_signal(CPUState *env1, void *puc); +void cpu_io_recompile(CPUState *env, void *retaddr); +TranslationBlock *tb_gen_code(CPUState *env, + target_ulong pc, target_ulong cs_base, int flags, + int cflags); void cpu_exec_init(CPUState *env); int page_unprotect(target_ulong address, unsigned long pc, void *puc); -void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, +void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end, int is_cpu_write_access); void tb_invalidate_page_range(target_ulong start, target_ulong end); void tlb_flush_page(CPUState *env, target_ulong addr); @@ -86,13 +91,13 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, target_phys_addr_t paddr, int prot, int mmu_idx, int is_softmmu); -static inline int tlb_set_page(CPUState *env, target_ulong vaddr, +static inline int tlb_set_page(CPUState *env1, target_ulong vaddr, target_phys_addr_t paddr, int prot, int mmu_idx, int is_softmmu) { if (prot & PAGE_READ) prot |= PAGE_EXEC; - return tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu); + return tlb_set_page_exec(env1, vaddr, paddr, prot, mmu_idx, is_softmmu); } #define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ @@ -100,30 +105,7 @@ #define CODE_GEN_PHYS_HASH_BITS 15 #define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS) -/* maximum total translate dcode allocated */ - -/* NOTE: the translated code area cannot be too big because on some - archs the range of "fast" function calls is limited. Here is a - summary of the ranges: - - i386 : signed 32 bits - arm : signed 26 bits - ppc : signed 24 bits - sparc : signed 32 bits - alpha : signed 23 bits -*/ - -#if defined(__alpha__) -#define CODE_GEN_BUFFER_SIZE (2 * 1024 * 1024) -#elif defined(__ia64) -#define CODE_GEN_BUFFER_SIZE (4 * 1024 * 1024) /* range of addl */ -#elif defined(__powerpc__) -#define CODE_GEN_BUFFER_SIZE (6 * 1024 * 1024) -#else -#define CODE_GEN_BUFFER_SIZE (16 * 1024 * 1024) -#endif - -//#define CODE_GEN_BUFFER_SIZE (128 * 1024) +#define MIN_CODE_GEN_BUFFER_SIZE (1024 * 1024) /* estimated block size for TB allocation */ /* XXX: use a per code average code fragment size and modulate it @@ -134,26 +116,22 @@ #define CODE_GEN_AVG_BLOCK_SIZE 64 #endif -#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / CODE_GEN_AVG_BLOCK_SIZE) - -#if defined(__powerpc__) +#if defined(__powerpc__) || defined(__x86_64__) || defined(__arm__) #define USE_DIRECT_JUMP #endif #if defined(__i386__) && !defined(_WIN32) #define USE_DIRECT_JUMP #endif -typedef struct TranslationBlock { +struct TranslationBlock { target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ target_ulong cs_base; /* CS base for this block */ uint64_t flags; /* flags defining in which context the code was generated */ uint16_t size; /* size of target code for this block (1 <= size <= TARGET_PAGE_SIZE) */ uint16_t cflags; /* compile flags */ -#define CF_CODE_COPY 0x0001 /* block was generated in code copy mode */ -#define CF_TB_FP_USED 0x0002 /* fp ops are used in the TB */ -#define CF_FP_USED 0x0004 /* fp ops are used in the TB or in a chained TB */ -#define CF_SINGLE_INSN 0x0008 /* compile only a single instruction */ +#define CF_COUNT_MASK 0x7fff +#define CF_LAST_IO 0x8000 /* Last insn may be an IO access. */ uint8_t *tc_ptr; /* pointer to the translated code */ /* next matching tb for physical address. */ @@ -169,7 +147,7 @@ #ifdef USE_DIRECT_JUMP uint16_t tb_jmp_offset[4]; /* offset of jump instruction */ #else - uint32_t tb_next[2]; /* address of jump generated code */ + unsigned long tb_next[2]; /* address of jump generated code */ #endif /* list of TBs jumping to this one. This is a circular list using the two least significant bits of the pointers to tell what is @@ -177,21 +155,22 @@ jmp_first */ struct TranslationBlock *jmp_next[2]; struct TranslationBlock *jmp_first; -} TranslationBlock; + uint32_t icount; +}; static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc) { target_ulong tmp; tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)); - return (tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK; + return (tmp >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)) & TB_JMP_PAGE_MASK; } static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc) { target_ulong tmp; tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)); - return (((tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK) | - (tmp & TB_JMP_ADDR_MASK)); + return (((tmp >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)) & TB_JMP_PAGE_MASK) + | (tmp & TB_JMP_ADDR_MASK)); } static inline unsigned int tb_phys_hash_func(unsigned long pc) @@ -200,40 +179,43 @@ } TranslationBlock *tb_alloc(target_ulong pc); +void tb_free(TranslationBlock *tb); void tb_flush(CPUState *env); void tb_link_phys(TranslationBlock *tb, target_ulong phys_pc, target_ulong phys_page2); +void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr); extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; - -extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; extern uint8_t *code_gen_ptr; +extern int code_gen_max_blocks; #if defined(USE_DIRECT_JUMP) #if defined(__powerpc__) +extern void ppc_tb_set_jmp_target(unsigned long jmp_addr, unsigned long addr); +#define tb_set_jmp_target1 ppc_tb_set_jmp_target +#elif defined(__i386__) || defined(__x86_64__) static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) { - uint32_t val, *ptr; - /* patch the branch destination */ - ptr = (uint32_t *)jmp_addr; - val = *ptr; - val = (val & ~0x03fffffc) | ((addr - jmp_addr) & 0x03fffffc); - *ptr = val; - /* flush icache */ - asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory"); - asm volatile ("sync" : : : "memory"); - asm volatile ("icbi 0,%0" : : "r"(ptr) : "memory"); - asm volatile ("sync" : : : "memory"); - asm volatile ("isync" : : : "memory"); + *(uint32_t *)jmp_addr = addr - (jmp_addr + 4); + /* no need to flush icache explicitly */ } -#elif defined(__i386__) +#elif defined(__arm__) static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) { - /* patch the branch destination */ - *(uint32_t *)jmp_addr = addr - (jmp_addr + 4); - /* no need to flush icache explicitely */ + register unsigned long _beg __asm ("a1"); + register unsigned long _end __asm ("a2"); + register unsigned long _flg __asm ("a3"); + + /* we could use a ldr pc, [pc, #-4] kind of branch and avoid the flush */ + *(uint32_t *)jmp_addr |= ((addr - (jmp_addr + 8)) >> 2) & 0xffffff; + + /* flush icache */ + _beg = jmp_addr; + _end = jmp_addr + 4; + _flg = 0; + __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); } #endif @@ -276,10 +258,6 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr); -#ifndef offsetof -#define offsetof(type, field) ((size_t) &((type *)0)->field) -#endif - #if defined(_WIN32) #define ASM_DATA_SECTION ".section \".data\"\n" #define ASM_PREVIOUS_SECTION ".section .text\n" @@ -294,216 +272,11 @@ #define ASM_OP_LABEL_NAME(n, opname) \ ASM_NAME(__op_label) #n "." ASM_NAME(opname) -#if defined(__powerpc__) - -/* we patch the jump instruction directly */ -#define GOTO_TB(opname, tbparam, n)\ -do {\ - asm volatile (ASM_DATA_SECTION\ - ASM_OP_LABEL_NAME(n, opname) ":\n"\ - ".long 1f\n"\ - ASM_PREVIOUS_SECTION \ - "b " ASM_NAME(__op_jmp) #n "\n"\ - "1:\n");\ -} while (0) - -#elif defined(__i386__) && defined(USE_DIRECT_JUMP) - -/* we patch the jump instruction directly */ -#define GOTO_TB(opname, tbparam, n)\ -do {\ - asm volatile (".section .data\n"\ - ASM_OP_LABEL_NAME(n, opname) ":\n"\ - ".long 1f\n"\ - ASM_PREVIOUS_SECTION \ - "jmp " ASM_NAME(__op_jmp) #n "\n"\ - "1:\n");\ -} while (0) - -#else - -/* jump to next block operations (more portable code, does not need - cache flushing, but slower because of indirect jump) */ -#define GOTO_TB(opname, tbparam, n)\ -do {\ - static void __attribute__((used)) *dummy ## n = &&dummy_label ## n;\ - static void __attribute__((used)) *__op_label ## n \ - __asm__(ASM_OP_LABEL_NAME(n, opname)) = &&label ## n;\ - goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\ -label ## n: ;\ -dummy_label ## n: ;\ -} while (0) - -#endif - extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; extern void *io_mem_opaque[IO_MEM_NB_ENTRIES]; -#if defined(__powerpc__) -static inline int testandset (int *p) -{ - int ret; - __asm__ __volatile__ ( - "0: lwarx %0,0,%1\n" - " xor. %0,%3,%0\n" - " bne 1f\n" - " stwcx. %2,0,%1\n" - " bne- 0b\n" - "1: " - : "=&r" (ret) - : "r" (p), "r" (1), "r" (0) - : "cr0", "memory"); - return ret; -} -#elif defined(__i386__) -static inline int testandset (int *p) -{ - long int readval = 0; - - __asm__ __volatile__ ("lock; cmpxchgl %2, %0" - : "+m" (*p), "+a" (readval) - : "r" (1) - : "cc"); - return readval; -} -#elif defined(__x86_64__) -static inline int testandset (int *p) -{ - long int readval = 0; - - __asm__ __volatile__ ("lock; cmpxchgl %2, %0" - : "+m" (*p), "+a" (readval) - : "r" (1) - : "cc"); - return readval; -} -#elif defined(__s390__) -static inline int testandset (int *p) -{ - int ret; - - __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n" - " jl 0b" - : "=&d" (ret) - : "r" (1), "a" (p), "0" (*p) - : "cc", "memory" ); - return ret; -} -#elif defined(__alpha__) -static inline int testandset (int *p) -{ - int ret; - unsigned long one; - - __asm__ __volatile__ ("0: mov 1,%2\n" - " ldl_l %0,%1\n" - " stl_c %2,%1\n" - " beq %2,1f\n" - ".subsection 2\n" - "1: br 0b\n" - ".previous" - : "=r" (ret), "=m" (*p), "=r" (one) - : "m" (*p)); - return ret; -} -#elif defined(__sparc__) -static inline int testandset (int *p) -{ - int ret; - - __asm__ __volatile__("ldstub [%1], %0" - : "=r" (ret) - : "r" (p) - : "memory"); - - return (ret ? 1 : 0); -} -#elif defined(__arm__) -static inline int testandset (int *spinlock) -{ - register unsigned int ret; - __asm__ __volatile__("swp %0, %1, [%2]" - : "=r"(ret) - : "0"(1), "r"(spinlock)); - - return ret; -} -#elif defined(__mc68000) -static inline int testandset (int *p) -{ - char ret; - __asm__ __volatile__("tas %1; sne %0" - : "=r" (ret) - : "m" (p) - : "cc","memory"); - return ret; -} -#elif defined(__ia64) - -#include - -static inline int testandset (int *p) -{ - return __sync_lock_test_and_set (p, 1); -} -#elif defined(__mips__) -static inline int testandset (int *p) -{ - int ret; - - __asm__ __volatile__ ( - " .set push \n" - " .set noat \n" - " .set mips2 \n" - "1: li $1, 1 \n" - " ll %0, %1 \n" - " sc $1, %1 \n" - " beqz $1, 1b \n" - " .set pop " - : "=r" (ret), "+R" (*p) - : - : "memory"); - - return ret; -} -#else -#error unimplemented CPU support -#endif - -typedef int spinlock_t; - -#define SPIN_LOCK_UNLOCKED 0 - -#if defined(CONFIG_USER_ONLY) -static inline void spin_lock(spinlock_t *lock) -{ - while (testandset(lock)); -} - -static inline void spin_unlock(spinlock_t *lock) -{ - *lock = 0; -} - -static inline int spin_trylock(spinlock_t *lock) -{ - return !testandset(lock); -} -#else -static inline void spin_lock(spinlock_t *lock) -{ -} - -static inline void spin_unlock(spinlock_t *lock) -{ -} - -static inline int spin_trylock(spinlock_t *lock) -{ - return 1; -} -#endif +#include "qemu-lock.h" extern spinlock_t tb_lock; @@ -514,6 +287,8 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr); +#include "softmmu_defs.h" + #define ACCESS_TYPE (NB_MMU_MODES + 1) #define MEMSUFFIX _code #define env cpu_single_env @@ -537,7 +312,7 @@ #endif #if defined(CONFIG_USER_ONLY) -static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) +static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr) { return addr; } @@ -545,40 +320,60 @@ /* NOTE: this function can trigger an exception */ /* NOTE2: the returned address is not exactly the physical address: it is the offset relative to phys_ram_base */ -static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) +static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr) { - int mmu_idx, index, pd; + int mmu_idx, page_index, pd; - index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - mmu_idx = cpu_mmu_index(env); - if (__builtin_expect(env->tlb_table[mmu_idx][index].addr_code != - (addr & TARGET_PAGE_MASK), 0)) { + page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + mmu_idx = cpu_mmu_index(env1); + if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code != + (addr & TARGET_PAGE_MASK))) { ldub_code(addr); } - pd = env->tlb_table[mmu_idx][index].addr_code & ~TARGET_PAGE_MASK; + pd = env1->tlb_table[mmu_idx][page_index].addr_code & ~TARGET_PAGE_MASK; if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { #if defined(TARGET_SPARC) || defined(TARGET_MIPS) - do_unassigned_access(addr, 0, 1, 0); + do_unassigned_access(addr, 0, 1, 0, 4); #else - cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr); + cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr); #endif } - return addr + env->tlb_table[mmu_idx][index].addend - (unsigned long)phys_ram_base; + return addr + env1->tlb_table[mmu_idx][page_index].addend - (unsigned long)phys_ram_base; +} + +/* Deterministic execution requires that IO only be performed on the last + instruction of a TB so that interrupts take effect immediately. */ +static inline int can_do_io(CPUState *env) +{ + if (!use_icount) + return 1; + + /* If not executing code then assume we are ok. */ + if (!env->current_tb) + return 1; + + return env->can_do_io != 0; } #endif #ifdef USE_KQEMU #define KQEMU_MODIFY_PAGE_MASK (0xff & ~(VGA_DIRTY_FLAG | CODE_DIRTY_FLAG)) +#define MSR_QPI_COMMBASE 0xfabe0010 + int kqemu_init(CPUState *env); int kqemu_cpu_exec(CPUState *env); void kqemu_flush_page(CPUState *env, target_ulong addr); void kqemu_flush(CPUState *env, int global); void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr); void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr); +void kqemu_set_phys_mem(uint64_t start_addr, ram_addr_t size, + ram_addr_t phys_offset); void kqemu_cpu_interrupt(CPUState *env); void kqemu_record_dump(void); +extern uint32_t kqemu_comm_base; + static inline int kqemu_is_ok(CPUState *env) { return(env->kqemu_enabled && @@ -592,3 +387,4 @@ } #endif +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/exec.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/exec.c --- qemu-0.9.1/exec.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/exec.c 2008-11-11 22:06:42.000000000 +0000 @@ -35,6 +35,11 @@ #include "cpu.h" #include "exec-all.h" +#include "qemu-common.h" +#include "tcg.h" +#include "hw/hw.h" +#include "osdep.h" +#include "kvm.h" #if defined(CONFIG_USER_ONLY) #include #endif @@ -56,9 +61,6 @@ #undef DEBUG_TB_CHECK #endif -/* threshold to flush the translated code buffer */ -#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - code_gen_max_block_size()) - #define SMC_BITMAP_USE_THRESHOLD 10 #define MMAP_AREA_START 0x00000000 @@ -73,30 +75,61 @@ #define TARGET_VIRT_ADDR_SPACE_BITS 42 #elif defined(TARGET_PPC64) #define TARGET_PHYS_ADDR_SPACE_BITS 42 +#elif defined(TARGET_X86_64) && !defined(USE_KQEMU) +#define TARGET_PHYS_ADDR_SPACE_BITS 42 +#elif defined(TARGET_I386) && !defined(USE_KQEMU) +#define TARGET_PHYS_ADDR_SPACE_BITS 36 #else /* Note: for compatibility with kqemu, we use 32 bits for x86_64 */ #define TARGET_PHYS_ADDR_SPACE_BITS 32 #endif -TranslationBlock tbs[CODE_GEN_MAX_BLOCKS]; +static TranslationBlock *tbs; +int code_gen_max_blocks; TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; -int nb_tbs; +static int nb_tbs; /* any access to the tbs or the page table must use this lock */ spinlock_t tb_lock = SPIN_LOCK_UNLOCKED; -uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32))); +#if defined(__arm__) || defined(__sparc_v9__) +/* The prologue must be reachable with a direct jump. ARM and Sparc64 + have limited branch ranges (possibly also PPC) so place it in a + section close to code segment. */ +#define code_gen_section \ + __attribute__((__section__(".gen_code"))) \ + __attribute__((aligned (32))) +#else +#define code_gen_section \ + __attribute__((aligned (32))) +#endif + +uint8_t code_gen_prologue[1024] code_gen_section; +static uint8_t *code_gen_buffer; +static unsigned long code_gen_buffer_size; +/* threshold to flush the translated code buffer */ +static unsigned long code_gen_buffer_max_size; uint8_t *code_gen_ptr; -int phys_ram_size; +#if !defined(CONFIG_USER_ONLY) +ram_addr_t phys_ram_size; int phys_ram_fd; uint8_t *phys_ram_base; uint8_t *phys_ram_dirty; +static int in_migration; static ram_addr_t phys_ram_alloc_offset = 0; +#endif CPUState *first_cpu; /* current CPU in the current thread. It is only valid inside cpu_exec() */ CPUState *cpu_single_env; +/* 0 = Do not count executed instructions. + 1 = Precise instruction counting. + 2 = Adaptive rate instruction counting. */ +int use_icount = 0; +/* Current instruction counter. While executing translated code this may + include some instructions that have not yet been executed. */ +int64_t qemu_icount; typedef struct PageDesc { /* list of TBs intersecting this ram page */ @@ -111,8 +144,8 @@ } PageDesc; typedef struct PhysPageDesc { - /* offset in host memory of the page + io_index in the low 12 bits */ - uint32_t phys_offset; + /* offset in host memory of the page + io_index in the low bits */ + ram_addr_t phys_offset; } PhysPageDesc; #define L2_BITS 10 @@ -129,8 +162,6 @@ #define L1_SIZE (1 << L1_BITS) #define L2_SIZE (1 << L2_BITS) -static void io_mem_init(void); - unsigned long qemu_real_host_page_size; unsigned long qemu_host_page_bits; unsigned long qemu_host_page_size; @@ -138,19 +169,21 @@ /* XXX: for system emulation, it could just be an array */ static PageDesc *l1_map[L1_SIZE]; -PhysPageDesc **l1_phys_map; +static PhysPageDesc **l1_phys_map; + +#if !defined(CONFIG_USER_ONLY) +static void io_mem_init(void); /* io memory support */ CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; void *io_mem_opaque[IO_MEM_NB_ENTRIES]; static int io_mem_nb; -#if defined(CONFIG_SOFTMMU) static int io_mem_watch; #endif /* log support */ -char *logfilename = "/tmp/qemu.log"; +static const char *logfilename = "/tmp/qemu.log"; FILE *logfile; int loglevel; static int log_append = 0; @@ -168,6 +201,32 @@ void *opaque[TARGET_PAGE_SIZE][2][4]; } subpage_t; +#ifdef _WIN32 +static void map_exec(void *addr, long size) +{ + DWORD old_protect; + VirtualProtect(addr, size, + PAGE_EXECUTE_READWRITE, &old_protect); + +} +#else +static void map_exec(void *addr, long size) +{ + unsigned long start, end, page_size; + + page_size = getpagesize(); + start = (unsigned long)addr; + start &= ~(page_size - 1); + + end = (unsigned long)addr + size; + end += page_size - 1; + end &= ~(page_size - 1); + + mprotect((void *)start, end - start, + PROT_READ | PROT_WRITE | PROT_EXEC); +} +#endif + static void page_init(void) { /* NOTE: we can always suppose that qemu_host_page_size >= @@ -175,31 +234,13 @@ #ifdef _WIN32 { SYSTEM_INFO system_info; - DWORD old_protect; GetSystemInfo(&system_info); qemu_real_host_page_size = system_info.dwPageSize; - - VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer), - PAGE_EXECUTE_READWRITE, &old_protect); } #else qemu_real_host_page_size = getpagesize(); - { - unsigned long start, end; - - start = (unsigned long)code_gen_buffer; - start &= ~(qemu_real_host_page_size - 1); - - end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer); - end += qemu_real_host_page_size - 1; - end &= ~(qemu_real_host_page_size - 1); - - mprotect((void *)start, end - start, - PROT_READ | PROT_WRITE | PROT_EXEC); - } #endif - if (qemu_host_page_size == 0) qemu_host_page_size = qemu_real_host_page_size; if (qemu_host_page_size < TARGET_PAGE_SIZE) @@ -217,42 +258,79 @@ FILE *f; int n; + mmap_lock(); + last_brk = (unsigned long)sbrk(0); f = fopen("/proc/self/maps", "r"); if (f) { do { n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr); if (n == 2) { - page_set_flags(TARGET_PAGE_ALIGN(startaddr), + startaddr = MIN(startaddr, + (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1); + endaddr = MIN(endaddr, + (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1); + page_set_flags(startaddr & TARGET_PAGE_MASK, TARGET_PAGE_ALIGN(endaddr), PAGE_RESERVED); } } while (!feof(f)); fclose(f); } + mmap_unlock(); } #endif } -static inline PageDesc *page_find_alloc(unsigned int index) +static inline PageDesc **page_l1_map(target_ulong index) +{ +#if TARGET_LONG_BITS > 32 + /* Host memory outside guest VM. For 32-bit targets we have already + excluded high addresses. */ + if (index > ((target_ulong)L2_SIZE * L1_SIZE)) + return NULL; +#endif + return &l1_map[index >> L2_BITS]; +} + +static inline PageDesc *page_find_alloc(target_ulong index) { PageDesc **lp, *p; + lp = page_l1_map(index); + if (!lp) + return NULL; - lp = &l1_map[index >> L2_BITS]; p = *lp; if (!p) { /* allocate if not found */ - p = qemu_malloc(sizeof(PageDesc) * L2_SIZE); - memset(p, 0, sizeof(PageDesc) * L2_SIZE); +#if defined(CONFIG_USER_ONLY) + unsigned long addr; + size_t len = sizeof(PageDesc) * L2_SIZE; + /* Don't use qemu_malloc because it may recurse. */ + p = mmap(0, len, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + *lp = p; + addr = h2g(p); + if (addr == (target_ulong)addr) { + page_set_flags(addr & TARGET_PAGE_MASK, + TARGET_PAGE_ALIGN(addr + len), + PAGE_RESERVED); + } +#else + p = qemu_mallocz(sizeof(PageDesc) * L2_SIZE); *lp = p; +#endif } return p + (index & (L2_SIZE - 1)); } -static inline PageDesc *page_find(unsigned int index) +static inline PageDesc *page_find(target_ulong index) { - PageDesc *p; + PageDesc **lp, *p; + lp = page_l1_map(index); + if (!lp) + return NULL; - p = l1_map[index >> L2_BITS]; + p = *lp; if (!p) return 0; return p + (index & (L2_SIZE - 1)); @@ -304,6 +382,146 @@ static void tlb_protect_code(ram_addr_t ram_addr); static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, target_ulong vaddr); +#define mmap_lock() do { } while(0) +#define mmap_unlock() do { } while(0) +#endif + +#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024) + +#if defined(CONFIG_USER_ONLY) +/* Currently it is not recommanded to allocate big chunks of data in + user mode. It will change when a dedicated libc will be used */ +#define USE_STATIC_CODE_GEN_BUFFER +#endif + +#ifdef USE_STATIC_CODE_GEN_BUFFER +static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE]; +#endif + +static void code_gen_alloc(unsigned long tb_size) +{ +#ifdef USE_STATIC_CODE_GEN_BUFFER + code_gen_buffer = static_code_gen_buffer; + code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE; + map_exec(code_gen_buffer, code_gen_buffer_size); +#else + code_gen_buffer_size = tb_size; + if (code_gen_buffer_size == 0) { +#if defined(CONFIG_USER_ONLY) + /* in user mode, phys_ram_size is not meaningful */ + code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE; +#else + /* XXX: needs ajustments */ + code_gen_buffer_size = (unsigned long)(phys_ram_size / 4); +#endif + } + if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE) + code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE; + /* The code gen buffer location may have constraints depending on + the host cpu and OS */ +#if defined(__linux__) + { + int flags; + void *start = NULL; + + flags = MAP_PRIVATE | MAP_ANONYMOUS; +#if defined(__x86_64__) + flags |= MAP_32BIT; + /* Cannot map more than that */ + if (code_gen_buffer_size > (800 * 1024 * 1024)) + code_gen_buffer_size = (800 * 1024 * 1024); +#elif defined(__sparc_v9__) + // Map the buffer below 2G, so we can use direct calls and branches + flags |= MAP_FIXED; + start = (void *) 0x60000000UL; + if (code_gen_buffer_size > (512 * 1024 * 1024)) + code_gen_buffer_size = (512 * 1024 * 1024); +#endif + code_gen_buffer = mmap(start, code_gen_buffer_size, + PROT_WRITE | PROT_READ | PROT_EXEC, + flags, -1, 0); + if (code_gen_buffer == MAP_FAILED) { + fprintf(stderr, "Could not allocate dynamic translator buffer\n"); + exit(1); + } + } +#elif defined(__FreeBSD__) + { + int flags; + void *addr = NULL; + flags = MAP_PRIVATE | MAP_ANONYMOUS; +#if defined(__x86_64__) + /* FreeBSD doesn't have MAP_32BIT, use MAP_FIXED and assume + * 0x40000000 is free */ + flags |= MAP_FIXED; + addr = (void *)0x40000000; + /* Cannot map more than that */ + if (code_gen_buffer_size > (800 * 1024 * 1024)) + code_gen_buffer_size = (800 * 1024 * 1024); +#endif + code_gen_buffer = mmap(addr, code_gen_buffer_size, + PROT_WRITE | PROT_READ | PROT_EXEC, + flags, -1, 0); + if (code_gen_buffer == MAP_FAILED) { + fprintf(stderr, "Could not allocate dynamic translator buffer\n"); + exit(1); + } + } +#else + code_gen_buffer = qemu_malloc(code_gen_buffer_size); + if (!code_gen_buffer) { + fprintf(stderr, "Could not allocate dynamic translator buffer\n"); + exit(1); + } + map_exec(code_gen_buffer, code_gen_buffer_size); +#endif +#endif /* !USE_STATIC_CODE_GEN_BUFFER */ + map_exec(code_gen_prologue, sizeof(code_gen_prologue)); + code_gen_buffer_max_size = code_gen_buffer_size - + code_gen_max_block_size(); + code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE; + tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock)); +} + +/* Must be called before using the QEMU cpus. 'tb_size' is the size + (in bytes) allocated to the translation buffer. Zero means default + size. */ +void cpu_exec_init_all(unsigned long tb_size) +{ + cpu_gen_init(); + code_gen_alloc(tb_size); + code_gen_ptr = code_gen_buffer; + page_init(); +#if !defined(CONFIG_USER_ONLY) + io_mem_init(); +#endif +} + +#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY) + +#define CPU_COMMON_SAVE_VERSION 1 + +static void cpu_common_save(QEMUFile *f, void *opaque) +{ + CPUState *env = opaque; + + qemu_put_be32s(f, &env->halted); + qemu_put_be32s(f, &env->interrupt_request); +} + +static int cpu_common_load(QEMUFile *f, void *opaque, int version_id) +{ + CPUState *env = opaque; + + if (version_id != CPU_COMMON_SAVE_VERSION) + return -EINVAL; + + qemu_get_be32s(f, &env->halted); + qemu_get_be32s(f, &env->interrupt_request); + tlb_flush(env, 1); + + return 0; +} #endif void cpu_exec_init(CPUState *env) @@ -311,11 +529,6 @@ CPUState **penv; int cpu_index; - if (!code_gen_ptr) { - code_gen_ptr = code_gen_buffer; - page_init(); - io_mem_init(); - } env->next_cpu = NULL; penv = &first_cpu; cpu_index = 0; @@ -326,6 +539,12 @@ env->cpu_index = cpu_index; env->nb_watchpoints = 0; *penv = env; +#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY) + register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION, + cpu_common_save, cpu_common_load, env); + register_savevm("cpu", cpu_index, CPU_SAVE_VERSION, + cpu_save, cpu_load, env); +#endif } static inline void invalidate_page_bitmap(PageDesc *p) @@ -366,6 +585,9 @@ nb_tbs, nb_tbs > 0 ? ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0); #endif + if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size) + cpu_abort(env1, "Internal error: code buffer overflow\n"); + nb_tbs = 0; for(env = first_cpu; env != NULL; env = env->next_cpu) { @@ -417,7 +639,7 @@ } } -void tb_jmp_check(TranslationBlock *tb) +static void tb_jmp_check(TranslationBlock *tb) { TranslationBlock *tb1; unsigned int n1; @@ -506,12 +728,12 @@ tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n])); } -static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr) +void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr) { CPUState *env; PageDesc *p; unsigned int h, n1; - target_ulong phys_pc; + target_phys_addr_t phys_pc; TranslationBlock *tb1, *tb2; /* remove the TB from the hash list */ @@ -594,10 +816,9 @@ int n, tb_start, tb_end; TranslationBlock *tb; - p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8); + p->code_bitmap = qemu_mallocz(TARGET_PAGE_SIZE / 8); if (!p->code_bitmap) return; - memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8); tb = p->first_tb; while (tb != NULL) { @@ -620,11 +841,9 @@ } } -#ifdef TARGET_HAS_PRECISE_SMC - -static void tb_gen_code(CPUState *env, - target_ulong pc, target_ulong cs_base, int flags, - int cflags) +TranslationBlock *tb_gen_code(CPUState *env, + target_ulong pc, target_ulong cs_base, + int flags, int cflags) { TranslationBlock *tb; uint8_t *tc_ptr; @@ -638,6 +857,8 @@ tb_flush(env); /* cannot fail at this point */ tb = tb_alloc(pc); + /* Don't forget to invalidate previous TB info. */ + tb_invalidated_flag = 1; } tc_ptr = code_gen_ptr; tb->tc_ptr = tc_ptr; @@ -654,15 +875,15 @@ phys_page2 = get_phys_addr_code(env, virt_page2); } tb_link_phys(tb, phys_pc, phys_page2); + return tb; } -#endif /* invalidate all TBs which intersect with the target physical page starting in range [start;end[. NOTE: start and end must refer to the same physical page. 'is_cpu_write_access' should be true if called from a real cpu write access: the virtual CPU will exit the current TB if code is modified inside this TB. */ -void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, +void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end, int is_cpu_write_access) { int n, current_tb_modified, current_tb_not_found, current_flags; @@ -710,13 +931,13 @@ if (current_tb_not_found) { current_tb_not_found = 0; current_tb = NULL; - if (env->mem_write_pc) { + if (env->mem_io_pc) { /* now we have a real cpu fault */ - current_tb = tb_find_pc(env->mem_write_pc); + current_tb = tb_find_pc(env->mem_io_pc); } } if (current_tb == tb && - !(current_tb->cflags & CF_SINGLE_INSN)) { + (current_tb->cflags & CF_COUNT_MASK) != 1) { /* If we are modifying the current TB, we must stop its execution. We could be more precise by checking that the modification is after the current PC, but it @@ -725,7 +946,7 @@ current_tb_modified = 1; cpu_restore_state(current_tb, env, - env->mem_write_pc, NULL); + env->mem_io_pc, NULL); #if defined(TARGET_I386) current_flags = env->hflags; current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)); @@ -757,7 +978,7 @@ if (!p->first_tb) { invalidate_page_bitmap(p); if (is_cpu_write_access) { - tlb_unprotect_code_phys(env, start, env->mem_write_vaddr); + tlb_unprotect_code_phys(env, start, env->mem_io_vaddr); } } #endif @@ -767,15 +988,14 @@ modifying the memory. It will ensure that it cannot modify itself */ env->current_tb = NULL; - tb_gen_code(env, current_pc, current_cs_base, current_flags, - CF_SINGLE_INSN); + tb_gen_code(env, current_pc, current_cs_base, current_flags, 1); cpu_resume_from_signal(env, NULL); } #endif } /* len must be <= 8 and start must be a multiple of len */ -static inline void tb_invalidate_phys_page_fast(target_ulong start, int len) +static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len) { PageDesc *p; int offset, b; @@ -783,7 +1003,7 @@ if (1) { if (loglevel) { fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n", - cpu_single_env->mem_write_vaddr, len, + cpu_single_env->mem_io_vaddr, len, cpu_single_env->eip, cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base); } @@ -804,7 +1024,7 @@ } #if !defined(CONFIG_SOFTMMU) -static void tb_invalidate_phys_page(target_ulong addr, +static void tb_invalidate_phys_page(target_phys_addr_t addr, unsigned long pc, void *puc) { int n, current_flags, current_tb_modified; @@ -835,7 +1055,7 @@ tb = (TranslationBlock *)((long)tb & ~3); #ifdef TARGET_HAS_PRECISE_SMC if (current_tb == tb && - !(current_tb->cflags & CF_SINGLE_INSN)) { + (current_tb->cflags & CF_COUNT_MASK) != 1) { /* If we are modifying the current TB, we must stop its execution. We could be more precise by checking that the modification is after the current PC, but it @@ -864,8 +1084,7 @@ modifying the memory. It will ensure that it cannot modify itself */ env->current_tb = NULL; - tb_gen_code(env, current_pc, current_cs_base, current_flags, - CF_SINGLE_INSN); + tb_gen_code(env, current_pc, current_cs_base, current_flags, 1); cpu_resume_from_signal(env, puc); } #endif @@ -933,8 +1152,8 @@ { TranslationBlock *tb; - if (nb_tbs >= CODE_GEN_MAX_BLOCKS || - (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE) + if (nb_tbs >= code_gen_max_blocks || + (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size) return NULL; tb = &tbs[nb_tbs++]; tb->pc = pc; @@ -942,6 +1161,17 @@ return tb; } +void tb_free(TranslationBlock *tb) +{ + /* In practice this is mostly used for single use temporary TB + Ignore the hard cases and just back up if this TB happens to + be the last one generated. */ + if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) { + code_gen_ptr = tb->tc_ptr; + nb_tbs--; + } +} + /* add a new TB and link it to the physical page tables. phys_page2 is (-1) to indicate that only one page contains the TB. */ void tb_link_phys(TranslationBlock *tb, @@ -950,6 +1180,9 @@ unsigned int h; TranslationBlock **ptb; + /* Grab the mmap lock to stop another thread invalidating this TB + before we are done. */ + mmap_lock(); /* add in the physical hash table */ h = tb_phys_hash_func(phys_pc); ptb = &tb_phys_hash[h]; @@ -976,6 +1209,7 @@ #ifdef DEBUG_TB_CHECK tb_page_check(); #endif + mmap_unlock(); } /* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr < @@ -1077,7 +1311,7 @@ #endif /* Add a watchpoint. */ -int cpu_watchpoint_insert(CPUState *env, target_ulong addr) +int cpu_watchpoint_insert(CPUState *env, target_ulong addr, int type) { int i; @@ -1090,6 +1324,7 @@ i = env->nb_watchpoints++; env->watchpoint[i].vaddr = addr; + env->watchpoint[i].type = type; tlb_flush_page(env, addr); /* FIXME: This flush is needed because of the hack to make memory ops terminate the TB. It can be removed once the proper IO trap and @@ -1114,6 +1349,16 @@ return -1; } +/* Remove all watchpoints. */ +void cpu_watchpoint_remove_all(CPUState *env) { + int i; + + for (i = 0; i < env->nb_watchpoints; i++) { + tlb_flush_page(env, env->watchpoint[i].vaddr); + } + env->nb_watchpoints = 0; +} + /* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a breakpoint is reached */ int cpu_breakpoint_insert(CPUState *env, target_ulong pc) @@ -1137,6 +1382,17 @@ #endif } +/* remove all breakpoints */ +void cpu_breakpoint_remove_all(CPUState *env) { +#if defined(TARGET_HAS_ICE) + int i; + for(i = 0; i < env->nb_breakpoints; i++) { + breakpoint_invalidate(env, env->breakpoints[i]); + } + env->nb_breakpoints = 0; +#endif +} + /* remove a breakpoint */ int cpu_breakpoint_remove(CPUState *env, target_ulong pc) { @@ -1186,7 +1442,7 @@ #if !defined(CONFIG_SOFTMMU) /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ { - static uint8_t logfile_buf[4096]; + static char logfile_buf[4096]; setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf)); } #else @@ -1213,18 +1469,43 @@ /* mask must never be zero, except for A20 change call */ void cpu_interrupt(CPUState *env, int mask) { +#if !defined(USE_NPTL) TranslationBlock *tb; - static int interrupt_lock; + static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED; +#endif + int old_mask; + old_mask = env->interrupt_request; + /* FIXME: This is probably not threadsafe. A different thread could + be in the middle of a read-modify-write operation. */ env->interrupt_request |= mask; - /* if the cpu is currently executing code, we must unlink it and - all the potentially executing TB */ - tb = env->current_tb; - if (tb && !testandset(&interrupt_lock)) { - env->current_tb = NULL; - tb_reset_jump_recursive(tb); - interrupt_lock = 0; +#if defined(USE_NPTL) + /* FIXME: TB unchaining isn't SMP safe. For now just ignore the + problem and hope the cpu will stop of its own accord. For userspace + emulation this often isn't actually as bad as it sounds. Often + signals are used primarily to interrupt blocking syscalls. */ +#else + if (use_icount) { + env->icount_decr.u16.high = 0xffff; +#ifndef CONFIG_USER_ONLY + /* CPU_INTERRUPT_EXIT isn't a real interrupt. It just means + an async event happened and we need to process it. */ + if (!can_do_io(env) + && (mask & ~(old_mask | CPU_INTERRUPT_EXIT)) != 0) { + cpu_abort(env, "Raised interrupt while not in I/O function"); + } +#endif + } else { + tb = env->current_tb; + /* if the cpu is currently executing code, we must unlink it and + all the potentially executing TB */ + if (tb && !testandset(&interrupt_lock)) { + env->current_tb = NULL; + tb_reset_jump_recursive(tb); + resetlock(&interrupt_lock); + } } +#endif } void cpu_reset_interrupt(CPUState *env, int mask) @@ -1232,17 +1513,19 @@ env->interrupt_request &= ~mask; } -CPULogItem cpu_log_items[] = { +const CPULogItem cpu_log_items[] = { { CPU_LOG_TB_OUT_ASM, "out_asm", "show generated host assembly code for each compiled TB" }, { CPU_LOG_TB_IN_ASM, "in_asm", "show target assembly code for each compiled TB" }, { CPU_LOG_TB_OP, "op", - "show micro ops for each compiled TB (only usable if 'in_asm' used)" }, -#ifdef TARGET_I386 + "show micro ops for each compiled TB" }, { CPU_LOG_TB_OP_OPT, "op_opt", - "show micro ops after optimization for each compiled TB" }, + "show micro ops " +#ifdef TARGET_I386 + "before eflags optimization and " #endif + "after liveness analysis" }, { CPU_LOG_INT, "int", "show interrupts/exceptions in short format" }, { CPU_LOG_EXEC, "exec", @@ -1270,7 +1553,7 @@ /* takes a comma separated list of log masks. Return 0 if error. */ int cpu_str_to_log_mask(const char *str) { - CPULogItem *item; + const CPULogItem *item; int mask; const char *p, *p1; @@ -1311,11 +1594,6 @@ vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); #ifdef TARGET_I386 - if(env->intercept & INTERCEPT_SVM_MASK) { - /* most probably the virtual machine should not - be shut down but rather caught by the VMM */ - vmexit(SVM_EXIT_SHUTDOWN, 0); - } cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP); #else cpu_dump_state(env, stderr, fprintf, 0); @@ -1351,6 +1629,21 @@ #if !defined(CONFIG_USER_ONLY) +static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr) +{ + unsigned int i; + + /* Discard jump cache entries for any tb which might potentially + overlap the flushed page. */ + i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE); + memset (&env->tb_jmp_cache[i], 0, + TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *)); + + i = tb_jmp_cache_hash_page(addr); + memset (&env->tb_jmp_cache[i], 0, + TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *)); +} + /* NOTE: if flush_global is true, also flush global entries (not implemented yet) */ void tlb_flush(CPUState *env, int flush_global) @@ -1385,9 +1678,6 @@ memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); -#if !defined(CONFIG_SOFTMMU) - munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START); -#endif #ifdef USE_KQEMU if (env->kqemu_enabled) { kqemu_flush(env, flush_global); @@ -1413,7 +1703,6 @@ void tlb_flush_page(CPUState *env, target_ulong addr) { int i; - TranslationBlock *tb; #if defined(DEBUG_TLB) printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr); @@ -1433,18 +1722,8 @@ #endif #endif - /* Discard jump cache entries for any tb which might potentially - overlap the flushed page. */ - i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE); - memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb)); - - i = tb_jmp_cache_hash_page(addr); - memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb)); + tlb_flush_jmp_cache(env, addr); -#if !defined(CONFIG_SOFTMMU) - if (addr < MMAP_AREA_END) - munmap((void *)addr, TARGET_PAGE_SIZE); -#endif #ifdef USE_KQEMU if (env->kqemu_enabled) { kqemu_flush_page(env, addr); @@ -1476,7 +1755,7 @@ if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend; if ((addr - start) < length) { - tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY; + tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | TLB_NOTDIRTY; } } } @@ -1530,34 +1809,17 @@ #endif #endif } +} -#if !defined(CONFIG_SOFTMMU) - /* XXX: this is expensive */ - { - VirtPageDesc *p; - int j; - target_ulong addr; +int cpu_physical_memory_set_dirty_tracking(int enable) +{ + in_migration = enable; + return 0; +} - for(i = 0; i < L1_SIZE; i++) { - p = l1_virt_map[i]; - if (p) { - addr = i << (TARGET_PAGE_BITS + L2_BITS); - for(j = 0; j < L2_SIZE; j++) { - if (p->valid_tag == virt_valid_tag && - p->phys_addr >= start && p->phys_addr < end && - (p->prot & PROT_WRITE)) { - if (addr < MMAP_AREA_END) { - mprotect((void *)addr, TARGET_PAGE_SIZE, - p->prot & ~PROT_WRITE); - } - } - addr += TARGET_PAGE_SIZE; - p++; - } - } - } - } -#endif +int cpu_physical_memory_get_dirty_tracking(void) +{ + return in_migration; } static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry) @@ -1568,7 +1830,7 @@ ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend - (unsigned long)phys_ram_base; if (!cpu_physical_memory_is_dirty(ram_addr)) { - tlb_entry->addr_write |= IO_MEM_NOTDIRTY; + tlb_entry->addr_write |= TLB_NOTDIRTY; } } } @@ -1591,33 +1853,26 @@ #endif } -static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, - unsigned long start) +static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr) { - unsigned long addr; - if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) { - addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend; - if (addr == start) { - tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_RAM; - } - } + if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY)) + tlb_entry->addr_write = vaddr; } -/* update the TLB corresponding to virtual page vaddr and phys addr - addr so that it is no longer dirty */ -static inline void tlb_set_dirty(CPUState *env, - unsigned long addr, target_ulong vaddr) +/* update the TLB corresponding to virtual page vaddr + so that it is no longer dirty */ +static inline void tlb_set_dirty(CPUState *env, target_ulong vaddr) { int i; - addr &= TARGET_PAGE_MASK; + vaddr &= TARGET_PAGE_MASK; i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - tlb_set_dirty1(&env->tlb_table[0][i], addr); - tlb_set_dirty1(&env->tlb_table[1][i], addr); + tlb_set_dirty1(&env->tlb_table[0][i], vaddr); + tlb_set_dirty1(&env->tlb_table[1][i], vaddr); #if (NB_MMU_MODES >= 3) - tlb_set_dirty1(&env->tlb_table[2][i], addr); + tlb_set_dirty1(&env->tlb_table[2][i], vaddr); #if (NB_MMU_MODES == 4) - tlb_set_dirty1(&env->tlb_table[3][i], addr); + tlb_set_dirty1(&env->tlb_table[3][i], vaddr); #endif #endif } @@ -1634,10 +1889,12 @@ unsigned long pd; unsigned int index; target_ulong address; + target_ulong code_address; target_phys_addr_t addend; int ret; CPUTLBEntry *te; int i; + target_phys_addr_t iotlb; p = phys_page_find(paddr >> TARGET_PAGE_BITS); if (!p) { @@ -1651,153 +1908,73 @@ #endif ret = 0; -#if !defined(CONFIG_SOFTMMU) - if (is_softmmu) -#endif - { - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { - /* IO memory case */ - address = vaddr | pd; - addend = paddr; - } else { - /* standard memory */ - address = vaddr; - addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK); - } + address = vaddr; + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { + /* IO memory case (romd handled later) */ + address |= TLB_MMIO; + } + addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK); + if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) { + /* Normal RAM. */ + iotlb = pd & TARGET_PAGE_MASK; + if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM) + iotlb |= IO_MEM_NOTDIRTY; + else + iotlb |= IO_MEM_ROM; + } else { + /* IO handlers are currently passed a phsical address. + It would be nice to pass an offset from the base address + of that region. This would avoid having to special case RAM, + and avoid full address decoding in every device. + We can't use the high bits of pd for this because + IO_MEM_ROMD uses these as a ram address. */ + iotlb = (pd & ~TARGET_PAGE_MASK) + paddr; + } - /* Make accesses to pages with watchpoints go via the - watchpoint trap routines. */ - for (i = 0; i < env->nb_watchpoints; i++) { - if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) { - if (address & ~TARGET_PAGE_MASK) { - env->watchpoint[i].addend = 0; - address = vaddr | io_mem_watch; - } else { - env->watchpoint[i].addend = pd - paddr + - (unsigned long) phys_ram_base; - /* TODO: Figure out how to make read watchpoints coexist - with code. */ - pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD; - } - } + code_address = address; + /* Make accesses to pages with watchpoints go via the + watchpoint trap routines. */ + for (i = 0; i < env->nb_watchpoints; i++) { + if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) { + iotlb = io_mem_watch + paddr; + /* TODO: The memory case can be optimized by not trapping + reads of pages with a write breakpoint. */ + address |= TLB_MMIO; } + } - index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - addend -= vaddr; - te = &env->tlb_table[mmu_idx][index]; - te->addend = addend; - if (prot & PAGE_READ) { - te->addr_read = address; - } else { - te->addr_read = -1; - } - if (prot & PAGE_EXEC) { - te->addr_code = address; - } else { - te->addr_code = -1; - } - if (prot & PAGE_WRITE) { - if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || - (pd & IO_MEM_ROMD)) { - /* write access calls the I/O callback */ - te->addr_write = vaddr | - (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD)); - } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && - !cpu_physical_memory_is_dirty(pd)) { - te->addr_write = vaddr | IO_MEM_NOTDIRTY; - } else { - te->addr_write = address; - } - } else { - te->addr_write = -1; - } + index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + env->iotlb[mmu_idx][index] = iotlb - vaddr; + te = &env->tlb_table[mmu_idx][index]; + te->addend = addend - vaddr; + if (prot & PAGE_READ) { + te->addr_read = address; + } else { + te->addr_read = -1; } -#if !defined(CONFIG_SOFTMMU) - else { - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { - /* IO access: no mapping is done as it will be handled by the - soft MMU */ - if (!(env->hflags & HF_SOFTMMU_MASK)) - ret = 2; - } else { - void *map_addr; - if (vaddr >= MMAP_AREA_END) { - ret = 2; - } else { - if (prot & PROT_WRITE) { - if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || -#if defined(TARGET_HAS_SMC) || 1 - first_tb || -#endif - ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && - !cpu_physical_memory_is_dirty(pd))) { - /* ROM: we do as if code was inside */ - /* if code is present, we only map as read only and save the - original mapping */ - VirtPageDesc *vp; - - vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1); - vp->phys_addr = pd; - vp->prot = prot; - vp->valid_tag = virt_valid_tag; - prot &= ~PAGE_WRITE; - } - } - map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot, - MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK)); - if (map_addr == MAP_FAILED) { - cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n", - paddr, vaddr); - } - } + if (prot & PAGE_EXEC) { + te->addr_code = code_address; + } else { + te->addr_code = -1; + } + if (prot & PAGE_WRITE) { + if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || + (pd & IO_MEM_ROMD)) { + /* Write access calls the I/O callback. */ + te->addr_write = address | TLB_MMIO; + } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && + !cpu_physical_memory_is_dirty(pd)) { + te->addr_write = address | TLB_NOTDIRTY; + } else { + te->addr_write = address; } + } else { + te->addr_write = -1; } -#endif return ret; } -/* called from signal handler: invalidate the code and unprotect the - page. Return TRUE if the fault was succesfully handled. */ -int page_unprotect(target_ulong addr, unsigned long pc, void *puc) -{ -#if !defined(CONFIG_SOFTMMU) - VirtPageDesc *vp; - -#if defined(DEBUG_TLB) - printf("page_unprotect: addr=0x%08x\n", addr); -#endif - addr &= TARGET_PAGE_MASK; - - /* if it is not mapped, no need to worry here */ - if (addr >= MMAP_AREA_END) - return 0; - vp = virt_page_find(addr >> TARGET_PAGE_BITS); - if (!vp) - return 0; - /* NOTE: in this case, validate_tag is _not_ tested as it - validates only the code TLB */ - if (vp->valid_tag != virt_valid_tag) - return 0; - if (!(vp->prot & PAGE_WRITE)) - return 0; -#if defined(DEBUG_TLB) - printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n", - addr, vp->phys_addr, vp->prot); -#endif - if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0) - cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n", - (unsigned long)addr, vp->prot); - /* set the dirty bit */ - phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff; - /* flush the code inside */ - tb_invalidate_phys_page(vp->phys_addr, pc, puc); - return 1; -#else - return 0; -#endif -} - #else void tlb_flush(CPUState *env, int flush_global) @@ -1876,13 +2053,17 @@ PageDesc *p; target_ulong addr; + /* mmap_lock should already be held. */ start = start & TARGET_PAGE_MASK; end = TARGET_PAGE_ALIGN(end); if (flags & PAGE_WRITE) flags |= PAGE_WRITE_ORG; - spin_lock(&tb_lock); for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { p = page_find_alloc(addr >> TARGET_PAGE_BITS); + /* We may be called for host regions that are outside guest + address space. */ + if (!p) + return; /* if the write protection is set, then we invalidate the code inside */ if (!(p->flags & PAGE_WRITE) && @@ -1892,7 +2073,6 @@ } p->flags = flags; } - spin_unlock(&tb_lock); } int page_check_range(target_ulong start, target_ulong len, int flags) @@ -1901,12 +2081,13 @@ target_ulong end; target_ulong addr; + if (start + len < start) + /* we've wrapped around */ + return -1; + end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */ start = start & TARGET_PAGE_MASK; - if( end < start ) - /* we've wrapped around */ - return -1; for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { p = page_find(addr >> TARGET_PAGE_BITS); if( !p ) @@ -1939,11 +2120,18 @@ PageDesc *p, *p1; target_ulong host_start, host_end, addr; + /* Technically this isn't safe inside a signal handler. However we + know this only ever happens in a synchronous SEGV handler, so in + practice it seems to be ok. */ + mmap_lock(); + host_start = address & qemu_host_page_mask; page_index = host_start >> TARGET_PAGE_BITS; p1 = page_find(page_index); - if (!p1) + if (!p1) { + mmap_unlock(); return 0; + } host_end = host_start + qemu_host_page_size; p = p1; prot = 0; @@ -1965,9 +2153,11 @@ #ifdef DEBUG_TB_CHECK tb_invalidate_check(address); #endif + mmap_unlock(); return 1; } } + mmap_unlock(); return 0; } @@ -1977,10 +2167,11 @@ } #endif /* defined(CONFIG_USER_ONLY) */ +#if !defined(CONFIG_USER_ONLY) static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end, - int memory); -static void *subpage_init (target_phys_addr_t base, uint32_t *phys, - int orig_memory); + ram_addr_t memory); +static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys, + ram_addr_t orig_memory); #define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \ need_subpage) \ do { \ @@ -2005,21 +2196,31 @@ page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an io memory page */ void cpu_register_physical_memory(target_phys_addr_t start_addr, - unsigned long size, - unsigned long phys_offset) + ram_addr_t size, + ram_addr_t phys_offset) { target_phys_addr_t addr, end_addr; PhysPageDesc *p; CPUState *env; - unsigned long orig_size = size; + ram_addr_t orig_size = size; void *subpage; +#ifdef USE_KQEMU + /* XXX: should not depend on cpu context */ + env = first_cpu; + if (env->kqemu_enabled) { + kqemu_set_phys_mem(start_addr, size, phys_offset); + } +#endif + if (kvm_enabled()) + kvm_set_phys_mem(start_addr, size, phys_offset); + size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; end_addr = start_addr + (target_phys_addr_t)size; for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) { p = phys_page_find(addr >> TARGET_PAGE_BITS); if (p && p->phys_offset != IO_MEM_UNASSIGNED) { - unsigned long orig_memory = p->phys_offset; + ram_addr_t orig_memory = p->phys_offset; target_phys_addr_t start_addr2, end_addr2; int need_subpage = 0; @@ -2072,7 +2273,7 @@ } /* XXX: temporary until new memory mapping API */ -uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr) +ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr) { PhysPageDesc *p; @@ -2083,12 +2284,12 @@ } /* XXX: better than nothing */ -ram_addr_t qemu_ram_alloc(unsigned int size) +ram_addr_t qemu_ram_alloc(ram_addr_t size) { ram_addr_t addr; - if ((phys_ram_alloc_offset + size) >= phys_ram_size) { - fprintf(stderr, "Not enough memory (requested_size = %u, max memory = %d)\n", - size, phys_ram_size); + if ((phys_ram_alloc_offset + size) > phys_ram_size) { + fprintf(stderr, "Not enough memory (requested_size = %" PRIu64 ", max memory = %" PRIu64 ")\n", + (uint64_t)size, (uint64_t)phys_ram_size); abort(); } addr = phys_ram_alloc_offset; @@ -2105,10 +2306,30 @@ #ifdef DEBUG_UNASSIGNED printf("Unassigned mem read " TARGET_FMT_plx "\n", addr); #endif -#ifdef TARGET_SPARC - do_unassigned_access(addr, 0, 0, 0); -#elif TARGET_CRIS - do_unassigned_access(addr, 0, 0, 0); +#if defined(TARGET_SPARC) || defined(TARGET_CRIS) + do_unassigned_access(addr, 0, 0, 0, 1); +#endif + return 0; +} + +static uint32_t unassigned_mem_readw(void *opaque, target_phys_addr_t addr) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem read " TARGET_FMT_plx "\n", addr); +#endif +#if defined(TARGET_SPARC) || defined(TARGET_CRIS) + do_unassigned_access(addr, 0, 0, 0, 2); +#endif + return 0; +} + +static uint32_t unassigned_mem_readl(void *opaque, target_phys_addr_t addr) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem read " TARGET_FMT_plx "\n", addr); +#endif +#if defined(TARGET_SPARC) || defined(TARGET_CRIS) + do_unassigned_access(addr, 0, 0, 0, 4); #endif return 0; } @@ -2118,30 +2339,47 @@ #ifdef DEBUG_UNASSIGNED printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val); #endif -#ifdef TARGET_SPARC - do_unassigned_access(addr, 1, 0, 0); -#elif TARGET_CRIS - do_unassigned_access(addr, 1, 0, 0); +#if defined(TARGET_SPARC) || defined(TARGET_CRIS) + do_unassigned_access(addr, 1, 0, 0, 1); +#endif +} + +static void unassigned_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val); +#endif +#if defined(TARGET_SPARC) || defined(TARGET_CRIS) + do_unassigned_access(addr, 1, 0, 0, 2); +#endif +} + +static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val); +#endif +#if defined(TARGET_SPARC) || defined(TARGET_CRIS) + do_unassigned_access(addr, 1, 0, 0, 4); #endif } static CPUReadMemoryFunc *unassigned_mem_read[3] = { unassigned_mem_readb, - unassigned_mem_readb, - unassigned_mem_readb, + unassigned_mem_readw, + unassigned_mem_readl, }; static CPUWriteMemoryFunc *unassigned_mem_write[3] = { unassigned_mem_writeb, - unassigned_mem_writeb, - unassigned_mem_writeb, + unassigned_mem_writew, + unassigned_mem_writel, }; -static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr, + uint32_t val) { - unsigned long ram_addr; int dirty_flags; - ram_addr = addr - (unsigned long)phys_ram_base; dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; if (!(dirty_flags & CODE_DIRTY_FLAG)) { #if !defined(CONFIG_USER_ONLY) @@ -2149,7 +2387,7 @@ dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; #endif } - stb_p((uint8_t *)(long)addr, val); + stb_p(phys_ram_base + ram_addr, val); #ifdef USE_KQEMU if (cpu_single_env->kqemu_enabled && (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK) @@ -2160,14 +2398,13 @@ /* we remove the notdirty callback only if the code has been flushed */ if (dirty_flags == 0xff) - tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr); + tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr); } -static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr, + uint32_t val) { - unsigned long ram_addr; int dirty_flags; - ram_addr = addr - (unsigned long)phys_ram_base; dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; if (!(dirty_flags & CODE_DIRTY_FLAG)) { #if !defined(CONFIG_USER_ONLY) @@ -2175,7 +2412,7 @@ dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; #endif } - stw_p((uint8_t *)(long)addr, val); + stw_p(phys_ram_base + ram_addr, val); #ifdef USE_KQEMU if (cpu_single_env->kqemu_enabled && (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK) @@ -2186,14 +2423,13 @@ /* we remove the notdirty callback only if the code has been flushed */ if (dirty_flags == 0xff) - tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr); + tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr); } -static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr, + uint32_t val) { - unsigned long ram_addr; int dirty_flags; - ram_addr = addr - (unsigned long)phys_ram_base; dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; if (!(dirty_flags & CODE_DIRTY_FLAG)) { #if !defined(CONFIG_USER_ONLY) @@ -2201,7 +2437,7 @@ dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; #endif } - stl_p((uint8_t *)(long)addr, val); + stl_p(phys_ram_base + ram_addr, val); #ifdef USE_KQEMU if (cpu_single_env->kqemu_enabled && (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK) @@ -2212,7 +2448,7 @@ /* we remove the notdirty callback only if the code has been flushed */ if (dirty_flags == 0xff) - tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr); + tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr); } static CPUReadMemoryFunc *error_mem_read[3] = { @@ -2227,68 +2463,63 @@ notdirty_mem_writel, }; -#if defined(CONFIG_SOFTMMU) +/* Generate a debug exception if a watchpoint has been hit. */ +static void check_watchpoint(int offset, int flags) +{ + CPUState *env = cpu_single_env; + target_ulong vaddr; + int i; + + vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset; + for (i = 0; i < env->nb_watchpoints; i++) { + if (vaddr == env->watchpoint[i].vaddr + && (env->watchpoint[i].type & flags)) { + env->watchpoint_hit = i + 1; + cpu_interrupt(env, CPU_INTERRUPT_DEBUG); + break; + } + } +} + /* Watchpoint access routines. Watchpoints are inserted using TLB tricks, so these check for a hit then pass through to the normal out-of-line phys routines. */ static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr) { + check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ); return ldub_phys(addr); } static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr) { + check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ); return lduw_phys(addr); } static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr) { + check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ); return ldl_phys(addr); } -/* Generate a debug exception if a watchpoint has been hit. - Returns the real physical address of the access. addr will be a host - address in case of a RAM location. */ -static target_ulong check_watchpoint(target_phys_addr_t addr) -{ - CPUState *env = cpu_single_env; - target_ulong watch; - target_ulong retaddr; - int i; - - retaddr = addr; - for (i = 0; i < env->nb_watchpoints; i++) { - watch = env->watchpoint[i].vaddr; - if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) { - retaddr = addr - env->watchpoint[i].addend; - if (((addr ^ watch) & ~TARGET_PAGE_MASK) == 0) { - cpu_single_env->watchpoint_hit = i + 1; - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_DEBUG); - break; - } - } - } - return retaddr; -} - static void watch_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { - addr = check_watchpoint(addr); + check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE); stb_phys(addr, val); } static void watch_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) { - addr = check_watchpoint(addr); + check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE); stw_phys(addr, val); } static void watch_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { - addr = check_watchpoint(addr); + check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE); stl_phys(addr, val); } @@ -2303,7 +2534,6 @@ watch_mem_writew, watch_mem_writel, }; -#endif static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr, unsigned int len) @@ -2401,7 +2631,7 @@ }; static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end, - int memory) + ram_addr_t memory) { int idx, eidx; unsigned int i; @@ -2431,8 +2661,8 @@ return 0; } -static void *subpage_init (target_phys_addr_t base, uint32_t *phys, - int orig_memory) +static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys, + ram_addr_t orig_memory) { subpage_t *mmio; int subpage_memory; @@ -2459,10 +2689,8 @@ cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL); io_mem_nb = 5; -#if defined(CONFIG_SOFTMMU) - io_mem_watch = cpu_register_io_memory(-1, watch_mem_read, + io_mem_watch = cpu_register_io_memory(0, watch_mem_read, watch_mem_write, NULL); -#endif /* alloc dirty bits array */ phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS); memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS); @@ -2512,6 +2740,8 @@ return io_mem_read[io_index >> IO_MEM_SHIFT]; } +#endif /* !defined(CONFIG_USER_ONLY) */ + /* physical memory access (slow version, mainly for debug) */ #if defined(CONFIG_USER_ONLY) void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, @@ -2533,19 +2763,19 @@ if (!(flags & PAGE_WRITE)) return; /* XXX: this code should not depend on lock_user */ - if (!(p = lock_user(VERIFY_WRITE, addr, len, 0))) + if (!(p = lock_user(VERIFY_WRITE, addr, l, 0))) /* FIXME - should this return an error rather than just fail? */ return; - memcpy(p, buf, len); - unlock_user(p, addr, len); + memcpy(p, buf, l); + unlock_user(p, addr, l); } else { if (!(flags & PAGE_READ)) return; /* XXX: this code should not depend on lock_user */ - if (!(p = lock_user(VERIFY_READ, addr, len, 1))) + if (!(p = lock_user(VERIFY_READ, addr, l, 1))) /* FIXME - should this return an error rather than just fail? */ return; - memcpy(buf, p, len); + memcpy(buf, p, l); unlock_user(p, addr, 0); } len -= l; @@ -2789,9 +3019,19 @@ io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); } else { - ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + - (addr & ~TARGET_PAGE_MASK); + unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); + ptr = phys_ram_base + addr1; stl_p(ptr, val); + + if (unlikely(in_migration)) { + if (!cpu_physical_memory_is_dirty(addr1)) { + /* invalidate code */ + tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); + /* set dirty bit */ + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= + (0xff & ~CODE_DIRTY_FLAG); + } + } } } @@ -2908,6 +3148,65 @@ return 0; } +/* in deterministic execution mode, instructions doing device I/Os + must be at the end of the TB */ +void cpu_io_recompile(CPUState *env, void *retaddr) +{ + TranslationBlock *tb; + uint32_t n, cflags; + target_ulong pc, cs_base; + uint64_t flags; + + tb = tb_find_pc((unsigned long)retaddr); + if (!tb) { + cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p", + retaddr); + } + n = env->icount_decr.u16.low + tb->icount; + cpu_restore_state(tb, env, (unsigned long)retaddr, NULL); + /* Calculate how many instructions had been executed before the fault + occurred. */ + n = n - env->icount_decr.u16.low; + /* Generate a new TB ending on the I/O insn. */ + n++; + /* On MIPS and SH, delay slot instructions can only be restarted if + they were already the first instruction in the TB. If this is not + the first instruction in a TB then re-execute the preceding + branch. */ +#if defined(TARGET_MIPS) + if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) { + env->active_tc.PC -= 4; + env->icount_decr.u16.low++; + env->hflags &= ~MIPS_HFLAG_BMASK; + } +#elif defined(TARGET_SH4) + if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0 + && n > 1) { + env->pc -= 2; + env->icount_decr.u16.low++; + env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL); + } +#endif + /* This should never happen. */ + if (n > CF_COUNT_MASK) + cpu_abort(env, "TB too big during recompile"); + + cflags = n | CF_LAST_IO; + pc = tb->pc; + cs_base = tb->cs_base; + flags = tb->flags; + tb_phys_invalidate(tb, -1); + /* FIXME: In theory this could raise an exception. In practice + we have already translated the block once so it's probably ok. */ + tb_gen_code(env, pc, cs_base, flags, cflags); + /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not + the first in the TB) then we end up generating a whole new TB and + repeating the fault, which is horribly inefficient. + Better would be to execute just this insn uncached, or generate a + second new TB. */ + cpu_resume_from_signal(env, NULL); +} + void dump_exec_info(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) { @@ -2935,7 +3234,11 @@ } } /* XXX: avoid using doubles ? */ - cpu_fprintf(f, "TB count %d\n", nb_tbs); + cpu_fprintf(f, "Translation buffer state:\n"); + cpu_fprintf(f, "gen code size %ld/%ld\n", + code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size); + cpu_fprintf(f, "TB count %d/%d\n", + nb_tbs, code_gen_max_blocks); cpu_fprintf(f, "TB avg target size %d max=%d bytes\n", nb_tbs ? target_code_size / nb_tbs : 0, max_target_code_size); @@ -2950,9 +3253,11 @@ nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0, direct_jmp2_count, nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0); + cpu_fprintf(f, "\nStatistics:\n"); cpu_fprintf(f, "TB flush count %d\n", tb_flush_count); cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count); cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count); + tcg_dump_info(f, cpu_fprintf); } #if !defined(CONFIG_USER_ONLY) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/feature_to_c.sh /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/feature_to_c.sh --- qemu-0.9.1/feature_to_c.sh 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/feature_to_c.sh 2008-10-26 13:43:07.000000000 +0000 @@ -0,0 +1,78 @@ +#!/bin/sh + +# Convert text files to compilable C arrays. +# +# Copyright (C) 2007 Free Software Foundation, Inc. +# +# This file is part of GDB. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. + +output=$1 +shift + +if test -z "$output" || test -z "$1"; then + echo "Usage: $0 OUTPUTFILE INPUTFILE..." + exit 1 +fi + +if test -e "$output"; then + echo "Output file \"$output\" already exists; refusing to overwrite." + exit 1 +fi + +for input; do + arrayname=xml_feature_`echo $input | sed 's,.*/,,; s/[-.]/_/g'` + + ${AWK:-awk} 'BEGIN { n = 0 + print "static const char '$arrayname'[] = {" + for (i = 0; i < 255; i++) + _ord_[sprintf("%c", i)] = i + } { + split($0, line, ""); + printf " " + for (i = 1; i <= length($0); i++) { + c = line[i] + if (c == "'\''") { + printf "'\''\\'\'''\'', " + } else if (c == "\\") { + printf "'\''\\\\'\'', " + } else if (_ord_[c] >= 32 && _ord_[c] < 127) { + printf "'\''%s'\'', ", c + } else { + printf "'\''\\%03o'\'', ", _ord_[c] + } + if (i % 10 == 0) + printf "\n " + } + printf "'\''\\n'\'', \n" + } END { + print " 0 };" + }' < $input >> $output +done + +echo >> $output +echo "extern const char *const xml_builtin[][2];" >> $output +echo "const char *const xml_builtin[][2] = {" >> $output + +for input; do + basename=`echo $input | sed 's,.*/,,'` + arrayname=xml_feature_`echo $input | sed 's,.*/,,; s/[-.]/_/g'` + echo " { \"$basename\", $arrayname }," >> $output +done + +echo " { 0, 0 }" >> $output +echo "};" >> $output diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/fpu/softfloat.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/fpu/softfloat.c --- qemu-0.9.1/fpu/softfloat.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/fpu/softfloat.c 2008-09-20 09:07:15.000000000 +0100 @@ -4987,7 +4987,7 @@ sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); } while ( 0 <= (sbits64) aSig0 ); add128( - aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 ); + aSig0, aSig1, alternateASig0, alternateASig1, (bits64 *)&sigMean0, &sigMean1 ); if ( ( sigMean0 < 0 ) || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) { aSig0 = alternateASig0; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/fpu/softfloat-native.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/fpu/softfloat-native.h --- qemu-0.9.1/fpu/softfloat-native.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/fpu/softfloat-native.h 2008-08-24 11:29:29.000000000 +0100 @@ -8,6 +8,11 @@ #include #endif +#ifdef __OpenBSD__ +/* Get OpenBSD version number */ +#include +#endif + /* * Define some C99-7.12.3 classification macros and * some C99-.12.4 for Solaris systems OS less than 10, @@ -15,7 +20,9 @@ * Solaris 10 with GCC4 does not need these macros as they * are defined in with a compiler directive */ -#if defined(HOST_SOLARIS) && (( HOST_SOLARIS <= 9 ) || ((HOST_SOLARIS >= 10) && (__GNUC__ <= 4))) +#if defined(HOST_SOLARIS) && (( HOST_SOLARIS <= 9 ) || ((HOST_SOLARIS >= 10) \ + && (__GNUC__ <= 4))) \ + || (defined(__OpenBSD__) && (OpenBSD < 200811)) /* * C99 7.12.3 classification macros * and @@ -24,6 +31,9 @@ * ... do not work on Solaris 10 using GNU CC 3.4.x. * Try to workaround the missing / broken C99 math macros. */ +#if defined(__OpenBSD__) +#define unordered(x, y) (isnan(x) || isnan(y)) +#endif #define isnormal(x) (fpclass(x) >= FP_NZERO) #define isgreater(x, y) ((!unordered(x, y)) && ((x) > (y))) @@ -84,6 +94,11 @@ | Software IEC/IEEE floating-point rounding mode. *----------------------------------------------------------------------------*/ #if (defined(_BSD) && !defined(__APPLE__)) || defined(HOST_SOLARIS) +#if defined(__OpenBSD__) +#define FE_RM FP_RM +#define FE_RP FP_RP +#define FE_RZ FP_RZ +#endif enum { float_round_nearest_even = FP_RN, float_round_down = FP_RM, diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/fpu/softfloat-specialize.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/fpu/softfloat-specialize.h --- qemu-0.9.1/fpu/softfloat-specialize.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/fpu/softfloat-specialize.h 2008-11-04 12:33:21.000000000 +0000 @@ -37,12 +37,6 @@ #endif /*---------------------------------------------------------------------------- -| Underflow tininess-detection mode, statically initialized to default value. -| (The declaration in `softfloat.h' must match the `int8' type here.) -*----------------------------------------------------------------------------*/ -int8 float_detect_tininess = float_tininess_after_rounding; - -/*---------------------------------------------------------------------------- | Raises the exceptions specified by `flags'. Floating-point traps can be | defined here if desired. It is currently not possible for such a trap | to substitute a result value. If traps are not implemented, this routine @@ -67,7 +61,7 @@ *----------------------------------------------------------------------------*/ #if defined(TARGET_SPARC) #define float32_default_nan make_float32(0x7FFFFFFF) -#elif defined(TARGET_POWERPC) +#elif defined(TARGET_POWERPC) || defined(TARGET_ARM) #define float32_default_nan make_float32(0x7FC00000) #elif defined(TARGET_HPPA) #define float32_default_nan make_float32(0x7FA00000) @@ -192,7 +186,7 @@ *----------------------------------------------------------------------------*/ #if defined(TARGET_SPARC) #define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF )) -#elif defined(TARGET_POWERPC) +#elif defined(TARGET_POWERPC) || defined(TARGET_ARM) #define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 )) #elif defined(TARGET_HPPA) #define float64_default_nan make_float64(LIT64( 0x7FF4000000000000 )) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/gdbstub.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/gdbstub.c --- qemu-0.9.1/gdbstub.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/gdbstub.c 2008-10-31 17:31:29.000000000 +0000 @@ -18,6 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" +#include "qemu-common.h" #ifdef CONFIG_USER_ONLY #include #include @@ -29,12 +30,13 @@ #include "qemu.h" #else -#include "qemu-common.h" #include "qemu-char.h" #include "sysemu.h" #include "gdbstub.h" #endif +#define MAX_PACKET_LENGTH 4096 + #include "qemu_socket.h" #ifdef _WIN32 /* XXX: these constants may be independent of the host ones even for Unix */ @@ -50,6 +52,15 @@ //#define DEBUG_GDB +typedef struct GDBRegisterState { + int base_reg; + int num_regs; + gdb_reg_cb get_reg; + gdb_reg_cb set_reg; + const char *xml; + struct GDBRegisterState *next; +} GDBRegisterState; + enum RSState { RS_IDLE, RS_GETLINE, @@ -60,11 +71,12 @@ typedef struct GDBState { CPUState *env; /* current CPU */ enum RSState state; /* parsing state */ - char line_buf[4096]; + char line_buf[MAX_PACKET_LENGTH]; int line_buf_index; int line_csum; - uint8_t last_packet[4100]; + uint8_t last_packet[MAX_PACKET_LENGTH + 4]; int last_packet_len; + int signal; #ifdef CONFIG_USER_ONLY int fd; int running_state; @@ -73,6 +85,16 @@ #endif } GDBState; +/* By default use no IRQs and no timers while single stepping so as to + * make single stepping like an ICE HW step. + */ +static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER; + +/* This is an ugly hack to cope with both new and old gdb. + If gdb sends qXfer:features:read then assume we're talking to a newish + gdb that understands target descriptions. */ +static int gdb_has_xml; + #ifdef CONFIG_USER_ONLY /* XXX: This is not thread safe. Do we care? */ static int gdbserver_fd = -1; @@ -88,9 +110,13 @@ for(;;) { ret = recv(s->fd, &ch, 1, 0); if (ret < 0) { + if (errno == ECONNRESET) + s->fd = -1; if (errno != EINTR && errno != EAGAIN) return -1; } else if (ret == 0) { + close(s->fd); + s->fd = -1; return -1; } else { break; @@ -121,6 +147,16 @@ return gdb_syscall_mode == GDB_SYS_ENABLED; } +/* Resume execution. */ +static inline void gdb_continue(GDBState *s) +{ +#ifdef CONFIG_USER_ONLY + s->running_state = 1; +#else + vm_start(); +#endif +} + static void put_buffer(GDBState *s, const uint8_t *buf, int len) { #ifdef CONFIG_USER_ONLY @@ -185,19 +221,14 @@ } /* return -1 if error, 0 if OK */ -static int put_packet(GDBState *s, char *buf) +static int put_packet_binary(GDBState *s, const char *buf, int len) { - int len, csum, i; + int csum, i; uint8_t *p; -#ifdef DEBUG_GDB - printf("reply='%s'\n", buf); -#endif - for(;;) { p = s->last_packet; *(p++) = '$'; - len = strlen(buf); memcpy(p, buf, len); p += len; csum = 0; @@ -224,448 +255,537 @@ return 0; } -#if defined(TARGET_I386) - -static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) +/* return -1 if error, 0 if OK */ +static int put_packet(GDBState *s, const char *buf) { - int i, fpus; - uint32_t *registers = (uint32_t *)mem_buf; +#ifdef DEBUG_GDB + printf("reply='%s'\n", buf); +#endif + + return put_packet_binary(s, buf, strlen(buf)); +} + +/* The GDB remote protocol transfers values in target byte order. This means + we can use the raw memory access routines to access the value buffer. + Conveniently, these also handle the case where the buffer is mis-aligned. + */ +#define GET_REG8(val) do { \ + stb_p(mem_buf, val); \ + return 1; \ + } while(0) +#define GET_REG16(val) do { \ + stw_p(mem_buf, val); \ + return 2; \ + } while(0) +#define GET_REG32(val) do { \ + stl_p(mem_buf, val); \ + return 4; \ + } while(0) +#define GET_REG64(val) do { \ + stq_p(mem_buf, val); \ + return 8; \ + } while(0) + +#if TARGET_LONG_BITS == 64 +#define GET_REGL(val) GET_REG64(val) +#define ldtul_p(addr) ldq_p(addr) +#else +#define GET_REGL(val) GET_REG32(val) +#define ldtul_p(addr) ldl_p(addr) +#endif + +#if defined(TARGET_I386) #ifdef TARGET_X86_64 - /* This corresponds with amd64_register_info[] in gdb/amd64-tdep.c */ - uint64_t *registers64 = (uint64_t *)mem_buf; +static const int gpr_map[16] = { + R_EAX, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP, R_ESP, + 8, 9, 10, 11, 12, 13, 14, 15 +}; +#else +static const int gpr_map[8] = {0, 1, 2, 3, 4, 5, 6, 7}; +#endif + +#define NUM_CORE_REGS (CPU_NB_REGS * 2 + 25) - if (env->hflags & HF_CS64_MASK) { - registers64[0] = tswap64(env->regs[R_EAX]); - registers64[1] = tswap64(env->regs[R_EBX]); - registers64[2] = tswap64(env->regs[R_ECX]); - registers64[3] = tswap64(env->regs[R_EDX]); - registers64[4] = tswap64(env->regs[R_ESI]); - registers64[5] = tswap64(env->regs[R_EDI]); - registers64[6] = tswap64(env->regs[R_EBP]); - registers64[7] = tswap64(env->regs[R_ESP]); - for(i = 8; i < 16; i++) { - registers64[i] = tswap64(env->regs[i]); - } - registers64[16] = tswap64(env->eip); - - registers = (uint32_t *)®isters64[17]; - registers[0] = tswap32(env->eflags); - registers[1] = tswap32(env->segs[R_CS].selector); - registers[2] = tswap32(env->segs[R_SS].selector); - registers[3] = tswap32(env->segs[R_DS].selector); - registers[4] = tswap32(env->segs[R_ES].selector); - registers[5] = tswap32(env->segs[R_FS].selector); - registers[6] = tswap32(env->segs[R_GS].selector); - /* XXX: convert floats */ - for(i = 0; i < 8; i++) { - memcpy(mem_buf + 16 * 8 + 7 * 4 + i * 10, &env->fpregs[i], 10); - } - registers[27] = tswap32(env->fpuc); /* fctrl */ - fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; - registers[28] = tswap32(fpus); /* fstat */ - registers[29] = 0; /* ftag */ - registers[30] = 0; /* fiseg */ - registers[31] = 0; /* fioff */ - registers[32] = 0; /* foseg */ - registers[33] = 0; /* fooff */ - registers[34] = 0; /* fop */ - for(i = 0; i < 16; i++) { - memcpy(mem_buf + 16 * 8 + 35 * 4 + i * 16, &env->xmm_regs[i], 16); - } - registers[99] = tswap32(env->mxcsr); - - return 8 * 17 + 4 * 7 + 10 * 8 + 4 * 8 + 16 * 16 + 4; - } -#endif - - for(i = 0; i < 8; i++) { - registers[i] = env->regs[i]; - } - registers[8] = env->eip; - registers[9] = env->eflags; - registers[10] = env->segs[R_CS].selector; - registers[11] = env->segs[R_SS].selector; - registers[12] = env->segs[R_DS].selector; - registers[13] = env->segs[R_ES].selector; - registers[14] = env->segs[R_FS].selector; - registers[15] = env->segs[R_GS].selector; - /* XXX: convert floats */ - for(i = 0; i < 8; i++) { - memcpy(mem_buf + 16 * 4 + i * 10, &env->fpregs[i], 10); - } - registers[36] = env->fpuc; - fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; - registers[37] = fpus; - registers[38] = 0; /* XXX: convert tags */ - registers[39] = 0; /* fiseg */ - registers[40] = 0; /* fioff */ - registers[41] = 0; /* foseg */ - registers[42] = 0; /* fooff */ - registers[43] = 0; /* fop */ - - for(i = 0; i < 16; i++) - tswapls(®isters[i]); - for(i = 36; i < 44; i++) - tswapls(®isters[i]); - return 44 * 4; +static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) +{ + if (n < CPU_NB_REGS) { + GET_REGL(env->regs[gpr_map[n]]); + } else if (n >= CPU_NB_REGS + 8 && n < CPU_NB_REGS + 16) { + /* FIXME: byteswap float values. */ +#ifdef USE_X86LDOUBLE + memcpy(mem_buf, &env->fpregs[n - (CPU_NB_REGS + 8)], 10); +#else + memset(mem_buf, 0, 10); +#endif + return 10; + } else if (n >= CPU_NB_REGS + 24) { + n -= CPU_NB_REGS + 24; + if (n < CPU_NB_REGS) { + stq_p(mem_buf, env->xmm_regs[n].XMM_Q(0)); + stq_p(mem_buf + 8, env->xmm_regs[n].XMM_Q(1)); + return 16; + } else if (n == CPU_NB_REGS) { + GET_REG32(env->mxcsr); + } + } else { + n -= CPU_NB_REGS; + switch (n) { + case 0: GET_REGL(env->eip); + case 1: GET_REG32(env->eflags); + case 2: GET_REG32(env->segs[R_CS].selector); + case 3: GET_REG32(env->segs[R_SS].selector); + case 4: GET_REG32(env->segs[R_DS].selector); + case 5: GET_REG32(env->segs[R_ES].selector); + case 6: GET_REG32(env->segs[R_FS].selector); + case 7: GET_REG32(env->segs[R_GS].selector); + /* 8...15 x87 regs. */ + case 16: GET_REG32(env->fpuc); + case 17: GET_REG32((env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11); + case 18: GET_REG32(0); /* ftag */ + case 19: GET_REG32(0); /* fiseg */ + case 20: GET_REG32(0); /* fioff */ + case 21: GET_REG32(0); /* foseg */ + case 22: GET_REG32(0); /* fooff */ + case 23: GET_REG32(0); /* fop */ + /* 24+ xmm regs. */ + } + } + return 0; } -static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int i) { - uint32_t *registers = (uint32_t *)mem_buf; - int i; + uint32_t tmp; - for(i = 0; i < 8; i++) { - env->regs[i] = tswapl(registers[i]); - } - env->eip = tswapl(registers[8]); - env->eflags = tswapl(registers[9]); + if (i < CPU_NB_REGS) { + env->regs[gpr_map[i]] = ldtul_p(mem_buf); + return sizeof(target_ulong); + } else if (i >= CPU_NB_REGS + 8 && i < CPU_NB_REGS + 16) { + i -= CPU_NB_REGS + 8; +#ifdef USE_X86LDOUBLE + memcpy(&env->fpregs[i], mem_buf, 10); +#endif + return 10; + } else if (i >= CPU_NB_REGS + 24) { + i -= CPU_NB_REGS + 24; + if (i < CPU_NB_REGS) { + env->xmm_regs[i].XMM_Q(0) = ldq_p(mem_buf); + env->xmm_regs[i].XMM_Q(1) = ldq_p(mem_buf + 8); + return 16; + } else if (i == CPU_NB_REGS) { + env->mxcsr = ldl_p(mem_buf); + return 4; + } + } else { + i -= CPU_NB_REGS; + switch (i) { + case 0: env->eip = ldtul_p(mem_buf); return sizeof(target_ulong); + case 1: env->eflags = ldl_p(mem_buf); return 4; #if defined(CONFIG_USER_ONLY) #define LOAD_SEG(index, sreg)\ - if (tswapl(registers[index]) != env->segs[sreg].selector)\ - cpu_x86_load_seg(env, sreg, tswapl(registers[index])); - LOAD_SEG(10, R_CS); - LOAD_SEG(11, R_SS); - LOAD_SEG(12, R_DS); - LOAD_SEG(13, R_ES); - LOAD_SEG(14, R_FS); - LOAD_SEG(15, R_GS); -#endif + tmp = ldl_p(mem_buf);\ + if (tmp != env->segs[sreg].selector)\ + cpu_x86_load_seg(env, sreg, tmp); +#else +/* FIXME: Honor segment registers. Needs to avoid raising an exception + when the selector is invalid. */ +#define LOAD_SEG(index, sreg) do {} while(0) +#endif + case 2: LOAD_SEG(10, R_CS); return 4; + case 3: LOAD_SEG(11, R_SS); return 4; + case 4: LOAD_SEG(12, R_DS); return 4; + case 5: LOAD_SEG(13, R_ES); return 4; + case 6: LOAD_SEG(14, R_FS); return 4; + case 7: LOAD_SEG(15, R_GS); return 4; + /* 8...15 x87 regs. */ + case 16: env->fpuc = ldl_p(mem_buf); return 4; + case 17: + tmp = ldl_p(mem_buf); + env->fpstt = (tmp >> 11) & 7; + env->fpus = tmp & ~0x3800; + return 4; + case 18: /* ftag */ return 4; + case 19: /* fiseg */ return 4; + case 20: /* fioff */ return 4; + case 21: /* foseg */ return 4; + case 22: /* fooff */ return 4; + case 23: /* fop */ return 4; + /* 24+ xmm regs. */ + } + } + /* Unrecognised register. */ + return 0; } #elif defined (TARGET_PPC) -static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) -{ - uint32_t *registers = (uint32_t *)mem_buf, tmp; - int i; - /* fill in gprs */ - for(i = 0; i < 32; i++) { - registers[i] = tswapl(env->gpr[i]); - } - /* fill in fprs */ - for (i = 0; i < 32; i++) { - registers[(i * 2) + 32] = tswapl(*((uint32_t *)&env->fpr[i])); - registers[(i * 2) + 33] = tswapl(*((uint32_t *)&env->fpr[i] + 1)); - } - /* nip, msr, ccr, lnk, ctr, xer, mq */ - registers[96] = tswapl(env->nip); - registers[97] = tswapl(env->msr); - tmp = 0; - for (i = 0; i < 8; i++) - tmp |= env->crf[i] << (32 - ((i + 1) * 4)); - registers[98] = tswapl(tmp); - registers[99] = tswapl(env->lr); - registers[100] = tswapl(env->ctr); - registers[101] = tswapl(ppc_load_xer(env)); - registers[102] = 0; +#define NUM_CORE_REGS 71 - return 103 * 4; +static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) +{ + if (n < 32) { + /* gprs */ + GET_REGL(env->gpr[n]); + } else if (n < 64) { + /* fprs */ + stfq_p(mem_buf, env->fpr[n]); + return 8; + } else { + switch (n) { + case 64: GET_REGL(env->nip); + case 65: GET_REGL(env->msr); + case 66: + { + uint32_t cr = 0; + int i; + for (i = 0; i < 8; i++) + cr |= env->crf[i] << (32 - ((i + 1) * 4)); + GET_REG32(cr); + } + case 67: GET_REGL(env->lr); + case 68: GET_REGL(env->ctr); + case 69: GET_REGL(env->xer); + case 70: GET_REG32(0); /* fpscr */ + } + } + return 0; } -static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) { - uint32_t *registers = (uint32_t *)mem_buf; - int i; - - /* fill in gprs */ - for (i = 0; i < 32; i++) { - env->gpr[i] = tswapl(registers[i]); - } - /* fill in fprs */ - for (i = 0; i < 32; i++) { - *((uint32_t *)&env->fpr[i]) = tswapl(registers[(i * 2) + 32]); - *((uint32_t *)&env->fpr[i] + 1) = tswapl(registers[(i * 2) + 33]); - } - /* nip, msr, ccr, lnk, ctr, xer, mq */ - env->nip = tswapl(registers[96]); - ppc_store_msr(env, tswapl(registers[97])); - registers[98] = tswapl(registers[98]); - for (i = 0; i < 8; i++) - env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF; - env->lr = tswapl(registers[99]); - env->ctr = tswapl(registers[100]); - ppc_store_xer(env, tswapl(registers[101])); + if (n < 32) { + /* gprs */ + env->gpr[n] = ldtul_p(mem_buf); + return sizeof(target_ulong); + } else if (n < 64) { + /* fprs */ + env->fpr[n] = ldfq_p(mem_buf); + return 8; + } else { + switch (n) { + case 64: + env->nip = ldtul_p(mem_buf); + return sizeof(target_ulong); + case 65: + ppc_store_msr(env, ldtul_p(mem_buf)); + return sizeof(target_ulong); + case 66: + { + uint32_t cr = ldl_p(mem_buf); + int i; + for (i = 0; i < 8; i++) + env->crf[i] = (cr >> (32 - ((i + 1) * 4))) & 0xF; + return 4; + } + case 67: + env->lr = ldtul_p(mem_buf); + return sizeof(target_ulong); + case 68: + env->ctr = ldtul_p(mem_buf); + return sizeof(target_ulong); + case 69: + env->xer = ldtul_p(mem_buf); + return sizeof(target_ulong); + case 70: + /* fpscr */ + return 4; + } + } + return 0; } + #elif defined (TARGET_SPARC) -static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) -{ - target_ulong *registers = (target_ulong *)mem_buf; - int i; - /* fill in g0..g7 */ - for(i = 0; i < 8; i++) { - registers[i] = tswapl(env->gregs[i]); - } - /* fill in register window */ - for(i = 0; i < 24; i++) { - registers[i + 8] = tswapl(env->regwptr[i]); - } -#ifndef TARGET_SPARC64 - /* fill in fprs */ - for (i = 0; i < 32; i++) { - registers[i + 32] = tswapl(*((uint32_t *)&env->fpr[i])); +#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) +#define NUM_CORE_REGS 86 +#else +#define NUM_CORE_REGS 73 +#endif + +#ifdef TARGET_ABI32 +#define GET_REGA(val) GET_REG32(val) +#else +#define GET_REGA(val) GET_REGL(val) +#endif + +static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) +{ + if (n < 8) { + /* g0..g7 */ + GET_REGA(env->gregs[n]); + } + if (n < 32) { + /* register window */ + GET_REGA(env->regwptr[n - 8]); + } +#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64) + if (n < 64) { + /* fprs */ + GET_REG32(*((uint32_t *)&env->fpr[n - 32])); } /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ - registers[64] = tswapl(env->y); - { - target_ulong tmp; - - tmp = GET_PSR(env); - registers[65] = tswapl(tmp); + switch (n) { + case 64: GET_REGA(env->y); + case 65: GET_REGA(GET_PSR(env)); + case 66: GET_REGA(env->wim); + case 67: GET_REGA(env->tbr); + case 68: GET_REGA(env->pc); + case 69: GET_REGA(env->npc); + case 70: GET_REGA(env->fsr); + case 71: GET_REGA(0); /* csr */ + case 72: GET_REGA(0); } - registers[66] = tswapl(env->wim); - registers[67] = tswapl(env->tbr); - registers[68] = tswapl(env->pc); - registers[69] = tswapl(env->npc); - registers[70] = tswapl(env->fsr); - registers[71] = 0; /* csr */ - registers[72] = 0; - return 73 * sizeof(target_ulong); #else - /* fill in fprs */ - for (i = 0; i < 64; i += 2) { - uint64_t tmp; - - tmp = ((uint64_t)*(uint32_t *)&env->fpr[i]) << 32; - tmp |= *(uint32_t *)&env->fpr[i + 1]; - registers[i / 2 + 32] = tswap64(tmp); - } - registers[64] = tswapl(env->pc); - registers[65] = tswapl(env->npc); - registers[66] = tswapl(((uint64_t)GET_CCR(env) << 32) | + if (n < 64) { + /* f0-f31 */ + GET_REG32(*((uint32_t *)&env->fpr[n - 32])); + } + if (n < 80) { + /* f32-f62 (double width, even numbers only) */ + uint64_t val; + + val = (uint64_t)*((uint32_t *)&env->fpr[(n - 64) * 2 + 32]) << 32; + val |= *((uint32_t *)&env->fpr[(n - 64) * 2 + 33]); + GET_REG64(val); + } + switch (n) { + case 80: GET_REGL(env->pc); + case 81: GET_REGL(env->npc); + case 82: GET_REGL(((uint64_t)GET_CCR(env) << 32) | ((env->asi & 0xff) << 24) | ((env->pstate & 0xfff) << 8) | GET_CWP64(env)); - registers[67] = tswapl(env->fsr); - registers[68] = tswapl(env->fprs); - registers[69] = tswapl(env->y); - return 70 * sizeof(target_ulong); + case 83: GET_REGL(env->fsr); + case 84: GET_REGL(env->fprs); + case 85: GET_REGL(env->y); + } #endif + return 0; } -static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) { - target_ulong *registers = (target_ulong *)mem_buf; - int i; +#if defined(TARGET_ABI32) + abi_ulong tmp; - /* fill in g0..g7 */ - for(i = 0; i < 7; i++) { - env->gregs[i] = tswapl(registers[i]); - } - /* fill in register window */ - for(i = 0; i < 24; i++) { - env->regwptr[i] = tswapl(registers[i + 8]); - } -#ifndef TARGET_SPARC64 - /* fill in fprs */ - for (i = 0; i < 32; i++) { - *((uint32_t *)&env->fpr[i]) = tswapl(registers[i + 32]); - } - /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ - env->y = tswapl(registers[64]); - PUT_PSR(env, tswapl(registers[65])); - env->wim = tswapl(registers[66]); - env->tbr = tswapl(registers[67]); - env->pc = tswapl(registers[68]); - env->npc = tswapl(registers[69]); - env->fsr = tswapl(registers[70]); + tmp = ldl_p(mem_buf); #else - for (i = 0; i < 64; i += 2) { - uint64_t tmp; + target_ulong tmp; - tmp = tswap64(registers[i / 2 + 32]); - *((uint32_t *)&env->fpr[i]) = tmp >> 32; - *((uint32_t *)&env->fpr[i + 1]) = tmp & 0xffffffff; - } - env->pc = tswapl(registers[64]); - env->npc = tswapl(registers[65]); - { - uint64_t tmp = tswapl(registers[66]); + tmp = ldtul_p(mem_buf); +#endif - PUT_CCR(env, tmp >> 32); - env->asi = (tmp >> 24) & 0xff; - env->pstate = (tmp >> 8) & 0xfff; - PUT_CWP64(env, tmp & 0xff); - } - env->fsr = tswapl(registers[67]); - env->fprs = tswapl(registers[68]); - env->y = tswapl(registers[69]); + if (n < 8) { + /* g0..g7 */ + env->gregs[n] = tmp; + } else if (n < 32) { + /* register window */ + env->regwptr[n - 8] = tmp; + } +#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64) + else if (n < 64) { + /* fprs */ + *((uint32_t *)&env->fpr[n - 32]) = tmp; + } else { + /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ + switch (n) { + case 64: env->y = tmp; break; + case 65: PUT_PSR(env, tmp); break; + case 66: env->wim = tmp; break; + case 67: env->tbr = tmp; break; + case 68: env->pc = tmp; break; + case 69: env->npc = tmp; break; + case 70: env->fsr = tmp; break; + default: return 0; + } + } + return 4; +#else + else if (n < 64) { + /* f0-f31 */ + env->fpr[n] = ldfl_p(mem_buf); + return 4; + } else if (n < 80) { + /* f32-f62 (double width, even numbers only) */ + *((uint32_t *)&env->fpr[(n - 64) * 2 + 32]) = tmp >> 32; + *((uint32_t *)&env->fpr[(n - 64) * 2 + 33]) = tmp; + } else { + switch (n) { + case 80: env->pc = tmp; break; + case 81: env->npc = tmp; break; + case 82: + PUT_CCR(env, tmp >> 32); + env->asi = (tmp >> 24) & 0xff; + env->pstate = (tmp >> 8) & 0xfff; + PUT_CWP64(env, tmp & 0xff); + break; + case 83: env->fsr = tmp; break; + case 84: env->fprs = tmp; break; + case 85: env->y = tmp; break; + default: return 0; + } + } + return 8; #endif } #elif defined (TARGET_ARM) -static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) -{ - int i; - uint8_t *ptr; - - ptr = mem_buf; - /* 16 core integer registers (4 bytes each). */ - for (i = 0; i < 16; i++) - { - *(uint32_t *)ptr = tswapl(env->regs[i]); - ptr += 4; - } - /* 8 FPA registers (12 bytes each), FPS (4 bytes). - Not yet implemented. */ - memset (ptr, 0, 8 * 12 + 4); - ptr += 8 * 12 + 4; - /* CPSR (4 bytes). */ - *(uint32_t *)ptr = tswapl (cpsr_read(env)); - ptr += 4; - return ptr - mem_buf; +/* Old gdb always expect FPA registers. Newer (xml-aware) gdb only expect + whatever the target description contains. Due to a historical mishap + the FPA registers appear in between core integer regs and the CPSR. + We hack round this by giving the FPA regs zero size when talking to a + newer gdb. */ +#define NUM_CORE_REGS 26 +#define GDB_CORE_XML "arm-core.xml" + +static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) +{ + if (n < 16) { + /* Core integer register. */ + GET_REG32(env->regs[n]); + } + if (n < 24) { + /* FPA registers. */ + if (gdb_has_xml) + return 0; + memset(mem_buf, 0, 12); + return 12; + } + switch (n) { + case 24: + /* FPA status register. */ + if (gdb_has_xml) + return 0; + GET_REG32(0); + case 25: + /* CPSR */ + GET_REG32(cpsr_read(env)); + } + /* Unknown register. */ + return 0; } -static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) { - int i; - uint8_t *ptr; + uint32_t tmp; + + tmp = ldl_p(mem_buf); - ptr = mem_buf; - /* Core integer registers. */ - for (i = 0; i < 16; i++) - { - env->regs[i] = tswapl(*(uint32_t *)ptr); - ptr += 4; - } - /* Ignore FPA regs and scr. */ - ptr += 8 * 12 + 4; - cpsr_write (env, tswapl(*(uint32_t *)ptr), 0xffffffff); + /* Mask out low bit of PC to workaround gdb bugs. This will probably + cause problems if we ever implement the Jazelle DBX extensions. */ + if (n == 15) + tmp &= ~1; + + if (n < 16) { + /* Core integer register. */ + env->regs[n] = tmp; + return 4; + } + if (n < 24) { /* 16-23 */ + /* FPA registers (ignored). */ + if (gdb_has_xml) + return 0; + return 12; + } + switch (n) { + case 24: + /* FPA status register (ignored). */ + if (gdb_has_xml) + return 0; + return 4; + case 25: + /* CPSR */ + cpsr_write (env, tmp, 0xffffffff); + return 4; + } + /* Unknown register. */ + return 0; } + #elif defined (TARGET_M68K) -static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) -{ - int i; - uint8_t *ptr; - CPU_DoubleU u; - ptr = mem_buf; - /* D0-D7 */ - for (i = 0; i < 8; i++) { - *(uint32_t *)ptr = tswapl(env->dregs[i]); - ptr += 4; - } - /* A0-A7 */ - for (i = 0; i < 8; i++) { - *(uint32_t *)ptr = tswapl(env->aregs[i]); - ptr += 4; - } - *(uint32_t *)ptr = tswapl(env->sr); - ptr += 4; - *(uint32_t *)ptr = tswapl(env->pc); - ptr += 4; - /* F0-F7. The 68881/68040 have 12-bit extended precision registers. - ColdFire has 8-bit double precision registers. */ - for (i = 0; i < 8; i++) { - u.d = env->fregs[i]; - *(uint32_t *)ptr = tswap32(u.l.upper); - *(uint32_t *)ptr = tswap32(u.l.lower); - } - /* FP control regs (not implemented). */ - memset (ptr, 0, 3 * 4); - ptr += 3 * 4; +#define NUM_CORE_REGS 18 - return ptr - mem_buf; -} +#define GDB_CORE_XML "cf-core.xml" -static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) { - int i; - uint8_t *ptr; - CPU_DoubleU u; - - ptr = mem_buf; - /* D0-D7 */ - for (i = 0; i < 8; i++) { - env->dregs[i] = tswapl(*(uint32_t *)ptr); - ptr += 4; - } - /* A0-A7 */ - for (i = 0; i < 8; i++) { - env->aregs[i] = tswapl(*(uint32_t *)ptr); - ptr += 4; - } - env->sr = tswapl(*(uint32_t *)ptr); - ptr += 4; - env->pc = tswapl(*(uint32_t *)ptr); - ptr += 4; - /* F0-F7. The 68881/68040 have 12-bit extended precision registers. - ColdFire has 8-bit double precision registers. */ - for (i = 0; i < 8; i++) { - u.l.upper = tswap32(*(uint32_t *)ptr); - u.l.lower = tswap32(*(uint32_t *)ptr); - env->fregs[i] = u.d; + if (n < 8) { + /* D0-D7 */ + GET_REG32(env->dregs[n]); + } else if (n < 16) { + /* A0-A7 */ + GET_REG32(env->aregs[n - 8]); + } else { + switch (n) { + case 16: GET_REG32(env->sr); + case 17: GET_REG32(env->pc); + } } - /* FP control regs (not implemented). */ - ptr += 3 * 4; + /* FP registers not included here because they vary between + ColdFire and m68k. Use XML bits for these. */ + return 0; } -#elif defined (TARGET_MIPS) -static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) -{ - int i; - uint8_t *ptr; - ptr = mem_buf; - for (i = 0; i < 32; i++) - { - *(target_ulong *)ptr = tswapl(env->gpr[i][env->current_tc]); - ptr += sizeof(target_ulong); - } - - *(target_ulong *)ptr = (int32_t)tswap32(env->CP0_Status); - ptr += sizeof(target_ulong); - - *(target_ulong *)ptr = tswapl(env->LO[0][env->current_tc]); - ptr += sizeof(target_ulong); - - *(target_ulong *)ptr = tswapl(env->HI[0][env->current_tc]); - ptr += sizeof(target_ulong); +static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) +{ + uint32_t tmp; - *(target_ulong *)ptr = tswapl(env->CP0_BadVAddr); - ptr += sizeof(target_ulong); + tmp = ldl_p(mem_buf); - *(target_ulong *)ptr = (int32_t)tswap32(env->CP0_Cause); - ptr += sizeof(target_ulong); + if (n < 8) { + /* D0-D7 */ + env->dregs[n] = tmp; + } else if (n < 8) { + /* A0-A7 */ + env->aregs[n - 8] = tmp; + } else { + switch (n) { + case 16: env->sr = tmp; break; + case 17: env->pc = tmp; break; + default: return 0; + } + } + return 4; +} +#elif defined (TARGET_MIPS) - *(target_ulong *)ptr = tswapl(env->PC[env->current_tc]); - ptr += sizeof(target_ulong); +#define NUM_CORE_REGS 73 - if (env->CP0_Config1 & (1 << CP0C1_FP)) - { - for (i = 0; i < 32; i++) - { +static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) +{ + if (n < 32) { + GET_REGL(env->active_tc.gpr[n]); + } + if (env->CP0_Config1 & (1 << CP0C1_FP)) { + if (n >= 38 && n < 70) { if (env->CP0_Status & (1 << CP0St_FR)) - *(target_ulong *)ptr = tswapl(env->fpu->fpr[i].d); + GET_REGL(env->active_fpu.fpr[n - 38].d); else - *(target_ulong *)ptr = tswap32(env->fpu->fpr[i].w[FP_ENDIAN_IDX]); - ptr += sizeof(target_ulong); - } - - *(target_ulong *)ptr = (int32_t)tswap32(env->fpu->fcr31); - ptr += sizeof(target_ulong); - - *(target_ulong *)ptr = (int32_t)tswap32(env->fpu->fcr0); - ptr += sizeof(target_ulong); - } - - /* "fp", pseudo frame pointer. Not yet implemented in gdb. */ - *(target_ulong *)ptr = 0; - ptr += sizeof(target_ulong); - - /* Registers for embedded use, we just pad them. */ - for (i = 0; i < 16; i++) - { - *(target_ulong *)ptr = 0; - ptr += sizeof(target_ulong); - } - - /* Processor ID. */ - *(target_ulong *)ptr = (int32_t)tswap32(env->CP0_PRid); - ptr += sizeof(target_ulong); + GET_REGL(env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX]); + } + switch (n) { + case 70: GET_REGL((int32_t)env->active_fpu.fcr31); + case 71: GET_REGL((int32_t)env->active_fpu.fcr0); + } + } + switch (n) { + case 32: GET_REGL((int32_t)env->CP0_Status); + case 33: GET_REGL(env->active_tc.LO[0]); + case 34: GET_REGL(env->active_tc.HI[0]); + case 35: GET_REGL(env->CP0_BadVAddr); + case 36: GET_REGL((int32_t)env->CP0_Cause); + case 37: GET_REGL(env->active_tc.PC); + case 72: GET_REGL(0); /* fp */ + case 89: GET_REGL((int32_t)env->CP0_PRid); + } + if (n >= 73 && n <= 88) { + /* 16 embedded regs. */ + GET_REGL(0); + } - return ptr - mem_buf; + return 0; } /* convert MIPS rounding mode in FCR31 to IEEE library */ @@ -677,204 +797,361 @@ float_round_down }; #define RESTORE_ROUNDING_MODE \ - set_float_rounding_mode(ieee_rm[env->fpu->fcr31 & 3], &env->fpu->fp_status) + set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status) -static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) { - int i; - uint8_t *ptr; - - ptr = mem_buf; - for (i = 0; i < 32; i++) - { - env->gpr[i][env->current_tc] = tswapl(*(target_ulong *)ptr); - ptr += sizeof(target_ulong); - } - - env->CP0_Status = tswapl(*(target_ulong *)ptr); - ptr += sizeof(target_ulong); - - env->LO[0][env->current_tc] = tswapl(*(target_ulong *)ptr); - ptr += sizeof(target_ulong); - - env->HI[0][env->current_tc] = tswapl(*(target_ulong *)ptr); - ptr += sizeof(target_ulong); - - env->CP0_BadVAddr = tswapl(*(target_ulong *)ptr); - ptr += sizeof(target_ulong); - - env->CP0_Cause = tswapl(*(target_ulong *)ptr); - ptr += sizeof(target_ulong); + target_ulong tmp; - env->PC[env->current_tc] = tswapl(*(target_ulong *)ptr); - ptr += sizeof(target_ulong); + tmp = ldtul_p(mem_buf); - if (env->CP0_Config1 & (1 << CP0C1_FP)) - { - for (i = 0; i < 32; i++) - { + if (n < 32) { + env->active_tc.gpr[n] = tmp; + return sizeof(target_ulong); + } + if (env->CP0_Config1 & (1 << CP0C1_FP) + && n >= 38 && n < 73) { + if (n < 70) { if (env->CP0_Status & (1 << CP0St_FR)) - env->fpu->fpr[i].d = tswapl(*(target_ulong *)ptr); + env->active_fpu.fpr[n - 38].d = tmp; else - env->fpu->fpr[i].w[FP_ENDIAN_IDX] = tswapl(*(target_ulong *)ptr); - ptr += sizeof(target_ulong); - } - - env->fpu->fcr31 = tswapl(*(target_ulong *)ptr) & 0xFF83FFFF; - ptr += sizeof(target_ulong); - - /* The remaining registers are assumed to be read-only. */ - - /* set rounding mode */ - RESTORE_ROUNDING_MODE; - + env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX] = tmp; + } + switch (n) { + case 70: + env->active_fpu.fcr31 = tmp & 0xFF83FFFF; + /* set rounding mode */ + RESTORE_ROUNDING_MODE; #ifndef CONFIG_SOFTFLOAT - /* no floating point exception for native float */ - SET_FP_ENABLE(env->fcr31, 0); + /* no floating point exception for native float */ + SET_FP_ENABLE(env->active_fpu.fcr31, 0); #endif - } + break; + case 71: env->active_fpu.fcr0 = tmp; break; + } + return sizeof(target_ulong); + } + switch (n) { + case 32: env->CP0_Status = tmp; break; + case 33: env->active_tc.LO[0] = tmp; break; + case 34: env->active_tc.HI[0] = tmp; break; + case 35: env->CP0_BadVAddr = tmp; break; + case 36: env->CP0_Cause = tmp; break; + case 37: env->active_tc.PC = tmp; break; + case 72: /* fp, ignored */ break; + default: + if (n > 89) + return 0; + /* Other registers are readonly. Ignore writes. */ + break; + } + + return sizeof(target_ulong); } #elif defined (TARGET_SH4) /* Hint: Use "set architecture sh4" in GDB to see fpu registers */ +/* FIXME: We should use XML for this. */ + +#define NUM_CORE_REGS 59 -static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) +static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) { - uint32_t *ptr = (uint32_t *)mem_buf; - int i; + if (n < 8) { + if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) { + GET_REGL(env->gregs[n + 16]); + } else { + GET_REGL(env->gregs[n]); + } + } else if (n < 16) { + GET_REGL(env->gregs[n - 8]); + } else if (n >= 25 && n < 41) { + GET_REGL(env->fregs[(n - 25) + ((env->fpscr & FPSCR_FR) ? 16 : 0)]); + } else if (n >= 43 && n < 51) { + GET_REGL(env->gregs[n - 43]); + } else if (n >= 51 && n < 59) { + GET_REGL(env->gregs[n - (51 - 16)]); + } + switch (n) { + case 16: GET_REGL(env->pc); + case 17: GET_REGL(env->pr); + case 18: GET_REGL(env->gbr); + case 19: GET_REGL(env->vbr); + case 20: GET_REGL(env->mach); + case 21: GET_REGL(env->macl); + case 22: GET_REGL(env->sr); + case 23: GET_REGL(env->fpul); + case 24: GET_REGL(env->fpscr); + case 41: GET_REGL(env->ssr); + case 42: GET_REGL(env->spc); + } -#define SAVE(x) *ptr++=tswapl(x) - if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) { - for (i = 0; i < 8; i++) SAVE(env->gregs[i + 16]); - } else { - for (i = 0; i < 8; i++) SAVE(env->gregs[i]); - } - for (i = 8; i < 16; i++) SAVE(env->gregs[i]); - SAVE (env->pc); - SAVE (env->pr); - SAVE (env->gbr); - SAVE (env->vbr); - SAVE (env->mach); - SAVE (env->macl); - SAVE (env->sr); - SAVE (env->fpul); - SAVE (env->fpscr); - for (i = 0; i < 16; i++) - SAVE(env->fregs[i + ((env->fpscr & FPSCR_FR) ? 16 : 0)]); - SAVE (env->ssr); - SAVE (env->spc); - for (i = 0; i < 8; i++) SAVE(env->gregs[i]); - for (i = 0; i < 8; i++) SAVE(env->gregs[i + 16]); - return ((uint8_t *)ptr - mem_buf); -} - -static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) -{ - uint32_t *ptr = (uint32_t *)mem_buf; - int i; - -#define LOAD(x) (x)=*ptr++; - if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) { - for (i = 0; i < 8; i++) LOAD(env->gregs[i + 16]); - } else { - for (i = 0; i < 8; i++) LOAD(env->gregs[i]); - } - for (i = 8; i < 16; i++) LOAD(env->gregs[i]); - LOAD (env->pc); - LOAD (env->pr); - LOAD (env->gbr); - LOAD (env->vbr); - LOAD (env->mach); - LOAD (env->macl); - LOAD (env->sr); - LOAD (env->fpul); - LOAD (env->fpscr); - for (i = 0; i < 16; i++) - LOAD(env->fregs[i + ((env->fpscr & FPSCR_FR) ? 16 : 0)]); - LOAD (env->ssr); - LOAD (env->spc); - for (i = 0; i < 8; i++) LOAD(env->gregs[i]); - for (i = 0; i < 8; i++) LOAD(env->gregs[i + 16]); + return 0; } -#elif defined (TARGET_CRIS) -static int cris_save_32 (unsigned char *d, uint32_t value) +static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) { - *d++ = (value); - *d++ = (value >>= 8); - *d++ = (value >>= 8); - *d++ = (value >>= 8); + uint32_t tmp; + + tmp = ldl_p(mem_buf); + + if (n < 8) { + if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) { + env->gregs[n + 16] = tmp; + } else { + env->gregs[n] = tmp; + } return 4; + } else if (n < 16) { + env->gregs[n - 8] = tmp; + return 4; + } else if (n >= 25 && n < 41) { + env->fregs[(n - 25) + ((env->fpscr & FPSCR_FR) ? 16 : 0)] = tmp; + } else if (n >= 43 && n < 51) { + env->gregs[n - 43] = tmp; + return 4; + } else if (n >= 51 && n < 59) { + env->gregs[n - (51 - 16)] = tmp; + return 4; + } + switch (n) { + case 16: env->pc = tmp; + case 17: env->pr = tmp; + case 18: env->gbr = tmp; + case 19: env->vbr = tmp; + case 20: env->mach = tmp; + case 21: env->macl = tmp; + case 22: env->sr = tmp; + case 23: env->fpul = tmp; + case 24: env->fpscr = tmp; + case 41: env->ssr = tmp; + case 42: env->spc = tmp; + default: return 0; + } + + return 4; } -static int cris_save_16 (unsigned char *d, uint32_t value) -{ - *d++ = (value); - *d++ = (value >>= 8); - return 2; -} -static int cris_save_8 (unsigned char *d, uint32_t value) +#elif defined (TARGET_CRIS) + +#define NUM_CORE_REGS 49 + +static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) { - *d++ = (value); - return 1; + uint8_t srs; + + srs = env->pregs[PR_SRS]; + if (n < 16) { + GET_REG32(env->regs[n]); + } + + if (n >= 21 && n < 32) { + GET_REG32(env->pregs[n - 16]); + } + if (n >= 33 && n < 49) { + GET_REG32(env->sregs[srs][n - 33]); + } + switch (n) { + case 16: GET_REG8(env->pregs[0]); + case 17: GET_REG8(env->pregs[1]); + case 18: GET_REG32(env->pregs[2]); + case 19: GET_REG8(srs); + case 20: GET_REG16(env->pregs[4]); + case 32: GET_REG32(env->pc); + } + + return 0; } -/* FIXME: this will bug on archs not supporting unaligned word accesses. */ -static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) +static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) { - uint8_t *ptr = mem_buf; - uint8_t srs; - int i; + uint32_t tmp; + + if (n > 49) + return 0; + + tmp = ldl_p(mem_buf); + + if (n < 16) { + env->regs[n] = tmp; + } - for (i = 0; i < 16; i++) - ptr += cris_save_32 (ptr, env->regs[i]); + if (n >= 21 && n < 32) { + env->pregs[n - 16] = tmp; + } - srs = env->pregs[SR_SRS]; + /* FIXME: Should support function regs be writable? */ + switch (n) { + case 16: return 1; + case 17: return 1; + case 18: env->pregs[PR_PID] = tmp; break; + case 19: return 1; + case 20: return 2; + case 32: env->pc = tmp; break; + } - ptr += cris_save_8 (ptr, env->pregs[0]); - ptr += cris_save_8 (ptr, env->pregs[1]); - ptr += cris_save_32 (ptr, env->pregs[2]); - ptr += cris_save_8 (ptr, srs); - ptr += cris_save_16 (ptr, env->pregs[4]); + return 4; +} +#else - for (i = 5; i < 16; i++) - ptr += cris_save_32 (ptr, env->pregs[i]); +#define NUM_CORE_REGS 0 - ptr += cris_save_32 (ptr, env->pc); +static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) +{ + return 0; +} - for (i = 0; i < 16; i++) - ptr += cris_save_32 (ptr, env->sregs[srs][i]); +static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) +{ + return 0; +} - return ((uint8_t *)ptr - mem_buf); +#endif + +static int num_g_regs = NUM_CORE_REGS; + +#ifdef GDB_CORE_XML +/* Encode data using the encoding for 'x' packets. */ +static int memtox(char *buf, const char *mem, int len) +{ + char *p = buf; + char c; + + while (len--) { + c = *(mem++); + switch (c) { + case '#': case '$': case '*': case '}': + *(p++) = '}'; + *(p++) = c ^ 0x20; + break; + default: + *(p++) = c; + break; + } + } + return p - buf; } -static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +const char *get_feature_xml(CPUState *env, const char *p, const char **newp) { - uint32_t *ptr = (uint32_t *)mem_buf; - int i; + extern const char *const xml_builtin[][2]; + size_t len; + int i; + const char *name; + static char target_xml[1024]; -#define LOAD(x) (x)=*ptr++; - for (i = 0; i < 16; i++) LOAD(env->regs[i]); - LOAD (env->pc); + len = 0; + while (p[len] && p[len] != ':') + len++; + *newp = p + len; + + name = NULL; + if (strncmp(p, "target.xml", len) == 0) { + /* Generate the XML description for this CPU. */ + if (!target_xml[0]) { + GDBRegisterState *r; + + snprintf(target_xml, sizeof(target_xml), + "" + "" + "" + "", + GDB_CORE_XML); + + for (r = env->gdb_regs; r; r = r->next) { + strcat(target_xml, "xml); + strcat(target_xml, "\"/>"); + } + strcat(target_xml, ""); + } + return target_xml; + } + for (i = 0; ; i++) { + name = xml_builtin[i][0]; + if (!name || (strncmp(name, p, len) == 0 && strlen(name) == len)) + break; + } + return name ? xml_builtin[i][1] : NULL; } -#else -static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) +#endif + +static int gdb_read_register(CPUState *env, uint8_t *mem_buf, int reg) { + GDBRegisterState *r; + + if (reg < NUM_CORE_REGS) + return cpu_gdb_read_register(env, mem_buf, reg); + + for (r = env->gdb_regs; r; r = r->next) { + if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) { + return r->get_reg(env, mem_buf, reg - r->base_reg); + } + } return 0; } -static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +static int gdb_write_register(CPUState *env, uint8_t *mem_buf, int reg) { + GDBRegisterState *r; + + if (reg < NUM_CORE_REGS) + return cpu_gdb_write_register(env, mem_buf, reg); + + for (r = env->gdb_regs; r; r = r->next) { + if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) { + return r->set_reg(env, mem_buf, reg - r->base_reg); + } + } + return 0; } -#endif +/* Register a supplemental set of CPU registers. If g_pos is nonzero it + specifies the first register number and these registers are included in + a standard "g" packet. Direction is relative to gdb, i.e. get_reg is + gdb reading a CPU register, and set_reg is gdb modifying a CPU register. + */ + +void gdb_register_coprocessor(CPUState * env, + gdb_reg_cb get_reg, gdb_reg_cb set_reg, + int num_regs, const char *xml, int g_pos) +{ + GDBRegisterState *s; + GDBRegisterState **p; + static int last_reg = NUM_CORE_REGS; + + s = (GDBRegisterState *)qemu_mallocz(sizeof(GDBRegisterState)); + s->base_reg = last_reg; + s->num_regs = num_regs; + s->get_reg = get_reg; + s->set_reg = set_reg; + s->xml = xml; + p = &env->gdb_regs; + while (*p) { + /* Check for duplicates. */ + if (strcmp((*p)->xml, xml) == 0) + return; + p = &(*p)->next; + } + /* Add to end of list. */ + last_reg += num_regs; + *p = s; + if (g_pos) { + if (g_pos != s->base_reg) { + fprintf(stderr, "Error: Bad gdb register numbering for '%s'\n" + "Expected %d got %d\n", xml, g_pos, s->base_reg); + } else { + num_g_regs = last_reg; + } + } +} static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) { const char *p; int ch, reg_size, type; - char buf[4096]; - uint8_t mem_buf[4096]; - uint32_t *registers; + char buf[MAX_PACKET_LENGTH]; + uint8_t mem_buf[MAX_PACKET_LENGTH]; + uint8_t *registers; target_ulong addr, len; #ifdef DEBUG_GDB @@ -887,6 +1164,12 @@ /* TODO: Make this return the correct value for user-mode. */ snprintf(buf, sizeof(buf), "S%02x", SIGTRAP); put_packet(s, buf); + /* Remove all the breakpoints when this query is issued, + * because gdb is doing and initial connect and the state + * should be cleaned up. + */ + cpu_breakpoint_remove_all(env); + cpu_watchpoint_remove_all(env); break; case 'c': if (*p != '\0') { @@ -903,17 +1186,28 @@ #elif defined (TARGET_SH4) env->pc = addr; #elif defined (TARGET_MIPS) - env->PC[env->current_tc] = addr; + env->active_tc.PC = addr; #elif defined (TARGET_CRIS) env->pc = addr; #endif } -#ifdef CONFIG_USER_ONLY - s->running_state = 1; -#else - vm_start(); -#endif + gdb_continue(s); return RS_IDLE; + case 'C': + s->signal = strtoul(p, (char **)&p, 16); + gdb_continue(s); + return RS_IDLE; + case 'k': + /* Kill the target */ + fprintf(stderr, "\nQEMU: Terminated via GDBstub\n"); + exit(0); + case 'D': + /* Detach packet */ + cpu_breakpoint_remove_all(env); + cpu_watchpoint_remove_all(env); + gdb_continue(s); + put_packet(s, "OK"); + break; case 's': if (*p != '\0') { addr = strtoull(p, (char **)&p, 16); @@ -929,17 +1223,13 @@ #elif defined (TARGET_SH4) env->pc = addr; #elif defined (TARGET_MIPS) - env->PC[env->current_tc] = addr; + env->active_tc.PC = addr; #elif defined (TARGET_CRIS) env->pc = addr; #endif } - cpu_single_step(env, 1); -#ifdef CONFIG_USER_ONLY - s->running_state = 1; -#else - vm_start(); -#endif + cpu_single_step(env, sstep_flags); + gdb_continue(s); return RS_IDLE; case 'F': { @@ -961,24 +1251,28 @@ if (type == 'C') { put_packet(s, "T02"); } else { -#ifdef CONFIG_USER_ONLY - s->running_state = 1; -#else - vm_start(); -#endif + gdb_continue(s); } } break; case 'g': - reg_size = cpu_gdb_read_registers(env, mem_buf); - memtohex(buf, mem_buf, reg_size); + len = 0; + for (addr = 0; addr < num_g_regs; addr++) { + reg_size = gdb_read_register(env, mem_buf + len, addr); + len += reg_size; + } + memtohex(buf, mem_buf, len); put_packet(s, buf); break; case 'G': - registers = (void *)mem_buf; + registers = mem_buf; len = strlen(p) / 2; hextomem((uint8_t *)registers, p, len); - cpu_gdb_write_registers(env, mem_buf, len); + for (addr = 0; addr < num_g_regs && len > 0; addr++) { + reg_size = gdb_write_register(env, registers, addr); + len -= reg_size; + registers += reg_size; + } put_packet(s, "OK"); break; case 'm': @@ -1006,6 +1300,32 @@ else put_packet(s, "OK"); break; + case 'p': + /* Older gdb are really dumb, and don't use 'g' if 'p' is avaialable. + This works, but can be very slow. Anything new enough to + understand XML also knows how to use this properly. */ + if (!gdb_has_xml) + goto unknown_command; + addr = strtoull(p, (char **)&p, 16); + reg_size = gdb_read_register(env, mem_buf, addr); + if (reg_size) { + memtohex(buf, mem_buf, reg_size); + put_packet(s, buf); + } else { + put_packet(s, "E14"); + } + break; + case 'P': + if (!gdb_has_xml) + goto unknown_command; + addr = strtoull(p, (char **)&p, 16); + if (*p == '=') + p++; + reg_size = strlen(p) / 2; + hextomem(mem_buf, p, reg_size); + gdb_write_register(env, mem_buf, addr); + put_packet(s, "OK"); + break; case 'Z': type = strtoul(p, (char **)&p, 16); if (*p == ',') @@ -1014,21 +1334,37 @@ if (*p == ',') p++; len = strtoull(p, (char **)&p, 16); - if (type == 0 || type == 1) { + switch (type) { + case 0: + case 1: if (cpu_breakpoint_insert(env, addr) < 0) goto breakpoint_error; put_packet(s, "OK"); + break; #ifndef CONFIG_USER_ONLY - } else if (type == 2) { - if (cpu_watchpoint_insert(env, addr) < 0) + case 2: + type = PAGE_WRITE; + goto insert_watchpoint; + case 3: + type = PAGE_READ; + goto insert_watchpoint; + case 4: + type = PAGE_READ | PAGE_WRITE; + insert_watchpoint: + if (cpu_watchpoint_insert(env, addr, type) < 0) goto breakpoint_error; put_packet(s, "OK"); + break; #endif - } else { - breakpoint_error: - put_packet(s, "E22"); + default: + put_packet(s, ""); + break; } break; + breakpoint_error: + put_packet(s, "E22"); + break; + case 'z': type = strtoul(p, (char **)&p, 16); if (*p == ',') @@ -1041,32 +1377,107 @@ cpu_breakpoint_remove(env, addr); put_packet(s, "OK"); #ifndef CONFIG_USER_ONLY - } else if (type == 2) { + } else if (type >= 2 || type <= 4) { cpu_watchpoint_remove(env, addr); put_packet(s, "OK"); #endif } else { - goto breakpoint_error; + put_packet(s, ""); } break; -#ifdef CONFIG_LINUX_USER case 'q': - if (strncmp(p, "Offsets", 7) == 0) { + case 'Q': + /* parse any 'q' packets here */ + if (!strcmp(p,"qemu.sstepbits")) { + /* Query Breakpoint bit definitions */ + snprintf(buf, sizeof(buf), "ENABLE=%x,NOIRQ=%x,NOTIMER=%x", + SSTEP_ENABLE, + SSTEP_NOIRQ, + SSTEP_NOTIMER); + put_packet(s, buf); + break; + } else if (strncmp(p,"qemu.sstep",10) == 0) { + /* Display or change the sstep_flags */ + p += 10; + if (*p != '=') { + /* Display current setting */ + snprintf(buf, sizeof(buf), "0x%x", sstep_flags); + put_packet(s, buf); + break; + } + p++; + type = strtoul(p, (char **)&p, 16); + sstep_flags = type; + put_packet(s, "OK"); + break; + } +#ifdef CONFIG_LINUX_USER + else if (strncmp(p, "Offsets", 7) == 0) { TaskState *ts = env->opaque; - sprintf(buf, - "Text=" TARGET_ABI_FMT_lx ";Data=" TARGET_ABI_FMT_lx - ";Bss=" TARGET_ABI_FMT_lx, - ts->info->code_offset, - ts->info->data_offset, - ts->info->data_offset); + snprintf(buf, sizeof(buf), + "Text=" TARGET_ABI_FMT_lx ";Data=" TARGET_ABI_FMT_lx + ";Bss=" TARGET_ABI_FMT_lx, + ts->info->code_offset, + ts->info->data_offset, + ts->info->data_offset); put_packet(s, buf); break; } - /* Fall through. */ #endif + if (strncmp(p, "Supported", 9) == 0) { + snprintf(buf, sizeof(buf), "PacketSize=%x", MAX_PACKET_LENGTH); +#ifdef GDB_CORE_XML + strcat(buf, ";qXfer:features:read+"); +#endif + put_packet(s, buf); + break; + } +#ifdef GDB_CORE_XML + if (strncmp(p, "Xfer:features:read:", 19) == 0) { + const char *xml; + target_ulong total_len; + + gdb_has_xml = 1; + p += 19; + xml = get_feature_xml(env, p, &p); + if (!xml) { + snprintf(buf, sizeof(buf), "E00"); + put_packet(s, buf); + break; + } + + if (*p == ':') + p++; + addr = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + len = strtoul(p, (char **)&p, 16); + + total_len = strlen(xml); + if (addr > total_len) { + snprintf(buf, sizeof(buf), "E00"); + put_packet(s, buf); + break; + } + if (len > (MAX_PACKET_LENGTH - 5) / 2) + len = (MAX_PACKET_LENGTH - 5) / 2; + if (len < total_len - addr) { + buf[0] = 'm'; + len = memtox(buf + 1, xml + addr, len); + } else { + buf[0] = 'l'; + len = memtox(buf + 1, xml + addr, total_len - addr); + } + put_packet_binary(s, buf, len + 1); + break; + } +#endif + /* Unrecognised 'q' command. */ + goto unknown_command; + default: - // unknown_command: + unknown_command: /* put empty packet */ buf[0] = '\0'; put_packet(s, buf); @@ -1116,7 +1527,7 @@ %x - target_ulong argument printed in hex. %lx - 64-bit argument printed in hex. %s - string pointer (target_ulong) and length (int) pair. */ -void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...) +void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...) { va_list va; char buf[256]; @@ -1143,17 +1554,18 @@ switch (*fmt++) { case 'x': addr = va_arg(va, target_ulong); - p += sprintf(p, TARGET_FMT_lx, addr); + p += snprintf(p, &buf[sizeof(buf)] - p, TARGET_FMT_lx, addr); break; case 'l': if (*(fmt++) != 'x') goto bad_format; i64 = va_arg(va, uint64_t); - p += sprintf(p, "%" PRIx64, i64); + p += snprintf(p, &buf[sizeof(buf)] - p, "%" PRIx64, i64); break; case 's': addr = va_arg(va, target_ulong); - p += sprintf(p, TARGET_FMT_lx "/%x", addr, va_arg(va, int)); + p += snprintf(p, &buf[sizeof(buf)] - p, TARGET_FMT_lx "/%x", + addr, va_arg(va, int)); break; default: bad_format: @@ -1260,10 +1672,9 @@ char buf[256]; int n; - if (gdbserver_fd < 0) - return sig; - s = &gdbserver_state; + if (gdbserver_fd < 0 || s->fd < 0) + return sig; /* disable single step if it was enabled */ cpu_single_step(env, 0); @@ -1274,6 +1685,10 @@ snprintf(buf, sizeof(buf), "S%02x", sig); put_packet(s, buf); } + /* put_packet() might have detected that the peer terminated the + connection. */ + if (s->fd < 0) + return sig; sig = 0; s->state = RS_IDLE; @@ -1294,6 +1709,8 @@ return sig; } } + sig = s->signal; + s->signal = 0; return sig; } @@ -1303,10 +1720,9 @@ GDBState *s; char buf[4]; - if (gdbserver_fd < 0) - return; - s = &gdbserver_state; + if (gdbserver_fd < 0 || s->fd < 0) + return; snprintf(buf, sizeof(buf), "W%02x", code); put_packet(s, buf); @@ -1339,6 +1755,7 @@ memset (s, 0, sizeof (GDBState)); s->env = first_cpu; /* XXX: allow to change CPU */ s->fd = fd; + gdb_has_xml = 0; gdb_syscall_state = s; @@ -1388,7 +1805,9 @@ #else static int gdb_chr_can_receive(void *opaque) { - return 1; + /* We can handle an arbitrarily large amount of data. + Pick the maximum packet size, which is as good as anything. */ + return MAX_PACKET_LENGTH; } static void gdb_chr_receive(void *opaque, const uint8_t *buf, int size) @@ -1407,6 +1826,7 @@ case CHR_EVENT_RESET: vm_stop(EXCP_INTERRUPT); gdb_syscall_state = opaque; + gdb_has_xml = 0; break; default: break; @@ -1432,7 +1852,7 @@ port = gdbstub_port_name; } - chr = qemu_chr_open(port); + chr = qemu_chr_open("gdb", port); if (!chr) return -1; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/gdbstub.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/gdbstub.h --- qemu-0.9.1/gdbstub.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/gdbstub.h 2008-10-11 18:55:29.000000000 +0100 @@ -6,7 +6,7 @@ typedef void (*gdb_syscall_complete_cb)(CPUState *env, target_ulong ret, target_ulong err); -void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...); +void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...); int use_gdb_syscalls(void); #ifdef CONFIG_USER_ONLY int gdb_handlesig (CPUState *, int); @@ -15,5 +15,10 @@ #else int gdbserver_start(const char *port); #endif +/* Get or set a register. Returns the size of the register. */ +typedef int (*gdb_reg_cb)(CPUState *env, uint8_t *buf, int reg); +void gdb_register_coprocessor(CPUState *env, + gdb_reg_cb get_reg, gdb_reg_cb set_reg, + int num_regs, const char *xml, int g_pos); #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/gdb-xml/arm-core.xml /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/gdb-xml/arm-core.xml --- qemu-0.9.1/gdb-xml/arm-core.xml 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/gdb-xml/arm-core.xml 2008-10-11 18:55:29.000000000 +0100 @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/gdb-xml/arm-neon.xml /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/gdb-xml/arm-neon.xml --- qemu-0.9.1/gdb-xml/arm-neon.xml 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/gdb-xml/arm-neon.xml 2008-10-11 18:55:29.000000000 +0100 @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/gdb-xml/arm-vfp3.xml /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/gdb-xml/arm-vfp3.xml --- qemu-0.9.1/gdb-xml/arm-vfp3.xml 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/gdb-xml/arm-vfp3.xml 2008-10-11 18:55:29.000000000 +0100 @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/gdb-xml/arm-vfp.xml /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/gdb-xml/arm-vfp.xml --- qemu-0.9.1/gdb-xml/arm-vfp.xml 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/gdb-xml/arm-vfp.xml 2008-10-11 18:55:29.000000000 +0100 @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/gdb-xml/cf-core.xml /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/gdb-xml/cf-core.xml --- qemu-0.9.1/gdb-xml/cf-core.xml 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/gdb-xml/cf-core.xml 2008-10-11 18:55:29.000000000 +0100 @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/gdb-xml/cf-fp.xml /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/gdb-xml/cf-fp.xml --- qemu-0.9.1/gdb-xml/cf-fp.xml 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/gdb-xml/cf-fp.xml 2008-10-11 18:55:29.000000000 +0100 @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + , + + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/gen-icount.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/gen-icount.h --- qemu-0.9.1/gen-icount.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/gen-icount.h 2008-06-30 18:22:19.000000000 +0100 @@ -0,0 +1,56 @@ +/* Helpers for instruction counting code generation. */ + +static TCGArg *icount_arg; +static int icount_label; + +static inline void gen_icount_start(void) +{ + TCGv count; + + if (!use_icount) + return; + + icount_label = gen_new_label(); + /* FIXME: This generates lousy code. We can't use tcg_new_temp because + count needs to live over the conditional branch. To workaround this + we allow the target to supply a convenient register temporary. */ +#ifndef ICOUNT_TEMP + count = tcg_temp_local_new(TCG_TYPE_I32); +#else + count = ICOUNT_TEMP; +#endif + tcg_gen_ld_i32(count, cpu_env, offsetof(CPUState, icount_decr.u32)); + /* This is a horrid hack to allow fixing up the value later. */ + icount_arg = gen_opparam_ptr + 1; + tcg_gen_subi_i32(count, count, 0xdeadbeef); + + tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, icount_label); + tcg_gen_st16_i32(count, cpu_env, offsetof(CPUState, icount_decr.u16.low)); +#ifndef ICOUNT_TEMP + tcg_temp_free(count); +#endif +} + +static void gen_icount_end(TranslationBlock *tb, int num_insns) +{ + if (use_icount) { + *icount_arg = num_insns; + gen_set_label(icount_label); + tcg_gen_exit_tb((long)tb + 2); + } +} + +static void inline gen_io_start(void) +{ + TCGv tmp = tcg_const_i32(1); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, can_do_io)); + tcg_temp_free(tmp); +} + +static inline void gen_io_end(void) +{ + TCGv tmp = tcg_const_i32(0); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, can_do_io)); + tcg_temp_free(tmp); +} + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/.gitignore /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/.gitignore --- qemu-0.9.1/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/.gitignore 2008-09-09 18:15:28.000000000 +0100 @@ -0,0 +1,33 @@ +config-host.* +dyngen +dyngen.dSYM +i386 +*-softmmu +*-darwin-user +*-linux-user +qemu-doc.html +qemu-tech.html +qemu-doc.info +qemu-tech.info +qemu.1 +qemu.pod +qemu-img.1 +qemu-img.pod +qemu-img +qemu-nbd +qemu-nbd.8 +.gdbinit +*.a +*.aux +*.cp +*.dvi +*.exe +*.fn +*.ky +*.log +*.pg +*.toc +*.tp +*.vr +*.d + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/host-utils.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/host-utils.h --- qemu-0.9.1/host-utils.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/host-utils.h 2008-10-12 17:15:04.000000000 +0100 @@ -23,6 +23,8 @@ * THE SOFTWARE. */ +#include "osdep.h" + #if defined(__x86_64__) #define __HAVE_FAST_MULU64__ static always_inline void mulu64 (uint64_t *plow, uint64_t *phigh, @@ -45,14 +47,16 @@ void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b); #endif -/* Note that some of those functions may end up calling libgcc functions, - depending on the host machine. It is up to the target emulation to - cope with that. */ - /* Binary search for leading zeros. */ static always_inline int clz32(uint32_t val) { +#if QEMU_GNUC_PREREQ(3, 4) + if (val) + return __builtin_clz(val); + else + return 32; +#else int cnt = 0; if (!(val & 0xFFFF0000U)) { @@ -79,6 +83,7 @@ cnt++; } return cnt; +#endif } static always_inline int clo32(uint32_t val) @@ -88,6 +93,12 @@ static always_inline int clz64(uint64_t val) { +#if QEMU_GNUC_PREREQ(3, 4) + if (val) + return __builtin_clzll(val); + else + return 64; +#else int cnt = 0; if (!(val >> 32)) { @@ -97,6 +108,7 @@ } return cnt + clz32(val); +#endif } static always_inline int clo64(uint64_t val) @@ -106,6 +118,12 @@ static always_inline int ctz32 (uint32_t val) { +#if QEMU_GNUC_PREREQ(3, 4) + if (val) + return __builtin_ctz(val); + else + return 32; +#else int cnt; cnt = 0; @@ -134,6 +152,7 @@ } return cnt; +#endif } static always_inline int cto32 (uint32_t val) @@ -143,6 +162,12 @@ static always_inline int ctz64 (uint64_t val) { +#if QEMU_GNUC_PREREQ(3, 4) + if (val) + return __builtin_ctz(val); + else + return 64; +#else int cnt; cnt = 0; @@ -152,6 +177,7 @@ } return cnt + ctz32(val); +#endif } static always_inline int cto64 (uint64_t val) @@ -180,6 +206,9 @@ static always_inline int ctpop32 (uint32_t val) { +#if QEMU_GNUC_PREREQ(3, 4) + return __builtin_popcount(val); +#else val = (val & 0x55555555) + ((val >> 1) & 0x55555555); val = (val & 0x33333333) + ((val >> 2) & 0x33333333); val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f); @@ -187,10 +216,14 @@ val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff); return val; +#endif } static always_inline int ctpop64 (uint64_t val) { +#if QEMU_GNUC_PREREQ(3, 4) + return __builtin_popcountll(val); +#else val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL); val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL); val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & 0x0f0f0f0f0f0f0f0fULL); @@ -199,4 +232,5 @@ val = (val & 0x00000000ffffffffULL) + ((val >> 32) & 0x00000000ffffffffULL); return val; +#endif } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hppa-dis.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hppa-dis.c --- qemu-0.9.1/hppa-dis.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hppa-dis.c 2008-04-12 21:14:54.000000000 +0100 @@ -0,0 +1,2834 @@ +/* Disassembler for the PA-RISC. Somewhat derived from sparc-pinsn.c. + Copyright 1989, 1990, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2003, + 2005 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "dis-asm.h" + +/* HP PA-RISC SOM object file format: definitions internal to BFD. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, + 2003 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _LIBHPPA_H +#define _LIBHPPA_H + +#define BYTES_IN_WORD 4 +#define PA_PAGESIZE 0x1000 + +/* The PA instruction set variants. */ +enum pa_arch {pa10 = 10, pa11 = 11, pa20 = 20, pa20w = 25}; + +/* HP PA-RISC relocation types */ + +enum hppa_reloc_field_selector_type + { + R_HPPA_FSEL = 0x0, + R_HPPA_LSSEL = 0x1, + R_HPPA_RSSEL = 0x2, + R_HPPA_LSEL = 0x3, + R_HPPA_RSEL = 0x4, + R_HPPA_LDSEL = 0x5, + R_HPPA_RDSEL = 0x6, + R_HPPA_LRSEL = 0x7, + R_HPPA_RRSEL = 0x8, + R_HPPA_NSEL = 0x9, + R_HPPA_NLSEL = 0xa, + R_HPPA_NLRSEL = 0xb, + R_HPPA_PSEL = 0xc, + R_HPPA_LPSEL = 0xd, + R_HPPA_RPSEL = 0xe, + R_HPPA_TSEL = 0xf, + R_HPPA_LTSEL = 0x10, + R_HPPA_RTSEL = 0x11, + R_HPPA_LTPSEL = 0x12, + R_HPPA_RTPSEL = 0x13 + }; + +/* /usr/include/reloc.h defines these to constants. We want to use + them in enums, so #undef them before we start using them. We might + be able to fix this another way by simply managing not to include + /usr/include/reloc.h, but currently GDB picks up these defines + somewhere. */ +#undef e_fsel +#undef e_lssel +#undef e_rssel +#undef e_lsel +#undef e_rsel +#undef e_ldsel +#undef e_rdsel +#undef e_lrsel +#undef e_rrsel +#undef e_nsel +#undef e_nlsel +#undef e_nlrsel +#undef e_psel +#undef e_lpsel +#undef e_rpsel +#undef e_tsel +#undef e_ltsel +#undef e_rtsel +#undef e_one +#undef e_two +#undef e_pcrel +#undef e_con +#undef e_plabel +#undef e_abs + +/* for compatibility */ +enum hppa_reloc_field_selector_type_alt + { + e_fsel = R_HPPA_FSEL, + e_lssel = R_HPPA_LSSEL, + e_rssel = R_HPPA_RSSEL, + e_lsel = R_HPPA_LSEL, + e_rsel = R_HPPA_RSEL, + e_ldsel = R_HPPA_LDSEL, + e_rdsel = R_HPPA_RDSEL, + e_lrsel = R_HPPA_LRSEL, + e_rrsel = R_HPPA_RRSEL, + e_nsel = R_HPPA_NSEL, + e_nlsel = R_HPPA_NLSEL, + e_nlrsel = R_HPPA_NLRSEL, + e_psel = R_HPPA_PSEL, + e_lpsel = R_HPPA_LPSEL, + e_rpsel = R_HPPA_RPSEL, + e_tsel = R_HPPA_TSEL, + e_ltsel = R_HPPA_LTSEL, + e_rtsel = R_HPPA_RTSEL, + e_ltpsel = R_HPPA_LTPSEL, + e_rtpsel = R_HPPA_RTPSEL + }; + +enum hppa_reloc_expr_type + { + R_HPPA_E_ONE = 0, + R_HPPA_E_TWO = 1, + R_HPPA_E_PCREL = 2, + R_HPPA_E_CON = 3, + R_HPPA_E_PLABEL = 7, + R_HPPA_E_ABS = 18 + }; + +/* for compatibility */ +enum hppa_reloc_expr_type_alt + { + e_one = R_HPPA_E_ONE, + e_two = R_HPPA_E_TWO, + e_pcrel = R_HPPA_E_PCREL, + e_con = R_HPPA_E_CON, + e_plabel = R_HPPA_E_PLABEL, + e_abs = R_HPPA_E_ABS + }; + + +/* Relocations for function calls must be accompanied by parameter + relocation bits. These bits describe exactly where the caller has + placed the function's arguments and where it expects to find a return + value. + + Both ELF and SOM encode this information within the addend field + of the call relocation. (Note this could break very badly if one + was to make a call like bl foo + 0x12345678). + + The high order 10 bits contain parameter relocation information, + the low order 22 bits contain the constant offset. */ + +#define HPPA_R_ARG_RELOC(a) \ + (((a) >> 22) & 0x3ff) +#define HPPA_R_CONSTANT(a) \ + ((((bfd_signed_vma)(a)) << (BFD_ARCH_SIZE-22)) >> (BFD_ARCH_SIZE-22)) +#define HPPA_R_ADDEND(r, c) \ + (((r) << 22) + ((c) & 0x3fffff)) + + +/* Some functions to manipulate PA instructions. */ + +/* Declare the functions with the unused attribute to avoid warnings. */ +static inline int sign_extend (int, int) ATTRIBUTE_UNUSED; +static inline int low_sign_extend (int, int) ATTRIBUTE_UNUSED; +static inline int sign_unext (int, int) ATTRIBUTE_UNUSED; +static inline int low_sign_unext (int, int) ATTRIBUTE_UNUSED; +static inline int re_assemble_3 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_12 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_14 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_16 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_17 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_21 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_22 (int) ATTRIBUTE_UNUSED; +static inline bfd_signed_vma hppa_field_adjust + (bfd_vma, bfd_signed_vma, enum hppa_reloc_field_selector_type_alt) + ATTRIBUTE_UNUSED; +static inline int hppa_rebuild_insn (int, int, int) ATTRIBUTE_UNUSED; + + +/* The *sign_extend functions are used to assemble various bitfields + taken from an instruction and return the resulting immediate + value. */ + +static inline int +sign_extend (int x, int len) +{ + int signbit = (1 << (len - 1)); + int mask = (signbit << 1) - 1; + return ((x & mask) ^ signbit) - signbit; +} + +static inline int +low_sign_extend (int x, int len) +{ + return (x >> 1) - ((x & 1) << (len - 1)); +} + + +/* The re_assemble_* functions prepare an immediate value for + insertion into an opcode. pa-risc uses all sorts of weird bitfields + in the instruction to hold the value. */ + +static inline int +sign_unext (int x, int len) +{ + int len_ones; + + len_ones = (1 << len) - 1; + + return x & len_ones; +} + +static inline int +low_sign_unext (int x, int len) +{ + int temp; + int sign; + + sign = (x >> (len-1)) & 1; + + temp = sign_unext (x, len-1); + + return (temp << 1) | sign; +} + +static inline int +re_assemble_3 (int as3) +{ + return (( (as3 & 4) << (13-2)) + | ((as3 & 3) << (13+1))); +} + +static inline int +re_assemble_12 (int as12) +{ + return (( (as12 & 0x800) >> 11) + | ((as12 & 0x400) >> (10 - 2)) + | ((as12 & 0x3ff) << (1 + 2))); +} + +static inline int +re_assemble_14 (int as14) +{ + return (( (as14 & 0x1fff) << 1) + | ((as14 & 0x2000) >> 13)); +} + +static inline int +re_assemble_16 (int as16) +{ + int s, t; + + /* Unusual 16-bit encoding, for wide mode only. */ + t = (as16 << 1) & 0xffff; + s = (as16 & 0x8000); + return (t ^ s ^ (s >> 1)) | (s >> 15); +} + +static inline int +re_assemble_17 (int as17) +{ + return (( (as17 & 0x10000) >> 16) + | ((as17 & 0x0f800) << (16 - 11)) + | ((as17 & 0x00400) >> (10 - 2)) + | ((as17 & 0x003ff) << (1 + 2))); +} + +static inline int +re_assemble_21 (int as21) +{ + return (( (as21 & 0x100000) >> 20) + | ((as21 & 0x0ffe00) >> 8) + | ((as21 & 0x000180) << 7) + | ((as21 & 0x00007c) << 14) + | ((as21 & 0x000003) << 12)); +} + +static inline int +re_assemble_22 (int as22) +{ + return (( (as22 & 0x200000) >> 21) + | ((as22 & 0x1f0000) << (21 - 16)) + | ((as22 & 0x00f800) << (16 - 11)) + | ((as22 & 0x000400) >> (10 - 2)) + | ((as22 & 0x0003ff) << (1 + 2))); +} + + +/* Handle field selectors for PA instructions. + The L and R (and LS, RS etc.) selectors are used in pairs to form a + full 32 bit address. eg. + + LDIL L'start,%r1 ; put left part into r1 + LDW R'start(%r1),%r2 ; add r1 and right part to form address + + This function returns sign extended values in all cases. +*/ + +static inline bfd_signed_vma +hppa_field_adjust (bfd_vma sym_val, + bfd_signed_vma addend, + enum hppa_reloc_field_selector_type_alt r_field) +{ + bfd_signed_vma value; + + value = sym_val + addend; + switch (r_field) + { + case e_fsel: + /* F: No change. */ + break; + + case e_nsel: + /* N: null selector. I don't really understand what this is all + about, but HP's documentation says "this indicates that zero + bits are to be used for the displacement on the instruction. + This fixup is used to identify three-instruction sequences to + access data (for importing shared library data)." */ + value = 0; + break; + + case e_lsel: + case e_nlsel: + /* L: Select top 21 bits. */ + value = value >> 11; + break; + + case e_rsel: + /* R: Select bottom 11 bits. */ + value = value & 0x7ff; + break; + + case e_lssel: + /* LS: Round to nearest multiple of 2048 then select top 21 bits. */ + value = value + 0x400; + value = value >> 11; + break; + + case e_rssel: + /* RS: Select bottom 11 bits for LS. + We need to return a value such that 2048 * LS'x + RS'x == x. + ie. RS'x = x - ((x + 0x400) & -0x800) + this is just a sign extension from bit 21. */ + value = ((value & 0x7ff) ^ 0x400) - 0x400; + break; + + case e_ldsel: + /* LD: Round to next multiple of 2048 then select top 21 bits. + Yes, if we are already on a multiple of 2048, we go up to the + next one. RD in this case will be -2048. */ + value = value + 0x800; + value = value >> 11; + break; + + case e_rdsel: + /* RD: Set bits 0-20 to one. */ + value = value | -0x800; + break; + + case e_lrsel: + case e_nlrsel: + /* LR: L with rounding of the addend to nearest 8k. */ + value = sym_val + ((addend + 0x1000) & -0x2000); + value = value >> 11; + break; + + case e_rrsel: + /* RR: R with rounding of the addend to nearest 8k. + We need to return a value such that 2048 * LR'x + RR'x == x + ie. RR'x = s+a - (s + (((a + 0x1000) & -0x2000) & -0x800)) + . = s+a - ((s & -0x800) + ((a + 0x1000) & -0x2000)) + . = (s & 0x7ff) + a - ((a + 0x1000) & -0x2000) */ + value = (sym_val & 0x7ff) + (((addend & 0x1fff) ^ 0x1000) - 0x1000); + break; + + default: + abort (); + } + return value; +} + +/* PA-RISC OPCODES */ +#define get_opcode(insn) (((insn) >> 26) & 0x3f) + +enum hppa_opcode_type +{ + /* None of the opcodes in the first group generate relocs, so we + aren't too concerned about them. */ + OP_SYSOP = 0x00, + OP_MEMMNG = 0x01, + OP_ALU = 0x02, + OP_NDXMEM = 0x03, + OP_SPOP = 0x04, + OP_DIAG = 0x05, + OP_FMPYADD = 0x06, + OP_UNDEF07 = 0x07, + OP_COPRW = 0x09, + OP_COPRDW = 0x0b, + OP_COPR = 0x0c, + OP_FLOAT = 0x0e, + OP_PRDSPEC = 0x0f, + OP_UNDEF15 = 0x15, + OP_UNDEF1d = 0x1d, + OP_FMPYSUB = 0x26, + OP_FPFUSED = 0x2e, + OP_SHEXDP0 = 0x34, + OP_SHEXDP1 = 0x35, + OP_SHEXDP2 = 0x36, + OP_UNDEF37 = 0x37, + OP_SHEXDP3 = 0x3c, + OP_SHEXDP4 = 0x3d, + OP_MULTMED = 0x3e, + OP_UNDEF3f = 0x3f, + + OP_LDIL = 0x08, + OP_ADDIL = 0x0a, + + OP_LDO = 0x0d, + OP_LDB = 0x10, + OP_LDH = 0x11, + OP_LDW = 0x12, + OP_LDWM = 0x13, + OP_STB = 0x18, + OP_STH = 0x19, + OP_STW = 0x1a, + OP_STWM = 0x1b, + + OP_LDD = 0x14, + OP_STD = 0x1c, + + OP_FLDW = 0x16, + OP_LDWL = 0x17, + OP_FSTW = 0x1e, + OP_STWL = 0x1f, + + OP_COMBT = 0x20, + OP_COMIBT = 0x21, + OP_COMBF = 0x22, + OP_COMIBF = 0x23, + OP_CMPBDT = 0x27, + OP_ADDBT = 0x28, + OP_ADDIBT = 0x29, + OP_ADDBF = 0x2a, + OP_ADDIBF = 0x2b, + OP_CMPBDF = 0x2f, + OP_BVB = 0x30, + OP_BB = 0x31, + OP_MOVB = 0x32, + OP_MOVIB = 0x33, + OP_CMPIBD = 0x3b, + + OP_COMICLR = 0x24, + OP_SUBI = 0x25, + OP_ADDIT = 0x2c, + OP_ADDI = 0x2d, + + OP_BE = 0x38, + OP_BLE = 0x39, + OP_BL = 0x3a +}; + + +/* Insert VALUE into INSN using R_FORMAT to determine exactly what + bits to change. */ + +static inline int +hppa_rebuild_insn (int insn, int value, int r_format) +{ + switch (r_format) + { + case 11: + return (insn & ~ 0x7ff) | low_sign_unext (value, 11); + + case 12: + return (insn & ~ 0x1ffd) | re_assemble_12 (value); + + + case 10: + return (insn & ~ 0x3ff1) | re_assemble_14 (value & -8); + + case -11: + return (insn & ~ 0x3ff9) | re_assemble_14 (value & -4); + + case 14: + return (insn & ~ 0x3fff) | re_assemble_14 (value); + + + case -10: + return (insn & ~ 0xfff1) | re_assemble_16 (value & -8); + + case -16: + return (insn & ~ 0xfff9) | re_assemble_16 (value & -4); + + case 16: + return (insn & ~ 0xffff) | re_assemble_16 (value); + + + case 17: + return (insn & ~ 0x1f1ffd) | re_assemble_17 (value); + + case 21: + return (insn & ~ 0x1fffff) | re_assemble_21 (value); + + case 22: + return (insn & ~ 0x3ff1ffd) | re_assemble_22 (value); + + case 32: + return value; + + default: + abort (); + } + return insn; +} + +#endif /* _LIBHPPA_H */ +/* Table of opcodes for the PA-RISC. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, + 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + +This file is part of GAS, the GNU Assembler, and GDB, the GNU disassembler. + +GAS/GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS/GDB 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS or GDB; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#if !defined(__STDC__) && !defined(const) +#define const +#endif + +/* + * Structure of an opcode table entry. + */ + +/* There are two kinds of delay slot nullification: normal which is + * controled by the nullification bit, and conditional, which depends + * on the direction of the branch and its success or failure. + * + * NONE is unfortunately #defined in the hiux system include files. + * #undef it away. + */ +#undef NONE +struct pa_opcode +{ + const char *name; + unsigned long int match; /* Bits that must be set... */ + unsigned long int mask; /* ... in these bits. */ + char *args; + enum pa_arch arch; + char flags; +}; + +/* Enables strict matching. Opcodes with match errors are skipped + when this bit is set. */ +#define FLAG_STRICT 0x1 + +/* + All hppa opcodes are 32 bits. + + The match component is a mask saying which bits must match a + particular opcode in order for an instruction to be an instance + of that opcode. + + The args component is a string containing one character for each operand of + the instruction. Characters used as a prefix allow any second character to + be used without conflicting with the main operand characters. + + Bit positions in this description follow HP usage of lsb = 31, + "at" is lsb of field. + + In the args field, the following characters must match exactly: + + '+,() ' + + In the args field, the following characters are unused: + + ' " - / 34 6789:; ' + '@ C M [\] ' + '` e g } ' + + Here are all the characters: + + ' !"#$%&'()*+-,./0123456789:;<=>?' + '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_' + '`abcdefghijklmnopqrstuvwxyz{|}~ ' + +Kinds of operands: + x integer register field at 15. + b integer register field at 10. + t integer register field at 31. + a integer register field at 10 and 15 (for PERMH) + 5 5 bit immediate at 15. + s 2 bit space specifier at 17. + S 3 bit space specifier at 18. + V 5 bit immediate value at 31 + i 11 bit immediate value at 31 + j 14 bit immediate value at 31 + k 21 bit immediate value at 31 + l 16 bit immediate value at 31 (wide mode only, unusual encoding). + n nullification for branch instructions + N nullification for spop and copr instructions + w 12 bit branch displacement + W 17 bit branch displacement (PC relative) + X 22 bit branch displacement (PC relative) + z 17 bit branch displacement (just a number, not an address) + +Also these: + + . 2 bit shift amount at 25 + * 4 bit shift amount at 25 + p 5 bit shift count at 26 (to support the SHD instruction) encoded as + 31-p + ~ 6 bit shift count at 20,22:26 encoded as 63-~. + P 5 bit bit position at 26 + q 6 bit bit position at 20,22:26 + T 5 bit field length at 31 (encoded as 32-T) + % 6 bit field length at 23,27:31 (variable extract/deposit) + | 6 bit field length at 19,27:31 (fixed extract/deposit) + A 13 bit immediate at 18 (to support the BREAK instruction) + ^ like b, but describes a control register + ! sar (cr11) register + D 26 bit immediate at 31 (to support the DIAG instruction) + $ 9 bit immediate at 28 (to support POPBTS) + + v 3 bit Special Function Unit identifier at 25 + O 20 bit Special Function Unit operation split between 15 bits at 20 + and 5 bits at 31 + o 15 bit Special Function Unit operation at 20 + 2 22 bit Special Function Unit operation split between 17 bits at 20 + and 5 bits at 31 + 1 15 bit Special Function Unit operation split between 10 bits at 20 + and 5 bits at 31 + 0 10 bit Special Function Unit operation split between 5 bits at 20 + and 5 bits at 31 + u 3 bit coprocessor unit identifier at 25 + F Source Floating Point Operand Format Completer encoded 2 bits at 20 + I Source Floating Point Operand Format Completer encoded 1 bits at 20 + (for 0xe format FP instructions) + G Destination Floating Point Operand Format Completer encoded 2 bits at 18 + H Floating Point Operand Format at 26 for 'fmpyadd' and 'fmpysub' + (very similar to 'F') + + r 5 bit immediate value at 31 (for the break instruction) + (very similar to V above, except the value is unsigned instead of + low_sign_ext) + R 5 bit immediate value at 15 (for the ssm, rsm, probei instructions) + (same as r above, except the value is in a different location) + U 10 bit immediate value at 15 (for SSM, RSM on pa2.0) + Q 5 bit immediate value at 10 (a bit position specified in + the bb instruction. It's the same as r above, except the + value is in a different location) + B 5 bit immediate value at 10 (a bit position specified in + the bb instruction. Similar to Q, but 64 bit handling is + different. + Z %r1 -- implicit target of addil instruction. + L ,%r2 completer for new syntax branch + { Source format completer for fcnv + _ Destination format completer for fcnv + h cbit for fcmp + = gfx tests for ftest + d 14 bit offset for single precision FP long load/store. + # 14 bit offset for double precision FP load long/store. + J Yet another 14 bit offset for load/store with ma,mb completers. + K Yet another 14 bit offset for load/store with ma,mb completers. + y 16 bit offset for word aligned load/store (PA2.0 wide). + & 16 bit offset for dword aligned load/store (PA2.0 wide). + < 16 bit offset for load/store with ma,mb completers (PA2.0 wide). + > 16 bit offset for load/store with ma,mb completers (PA2.0 wide). + Y %sr0,%r31 -- implicit target of be,l instruction. + @ implicit immediate value of 0 + +Completer operands all have 'c' as the prefix: + + cx indexed load and store completer. + cX indexed load and store completer. Like cx, but emits a space + after in disassembler. + cm short load and store completer. + cM short load and store completer. Like cm, but emits a space + after in disassembler. + cq long load and store completer (like cm, but inserted into a + different location in the target instruction). + cs store bytes short completer. + cA store bytes short completer. Like cs, but emits a space + after in disassembler. + ce long load/store completer for LDW/STW with a different encoding + than the others + cc load cache control hint + cd load and clear cache control hint + cC store cache control hint + co ordered access + + cp branch link and push completer + cP branch pop completer + cl branch link completer + cg branch gate completer + + cw read/write completer for PROBE + cW wide completer for MFCTL + cL local processor completer for cache control + cZ System Control Completer (to support LPA, LHA, etc.) + + ci correction completer for DCOR + ca add completer + cy 32 bit add carry completer + cY 64 bit add carry completer + cv signed overflow trap completer + ct trap on condition completer for ADDI, SUB + cT trap on condition completer for UADDCM + cb 32 bit borrow completer for SUB + cB 64 bit borrow completer for SUB + + ch left/right half completer + cH signed/unsigned saturation completer + cS signed/unsigned completer at 21 + cz zero/sign extension completer. + c* permutation completer + +Condition operands all have '?' as the prefix: + + ?f Floating point compare conditions (encoded as 5 bits at 31) + + ?a add conditions + ?A 64 bit add conditions + ?@ add branch conditions followed by nullify + ?d non-negated add branch conditions + ?D negated add branch conditions + ?w wide mode non-negated add branch conditions + ?W wide mode negated add branch conditions + + ?s compare/subtract conditions + ?S 64 bit compare/subtract conditions + ?t non-negated compare and branch conditions + ?n 32 bit compare and branch conditions followed by nullify + ?N 64 bit compare and branch conditions followed by nullify + ?Q 64 bit compare and branch conditions for CMPIB instruction + + ?l logical conditions + ?L 64 bit logical conditions + + ?b branch on bit conditions + ?B 64 bit branch on bit conditions + + ?x shift/extract/deposit conditions + ?X 64 bit shift/extract/deposit conditions + ?y shift/extract/deposit conditions followed by nullify for conditional + branches + + ?u unit conditions + ?U 64 bit unit conditions + +Floating point registers all have 'f' as a prefix: + + ft target register at 31 + fT target register with L/R halves at 31 + fa operand 1 register at 10 + fA operand 1 register with L/R halves at 10 + fX Same as fA, except prints a space before register during disasm + fb operand 2 register at 15 + fB operand 2 register with L/R halves at 15 + fC operand 3 register with L/R halves at 16:18,21:23 + fe Like fT, but encoding is different. + fE Same as fe, except prints a space before register during disasm. + fx target register at 15 (only for PA 2.0 long format FLDD/FSTD). + +Float registers for fmpyadd and fmpysub: + + fi mult operand 1 register at 10 + fj mult operand 2 register at 15 + fk mult target register at 20 + fl add/sub operand register at 25 + fm add/sub target register at 31 + +*/ + + +#if 0 +/* List of characters not to put a space after. Note that + "," is included, as the "spopN" operations use literal + commas in their completer sections. */ +static const char *const completer_chars = ",CcY<>?!@+&U~FfGHINnOoZMadu|/=0123%e$m}"; +#endif + +/* The order of the opcodes in this table is significant: + + * The assembler requires that all instances of the same mnemonic be + consecutive. If they aren't, the assembler will bomb at runtime. + + * Immediate fields use pa_get_absolute_expression to parse the + string. It will generate a "bad expression" error if passed + a register name. Thus, register index variants of an opcode + need to precede immediate variants. + + * The disassembler does not care about the order of the opcodes + except in cases where implicit addressing is used. + + Here are the rules for ordering the opcodes of a mnemonic: + + 1) Opcodes with FLAG_STRICT should precede opcodes without + FLAG_STRICT. + + 2) Opcodes with FLAG_STRICT should be ordered as follows: + register index opcodes, short immediate opcodes, and finally + long immediate opcodes. When both pa10 and pa11 variants + of the same opcode are available, the pa10 opcode should + come first for correct architectural promotion. + + 3) When implicit addressing is available for an opcode, the + implicit opcode should precede the explicit opcode. + + 4) Opcodes without FLAG_STRICT should be ordered as follows: + register index opcodes, long immediate opcodes, and finally + short immediate opcodes. */ + +static const struct pa_opcode pa_opcodes[] = +{ + +/* Pseudo-instructions. */ + +{ "ldi", 0x34000000, 0xffe00000, "l,x", pa20w, 0},/* ldo val(r0),r */ +{ "ldi", 0x34000000, 0xffe0c000, "j,x", pa10, 0},/* ldo val(r0),r */ + +{ "cmpib", 0xec000000, 0xfc000000, "?Qn5,b,w", pa20, FLAG_STRICT}, +{ "cmpib", 0x84000000, 0xf4000000, "?nn5,b,w", pa10, FLAG_STRICT}, +{ "comib", 0x84000000, 0xfc000000, "?nn5,b,w", pa10, 0}, /* comib{tf}*/ +/* This entry is for the disassembler only. It will never be used by + assembler. */ +{ "comib", 0x8c000000, 0xfc000000, "?nn5,b,w", pa10, 0}, /* comib{tf}*/ +{ "cmpb", 0x9c000000, 0xdc000000, "?Nnx,b,w", pa20, FLAG_STRICT}, +{ "cmpb", 0x80000000, 0xf4000000, "?nnx,b,w", pa10, FLAG_STRICT}, +{ "comb", 0x80000000, 0xfc000000, "?nnx,b,w", pa10, 0}, /* comb{tf} */ +/* This entry is for the disassembler only. It will never be used by + assembler. */ +{ "comb", 0x88000000, 0xfc000000, "?nnx,b,w", pa10, 0}, /* comb{tf} */ +{ "addb", 0xa0000000, 0xf4000000, "?Wnx,b,w", pa20w, FLAG_STRICT}, +{ "addb", 0xa0000000, 0xfc000000, "?@nx,b,w", pa10, 0}, /* addb{tf} */ +/* This entry is for the disassembler only. It will never be used by + assembler. */ +{ "addb", 0xa8000000, 0xfc000000, "?@nx,b,w", pa10, 0}, +{ "addib", 0xa4000000, 0xf4000000, "?Wn5,b,w", pa20w, FLAG_STRICT}, +{ "addib", 0xa4000000, 0xfc000000, "?@n5,b,w", pa10, 0}, /* addib{tf}*/ +/* This entry is for the disassembler only. It will never be used by + assembler. */ +{ "addib", 0xac000000, 0xfc000000, "?@n5,b,w", pa10, 0}, /* addib{tf}*/ +{ "nop", 0x08000240, 0xffffffff, "", pa10, 0}, /* or 0,0,0 */ +{ "copy", 0x08000240, 0xffe0ffe0, "x,t", pa10, 0}, /* or r,0,t */ +{ "mtsar", 0x01601840, 0xffe0ffff, "x", pa10, 0}, /* mtctl r,cr11 */ + +/* Loads and Stores for integer registers. */ + +{ "ldd", 0x0c0000c0, 0xfc00d3c0, "cxccx(b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0000c0, 0xfc0013c0, "cxccx(s,b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0010e0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0010e0, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0010c0, 0xfc00d3c0, "cmcc5(b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0010c0, 0xfc0013c0, "cmcc5(s,b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x50000000, 0xfc000002, "cq&(b),x", pa20w, FLAG_STRICT}, +{ "ldd", 0x50000000, 0xfc00c002, "cq#(b),x", pa20, FLAG_STRICT}, +{ "ldd", 0x50000000, 0xfc000002, "cq#(s,b),x", pa20, FLAG_STRICT}, +{ "ldw", 0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldw", 0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldw", 0x0c000080, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldw", 0x0c000080, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldw", 0x0c0010a0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldw", 0x0c0010a0, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, +{ "ldw", 0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldw", 0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldw", 0x0c001080, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldw", 0x0c001080, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldw", 0x4c000000, 0xfc000000, "ce<(b),x", pa20w, FLAG_STRICT}, +{ "ldw", 0x5c000004, 0xfc000006, "ce>(b),x", pa20w, FLAG_STRICT}, +{ "ldw", 0x48000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT}, +{ "ldw", 0x5c000004, 0xfc00c006, "ceK(b),x", pa20, FLAG_STRICT}, +{ "ldw", 0x5c000004, 0xfc000006, "ceK(s,b),x", pa20, FLAG_STRICT}, +{ "ldw", 0x4c000000, 0xfc00c000, "ceJ(b),x", pa10, FLAG_STRICT}, +{ "ldw", 0x4c000000, 0xfc000000, "ceJ(s,b),x", pa10, FLAG_STRICT}, +{ "ldw", 0x48000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldw", 0x48000000, 0xfc000000, "j(s,b),x", pa10, 0}, +{ "ldh", 0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldh", 0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldh", 0x0c000040, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldh", 0x0c000040, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldh", 0x0c001060, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldh", 0x0c001060, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, +{ "ldh", 0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldh", 0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldh", 0x0c001040, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldh", 0x0c001040, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldh", 0x44000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT}, +{ "ldh", 0x44000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldh", 0x44000000, 0xfc000000, "j(s,b),x", pa10, 0}, +{ "ldb", 0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldb", 0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldb", 0x0c000000, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldb", 0x0c000000, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldb", 0x0c001020, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldb", 0x0c001020, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, +{ "ldb", 0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldb", 0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldb", 0x0c001000, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldb", 0x0c001000, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldb", 0x40000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT}, +{ "ldb", 0x40000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldb", 0x40000000, 0xfc000000, "j(s,b),x", pa10, 0}, +{ "std", 0x0c0012e0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "std", 0x0c0012e0, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, +{ "std", 0x0c0012c0, 0xfc00d3c0, "cmcCx,V(b)", pa20, FLAG_STRICT}, +{ "std", 0x0c0012c0, 0xfc0013c0, "cmcCx,V(s,b)", pa20, FLAG_STRICT}, +{ "std", 0x70000000, 0xfc000002, "cqx,&(b)", pa20w, FLAG_STRICT}, +{ "std", 0x70000000, 0xfc00c002, "cqx,#(b)", pa20, FLAG_STRICT}, +{ "std", 0x70000000, 0xfc000002, "cqx,#(s,b)", pa20, FLAG_STRICT}, +{ "stw", 0x0c0012a0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "stw", 0x0c0012a0, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, +{ "stw", 0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stw", 0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "stw", 0x0c001280, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stw", 0x0c001280, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "stw", 0x6c000000, 0xfc000000, "cex,<(b)", pa20w, FLAG_STRICT}, +{ "stw", 0x7c000004, 0xfc000006, "cex,>(b)", pa20w, FLAG_STRICT}, +{ "stw", 0x68000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT}, +{ "stw", 0x7c000004, 0xfc00c006, "cex,K(b)", pa20, FLAG_STRICT}, +{ "stw", 0x7c000004, 0xfc000006, "cex,K(s,b)", pa20, FLAG_STRICT}, +{ "stw", 0x6c000000, 0xfc00c000, "cex,J(b)", pa10, FLAG_STRICT}, +{ "stw", 0x6c000000, 0xfc000000, "cex,J(s,b)", pa10, FLAG_STRICT}, +{ "stw", 0x68000000, 0xfc00c000, "x,j(b)", pa10, 0}, +{ "stw", 0x68000000, 0xfc000000, "x,j(s,b)", pa10, 0}, +{ "sth", 0x0c001260, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "sth", 0x0c001260, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, +{ "sth", 0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "sth", 0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "sth", 0x0c001240, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "sth", 0x0c001240, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "sth", 0x64000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT}, +{ "sth", 0x64000000, 0xfc00c000, "x,j(b)", pa10, 0}, +{ "sth", 0x64000000, 0xfc000000, "x,j(s,b)", pa10, 0}, +{ "stb", 0x0c001220, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "stb", 0x0c001220, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, +{ "stb", 0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stb", 0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "stb", 0x0c001200, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stb", 0x0c001200, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "stb", 0x60000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT}, +{ "stb", 0x60000000, 0xfc00c000, "x,j(b)", pa10, 0}, +{ "stb", 0x60000000, 0xfc000000, "x,j(s,b)", pa10, 0}, +{ "ldwm", 0x4c000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldwm", 0x4c000000, 0xfc000000, "j(s,b),x", pa10, 0}, +{ "stwm", 0x6c000000, 0xfc00c000, "x,j(b)", pa10, 0}, +{ "stwm", 0x6c000000, 0xfc000000, "x,j(s,b)", pa10, 0}, +{ "ldwx", 0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldwx", 0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldwx", 0x0c000080, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldwx", 0x0c000080, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldwx", 0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, 0}, +{ "ldwx", 0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, +{ "ldhx", 0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldhx", 0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldhx", 0x0c000040, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldhx", 0x0c000040, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldhx", 0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, 0}, +{ "ldhx", 0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, +{ "ldbx", 0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldbx", 0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldbx", 0x0c000000, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldbx", 0x0c000000, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldbx", 0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, 0}, +{ "ldbx", 0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, +{ "ldwa", 0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldwa", 0x0c000180, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldwa", 0x0c0011a0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldwa", 0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldwa", 0x0c001180, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldcw", 0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldcw", 0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldcw", 0x0c0001c0, 0xfc00d3c0, "cxcdx(b),t", pa11, FLAG_STRICT}, +{ "ldcw", 0x0c0001c0, 0xfc0013c0, "cxcdx(s,b),t", pa11, FLAG_STRICT}, +{ "ldcw", 0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldcw", 0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldcw", 0x0c0011c0, 0xfc00d3c0, "cmcd5(b),t", pa11, FLAG_STRICT}, +{ "ldcw", 0x0c0011c0, 0xfc0013c0, "cmcd5(s,b),t", pa11, FLAG_STRICT}, +{ "stwa", 0x0c0013a0, 0xfc00d3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "stwa", 0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stwa", 0x0c001380, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stby", 0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, FLAG_STRICT}, +{ "stby", 0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, FLAG_STRICT}, +{ "stby", 0x0c001300, 0xfc00d3c0, "cscCx,V(b)", pa11, FLAG_STRICT}, +{ "stby", 0x0c001300, 0xfc0013c0, "cscCx,V(s,b)", pa11, FLAG_STRICT}, +{ "ldda", 0x0c000100, 0xfc00d3c0, "cxccx(b),t", pa20, FLAG_STRICT}, +{ "ldda", 0x0c001120, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldda", 0x0c001100, 0xfc00d3c0, "cmcc5(b),t", pa20, FLAG_STRICT}, +{ "ldcd", 0x0c000140, 0xfc00d3c0, "cxcdx(b),t", pa20, FLAG_STRICT}, +{ "ldcd", 0x0c000140, 0xfc0013c0, "cxcdx(s,b),t", pa20, FLAG_STRICT}, +{ "ldcd", 0x0c001140, 0xfc00d3c0, "cmcd5(b),t", pa20, FLAG_STRICT}, +{ "ldcd", 0x0c001140, 0xfc0013c0, "cmcd5(s,b),t", pa20, FLAG_STRICT}, +{ "stda", 0x0c0013e0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "stda", 0x0c0013c0, 0xfc00d3c0, "cmcCx,V(b)", pa20, FLAG_STRICT}, +{ "ldwax", 0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldwax", 0x0c000180, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldwax", 0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, 0}, +{ "ldcwx", 0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldcwx", 0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldcwx", 0x0c0001c0, 0xfc00d3c0, "cxcdx(b),t", pa11, FLAG_STRICT}, +{ "ldcwx", 0x0c0001c0, 0xfc0013c0, "cxcdx(s,b),t", pa11, FLAG_STRICT}, +{ "ldcwx", 0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, 0}, +{ "ldcwx", 0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, +{ "ldws", 0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldws", 0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldws", 0x0c001080, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldws", 0x0c001080, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldws", 0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, 0}, +{ "ldws", 0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, 0}, +{ "ldhs", 0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldhs", 0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldhs", 0x0c001040, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldhs", 0x0c001040, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldhs", 0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, 0}, +{ "ldhs", 0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, 0}, +{ "ldbs", 0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldbs", 0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldbs", 0x0c001000, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldbs", 0x0c001000, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldbs", 0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, 0}, +{ "ldbs", 0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, 0}, +{ "ldwas", 0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldwas", 0x0c001180, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldwas", 0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, 0}, +{ "ldcws", 0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldcws", 0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldcws", 0x0c0011c0, 0xfc00d3c0, "cmcd5(b),t", pa11, FLAG_STRICT}, +{ "ldcws", 0x0c0011c0, 0xfc0013c0, "cmcd5(s,b),t", pa11, FLAG_STRICT}, +{ "ldcws", 0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, 0}, +{ "ldcws", 0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, 0}, +{ "stws", 0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stws", 0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "stws", 0x0c001280, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stws", 0x0c001280, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "stws", 0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, 0}, +{ "stws", 0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, 0}, +{ "sths", 0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "sths", 0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "sths", 0x0c001240, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "sths", 0x0c001240, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "sths", 0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, 0}, +{ "sths", 0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, 0}, +{ "stbs", 0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stbs", 0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "stbs", 0x0c001200, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stbs", 0x0c001200, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "stbs", 0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, 0}, +{ "stbs", 0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, 0}, +{ "stwas", 0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stwas", 0x0c001380, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stwas", 0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, 0}, +{ "stdby", 0x0c001340, 0xfc00d3c0, "cscCx,V(b)", pa20, FLAG_STRICT}, +{ "stdby", 0x0c001340, 0xfc0013c0, "cscCx,V(s,b)", pa20, FLAG_STRICT}, +{ "stbys", 0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, FLAG_STRICT}, +{ "stbys", 0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, FLAG_STRICT}, +{ "stbys", 0x0c001300, 0xfc00d3c0, "cscCx,V(b)", pa11, FLAG_STRICT}, +{ "stbys", 0x0c001300, 0xfc0013c0, "cscCx,V(s,b)", pa11, FLAG_STRICT}, +{ "stbys", 0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, 0}, +{ "stbys", 0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, 0}, + +/* Immediate instructions. */ +{ "ldo", 0x34000000, 0xfc000000, "l(b),x", pa20w, 0}, +{ "ldo", 0x34000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldil", 0x20000000, 0xfc000000, "k,b", pa10, 0}, +{ "addil", 0x28000000, 0xfc000000, "k,b,Z", pa10, 0}, +{ "addil", 0x28000000, 0xfc000000, "k,b", pa10, 0}, + +/* Branching instructions. */ +{ "b", 0xe8008000, 0xfc00e000, "cpnXL", pa20, FLAG_STRICT}, +{ "b", 0xe800a000, 0xfc00e000, "clnXL", pa20, FLAG_STRICT}, +{ "b", 0xe8000000, 0xfc00e000, "clnW,b", pa10, FLAG_STRICT}, +{ "b", 0xe8002000, 0xfc00e000, "cgnW,b", pa10, FLAG_STRICT}, +{ "b", 0xe8000000, 0xffe0e000, "nW", pa10, 0}, /* b,l foo,r0 */ +{ "bl", 0xe8000000, 0xfc00e000, "nW,b", pa10, 0}, +{ "gate", 0xe8002000, 0xfc00e000, "nW,b", pa10, 0}, +{ "blr", 0xe8004000, 0xfc00e001, "nx,b", pa10, 0}, +{ "bv", 0xe800c000, 0xfc00fffd, "nx(b)", pa10, 0}, +{ "bv", 0xe800c000, 0xfc00fffd, "n(b)", pa10, 0}, +{ "bve", 0xe800f001, 0xfc1ffffd, "cpn(b)L", pa20, FLAG_STRICT}, +{ "bve", 0xe800f000, 0xfc1ffffd, "cln(b)L", pa20, FLAG_STRICT}, +{ "bve", 0xe800d001, 0xfc1ffffd, "cPn(b)", pa20, FLAG_STRICT}, +{ "bve", 0xe800d000, 0xfc1ffffd, "n(b)", pa20, FLAG_STRICT}, +{ "be", 0xe4000000, 0xfc000000, "clnz(S,b),Y", pa10, FLAG_STRICT}, +{ "be", 0xe4000000, 0xfc000000, "clnz(b),Y", pa10, FLAG_STRICT}, +{ "be", 0xe0000000, 0xfc000000, "nz(S,b)", pa10, 0}, +{ "be", 0xe0000000, 0xfc000000, "nz(b)", pa10, 0}, +{ "ble", 0xe4000000, 0xfc000000, "nz(S,b)", pa10, 0}, +{ "movb", 0xc8000000, 0xfc000000, "?ynx,b,w", pa10, 0}, +{ "movib", 0xcc000000, 0xfc000000, "?yn5,b,w", pa10, 0}, +{ "combt", 0x80000000, 0xfc000000, "?tnx,b,w", pa10, 0}, +{ "combf", 0x88000000, 0xfc000000, "?tnx,b,w", pa10, 0}, +{ "comibt", 0x84000000, 0xfc000000, "?tn5,b,w", pa10, 0}, +{ "comibf", 0x8c000000, 0xfc000000, "?tn5,b,w", pa10, 0}, +{ "addbt", 0xa0000000, 0xfc000000, "?dnx,b,w", pa10, 0}, +{ "addbf", 0xa8000000, 0xfc000000, "?dnx,b,w", pa10, 0}, +{ "addibt", 0xa4000000, 0xfc000000, "?dn5,b,w", pa10, 0}, +{ "addibf", 0xac000000, 0xfc000000, "?dn5,b,w", pa10, 0}, +{ "bb", 0xc0004000, 0xffe06000, "?bnx,!,w", pa10, FLAG_STRICT}, +{ "bb", 0xc0006000, 0xffe06000, "?Bnx,!,w", pa20, FLAG_STRICT}, +{ "bb", 0xc4004000, 0xfc006000, "?bnx,Q,w", pa10, FLAG_STRICT}, +{ "bb", 0xc4004000, 0xfc004000, "?Bnx,B,w", pa20, FLAG_STRICT}, +{ "bvb", 0xc0004000, 0xffe04000, "?bnx,w", pa10, 0}, +{ "clrbts", 0xe8004005, 0xffffffff, "", pa20, FLAG_STRICT}, +{ "popbts", 0xe8004005, 0xfffff007, "$", pa20, FLAG_STRICT}, +{ "pushnom", 0xe8004001, 0xffffffff, "", pa20, FLAG_STRICT}, +{ "pushbts", 0xe8004001, 0xffe0ffff, "x", pa20, FLAG_STRICT}, + +/* Computation Instructions. */ + +{ "cmpclr", 0x080008a0, 0xfc000fe0, "?Sx,b,t", pa20, FLAG_STRICT}, +{ "cmpclr", 0x08000880, 0xfc000fe0, "?sx,b,t", pa10, FLAG_STRICT}, +{ "comclr", 0x08000880, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "or", 0x08000260, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT}, +{ "or", 0x08000240, 0xfc000fe0, "?lx,b,t", pa10, 0}, +{ "xor", 0x080002a0, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT}, +{ "xor", 0x08000280, 0xfc000fe0, "?lx,b,t", pa10, 0}, +{ "and", 0x08000220, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT}, +{ "and", 0x08000200, 0xfc000fe0, "?lx,b,t", pa10, 0}, +{ "andcm", 0x08000020, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT}, +{ "andcm", 0x08000000, 0xfc000fe0, "?lx,b,t", pa10, 0}, +{ "uxor", 0x080003a0, 0xfc000fe0, "?Ux,b,t", pa20, FLAG_STRICT}, +{ "uxor", 0x08000380, 0xfc000fe0, "?ux,b,t", pa10, 0}, +{ "uaddcm", 0x080009a0, 0xfc000fa0, "cT?Ux,b,t", pa20, FLAG_STRICT}, +{ "uaddcm", 0x08000980, 0xfc000fa0, "cT?ux,b,t", pa10, FLAG_STRICT}, +{ "uaddcm", 0x08000980, 0xfc000fe0, "?ux,b,t", pa10, 0}, +{ "uaddcmt", 0x080009c0, 0xfc000fe0, "?ux,b,t", pa10, 0}, +{ "dcor", 0x08000ba0, 0xfc1f0fa0, "ci?Ub,t", pa20, FLAG_STRICT}, +{ "dcor", 0x08000b80, 0xfc1f0fa0, "ci?ub,t", pa10, FLAG_STRICT}, +{ "dcor", 0x08000b80, 0xfc1f0fe0, "?ub,t", pa10, 0}, +{ "idcor", 0x08000bc0, 0xfc1f0fe0, "?ub,t", pa10, 0}, +{ "addi", 0xb0000000, 0xfc000000, "ct?ai,b,x", pa10, FLAG_STRICT}, +{ "addi", 0xb4000000, 0xfc000000, "cv?ai,b,x", pa10, FLAG_STRICT}, +{ "addi", 0xb4000000, 0xfc000800, "?ai,b,x", pa10, 0}, +{ "addio", 0xb4000800, 0xfc000800, "?ai,b,x", pa10, 0}, +{ "addit", 0xb0000000, 0xfc000800, "?ai,b,x", pa10, 0}, +{ "addito", 0xb0000800, 0xfc000800, "?ai,b,x", pa10, 0}, +{ "add", 0x08000720, 0xfc0007e0, "cY?Ax,b,t", pa20, FLAG_STRICT}, +{ "add", 0x08000700, 0xfc0007e0, "cy?ax,b,t", pa10, FLAG_STRICT}, +{ "add", 0x08000220, 0xfc0003e0, "ca?Ax,b,t", pa20, FLAG_STRICT}, +{ "add", 0x08000200, 0xfc0003e0, "ca?ax,b,t", pa10, FLAG_STRICT}, +{ "add", 0x08000600, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "addl", 0x08000a00, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "addo", 0x08000e00, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "addc", 0x08000700, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "addco", 0x08000f00, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sub", 0x080004e0, 0xfc0007e0, "ct?Sx,b,t", pa20, FLAG_STRICT}, +{ "sub", 0x080004c0, 0xfc0007e0, "ct?sx,b,t", pa10, FLAG_STRICT}, +{ "sub", 0x08000520, 0xfc0007e0, "cB?Sx,b,t", pa20, FLAG_STRICT}, +{ "sub", 0x08000500, 0xfc0007e0, "cb?sx,b,t", pa10, FLAG_STRICT}, +{ "sub", 0x08000420, 0xfc0007e0, "cv?Sx,b,t", pa20, FLAG_STRICT}, +{ "sub", 0x08000400, 0xfc0007e0, "cv?sx,b,t", pa10, FLAG_STRICT}, +{ "sub", 0x08000400, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "subo", 0x08000c00, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "subb", 0x08000500, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "subbo", 0x08000d00, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "subt", 0x080004c0, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "subto", 0x08000cc0, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "ds", 0x08000440, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "subi", 0x94000000, 0xfc000000, "cv?si,b,x", pa10, FLAG_STRICT}, +{ "subi", 0x94000000, 0xfc000800, "?si,b,x", pa10, 0}, +{ "subio", 0x94000800, 0xfc000800, "?si,b,x", pa10, 0}, +{ "cmpiclr", 0x90000800, 0xfc000800, "?Si,b,x", pa20, FLAG_STRICT}, +{ "cmpiclr", 0x90000000, 0xfc000800, "?si,b,x", pa10, FLAG_STRICT}, +{ "comiclr", 0x90000000, 0xfc000800, "?si,b,x", pa10, 0}, +{ "shladd", 0x08000220, 0xfc000320, "ca?Ax,.,b,t", pa20, FLAG_STRICT}, +{ "shladd", 0x08000200, 0xfc000320, "ca?ax,.,b,t", pa10, FLAG_STRICT}, +{ "sh1add", 0x08000640, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh1addl", 0x08000a40, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh1addo", 0x08000e40, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh2add", 0x08000680, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh2addl", 0x08000a80, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh2addo", 0x08000e80, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh3add", 0x080006c0, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh3addl", 0x08000ac0, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh3addo", 0x08000ec0, 0xfc000fe0, "?ax,b,t", pa10, 0}, + +/* Subword Operation Instructions. */ + +{ "hadd", 0x08000300, 0xfc00ff20, "cHx,b,t", pa20, FLAG_STRICT}, +{ "havg", 0x080002c0, 0xfc00ffe0, "x,b,t", pa20, FLAG_STRICT}, +{ "hshl", 0xf8008800, 0xffe0fc20, "x,*,t", pa20, FLAG_STRICT}, +{ "hshladd", 0x08000700, 0xfc00ff20, "x,.,b,t", pa20, FLAG_STRICT}, +{ "hshr", 0xf800c800, 0xfc1ff820, "cSb,*,t", pa20, FLAG_STRICT}, +{ "hshradd", 0x08000500, 0xfc00ff20, "x,.,b,t", pa20, FLAG_STRICT}, +{ "hsub", 0x08000100, 0xfc00ff20, "cHx,b,t", pa20, FLAG_STRICT}, +{ "mixh", 0xf8008400, 0xfc009fe0, "chx,b,t", pa20, FLAG_STRICT}, +{ "mixw", 0xf8008000, 0xfc009fe0, "chx,b,t", pa20, FLAG_STRICT}, +{ "permh", 0xf8000000, 0xfc009020, "c*a,t", pa20, FLAG_STRICT}, + + +/* Extract and Deposit Instructions. */ + +{ "shrpd", 0xd0000200, 0xfc001fe0, "?Xx,b,!,t", pa20, FLAG_STRICT}, +{ "shrpd", 0xd0000400, 0xfc001400, "?Xx,b,~,t", pa20, FLAG_STRICT}, +{ "shrpw", 0xd0000000, 0xfc001fe0, "?xx,b,!,t", pa10, FLAG_STRICT}, +{ "shrpw", 0xd0000800, 0xfc001c00, "?xx,b,p,t", pa10, FLAG_STRICT}, +{ "vshd", 0xd0000000, 0xfc001fe0, "?xx,b,t", pa10, 0}, +{ "shd", 0xd0000800, 0xfc001c00, "?xx,b,p,t", pa10, 0}, +{ "extrd", 0xd0001200, 0xfc001ae0, "cS?Xb,!,%,x", pa20, FLAG_STRICT}, +{ "extrd", 0xd8000000, 0xfc000000, "cS?Xb,q,|,x", pa20, FLAG_STRICT}, +{ "extrw", 0xd0001000, 0xfc001be0, "cS?xb,!,T,x", pa10, FLAG_STRICT}, +{ "extrw", 0xd0001800, 0xfc001800, "cS?xb,P,T,x", pa10, FLAG_STRICT}, +{ "vextru", 0xd0001000, 0xfc001fe0, "?xb,T,x", pa10, 0}, +{ "vextrs", 0xd0001400, 0xfc001fe0, "?xb,T,x", pa10, 0}, +{ "extru", 0xd0001800, 0xfc001c00, "?xb,P,T,x", pa10, 0}, +{ "extrs", 0xd0001c00, 0xfc001c00, "?xb,P,T,x", pa10, 0}, +{ "depd", 0xd4000200, 0xfc001ae0, "cz?Xx,!,%,b", pa20, FLAG_STRICT}, +{ "depd", 0xf0000000, 0xfc000000, "cz?Xx,~,|,b", pa20, FLAG_STRICT}, +{ "depdi", 0xd4001200, 0xfc001ae0, "cz?X5,!,%,b", pa20, FLAG_STRICT}, +{ "depdi", 0xf4000000, 0xfc000000, "cz?X5,~,|,b", pa20, FLAG_STRICT}, +{ "depw", 0xd4000000, 0xfc001be0, "cz?xx,!,T,b", pa10, FLAG_STRICT}, +{ "depw", 0xd4000800, 0xfc001800, "cz?xx,p,T,b", pa10, FLAG_STRICT}, +{ "depwi", 0xd4001000, 0xfc001be0, "cz?x5,!,T,b", pa10, FLAG_STRICT}, +{ "depwi", 0xd4001800, 0xfc001800, "cz?x5,p,T,b", pa10, FLAG_STRICT}, +{ "zvdep", 0xd4000000, 0xfc001fe0, "?xx,T,b", pa10, 0}, +{ "vdep", 0xd4000400, 0xfc001fe0, "?xx,T,b", pa10, 0}, +{ "zdep", 0xd4000800, 0xfc001c00, "?xx,p,T,b", pa10, 0}, +{ "dep", 0xd4000c00, 0xfc001c00, "?xx,p,T,b", pa10, 0}, +{ "zvdepi", 0xd4001000, 0xfc001fe0, "?x5,T,b", pa10, 0}, +{ "vdepi", 0xd4001400, 0xfc001fe0, "?x5,T,b", pa10, 0}, +{ "zdepi", 0xd4001800, 0xfc001c00, "?x5,p,T,b", pa10, 0}, +{ "depi", 0xd4001c00, 0xfc001c00, "?x5,p,T,b", pa10, 0}, + +/* System Control Instructions. */ + +{ "break", 0x00000000, 0xfc001fe0, "r,A", pa10, 0}, +{ "rfi", 0x00000c00, 0xffffff1f, "cr", pa10, FLAG_STRICT}, +{ "rfi", 0x00000c00, 0xffffffff, "", pa10, 0}, +{ "rfir", 0x00000ca0, 0xffffffff, "", pa11, 0}, +{ "ssm", 0x00000d60, 0xfc00ffe0, "U,t", pa20, FLAG_STRICT}, +{ "ssm", 0x00000d60, 0xffe0ffe0, "R,t", pa10, 0}, +{ "rsm", 0x00000e60, 0xfc00ffe0, "U,t", pa20, FLAG_STRICT}, +{ "rsm", 0x00000e60, 0xffe0ffe0, "R,t", pa10, 0}, +{ "mtsm", 0x00001860, 0xffe0ffff, "x", pa10, 0}, +{ "ldsid", 0x000010a0, 0xfc1fffe0, "(b),t", pa10, 0}, +{ "ldsid", 0x000010a0, 0xfc1f3fe0, "(s,b),t", pa10, 0}, +{ "mtsp", 0x00001820, 0xffe01fff, "x,S", pa10, 0}, +{ "mtctl", 0x00001840, 0xfc00ffff, "x,^", pa10, 0}, +{ "mtsarcm", 0x016018C0, 0xffe0ffff, "x", pa20, FLAG_STRICT}, +{ "mfia", 0x000014A0, 0xffffffe0, "t", pa20, FLAG_STRICT}, +{ "mfsp", 0x000004a0, 0xffff1fe0, "S,t", pa10, 0}, +{ "mfctl", 0x016048a0, 0xffffffe0, "cW!,t", pa20, FLAG_STRICT}, +{ "mfctl", 0x000008a0, 0xfc1fffe0, "^,t", pa10, 0}, +{ "sync", 0x00000400, 0xffffffff, "", pa10, 0}, +{ "syncdma", 0x00100400, 0xffffffff, "", pa10, 0}, +{ "probe", 0x04001180, 0xfc00ffa0, "cw(b),x,t", pa10, FLAG_STRICT}, +{ "probe", 0x04001180, 0xfc003fa0, "cw(s,b),x,t", pa10, FLAG_STRICT}, +{ "probei", 0x04003180, 0xfc00ffa0, "cw(b),R,t", pa10, FLAG_STRICT}, +{ "probei", 0x04003180, 0xfc003fa0, "cw(s,b),R,t", pa10, FLAG_STRICT}, +{ "prober", 0x04001180, 0xfc00ffe0, "(b),x,t", pa10, 0}, +{ "prober", 0x04001180, 0xfc003fe0, "(s,b),x,t", pa10, 0}, +{ "proberi", 0x04003180, 0xfc00ffe0, "(b),R,t", pa10, 0}, +{ "proberi", 0x04003180, 0xfc003fe0, "(s,b),R,t", pa10, 0}, +{ "probew", 0x040011c0, 0xfc00ffe0, "(b),x,t", pa10, 0}, +{ "probew", 0x040011c0, 0xfc003fe0, "(s,b),x,t", pa10, 0}, +{ "probewi", 0x040031c0, 0xfc00ffe0, "(b),R,t", pa10, 0}, +{ "probewi", 0x040031c0, 0xfc003fe0, "(s,b),R,t", pa10, 0}, +{ "lpa", 0x04001340, 0xfc00ffc0, "cZx(b),t", pa10, 0}, +{ "lpa", 0x04001340, 0xfc003fc0, "cZx(s,b),t", pa10, 0}, +{ "lci", 0x04001300, 0xfc00ffe0, "x(b),t", pa11, 0}, +{ "lci", 0x04001300, 0xfc003fe0, "x(s,b),t", pa11, 0}, +{ "pdtlb", 0x04001600, 0xfc00ffdf, "cLcZx(b)", pa20, FLAG_STRICT}, +{ "pdtlb", 0x04001600, 0xfc003fdf, "cLcZx(s,b)", pa20, FLAG_STRICT}, +{ "pdtlb", 0x04001600, 0xfc1fffdf, "cLcZ@(b)", pa20, FLAG_STRICT}, +{ "pdtlb", 0x04001600, 0xfc1f3fdf, "cLcZ@(s,b)", pa20, FLAG_STRICT}, +{ "pdtlb", 0x04001200, 0xfc00ffdf, "cZx(b)", pa10, 0}, +{ "pdtlb", 0x04001200, 0xfc003fdf, "cZx(s,b)", pa10, 0}, +{ "pitlb", 0x04000600, 0xfc001fdf, "cLcZx(S,b)", pa20, FLAG_STRICT}, +{ "pitlb", 0x04000600, 0xfc1f1fdf, "cLcZ@(S,b)", pa20, FLAG_STRICT}, +{ "pitlb", 0x04000200, 0xfc001fdf, "cZx(S,b)", pa10, 0}, +{ "pdtlbe", 0x04001240, 0xfc00ffdf, "cZx(b)", pa10, 0}, +{ "pdtlbe", 0x04001240, 0xfc003fdf, "cZx(s,b)", pa10, 0}, +{ "pitlbe", 0x04000240, 0xfc001fdf, "cZx(S,b)", pa10, 0}, +{ "idtlba", 0x04001040, 0xfc00ffff, "x,(b)", pa10, 0}, +{ "idtlba", 0x04001040, 0xfc003fff, "x,(s,b)", pa10, 0}, +{ "iitlba", 0x04000040, 0xfc001fff, "x,(S,b)", pa10, 0}, +{ "idtlbp", 0x04001000, 0xfc00ffff, "x,(b)", pa10, 0}, +{ "idtlbp", 0x04001000, 0xfc003fff, "x,(s,b)", pa10, 0}, +{ "iitlbp", 0x04000000, 0xfc001fff, "x,(S,b)", pa10, 0}, +{ "pdc", 0x04001380, 0xfc00ffdf, "cZx(b)", pa10, 0}, +{ "pdc", 0x04001380, 0xfc003fdf, "cZx(s,b)", pa10, 0}, +{ "fdc", 0x04001280, 0xfc00ffdf, "cZx(b)", pa10, FLAG_STRICT}, +{ "fdc", 0x04001280, 0xfc003fdf, "cZx(s,b)", pa10, FLAG_STRICT}, +{ "fdc", 0x04003280, 0xfc00ffff, "5(b)", pa20, FLAG_STRICT}, +{ "fdc", 0x04003280, 0xfc003fff, "5(s,b)", pa20, FLAG_STRICT}, +{ "fdc", 0x04001280, 0xfc00ffdf, "cZx(b)", pa10, 0}, +{ "fdc", 0x04001280, 0xfc003fdf, "cZx(s,b)", pa10, 0}, +{ "fic", 0x040013c0, 0xfc00dfdf, "cZx(b)", pa20, FLAG_STRICT}, +{ "fic", 0x04000280, 0xfc001fdf, "cZx(S,b)", pa10, 0}, +{ "fdce", 0x040012c0, 0xfc00ffdf, "cZx(b)", pa10, 0}, +{ "fdce", 0x040012c0, 0xfc003fdf, "cZx(s,b)", pa10, 0}, +{ "fice", 0x040002c0, 0xfc001fdf, "cZx(S,b)", pa10, 0}, +{ "diag", 0x14000000, 0xfc000000, "D", pa10, 0}, +{ "idtlbt", 0x04001800, 0xfc00ffff, "x,b", pa20, FLAG_STRICT}, +{ "iitlbt", 0x04000800, 0xfc00ffff, "x,b", pa20, FLAG_STRICT}, + +/* These may be specific to certain versions of the PA. Joel claimed + they were 72000 (7200?) specific. However, I'm almost certain the + mtcpu/mfcpu were undocumented, but available in the older 700 machines. */ +{ "mtcpu", 0x14001600, 0xfc00ffff, "x,^", pa10, 0}, +{ "mfcpu", 0x14001A00, 0xfc00ffff, "^,x", pa10, 0}, +{ "tocen", 0x14403600, 0xffffffff, "", pa10, 0}, +{ "tocdis", 0x14401620, 0xffffffff, "", pa10, 0}, +{ "shdwgr", 0x14402600, 0xffffffff, "", pa10, 0}, +{ "grshdw", 0x14400620, 0xffffffff, "", pa10, 0}, + +/* gfw and gfr are not in the HP PA 1.1 manual, but they are in either + the Timex FPU or the Mustang ERS (not sure which) manual. */ +{ "gfw", 0x04001680, 0xfc00ffdf, "cZx(b)", pa11, 0}, +{ "gfw", 0x04001680, 0xfc003fdf, "cZx(s,b)", pa11, 0}, +{ "gfr", 0x04001a80, 0xfc00ffdf, "cZx(b)", pa11, 0}, +{ "gfr", 0x04001a80, 0xfc003fdf, "cZx(s,b)", pa11, 0}, + +/* Floating Point Coprocessor Instructions. */ + +{ "fldw", 0x24000000, 0xfc00df80, "cXx(b),fT", pa10, FLAG_STRICT}, +{ "fldw", 0x24000000, 0xfc001f80, "cXx(s,b),fT", pa10, FLAG_STRICT}, +{ "fldw", 0x24000000, 0xfc00d380, "cxccx(b),fT", pa11, FLAG_STRICT}, +{ "fldw", 0x24000000, 0xfc001380, "cxccx(s,b),fT", pa11, FLAG_STRICT}, +{ "fldw", 0x24001020, 0xfc1ff3a0, "cocc@(b),fT", pa20, FLAG_STRICT}, +{ "fldw", 0x24001020, 0xfc1f33a0, "cocc@(s,b),fT", pa20, FLAG_STRICT}, +{ "fldw", 0x24001000, 0xfc00df80, "cM5(b),fT", pa10, FLAG_STRICT}, +{ "fldw", 0x24001000, 0xfc001f80, "cM5(s,b),fT", pa10, FLAG_STRICT}, +{ "fldw", 0x24001000, 0xfc00d380, "cmcc5(b),fT", pa11, FLAG_STRICT}, +{ "fldw", 0x24001000, 0xfc001380, "cmcc5(s,b),fT", pa11, FLAG_STRICT}, +{ "fldw", 0x5c000000, 0xfc000004, "y(b),fe", pa20w, FLAG_STRICT}, +{ "fldw", 0x58000000, 0xfc000000, "cJy(b),fe", pa20w, FLAG_STRICT}, +{ "fldw", 0x5c000000, 0xfc00c004, "d(b),fe", pa20, FLAG_STRICT}, +{ "fldw", 0x5c000000, 0xfc000004, "d(s,b),fe", pa20, FLAG_STRICT}, +{ "fldw", 0x58000000, 0xfc00c000, "cJd(b),fe", pa20, FLAG_STRICT}, +{ "fldw", 0x58000000, 0xfc000000, "cJd(s,b),fe", pa20, FLAG_STRICT}, +{ "fldd", 0x2c000000, 0xfc00dfc0, "cXx(b),ft", pa10, FLAG_STRICT}, +{ "fldd", 0x2c000000, 0xfc001fc0, "cXx(s,b),ft", pa10, FLAG_STRICT}, +{ "fldd", 0x2c000000, 0xfc00d3c0, "cxccx(b),ft", pa11, FLAG_STRICT}, +{ "fldd", 0x2c000000, 0xfc0013c0, "cxccx(s,b),ft", pa11, FLAG_STRICT}, +{ "fldd", 0x2c001020, 0xfc1ff3e0, "cocc@(b),ft", pa20, FLAG_STRICT}, +{ "fldd", 0x2c001020, 0xfc1f33e0, "cocc@(s,b),ft", pa20, FLAG_STRICT}, +{ "fldd", 0x2c001000, 0xfc00dfc0, "cM5(b),ft", pa10, FLAG_STRICT}, +{ "fldd", 0x2c001000, 0xfc001fc0, "cM5(s,b),ft", pa10, FLAG_STRICT}, +{ "fldd", 0x2c001000, 0xfc00d3c0, "cmcc5(b),ft", pa11, FLAG_STRICT}, +{ "fldd", 0x2c001000, 0xfc0013c0, "cmcc5(s,b),ft", pa11, FLAG_STRICT}, +{ "fldd", 0x50000002, 0xfc000002, "cq&(b),fx", pa20w, FLAG_STRICT}, +{ "fldd", 0x50000002, 0xfc00c002, "cq#(b),fx", pa20, FLAG_STRICT}, +{ "fldd", 0x50000002, 0xfc000002, "cq#(s,b),fx", pa20, FLAG_STRICT}, +{ "fstw", 0x24000200, 0xfc00df80, "cXfT,x(b)", pa10, FLAG_STRICT}, +{ "fstw", 0x24000200, 0xfc001f80, "cXfT,x(s,b)", pa10, FLAG_STRICT}, +{ "fstw", 0x24000200, 0xfc00d380, "cxcCfT,x(b)", pa11, FLAG_STRICT}, +{ "fstw", 0x24000200, 0xfc001380, "cxcCfT,x(s,b)", pa11, FLAG_STRICT}, +{ "fstw", 0x24001220, 0xfc1ff3a0, "cocCfT,@(b)", pa20, FLAG_STRICT}, +{ "fstw", 0x24001220, 0xfc1f33a0, "cocCfT,@(s,b)", pa20, FLAG_STRICT}, +{ "fstw", 0x24001200, 0xfc00df80, "cMfT,5(b)", pa10, FLAG_STRICT}, +{ "fstw", 0x24001200, 0xfc001f80, "cMfT,5(s,b)", pa10, FLAG_STRICT}, +{ "fstw", 0x24001200, 0xfc00df80, "cMfT,5(b)", pa10, FLAG_STRICT}, +{ "fstw", 0x24001200, 0xfc001f80, "cMfT,5(s,b)", pa10, FLAG_STRICT}, +{ "fstw", 0x7c000000, 0xfc000004, "fE,y(b)", pa20w, FLAG_STRICT}, +{ "fstw", 0x78000000, 0xfc000000, "cJfE,y(b)", pa20w, FLAG_STRICT}, +{ "fstw", 0x7c000000, 0xfc00c004, "fE,d(b)", pa20, FLAG_STRICT}, +{ "fstw", 0x7c000000, 0xfc000004, "fE,d(s,b)", pa20, FLAG_STRICT}, +{ "fstw", 0x78000000, 0xfc00c000, "cJfE,d(b)", pa20, FLAG_STRICT}, +{ "fstw", 0x78000000, 0xfc000000, "cJfE,d(s,b)", pa20, FLAG_STRICT}, +{ "fstd", 0x2c000200, 0xfc00dfc0, "cXft,x(b)", pa10, FLAG_STRICT}, +{ "fstd", 0x2c000200, 0xfc001fc0, "cXft,x(s,b)", pa10, FLAG_STRICT}, +{ "fstd", 0x2c000200, 0xfc00d3c0, "cxcCft,x(b)", pa11, FLAG_STRICT}, +{ "fstd", 0x2c000200, 0xfc0013c0, "cxcCft,x(s,b)", pa11, FLAG_STRICT}, +{ "fstd", 0x2c001220, 0xfc1ff3e0, "cocCft,@(b)", pa20, FLAG_STRICT}, +{ "fstd", 0x2c001220, 0xfc1f33e0, "cocCft,@(s,b)", pa20, FLAG_STRICT}, +{ "fstd", 0x2c001200, 0xfc00dfc0, "cMft,5(b)", pa10, FLAG_STRICT}, +{ "fstd", 0x2c001200, 0xfc001fc0, "cMft,5(s,b)", pa10, FLAG_STRICT}, +{ "fstd", 0x2c001200, 0xfc00d3c0, "cmcCft,5(b)", pa11, FLAG_STRICT}, +{ "fstd", 0x2c001200, 0xfc0013c0, "cmcCft,5(s,b)", pa11, FLAG_STRICT}, +{ "fstd", 0x70000002, 0xfc000002, "cqfx,&(b)", pa20w, FLAG_STRICT}, +{ "fstd", 0x70000002, 0xfc00c002, "cqfx,#(b)", pa20, FLAG_STRICT}, +{ "fstd", 0x70000002, 0xfc000002, "cqfx,#(s,b)", pa20, FLAG_STRICT}, +{ "fldwx", 0x24000000, 0xfc00df80, "cXx(b),fT", pa10, FLAG_STRICT}, +{ "fldwx", 0x24000000, 0xfc001f80, "cXx(s,b),fT", pa10, FLAG_STRICT}, +{ "fldwx", 0x24000000, 0xfc00d380, "cxccx(b),fT", pa11, FLAG_STRICT}, +{ "fldwx", 0x24000000, 0xfc001380, "cxccx(s,b),fT", pa11, FLAG_STRICT}, +{ "fldwx", 0x24000000, 0xfc00df80, "cXx(b),fT", pa10, 0}, +{ "fldwx", 0x24000000, 0xfc001f80, "cXx(s,b),fT", pa10, 0}, +{ "flddx", 0x2c000000, 0xfc00dfc0, "cXx(b),ft", pa10, FLAG_STRICT}, +{ "flddx", 0x2c000000, 0xfc001fc0, "cXx(s,b),ft", pa10, FLAG_STRICT}, +{ "flddx", 0x2c000000, 0xfc00d3c0, "cxccx(b),ft", pa11, FLAG_STRICT}, +{ "flddx", 0x2c000000, 0xfc0013c0, "cxccx(s,b),ft", pa11, FLAG_STRICT}, +{ "flddx", 0x2c000000, 0xfc00dfc0, "cXx(b),ft", pa10, 0}, +{ "flddx", 0x2c000000, 0xfc001fc0, "cXx(s,b),ft", pa10, 0}, +{ "fstwx", 0x24000200, 0xfc00df80, "cxfT,x(b)", pa10, FLAG_STRICT}, +{ "fstwx", 0x24000200, 0xfc001f80, "cxfT,x(s,b)", pa10, FLAG_STRICT}, +{ "fstwx", 0x24000200, 0xfc00d380, "cxcCfT,x(b)", pa11, FLAG_STRICT}, +{ "fstwx", 0x24000200, 0xfc001380, "cxcCfT,x(s,b)", pa11, FLAG_STRICT}, +{ "fstwx", 0x24000200, 0xfc00df80, "cxfT,x(b)", pa10, 0}, +{ "fstwx", 0x24000200, 0xfc001f80, "cxfT,x(s,b)", pa10, 0}, +{ "fstdx", 0x2c000200, 0xfc00dfc0, "cxft,x(b)", pa10, FLAG_STRICT}, +{ "fstdx", 0x2c000200, 0xfc001fc0, "cxft,x(s,b)", pa10, FLAG_STRICT}, +{ "fstdx", 0x2c000200, 0xfc00d3c0, "cxcCft,x(b)", pa11, FLAG_STRICT}, +{ "fstdx", 0x2c000200, 0xfc0013c0, "cxcCft,x(s,b)", pa11, FLAG_STRICT}, +{ "fstdx", 0x2c000200, 0xfc00dfc0, "cxft,x(b)", pa10, 0}, +{ "fstdx", 0x2c000200, 0xfc001fc0, "cxft,x(s,b)", pa10, 0}, +{ "fstqx", 0x3c000200, 0xfc00dfc0, "cxft,x(b)", pa10, 0}, +{ "fstqx", 0x3c000200, 0xfc001fc0, "cxft,x(s,b)", pa10, 0}, +{ "fldws", 0x24001000, 0xfc00df80, "cm5(b),fT", pa10, FLAG_STRICT}, +{ "fldws", 0x24001000, 0xfc001f80, "cm5(s,b),fT", pa10, FLAG_STRICT}, +{ "fldws", 0x24001000, 0xfc00d380, "cmcc5(b),fT", pa11, FLAG_STRICT}, +{ "fldws", 0x24001000, 0xfc001380, "cmcc5(s,b),fT", pa11, FLAG_STRICT}, +{ "fldws", 0x24001000, 0xfc00df80, "cm5(b),fT", pa10, 0}, +{ "fldws", 0x24001000, 0xfc001f80, "cm5(s,b),fT", pa10, 0}, +{ "fldds", 0x2c001000, 0xfc00dfc0, "cm5(b),ft", pa10, FLAG_STRICT}, +{ "fldds", 0x2c001000, 0xfc001fc0, "cm5(s,b),ft", pa10, FLAG_STRICT}, +{ "fldds", 0x2c001000, 0xfc00d3c0, "cmcc5(b),ft", pa11, FLAG_STRICT}, +{ "fldds", 0x2c001000, 0xfc0013c0, "cmcc5(s,b),ft", pa11, FLAG_STRICT}, +{ "fldds", 0x2c001000, 0xfc00dfc0, "cm5(b),ft", pa10, 0}, +{ "fldds", 0x2c001000, 0xfc001fc0, "cm5(s,b),ft", pa10, 0}, +{ "fstws", 0x24001200, 0xfc00df80, "cmfT,5(b)", pa10, FLAG_STRICT}, +{ "fstws", 0x24001200, 0xfc001f80, "cmfT,5(s,b)", pa10, FLAG_STRICT}, +{ "fstws", 0x24001200, 0xfc00d380, "cmcCfT,5(b)", pa11, FLAG_STRICT}, +{ "fstws", 0x24001200, 0xfc001380, "cmcCfT,5(s,b)", pa11, FLAG_STRICT}, +{ "fstws", 0x24001200, 0xfc00df80, "cmfT,5(b)", pa10, 0}, +{ "fstws", 0x24001200, 0xfc001f80, "cmfT,5(s,b)", pa10, 0}, +{ "fstds", 0x2c001200, 0xfc00dfc0, "cmft,5(b)", pa10, FLAG_STRICT}, +{ "fstds", 0x2c001200, 0xfc001fc0, "cmft,5(s,b)", pa10, FLAG_STRICT}, +{ "fstds", 0x2c001200, 0xfc00d3c0, "cmcCft,5(b)", pa11, FLAG_STRICT}, +{ "fstds", 0x2c001200, 0xfc0013c0, "cmcCft,5(s,b)", pa11, FLAG_STRICT}, +{ "fstds", 0x2c001200, 0xfc00dfc0, "cmft,5(b)", pa10, 0}, +{ "fstds", 0x2c001200, 0xfc001fc0, "cmft,5(s,b)", pa10, 0}, +{ "fstqs", 0x3c001200, 0xfc00dfc0, "cmft,5(b)", pa10, 0}, +{ "fstqs", 0x3c001200, 0xfc001fc0, "cmft,5(s,b)", pa10, 0}, +{ "fadd", 0x30000600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, +{ "fadd", 0x38000600, 0xfc00e720, "IfA,fB,fT", pa10, 0}, +{ "fsub", 0x30002600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, +{ "fsub", 0x38002600, 0xfc00e720, "IfA,fB,fT", pa10, 0}, +{ "fmpy", 0x30004600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, +{ "fmpy", 0x38004600, 0xfc00e720, "IfA,fB,fT", pa10, 0}, +{ "fdiv", 0x30006600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, +{ "fdiv", 0x38006600, 0xfc00e720, "IfA,fB,fT", pa10, 0}, +{ "fsqrt", 0x30008000, 0xfc1fe7e0, "Ffa,fT", pa10, 0}, +{ "fsqrt", 0x38008000, 0xfc1fe720, "FfA,fT", pa10, 0}, +{ "fabs", 0x30006000, 0xfc1fe7e0, "Ffa,fT", pa10, 0}, +{ "fabs", 0x38006000, 0xfc1fe720, "FfA,fT", pa10, 0}, +{ "frem", 0x30008600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, +{ "frem", 0x38008600, 0xfc00e720, "FfA,fB,fT", pa10, 0}, +{ "frnd", 0x3000a000, 0xfc1fe7e0, "Ffa,fT", pa10, 0}, +{ "frnd", 0x3800a000, 0xfc1fe720, "FfA,fT", pa10, 0}, +{ "fcpy", 0x30004000, 0xfc1fe7e0, "Ffa,fT", pa10, 0}, +{ "fcpy", 0x38004000, 0xfc1fe720, "FfA,fT", pa10, 0}, +{ "fcnvff", 0x30000200, 0xfc1f87e0, "FGfa,fT", pa10, 0}, +{ "fcnvff", 0x38000200, 0xfc1f8720, "FGfA,fT", pa10, 0}, +{ "fcnvxf", 0x30008200, 0xfc1f87e0, "FGfa,fT", pa10, 0}, +{ "fcnvxf", 0x38008200, 0xfc1f8720, "FGfA,fT", pa10, 0}, +{ "fcnvfx", 0x30010200, 0xfc1f87e0, "FGfa,fT", pa10, 0}, +{ "fcnvfx", 0x38010200, 0xfc1f8720, "FGfA,fT", pa10, 0}, +{ "fcnvfxt", 0x30018200, 0xfc1f87e0, "FGfa,fT", pa10, 0}, +{ "fcnvfxt", 0x38018200, 0xfc1f8720, "FGfA,fT", pa10, 0}, +{ "fmpyfadd", 0xb8000000, 0xfc000020, "IfA,fB,fC,fT", pa20, FLAG_STRICT}, +{ "fmpynfadd", 0xb8000020, 0xfc000020, "IfA,fB,fC,fT", pa20, FLAG_STRICT}, +{ "fneg", 0x3000c000, 0xfc1fe7e0, "Ffa,fT", pa20, FLAG_STRICT}, +{ "fneg", 0x3800c000, 0xfc1fe720, "IfA,fT", pa20, FLAG_STRICT}, +{ "fnegabs", 0x3000e000, 0xfc1fe7e0, "Ffa,fT", pa20, FLAG_STRICT}, +{ "fnegabs", 0x3800e000, 0xfc1fe720, "IfA,fT", pa20, FLAG_STRICT}, +{ "fcnv", 0x30000200, 0xfc1c0720, "{_fa,fT", pa20, FLAG_STRICT}, +{ "fcnv", 0x38000200, 0xfc1c0720, "FGfA,fT", pa20, FLAG_STRICT}, +{ "fcmp", 0x30000400, 0xfc00e7e0, "F?ffa,fb", pa10, FLAG_STRICT}, +{ "fcmp", 0x38000400, 0xfc00e720, "I?ffA,fB", pa10, FLAG_STRICT}, +{ "fcmp", 0x30000400, 0xfc0007e0, "F?ffa,fb,h", pa20, FLAG_STRICT}, +{ "fcmp", 0x38000400, 0xfc000720, "I?ffA,fB,h", pa20, FLAG_STRICT}, +{ "fcmp", 0x30000400, 0xfc00e7e0, "F?ffa,fb", pa10, 0}, +{ "fcmp", 0x38000400, 0xfc00e720, "I?ffA,fB", pa10, 0}, +{ "xmpyu", 0x38004700, 0xfc00e720, "fX,fB,fT", pa11, 0}, +{ "fmpyadd", 0x18000000, 0xfc000000, "Hfi,fj,fk,fl,fm", pa11, 0}, +{ "fmpysub", 0x98000000, 0xfc000000, "Hfi,fj,fk,fl,fm", pa11, 0}, +{ "ftest", 0x30002420, 0xffffffff, "", pa10, FLAG_STRICT}, +{ "ftest", 0x30002420, 0xffffffe0, ",=", pa20, FLAG_STRICT}, +{ "ftest", 0x30000420, 0xffff1fff, "m", pa20, FLAG_STRICT}, +{ "fid", 0x30000000, 0xffffffff, "", pa11, 0}, + +/* Performance Monitor Instructions. */ + +{ "pmdis", 0x30000280, 0xffffffdf, "N", pa20, FLAG_STRICT}, +{ "pmenb", 0x30000680, 0xffffffff, "", pa20, FLAG_STRICT}, + +/* Assist Instructions. */ + +{ "spop0", 0x10000000, 0xfc000600, "v,ON", pa10, 0}, +{ "spop1", 0x10000200, 0xfc000600, "v,oNt", pa10, 0}, +{ "spop2", 0x10000400, 0xfc000600, "v,1Nb", pa10, 0}, +{ "spop3", 0x10000600, 0xfc000600, "v,0Nx,b", pa10, 0}, +{ "copr", 0x30000000, 0xfc000000, "u,2N", pa10, 0}, +{ "cldw", 0x24000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT}, +{ "cldw", 0x24000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT}, +{ "cldw", 0x24000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT}, +{ "cldw", 0x24000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT}, +{ "cldw", 0x24001000, 0xfc00d200, "ucocc@(b),t", pa20, FLAG_STRICT}, +{ "cldw", 0x24001000, 0xfc001200, "ucocc@(s,b),t", pa20, FLAG_STRICT}, +{ "cldw", 0x24001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT}, +{ "cldw", 0x24001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT}, +{ "cldw", 0x24001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT}, +{ "cldw", 0x24001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "cldd", 0x2c000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT}, +{ "cldd", 0x2c000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT}, +{ "cldd", 0x2c000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT}, +{ "cldd", 0x2c000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT}, +{ "cldd", 0x2c001000, 0xfc00d200, "ucocc@(b),t", pa20, FLAG_STRICT}, +{ "cldd", 0x2c001000, 0xfc001200, "ucocc@(s,b),t", pa20, FLAG_STRICT}, +{ "cldd", 0x2c001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT}, +{ "cldd", 0x2c001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT}, +{ "cldd", 0x2c001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT}, +{ "cldd", 0x2c001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "cstw", 0x24000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT}, +{ "cstw", 0x24000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT}, +{ "cstw", 0x24000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT}, +{ "cstw", 0x24000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT}, +{ "cstw", 0x24001200, 0xfc00d200, "ucocCt,@(b)", pa20, FLAG_STRICT}, +{ "cstw", 0x24001200, 0xfc001200, "ucocCt,@(s,b)", pa20, FLAG_STRICT}, +{ "cstw", 0x24001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT}, +{ "cstw", 0x24001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT}, +{ "cstw", 0x24001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT}, +{ "cstw", 0x24001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT}, +{ "cstd", 0x2c000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT}, +{ "cstd", 0x2c000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT}, +{ "cstd", 0x2c000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT}, +{ "cstd", 0x2c000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT}, +{ "cstd", 0x2c001200, 0xfc00d200, "ucocCt,@(b)", pa20, FLAG_STRICT}, +{ "cstd", 0x2c001200, 0xfc001200, "ucocCt,@(s,b)", pa20, FLAG_STRICT}, +{ "cstd", 0x2c001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT}, +{ "cstd", 0x2c001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT}, +{ "cstd", 0x2c001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT}, +{ "cstd", 0x2c001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT}, +{ "cldwx", 0x24000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT}, +{ "cldwx", 0x24000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT}, +{ "cldwx", 0x24000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT}, +{ "cldwx", 0x24000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT}, +{ "cldwx", 0x24000000, 0xfc00de00, "ucXx(b),t", pa10, 0}, +{ "cldwx", 0x24000000, 0xfc001e00, "ucXx(s,b),t", pa10, 0}, +{ "clddx", 0x2c000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT}, +{ "clddx", 0x2c000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT}, +{ "clddx", 0x2c000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT}, +{ "clddx", 0x2c000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT}, +{ "clddx", 0x2c000000, 0xfc00de00, "ucXx(b),t", pa10, 0}, +{ "clddx", 0x2c000000, 0xfc001e00, "ucXx(s,b),t", pa10, 0}, +{ "cstwx", 0x24000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT}, +{ "cstwx", 0x24000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT}, +{ "cstwx", 0x24000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT}, +{ "cstwx", 0x24000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT}, +{ "cstwx", 0x24000200, 0xfc00de00, "ucXt,x(b)", pa10, 0}, +{ "cstwx", 0x24000200, 0xfc001e00, "ucXt,x(s,b)", pa10, 0}, +{ "cstdx", 0x2c000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT}, +{ "cstdx", 0x2c000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT}, +{ "cstdx", 0x2c000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT}, +{ "cstdx", 0x2c000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT}, +{ "cstdx", 0x2c000200, 0xfc00de00, "ucXt,x(b)", pa10, 0}, +{ "cstdx", 0x2c000200, 0xfc001e00, "ucXt,x(s,b)", pa10, 0}, +{ "cldws", 0x24001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT}, +{ "cldws", 0x24001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT}, +{ "cldws", 0x24001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT}, +{ "cldws", 0x24001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "cldws", 0x24001000, 0xfc00de00, "ucM5(b),t", pa10, 0}, +{ "cldws", 0x24001000, 0xfc001e00, "ucM5(s,b),t", pa10, 0}, +{ "cldds", 0x2c001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT}, +{ "cldds", 0x2c001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT}, +{ "cldds", 0x2c001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT}, +{ "cldds", 0x2c001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "cldds", 0x2c001000, 0xfc00de00, "ucM5(b),t", pa10, 0}, +{ "cldds", 0x2c001000, 0xfc001e00, "ucM5(s,b),t", pa10, 0}, +{ "cstws", 0x24001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT}, +{ "cstws", 0x24001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT}, +{ "cstws", 0x24001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT}, +{ "cstws", 0x24001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT}, +{ "cstws", 0x24001200, 0xfc00de00, "ucMt,5(b)", pa10, 0}, +{ "cstws", 0x24001200, 0xfc001e00, "ucMt,5(s,b)", pa10, 0}, +{ "cstds", 0x2c001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT}, +{ "cstds", 0x2c001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT}, +{ "cstds", 0x2c001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT}, +{ "cstds", 0x2c001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT}, +{ "cstds", 0x2c001200, 0xfc00de00, "ucMt,5(b)", pa10, 0}, +{ "cstds", 0x2c001200, 0xfc001e00, "ucMt,5(s,b)", pa10, 0}, + +/* More pseudo instructions which must follow the main table. */ +{ "call", 0xe800f000, 0xfc1ffffd, "n(b)", pa20, FLAG_STRICT}, +{ "call", 0xe800a000, 0xffe0e000, "nW", pa10, FLAG_STRICT}, +{ "ret", 0xe840d000, 0xfffffffd, "n", pa20, FLAG_STRICT}, + +}; + +#define NUMOPCODES ((sizeof pa_opcodes)/(sizeof pa_opcodes[0])) + +/* SKV 12/18/92. Added some denotations for various operands. */ + +#define PA_IMM11_AT_31 'i' +#define PA_IMM14_AT_31 'j' +#define PA_IMM21_AT_31 'k' +#define PA_DISP12 'w' +#define PA_DISP17 'W' + +#define N_HPPA_OPERAND_FORMATS 5 + +/* Integer register names, indexed by the numbers which appear in the + opcodes. */ +static const char *const reg_names[] = +{ + "flags", "r1", "rp", "r3", "r4", "r5", "r6", "r7", "r8", "r9", + "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", + "r20", "r21", "r22", "r23", "r24", "r25", "r26", "dp", "ret0", "ret1", + "sp", "r31" +}; + +/* Floating point register names, indexed by the numbers which appear in the + opcodes. */ +static const char *const fp_reg_names[] = +{ + "fpsr", "fpe2", "fpe4", "fpe6", + "fr4", "fr5", "fr6", "fr7", "fr8", + "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15", + "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23", + "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31" +}; + +typedef unsigned int CORE_ADDR; + +/* Get at various relevent fields of an instruction word. */ + +#define MASK_5 0x1f +#define MASK_10 0x3ff +#define MASK_11 0x7ff +#define MASK_14 0x3fff +#define MASK_16 0xffff +#define MASK_21 0x1fffff + +/* These macros get bit fields using HP's numbering (MSB = 0). */ + +#define GET_FIELD(X, FROM, TO) \ + ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) + +#define GET_BIT(X, WHICH) \ + GET_FIELD (X, WHICH, WHICH) + +/* Some of these have been converted to 2-d arrays because they + consume less storage this way. If the maintenance becomes a + problem, convert them back to const 1-d pointer arrays. */ +static const char *const control_reg[] = +{ + "rctr", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", + "pidr1", "pidr2", "ccr", "sar", "pidr3", "pidr4", + "iva", "eiem", "itmr", "pcsq", "pcoq", "iir", "isr", + "ior", "ipsw", "eirr", "tr0", "tr1", "tr2", "tr3", + "tr4", "tr5", "tr6", "tr7" +}; + +static const char *const compare_cond_names[] = +{ + "", ",=", ",<", ",<=", ",<<", ",<<=", ",sv", ",od", + ",tr", ",<>", ",>=", ",>", ",>>=", ",>>", ",nsv", ",ev" +}; +static const char *const compare_cond_64_names[] = +{ + "", ",*=", ",*<", ",*<=", ",*<<", ",*<<=", ",*sv", ",*od", + ",*tr", ",*<>", ",*>=", ",*>", ",*>>=", ",*>>", ",*nsv", ",*ev" +}; +static const char *const cmpib_cond_64_names[] = +{ + ",*<<", ",*=", ",*<", ",*<=", ",*>>=", ",*<>", ",*>=", ",*>" +}; +static const char *const add_cond_names[] = +{ + "", ",=", ",<", ",<=", ",nuv", ",znv", ",sv", ",od", + ",tr", ",<>", ",>=", ",>", ",uv", ",vnz", ",nsv", ",ev" +}; +static const char *const add_cond_64_names[] = +{ + "", ",*=", ",*<", ",*<=", ",*nuv", ",*znv", ",*sv", ",*od", + ",*tr", ",*<>", ",*>=", ",*>", ",*uv", ",*vnz", ",*nsv", ",*ev" +}; +static const char *const wide_add_cond_names[] = +{ + "", ",=", ",<", ",<=", ",nuv", ",*=", ",*<", ",*<=", + ",tr", ",<>", ",>=", ",>", ",uv", ",*<>", ",*>=", ",*>" +}; +static const char *const logical_cond_names[] = +{ + "", ",=", ",<", ",<=", 0, 0, 0, ",od", + ",tr", ",<>", ",>=", ",>", 0, 0, 0, ",ev"}; +static const char *const logical_cond_64_names[] = +{ + "", ",*=", ",*<", ",*<=", 0, 0, 0, ",*od", + ",*tr", ",*<>", ",*>=", ",*>", 0, 0, 0, ",*ev"}; +static const char *const unit_cond_names[] = +{ + "", ",swz", ",sbz", ",shz", ",sdc", ",swc", ",sbc", ",shc", + ",tr", ",nwz", ",nbz", ",nhz", ",ndc", ",nwc", ",nbc", ",nhc" +}; +static const char *const unit_cond_64_names[] = +{ + "", ",*swz", ",*sbz", ",*shz", ",*sdc", ",*swc", ",*sbc", ",*shc", + ",*tr", ",*nwz", ",*nbz", ",*nhz", ",*ndc", ",*nwc", ",*nbc", ",*nhc" +}; +static const char *const shift_cond_names[] = +{ + "", ",=", ",<", ",od", ",tr", ",<>", ",>=", ",ev" +}; +static const char *const shift_cond_64_names[] = +{ + "", ",*=", ",*<", ",*od", ",*tr", ",*<>", ",*>=", ",*ev" +}; +static const char *const bb_cond_64_names[] = +{ + ",*<", ",*>=" +}; +static const char *const index_compl_names[] = {"", ",m", ",s", ",sm"}; +static const char *const short_ldst_compl_names[] = {"", ",ma", "", ",mb"}; +static const char *const short_bytes_compl_names[] = +{ + "", ",b,m", ",e", ",e,m" +}; +static const char *const float_format_names[] = {",sgl", ",dbl", "", ",quad"}; +static const char *const fcnv_fixed_names[] = {",w", ",dw", "", ",qw"}; +static const char *const fcnv_ufixed_names[] = {",uw", ",udw", "", ",uqw"}; +static const char *const float_comp_names[] = +{ + ",false?", ",false", ",?", ",!<=>", ",=", ",=t", ",?=", ",!<>", + ",!?>=", ",<", ",?<", ",!>=", ",!?>", ",<=", ",?<=", ",!>", + ",!?<=", ",>", ",?>", ",!<=", ",!?<", ",>=", ",?>=", ",!<", + ",!?=", ",<>", ",!=", ",!=t", ",!?", ",<=>", ",true?", ",true" +}; +static const char *const signed_unsigned_names[] = {",u", ",s"}; +static const char *const mix_half_names[] = {",l", ",r"}; +static const char *const saturation_names[] = {",us", ",ss", 0, ""}; +static const char *const read_write_names[] = {",r", ",w"}; +static const char *const add_compl_names[] = { 0, "", ",l", ",tsv" }; + +/* For a bunch of different instructions form an index into a + completer name table. */ +#define GET_COMPL(insn) (GET_FIELD (insn, 26, 26) | \ + GET_FIELD (insn, 18, 18) << 1) + +#define GET_COND(insn) (GET_FIELD ((insn), 16, 18) + \ + (GET_FIELD ((insn), 19, 19) ? 8 : 0)) + +/* Utility function to print registers. Put these first, so gcc's function + inlining can do its stuff. */ + +#define fputs_filtered(STR,F) (*info->fprintf_func) (info->stream, "%s", STR) + +static void +fput_reg (unsigned reg, disassemble_info *info) +{ + (*info->fprintf_func) (info->stream, reg ? reg_names[reg] : "r0"); +} + +static void +fput_fp_reg (unsigned reg, disassemble_info *info) +{ + (*info->fprintf_func) (info->stream, reg ? fp_reg_names[reg] : "fr0"); +} + +static void +fput_fp_reg_r (unsigned reg, disassemble_info *info) +{ + /* Special case floating point exception registers. */ + if (reg < 4) + (*info->fprintf_func) (info->stream, "fpe%d", reg * 2 + 1); + else + (*info->fprintf_func) (info->stream, "%sR", + reg ? fp_reg_names[reg] : "fr0"); +} + +static void +fput_creg (unsigned reg, disassemble_info *info) +{ + (*info->fprintf_func) (info->stream, control_reg[reg]); +} + +/* Print constants with sign. */ + +static void +fput_const (unsigned num, disassemble_info *info) +{ + if ((int) num < 0) + (*info->fprintf_func) (info->stream, "-%x", - (int) num); + else + (*info->fprintf_func) (info->stream, "%x", num); +} + +/* Routines to extract various sized constants out of hppa + instructions. */ + +/* Extract a 3-bit space register number from a be, ble, mtsp or mfsp. */ +static int +extract_3 (unsigned word) +{ + return GET_FIELD (word, 18, 18) << 2 | GET_FIELD (word, 16, 17); +} + +static int +extract_5_load (unsigned word) +{ + return low_sign_extend (word >> 16 & MASK_5, 5); +} + +/* Extract the immediate field from a st{bhw}s instruction. */ + +static int +extract_5_store (unsigned word) +{ + return low_sign_extend (word & MASK_5, 5); +} + +/* Extract the immediate field from a break instruction. */ + +static unsigned +extract_5r_store (unsigned word) +{ + return (word & MASK_5); +} + +/* Extract the immediate field from a {sr}sm instruction. */ + +static unsigned +extract_5R_store (unsigned word) +{ + return (word >> 16 & MASK_5); +} + +/* Extract the 10 bit immediate field from a {sr}sm instruction. */ + +static unsigned +extract_10U_store (unsigned word) +{ + return (word >> 16 & MASK_10); +} + +/* Extract the immediate field from a bb instruction. */ + +static unsigned +extract_5Q_store (unsigned word) +{ + return (word >> 21 & MASK_5); +} + +/* Extract an 11 bit immediate field. */ + +static int +extract_11 (unsigned word) +{ + return low_sign_extend (word & MASK_11, 11); +} + +/* Extract a 14 bit immediate field. */ + +static int +extract_14 (unsigned word) +{ + return low_sign_extend (word & MASK_14, 14); +} + +/* Extract a 16 bit immediate field (PA2.0 wide only). */ + +static int +extract_16 (unsigned word) +{ + int m15, m0, m1; + + m0 = GET_BIT (word, 16); + m1 = GET_BIT (word, 17); + m15 = GET_BIT (word, 31); + word = (word >> 1) & 0x1fff; + word = word | (m15 << 15) | ((m15 ^ m0) << 14) | ((m15 ^ m1) << 13); + return sign_extend (word, 16); +} + +/* Extract a 21 bit constant. */ + +static int +extract_21 (unsigned word) +{ + int val; + + word &= MASK_21; + word <<= 11; + val = GET_FIELD (word, 20, 20); + val <<= 11; + val |= GET_FIELD (word, 9, 19); + val <<= 2; + val |= GET_FIELD (word, 5, 6); + val <<= 5; + val |= GET_FIELD (word, 0, 4); + val <<= 2; + val |= GET_FIELD (word, 7, 8); + return sign_extend (val, 21) << 11; +} + +/* Extract a 12 bit constant from branch instructions. */ + +static int +extract_12 (unsigned word) +{ + return sign_extend (GET_FIELD (word, 19, 28) + | GET_FIELD (word, 29, 29) << 10 + | (word & 0x1) << 11, 12) << 2; +} + +/* Extract a 17 bit constant from branch instructions, returning the + 19 bit signed value. */ + +static int +extract_17 (unsigned word) +{ + return sign_extend (GET_FIELD (word, 19, 28) + | GET_FIELD (word, 29, 29) << 10 + | GET_FIELD (word, 11, 15) << 11 + | (word & 0x1) << 16, 17) << 2; +} + +static int +extract_22 (unsigned word) +{ + return sign_extend (GET_FIELD (word, 19, 28) + | GET_FIELD (word, 29, 29) << 10 + | GET_FIELD (word, 11, 15) << 11 + | GET_FIELD (word, 6, 10) << 16 + | (word & 0x1) << 21, 22) << 2; +} + +/* Print one instruction. */ + +int +print_insn_hppa (bfd_vma memaddr, disassemble_info *info) +{ + bfd_byte buffer[4]; + unsigned int insn, i; + + { + int status = + (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + } + + insn = bfd_getb32 (buffer); + + for (i = 0; i < NUMOPCODES; ++i) + { + const struct pa_opcode *opcode = &pa_opcodes[i]; + + if ((insn & opcode->mask) == opcode->match) + { + const char *s; +#ifndef BFD64 + if (opcode->arch == pa20w) + continue; +#endif + (*info->fprintf_func) (info->stream, "%s", opcode->name); + + if (!strchr ("cfCY?-+nHNZFIuv{", opcode->args[0])) + (*info->fprintf_func) (info->stream, " "); + for (s = opcode->args; *s != '\0'; ++s) + { + switch (*s) + { + case 'x': + fput_reg (GET_FIELD (insn, 11, 15), info); + break; + case 'a': + case 'b': + fput_reg (GET_FIELD (insn, 6, 10), info); + break; + case '^': + fput_creg (GET_FIELD (insn, 6, 10), info); + break; + case 't': + fput_reg (GET_FIELD (insn, 27, 31), info); + break; + + /* Handle floating point registers. */ + case 'f': + switch (*++s) + { + case 't': + fput_fp_reg (GET_FIELD (insn, 27, 31), info); + break; + case 'T': + if (GET_FIELD (insn, 25, 25)) + fput_fp_reg_r (GET_FIELD (insn, 27, 31), info); + else + fput_fp_reg (GET_FIELD (insn, 27, 31), info); + break; + case 'a': + if (GET_FIELD (insn, 25, 25)) + fput_fp_reg_r (GET_FIELD (insn, 6, 10), info); + else + fput_fp_reg (GET_FIELD (insn, 6, 10), info); + break; + + /* 'fA' will not generate a space before the regsiter + name. Normally that is fine. Except that it + causes problems with xmpyu which has no FP format + completer. */ + case 'X': + fputs_filtered (" ", info); + /* FALLTHRU */ + + case 'A': + if (GET_FIELD (insn, 24, 24)) + fput_fp_reg_r (GET_FIELD (insn, 6, 10), info); + else + fput_fp_reg (GET_FIELD (insn, 6, 10), info); + break; + case 'b': + if (GET_FIELD (insn, 25, 25)) + fput_fp_reg_r (GET_FIELD (insn, 11, 15), info); + else + fput_fp_reg (GET_FIELD (insn, 11, 15), info); + break; + case 'B': + if (GET_FIELD (insn, 19, 19)) + fput_fp_reg_r (GET_FIELD (insn, 11, 15), info); + else + fput_fp_reg (GET_FIELD (insn, 11, 15), info); + break; + case 'C': + { + int reg = GET_FIELD (insn, 21, 22); + reg |= GET_FIELD (insn, 16, 18) << 2; + if (GET_FIELD (insn, 23, 23) != 0) + fput_fp_reg_r (reg, info); + else + fput_fp_reg (reg, info); + break; + } + case 'i': + { + int reg = GET_FIELD (insn, 6, 10); + + reg |= (GET_FIELD (insn, 26, 26) << 4); + fput_fp_reg (reg, info); + break; + } + case 'j': + { + int reg = GET_FIELD (insn, 11, 15); + + reg |= (GET_FIELD (insn, 26, 26) << 4); + fput_fp_reg (reg, info); + break; + } + case 'k': + { + int reg = GET_FIELD (insn, 27, 31); + + reg |= (GET_FIELD (insn, 26, 26) << 4); + fput_fp_reg (reg, info); + break; + } + case 'l': + { + int reg = GET_FIELD (insn, 21, 25); + + reg |= (GET_FIELD (insn, 26, 26) << 4); + fput_fp_reg (reg, info); + break; + } + case 'm': + { + int reg = GET_FIELD (insn, 16, 20); + + reg |= (GET_FIELD (insn, 26, 26) << 4); + fput_fp_reg (reg, info); + break; + } + + /* 'fe' will not generate a space before the register + name. Normally that is fine. Except that it + causes problems with fstw fe,y(b) which has no FP + format completer. */ + case 'E': + fputs_filtered (" ", info); + /* FALLTHRU */ + + case 'e': + if (GET_FIELD (insn, 30, 30)) + fput_fp_reg_r (GET_FIELD (insn, 11, 15), info); + else + fput_fp_reg (GET_FIELD (insn, 11, 15), info); + break; + case 'x': + fput_fp_reg (GET_FIELD (insn, 11, 15), info); + break; + } + break; + + case '5': + fput_const (extract_5_load (insn), info); + break; + case 's': + { + int space = GET_FIELD (insn, 16, 17); + /* Zero means implicit addressing, not use of sr0. */ + if (space != 0) + (*info->fprintf_func) (info->stream, "sr%d", space); + } + break; + + case 'S': + (*info->fprintf_func) (info->stream, "sr%d", + extract_3 (insn)); + break; + + /* Handle completers. */ + case 'c': + switch (*++s) + { + case 'x': + (*info->fprintf_func) + (info->stream, "%s", + index_compl_names[GET_COMPL (insn)]); + break; + case 'X': + (*info->fprintf_func) + (info->stream, "%s ", + index_compl_names[GET_COMPL (insn)]); + break; + case 'm': + (*info->fprintf_func) + (info->stream, "%s", + short_ldst_compl_names[GET_COMPL (insn)]); + break; + case 'M': + (*info->fprintf_func) + (info->stream, "%s ", + short_ldst_compl_names[GET_COMPL (insn)]); + break; + case 'A': + (*info->fprintf_func) + (info->stream, "%s ", + short_bytes_compl_names[GET_COMPL (insn)]); + break; + case 's': + (*info->fprintf_func) + (info->stream, "%s", + short_bytes_compl_names[GET_COMPL (insn)]); + break; + case 'c': + case 'C': + switch (GET_FIELD (insn, 20, 21)) + { + case 1: + (*info->fprintf_func) (info->stream, ",bc "); + break; + case 2: + (*info->fprintf_func) (info->stream, ",sl "); + break; + default: + (*info->fprintf_func) (info->stream, " "); + } + break; + case 'd': + switch (GET_FIELD (insn, 20, 21)) + { + case 1: + (*info->fprintf_func) (info->stream, ",co "); + break; + default: + (*info->fprintf_func) (info->stream, " "); + } + break; + case 'o': + (*info->fprintf_func) (info->stream, ",o"); + break; + case 'g': + (*info->fprintf_func) (info->stream, ",gate"); + break; + case 'p': + (*info->fprintf_func) (info->stream, ",l,push"); + break; + case 'P': + (*info->fprintf_func) (info->stream, ",pop"); + break; + case 'l': + case 'L': + (*info->fprintf_func) (info->stream, ",l"); + break; + case 'w': + (*info->fprintf_func) + (info->stream, "%s ", + read_write_names[GET_FIELD (insn, 25, 25)]); + break; + case 'W': + (*info->fprintf_func) (info->stream, ",w "); + break; + case 'r': + if (GET_FIELD (insn, 23, 26) == 5) + (*info->fprintf_func) (info->stream, ",r"); + break; + case 'Z': + if (GET_FIELD (insn, 26, 26)) + (*info->fprintf_func) (info->stream, ",m "); + else + (*info->fprintf_func) (info->stream, " "); + break; + case 'i': + if (GET_FIELD (insn, 25, 25)) + (*info->fprintf_func) (info->stream, ",i"); + break; + case 'z': + if (!GET_FIELD (insn, 21, 21)) + (*info->fprintf_func) (info->stream, ",z"); + break; + case 'a': + (*info->fprintf_func) + (info->stream, "%s", + add_compl_names[GET_FIELD (insn, 20, 21)]); + break; + case 'Y': + (*info->fprintf_func) + (info->stream, ",dc%s", + add_compl_names[GET_FIELD (insn, 20, 21)]); + break; + case 'y': + (*info->fprintf_func) + (info->stream, ",c%s", + add_compl_names[GET_FIELD (insn, 20, 21)]); + break; + case 'v': + if (GET_FIELD (insn, 20, 20)) + (*info->fprintf_func) (info->stream, ",tsv"); + break; + case 't': + (*info->fprintf_func) (info->stream, ",tc"); + if (GET_FIELD (insn, 20, 20)) + (*info->fprintf_func) (info->stream, ",tsv"); + break; + case 'B': + (*info->fprintf_func) (info->stream, ",db"); + if (GET_FIELD (insn, 20, 20)) + (*info->fprintf_func) (info->stream, ",tsv"); + break; + case 'b': + (*info->fprintf_func) (info->stream, ",b"); + if (GET_FIELD (insn, 20, 20)) + (*info->fprintf_func) (info->stream, ",tsv"); + break; + case 'T': + if (GET_FIELD (insn, 25, 25)) + (*info->fprintf_func) (info->stream, ",tc"); + break; + case 'S': + /* EXTRD/W has a following condition. */ + if (*(s + 1) == '?') + (*info->fprintf_func) + (info->stream, "%s", + signed_unsigned_names[GET_FIELD (insn, 21, 21)]); + else + (*info->fprintf_func) + (info->stream, "%s ", + signed_unsigned_names[GET_FIELD (insn, 21, 21)]); + break; + case 'h': + (*info->fprintf_func) + (info->stream, "%s", + mix_half_names[GET_FIELD (insn, 17, 17)]); + break; + case 'H': + (*info->fprintf_func) + (info->stream, "%s ", + saturation_names[GET_FIELD (insn, 24, 25)]); + break; + case '*': + (*info->fprintf_func) + (info->stream, ",%d%d%d%d ", + GET_FIELD (insn, 17, 18), GET_FIELD (insn, 20, 21), + GET_FIELD (insn, 22, 23), GET_FIELD (insn, 24, 25)); + break; + + case 'q': + { + int m, a; + + m = GET_FIELD (insn, 28, 28); + a = GET_FIELD (insn, 29, 29); + + if (m && !a) + fputs_filtered (",ma ", info); + else if (m && a) + fputs_filtered (",mb ", info); + else + fputs_filtered (" ", info); + break; + } + + case 'J': + { + int opc = GET_FIELD (insn, 0, 5); + + if (opc == 0x16 || opc == 0x1e) + { + if (GET_FIELD (insn, 29, 29) == 0) + fputs_filtered (",ma ", info); + else + fputs_filtered (",mb ", info); + } + else + fputs_filtered (" ", info); + break; + } + + case 'e': + { + int opc = GET_FIELD (insn, 0, 5); + + if (opc == 0x13 || opc == 0x1b) + { + if (GET_FIELD (insn, 18, 18) == 1) + fputs_filtered (",mb ", info); + else + fputs_filtered (",ma ", info); + } + else if (opc == 0x17 || opc == 0x1f) + { + if (GET_FIELD (insn, 31, 31) == 1) + fputs_filtered (",ma ", info); + else + fputs_filtered (",mb ", info); + } + else + fputs_filtered (" ", info); + + break; + } + } + break; + + /* Handle conditions. */ + case '?': + { + s++; + switch (*s) + { + case 'f': + (*info->fprintf_func) + (info->stream, "%s ", + float_comp_names[GET_FIELD (insn, 27, 31)]); + break; + + /* These four conditions are for the set of instructions + which distinguish true/false conditions by opcode + rather than by the 'f' bit (sigh): comb, comib, + addb, addib. */ + case 't': + fputs_filtered + (compare_cond_names[GET_FIELD (insn, 16, 18)], info); + break; + case 'n': + fputs_filtered + (compare_cond_names[GET_FIELD (insn, 16, 18) + + GET_FIELD (insn, 4, 4) * 8], + info); + break; + case 'N': + fputs_filtered + (compare_cond_64_names[GET_FIELD (insn, 16, 18) + + GET_FIELD (insn, 2, 2) * 8], + info); + break; + case 'Q': + fputs_filtered + (cmpib_cond_64_names[GET_FIELD (insn, 16, 18)], + info); + break; + case '@': + fputs_filtered + (add_cond_names[GET_FIELD (insn, 16, 18) + + GET_FIELD (insn, 4, 4) * 8], + info); + break; + case 's': + (*info->fprintf_func) + (info->stream, "%s ", + compare_cond_names[GET_COND (insn)]); + break; + case 'S': + (*info->fprintf_func) + (info->stream, "%s ", + compare_cond_64_names[GET_COND (insn)]); + break; + case 'a': + (*info->fprintf_func) + (info->stream, "%s ", + add_cond_names[GET_COND (insn)]); + break; + case 'A': + (*info->fprintf_func) + (info->stream, "%s ", + add_cond_64_names[GET_COND (insn)]); + break; + case 'd': + (*info->fprintf_func) + (info->stream, "%s", + add_cond_names[GET_FIELD (insn, 16, 18)]); + break; + + case 'W': + (*info->fprintf_func) + (info->stream, "%s", + wide_add_cond_names[GET_FIELD (insn, 16, 18) + + GET_FIELD (insn, 4, 4) * 8]); + break; + + case 'l': + (*info->fprintf_func) + (info->stream, "%s ", + logical_cond_names[GET_COND (insn)]); + break; + case 'L': + (*info->fprintf_func) + (info->stream, "%s ", + logical_cond_64_names[GET_COND (insn)]); + break; + case 'u': + (*info->fprintf_func) + (info->stream, "%s ", + unit_cond_names[GET_COND (insn)]); + break; + case 'U': + (*info->fprintf_func) + (info->stream, "%s ", + unit_cond_64_names[GET_COND (insn)]); + break; + case 'y': + case 'x': + case 'b': + (*info->fprintf_func) + (info->stream, "%s", + shift_cond_names[GET_FIELD (insn, 16, 18)]); + + /* If the next character in args is 'n', it will handle + putting out the space. */ + if (s[1] != 'n') + (*info->fprintf_func) (info->stream, " "); + break; + case 'X': + (*info->fprintf_func) + (info->stream, "%s ", + shift_cond_64_names[GET_FIELD (insn, 16, 18)]); + break; + case 'B': + (*info->fprintf_func) + (info->stream, "%s", + bb_cond_64_names[GET_FIELD (insn, 16, 16)]); + + /* If the next character in args is 'n', it will handle + putting out the space. */ + if (s[1] != 'n') + (*info->fprintf_func) (info->stream, " "); + break; + } + break; + } + + case 'V': + fput_const (extract_5_store (insn), info); + break; + case 'r': + fput_const (extract_5r_store (insn), info); + break; + case 'R': + fput_const (extract_5R_store (insn), info); + break; + case 'U': + fput_const (extract_10U_store (insn), info); + break; + case 'B': + case 'Q': + fput_const (extract_5Q_store (insn), info); + break; + case 'i': + fput_const (extract_11 (insn), info); + break; + case 'j': + fput_const (extract_14 (insn), info); + break; + case 'k': + fputs_filtered ("L%", info); + fput_const (extract_21 (insn), info); + break; + case '<': + case 'l': + /* 16-bit long disp., PA2.0 wide only. */ + fput_const (extract_16 (insn), info); + break; + case 'n': + if (insn & 0x2) + (*info->fprintf_func) (info->stream, ",n "); + else + (*info->fprintf_func) (info->stream, " "); + break; + case 'N': + if ((insn & 0x20) && s[1]) + (*info->fprintf_func) (info->stream, ",n "); + else if (insn & 0x20) + (*info->fprintf_func) (info->stream, ",n"); + else if (s[1]) + (*info->fprintf_func) (info->stream, " "); + break; + case 'w': + (*info->print_address_func) + (memaddr + 8 + extract_12 (insn), info); + break; + case 'W': + /* 17 bit PC-relative branch. */ + (*info->print_address_func) + ((memaddr + 8 + extract_17 (insn)), info); + break; + case 'z': + /* 17 bit displacement. This is an offset from a register + so it gets disasssembled as just a number, not any sort + of address. */ + fput_const (extract_17 (insn), info); + break; + + case 'Z': + /* addil %r1 implicit output. */ + fputs_filtered ("r1", info); + break; + + case 'Y': + /* be,l %sr0,%r31 implicit output. */ + fputs_filtered ("sr0,r31", info); + break; + + case '@': + (*info->fprintf_func) (info->stream, "0"); + break; + + case '.': + (*info->fprintf_func) (info->stream, "%d", + GET_FIELD (insn, 24, 25)); + break; + case '*': + (*info->fprintf_func) (info->stream, "%d", + GET_FIELD (insn, 22, 25)); + break; + case '!': + fputs_filtered ("sar", info); + break; + case 'p': + (*info->fprintf_func) (info->stream, "%d", + 31 - GET_FIELD (insn, 22, 26)); + break; + case '~': + { + int num; + num = GET_FIELD (insn, 20, 20) << 5; + num |= GET_FIELD (insn, 22, 26); + (*info->fprintf_func) (info->stream, "%d", 63 - num); + break; + } + case 'P': + (*info->fprintf_func) (info->stream, "%d", + GET_FIELD (insn, 22, 26)); + break; + case 'q': + { + int num; + num = GET_FIELD (insn, 20, 20) << 5; + num |= GET_FIELD (insn, 22, 26); + (*info->fprintf_func) (info->stream, "%d", num); + break; + } + case 'T': + (*info->fprintf_func) (info->stream, "%d", + 32 - GET_FIELD (insn, 27, 31)); + break; + case '%': + { + int num; + num = (GET_FIELD (insn, 23, 23) + 1) * 32; + num -= GET_FIELD (insn, 27, 31); + (*info->fprintf_func) (info->stream, "%d", num); + break; + } + case '|': + { + int num; + num = (GET_FIELD (insn, 19, 19) + 1) * 32; + num -= GET_FIELD (insn, 27, 31); + (*info->fprintf_func) (info->stream, "%d", num); + break; + } + case '$': + fput_const (GET_FIELD (insn, 20, 28), info); + break; + case 'A': + fput_const (GET_FIELD (insn, 6, 18), info); + break; + case 'D': + fput_const (GET_FIELD (insn, 6, 31), info); + break; + case 'v': + (*info->fprintf_func) (info->stream, ",%d", + GET_FIELD (insn, 23, 25)); + break; + case 'O': + fput_const ((GET_FIELD (insn, 6,20) << 5 | + GET_FIELD (insn, 27, 31)), info); + break; + case 'o': + fput_const (GET_FIELD (insn, 6, 20), info); + break; + case '2': + fput_const ((GET_FIELD (insn, 6, 22) << 5 | + GET_FIELD (insn, 27, 31)), info); + break; + case '1': + fput_const ((GET_FIELD (insn, 11, 20) << 5 | + GET_FIELD (insn, 27, 31)), info); + break; + case '0': + fput_const ((GET_FIELD (insn, 16, 20) << 5 | + GET_FIELD (insn, 27, 31)), info); + break; + case 'u': + (*info->fprintf_func) (info->stream, ",%d", + GET_FIELD (insn, 23, 25)); + break; + case 'F': + /* If no destination completer and not before a completer + for fcmp, need a space here. */ + if (s[1] == 'G' || s[1] == '?') + fputs_filtered + (float_format_names[GET_FIELD (insn, 19, 20)], info); + else + (*info->fprintf_func) + (info->stream, "%s ", + float_format_names[GET_FIELD (insn, 19, 20)]); + break; + case 'G': + (*info->fprintf_func) + (info->stream, "%s ", + float_format_names[GET_FIELD (insn, 17, 18)]); + break; + case 'H': + if (GET_FIELD (insn, 26, 26) == 1) + (*info->fprintf_func) (info->stream, "%s ", + float_format_names[0]); + else + (*info->fprintf_func) (info->stream, "%s ", + float_format_names[1]); + break; + case 'I': + /* If no destination completer and not before a completer + for fcmp, need a space here. */ + if (s[1] == '?') + fputs_filtered + (float_format_names[GET_FIELD (insn, 20, 20)], info); + else + (*info->fprintf_func) + (info->stream, "%s ", + float_format_names[GET_FIELD (insn, 20, 20)]); + break; + + case 'J': + fput_const (extract_14 (insn), info); + break; + + case '#': + { + int sign = GET_FIELD (insn, 31, 31); + int imm10 = GET_FIELD (insn, 18, 27); + int disp; + + if (sign) + disp = (-1 << 10) | imm10; + else + disp = imm10; + + disp <<= 3; + fput_const (disp, info); + break; + } + case 'K': + case 'd': + { + int sign = GET_FIELD (insn, 31, 31); + int imm11 = GET_FIELD (insn, 18, 28); + int disp; + + if (sign) + disp = (-1 << 11) | imm11; + else + disp = imm11; + + disp <<= 2; + fput_const (disp, info); + break; + } + + case '>': + case 'y': + { + /* 16-bit long disp., PA2.0 wide only. */ + int disp = extract_16 (insn); + disp &= ~3; + fput_const (disp, info); + break; + } + + case '&': + { + /* 16-bit long disp., PA2.0 wide only. */ + int disp = extract_16 (insn); + disp &= ~7; + fput_const (disp, info); + break; + } + + case '_': + break; /* Dealt with by '{' */ + + case '{': + { + int sub = GET_FIELD (insn, 14, 16); + int df = GET_FIELD (insn, 17, 18); + int sf = GET_FIELD (insn, 19, 20); + const char * const * source = float_format_names; + const char * const * dest = float_format_names; + char *t = ""; + + if (sub == 4) + { + fputs_filtered (",UND ", info); + break; + } + if ((sub & 3) == 3) + t = ",t"; + if ((sub & 3) == 1) + source = sub & 4 ? fcnv_ufixed_names : fcnv_fixed_names; + if (sub & 2) + dest = sub & 4 ? fcnv_ufixed_names : fcnv_fixed_names; + + (*info->fprintf_func) (info->stream, "%s%s%s ", + t, source[sf], dest[df]); + break; + } + + case 'm': + { + int y = GET_FIELD (insn, 16, 18); + + if (y != 1) + fput_const ((y ^ 1) - 1, info); + } + break; + + case 'h': + { + int cbit; + + cbit = GET_FIELD (insn, 16, 18); + + if (cbit > 0) + (*info->fprintf_func) (info->stream, ",%d", cbit - 1); + break; + } + + case '=': + { + int cond = GET_FIELD (insn, 27, 31); + + switch (cond) + { + case 0: fputs_filtered (" ", info); break; + case 1: fputs_filtered ("acc ", info); break; + case 2: fputs_filtered ("rej ", info); break; + case 5: fputs_filtered ("acc8 ", info); break; + case 6: fputs_filtered ("rej8 ", info); break; + case 9: fputs_filtered ("acc6 ", info); break; + case 13: fputs_filtered ("acc4 ", info); break; + case 17: fputs_filtered ("acc2 ", info); break; + default: break; + } + break; + } + + case 'X': + (*info->print_address_func) + (memaddr + 8 + extract_22 (insn), info); + break; + case 'L': + fputs_filtered (",rp", info); + break; + default: + (*info->fprintf_func) (info->stream, "%c", *s); + break; + } + } + return sizeof (insn); + } + } + (*info->fprintf_func) (info->stream, "#%8x", insn); + return sizeof (insn); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hppa.ld /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hppa.ld --- qemu-0.9.1/hppa.ld 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hppa.ld 2008-04-12 21:14:54.000000000 +0100 @@ -0,0 +1,214 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf32-hppa-linux", "elf32-hppa-linux", + "elf32-hppa-linux") +OUTPUT_ARCH(hppa:hppa1.1) +ENTRY(_start) +SEARCH_DIR("/usr/hppa-linux-gnu/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib"); +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) } + .rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x08000240 + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x08000240 + .fini : + { + KEEP (*(.fini)) + } =0x08000240 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : + { + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .PARISC.unwind : { *(.PARISC.unwind) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x10000) + (. & (0x10000 - 1)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin*.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .data : + { + PROVIDE ($global$ = .); + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .plt : { *(.plt) } + .got : { *(.got.plt) *(.got) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + _edata = .; PROVIDE (edata = .); + __bss_start = .; + .sbss : + { + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); + } + . = ALIGN(32 / 8); + . = ALIGN(32 / 8); + _end = .; PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ac97.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ac97.c --- qemu-0.9.1/hw/ac97.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/ac97.c 2008-06-21 18:14:50.000000000 +0100 @@ -0,0 +1,1385 @@ +/* + * Copyright (C) 2006 InnoTek Systemberatung GmbH + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation, + * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE + * distribution. VirtualBox OSE is distributed in the hope that it will + * be useful, but WITHOUT ANY WARRANTY of any kind. + * + * If you received this file as part of a commercial VirtualBox + * distribution, then only the terms of your commercial VirtualBox + * license agreement apply instead of the previous paragraph. + */ + +#include "hw.h" +#include "audiodev.h" +#include "audio/audio.h" +#include "pci.h" + +enum { + AC97_Reset = 0x00, + AC97_Master_Volume_Mute = 0x02, + AC97_Headphone_Volume_Mute = 0x04, + AC97_Master_Volume_Mono_Mute = 0x06, + AC97_Master_Tone_RL = 0x08, + AC97_PC_BEEP_Volume_Mute = 0x0A, + AC97_Phone_Volume_Mute = 0x0C, + AC97_Mic_Volume_Mute = 0x0E, + AC97_Line_In_Volume_Mute = 0x10, + AC97_CD_Volume_Mute = 0x12, + AC97_Video_Volume_Mute = 0x14, + AC97_Aux_Volume_Mute = 0x16, + AC97_PCM_Out_Volume_Mute = 0x18, + AC97_Record_Select = 0x1A, + AC97_Record_Gain_Mute = 0x1C, + AC97_Record_Gain_Mic_Mute = 0x1E, + AC97_General_Purpose = 0x20, + AC97_3D_Control = 0x22, + AC97_AC_97_RESERVED = 0x24, + AC97_Powerdown_Ctrl_Stat = 0x26, + AC97_Extended_Audio_ID = 0x28, + AC97_Extended_Audio_Ctrl_Stat = 0x2A, + AC97_PCM_Front_DAC_Rate = 0x2C, + AC97_PCM_Surround_DAC_Rate = 0x2E, + AC97_PCM_LFE_DAC_Rate = 0x30, + AC97_PCM_LR_ADC_Rate = 0x32, + AC97_MIC_ADC_Rate = 0x34, + AC97_6Ch_Vol_C_LFE_Mute = 0x36, + AC97_6Ch_Vol_L_R_Surround_Mute = 0x38, + AC97_Vendor_Reserved = 0x58, + AC97_Vendor_ID1 = 0x7c, + AC97_Vendor_ID2 = 0x7e +}; + +#define SOFT_VOLUME +#define SR_FIFOE 16 /* rwc */ +#define SR_BCIS 8 /* rwc */ +#define SR_LVBCI 4 /* rwc */ +#define SR_CELV 2 /* ro */ +#define SR_DCH 1 /* ro */ +#define SR_VALID_MASK ((1 << 5) - 1) +#define SR_WCLEAR_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI) +#define SR_RO_MASK (SR_DCH | SR_CELV) +#define SR_INT_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI) + +#define CR_IOCE 16 /* rw */ +#define CR_FEIE 8 /* rw */ +#define CR_LVBIE 4 /* rw */ +#define CR_RR 2 /* rw */ +#define CR_RPBM 1 /* rw */ +#define CR_VALID_MASK ((1 << 5) - 1) +#define CR_DONT_CLEAR_MASK (CR_IOCE | CR_FEIE | CR_LVBIE) + +#define GC_WR 4 /* rw */ +#define GC_CR 2 /* rw */ +#define GC_VALID_MASK ((1 << 6) - 1) + +#define GS_MD3 (1<<17) /* rw */ +#define GS_AD3 (1<<16) /* rw */ +#define GS_RCS (1<<15) /* rwc */ +#define GS_B3S12 (1<<14) /* ro */ +#define GS_B2S12 (1<<13) /* ro */ +#define GS_B1S12 (1<<12) /* ro */ +#define GS_S1R1 (1<<11) /* rwc */ +#define GS_S0R1 (1<<10) /* rwc */ +#define GS_S1CR (1<<9) /* ro */ +#define GS_S0CR (1<<8) /* ro */ +#define GS_MINT (1<<7) /* ro */ +#define GS_POINT (1<<6) /* ro */ +#define GS_PIINT (1<<5) /* ro */ +#define GS_RSRVD ((1<<4)|(1<<3)) +#define GS_MOINT (1<<2) /* ro */ +#define GS_MIINT (1<<1) /* ro */ +#define GS_GSCI 1 /* rwc */ +#define GS_RO_MASK (GS_B3S12| \ + GS_B2S12| \ + GS_B1S12| \ + GS_S1CR| \ + GS_S0CR| \ + GS_MINT| \ + GS_POINT| \ + GS_PIINT| \ + GS_RSRVD| \ + GS_MOINT| \ + GS_MIINT) +#define GS_VALID_MASK ((1 << 18) - 1) +#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI) + +#define BD_IOC (1<<31) +#define BD_BUP (1<<30) + +#define EACS_VRA 1 +#define EACS_VRM 8 + +#define VOL_MASK 0x1f +#define MUTE_SHIFT 15 + +#define REC_MASK 7 +enum { + REC_MIC = 0, + REC_CD, + REC_VIDEO, + REC_AUX, + REC_LINE_IN, + REC_STEREO_MIX, + REC_MONO_MIX, + REC_PHONE +}; + +typedef struct BD { + uint32_t addr; + uint32_t ctl_len; +} BD; + +typedef struct AC97BusMasterRegs { + uint32_t bdbar; /* rw 0 */ + uint8_t civ; /* ro 0 */ + uint8_t lvi; /* rw 0 */ + uint16_t sr; /* rw 1 */ + uint16_t picb; /* ro 0 */ + uint8_t piv; /* ro 0 */ + uint8_t cr; /* rw 0 */ + unsigned int bd_valid; + BD bd; +} AC97BusMasterRegs; + +typedef struct AC97LinkState { + PCIDevice *pci_dev; + QEMUSoundCard card; + uint32_t glob_cnt; + uint32_t glob_sta; + uint32_t cas; + uint32_t last_samp; + AC97BusMasterRegs bm_regs[3]; + uint8_t mixer_data[256]; + SWVoiceIn *voice_pi; + SWVoiceOut *voice_po; + SWVoiceIn *voice_mc; + int invalid_freq[3]; + uint8_t silence[128]; + uint32_t base[2]; + int bup_flag; +} AC97LinkState; + +enum { + BUP_SET = 1, + BUP_LAST = 2 +}; + +#ifdef DEBUG_AC97 +#define dolog(...) AUD_log ("ac97", __VA_ARGS__) +#else +#define dolog(...) +#endif + +typedef struct PCIAC97LinkState { + PCIDevice dev; + AC97LinkState ac97; +} PCIAC97LinkState; + +#define MKREGS(prefix, start) \ +enum { \ + prefix ## _BDBAR = start, \ + prefix ## _CIV = start + 4, \ + prefix ## _LVI = start + 5, \ + prefix ## _SR = start + 6, \ + prefix ## _PICB = start + 8, \ + prefix ## _PIV = start + 10, \ + prefix ## _CR = start + 11 \ +} + +enum { + PI_INDEX = 0, + PO_INDEX, + MC_INDEX, + LAST_INDEX +}; + +MKREGS (PI, PI_INDEX * 16); +MKREGS (PO, PO_INDEX * 16); +MKREGS (MC, MC_INDEX * 16); + +enum { + GLOB_CNT = 0x2c, + GLOB_STA = 0x30, + CAS = 0x34 +}; + +#define GET_BM(index) (((index) >> 4) & 3) + +static void po_callback (void *opaque, int free); +static void pi_callback (void *opaque, int avail); +static void mc_callback (void *opaque, int avail); + +static void warm_reset (AC97LinkState *s) +{ + (void) s; +} + +static void cold_reset (AC97LinkState * s) +{ + (void) s; +} + +static void fetch_bd (AC97LinkState *s, AC97BusMasterRegs *r) +{ + uint8_t b[8]; + + cpu_physical_memory_read (r->bdbar + r->civ * 8, b, 8); + r->bd_valid = 1; + r->bd.addr = le32_to_cpu (*(uint32_t *) &b[0]) & ~3; + r->bd.ctl_len = le32_to_cpu (*(uint32_t *) &b[4]); + r->picb = r->bd.ctl_len & 0xffff; + dolog ("bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n", + r->civ, r->bd.addr, r->bd.ctl_len >> 16, + r->bd.ctl_len & 0xffff, + (r->bd.ctl_len & 0xffff) << 1); +} + +static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr) +{ + int event = 0; + int level = 0; + uint32_t new_mask = new_sr & SR_INT_MASK; + uint32_t old_mask = r->sr & SR_INT_MASK; + uint32_t masks[] = {GS_PIINT, GS_POINT, GS_MINT}; + + if (new_mask ^ old_mask) { + /** @todo is IRQ deasserted when only one of status bits is cleared? */ + if (!new_mask) { + event = 1; + level = 0; + } + else { + if ((new_mask & SR_LVBCI) && (r->cr & CR_LVBIE)) { + event = 1; + level = 1; + } + if ((new_mask & SR_BCIS) && (r->cr & CR_IOCE)) { + event = 1; + level = 1; + } + } + } + + r->sr = new_sr; + + dolog ("IOC%d LVB%d sr=%#x event=%d level=%d\n", + r->sr & SR_BCIS, r->sr & SR_LVBCI, + r->sr, + event, level); + + if (!event) + return; + + if (level) { + s->glob_sta |= masks[r - s->bm_regs]; + dolog ("set irq level=1\n"); + qemu_set_irq(s->pci_dev->irq[0], 1); + } + else { + s->glob_sta &= ~masks[r - s->bm_regs]; + dolog ("set irq level=0\n"); + qemu_set_irq(s->pci_dev->irq[0], 0); + } +} + +static void voice_set_active (AC97LinkState *s, int bm_index, int on) +{ + switch (bm_index) { + case PI_INDEX: + AUD_set_active_in (s->voice_pi, on); + break; + + case PO_INDEX: + AUD_set_active_out (s->voice_po, on); + break; + + case MC_INDEX: + AUD_set_active_in (s->voice_mc, on); + break; + + default: + AUD_log ("ac97", "invalid bm_index(%d) in voice_set_active", bm_index); + break; + } +} + +static void reset_bm_regs (AC97LinkState *s, AC97BusMasterRegs *r) +{ + dolog ("reset_bm_regs\n"); + r->bdbar = 0; + r->civ = 0; + r->lvi = 0; + /** todo do we need to do that? */ + update_sr (s, r, SR_DCH); + r->picb = 0; + r->piv = 0; + r->cr = r->cr & CR_DONT_CLEAR_MASK; + r->bd_valid = 0; + + voice_set_active (s, r - s->bm_regs, 0); + memset (s->silence, 0, sizeof (s->silence)); +} + +static void mixer_store (AC97LinkState *s, uint32_t i, uint16_t v) +{ + if (i + 2 > sizeof (s->mixer_data)) { + dolog ("mixer_store: index %d out of bounds %d\n", + i, sizeof (s->mixer_data)); + return; + } + + s->mixer_data[i + 0] = v & 0xff; + s->mixer_data[i + 1] = v >> 8; +} + +static uint16_t mixer_load (AC97LinkState *s, uint32_t i) +{ + uint16_t val = 0xffff; + + if (i + 2 > sizeof (s->mixer_data)) { + dolog ("mixer_store: index %d out of bounds %d\n", + i, sizeof (s->mixer_data)); + } + else { + val = s->mixer_data[i + 0] | (s->mixer_data[i + 1] << 8); + } + + return val; +} + +static void open_voice (AC97LinkState *s, int index, int freq) +{ + audsettings_t as; + + as.freq = freq; + as.nchannels = 2; + as.fmt = AUD_FMT_S16; + as.endianness = 0; + + if (freq > 0) { + s->invalid_freq[index] = 0; + switch (index) { + case PI_INDEX: + s->voice_pi = AUD_open_in ( + &s->card, + s->voice_pi, + "ac97.pi", + s, + pi_callback, + &as + ); + break; + + case PO_INDEX: + s->voice_po = AUD_open_out ( + &s->card, + s->voice_po, + "ac97.po", + s, + po_callback, + &as + ); + break; + + case MC_INDEX: + s->voice_mc = AUD_open_in ( + &s->card, + s->voice_mc, + "ac97.mc", + s, + mc_callback, + &as + ); + break; + } + } + else { + s->invalid_freq[index] = freq; + switch (index) { + case PI_INDEX: + AUD_close_in (&s->card, s->voice_pi); + s->voice_pi = NULL; + break; + + case PO_INDEX: + AUD_close_out (&s->card, s->voice_po); + s->voice_po = NULL; + break; + + case MC_INDEX: + AUD_close_in (&s->card, s->voice_mc); + s->voice_mc = NULL; + break; + } + } +} + +static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) +{ + uint16_t freq; + + freq = mixer_load (s, AC97_PCM_LR_ADC_Rate); + open_voice (s, PI_INDEX, freq); + AUD_set_active_in (s->voice_pi, active[PI_INDEX]); + + freq = mixer_load (s, AC97_PCM_Front_DAC_Rate); + open_voice (s, PO_INDEX, freq); + AUD_set_active_out (s->voice_po, active[PO_INDEX]); + + freq = mixer_load (s, AC97_MIC_ADC_Rate); + open_voice (s, MC_INDEX, freq); + AUD_set_active_in (s->voice_mc, active[MC_INDEX]); +} + +#ifdef USE_MIXER +static void set_volume (AC97LinkState *s, int index, + audmixerctl_t mt, uint32_t val) +{ + int mute = (val >> MUTE_SHIFT) & 1; + uint8_t rvol = VOL_MASK - (val & VOL_MASK); + uint8_t lvol = VOL_MASK - ((val >> 8) & VOL_MASK); + rvol = 255 * rvol / VOL_MASK; + lvol = 255 * lvol / VOL_MASK; + +#ifdef SOFT_VOLUME + if (index == AC97_Master_Volume_Mute) { + AUD_set_volume_out (s->voice_po, mute, lvol, rvol); + } + else { + AUD_set_volume (mt, &mute, &lvol, &rvol); + } +#else + AUD_set_volume (mt, &mute, &lvol, &rvol); +#endif + + rvol = VOL_MASK - ((VOL_MASK * rvol) / 255); + lvol = VOL_MASK - ((VOL_MASK * lvol) / 255); + mixer_store (s, index, val); +} + +static audrecsource_t ac97_to_aud_record_source (uint8_t i) +{ + switch (i) { + case REC_MIC: + return AUD_REC_MIC; + + case REC_CD: + return AUD_REC_CD; + + case REC_VIDEO: + return AUD_REC_VIDEO; + + case REC_AUX: + return AUD_REC_AUX; + + case REC_LINE_IN: + return AUD_REC_LINE_IN; + + case REC_PHONE: + return AUD_REC_PHONE; + + default: + dolog ("Unknown record source %d, using MIC\n", i); + return AUD_REC_MIC; + } +} + +static uint8_t aud_to_ac97_record_source (audrecsource_t rs) +{ + switch (rs) { + case AUD_REC_MIC: + return REC_MIC; + + case AUD_REC_CD: + return REC_CD; + + case AUD_REC_VIDEO: + return REC_VIDEO; + + case AUD_REC_AUX: + return REC_AUX; + + case AUD_REC_LINE_IN: + return REC_LINE_IN; + + case AUD_REC_PHONE: + return REC_PHONE; + + default: + dolog ("Unknown audio recording source %d using MIC\n", rs); + return REC_MIC; + } +} + +static void record_select (AC97LinkState *s, uint32_t val) +{ + uint8_t rs = val & REC_MASK; + uint8_t ls = (val >> 8) & REC_MASK; + audrecsource_t ars = ac97_to_aud_record_source (rs); + audrecsource_t als = ac97_to_aud_record_source (ls); + AUD_set_record_source (&als, &ars); + rs = aud_to_ac97_record_source (ars); + ls = aud_to_ac97_record_source (als); + mixer_store (s, AC97_Record_Select, rs | (ls << 8)); +} +#endif + +static void mixer_reset (AC97LinkState *s) +{ + uint8_t active[LAST_INDEX]; + + dolog ("mixer_reset\n"); + memset (s->mixer_data, 0, sizeof (s->mixer_data)); + memset (active, 0, sizeof (active)); + mixer_store (s, AC97_Reset , 0x0000); /* 6940 */ + mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x8000); + mixer_store (s, AC97_PC_BEEP_Volume_Mute , 0x0000); + + mixer_store (s, AC97_Phone_Volume_Mute , 0x8008); + mixer_store (s, AC97_Mic_Volume_Mute , 0x8008); + mixer_store (s, AC97_CD_Volume_Mute , 0x8808); + mixer_store (s, AC97_Aux_Volume_Mute , 0x8808); + mixer_store (s, AC97_Record_Gain_Mic_Mute , 0x8000); + mixer_store (s, AC97_General_Purpose , 0x0000); + mixer_store (s, AC97_3D_Control , 0x0000); + mixer_store (s, AC97_Powerdown_Ctrl_Stat , 0x000f); + + /* + * Sigmatel 9700 (STAC9700) + */ + mixer_store (s, AC97_Vendor_ID1 , 0x8384); + mixer_store (s, AC97_Vendor_ID2 , 0x7600); /* 7608 */ + + mixer_store (s, AC97_Extended_Audio_ID , 0x0809); + mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, 0x0009); + mixer_store (s, AC97_PCM_Front_DAC_Rate , 0xbb80); + mixer_store (s, AC97_PCM_Surround_DAC_Rate , 0xbb80); + mixer_store (s, AC97_PCM_LFE_DAC_Rate , 0xbb80); + mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); + mixer_store (s, AC97_MIC_ADC_Rate , 0xbb80); + +#ifdef USE_MIXER + record_select (s, 0); + set_volume (s, AC97_Master_Volume_Mute, AUD_MIXER_VOLUME , 0x8000); + set_volume (s, AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM , 0x8808); + set_volume (s, AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN, 0x8808); +#endif + reset_voices (s, active); +} + +/** + * Native audio mixer + * I/O Reads + */ +static uint32_t nam_readb (void *opaque, uint32_t addr) +{ + PCIAC97LinkState *d = opaque; + AC97LinkState *s = &d->ac97; + dolog ("U nam readb %#x\n", addr); + s->cas = 0; + return ~0U; +} + +static uint32_t nam_readw (void *opaque, uint32_t addr) +{ + PCIAC97LinkState *d = opaque; + AC97LinkState *s = &d->ac97; + uint32_t val = ~0U; + uint32_t index = addr - s->base[0]; + s->cas = 0; + val = mixer_load (s, index); + return val; +} + +static uint32_t nam_readl (void *opaque, uint32_t addr) +{ + PCIAC97LinkState *d = opaque; + AC97LinkState *s = &d->ac97; + dolog ("U nam readl %#x\n", addr); + s->cas = 0; + return ~0U; +} + +/** + * Native audio mixer + * I/O Writes + */ +static void nam_writeb (void *opaque, uint32_t addr, uint32_t val) +{ + PCIAC97LinkState *d = opaque; + AC97LinkState *s = &d->ac97; + dolog ("U nam writeb %#x <- %#x\n", addr, val); + s->cas = 0; +} + +static void nam_writew (void *opaque, uint32_t addr, uint32_t val) +{ + PCIAC97LinkState *d = opaque; + AC97LinkState *s = &d->ac97; + uint32_t index = addr - s->base[0]; + s->cas = 0; + switch (index) { + case AC97_Reset: + mixer_reset (s); + break; + case AC97_Powerdown_Ctrl_Stat: + val &= ~0xf; + val |= mixer_load (s, index) & 0xf; + mixer_store (s, index, val); + break; +#ifdef USE_MIXER + case AC97_Master_Volume_Mute: + set_volume (s, index, AUD_MIXER_VOLUME, val); + break; + case AC97_PCM_Out_Volume_Mute: + set_volume (s, index, AUD_MIXER_PCM, val); + break; + case AC97_Line_In_Volume_Mute: + set_volume (s, index, AUD_MIXER_LINE_IN, val); + break; + case AC97_Record_Select: + record_select (s, val); + break; +#endif + case AC97_Vendor_ID1: + case AC97_Vendor_ID2: + dolog ("Attempt to write vendor ID to %#x\n", val); + break; + case AC97_Extended_Audio_ID: + dolog ("Attempt to write extended audio ID to %#x\n", val); + break; + case AC97_Extended_Audio_Ctrl_Stat: + if (!(val & EACS_VRA)) { + mixer_store (s, AC97_PCM_Front_DAC_Rate, 0xbb80); + mixer_store (s, AC97_PCM_LR_ADC_Rate, 0xbb80); + open_voice (s, PI_INDEX, 48000); + open_voice (s, PO_INDEX, 48000); + } + if (!(val & EACS_VRM)) { + mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80); + open_voice (s, MC_INDEX, 48000); + } + dolog ("Setting extended audio control to %#x\n", val); + mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, val); + break; + case AC97_PCM_Front_DAC_Rate: + if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { + mixer_store (s, index, val); + dolog ("Set front DAC rate to %d\n", val); + open_voice (s, PO_INDEX, val); + } + else { + dolog ("Attempt to set front DAC rate to %d, " + "but VRA is not set\n", + val); + } + break; + case AC97_MIC_ADC_Rate: + if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM) { + mixer_store (s, index, val); + dolog ("Set MIC ADC rate to %d\n", val); + open_voice (s, MC_INDEX, val); + } + else { + dolog ("Attempt to set MIC ADC rate to %d, " + "but VRM is not set\n", + val); + } + break; + case AC97_PCM_LR_ADC_Rate: + if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { + mixer_store (s, index, val); + dolog ("Set front LR ADC rate to %d\n", val); + open_voice (s, PI_INDEX, val); + } + else { + dolog ("Attempt to set LR ADC rate to %d, but VRA is not set\n", + val); + } + break; + default: + dolog ("U nam writew %#x <- %#x\n", addr, val); + mixer_store (s, index, val); + break; + } +} + +static void nam_writel (void *opaque, uint32_t addr, uint32_t val) +{ + PCIAC97LinkState *d = opaque; + AC97LinkState *s = &d->ac97; + dolog ("U nam writel %#x <- %#x\n", addr, val); + s->cas = 0; +} + +/** + * Native audio bus master + * I/O Reads + */ +static uint32_t nabm_readb (void *opaque, uint32_t addr) +{ + PCIAC97LinkState *d = opaque; + AC97LinkState *s = &d->ac97; + AC97BusMasterRegs *r = NULL; + uint32_t index = addr - s->base[1]; + uint32_t val = ~0U; + + switch (index) { + case CAS: + dolog ("CAS %d\n", s->cas); + val = s->cas; + s->cas = 1; + break; + case PI_CIV: + case PO_CIV: + case MC_CIV: + r = &s->bm_regs[GET_BM (index)]; + val = r->civ; + dolog ("CIV[%d] -> %#x\n", GET_BM (index), val); + break; + case PI_LVI: + case PO_LVI: + case MC_LVI: + r = &s->bm_regs[GET_BM (index)]; + val = r->lvi; + dolog ("LVI[%d] -> %#x\n", GET_BM (index), val); + break; + case PI_PIV: + case PO_PIV: + case MC_PIV: + r = &s->bm_regs[GET_BM (index)]; + val = r->piv; + dolog ("PIV[%d] -> %#x\n", GET_BM (index), val); + break; + case PI_CR: + case PO_CR: + case MC_CR: + r = &s->bm_regs[GET_BM (index)]; + val = r->cr; + dolog ("CR[%d] -> %#x\n", GET_BM (index), val); + break; + case PI_SR: + case PO_SR: + case MC_SR: + r = &s->bm_regs[GET_BM (index)]; + val = r->sr & 0xff; + dolog ("SRb[%d] -> %#x\n", GET_BM (index), val); + break; + default: + dolog ("U nabm readb %#x -> %#x\n", addr, val); + break; + } + return val; +} + +static uint32_t nabm_readw (void *opaque, uint32_t addr) +{ + PCIAC97LinkState *d = opaque; + AC97LinkState *s = &d->ac97; + AC97BusMasterRegs *r = NULL; + uint32_t index = addr - s->base[1]; + uint32_t val = ~0U; + + switch (index) { + case PI_SR: + case PO_SR: + case MC_SR: + r = &s->bm_regs[GET_BM (index)]; + val = r->sr; + dolog ("SR[%d] -> %#x\n", GET_BM (index), val); + break; + case PI_PICB: + case PO_PICB: + case MC_PICB: + r = &s->bm_regs[GET_BM (index)]; + val = r->picb; + dolog ("PICB[%d] -> %#x\n", GET_BM (index), val); + break; + default: + dolog ("U nabm readw %#x -> %#x\n", addr, val); + break; + } + return val; +} + +static uint32_t nabm_readl (void *opaque, uint32_t addr) +{ + PCIAC97LinkState *d = opaque; + AC97LinkState *s = &d->ac97; + AC97BusMasterRegs *r = NULL; + uint32_t index = addr - s->base[1]; + uint32_t val = ~0U; + + switch (index) { + case PI_BDBAR: + case PO_BDBAR: + case MC_BDBAR: + r = &s->bm_regs[GET_BM (index)]; + val = r->bdbar; + dolog ("BMADDR[%d] -> %#x\n", GET_BM (index), val); + break; + case PI_CIV: + case PO_CIV: + case MC_CIV: + r = &s->bm_regs[GET_BM (index)]; + val = r->civ | (r->lvi << 8) | (r->sr << 16); + dolog ("CIV LVI SR[%d] -> %#x, %#x, %#x\n", GET_BM (index), + r->civ, r->lvi, r->sr); + break; + case PI_PICB: + case PO_PICB: + case MC_PICB: + r = &s->bm_regs[GET_BM (index)]; + val = r->picb | (r->piv << 16) | (r->cr << 24); + dolog ("PICB PIV CR[%d] -> %#x %#x %#x %#x\n", GET_BM (index), + val, r->picb, r->piv, r->cr); + break; + case GLOB_CNT: + val = s->glob_cnt; + dolog ("glob_cnt -> %#x\n", val); + break; + case GLOB_STA: + val = s->glob_sta | GS_S0CR; + dolog ("glob_sta -> %#x\n", val); + break; + default: + dolog ("U nabm readl %#x -> %#x\n", addr, val); + break; + } + return val; +} + +/** + * Native audio bus master + * I/O Writes + */ +static void nabm_writeb (void *opaque, uint32_t addr, uint32_t val) +{ + PCIAC97LinkState *d = opaque; + AC97LinkState *s = &d->ac97; + AC97BusMasterRegs *r = NULL; + uint32_t index = addr - s->base[1]; + switch (index) { + case PI_LVI: + case PO_LVI: + case MC_LVI: + r = &s->bm_regs[GET_BM (index)]; + if ((r->cr & CR_RPBM) && (r->sr & SR_DCH)) { + r->sr &= ~(SR_DCH | SR_CELV); + r->civ = r->piv; + r->piv = (r->piv + 1) % 32; + fetch_bd (s, r); + } + r->lvi = val % 32; + dolog ("LVI[%d] <- %#x\n", GET_BM (index), val); + break; + case PI_CR: + case PO_CR: + case MC_CR: + r = &s->bm_regs[GET_BM (index)]; + if (val & CR_RR) { + reset_bm_regs (s, r); + } + else { + r->cr = val & CR_VALID_MASK; + if (!(r->cr & CR_RPBM)) { + voice_set_active (s, r - s->bm_regs, 0); + r->sr |= SR_DCH; + } + else { + r->civ = r->piv; + r->piv = (r->piv + 1) % 32; + fetch_bd (s, r); + r->sr &= ~SR_DCH; + voice_set_active (s, r - s->bm_regs, 1); + } + } + dolog ("CR[%d] <- %#x (cr %#x)\n", GET_BM (index), val, r->cr); + break; + case PI_SR: + case PO_SR: + case MC_SR: + r = &s->bm_regs[GET_BM (index)]; + r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK); + update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK)); + dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr); + break; + default: + dolog ("U nabm writeb %#x <- %#x\n", addr, val); + break; + } +} + +static void nabm_writew (void *opaque, uint32_t addr, uint32_t val) +{ + PCIAC97LinkState *d = opaque; + AC97LinkState *s = &d->ac97; + AC97BusMasterRegs *r = NULL; + uint32_t index = addr - s->base[1]; + switch (index) { + case PI_SR: + case PO_SR: + case MC_SR: + r = &s->bm_regs[GET_BM (index)]; + r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK); + update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK)); + dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr); + break; + default: + dolog ("U nabm writew %#x <- %#x\n", addr, val); + break; + } +} + +static void nabm_writel (void *opaque, uint32_t addr, uint32_t val) +{ + PCIAC97LinkState *d = opaque; + AC97LinkState *s = &d->ac97; + AC97BusMasterRegs *r = NULL; + uint32_t index = addr - s->base[1]; + switch (index) { + case PI_BDBAR: + case PO_BDBAR: + case MC_BDBAR: + r = &s->bm_regs[GET_BM (index)]; + r->bdbar = val & ~3; + dolog ("BDBAR[%d] <- %#x (bdbar %#x)\n", + GET_BM (index), val, r->bdbar); + break; + case GLOB_CNT: + if (val & GC_WR) + warm_reset (s); + if (val & GC_CR) + cold_reset (s); + if (!(val & (GC_WR | GC_CR))) + s->glob_cnt = val & GC_VALID_MASK; + dolog ("glob_cnt <- %#x (glob_cnt %#x)\n", val, s->glob_cnt); + break; + case GLOB_STA: + s->glob_sta &= ~(val & GS_WCLEAR_MASK); + s->glob_sta |= (val & ~(GS_WCLEAR_MASK | GS_RO_MASK)) & GS_VALID_MASK; + dolog ("glob_sta <- %#x (glob_sta %#x)\n", val, s->glob_sta); + break; + default: + dolog ("U nabm writel %#x <- %#x\n", addr, val); + break; + } +} + +static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, + int max, int *stop) +{ + uint8_t tmpbuf[4096]; + uint32_t addr = r->bd.addr; + uint32_t temp = r->picb << 1; + uint32_t written = 0; + int to_copy = 0; + temp = audio_MIN (temp, max); + + if (!temp) { + *stop = 1; + return 0; + } + + while (temp) { + int copied; + to_copy = audio_MIN (temp, sizeof (tmpbuf)); + cpu_physical_memory_read (addr, tmpbuf, to_copy); + copied = AUD_write (s->voice_po, tmpbuf, to_copy); + dolog ("write_audio max=%x to_copy=%x copied=%x\n", + max, to_copy, copied); + if (!copied) { + *stop = 1; + break; + } + temp -= copied; + addr += copied; + written += copied; + } + + if (!temp) { + if (to_copy < 4) { + dolog ("whoops\n"); + s->last_samp = 0; + } + else { + s->last_samp = *(uint32_t *) &tmpbuf[to_copy - 4]; + } + } + + r->bd.addr = addr; + return written; +} + +static void write_bup (AC97LinkState *s, int elapsed) +{ + int written = 0; + + dolog ("write_bup\n"); + if (!(s->bup_flag & BUP_SET)) { + if (s->bup_flag & BUP_LAST) { + int i; + uint8_t *p = s->silence; + for (i = 0; i < sizeof (s->silence) / 4; i++, p += 4) { + *(uint32_t *) p = s->last_samp; + } + } + else { + memset (s->silence, 0, sizeof (s->silence)); + } + s->bup_flag |= BUP_SET; + } + + while (elapsed) { + int temp = audio_MIN (elapsed, sizeof (s->silence)); + while (temp) { + int copied = AUD_write (s->voice_po, s->silence, temp); + if (!copied) + return; + temp -= copied; + elapsed -= copied; + written += copied; + } + } +} + +static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r, + int max, int *stop) +{ + uint8_t tmpbuf[4096]; + uint32_t addr = r->bd.addr; + uint32_t temp = r->picb << 1; + uint32_t nread = 0; + int to_copy = 0; + SWVoiceIn *voice = (r - s->bm_regs) == MC_INDEX ? s->voice_mc : s->voice_pi; + + temp = audio_MIN (temp, max); + + if (!temp) { + *stop = 1; + return 0; + } + + while (temp) { + int acquired; + to_copy = audio_MIN (temp, sizeof (tmpbuf)); + acquired = AUD_read (voice, tmpbuf, to_copy); + if (!acquired) { + *stop = 1; + break; + } + cpu_physical_memory_write (addr, tmpbuf, acquired); + temp -= acquired; + addr += acquired; + nread += acquired; + } + + r->bd.addr = addr; + return nread; +} + +static void transfer_audio (AC97LinkState *s, int index, int elapsed) +{ + AC97BusMasterRegs *r = &s->bm_regs[index]; + int written = 0, stop = 0; + + if (s->invalid_freq[index]) { + AUD_log ("ac97", "attempt to use voice %d with invalid frequency %d\n", + index, s->invalid_freq[index]); + return; + } + + if (r->sr & SR_DCH) { + if (r->cr & CR_RPBM) { + switch (index) { + case PO_INDEX: + write_bup (s, elapsed); + break; + } + } + return; + } + + while ((elapsed >> 1) && !stop) { + int temp; + + if (!r->bd_valid) { + dolog ("invalid bd\n"); + fetch_bd (s, r); + } + + if (!r->picb) { + dolog ("fresh bd %d is empty %#x %#x\n", + r->civ, r->bd.addr, r->bd.ctl_len); + if (r->civ == r->lvi) { + r->sr |= SR_DCH; /* CELV? */ + s->bup_flag = 0; + break; + } + r->sr &= ~SR_CELV; + r->civ = r->piv; + r->piv = (r->piv + 1) % 32; + fetch_bd (s, r); + return; + } + + switch (index) { + case PO_INDEX: + temp = write_audio (s, r, elapsed, &stop); + written += temp; + elapsed -= temp; + r->picb -= (temp >> 1); + break; + + case PI_INDEX: + case MC_INDEX: + temp = read_audio (s, r, elapsed, &stop); + elapsed -= temp; + r->picb -= (temp >> 1); + break; + } + + if (!r->picb) { + uint32_t new_sr = r->sr & ~SR_CELV; + + if (r->bd.ctl_len & BD_IOC) { + new_sr |= SR_BCIS; + } + + if (r->civ == r->lvi) { + dolog ("Underrun civ (%d) == lvi (%d)\n", r->civ, r->lvi); + + new_sr |= SR_LVBCI | SR_DCH | SR_CELV; + stop = 1; + s->bup_flag = (r->bd.ctl_len & BD_BUP) ? BUP_LAST : 0; + } + else { + r->civ = r->piv; + r->piv = (r->piv + 1) % 32; + fetch_bd (s, r); + } + + update_sr (s, r, new_sr); + } + } +} + +static void pi_callback (void *opaque, int avail) +{ + transfer_audio (opaque, PI_INDEX, avail); +} + +static void mc_callback (void *opaque, int avail) +{ + transfer_audio (opaque, MC_INDEX, avail); +} + +static void po_callback (void *opaque, int free) +{ + transfer_audio (opaque, PO_INDEX, free); +} + +static void ac97_save (QEMUFile *f, void *opaque) +{ + size_t i; + uint8_t active[LAST_INDEX]; + AC97LinkState *s = opaque; + + pci_device_save (s->pci_dev, f); + + qemu_put_be32s (f, &s->glob_cnt); + qemu_put_be32s (f, &s->glob_sta); + qemu_put_be32s (f, &s->cas); + + for (i = 0; i < sizeof (s->bm_regs) / sizeof (s->bm_regs[0]); ++i) { + AC97BusMasterRegs *r = &s->bm_regs[i]; + qemu_put_be32s (f, &r->bdbar); + qemu_put_8s (f, &r->civ); + qemu_put_8s (f, &r->lvi); + qemu_put_be16s (f, &r->sr); + qemu_put_be16s (f, &r->picb); + qemu_put_8s (f, &r->piv); + qemu_put_8s (f, &r->cr); + qemu_put_be32s (f, &r->bd_valid); + qemu_put_be32s (f, &r->bd.addr); + qemu_put_be32s (f, &r->bd.ctl_len); + } + qemu_put_buffer (f, s->mixer_data, sizeof (s->mixer_data)); + + active[PI_INDEX] = AUD_is_active_in (s->voice_pi) ? 1 : 0; + active[PO_INDEX] = AUD_is_active_out (s->voice_po) ? 1 : 0; + active[MC_INDEX] = AUD_is_active_in (s->voice_mc) ? 1 : 0; + qemu_put_buffer (f, active, sizeof (active)); +} + +static int ac97_load (QEMUFile *f, void *opaque, int version_id) +{ + int ret; + size_t i; + uint8_t active[LAST_INDEX]; + AC97LinkState *s = opaque; + + if (version_id != 2) + return -EINVAL; + + ret = pci_device_load (s->pci_dev, f); + if (ret) + return ret; + + qemu_get_be32s (f, &s->glob_cnt); + qemu_get_be32s (f, &s->glob_sta); + qemu_get_be32s (f, &s->cas); + + for (i = 0; i < sizeof (s->bm_regs) / sizeof (s->bm_regs[0]); ++i) { + AC97BusMasterRegs *r = &s->bm_regs[i]; + qemu_get_be32s (f, &r->bdbar); + qemu_get_8s (f, &r->civ); + qemu_get_8s (f, &r->lvi); + qemu_get_be16s (f, &r->sr); + qemu_get_be16s (f, &r->picb); + qemu_get_8s (f, &r->piv); + qemu_get_8s (f, &r->cr); + qemu_get_be32s (f, &r->bd_valid); + qemu_get_be32s (f, &r->bd.addr); + qemu_get_be32s (f, &r->bd.ctl_len); + } + qemu_get_buffer (f, s->mixer_data, sizeof (s->mixer_data)); + qemu_get_buffer (f, active, sizeof (active)); + +#ifdef USE_MIXER + record_select (s, mixer_load (s, AC97_Record_Select)); +#define V_(a, b) set_volume (s, a, b, mixer_load (s, a)) + V_ (AC97_Master_Volume_Mute, AUD_MIXER_VOLUME); + V_ (AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM); + V_ (AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN); +#undef V_ +#endif + reset_voices (s, active); + + s->bup_flag = 0; + s->last_samp = 0; + return 0; +} + +static void ac97_map (PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + PCIAC97LinkState *d = (PCIAC97LinkState *) pci_dev; + AC97LinkState *s = &d->ac97; + + if (!region_num) { + s->base[0] = addr; + register_ioport_read (addr, 256 * 1, 1, nam_readb, d); + register_ioport_read (addr, 256 * 2, 2, nam_readw, d); + register_ioport_read (addr, 256 * 4, 4, nam_readl, d); + register_ioport_write (addr, 256 * 1, 1, nam_writeb, d); + register_ioport_write (addr, 256 * 2, 2, nam_writew, d); + register_ioport_write (addr, 256 * 4, 4, nam_writel, d); + } + else { + s->base[1] = addr; + register_ioport_read (addr, 64 * 1, 1, nabm_readb, d); + register_ioport_read (addr, 64 * 2, 2, nabm_readw, d); + register_ioport_read (addr, 64 * 4, 4, nabm_readl, d); + register_ioport_write (addr, 64 * 1, 1, nabm_writeb, d); + register_ioport_write (addr, 64 * 2, 2, nabm_writew, d); + register_ioport_write (addr, 64 * 4, 4, nabm_writel, d); + } +} + +static void ac97_on_reset (void *opaque) +{ + AC97LinkState *s = opaque; + + reset_bm_regs (s, &s->bm_regs[0]); + reset_bm_regs (s, &s->bm_regs[1]); + reset_bm_regs (s, &s->bm_regs[2]); + + /* + * Reset the mixer too. The Windows XP driver seems to rely on + * this. At least it wants to read the vendor id before it resets + * the codec manually. + */ + mixer_reset (s); +} + +int ac97_init (PCIBus *bus, AudioState *audio) +{ + PCIAC97LinkState *d; + AC97LinkState *s; + uint8_t *c; + + if (!bus) { + AUD_log ("ac97", "No PCI bus\n"); + return -1; + } + + if (!audio) { + AUD_log ("ac97", "No audio state\n"); + return -1; + } + + d = (PCIAC97LinkState *) pci_register_device (bus, "AC97", + sizeof (PCIAC97LinkState), + -1, NULL, NULL); + + if (!d) { + AUD_log ("ac97", "Failed to register PCI device\n"); + return -1; + } + + s = &d->ac97; + s->pci_dev = &d->dev; + c = d->dev.config; + c[0x00] = 0x86; /* vid vendor id intel ro */ + c[0x01] = 0x80; /* intel */ + + c[0x02] = 0x15; /* did device id 82801 ro */ + c[0x03] = 0x24; /* 82801aa */ + + c[0x04] = 0x00; /* pcicmd pci command rw, ro */ + c[0x05] = 0x00; + + c[0x06] = 0x80; /* pcists pci status rwc, ro */ + c[0x07] = 0x02; + + c[0x08] = 0x01; /* rid revision ro */ + c[0x09] = 0x00; /* pi programming interface ro */ + c[0x0a] = 0x01; /* scc sub class code ro */ + c[0x0b] = 0x04; /* bcc base class code ro */ + c[0x0e] = 0x00; /* headtyp header type ro */ + + c[0x10] = 0x01; /* nabmar native audio mixer base + address rw */ + c[0x11] = 0x00; + c[0x12] = 0x00; + c[0x13] = 0x00; + + c[0x14] = 0x01; /* nabmbar native audio bus mastering + base address rw */ + c[0x15] = 0x00; + c[0x16] = 0x00; + c[0x17] = 0x00; + + c[0x2c] = 0x86; /* svid subsystem vendor id rwo */ + c[0x2d] = 0x80; + + c[0x2e] = 0x00; /* sid subsystem id rwo */ + c[0x2f] = 0x00; + + c[0x3c] = 0x00; /* intr_ln interrupt line rw */ + c[0x3d] = 0x01; /* intr_pn interrupt pin ro */ + + pci_register_io_region (&d->dev, 0, 256 * 4, PCI_ADDRESS_SPACE_IO, ac97_map); + pci_register_io_region (&d->dev, 1, 64 * 4, PCI_ADDRESS_SPACE_IO, ac97_map); + register_savevm ("ac97", 0, 2, ac97_save, ac97_load, s); + qemu_register_reset (ac97_on_reset, s); + AUD_register_card (audio, "ac97", &s->card); + ac97_on_reset (s); + return 0; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/acpi.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/acpi.c --- qemu-0.9.1/hw/acpi.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/acpi.c 2008-11-05 16:04:33.000000000 +0000 @@ -23,6 +23,7 @@ #include "sysemu.h" #include "i2c.h" #include "smbus.h" +#include "kvm.h" //#define DEBUG @@ -49,6 +50,7 @@ uint8_t smb_data1; uint8_t smb_data[32]; uint8_t smb_index; + qemu_irq irq; } PIIX4PMState; #define RTC_EN (1 << 10) @@ -71,6 +73,8 @@ #define SMBHSTDAT1 0x06 #define SMBBLKDAT 0x07 +static PIIX4PMState *pm_state; + static uint32_t get_pmtmr(PIIX4PMState *s) { uint32_t d; @@ -97,7 +101,7 @@ pmsts = get_pmsts(s); sci_level = (((pmsts & s->pmen) & (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0); - qemu_set_irq(s->dev.irq[0], sci_level); + qemu_set_irq(s->irq, sci_level); /* schedule a timer interruption if needed */ if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) { expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec, PM_FREQ); @@ -142,7 +146,7 @@ s->pmcntrl = val & ~(SUS_EN); if (val & SUS_EN) { /* change suspend type */ - sus_typ = (val >> 10) & 3; + sus_typ = (val >> 10) & 7; switch(sus_typ) { case 0: /* soft power off */ qemu_system_shutdown_request(); @@ -467,7 +471,8 @@ return 0; } -i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base) +i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, + qemu_irq sci_irq) { PIIX4PMState *s; uint8_t *pci_conf; @@ -475,6 +480,7 @@ s = (PIIX4PMState *)pci_register_device(bus, "PM", sizeof(PIIX4PMState), devfn, NULL, pm_write_config); + pm_state = s; pci_conf = s->dev.config; pci_conf[0x00] = 0x86; pci_conf[0x01] = 0x80; @@ -482,7 +488,7 @@ pci_conf[0x03] = 0x71; pci_conf[0x06] = 0x80; pci_conf[0x07] = 0x02; - pci_conf[0x08] = 0x00; // revision number + pci_conf[0x08] = 0x03; // revision number pci_conf[0x09] = 0x00; pci_conf[0x0a] = 0x80; // other bridge device pci_conf[0x0b] = 0x06; // bridge device @@ -496,6 +502,12 @@ register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s); + if (kvm_enabled()) { + /* Mark SMM as already inited to prevent SMM from running. KVM does not + * support SMM mode. */ + pci_conf[0x5B] = 0x02; + } + /* XXX: which specification is used ? The i82731AB has different mappings */ pci_conf[0x5f] = (parallel_hds[0] != NULL ? 0x80 : 0) | 0x10; @@ -514,5 +526,18 @@ register_savevm("piix4_pm", 0, 1, pm_save, pm_load, s); s->smbus = i2c_init_bus(); + s->irq = sci_irq; return s->smbus; } + +#if defined(TARGET_I386) +void qemu_system_powerdown(void) +{ + if (!pm_state) { + qemu_system_shutdown_request(); + } else if (pm_state->pmen & PWRBTN_EN) { + pm_state->pmsts |= PWRBTN_EN; + pm_update_sci(pm_state); + } +} +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ads7846.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ads7846.c --- qemu-0.9.1/hw/ads7846.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/ads7846.c 2008-07-01 22:31:54.000000000 +0100 @@ -140,8 +140,6 @@ return 0; } -static int ads7846_iid = 0; - struct ads7846_state_s *ads7846_init(qemu_irq penirq) { struct ads7846_state_s *s; @@ -162,8 +160,7 @@ ads7846_int_update(s); - register_savevm("ads7846", ads7846_iid ++, 0, - ads7846_save, ads7846_load, s); + register_savevm("ads7846", -1, 0, ads7846_save, ads7846_load, s); return s; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/alpha_palcode.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/alpha_palcode.c --- qemu-0.9.1/hw/alpha_palcode.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/alpha_palcode.c 2008-11-11 13:42:22.000000000 +0000 @@ -55,8 +55,8 @@ }; #if 0 -/* One must explicitely check that the TB is valid and the FOE bit is reset */ -static void update_itb () +/* One must explicitly check that the TB is valid and the FOE bit is reset */ +static void update_itb (void) { /* This writes into a temp register, not the actual one */ mtpr(TB_TAG); @@ -65,7 +65,7 @@ mtpr(ITB_PTE); } -static void update_dtb (); +static void update_dtb (void); { mtpr(TB_CTL); /* This write into a temp register, not the actual one */ @@ -1059,39 +1059,39 @@ void call_pal (CPUState *env, int palcode) { - target_ulong ret; + target_long ret; - printf("%s: palcode %02x\n", __func__, palcode); if (logfile != NULL) fprintf(logfile, "%s: palcode %02x\n", __func__, palcode); switch (palcode) { case 0x83: /* CALLSYS */ - printf("CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]); if (logfile != NULL) fprintf(logfile, "CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]); ret = do_syscall(env, env->ir[IR_V0], env->ir[IR_A0], env->ir[IR_A1], env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4], env->ir[IR_A5]); - env->ir[IR_A3] = ret; - if (ret > (target_ulong)(-515)) { - env->ir[IR_V0] = 1; + if (ret >= 0) { + env->ir[IR_A3] = 0; + env->ir[IR_V0] = ret; } else { - env->ir[IR_V0] = 0; + env->ir[IR_A3] = 1; + env->ir[IR_V0] = -ret; } break; case 0x9E: /* RDUNIQUE */ env->ir[IR_V0] = env->unique; - printf("RDUNIQUE: " TARGET_FMT_lx "\n", env->unique); + if (logfile != NULL) + fprintf(logfile, "RDUNIQUE: " TARGET_FMT_lx "\n", env->unique); break; case 0x9F: /* WRUNIQUE */ env->unique = env->ir[IR_A0]; - printf("WRUNIQUE: " TARGET_FMT_lx "\n", env->unique); + if (logfile != NULL) + fprintf(logfile, "WRUNIQUE: " TARGET_FMT_lx "\n", env->unique); break; default: - printf("%s: unhandled palcode %02x\n", __func__, palcode); if (logfile != NULL) fprintf(logfile, "%s: unhandled palcode %02x\n", __func__, palcode); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/an5206.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/an5206.c --- qemu-0.9.1/hw/an5206.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/an5206.c 2008-10-31 17:25:56.000000000 +0000 @@ -24,13 +24,9 @@ { } -void DMA_run (void) -{ -} - /* Board init. */ -static void an5206_init(int ram_size, int vga_ram_size, +static void an5206_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -88,7 +84,8 @@ } QEMUMachine an5206_machine = { - "an5206", - "Arnewsh 5206", - an5206_init, + .name = "an5206", + .desc = "Arnewsh 5206", + .init = an5206_init, + .ram_require = 512, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/apb_pci.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/apb_pci.c --- qemu-0.9.1/hw/apb_pci.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/apb_pci.c 2008-05-12 17:13:33.000000000 +0100 @@ -230,9 +230,12 @@ pci_apb_iowrite, s); cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config); - cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config); - cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport); - cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom + cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, + pci_mem_config); + cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, + pci_ioport); + cpu_register_physical_memory(mem_base, 0x10000000, + pci_mem_data); // XXX size should be 4G-prom d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice), 0, NULL, NULL); @@ -252,8 +255,10 @@ d->config[0x0E] = 0x00; // header_type /* APB secondary busses */ - secondary = pci_bridge_init(s->bus, 8, 0x108e5000, pci_apb_map_irq, "Advanced PCI Bus secondary bridge 1"); - pci_bridge_init(s->bus, 9, 0x108e5000, pci_apb_map_irq, "Advanced PCI Bus secondary bridge 2"); + secondary = pci_bridge_init(s->bus, 8, 0x108e5000, pci_apb_map_irq, + "Advanced PCI Bus secondary bridge 1"); + pci_bridge_init(s->bus, 9, 0x108e5000, pci_apb_map_irq, + "Advanced PCI Bus secondary bridge 2"); return secondary; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/apic.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/apic.c --- qemu-0.9.1/hw/apic.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/apic.c 2008-10-12 21:16:03.000000000 +0100 @@ -20,6 +20,7 @@ #include "hw.h" #include "pc.h" #include "qemu-timer.h" +#include "host-utils.h" //#define DEBUG_APIC //#define DEBUG_IOAPIC @@ -104,50 +105,16 @@ static void apic_set_irq(APICState *s, int vector_num, int trigger_mode); static void apic_update_irq(APICState *s); -/* Find first bit starting from msb. Return 0 if value = 0 */ +/* Find first bit starting from msb */ static int fls_bit(uint32_t value) { - unsigned int ret = 0; - -#if defined(HOST_I386) - __asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value)); - return ret; -#else - if (value > 0xffff) - value >>= 16, ret = 16; - if (value > 0xff) - value >>= 8, ret += 8; - if (value > 0xf) - value >>= 4, ret += 4; - if (value > 0x3) - value >>= 2, ret += 2; - return ret + (value >> 1); -#endif + return 31 - clz32(value); } -/* Find first bit starting from lsb. Return 0 if value = 0 */ +/* Find first bit starting from lsb */ static int ffs_bit(uint32_t value) { - unsigned int ret = 0; - -#if defined(HOST_I386) - __asm__ __volatile__ ("bsf %1, %0\n" : "+r" (ret) : "rm" (value)); - return ret; -#else - if (!value) - return 0; - if (!(value & 0xffff)) - value >>= 16, ret = 16; - if (!(value & 0xff)) - value >>= 8, ret += 8; - if (!(value & 0xf)) - value >>= 4, ret += 4; - if (!(value & 0x3)) - value >>= 2, ret += 2; - if (!(value & 0x1)) - ret++; - return ret; -#endif + return ctz32(value); } static inline void set_bit(uint32_t *tab, int index) @@ -166,6 +133,58 @@ tab[i] &= ~mask; } +static void apic_local_deliver(CPUState *env, int vector) +{ + APICState *s = env->apic_state; + uint32_t lvt = s->lvt[vector]; + int trigger_mode; + + if (lvt & APIC_LVT_MASKED) + return; + + switch ((lvt >> 8) & 7) { + case APIC_DM_SMI: + cpu_interrupt(env, CPU_INTERRUPT_SMI); + break; + + case APIC_DM_NMI: + cpu_interrupt(env, CPU_INTERRUPT_NMI); + break; + + case APIC_DM_EXTINT: + cpu_interrupt(env, CPU_INTERRUPT_HARD); + break; + + case APIC_DM_FIXED: + trigger_mode = APIC_TRIGGER_EDGE; + if ((vector == APIC_LVT_LINT0 || vector == APIC_LVT_LINT1) && + (lvt & APIC_LVT_LEVEL_TRIGGER)) + trigger_mode = APIC_TRIGGER_LEVEL; + apic_set_irq(s, lvt & 0xff, trigger_mode); + } +} + +void apic_deliver_pic_intr(CPUState *env, int level) +{ + if (level) + apic_local_deliver(env, APIC_LVT_LINT0); + else { + APICState *s = env->apic_state; + uint32_t lvt = s->lvt[APIC_LVT_LINT0]; + + switch ((lvt >> 8) & 7) { + case APIC_DM_FIXED: + if (!(lvt & APIC_LVT_LEVEL_TRIGGER)) + break; + reset_bit(s->irr, lvt & 0xff); + /* fall through */ + case APIC_DM_EXTINT: + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + break; + } + } +} + #define foreach_apic(apic, deliver_bitmask, code) \ {\ int __i, __j, __mask;\ @@ -216,8 +235,14 @@ break; case APIC_DM_SMI: + foreach_apic(apic_iter, deliver_bitmask, + cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_SMI) ); + return; + case APIC_DM_NMI: - break; + foreach_apic(apic_iter, deliver_bitmask, + cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_NMI) ); + return; case APIC_DM_INIT: /* normal INIT IPI sent to processors */ @@ -400,18 +425,23 @@ s->initial_count = 0; s->initial_count_load_time = 0; s->next_time = 0; + + cpu_reset(s->cpu_env); + + if (!(s->apicbase & MSR_IA32_APICBASE_BSP)) + s->cpu_env->halted = 1; } /* send a SIPI message to the CPU to start it */ static void apic_startup(APICState *s, int vector_num) { CPUState *env = s->cpu_env; - if (!(env->hflags & HF_HALTED_MASK)) + if (!env->halted) return; env->eip = 0; cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12, 0xffff, 0); - env->hflags &= ~HF_HALTED_MASK; + env->halted = 0; } static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode, @@ -496,10 +526,8 @@ lvt0 = s->lvt[APIC_LVT_LINT0]; - if (s->id == 0 && - ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 || - ((lvt0 & APIC_LVT_MASKED) == 0 && - ((lvt0 >> 8) & 0x7) == APIC_DM_EXTINT))) + if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 || + (lvt0 & APIC_LVT_MASKED) == 0) return 1; return 0; @@ -531,6 +559,8 @@ d = (current_time - s->initial_count_load_time) >> s->count_shift; if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { + if (!s->initial_count) + goto no_timer; d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1); } else { if (d >= s->initial_count) @@ -550,9 +580,7 @@ { APICState *s = opaque; - if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) { - apic_set_irq(s, s->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE); - } + apic_local_deliver(s->cpu_env, APIC_LVT_TIMER); apic_timer_update(s, s->next_time); } @@ -604,6 +632,9 @@ /* ppr */ val = apic_get_ppr(s); break; + case 0x0b: + val = 0; + break; case 0x0d: val = s->log_dest << 24; break; @@ -810,14 +841,20 @@ static void apic_reset(void *opaque) { APICState *s = opaque; + + s->apicbase = 0xfee00000 | + (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE; + apic_init_ipi(s); - /* - * LINT0 delivery mode is set to ExtInt at initialization time - * typically by BIOS, so PIC interrupt can be delivered to the - * processor when local APIC is enabled. - */ - s->lvt[APIC_LVT_LINT0] = 0x700; + if (s->id == 0) { + /* + * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization + * time typically by BIOS, so PIC interrupt can be delivered to the + * processor when local APIC is enabled. + */ + s->lvt[APIC_LVT_LINT0] = 0x700; + } } static CPUReadMemoryFunc *apic_mem_read[3] = { @@ -842,19 +879,11 @@ if (!s) return -1; env->apic_state = s; - apic_init_ipi(s); s->id = last_apic_id++; env->cpuid_apic_id = s->id; s->cpu_env = env; - s->apicbase = 0xfee00000 | - (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE; - /* - * LINT0 delivery mode is set to ExtInt at initialization time - * typically by BIOS, so PIC interrupt can be delivered to the - * processor when local APIC is enabled. - */ - s->lvt[APIC_LVT_LINT0] = 0x700; + apic_reset(s); /* XXX: mapping more APICs at the same memory location */ if (apic_io_memory == 0) { diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/arm_boot.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/arm_boot.c --- qemu-0.9.1/hw/arm_boot.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/arm_boot.c 2008-04-14 21:27:51.000000000 +0100 @@ -47,21 +47,18 @@ CPUState *env = opaque; cpu_reset(env); - if (env->kernel_filename) - arm_load_kernel(env, env->ram_size, env->kernel_filename, - env->kernel_cmdline, env->initrd_filename, - env->board_id, env->loader_start); + if (env->boot_info) + arm_load_kernel(env, env->boot_info); /* TODO: Reset secondary CPUs. */ } -static void set_kernel_args(uint32_t ram_size, int initrd_size, - const char *kernel_cmdline, - target_phys_addr_t loader_start) +static void set_kernel_args(struct arm_boot_info *info, + int initrd_size, void *base) { uint32_t *p; - p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR); + p = (uint32_t *)(base + KERNEL_ARGS_ADDR); /* ATAG_CORE */ stl_raw(p++, 5); stl_raw(p++, 0x54410001); @@ -69,46 +66,55 @@ stl_raw(p++, 0x1000); stl_raw(p++, 0); /* ATAG_MEM */ + /* TODO: handle multiple chips on one ATAG list */ stl_raw(p++, 4); stl_raw(p++, 0x54410002); - stl_raw(p++, ram_size); - stl_raw(p++, loader_start); + stl_raw(p++, info->ram_size); + stl_raw(p++, info->loader_start); if (initrd_size) { /* ATAG_INITRD2 */ stl_raw(p++, 4); stl_raw(p++, 0x54420005); - stl_raw(p++, loader_start + INITRD_LOAD_ADDR); + stl_raw(p++, info->loader_start + INITRD_LOAD_ADDR); stl_raw(p++, initrd_size); } - if (kernel_cmdline && *kernel_cmdline) { + if (info->kernel_cmdline && *info->kernel_cmdline) { /* ATAG_CMDLINE */ int cmdline_size; - cmdline_size = strlen(kernel_cmdline); - memcpy (p + 2, kernel_cmdline, cmdline_size + 1); + cmdline_size = strlen(info->kernel_cmdline); + memcpy(p + 2, info->kernel_cmdline, cmdline_size + 1); cmdline_size = (cmdline_size >> 2) + 1; stl_raw(p++, cmdline_size + 2); stl_raw(p++, 0x54410009); p += cmdline_size; } + if (info->atag_board) { + /* ATAG_BOARD */ + int atag_board_len; + + atag_board_len = (info->atag_board(info, p + 2) + 3) >> 2; + stl_raw(p++, 2 + atag_board_len); + stl_raw(p++, 0x414f4d50); + p += atag_board_len; + } /* ATAG_END */ stl_raw(p++, 0); stl_raw(p++, 0); } -static void set_kernel_args_old(uint32_t ram_size, int initrd_size, - const char *kernel_cmdline, - target_phys_addr_t loader_start) +static void set_kernel_args_old(struct arm_boot_info *info, + int initrd_size, void *base) { uint32_t *p; unsigned char *s; /* see linux/include/asm-arm/setup.h */ - p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR); + p = (uint32_t *)(base + KERNEL_ARGS_ADDR); /* page_size */ stl_raw(p++, 4096); /* nr_pages */ - stl_raw(p++, ram_size / 4096); + stl_raw(p++, info->ram_size / 4096); /* ramdisk_size */ stl_raw(p++, 0); #define FLAG_READONLY 1 @@ -142,7 +148,7 @@ stl_raw(p++, 0); /* initrd_start */ if (initrd_size) - stl_raw(p++, loader_start + INITRD_LOAD_ADDR); + stl_raw(p++, info->loader_start + INITRD_LOAD_ADDR); else stl_raw(p++, 0); /* initrd_size */ @@ -159,17 +165,15 @@ stl_raw(p++, 0); /* zero unused fields */ memset(p, 0, 256 + 1024 - - (p - ((uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR)))); - s = phys_ram_base + KERNEL_ARGS_ADDR + 256 + 1024; - if (kernel_cmdline) - strcpy (s, kernel_cmdline); + (p - ((uint32_t *)(base + KERNEL_ARGS_ADDR)))); + s = base + KERNEL_ARGS_ADDR + 256 + 1024; + if (info->kernel_cmdline) + strcpy (s, info->kernel_cmdline); else stb_raw(s, 0); } -void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, - const char *kernel_cmdline, const char *initrd_filename, - int board_id, target_phys_addr_t loader_start) +void arm_load_kernel(CPUState *env, struct arm_boot_info *info) { int kernel_size; int initrd_size; @@ -177,36 +181,41 @@ int is_linux = 0; uint64_t elf_entry; target_ulong entry; + uint32_t pd; + void *loader_phys; /* Load the kernel. */ - if (!kernel_filename) { + if (!info->kernel_filename) { fprintf(stderr, "Kernel image must be specified\n"); exit(1); } - if (!env->kernel_filename) { - env->ram_size = ram_size; - env->kernel_filename = kernel_filename; - env->kernel_cmdline = kernel_cmdline; - env->initrd_filename = initrd_filename; - env->board_id = board_id; - env->loader_start = loader_start; + if (!env->boot_info) { + if (info->nb_cpus == 0) + info->nb_cpus = 1; + env->boot_info = info; qemu_register_reset(main_cpu_reset, env); } + + pd = cpu_get_physical_page_desc(info->loader_start); + loader_phys = phys_ram_base + (pd & TARGET_PAGE_MASK) + + (info->loader_start & ~TARGET_PAGE_MASK); + /* Assume that raw images are linux kernels, and ELF images are not. */ - kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL); + kernel_size = load_elf(info->kernel_filename, 0, &elf_entry, NULL, NULL); entry = elf_entry; if (kernel_size < 0) { - kernel_size = load_uboot(kernel_filename, &entry, &is_linux); + kernel_size = load_uboot(info->kernel_filename, &entry, &is_linux); } if (kernel_size < 0) { - kernel_size = load_image(kernel_filename, - phys_ram_base + KERNEL_LOAD_ADDR); - entry = loader_start + KERNEL_LOAD_ADDR; + kernel_size = load_image(info->kernel_filename, + loader_phys + KERNEL_LOAD_ADDR); + entry = info->loader_start + KERNEL_LOAD_ADDR; is_linux = 1; } if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); + fprintf(stderr, "qemu: could not load kernel '%s'\n", + info->kernel_filename); exit(1); } if (!is_linux) { @@ -214,30 +223,29 @@ env->regs[15] = entry & 0xfffffffe; env->thumb = entry & 1; } else { - if (initrd_filename) { - initrd_size = load_image(initrd_filename, - phys_ram_base + INITRD_LOAD_ADDR); + if (info->initrd_filename) { + initrd_size = load_image(info->initrd_filename, + loader_phys + INITRD_LOAD_ADDR); if (initrd_size < 0) { fprintf(stderr, "qemu: could not load initrd '%s'\n", - initrd_filename); + info->initrd_filename); exit(1); } } else { initrd_size = 0; } - bootloader[1] |= board_id & 0xff; - bootloader[2] |= (board_id >> 8) & 0xff; - bootloader[5] = loader_start + KERNEL_ARGS_ADDR; + bootloader[1] |= info->board_id & 0xff; + bootloader[2] |= (info->board_id >> 8) & 0xff; + bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR; bootloader[6] = entry; for (n = 0; n < sizeof(bootloader) / 4; n++) - stl_raw(phys_ram_base + (n * 4), bootloader[n]); - for (n = 0; n < sizeof(smpboot) / 4; n++) - stl_raw(phys_ram_base + ram_size + (n * 4), smpboot[n]); + stl_raw(loader_phys + (n * 4), bootloader[n]); + if (info->nb_cpus > 1) + for (n = 0; n < sizeof(smpboot) / 4; n++) + stl_raw(loader_phys + info->ram_size + (n * 4), smpboot[n]); if (old_param) - set_kernel_args_old(ram_size, initrd_size, - kernel_cmdline, loader_start); + set_kernel_args_old(info, initrd_size, loader_phys); else - set_kernel_args(ram_size, initrd_size, - kernel_cmdline, loader_start); + set_kernel_args(info, initrd_size, loader_phys); } } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/arm_gic.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/arm_gic.c --- qemu-0.9.1/hw/arm_gic.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/arm_gic.c 2008-07-02 17:48:32.000000000 +0100 @@ -62,7 +62,7 @@ #define GIC_TEST_MODEL(irq) s->irq_state[irq].model #define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm) #define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm) -#define GIC_TEST_LEVEL(irq, cm) (s->irq_state[irq].level & (cm)) != 0 +#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0) #define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1 #define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0 #define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger @@ -650,6 +650,79 @@ #endif } +static void gic_save(QEMUFile *f, void *opaque) +{ + gic_state *s = (gic_state *)opaque; + int i; + int j; + + qemu_put_be32(f, s->enabled); + for (i = 0; i < NCPU; i++) { + qemu_put_be32(f, s->cpu_enabled[i]); +#ifndef NVIC + qemu_put_be32(f, s->irq_target[i]); +#endif + for (j = 0; j < 32; j++) + qemu_put_be32(f, s->priority1[j][i]); + for (j = 0; j < GIC_NIRQ; j++) + qemu_put_be32(f, s->last_active[j][i]); + qemu_put_be32(f, s->priority_mask[i]); + qemu_put_be32(f, s->running_irq[i]); + qemu_put_be32(f, s->running_priority[i]); + qemu_put_be32(f, s->current_pending[i]); + } + for (i = 0; i < GIC_NIRQ - 32; i++) { + qemu_put_be32(f, s->priority2[i]); + } + for (i = 0; i < GIC_NIRQ; i++) { + qemu_put_byte(f, s->irq_state[i].enabled); + qemu_put_byte(f, s->irq_state[i].pending); + qemu_put_byte(f, s->irq_state[i].active); + qemu_put_byte(f, s->irq_state[i].level); + qemu_put_byte(f, s->irq_state[i].model); + qemu_put_byte(f, s->irq_state[i].trigger); + } +} + +static int gic_load(QEMUFile *f, void *opaque, int version_id) +{ + gic_state *s = (gic_state *)opaque; + int i; + int j; + + if (version_id != 1) + return -EINVAL; + + s->enabled = qemu_get_be32(f); + for (i = 0; i < NCPU; i++) { + s->cpu_enabled[i] = qemu_get_be32(f); +#ifndef NVIC + s->irq_target[i] = qemu_get_be32(f); +#endif + for (j = 0; j < 32; j++) + s->priority1[j][i] = qemu_get_be32(f); + for (j = 0; j < GIC_NIRQ; j++) + s->last_active[j][i] = qemu_get_be32(f); + s->priority_mask[i] = qemu_get_be32(f); + s->running_irq[i] = qemu_get_be32(f); + s->running_priority[i] = qemu_get_be32(f); + s->current_pending[i] = qemu_get_be32(f); + } + for (i = 0; i < GIC_NIRQ - 32; i++) { + s->priority2[i] = qemu_get_be32(f); + } + for (i = 0; i < GIC_NIRQ; i++) { + s->irq_state[i].enabled = qemu_get_byte(f); + s->irq_state[i].pending = qemu_get_byte(f); + s->irq_state[i].active = qemu_get_byte(f); + s->irq_state[i].level = qemu_get_byte(f); + s->irq_state[i].model = qemu_get_byte(f); + s->irq_state[i].trigger = qemu_get_byte(f); + } + + return 0; +} + static gic_state *gic_init(uint32_t base, qemu_irq *parent_irq) { gic_state *s; @@ -669,5 +742,6 @@ iomemtype); s->base = base; gic_reset(s); + register_savevm("arm_gic", -1, 1, gic_save, gic_load, s); return s; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/arm-misc.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/arm-misc.h --- qemu-0.9.1/hw/arm-misc.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/arm-misc.h 2008-09-17 20:04:14.000000000 +0100 @@ -21,13 +21,23 @@ const char *kernel_filename, const char *cpu_model); /* arm_boot.c */ - -void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, - const char *kernel_cmdline, const char *initrd_filename, - int board_id, target_phys_addr_t loader_start); +struct arm_boot_info { + int ram_size; + const char *kernel_filename; + const char *kernel_cmdline; + const char *initrd_filename; + target_phys_addr_t loader_start; + int nb_cpus; + int board_id; + int (*atag_board)(struct arm_boot_info *info, void *p); +}; +void arm_load_kernel(CPUState *env, struct arm_boot_info *info); /* armv7m_nvic.c */ -int system_clock_scale; + +/* Multiplication factor to convert from system clock ticks to qemu timer + ticks. */ +extern int system_clock_scale; qemu_irq *armv7m_nvic_init(CPUState *env); /* stellaris_enent.c */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/arm_timer.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/arm_timer.c --- qemu-0.9.1/hw/arm_timer.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/arm_timer.c 2008-07-02 17:48:32.000000000 +0100 @@ -143,6 +143,29 @@ arm_timer_update(s); } +static void arm_timer_save(QEMUFile *f, void *opaque) +{ + arm_timer_state *s = (arm_timer_state *)opaque; + qemu_put_be32(f, s->control); + qemu_put_be32(f, s->limit); + qemu_put_be32(f, s->int_level); + qemu_put_ptimer(f, s->timer); +} + +static int arm_timer_load(QEMUFile *f, void *opaque, int version_id) +{ + arm_timer_state *s = (arm_timer_state *)opaque; + + if (version_id != 1) + return -EINVAL; + + s->control = qemu_get_be32(f); + s->limit = qemu_get_be32(f); + s->int_level = qemu_get_be32(f); + qemu_get_ptimer(f, s->timer); + return 0; +} + static void *arm_timer_init(uint32_t freq, qemu_irq irq) { arm_timer_state *s; @@ -155,7 +178,7 @@ bh = qemu_bh_new(arm_timer_tick, s); s->timer = ptimer_init(bh); - /* ??? Save/restore. */ + register_savevm("arm_timer", -1, 1, arm_timer_save, arm_timer_load, s); return s; } @@ -218,6 +241,25 @@ sp804_write }; +static void sp804_save(QEMUFile *f, void *opaque) +{ + sp804_state *s = (sp804_state *)opaque; + qemu_put_be32(f, s->level[0]); + qemu_put_be32(f, s->level[1]); +} + +static int sp804_load(QEMUFile *f, void *opaque, int version_id) +{ + sp804_state *s = (sp804_state *)opaque; + + if (version_id != 1) + return -EINVAL; + + s->level[0] = qemu_get_be32(f); + s->level[1] = qemu_get_be32(f); + return 0; +} + void sp804_init(uint32_t base, qemu_irq irq) { int iomemtype; @@ -235,7 +277,7 @@ iomemtype = cpu_register_io_memory(0, sp804_readfn, sp804_writefn, s); cpu_register_physical_memory(base, 0x00001000, iomemtype); - /* ??? Save/restore. */ + register_savevm("sp804", -1, 1, sp804_save, sp804_load, s); } @@ -303,6 +345,7 @@ iomemtype = cpu_register_io_memory(0, icp_pit_readfn, icp_pit_writefn, s); cpu_register_physical_memory(base, 0x00001000, iomemtype); - /* ??? Save/restore. */ + /* This device has no state to save/restore. The component timers will + save themselves. */ } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/armv7m_nvic.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/armv7m_nvic.c --- qemu-0.9.1/hw/armv7m_nvic.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/armv7m_nvic.c 2008-09-17 20:04:14.000000000 +0100 @@ -50,8 +50,6 @@ #define SYSTICK_CLKSOURCE (1 << 2) #define SYSTICK_COUNTFLAG (1 << 16) -/* Multiplication factor to convert from system clock ticks to qemu timer - ticks. */ int system_clock_scale; /* Conversion factor from qemu timer to SysTick frequencies. */ @@ -368,6 +366,31 @@ } } +static void nvic_save(QEMUFile *f, void *opaque) +{ + nvic_state *s = (nvic_state *)opaque; + + qemu_put_be32(f, s->systick.control); + qemu_put_be32(f, s->systick.reload); + qemu_put_be64(f, s->systick.tick); + qemu_put_timer(f, s->systick.timer); +} + +static int nvic_load(QEMUFile *f, void *opaque, int version_id) +{ + nvic_state *s = (nvic_state *)opaque; + + if (version_id != 1) + return -EINVAL; + + s->systick.control = qemu_get_be32(f); + s->systick.reload = qemu_get_be32(f); + s->systick.tick = qemu_get_be64(f); + qemu_get_timer(f, s->systick.timer); + + return 0; +} + qemu_irq *armv7m_nvic_init(CPUState *env) { nvic_state *s; @@ -381,5 +404,6 @@ if (env->v7m.nvic) cpu_abort(env, "CPU can only have one NVIC\n"); env->v7m.nvic = s; + register_savevm("armv7m_nvic", -1, 1, nvic_save, nvic_load, s); return s->gic->in; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/audiodev.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/audiodev.h --- qemu-0.9.1/hw/audiodev.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/audiodev.h 2008-06-13 11:48:22.000000000 +0100 @@ -10,3 +10,8 @@ /* gus.c */ int GUS_init (AudioState *s, qemu_irq *pic); +/* ac97.c */ +int ac97_init (PCIBus *buf, AudioState *s); + +/* cs4231a.c */ +int cs4231a_init (AudioState *s, qemu_irq *pic); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/baum.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/baum.c --- qemu-0.9.1/hw/baum.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/baum.c 2008-04-08 07:01:02.000000000 +0100 @@ -0,0 +1,643 @@ +/* + * QEMU Baum Braille Device + * + * Copyright (c) 2008 Samuel Thibault + * + * 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 "qemu-common.h" +#include "qemu-char.h" +#include "qemu-timer.h" +#include "usb.h" +#include +#include +#include +#include +#ifdef CONFIG_SDL +#include +#endif + +#if 0 +#define DPRINTF(fmt, ...) \ + printf(fmt, ## __VA_ARGS__) +#else +#define DPRINTF(fmt, ...) +#endif + +#define ESC 0x1B + +#define BAUM_REQ_DisplayData 0x01 +#define BAUM_REQ_GetVersionNumber 0x05 +#define BAUM_REQ_GetKeys 0x08 +#define BAUM_REQ_SetMode 0x12 +#define BAUM_REQ_SetProtocol 0x15 +#define BAUM_REQ_GetDeviceIdentity 0x84 +#define BAUM_REQ_GetSerialNumber 0x8A + +#define BAUM_RSP_CellCount 0x01 +#define BAUM_RSP_VersionNumber 0x05 +#define BAUM_RSP_ModeSetting 0x11 +#define BAUM_RSP_CommunicationChannel 0x16 +#define BAUM_RSP_PowerdownSignal 0x17 +#define BAUM_RSP_HorizontalSensors 0x20 +#define BAUM_RSP_VerticalSensors 0x21 +#define BAUM_RSP_RoutingKeys 0x22 +#define BAUM_RSP_Switches 0x23 +#define BAUM_RSP_TopKeys 0x24 +#define BAUM_RSP_HorizontalSensor 0x25 +#define BAUM_RSP_VerticalSensor 0x26 +#define BAUM_RSP_RoutingKey 0x27 +#define BAUM_RSP_FrontKeys6 0x28 +#define BAUM_RSP_BackKeys6 0x29 +#define BAUM_RSP_CommandKeys 0x2B +#define BAUM_RSP_FrontKeys10 0x2C +#define BAUM_RSP_BackKeys10 0x2D +#define BAUM_RSP_EntryKeys 0x33 +#define BAUM_RSP_JoyStick 0x34 +#define BAUM_RSP_ErrorCode 0x40 +#define BAUM_RSP_InfoBlock 0x42 +#define BAUM_RSP_DeviceIdentity 0x84 +#define BAUM_RSP_SerialNumber 0x8A +#define BAUM_RSP_BluetoothName 0x8C + +#define BAUM_TL1 0x01 +#define BAUM_TL2 0x02 +#define BAUM_TL3 0x04 +#define BAUM_TR1 0x08 +#define BAUM_TR2 0x10 +#define BAUM_TR3 0x20 + +#define BUF_SIZE 256 + +typedef struct { + CharDriverState *chr; + + brlapi_handle_t *brlapi; + int brlapi_fd; + int x, y; + + uint8_t in_buf[BUF_SIZE]; + uint8_t in_buf_used; + uint8_t out_buf[BUF_SIZE]; + uint8_t out_buf_used, out_buf_ptr; + + QEMUTimer *cellCount_timer; +} BaumDriverState; + +/* Let's assume NABCC by default */ +static const uint8_t nabcc_translation[256] = { + [0] = ' ', +#ifndef BRLAPI_DOTS +#define BRLAPI_DOTS(d1,d2,d3,d4,d5,d6,d7,d8) \ + ((d1?BRLAPI_DOT1:0)|\ + (d2?BRLAPI_DOT2:0)|\ + (d3?BRLAPI_DOT3:0)|\ + (d4?BRLAPI_DOT4:0)|\ + (d5?BRLAPI_DOT5:0)|\ + (d6?BRLAPI_DOT6:0)|\ + (d7?BRLAPI_DOT7:0)|\ + (d8?BRLAPI_DOT8:0)) +#endif + [BRLAPI_DOTS(1,0,0,0,0,0,0,0)] = 'a', + [BRLAPI_DOTS(1,1,0,0,0,0,0,0)] = 'b', + [BRLAPI_DOTS(1,0,0,1,0,0,0,0)] = 'c', + [BRLAPI_DOTS(1,0,0,1,1,0,0,0)] = 'd', + [BRLAPI_DOTS(1,0,0,0,1,0,0,0)] = 'e', + [BRLAPI_DOTS(1,1,0,1,0,0,0,0)] = 'f', + [BRLAPI_DOTS(1,1,0,1,1,0,0,0)] = 'g', + [BRLAPI_DOTS(1,1,0,0,1,0,0,0)] = 'h', + [BRLAPI_DOTS(0,1,0,1,0,0,0,0)] = 'i', + [BRLAPI_DOTS(0,1,0,1,1,0,0,0)] = 'j', + [BRLAPI_DOTS(1,0,1,0,0,0,0,0)] = 'k', + [BRLAPI_DOTS(1,1,1,0,0,0,0,0)] = 'l', + [BRLAPI_DOTS(1,0,1,1,0,0,0,0)] = 'm', + [BRLAPI_DOTS(1,0,1,1,1,0,0,0)] = 'n', + [BRLAPI_DOTS(1,0,1,0,1,0,0,0)] = 'o', + [BRLAPI_DOTS(1,1,1,1,0,0,0,0)] = 'p', + [BRLAPI_DOTS(1,1,1,1,1,0,0,0)] = 'q', + [BRLAPI_DOTS(1,1,1,0,1,0,0,0)] = 'r', + [BRLAPI_DOTS(0,1,1,1,0,0,0,0)] = 's', + [BRLAPI_DOTS(0,1,1,1,1,0,0,0)] = 't', + [BRLAPI_DOTS(1,0,1,0,0,1,0,0)] = 'u', + [BRLAPI_DOTS(1,1,1,0,0,1,0,0)] = 'v', + [BRLAPI_DOTS(0,1,0,1,1,1,0,0)] = 'w', + [BRLAPI_DOTS(1,0,1,1,0,1,0,0)] = 'x', + [BRLAPI_DOTS(1,0,1,1,1,1,0,0)] = 'y', + [BRLAPI_DOTS(1,0,1,0,1,1,0,0)] = 'z', + + [BRLAPI_DOTS(1,0,0,0,0,0,1,0)] = 'A', + [BRLAPI_DOTS(1,1,0,0,0,0,1,0)] = 'B', + [BRLAPI_DOTS(1,0,0,1,0,0,1,0)] = 'C', + [BRLAPI_DOTS(1,0,0,1,1,0,1,0)] = 'D', + [BRLAPI_DOTS(1,0,0,0,1,0,1,0)] = 'E', + [BRLAPI_DOTS(1,1,0,1,0,0,1,0)] = 'F', + [BRLAPI_DOTS(1,1,0,1,1,0,1,0)] = 'G', + [BRLAPI_DOTS(1,1,0,0,1,0,1,0)] = 'H', + [BRLAPI_DOTS(0,1,0,1,0,0,1,0)] = 'I', + [BRLAPI_DOTS(0,1,0,1,1,0,1,0)] = 'J', + [BRLAPI_DOTS(1,0,1,0,0,0,1,0)] = 'K', + [BRLAPI_DOTS(1,1,1,0,0,0,1,0)] = 'L', + [BRLAPI_DOTS(1,0,1,1,0,0,1,0)] = 'M', + [BRLAPI_DOTS(1,0,1,1,1,0,1,0)] = 'N', + [BRLAPI_DOTS(1,0,1,0,1,0,1,0)] = 'O', + [BRLAPI_DOTS(1,1,1,1,0,0,1,0)] = 'P', + [BRLAPI_DOTS(1,1,1,1,1,0,1,0)] = 'Q', + [BRLAPI_DOTS(1,1,1,0,1,0,1,0)] = 'R', + [BRLAPI_DOTS(0,1,1,1,0,0,1,0)] = 'S', + [BRLAPI_DOTS(0,1,1,1,1,0,1,0)] = 'T', + [BRLAPI_DOTS(1,0,1,0,0,1,1,0)] = 'U', + [BRLAPI_DOTS(1,1,1,0,0,1,1,0)] = 'V', + [BRLAPI_DOTS(0,1,0,1,1,1,1,0)] = 'W', + [BRLAPI_DOTS(1,0,1,1,0,1,1,0)] = 'X', + [BRLAPI_DOTS(1,0,1,1,1,1,1,0)] = 'Y', + [BRLAPI_DOTS(1,0,1,0,1,1,1,0)] = 'Z', + + [BRLAPI_DOTS(0,0,1,0,1,1,0,0)] = '0', + [BRLAPI_DOTS(0,1,0,0,0,0,0,0)] = '1', + [BRLAPI_DOTS(0,1,1,0,0,0,0,0)] = '2', + [BRLAPI_DOTS(0,1,0,0,1,0,0,0)] = '3', + [BRLAPI_DOTS(0,1,0,0,1,1,0,0)] = '4', + [BRLAPI_DOTS(0,1,0,0,0,1,0,0)] = '5', + [BRLAPI_DOTS(0,1,1,0,1,0,0,0)] = '6', + [BRLAPI_DOTS(0,1,1,0,1,1,0,0)] = '7', + [BRLAPI_DOTS(0,1,1,0,0,1,0,0)] = '8', + [BRLAPI_DOTS(0,0,1,0,1,0,0,0)] = '9', + + [BRLAPI_DOTS(0,0,0,1,0,1,0,0)] = '.', + [BRLAPI_DOTS(0,0,1,1,0,1,0,0)] = '+', + [BRLAPI_DOTS(0,0,1,0,0,1,0,0)] = '-', + [BRLAPI_DOTS(1,0,0,0,0,1,0,0)] = '*', + [BRLAPI_DOTS(0,0,1,1,0,0,0,0)] = '/', + [BRLAPI_DOTS(1,1,1,0,1,1,0,0)] = '(', + [BRLAPI_DOTS(0,1,1,1,1,1,0,0)] = ')', + + [BRLAPI_DOTS(1,1,1,1,0,1,0,0)] = '&', + [BRLAPI_DOTS(0,0,1,1,1,1,0,0)] = '#', + + [BRLAPI_DOTS(0,0,0,0,0,1,0,0)] = ',', + [BRLAPI_DOTS(0,0,0,0,1,1,0,0)] = ';', + [BRLAPI_DOTS(1,0,0,0,1,1,0,0)] = ':', + [BRLAPI_DOTS(0,1,1,1,0,1,0,0)] = '!', + [BRLAPI_DOTS(1,0,0,1,1,1,0,0)] = '?', + [BRLAPI_DOTS(0,0,0,0,1,0,0,0)] = '"', + [BRLAPI_DOTS(0,0,1,0,0,0,0,0)] ='\'', + [BRLAPI_DOTS(0,0,0,1,0,0,0,0)] = '`', + [BRLAPI_DOTS(0,0,0,1,1,0,1,0)] = '^', + [BRLAPI_DOTS(0,0,0,1,1,0,0,0)] = '~', + [BRLAPI_DOTS(0,1,0,1,0,1,1,0)] = '[', + [BRLAPI_DOTS(1,1,0,1,1,1,1,0)] = ']', + [BRLAPI_DOTS(0,1,0,1,0,1,0,0)] = '{', + [BRLAPI_DOTS(1,1,0,1,1,1,0,0)] = '}', + [BRLAPI_DOTS(1,1,1,1,1,1,0,0)] = '=', + [BRLAPI_DOTS(1,1,0,0,0,1,0,0)] = '<', + [BRLAPI_DOTS(0,0,1,1,1,0,0,0)] = '>', + [BRLAPI_DOTS(1,1,0,1,0,1,0,0)] = '$', + [BRLAPI_DOTS(1,0,0,1,0,1,0,0)] = '%', + [BRLAPI_DOTS(0,0,0,1,0,0,1,0)] = '@', + [BRLAPI_DOTS(1,1,0,0,1,1,0,0)] = '|', + [BRLAPI_DOTS(1,1,0,0,1,1,1,0)] ='\\', + [BRLAPI_DOTS(0,0,0,1,1,1,0,0)] = '_', +}; + +/* The serial port can receive more of our data */ +static void baum_accept_input(struct CharDriverState *chr) +{ + BaumDriverState *baum = chr->opaque; + int room, first; + + if (!baum->out_buf_used) + return; + room = qemu_chr_can_read(chr); + if (!room) + return; + if (room > baum->out_buf_used) + room = baum->out_buf_used; + + first = BUF_SIZE - baum->out_buf_ptr; + if (room > first) { + qemu_chr_read(chr, baum->out_buf + baum->out_buf_ptr, first); + baum->out_buf_ptr = 0; + baum->out_buf_used -= first; + room -= first; + } + qemu_chr_read(chr, baum->out_buf + baum->out_buf_ptr, room); + baum->out_buf_ptr += room; + baum->out_buf_used -= room; +} + +/* We want to send a packet */ +static void baum_write_packet(BaumDriverState *baum, const uint8_t *buf, int len) +{ + uint8_t io_buf[1 + 2 * len], *cur = io_buf; + int room; + *cur++ = ESC; + while (len--) + if ((*cur++ = *buf++) == ESC) + *cur++ = ESC; + room = qemu_chr_can_read(baum->chr); + len = cur - io_buf; + if (len <= room) { + /* Fits */ + qemu_chr_read(baum->chr, io_buf, len); + } else { + int first; + uint8_t out; + /* Can't fit all, send what can be, and store the rest. */ + qemu_chr_read(baum->chr, io_buf, room); + len -= room; + cur = io_buf + room; + if (len > BUF_SIZE - baum->out_buf_used) { + /* Can't even store it, drop the previous data... */ + assert(len <= BUF_SIZE); + baum->out_buf_used = 0; + baum->out_buf_ptr = 0; + } + out = baum->out_buf_ptr; + baum->out_buf_used += len; + first = BUF_SIZE - baum->out_buf_ptr; + if (len > first) { + memcpy(baum->out_buf + out, cur, first); + out = 0; + len -= first; + cur += first; + } + memcpy(baum->out_buf + out, cur, len); + } +} + +/* Called when the other end seems to have a wrong idea of our display size */ +static void baum_cellCount_timer_cb(void *opaque) +{ + BaumDriverState *baum = opaque; + uint8_t cell_count[] = { BAUM_RSP_CellCount, baum->x * baum->y }; + DPRINTF("Timeout waiting for DisplayData, sending cell count\n"); + baum_write_packet(baum, cell_count, sizeof(cell_count)); +} + +/* Try to interpret a whole incoming packet */ +static int baum_eat_packet(BaumDriverState *baum, const uint8_t *buf, int len) +{ + const uint8_t *cur = buf; + uint8_t req = 0; + + if (!len--) + return 0; + if (*cur++ != ESC) { + while (*cur != ESC) { + if (!len--) + return 0; + cur++; + } + DPRINTF("Dropped %d bytes!\n", cur - buf); + } + +#define EAT(c) do {\ + if (!len--) \ + return 0; \ + if ((c = *cur++) == ESC) { \ + if (!len--) \ + return 0; \ + if (*cur++ != ESC) { \ + DPRINTF("Broken packet %#2x, tossing\n", req); \ + if (qemu_timer_pending(baum->cellCount_timer)) { \ + qemu_del_timer(baum->cellCount_timer); \ + baum_cellCount_timer_cb(baum); \ + } \ + return (cur - 2 - buf); \ + } \ + } \ +} while (0) + + EAT(req); + switch (req) { + case BAUM_REQ_DisplayData: + { + uint8_t cells[baum->x * baum->y], c; + uint8_t text[baum->x * baum->y]; + uint8_t zero[baum->x * baum->y]; + int cursor = BRLAPI_CURSOR_OFF; + int i; + + /* Allow 100ms to complete the DisplayData packet */ + qemu_mod_timer(baum->cellCount_timer, qemu_get_clock(vm_clock) + ticks_per_sec / 10); + for (i = 0; i < baum->x * baum->y ; i++) { + EAT(c); + cells[i] = c; + if ((c & (BRLAPI_DOT7|BRLAPI_DOT8)) + == (BRLAPI_DOT7|BRLAPI_DOT8)) { + cursor = i + 1; + c &= ~(BRLAPI_DOT7|BRLAPI_DOT8); + } + if (!(c = nabcc_translation[c])) + c = '?'; + text[i] = c; + } + qemu_del_timer(baum->cellCount_timer); + + memset(zero, 0, sizeof(zero)); + + brlapi_writeArguments_t wa = { + .displayNumber = BRLAPI_DISPLAY_DEFAULT, + .regionBegin = 1, + .regionSize = baum->x * baum->y, + .text = text, + .textSize = baum->x * baum->y, + .andMask = zero, + .orMask = cells, + .cursor = cursor, + .charset = "ISO-8859-1", + }; + + if (brlapi__write(baum->brlapi, &wa) == -1) + brlapi_perror("baum brlapi_write"); + break; + } + case BAUM_REQ_SetMode: + { + uint8_t mode, setting; + DPRINTF("SetMode\n"); + EAT(mode); + EAT(setting); + /* ignore */ + break; + } + case BAUM_REQ_SetProtocol: + { + uint8_t protocol; + DPRINTF("SetProtocol\n"); + EAT(protocol); + /* ignore */ + break; + } + case BAUM_REQ_GetDeviceIdentity: + { + uint8_t identity[17] = { BAUM_RSP_DeviceIdentity, + 'B','a','u','m',' ','V','a','r','i','o' }; + DPRINTF("GetDeviceIdentity\n"); + identity[11] = '0' + baum->x / 10; + identity[12] = '0' + baum->x % 10; + baum_write_packet(baum, identity, sizeof(identity)); + break; + } + case BAUM_REQ_GetVersionNumber: + { + uint8_t version[] = { BAUM_RSP_VersionNumber, 1 }; /* ? */ + DPRINTF("GetVersionNumber\n"); + baum_write_packet(baum, version, sizeof(version)); + break; + } + case BAUM_REQ_GetSerialNumber: + { + uint8_t serial[] = { BAUM_RSP_SerialNumber, + '0','0','0','0','0','0','0','0' }; + DPRINTF("GetSerialNumber\n"); + baum_write_packet(baum, serial, sizeof(serial)); + break; + } + case BAUM_REQ_GetKeys: + { + DPRINTF("Get%0#2x\n", req); + /* ignore */ + break; + } + default: + DPRINTF("unrecognized request %0#2x\n", req); + do + if (!len--) + return 0; + while (*cur++ != ESC); + cur--; + break; + } + return cur - buf; +} + +/* The other end is writing some data. Store it and try to interpret */ +static int baum_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + BaumDriverState *baum = chr->opaque; + int tocopy, cur, eaten, orig_len = len; + + if (!len) + return 0; + if (!baum->brlapi) + return len; + + while (len) { + /* Complete our buffer as much as possible */ + tocopy = len; + if (tocopy > BUF_SIZE - baum->in_buf_used) + tocopy = BUF_SIZE - baum->in_buf_used; + + memcpy(baum->in_buf + baum->in_buf_used, buf, tocopy); + baum->in_buf_used += tocopy; + buf += tocopy; + len -= tocopy; + + /* Interpret it as much as possible */ + cur = 0; + while (cur < baum->in_buf_used && + (eaten = baum_eat_packet(baum, baum->in_buf + cur, baum->in_buf_used - cur))) + cur += eaten; + + /* Shift the remainder */ + if (cur) { + memmove(baum->in_buf, baum->in_buf + cur, baum->in_buf_used - cur); + baum->in_buf_used -= cur; + } + + /* And continue if any data left */ + } + return orig_len; +} + +/* The other end sent us some event */ +static void baum_send_event(CharDriverState *chr, int event) +{ + BaumDriverState *baum = chr->opaque; + switch (event) { + case CHR_EVENT_BREAK: + break; + case CHR_EVENT_RESET: + /* Reset state */ + baum->in_buf_used = 0; + break; + } +} + +/* Send the key code to the other end */ +static void baum_send_key(BaumDriverState *baum, uint8_t type, uint8_t value) { + uint8_t packet[] = { type, value }; + DPRINTF("writing key %x %x\n", type, value); + baum_write_packet(baum, packet, sizeof(packet)); +} + +/* We got some data on the BrlAPI socket */ +static void baum_chr_read(void *opaque) +{ + BaumDriverState *baum = opaque; + brlapi_keyCode_t code; + int ret; + if (!baum->brlapi) + return; + while ((ret = brlapi__readKey(baum->brlapi, 0, &code)) == 1) { + DPRINTF("got key %"BRLAPI_PRIxKEYCODE"\n", code); + /* Emulate */ + switch (code & BRLAPI_KEY_TYPE_MASK) { + case BRLAPI_KEY_TYPE_CMD: + switch (code & BRLAPI_KEY_CMD_BLK_MASK) { + case BRLAPI_KEY_CMD_ROUTE: + baum_send_key(baum, BAUM_RSP_RoutingKey, (code & BRLAPI_KEY_CMD_ARG_MASK)+1); + baum_send_key(baum, BAUM_RSP_RoutingKey, 0); + break; + case 0: + switch (code & BRLAPI_KEY_CMD_ARG_MASK) { + case BRLAPI_KEY_CMD_FWINLT: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + case BRLAPI_KEY_CMD_FWINRT: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR2); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + case BRLAPI_KEY_CMD_LNUP: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR1); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + case BRLAPI_KEY_CMD_LNDN: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR3); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + case BRLAPI_KEY_CMD_TOP: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TR1); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + case BRLAPI_KEY_CMD_BOT: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL3|BAUM_TR3); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + case BRLAPI_KEY_CMD_TOP_LEFT: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + case BRLAPI_KEY_CMD_BOT_LEFT: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR3); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + case BRLAPI_KEY_CMD_HOME: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1|BAUM_TR3); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + case BRLAPI_KEY_CMD_PREFMENU: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TL3|BAUM_TR1); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + } + } + break; + case BRLAPI_KEY_TYPE_SYM: + break; + } + } + if (ret == -1 && (brlapi_errno != BRLAPI_ERROR_LIBCERR || errno != EINTR)) { + brlapi_perror("baum: brlapi_readKey"); + brlapi__closeConnection(baum->brlapi); + free(baum->brlapi); + baum->brlapi = NULL; + } +} + +CharDriverState *chr_baum_init(void) +{ + BaumDriverState *baum; + CharDriverState *chr; + brlapi_handle_t *handle; +#ifdef CONFIG_SDL + SDL_SysWMinfo info; +#endif + int tty; + + baum = qemu_mallocz(sizeof(BaumDriverState)); + if (!baum) + return NULL; + + baum->chr = chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + goto fail_baum; + + chr->opaque = baum; + chr->chr_write = baum_write; + chr->chr_send_event = baum_send_event; + chr->chr_accept_input = baum_accept_input; + + handle = qemu_mallocz(brlapi_getHandleSize()); + if (!handle) + goto fail_chr; + baum->brlapi = handle; + + baum->brlapi_fd = brlapi__openConnection(handle, NULL, NULL); + if (baum->brlapi_fd == -1) { + brlapi_perror("baum_init: brlapi_openConnection"); + goto fail_handle; + } + + baum->cellCount_timer = qemu_new_timer(vm_clock, baum_cellCount_timer_cb, baum); + + if (brlapi__getDisplaySize(handle, &baum->x, &baum->y) == -1) { + brlapi_perror("baum_init: brlapi_getDisplaySize"); + goto fail; + } + +#ifdef CONFIG_SDL + memset(&info, 0, sizeof(info)); + SDL_VERSION(&info.version); + if (SDL_GetWMInfo(&info)) + tty = info.info.x11.wmwindow; + else +#endif + tty = BRLAPI_TTY_DEFAULT; + + if (brlapi__enterTtyMode(handle, tty, NULL) == -1) { + brlapi_perror("baum_init: brlapi_enterTtyMode"); + goto fail; + } + + qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum); + + qemu_chr_reset(chr); + + return chr; + +fail: + qemu_free_timer(baum->cellCount_timer); + brlapi__closeConnection(handle); +fail_handle: + free(handle); +fail_chr: + free(chr); +fail_baum: + free(baum); + return NULL; +} + +USBDevice *usb_baum_init(void) +{ + /* USB Product ID of Super Vario 40 */ + return usb_serial_init("productid=FE72:braille"); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/baum.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/baum.h --- qemu-0.9.1/hw/baum.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/baum.h 2008-04-08 07:01:02.000000000 +0100 @@ -0,0 +1,29 @@ +/* + * QEMU Baum + * + * Copyright (c) 2008 Samuel Thibault + * + * 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. + */ + +/* usb device */ +USBDevice *usb_baum_init(void); + +/* char device */ +CharDriverState *chr_baum_init(void); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/blizzard.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/blizzard.c --- qemu-0.9.1/hw/blizzard.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/blizzard.c 2008-08-06 09:37:17.000000000 +0100 @@ -0,0 +1,1002 @@ +/* + * Epson S1D13744/S1D13745 (Blizzard/Hailstorm/Tornado) LCD/TV controller. + * + * Copyright (C) 2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "qemu-common.h" +#include "sysemu.h" +#include "console.h" +#include "devices.h" +#include "vga_int.h" +#include "pixel_ops.h" + +typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int); + +struct blizzard_s { + uint8_t reg; + uint32_t addr; + int swallow; + + int pll; + int pll_range; + int pll_ctrl; + uint8_t pll_mode; + uint8_t clksel; + int memenable; + int memrefresh; + uint8_t timing[3]; + int priority; + + uint8_t lcd_config; + int x; + int y; + int skipx; + int skipy; + uint8_t hndp; + uint8_t vndp; + uint8_t hsync; + uint8_t vsync; + uint8_t pclk; + uint8_t u; + uint8_t v; + uint8_t yrc[2]; + int ix[2]; + int iy[2]; + int ox[2]; + int oy[2]; + + int enable; + int blank; + int bpp; + int invalidate; + int mx[2]; + int my[2]; + uint8_t mode; + uint8_t effect; + uint8_t iformat; + uint8_t source; + DisplayState *state; + QEMUConsole *console; + blizzard_fn_t *line_fn_tab[2]; + void *fb; + + uint8_t hssi_config[3]; + uint8_t tv_config; + uint8_t tv_timing[4]; + uint8_t vbi; + uint8_t tv_x; + uint8_t tv_y; + uint8_t tv_test; + uint8_t tv_filter_config; + uint8_t tv_filter_idx; + uint8_t tv_filter_coeff[0x20]; + uint8_t border_r; + uint8_t border_g; + uint8_t border_b; + uint8_t gamma_config; + uint8_t gamma_idx; + uint8_t gamma_lut[0x100]; + uint8_t matrix_ena; + uint8_t matrix_coeff[0x12]; + uint8_t matrix_r; + uint8_t matrix_g; + uint8_t matrix_b; + uint8_t pm; + uint8_t status; + uint8_t rgbgpio_dir; + uint8_t rgbgpio; + uint8_t gpio_dir; + uint8_t gpio; + uint8_t gpio_edge[2]; + uint8_t gpio_irq; + uint8_t gpio_pdown; + + struct { + int x; + int y; + int dx; + int dy; + int len; + int buflen; + void *buf; + void *data; + uint16_t *ptr; + int angle; + int pitch; + blizzard_fn_t line_fn; + } data; +}; + +/* Bytes(!) per pixel */ +static const int blizzard_iformat_bpp[0x10] = { + 0, + 2, /* RGB 5:6:5*/ + 3, /* RGB 6:6:6 mode 1 */ + 3, /* RGB 8:8:8 mode 1 */ + 0, 0, + 4, /* RGB 6:6:6 mode 2 */ + 4, /* RGB 8:8:8 mode 2 */ + 0, /* YUV 4:2:2 */ + 0, /* YUV 4:2:0 */ + 0, 0, 0, 0, 0, 0, +}; + +static inline void blizzard_rgb2yuv(int r, int g, int b, + int *y, int *u, int *v) +{ + *y = 0x10 + ((0x838 * r + 0x1022 * g + 0x322 * b) >> 13); + *u = 0x80 + ((0xe0e * b - 0x04c1 * r - 0x94e * g) >> 13); + *v = 0x80 + ((0xe0e * r - 0x0bc7 * g - 0x247 * b) >> 13); +} + +static void blizzard_window(struct blizzard_s *s) +{ + uint8_t *src, *dst; + int bypp[2]; + int bypl[3]; + int y; + blizzard_fn_t fn = s->data.line_fn; + + if (!fn) + return; + if (s->mx[0] > s->data.x) + s->mx[0] = s->data.x; + if (s->my[0] > s->data.y) + s->my[0] = s->data.y; + if (s->mx[1] < s->data.x + s->data.dx) + s->mx[1] = s->data.x + s->data.dx; + if (s->my[1] < s->data.y + s->data.dy) + s->my[1] = s->data.y + s->data.dy; + + bypp[0] = s->bpp; + bypp[1] = (s->state->depth + 7) >> 3; + bypl[0] = bypp[0] * s->data.pitch; + bypl[1] = bypp[1] * s->x; + bypl[2] = bypp[0] * s->data.dx; + + src = s->data.data; + dst = s->fb + bypl[1] * s->data.y + bypp[1] * s->data.x; + for (y = s->data.dy; y > 0; y --, src += bypl[0], dst += bypl[1]) + fn(dst, src, bypl[2]); +} + +static int blizzard_transfer_setup(struct blizzard_s *s) +{ + if (s->source > 3 || !s->bpp || + s->ix[1] < s->ix[0] || s->iy[1] < s->iy[0]) + return 0; + + s->data.angle = s->effect & 3; + s->data.line_fn = s->line_fn_tab[!!s->data.angle][s->iformat]; + s->data.x = s->ix[0]; + s->data.y = s->iy[0]; + s->data.dx = s->ix[1] - s->ix[0] + 1; + s->data.dy = s->iy[1] - s->iy[0] + 1; + s->data.len = s->bpp * s->data.dx * s->data.dy; + s->data.pitch = s->data.dx; + if (s->data.len > s->data.buflen) { + s->data.buf = qemu_realloc(s->data.buf, s->data.len); + s->data.buflen = s->data.len; + } + s->data.ptr = s->data.buf; + s->data.data = s->data.buf; + s->data.len /= 2; + return 1; +} + +static void blizzard_reset(struct blizzard_s *s) +{ + s->reg = 0; + s->swallow = 0; + + s->pll = 9; + s->pll_range = 1; + s->pll_ctrl = 0x14; + s->pll_mode = 0x32; + s->clksel = 0x00; + s->memenable = 0; + s->memrefresh = 0x25c; + s->timing[0] = 0x3f; + s->timing[1] = 0x13; + s->timing[2] = 0x21; + s->priority = 0; + + s->lcd_config = 0x74; + s->x = 8; + s->y = 1; + s->skipx = 0; + s->skipy = 0; + s->hndp = 3; + s->vndp = 2; + s->hsync = 1; + s->vsync = 1; + s->pclk = 0x80; + + s->ix[0] = 0; + s->ix[1] = 0; + s->iy[0] = 0; + s->iy[1] = 0; + s->ox[0] = 0; + s->ox[1] = 0; + s->oy[0] = 0; + s->oy[1] = 0; + + s->yrc[0] = 0x00; + s->yrc[1] = 0x30; + s->u = 0; + s->v = 0; + + s->iformat = 3; + s->source = 0; + s->bpp = blizzard_iformat_bpp[s->iformat]; + + s->hssi_config[0] = 0x00; + s->hssi_config[1] = 0x00; + s->hssi_config[2] = 0x01; + s->tv_config = 0x00; + s->tv_timing[0] = 0x00; + s->tv_timing[1] = 0x00; + s->tv_timing[2] = 0x00; + s->tv_timing[3] = 0x00; + s->vbi = 0x10; + s->tv_x = 0x14; + s->tv_y = 0x03; + s->tv_test = 0x00; + s->tv_filter_config = 0x80; + s->tv_filter_idx = 0x00; + s->border_r = 0x10; + s->border_g = 0x80; + s->border_b = 0x80; + s->gamma_config = 0x00; + s->gamma_idx = 0x00; + s->matrix_ena = 0x00; + memset(&s->matrix_coeff, 0, sizeof(s->matrix_coeff)); + s->matrix_r = 0x00; + s->matrix_g = 0x00; + s->matrix_b = 0x00; + s->pm = 0x02; + s->status = 0x00; + s->rgbgpio_dir = 0x00; + s->gpio_dir = 0x00; + s->gpio_edge[0] = 0x00; + s->gpio_edge[1] = 0x00; + s->gpio_irq = 0x00; + s->gpio_pdown = 0xff; +} + +static inline void blizzard_invalidate_display(void *opaque) { + struct blizzard_s *s = (struct blizzard_s *) opaque; + + s->invalidate = 1; +} + +static uint16_t blizzard_reg_read(void *opaque, uint8_t reg) +{ + struct blizzard_s *s = (struct blizzard_s *) opaque; + + switch (reg) { + case 0x00: /* Revision Code */ + return 0xa5; + + case 0x02: /* Configuration Readback */ + return 0x83; /* Macrovision OK, CNF[2:0] = 3 */ + + case 0x04: /* PLL M-Divider */ + return (s->pll - 1) | (1 << 7); + case 0x06: /* PLL Lock Range Control */ + return s->pll_range; + case 0x08: /* PLL Lock Synthesis Control 0 */ + return s->pll_ctrl & 0xff; + case 0x0a: /* PLL Lock Synthesis Control 1 */ + return s->pll_ctrl >> 8; + case 0x0c: /* PLL Mode Control 0 */ + return s->pll_mode; + + case 0x0e: /* Clock-Source Select */ + return s->clksel; + + case 0x10: /* Memory Controller Activate */ + case 0x14: /* Memory Controller Bank 0 Status Flag */ + return s->memenable; + + case 0x18: /* Auto-Refresh Interval Setting 0 */ + return s->memrefresh & 0xff; + case 0x1a: /* Auto-Refresh Interval Setting 1 */ + return s->memrefresh >> 8; + + case 0x1c: /* Power-On Sequence Timing Control */ + return s->timing[0]; + case 0x1e: /* Timing Control 0 */ + return s->timing[1]; + case 0x20: /* Timing Control 1 */ + return s->timing[2]; + + case 0x24: /* Arbitration Priority Control */ + return s->priority; + + case 0x28: /* LCD Panel Configuration */ + return s->lcd_config; + + case 0x2a: /* LCD Horizontal Display Width */ + return s->x >> 3; + case 0x2c: /* LCD Horizontal Non-display Period */ + return s->hndp; + case 0x2e: /* LCD Vertical Display Height 0 */ + return s->y & 0xff; + case 0x30: /* LCD Vertical Display Height 1 */ + return s->y >> 8; + case 0x32: /* LCD Vertical Non-display Period */ + return s->vndp; + case 0x34: /* LCD HS Pulse-width */ + return s->hsync; + case 0x36: /* LCd HS Pulse Start Position */ + return s->skipx >> 3; + case 0x38: /* LCD VS Pulse-width */ + return s->vsync; + case 0x3a: /* LCD VS Pulse Start Position */ + return s->skipy; + + case 0x3c: /* PCLK Polarity */ + return s->pclk; + + case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */ + return s->hssi_config[0]; + case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */ + return s->hssi_config[1]; + case 0x42: /* High-speed Serial Interface Tx Mode */ + return s->hssi_config[2]; + case 0x44: /* TV Display Configuration */ + return s->tv_config; + case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits */ + return s->tv_timing[(reg - 0x46) >> 1]; + case 0x4e: /* VBI: Closed Caption / XDS Control / Status */ + return s->vbi; + case 0x50: /* TV Horizontal Start Position */ + return s->tv_x; + case 0x52: /* TV Vertical Start Position */ + return s->tv_y; + case 0x54: /* TV Test Pattern Setting */ + return s->tv_test; + case 0x56: /* TV Filter Setting */ + return s->tv_filter_config; + case 0x58: /* TV Filter Coefficient Index */ + return s->tv_filter_idx; + case 0x5a: /* TV Filter Coefficient Data */ + if (s->tv_filter_idx < 0x20) + return s->tv_filter_coeff[s->tv_filter_idx ++]; + return 0; + + case 0x60: /* Input YUV/RGB Translate Mode 0 */ + return s->yrc[0]; + case 0x62: /* Input YUV/RGB Translate Mode 1 */ + return s->yrc[1]; + case 0x64: /* U Data Fix */ + return s->u; + case 0x66: /* V Data Fix */ + return s->v; + + case 0x68: /* Display Mode */ + return s->mode; + + case 0x6a: /* Special Effects */ + return s->effect; + + case 0x6c: /* Input Window X Start Position 0 */ + return s->ix[0] & 0xff; + case 0x6e: /* Input Window X Start Position 1 */ + return s->ix[0] >> 3; + case 0x70: /* Input Window Y Start Position 0 */ + return s->ix[0] & 0xff; + case 0x72: /* Input Window Y Start Position 1 */ + return s->ix[0] >> 3; + case 0x74: /* Input Window X End Position 0 */ + return s->ix[1] & 0xff; + case 0x76: /* Input Window X End Position 1 */ + return s->ix[1] >> 3; + case 0x78: /* Input Window Y End Position 0 */ + return s->ix[1] & 0xff; + case 0x7a: /* Input Window Y End Position 1 */ + return s->ix[1] >> 3; + case 0x7c: /* Output Window X Start Position 0 */ + return s->ox[0] & 0xff; + case 0x7e: /* Output Window X Start Position 1 */ + return s->ox[0] >> 3; + case 0x80: /* Output Window Y Start Position 0 */ + return s->oy[0] & 0xff; + case 0x82: /* Output Window Y Start Position 1 */ + return s->oy[0] >> 3; + case 0x84: /* Output Window X End Position 0 */ + return s->ox[1] & 0xff; + case 0x86: /* Output Window X End Position 1 */ + return s->ox[1] >> 3; + case 0x88: /* Output Window Y End Position 0 */ + return s->oy[1] & 0xff; + case 0x8a: /* Output Window Y End Position 1 */ + return s->oy[1] >> 3; + + case 0x8c: /* Input Data Format */ + return s->iformat; + case 0x8e: /* Data Source Select */ + return s->source; + case 0x90: /* Display Memory Data Port */ + return 0; + + case 0xa8: /* Border Color 0 */ + return s->border_r; + case 0xaa: /* Border Color 1 */ + return s->border_g; + case 0xac: /* Border Color 2 */ + return s->border_b; + + case 0xb4: /* Gamma Correction Enable */ + return s->gamma_config; + case 0xb6: /* Gamma Correction Table Index */ + return s->gamma_idx; + case 0xb8: /* Gamma Correction Table Data */ + return s->gamma_lut[s->gamma_idx ++]; + + case 0xba: /* 3x3 Matrix Enable */ + return s->matrix_ena; + case 0xbc ... 0xde: /* Coefficient Registers */ + return s->matrix_coeff[(reg - 0xbc) >> 1]; + case 0xe0: /* 3x3 Matrix Red Offset */ + return s->matrix_r; + case 0xe2: /* 3x3 Matrix Green Offset */ + return s->matrix_g; + case 0xe4: /* 3x3 Matrix Blue Offset */ + return s->matrix_b; + + case 0xe6: /* Power-save */ + return s->pm; + case 0xe8: /* Non-display Period Control / Status */ + return s->status | (1 << 5); + case 0xea: /* RGB Interface Control */ + return s->rgbgpio_dir; + case 0xec: /* RGB Interface Status */ + return s->rgbgpio; + case 0xee: /* General-purpose IO Pins Configuration */ + return s->gpio_dir; + case 0xf0: /* General-purpose IO Pins Status / Control */ + return s->gpio; + case 0xf2: /* GPIO Positive Edge Interrupt Trigger */ + return s->gpio_edge[0]; + case 0xf4: /* GPIO Negative Edge Interrupt Trigger */ + return s->gpio_edge[1]; + case 0xf6: /* GPIO Interrupt Status */ + return s->gpio_irq; + case 0xf8: /* GPIO Pull-down Control */ + return s->gpio_pdown; + + default: + fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg); + return 0; + } +} + +static void blizzard_reg_write(void *opaque, uint8_t reg, uint16_t value) +{ + struct blizzard_s *s = (struct blizzard_s *) opaque; + + switch (reg) { + case 0x04: /* PLL M-Divider */ + s->pll = (value & 0x3f) + 1; + break; + case 0x06: /* PLL Lock Range Control */ + s->pll_range = value & 3; + break; + case 0x08: /* PLL Lock Synthesis Control 0 */ + s->pll_ctrl &= 0xf00; + s->pll_ctrl |= (value << 0) & 0x0ff; + break; + case 0x0a: /* PLL Lock Synthesis Control 1 */ + s->pll_ctrl &= 0x0ff; + s->pll_ctrl |= (value << 8) & 0xf00; + break; + case 0x0c: /* PLL Mode Control 0 */ + s->pll_mode = value & 0x77; + if ((value & 3) == 0 || (value & 3) == 3) + fprintf(stderr, "%s: wrong PLL Control bits (%i)\n", + __FUNCTION__, value & 3); + break; + + case 0x0e: /* Clock-Source Select */ + s->clksel = value & 0xff; + break; + + case 0x10: /* Memory Controller Activate */ + s->memenable = value & 1; + break; + case 0x14: /* Memory Controller Bank 0 Status Flag */ + break; + + case 0x18: /* Auto-Refresh Interval Setting 0 */ + s->memrefresh &= 0xf00; + s->memrefresh |= (value << 0) & 0x0ff; + break; + case 0x1a: /* Auto-Refresh Interval Setting 1 */ + s->memrefresh &= 0x0ff; + s->memrefresh |= (value << 8) & 0xf00; + break; + + case 0x1c: /* Power-On Sequence Timing Control */ + s->timing[0] = value & 0x7f; + break; + case 0x1e: /* Timing Control 0 */ + s->timing[1] = value & 0x17; + break; + case 0x20: /* Timing Control 1 */ + s->timing[2] = value & 0x35; + break; + + case 0x24: /* Arbitration Priority Control */ + s->priority = value & 1; + break; + + case 0x28: /* LCD Panel Configuration */ + s->lcd_config = value & 0xff; + if (value & (1 << 7)) + fprintf(stderr, "%s: data swap not supported!\n", __FUNCTION__); + break; + + case 0x2a: /* LCD Horizontal Display Width */ + s->x = value << 3; + break; + case 0x2c: /* LCD Horizontal Non-display Period */ + s->hndp = value & 0xff; + break; + case 0x2e: /* LCD Vertical Display Height 0 */ + s->y &= 0x300; + s->y |= (value << 0) & 0x0ff; + break; + case 0x30: /* LCD Vertical Display Height 1 */ + s->y &= 0x0ff; + s->y |= (value << 8) & 0x300; + break; + case 0x32: /* LCD Vertical Non-display Period */ + s->vndp = value & 0xff; + break; + case 0x34: /* LCD HS Pulse-width */ + s->hsync = value & 0xff; + break; + case 0x36: /* LCD HS Pulse Start Position */ + s->skipx = value & 0xff; + break; + case 0x38: /* LCD VS Pulse-width */ + s->vsync = value & 0xbf; + break; + case 0x3a: /* LCD VS Pulse Start Position */ + s->skipy = value & 0xff; + break; + + case 0x3c: /* PCLK Polarity */ + s->pclk = value & 0x82; + /* Affects calculation of s->hndp, s->hsync and s->skipx. */ + break; + + case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */ + s->hssi_config[0] = value; + break; + case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */ + s->hssi_config[1] = value; + if (((value >> 4) & 3) == 3) + fprintf(stderr, "%s: Illegal active-data-links value\n", + __FUNCTION__); + break; + case 0x42: /* High-speed Serial Interface Tx Mode */ + s->hssi_config[2] = value & 0xbd; + break; + + case 0x44: /* TV Display Configuration */ + s->tv_config = value & 0xfe; + break; + case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits 0 */ + s->tv_timing[(reg - 0x46) >> 1] = value; + break; + case 0x4e: /* VBI: Closed Caption / XDS Control / Status */ + s->vbi = value; + break; + case 0x50: /* TV Horizontal Start Position */ + s->tv_x = value; + break; + case 0x52: /* TV Vertical Start Position */ + s->tv_y = value & 0x7f; + break; + case 0x54: /* TV Test Pattern Setting */ + s->tv_test = value; + break; + case 0x56: /* TV Filter Setting */ + s->tv_filter_config = value & 0xbf; + break; + case 0x58: /* TV Filter Coefficient Index */ + s->tv_filter_idx = value & 0x1f; + break; + case 0x5a: /* TV Filter Coefficient Data */ + if (s->tv_filter_idx < 0x20) + s->tv_filter_coeff[s->tv_filter_idx ++] = value; + break; + + case 0x60: /* Input YUV/RGB Translate Mode 0 */ + s->yrc[0] = value & 0xb0; + break; + case 0x62: /* Input YUV/RGB Translate Mode 1 */ + s->yrc[1] = value & 0x30; + break; + case 0x64: /* U Data Fix */ + s->u = value & 0xff; + break; + case 0x66: /* V Data Fix */ + s->v = value & 0xff; + break; + + case 0x68: /* Display Mode */ + if ((s->mode ^ value) & 3) + s->invalidate = 1; + s->mode = value & 0xb7; + s->enable = value & 1; + s->blank = (value >> 1) & 1; + if (value & (1 << 4)) + fprintf(stderr, "%s: Macrovision enable attempt!\n", __FUNCTION__); + break; + + case 0x6a: /* Special Effects */ + s->effect = value & 0xfb; + break; + + case 0x6c: /* Input Window X Start Position 0 */ + s->ix[0] &= 0x300; + s->ix[0] |= (value << 0) & 0x0ff; + break; + case 0x6e: /* Input Window X Start Position 1 */ + s->ix[0] &= 0x0ff; + s->ix[0] |= (value << 8) & 0x300; + break; + case 0x70: /* Input Window Y Start Position 0 */ + s->iy[0] &= 0x300; + s->iy[0] |= (value << 0) & 0x0ff; + break; + case 0x72: /* Input Window Y Start Position 1 */ + s->iy[0] &= 0x0ff; + s->iy[0] |= (value << 8) & 0x300; + break; + case 0x74: /* Input Window X End Position 0 */ + s->ix[1] &= 0x300; + s->ix[1] |= (value << 0) & 0x0ff; + break; + case 0x76: /* Input Window X End Position 1 */ + s->ix[1] &= 0x0ff; + s->ix[1] |= (value << 8) & 0x300; + break; + case 0x78: /* Input Window Y End Position 0 */ + s->iy[1] &= 0x300; + s->iy[1] |= (value << 0) & 0x0ff; + break; + case 0x7a: /* Input Window Y End Position 1 */ + s->iy[1] &= 0x0ff; + s->iy[1] |= (value << 8) & 0x300; + break; + case 0x7c: /* Output Window X Start Position 0 */ + s->ox[0] &= 0x300; + s->ox[0] |= (value << 0) & 0x0ff; + break; + case 0x7e: /* Output Window X Start Position 1 */ + s->ox[0] &= 0x0ff; + s->ox[0] |= (value << 8) & 0x300; + break; + case 0x80: /* Output Window Y Start Position 0 */ + s->oy[0] &= 0x300; + s->oy[0] |= (value << 0) & 0x0ff; + break; + case 0x82: /* Output Window Y Start Position 1 */ + s->oy[0] &= 0x0ff; + s->oy[0] |= (value << 8) & 0x300; + break; + case 0x84: /* Output Window X End Position 0 */ + s->ox[1] &= 0x300; + s->ox[1] |= (value << 0) & 0x0ff; + break; + case 0x86: /* Output Window X End Position 1 */ + s->ox[1] &= 0x0ff; + s->ox[1] |= (value << 8) & 0x300; + break; + case 0x88: /* Output Window Y End Position 0 */ + s->oy[1] &= 0x300; + s->oy[1] |= (value << 0) & 0x0ff; + break; + case 0x8a: /* Output Window Y End Position 1 */ + s->oy[1] &= 0x0ff; + s->oy[1] |= (value << 8) & 0x300; + break; + + case 0x8c: /* Input Data Format */ + s->iformat = value & 0xf; + s->bpp = blizzard_iformat_bpp[s->iformat]; + if (!s->bpp) + fprintf(stderr, "%s: Illegal or unsupported input format %x\n", + __FUNCTION__, s->iformat); + break; + case 0x8e: /* Data Source Select */ + s->source = value & 7; + /* Currently all windows will be "destructive overlays". */ + if ((!(s->effect & (1 << 3)) && (s->ix[0] != s->ox[0] || + s->iy[0] != s->oy[0] || + s->ix[1] != s->ox[1] || + s->iy[1] != s->oy[1])) || + !((s->ix[1] - s->ix[0]) & (s->iy[1] - s->iy[0]) & + (s->ox[1] - s->ox[0]) & (s->oy[1] - s->oy[0]) & 1)) + fprintf(stderr, "%s: Illegal input/output window positions\n", + __FUNCTION__); + + blizzard_transfer_setup(s); + break; + + case 0x90: /* Display Memory Data Port */ + if (!s->data.len && !blizzard_transfer_setup(s)) + break; + + *s->data.ptr ++ = value; + if (-- s->data.len == 0) + blizzard_window(s); + break; + + case 0xa8: /* Border Color 0 */ + s->border_r = value; + break; + case 0xaa: /* Border Color 1 */ + s->border_g = value; + break; + case 0xac: /* Border Color 2 */ + s->border_b = value; + break; + + case 0xb4: /* Gamma Correction Enable */ + s->gamma_config = value & 0x87; + break; + case 0xb6: /* Gamma Correction Table Index */ + s->gamma_idx = value; + break; + case 0xb8: /* Gamma Correction Table Data */ + s->gamma_lut[s->gamma_idx ++] = value; + break; + + case 0xba: /* 3x3 Matrix Enable */ + s->matrix_ena = value & 1; + break; + case 0xbc ... 0xde: /* Coefficient Registers */ + s->matrix_coeff[(reg - 0xbc) >> 1] = value & ((reg & 2) ? 0x80 : 0xff); + break; + case 0xe0: /* 3x3 Matrix Red Offset */ + s->matrix_r = value; + break; + case 0xe2: /* 3x3 Matrix Green Offset */ + s->matrix_g = value; + break; + case 0xe4: /* 3x3 Matrix Blue Offset */ + s->matrix_b = value; + break; + + case 0xe6: /* Power-save */ + s->pm = value & 0x83; + if (value & s->mode & 1) + fprintf(stderr, "%s: The display must be disabled before entering " + "Standby Mode\n", __FUNCTION__); + break; + case 0xe8: /* Non-display Period Control / Status */ + s->status = value & 0x1b; + break; + case 0xea: /* RGB Interface Control */ + s->rgbgpio_dir = value & 0x8f; + break; + case 0xec: /* RGB Interface Status */ + s->rgbgpio = value & 0xcf; + break; + case 0xee: /* General-purpose IO Pins Configuration */ + s->gpio_dir = value; + break; + case 0xf0: /* General-purpose IO Pins Status / Control */ + s->gpio = value; + break; + case 0xf2: /* GPIO Positive Edge Interrupt Trigger */ + s->gpio_edge[0] = value; + break; + case 0xf4: /* GPIO Negative Edge Interrupt Trigger */ + s->gpio_edge[1] = value; + break; + case 0xf6: /* GPIO Interrupt Status */ + s->gpio_irq &= value; + break; + case 0xf8: /* GPIO Pull-down Control */ + s->gpio_pdown = value; + break; + + default: + fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg); + break; + } +} + +uint16_t s1d13745_read(void *opaque, int dc) +{ + struct blizzard_s *s = (struct blizzard_s *) opaque; + uint16_t value = blizzard_reg_read(s, s->reg); + + if (s->swallow -- > 0) + return 0; + if (dc) + s->reg ++; + + return value; +} + +void s1d13745_write(void *opaque, int dc, uint16_t value) +{ + struct blizzard_s *s = (struct blizzard_s *) opaque; + + if (s->swallow -- > 0) + return; + if (dc) { + blizzard_reg_write(s, s->reg, value); + + if (s->reg != 0x90 && s->reg != 0x5a && s->reg != 0xb8) + s->reg += 2; + } else + s->reg = value & 0xff; +} + +void s1d13745_write_block(void *opaque, int dc, + void *buf, size_t len, int pitch) +{ + struct blizzard_s *s = (struct blizzard_s *) opaque; + + while (len > 0) { + if (s->reg == 0x90 && dc && + (s->data.len || blizzard_transfer_setup(s)) && + len >= (s->data.len << 1)) { + len -= s->data.len << 1; + s->data.len = 0; + s->data.data = buf; + if (pitch) + s->data.pitch = pitch; + blizzard_window(s); + s->data.data = s->data.buf; + continue; + } + + s1d13745_write(opaque, dc, *(uint16_t *) buf); + len -= 2; + buf += 2; + } + + return; +} + +static void blizzard_update_display(void *opaque) +{ + struct blizzard_s *s = (struct blizzard_s *) opaque; + int y, bypp, bypl, bwidth; + uint8_t *src, *dst; + + if (!s->enable) + return; + + if (s->x != s->state->width || s->y != s->state->height) { + s->invalidate = 1; + qemu_console_resize(s->console, s->x, s->y); + } + + if (s->invalidate) { + s->invalidate = 0; + + if (s->blank) { + bypp = (s->state->depth + 7) >> 3; + memset(s->state->data, 0, bypp * s->x * s->y); + return; + } + + s->mx[0] = 0; + s->mx[1] = s->x; + s->my[0] = 0; + s->my[1] = s->y; + } + + if (s->mx[1] <= s->mx[0]) + return; + + bypp = (s->state->depth + 7) >> 3; + bypl = bypp * s->x; + bwidth = bypp * (s->mx[1] - s->mx[0]); + y = s->my[0]; + src = s->fb + bypl * y + bypp * s->mx[0]; + dst = s->state->data + bypl * y + bypp * s->mx[0]; + for (; y < s->my[1]; y ++, src += bypl, dst += bypl) + memcpy(dst, src, bwidth); + + dpy_update(s->state, s->mx[0], s->my[0], + s->mx[1] - s->mx[0], y - s->my[0]); + + s->mx[0] = s->x; + s->mx[1] = 0; + s->my[0] = s->y; + s->my[1] = 0; +} + +static void blizzard_screen_dump(void *opaque, const char *filename) { + struct blizzard_s *s = (struct blizzard_s *) opaque; + + blizzard_update_display(opaque); + if (s && s->state->data) + ppm_save(filename, s->state->data, s->x, s->y, s->state->linesize); +} + +#define DEPTH 8 +#include "blizzard_template.h" +#define DEPTH 15 +#include "blizzard_template.h" +#define DEPTH 16 +#include "blizzard_template.h" +#define DEPTH 24 +#include "blizzard_template.h" +#define DEPTH 32 +#include "blizzard_template.h" + +void *s1d13745_init(qemu_irq gpio_int, DisplayState *ds) +{ + struct blizzard_s *s = (struct blizzard_s *) qemu_mallocz(sizeof(*s)); + + s->state = ds; + s->fb = qemu_malloc(0x180000); + + switch (s->state->depth) { + case 0: + s->line_fn_tab[0] = s->line_fn_tab[1] = + qemu_mallocz(sizeof(blizzard_fn_t) * 0x10); + break; + case 8: + s->line_fn_tab[0] = blizzard_draw_fn_8; + s->line_fn_tab[1] = blizzard_draw_fn_r_8; + break; + case 15: + s->line_fn_tab[0] = blizzard_draw_fn_15; + s->line_fn_tab[1] = blizzard_draw_fn_r_15; + break; + case 16: + s->line_fn_tab[0] = blizzard_draw_fn_16; + s->line_fn_tab[1] = blizzard_draw_fn_r_16; + break; + case 24: + s->line_fn_tab[0] = blizzard_draw_fn_24; + s->line_fn_tab[1] = blizzard_draw_fn_r_24; + break; + case 32: + s->line_fn_tab[0] = blizzard_draw_fn_32; + s->line_fn_tab[1] = blizzard_draw_fn_r_32; + break; + default: + fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__); + exit(1); + } + + blizzard_reset(s); + + s->console = graphic_console_init(s->state, blizzard_update_display, + blizzard_invalidate_display, + blizzard_screen_dump, NULL, s); + + return s; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/blizzard_template.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/blizzard_template.h --- qemu-0.9.1/hw/blizzard_template.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/blizzard_template.h 2008-04-22 03:52:38.000000000 +0100 @@ -0,0 +1,138 @@ +/* + * QEMU Epson S1D13744/S1D13745 templates + * + * Copyright (C) 2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#define SKIP_PIXEL(to) to += deststep +#if DEPTH == 8 +# define PIXEL_TYPE uint8_t +# define COPY_PIXEL(to, from) *to = from; SKIP_PIXEL(to) +# define COPY_PIXEL1(to, from) *to ++ = from +#elif DEPTH == 15 || DEPTH == 16 +# define PIXEL_TYPE uint16_t +# define COPY_PIXEL(to, from) *to = from; SKIP_PIXEL(to) +# define COPY_PIXEL1(to, from) *to ++ = from +#elif DEPTH == 24 +# define PIXEL_TYPE uint8_t +# define COPY_PIXEL(to, from) \ + to[0] = from; to[1] = (from) >> 8; to[2] = (from) >> 16; SKIP_PIXEL(to) +# define COPY_PIXEL1(to, from) \ + *to ++ = from; *to ++ = (from) >> 8; *to ++ = (from) >> 16 +#elif DEPTH == 32 +# define PIXEL_TYPE uint32_t +# define COPY_PIXEL(to, from) *to = from; SKIP_PIXEL(to) +# define COPY_PIXEL1(to, from) *to ++ = from +#else +# error unknown bit depth +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP_WORDS 1 +#endif + +static void glue(blizzard_draw_line16_, DEPTH)(PIXEL_TYPE *dest, + const uint16_t *src, unsigned int width) +{ +#if !defined(SWAP_WORDS) && DEPTH == 16 + memcpy(dest, src, width); +#else + uint16_t data; + unsigned int r, g, b; + const uint16_t *end = (const void *) src + width; + while (src < end) { + data = lduw_raw(src ++); + b = (data & 0x1f) << 3; + data >>= 5; + g = (data & 0x3f) << 2; + data >>= 6; + r = (data & 0x1f) << 3; + data >>= 5; + COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b)); + } +#endif +} + +static void glue(blizzard_draw_line24mode1_, DEPTH)(PIXEL_TYPE *dest, + const uint8_t *src, unsigned int width) +{ + /* TODO: check if SDL 24-bit planes are not in the same format and + * if so, use memcpy */ + unsigned int r[2], g[2], b[2]; + const uint8_t *end = src + width; + while (src < end) { + g[0] = *src ++; + r[0] = *src ++; + r[1] = *src ++; + b[0] = *src ++; + COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r[0], g[0], b[0])); + b[1] = *src ++; + g[1] = *src ++; + COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r[1], g[1], b[1])); + } +} + +static void glue(blizzard_draw_line24mode2_, DEPTH)(PIXEL_TYPE *dest, + const uint8_t *src, unsigned int width) +{ + unsigned int r, g, b; + const uint8_t *end = src + width; + while (src < end) { + r = *src ++; + src ++; + b = *src ++; + g = *src ++; + COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b)); + } +} + +/* No rotation */ +static blizzard_fn_t glue(blizzard_draw_fn_, DEPTH)[0x10] = { + NULL, + /* RGB 5:6:5*/ + (blizzard_fn_t) glue(blizzard_draw_line16_, DEPTH), + /* RGB 6:6:6 mode 1 */ + (blizzard_fn_t) glue(blizzard_draw_line24mode1_, DEPTH), + /* RGB 8:8:8 mode 1 */ + (blizzard_fn_t) glue(blizzard_draw_line24mode1_, DEPTH), + NULL, NULL, + /* RGB 6:6:6 mode 2 */ + (blizzard_fn_t) glue(blizzard_draw_line24mode2_, DEPTH), + /* RGB 8:8:8 mode 2 */ + (blizzard_fn_t) glue(blizzard_draw_line24mode2_, DEPTH), + /* YUV 4:2:2 */ + NULL, + /* YUV 4:2:0 */ + NULL, + NULL, NULL, NULL, NULL, NULL, NULL, +}; + +/* 90deg, 180deg and 270deg rotation */ +static blizzard_fn_t glue(blizzard_draw_fn_r_, DEPTH)[0x10] = { + /* TODO */ + [0 ... 0xf] = NULL, +}; + +#undef DEPTH +#undef SKIP_PIXEL +#undef COPY_PIXEL +#undef COPY_PIXEL1 +#undef PIXEL_TYPE + +#undef SWAP_WORDS diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/boards.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/boards.h --- qemu-0.9.1/hw/boards.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/boards.h 2008-10-07 21:39:39.000000000 +0100 @@ -3,7 +3,7 @@ #ifndef HW_BOARDS_H #define HW_BOARDS_H -typedef void QEMUMachineInitFunc(int ram_size, int vga_ram_size, +typedef void QEMUMachineInitFunc(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, @@ -14,10 +14,16 @@ const char *name; const char *desc; QEMUMachineInitFunc *init; +#define RAMSIZE_FIXED (1 << 0) + ram_addr_t ram_require; + int nodisk_ok; + int use_scsi; + int max_cpus; struct QEMUMachine *next; } QEMUMachine; int qemu_register_machine(QEMUMachine *m); +void register_machines(void); /* Axis ETRAX. */ extern QEMUMachine bareetraxfs_machine; @@ -36,12 +42,13 @@ /* mips_r4k.c */ extern QEMUMachine mips_machine; +/* mips_jazz.c */ +extern QEMUMachine mips_magnum_machine; +extern QEMUMachine mips_pica61_machine; + /* mips_malta.c */ extern QEMUMachine mips_malta_machine; -/* mips_pica61.c */ -extern QEMUMachine mips_pica61_machine; - /* mips_mipssim.c */ extern QEMUMachine mips_mipssim_machine; @@ -53,11 +60,15 @@ /* sun4m.c */ extern QEMUMachine ss5_machine, ss10_machine, ss600mp_machine, ss20_machine; +extern QEMUMachine voyager_machine, ss_lx_machine, ss4_machine, scls_machine; +extern QEMUMachine sbook_machine; extern QEMUMachine ss2_machine; extern QEMUMachine ss1000_machine, ss2000_machine; /* sun4u.c */ extern QEMUMachine sun4u_machine; +extern QEMUMachine sun4v_machine; +extern QEMUMachine niagara_machine; /* integratorcp.c */ extern QEMUMachine integratorcp_machine; @@ -78,6 +89,10 @@ /* palm.c */ extern QEMUMachine palmte_machine; +/* nseries.c */ +extern QEMUMachine n800_machine; +extern QEMUMachine n810_machine; + /* gumstix.c */ extern QEMUMachine connex_machine; extern QEMUMachine verdex_machine; @@ -98,4 +113,10 @@ /* mainstone.c */ extern QEMUMachine mainstone2_machine; +/* musicpal.c */ +extern QEMUMachine musicpal_machine; + +/* tosa.c */ +extern QEMUMachine tosapda_machine; + #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/bt.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/bt.c --- qemu-0.9.1/hw/bt.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/bt.c 2008-09-29 00:19:47.000000000 +0100 @@ -0,0 +1,123 @@ +/* + * Convenience functions for bluetooth. + * + * Copyright (C) 2008 Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "qemu-common.h" +#include "net.h" +#include "bt.h" + +/* Slave implementations can ignore this */ +static void bt_dummy_lmp_mode_change(struct bt_link_s *link) +{ +} + +/* Slaves should never receive these PDUs */ +static void bt_dummy_lmp_connection_complete(struct bt_link_s *link) +{ + if (link->slave->reject_reason) + fprintf(stderr, "%s: stray LMP_not_accepted received, fixme\n", + __FUNCTION__); + else + fprintf(stderr, "%s: stray LMP_accepted received, fixme\n", + __FUNCTION__); + exit(-1); +} + +static void bt_dummy_lmp_disconnect_master(struct bt_link_s *link) +{ + fprintf(stderr, "%s: stray LMP_detach received, fixme\n", __FUNCTION__); + exit(-1); +} + +static void bt_dummy_lmp_acl_resp(struct bt_link_s *link, + const uint8_t *data, int start, int len) +{ + fprintf(stderr, "%s: stray ACL response PDU, fixme\n", __FUNCTION__); + exit(-1); +} + +/* Slaves that don't hold any additional per link state can use these */ +static void bt_dummy_lmp_connection_request(struct bt_link_s *req) +{ + struct bt_link_s *link = qemu_mallocz(sizeof(struct bt_link_s)); + + link->slave = req->slave; + link->host = req->host; + + req->host->reject_reason = 0; + req->host->lmp_connection_complete(link); +} + +static void bt_dummy_lmp_disconnect_slave(struct bt_link_s *link) +{ + qemu_free(link); +} + +static void bt_dummy_destroy(struct bt_device_s *device) +{ + bt_device_done(device); + qemu_free(device); +} + +static int bt_dev_idx = 0; + +void bt_device_init(struct bt_device_s *dev, struct bt_scatternet_s *net) +{ + memset(dev, 0, sizeof(*dev)); + dev->inquiry_scan = 1; + dev->page_scan = 1; + + dev->bd_addr.b[0] = bt_dev_idx & 0xff; + dev->bd_addr.b[1] = bt_dev_idx >> 8; + dev->bd_addr.b[2] = 0xd0; + dev->bd_addr.b[3] = 0xba; + dev->bd_addr.b[4] = 0xbe; + dev->bd_addr.b[5] = 0xba; + bt_dev_idx ++; + + /* Simple slave-only devices need to implement only .lmp_acl_data */ + dev->lmp_connection_complete = bt_dummy_lmp_connection_complete; + dev->lmp_disconnect_master = bt_dummy_lmp_disconnect_master; + dev->lmp_acl_resp = bt_dummy_lmp_acl_resp; + dev->lmp_mode_change = bt_dummy_lmp_mode_change; + dev->lmp_connection_request = bt_dummy_lmp_connection_request; + dev->lmp_disconnect_slave = bt_dummy_lmp_disconnect_slave; + + dev->handle_destroy = bt_dummy_destroy; + + dev->net = net; + dev->next = net->slave; + net->slave = dev; +} + +void bt_device_done(struct bt_device_s *dev) +{ + struct bt_device_s **p = &dev->net->slave; + + while (*p && *p != dev) + p = &(*p)->next; + if (*p != dev) { + fprintf(stderr, "%s: bad bt device \"%s\"\n", __FUNCTION__, + dev->lmp_name ?: "(null)"); + exit(-1); + } + + *p = dev->next; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/bt.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/bt.h --- qemu-0.9.1/hw/bt.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/bt.h 2008-09-29 01:31:41.000000000 +0100 @@ -0,0 +1,2188 @@ +/* + * QEMU Bluetooth HCI helpers. + * + * Copyright (C) 2007 OpenMoko, Inc. + * Written by Andrzej Zaborowski + * + * Useful definitions taken from BlueZ project's headers. + * Copyright (C) 2000-2001 Qualcomm Incorporated + * Copyright (C) 2002-2003 Maxim Krasnyansky + * Copyright (C) 2002-2006 Marcel Holtmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +/* BD Address */ +typedef struct { + uint8_t b[6]; +} __attribute__((packed)) bdaddr_t; + +#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}}) +#define BDADDR_ALL (&(bdaddr_t) {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}) +#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}}) + +/* Copy, swap, convert BD Address */ +static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2) +{ + return memcmp(ba1, ba2, sizeof(bdaddr_t)); +} +static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src) +{ + memcpy(dst, src, sizeof(bdaddr_t)); +} + +#define BAINIT(orig) { .b = { \ + (orig)->b[0], (orig)->b[1], (orig)->b[2], \ + (orig)->b[3], (orig)->b[4], (orig)->b[5], \ +}, } + +/* The twisted structures of a bluetooth environment */ +struct bt_device_s; +struct bt_scatternet_s; +struct bt_piconet_s; +struct bt_link_s; + +struct bt_scatternet_s { + struct bt_device_s *slave; +}; + +struct bt_link_s { + struct bt_device_s *slave, *host; + uint16_t handle; /* Master (host) side handle */ + uint16_t acl_interval; + enum { + acl_active, + acl_hold, + acl_sniff, + acl_parked, + } acl_mode; +}; + +struct bt_device_s { + int lt_addr; + bdaddr_t bd_addr; + int mtu; + int setup; + struct bt_scatternet_s *net; + + uint8_t key[16]; + int key_present; + uint8_t class[3]; + + uint8_t reject_reason; + + uint64_t lmp_caps; + const char *lmp_name; + void (*lmp_connection_request)(struct bt_link_s *link); + void (*lmp_connection_complete)(struct bt_link_s *link); + void (*lmp_disconnect_master)(struct bt_link_s *link); + void (*lmp_disconnect_slave)(struct bt_link_s *link); + void (*lmp_acl_data)(struct bt_link_s *link, const uint8_t *data, + int start, int len); + void (*lmp_acl_resp)(struct bt_link_s *link, const uint8_t *data, + int start, int len); + void (*lmp_mode_change)(struct bt_link_s *link); + + void (*handle_destroy)(struct bt_device_s *device); + struct bt_device_s *next; /* Next in the piconet/scatternet */ + + int inquiry_scan; + int page_scan; + + uint16_t clkoff; /* Note: Always little-endian */ +}; + +/* bt.c */ +void bt_device_init(struct bt_device_s *dev, struct bt_scatternet_s *net); +void bt_device_done(struct bt_device_s *dev); + +/* bt-hci.c */ +struct HCIInfo *bt_new_hci(struct bt_scatternet_s *net); + +/* bt-host.c */ +struct HCIInfo *bt_host_hci(const char *id); + +/* bt-vhci.c */ +void bt_vhci_init(struct HCIInfo *info); + +/* bt-hci-csr.c */ +enum { + csrhci_pin_reset, + csrhci_pin_wakeup, + __csrhci_pins, +}; +qemu_irq *csrhci_pins_get(CharDriverState *chr); +CharDriverState *uart_hci_init(qemu_irq wakeup); + +/* bt-l2cap.c */ +struct bt_l2cap_device_s; +struct bt_l2cap_conn_params_s; +struct bt_l2cap_psm_s; +void bt_l2cap_device_init(struct bt_l2cap_device_s *dev, + struct bt_scatternet_s *net); +void bt_l2cap_device_done(struct bt_l2cap_device_s *dev); +void bt_l2cap_psm_register(struct bt_l2cap_device_s *dev, int psm, + int min_mtu, int (*new_channel)(struct bt_l2cap_device_s *dev, + struct bt_l2cap_conn_params_s *params)); + +struct bt_l2cap_device_s { + struct bt_device_s device; + struct bt_l2cap_psm_s *first_psm; +}; + +struct bt_l2cap_conn_params_s { + /* Input */ + uint8_t *(*sdu_out)(struct bt_l2cap_conn_params_s *chan, int len); + void (*sdu_submit)(struct bt_l2cap_conn_params_s *chan); + int remote_mtu; + /* Output */ + void *opaque; + void (*sdu_in)(void *opaque, const uint8_t *data, int len); + void (*close)(void *opaque); +}; + +enum bt_l2cap_psm_predef { + BT_PSM_SDP = 0x0001, + BT_PSM_RFCOMM = 0x0003, + BT_PSM_TELEPHONY = 0x0005, + BT_PSM_TCS = 0x0007, + BT_PSM_BNEP = 0x000f, + BT_PSM_HID_CTRL = 0x0011, + BT_PSM_HID_INTR = 0x0013, + BT_PSM_UPNP = 0x0015, + BT_PSM_AVCTP = 0x0017, + BT_PSM_AVDTP = 0x0019, +}; + +/* bt-sdp.c */ +void bt_l2cap_sdp_init(struct bt_l2cap_device_s *dev); + +/* bt-hid.c */ +struct bt_device_s *bt_mouse_init(struct bt_scatternet_s *net); +struct bt_device_s *bt_tablet_init(struct bt_scatternet_s *net); +struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net); + +/* Link Management Protocol layer defines */ + +#define LLID_ACLU_CONT 0x1 +#define LLID_ACLU_START 0x2 +#define LLID_ACLC 0x3 + +enum lmp_pdu_type { + LMP_NAME_REQ = 0x0001, + LMP_NAME_RES = 0x0002, + LMP_ACCEPTED = 0x0003, + LMP_NOT_ACCEPTED = 0x0004, + LMP_CLKOFFSET_REQ = 0x0005, + LMP_CLKOFFSET_RES = 0x0006, + LMP_DETACH = 0x0007, + LMP_IN_RAND = 0x0008, + LMP_COMB_KEY = 0x0009, + LMP_UNIT_KEY = 0x000a, + LMP_AU_RAND = 0x000b, + LMP_SRES = 0x000c, + LMP_TEMP_RAND = 0x000d, + LMP_TEMP_KEY = 0x000e, + LMP_CRYPT_MODE_REQ = 0x000f, + LMP_CRYPT_KEY_SIZE_REQ = 0x0010, + LMP_START_ENCRYPT_REQ = 0x0011, + LMP_STOP_ENCRYPT_REQ = 0x0012, + LMP_SWITCH_REQ = 0x0013, + LMP_HOLD = 0x0014, + LMP_HOLD_REQ = 0x0015, + LMP_SNIFF_REQ = 0x0017, + LMP_UNSNIFF_REQ = 0x0018, + LMP_LMP_PARK_REQ = 0x0019, + LMP_SET_BCAST_SCAN_WND = 0x001b, + LMP_MODIFY_BEACON = 0x001c, + LMP_UNPARK_BD_ADDR_REQ = 0x001d, + LMP_UNPARK_PM_ADDR_REQ = 0x001e, + LMP_INCR_POWER_REQ = 0x001f, + LMP_DECR_POWER_REQ = 0x0020, + LMP_MAX_POWER = 0x0021, + LMP_MIN_POWER = 0x0022, + LMP_AUTO_RATE = 0x0023, + LMP_PREFERRED_RATE = 0x0024, + LMP_VERSION_REQ = 0x0025, + LMP_VERSION_RES = 0x0026, + LMP_FEATURES_REQ = 0x0027, + LMP_FEATURES_RES = 0x0028, + LMP_QUALITY_OF_SERVICE = 0x0029, + LMP_QOS_REQ = 0x002a, + LMP_RM_SCO_LINK_REQ = 0x002b, + LMP_SCO_LINK_REQ = 0x002c, + LMP_MAX_SLOT = 0x002d, + LMP_MAX_SLOT_REQ = 0x002e, + LMP_TIMING_ACCURACY_REQ = 0x002f, + LMP_TIMING_ACCURACY_RES = 0x0030, + LMP_SETUP_COMPLETE = 0x0031, + LMP_USE_SEMIPERM_KEY = 0x0032, + LMP_HOST_CONNECTION_REQ = 0x0033, + LMP_SLOT_OFFSET = 0x0034, + LMP_PAGE_MODE_REQ = 0x0035, + LMP_PAGE_SCAN_MODE_REQ = 0x0036, + LMP_SUPERVISION_TIMEOUT = 0x0037, + LMP_TEST_ACTIVATE = 0x0038, + LMP_TEST_CONTROL = 0x0039, + LMP_CRYPT_KEY_MASK_REQ = 0x003a, + LMP_CRYPT_KEY_MASK_RES = 0x003b, + LMP_SET_AFH = 0x003c, + LMP_ACCEPTED_EXT = 0x7f01, + LMP_NOT_ACCEPTED_EXT = 0x7f02, + LMP_FEATURES_REQ_EXT = 0x7f03, + LMP_FEATURES_RES_EXT = 0x7f04, + LMP_PACKET_TYPE_TBL_REQ = 0x7f0b, + LMP_ESCO_LINK_REQ = 0x7f0c, + LMP_RM_ESCO_LINK_REQ = 0x7f0d, + LMP_CHANNEL_CLASS_REQ = 0x7f10, + LMP_CHANNEL_CLASS = 0x7f11, +}; + +/* Host Controller Interface layer defines */ + +enum hci_packet_type { + HCI_COMMAND_PKT = 0x01, + HCI_ACLDATA_PKT = 0x02, + HCI_SCODATA_PKT = 0x03, + HCI_EVENT_PKT = 0x04, + HCI_VENDOR_PKT = 0xff, +}; + +enum bt_packet_type { + HCI_2DH1 = 1 << 1, + HCI_3DH1 = 1 << 2, + HCI_DM1 = 1 << 3, + HCI_DH1 = 1 << 4, + HCI_2DH3 = 1 << 8, + HCI_3DH3 = 1 << 9, + HCI_DM3 = 1 << 10, + HCI_DH3 = 1 << 11, + HCI_2DH5 = 1 << 12, + HCI_3DH5 = 1 << 13, + HCI_DM5 = 1 << 14, + HCI_DH5 = 1 << 15, +}; + +enum sco_packet_type { + HCI_HV1 = 1 << 5, + HCI_HV2 = 1 << 6, + HCI_HV3 = 1 << 7, +}; + +enum ev_packet_type { + HCI_EV3 = 1 << 3, + HCI_EV4 = 1 << 4, + HCI_EV5 = 1 << 5, + HCI_2EV3 = 1 << 6, + HCI_3EV3 = 1 << 7, + HCI_2EV5 = 1 << 8, + HCI_3EV5 = 1 << 9, +}; + +enum hci_error_code { + HCI_SUCCESS = 0x00, + HCI_UNKNOWN_COMMAND = 0x01, + HCI_NO_CONNECTION = 0x02, + HCI_HARDWARE_FAILURE = 0x03, + HCI_PAGE_TIMEOUT = 0x04, + HCI_AUTHENTICATION_FAILURE = 0x05, + HCI_PIN_OR_KEY_MISSING = 0x06, + HCI_MEMORY_FULL = 0x07, + HCI_CONNECTION_TIMEOUT = 0x08, + HCI_MAX_NUMBER_OF_CONNECTIONS = 0x09, + HCI_MAX_NUMBER_OF_SCO_CONNECTIONS = 0x0a, + HCI_ACL_CONNECTION_EXISTS = 0x0b, + HCI_COMMAND_DISALLOWED = 0x0c, + HCI_REJECTED_LIMITED_RESOURCES = 0x0d, + HCI_REJECTED_SECURITY = 0x0e, + HCI_REJECTED_PERSONAL = 0x0f, + HCI_HOST_TIMEOUT = 0x10, + HCI_UNSUPPORTED_FEATURE = 0x11, + HCI_INVALID_PARAMETERS = 0x12, + HCI_OE_USER_ENDED_CONNECTION = 0x13, + HCI_OE_LOW_RESOURCES = 0x14, + HCI_OE_POWER_OFF = 0x15, + HCI_CONNECTION_TERMINATED = 0x16, + HCI_REPEATED_ATTEMPTS = 0x17, + HCI_PAIRING_NOT_ALLOWED = 0x18, + HCI_UNKNOWN_LMP_PDU = 0x19, + HCI_UNSUPPORTED_REMOTE_FEATURE = 0x1a, + HCI_SCO_OFFSET_REJECTED = 0x1b, + HCI_SCO_INTERVAL_REJECTED = 0x1c, + HCI_AIR_MODE_REJECTED = 0x1d, + HCI_INVALID_LMP_PARAMETERS = 0x1e, + HCI_UNSPECIFIED_ERROR = 0x1f, + HCI_UNSUPPORTED_LMP_PARAMETER_VALUE = 0x20, + HCI_ROLE_CHANGE_NOT_ALLOWED = 0x21, + HCI_LMP_RESPONSE_TIMEOUT = 0x22, + HCI_LMP_ERROR_TRANSACTION_COLLISION = 0x23, + HCI_LMP_PDU_NOT_ALLOWED = 0x24, + HCI_ENCRYPTION_MODE_NOT_ACCEPTED = 0x25, + HCI_UNIT_LINK_KEY_USED = 0x26, + HCI_QOS_NOT_SUPPORTED = 0x27, + HCI_INSTANT_PASSED = 0x28, + HCI_PAIRING_NOT_SUPPORTED = 0x29, + HCI_TRANSACTION_COLLISION = 0x2a, + HCI_QOS_UNACCEPTABLE_PARAMETER = 0x2c, + HCI_QOS_REJECTED = 0x2d, + HCI_CLASSIFICATION_NOT_SUPPORTED = 0x2e, + HCI_INSUFFICIENT_SECURITY = 0x2f, + HCI_PARAMETER_OUT_OF_RANGE = 0x30, + HCI_ROLE_SWITCH_PENDING = 0x32, + HCI_SLOT_VIOLATION = 0x34, + HCI_ROLE_SWITCH_FAILED = 0x35, +}; + +enum acl_flag_bits { + ACL_CONT = 1 << 0, + ACL_START = 1 << 1, + ACL_ACTIVE_BCAST = 1 << 2, + ACL_PICO_BCAST = 1 << 3, +}; + +enum baseband_link_type { + SCO_LINK = 0x00, + ACL_LINK = 0x01, +}; + +enum lmp_feature_bits0 { + LMP_3SLOT = 1 << 0, + LMP_5SLOT = 1 << 1, + LMP_ENCRYPT = 1 << 2, + LMP_SOFFSET = 1 << 3, + LMP_TACCURACY = 1 << 4, + LMP_RSWITCH = 1 << 5, + LMP_HOLD_MODE = 1 << 6, + LMP_SNIFF_MODE = 1 << 7, +}; + +enum lmp_feature_bits1 { + LMP_PARK = 1 << 0, + LMP_RSSI = 1 << 1, + LMP_QUALITY = 1 << 2, + LMP_SCO = 1 << 3, + LMP_HV2 = 1 << 4, + LMP_HV3 = 1 << 5, + LMP_ULAW = 1 << 6, + LMP_ALAW = 1 << 7, +}; + +enum lmp_feature_bits2 { + LMP_CVSD = 1 << 0, + LMP_PSCHEME = 1 << 1, + LMP_PCONTROL = 1 << 2, + LMP_TRSP_SCO = 1 << 3, + LMP_BCAST_ENC = 1 << 7, +}; + +enum lmp_feature_bits3 { + LMP_EDR_ACL_2M = 1 << 1, + LMP_EDR_ACL_3M = 1 << 2, + LMP_ENH_ISCAN = 1 << 3, + LMP_ILACE_ISCAN = 1 << 4, + LMP_ILACE_PSCAN = 1 << 5, + LMP_RSSI_INQ = 1 << 6, + LMP_ESCO = 1 << 7, +}; + +enum lmp_feature_bits4 { + LMP_EV4 = 1 << 0, + LMP_EV5 = 1 << 1, + LMP_AFH_CAP_SLV = 1 << 3, + LMP_AFH_CLS_SLV = 1 << 4, + LMP_EDR_3SLOT = 1 << 7, +}; + +enum lmp_feature_bits5 { + LMP_EDR_5SLOT = 1 << 0, + LMP_SNIFF_SUBR = 1 << 1, + LMP_AFH_CAP_MST = 1 << 3, + LMP_AFH_CLS_MST = 1 << 4, + LMP_EDR_ESCO_2M = 1 << 5, + LMP_EDR_ESCO_3M = 1 << 6, + LMP_EDR_3S_ESCO = 1 << 7, +}; + +enum lmp_feature_bits6 { + LMP_EXT_INQ = 1 << 0, +}; + +enum lmp_feature_bits7 { + LMP_EXT_FEAT = 1 << 7, +}; + +enum hci_link_policy { + HCI_LP_RSWITCH = 1 << 0, + HCI_LP_HOLD = 1 << 1, + HCI_LP_SNIFF = 1 << 2, + HCI_LP_PARK = 1 << 3, +}; + +enum hci_link_mode { + HCI_LM_ACCEPT = 1 << 15, + HCI_LM_MASTER = 1 << 0, + HCI_LM_AUTH = 1 << 1, + HCI_LM_ENCRYPT = 1 << 2, + HCI_LM_TRUSTED = 1 << 3, + HCI_LM_RELIABLE = 1 << 4, + HCI_LM_SECURE = 1 << 5, +}; + +/* HCI Commands */ + +/* Link Control */ +#define OGF_LINK_CTL 0x01 + +#define OCF_INQUIRY 0x0001 +typedef struct { + uint8_t lap[3]; + uint8_t length; /* 1.28s units */ + uint8_t num_rsp; +} __attribute__ ((packed)) inquiry_cp; +#define INQUIRY_CP_SIZE 5 + +typedef struct { + uint8_t status; + bdaddr_t bdaddr; +} __attribute__ ((packed)) status_bdaddr_rp; +#define STATUS_BDADDR_RP_SIZE 7 + +#define OCF_INQUIRY_CANCEL 0x0002 + +#define OCF_PERIODIC_INQUIRY 0x0003 +typedef struct { + uint16_t max_period; /* 1.28s units */ + uint16_t min_period; /* 1.28s units */ + uint8_t lap[3]; + uint8_t length; /* 1.28s units */ + uint8_t num_rsp; +} __attribute__ ((packed)) periodic_inquiry_cp; +#define PERIODIC_INQUIRY_CP_SIZE 9 + +#define OCF_EXIT_PERIODIC_INQUIRY 0x0004 + +#define OCF_CREATE_CONN 0x0005 +typedef struct { + bdaddr_t bdaddr; + uint16_t pkt_type; + uint8_t pscan_rep_mode; + uint8_t pscan_mode; + uint16_t clock_offset; + uint8_t role_switch; +} __attribute__ ((packed)) create_conn_cp; +#define CREATE_CONN_CP_SIZE 13 + +#define OCF_DISCONNECT 0x0006 +typedef struct { + uint16_t handle; + uint8_t reason; +} __attribute__ ((packed)) disconnect_cp; +#define DISCONNECT_CP_SIZE 3 + +#define OCF_ADD_SCO 0x0007 +typedef struct { + uint16_t handle; + uint16_t pkt_type; +} __attribute__ ((packed)) add_sco_cp; +#define ADD_SCO_CP_SIZE 4 + +#define OCF_CREATE_CONN_CANCEL 0x0008 +typedef struct { + uint8_t status; + bdaddr_t bdaddr; +} __attribute__ ((packed)) create_conn_cancel_cp; +#define CREATE_CONN_CANCEL_CP_SIZE 6 + +typedef struct { + uint8_t status; + bdaddr_t bdaddr; +} __attribute__ ((packed)) create_conn_cancel_rp; +#define CREATE_CONN_CANCEL_RP_SIZE 7 + +#define OCF_ACCEPT_CONN_REQ 0x0009 +typedef struct { + bdaddr_t bdaddr; + uint8_t role; +} __attribute__ ((packed)) accept_conn_req_cp; +#define ACCEPT_CONN_REQ_CP_SIZE 7 + +#define OCF_REJECT_CONN_REQ 0x000A +typedef struct { + bdaddr_t bdaddr; + uint8_t reason; +} __attribute__ ((packed)) reject_conn_req_cp; +#define REJECT_CONN_REQ_CP_SIZE 7 + +#define OCF_LINK_KEY_REPLY 0x000B +typedef struct { + bdaddr_t bdaddr; + uint8_t link_key[16]; +} __attribute__ ((packed)) link_key_reply_cp; +#define LINK_KEY_REPLY_CP_SIZE 22 + +#define OCF_LINK_KEY_NEG_REPLY 0x000C + +#define OCF_PIN_CODE_REPLY 0x000D +typedef struct { + bdaddr_t bdaddr; + uint8_t pin_len; + uint8_t pin_code[16]; +} __attribute__ ((packed)) pin_code_reply_cp; +#define PIN_CODE_REPLY_CP_SIZE 23 + +#define OCF_PIN_CODE_NEG_REPLY 0x000E + +#define OCF_SET_CONN_PTYPE 0x000F +typedef struct { + uint16_t handle; + uint16_t pkt_type; +} __attribute__ ((packed)) set_conn_ptype_cp; +#define SET_CONN_PTYPE_CP_SIZE 4 + +#define OCF_AUTH_REQUESTED 0x0011 +typedef struct { + uint16_t handle; +} __attribute__ ((packed)) auth_requested_cp; +#define AUTH_REQUESTED_CP_SIZE 2 + +#define OCF_SET_CONN_ENCRYPT 0x0013 +typedef struct { + uint16_t handle; + uint8_t encrypt; +} __attribute__ ((packed)) set_conn_encrypt_cp; +#define SET_CONN_ENCRYPT_CP_SIZE 3 + +#define OCF_CHANGE_CONN_LINK_KEY 0x0015 +typedef struct { + uint16_t handle; +} __attribute__ ((packed)) change_conn_link_key_cp; +#define CHANGE_CONN_LINK_KEY_CP_SIZE 2 + +#define OCF_MASTER_LINK_KEY 0x0017 +typedef struct { + uint8_t key_flag; +} __attribute__ ((packed)) master_link_key_cp; +#define MASTER_LINK_KEY_CP_SIZE 1 + +#define OCF_REMOTE_NAME_REQ 0x0019 +typedef struct { + bdaddr_t bdaddr; + uint8_t pscan_rep_mode; + uint8_t pscan_mode; + uint16_t clock_offset; +} __attribute__ ((packed)) remote_name_req_cp; +#define REMOTE_NAME_REQ_CP_SIZE 10 + +#define OCF_REMOTE_NAME_REQ_CANCEL 0x001A +typedef struct { + bdaddr_t bdaddr; +} __attribute__ ((packed)) remote_name_req_cancel_cp; +#define REMOTE_NAME_REQ_CANCEL_CP_SIZE 6 + +typedef struct { + uint8_t status; + bdaddr_t bdaddr; +} __attribute__ ((packed)) remote_name_req_cancel_rp; +#define REMOTE_NAME_REQ_CANCEL_RP_SIZE 7 + +#define OCF_READ_REMOTE_FEATURES 0x001B +typedef struct { + uint16_t handle; +} __attribute__ ((packed)) read_remote_features_cp; +#define READ_REMOTE_FEATURES_CP_SIZE 2 + +#define OCF_READ_REMOTE_EXT_FEATURES 0x001C +typedef struct { + uint16_t handle; + uint8_t page_num; +} __attribute__ ((packed)) read_remote_ext_features_cp; +#define READ_REMOTE_EXT_FEATURES_CP_SIZE 3 + +#define OCF_READ_REMOTE_VERSION 0x001D +typedef struct { + uint16_t handle; +} __attribute__ ((packed)) read_remote_version_cp; +#define READ_REMOTE_VERSION_CP_SIZE 2 + +#define OCF_READ_CLOCK_OFFSET 0x001F +typedef struct { + uint16_t handle; +} __attribute__ ((packed)) read_clock_offset_cp; +#define READ_CLOCK_OFFSET_CP_SIZE 2 + +#define OCF_READ_LMP_HANDLE 0x0020 +typedef struct { + uint16_t handle; +} __attribute__ ((packed)) read_lmp_handle_cp; +#define READ_LMP_HANDLE_CP_SIZE 2 + +typedef struct { + uint8_t status; + uint16_t handle; + uint8_t lmp_handle; + uint32_t reserved; +} __attribute__ ((packed)) read_lmp_handle_rp; +#define READ_LMP_HANDLE_RP_SIZE 8 + +#define OCF_SETUP_SYNC_CONN 0x0028 +typedef struct { + uint16_t handle; + uint32_t tx_bandwith; + uint32_t rx_bandwith; + uint16_t max_latency; + uint16_t voice_setting; + uint8_t retrans_effort; + uint16_t pkt_type; +} __attribute__ ((packed)) setup_sync_conn_cp; +#define SETUP_SYNC_CONN_CP_SIZE 17 + +#define OCF_ACCEPT_SYNC_CONN_REQ 0x0029 +typedef struct { + bdaddr_t bdaddr; + uint32_t tx_bandwith; + uint32_t rx_bandwith; + uint16_t max_latency; + uint16_t voice_setting; + uint8_t retrans_effort; + uint16_t pkt_type; +} __attribute__ ((packed)) accept_sync_conn_req_cp; +#define ACCEPT_SYNC_CONN_REQ_CP_SIZE 21 + +#define OCF_REJECT_SYNC_CONN_REQ 0x002A +typedef struct { + bdaddr_t bdaddr; + uint8_t reason; +} __attribute__ ((packed)) reject_sync_conn_req_cp; +#define REJECT_SYNC_CONN_REQ_CP_SIZE 7 + +/* Link Policy */ +#define OGF_LINK_POLICY 0x02 + +#define OCF_HOLD_MODE 0x0001 +typedef struct { + uint16_t handle; + uint16_t max_interval; + uint16_t min_interval; +} __attribute__ ((packed)) hold_mode_cp; +#define HOLD_MODE_CP_SIZE 6 + +#define OCF_SNIFF_MODE 0x0003 +typedef struct { + uint16_t handle; + uint16_t max_interval; + uint16_t min_interval; + uint16_t attempt; + uint16_t timeout; +} __attribute__ ((packed)) sniff_mode_cp; +#define SNIFF_MODE_CP_SIZE 10 + +#define OCF_EXIT_SNIFF_MODE 0x0004 +typedef struct { + uint16_t handle; +} __attribute__ ((packed)) exit_sniff_mode_cp; +#define EXIT_SNIFF_MODE_CP_SIZE 2 + +#define OCF_PARK_MODE 0x0005 +typedef struct { + uint16_t handle; + uint16_t max_interval; + uint16_t min_interval; +} __attribute__ ((packed)) park_mode_cp; +#define PARK_MODE_CP_SIZE 6 + +#define OCF_EXIT_PARK_MODE 0x0006 +typedef struct { + uint16_t handle; +} __attribute__ ((packed)) exit_park_mode_cp; +#define EXIT_PARK_MODE_CP_SIZE 2 + +#define OCF_QOS_SETUP 0x0007 +typedef struct { + uint8_t service_type; /* 1 = best effort */ + uint32_t token_rate; /* Byte per seconds */ + uint32_t peak_bandwidth; /* Byte per seconds */ + uint32_t latency; /* Microseconds */ + uint32_t delay_variation; /* Microseconds */ +} __attribute__ ((packed)) hci_qos; +#define HCI_QOS_CP_SIZE 17 +typedef struct { + uint16_t handle; + uint8_t flags; /* Reserved */ + hci_qos qos; +} __attribute__ ((packed)) qos_setup_cp; +#define QOS_SETUP_CP_SIZE (3 + HCI_QOS_CP_SIZE) + +#define OCF_ROLE_DISCOVERY 0x0009 +typedef struct { + uint16_t handle; +} __attribute__ ((packed)) role_discovery_cp; +#define ROLE_DISCOVERY_CP_SIZE 2 +typedef struct { + uint8_t status; + uint16_t handle; + uint8_t role; +} __attribute__ ((packed)) role_discovery_rp; +#define ROLE_DISCOVERY_RP_SIZE 4 + +#define OCF_SWITCH_ROLE 0x000B +typedef struct { + bdaddr_t bdaddr; + uint8_t role; +} __attribute__ ((packed)) switch_role_cp; +#define SWITCH_ROLE_CP_SIZE 7 + +#define OCF_READ_LINK_POLICY 0x000C +typedef struct { + uint16_t handle; +} __attribute__ ((packed)) read_link_policy_cp; +#define READ_LINK_POLICY_CP_SIZE 2 +typedef struct { + uint8_t status; + uint16_t handle; + uint16_t policy; +} __attribute__ ((packed)) read_link_policy_rp; +#define READ_LINK_POLICY_RP_SIZE 5 + +#define OCF_WRITE_LINK_POLICY 0x000D +typedef struct { + uint16_t handle; + uint16_t policy; +} __attribute__ ((packed)) write_link_policy_cp; +#define WRITE_LINK_POLICY_CP_SIZE 4 +typedef struct { + uint8_t status; + uint16_t handle; +} __attribute__ ((packed)) write_link_policy_rp; +#define WRITE_LINK_POLICY_RP_SIZE 3 + +#define OCF_READ_DEFAULT_LINK_POLICY 0x000E + +#define OCF_WRITE_DEFAULT_LINK_POLICY 0x000F + +#define OCF_FLOW_SPECIFICATION 0x0010 + +#define OCF_SNIFF_SUBRATE 0x0011 +typedef struct { + uint16_t handle; + uint16_t max_remote_latency; + uint16_t max_local_latency; + uint16_t min_remote_timeout; + uint16_t min_local_timeout; +} __attribute__ ((packed)) sniff_subrate_cp; +#define SNIFF_SUBRATE_CP_SIZE 10 + +/* Host Controller and Baseband */ +#define OGF_HOST_CTL 0x03 + +#define OCF_SET_EVENT_MASK 0x0001 +typedef struct { + uint8_t mask[8]; +} __attribute__ ((packed)) set_event_mask_cp; +#define SET_EVENT_MASK_CP_SIZE 8 + +#define OCF_RESET 0x0003 + +#define OCF_SET_EVENT_FLT 0x0005 +typedef struct { + uint8_t flt_type; + uint8_t cond_type; + uint8_t condition[0]; +} __attribute__ ((packed)) set_event_flt_cp; +#define SET_EVENT_FLT_CP_SIZE 2 + +enum bt_filter_type { + FLT_CLEAR_ALL = 0x00, + FLT_INQ_RESULT = 0x01, + FLT_CONN_SETUP = 0x02, +}; +enum inq_result_cond_type { + INQ_RESULT_RETURN_ALL = 0x00, + INQ_RESULT_RETURN_CLASS = 0x01, + INQ_RESULT_RETURN_BDADDR = 0x02, +}; +enum conn_setup_cond_type { + CONN_SETUP_ALLOW_ALL = 0x00, + CONN_SETUP_ALLOW_CLASS = 0x01, + CONN_SETUP_ALLOW_BDADDR = 0x02, +}; +enum conn_setup_cond { + CONN_SETUP_AUTO_OFF = 0x01, + CONN_SETUP_AUTO_ON = 0x02, +}; + +#define OCF_FLUSH 0x0008 +typedef struct { + uint16_t handle; +} __attribute__ ((packed)) flush_cp; +#define FLUSH_CP_SIZE 2 + +typedef struct { + uint8_t status; + uint16_t handle; +} __attribute__ ((packed)) flush_rp; +#define FLUSH_RP_SIZE 3 + +#define OCF_READ_PIN_TYPE 0x0009 +typedef struct { + uint8_t status; + uint8_t pin_type; +} __attribute__ ((packed)) read_pin_type_rp; +#define READ_PIN_TYPE_RP_SIZE 2 + +#define OCF_WRITE_PIN_TYPE 0x000A +typedef struct { + uint8_t pin_type; +} __attribute__ ((packed)) write_pin_type_cp; +#define WRITE_PIN_TYPE_CP_SIZE 1 + +#define OCF_CREATE_NEW_UNIT_KEY 0x000B + +#define OCF_READ_STORED_LINK_KEY 0x000D +typedef struct { + bdaddr_t bdaddr; + uint8_t read_all; +} __attribute__ ((packed)) read_stored_link_key_cp; +#define READ_STORED_LINK_KEY_CP_SIZE 7 +typedef struct { + uint8_t status; + uint16_t max_keys; + uint16_t num_keys; +} __attribute__ ((packed)) read_stored_link_key_rp; +#define READ_STORED_LINK_KEY_RP_SIZE 5 + +#define OCF_WRITE_STORED_LINK_KEY 0x0011 +typedef struct { + uint8_t num_keys; + /* variable length part */ +} __attribute__ ((packed)) write_stored_link_key_cp; +#define WRITE_STORED_LINK_KEY_CP_SIZE 1 +typedef struct { + uint8_t status; + uint8_t num_keys; +} __attribute__ ((packed)) write_stored_link_key_rp; +#define READ_WRITE_LINK_KEY_RP_SIZE 2 + +#define OCF_DELETE_STORED_LINK_KEY 0x0012 +typedef struct { + bdaddr_t bdaddr; + uint8_t delete_all; +} __attribute__ ((packed)) delete_stored_link_key_cp; +#define DELETE_STORED_LINK_KEY_CP_SIZE 7 +typedef struct { + uint8_t status; + uint16_t num_keys; +} __attribute__ ((packed)) delete_stored_link_key_rp; +#define DELETE_STORED_LINK_KEY_RP_SIZE 3 + +#define OCF_CHANGE_LOCAL_NAME 0x0013 +typedef struct { + char name[248]; +} __attribute__ ((packed)) change_local_name_cp; +#define CHANGE_LOCAL_NAME_CP_SIZE 248 + +#define OCF_READ_LOCAL_NAME 0x0014 +typedef struct { + uint8_t status; + char name[248]; +} __attribute__ ((packed)) read_local_name_rp; +#define READ_LOCAL_NAME_RP_SIZE 249 + +#define OCF_READ_CONN_ACCEPT_TIMEOUT 0x0015 +typedef struct { + uint8_t status; + uint16_t timeout; +} __attribute__ ((packed)) read_conn_accept_timeout_rp; +#define READ_CONN_ACCEPT_TIMEOUT_RP_SIZE 3 + +#define OCF_WRITE_CONN_ACCEPT_TIMEOUT 0x0016 +typedef struct { + uint16_t timeout; +} __attribute__ ((packed)) write_conn_accept_timeout_cp; +#define WRITE_CONN_ACCEPT_TIMEOUT_CP_SIZE 2 + +#define OCF_READ_PAGE_TIMEOUT 0x0017 +typedef struct { + uint8_t status; + uint16_t timeout; +} __attribute__ ((packed)) read_page_timeout_rp; +#define READ_PAGE_TIMEOUT_RP_SIZE 3 + +#define OCF_WRITE_PAGE_TIMEOUT 0x0018 +typedef struct { + uint16_t timeout; +} __attribute__ ((packed)) write_page_timeout_cp; +#define WRITE_PAGE_TIMEOUT_CP_SIZE 2 + +#define OCF_READ_SCAN_ENABLE 0x0019 +typedef struct { + uint8_t status; + uint8_t enable; +} __attribute__ ((packed)) read_scan_enable_rp; +#define READ_SCAN_ENABLE_RP_SIZE 2 + +#define OCF_WRITE_SCAN_ENABLE 0x001A +typedef struct { + uint8_t scan_enable; +} __attribute__ ((packed)) write_scan_enable_cp; +#define WRITE_SCAN_ENABLE_CP_SIZE 1 + +enum scan_enable_bits { + SCAN_DISABLED = 0, + SCAN_INQUIRY = 1 << 0, + SCAN_PAGE = 1 << 1, +}; + +#define OCF_READ_PAGE_ACTIVITY 0x001B +typedef struct { + uint8_t status; + uint16_t interval; + uint16_t window; +} __attribute__ ((packed)) read_page_activity_rp; +#define READ_PAGE_ACTIVITY_RP_SIZE 5 + +#define OCF_WRITE_PAGE_ACTIVITY 0x001C +typedef struct { + uint16_t interval; + uint16_t window; +} __attribute__ ((packed)) write_page_activity_cp; +#define WRITE_PAGE_ACTIVITY_CP_SIZE 4 + +#define OCF_READ_INQ_ACTIVITY 0x001D +typedef struct { + uint8_t status; + uint16_t interval; + uint16_t window; +} __attribute__ ((packed)) read_inq_activity_rp; +#define READ_INQ_ACTIVITY_RP_SIZE 5 + +#define OCF_WRITE_INQ_ACTIVITY 0x001E +typedef struct { + uint16_t interval; + uint16_t window; +} __attribute__ ((packed)) write_inq_activity_cp; +#define WRITE_INQ_ACTIVITY_CP_SIZE 4 + +#define OCF_READ_AUTH_ENABLE 0x001F + +#define OCF_WRITE_AUTH_ENABLE 0x0020 + +#define AUTH_DISABLED 0x00 +#define AUTH_ENABLED 0x01 + +#define OCF_READ_ENCRYPT_MODE 0x0021 + +#define OCF_WRITE_ENCRYPT_MODE 0x0022 + +#define ENCRYPT_DISABLED 0x00 +#define ENCRYPT_P2P 0x01 +#define ENCRYPT_BOTH 0x02 + +#define OCF_READ_CLASS_OF_DEV 0x0023 +typedef struct { + uint8_t status; + uint8_t dev_class[3]; +} __attribute__ ((packed)) read_class_of_dev_rp; +#define READ_CLASS_OF_DEV_RP_SIZE 4 + +#define OCF_WRITE_CLASS_OF_DEV 0x0024 +typedef struct { + uint8_t dev_class[3]; +} __attribute__ ((packed)) write_class_of_dev_cp; +#define WRITE_CLASS_OF_DEV_CP_SIZE 3 + +#define OCF_READ_VOICE_SETTING 0x0025 +typedef struct { + uint8_t status; + uint16_t voice_setting; +} __attribute__ ((packed)) read_voice_setting_rp; +#define READ_VOICE_SETTING_RP_SIZE 3 + +#define OCF_WRITE_VOICE_SETTING 0x0026 +typedef struct { + uint16_t voice_setting; +} __attribute__ ((packed)) write_voice_setting_cp; +#define WRITE_VOICE_SETTING_CP_SIZE 2 + +#define OCF_READ_AUTOMATIC_FLUSH_TIMEOUT 0x0027 + +#define OCF_WRITE_AUTOMATIC_FLUSH_TIMEOUT 0x0028 + +#define OCF_READ_NUM_BROADCAST_RETRANS 0x0029 + +#define OCF_WRITE_NUM_BROADCAST_RETRANS 0x002A + +#define OCF_READ_HOLD_MODE_ACTIVITY 0x002B + +#define OCF_WRITE_HOLD_MODE_ACTIVITY 0x002C + +#define OCF_READ_TRANSMIT_POWER_LEVEL 0x002D +typedef struct { + uint16_t handle; + uint8_t type; +} __attribute__ ((packed)) read_transmit_power_level_cp; +#define READ_TRANSMIT_POWER_LEVEL_CP_SIZE 3 +typedef struct { + uint8_t status; + uint16_t handle; + int8_t level; +} __attribute__ ((packed)) read_transmit_power_level_rp; +#define READ_TRANSMIT_POWER_LEVEL_RP_SIZE 4 + +#define OCF_HOST_BUFFER_SIZE 0x0033 +typedef struct { + uint16_t acl_mtu; + uint8_t sco_mtu; + uint16_t acl_max_pkt; + uint16_t sco_max_pkt; +} __attribute__ ((packed)) host_buffer_size_cp; +#define HOST_BUFFER_SIZE_CP_SIZE 7 + +#define OCF_HOST_NUMBER_OF_COMPLETED_PACKETS 0x0035 + +#define OCF_READ_LINK_SUPERVISION_TIMEOUT 0x0036 +typedef struct { + uint8_t status; + uint16_t handle; + uint16_t link_sup_to; +} __attribute__ ((packed)) read_link_supervision_timeout_rp; +#define READ_LINK_SUPERVISION_TIMEOUT_RP_SIZE 5 + +#define OCF_WRITE_LINK_SUPERVISION_TIMEOUT 0x0037 +typedef struct { + uint16_t handle; + uint16_t link_sup_to; +} __attribute__ ((packed)) write_link_supervision_timeout_cp; +#define WRITE_LINK_SUPERVISION_TIMEOUT_CP_SIZE 4 +typedef struct { + uint8_t status; + uint16_t handle; +} __attribute__ ((packed)) write_link_supervision_timeout_rp; +#define WRITE_LINK_SUPERVISION_TIMEOUT_RP_SIZE 3 + +#define OCF_READ_NUM_SUPPORTED_IAC 0x0038 + +#define MAX_IAC_LAP 0x40 +#define OCF_READ_CURRENT_IAC_LAP 0x0039 +typedef struct { + uint8_t status; + uint8_t num_current_iac; + uint8_t lap[MAX_IAC_LAP][3]; +} __attribute__ ((packed)) read_current_iac_lap_rp; +#define READ_CURRENT_IAC_LAP_RP_SIZE 2+3*MAX_IAC_LAP + +#define OCF_WRITE_CURRENT_IAC_LAP 0x003A +typedef struct { + uint8_t num_current_iac; + uint8_t lap[MAX_IAC_LAP][3]; +} __attribute__ ((packed)) write_current_iac_lap_cp; +#define WRITE_CURRENT_IAC_LAP_CP_SIZE 1+3*MAX_IAC_LAP + +#define OCF_READ_PAGE_SCAN_PERIOD_MODE 0x003B + +#define OCF_WRITE_PAGE_SCAN_PERIOD_MODE 0x003C + +#define OCF_READ_PAGE_SCAN_MODE 0x003D + +#define OCF_WRITE_PAGE_SCAN_MODE 0x003E + +#define OCF_SET_AFH_CLASSIFICATION 0x003F +typedef struct { + uint8_t map[10]; +} __attribute__ ((packed)) set_afh_classification_cp; +#define SET_AFH_CLASSIFICATION_CP_SIZE 10 +typedef struct { + uint8_t status; +} __attribute__ ((packed)) set_afh_classification_rp; +#define SET_AFH_CLASSIFICATION_RP_SIZE 1 + +#define OCF_READ_INQUIRY_SCAN_TYPE 0x0042 +typedef struct { + uint8_t status; + uint8_t type; +} __attribute__ ((packed)) read_inquiry_scan_type_rp; +#define READ_INQUIRY_SCAN_TYPE_RP_SIZE 2 + +#define OCF_WRITE_INQUIRY_SCAN_TYPE 0x0043 +typedef struct { + uint8_t type; +} __attribute__ ((packed)) write_inquiry_scan_type_cp; +#define WRITE_INQUIRY_SCAN_TYPE_CP_SIZE 1 +typedef struct { + uint8_t status; +} __attribute__ ((packed)) write_inquiry_scan_type_rp; +#define WRITE_INQUIRY_SCAN_TYPE_RP_SIZE 1 + +#define OCF_READ_INQUIRY_MODE 0x0044 +typedef struct { + uint8_t status; + uint8_t mode; +} __attribute__ ((packed)) read_inquiry_mode_rp; +#define READ_INQUIRY_MODE_RP_SIZE 2 + +#define OCF_WRITE_INQUIRY_MODE 0x0045 +typedef struct { + uint8_t mode; +} __attribute__ ((packed)) write_inquiry_mode_cp; +#define WRITE_INQUIRY_MODE_CP_SIZE 1 +typedef struct { + uint8_t status; +} __attribute__ ((packed)) write_inquiry_mode_rp; +#define WRITE_INQUIRY_MODE_RP_SIZE 1 + +#define OCF_READ_PAGE_SCAN_TYPE 0x0046 + +#define OCF_WRITE_PAGE_SCAN_TYPE 0x0047 + +#define OCF_READ_AFH_MODE 0x0048 +typedef struct { + uint8_t status; + uint8_t mode; +} __attribute__ ((packed)) read_afh_mode_rp; +#define READ_AFH_MODE_RP_SIZE 2 + +#define OCF_WRITE_AFH_MODE 0x0049 +typedef struct { + uint8_t mode; +} __attribute__ ((packed)) write_afh_mode_cp; +#define WRITE_AFH_MODE_CP_SIZE 1 +typedef struct { + uint8_t status; +} __attribute__ ((packed)) write_afh_mode_rp; +#define WRITE_AFH_MODE_RP_SIZE 1 + +#define OCF_READ_EXT_INQUIRY_RESPONSE 0x0051 +typedef struct { + uint8_t status; + uint8_t fec; + uint8_t data[240]; +} __attribute__ ((packed)) read_ext_inquiry_response_rp; +#define READ_EXT_INQUIRY_RESPONSE_RP_SIZE 242 + +#define OCF_WRITE_EXT_INQUIRY_RESPONSE 0x0052 +typedef struct { + uint8_t fec; + uint8_t data[240]; +} __attribute__ ((packed)) write_ext_inquiry_response_cp; +#define WRITE_EXT_INQUIRY_RESPONSE_CP_SIZE 241 +typedef struct { + uint8_t status; +} __attribute__ ((packed)) write_ext_inquiry_response_rp; +#define WRITE_EXT_INQUIRY_RESPONSE_RP_SIZE 1 + +/* Informational Parameters */ +#define OGF_INFO_PARAM 0x04 + +#define OCF_READ_LOCAL_VERSION 0x0001 +typedef struct { + uint8_t status; + uint8_t hci_ver; + uint16_t hci_rev; + uint8_t lmp_ver; + uint16_t manufacturer; + uint16_t lmp_subver; +} __attribute__ ((packed)) read_local_version_rp; +#define READ_LOCAL_VERSION_RP_SIZE 9 + +#define OCF_READ_LOCAL_COMMANDS 0x0002 +typedef struct { + uint8_t status; + uint8_t commands[64]; +} __attribute__ ((packed)) read_local_commands_rp; +#define READ_LOCAL_COMMANDS_RP_SIZE 65 + +#define OCF_READ_LOCAL_FEATURES 0x0003 +typedef struct { + uint8_t status; + uint8_t features[8]; +} __attribute__ ((packed)) read_local_features_rp; +#define READ_LOCAL_FEATURES_RP_SIZE 9 + +#define OCF_READ_LOCAL_EXT_FEATURES 0x0004 +typedef struct { + uint8_t page_num; +} __attribute__ ((packed)) read_local_ext_features_cp; +#define READ_LOCAL_EXT_FEATURES_CP_SIZE 1 +typedef struct { + uint8_t status; + uint8_t page_num; + uint8_t max_page_num; + uint8_t features[8]; +} __attribute__ ((packed)) read_local_ext_features_rp; +#define READ_LOCAL_EXT_FEATURES_RP_SIZE 11 + +#define OCF_READ_BUFFER_SIZE 0x0005 +typedef struct { + uint8_t status; + uint16_t acl_mtu; + uint8_t sco_mtu; + uint16_t acl_max_pkt; + uint16_t sco_max_pkt; +} __attribute__ ((packed)) read_buffer_size_rp; +#define READ_BUFFER_SIZE_RP_SIZE 8 + +#define OCF_READ_COUNTRY_CODE 0x0007 +typedef struct { + uint8_t status; + uint8_t country_code; +} __attribute__ ((packed)) read_country_code_rp; +#define READ_COUNTRY_CODE_RP_SIZE 2 + +#define OCF_READ_BD_ADDR 0x0009 +typedef struct { + uint8_t status; + bdaddr_t bdaddr; +} __attribute__ ((packed)) read_bd_addr_rp; +#define READ_BD_ADDR_RP_SIZE 7 + +/* Status params */ +#define OGF_STATUS_PARAM 0x05 + +#define OCF_READ_FAILED_CONTACT_COUNTER 0x0001 +typedef struct { + uint8_t status; + uint16_t handle; + uint8_t counter; +} __attribute__ ((packed)) read_failed_contact_counter_rp; +#define READ_FAILED_CONTACT_COUNTER_RP_SIZE 4 + +#define OCF_RESET_FAILED_CONTACT_COUNTER 0x0002 +typedef struct { + uint8_t status; + uint16_t handle; +} __attribute__ ((packed)) reset_failed_contact_counter_rp; +#define RESET_FAILED_CONTACT_COUNTER_RP_SIZE 4 + +#define OCF_READ_LINK_QUALITY 0x0003 +typedef struct { + uint16_t handle; +} __attribute__ ((packed)) read_link_quality_cp; +#define READ_LINK_QUALITY_CP_SIZE 4 + +typedef struct { + uint8_t status; + uint16_t handle; + uint8_t link_quality; +} __attribute__ ((packed)) read_link_quality_rp; +#define READ_LINK_QUALITY_RP_SIZE 4 + +#define OCF_READ_RSSI 0x0005 +typedef struct { + uint8_t status; + uint16_t handle; + int8_t rssi; +} __attribute__ ((packed)) read_rssi_rp; +#define READ_RSSI_RP_SIZE 4 + +#define OCF_READ_AFH_MAP 0x0006 +typedef struct { + uint8_t status; + uint16_t handle; + uint8_t mode; + uint8_t map[10]; +} __attribute__ ((packed)) read_afh_map_rp; +#define READ_AFH_MAP_RP_SIZE 14 + +#define OCF_READ_CLOCK 0x0007 +typedef struct { + uint16_t handle; + uint8_t which_clock; +} __attribute__ ((packed)) read_clock_cp; +#define READ_CLOCK_CP_SIZE 3 +typedef struct { + uint8_t status; + uint16_t handle; + uint32_t clock; + uint16_t accuracy; +} __attribute__ ((packed)) read_clock_rp; +#define READ_CLOCK_RP_SIZE 9 + +/* Testing commands */ +#define OGF_TESTING_CMD 0x3e + +/* Vendor specific commands */ +#define OGF_VENDOR_CMD 0x3f + +/* HCI Events */ + +#define EVT_INQUIRY_COMPLETE 0x01 + +#define EVT_INQUIRY_RESULT 0x02 +typedef struct { + uint8_t num_responses; + bdaddr_t bdaddr; + uint8_t pscan_rep_mode; + uint8_t pscan_period_mode; + uint8_t pscan_mode; + uint8_t dev_class[3]; + uint16_t clock_offset; +} __attribute__ ((packed)) inquiry_info; +#define INQUIRY_INFO_SIZE 14 + +#define EVT_CONN_COMPLETE 0x03 +typedef struct { + uint8_t status; + uint16_t handle; + bdaddr_t bdaddr; + uint8_t link_type; + uint8_t encr_mode; +} __attribute__ ((packed)) evt_conn_complete; +#define EVT_CONN_COMPLETE_SIZE 11 + +#define EVT_CONN_REQUEST 0x04 +typedef struct { + bdaddr_t bdaddr; + uint8_t dev_class[3]; + uint8_t link_type; +} __attribute__ ((packed)) evt_conn_request; +#define EVT_CONN_REQUEST_SIZE 10 + +#define EVT_DISCONN_COMPLETE 0x05 +typedef struct { + uint8_t status; + uint16_t handle; + uint8_t reason; +} __attribute__ ((packed)) evt_disconn_complete; +#define EVT_DISCONN_COMPLETE_SIZE 4 + +#define EVT_AUTH_COMPLETE 0x06 +typedef struct { + uint8_t status; + uint16_t handle; +} __attribute__ ((packed)) evt_auth_complete; +#define EVT_AUTH_COMPLETE_SIZE 3 + +#define EVT_REMOTE_NAME_REQ_COMPLETE 0x07 +typedef struct { + uint8_t status; + bdaddr_t bdaddr; + char name[248]; +} __attribute__ ((packed)) evt_remote_name_req_complete; +#define EVT_REMOTE_NAME_REQ_COMPLETE_SIZE 255 + +#define EVT_ENCRYPT_CHANGE 0x08 +typedef struct { + uint8_t status; + uint16_t handle; + uint8_t encrypt; +} __attribute__ ((packed)) evt_encrypt_change; +#define EVT_ENCRYPT_CHANGE_SIZE 5 + +#define EVT_CHANGE_CONN_LINK_KEY_COMPLETE 0x09 +typedef struct { + uint8_t status; + uint16_t handle; +} __attribute__ ((packed)) evt_change_conn_link_key_complete; +#define EVT_CHANGE_CONN_LINK_KEY_COMPLETE_SIZE 3 + +#define EVT_MASTER_LINK_KEY_COMPLETE 0x0A +typedef struct { + uint8_t status; + uint16_t handle; + uint8_t key_flag; +} __attribute__ ((packed)) evt_master_link_key_complete; +#define EVT_MASTER_LINK_KEY_COMPLETE_SIZE 4 + +#define EVT_READ_REMOTE_FEATURES_COMPLETE 0x0B +typedef struct { + uint8_t status; + uint16_t handle; + uint8_t features[8]; +} __attribute__ ((packed)) evt_read_remote_features_complete; +#define EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE 11 + +#define EVT_READ_REMOTE_VERSION_COMPLETE 0x0C +typedef struct { + uint8_t status; + uint16_t handle; + uint8_t lmp_ver; + uint16_t manufacturer; + uint16_t lmp_subver; +} __attribute__ ((packed)) evt_read_remote_version_complete; +#define EVT_READ_REMOTE_VERSION_COMPLETE_SIZE 8 + +#define EVT_QOS_SETUP_COMPLETE 0x0D +typedef struct { + uint8_t status; + uint16_t handle; + uint8_t flags; /* Reserved */ + hci_qos qos; +} __attribute__ ((packed)) evt_qos_setup_complete; +#define EVT_QOS_SETUP_COMPLETE_SIZE (4 + HCI_QOS_CP_SIZE) + +#define EVT_CMD_COMPLETE 0x0E +typedef struct { + uint8_t ncmd; + uint16_t opcode; +} __attribute__ ((packed)) evt_cmd_complete; +#define EVT_CMD_COMPLETE_SIZE 3 + +#define EVT_CMD_STATUS 0x0F +typedef struct { + uint8_t status; + uint8_t ncmd; + uint16_t opcode; +} __attribute__ ((packed)) evt_cmd_status; +#define EVT_CMD_STATUS_SIZE 4 + +#define EVT_HARDWARE_ERROR 0x10 +typedef struct { + uint8_t code; +} __attribute__ ((packed)) evt_hardware_error; +#define EVT_HARDWARE_ERROR_SIZE 1 + +#define EVT_FLUSH_OCCURRED 0x11 +typedef struct { + uint16_t handle; +} __attribute__ ((packed)) evt_flush_occured; +#define EVT_FLUSH_OCCURRED_SIZE 2 + +#define EVT_ROLE_CHANGE 0x12 +typedef struct { + uint8_t status; + bdaddr_t bdaddr; + uint8_t role; +} __attribute__ ((packed)) evt_role_change; +#define EVT_ROLE_CHANGE_SIZE 8 + +#define EVT_NUM_COMP_PKTS 0x13 +typedef struct { + uint8_t num_hndl; + struct { + uint16_t handle; + uint16_t num_packets; + } connection[0]; +} __attribute__ ((packed)) evt_num_comp_pkts; +#define EVT_NUM_COMP_PKTS_SIZE(num_hndl) (1 + 4 * (num_hndl)) + +#define EVT_MODE_CHANGE 0x14 +typedef struct { + uint8_t status; + uint16_t handle; + uint8_t mode; + uint16_t interval; +} __attribute__ ((packed)) evt_mode_change; +#define EVT_MODE_CHANGE_SIZE 6 + +#define EVT_RETURN_LINK_KEYS 0x15 +typedef struct { + uint8_t num_keys; + /* variable length part */ +} __attribute__ ((packed)) evt_return_link_keys; +#define EVT_RETURN_LINK_KEYS_SIZE 1 + +#define EVT_PIN_CODE_REQ 0x16 +typedef struct { + bdaddr_t bdaddr; +} __attribute__ ((packed)) evt_pin_code_req; +#define EVT_PIN_CODE_REQ_SIZE 6 + +#define EVT_LINK_KEY_REQ 0x17 +typedef struct { + bdaddr_t bdaddr; +} __attribute__ ((packed)) evt_link_key_req; +#define EVT_LINK_KEY_REQ_SIZE 6 + +#define EVT_LINK_KEY_NOTIFY 0x18 +typedef struct { + bdaddr_t bdaddr; + uint8_t link_key[16]; + uint8_t key_type; +} __attribute__ ((packed)) evt_link_key_notify; +#define EVT_LINK_KEY_NOTIFY_SIZE 23 + +#define EVT_LOOPBACK_COMMAND 0x19 + +#define EVT_DATA_BUFFER_OVERFLOW 0x1A +typedef struct { + uint8_t link_type; +} __attribute__ ((packed)) evt_data_buffer_overflow; +#define EVT_DATA_BUFFER_OVERFLOW_SIZE 1 + +#define EVT_MAX_SLOTS_CHANGE 0x1B +typedef struct { + uint16_t handle; + uint8_t max_slots; +} __attribute__ ((packed)) evt_max_slots_change; +#define EVT_MAX_SLOTS_CHANGE_SIZE 3 + +#define EVT_READ_CLOCK_OFFSET_COMPLETE 0x1C +typedef struct { + uint8_t status; + uint16_t handle; + uint16_t clock_offset; +} __attribute__ ((packed)) evt_read_clock_offset_complete; +#define EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE 5 + +#define EVT_CONN_PTYPE_CHANGED 0x1D +typedef struct { + uint8_t status; + uint16_t handle; + uint16_t ptype; +} __attribute__ ((packed)) evt_conn_ptype_changed; +#define EVT_CONN_PTYPE_CHANGED_SIZE 5 + +#define EVT_QOS_VIOLATION 0x1E +typedef struct { + uint16_t handle; +} __attribute__ ((packed)) evt_qos_violation; +#define EVT_QOS_VIOLATION_SIZE 2 + +#define EVT_PSCAN_REP_MODE_CHANGE 0x20 +typedef struct { + bdaddr_t bdaddr; + uint8_t pscan_rep_mode; +} __attribute__ ((packed)) evt_pscan_rep_mode_change; +#define EVT_PSCAN_REP_MODE_CHANGE_SIZE 7 + +#define EVT_FLOW_SPEC_COMPLETE 0x21 +typedef struct { + uint8_t status; + uint16_t handle; + uint8_t flags; + uint8_t direction; + hci_qos qos; +} __attribute__ ((packed)) evt_flow_spec_complete; +#define EVT_FLOW_SPEC_COMPLETE_SIZE (5 + HCI_QOS_CP_SIZE) + +#define EVT_INQUIRY_RESULT_WITH_RSSI 0x22 +typedef struct { + uint8_t num_responses; + bdaddr_t bdaddr; + uint8_t pscan_rep_mode; + uint8_t pscan_period_mode; + uint8_t dev_class[3]; + uint16_t clock_offset; + int8_t rssi; +} __attribute__ ((packed)) inquiry_info_with_rssi; +#define INQUIRY_INFO_WITH_RSSI_SIZE 15 +typedef struct { + uint8_t num_responses; + bdaddr_t bdaddr; + uint8_t pscan_rep_mode; + uint8_t pscan_period_mode; + uint8_t pscan_mode; + uint8_t dev_class[3]; + uint16_t clock_offset; + int8_t rssi; +} __attribute__ ((packed)) inquiry_info_with_rssi_and_pscan_mode; +#define INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE 16 + +#define EVT_READ_REMOTE_EXT_FEATURES_COMPLETE 0x23 +typedef struct { + uint8_t status; + uint16_t handle; + uint8_t page_num; + uint8_t max_page_num; + uint8_t features[8]; +} __attribute__ ((packed)) evt_read_remote_ext_features_complete; +#define EVT_READ_REMOTE_EXT_FEATURES_COMPLETE_SIZE 13 + +#define EVT_SYNC_CONN_COMPLETE 0x2C +typedef struct { + uint8_t status; + uint16_t handle; + bdaddr_t bdaddr; + uint8_t link_type; + uint8_t trans_interval; + uint8_t retrans_window; + uint16_t rx_pkt_len; + uint16_t tx_pkt_len; + uint8_t air_mode; +} __attribute__ ((packed)) evt_sync_conn_complete; +#define EVT_SYNC_CONN_COMPLETE_SIZE 17 + +#define EVT_SYNC_CONN_CHANGED 0x2D +typedef struct { + uint8_t status; + uint16_t handle; + uint8_t trans_interval; + uint8_t retrans_window; + uint16_t rx_pkt_len; + uint16_t tx_pkt_len; +} __attribute__ ((packed)) evt_sync_conn_changed; +#define EVT_SYNC_CONN_CHANGED_SIZE 9 + +#define EVT_SNIFF_SUBRATE 0x2E +typedef struct { + uint8_t status; + uint16_t handle; + uint16_t max_remote_latency; + uint16_t max_local_latency; + uint16_t min_remote_timeout; + uint16_t min_local_timeout; +} __attribute__ ((packed)) evt_sniff_subrate; +#define EVT_SNIFF_SUBRATE_SIZE 11 + +#define EVT_EXTENDED_INQUIRY_RESULT 0x2F +typedef struct { + bdaddr_t bdaddr; + uint8_t pscan_rep_mode; + uint8_t pscan_period_mode; + uint8_t dev_class[3]; + uint16_t clock_offset; + int8_t rssi; + uint8_t data[240]; +} __attribute__ ((packed)) extended_inquiry_info; +#define EXTENDED_INQUIRY_INFO_SIZE 254 + +#define EVT_TESTING 0xFE + +#define EVT_VENDOR 0xFF + +/* Command opcode pack/unpack */ +#define cmd_opcode_pack(ogf, ocf) (uint16_t)((ocf & 0x03ff)|(ogf << 10)) +#define cmd_opcode_ogf(op) (op >> 10) +#define cmd_opcode_ocf(op) (op & 0x03ff) + +/* ACL handle and flags pack/unpack */ +#define acl_handle_pack(h, f) (uint16_t)(((h) & 0x0fff)|((f) << 12)) +#define acl_handle(h) ((h) & 0x0fff) +#define acl_flags(h) ((h) >> 12) + +/* HCI Packet structures */ +#define HCI_COMMAND_HDR_SIZE 3 +#define HCI_EVENT_HDR_SIZE 2 +#define HCI_ACL_HDR_SIZE 4 +#define HCI_SCO_HDR_SIZE 3 + +struct hci_command_hdr { + uint16_t opcode; /* OCF & OGF */ + uint8_t plen; +} __attribute__ ((packed)); + +struct hci_event_hdr { + uint8_t evt; + uint8_t plen; +} __attribute__ ((packed)); + +struct hci_acl_hdr { + uint16_t handle; /* Handle & Flags(PB, BC) */ + uint16_t dlen; +} __attribute__ ((packed)); + +struct hci_sco_hdr { + uint16_t handle; + uint8_t dlen; +} __attribute__ ((packed)); + +/* L2CAP layer defines */ + +enum bt_l2cap_lm_bits { + L2CAP_LM_MASTER = 1 << 0, + L2CAP_LM_AUTH = 1 << 1, + L2CAP_LM_ENCRYPT = 1 << 2, + L2CAP_LM_TRUSTED = 1 << 3, + L2CAP_LM_RELIABLE = 1 << 4, + L2CAP_LM_SECURE = 1 << 5, +}; + +enum bt_l2cap_cid_predef { + L2CAP_CID_INVALID = 0x0000, + L2CAP_CID_SIGNALLING= 0x0001, + L2CAP_CID_GROUP = 0x0002, + L2CAP_CID_ALLOC = 0x0040, +}; + +/* L2CAP command codes */ +enum bt_l2cap_cmd { + L2CAP_COMMAND_REJ = 1, + L2CAP_CONN_REQ, + L2CAP_CONN_RSP, + L2CAP_CONF_REQ, + L2CAP_CONF_RSP, + L2CAP_DISCONN_REQ, + L2CAP_DISCONN_RSP, + L2CAP_ECHO_REQ, + L2CAP_ECHO_RSP, + L2CAP_INFO_REQ, + L2CAP_INFO_RSP, +}; + +enum bt_l2cap_sar_bits { + L2CAP_SAR_NO_SEG = 0, + L2CAP_SAR_START, + L2CAP_SAR_END, + L2CAP_SAR_CONT, +}; + +/* L2CAP structures */ +typedef struct { + uint16_t len; + uint16_t cid; + uint8_t data[0]; +} __attribute__ ((packed)) l2cap_hdr; +#define L2CAP_HDR_SIZE 4 + +typedef struct { + uint8_t code; + uint8_t ident; + uint16_t len; +} __attribute__ ((packed)) l2cap_cmd_hdr; +#define L2CAP_CMD_HDR_SIZE 4 + +typedef struct { + uint16_t reason; +} __attribute__ ((packed)) l2cap_cmd_rej; +#define L2CAP_CMD_REJ_SIZE 2 + +typedef struct { + uint16_t dcid; + uint16_t scid; +} __attribute__ ((packed)) l2cap_cmd_rej_cid; +#define L2CAP_CMD_REJ_CID_SIZE 4 + +/* reject reason */ +enum bt_l2cap_rej_reason { + L2CAP_REJ_CMD_NOT_UNDERSTOOD = 0, + L2CAP_REJ_SIG_TOOBIG, + L2CAP_REJ_CID_INVAL, +}; + +typedef struct { + uint16_t psm; + uint16_t scid; +} __attribute__ ((packed)) l2cap_conn_req; +#define L2CAP_CONN_REQ_SIZE 4 + +typedef struct { + uint16_t dcid; + uint16_t scid; + uint16_t result; + uint16_t status; +} __attribute__ ((packed)) l2cap_conn_rsp; +#define L2CAP_CONN_RSP_SIZE 8 + +/* connect result */ +enum bt_l2cap_conn_res { + L2CAP_CR_SUCCESS = 0, + L2CAP_CR_PEND, + L2CAP_CR_BAD_PSM, + L2CAP_CR_SEC_BLOCK, + L2CAP_CR_NO_MEM, +}; + +/* connect status */ +enum bt_l2cap_conn_stat { + L2CAP_CS_NO_INFO = 0, + L2CAP_CS_AUTHEN_PEND, + L2CAP_CS_AUTHOR_PEND, +}; + +typedef struct { + uint16_t dcid; + uint16_t flags; + uint8_t data[0]; +} __attribute__ ((packed)) l2cap_conf_req; +#define L2CAP_CONF_REQ_SIZE(datalen) (4 + (datalen)) + +typedef struct { + uint16_t scid; + uint16_t flags; + uint16_t result; + uint8_t data[0]; +} __attribute__ ((packed)) l2cap_conf_rsp; +#define L2CAP_CONF_RSP_SIZE(datalen) (6 + datalen) + +enum bt_l2cap_conf_res { + L2CAP_CONF_SUCCESS = 0, + L2CAP_CONF_UNACCEPT, + L2CAP_CONF_REJECT, + L2CAP_CONF_UNKNOWN, +}; + +typedef struct { + uint8_t type; + uint8_t len; + uint8_t val[0]; +} __attribute__ ((packed)) l2cap_conf_opt; +#define L2CAP_CONF_OPT_SIZE 2 + +enum bt_l2cap_conf_val { + L2CAP_CONF_MTU = 1, + L2CAP_CONF_FLUSH_TO, + L2CAP_CONF_QOS, + L2CAP_CONF_RFC, + L2CAP_CONF_RFC_MODE = L2CAP_CONF_RFC, +}; + +typedef struct { + uint8_t flags; + uint8_t service_type; + uint32_t token_rate; + uint32_t token_bucket_size; + uint32_t peak_bandwidth; + uint32_t latency; + uint32_t delay_variation; +} __attribute__ ((packed)) l2cap_conf_opt_qos; +#define L2CAP_CONF_OPT_QOS_SIZE 22 + +enum bt_l2cap_conf_opt_qos_st { + L2CAP_CONF_QOS_NO_TRAFFIC = 0x00, + L2CAP_CONF_QOS_BEST_EFFORT, + L2CAP_CONF_QOS_GUARANTEED, +}; + +#define L2CAP_CONF_QOS_WILDCARD 0xffffffff + +enum bt_l2cap_mode { + L2CAP_MODE_BASIC = 0, + L2CAP_MODE_RETRANS = 1, + L2CAP_MODE_FLOWCTL = 2, +}; + +typedef struct { + uint16_t dcid; + uint16_t scid; +} __attribute__ ((packed)) l2cap_disconn_req; +#define L2CAP_DISCONN_REQ_SIZE 4 + +typedef struct { + uint16_t dcid; + uint16_t scid; +} __attribute__ ((packed)) l2cap_disconn_rsp; +#define L2CAP_DISCONN_RSP_SIZE 4 + +typedef struct { + uint16_t type; +} __attribute__ ((packed)) l2cap_info_req; +#define L2CAP_INFO_REQ_SIZE 2 + +typedef struct { + uint16_t type; + uint16_t result; + uint8_t data[0]; +} __attribute__ ((packed)) l2cap_info_rsp; +#define L2CAP_INFO_RSP_SIZE 4 + +/* info type */ +enum bt_l2cap_info_type { + L2CAP_IT_CL_MTU = 1, + L2CAP_IT_FEAT_MASK, +}; + +/* info result */ +enum bt_l2cap_info_result { + L2CAP_IR_SUCCESS = 0, + L2CAP_IR_NOTSUPP, +}; + +/* Service Discovery Protocol defines */ +/* Note that all multibyte values in lower layer protocols (above in this file) + * are little-endian while SDP is big-endian. */ + +/* Protocol UUIDs */ +enum sdp_proto_uuid { + SDP_UUID = 0x0001, + UDP_UUID = 0x0002, + RFCOMM_UUID = 0x0003, + TCP_UUID = 0x0004, + TCS_BIN_UUID = 0x0005, + TCS_AT_UUID = 0x0006, + OBEX_UUID = 0x0008, + IP_UUID = 0x0009, + FTP_UUID = 0x000a, + HTTP_UUID = 0x000c, + WSP_UUID = 0x000e, + BNEP_UUID = 0x000f, + UPNP_UUID = 0x0010, + HIDP_UUID = 0x0011, + HCRP_CTRL_UUID = 0x0012, + HCRP_DATA_UUID = 0x0014, + HCRP_NOTE_UUID = 0x0016, + AVCTP_UUID = 0x0017, + AVDTP_UUID = 0x0019, + CMTP_UUID = 0x001b, + UDI_UUID = 0x001d, + MCAP_CTRL_UUID = 0x001e, + MCAP_DATA_UUID = 0x001f, + L2CAP_UUID = 0x0100, +}; + +/* + * Service class identifiers of standard services and service groups + */ +enum service_class_id { + SDP_SERVER_SVCLASS_ID = 0x1000, + BROWSE_GRP_DESC_SVCLASS_ID = 0x1001, + PUBLIC_BROWSE_GROUP = 0x1002, + SERIAL_PORT_SVCLASS_ID = 0x1101, + LAN_ACCESS_SVCLASS_ID = 0x1102, + DIALUP_NET_SVCLASS_ID = 0x1103, + IRMC_SYNC_SVCLASS_ID = 0x1104, + OBEX_OBJPUSH_SVCLASS_ID = 0x1105, + OBEX_FILETRANS_SVCLASS_ID = 0x1106, + IRMC_SYNC_CMD_SVCLASS_ID = 0x1107, + HEADSET_SVCLASS_ID = 0x1108, + CORDLESS_TELEPHONY_SVCLASS_ID = 0x1109, + AUDIO_SOURCE_SVCLASS_ID = 0x110a, + AUDIO_SINK_SVCLASS_ID = 0x110b, + AV_REMOTE_TARGET_SVCLASS_ID = 0x110c, + ADVANCED_AUDIO_SVCLASS_ID = 0x110d, + AV_REMOTE_SVCLASS_ID = 0x110e, + VIDEO_CONF_SVCLASS_ID = 0x110f, + INTERCOM_SVCLASS_ID = 0x1110, + FAX_SVCLASS_ID = 0x1111, + HEADSET_AGW_SVCLASS_ID = 0x1112, + WAP_SVCLASS_ID = 0x1113, + WAP_CLIENT_SVCLASS_ID = 0x1114, + PANU_SVCLASS_ID = 0x1115, + NAP_SVCLASS_ID = 0x1116, + GN_SVCLASS_ID = 0x1117, + DIRECT_PRINTING_SVCLASS_ID = 0x1118, + REFERENCE_PRINTING_SVCLASS_ID = 0x1119, + IMAGING_SVCLASS_ID = 0x111a, + IMAGING_RESPONDER_SVCLASS_ID = 0x111b, + IMAGING_ARCHIVE_SVCLASS_ID = 0x111c, + IMAGING_REFOBJS_SVCLASS_ID = 0x111d, + HANDSFREE_SVCLASS_ID = 0x111e, + HANDSFREE_AGW_SVCLASS_ID = 0x111f, + DIRECT_PRT_REFOBJS_SVCLASS_ID = 0x1120, + REFLECTED_UI_SVCLASS_ID = 0x1121, + BASIC_PRINTING_SVCLASS_ID = 0x1122, + PRINTING_STATUS_SVCLASS_ID = 0x1123, + HID_SVCLASS_ID = 0x1124, + HCR_SVCLASS_ID = 0x1125, + HCR_PRINT_SVCLASS_ID = 0x1126, + HCR_SCAN_SVCLASS_ID = 0x1127, + CIP_SVCLASS_ID = 0x1128, + VIDEO_CONF_GW_SVCLASS_ID = 0x1129, + UDI_MT_SVCLASS_ID = 0x112a, + UDI_TA_SVCLASS_ID = 0x112b, + AV_SVCLASS_ID = 0x112c, + SAP_SVCLASS_ID = 0x112d, + PBAP_PCE_SVCLASS_ID = 0x112e, + PBAP_PSE_SVCLASS_ID = 0x112f, + PBAP_SVCLASS_ID = 0x1130, + PNP_INFO_SVCLASS_ID = 0x1200, + GENERIC_NETWORKING_SVCLASS_ID = 0x1201, + GENERIC_FILETRANS_SVCLASS_ID = 0x1202, + GENERIC_AUDIO_SVCLASS_ID = 0x1203, + GENERIC_TELEPHONY_SVCLASS_ID = 0x1204, + UPNP_SVCLASS_ID = 0x1205, + UPNP_IP_SVCLASS_ID = 0x1206, + UPNP_PAN_SVCLASS_ID = 0x1300, + UPNP_LAP_SVCLASS_ID = 0x1301, + UPNP_L2CAP_SVCLASS_ID = 0x1302, + VIDEO_SOURCE_SVCLASS_ID = 0x1303, + VIDEO_SINK_SVCLASS_ID = 0x1304, + VIDEO_DISTRIBUTION_SVCLASS_ID = 0x1305, + MDP_SVCLASS_ID = 0x1400, + MDP_SOURCE_SVCLASS_ID = 0x1401, + MDP_SINK_SVCLASS_ID = 0x1402, + APPLE_AGENT_SVCLASS_ID = 0x2112, +}; + +/* + * Standard profile descriptor identifiers; note these + * may be identical to some of the service classes defined above + */ +#define SDP_SERVER_PROFILE_ID SDP_SERVER_SVCLASS_ID +#define BROWSE_GRP_DESC_PROFILE_ID BROWSE_GRP_DESC_SVCLASS_ID +#define SERIAL_PORT_PROFILE_ID SERIAL_PORT_SVCLASS_ID +#define LAN_ACCESS_PROFILE_ID LAN_ACCESS_SVCLASS_ID +#define DIALUP_NET_PROFILE_ID DIALUP_NET_SVCLASS_ID +#define IRMC_SYNC_PROFILE_ID IRMC_SYNC_SVCLASS_ID +#define OBEX_OBJPUSH_PROFILE_ID OBEX_OBJPUSH_SVCLASS_ID +#define OBEX_FILETRANS_PROFILE_ID OBEX_FILETRANS_SVCLASS_ID +#define IRMC_SYNC_CMD_PROFILE_ID IRMC_SYNC_CMD_SVCLASS_ID +#define HEADSET_PROFILE_ID HEADSET_SVCLASS_ID +#define CORDLESS_TELEPHONY_PROFILE_ID CORDLESS_TELEPHONY_SVCLASS_ID +#define AUDIO_SOURCE_PROFILE_ID AUDIO_SOURCE_SVCLASS_ID +#define AUDIO_SINK_PROFILE_ID AUDIO_SINK_SVCLASS_ID +#define AV_REMOTE_TARGET_PROFILE_ID AV_REMOTE_TARGET_SVCLASS_ID +#define ADVANCED_AUDIO_PROFILE_ID ADVANCED_AUDIO_SVCLASS_ID +#define AV_REMOTE_PROFILE_ID AV_REMOTE_SVCLASS_ID +#define VIDEO_CONF_PROFILE_ID VIDEO_CONF_SVCLASS_ID +#define INTERCOM_PROFILE_ID INTERCOM_SVCLASS_ID +#define FAX_PROFILE_ID FAX_SVCLASS_ID +#define HEADSET_AGW_PROFILE_ID HEADSET_AGW_SVCLASS_ID +#define WAP_PROFILE_ID WAP_SVCLASS_ID +#define WAP_CLIENT_PROFILE_ID WAP_CLIENT_SVCLASS_ID +#define PANU_PROFILE_ID PANU_SVCLASS_ID +#define NAP_PROFILE_ID NAP_SVCLASS_ID +#define GN_PROFILE_ID GN_SVCLASS_ID +#define DIRECT_PRINTING_PROFILE_ID DIRECT_PRINTING_SVCLASS_ID +#define REFERENCE_PRINTING_PROFILE_ID REFERENCE_PRINTING_SVCLASS_ID +#define IMAGING_PROFILE_ID IMAGING_SVCLASS_ID +#define IMAGING_RESPONDER_PROFILE_ID IMAGING_RESPONDER_SVCLASS_ID +#define IMAGING_ARCHIVE_PROFILE_ID IMAGING_ARCHIVE_SVCLASS_ID +#define IMAGING_REFOBJS_PROFILE_ID IMAGING_REFOBJS_SVCLASS_ID +#define HANDSFREE_PROFILE_ID HANDSFREE_SVCLASS_ID +#define HANDSFREE_AGW_PROFILE_ID HANDSFREE_AGW_SVCLASS_ID +#define DIRECT_PRT_REFOBJS_PROFILE_ID DIRECT_PRT_REFOBJS_SVCLASS_ID +#define REFLECTED_UI_PROFILE_ID REFLECTED_UI_SVCLASS_ID +#define BASIC_PRINTING_PROFILE_ID BASIC_PRINTING_SVCLASS_ID +#define PRINTING_STATUS_PROFILE_ID PRINTING_STATUS_SVCLASS_ID +#define HID_PROFILE_ID HID_SVCLASS_ID +#define HCR_PROFILE_ID HCR_SCAN_SVCLASS_ID +#define HCR_PRINT_PROFILE_ID HCR_PRINT_SVCLASS_ID +#define HCR_SCAN_PROFILE_ID HCR_SCAN_SVCLASS_ID +#define CIP_PROFILE_ID CIP_SVCLASS_ID +#define VIDEO_CONF_GW_PROFILE_ID VIDEO_CONF_GW_SVCLASS_ID +#define UDI_MT_PROFILE_ID UDI_MT_SVCLASS_ID +#define UDI_TA_PROFILE_ID UDI_TA_SVCLASS_ID +#define AV_PROFILE_ID AV_SVCLASS_ID +#define SAP_PROFILE_ID SAP_SVCLASS_ID +#define PBAP_PCE_PROFILE_ID PBAP_PCE_SVCLASS_ID +#define PBAP_PSE_PROFILE_ID PBAP_PSE_SVCLASS_ID +#define PBAP_PROFILE_ID PBAP_SVCLASS_ID +#define PNP_INFO_PROFILE_ID PNP_INFO_SVCLASS_ID +#define GENERIC_NETWORKING_PROFILE_ID GENERIC_NETWORKING_SVCLASS_ID +#define GENERIC_FILETRANS_PROFILE_ID GENERIC_FILETRANS_SVCLASS_ID +#define GENERIC_AUDIO_PROFILE_ID GENERIC_AUDIO_SVCLASS_ID +#define GENERIC_TELEPHONY_PROFILE_ID GENERIC_TELEPHONY_SVCLASS_ID +#define UPNP_PROFILE_ID UPNP_SVCLASS_ID +#define UPNP_IP_PROFILE_ID UPNP_IP_SVCLASS_ID +#define UPNP_PAN_PROFILE_ID UPNP_PAN_SVCLASS_ID +#define UPNP_LAP_PROFILE_ID UPNP_LAP_SVCLASS_ID +#define UPNP_L2CAP_PROFILE_ID UPNP_L2CAP_SVCLASS_ID +#define VIDEO_SOURCE_PROFILE_ID VIDEO_SOURCE_SVCLASS_ID +#define VIDEO_SINK_PROFILE_ID VIDEO_SINK_SVCLASS_ID +#define VIDEO_DISTRIBUTION_PROFILE_ID VIDEO_DISTRIBUTION_SVCLASS_ID +#define MDP_PROFILE_ID MDP_SVCLASS_ID +#define MDP_SOURCE_PROFILE_ID MDP_SROUCE_SVCLASS_ID +#define MDP_SINK_PROFILE_ID MDP_SINK_SVCLASS_ID +#define APPLE_AGENT_PROFILE_ID APPLE_AGENT_SVCLASS_ID + +/* Data Representation */ +enum bt_sdp_data_type { + SDP_DTYPE_NIL = 0 << 3, + SDP_DTYPE_UINT = 1 << 3, + SDP_DTYPE_SINT = 2 << 3, + SDP_DTYPE_UUID = 3 << 3, + SDP_DTYPE_STRING = 4 << 3, + SDP_DTYPE_BOOL = 5 << 3, + SDP_DTYPE_SEQ = 6 << 3, + SDP_DTYPE_ALT = 7 << 3, + SDP_DTYPE_URL = 8 << 3, +}; + +enum bt_sdp_data_size { + SDP_DSIZE_1 = 0, + SDP_DSIZE_2, + SDP_DSIZE_4, + SDP_DSIZE_8, + SDP_DSIZE_16, + SDP_DSIZE_NEXT1, + SDP_DSIZE_NEXT2, + SDP_DSIZE_NEXT4, + SDP_DSIZE_MASK = SDP_DSIZE_NEXT4, +}; + +enum bt_sdp_cmd { + SDP_ERROR_RSP = 0x01, + SDP_SVC_SEARCH_REQ = 0x02, + SDP_SVC_SEARCH_RSP = 0x03, + SDP_SVC_ATTR_REQ = 0x04, + SDP_SVC_ATTR_RSP = 0x05, + SDP_SVC_SEARCH_ATTR_REQ = 0x06, + SDP_SVC_SEARCH_ATTR_RSP = 0x07, +}; + +enum bt_sdp_errorcode { + SDP_INVALID_VERSION = 0x0001, + SDP_INVALID_RECORD_HANDLE = 0x0002, + SDP_INVALID_SYNTAX = 0x0003, + SDP_INVALID_PDU_SIZE = 0x0004, + SDP_INVALID_CSTATE = 0x0005, +}; + +/* + * String identifiers are based on the SDP spec stating that + * "base attribute id of the primary (universal) language must be 0x0100" + * + * Other languages should have their own offset; e.g.: + * #define XXXLangBase yyyy + * #define AttrServiceName_XXX 0x0000+XXXLangBase + */ +#define SDP_PRIMARY_LANG_BASE 0x0100 + +enum bt_sdp_attribute_id { + SDP_ATTR_RECORD_HANDLE = 0x0000, + SDP_ATTR_SVCLASS_ID_LIST = 0x0001, + SDP_ATTR_RECORD_STATE = 0x0002, + SDP_ATTR_SERVICE_ID = 0x0003, + SDP_ATTR_PROTO_DESC_LIST = 0x0004, + SDP_ATTR_BROWSE_GRP_LIST = 0x0005, + SDP_ATTR_LANG_BASE_ATTR_ID_LIST = 0x0006, + SDP_ATTR_SVCINFO_TTL = 0x0007, + SDP_ATTR_SERVICE_AVAILABILITY = 0x0008, + SDP_ATTR_PFILE_DESC_LIST = 0x0009, + SDP_ATTR_DOC_URL = 0x000a, + SDP_ATTR_CLNT_EXEC_URL = 0x000b, + SDP_ATTR_ICON_URL = 0x000c, + SDP_ATTR_ADD_PROTO_DESC_LIST = 0x000d, + + SDP_ATTR_SVCNAME_PRIMARY = SDP_PRIMARY_LANG_BASE + 0, + SDP_ATTR_SVCDESC_PRIMARY = SDP_PRIMARY_LANG_BASE + 1, + SDP_ATTR_SVCPROV_PRIMARY = SDP_PRIMARY_LANG_BASE + 2, + + SDP_ATTR_GROUP_ID = 0x0200, + SDP_ATTR_IP_SUBNET = 0x0200, + + /* SDP */ + SDP_ATTR_VERSION_NUM_LIST = 0x0200, + SDP_ATTR_SVCDB_STATE = 0x0201, + + SDP_ATTR_SERVICE_VERSION = 0x0300, + SDP_ATTR_EXTERNAL_NETWORK = 0x0301, + SDP_ATTR_SUPPORTED_DATA_STORES_LIST = 0x0301, + SDP_ATTR_FAX_CLASS1_SUPPORT = 0x0302, + SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL = 0x0302, + SDP_ATTR_FAX_CLASS20_SUPPORT = 0x0303, + SDP_ATTR_SUPPORTED_FORMATS_LIST = 0x0303, + SDP_ATTR_FAX_CLASS2_SUPPORT = 0x0304, + SDP_ATTR_AUDIO_FEEDBACK_SUPPORT = 0x0305, + SDP_ATTR_NETWORK_ADDRESS = 0x0306, + SDP_ATTR_WAP_GATEWAY = 0x0307, + SDP_ATTR_HOMEPAGE_URL = 0x0308, + SDP_ATTR_WAP_STACK_TYPE = 0x0309, + SDP_ATTR_SECURITY_DESC = 0x030a, + SDP_ATTR_NET_ACCESS_TYPE = 0x030b, + SDP_ATTR_MAX_NET_ACCESSRATE = 0x030c, + SDP_ATTR_IP4_SUBNET = 0x030d, + SDP_ATTR_IP6_SUBNET = 0x030e, + SDP_ATTR_SUPPORTED_CAPABILITIES = 0x0310, + SDP_ATTR_SUPPORTED_FEATURES = 0x0311, + SDP_ATTR_SUPPORTED_FUNCTIONS = 0x0312, + SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY = 0x0313, + SDP_ATTR_SUPPORTED_REPOSITORIES = 0x0314, + + /* PnP Information */ + SDP_ATTR_SPECIFICATION_ID = 0x0200, + SDP_ATTR_VENDOR_ID = 0x0201, + SDP_ATTR_PRODUCT_ID = 0x0202, + SDP_ATTR_VERSION = 0x0203, + SDP_ATTR_PRIMARY_RECORD = 0x0204, + SDP_ATTR_VENDOR_ID_SOURCE = 0x0205, + + /* BT HID */ + SDP_ATTR_DEVICE_RELEASE_NUMBER = 0x0200, + SDP_ATTR_PARSER_VERSION = 0x0201, + SDP_ATTR_DEVICE_SUBCLASS = 0x0202, + SDP_ATTR_COUNTRY_CODE = 0x0203, + SDP_ATTR_VIRTUAL_CABLE = 0x0204, + SDP_ATTR_RECONNECT_INITIATE = 0x0205, + SDP_ATTR_DESCRIPTOR_LIST = 0x0206, + SDP_ATTR_LANG_ID_BASE_LIST = 0x0207, + SDP_ATTR_SDP_DISABLE = 0x0208, + SDP_ATTR_BATTERY_POWER = 0x0209, + SDP_ATTR_REMOTE_WAKEUP = 0x020a, + SDP_ATTR_PROFILE_VERSION = 0x020b, + SDP_ATTR_SUPERVISION_TIMEOUT = 0x020c, + SDP_ATTR_NORMALLY_CONNECTABLE = 0x020d, + SDP_ATTR_BOOT_DEVICE = 0x020e, +}; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/bt-hci.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/bt-hci.c --- qemu-0.9.1/hw/bt-hci.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/bt-hci.c 2008-11-09 00:28:40.000000000 +0000 @@ -0,0 +1,2222 @@ +/* + * QEMU Bluetooth HCI logic. + * + * Copyright (C) 2007 OpenMoko, Inc. + * Copyright (C) 2008 Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "qemu-common.h" +#include "qemu-timer.h" +#include "usb.h" +#include "net.h" +#include "bt.h" + +struct bt_hci_s { + uint8_t *(*evt_packet)(void *opaque); + void (*evt_submit)(void *opaque, int len); + void *opaque; + uint8_t evt_buf[256]; + + uint8_t acl_buf[4096]; + int acl_len; + + uint16_t asb_handle; + uint16_t psb_handle; + + int last_cmd; /* Note: Always little-endian */ + + struct bt_device_s *conn_req_host; + + struct { + int inquire; + int periodic; + int responses_left; + int responses; + QEMUTimer *inquiry_done; + QEMUTimer *inquiry_next; + int inquiry_length; + int inquiry_period; + int inquiry_mode; + +#define HCI_HANDLE_OFFSET 0x20 +#define HCI_HANDLES_MAX 0x10 + struct bt_hci_master_link_s { + struct bt_link_s *link; + void (*lmp_acl_data)(struct bt_link_s *link, + const uint8_t *data, int start, int len); + QEMUTimer *acl_mode_timer; + } handle[HCI_HANDLES_MAX]; + uint32_t role_bmp; + int last_handle; + int connecting; + bdaddr_t awaiting_bdaddr[HCI_HANDLES_MAX]; + } lm; + + uint8_t event_mask[8]; + uint16_t voice_setting; /* Notw: Always little-endian */ + uint16_t conn_accept_tout; + QEMUTimer *conn_accept_timer; + + struct HCIInfo info; + struct bt_device_s device; +}; + +#define DEFAULT_RSSI_DBM 20 + +#define hci_from_info(ptr) container_of((ptr), struct bt_hci_s, info) +#define hci_from_device(ptr) container_of((ptr), struct bt_hci_s, device) + +struct bt_hci_link_s { + struct bt_link_s btlink; + uint16_t handle; /* Local */ +}; + +/* LMP layer emulation */ +#if 0 +static void bt_submit_lmp(struct bt_device_s *bt, int length, uint8_t *data) +{ + int resp, resplen, error, op, tr; + uint8_t respdata[17]; + + if (length < 1) + return; + + tr = *data & 1; + op = *(data ++) >> 1; + resp = LMP_ACCEPTED; + resplen = 2; + respdata[1] = op; + error = 0; + length --; + + if (op >= 0x7c) { /* Extended opcode */ + op |= *(data ++) << 8; + resp = LMP_ACCEPTED_EXT; + resplen = 4; + respdata[0] = op >> 8; + respdata[1] = op & 0xff; + length --; + } + + switch (op) { + case LMP_ACCEPTED: + /* data[0] Op code + */ + if (length < 1) { + error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; + goto not_accepted; + } + resp = 0; + break; + + case LMP_ACCEPTED_EXT: + /* data[0] Escape op code + * data[1] Extended op code + */ + if (length < 2) { + error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; + goto not_accepted; + } + resp = 0; + break; + + case LMP_NOT_ACCEPTED: + /* data[0] Op code + * data[1] Error code + */ + if (length < 2) { + error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; + goto not_accepted; + } + resp = 0; + break; + + case LMP_NOT_ACCEPTED_EXT: + /* data[0] Op code + * data[1] Extended op code + * data[2] Error code + */ + if (length < 3) { + error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; + goto not_accepted; + } + resp = 0; + break; + + case LMP_HOST_CONNECTION_REQ: + break; + + case LMP_SETUP_COMPLETE: + resp = LMP_SETUP_COMPLETE; + resplen = 1; + bt->setup = 1; + break; + + case LMP_DETACH: + /* data[0] Error code + */ + if (length < 1) { + error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; + goto not_accepted; + } + bt->setup = 0; + resp = 0; + break; + + case LMP_SUPERVISION_TIMEOUT: + /* data[0,1] Supervision timeout + */ + if (length < 2) { + error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; + goto not_accepted; + } + resp = 0; + break; + + case LMP_QUALITY_OF_SERVICE: + resp = 0; + /* Fall through */ + case LMP_QOS_REQ: + /* data[0,1] Poll interval + * data[2] N(BC) + */ + if (length < 3) { + error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; + goto not_accepted; + } + break; + + case LMP_MAX_SLOT: + resp = 0; + /* Fall through */ + case LMP_MAX_SLOT_REQ: + /* data[0] Max slots + */ + if (length < 1) { + error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; + goto not_accepted; + } + break; + + case LMP_AU_RAND: + case LMP_IN_RAND: + case LMP_COMB_KEY: + /* data[0-15] Random number + */ + if (length < 16) { + error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; + goto not_accepted; + } + if (op == LMP_AU_RAND) { + if (bt->key_present) { + resp = LMP_SRES; + resplen = 5; + /* XXX: [Part H] Section 6.1 on page 801 */ + } else { + error = HCI_PIN_OR_KEY_MISSING; + goto not_accepted; + } + } else if (op == LMP_IN_RAND) { + error = HCI_PAIRING_NOT_ALLOWED; + goto not_accepted; + } else { + /* XXX: [Part H] Section 3.2 on page 779 */ + resp = LMP_UNIT_KEY; + resplen = 17; + memcpy(respdata + 1, bt->key, 16); + + error = HCI_UNIT_LINK_KEY_USED; + goto not_accepted; + } + break; + + case LMP_UNIT_KEY: + /* data[0-15] Key + */ + if (length < 16) { + error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; + goto not_accepted; + } + memcpy(bt->key, data, 16); + bt->key_present = 1; + break; + + case LMP_SRES: + /* data[0-3] Authentication response + */ + if (length < 4) { + error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; + goto not_accepted; + } + break; + + case LMP_CLKOFFSET_REQ: + resp = LMP_CLKOFFSET_RES; + resplen = 3; + respdata[1] = 0x33; + respdata[2] = 0x33; + break; + + case LMP_CLKOFFSET_RES: + /* data[0,1] Clock offset + * (Slave to master only) + */ + if (length < 2) { + error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; + goto not_accepted; + } + break; + + case LMP_VERSION_REQ: + case LMP_VERSION_RES: + /* data[0] VersNr + * data[1,2] CompId + * data[3,4] SubVersNr + */ + if (length < 5) { + error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; + goto not_accepted; + } + if (op == LMP_VERSION_REQ) { + resp = LMP_VERSION_RES; + resplen = 6; + respdata[1] = 0x20; + respdata[2] = 0xff; + respdata[3] = 0xff; + respdata[4] = 0xff; + respdata[5] = 0xff; + } else + resp = 0; + break; + + case LMP_FEATURES_REQ: + case LMP_FEATURES_RES: + /* data[0-7] Features + */ + if (length < 8) { + error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; + goto not_accepted; + } + if (op == LMP_FEATURES_REQ) { + resp = LMP_FEATURES_RES; + resplen = 9; + respdata[1] = (bt->lmp_caps >> 0) & 0xff; + respdata[2] = (bt->lmp_caps >> 8) & 0xff; + respdata[3] = (bt->lmp_caps >> 16) & 0xff; + respdata[4] = (bt->lmp_caps >> 24) & 0xff; + respdata[5] = (bt->lmp_caps >> 32) & 0xff; + respdata[6] = (bt->lmp_caps >> 40) & 0xff; + respdata[7] = (bt->lmp_caps >> 48) & 0xff; + respdata[8] = (bt->lmp_caps >> 56) & 0xff; + } else + resp = 0; + break; + + case LMP_NAME_REQ: + /* data[0] Name offset + */ + if (length < 1) { + error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; + goto not_accepted; + } + resp = LMP_NAME_RES; + resplen = 17; + respdata[1] = data[0]; + respdata[2] = strlen(bt->lmp_name); + memset(respdata + 3, 0x00, 14); + if (respdata[2] > respdata[1]) + memcpy(respdata + 3, bt->lmp_name + respdata[1], + respdata[2] - respdata[1]); + break; + + case LMP_NAME_RES: + /* data[0] Name offset + * data[1] Name length + * data[2-15] Name fragment + */ + if (length < 16) { + error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; + goto not_accepted; + } + resp = 0; + break; + + default: + error = HCI_UNKNOWN_LMP_PDU; + /* Fall through */ + not_accepted: + if (op >> 8) { + resp = LMP_NOT_ACCEPTED_EXT; + resplen = 5; + respdata[0] = op >> 8; + respdata[1] = op & 0xff; + respdata[2] = error; + } else { + resp = LMP_NOT_ACCEPTED; + resplen = 3; + respdata[0] = op & 0xff; + respdata[1] = error; + } + } + + if (resp == 0) + return; + + if (resp >> 8) { + respdata[0] = resp >> 8; + respdata[1] = resp & 0xff; + } else + respdata[0] = resp & 0xff; + + respdata[0] <<= 1; + respdata[0] |= tr; +} + +static void bt_submit_raw_acl(struct bt_piconet_s *net, int length, uint8_t *data) +{ + struct bt_device_s *slave; + if (length < 1) + return; + + slave = 0; +#if 0 + slave = net->slave; +#endif + + switch (data[0] & 3) { + case LLID_ACLC: + bt_submit_lmp(slave, length - 1, data + 1); + break; + case LLID_ACLU_START: +#if 0 + bt_sumbit_l2cap(slave, length - 1, data + 1, (data[0] >> 2) & 1); + breka; +#endif + default: + case LLID_ACLU_CONT: + break; + } +} +#endif + +/* HCI layer emulation */ + +/* Note: we could ignore endiannes because unswapped handles will still + * be valid as connection identifiers for the guest - they don't have to + * be continuously allocated. We do it though, to preserve similar + * behaviour between hosts. Some things, like the BD_ADDR cannot be + * preserved though (for example if a real hci is used). */ +#ifdef WORDS_BIGENDIAN +# define HNDL(raw) bswap16(raw) +#else +# define HNDL(raw) (raw) +#endif + +static const uint8_t bt_event_reserved_mask[8] = { + 0xff, 0x9f, 0xfb, 0xff, 0x07, 0x18, 0x00, 0x00, +}; + +static inline uint8_t *bt_hci_event_start(struct bt_hci_s *hci, + int evt, int len) +{ + uint8_t *packet, mask; + int mask_byte; + + if (len > 255) { + fprintf(stderr, "%s: HCI event params too long (%ib)\n", + __FUNCTION__, len); + exit(-1); + } + + mask_byte = (evt - 1) >> 3; + mask = 1 << ((evt - 1) & 3); + if (mask & bt_event_reserved_mask[mask_byte] & ~hci->event_mask[mask_byte]) + return 0; + + packet = hci->evt_packet(hci->opaque); + packet[0] = evt; + packet[1] = len; + + return &packet[2]; +} + +static inline void bt_hci_event(struct bt_hci_s *hci, int evt, + void *params, int len) +{ + uint8_t *packet = bt_hci_event_start(hci, evt, len); + + if (!packet) + return; + + if (len) + memcpy(packet, params, len); + + hci->evt_submit(hci->opaque, len + 2); +} + +static inline void bt_hci_event_status(struct bt_hci_s *hci, int status) +{ + evt_cmd_status params = { + .status = status, + .ncmd = 1, + .opcode = hci->last_cmd, + }; + + bt_hci_event(hci, EVT_CMD_STATUS, ¶ms, EVT_CMD_STATUS_SIZE); +} + +static inline void bt_hci_event_complete(struct bt_hci_s *hci, + void *ret, int len) +{ + uint8_t *packet = bt_hci_event_start(hci, EVT_CMD_COMPLETE, + len + EVT_CMD_COMPLETE_SIZE); + evt_cmd_complete *params = (evt_cmd_complete *) packet; + + if (!packet) + return; + + params->ncmd = 1; + params->opcode = hci->last_cmd; + if (len) + memcpy(&packet[EVT_CMD_COMPLETE_SIZE], ret, len); + + hci->evt_submit(hci->opaque, len + EVT_CMD_COMPLETE_SIZE + 2); +} + +static void bt_hci_inquiry_done(void *opaque) +{ + struct bt_hci_s *hci = (struct bt_hci_s *) opaque; + uint8_t status = HCI_SUCCESS; + + if (!hci->lm.periodic) + hci->lm.inquire = 0; + + /* The specification is inconsistent about this one. Page 565 reads + * "The event parameters of Inquiry Complete event will have a summary + * of the result from the Inquiry process, which reports the number of + * nearby Bluetooth devices that responded [so hci->responses].", but + * Event Parameters (see page 729) has only Status. */ + bt_hci_event(hci, EVT_INQUIRY_COMPLETE, &status, 1); +} + +static void bt_hci_inquiry_result_standard(struct bt_hci_s *hci, + struct bt_device_s *slave) +{ + inquiry_info params = { + .num_responses = 1, + .bdaddr = BAINIT(&slave->bd_addr), + .pscan_rep_mode = 0x00, /* R0 */ + .pscan_period_mode = 0x00, /* P0 - deprecated */ + .pscan_mode = 0x00, /* Standard scan - deprecated */ + .dev_class[0] = slave->class[0], + .dev_class[1] = slave->class[1], + .dev_class[2] = slave->class[2], + /* TODO: return the clkoff *differenece* */ + .clock_offset = slave->clkoff, /* Note: no swapping */ + }; + + bt_hci_event(hci, EVT_INQUIRY_RESULT, ¶ms, INQUIRY_INFO_SIZE); +} + +static void bt_hci_inquiry_result_with_rssi(struct bt_hci_s *hci, + struct bt_device_s *slave) +{ + inquiry_info_with_rssi params = { + .num_responses = 1, + .bdaddr = BAINIT(&slave->bd_addr), + .pscan_rep_mode = 0x00, /* R0 */ + .pscan_period_mode = 0x00, /* P0 - deprecated */ + .dev_class[0] = slave->class[0], + .dev_class[1] = slave->class[1], + .dev_class[2] = slave->class[2], + /* TODO: return the clkoff *differenece* */ + .clock_offset = slave->clkoff, /* Note: no swapping */ + .rssi = DEFAULT_RSSI_DBM, + }; + + bt_hci_event(hci, EVT_INQUIRY_RESULT_WITH_RSSI, + ¶ms, INQUIRY_INFO_WITH_RSSI_SIZE); +} + +static void bt_hci_inquiry_result(struct bt_hci_s *hci, + struct bt_device_s *slave) +{ + if (!slave->inquiry_scan || !hci->lm.responses_left) + return; + + hci->lm.responses_left --; + hci->lm.responses ++; + + switch (hci->lm.inquiry_mode) { + case 0x00: + return bt_hci_inquiry_result_standard(hci, slave); + case 0x01: + return bt_hci_inquiry_result_with_rssi(hci, slave); + default: + fprintf(stderr, "%s: bad inquiry mode %02x\n", __FUNCTION__, + hci->lm.inquiry_mode); + exit(-1); + } +} + +static void bt_hci_mod_timer_1280ms(QEMUTimer *timer, int period) +{ + qemu_mod_timer(timer, qemu_get_clock(vm_clock) + + muldiv64(period << 7, ticks_per_sec, 100)); +} + +static void bt_hci_inquiry_start(struct bt_hci_s *hci, int length) +{ + struct bt_device_s *slave; + + hci->lm.inquiry_length = length; + for (slave = hci->device.net->slave; slave; slave = slave->next) + /* Don't uncover ourselves. */ + if (slave != &hci->device) + bt_hci_inquiry_result(hci, slave); + + /* TODO: register for a callback on a new device's addition to the + * scatternet so that if it's added before inquiry_length expires, + * an Inquiry Result is generated immediately. Alternatively re-loop + * through the devices on the inquiry_length expiration and report + * devices not seen before. */ + if (hci->lm.responses_left) + bt_hci_mod_timer_1280ms(hci->lm.inquiry_done, hci->lm.inquiry_length); + else + bt_hci_inquiry_done(hci); + + if (hci->lm.periodic) + bt_hci_mod_timer_1280ms(hci->lm.inquiry_next, hci->lm.inquiry_period); +} + +static void bt_hci_inquiry_next(void *opaque) +{ + struct bt_hci_s *hci = (struct bt_hci_s *) opaque; + + hci->lm.responses_left += hci->lm.responses; + hci->lm.responses = 0; + bt_hci_inquiry_start(hci, hci->lm.inquiry_length); +} + +static inline int bt_hci_handle_bad(struct bt_hci_s *hci, uint16_t handle) +{ + return !(handle & HCI_HANDLE_OFFSET) || + handle >= (HCI_HANDLE_OFFSET | HCI_HANDLES_MAX) || + !hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link; +} + +static inline int bt_hci_role_master(struct bt_hci_s *hci, uint16_t handle) +{ + return !!(hci->lm.role_bmp & (1 << (handle & ~HCI_HANDLE_OFFSET))); +} + +static inline struct bt_device_s *bt_hci_remote_dev(struct bt_hci_s *hci, + uint16_t handle) +{ + struct bt_link_s *link = hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link; + + return bt_hci_role_master(hci, handle) ? link->slave : link->host; +} + +static void bt_hci_mode_tick(void *opaque); +static void bt_hci_lmp_link_establish(struct bt_hci_s *hci, + struct bt_link_s *link, int master) +{ + hci->lm.handle[hci->lm.last_handle].link = link; + + if (master) { + /* We are the master side of an ACL link */ + hci->lm.role_bmp |= 1 << hci->lm.last_handle; + + hci->lm.handle[hci->lm.last_handle].lmp_acl_data = + link->slave->lmp_acl_data; + } else { + /* We are the slave side of an ACL link */ + hci->lm.role_bmp &= ~(1 << hci->lm.last_handle); + + hci->lm.handle[hci->lm.last_handle].lmp_acl_data = + link->host->lmp_acl_resp; + } + + /* Mode */ + if (master) { + link->acl_mode = acl_active; + hci->lm.handle[hci->lm.last_handle].acl_mode_timer = + qemu_new_timer(vm_clock, bt_hci_mode_tick, link); + } +} + +static void bt_hci_lmp_link_teardown(struct bt_hci_s *hci, uint16_t handle) +{ + handle &= ~HCI_HANDLE_OFFSET; + hci->lm.handle[handle].link = 0; + + if (bt_hci_role_master(hci, handle)) { + qemu_del_timer(hci->lm.handle[handle].acl_mode_timer); + qemu_free_timer(hci->lm.handle[handle].acl_mode_timer); + } +} + +static int bt_hci_connect(struct bt_hci_s *hci, bdaddr_t *bdaddr) +{ + struct bt_device_s *slave; + struct bt_link_s link; + + for (slave = hci->device.net->slave; slave; slave = slave->next) + if (slave->page_scan && !bacmp(&slave->bd_addr, bdaddr)) + break; + if (!slave || slave == &hci->device) + return -ENODEV; + + bacpy(&hci->lm.awaiting_bdaddr[hci->lm.connecting ++], &slave->bd_addr); + + link.slave = slave; + link.host = &hci->device; + link.slave->lmp_connection_request(&link); /* Always last */ + + return 0; +} + +static void bt_hci_connection_reject(struct bt_hci_s *hci, + struct bt_device_s *host, uint8_t because) +{ + struct bt_link_s link = { + .slave = &hci->device, + .host = host, + /* Rest uninitialised */ + }; + + host->reject_reason = because; + host->lmp_connection_complete(&link); +} + +static void bt_hci_connection_reject_event(struct bt_hci_s *hci, + bdaddr_t *bdaddr) +{ + evt_conn_complete params; + + params.status = HCI_NO_CONNECTION; + params.handle = 0; + bacpy(¶ms.bdaddr, bdaddr); + params.link_type = ACL_LINK; + params.encr_mode = 0x00; /* Encryption not required */ + bt_hci_event(hci, EVT_CONN_COMPLETE, ¶ms, EVT_CONN_COMPLETE_SIZE); +} + +static void bt_hci_connection_accept(struct bt_hci_s *hci, + struct bt_device_s *host) +{ + struct bt_hci_link_s *link = qemu_mallocz(sizeof(struct bt_hci_link_s)); + evt_conn_complete params; + uint16_t handle; + uint8_t status = HCI_SUCCESS; + int tries = HCI_HANDLES_MAX; + + /* Make a connection handle */ + do { + while (hci->lm.handle[++ hci->lm.last_handle].link && -- tries) + hci->lm.last_handle &= HCI_HANDLES_MAX - 1; + handle = hci->lm.last_handle | HCI_HANDLE_OFFSET; + } while ((handle == hci->asb_handle || handle == hci->psb_handle) && + tries); + + if (!tries) { + qemu_free(link); + bt_hci_connection_reject(hci, host, HCI_REJECTED_LIMITED_RESOURCES); + status = HCI_NO_CONNECTION; + goto complete; + } + + link->btlink.slave = &hci->device; + link->btlink.host = host; + link->handle = handle; + + /* Link established */ + bt_hci_lmp_link_establish(hci, &link->btlink, 0); + +complete: + params.status = status; + params.handle = HNDL(handle); + bacpy(¶ms.bdaddr, &host->bd_addr); + params.link_type = ACL_LINK; + params.encr_mode = 0x00; /* Encryption not required */ + bt_hci_event(hci, EVT_CONN_COMPLETE, ¶ms, EVT_CONN_COMPLETE_SIZE); + + /* Neets to be done at the very end because it can trigger a (nested) + * disconnected, in case the other and had cancelled the request + * locally. */ + if (status == HCI_SUCCESS) { + host->reject_reason = 0; + host->lmp_connection_complete(&link->btlink); + } +} + +static void bt_hci_lmp_connection_request(struct bt_link_s *link) +{ + struct bt_hci_s *hci = hci_from_device(link->slave); + evt_conn_request params; + + if (hci->conn_req_host) + return bt_hci_connection_reject(hci, link->host, + HCI_REJECTED_LIMITED_RESOURCES); + hci->conn_req_host = link->host; + /* TODO: if masked and auto-accept, then auto-accept, + * if masked and not auto-accept, then auto-reject */ + /* TODO: kick the hci->conn_accept_timer, timeout after + * hci->conn_accept_tout * 0.625 msec */ + + bacpy(¶ms.bdaddr, &link->host->bd_addr); + memcpy(¶ms.dev_class, &link->host->class, sizeof(params.dev_class)); + params.link_type = ACL_LINK; + bt_hci_event(hci, EVT_CONN_REQUEST, ¶ms, EVT_CONN_REQUEST_SIZE); + return; +} + +static void bt_hci_conn_accept_timeout(void *opaque) +{ + struct bt_hci_s *hci = (struct bt_hci_s *) opaque; + + if (!hci->conn_req_host) + /* Already accepted or rejected. If the other end cancelled the + * connection request then we still have to reject or accept it + * and then we'll get a disconnect. */ + return; + + /* TODO */ +} + +/* Remove from the list of devices which we wanted to connect to and + * are awaiting a response from. If the callback sees a response from + * a device which is not on the list it will assume it's a connection + * that's been cancelled by the host in the meantime and immediately + * try to detach the link and send a Connection Complete. */ +static int bt_hci_lmp_connection_ready(struct bt_hci_s *hci, + bdaddr_t *bdaddr) +{ + int i; + + for (i = 0; i < hci->lm.connecting; i ++) + if (!bacmp(&hci->lm.awaiting_bdaddr[i], bdaddr)) { + if (i < -- hci->lm.connecting) + bacpy(&hci->lm.awaiting_bdaddr[i], + &hci->lm.awaiting_bdaddr[hci->lm.connecting]); + return 0; + } + + return 1; +} + +static void bt_hci_lmp_connection_complete(struct bt_link_s *link) +{ + struct bt_hci_s *hci = hci_from_device(link->host); + evt_conn_complete params; + uint16_t handle; + uint8_t status = HCI_SUCCESS; + int tries = HCI_HANDLES_MAX; + + if (bt_hci_lmp_connection_ready(hci, &link->slave->bd_addr)) { + if (!hci->device.reject_reason) + link->slave->lmp_disconnect_slave(link); + handle = 0; + status = HCI_NO_CONNECTION; + goto complete; + } + + if (hci->device.reject_reason) { + handle = 0; + status = hci->device.reject_reason; + goto complete; + } + + /* Make a connection handle */ + do { + while (hci->lm.handle[++ hci->lm.last_handle].link && -- tries) + hci->lm.last_handle &= HCI_HANDLES_MAX - 1; + handle = hci->lm.last_handle | HCI_HANDLE_OFFSET; + } while ((handle == hci->asb_handle || handle == hci->psb_handle) && + tries); + + if (!tries) { + link->slave->lmp_disconnect_slave(link); + status = HCI_NO_CONNECTION; + goto complete; + } + + /* Link established */ + link->handle = handle; + bt_hci_lmp_link_establish(hci, link, 1); + +complete: + params.status = status; + params.handle = HNDL(handle); + params.link_type = ACL_LINK; + bacpy(¶ms.bdaddr, &link->slave->bd_addr); + params.encr_mode = 0x00; /* Encryption not required */ + bt_hci_event(hci, EVT_CONN_COMPLETE, ¶ms, EVT_CONN_COMPLETE_SIZE); +} + +static void bt_hci_disconnect(struct bt_hci_s *hci, + uint16_t handle, int reason) +{ + struct bt_link_s *btlink = + hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link; + struct bt_hci_link_s *link; + evt_disconn_complete params; + + if (bt_hci_role_master(hci, handle)) { + btlink->slave->reject_reason = reason; + btlink->slave->lmp_disconnect_slave(btlink); + /* The link pointer is invalid from now on */ + + goto complete; + } + + btlink->host->reject_reason = reason; + btlink->host->lmp_disconnect_master(btlink); + + /* We are the slave, we get to clean this burden */ + link = (struct bt_hci_link_s *) btlink; + qemu_free(link); + +complete: + bt_hci_lmp_link_teardown(hci, handle); + + params.status = HCI_SUCCESS; + params.handle = HNDL(handle); + params.reason = HCI_CONNECTION_TERMINATED; + bt_hci_event(hci, EVT_DISCONN_COMPLETE, + ¶ms, EVT_DISCONN_COMPLETE_SIZE); +} + +/* TODO: use only one function */ +static void bt_hci_lmp_disconnect_host(struct bt_link_s *link) +{ + struct bt_hci_s *hci = hci_from_device(link->host); + uint16_t handle = link->handle; + evt_disconn_complete params; + + bt_hci_lmp_link_teardown(hci, handle); + + params.status = HCI_SUCCESS; + params.handle = HNDL(handle); + params.reason = hci->device.reject_reason; + bt_hci_event(hci, EVT_DISCONN_COMPLETE, + ¶ms, EVT_DISCONN_COMPLETE_SIZE); +} + +static void bt_hci_lmp_disconnect_slave(struct bt_link_s *btlink) +{ + struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink; + struct bt_hci_s *hci = hci_from_device(btlink->slave); + uint16_t handle = link->handle; + evt_disconn_complete params; + + qemu_free(link); + + bt_hci_lmp_link_teardown(hci, handle); + + params.status = HCI_SUCCESS; + params.handle = HNDL(handle); + params.reason = hci->device.reject_reason; + bt_hci_event(hci, EVT_DISCONN_COMPLETE, + ¶ms, EVT_DISCONN_COMPLETE_SIZE); +} + +static int bt_hci_name_req(struct bt_hci_s *hci, bdaddr_t *bdaddr) +{ + struct bt_device_s *slave; + evt_remote_name_req_complete params; + int len; + + for (slave = hci->device.net->slave; slave; slave = slave->next) + if (slave->page_scan && !bacmp(&slave->bd_addr, bdaddr)) + break; + if (!slave) + return -ENODEV; + + bt_hci_event_status(hci, HCI_SUCCESS); + + params.status = HCI_SUCCESS; + bacpy(¶ms.bdaddr, &slave->bd_addr); + len = snprintf(params.name, sizeof(params.name), + "%s", slave->lmp_name ?: ""); + memset(params.name + len, 0, sizeof(params.name) - len); + bt_hci_event(hci, EVT_REMOTE_NAME_REQ_COMPLETE, + ¶ms, EVT_REMOTE_NAME_REQ_COMPLETE_SIZE); + + return 0; +} + +static int bt_hci_features_req(struct bt_hci_s *hci, uint16_t handle) +{ + struct bt_device_s *slave; + evt_read_remote_features_complete params; + + if (bt_hci_handle_bad(hci, handle)) + return -ENODEV; + + slave = bt_hci_remote_dev(hci, handle); + + bt_hci_event_status(hci, HCI_SUCCESS); + + params.status = HCI_SUCCESS; + params.handle = HNDL(handle); + params.features[0] = (slave->lmp_caps >> 0) & 0xff; + params.features[1] = (slave->lmp_caps >> 8) & 0xff; + params.features[2] = (slave->lmp_caps >> 16) & 0xff; + params.features[3] = (slave->lmp_caps >> 24) & 0xff; + params.features[4] = (slave->lmp_caps >> 32) & 0xff; + params.features[5] = (slave->lmp_caps >> 40) & 0xff; + params.features[6] = (slave->lmp_caps >> 48) & 0xff; + params.features[7] = (slave->lmp_caps >> 56) & 0xff; + bt_hci_event(hci, EVT_READ_REMOTE_FEATURES_COMPLETE, + ¶ms, EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE); + + return 0; +} + +static int bt_hci_version_req(struct bt_hci_s *hci, uint16_t handle) +{ + struct bt_device_s *slave; + evt_read_remote_version_complete params; + + if (bt_hci_handle_bad(hci, handle)) + return -ENODEV; + + slave = bt_hci_remote_dev(hci, handle); + + bt_hci_event_status(hci, HCI_SUCCESS); + + params.status = HCI_SUCCESS; + params.handle = HNDL(handle); + params.lmp_ver = 0x03; + params.manufacturer = cpu_to_le16(0xa000); + params.lmp_subver = cpu_to_le16(0xa607); + bt_hci_event(hci, EVT_READ_REMOTE_VERSION_COMPLETE, + ¶ms, EVT_READ_REMOTE_VERSION_COMPLETE_SIZE); + + return 0; +} + +static int bt_hci_clkoffset_req(struct bt_hci_s *hci, uint16_t handle) +{ + struct bt_device_s *slave; + evt_read_clock_offset_complete params; + + if (bt_hci_handle_bad(hci, handle)) + return -ENODEV; + + slave = bt_hci_remote_dev(hci, handle); + + bt_hci_event_status(hci, HCI_SUCCESS); + + params.status = HCI_SUCCESS; + params.handle = HNDL(handle); + /* TODO: return the clkoff *differenece* */ + params.clock_offset = slave->clkoff; /* Note: no swapping */ + bt_hci_event(hci, EVT_READ_CLOCK_OFFSET_COMPLETE, + ¶ms, EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE); + + return 0; +} + +static void bt_hci_event_mode(struct bt_hci_s *hci, struct bt_link_s *link, + uint16_t handle) +{ + evt_mode_change params = { + .status = HCI_SUCCESS, + .handle = HNDL(handle), + .mode = link->acl_mode, + .interval = cpu_to_le16(link->acl_interval), + }; + + bt_hci_event(hci, EVT_MODE_CHANGE, ¶ms, EVT_MODE_CHANGE_SIZE); +} + +static void bt_hci_lmp_mode_change_master(struct bt_hci_s *hci, + struct bt_link_s *link, int mode, uint16_t interval) +{ + link->acl_mode = mode; + link->acl_interval = interval; + + bt_hci_event_mode(hci, link, link->handle); + + link->slave->lmp_mode_change(link); +} + +static void bt_hci_lmp_mode_change_slave(struct bt_link_s *btlink) +{ + struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink; + struct bt_hci_s *hci = hci_from_device(btlink->slave); + + bt_hci_event_mode(hci, btlink, link->handle); +} + +static int bt_hci_mode_change(struct bt_hci_s *hci, uint16_t handle, + int interval, int mode) +{ + struct bt_hci_master_link_s *link; + + if (bt_hci_handle_bad(hci, handle) || !bt_hci_role_master(hci, handle)) + return -ENODEV; + + link = &hci->lm.handle[handle & ~HCI_HANDLE_OFFSET]; + if (link->link->acl_mode != acl_active) { + bt_hci_event_status(hci, HCI_COMMAND_DISALLOWED); + return 0; + } + + bt_hci_event_status(hci, HCI_SUCCESS); + + qemu_mod_timer(link->acl_mode_timer, qemu_get_clock(vm_clock) + + muldiv64(interval * 625, ticks_per_sec, 1000000)); + bt_hci_lmp_mode_change_master(hci, link->link, mode, interval); + + return 0; +} + +static int bt_hci_mode_cancel(struct bt_hci_s *hci, uint16_t handle, int mode) +{ + struct bt_hci_master_link_s *link; + + if (bt_hci_handle_bad(hci, handle) || !bt_hci_role_master(hci, handle)) + return -ENODEV; + + link = &hci->lm.handle[handle & ~HCI_HANDLE_OFFSET]; + if (link->link->acl_mode != mode) { + bt_hci_event_status(hci, HCI_COMMAND_DISALLOWED); + + return 0; + } + + bt_hci_event_status(hci, HCI_SUCCESS); + + qemu_del_timer(link->acl_mode_timer); + bt_hci_lmp_mode_change_master(hci, link->link, acl_active, 0); + + return 0; +} + +static void bt_hci_mode_tick(void *opaque) +{ + struct bt_link_s *link = opaque; + struct bt_hci_s *hci = hci_from_device(link->host); + + bt_hci_lmp_mode_change_master(hci, link, acl_active, 0); +} + +static void bt_hci_reset(struct bt_hci_s *hci) +{ + hci->acl_len = 0; + hci->last_cmd = 0; + hci->lm.connecting = 0; + + hci->event_mask[0] = 0xff; + hci->event_mask[1] = 0xff; + hci->event_mask[2] = 0xff; + hci->event_mask[3] = 0xff; + hci->event_mask[4] = 0xff; + hci->event_mask[5] = 0x1f; + hci->event_mask[6] = 0x00; + hci->event_mask[7] = 0x00; + hci->device.inquiry_scan = 0; + hci->device.page_scan = 0; + if (hci->device.lmp_name) + qemu_free((void *) hci->device.lmp_name); + hci->device.lmp_name = 0; + hci->device.class[0] = 0x00; + hci->device.class[1] = 0x00; + hci->device.class[2] = 0x00; + hci->voice_setting = 0x0000; + hci->conn_accept_tout = 0x1f40; + hci->lm.inquiry_mode = 0x00; + + hci->psb_handle = 0x000; + hci->asb_handle = 0x000; + + /* XXX: qemu_del_timer(sl->acl_mode_timer); for all links */ + qemu_del_timer(hci->lm.inquiry_done); + qemu_del_timer(hci->lm.inquiry_next); + qemu_del_timer(hci->conn_accept_timer); +} + +static void bt_hci_read_local_version_rp(struct bt_hci_s *hci) +{ + read_local_version_rp lv = { + .status = HCI_SUCCESS, + .hci_ver = 0x03, + .hci_rev = cpu_to_le16(0xa607), + .lmp_ver = 0x03, + .manufacturer = cpu_to_le16(0xa000), + .lmp_subver = cpu_to_le16(0xa607), + }; + + bt_hci_event_complete(hci, &lv, READ_LOCAL_VERSION_RP_SIZE); +} + +static void bt_hci_read_local_commands_rp(struct bt_hci_s *hci) +{ + read_local_commands_rp lc = { + .status = HCI_SUCCESS, + .commands = { + /* Keep updated! */ + /* Also, keep in sync with hci->device.lmp_caps in bt_new_hci */ + 0xbf, 0x80, 0xf9, 0x03, 0xb2, 0xc0, 0x03, 0xc3, + 0x00, 0x0f, 0x80, 0x00, 0xc0, 0x00, 0xe8, 0x13, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }; + + bt_hci_event_complete(hci, &lc, READ_LOCAL_COMMANDS_RP_SIZE); +} + +static void bt_hci_read_local_features_rp(struct bt_hci_s *hci) +{ + read_local_features_rp lf = { + .status = HCI_SUCCESS, + .features = { + (hci->device.lmp_caps >> 0) & 0xff, + (hci->device.lmp_caps >> 8) & 0xff, + (hci->device.lmp_caps >> 16) & 0xff, + (hci->device.lmp_caps >> 24) & 0xff, + (hci->device.lmp_caps >> 32) & 0xff, + (hci->device.lmp_caps >> 40) & 0xff, + (hci->device.lmp_caps >> 48) & 0xff, + (hci->device.lmp_caps >> 56) & 0xff, + }, + }; + + bt_hci_event_complete(hci, &lf, READ_LOCAL_FEATURES_RP_SIZE); +} + +static void bt_hci_read_local_ext_features_rp(struct bt_hci_s *hci, int page) +{ + read_local_ext_features_rp lef = { + .status = HCI_SUCCESS, + .page_num = page, + .max_page_num = 0x00, + .features = { + /* Keep updated! */ + 0x5f, 0x35, 0x85, 0x7e, 0x9b, 0x19, 0x00, 0x80, + }, + }; + if (page) + memset(lef.features, 0, sizeof(lef.features)); + + bt_hci_event_complete(hci, &lef, READ_LOCAL_EXT_FEATURES_RP_SIZE); +} + +static void bt_hci_read_buffer_size_rp(struct bt_hci_s *hci) +{ + read_buffer_size_rp bs = { + /* This can be made configurable, for one standard USB dongle HCI + * the four values are cpu_to_le16(0x0180), 0x40, + * cpu_to_le16(0x0008), cpu_to_le16(0x0008). */ + .status = HCI_SUCCESS, + .acl_mtu = cpu_to_le16(0x0200), + .sco_mtu = 0, + .acl_max_pkt = cpu_to_le16(0x0001), + .sco_max_pkt = cpu_to_le16(0x0000), + }; + + bt_hci_event_complete(hci, &bs, READ_BUFFER_SIZE_RP_SIZE); +} + +/* Deprecated in V2.0 (page 661) */ +static void bt_hci_read_country_code_rp(struct bt_hci_s *hci) +{ + read_country_code_rp cc ={ + .status = HCI_SUCCESS, + .country_code = 0x00, /* North America & Europe^1 and Japan */ + }; + + bt_hci_event_complete(hci, &cc, READ_COUNTRY_CODE_RP_SIZE); + + /* ^1. Except France, sorry */ +} + +static void bt_hci_read_bd_addr_rp(struct bt_hci_s *hci) +{ + read_bd_addr_rp ba = { + .status = HCI_SUCCESS, + .bdaddr = BAINIT(&hci->device.bd_addr), + }; + + bt_hci_event_complete(hci, &ba, READ_BD_ADDR_RP_SIZE); +} + +static int bt_hci_link_quality_rp(struct bt_hci_s *hci, uint16_t handle) +{ + read_link_quality_rp lq = { + .status = HCI_SUCCESS, + .handle = HNDL(handle), + .link_quality = 0xff, + }; + + if (bt_hci_handle_bad(hci, handle)) + lq.status = HCI_NO_CONNECTION; + + bt_hci_event_complete(hci, &lq, READ_LINK_QUALITY_RP_SIZE); + return 0; +} + +/* Generate a Command Complete event with only the Status parameter */ +static inline void bt_hci_event_complete_status(struct bt_hci_s *hci, + uint8_t status) +{ + bt_hci_event_complete(hci, &status, 1); +} + +static inline void bt_hci_event_complete_conn_cancel(struct bt_hci_s *hci, + uint8_t status, bdaddr_t *bd_addr) +{ + create_conn_cancel_rp params = { + .status = status, + .bdaddr = BAINIT(bd_addr), + }; + + bt_hci_event_complete(hci, ¶ms, CREATE_CONN_CANCEL_RP_SIZE); +} + +static inline void bt_hci_event_auth_complete(struct bt_hci_s *hci, + uint16_t handle) +{ + evt_auth_complete params = { + .status = HCI_SUCCESS, + .handle = HNDL(handle), + }; + + bt_hci_event(hci, EVT_AUTH_COMPLETE, ¶ms, EVT_AUTH_COMPLETE_SIZE); +} + +static inline void bt_hci_event_encrypt_change(struct bt_hci_s *hci, + uint16_t handle, uint8_t mode) +{ + evt_encrypt_change params = { + .status = HCI_SUCCESS, + .handle = HNDL(handle), + .encrypt = mode, + }; + + bt_hci_event(hci, EVT_ENCRYPT_CHANGE, ¶ms, EVT_ENCRYPT_CHANGE_SIZE); +} + +static inline void bt_hci_event_complete_name_cancel(struct bt_hci_s *hci, + bdaddr_t *bd_addr) +{ + remote_name_req_cancel_rp params = { + .status = HCI_INVALID_PARAMETERS, + .bdaddr = BAINIT(bd_addr), + }; + + bt_hci_event_complete(hci, ¶ms, REMOTE_NAME_REQ_CANCEL_RP_SIZE); +} + +static inline void bt_hci_event_read_remote_ext_features(struct bt_hci_s *hci, + uint16_t handle) +{ + evt_read_remote_ext_features_complete params = { + .status = HCI_UNSUPPORTED_FEATURE, + .handle = HNDL(handle), + /* Rest uninitialised */ + }; + + bt_hci_event(hci, EVT_READ_REMOTE_EXT_FEATURES_COMPLETE, + ¶ms, EVT_READ_REMOTE_EXT_FEATURES_COMPLETE_SIZE); +} + +static inline void bt_hci_event_complete_lmp_handle(struct bt_hci_s *hci, + uint16_t handle) +{ + read_lmp_handle_rp params = { + .status = HCI_NO_CONNECTION, + .handle = HNDL(handle), + .reserved = 0, + /* Rest uninitialised */ + }; + + bt_hci_event_complete(hci, ¶ms, READ_LMP_HANDLE_RP_SIZE); +} + +static inline void bt_hci_event_complete_role_discovery(struct bt_hci_s *hci, + int status, uint16_t handle, int master) +{ + role_discovery_rp params = { + .status = status, + .handle = HNDL(handle), + .role = master ? 0x00 : 0x01, + }; + + bt_hci_event_complete(hci, ¶ms, ROLE_DISCOVERY_RP_SIZE); +} + +static inline void bt_hci_event_complete_flush(struct bt_hci_s *hci, + int status, uint16_t handle) +{ + flush_rp params = { + .status = status, + .handle = HNDL(handle), + }; + + bt_hci_event_complete(hci, ¶ms, FLUSH_RP_SIZE); +} + +static inline void bt_hci_event_complete_read_local_name(struct bt_hci_s *hci) +{ + read_local_name_rp params; + params.status = HCI_SUCCESS; + memset(params.name, 0, sizeof(params.name)); + if (hci->device.lmp_name) + strncpy(params.name, hci->device.lmp_name, sizeof(params.name)); + + bt_hci_event_complete(hci, ¶ms, READ_LOCAL_NAME_RP_SIZE); +} + +static inline void bt_hci_event_complete_read_conn_accept_timeout( + struct bt_hci_s *hci) +{ + read_conn_accept_timeout_rp params = { + .status = HCI_SUCCESS, + .timeout = cpu_to_le16(hci->conn_accept_tout), + }; + + bt_hci_event_complete(hci, ¶ms, READ_CONN_ACCEPT_TIMEOUT_RP_SIZE); +} + +static inline void bt_hci_event_complete_read_scan_enable(struct bt_hci_s *hci) +{ + read_scan_enable_rp params = { + .status = HCI_SUCCESS, + .enable = + (hci->device.inquiry_scan ? SCAN_INQUIRY : 0) | + (hci->device.page_scan ? SCAN_PAGE : 0), + }; + + bt_hci_event_complete(hci, ¶ms, READ_SCAN_ENABLE_RP_SIZE); +} + +static inline void bt_hci_event_complete_read_local_class(struct bt_hci_s *hci) +{ + read_class_of_dev_rp params; + + params.status = HCI_SUCCESS; + memcpy(params.dev_class, hci->device.class, sizeof(params.dev_class)); + + bt_hci_event_complete(hci, ¶ms, READ_CLASS_OF_DEV_RP_SIZE); +} + +static inline void bt_hci_event_complete_voice_setting(struct bt_hci_s *hci) +{ + read_voice_setting_rp params = { + .status = HCI_SUCCESS, + .voice_setting = hci->voice_setting, /* Note: no swapping */ + }; + + bt_hci_event_complete(hci, ¶ms, READ_VOICE_SETTING_RP_SIZE); +} + +static inline void bt_hci_event_complete_read_inquiry_mode( + struct bt_hci_s *hci) +{ + read_inquiry_mode_rp params = { + .status = HCI_SUCCESS, + .mode = hci->lm.inquiry_mode, + }; + + bt_hci_event_complete(hci, ¶ms, READ_INQUIRY_MODE_RP_SIZE); +} + +static inline void bt_hci_event_num_comp_pkts(struct bt_hci_s *hci, + uint16_t handle, int packets) +{ + uint16_t buf[EVT_NUM_COMP_PKTS_SIZE(1) / 2 + 1]; + evt_num_comp_pkts *params = (void *) ((uint8_t *) buf + 1); + + params->num_hndl = 1; + params->connection->handle = HNDL(handle); + params->connection->num_packets = cpu_to_le16(packets); + + bt_hci_event(hci, EVT_NUM_COMP_PKTS, params, EVT_NUM_COMP_PKTS_SIZE(1)); +} + +static void bt_submit_hci(struct HCIInfo *info, + const uint8_t *data, int length) +{ + struct bt_hci_s *hci = hci_from_info(info); + uint16_t cmd; + int paramlen, i; + + if (length < HCI_COMMAND_HDR_SIZE) + goto short_hci; + + memcpy(&hci->last_cmd, data, 2); + + cmd = (data[1] << 8) | data[0]; + paramlen = data[2]; + if (cmd_opcode_ogf(cmd) == 0 || cmd_opcode_ocf(cmd) == 0) /* NOP */ + return; + + data += HCI_COMMAND_HDR_SIZE; + length -= HCI_COMMAND_HDR_SIZE; + + if (paramlen > length) + return; + +#define PARAM(cmd, param) (((cmd##_cp *) data)->param) +#define PARAM16(cmd, param) le16_to_cpup(&PARAM(cmd, param)) +#define PARAMHANDLE(cmd) HNDL(PARAM(cmd, handle)) +#define LENGTH_CHECK(cmd) if (length < sizeof(cmd##_cp)) goto short_hci + /* Note: the supported commands bitmask in bt_hci_read_local_commands_rp + * needs to be updated every time a command is implemented here! */ + switch (cmd) { + case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY): + LENGTH_CHECK(inquiry); + + if (PARAM(inquiry, length) < 1) { + bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS); + break; + } + + hci->lm.inquire = 1; + hci->lm.periodic = 0; + hci->lm.responses_left = PARAM(inquiry, num_rsp) ?: INT_MAX; + hci->lm.responses = 0; + bt_hci_event_status(hci, HCI_SUCCESS); + bt_hci_inquiry_start(hci, PARAM(inquiry, length)); + break; + + case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY_CANCEL): + if (!hci->lm.inquire || hci->lm.periodic) { + fprintf(stderr, "%s: Inquiry Cancel should only be issued after " + "the Inquiry command has been issued, a Command " + "Status event has been received for the Inquiry " + "command, and before the Inquiry Complete event " + "occurs", __FUNCTION__); + bt_hci_event_complete_status(hci, HCI_COMMAND_DISALLOWED); + break; + } + + hci->lm.inquire = 0; + qemu_del_timer(hci->lm.inquiry_done); + bt_hci_event_complete_status(hci, HCI_SUCCESS); + break; + + case cmd_opcode_pack(OGF_LINK_CTL, OCF_PERIODIC_INQUIRY): + LENGTH_CHECK(periodic_inquiry); + + if (!(PARAM(periodic_inquiry, length) < + PARAM16(periodic_inquiry, min_period) && + PARAM16(periodic_inquiry, min_period) < + PARAM16(periodic_inquiry, max_period)) || + PARAM(periodic_inquiry, length) < 1 || + PARAM16(periodic_inquiry, min_period) < 2 || + PARAM16(periodic_inquiry, max_period) < 3) { + bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS); + break; + } + + hci->lm.inquire = 1; + hci->lm.periodic = 1; + hci->lm.responses_left = PARAM(periodic_inquiry, num_rsp); + hci->lm.responses = 0; + hci->lm.inquiry_period = PARAM16(periodic_inquiry, max_period); + bt_hci_event_complete_status(hci, HCI_SUCCESS); + bt_hci_inquiry_start(hci, PARAM(periodic_inquiry, length)); + break; + + case cmd_opcode_pack(OGF_LINK_CTL, OCF_EXIT_PERIODIC_INQUIRY): + if (!hci->lm.inquire || !hci->lm.periodic) { + fprintf(stderr, "%s: Inquiry Cancel should only be issued after " + "the Inquiry command has been issued, a Command " + "Status event has been received for the Inquiry " + "command, and before the Inquiry Complete event " + "occurs", __FUNCTION__); + bt_hci_event_complete_status(hci, HCI_COMMAND_DISALLOWED); + break; + } + hci->lm.inquire = 0; + qemu_del_timer(hci->lm.inquiry_done); + qemu_del_timer(hci->lm.inquiry_next); + bt_hci_event_complete_status(hci, HCI_SUCCESS); + break; + + case cmd_opcode_pack(OGF_LINK_CTL, OCF_CREATE_CONN): + LENGTH_CHECK(create_conn); + + if (hci->lm.connecting >= HCI_HANDLES_MAX) { + bt_hci_event_status(hci, HCI_REJECTED_LIMITED_RESOURCES); + break; + } + bt_hci_event_status(hci, HCI_SUCCESS); + + if (bt_hci_connect(hci, &PARAM(create_conn, bdaddr))) + bt_hci_connection_reject_event(hci, &PARAM(create_conn, bdaddr)); + break; + + case cmd_opcode_pack(OGF_LINK_CTL, OCF_DISCONNECT): + LENGTH_CHECK(disconnect); + + if (bt_hci_handle_bad(hci, PARAMHANDLE(disconnect))) { + bt_hci_event_status(hci, HCI_NO_CONNECTION); + break; + } + + bt_hci_event_status(hci, HCI_SUCCESS); + bt_hci_disconnect(hci, PARAMHANDLE(disconnect), + PARAM(disconnect, reason)); + break; + + case cmd_opcode_pack(OGF_LINK_CTL, OCF_CREATE_CONN_CANCEL): + LENGTH_CHECK(create_conn_cancel); + + if (bt_hci_lmp_connection_ready(hci, + &PARAM(create_conn_cancel, bdaddr))) { + for (i = 0; i < HCI_HANDLES_MAX; i ++) + if (bt_hci_role_master(hci, i) && hci->lm.handle[i].link && + !bacmp(&hci->lm.handle[i].link->slave->bd_addr, + &PARAM(create_conn_cancel, bdaddr))) + break; + + bt_hci_event_complete_conn_cancel(hci, i < HCI_HANDLES_MAX ? + HCI_ACL_CONNECTION_EXISTS : HCI_NO_CONNECTION, + &PARAM(create_conn_cancel, bdaddr)); + } else + bt_hci_event_complete_conn_cancel(hci, HCI_SUCCESS, + &PARAM(create_conn_cancel, bdaddr)); + break; + + case cmd_opcode_pack(OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ): + LENGTH_CHECK(accept_conn_req); + + if (!hci->conn_req_host || + bacmp(&PARAM(accept_conn_req, bdaddr), + &hci->conn_req_host->bd_addr)) { + bt_hci_event_status(hci, HCI_INVALID_PARAMETERS); + break; + } + + bt_hci_event_status(hci, HCI_SUCCESS); + bt_hci_connection_accept(hci, hci->conn_req_host); + hci->conn_req_host = 0; + break; + + case cmd_opcode_pack(OGF_LINK_CTL, OCF_REJECT_CONN_REQ): + LENGTH_CHECK(reject_conn_req); + + if (!hci->conn_req_host || + bacmp(&PARAM(reject_conn_req, bdaddr), + &hci->conn_req_host->bd_addr)) { + bt_hci_event_status(hci, HCI_INVALID_PARAMETERS); + break; + } + + bt_hci_event_status(hci, HCI_SUCCESS); + bt_hci_connection_reject(hci, hci->conn_req_host, + PARAM(reject_conn_req, reason)); + bt_hci_connection_reject_event(hci, &hci->conn_req_host->bd_addr); + hci->conn_req_host = 0; + break; + + case cmd_opcode_pack(OGF_LINK_CTL, OCF_AUTH_REQUESTED): + LENGTH_CHECK(auth_requested); + + if (bt_hci_handle_bad(hci, PARAMHANDLE(auth_requested))) + bt_hci_event_status(hci, HCI_NO_CONNECTION); + else { + bt_hci_event_status(hci, HCI_SUCCESS); + bt_hci_event_auth_complete(hci, PARAMHANDLE(auth_requested)); + } + break; + + case cmd_opcode_pack(OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT): + LENGTH_CHECK(set_conn_encrypt); + + if (bt_hci_handle_bad(hci, PARAMHANDLE(set_conn_encrypt))) + bt_hci_event_status(hci, HCI_NO_CONNECTION); + else { + bt_hci_event_status(hci, HCI_SUCCESS); + bt_hci_event_encrypt_change(hci, + PARAMHANDLE(set_conn_encrypt), + PARAM(set_conn_encrypt, encrypt)); + } + break; + + case cmd_opcode_pack(OGF_LINK_CTL, OCF_REMOTE_NAME_REQ): + LENGTH_CHECK(remote_name_req); + + if (bt_hci_name_req(hci, &PARAM(remote_name_req, bdaddr))) + bt_hci_event_status(hci, HCI_NO_CONNECTION); + break; + + case cmd_opcode_pack(OGF_LINK_CTL, OCF_REMOTE_NAME_REQ_CANCEL): + LENGTH_CHECK(remote_name_req_cancel); + + bt_hci_event_complete_name_cancel(hci, + &PARAM(remote_name_req_cancel, bdaddr)); + break; + + case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_FEATURES): + LENGTH_CHECK(read_remote_features); + + if (bt_hci_features_req(hci, PARAMHANDLE(read_remote_features))) + bt_hci_event_status(hci, HCI_NO_CONNECTION); + break; + + case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_EXT_FEATURES): + LENGTH_CHECK(read_remote_ext_features); + + if (bt_hci_handle_bad(hci, PARAMHANDLE(read_remote_ext_features))) + bt_hci_event_status(hci, HCI_NO_CONNECTION); + else { + bt_hci_event_status(hci, HCI_SUCCESS); + bt_hci_event_read_remote_ext_features(hci, + PARAMHANDLE(read_remote_ext_features)); + } + break; + + case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_VERSION): + LENGTH_CHECK(read_remote_version); + + if (bt_hci_version_req(hci, PARAMHANDLE(read_remote_version))) + bt_hci_event_status(hci, HCI_NO_CONNECTION); + break; + + case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_CLOCK_OFFSET): + LENGTH_CHECK(read_clock_offset); + + if (bt_hci_clkoffset_req(hci, PARAMHANDLE(read_clock_offset))) + bt_hci_event_status(hci, HCI_NO_CONNECTION); + break; + + case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_LMP_HANDLE): + LENGTH_CHECK(read_lmp_handle); + + /* TODO: */ + bt_hci_event_complete_lmp_handle(hci, PARAMHANDLE(read_lmp_handle)); + break; + + case cmd_opcode_pack(OGF_LINK_POLICY, OCF_HOLD_MODE): + LENGTH_CHECK(hold_mode); + + if (PARAM16(hold_mode, min_interval) > + PARAM16(hold_mode, max_interval) || + PARAM16(hold_mode, min_interval) < 0x0002 || + PARAM16(hold_mode, max_interval) > 0xff00 || + (PARAM16(hold_mode, min_interval) & 1) || + (PARAM16(hold_mode, max_interval) & 1)) { + bt_hci_event_status(hci, HCI_INVALID_PARAMETERS); + break; + } + + if (bt_hci_mode_change(hci, PARAMHANDLE(hold_mode), + PARAM16(hold_mode, max_interval), + acl_hold)) + bt_hci_event_status(hci, HCI_NO_CONNECTION); + break; + + case cmd_opcode_pack(OGF_LINK_POLICY, OCF_PARK_MODE): + LENGTH_CHECK(park_mode); + + if (PARAM16(park_mode, min_interval) > + PARAM16(park_mode, max_interval) || + PARAM16(park_mode, min_interval) < 0x000e || + (PARAM16(park_mode, min_interval) & 1) || + (PARAM16(park_mode, max_interval) & 1)) { + bt_hci_event_status(hci, HCI_INVALID_PARAMETERS); + break; + } + + if (bt_hci_mode_change(hci, PARAMHANDLE(park_mode), + PARAM16(park_mode, max_interval), + acl_parked)) + bt_hci_event_status(hci, HCI_NO_CONNECTION); + break; + + case cmd_opcode_pack(OGF_LINK_POLICY, OCF_EXIT_PARK_MODE): + LENGTH_CHECK(exit_park_mode); + + if (bt_hci_mode_cancel(hci, PARAMHANDLE(exit_park_mode), + acl_parked)) + bt_hci_event_status(hci, HCI_NO_CONNECTION); + break; + + case cmd_opcode_pack(OGF_LINK_POLICY, OCF_ROLE_DISCOVERY): + LENGTH_CHECK(role_discovery); + + if (bt_hci_handle_bad(hci, PARAMHANDLE(role_discovery))) + bt_hci_event_complete_role_discovery(hci, + HCI_NO_CONNECTION, PARAMHANDLE(role_discovery), 0); + else + bt_hci_event_complete_role_discovery(hci, + HCI_SUCCESS, PARAMHANDLE(role_discovery), + bt_hci_role_master(hci, + PARAMHANDLE(role_discovery))); + break; + + case cmd_opcode_pack(OGF_HOST_CTL, OCF_SET_EVENT_MASK): + LENGTH_CHECK(set_event_mask); + + memcpy(hci->event_mask, PARAM(set_event_mask, mask), 8); + bt_hci_event_complete_status(hci, HCI_SUCCESS); + break; + + case cmd_opcode_pack(OGF_HOST_CTL, OCF_RESET): + bt_hci_reset(hci); + bt_hci_event_status(hci, HCI_SUCCESS); + break; + + case cmd_opcode_pack(OGF_HOST_CTL, OCF_SET_EVENT_FLT): + if (length >= 1 && PARAM(set_event_flt, flt_type) == FLT_CLEAR_ALL) + /* No length check */; + else + LENGTH_CHECK(set_event_flt); + + /* Filters are not implemented */ + bt_hci_event_complete_status(hci, HCI_SUCCESS); + break; + + case cmd_opcode_pack(OGF_HOST_CTL, OCF_FLUSH): + LENGTH_CHECK(flush); + + if (bt_hci_handle_bad(hci, PARAMHANDLE(flush))) + bt_hci_event_complete_flush(hci, + HCI_NO_CONNECTION, PARAMHANDLE(flush)); + else { + /* TODO: ordering? */ + bt_hci_event(hci, EVT_FLUSH_OCCURRED, + &PARAM(flush, handle), + EVT_FLUSH_OCCURRED_SIZE); + bt_hci_event_complete_flush(hci, + HCI_SUCCESS, PARAMHANDLE(flush)); + } + break; + + case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME): + LENGTH_CHECK(change_local_name); + + if (hci->device.lmp_name) + qemu_free((void *) hci->device.lmp_name); + hci->device.lmp_name = qemu_strndup(PARAM(change_local_name, name), + sizeof(PARAM(change_local_name, name))); + bt_hci_event_complete_status(hci, HCI_SUCCESS); + break; + + case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_NAME): + bt_hci_event_complete_read_local_name(hci); + break; + + case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_CONN_ACCEPT_TIMEOUT): + bt_hci_event_complete_read_conn_accept_timeout(hci); + break; + + case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CONN_ACCEPT_TIMEOUT): + /* TODO */ + LENGTH_CHECK(write_conn_accept_timeout); + + if (PARAM16(write_conn_accept_timeout, timeout) < 0x0001 || + PARAM16(write_conn_accept_timeout, timeout) > 0xb540) { + bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS); + break; + } + + hci->conn_accept_tout = PARAM16(write_conn_accept_timeout, timeout); + bt_hci_event_complete_status(hci, HCI_SUCCESS); + break; + + case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_SCAN_ENABLE): + bt_hci_event_complete_read_scan_enable(hci); + break; + + case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE): + LENGTH_CHECK(write_scan_enable); + + /* TODO: check that the remaining bits are all 0 */ + hci->device.inquiry_scan = + !!(PARAM(write_scan_enable, scan_enable) & SCAN_INQUIRY); + hci->device.page_scan = + !!(PARAM(write_scan_enable, scan_enable) & SCAN_PAGE); + bt_hci_event_complete_status(hci, HCI_SUCCESS); + break; + + case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_CLASS_OF_DEV): + bt_hci_event_complete_read_local_class(hci); + break; + + case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV): + LENGTH_CHECK(write_class_of_dev); + + memcpy(hci->device.class, PARAM(write_class_of_dev, dev_class), + sizeof(PARAM(write_class_of_dev, dev_class))); + bt_hci_event_complete_status(hci, HCI_SUCCESS); + break; + + case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_VOICE_SETTING): + bt_hci_event_complete_voice_setting(hci); + break; + + case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING): + LENGTH_CHECK(write_voice_setting); + + hci->voice_setting = PARAM(write_voice_setting, voice_setting); + bt_hci_event_complete_status(hci, HCI_SUCCESS); + break; + + case cmd_opcode_pack(OGF_HOST_CTL, OCF_HOST_NUMBER_OF_COMPLETED_PACKETS): + if (length < data[0] * 2 + 1) + goto short_hci; + + for (i = 0; i < data[0]; i ++) + if (bt_hci_handle_bad(hci, + data[i * 2 + 1] | (data[i * 2 + 2] << 8))) + bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS); + break; + + case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_INQUIRY_MODE): + /* Only if (local_features[3] & 0x40) && (local_commands[12] & 0x40) + * else + * goto unknown_command */ + bt_hci_event_complete_read_inquiry_mode(hci); + break; + + case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_INQUIRY_MODE): + /* Only if (local_features[3] & 0x40) && (local_commands[12] & 0x80) + * else + * goto unknown_command */ + LENGTH_CHECK(write_inquiry_mode); + + if (PARAM(write_inquiry_mode, mode) > 0x01) { + bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS); + break; + } + + hci->lm.inquiry_mode = PARAM(write_inquiry_mode, mode); + bt_hci_event_complete_status(hci, HCI_SUCCESS); + break; + + case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION): + bt_hci_read_local_version_rp(hci); + break; + + case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_COMMANDS): + bt_hci_read_local_commands_rp(hci); + break; + + case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES): + bt_hci_read_local_features_rp(hci); + break; + + case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_EXT_FEATURES): + LENGTH_CHECK(read_local_ext_features); + + bt_hci_read_local_ext_features_rp(hci, + PARAM(read_local_ext_features, page_num)); + break; + + case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE): + bt_hci_read_buffer_size_rp(hci); + break; + + case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_COUNTRY_CODE): + bt_hci_read_country_code_rp(hci); + break; + + case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BD_ADDR): + bt_hci_read_bd_addr_rp(hci); + break; + + case cmd_opcode_pack(OGF_STATUS_PARAM, OCF_READ_LINK_QUALITY): + LENGTH_CHECK(read_link_quality); + + bt_hci_link_quality_rp(hci, PARAMHANDLE(read_link_quality)); + break; + + default: + bt_hci_event_status(hci, HCI_UNKNOWN_COMMAND); + break; + + short_hci: + fprintf(stderr, "%s: HCI packet too short (%iB)\n", + __FUNCTION__, length); + bt_hci_event_status(hci, HCI_INVALID_PARAMETERS); + break; + } +} + +/* We could perform fragmentation here, we can't do "recombination" because + * at this layer the length of the payload is not know ahead, so we only + * know that a packet contained the last fragment of the SDU when the next + * SDU starts. */ +static inline void bt_hci_lmp_acl_data(struct bt_hci_s *hci, uint16_t handle, + const uint8_t *data, int start, int len) +{ + struct hci_acl_hdr *pkt = (void *) hci->acl_buf; + + /* TODO: packet flags */ + /* TODO: avoid memcpy'ing */ + + if (len + HCI_ACL_HDR_SIZE > sizeof(hci->acl_buf)) { + fprintf(stderr, "%s: can't take ACL packets %i bytes long\n", + __FUNCTION__, len); + return; + } + memcpy(hci->acl_buf + HCI_ACL_HDR_SIZE, data, len); + + pkt->handle = cpu_to_le16( + acl_handle_pack(handle, start ? ACL_START : ACL_CONT)); + pkt->dlen = cpu_to_le16(len); + hci->info.acl_recv(hci->info.opaque, + hci->acl_buf, len + HCI_ACL_HDR_SIZE); +} + +static void bt_hci_lmp_acl_data_slave(struct bt_link_s *btlink, + const uint8_t *data, int start, int len) +{ + struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink; + + bt_hci_lmp_acl_data(hci_from_device(btlink->slave), + link->handle, data, start, len); +} + +static void bt_hci_lmp_acl_data_host(struct bt_link_s *link, + const uint8_t *data, int start, int len) +{ + bt_hci_lmp_acl_data(hci_from_device(link->host), + link->handle, data, start, len); +} + +static void bt_submit_acl(struct HCIInfo *info, + const uint8_t *data, int length) +{ + struct bt_hci_s *hci = hci_from_info(info); + uint16_t handle; + int datalen, flags; + struct bt_link_s *link; + + if (length < HCI_ACL_HDR_SIZE) { + fprintf(stderr, "%s: ACL packet too short (%iB)\n", + __FUNCTION__, length); + return; + } + + handle = acl_handle((data[1] << 8) | data[0]); + flags = acl_flags((data[1] << 8) | data[0]); + datalen = (data[3] << 8) | data[2]; + data += HCI_ACL_HDR_SIZE; + length -= HCI_ACL_HDR_SIZE; + + if (bt_hci_handle_bad(hci, handle)) { + fprintf(stderr, "%s: invalid ACL handle %03x\n", + __FUNCTION__, handle); + /* TODO: signal an error */ + return; + } + handle &= ~HCI_HANDLE_OFFSET; + + if (datalen > length) { + fprintf(stderr, "%s: ACL packet too short (%iB < %iB)\n", + __FUNCTION__, length, datalen); + return; + } + + link = hci->lm.handle[handle].link; + + if ((flags & ~3) == ACL_ACTIVE_BCAST) { + if (!hci->asb_handle) + hci->asb_handle = handle; + else if (handle != hci->asb_handle) { + fprintf(stderr, "%s: Bad handle %03x in Active Slave Broadcast\n", + __FUNCTION__, handle); + /* TODO: signal an error */ + return; + } + + /* TODO */ + } + + if ((flags & ~3) == ACL_PICO_BCAST) { + if (!hci->psb_handle) + hci->psb_handle = handle; + else if (handle != hci->psb_handle) { + fprintf(stderr, "%s: Bad handle %03x in Parked Slave Broadcast\n", + __FUNCTION__, handle); + /* TODO: signal an error */ + return; + } + + /* TODO */ + } + + /* TODO: increase counter and send EVT_NUM_COMP_PKTS */ + bt_hci_event_num_comp_pkts(hci, handle | HCI_HANDLE_OFFSET, 1); + + /* Do this last as it can trigger further events even in this HCI */ + hci->lm.handle[handle].lmp_acl_data(link, data, + (flags & 3) == ACL_START, length); +} + +static void bt_submit_sco(struct HCIInfo *info, + const uint8_t *data, int length) +{ + struct bt_hci_s *hci = hci_from_info(info); + struct bt_link_s *link; + uint16_t handle; + int datalen; + + if (length < 3) + return; + + handle = acl_handle((data[1] << 8) | data[0]); + datalen = data[2]; + data += 3; + length -= 3; + + if (bt_hci_handle_bad(hci, handle)) { + fprintf(stderr, "%s: invalid SCO handle %03x\n", + __FUNCTION__, handle); + return; + } + handle &= ~HCI_HANDLE_OFFSET; + + if (datalen > length) { + fprintf(stderr, "%s: SCO packet too short (%iB < %iB)\n", + __FUNCTION__, length, datalen); + return; + } + + link = hci->lm.handle[handle].link; + /* TODO */ + + /* TODO: increase counter and send EVT_NUM_COMP_PKTS if synchronous + * Flow Control is enabled. + * (See Read/Write_Synchronous_Flow_Control_Enable on page 513 and + * page 514.) */ +} + +static uint8_t *bt_hci_evt_packet(void *opaque) +{ + /* TODO: allocate a packet from upper layer */ + struct bt_hci_s *s = opaque; + + return s->evt_buf; +} + +static void bt_hci_evt_submit(void *opaque, int len) +{ + /* TODO: notify upper layer */ + struct bt_hci_s *s = opaque; + + return s->info.evt_recv(s->info.opaque, s->evt_buf, len); +} + +static int bt_hci_bdaddr_set(struct HCIInfo *info, const uint8_t *bd_addr) +{ + struct bt_hci_s *hci = hci_from_info(info); + + bacpy(&hci->device.bd_addr, (const bdaddr_t *) bd_addr); + return 0; +} + +static void bt_hci_done(struct HCIInfo *info); +static void bt_hci_destroy(struct bt_device_s *dev) +{ + struct bt_hci_s *hci = hci_from_device(dev); + + return bt_hci_done(&hci->info); +} + +struct HCIInfo *bt_new_hci(struct bt_scatternet_s *net) +{ + struct bt_hci_s *s = qemu_mallocz(sizeof(struct bt_hci_s)); + + s->lm.inquiry_done = qemu_new_timer(vm_clock, bt_hci_inquiry_done, s); + s->lm.inquiry_next = qemu_new_timer(vm_clock, bt_hci_inquiry_next, s); + s->conn_accept_timer = + qemu_new_timer(vm_clock, bt_hci_conn_accept_timeout, s); + + s->evt_packet = bt_hci_evt_packet; + s->evt_submit = bt_hci_evt_submit; + s->opaque = s; + + bt_device_init(&s->device, net); + s->device.lmp_connection_request = bt_hci_lmp_connection_request; + s->device.lmp_connection_complete = bt_hci_lmp_connection_complete; + s->device.lmp_disconnect_master = bt_hci_lmp_disconnect_host; + s->device.lmp_disconnect_slave = bt_hci_lmp_disconnect_slave; + s->device.lmp_acl_data = bt_hci_lmp_acl_data_slave; + s->device.lmp_acl_resp = bt_hci_lmp_acl_data_host; + s->device.lmp_mode_change = bt_hci_lmp_mode_change_slave; + + /* Keep updated! */ + /* Also keep in sync with supported commands bitmask in + * bt_hci_read_local_commands_rp */ + s->device.lmp_caps = 0x8000199b7e85355fll; + + bt_hci_reset(s); + + s->info.cmd_send = bt_submit_hci; + s->info.sco_send = bt_submit_sco; + s->info.acl_send = bt_submit_acl; + s->info.bdaddr_set = bt_hci_bdaddr_set; + + s->device.handle_destroy = bt_hci_destroy; + + return &s->info; +} + +static void bt_hci_done(struct HCIInfo *info) +{ + struct bt_hci_s *hci = hci_from_info(info); + int handle; + + bt_device_done(&hci->device); + + if (hci->device.lmp_name) + qemu_free((void *) hci->device.lmp_name); + + /* Be gentle and send DISCONNECT to all connected peers and those + * currently waiting for us to accept or reject a connection request. + * This frees the links. */ + if (hci->conn_req_host) + return bt_hci_connection_reject(hci, + hci->conn_req_host, HCI_OE_POWER_OFF); + + for (handle = HCI_HANDLE_OFFSET; + handle < (HCI_HANDLE_OFFSET | HCI_HANDLES_MAX); handle ++) + if (!bt_hci_handle_bad(hci, handle)) + bt_hci_disconnect(hci, handle, HCI_OE_POWER_OFF); + + /* TODO: this is not enough actually, there may be slaves from whom + * we have requested a connection who will soon (or not) respond with + * an accept or a reject, so we should also check if hci->lm.connecting + * is non-zero and if so, avoid freeing the hci but otherwise disappear + * from all qemu social life (e.g. stop scanning and request to be + * removed from s->device.net) and arrange for + * s->device.lmp_connection_complete to free the remaining bits once + * hci->lm.awaiting_bdaddr[] is empty. */ + + qemu_free_timer(hci->lm.inquiry_done); + qemu_free_timer(hci->lm.inquiry_next); + qemu_free_timer(hci->conn_accept_timer); + + qemu_free(hci); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/bt-hci-csr.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/bt-hci-csr.c --- qemu-0.9.1/hw/bt-hci-csr.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/bt-hci-csr.c 2008-09-29 00:34:13.000000000 +0100 @@ -0,0 +1,456 @@ +/* + * Bluetooth serial HCI transport. + * CSR41814 HCI with H4p vendor extensions. + * + * Copyright (C) 2008 Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "qemu-common.h" +#include "qemu-char.h" +#include "qemu-timer.h" +#include "irq.h" +#include "sysemu.h" +#include "net.h" +#include "bt.h" + +struct csrhci_s { + int enable; + qemu_irq *pins; + int pin_state; + int modem_state; + CharDriverState chr; +#define FIFO_LEN 4096 + int out_start; + int out_len; + int out_size; + uint8_t outfifo[FIFO_LEN * 2]; + uint8_t inpkt[FIFO_LEN]; + int in_len; + int in_hdr; + int in_data; + QEMUTimer *out_tm; + int64_t baud_delay; + + bdaddr_t bd_addr; + struct HCIInfo *hci; +}; + +/* H4+ packet types */ +enum { + H4_CMD_PKT = 1, + H4_ACL_PKT = 2, + H4_SCO_PKT = 3, + H4_EVT_PKT = 4, + H4_NEG_PKT = 6, + H4_ALIVE_PKT = 7, +}; + +/* CSR41814 negotiation start magic packet */ +static const uint8_t csrhci_neg_packet[] = { + H4_NEG_PKT, 10, + 0x00, 0xa0, 0x01, 0x00, 0x00, + 0x4c, 0x00, 0x96, 0x00, 0x00, +}; + +/* CSR41814 vendor-specific command OCFs */ +enum { + OCF_CSR_SEND_FIRMWARE = 0x000, +}; + +static inline void csrhci_fifo_wake(struct csrhci_s *s) +{ + if (!s->enable || !s->out_len) + return; + + /* XXX: Should wait for s->modem_state & CHR_TIOCM_RTS? */ + if (s->chr.chr_can_read && s->chr.chr_can_read(s->chr.handler_opaque) && + s->chr.chr_read) { + s->chr.chr_read(s->chr.handler_opaque, + s->outfifo + s->out_start ++, 1); + s->out_len --; + if (s->out_start >= s->out_size) { + s->out_start = 0; + s->out_size = FIFO_LEN; + } + } + + if (s->out_len) + qemu_mod_timer(s->out_tm, qemu_get_clock(vm_clock) + s->baud_delay); +} + +#define csrhci_out_packetz(s, len) memset(csrhci_out_packet(s, len), 0, len) +static uint8_t *csrhci_out_packet(struct csrhci_s *s, int len) +{ + int off = s->out_start + s->out_len; + + /* TODO: do the padding here, i.e. align len */ + s->out_len += len; + + if (off < FIFO_LEN) { + if (off + len > FIFO_LEN && (s->out_size = off + len) > FIFO_LEN * 2) { + fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len); + exit(-1); + } + return s->outfifo + off; + } + + if (s->out_len > s->out_size) { + fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len); + exit(-1); + } + + return s->outfifo + off - s->out_size; +} + +static inline uint8_t *csrhci_out_packet_csr(struct csrhci_s *s, + int type, int len) +{ + uint8_t *ret = csrhci_out_packetz(s, len + 2); + + *ret ++ = type; + *ret ++ = len; + + return ret; +} + +static inline uint8_t *csrhci_out_packet_event(struct csrhci_s *s, + int evt, int len) +{ + uint8_t *ret = csrhci_out_packetz(s, + len + 1 + sizeof(struct hci_event_hdr)); + + *ret ++ = H4_EVT_PKT; + ((struct hci_event_hdr *) ret)->evt = evt; + ((struct hci_event_hdr *) ret)->plen = len; + + return ret + sizeof(struct hci_event_hdr); +} + +static void csrhci_in_packet_vendor(struct csrhci_s *s, int ocf, + uint8_t *data, int len) +{ + int offset; + uint8_t *rpkt; + + switch (ocf) { + case OCF_CSR_SEND_FIRMWARE: + /* Check if this is the bd_address packet */ + if (len >= 18 + 8 && data[12] == 0x01 && data[13] == 0x00) { + offset = 18; + s->bd_addr.b[0] = data[offset + 7]; /* Beyond cmd packet end(!?) */ + s->bd_addr.b[1] = data[offset + 6]; + s->bd_addr.b[2] = data[offset + 4]; + s->bd_addr.b[3] = data[offset + 0]; + s->bd_addr.b[4] = data[offset + 3]; + s->bd_addr.b[5] = data[offset + 2]; + + s->hci->bdaddr_set(s->hci, s->bd_addr.b); + fprintf(stderr, "%s: bd_address loaded from firmware: " + "%02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__, + s->bd_addr.b[0], s->bd_addr.b[1], s->bd_addr.b[2], + s->bd_addr.b[3], s->bd_addr.b[4], s->bd_addr.b[5]); + } + + rpkt = csrhci_out_packet_event(s, EVT_VENDOR, 11); + /* Status bytes: no error */ + rpkt[9] = 0x00; + rpkt[10] = 0x00; + break; + + default: + fprintf(stderr, "%s: got a bad CMD packet\n", __FUNCTION__); + return; + } + + csrhci_fifo_wake(s); +} + +static void csrhci_in_packet(struct csrhci_s *s, uint8_t *pkt) +{ + uint8_t *rpkt; + int opc; + + switch (*pkt ++) { + case H4_CMD_PKT: + opc = le16_to_cpu(((struct hci_command_hdr *) pkt)->opcode); + if (cmd_opcode_ogf(opc) == OGF_VENDOR_CMD) { + csrhci_in_packet_vendor(s, cmd_opcode_ocf(opc), + pkt + sizeof(struct hci_command_hdr), + s->in_len - sizeof(struct hci_command_hdr) - 1); + return; + } + + /* TODO: if the command is OCF_READ_LOCAL_COMMANDS or the likes, + * we need to send it to the HCI layer and then add our supported + * commands to the returned mask (such as OGF_VENDOR_CMD). With + * bt-hci.c we could just have hooks for this kind of commands but + * we can't with bt-host.c. */ + + s->hci->cmd_send(s->hci, pkt, s->in_len - 1); + break; + + case H4_EVT_PKT: + goto bad_pkt; + + case H4_ACL_PKT: + s->hci->acl_send(s->hci, pkt, s->in_len - 1); + break; + + case H4_SCO_PKT: + s->hci->sco_send(s->hci, pkt, s->in_len - 1); + break; + + case H4_NEG_PKT: + if (s->in_hdr != sizeof(csrhci_neg_packet) || + memcmp(pkt - 1, csrhci_neg_packet, s->in_hdr)) { + fprintf(stderr, "%s: got a bad NEG packet\n", __FUNCTION__); + return; + } + pkt += 2; + + rpkt = csrhci_out_packet_csr(s, H4_NEG_PKT, 10); + + *rpkt ++ = 0x20; /* Operational settings negotation Ok */ + memcpy(rpkt, pkt, 7); rpkt += 7; + *rpkt ++ = 0xff; + *rpkt ++ = 0xff; + break; + + case H4_ALIVE_PKT: + if (s->in_hdr != 4 || pkt[1] != 0x55 || pkt[2] != 0x00) { + fprintf(stderr, "%s: got a bad ALIVE packet\n", __FUNCTION__); + return; + } + + rpkt = csrhci_out_packet_csr(s, H4_ALIVE_PKT, 2); + + *rpkt ++ = 0xcc; + *rpkt ++ = 0x00; + break; + + default: + bad_pkt: + /* TODO: error out */ + fprintf(stderr, "%s: got a bad packet\n", __FUNCTION__); + break; + } + + csrhci_fifo_wake(s); +} + +static int csrhci_header_len(const uint8_t *pkt) +{ + switch (pkt[0]) { + case H4_CMD_PKT: + return HCI_COMMAND_HDR_SIZE; + case H4_EVT_PKT: + return HCI_EVENT_HDR_SIZE; + case H4_ACL_PKT: + return HCI_ACL_HDR_SIZE; + case H4_SCO_PKT: + return HCI_SCO_HDR_SIZE; + case H4_NEG_PKT: + return pkt[1] + 1; + case H4_ALIVE_PKT: + return 3; + } + + exit(-1); +} + +static int csrhci_data_len(const uint8_t *pkt) +{ + switch (*pkt ++) { + case H4_CMD_PKT: + /* It seems that vendor-specific command packets for H4+ are all + * one byte longer than indicated in the standard header. */ + if (le16_to_cpu(((struct hci_command_hdr *) pkt)->opcode) == 0xfc00) + return (((struct hci_command_hdr *) pkt)->plen + 1) & ~1; + + return ((struct hci_command_hdr *) pkt)->plen; + case H4_EVT_PKT: + return ((struct hci_event_hdr *) pkt)->plen; + case H4_ACL_PKT: + return le16_to_cpu(((struct hci_acl_hdr *) pkt)->dlen); + case H4_SCO_PKT: + return ((struct hci_sco_hdr *) pkt)->dlen; + case H4_NEG_PKT: + case H4_ALIVE_PKT: + return 0; + } + + exit(-1); +} + +static int csrhci_write(struct CharDriverState *chr, + const uint8_t *buf, int len) +{ + struct csrhci_s *s = (struct csrhci_s *) chr->opaque; + int plen = s->in_len; + + if (!s->enable) + return 0; + + s->in_len += len; + memcpy(s->inpkt + plen, buf, len); + + while (1) { + if (s->in_len >= 2 && plen < 2) + s->in_hdr = csrhci_header_len(s->inpkt) + 1; + + if (s->in_len >= s->in_hdr && plen < s->in_hdr) + s->in_data = csrhci_data_len(s->inpkt) + s->in_hdr; + + if (s->in_len >= s->in_data) { + csrhci_in_packet(s, s->inpkt); + + memmove(s->inpkt, s->inpkt + s->in_len, s->in_len - s->in_data); + s->in_len -= s->in_data; + s->in_hdr = INT_MAX; + s->in_data = INT_MAX; + plen = 0; + } else + break; + } + + return len; +} + +static void csrhci_out_hci_packet_event(void *opaque, + const uint8_t *data, int len) +{ + struct csrhci_s *s = (struct csrhci_s *) opaque; + uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1); /* Align */ + + *pkt ++ = H4_EVT_PKT; + memcpy(pkt, data, len); + + csrhci_fifo_wake(s); +} + +static void csrhci_out_hci_packet_acl(void *opaque, + const uint8_t *data, int len) +{ + struct csrhci_s *s = (struct csrhci_s *) opaque; + uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1); /* Align */ + + *pkt ++ = H4_ACL_PKT; + pkt[len & ~1] = 0; + memcpy(pkt, data, len); + + csrhci_fifo_wake(s); +} + +static int csrhci_ioctl(struct CharDriverState *chr, int cmd, void *arg) +{ + QEMUSerialSetParams *ssp; + struct csrhci_s *s = (struct csrhci_s *) chr->opaque; + int prev_state = s->modem_state; + + switch (cmd) { + case CHR_IOCTL_SERIAL_SET_PARAMS: + ssp = (QEMUSerialSetParams *) arg; + s->baud_delay = ticks_per_sec / ssp->speed; + /* Moments later... (but shorter than 100ms) */ + s->modem_state |= CHR_TIOCM_CTS; + break; + + case CHR_IOCTL_SERIAL_GET_TIOCM: + *(int *) arg = s->modem_state; + break; + + case CHR_IOCTL_SERIAL_SET_TIOCM: + s->modem_state = *(int *) arg; + if (~s->modem_state & prev_state & CHR_TIOCM_RTS) + s->modem_state &= ~CHR_TIOCM_CTS; + break; + + default: + return -ENOTSUP; + } + return 0; +} + +static void csrhci_reset(struct csrhci_s *s) +{ + s->out_len = 0; + s->out_size = FIFO_LEN; + s->in_len = 0; + s->baud_delay = ticks_per_sec; + s->enable = 0; + s->in_hdr = INT_MAX; + s->in_data = INT_MAX; + + s->modem_state = 0; + /* After a while... (but sooner than 10ms) */ + s->modem_state |= CHR_TIOCM_CTS; + + memset(&s->bd_addr, 0, sizeof(bdaddr_t)); +} + +static void csrhci_out_tick(void *opaque) +{ + csrhci_fifo_wake((struct csrhci_s *) opaque); +} + +static void csrhci_pins(void *opaque, int line, int level) +{ + struct csrhci_s *s = (struct csrhci_s *) opaque; + int state = s->pin_state; + + s->pin_state &= ~(1 << line); + s->pin_state |= (!!level) << line; + + if ((state & ~s->pin_state) & (1 << csrhci_pin_reset)) { + /* TODO: Disappear from lower layers */ + csrhci_reset(s); + } + + if (s->pin_state == 3 && state != 3) { + s->enable = 1; + /* TODO: Wake lower layers up */ + } +} + +qemu_irq *csrhci_pins_get(CharDriverState *chr) +{ + struct csrhci_s *s = (struct csrhci_s *) chr->opaque; + + return s->pins; +} + +CharDriverState *uart_hci_init(qemu_irq wakeup) +{ + struct csrhci_s *s = (struct csrhci_s *) + qemu_mallocz(sizeof(struct csrhci_s)); + + s->chr.opaque = s; + s->chr.chr_write = csrhci_write; + s->chr.chr_ioctl = csrhci_ioctl; + + s->hci = qemu_next_hci(); + s->hci->opaque = s; + s->hci->evt_recv = csrhci_out_hci_packet_event; + s->hci->acl_recv = csrhci_out_hci_packet_acl; + + s->out_tm = qemu_new_timer(vm_clock, csrhci_out_tick, s); + s->pins = qemu_allocate_irqs(csrhci_pins, s, __csrhci_pins); + csrhci_reset(s); + + return &s->chr; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/bt-hid.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/bt-hid.c --- qemu-0.9.1/hw/bt-hid.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/bt-hid.c 2008-09-29 01:25:17.000000000 +0100 @@ -0,0 +1,571 @@ +/* + * QEMU Bluetooth HID Profile wrapper for USB HID. + * + * Copyright (C) 2007-2008 OpenMoko, Inc. + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "qemu-common.h" +#include "usb.h" +#include "bt.h" + +enum hid_transaction_req { + BT_HANDSHAKE = 0x0, + BT_HID_CONTROL = 0x1, + BT_GET_REPORT = 0x4, + BT_SET_REPORT = 0x5, + BT_GET_PROTOCOL = 0x6, + BT_SET_PROTOCOL = 0x7, + BT_GET_IDLE = 0x8, + BT_SET_IDLE = 0x9, + BT_DATA = 0xa, + BT_DATC = 0xb, +}; + +enum hid_transaction_handshake { + BT_HS_SUCCESSFUL = 0x0, + BT_HS_NOT_READY = 0x1, + BT_HS_ERR_INVALID_REPORT_ID = 0x2, + BT_HS_ERR_UNSUPPORTED_REQUEST = 0x3, + BT_HS_ERR_INVALID_PARAMETER = 0x4, + BT_HS_ERR_UNKNOWN = 0xe, + BT_HS_ERR_FATAL = 0xf, +}; + +enum hid_transaction_control { + BT_HC_NOP = 0x0, + BT_HC_HARD_RESET = 0x1, + BT_HC_SOFT_RESET = 0x2, + BT_HC_SUSPEND = 0x3, + BT_HC_EXIT_SUSPEND = 0x4, + BT_HC_VIRTUAL_CABLE_UNPLUG = 0x5, +}; + +enum hid_protocol { + BT_HID_PROTO_BOOT = 0, + BT_HID_PROTO_REPORT = 1, +}; + +enum hid_boot_reportid { + BT_HID_BOOT_INVALID = 0, + BT_HID_BOOT_KEYBOARD, + BT_HID_BOOT_MOUSE, +}; + +enum hid_data_pkt { + BT_DATA_OTHER = 0, + BT_DATA_INPUT, + BT_DATA_OUTPUT, + BT_DATA_FEATURE, +}; + +#define BT_HID_MTU 48 + +/* HID interface requests */ +#define GET_REPORT 0xa101 +#define GET_IDLE 0xa102 +#define GET_PROTOCOL 0xa103 +#define SET_REPORT 0x2109 +#define SET_IDLE 0x210a +#define SET_PROTOCOL 0x210b + +struct bt_hid_device_s { + struct bt_l2cap_device_s btdev; + struct bt_l2cap_conn_params_s *control; + struct bt_l2cap_conn_params_s *interrupt; + USBDevice *usbdev; + + int proto; + int connected; + int data_type; + int intr_state; + struct { + int len; + uint8_t buffer[1024]; + } dataother, datain, dataout, feature, intrdataout; + enum { + bt_state_ready, + bt_state_transaction, + bt_state_suspend, + } state; +}; + +static void bt_hid_reset(struct bt_hid_device_s *s) +{ + struct bt_scatternet_s *net = s->btdev.device.net; + + /* Go as far as... */ + bt_l2cap_device_done(&s->btdev); + bt_l2cap_device_init(&s->btdev, net); + + s->usbdev->handle_reset(s->usbdev); + s->proto = BT_HID_PROTO_REPORT; + s->state = bt_state_ready; + s->dataother.len = 0; + s->datain.len = 0; + s->dataout.len = 0; + s->feature.len = 0; + s->intrdataout.len = 0; + s->intr_state = 0; +} + +static int bt_hid_out(struct bt_hid_device_s *s) +{ + USBPacket p; + + if (s->data_type == BT_DATA_OUTPUT) { + p.pid = USB_TOKEN_OUT; + p.devep = 1; + p.data = s->dataout.buffer; + p.len = s->dataout.len; + s->dataout.len = s->usbdev->handle_data(s->usbdev, &p); + + return s->dataout.len; + } + + if (s->data_type == BT_DATA_FEATURE) { + /* XXX: + * does this send a USB_REQ_CLEAR_FEATURE/USB_REQ_SET_FEATURE + * or a SET_REPORT? */ + p.devep = 0; + } + + return -1; +} + +static int bt_hid_in(struct bt_hid_device_s *s) +{ + USBPacket p; + + p.pid = USB_TOKEN_IN; + p.devep = 1; + p.data = s->datain.buffer; + p.len = sizeof(s->datain.buffer); + s->datain.len = s->usbdev->handle_data(s->usbdev, &p); + + return s->datain.len; +} + +static void bt_hid_send_handshake(struct bt_hid_device_s *s, int result) +{ + *s->control->sdu_out(s->control, 1) = + (BT_HANDSHAKE << 4) | result; + s->control->sdu_submit(s->control); +} + +static void bt_hid_send_control(struct bt_hid_device_s *s, int operation) +{ + *s->control->sdu_out(s->control, 1) = + (BT_HID_CONTROL << 4) | operation; + s->control->sdu_submit(s->control); +} + +static void bt_hid_disconnect(struct bt_hid_device_s *s) +{ + /* Disconnect s->control and s->interrupt */ +} + +static void bt_hid_send_data(struct bt_l2cap_conn_params_s *ch, int type, + const uint8_t *data, int len) +{ + uint8_t *pkt, hdr = (BT_DATA << 4) | type; + int plen; + + do { + plen = MIN(len, ch->remote_mtu - 1); + pkt = ch->sdu_out(ch, plen + 1); + + pkt[0] = hdr; + if (plen) + memcpy(pkt + 1, data, plen); + ch->sdu_submit(ch); + + len -= plen; + data += plen; + hdr = (BT_DATC << 4) | type; + } while (plen == ch->remote_mtu - 1); +} + +static void bt_hid_control_transaction(struct bt_hid_device_s *s, + const uint8_t *data, int len) +{ + uint8_t type, parameter; + int rlen, ret = -1; + if (len < 1) + return; + + type = data[0] >> 4; + parameter = data[0] & 0xf; + + switch (type) { + case BT_HANDSHAKE: + case BT_DATA: + switch (parameter) { + default: + /* These are not expected to be sent this direction. */ + ret = BT_HS_ERR_INVALID_PARAMETER; + } + break; + + case BT_HID_CONTROL: + if (len != 1 || (parameter != BT_HC_VIRTUAL_CABLE_UNPLUG && + s->state == bt_state_transaction)) { + ret = BT_HS_ERR_INVALID_PARAMETER; + break; + } + switch (parameter) { + case BT_HC_NOP: + break; + case BT_HC_HARD_RESET: + case BT_HC_SOFT_RESET: + bt_hid_reset(s); + break; + case BT_HC_SUSPEND: + if (s->state == bt_state_ready) + s->state = bt_state_suspend; + else + ret = BT_HS_ERR_INVALID_PARAMETER; + break; + case BT_HC_EXIT_SUSPEND: + if (s->state == bt_state_suspend) + s->state = bt_state_ready; + else + ret = BT_HS_ERR_INVALID_PARAMETER; + break; + case BT_HC_VIRTUAL_CABLE_UNPLUG: + bt_hid_disconnect(s); + break; + default: + ret = BT_HS_ERR_INVALID_PARAMETER; + } + break; + + case BT_GET_REPORT: + /* No ReportIDs declared. */ + if (((parameter & 8) && len != 3) || + (!(parameter & 8) && len != 1) || + s->state != bt_state_ready) { + ret = BT_HS_ERR_INVALID_PARAMETER; + break; + } + if (parameter & 8) + rlen = data[2] | (data[3] << 8); + else + rlen = INT_MAX; + switch (parameter & 3) { + case BT_DATA_OTHER: + ret = BT_HS_ERR_INVALID_PARAMETER; + break; + case BT_DATA_INPUT: + /* Here we can as well poll s->usbdev */ + bt_hid_send_data(s->control, BT_DATA_INPUT, + s->datain.buffer, MIN(rlen, s->datain.len)); + break; + case BT_DATA_OUTPUT: + bt_hid_send_data(s->control, BT_DATA_OUTPUT, + s->dataout.buffer, MIN(rlen, s->dataout.len)); + break; + case BT_DATA_FEATURE: + bt_hid_send_data(s->control, BT_DATA_FEATURE, + s->feature.buffer, MIN(rlen, s->feature.len)); + break; + } + break; + + case BT_SET_REPORT: + if (len < 2 || len > BT_HID_MTU || s->state != bt_state_ready || + (parameter & 3) == BT_DATA_OTHER || + (parameter & 3) == BT_DATA_INPUT) { + ret = BT_HS_ERR_INVALID_PARAMETER; + break; + } + s->data_type = parameter & 3; + if (s->data_type == BT_DATA_OUTPUT) { + s->dataout.len = len - 1; + memcpy(s->dataout.buffer, data + 1, s->dataout.len); + } else { + s->feature.len = len - 1; + memcpy(s->feature.buffer, data + 1, s->feature.len); + } + if (len == BT_HID_MTU) + s->state = bt_state_transaction; + else + bt_hid_out(s); + break; + + case BT_GET_PROTOCOL: + if (len != 1 || s->state == bt_state_transaction) { + ret = BT_HS_ERR_INVALID_PARAMETER; + break; + } + *s->control->sdu_out(s->control, 1) = s->proto; + s->control->sdu_submit(s->control); + break; + + case BT_SET_PROTOCOL: + if (len != 1 || s->state == bt_state_transaction || + (parameter != BT_HID_PROTO_BOOT && + parameter != BT_HID_PROTO_REPORT)) { + ret = BT_HS_ERR_INVALID_PARAMETER; + break; + } + s->proto = parameter; + s->usbdev->handle_control(s->usbdev, SET_PROTOCOL, s->proto, 0, 0, 0); + ret = BT_HS_SUCCESSFUL; + break; + + case BT_GET_IDLE: + if (len != 1 || s->state == bt_state_transaction) { + ret = BT_HS_ERR_INVALID_PARAMETER; + break; + } + s->usbdev->handle_control(s->usbdev, GET_IDLE, 0, 0, 1, + s->control->sdu_out(s->control, 1)); + s->control->sdu_submit(s->control); + break; + + case BT_SET_IDLE: + if (len != 2 || s->state == bt_state_transaction) { + ret = BT_HS_ERR_INVALID_PARAMETER; + break; + } + + /* We don't need to know about the Idle Rate here really, + * so just pass it on to the device. */ + ret = s->usbdev->handle_control(s->usbdev, + SET_IDLE, data[1], 0, 0, 0) ? + BT_HS_SUCCESSFUL : BT_HS_ERR_INVALID_PARAMETER; + /* XXX: Does this generate a handshake? */ + break; + + case BT_DATC: + if (len > BT_HID_MTU || s->state != bt_state_transaction) { + ret = BT_HS_ERR_INVALID_PARAMETER; + break; + } + if (s->data_type == BT_DATA_OUTPUT) { + memcpy(s->dataout.buffer + s->dataout.len, data + 1, len - 1); + s->dataout.len += len - 1; + } else { + memcpy(s->feature.buffer + s->feature.len, data + 1, len - 1); + s->feature.len += len - 1; + } + if (len < BT_HID_MTU) { + bt_hid_out(s); + s->state = bt_state_ready; + } + break; + + default: + ret = BT_HS_ERR_UNSUPPORTED_REQUEST; + } + + if (ret != -1) + bt_hid_send_handshake(s, ret); +} + +static void bt_hid_control_sdu(void *opaque, const uint8_t *data, int len) +{ + struct bt_hid_device_s *hid = opaque; + + return bt_hid_control_transaction(hid, data, len); +} + +static void bt_hid_datain(void *opaque) +{ + struct bt_hid_device_s *hid = opaque; + + /* If suspended, wake-up and send a wake-up event first. We might + * want to also inspect the input report and ignore event like + * mouse movements until a button event occurs. */ + if (hid->state == bt_state_suspend) { + hid->state = bt_state_ready; + } + + if (bt_hid_in(hid) > 0) + /* TODO: when in boot-mode precede any Input reports with the ReportID + * byte, here and in GetReport/SetReport on the Control channel. */ + bt_hid_send_data(hid->interrupt, BT_DATA_INPUT, + hid->datain.buffer, hid->datain.len); +} + +static void bt_hid_interrupt_sdu(void *opaque, const uint8_t *data, int len) +{ + struct bt_hid_device_s *hid = opaque; + + if (len > BT_HID_MTU || len < 1) + goto bad; + if ((data[0] & 3) != BT_DATA_OUTPUT) + goto bad; + if ((data[0] >> 4) == BT_DATA) { + if (hid->intr_state) + goto bad; + + hid->data_type = BT_DATA_OUTPUT; + hid->intrdataout.len = 0; + } else if ((data[0] >> 4) == BT_DATC) { + if (!hid->intr_state) + goto bad; + } else + goto bad; + + memcpy(hid->intrdataout.buffer + hid->intrdataout.len, data + 1, len - 1); + hid->intrdataout.len += len - 1; + hid->intr_state = (len == BT_HID_MTU); + if (!hid->intr_state) { + memcpy(hid->dataout.buffer, hid->intrdataout.buffer, + hid->dataout.len = hid->intrdataout.len); + bt_hid_out(hid); + } + + return; +bad: + fprintf(stderr, "%s: bad transaction on Interrupt channel.\n", + __FUNCTION__); +} + +/* "Virtual cable" plug/unplug event. */ +static void bt_hid_connected_update(struct bt_hid_device_s *hid) +{ + int prev = hid->connected; + + hid->connected = hid->control && hid->interrupt; + + /* Stop page-/inquiry-scanning when a host is connected. */ + hid->btdev.device.page_scan = !hid->connected; + hid->btdev.device.inquiry_scan = !hid->connected; + + if (hid->connected && !prev) { + hid->usbdev->handle_reset(hid->usbdev); + hid->proto = BT_HID_PROTO_REPORT; + } + + /* Should set HIDVirtualCable in SDP (possibly need to check that SDP + * isn't destroyed yet, in case we're being called from handle_destroy) */ +} + +static void bt_hid_close_control(void *opaque) +{ + struct bt_hid_device_s *hid = opaque; + + hid->control = 0; + bt_hid_connected_update(hid); +} + +static void bt_hid_close_interrupt(void *opaque) +{ + struct bt_hid_device_s *hid = opaque; + + hid->interrupt = 0; + bt_hid_connected_update(hid); +} + +static int bt_hid_new_control_ch(struct bt_l2cap_device_s *dev, + struct bt_l2cap_conn_params_s *params) +{ + struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev; + + if (hid->control) + return 1; + + hid->control = params; + hid->control->opaque = hid; + hid->control->close = bt_hid_close_control; + hid->control->sdu_in = bt_hid_control_sdu; + + bt_hid_connected_update(hid); + + return 0; +} + +static int bt_hid_new_interrupt_ch(struct bt_l2cap_device_s *dev, + struct bt_l2cap_conn_params_s *params) +{ + struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev; + + if (hid->interrupt) + return 1; + + hid->interrupt = params; + hid->interrupt->opaque = hid; + hid->interrupt->close = bt_hid_close_interrupt; + hid->interrupt->sdu_in = bt_hid_interrupt_sdu; + + bt_hid_connected_update(hid); + + return 0; +} + +static void bt_hid_destroy(struct bt_device_s *dev) +{ + struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev; + + if (hid->connected) + bt_hid_send_control(hid, BT_HC_VIRTUAL_CABLE_UNPLUG); + bt_l2cap_device_done(&hid->btdev); + + hid->usbdev->handle_destroy(hid->usbdev); + + qemu_free(hid); +} + +enum peripheral_minor_class { + class_other = 0 << 4, + class_keyboard = 1 << 4, + class_pointing = 2 << 4, + class_combo = 3 << 4, +}; + +static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net, + USBDevice *dev, enum peripheral_minor_class minor) +{ + struct bt_hid_device_s *s = qemu_mallocz(sizeof(*s)); + uint32_t class = + /* Format type */ + (0 << 0) | + /* Device class */ + (minor << 2) | + (5 << 8) | /* "Peripheral" */ + /* Service classes */ + (1 << 13) | /* Limited discoverable mode */ + (1 << 19); /* Capturing device (?) */ + + bt_l2cap_device_init(&s->btdev, net); + bt_l2cap_sdp_init(&s->btdev); + bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_CTRL, + BT_HID_MTU, bt_hid_new_control_ch); + bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_INTR, + BT_HID_MTU, bt_hid_new_interrupt_ch); + + s->usbdev = dev; + s->btdev.device.lmp_name = s->usbdev->devname; + usb_hid_datain_cb(s->usbdev, s, bt_hid_datain); + + s->btdev.device.handle_destroy = bt_hid_destroy; + + s->btdev.device.class[0] = (class >> 0) & 0xff; + s->btdev.device.class[1] = (class >> 8) & 0xff; + s->btdev.device.class[2] = (class >> 16) & 0xff; + + return &s->btdev.device; +} + +struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net) +{ + return bt_hid_init(net, usb_keyboard_init(), class_keyboard); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/bt-l2cap.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/bt-l2cap.c --- qemu-0.9.1/hw/bt-l2cap.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/bt-l2cap.c 2008-09-29 01:14:22.000000000 +0100 @@ -0,0 +1,1364 @@ +/* + * QEMU Bluetooth L2CAP logic. + * + * Copyright (C) 2008 Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "qemu-common.h" +#include "qemu-timer.h" +#include "bt.h" + +#define L2CAP_CID_MAX 0x100 /* Between 0x40 and 0x10000 */ + +struct l2cap_instance_s { + struct bt_link_s *link; + struct bt_l2cap_device_s *dev; + int role; + + uint8_t frame_in[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4))); + int frame_in_len; + + uint8_t frame_out[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4))); + int frame_out_len; + + /* Signalling channel timers. They exist per-request but we can make + * sure we have no more than one outstanding request at any time. */ + QEMUTimer *rtx; + QEMUTimer *ertx; + + int last_id; + int next_id; + + struct l2cap_chan_s { + struct bt_l2cap_conn_params_s params; + + void (*frame_in)(struct l2cap_chan_s *chan, uint16_t cid, + const l2cap_hdr *hdr, int len); + int mps; + int min_mtu; + + struct l2cap_instance_s *l2cap; + + /* Only allocated channels */ + uint16_t remote_cid; +#define L2CAP_CFG_INIT 2 +#define L2CAP_CFG_ACC 1 + int config_req_id; /* TODO: handle outgoing requests generically */ + int config; + + /* Only connection-oriented channels. Note: if we allow the tx and + * rx traffic to be in different modes at any time, we need two. */ + int mode; + + /* Only flow-controlled, connection-oriented channels */ + uint8_t sdu[65536]; /* TODO: dynamically allocate */ + int len_cur, len_total; + int rexmit; + int monitor_timeout; + QEMUTimer *monitor_timer; + QEMUTimer *retransmission_timer; + } *cid[L2CAP_CID_MAX]; + /* The channel state machine states map as following: + * CLOSED -> !cid[N] + * WAIT_CONNECT -> never occurs + * WAIT_CONNECT_RSP -> never occurs + * CONFIG -> cid[N] && config < 3 + * WAIT_CONFIG -> never occurs, cid[N] && config == 0 && !config_r + * WAIT_SEND_CONFIG -> never occurs, cid[N] && config == 1 && !config_r + * WAIT_CONFIG_REQ_RSP -> cid[N] && config == 0 && config_req_id + * WAIT_CONFIG_RSP -> cid[N] && config == 1 && config_req_id + * WAIT_CONFIG_REQ -> cid[N] && config == 2 + * OPEN -> cid[N] && config == 3 + * WAIT_DISCONNECT -> never occurs + */ + + struct l2cap_chan_s signalling_ch; + struct l2cap_chan_s group_ch; +}; + +struct slave_l2cap_instance_s { + struct bt_link_s link; /* Underlying logical link (ACL) */ + struct l2cap_instance_s l2cap; +}; + +struct bt_l2cap_psm_s { + int psm; + int min_mtu; + int (*new_channel)(struct bt_l2cap_device_s *device, + struct bt_l2cap_conn_params_s *params); + struct bt_l2cap_psm_s *next; +}; + +static const uint16_t l2cap_fcs16_table[256] = { + 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, + 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, + 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, + 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, + 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, + 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, + 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, + 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, + 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, + 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, + 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, + 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, + 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, + 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, + 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, + 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, + 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, + 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, + 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, + 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, + 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, + 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, + 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, + 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, + 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, + 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, + 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, + 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, + 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, + 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, + 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, + 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040, +}; + +static uint16_t l2cap_fcs16(const uint8_t *message, int len) +{ + uint16_t fcs = 0x0000; + + while (len --) +#if 0 + { + int i; + + fcs ^= *message ++; + for (i = 8; i; -- i) + if (fcs & 1) + fcs = (fcs >> 1) ^ 0xa001; + else + fcs = (fcs >> 1); + } +#else + fcs = (fcs >> 8) ^ l2cap_fcs16_table[(fcs ^ *message ++) & 0xff]; +#endif + + return fcs; +} + +/* L2CAP layer logic (protocol) */ + +static void l2cap_retransmission_timer_update(struct l2cap_chan_s *ch) +{ +#if 0 + if (ch->mode != L2CAP_MODE_BASIC && ch->rexmit) + qemu_mod_timer(ch->retransmission_timer); + else + qemu_del_timer(ch->retransmission_timer); +#endif +} + +static void l2cap_monitor_timer_update(struct l2cap_chan_s *ch) +{ +#if 0 + if (ch->mode != L2CAP_MODE_BASIC && !ch->rexmit) + qemu_mod_timer(ch->monitor_timer); + else + qemu_del_timer(ch->monitor_timer); +#endif +} + +static void l2cap_command_reject(struct l2cap_instance_s *l2cap, int id, + uint16_t reason, const void *data, int plen) +{ + uint8_t *pkt; + l2cap_cmd_hdr *hdr; + l2cap_cmd_rej *params; + uint16_t len; + + reason = cpu_to_le16(reason); + len = cpu_to_le16(L2CAP_CMD_REJ_SIZE + plen); + + pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params, + L2CAP_CMD_HDR_SIZE + L2CAP_CMD_REJ_SIZE + plen); + hdr = (void *) (pkt + 0); + params = (void *) (pkt + L2CAP_CMD_HDR_SIZE); + + hdr->code = L2CAP_COMMAND_REJ; + hdr->ident = id; + memcpy(&hdr->len, &len, sizeof(hdr->len)); + memcpy(¶ms->reason, &reason, sizeof(reason)); + if (plen) + memcpy(pkt + L2CAP_CMD_HDR_SIZE + L2CAP_CMD_REJ_SIZE, data, plen); + + l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params); +} + +static void l2cap_command_reject_cid(struct l2cap_instance_s *l2cap, int id, + uint16_t reason, uint16_t dcid, uint16_t scid) +{ + l2cap_cmd_rej_cid params = { + .dcid = dcid, + .scid = scid, + }; + + l2cap_command_reject(l2cap, id, reason, ¶ms, L2CAP_CMD_REJ_CID_SIZE); +} + +static void l2cap_connection_response(struct l2cap_instance_s *l2cap, + int dcid, int scid, int result, int status) +{ + uint8_t *pkt; + l2cap_cmd_hdr *hdr; + l2cap_conn_rsp *params; + + pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params, + L2CAP_CMD_HDR_SIZE + L2CAP_CONN_RSP_SIZE); + hdr = (void *) (pkt + 0); + params = (void *) (pkt + L2CAP_CMD_HDR_SIZE); + + hdr->code = L2CAP_CONN_RSP; + hdr->ident = l2cap->last_id; + hdr->len = cpu_to_le16(L2CAP_CONN_RSP_SIZE); + + params->dcid = cpu_to_le16(dcid); + params->scid = cpu_to_le16(scid); + params->result = cpu_to_le16(result); + params->status = cpu_to_le16(status); + + l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params); +} + +static void l2cap_configuration_request(struct l2cap_instance_s *l2cap, + int dcid, int flag, const uint8_t *data, int len) +{ + uint8_t *pkt; + l2cap_cmd_hdr *hdr; + l2cap_conf_req *params; + + pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params, + L2CAP_CMD_HDR_SIZE + L2CAP_CONF_REQ_SIZE(len)); + hdr = (void *) (pkt + 0); + params = (void *) (pkt + L2CAP_CMD_HDR_SIZE); + + /* TODO: unify the id sequencing */ + l2cap->last_id = l2cap->next_id; + l2cap->next_id = l2cap->next_id == 255 ? 1 : l2cap->next_id + 1; + + hdr->code = L2CAP_CONF_REQ; + hdr->ident = l2cap->last_id; + hdr->len = cpu_to_le16(L2CAP_CONF_REQ_SIZE(len)); + + params->dcid = cpu_to_le16(dcid); + params->flags = cpu_to_le16(flag); + if (len) + memcpy(params->data, data, len); + + l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params); +} + +static void l2cap_configuration_response(struct l2cap_instance_s *l2cap, + int scid, int flag, int result, const uint8_t *data, int len) +{ + uint8_t *pkt; + l2cap_cmd_hdr *hdr; + l2cap_conf_rsp *params; + + pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params, + L2CAP_CMD_HDR_SIZE + L2CAP_CONF_RSP_SIZE(len)); + hdr = (void *) (pkt + 0); + params = (void *) (pkt + L2CAP_CMD_HDR_SIZE); + + hdr->code = L2CAP_CONF_RSP; + hdr->ident = l2cap->last_id; + hdr->len = cpu_to_le16(L2CAP_CONF_RSP_SIZE(len)); + + params->scid = cpu_to_le16(scid); + params->flags = cpu_to_le16(flag); + params->result = cpu_to_le16(result); + if (len) + memcpy(params->data, data, len); + + l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params); +} + +static void l2cap_disconnection_response(struct l2cap_instance_s *l2cap, + int dcid, int scid) +{ + uint8_t *pkt; + l2cap_cmd_hdr *hdr; + l2cap_disconn_rsp *params; + + pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params, + L2CAP_CMD_HDR_SIZE + L2CAP_DISCONN_RSP_SIZE); + hdr = (void *) (pkt + 0); + params = (void *) (pkt + L2CAP_CMD_HDR_SIZE); + + hdr->code = L2CAP_DISCONN_RSP; + hdr->ident = l2cap->last_id; + hdr->len = cpu_to_le16(L2CAP_DISCONN_RSP_SIZE); + + params->dcid = cpu_to_le16(dcid); + params->scid = cpu_to_le16(scid); + + l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params); +} + +static void l2cap_echo_response(struct l2cap_instance_s *l2cap, + const uint8_t *data, int len) +{ + uint8_t *pkt; + l2cap_cmd_hdr *hdr; + uint8_t *params; + + pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params, + L2CAP_CMD_HDR_SIZE + len); + hdr = (void *) (pkt + 0); + params = (void *) (pkt + L2CAP_CMD_HDR_SIZE); + + hdr->code = L2CAP_ECHO_RSP; + hdr->ident = l2cap->last_id; + hdr->len = cpu_to_le16(len); + + memcpy(params, data, len); + + l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params); +} + +static void l2cap_info_response(struct l2cap_instance_s *l2cap, int type, + int result, const uint8_t *data, int len) +{ + uint8_t *pkt; + l2cap_cmd_hdr *hdr; + l2cap_info_rsp *params; + + pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params, + L2CAP_CMD_HDR_SIZE + L2CAP_INFO_RSP_SIZE + len); + hdr = (void *) (pkt + 0); + params = (void *) (pkt + L2CAP_CMD_HDR_SIZE); + + hdr->code = L2CAP_INFO_RSP; + hdr->ident = l2cap->last_id; + hdr->len = cpu_to_le16(L2CAP_INFO_RSP_SIZE + len); + + params->type = cpu_to_le16(type); + params->result = cpu_to_le16(result); + if (len) + memcpy(params->data, data, len); + + l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params); +} + +static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len); +static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms); +#if 0 +static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len); +static void l2cap_iframe_submit(struct bt_l2cap_conn_params_s *parm); +#endif +static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid, + const l2cap_hdr *hdr, int len); +static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid, + const l2cap_hdr *hdr, int len); + +static int l2cap_cid_new(struct l2cap_instance_s *l2cap) +{ + int i; + + for (i = L2CAP_CID_ALLOC; i < L2CAP_CID_MAX; i ++) + if (!l2cap->cid[i]) + return i; + + return L2CAP_CID_INVALID; +} + +static inline struct bt_l2cap_psm_s *l2cap_psm( + struct bt_l2cap_device_s *device, int psm) +{ + struct bt_l2cap_psm_s *ret = device->first_psm; + + while (ret && ret->psm != psm) + ret = ret->next; + + return ret; +} + +static struct l2cap_chan_s *l2cap_channel_open(struct l2cap_instance_s *l2cap, + int psm, int source_cid) +{ + struct l2cap_chan_s *ch = 0; + struct bt_l2cap_psm_s *psm_info; + int result, status; + int cid = l2cap_cid_new(l2cap); + + if (cid) { + /* See what the channel is to be used for.. */ + psm_info = l2cap_psm(l2cap->dev, psm); + + if (psm_info) { + /* Device supports this use-case. */ + ch = qemu_mallocz(sizeof(*ch)); + ch->params.sdu_out = l2cap_bframe_out; + ch->params.sdu_submit = l2cap_bframe_submit; + ch->frame_in = l2cap_bframe_in; + ch->mps = 65536; + ch->min_mtu = MAX(48, psm_info->min_mtu); + ch->params.remote_mtu = MAX(672, ch->min_mtu); + ch->remote_cid = source_cid; + ch->mode = L2CAP_MODE_BASIC; + ch->l2cap = l2cap; + + /* Does it feel like opening yet another channel though? */ + if (!psm_info->new_channel(l2cap->dev, &ch->params)) { + l2cap->cid[cid] = ch; + + result = L2CAP_CR_SUCCESS; + status = L2CAP_CS_NO_INFO; + } else { + qemu_free(ch); + + result = L2CAP_CR_NO_MEM; + status = L2CAP_CS_NO_INFO; + } + } else { + result = L2CAP_CR_BAD_PSM; + status = L2CAP_CS_NO_INFO; + } + } else { + result = L2CAP_CR_NO_MEM; + status = L2CAP_CS_NO_INFO; + } + + l2cap_connection_response(l2cap, cid, source_cid, result, status); + + return ch; +} + +static void l2cap_channel_close(struct l2cap_instance_s *l2cap, + int cid, int source_cid) +{ + struct l2cap_chan_s *ch = 0; + + /* According to Volume 3, section 6.1.1, pg 1048 of BT Core V2.0, a + * connection in CLOSED state still responds with a L2CAP_DisconnectRsp + * message on an L2CAP_DisconnectReq event. */ + if (unlikely(cid < L2CAP_CID_ALLOC)) { + l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL, + cid, source_cid); + return; + } + if (likely(cid >= L2CAP_CID_ALLOC && cid < L2CAP_CID_MAX)) + ch = l2cap->cid[cid]; + + if (likely(ch)) { + if (ch->remote_cid != source_cid) { + fprintf(stderr, "%s: Ignoring a Disconnection Request with the " + "invalid SCID %04x.\n", __FUNCTION__, source_cid); + return; + } + + l2cap->cid[cid] = 0; + + ch->params.close(ch->params.opaque); + qemu_free(ch); + } + + l2cap_disconnection_response(l2cap, cid, source_cid); +} + +static void l2cap_channel_config_null(struct l2cap_instance_s *l2cap, + struct l2cap_chan_s *ch) +{ + l2cap_configuration_request(l2cap, ch->remote_cid, 0, 0, 0); + ch->config_req_id = l2cap->last_id; + ch->config &= ~L2CAP_CFG_INIT; +} + +static void l2cap_channel_config_req_event(struct l2cap_instance_s *l2cap, + struct l2cap_chan_s *ch) +{ + /* Use all default channel options and terminate negotiation. */ + l2cap_channel_config_null(l2cap, ch); +} + +static int l2cap_channel_config(struct l2cap_instance_s *l2cap, + struct l2cap_chan_s *ch, int flag, + const uint8_t *data, int len) +{ + l2cap_conf_opt *opt; + l2cap_conf_opt_qos *qos; + uint32_t val; + uint8_t rsp[len]; + int result = L2CAP_CONF_SUCCESS; + + data = memcpy(rsp, data, len); + while (len) { + opt = (void *) data; + + if (len < L2CAP_CONF_OPT_SIZE || + len < L2CAP_CONF_OPT_SIZE + opt->len) { + result = L2CAP_CONF_REJECT; + break; + } + data += L2CAP_CONF_OPT_SIZE + opt->len; + len -= L2CAP_CONF_OPT_SIZE + opt->len; + + switch (opt->type & 0x7f) { + case L2CAP_CONF_MTU: + if (opt->len != 2) { + result = L2CAP_CONF_REJECT; + break; + } + + /* MTU */ + val = le16_to_cpup((void *) opt->val); + if (val < ch->min_mtu) { + cpu_to_le16w((void *) opt->val, ch->min_mtu); + result = L2CAP_CONF_UNACCEPT; + break; + } + + ch->params.remote_mtu = val; + break; + + case L2CAP_CONF_FLUSH_TO: + if (opt->len != 2) { + result = L2CAP_CONF_REJECT; + break; + } + + /* Flush Timeout */ + val = le16_to_cpup((void *) opt->val); + if (val < 0x0001) { + opt->val[0] = 0xff; + opt->val[1] = 0xff; + result = L2CAP_CONF_UNACCEPT; + break; + } + break; + + case L2CAP_CONF_QOS: + if (opt->len != L2CAP_CONF_OPT_QOS_SIZE) { + result = L2CAP_CONF_REJECT; + break; + } + qos = (void *) opt->val; + + /* Flags */ + val = qos->flags; + if (val) { + qos->flags = 0; + result = L2CAP_CONF_UNACCEPT; + } + + /* Service type */ + val = qos->service_type; + if (val != L2CAP_CONF_QOS_BEST_EFFORT && + val != L2CAP_CONF_QOS_NO_TRAFFIC) { + qos->service_type = L2CAP_CONF_QOS_BEST_EFFORT; + result = L2CAP_CONF_UNACCEPT; + } + + if (val != L2CAP_CONF_QOS_NO_TRAFFIC) { + /* XXX: These values should possibly be calculated + * based on LM / baseband properties also. */ + + /* Token rate */ + val = le32_to_cpu(qos->token_rate); + if (val == L2CAP_CONF_QOS_WILDCARD) + qos->token_rate = cpu_to_le32(0x100000); + + /* Token bucket size */ + val = le32_to_cpu(qos->token_bucket_size); + if (val == L2CAP_CONF_QOS_WILDCARD) + qos->token_bucket_size = cpu_to_le32(65500); + + /* Any Peak bandwidth value is correct to return as-is */ + /* Any Access latency value is correct to return as-is */ + /* Any Delay variation value is correct to return as-is */ + } + break; + + case L2CAP_CONF_RFC: + if (opt->len != 9) { + result = L2CAP_CONF_REJECT; + break; + } + + /* Mode */ + val = opt->val[0]; + switch (val) { + case L2CAP_MODE_BASIC: + ch->mode = val; + ch->frame_in = l2cap_bframe_in; + + /* All other parameters shall be ignored */ + break; + + case L2CAP_MODE_RETRANS: + case L2CAP_MODE_FLOWCTL: + ch->mode = val; + ch->frame_in = l2cap_iframe_in; + /* Note: most of these parameters refer to incoming traffic + * so we don't need to save them as long as we can accept + * incoming PDUs at any values of the parameters. */ + + /* TxWindow size */ + val = opt->val[1]; + if (val < 1 || val > 32) { + opt->val[1] = 32; + result = L2CAP_CONF_UNACCEPT; + break; + } + + /* MaxTransmit */ + val = opt->val[2]; + if (val < 1) { + opt->val[2] = 1; + result = L2CAP_CONF_UNACCEPT; + break; + } + + /* Remote Retransmission time-out shouldn't affect local + * operation (?) */ + + /* The Monitor time-out drives the local Monitor timer (?), + * so save the value. */ + val = (opt->val[6] << 8) | opt->val[5]; + if (val < 30) { + opt->val[5] = 100 & 0xff; + opt->val[6] = 100 >> 8; + result = L2CAP_CONF_UNACCEPT; + break; + } + ch->monitor_timeout = val; + l2cap_monitor_timer_update(ch); + + /* MPS */ + val = (opt->val[8] << 8) | opt->val[7]; + if (val < ch->min_mtu) { + opt->val[7] = ch->min_mtu & 0xff; + opt->val[8] = ch->min_mtu >> 8; + result = L2CAP_CONF_UNACCEPT; + break; + } + ch->mps = val; + break; + + default: + result = L2CAP_CONF_UNACCEPT; + break; + } + break; + + default: + if (!(opt->type >> 7)) + result = L2CAP_CONF_UNKNOWN; + break; + } + + if (result != L2CAP_CONF_SUCCESS) + break; /* XXX: should continue? */ + } + + l2cap_configuration_response(l2cap, ch->remote_cid, + flag, result, rsp, len); + + return result == L2CAP_CONF_SUCCESS && !flag; +} + +static void l2cap_channel_config_req_msg(struct l2cap_instance_s *l2cap, + int flag, int cid, const uint8_t *data, int len) +{ + struct l2cap_chan_s *ch; + + if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) { + l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL, + cid, 0x0000); + return; + } + ch = l2cap->cid[cid]; + + /* From OPEN go to WAIT_CONFIG_REQ and from WAIT_CONFIG_REQ_RSP to + * WAIT_CONFIG_REQ_RSP. This is assuming the transition chart for OPEN + * on pg 1053, section 6.1.5, volume 3 of BT Core V2.0 has a mistake + * and on options-acceptable we go back to OPEN and otherwise to + * WAIT_CONFIG_REQ and not the other way. */ + ch->config &= ~L2CAP_CFG_ACC; + + if (l2cap_channel_config(l2cap, ch, flag, data, len)) + /* Go to OPEN or WAIT_CONFIG_RSP */ + ch->config |= L2CAP_CFG_ACC; + + /* TODO: if the incoming traffic flow control or retransmission mode + * changed then we probably need to also generate the + * ConfigureChannel_Req event and set the outgoing traffic to the same + * mode. */ + if (!(ch->config & L2CAP_CFG_INIT) && (ch->config & L2CAP_CFG_ACC) && + !ch->config_req_id) + l2cap_channel_config_req_event(l2cap, ch); +} + +static int l2cap_channel_config_rsp_msg(struct l2cap_instance_s *l2cap, + int result, int flag, int cid, const uint8_t *data, int len) +{ + struct l2cap_chan_s *ch; + + if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) { + l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL, + cid, 0x0000); + return 0; + } + ch = l2cap->cid[cid]; + + if (ch->config_req_id != l2cap->last_id) + return 1; + ch->config_req_id = 0; + + if (result == L2CAP_CONF_SUCCESS) { + if (!flag) + ch->config |= L2CAP_CFG_INIT; + else + l2cap_channel_config_null(l2cap, ch); + } else + /* Retry until we succeed */ + l2cap_channel_config_req_event(l2cap, ch); + + return 0; +} + +static void l2cap_channel_open_req_msg(struct l2cap_instance_s *l2cap, + int psm, int source_cid) +{ + struct l2cap_chan_s *ch = l2cap_channel_open(l2cap, psm, source_cid); + + if (!ch) + return; + + /* Optional */ + if (!(ch->config & L2CAP_CFG_INIT) && !ch->config_req_id) + l2cap_channel_config_req_event(l2cap, ch); +} + +static void l2cap_info(struct l2cap_instance_s *l2cap, int type) +{ + uint8_t data[4]; + int len = 0; + int result = L2CAP_IR_SUCCESS; + + switch (type) { + case L2CAP_IT_CL_MTU: + data[len ++] = l2cap->group_ch.mps & 0xff; + data[len ++] = l2cap->group_ch.mps >> 8; + break; + + case L2CAP_IT_FEAT_MASK: + /* (Prematurely) report Flow control and Retransmission modes. */ + data[len ++] = 0x03; + data[len ++] = 0x00; + data[len ++] = 0x00; + data[len ++] = 0x00; + break; + + default: + result = L2CAP_IR_NOTSUPP; + } + + l2cap_info_response(l2cap, type, result, data, len); +} + +static void l2cap_command(struct l2cap_instance_s *l2cap, int code, int id, + const uint8_t *params, int len) +{ + int err; + +#if 0 + /* TODO: do the IDs really have to be in sequence? */ + if (!id || (id != l2cap->last_id && id != l2cap->next_id)) { + fprintf(stderr, "%s: out of sequence command packet ignored.\n", + __FUNCTION__); + return; + } +#else + l2cap->next_id = id; +#endif + if (id == l2cap->next_id) { + l2cap->last_id = l2cap->next_id; + l2cap->next_id = l2cap->next_id == 255 ? 1 : l2cap->next_id + 1; + } else { + /* TODO: Need to re-send the same response, without re-executing + * the corresponding command! */ + } + + switch (code) { + case L2CAP_COMMAND_REJ: + if (unlikely(len != 2 && len != 4 && len != 6)) { + err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; + goto reject; + } + + /* We never issue commands other than Command Reject currently. */ + fprintf(stderr, "%s: stray Command Reject (%02x, %04x) " + "packet, ignoring.\n", __FUNCTION__, id, + le16_to_cpu(((l2cap_cmd_rej *) params)->reason)); + break; + + case L2CAP_CONN_REQ: + if (unlikely(len != L2CAP_CONN_REQ_SIZE)) { + err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; + goto reject; + } + + l2cap_channel_open_req_msg(l2cap, + le16_to_cpu(((l2cap_conn_req *) params)->psm), + le16_to_cpu(((l2cap_conn_req *) params)->scid)); + break; + + case L2CAP_CONN_RSP: + if (unlikely(len != L2CAP_CONN_RSP_SIZE)) { + err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; + goto reject; + } + + /* We never issue Connection Requests currently. TODO */ + fprintf(stderr, "%s: unexpected Connection Response (%02x) " + "packet, ignoring.\n", __FUNCTION__, id); + break; + + case L2CAP_CONF_REQ: + if (unlikely(len < L2CAP_CONF_REQ_SIZE(0))) { + err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; + goto reject; + } + + l2cap_channel_config_req_msg(l2cap, + le16_to_cpu(((l2cap_conf_req *) params)->flags) & 1, + le16_to_cpu(((l2cap_conf_req *) params)->dcid), + ((l2cap_conf_req *) params)->data, + len - L2CAP_CONF_REQ_SIZE(0)); + break; + + case L2CAP_CONF_RSP: + if (unlikely(len < L2CAP_CONF_RSP_SIZE(0))) { + err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; + goto reject; + } + + if (l2cap_channel_config_rsp_msg(l2cap, + le16_to_cpu(((l2cap_conf_rsp *) params)->result), + le16_to_cpu(((l2cap_conf_rsp *) params)->flags) & 1, + le16_to_cpu(((l2cap_conf_rsp *) params)->scid), + ((l2cap_conf_rsp *) params)->data, + len - L2CAP_CONF_RSP_SIZE(0))) + fprintf(stderr, "%s: unexpected Configure Response (%02x) " + "packet, ignoring.\n", __FUNCTION__, id); + break; + + case L2CAP_DISCONN_REQ: + if (unlikely(len != L2CAP_DISCONN_REQ_SIZE)) { + err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; + goto reject; + } + + l2cap_channel_close(l2cap, + le16_to_cpu(((l2cap_disconn_req *) params)->dcid), + le16_to_cpu(((l2cap_disconn_req *) params)->scid)); + break; + + case L2CAP_DISCONN_RSP: + if (unlikely(len != L2CAP_DISCONN_RSP_SIZE)) { + err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; + goto reject; + } + + /* We never issue Disconnection Requests currently. TODO */ + fprintf(stderr, "%s: unexpected Disconnection Response (%02x) " + "packet, ignoring.\n", __FUNCTION__, id); + break; + + case L2CAP_ECHO_REQ: + l2cap_echo_response(l2cap, params, len); + break; + + case L2CAP_ECHO_RSP: + /* We never issue Echo Requests currently. TODO */ + fprintf(stderr, "%s: unexpected Echo Response (%02x) " + "packet, ignoring.\n", __FUNCTION__, id); + break; + + case L2CAP_INFO_REQ: + if (unlikely(len != L2CAP_INFO_REQ_SIZE)) { + err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; + goto reject; + } + + l2cap_info(l2cap, le16_to_cpu(((l2cap_info_req *) params)->type)); + break; + + case L2CAP_INFO_RSP: + if (unlikely(len != L2CAP_INFO_RSP_SIZE)) { + err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; + goto reject; + } + + /* We never issue Information Requests currently. TODO */ + fprintf(stderr, "%s: unexpected Information Response (%02x) " + "packet, ignoring.\n", __FUNCTION__, id); + break; + + default: + err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; + reject: + l2cap_command_reject(l2cap, id, err, 0, 0); + break; + } +} + +static void l2cap_rexmit_enable(struct l2cap_chan_s *ch, int enable) +{ + ch->rexmit = enable; + + l2cap_retransmission_timer_update(ch); + l2cap_monitor_timer_update(ch); +} + +/* Command frame SDU */ +static void l2cap_cframe_in(void *opaque, const uint8_t *data, int len) +{ + struct l2cap_instance_s *l2cap = opaque; + const l2cap_cmd_hdr *hdr; + int clen; + + while (len) { + hdr = (void *) data; + if (len < L2CAP_CMD_HDR_SIZE) + /* TODO: signal an error */ + return; + len -= L2CAP_CMD_HDR_SIZE; + data += L2CAP_CMD_HDR_SIZE; + + clen = le16_to_cpu(hdr->len); + if (len < clen) { + l2cap_command_reject(l2cap, hdr->ident, + L2CAP_REJ_CMD_NOT_UNDERSTOOD, 0, 0); + break; + } + + l2cap_command(l2cap, hdr->code, hdr->ident, data, clen); + len -= clen; + data += clen; + } +} + +/* Group frame SDU */ +static void l2cap_gframe_in(void *opaque, const uint8_t *data, int len) +{ +} + +/* Supervisory frame */ +static void l2cap_sframe_in(struct l2cap_chan_s *ch, uint16_t ctrl) +{ +} + +/* Basic L2CAP mode Information frame */ +static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid, + const l2cap_hdr *hdr, int len) +{ + /* We have a full SDU, no further processing */ + ch->params.sdu_in(ch->params.opaque, hdr->data, len); +} + +/* Flow Control and Retransmission mode frame */ +static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid, + const l2cap_hdr *hdr, int len) +{ + uint16_t fcs = le16_to_cpup((void *) (hdr->data + len - 2)); + + if (len < 4) + goto len_error; + if (l2cap_fcs16((const uint8_t *) hdr, L2CAP_HDR_SIZE + len - 2) != fcs) + goto fcs_error; + + if ((hdr->data[0] >> 7) == ch->rexmit) + l2cap_rexmit_enable(ch, !(hdr->data[0] >> 7)); + + if (hdr->data[0] & 1) { + if (len != 4) + /* TODO: Signal an error? */; + return; + + return l2cap_sframe_in(ch, le16_to_cpup((void *) hdr->data)); + } + + switch (hdr->data[1] >> 6) { /* SAR */ + case L2CAP_SAR_NO_SEG: + if (ch->len_total) + goto seg_error; + if (len - 4 > ch->mps) + goto len_error; + + return ch->params.sdu_in(ch->params.opaque, hdr->data + 2, len - 4); + + case L2CAP_SAR_START: + if (ch->len_total || len < 6) + goto seg_error; + if (len - 6 > ch->mps) + goto len_error; + + ch->len_total = le16_to_cpup((void *) (hdr->data + 2)); + if (len >= 6 + ch->len_total) + goto seg_error; + + ch->len_cur = len - 6; + memcpy(ch->sdu, hdr->data + 4, ch->len_cur); + break; + + case L2CAP_SAR_END: + if (!ch->len_total || ch->len_cur + len - 4 < ch->len_total) + goto seg_error; + if (len - 4 > ch->mps) + goto len_error; + + memcpy(ch->sdu + ch->len_cur, hdr->data + 2, len - 4); + return ch->params.sdu_in(ch->params.opaque, ch->sdu, ch->len_total); + + case L2CAP_SAR_CONT: + if (!ch->len_total || ch->len_cur + len - 4 >= ch->len_total) + goto seg_error; + if (len - 4 > ch->mps) + goto len_error; + + memcpy(ch->sdu + ch->len_cur, hdr->data + 2, len - 4); + ch->len_cur += len - 4; + break; + + seg_error: + len_error: /* TODO */ + fcs_error: /* TODO */ + ch->len_cur = 0; + ch->len_total = 0; + break; + } +} + +static void l2cap_frame_in(struct l2cap_instance_s *l2cap, + const l2cap_hdr *frame) +{ + uint16_t cid = le16_to_cpu(frame->cid); + uint16_t len = le16_to_cpu(frame->len); + + if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) { + fprintf(stderr, "%s: frame addressed to a non-existent L2CAP " + "channel %04x received.\n", __FUNCTION__, cid); + return; + } + + l2cap->cid[cid]->frame_in(l2cap->cid[cid], cid, frame, len); +} + +/* "Recombination" */ +static void l2cap_pdu_in(struct l2cap_instance_s *l2cap, + const uint8_t *data, int len) +{ + const l2cap_hdr *hdr = (void *) l2cap->frame_in; + + if (unlikely(len + l2cap->frame_in_len > sizeof(l2cap->frame_in))) { + if (l2cap->frame_in_len < sizeof(l2cap->frame_in)) { + memcpy(l2cap->frame_in + l2cap->frame_in_len, data, + sizeof(l2cap->frame_in) - l2cap->frame_in_len); + l2cap->frame_in_len = sizeof(l2cap->frame_in); + /* TODO: truncate */ + l2cap_frame_in(l2cap, hdr); + } + + return; + } + + memcpy(l2cap->frame_in + l2cap->frame_in_len, data, len); + l2cap->frame_in_len += len; + + if (len >= L2CAP_HDR_SIZE) + if (len >= L2CAP_HDR_SIZE + le16_to_cpu(hdr->len)) + l2cap_frame_in(l2cap, hdr); + /* There is never a start of a new PDU in the same ACL packet, so + * no need to memmove the remaining payload and loop. */ +} + +static inline uint8_t *l2cap_pdu_out(struct l2cap_instance_s *l2cap, + uint16_t cid, uint16_t len) +{ + l2cap_hdr *hdr = (void *) l2cap->frame_out; + + l2cap->frame_out_len = len + L2CAP_HDR_SIZE; + + hdr->cid = cpu_to_le16(cid); + hdr->len = cpu_to_le16(len); + + return l2cap->frame_out + L2CAP_HDR_SIZE; +} + +static inline void l2cap_pdu_submit(struct l2cap_instance_s *l2cap) +{ + /* TODO: Fragmentation */ + (l2cap->role ? + l2cap->link->slave->lmp_acl_data : l2cap->link->host->lmp_acl_resp) + (l2cap->link, l2cap->frame_out, 1, l2cap->frame_out_len); +} + +static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len) +{ + struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm; + + if (len > chan->params.remote_mtu) { + fprintf(stderr, "%s: B-Frame for CID %04x longer than %i octets.\n", + __FUNCTION__, + chan->remote_cid, chan->params.remote_mtu); + exit(-1); + } + + return l2cap_pdu_out(chan->l2cap, chan->remote_cid, len); +} + +static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms) +{ + struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parms; + + return l2cap_pdu_submit(chan->l2cap); +} + +#if 0 +/* Stub: Only used if an emulated device requests outgoing flow control */ +static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len) +{ + struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm; + + if (len > chan->params.remote_mtu) { + /* TODO: slice into segments and queue each segment as a separate + * I-Frame in a FIFO of I-Frames, local to the CID. */ + } else { + /* TODO: add to the FIFO of I-Frames, local to the CID. */ + /* Possibly we need to return a pointer to a contiguous buffer + * for now and then memcpy from it into FIFOs in l2cap_iframe_submit + * while segmenting at the same time. */ + } + return 0; +} + +static void l2cap_iframe_submit(struct bt_l2cap_conn_params_s *parm) +{ + /* TODO: If flow control indicates clear to send, start submitting the + * invidual I-Frames from the FIFO, but don't remove them from there. + * Kick the appropriate timer until we get an S-Frame, and only then + * remove from FIFO or resubmit and re-kick the timer if the timer + * expired. */ +} +#endif + +static void l2cap_init(struct l2cap_instance_s *l2cap, + struct bt_link_s *link, int role) +{ + l2cap->link = link; + l2cap->role = role; + l2cap->dev = (struct bt_l2cap_device_s *) + (role ? link->host : link->slave); + + l2cap->next_id = 1; + + /* Establish the signalling channel */ + l2cap->signalling_ch.params.sdu_in = l2cap_cframe_in; + l2cap->signalling_ch.params.sdu_out = l2cap_bframe_out; + l2cap->signalling_ch.params.sdu_submit = l2cap_bframe_submit; + l2cap->signalling_ch.params.opaque = l2cap; + l2cap->signalling_ch.params.remote_mtu = 48; + l2cap->signalling_ch.remote_cid = L2CAP_CID_SIGNALLING; + l2cap->signalling_ch.frame_in = l2cap_bframe_in; + l2cap->signalling_ch.mps = 65536; + l2cap->signalling_ch.min_mtu = 48; + l2cap->signalling_ch.mode = L2CAP_MODE_BASIC; + l2cap->signalling_ch.l2cap = l2cap; + l2cap->cid[L2CAP_CID_SIGNALLING] = &l2cap->signalling_ch; + + /* Establish the connection-less data channel */ + l2cap->group_ch.params.sdu_in = l2cap_gframe_in; + l2cap->group_ch.params.opaque = l2cap; + l2cap->group_ch.frame_in = l2cap_bframe_in; + l2cap->group_ch.mps = 65533; + l2cap->group_ch.l2cap = l2cap; + l2cap->group_ch.remote_cid = L2CAP_CID_INVALID; + l2cap->cid[L2CAP_CID_GROUP] = &l2cap->group_ch; +} + +static void l2cap_teardown(struct l2cap_instance_s *l2cap, int send_disconnect) +{ + int cid; + + /* Don't send DISCONNECT if we are currently handling a DISCONNECT + * sent from the other side. */ + if (send_disconnect) { + if (l2cap->role) + l2cap->dev->device.lmp_disconnect_slave(l2cap->link); + /* l2cap->link is invalid from now on. */ + else + l2cap->dev->device.lmp_disconnect_master(l2cap->link); + } + + for (cid = L2CAP_CID_ALLOC; cid < L2CAP_CID_MAX; cid ++) + if (l2cap->cid[cid]) { + l2cap->cid[cid]->params.close(l2cap->cid[cid]->params.opaque); + free(l2cap->cid[cid]); + } + + if (l2cap->role) + qemu_free(l2cap); + else + qemu_free(l2cap->link); +} + +/* L2CAP glue to lower layers in bluetooth stack (LMP) */ + +static void l2cap_lmp_connection_request(struct bt_link_s *link) +{ + struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->slave; + struct slave_l2cap_instance_s *l2cap; + + /* Always accept - we only get called if (dev->device->page_scan). */ + + l2cap = qemu_mallocz(sizeof(struct slave_l2cap_instance_s)); + l2cap->link.slave = &dev->device; + l2cap->link.host = link->host; + l2cap_init(&l2cap->l2cap, &l2cap->link, 0); + + /* Always at the end */ + link->host->reject_reason = 0; + link->host->lmp_connection_complete(&l2cap->link); +} + +/* Stub */ +static void l2cap_lmp_connection_complete(struct bt_link_s *link) +{ + struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host; + struct l2cap_instance_s *l2cap; + + if (dev->device.reject_reason) { + /* Signal to upper layer */ + return; + } + + l2cap = qemu_mallocz(sizeof(struct l2cap_instance_s)); + l2cap_init(l2cap, link, 1); + + link->acl_mode = acl_active; + + /* Signal to upper layer */ +} + +/* Stub */ +static void l2cap_lmp_disconnect_host(struct bt_link_s *link) +{ + struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host; + struct l2cap_instance_s *l2cap = + /* TODO: Retrieve from upper layer */ (void *) dev; + + /* Signal to upper layer */ + + l2cap_teardown(l2cap, 0); +} + +static void l2cap_lmp_disconnect_slave(struct bt_link_s *link) +{ + struct slave_l2cap_instance_s *l2cap = + (struct slave_l2cap_instance_s *) link; + + l2cap_teardown(&l2cap->l2cap, 0); +} + +static void l2cap_lmp_acl_data_slave(struct bt_link_s *link, + const uint8_t *data, int start, int len) +{ + struct slave_l2cap_instance_s *l2cap = + (struct slave_l2cap_instance_s *) link; + + if (start) + l2cap->l2cap.frame_in_len = 0; + + l2cap_pdu_in(&l2cap->l2cap, data, len); +} + +/* Stub */ +static void l2cap_lmp_acl_data_host(struct bt_link_s *link, + const uint8_t *data, int start, int len) +{ + struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host; + struct l2cap_instance_s *l2cap = + /* TODO: Retrieve from upper layer */ (void *) dev; + + if (start) + l2cap->frame_in_len = 0; + + l2cap_pdu_in(l2cap, data, len); +} + +static void l2cap_dummy_destroy(struct bt_device_s *dev) +{ + struct bt_l2cap_device_s *l2cap_dev = (struct bt_l2cap_device_s *) dev; + + bt_l2cap_device_done(l2cap_dev); +} + +void bt_l2cap_device_init(struct bt_l2cap_device_s *dev, + struct bt_scatternet_s *net) +{ + bt_device_init(&dev->device, net); + + dev->device.lmp_connection_request = l2cap_lmp_connection_request; + dev->device.lmp_connection_complete = l2cap_lmp_connection_complete; + dev->device.lmp_disconnect_master = l2cap_lmp_disconnect_host; + dev->device.lmp_disconnect_slave = l2cap_lmp_disconnect_slave; + dev->device.lmp_acl_data = l2cap_lmp_acl_data_slave; + dev->device.lmp_acl_resp = l2cap_lmp_acl_data_host; + + dev->device.handle_destroy = l2cap_dummy_destroy; +} + +void bt_l2cap_device_done(struct bt_l2cap_device_s *dev) +{ + bt_device_done(&dev->device); + + /* Should keep a list of all instances and go through it and + * invoke l2cap_teardown() for each. */ +} + +void bt_l2cap_psm_register(struct bt_l2cap_device_s *dev, int psm, int min_mtu, + int (*new_channel)(struct bt_l2cap_device_s *dev, + struct bt_l2cap_conn_params_s *params)) +{ + struct bt_l2cap_psm_s *new_psm = l2cap_psm(dev, psm); + + if (new_psm) { + fprintf(stderr, "%s: PSM %04x already registered for device `%s'.\n", + __FUNCTION__, psm, dev->device.lmp_name); + exit(-1); + } + + new_psm = qemu_mallocz(sizeof(*new_psm)); + new_psm->psm = psm; + new_psm->min_mtu = min_mtu; + new_psm->new_channel = new_channel; + new_psm->next = dev->first_psm; + dev->first_psm = new_psm; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/bt-sdp.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/bt-sdp.c --- qemu-0.9.1/hw/bt-sdp.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/bt-sdp.c 2008-10-25 01:10:20.000000000 +0100 @@ -0,0 +1,969 @@ +/* + * Service Discover Protocol server for QEMU L2CAP devices + * + * Copyright (C) 2008 Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "qemu-common.h" +#include "bt.h" + +struct bt_l2cap_sdp_state_s { + struct bt_l2cap_conn_params_s *channel; + + struct sdp_service_record_s { + int match; + + int *uuid; + int uuids; + struct sdp_service_attribute_s { + int match; + + int attribute_id; + int len; + void *pair; + } *attribute_list; + int attributes; + } *service_list; + int services; +}; + +static ssize_t sdp_datalen(const uint8_t **element, ssize_t *left) +{ + size_t len = *(*element) ++ & SDP_DSIZE_MASK; + + if (!*left) + return -1; + (*left) --; + + if (len < SDP_DSIZE_NEXT1) + return 1 << len; + else if (len == SDP_DSIZE_NEXT1) { + if (*left < 1) + return -1; + (*left) --; + + return *(*element) ++; + } else if (len == SDP_DSIZE_NEXT2) { + if (*left < 2) + return -1; + (*left) -= 2; + + len = (*(*element) ++) << 8; + return len | (*(*element) ++); + } else { + if (*left < 4) + return -1; + (*left) -= 4; + + len = (*(*element) ++) << 24; + len |= (*(*element) ++) << 16; + len |= (*(*element) ++) << 8; + return len | (*(*element) ++); + } +} + +static const uint8_t bt_base_uuid[12] = { + 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb, +}; + +static int sdp_uuid_match(struct sdp_service_record_s *record, + const uint8_t *uuid, ssize_t datalen) +{ + int *lo, hi, val; + + if (datalen == 16 || datalen == 4) { + if (datalen == 16 && memcmp(uuid + 4, bt_base_uuid, 12)) + return 0; + + if (uuid[0] | uuid[1]) + return 0; + uuid += 2; + } + + val = (uuid[0] << 8) | uuid[1]; + lo = record->uuid; + hi = record->uuids; + while (hi >>= 1) + if (lo[hi] <= val) + lo += hi; + + return *lo == val; +} + +#define CONTINUATION_PARAM_SIZE (1 + sizeof(int)) +#define MAX_PDU_OUT_SIZE 96 /* Arbitrary */ +#define PDU_HEADER_SIZE 5 +#define MAX_RSP_PARAM_SIZE (MAX_PDU_OUT_SIZE - PDU_HEADER_SIZE - \ + CONTINUATION_PARAM_SIZE) + +static int sdp_svc_match(struct bt_l2cap_sdp_state_s *sdp, + const uint8_t **req, ssize_t *len) +{ + size_t datalen; + int i; + + if ((**req & ~SDP_DSIZE_MASK) != SDP_DTYPE_UUID) + return 1; + + datalen = sdp_datalen(req, len); + if (datalen != 2 && datalen != 4 && datalen != 16) + return 1; + + for (i = 0; i < sdp->services; i ++) + if (sdp_uuid_match(&sdp->service_list[i], *req, datalen)) + sdp->service_list[i].match = 1; + + (*req) += datalen; + (*len) -= datalen; + + return 0; +} + +static ssize_t sdp_svc_search(struct bt_l2cap_sdp_state_s *sdp, + uint8_t *rsp, const uint8_t *req, ssize_t len) +{ + ssize_t seqlen; + int i, count, start, end, max; + int32_t handle; + + /* Perform the search */ + for (i = 0; i < sdp->services; i ++) + sdp->service_list[i].match = 0; + + if (len < 1) + return -SDP_INVALID_SYNTAX; + if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) { + seqlen = sdp_datalen(&req, &len); + if (seqlen < 3 || len < seqlen) + return -SDP_INVALID_SYNTAX; + len -= seqlen; + + while (seqlen) + if (sdp_svc_match(sdp, &req, &seqlen)) + return -SDP_INVALID_SYNTAX; + } else if (sdp_svc_match(sdp, &req, &seqlen)) + return -SDP_INVALID_SYNTAX; + + if (len < 3) + return -SDP_INVALID_SYNTAX; + end = (req[0] << 8) | req[1]; + req += 2; + len -= 2; + + if (*req) { + if (len <= sizeof(int)) + return -SDP_INVALID_SYNTAX; + len -= sizeof(int); + memcpy(&start, req + 1, sizeof(int)); + } else + start = 0; + + if (len > 1); + return -SDP_INVALID_SYNTAX; + + /* Output the results */ + len = 4; + count = 0; + end = start; + for (i = 0; i < sdp->services; i ++) + if (sdp->service_list[i].match) { + if (count >= start && count < max && len + 4 < MAX_RSP_PARAM_SIZE) { + handle = i; + memcpy(rsp + len, &handle, 4); + len += 4; + end = count + 1; + } + + count ++; + } + + rsp[0] = count >> 8; + rsp[1] = count & 0xff; + rsp[2] = (end - start) >> 8; + rsp[3] = (end - start) & 0xff; + + if (end < count) { + rsp[len ++] = sizeof(int); + memcpy(rsp + len, &end, sizeof(int)); + len += 4; + } else + rsp[len ++] = 0; + + return len; +} + +static int sdp_attr_match(struct sdp_service_record_s *record, + const uint8_t **req, ssize_t *len) +{ + int i, start, end; + + if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_2)) { + (*req) ++; + if (*len < 3) + return 1; + + start = (*(*req) ++) << 8; + start |= *(*req) ++; + end = start; + *len -= 3; + } else if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_4)) { + (*req) ++; + if (*len < 5) + return 1; + + start = (*(*req) ++) << 8; + start |= *(*req) ++; + end = (*(*req) ++) << 8; + end |= *(*req) ++; + *len -= 5; + } else + return 1; + + for (i = 0; i < record->attributes; i ++) + if (record->attribute_list[i].attribute_id >= start && + record->attribute_list[i].attribute_id <= end) + record->attribute_list[i].match = 1; + + return 0; +} + +static ssize_t sdp_attr_get(struct bt_l2cap_sdp_state_s *sdp, + uint8_t *rsp, const uint8_t *req, ssize_t len) +{ + ssize_t seqlen; + int i, start, end, max; + int32_t handle; + struct sdp_service_record_s *record; + uint8_t *lst; + + /* Perform the search */ + if (len < 7) + return -SDP_INVALID_SYNTAX; + memcpy(&handle, req, 4); + req += 4; + len -= 4; + + if (handle < 0 || handle > sdp->services) + return -SDP_INVALID_RECORD_HANDLE; + record = &sdp->service_list[handle]; + + for (i = 0; i < record->attributes; i ++) + record->attribute_list[i].match = 0; + + max = (req[0] << 8) | req[1]; + req += 2; + len -= 2; + if (max < 0x0007) + return -SDP_INVALID_SYNTAX; + + if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) { + seqlen = sdp_datalen(&req, &len); + if (seqlen < 3 || len < seqlen) + return -SDP_INVALID_SYNTAX; + len -= seqlen; + + while (seqlen) + if (sdp_attr_match(record, &req, &seqlen)) + return -SDP_INVALID_SYNTAX; + } else if (sdp_attr_match(record, &req, &seqlen)) + return -SDP_INVALID_SYNTAX; + + if (len < 1) + return -SDP_INVALID_SYNTAX; + + if (*req) { + if (len <= sizeof(int)) + return -SDP_INVALID_SYNTAX; + len -= sizeof(int); + memcpy(&start, req + 1, sizeof(int)); + } else + start = 0; + + if (len > 1) + return -SDP_INVALID_SYNTAX; + + /* Output the results */ + lst = rsp + 2; + max = MIN(max, MAX_RSP_PARAM_SIZE); + len = 3 - start; + end = 0; + for (i = 0; i < record->attributes; i ++) + if (record->attribute_list[i].match) { + if (len >= 0 && len + record->attribute_list[i].len < max) { + memcpy(lst + len, record->attribute_list[i].pair, + record->attribute_list[i].len); + end = len + record->attribute_list[i].len; + } + len += record->attribute_list[i].len; + } + if (0 >= start) { + lst[0] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2; + lst[1] = (len + start - 3) >> 8; + lst[2] = (len + start - 3) & 0xff; + } + + rsp[0] = end >> 8; + rsp[1] = end & 0xff; + + if (end < len) { + len = end + start; + lst[end ++] = sizeof(int); + memcpy(lst + end, &len, sizeof(int)); + end += sizeof(int); + } else + lst[end ++] = 0; + + return end + 2; +} + +static int sdp_svc_attr_match(struct bt_l2cap_sdp_state_s *sdp, + const uint8_t **req, ssize_t *len) +{ + int i, j, start, end; + struct sdp_service_record_s *record; + + if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_2)) { + (*req) ++; + if (*len < 3) + return 1; + + start = (*(*req) ++) << 8; + start |= *(*req) ++; + end = start; + *len -= 3; + } else if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_4)) { + (*req) ++; + if (*len < 5) + return 1; + + start = (*(*req) ++) << 8; + start |= *(*req) ++; + end = (*(*req) ++) << 8; + end |= *(*req) ++; + *len -= 5; + } else + return 1; + + for (i = 0; i < sdp->services; i ++) + if ((record = &sdp->service_list[i])->match) + for (j = 0; j < record->attributes; j ++) + if (record->attribute_list[j].attribute_id >= start && + record->attribute_list[j].attribute_id <= end) + record->attribute_list[j].match = 1; + + return 0; +} + +static ssize_t sdp_svc_search_attr_get(struct bt_l2cap_sdp_state_s *sdp, + uint8_t *rsp, const uint8_t *req, ssize_t len) +{ + ssize_t seqlen; + int i, j, start, end, max; + struct sdp_service_record_s *record; + uint8_t *lst; + + /* Perform the search */ + for (i = 0; i < sdp->services; i ++) { + sdp->service_list[i].match = 0; + for (j = 0; j < sdp->service_list[i].attributes; j ++) + sdp->service_list[i].attribute_list[j].match = 0; + } + + if (len < 1) + return -SDP_INVALID_SYNTAX; + if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) { + seqlen = sdp_datalen(&req, &len); + if (seqlen < 3 || len < seqlen) + return -SDP_INVALID_SYNTAX; + len -= seqlen; + + while (seqlen) + if (sdp_svc_match(sdp, &req, &seqlen)) + return -SDP_INVALID_SYNTAX; + } else if (sdp_svc_match(sdp, &req, &seqlen)) + return -SDP_INVALID_SYNTAX; + + if (len < 3) + return -SDP_INVALID_SYNTAX; + max = (req[0] << 8) | req[1]; + req += 2; + len -= 2; + if (max < 0x0007) + return -SDP_INVALID_SYNTAX; + + if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) { + seqlen = sdp_datalen(&req, &len); + if (seqlen < 3 || len < seqlen) + return -SDP_INVALID_SYNTAX; + len -= seqlen; + + while (seqlen) + if (sdp_svc_attr_match(sdp, &req, &seqlen)) + return -SDP_INVALID_SYNTAX; + } else if (sdp_svc_attr_match(sdp, &req, &seqlen)) + return -SDP_INVALID_SYNTAX; + + if (len < 1) + return -SDP_INVALID_SYNTAX; + + if (*req) { + if (len <= sizeof(int)) + return -SDP_INVALID_SYNTAX; + len -= sizeof(int); + memcpy(&start, req + 1, sizeof(int)); + } else + start = 0; + + if (len > 1) + return -SDP_INVALID_SYNTAX; + + /* Output the results */ + /* This assumes empty attribute lists are never to be returned even + * for matching Service Records. In practice this shouldn't happen + * as the requestor will usually include the always present + * ServiceRecordHandle AttributeID in AttributeIDList. */ + lst = rsp + 2; + max = MIN(max, MAX_RSP_PARAM_SIZE); + len = 3 - start; + end = 0; + for (i = 0; i < sdp->services; i ++) + if ((record = &sdp->service_list[i])->match) { + len += 3; + seqlen = len; + for (j = 0; j < record->attributes; j ++) + if (record->attribute_list[j].match) { + if (len >= 0) + if (len + record->attribute_list[j].len < max) { + memcpy(lst + len, record->attribute_list[j].pair, + record->attribute_list[j].len); + end = len + record->attribute_list[j].len; + } + len += record->attribute_list[j].len; + } + if (seqlen == len) + len -= 3; + else if (seqlen >= 3 && seqlen < max) { + lst[seqlen - 3] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2; + lst[seqlen - 2] = (len - seqlen) >> 8; + lst[seqlen - 1] = (len - seqlen) & 0xff; + } + } + if (len == 3 - start) + len -= 3; + else if (0 >= start) { + lst[0] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2; + lst[1] = (len + start - 3) >> 8; + lst[2] = (len + start - 3) & 0xff; + } + + rsp[0] = end >> 8; + rsp[1] = end & 0xff; + + if (end < len) { + len = end + start; + lst[end ++] = sizeof(int); + memcpy(lst + end, &len, sizeof(int)); + end += sizeof(int); + } else + lst[end ++] = 0; + + return end + 2; +} + +static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, int len) +{ + struct bt_l2cap_sdp_state_s *sdp = opaque; + enum bt_sdp_cmd pdu_id; + uint8_t rsp[MAX_PDU_OUT_SIZE - PDU_HEADER_SIZE], *sdu_out; + int transaction_id, plen; + int err = 0; + int rsp_len = 0; + + if (len < 5) { + fprintf(stderr, "%s: short SDP PDU (%iB).\n", __FUNCTION__, len); + return; + } + + pdu_id = *data ++; + transaction_id = (data[0] << 8) | data[1]; + plen = (data[2] << 8) | data[3]; + data += 4; + len -= 5; + + if (len != plen) { + fprintf(stderr, "%s: wrong SDP PDU length (%iB != %iB).\n", + __FUNCTION__, plen, len); + err = SDP_INVALID_PDU_SIZE; + goto respond; + } + + switch (pdu_id) { + case SDP_SVC_SEARCH_REQ: + rsp_len = sdp_svc_search(sdp, rsp, data, len); + pdu_id = SDP_SVC_SEARCH_RSP; + break; + + case SDP_SVC_ATTR_REQ: + rsp_len = sdp_attr_get(sdp, rsp, data, len); + pdu_id = SDP_SVC_ATTR_RSP; + break; + + case SDP_SVC_SEARCH_ATTR_REQ: + rsp_len = sdp_svc_search_attr_get(sdp, rsp, data, len); + pdu_id = SDP_SVC_SEARCH_ATTR_RSP; + break; + + case SDP_ERROR_RSP: + case SDP_SVC_ATTR_RSP: + case SDP_SVC_SEARCH_RSP: + case SDP_SVC_SEARCH_ATTR_RSP: + default: + fprintf(stderr, "%s: unexpected SDP PDU ID %02x.\n", + __FUNCTION__, pdu_id); + err = SDP_INVALID_SYNTAX; + break; + } + + if (rsp_len < 0) { + err = -rsp_len; + rsp_len = 0; + } + +respond: + if (err) { + pdu_id = SDP_ERROR_RSP; + rsp[rsp_len ++] = err >> 8; + rsp[rsp_len ++] = err & 0xff; + } + + sdu_out = sdp->channel->sdu_out(sdp->channel, rsp_len + PDU_HEADER_SIZE); + + sdu_out[0] = pdu_id; + sdu_out[1] = transaction_id >> 8; + sdu_out[2] = transaction_id & 0xff; + sdu_out[3] = rsp_len >> 8; + sdu_out[4] = rsp_len & 0xff; + memcpy(sdu_out + PDU_HEADER_SIZE, rsp, rsp_len); + + sdp->channel->sdu_submit(sdp->channel); +} + +static void bt_l2cap_sdp_close_ch(void *opaque) +{ + struct bt_l2cap_sdp_state_s *sdp = opaque; + int i; + + for (i = 0; i < sdp->services; i ++) { + qemu_free(sdp->service_list[i].attribute_list->pair); + qemu_free(sdp->service_list[i].attribute_list); + qemu_free(sdp->service_list[i].uuid); + } + qemu_free(sdp->service_list); + qemu_free(sdp); +} + +struct sdp_def_service_s { + uint16_t class_uuid; + struct sdp_def_attribute_s { + uint16_t id; + struct sdp_def_data_element_s { + uint8_t type; + union { + uint32_t uint; + const char *str; + struct sdp_def_data_element_s *list; + } value; + } data; + } attributes[]; +}; + +/* Calculate a safe byte count to allocate that will store the given + * element, at the same time count elements of a UUID type. */ +static int sdp_attr_max_size(struct sdp_def_data_element_s *element, + int *uuids) +{ + int type = element->type & ~SDP_DSIZE_MASK; + int len; + + if (type == SDP_DTYPE_UINT || type == SDP_DTYPE_UUID || + type == SDP_DTYPE_BOOL) { + if (type == SDP_DTYPE_UUID) + (*uuids) ++; + return 1 + (1 << (element->type & SDP_DSIZE_MASK)); + } + + if (type == SDP_DTYPE_STRING || type == SDP_DTYPE_URL) { + if (element->type & SDP_DSIZE_MASK) { + for (len = 0; element->value.str[len] | + element->value.str[len + 1]; len ++); + return len; + } else + return 2 + strlen(element->value.str); + } + + if (type != SDP_DTYPE_SEQ) + exit(-1); + len = 2; + element = element->value.list; + while (element->type) + len += sdp_attr_max_size(element ++, uuids); + if (len > 255) + exit (-1); + + return len; +} + +static int sdp_attr_write(uint8_t *data, + struct sdp_def_data_element_s *element, int **uuid) +{ + int type = element->type & ~SDP_DSIZE_MASK; + int len = 0; + + if (type == SDP_DTYPE_UINT || type == SDP_DTYPE_BOOL) { + data[len ++] = element->type; + if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_1) + data[len ++] = (element->value.uint >> 0) & 0xff; + else if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_2) { + data[len ++] = (element->value.uint >> 8) & 0xff; + data[len ++] = (element->value.uint >> 0) & 0xff; + } else if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_4) { + data[len ++] = (element->value.uint >> 24) & 0xff; + data[len ++] = (element->value.uint >> 16) & 0xff; + data[len ++] = (element->value.uint >> 8) & 0xff; + data[len ++] = (element->value.uint >> 0) & 0xff; + } + + return len; + } + + if (type == SDP_DTYPE_UUID) { + *(*uuid) ++ = element->value.uint; + + data[len ++] = element->type; + data[len ++] = (element->value.uint >> 24) & 0xff; + data[len ++] = (element->value.uint >> 16) & 0xff; + data[len ++] = (element->value.uint >> 8) & 0xff; + data[len ++] = (element->value.uint >> 0) & 0xff; + memcpy(data + len, bt_base_uuid, 12); + + return len + 12; + } + + data[0] = type | SDP_DSIZE_NEXT1; + if (type == SDP_DTYPE_STRING || type == SDP_DTYPE_URL) { + if (element->type & SDP_DSIZE_MASK) + for (len = 0; element->value.str[len] | + element->value.str[len + 1]; len ++); + else + len = strlen(element->value.str); + memcpy(data + 2, element->value.str, data[1] = len); + + return len + 2; + } + + len = 2; + element = element->value.list; + while (element->type) + len += sdp_attr_write(data + len, element ++, uuid); + data[1] = len - 2; + + return len; +} + +static int sdp_attributeid_compare(const struct sdp_service_attribute_s *a, + const struct sdp_service_attribute_s *b) +{ + return (int) b->attribute_id - a->attribute_id; +} + +static int sdp_uuid_compare(const int *a, const int *b) +{ + return *a - *b; +} + +static void sdp_service_record_build(struct sdp_service_record_s *record, + struct sdp_def_service_s *def, int handle) +{ + int len = 0; + uint8_t *data; + int *uuid; + + record->uuids = 0; + while (def->attributes[record->attributes].data.type) { + len += 3; + len += sdp_attr_max_size(&def->attributes[record->attributes ++].data, + &record->uuids); + } + record->uuids = 1 << ffs(record->uuids - 1); + record->attribute_list = + qemu_mallocz(record->attributes * sizeof(*record->attribute_list)); + record->uuid = + qemu_mallocz(record->uuids * sizeof(*record->uuid)); + data = qemu_malloc(len); + + record->attributes = 0; + uuid = record->uuid; + while (def->attributes[record->attributes].data.type) { + record->attribute_list[record->attributes].pair = data; + + len = 0; + data[len ++] = SDP_DTYPE_UINT | SDP_DSIZE_2; + data[len ++] = def->attributes[record->attributes].id >> 8; + data[len ++] = def->attributes[record->attributes].id & 0xff; + len += sdp_attr_write(data + len, + &def->attributes[record->attributes].data, &uuid); + + /* Special case: assign a ServiceRecordHandle in sequence */ + if (def->attributes[record->attributes].id == SDP_ATTR_RECORD_HANDLE) + def->attributes[record->attributes].data.value.uint = handle; + /* Note: we could also assign a ServiceDescription based on + * sdp->device.device->lmp_name. */ + + record->attribute_list[record->attributes ++].len = len; + data += len; + } + + /* Sort the attribute list by the AttributeID */ + qsort(record->attribute_list, record->attributes, + sizeof(*record->attribute_list), + (void *) sdp_attributeid_compare); + /* Sort the searchable UUIDs list for bisection */ + qsort(record->uuid, record->uuids, + sizeof(*record->uuid), + (void *) sdp_uuid_compare); +} + +static void sdp_service_db_build(struct bt_l2cap_sdp_state_s *sdp, + struct sdp_def_service_s **service) +{ + sdp->services = 0; + while (service[sdp->services]) + sdp->services ++; + sdp->service_list = + qemu_mallocz(sdp->services * sizeof(*sdp->service_list)); + + sdp->services = 0; + while (*service) { + sdp_service_record_build(&sdp->service_list[sdp->services], + *service, sdp->services); + service ++; + sdp->services ++; + } +} + +#define LAST { .type = 0 } +#define SERVICE(name, attrs) \ + static struct sdp_def_service_s glue(glue(sdp_service_, name), _s) = { \ + .attributes = { attrs { .data = LAST } }, \ + }; +#define ATTRIBUTE(attrid, val) { .id = glue(SDP_ATTR_, attrid), .data = val }, +#define UINT8(val) { \ + .type = SDP_DTYPE_UINT | SDP_DSIZE_1, \ + .value.uint = val, \ + }, +#define UINT16(val) { \ + .type = SDP_DTYPE_UINT | SDP_DSIZE_2, \ + .value.uint = val, \ + }, +#define UINT32(val) { \ + .type = SDP_DTYPE_UINT | SDP_DSIZE_4, \ + .value.uint = val, \ + }, +#define UUID128(val) { \ + .type = SDP_DTYPE_UUID | SDP_DSIZE_16, \ + .value.uint = val, \ + }, +#define TRUE { \ + .type = SDP_DTYPE_BOOL | SDP_DSIZE_1, \ + .value.uint = 1, \ + }, +#define FALSE { \ + .type = SDP_DTYPE_BOOL | SDP_DSIZE_1, \ + .value.uint = 0, \ + }, +#define STRING(val) { \ + .type = SDP_DTYPE_STRING, \ + .value.str = val, \ + }, +#define ARRAY(...) { \ + .type = SDP_DTYPE_STRING | SDP_DSIZE_2, \ + .value.str = (char []) { __VA_ARGS__, 0, 0 }, \ + }, +#define URL(val) { \ + .type = SDP_DTYPE_URL, \ + .value.str = val, \ + }, +#if 1 +#define LIST(val) { \ + .type = SDP_DTYPE_SEQ, \ + .value.list = (struct sdp_def_data_element_s []) { val LAST }, \ + }, +#endif + +/* Try to keep each single attribute below MAX_PDU_OUT_SIZE bytes + * in resulting SDP data representation size. */ + +SERVICE(hid, + ATTRIBUTE(RECORD_HANDLE, UINT32(0)) /* Filled in later */ + ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(HID_SVCLASS_ID))) + ATTRIBUTE(RECORD_STATE, UINT32(1)) + ATTRIBUTE(PROTO_DESC_LIST, LIST( + LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_HID_CTRL)) + LIST(UUID128(HIDP_UUID)) + )) + ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002))) + ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST( + UINT16(0x656e) UINT16(0x006a) UINT16(0x0100) + )) + ATTRIBUTE(PFILE_DESC_LIST, LIST( + LIST(UUID128(HID_PROFILE_ID) UINT16(0x0100)) + )) + ATTRIBUTE(DOC_URL, URL("http://bellard.org/qemu/user-doc.html")) + ATTRIBUTE(SVCNAME_PRIMARY, STRING("QEMU Bluetooth HID")) + ATTRIBUTE(SVCDESC_PRIMARY, STRING("QEMU Keyboard/Mouse")) + ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU " QEMU_VERSION)) + + /* Profile specific */ + ATTRIBUTE(DEVICE_RELEASE_NUMBER, UINT16(0x0091)) /* Deprecated, remove */ + ATTRIBUTE(PARSER_VERSION, UINT16(0x0111)) + /* TODO: extract from l2cap_device->device.class[0] */ + ATTRIBUTE(DEVICE_SUBCLASS, UINT8(0x40)) + ATTRIBUTE(COUNTRY_CODE, UINT8(0x15)) + ATTRIBUTE(VIRTUAL_CABLE, TRUE) + ATTRIBUTE(RECONNECT_INITIATE, FALSE) + /* TODO: extract from hid->usbdev->report_desc */ + ATTRIBUTE(DESCRIPTOR_LIST, LIST( + LIST(UINT8(0x22) ARRAY( + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x06, /* Usage (Keyboard) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x75, 0x01, /* Report Size (1) */ + 0x95, 0x08, /* Report Count (8) */ + 0x05, 0x07, /* Usage Page (Key Codes) */ + 0x19, 0xe0, /* Usage Minimum (224) */ + 0x29, 0xe7, /* Usage Maximum (231) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x08, /* Report Size (8) */ + 0x81, 0x01, /* Input (Constant) */ + 0x95, 0x05, /* Report Count (5) */ + 0x75, 0x01, /* Report Size (1) */ + 0x05, 0x08, /* Usage Page (LEDs) */ + 0x19, 0x01, /* Usage Minimum (1) */ + 0x29, 0x05, /* Usage Maximum (5) */ + 0x91, 0x02, /* Output (Data, Variable, Absolute) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x03, /* Report Size (3) */ + 0x91, 0x01, /* Output (Constant) */ + 0x95, 0x06, /* Report Count (6) */ + 0x75, 0x08, /* Report Size (8) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0xff, /* Logical Maximum (255) */ + 0x05, 0x07, /* Usage Page (Key Codes) */ + 0x19, 0x00, /* Usage Minimum (0) */ + 0x29, 0xff, /* Usage Maximum (255) */ + 0x81, 0x00, /* Input (Data, Array) */ + 0xc0 /* End Collection */ + )))) + ATTRIBUTE(LANG_ID_BASE_LIST, LIST( + LIST(UINT16(0x0409) UINT16(0x0100)) + )) + ATTRIBUTE(SDP_DISABLE, FALSE) + ATTRIBUTE(BATTERY_POWER, TRUE) + ATTRIBUTE(REMOTE_WAKEUP, TRUE) + ATTRIBUTE(BOOT_DEVICE, TRUE) /* XXX: untested */ + ATTRIBUTE(SUPERVISION_TIMEOUT, UINT16(0x0c80)) + ATTRIBUTE(NORMALLY_CONNECTABLE, TRUE) + ATTRIBUTE(PROFILE_VERSION, UINT16(0x0100)) +) + +SERVICE(sdp, + ATTRIBUTE(RECORD_HANDLE, UINT32(0)) /* Filled in later */ + ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(SDP_SERVER_SVCLASS_ID))) + ATTRIBUTE(RECORD_STATE, UINT32(1)) + ATTRIBUTE(PROTO_DESC_LIST, LIST( + LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_SDP)) + LIST(UUID128(SDP_UUID)) + )) + ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002))) + ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST( + UINT16(0x656e) UINT16(0x006a) UINT16(0x0100) + )) + ATTRIBUTE(PFILE_DESC_LIST, LIST( + LIST(UUID128(SDP_SERVER_PROFILE_ID) UINT16(0x0100)) + )) + ATTRIBUTE(DOC_URL, URL("http://bellard.org/qemu/user-doc.html")) + ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU " QEMU_VERSION)) + + /* Profile specific */ + ATTRIBUTE(VERSION_NUM_LIST, LIST(UINT16(0x0100))) + ATTRIBUTE(SVCDB_STATE , UINT32(1)) +) + +SERVICE(pnp, + ATTRIBUTE(RECORD_HANDLE, UINT32(0)) /* Filled in later */ + ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(PNP_INFO_SVCLASS_ID))) + ATTRIBUTE(RECORD_STATE, UINT32(1)) + ATTRIBUTE(PROTO_DESC_LIST, LIST( + LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_SDP)) + LIST(UUID128(SDP_UUID)) + )) + ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002))) + ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST( + UINT16(0x656e) UINT16(0x006a) UINT16(0x0100) + )) + ATTRIBUTE(PFILE_DESC_LIST, LIST( + LIST(UUID128(PNP_INFO_PROFILE_ID) UINT16(0x0100)) + )) + ATTRIBUTE(DOC_URL, URL("http://bellard.org/qemu/user-doc.html")) + ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU " QEMU_VERSION)) + + /* Profile specific */ + ATTRIBUTE(SPECIFICATION_ID, UINT16(0x0100)) + ATTRIBUTE(VERSION, UINT16(0x0100)) + ATTRIBUTE(PRIMARY_RECORD, TRUE) +) + +static int bt_l2cap_sdp_new_ch(struct bt_l2cap_device_s *dev, + struct bt_l2cap_conn_params_s *params) +{ + struct bt_l2cap_sdp_state_s *sdp = qemu_mallocz(sizeof(*sdp)); + struct sdp_def_service_s *services[] = { + &sdp_service_sdp_s, + &sdp_service_hid_s, + &sdp_service_pnp_s, + 0, + }; + + sdp->channel = params; + sdp->channel->opaque = sdp; + sdp->channel->close = bt_l2cap_sdp_close_ch; + sdp->channel->sdu_in = bt_l2cap_sdp_sdu_in; + + sdp_service_db_build(sdp, services); + + return 0; +} + +void bt_l2cap_sdp_init(struct bt_l2cap_device_s *dev) +{ + bt_l2cap_psm_register(dev, BT_PSM_SDP, + MAX_PDU_OUT_SIZE, bt_l2cap_sdp_new_ch); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/cbus.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/cbus.c --- qemu-0.9.1/hw/cbus.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/cbus.c 2008-10-26 13:43:07.000000000 +0000 @@ -0,0 +1,626 @@ +/* + * CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma / + * Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms. + * Based on reverse-engineering of a linux driver. + * + * Copyright (C) 2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "qemu-common.h" +#include "irq.h" +#include "devices.h" +#include "sysemu.h" + +//#define DEBUG + +struct cbus_slave_s; +struct cbus_priv_s { + struct cbus_s cbus; + + int sel; + int dat; + int clk; + int bit; + int dir; + uint16_t val; + qemu_irq dat_out; + + int addr; + int reg; + int rw; + enum { + cbus_address, + cbus_value, + } cycle; + + struct cbus_slave_s *slave[8]; +}; + +struct cbus_slave_s { + void *opaque; + void (*io)(void *opaque, int rw, int reg, uint16_t *val); + int addr; +}; + +static void cbus_io(struct cbus_priv_s *s) +{ + if (s->slave[s->addr]) + s->slave[s->addr]->io(s->slave[s->addr]->opaque, + s->rw, s->reg, &s->val); + else + cpu_abort(cpu_single_env, "%s: bad slave address %i\n", + __FUNCTION__, s->addr); +} + +static void cbus_cycle(struct cbus_priv_s *s) +{ + switch (s->cycle) { + case cbus_address: + s->addr = (s->val >> 6) & 7; + s->rw = (s->val >> 5) & 1; + s->reg = (s->val >> 0) & 0x1f; + + s->cycle = cbus_value; + s->bit = 15; + s->dir = !s->rw; + s->val = 0; + + if (s->rw) + cbus_io(s); + break; + + case cbus_value: + if (!s->rw) + cbus_io(s); + + s->cycle = cbus_address; + s->bit = 8; + s->dir = 1; + s->val = 0; + break; + } +} + +static void cbus_clk(void *opaque, int line, int level) +{ + struct cbus_priv_s *s = (struct cbus_priv_s *) opaque; + + if (!s->sel && level && !s->clk) { + if (s->dir) + s->val |= s->dat << (s->bit --); + else + qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1); + + if (s->bit < 0) + cbus_cycle(s); + } + + s->clk = level; +} + +static void cbus_dat(void *opaque, int line, int level) +{ + struct cbus_priv_s *s = (struct cbus_priv_s *) opaque; + + s->dat = level; +} + +static void cbus_sel(void *opaque, int line, int level) +{ + struct cbus_priv_s *s = (struct cbus_priv_s *) opaque; + + if (!level) { + s->dir = 1; + s->bit = 8; + s->val = 0; + } + + s->sel = level; +} + +struct cbus_s *cbus_init(qemu_irq dat) +{ + struct cbus_priv_s *s = (struct cbus_priv_s *) qemu_mallocz(sizeof(*s)); + + s->dat_out = dat; + s->cbus.clk = qemu_allocate_irqs(cbus_clk, s, 1)[0]; + s->cbus.dat = qemu_allocate_irqs(cbus_dat, s, 1)[0]; + s->cbus.sel = qemu_allocate_irqs(cbus_sel, s, 1)[0]; + + s->sel = 1; + s->clk = 0; + s->dat = 0; + + return &s->cbus; +} + +void cbus_attach(struct cbus_s *bus, void *slave_opaque) +{ + struct cbus_slave_s *slave = (struct cbus_slave_s *) slave_opaque; + struct cbus_priv_s *s = (struct cbus_priv_s *) bus; + + s->slave[slave->addr] = slave; +} + +/* Retu/Vilma */ +struct cbus_retu_s { + uint16_t irqst; + uint16_t irqen; + uint16_t cc[2]; + int channel; + uint16_t result[16]; + uint16_t sample; + uint16_t status; + + struct { + uint16_t cal; + } rtc; + + int is_vilma; + qemu_irq irq; + struct cbus_slave_s cbus; +}; + +static void retu_interrupt_update(struct cbus_retu_s *s) +{ + qemu_set_irq(s->irq, s->irqst & ~s->irqen); +} + +#define RETU_REG_ASICR 0x00 /* (RO) ASIC ID & revision */ +#define RETU_REG_IDR 0x01 /* (T) Interrupt ID */ +#define RETU_REG_IMR 0x02 /* (RW) Interrupt mask */ +#define RETU_REG_RTCDSR 0x03 /* (RW) RTC seconds register */ +#define RETU_REG_RTCHMR 0x04 /* (RO) RTC hours and minutes reg */ +#define RETU_REG_RTCHMAR 0x05 /* (RW) RTC hours and minutes set reg */ +#define RETU_REG_RTCCALR 0x06 /* (RW) RTC calibration register */ +#define RETU_REG_ADCR 0x08 /* (RW) ADC result register */ +#define RETU_REG_ADCSCR 0x09 /* (RW) ADC sample control register */ +#define RETU_REG_AFCR 0x0a /* (RW) AFC register */ +#define RETU_REG_ANTIFR 0x0b /* (RW) AntiF register */ +#define RETU_REG_CALIBR 0x0c /* (RW) CalibR register*/ +#define RETU_REG_CCR1 0x0d /* (RW) Common control register 1 */ +#define RETU_REG_CCR2 0x0e /* (RW) Common control register 2 */ +#define RETU_REG_RCTRL_CLR 0x0f /* (T) Regulator clear register */ +#define RETU_REG_RCTRL_SET 0x10 /* (T) Regulator set register */ +#define RETU_REG_TXCR 0x11 /* (RW) TxC register */ +#define RETU_REG_STATUS 0x16 /* (RO) Status register */ +#define RETU_REG_WATCHDOG 0x17 /* (RW) Watchdog register */ +#define RETU_REG_AUDTXR 0x18 /* (RW) Audio Codec Tx register */ +#define RETU_REG_AUDPAR 0x19 /* (RW) AudioPA register */ +#define RETU_REG_AUDRXR1 0x1a /* (RW) Audio receive register 1 */ +#define RETU_REG_AUDRXR2 0x1b /* (RW) Audio receive register 2 */ +#define RETU_REG_SGR1 0x1c /* (RW) */ +#define RETU_REG_SCR1 0x1d /* (RW) */ +#define RETU_REG_SGR2 0x1e /* (RW) */ +#define RETU_REG_SCR2 0x1f /* (RW) */ + +/* Retu Interrupt sources */ +enum { + retu_int_pwr = 0, /* Power button */ + retu_int_char = 1, /* Charger */ + retu_int_rtcs = 2, /* Seconds */ + retu_int_rtcm = 3, /* Minutes */ + retu_int_rtcd = 4, /* Days */ + retu_int_rtca = 5, /* Alarm */ + retu_int_hook = 6, /* Hook */ + retu_int_head = 7, /* Headset */ + retu_int_adcs = 8, /* ADC sample */ +}; + +/* Retu ADC channel wiring */ +enum { + retu_adc_bsi = 1, /* BSI */ + retu_adc_batt_temp = 2, /* Battery temperature */ + retu_adc_chg_volt = 3, /* Charger voltage */ + retu_adc_head_det = 4, /* Headset detection */ + retu_adc_hook_det = 5, /* Hook detection */ + retu_adc_rf_gp = 6, /* RF GP */ + retu_adc_tx_det = 7, /* Wideband Tx detection */ + retu_adc_batt_volt = 8, /* Battery voltage */ + retu_adc_sens = 10, /* Light sensor */ + retu_adc_sens_temp = 11, /* Light sensor temperature */ + retu_adc_bbatt_volt = 12, /* Backup battery voltage */ + retu_adc_self_temp = 13, /* RETU temperature */ +}; + +static inline uint16_t retu_read(struct cbus_retu_s *s, int reg) +{ +#ifdef DEBUG + printf("RETU read at %02x\n", reg); +#endif + + switch (reg) { + case RETU_REG_ASICR: + return 0x0215 | (s->is_vilma << 7); + + case RETU_REG_IDR: /* TODO: Or is this ffs(s->irqst)? */ + return s->irqst; + + case RETU_REG_IMR: + return s->irqen; + + case RETU_REG_RTCDSR: + case RETU_REG_RTCHMR: + case RETU_REG_RTCHMAR: + /* TODO */ + return 0x0000; + + case RETU_REG_RTCCALR: + return s->rtc.cal; + + case RETU_REG_ADCR: + return (s->channel << 10) | s->result[s->channel]; + case RETU_REG_ADCSCR: + return s->sample; + + case RETU_REG_AFCR: + case RETU_REG_ANTIFR: + case RETU_REG_CALIBR: + /* TODO */ + return 0x0000; + + case RETU_REG_CCR1: + return s->cc[0]; + case RETU_REG_CCR2: + return s->cc[1]; + + case RETU_REG_RCTRL_CLR: + case RETU_REG_RCTRL_SET: + case RETU_REG_TXCR: + /* TODO */ + return 0x0000; + + case RETU_REG_STATUS: + return s->status; + + case RETU_REG_WATCHDOG: + case RETU_REG_AUDTXR: + case RETU_REG_AUDPAR: + case RETU_REG_AUDRXR1: + case RETU_REG_AUDRXR2: + case RETU_REG_SGR1: + case RETU_REG_SCR1: + case RETU_REG_SGR2: + case RETU_REG_SCR2: + /* TODO */ + return 0x0000; + + default: + cpu_abort(cpu_single_env, "%s: bad register %02x\n", + __FUNCTION__, reg); + } +} + +static inline void retu_write(struct cbus_retu_s *s, int reg, uint16_t val) +{ +#ifdef DEBUG + printf("RETU write of %04x at %02x\n", val, reg); +#endif + + switch (reg) { + case RETU_REG_IDR: + s->irqst ^= val; + retu_interrupt_update(s); + break; + + case RETU_REG_IMR: + s->irqen = val; + retu_interrupt_update(s); + break; + + case RETU_REG_RTCDSR: + case RETU_REG_RTCHMAR: + /* TODO */ + break; + + case RETU_REG_RTCCALR: + s->rtc.cal = val; + break; + + case RETU_REG_ADCR: + s->channel = (val >> 10) & 0xf; + s->irqst |= 1 << retu_int_adcs; + retu_interrupt_update(s); + break; + case RETU_REG_ADCSCR: + s->sample &= ~val; + break; + + case RETU_REG_AFCR: + case RETU_REG_ANTIFR: + case RETU_REG_CALIBR: + + case RETU_REG_CCR1: + s->cc[0] = val; + break; + case RETU_REG_CCR2: + s->cc[1] = val; + break; + + case RETU_REG_RCTRL_CLR: + case RETU_REG_RCTRL_SET: + /* TODO */ + break; + + case RETU_REG_WATCHDOG: + if (val == 0 && (s->cc[0] & 2)) + qemu_system_shutdown_request(); + break; + + case RETU_REG_TXCR: + case RETU_REG_AUDTXR: + case RETU_REG_AUDPAR: + case RETU_REG_AUDRXR1: + case RETU_REG_AUDRXR2: + case RETU_REG_SGR1: + case RETU_REG_SCR1: + case RETU_REG_SGR2: + case RETU_REG_SCR2: + /* TODO */ + break; + + default: + cpu_abort(cpu_single_env, "%s: bad register %02x\n", + __FUNCTION__, reg); + } +} + +static void retu_io(void *opaque, int rw, int reg, uint16_t *val) +{ + struct cbus_retu_s *s = (struct cbus_retu_s *) opaque; + + if (rw) + *val = retu_read(s, reg); + else + retu_write(s, reg, *val); +} + +void *retu_init(qemu_irq irq, int vilma) +{ + struct cbus_retu_s *s = (struct cbus_retu_s *) qemu_mallocz(sizeof(*s)); + + s->irq = irq; + s->irqen = 0xffff; + s->irqst = 0x0000; + s->status = 0x0020; + s->is_vilma = !!vilma; + s->rtc.cal = 0x01; + s->result[retu_adc_bsi] = 0x3c2; + s->result[retu_adc_batt_temp] = 0x0fc; + s->result[retu_adc_chg_volt] = 0x165; + s->result[retu_adc_head_det] = 123; + s->result[retu_adc_hook_det] = 1023; + s->result[retu_adc_rf_gp] = 0x11; + s->result[retu_adc_tx_det] = 0x11; + s->result[retu_adc_batt_volt] = 0x250; + s->result[retu_adc_sens] = 2; + s->result[retu_adc_sens_temp] = 0x11; + s->result[retu_adc_bbatt_volt] = 0x3d0; + s->result[retu_adc_self_temp] = 0x330; + + s->cbus.opaque = s; + s->cbus.io = retu_io; + s->cbus.addr = 1; + + return &s->cbus; +} + +void retu_key_event(void *retu, int state) +{ + struct cbus_slave_s *slave = (struct cbus_slave_s *) retu; + struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque; + + s->irqst |= 1 << retu_int_pwr; + retu_interrupt_update(s); + + if (state) + s->status &= ~(1 << 5); + else + s->status |= 1 << 5; +} + +#if 0 +static void retu_head_event(void *retu, int state) +{ + struct cbus_slave_s *slave = (struct cbus_slave_s *) retu; + struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque; + + if ((s->cc[0] & 0x500) == 0x500) { /* TODO: Which bits? */ + /* TODO: reissue the interrupt every 100ms or so. */ + s->irqst |= 1 << retu_int_head; + retu_interrupt_update(s); + } + + if (state) + s->result[retu_adc_head_det] = 50; + else + s->result[retu_adc_head_det] = 123; +} + +static void retu_hook_event(void *retu, int state) +{ + struct cbus_slave_s *slave = (struct cbus_slave_s *) retu; + struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque; + + if ((s->cc[0] & 0x500) == 0x500) { + /* TODO: reissue the interrupt every 100ms or so. */ + s->irqst |= 1 << retu_int_hook; + retu_interrupt_update(s); + } + + if (state) + s->result[retu_adc_hook_det] = 50; + else + s->result[retu_adc_hook_det] = 123; +} +#endif + +/* Tahvo/Betty */ +struct cbus_tahvo_s { + uint16_t irqst; + uint16_t irqen; + uint8_t charger; + uint8_t backlight; + uint16_t usbr; + uint16_t power; + + int is_betty; + qemu_irq irq; + struct cbus_slave_s cbus; +}; + +static void tahvo_interrupt_update(struct cbus_tahvo_s *s) +{ + qemu_set_irq(s->irq, s->irqst & ~s->irqen); +} + +#define TAHVO_REG_ASICR 0x00 /* (RO) ASIC ID & revision */ +#define TAHVO_REG_IDR 0x01 /* (T) Interrupt ID */ +#define TAHVO_REG_IDSR 0x02 /* (RO) Interrupt status */ +#define TAHVO_REG_IMR 0x03 /* (RW) Interrupt mask */ +#define TAHVO_REG_CHAPWMR 0x04 /* (RW) Charger PWM */ +#define TAHVO_REG_LEDPWMR 0x05 /* (RW) LED PWM */ +#define TAHVO_REG_USBR 0x06 /* (RW) USB control */ +#define TAHVO_REG_RCR 0x07 /* (RW) Some kind of power management */ +#define TAHVO_REG_CCR1 0x08 /* (RW) Common control register 1 */ +#define TAHVO_REG_CCR2 0x09 /* (RW) Common control register 2 */ +#define TAHVO_REG_TESTR1 0x0a /* (RW) Test register 1 */ +#define TAHVO_REG_TESTR2 0x0b /* (RW) Test register 2 */ +#define TAHVO_REG_NOPR 0x0c /* (RW) Number of periods */ +#define TAHVO_REG_FRR 0x0d /* (RO) FR */ + +static inline uint16_t tahvo_read(struct cbus_tahvo_s *s, int reg) +{ +#ifdef DEBUG + printf("TAHVO read at %02x\n", reg); +#endif + + switch (reg) { + case TAHVO_REG_ASICR: + return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300); /* 22 in N810 */ + + case TAHVO_REG_IDR: + case TAHVO_REG_IDSR: /* XXX: what does this do? */ + return s->irqst; + + case TAHVO_REG_IMR: + return s->irqen; + + case TAHVO_REG_CHAPWMR: + return s->charger; + + case TAHVO_REG_LEDPWMR: + return s->backlight; + + case TAHVO_REG_USBR: + return s->usbr; + + case TAHVO_REG_RCR: + return s->power; + + case TAHVO_REG_CCR1: + case TAHVO_REG_CCR2: + case TAHVO_REG_TESTR1: + case TAHVO_REG_TESTR2: + case TAHVO_REG_NOPR: + case TAHVO_REG_FRR: + return 0x0000; + + default: + cpu_abort(cpu_single_env, "%s: bad register %02x\n", + __FUNCTION__, reg); + } +} + +static inline void tahvo_write(struct cbus_tahvo_s *s, int reg, uint16_t val) +{ +#ifdef DEBUG + printf("TAHVO write of %04x at %02x\n", val, reg); +#endif + + switch (reg) { + case TAHVO_REG_IDR: + s->irqst ^= val; + tahvo_interrupt_update(s); + break; + + case TAHVO_REG_IMR: + s->irqen = val; + tahvo_interrupt_update(s); + break; + + case TAHVO_REG_CHAPWMR: + s->charger = val; + break; + + case TAHVO_REG_LEDPWMR: + if (s->backlight != (val & 0x7f)) { + s->backlight = val & 0x7f; + printf("%s: LCD backlight now at %i / 127\n", + __FUNCTION__, s->backlight); + } + break; + + case TAHVO_REG_USBR: + s->usbr = val; + break; + + case TAHVO_REG_RCR: + s->power = val; + break; + + case TAHVO_REG_CCR1: + case TAHVO_REG_CCR2: + case TAHVO_REG_TESTR1: + case TAHVO_REG_TESTR2: + case TAHVO_REG_NOPR: + case TAHVO_REG_FRR: + break; + + default: + cpu_abort(cpu_single_env, "%s: bad register %02x\n", + __FUNCTION__, reg); + } +} + +static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val) +{ + struct cbus_tahvo_s *s = (struct cbus_tahvo_s *) opaque; + + if (rw) + *val = tahvo_read(s, reg); + else + tahvo_write(s, reg, *val); +} + +void *tahvo_init(qemu_irq irq, int betty) +{ + struct cbus_tahvo_s *s = (struct cbus_tahvo_s *) qemu_mallocz(sizeof(*s)); + + s->irq = irq; + s->irqen = 0xffff; + s->irqst = 0x0000; + s->is_betty = !!betty; + + s->cbus.opaque = s; + s->cbus.io = tahvo_io; + s->cbus.addr = 2; + + return &s->cbus; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/cirrus_vga.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/cirrus_vga.c --- qemu-0.9.1/hw/cirrus_vga.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/cirrus_vga.c 2008-11-01 00:53:39.000000000 +0000 @@ -220,6 +220,20 @@ #define CIRRUS_HOOK_NOT_HANDLED 0 #define CIRRUS_HOOK_HANDLED 1 +#define BLTUNSAFE(s) \ + ( \ + ( /* check dst is within bounds */ \ + (s)->cirrus_blt_height * (s)->cirrus_blt_dstpitch \ + + ((s)->cirrus_blt_dstaddr & (s)->cirrus_addr_mask) > \ + (s)->vram_size \ + ) || \ + ( /* check src is within bounds */ \ + (s)->cirrus_blt_height * (s)->cirrus_blt_srcpitch \ + + ((s)->cirrus_blt_srcaddr & (s)->cirrus_addr_mask) > \ + (s)->vram_size \ + ) \ + ) + struct CirrusVGAState; typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s, uint8_t * dst, const uint8_t * src, @@ -639,7 +653,7 @@ for (y = 0; y < lines; y++) { off_cur = off_begin; - off_cur_end = off_cur + bytesperline; + off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask; off_cur &= TARGET_PAGE_MASK; while (off_cur < off_cur_end) { cpu_physical_memory_set_dirty(s->vram_offset + off_cur); @@ -654,7 +668,11 @@ { uint8_t *dst; - dst = s->vram_ptr + s->cirrus_blt_dstaddr; + dst = s->vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask); + + if (BLTUNSAFE(s)) + return 0; + (*s->cirrus_rop) (s, dst, src, s->cirrus_blt_dstpitch, 0, s->cirrus_blt_width, s->cirrus_blt_height); @@ -670,8 +688,10 @@ { cirrus_fill_t rop_func; + if (BLTUNSAFE(s)) + return 0; rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; - rop_func(s, s->vram_ptr + s->cirrus_blt_dstaddr, + rop_func(s, s->vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), s->cirrus_blt_dstpitch, s->cirrus_blt_width, s->cirrus_blt_height); cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, @@ -690,8 +710,8 @@ static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s) { return cirrus_bitblt_common_patterncopy(s, - s->vram_ptr + - (s->cirrus_blt_srcaddr & ~7)); + s->vram_ptr + ((s->cirrus_blt_srcaddr & ~7) & + s->cirrus_addr_mask)); } static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) @@ -741,19 +761,21 @@ if (notify) vga_hw_update(); - (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr, - s->vram_ptr + s->cirrus_blt_srcaddr, + (*s->cirrus_rop) (s, s->vram_ptr + + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), + s->vram_ptr + + (s->cirrus_blt_srcaddr & s->cirrus_addr_mask), s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, s->cirrus_blt_width, s->cirrus_blt_height); if (notify) - s->ds->dpy_copy(s->ds, - sx, sy, dx, dy, - s->cirrus_blt_width / depth, - s->cirrus_blt_height); + qemu_console_copy(s->console, + sx, sy, dx, dy, + s->cirrus_blt_width / depth, + s->cirrus_blt_height); /* we don't have to notify the display that this portion has - changed since dpy_copy implies this */ + changed since qemu_console_copy implies this */ if (!notify) cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, @@ -763,13 +785,18 @@ static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) { + if (BLTUNSAFE(s)) + return 0; + if (s->ds->dpy_copy) { cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr, s->cirrus_blt_srcaddr - s->start_addr, s->cirrus_blt_width, s->cirrus_blt_height); } else { - (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr, - s->vram_ptr + s->cirrus_blt_srcaddr, + (*s->cirrus_rop) (s, s->vram_ptr + + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), + s->vram_ptr + + (s->cirrus_blt_srcaddr & s->cirrus_addr_mask), s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, s->cirrus_blt_width, s->cirrus_blt_height); @@ -801,8 +828,9 @@ } else { /* at least one scan line */ do { - (*s->cirrus_rop)(s, s->vram_ptr + s->cirrus_blt_dstaddr, - s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1); + (*s->cirrus_rop)(s, s->vram_ptr + + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), + s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1); cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0, s->cirrus_blt_width, 1); s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch; @@ -1597,13 +1625,15 @@ case 0x17: // Standard VGA case 0x18: // Standard VGA return CIRRUS_HOOK_NOT_HANDLED; + case 0x24: // Attribute Controller Toggle Readback (R) + *reg_value = (s->ar_flip_flop << 7); + break; case 0x19: // Interlace End case 0x1a: // Miscellaneous Control case 0x1b: // Extended Display Control case 0x1c: // Sync Adjust and Genlock case 0x1d: // Overlay Extended Control case 0x22: // Graphics Data Latches Readback (R) - case 0x24: // Attribute Controller Toggle Readback (R) case 0x25: // Part Status case 0x27: // Part ID (R) *reg_value = s->cr[reg_index]; @@ -1920,7 +1950,7 @@ unsigned val = mem_value; uint8_t *dst; - dst = s->vram_ptr + offset; + dst = s->vram_ptr + (offset &= s->cirrus_addr_mask); for (x = 0; x < 8; x++) { if (val & 0x80) { *dst = s->cirrus_shadow_gr1; @@ -1943,7 +1973,7 @@ unsigned val = mem_value; uint8_t *dst; - dst = s->vram_ptr + offset; + dst = s->vram_ptr + (offset &= s->cirrus_addr_mask); for (x = 0; x < 8; x++) { if (val & 0x80) { *dst = s->cirrus_shadow_gr1; @@ -2713,8 +2743,7 @@ case 0x3ba: case 0x3da: /* just toggle to fool polling */ - s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE; - val = s->st01; + val = s->st01 = s->retrace((VGAState *) s); s->ar_flip_flop = 0; break; default: @@ -2777,6 +2806,7 @@ break; case 0x3c2: s->msr = val & ~0x10; + s->update_retrace_info((VGAState *) s); break; case 0x3c4: s->sr_index = val; @@ -2788,6 +2818,7 @@ printf("vga: write SR%x = 0x%02x\n", s->sr_index, val); #endif s->sr[s->sr_index] = val & sr_mask[s->sr_index]; + if (s->sr_index == 1) s->update_retrace_info((VGAState *) s); break; case 0x3c6: cirrus_write_hidden_dac(s, val); @@ -2855,6 +2886,18 @@ s->cr[s->cr_index] = val; break; } + + switch(s->cr_index) { + case 0x00: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x11: + case 0x17: + s->update_retrace_info((VGAState *) s); + break; + } break; case 0x3ba: case 0x3da: @@ -3197,6 +3240,8 @@ vga_common_init((VGAState *)s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0); + s->console = graphic_console_init(s->ds, s->update, s->invalidate, + s->screen_dump, s->text_update, s); /* XXX ISA-LFB support */ } @@ -3257,7 +3302,8 @@ ds, vga_ram_base, vga_ram_offset, vga_ram_size); cirrus_init_common(s, device_id, 1); - graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); + s->console = graphic_console_init(s->ds, s->update, s->invalidate, + s->screen_dump, s->text_update, s); s->pci_dev = (PCIDevice *)d; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/cirrus_vga_rop.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/cirrus_vga_rop.h --- qemu-0.9.1/hw/cirrus_vga_rop.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/cirrus_vga_rop.h 2008-05-05 22:26:31.000000000 +0100 @@ -31,6 +31,12 @@ int x,y; dstpitch -= bltwidth; srcpitch -= bltwidth; + + if (dstpitch < 0 || srcpitch < 0) { + /* is 0 valid? srcpitch == 0 could be useful */ + return; + } + for (y = 0; y < bltheight; y++) { for (x = 0; x < bltwidth; x++) { ROP_OP(*dst, *src); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/cs4231a.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/cs4231a.c --- qemu-0.9.1/hw/cs4231a.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/cs4231a.c 2008-06-21 18:15:00.000000000 +0100 @@ -0,0 +1,674 @@ +/* + * QEMU Crystal CS4231 audio chip emulation + * + * Copyright (c) 2006 Fabrice Bellard + * + * 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 "hw.h" +#include "audiodev.h" +#include "audio/audio.h" +#include "isa.h" +#include "qemu-timer.h" + +/* + Missing features: + ADC + Loopback + Timer + ADPCM + More... +*/ + +/* #define DEBUG */ +/* #define DEBUG_XLAW */ + +static struct { + int irq; + int dma; + int port; + int aci_counter; +} conf = {9, 3, 0x534, 1}; + +#ifdef DEBUG +#define dolog(...) AUD_log ("cs4231a", __VA_ARGS__) +#else +#define dolog(...) +#endif + +#define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__) +#define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__) + +#define CS_REGS 16 +#define CS_DREGS 32 + +typedef struct CSState { + QEMUSoundCard card; + qemu_irq *pic; + uint32_t regs[CS_REGS]; + uint8_t dregs[CS_DREGS]; + int irq; + int dma; + int port; + int shift; + int dma_running; + int audio_free; + int transferred; + int aci_counter; + SWVoiceOut *voice; + int16_t *tab; +} CSState; + +#define IO_READ_PROTO(name) \ + static uint32_t name (void *opaque, uint32_t addr) + +#define IO_WRITE_PROTO(name) \ + static void name (void *opaque, uint32_t addr, uint32_t val) + +#define GET_SADDR(addr) (addr & 3) + +#define MODE2 (1 << 6) +#define MCE (1 << 6) +#define PMCE (1 << 4) +#define CMCE (1 << 5) +#define TE (1 << 6) +#define PEN (1 << 0) +#define INT (1 << 0) +#define IEN (1 << 1) +#define PPIO (1 << 6) +#define PI (1 << 4) +#define CI (1 << 5) +#define TI (1 << 6) + +enum { + Index_Address, + Index_Data, + Status, + PIO_Data +}; + +enum { + Left_ADC_Input_Control, + Right_ADC_Input_Control, + Left_AUX1_Input_Control, + Right_AUX1_Input_Control, + Left_AUX2_Input_Control, + Right_AUX2_Input_Control, + Left_DAC_Output_Control, + Right_DAC_Output_Control, + FS_And_Playback_Data_Format, + Interface_Configuration, + Pin_Control, + Error_Status_And_Initialization, + MODE_And_ID, + Loopback_Control, + Playback_Upper_Base_Count, + Playback_Lower_Base_Count, + Alternate_Feature_Enable_I, + Alternate_Feature_Enable_II, + Left_Line_Input_Control, + Right_Line_Input_Control, + Timer_Low_Base, + Timer_High_Base, + RESERVED, + Alternate_Feature_Enable_III, + Alternate_Feature_Status, + Version_Chip_ID, + Mono_Input_And_Output_Control, + RESERVED_2, + Capture_Data_Format, + RESERVED_3, + Capture_Upper_Base_Count, + Capture_Lower_Base_Count +}; + +static int freqs[2][8] = { + { 8000, 16000, 27420, 32000, -1, -1, 48000, 9000 }, + { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 } +}; + +/* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */ +static int16_t MuLawDecompressTable[256] = +{ + -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956, + -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764, + -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412, + -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316, + -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, + -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, + -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, + -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, + -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, + -876, -844, -812, -780, -748, -716, -684, -652, + -620, -588, -556, -524, -492, -460, -428, -396, + -372, -356, -340, -324, -308, -292, -276, -260, + -244, -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, -64, + -56, -48, -40, -32, -24, -16, -8, 0, + 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, + 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, + 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, + 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, + 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, + 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, + 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, + 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, + 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, + 876, 844, 812, 780, 748, 716, 684, 652, + 620, 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, 260, + 244, 228, 212, 196, 180, 164, 148, 132, + 120, 112, 104, 96, 88, 80, 72, 64, + 56, 48, 40, 32, 24, 16, 8, 0 +}; + +static int16_t ALawDecompressTable[256] = +{ + -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, + -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, + -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, + -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, + -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944, + -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136, + -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472, + -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568, + -344, -328, -376, -360, -280, -264, -312, -296, + -472, -456, -504, -488, -408, -392, -440, -424, + -88, -72, -120, -104, -24, -8, -56, -40, + -216, -200, -248, -232, -152, -136, -184, -168, + -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, + -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, -592, + -944, -912, -1008, -976, -816, -784, -880, -848, + 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, + 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, + 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, + 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, + 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, + 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, + 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, + 344, 328, 376, 360, 280, 264, 312, 296, + 472, 456, 504, 488, 408, 392, 440, 424, + 88, 72, 120, 104, 24, 8, 56, 40, + 216, 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, + 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, + 688, 656, 752, 720, 560, 528, 624, 592, + 944, 912, 1008, 976, 816, 784, 880, 848 +}; + +static void cs_reset(void *opaque) +{ + CSState *s = opaque; + + s->regs[Index_Address] = 0x40; + s->regs[Index_Data] = 0x00; + s->regs[Status] = 0x00; + s->regs[PIO_Data] = 0x00; + + s->dregs[Left_ADC_Input_Control] = 0x00; + s->dregs[Right_ADC_Input_Control] = 0x00; + s->dregs[Left_AUX1_Input_Control] = 0x88; + s->dregs[Right_AUX1_Input_Control] = 0x88; + s->dregs[Left_AUX2_Input_Control] = 0x88; + s->dregs[Right_AUX2_Input_Control] = 0x88; + s->dregs[Left_DAC_Output_Control] = 0x80; + s->dregs[Right_DAC_Output_Control] = 0x80; + s->dregs[FS_And_Playback_Data_Format] = 0x00; + s->dregs[Interface_Configuration] = 0x08; + s->dregs[Pin_Control] = 0x00; + s->dregs[Error_Status_And_Initialization] = 0x00; + s->dregs[MODE_And_ID] = 0x8a; + s->dregs[Loopback_Control] = 0x00; + s->dregs[Playback_Upper_Base_Count] = 0x00; + s->dregs[Playback_Lower_Base_Count] = 0x00; + s->dregs[Alternate_Feature_Enable_I] = 0x00; + s->dregs[Alternate_Feature_Enable_II] = 0x00; + s->dregs[Left_Line_Input_Control] = 0x88; + s->dregs[Right_Line_Input_Control] = 0x88; + s->dregs[Timer_Low_Base] = 0x00; + s->dregs[Timer_High_Base] = 0x00; + s->dregs[RESERVED] = 0x00; + s->dregs[Alternate_Feature_Enable_III] = 0x00; + s->dregs[Alternate_Feature_Status] = 0x00; + s->dregs[Version_Chip_ID] = 0xa0; + s->dregs[Mono_Input_And_Output_Control] = 0xa0; + s->dregs[RESERVED_2] = 0x00; + s->dregs[Capture_Data_Format] = 0x00; + s->dregs[RESERVED_3] = 0x00; + s->dregs[Capture_Upper_Base_Count] = 0x00; + s->dregs[Capture_Lower_Base_Count] = 0x00; +} + +static void cs_audio_callback (void *opaque, int free) +{ + CSState *s = opaque; + s->audio_free = free; +} + +static void cs_reset_voices (CSState *s, uint32_t val) +{ + int xtal; + audsettings_t as; + +#ifdef DEBUG_XLAW + if (val == 0 || val == 32) + val = (1 << 4) | (1 << 5); +#endif + + xtal = val & 1; + as.freq = freqs[xtal][(val >> 1) & 7]; + + if (as.freq == -1) { + lerr ("unsupported frequency (val=%#x)\n", val); + goto error; + } + + as.nchannels = (val & (1 << 4)) ? 2 : 1; + as.endianness = 0; + s->tab = NULL; + + switch ((val >> 5) & ((s->dregs[MODE_And_ID] & MODE2) ? 7 : 3)) { + case 0: + as.fmt = AUD_FMT_U8; + s->shift = as.nchannels == 2; + break; + + case 1: + s->tab = MuLawDecompressTable; + goto x_law; + case 3: + s->tab = ALawDecompressTable; + x_law: + as.fmt = AUD_FMT_S16; + as.endianness = AUDIO_HOST_ENDIANNESS; + s->shift = as.nchannels == 2; + break; + + case 6: + as.endianness = 1; + case 2: + as.fmt = AUD_FMT_S16; + s->shift = as.nchannels; + break; + + case 7: + case 4: + lerr ("attempt to use reserved format value (%#x)\n", val); + goto error; + + case 5: + lerr ("ADPCM 4 bit IMA compatible format is not supported\n"); + goto error; + } + + s->voice = AUD_open_out ( + &s->card, + s->voice, + "cs4231a", + s, + cs_audio_callback, + &as + ); + + if (s->dregs[Interface_Configuration] & PEN) { + if (!s->dma_running) { + DMA_hold_DREQ (s->dma); + AUD_set_active_out (s->voice, 1); + s->transferred = 0; + } + s->dma_running = 1; + } + else { + if (s->dma_running) { + DMA_release_DREQ (s->dma); + AUD_set_active_out (s->voice, 0); + } + s->dma_running = 0; + } + return; + + error: + if (s->dma_running) { + DMA_release_DREQ (s->dma); + AUD_set_active_out (s->voice, 0); + } +} + +IO_READ_PROTO (cs_read) +{ + CSState *s = opaque; + uint32_t saddr, iaddr, ret; + + saddr = GET_SADDR (addr); + iaddr = ~0U; + + switch (saddr) { + case Index_Address: + ret = s->regs[saddr] & ~0x80; + break; + + case Index_Data: + if (!(s->dregs[MODE_And_ID] & MODE2)) + iaddr = s->regs[Index_Address] & 0x0f; + else + iaddr = s->regs[Index_Address] & 0x1f; + + ret = s->dregs[iaddr]; + if (iaddr == Error_Status_And_Initialization) { + /* keep SEAL happy */ + if (s->aci_counter) { + ret |= 1 << 5; + s->aci_counter -= 1; + } + } + break; + + default: + ret = s->regs[saddr]; + break; + } + dolog ("read %d:%d -> %d\n", saddr, iaddr, ret); + return ret; +} + +IO_WRITE_PROTO (cs_write) +{ + CSState *s = opaque; + uint32_t saddr, iaddr; + + saddr = GET_SADDR (addr); + + switch (saddr) { + case Index_Address: + if (!(s->regs[Index_Address] & MCE) && (val & MCE) + && (s->dregs[Interface_Configuration] & (3 << 3))) + s->aci_counter = conf.aci_counter; + + s->regs[Index_Address] = val & ~(1 << 7); + break; + + case Index_Data: + if (!(s->dregs[MODE_And_ID] & MODE2)) + iaddr = s->regs[Index_Address] & 0x0f; + else + iaddr = s->regs[Index_Address] & 0x1f; + + switch (iaddr) { + case RESERVED: + case RESERVED_2: + case RESERVED_3: + lwarn ("attempt to write %#x to reserved indirect register %d\n", + val, iaddr); + break; + + case FS_And_Playback_Data_Format: + if (s->regs[Index_Address] & MCE) { + cs_reset_voices (s, val); + } + else { + if (s->dregs[Alternate_Feature_Status] & PMCE) { + val = (val & ~0x0f) | (s->dregs[iaddr] & 0x0f); + cs_reset_voices (s, val); + } + else { + lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n", + s->regs[Index_Address], + s->dregs[Alternate_Feature_Status], + val); + break; + } + } + s->dregs[iaddr] = val; + break; + + case Interface_Configuration: + val &= ~(1 << 5); /* D5 is reserved */ + s->dregs[iaddr] = val; + if (val & PPIO) { + lwarn ("PIO is not supported (%#x)\n", val); + break; + } + if (val & PEN) { + if (!s->dma_running) { + cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]); + } + } + else { + if (s->dma_running) { + DMA_release_DREQ (s->dma); + AUD_set_active_out (s->voice, 0); + s->dma_running = 0; + } + } + break; + + case Error_Status_And_Initialization: + lwarn ("attempt to write to read only register %d\n", iaddr); + break; + + case MODE_And_ID: + dolog ("val=%#x\n", val); + if (val & MODE2) + s->dregs[iaddr] |= MODE2; + else + s->dregs[iaddr] &= ~MODE2; + break; + + case Alternate_Feature_Enable_I: + if (val & TE) + lerr ("timer is not yet supported\n"); + s->dregs[iaddr] = val; + break; + + case Alternate_Feature_Status: + if ((s->dregs[iaddr] & PI) && !(val & PI)) { + /* XXX: TI CI */ + qemu_irq_lower (s->pic[s->irq]); + s->regs[Status] &= ~INT; + } + s->dregs[iaddr] = val; + break; + + case Version_Chip_ID: + lwarn ("write to Version_Chip_ID register %#x\n", val); + s->dregs[iaddr] = val; + break; + + default: + s->dregs[iaddr] = val; + break; + } + dolog ("written value %#x to indirect register %d\n", val, iaddr); + break; + + case Status: + if (s->regs[Status] & INT) { + qemu_irq_lower (s->pic[s->irq]); + } + s->regs[Status] &= ~INT; + s->dregs[Alternate_Feature_Status] &= ~(PI | CI | TI); + break; + + case PIO_Data: + lwarn ("attempt to write value %#x to PIO register\n", val); + break; + } +} + +static int cs_write_audio (CSState *s, int nchan, int dma_pos, + int dma_len, int len) +{ + int temp, net; + uint8_t tmpbuf[4096]; + + temp = len; + net = 0; + + while (temp) { + int left = dma_len - dma_pos; + int copied; + size_t to_copy; + + to_copy = audio_MIN (temp, left); + if (to_copy > sizeof (tmpbuf)) { + to_copy = sizeof (tmpbuf); + } + + copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy); + if (s->tab) { + int i; + int16_t linbuf[4096]; + + for (i = 0; i < copied; ++i) + linbuf[i] = s->tab[tmpbuf[i]]; + copied = AUD_write (s->voice, linbuf, copied << 1); + copied >>= 1; + } + else { + copied = AUD_write (s->voice, tmpbuf, copied); + } + + temp -= copied; + dma_pos = (dma_pos + copied) % dma_len; + net += copied; + + if (!copied) { + break; + } + } + + return net; +} + +static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len) +{ + CSState *s = opaque; + int copy, written; + int till = -1; + + copy = s->voice ? (s->audio_free >> (s->tab != NULL)) : dma_len; + + if (s->dregs[Pin_Control] & IEN) { + till = (s->dregs[Playback_Lower_Base_Count] + | (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift; + till -= s->transferred; + copy = audio_MIN (till, copy); + } + + if ((copy <= 0) || (dma_len <= 0)) { + return dma_pos; + } + + written = cs_write_audio (s, nchan, dma_pos, dma_len, copy); + + dma_pos = (dma_pos + written) % dma_len; + s->audio_free -= (written << (s->tab != NULL)); + + if (written == till) { + s->regs[Status] |= INT; + s->dregs[Alternate_Feature_Status] |= PI; + s->transferred = 0; + qemu_irq_raise (s->pic[s->irq]); + } + else { + s->transferred += written; + } + + return dma_pos; +} + +static void cs_save(QEMUFile *f, void *opaque) +{ + CSState *s = opaque; + unsigned int i; + uint32_t val; + + for (i = 0; i < CS_REGS; i++) + qemu_put_be32s(f, &s->regs[i]); + + qemu_put_buffer(f, s->dregs, CS_DREGS); + val = s->dma_running; qemu_put_be32s(f, &val); + val = s->audio_free; qemu_put_be32s(f, &val); + val = s->transferred; qemu_put_be32s(f, &val); + val = s->aci_counter; qemu_put_be32s(f, &val); +} + +static int cs_load(QEMUFile *f, void *opaque, int version_id) +{ + CSState *s = opaque; + unsigned int i; + uint32_t val, dma_running; + + if (version_id > 1) + return -EINVAL; + + for (i = 0; i < CS_REGS; i++) + qemu_get_be32s(f, &s->regs[i]); + + qemu_get_buffer(f, s->dregs, CS_DREGS); + + qemu_get_be32s(f, &dma_running); + qemu_get_be32s(f, &val); s->audio_free = val; + qemu_get_be32s(f, &val); s->transferred = val; + qemu_get_be32s(f, &val); s->aci_counter = val; + if (dma_running && (s->dregs[Interface_Configuration] & PEN)) + cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]); + return 0; +} + +int cs4231a_init (AudioState *audio, qemu_irq *pic) +{ + int i; + CSState *s; + + if (!audio) { + lerr ("No audio state\n"); + return -1; + } + + s = qemu_mallocz (sizeof (*s)); + if (!s) { + lerr ("Could not allocate memory for cs4231a (%zu bytes)\n", + sizeof (*s)); + return -1; + } + + s->pic = pic; + s->irq = conf.irq; + s->dma = conf.dma; + s->port = conf.port; + + for (i = 0; i < 4; i++) { + register_ioport_write (s->port + i, 1, 1, cs_write, s); + register_ioport_read (s->port + i, 1, 1, cs_read, s); + } + + DMA_register_channel (s->dma, cs_dma_read, s); + + register_savevm ("cs4231a", 0, 1, cs_save, cs_load, s); + qemu_register_reset (cs_reset, s); + cs_reset (s); + + AUD_register_card (audio,"cs4231a", &s->card); + return 0; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/cs4231.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/cs4231.c --- qemu-0.9.1/hw/cs4231.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/cs4231.c 2008-05-12 17:13:33.000000000 +0100 @@ -98,7 +98,8 @@ DPRINTF("write reg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->regs[saddr], val); switch (saddr) { case 1: - DPRINTF("write dreg[%d]: 0x%2.2x -> 0x%2.2x\n", CS_RAP(s), s->dregs[CS_RAP(s)], val); + DPRINTF("write dreg[%d]: 0x%2.2x -> 0x%2.2x\n", CS_RAP(s), + s->dregs[CS_RAP(s)], val); switch(CS_RAP(s)) { case 11: case 25: // Read only diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/devices.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/devices.h --- qemu-0.9.1/hw/devices.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/devices.h 2008-11-05 20:24:35.000000000 +0000 @@ -16,7 +16,64 @@ void ads7846_write(void *opaque, uint32_t value); struct ads7846_state_s *ads7846_init(qemu_irq penirq); +/* tsc210x.c */ +struct uwire_slave_s; +struct mouse_transform_info_s; +struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio); +struct uwire_slave_s *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, + qemu_irq dav, AudioState *audio); +struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip); +uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len); +void tsc210x_set_transform(struct uwire_slave_s *chip, + struct mouse_transform_info_s *info); +void tsc210x_key_event(struct uwire_slave_s *chip, int key, int down); + +/* tsc2005.c */ +void *tsc2005_init(qemu_irq pintdav); +uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len); +void tsc2005_set_transform(void *opaque, struct mouse_transform_info_s *info); + /* stellaris_input.c */ void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode); +/* blizzard.c */ +void *s1d13745_init(qemu_irq gpio_int, DisplayState *ds); +void s1d13745_write(void *opaque, int dc, uint16_t value); +void s1d13745_write_block(void *opaque, int dc, + void *buf, size_t len, int pitch); +uint16_t s1d13745_read(void *opaque, int dc); + +/* cbus.c */ +struct cbus_s { + qemu_irq clk; + qemu_irq dat; + qemu_irq sel; +}; +struct cbus_s *cbus_init(qemu_irq dat_out); +void cbus_attach(struct cbus_s *bus, void *slave_opaque); + +void *retu_init(qemu_irq irq, int vilma); +void *tahvo_init(qemu_irq irq, int betty); + +void retu_key_event(void *retu, int state); + +/* tusb6010.c */ +struct tusb_s; +struct tusb_s *tusb6010_init(qemu_irq intr); +int tusb6010_sync_io(struct tusb_s *s); +int tusb6010_async_io(struct tusb_s *s); +void tusb6010_power(struct tusb_s *s, int on); + +/* tc6393xb.c */ +struct tc6393xb_s; +#define TC6393XB_RAM 0x110000 /* amount of ram for Video and USB */ +struct tc6393xb_s *tc6393xb_init(uint32_t base, qemu_irq irq, DisplayState *ds); +void tc6393xb_gpio_out_set(struct tc6393xb_s *s, int line, + qemu_irq handler); +qemu_irq *tc6393xb_gpio_in_get(struct tc6393xb_s *s); +qemu_irq tc6393xb_l3v_get(struct tc6393xb_s *s); + +/* sm501.c */ +void sm501_init(DisplayState *ds, uint32_t base, unsigned long local_mem_base, + uint32_t local_mem_bytes, CharDriverState *chr); #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/dma.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/dma.c --- qemu-0.9.1/hw/dma.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/dma.c 2008-10-31 17:25:56.000000000 +0000 @@ -78,6 +78,8 @@ }; +static void DMA_run (void); + static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0}; static void write_page (void *opaque, uint32_t nport, uint32_t data) @@ -214,6 +216,7 @@ d->status &= ~(1 << (ichan + 4)); } d->status &= ~(1 << ichan); + DMA_run(); break; case 0x0a: /* single mask */ @@ -221,6 +224,7 @@ d->mask |= 1 << (data & 3); else d->mask &= ~(1 << (data & 3)); + DMA_run(); break; case 0x0b: /* mode */ @@ -255,10 +259,12 @@ case 0x0e: /* clear mask for all channels */ d->mask = 0; + DMA_run(); break; case 0x0f: /* write mask for all channels */ d->mask = data; + DMA_run(); break; default: @@ -310,6 +316,7 @@ ichan = nchan & 3; linfo ("held cont=%d chan=%d\n", ncont, ichan); dma_controllers[ncont].status |= 1 << (ichan + 4); + DMA_run(); } void DMA_release_DREQ (int nchan) @@ -320,6 +327,7 @@ ichan = nchan & 3; linfo ("released cont=%d chan=%d\n", ncont, ichan); dma_controllers[ncont].status &= ~(1 << (ichan + 4)); + DMA_run(); } static void channel_run (int ncont, int ichan) @@ -347,10 +355,13 @@ ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont); } -void DMA_run (void) +static QEMUBH *dma_bh; + +static void DMA_run (void) { struct dma_cont *d; int icont, ichan; + int rearm = 0; d = dma_controllers; @@ -360,10 +371,20 @@ mask = 1 << ichan; - if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4)))) + if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4)))) { channel_run (icont, ichan); + rearm = 1; + } } } + + if (rearm) + qemu_bh_schedule_idle(dma_bh); +} + +static void DMA_run_bh(void *unused) +{ + DMA_run(); } void DMA_register_channel (int nchan, @@ -439,11 +460,18 @@ write_cont (d, (0x0d << d->dshift), 0); } +static int dma_phony_handler (void *opaque, int nchan, int dma_pos, int dma_len) +{ + dolog ("unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d\n", + nchan, dma_pos, dma_len); + return dma_pos; +} + /* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */ static void dma_init2(struct dma_cont *d, int base, int dshift, int page_base, int pageh_base) { - const static int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 }; + static const int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 }; int i; d->dshift = dshift; @@ -471,6 +499,9 @@ } qemu_register_reset(dma_reset, d); dma_reset(d); + for (i = 0; i < LENOFA (d->regs); ++i) { + d->regs[i].transfer_handler = dma_phony_handler; + } } static void dma_save (QEMUFile *f, void *opaque) @@ -524,6 +555,9 @@ qemu_get_8s (f, &r->dack); qemu_get_8s (f, &r->eop); } + + DMA_run(); + return 0; } @@ -535,4 +569,6 @@ high_page_enable ? 0x488 : -1); register_savevm ("dma", 0, 1, dma_save, dma_load, &dma_controllers[0]); register_savevm ("dma", 1, 1, dma_save, dma_load, &dma_controllers[1]); + + dma_bh = qemu_bh_new(DMA_run_bh, NULL); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ds1225y.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ds1225y.c --- qemu-0.9.1/hw/ds1225y.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/ds1225y.c 2008-03-13 19:23:00.000000000 +0000 @@ -1,123 +1,194 @@ -/* - * QEMU NVRAM emulation for DS1225Y chip - * - * Copyright (c) 2007 Hervé Poussineau - * - * 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 "hw.h" -#include "mips.h" -#include "nvram.h" - -typedef enum -{ - none = 0, - readmode, - writemode, -} nvram_open_mode; - -struct ds1225y_t -{ - target_phys_addr_t mem_base; - uint32_t capacity; - const char *filename; - QEMUFile *file; - nvram_open_mode open_mode; -}; - -static int ds1225y_set_to_mode(ds1225y_t *NVRAM, nvram_open_mode mode, const char *filemode) -{ - if (NVRAM->open_mode != mode) - { - if (NVRAM->file) - qemu_fclose(NVRAM->file); - NVRAM->file = qemu_fopen(NVRAM->filename, filemode); - NVRAM->open_mode = mode; - } - return (NVRAM->file != NULL); -} - -static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) -{ - ds1225y_t *NVRAM = opaque; - int64_t pos; - - pos = addr - NVRAM->mem_base; - if (addr >= NVRAM->capacity) - addr -= NVRAM->capacity; - - if (!ds1225y_set_to_mode(NVRAM, readmode, "rb")) - return 0; - qemu_fseek(NVRAM->file, pos, SEEK_SET); - return (uint32_t)qemu_get_byte(NVRAM->file); -} - -static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - ds1225y_t *NVRAM = opaque; - int64_t pos; - - pos = addr - NVRAM->mem_base; - if (ds1225y_set_to_mode(NVRAM, writemode, "wb")) - { - qemu_fseek(NVRAM->file, pos, SEEK_SET); - qemu_put_byte(NVRAM->file, (int)value); - } -} - -static CPUReadMemoryFunc *nvram_read[] = { - &nvram_readb, - NULL, - NULL, -}; - -static CPUWriteMemoryFunc *nvram_write[] = { - &nvram_writeb, - NULL, - NULL, -}; - -static CPUWriteMemoryFunc *nvram_none[] = { - NULL, - NULL, - NULL, -}; - -/* Initialisation routine */ -ds1225y_t *ds1225y_init(target_phys_addr_t mem_base, const char *filename) -{ - ds1225y_t *s; - int mem_index1, mem_index2; - - s = qemu_mallocz(sizeof(ds1225y_t)); - if (!s) - return NULL; - s->mem_base = mem_base; - s->capacity = 0x2000; /* Fixed for ds1225y chip: 8K */ - s->filename = filename; - - /* Read/write memory */ - mem_index1 = cpu_register_io_memory(0, nvram_read, nvram_write, s); - cpu_register_physical_memory(mem_base, s->capacity, mem_index1); - /* Read-only memory */ - mem_index2 = cpu_register_io_memory(0, nvram_read, nvram_none, s); - cpu_register_physical_memory(mem_base + s->capacity, s->capacity, mem_index2); - return s; -} +/* + * QEMU NVRAM emulation for DS1225Y chip + * + * Copyright (c) 2007-2008 Hervé Poussineau + * + * 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 "hw.h" +#include "mips.h" +#include "nvram.h" + +//#define DEBUG_NVRAM + +typedef struct ds1225y_t +{ + target_phys_addr_t mem_base; + uint32_t chip_size; + QEMUFile *file; + uint8_t *contents; + uint8_t protection; +} ds1225y_t; + + +static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) +{ + ds1225y_t *s = opaque; + int64_t pos; + uint32_t val; + + pos = addr - s->mem_base; + if (pos >= s->chip_size) + pos -= s->chip_size; + + val = s->contents[pos]; + +#ifdef DEBUG_NVRAM + printf("nvram: read 0x%x at " TARGET_FMT_lx "\n", val, addr); +#endif + return val; +} + +static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr) +{ + uint32_t v; + v = nvram_readb(opaque, addr); + v |= nvram_readb(opaque, addr + 1) << 8; + return v; +} + +static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr) +{ + uint32_t v; + v = nvram_readb(opaque, addr); + v |= nvram_readb(opaque, addr + 1) << 8; + v |= nvram_readb(opaque, addr + 2) << 16; + v |= nvram_readb(opaque, addr + 3) << 24; + return v; +} + +static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) +{ + ds1225y_t *s = opaque; + int64_t pos; + +#ifdef DEBUG_NVRAM + printf("nvram: write 0x%x at " TARGET_FMT_lx "\n", val, addr); +#endif + + pos = addr - s->mem_base; + s->contents[pos] = val & 0xff; + if (s->file) { + qemu_fseek(s->file, pos, SEEK_SET); + qemu_put_byte(s->file, (int)val); + qemu_fflush(s->file); + } +} + +static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t val) +{ + nvram_writeb(opaque, addr, val & 0xff); + nvram_writeb(opaque, addr + 1, (val >> 8) & 0xff); +} + +static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t val) +{ + nvram_writeb(opaque, addr, val & 0xff); + nvram_writeb(opaque, addr + 1, (val >> 8) & 0xff); + nvram_writeb(opaque, addr + 2, (val >> 16) & 0xff); + nvram_writeb(opaque, addr + 3, (val >> 24) & 0xff); +} + +static void nvram_writeb_protected (void *opaque, target_phys_addr_t addr, uint32_t val) +{ + ds1225y_t *s = opaque; + + if (s->protection != 7) { +#ifdef DEBUG_NVRAM + printf("nvram: prevent write of 0x%x at " TARGET_FMT_lx "\n", val, addr); +#endif + return; + } + + nvram_writeb(opaque, addr - s->chip_size, val); +} + +static void nvram_writew_protected (void *opaque, target_phys_addr_t addr, uint32_t val) +{ + nvram_writeb_protected(opaque, addr, val & 0xff); + nvram_writeb_protected(opaque, addr + 1, (val >> 8) & 0xff); +} + +static void nvram_writel_protected (void *opaque, target_phys_addr_t addr, uint32_t val) +{ + nvram_writeb_protected(opaque, addr, val & 0xff); + nvram_writeb_protected(opaque, addr + 1, (val >> 8) & 0xff); + nvram_writeb_protected(opaque, addr + 2, (val >> 16) & 0xff); + nvram_writeb_protected(opaque, addr + 3, (val >> 24) & 0xff); +} + +static CPUReadMemoryFunc *nvram_read[] = { + &nvram_readb, + &nvram_readw, + &nvram_readl, +}; + +static CPUWriteMemoryFunc *nvram_write[] = { + &nvram_writeb, + &nvram_writew, + &nvram_writel, +}; + +static CPUWriteMemoryFunc *nvram_write_protected[] = { + &nvram_writeb_protected, + &nvram_writew_protected, + &nvram_writel_protected, +}; + +/* Initialisation routine */ +void *ds1225y_init(target_phys_addr_t mem_base, const char *filename) +{ + ds1225y_t *s; + int mem_indexRW, mem_indexRP; + QEMUFile *file; + + s = qemu_mallocz(sizeof(ds1225y_t)); + if (!s) + return NULL; + s->chip_size = 0x2000; /* Fixed for ds1225y chip: 8 KiB */ + s->contents = qemu_mallocz(s->chip_size); + if (!s->contents) { + return NULL; + } + s->mem_base = mem_base; + s->protection = 7; + + /* Read current file */ + file = qemu_fopen(filename, "rb"); + if (file) { + /* Read nvram contents */ + qemu_get_buffer(file, s->contents, s->chip_size); + qemu_fclose(file); + } + s->file = qemu_fopen(filename, "wb"); + if (s->file) { + /* Write back contents, as 'wb' mode cleaned the file */ + qemu_put_buffer(s->file, s->contents, s->chip_size); + qemu_fflush(s->file); + } + + /* Read/write memory */ + mem_indexRW = cpu_register_io_memory(0, nvram_read, nvram_write, s); + cpu_register_physical_memory(mem_base, s->chip_size, mem_indexRW); + /* Read/write protected memory */ + mem_indexRP = cpu_register_io_memory(0, nvram_read, nvram_write_protected, s); + cpu_register_physical_memory(mem_base + s->chip_size, s->chip_size, mem_indexRP); + return s; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/dummy_m68k.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/dummy_m68k.c --- qemu-0.9.1/hw/dummy_m68k.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/dummy_m68k.c 2008-10-28 10:59:59.000000000 +0000 @@ -14,7 +14,7 @@ /* Board init. */ -static void dummy_m68k_init(int ram_size, int vga_ram_size, +static void dummy_m68k_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -63,7 +63,7 @@ } QEMUMachine dummy_m68k_machine = { - "dummy", - "Dummy board", - dummy_m68k_init, + .name = "dummy", + .desc = "Dummy board", + .init = dummy_m68k_init, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/e1000.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/e1000.c --- qemu-0.9.1/hw/e1000.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/e1000.c 2008-10-02 20:14:17.000000000 +0100 @@ -0,0 +1,1007 @@ +/* + * QEMU e1000 emulation + * + * Nir Peleg, Tutis Systems Ltd. for Qumranet Inc. + * Copyright (c) 2008 Qumranet + * Based on work done by: + * Copyright (c) 2007 Dan Aloni + * Copyright (c) 2004 Antony T Curtis + * + * 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 "hw.h" +#include "pci.h" +#include "net.h" + +#include "e1000_hw.h" + +#define DEBUG + +#ifdef DEBUG +enum { + DEBUG_GENERAL, DEBUG_IO, DEBUG_MMIO, DEBUG_INTERRUPT, + DEBUG_RX, DEBUG_TX, DEBUG_MDIC, DEBUG_EEPROM, + DEBUG_UNKNOWN, DEBUG_TXSUM, DEBUG_TXERR, DEBUG_RXERR, + DEBUG_RXFILTER, DEBUG_NOTYET, +}; +#define DBGBIT(x) (1<>2) +enum { + defreg(CTRL), defreg(EECD), defreg(EERD), defreg(GPRC), + defreg(GPTC), defreg(ICR), defreg(ICS), defreg(IMC), + defreg(IMS), defreg(LEDCTL), defreg(MANC), defreg(MDIC), + defreg(MPC), defreg(PBA), defreg(RCTL), defreg(RDBAH), + defreg(RDBAL), defreg(RDH), defreg(RDLEN), defreg(RDT), + defreg(STATUS), defreg(SWSM), defreg(TCTL), defreg(TDBAH), + defreg(TDBAL), defreg(TDH), defreg(TDLEN), defreg(TDT), + defreg(TORH), defreg(TORL), defreg(TOTH), defreg(TOTL), + defreg(TPR), defreg(TPT), defreg(TXDCTL), defreg(WUFC), + defreg(RA), defreg(MTA), defreg(CRCERRS), +}; + +enum { PHY_R = 1, PHY_W = 2, PHY_RW = PHY_R | PHY_W }; +static const char phy_regcap[0x20] = { + [PHY_STATUS] = PHY_R, [M88E1000_EXT_PHY_SPEC_CTRL] = PHY_RW, + [PHY_ID1] = PHY_R, [M88E1000_PHY_SPEC_CTRL] = PHY_RW, + [PHY_CTRL] = PHY_RW, [PHY_1000T_CTRL] = PHY_RW, + [PHY_LP_ABILITY] = PHY_R, [PHY_1000T_STATUS] = PHY_R, + [PHY_AUTONEG_ADV] = PHY_RW, [M88E1000_RX_ERR_CNTR] = PHY_R, + [PHY_ID2] = PHY_R, [M88E1000_PHY_SPEC_STATUS] = PHY_R +}; + +static void +ioport_map(PCIDevice *pci_dev, int region_num, uint32_t addr, + uint32_t size, int type) +{ + DBGOUT(IO, "e1000_ioport_map addr=0x%04x size=0x%08x\n", addr, size); +} + +static void +set_interrupt_cause(E1000State *s, int index, uint32_t val) +{ + if (val) + val |= E1000_ICR_INT_ASSERTED; + s->mac_reg[ICR] = val; + qemu_set_irq(s->dev.irq[0], (s->mac_reg[IMS] & s->mac_reg[ICR]) != 0); +} + +static void +set_ics(E1000State *s, int index, uint32_t val) +{ + DBGOUT(INTERRUPT, "set_ics %x, ICR %x, IMR %x\n", val, s->mac_reg[ICR], + s->mac_reg[IMS]); + set_interrupt_cause(s, 0, val | s->mac_reg[ICR]); +} + +static int +rxbufsize(uint32_t v) +{ + v &= E1000_RCTL_BSEX | E1000_RCTL_SZ_16384 | E1000_RCTL_SZ_8192 | + E1000_RCTL_SZ_4096 | E1000_RCTL_SZ_2048 | E1000_RCTL_SZ_1024 | + E1000_RCTL_SZ_512 | E1000_RCTL_SZ_256; + switch (v) { + case E1000_RCTL_BSEX | E1000_RCTL_SZ_16384: + return 16384; + case E1000_RCTL_BSEX | E1000_RCTL_SZ_8192: + return 8192; + case E1000_RCTL_BSEX | E1000_RCTL_SZ_4096: + return 4096; + case E1000_RCTL_SZ_1024: + return 1024; + case E1000_RCTL_SZ_512: + return 512; + case E1000_RCTL_SZ_256: + return 256; + } + return 2048; +} + +static void +set_rx_control(E1000State *s, int index, uint32_t val) +{ + s->mac_reg[RCTL] = val; + s->rxbuf_size = rxbufsize(val); + s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1; + DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT], + s->mac_reg[RCTL]); +} + +static void +set_mdic(E1000State *s, int index, uint32_t val) +{ + uint32_t data = val & E1000_MDIC_DATA_MASK; + uint32_t addr = ((val & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT); + + if ((val & E1000_MDIC_PHY_MASK) >> E1000_MDIC_PHY_SHIFT != 1) // phy # + val = s->mac_reg[MDIC] | E1000_MDIC_ERROR; + else if (val & E1000_MDIC_OP_READ) { + DBGOUT(MDIC, "MDIC read reg 0x%x\n", addr); + if (!(phy_regcap[addr] & PHY_R)) { + DBGOUT(MDIC, "MDIC read reg %x unhandled\n", addr); + val |= E1000_MDIC_ERROR; + } else + val = (val ^ data) | s->phy_reg[addr]; + } else if (val & E1000_MDIC_OP_WRITE) { + DBGOUT(MDIC, "MDIC write reg 0x%x, value 0x%x\n", addr, data); + if (!(phy_regcap[addr] & PHY_W)) { + DBGOUT(MDIC, "MDIC write reg %x unhandled\n", addr); + val |= E1000_MDIC_ERROR; + } else + s->phy_reg[addr] = data; + } + s->mac_reg[MDIC] = val | E1000_MDIC_READY; + set_ics(s, 0, E1000_ICR_MDAC); +} + +static uint32_t +get_eecd(E1000State *s, int index) +{ + uint32_t ret = E1000_EECD_PRES|E1000_EECD_GNT | s->eecd_state.old_eecd; + + DBGOUT(EEPROM, "reading eeprom bit %d (reading %d)\n", + s->eecd_state.bitnum_out, s->eecd_state.reading); + if (!s->eecd_state.reading || + ((s->eeprom_data[(s->eecd_state.bitnum_out >> 4) & 0x3f] >> + ((s->eecd_state.bitnum_out & 0xf) ^ 0xf))) & 1) + ret |= E1000_EECD_DO; + return ret; +} + +static void +set_eecd(E1000State *s, int index, uint32_t val) +{ + uint32_t oldval = s->eecd_state.old_eecd; + + s->eecd_state.old_eecd = val & (E1000_EECD_SK | E1000_EECD_CS | + E1000_EECD_DI|E1000_EECD_FWE_MASK|E1000_EECD_REQ); + if (!(E1000_EECD_SK & (val ^ oldval))) // no clock edge + return; + if (!(E1000_EECD_SK & val)) { // falling edge + s->eecd_state.bitnum_out++; + return; + } + if (!(val & E1000_EECD_CS)) { // rising, no CS (EEPROM reset) + memset(&s->eecd_state, 0, sizeof s->eecd_state); + return; + } + s->eecd_state.val_in <<= 1; + if (val & E1000_EECD_DI) + s->eecd_state.val_in |= 1; + if (++s->eecd_state.bitnum_in == 9 && !s->eecd_state.reading) { + s->eecd_state.bitnum_out = ((s->eecd_state.val_in & 0x3f)<<4)-1; + s->eecd_state.reading = (((s->eecd_state.val_in >> 6) & 7) == + EEPROM_READ_OPCODE_MICROWIRE); + } + DBGOUT(EEPROM, "eeprom bitnum in %d out %d, reading %d\n", + s->eecd_state.bitnum_in, s->eecd_state.bitnum_out, + s->eecd_state.reading); +} + +static uint32_t +flash_eerd_read(E1000State *s, int x) +{ + unsigned int index, r = s->mac_reg[EERD] & ~E1000_EEPROM_RW_REG_START; + + if ((index = r >> E1000_EEPROM_RW_ADDR_SHIFT) > EEPROM_CHECKSUM_REG) + return 0; + return (s->eeprom_data[index] << E1000_EEPROM_RW_REG_DATA) | + E1000_EEPROM_RW_REG_DONE | r; +} + +static void +putsum(uint8_t *data, uint32_t n, uint32_t sloc, uint32_t css, uint32_t cse) +{ + uint32_t sum; + + if (cse && cse < n) + n = cse + 1; + if (sloc < n-1) { + sum = net_checksum_add(n-css, data+css); + cpu_to_be16wu((uint16_t *)(data + sloc), + net_checksum_finish(sum)); + } +} + +static void +xmit_seg(E1000State *s) +{ + uint16_t len, *sp; + unsigned int frames = s->tx.tso_frames, css, sofar, n; + struct e1000_tx *tp = &s->tx; + + if (tp->tse && tp->cptse) { + css = tp->ipcss; + DBGOUT(TXSUM, "frames %d size %d ipcss %d\n", + frames, tp->size, css); + if (tp->ip) { // IPv4 + cpu_to_be16wu((uint16_t *)(tp->data+css+2), + tp->size - css); + cpu_to_be16wu((uint16_t *)(tp->data+css+4), + be16_to_cpup((uint16_t *)(tp->data+css+4))+frames); + } else // IPv6 + cpu_to_be16wu((uint16_t *)(tp->data+css+4), + tp->size - css); + css = tp->tucss; + len = tp->size - css; + DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", tp->tcp, css, len); + if (tp->tcp) { + sofar = frames * tp->mss; + cpu_to_be32wu((uint32_t *)(tp->data+css+4), // seq + be32_to_cpupu((uint32_t *)(tp->data+css+4))+sofar); + if (tp->paylen - sofar > tp->mss) + tp->data[css + 13] &= ~9; // PSH, FIN + } else // UDP + cpu_to_be16wu((uint16_t *)(tp->data+css+4), len); + if (tp->sum_needed & E1000_TXD_POPTS_TXSM) { + // add pseudo-header length before checksum calculation + sp = (uint16_t *)(tp->data + tp->tucso); + cpu_to_be16wu(sp, be16_to_cpup(sp) + len); + } + tp->tso_frames++; + } + + if (tp->sum_needed & E1000_TXD_POPTS_TXSM) + putsum(tp->data, tp->size, tp->tucso, tp->tucss, tp->tucse); + if (tp->sum_needed & E1000_TXD_POPTS_IXSM) + putsum(tp->data, tp->size, tp->ipcso, tp->ipcss, tp->ipcse); + qemu_send_packet(s->vc, tp->data, tp->size); + s->mac_reg[TPT]++; + s->mac_reg[GPTC]++; + n = s->mac_reg[TOTL]; + if ((s->mac_reg[TOTL] += s->tx.size) < n) + s->mac_reg[TOTH]++; +} + +static void +process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) +{ + uint32_t txd_lower = le32_to_cpu(dp->lower.data); + uint32_t dtype = txd_lower & (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D); + unsigned int split_size = txd_lower & 0xffff, bytes, sz, op; + unsigned int msh = 0xfffff, hdr = 0; + uint64_t addr; + struct e1000_context_desc *xp = (struct e1000_context_desc *)dp; + struct e1000_tx *tp = &s->tx; + + if (dtype == E1000_TXD_CMD_DEXT) { // context descriptor + op = le32_to_cpu(xp->cmd_and_length); + tp->ipcss = xp->lower_setup.ip_fields.ipcss; + tp->ipcso = xp->lower_setup.ip_fields.ipcso; + tp->ipcse = le16_to_cpu(xp->lower_setup.ip_fields.ipcse); + tp->tucss = xp->upper_setup.tcp_fields.tucss; + tp->tucso = xp->upper_setup.tcp_fields.tucso; + tp->tucse = le16_to_cpu(xp->upper_setup.tcp_fields.tucse); + tp->paylen = op & 0xfffff; + tp->hdr_len = xp->tcp_seg_setup.fields.hdr_len; + tp->mss = le16_to_cpu(xp->tcp_seg_setup.fields.mss); + tp->ip = (op & E1000_TXD_CMD_IP) ? 1 : 0; + tp->tcp = (op & E1000_TXD_CMD_TCP) ? 1 : 0; + tp->tse = (op & E1000_TXD_CMD_TSE) ? 1 : 0; + tp->tso_frames = 0; + if (tp->tucso == 0) { // this is probably wrong + DBGOUT(TXSUM, "TCP/UDP: cso 0!\n"); + tp->tucso = tp->tucss + (tp->tcp ? 16 : 6); + } + return; + } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) { + // data descriptor + tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8; + tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0; + } else + // legacy descriptor + tp->cptse = 0; + + addr = le64_to_cpu(dp->buffer_addr); + if (tp->tse && tp->cptse) { + hdr = tp->hdr_len; + msh = hdr + tp->mss; + do { + bytes = split_size; + if (tp->size + bytes > msh) + bytes = msh - tp->size; + cpu_physical_memory_read(addr, tp->data + tp->size, bytes); + if ((sz = tp->size + bytes) >= hdr && tp->size < hdr) + memmove(tp->header, tp->data, hdr); + tp->size = sz; + addr += bytes; + if (sz == msh) { + xmit_seg(s); + memmove(tp->data, tp->header, hdr); + tp->size = hdr; + } + } while (split_size -= bytes); + } else if (!tp->tse && tp->cptse) { + // context descriptor TSE is not set, while data descriptor TSE is set + DBGOUT(TXERR, "TCP segmentaion Error\n"); + } else { + cpu_physical_memory_read(addr, tp->data + tp->size, split_size); + tp->size += split_size; + } + + if (!(txd_lower & E1000_TXD_CMD_EOP)) + return; + if (!(tp->tse && tp->cptse && tp->size < hdr)) + xmit_seg(s); + tp->tso_frames = 0; + tp->sum_needed = 0; + tp->size = 0; + tp->cptse = 0; +} + +static uint32_t +txdesc_writeback(target_phys_addr_t base, struct e1000_tx_desc *dp) +{ + uint32_t txd_upper, txd_lower = le32_to_cpu(dp->lower.data); + + if (!(txd_lower & (E1000_TXD_CMD_RS|E1000_TXD_CMD_RPS))) + return 0; + txd_upper = (le32_to_cpu(dp->upper.data) | E1000_TXD_STAT_DD) & + ~(E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | E1000_TXD_STAT_TU); + dp->upper.data = cpu_to_le32(txd_upper); + cpu_physical_memory_write(base + ((char *)&dp->upper - (char *)dp), + (void *)&dp->upper, sizeof(dp->upper)); + return E1000_ICR_TXDW; +} + +static void +start_xmit(E1000State *s) +{ + target_phys_addr_t base; + struct e1000_tx_desc desc; + uint32_t tdh_start = s->mac_reg[TDH], cause = E1000_ICS_TXQE; + + if (!(s->mac_reg[TCTL] & E1000_TCTL_EN)) { + DBGOUT(TX, "tx disabled\n"); + return; + } + + while (s->mac_reg[TDH] != s->mac_reg[TDT]) { + base = ((uint64_t)s->mac_reg[TDBAH] << 32) + s->mac_reg[TDBAL] + + sizeof(struct e1000_tx_desc) * s->mac_reg[TDH]; + cpu_physical_memory_read(base, (void *)&desc, sizeof(desc)); + + DBGOUT(TX, "index %d: %p : %x %x\n", s->mac_reg[TDH], + (void *)(intptr_t)desc.buffer_addr, desc.lower.data, + desc.upper.data); + + process_tx_desc(s, &desc); + cause |= txdesc_writeback(base, &desc); + + if (++s->mac_reg[TDH] * sizeof(desc) >= s->mac_reg[TDLEN]) + s->mac_reg[TDH] = 0; + /* + * the following could happen only if guest sw assigns + * bogus values to TDT/TDLEN. + * there's nothing too intelligent we could do about this. + */ + if (s->mac_reg[TDH] == tdh_start) { + DBGOUT(TXERR, "TDH wraparound @%x, TDT %x, TDLEN %x\n", + tdh_start, s->mac_reg[TDT], s->mac_reg[TDLEN]); + break; + } + } + set_ics(s, 0, cause); +} + +static int +receive_filter(E1000State *s, const uint8_t *buf, int size) +{ + static uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + static int mta_shift[] = {4, 3, 2, 0}; + uint32_t f, rctl = s->mac_reg[RCTL], ra[2], *rp; + + if (rctl & E1000_RCTL_UPE) // promiscuous + return 1; + + if ((buf[0] & 1) && (rctl & E1000_RCTL_MPE)) // promiscuous mcast + return 1; + + if ((rctl & E1000_RCTL_BAM) && !memcmp(buf, bcast, sizeof bcast)) + return 1; + + for (rp = s->mac_reg + RA; rp < s->mac_reg + RA + 32; rp += 2) { + if (!(rp[1] & E1000_RAH_AV)) + continue; + ra[0] = cpu_to_le32(rp[0]); + ra[1] = cpu_to_le32(rp[1]); + if (!memcmp(buf, (uint8_t *)ra, 6)) { + DBGOUT(RXFILTER, + "unicast match[%d]: %02x:%02x:%02x:%02x:%02x:%02x\n", + (int)(rp - s->mac_reg - RA)/2, + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + return 1; + } + } + DBGOUT(RXFILTER, "unicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + + f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3]; + f = (((buf[5] << 8) | buf[4]) >> f) & 0xfff; + if (s->mac_reg[MTA + (f >> 5)] & (1 << (f & 0x1f))) + return 1; + DBGOUT(RXFILTER, + "dropping, inexact filter mismatch: %02x:%02x:%02x:%02x:%02x:%02x MO %d MTA[%d] %x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], + (rctl >> E1000_RCTL_MO_SHIFT) & 3, f >> 5, + s->mac_reg[MTA + (f >> 5)]); + + return 0; +} + +static int +e1000_can_receive(void *opaque) +{ + E1000State *s = opaque; + + return (s->mac_reg[RCTL] & E1000_RCTL_EN); +} + +static void +e1000_receive(void *opaque, const uint8_t *buf, int size) +{ + E1000State *s = opaque; + struct e1000_rx_desc desc; + target_phys_addr_t base; + unsigned int n, rdt; + uint32_t rdh_start; + + if (!(s->mac_reg[RCTL] & E1000_RCTL_EN)) + return; + + if (size > s->rxbuf_size) { + DBGOUT(RX, "packet too large for buffers (%d > %d)\n", size, + s->rxbuf_size); + return; + } + + if (!receive_filter(s, buf, size)) + return; + + rdh_start = s->mac_reg[RDH]; + size += 4; // for the header + do { + if (s->mac_reg[RDH] == s->mac_reg[RDT] && s->check_rxov) { + set_ics(s, 0, E1000_ICS_RXO); + return; + } + base = ((uint64_t)s->mac_reg[RDBAH] << 32) + s->mac_reg[RDBAL] + + sizeof(desc) * s->mac_reg[RDH]; + cpu_physical_memory_read(base, (void *)&desc, sizeof(desc)); + desc.status |= E1000_RXD_STAT_DD; + if (desc.buffer_addr) { + cpu_physical_memory_write(le64_to_cpu(desc.buffer_addr), + (void *)buf, size); + desc.length = cpu_to_le16(size); + desc.status |= E1000_RXD_STAT_EOP|E1000_RXD_STAT_IXSM; + } else // as per intel docs; skip descriptors with null buf addr + DBGOUT(RX, "Null RX descriptor!!\n"); + cpu_physical_memory_write(base, (void *)&desc, sizeof(desc)); + + if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN]) + s->mac_reg[RDH] = 0; + s->check_rxov = 1; + /* see comment in start_xmit; same here */ + if (s->mac_reg[RDH] == rdh_start) { + DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n", + rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]); + set_ics(s, 0, E1000_ICS_RXO); + return; + } + } while (desc.buffer_addr == 0); + + s->mac_reg[GPRC]++; + s->mac_reg[TPR]++; + n = s->mac_reg[TORL]; + if ((s->mac_reg[TORL] += size) < n) + s->mac_reg[TORH]++; + + n = E1000_ICS_RXT0; + if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH]) + rdt += s->mac_reg[RDLEN] / sizeof(desc); + if (((rdt - s->mac_reg[RDH]) * sizeof(desc)) << s->rxbuf_min_shift >= + s->mac_reg[RDLEN]) + n |= E1000_ICS_RXDMT0; + + set_ics(s, 0, n); +} + +static uint32_t +mac_readreg(E1000State *s, int index) +{ + return s->mac_reg[index]; +} + +static uint32_t +mac_icr_read(E1000State *s, int index) +{ + uint32_t ret = s->mac_reg[ICR]; + + DBGOUT(INTERRUPT, "ICR read: %x\n", ret); + set_interrupt_cause(s, 0, 0); + return ret; +} + +static uint32_t +mac_read_clr4(E1000State *s, int index) +{ + uint32_t ret = s->mac_reg[index]; + + s->mac_reg[index] = 0; + return ret; +} + +static uint32_t +mac_read_clr8(E1000State *s, int index) +{ + uint32_t ret = s->mac_reg[index]; + + s->mac_reg[index] = 0; + s->mac_reg[index-1] = 0; + return ret; +} + +static void +mac_writereg(E1000State *s, int index, uint32_t val) +{ + s->mac_reg[index] = val; +} + +static void +set_rdt(E1000State *s, int index, uint32_t val) +{ + s->check_rxov = 0; + s->mac_reg[index] = val & 0xffff; +} + +static void +set_16bit(E1000State *s, int index, uint32_t val) +{ + s->mac_reg[index] = val & 0xffff; +} + +static void +set_dlen(E1000State *s, int index, uint32_t val) +{ + s->mac_reg[index] = val & 0xfff80; +} + +static void +set_tctl(E1000State *s, int index, uint32_t val) +{ + s->mac_reg[index] = val; + s->mac_reg[TDT] &= 0xffff; + start_xmit(s); +} + +static void +set_icr(E1000State *s, int index, uint32_t val) +{ + DBGOUT(INTERRUPT, "set_icr %x\n", val); + set_interrupt_cause(s, 0, s->mac_reg[ICR] & ~val); +} + +static void +set_imc(E1000State *s, int index, uint32_t val) +{ + s->mac_reg[IMS] &= ~val; + set_ics(s, 0, 0); +} + +static void +set_ims(E1000State *s, int index, uint32_t val) +{ + s->mac_reg[IMS] |= val; + set_ics(s, 0, 0); +} + +#define getreg(x) [x] = mac_readreg +static uint32_t (*macreg_readops[])(E1000State *, int) = { + getreg(PBA), getreg(RCTL), getreg(TDH), getreg(TXDCTL), + getreg(WUFC), getreg(TDT), getreg(CTRL), getreg(LEDCTL), + getreg(MANC), getreg(MDIC), getreg(SWSM), getreg(STATUS), + getreg(TORL), getreg(TOTL), getreg(IMS), getreg(TCTL), + getreg(RDH), getreg(RDT), + + [TOTH] = mac_read_clr8, [TORH] = mac_read_clr8, [GPRC] = mac_read_clr4, + [GPTC] = mac_read_clr4, [TPR] = mac_read_clr4, [TPT] = mac_read_clr4, + [ICR] = mac_icr_read, [EECD] = get_eecd, [EERD] = flash_eerd_read, + [CRCERRS ... MPC] = &mac_readreg, + [RA ... RA+31] = &mac_readreg, + [MTA ... MTA+127] = &mac_readreg, +}; +enum { NREADOPS = sizeof(macreg_readops) / sizeof(*macreg_readops) }; + +#define putreg(x) [x] = mac_writereg +static void (*macreg_writeops[])(E1000State *, int, uint32_t) = { + putreg(PBA), putreg(EERD), putreg(SWSM), putreg(WUFC), + putreg(TDBAL), putreg(TDBAH), putreg(TXDCTL), putreg(RDBAH), + putreg(RDBAL), putreg(LEDCTL), + [TDLEN] = set_dlen, [RDLEN] = set_dlen, [TCTL] = set_tctl, + [TDT] = set_tctl, [MDIC] = set_mdic, [ICS] = set_ics, + [TDH] = set_16bit, [RDH] = set_16bit, [RDT] = set_rdt, + [IMC] = set_imc, [IMS] = set_ims, [ICR] = set_icr, + [EECD] = set_eecd, [RCTL] = set_rx_control, + [RA ... RA+31] = &mac_writereg, + [MTA ... MTA+127] = &mac_writereg, +}; +enum { NWRITEOPS = sizeof(macreg_writeops) / sizeof(*macreg_writeops) }; + +static void +e1000_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + E1000State *s = opaque; + unsigned int index = ((addr - s->mmio_base) & 0x1ffff) >> 2; + +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + if (index < NWRITEOPS && macreg_writeops[index]) + macreg_writeops[index](s, index, val); + else if (index < NREADOPS && macreg_readops[index]) + DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04x\n", index<<2, val); + else + DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08x\n", + index<<2, val); +} + +static void +e1000_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + // emulate hw without byte enables: no RMW + e1000_mmio_writel(opaque, addr & ~3, + (val & 0xffff) << (8*(addr & 3))); +} + +static void +e1000_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + // emulate hw without byte enables: no RMW + e1000_mmio_writel(opaque, addr & ~3, + (val & 0xff) << (8*(addr & 3))); +} + +static uint32_t +e1000_mmio_readl(void *opaque, target_phys_addr_t addr) +{ + E1000State *s = opaque; + unsigned int index = ((addr - s->mmio_base) & 0x1ffff) >> 2; + + if (index < NREADOPS && macreg_readops[index]) + { + uint32_t val = macreg_readops[index](s, index); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; + } + DBGOUT(UNKNOWN, "MMIO unknown read addr=0x%08x\n", index<<2); + return 0; +} + +static uint32_t +e1000_mmio_readb(void *opaque, target_phys_addr_t addr) +{ + return ((e1000_mmio_readl(opaque, addr & ~3)) >> + (8 * (addr & 3))) & 0xff; +} + +static uint32_t +e1000_mmio_readw(void *opaque, target_phys_addr_t addr) +{ + return ((e1000_mmio_readl(opaque, addr & ~3)) >> + (8 * (addr & 3))) & 0xffff; +} + +static const int mac_regtosave[] = { + CTRL, EECD, EERD, GPRC, GPTC, ICR, ICS, IMC, IMS, + LEDCTL, MANC, MDIC, MPC, PBA, RCTL, RDBAH, RDBAL, RDH, + RDLEN, RDT, STATUS, SWSM, TCTL, TDBAH, TDBAL, TDH, TDLEN, + TDT, TORH, TORL, TOTH, TOTL, TPR, TPT, TXDCTL, WUFC, +}; +enum { MAC_NSAVE = sizeof mac_regtosave/sizeof *mac_regtosave }; + +static const struct { + int size; + int array0; +} mac_regarraystosave[] = { {32, RA}, {128, MTA} }; +enum { MAC_NARRAYS = sizeof mac_regarraystosave/sizeof *mac_regarraystosave }; + +static void +nic_save(QEMUFile *f, void *opaque) +{ + E1000State *s = (E1000State *)opaque; + int i, j; + + pci_device_save(&s->dev, f); + qemu_put_be32s(f, &s->mmio_base); + qemu_put_be32s(f, &s->rxbuf_size); + qemu_put_be32s(f, &s->rxbuf_min_shift); + qemu_put_be32s(f, &s->eecd_state.val_in); + qemu_put_be16s(f, &s->eecd_state.bitnum_in); + qemu_put_be16s(f, &s->eecd_state.bitnum_out); + qemu_put_be16s(f, &s->eecd_state.reading); + qemu_put_be32s(f, &s->eecd_state.old_eecd); + qemu_put_8s(f, &s->tx.ipcss); + qemu_put_8s(f, &s->tx.ipcso); + qemu_put_be16s(f, &s->tx.ipcse); + qemu_put_8s(f, &s->tx.tucss); + qemu_put_8s(f, &s->tx.tucso); + qemu_put_be16s(f, &s->tx.tucse); + qemu_put_be32s(f, &s->tx.paylen); + qemu_put_8s(f, &s->tx.hdr_len); + qemu_put_be16s(f, &s->tx.mss); + qemu_put_be16s(f, &s->tx.size); + qemu_put_be16s(f, &s->tx.tso_frames); + qemu_put_8s(f, &s->tx.sum_needed); + qemu_put_s8s(f, &s->tx.ip); + qemu_put_s8s(f, &s->tx.tcp); + qemu_put_buffer(f, s->tx.header, sizeof s->tx.header); + qemu_put_buffer(f, s->tx.data, sizeof s->tx.data); + for (i = 0; i < 64; i++) + qemu_put_be16s(f, s->eeprom_data + i); + for (i = 0; i < 0x20; i++) + qemu_put_be16s(f, s->phy_reg + i); + for (i = 0; i < MAC_NSAVE; i++) + qemu_put_be32s(f, s->mac_reg + mac_regtosave[i]); + for (i = 0; i < MAC_NARRAYS; i++) + for (j = 0; j < mac_regarraystosave[i].size; j++) + qemu_put_be32s(f, + s->mac_reg + mac_regarraystosave[i].array0 + j); +} + +static int +nic_load(QEMUFile *f, void *opaque, int version_id) +{ + E1000State *s = (E1000State *)opaque; + int i, j, ret; + + if ((ret = pci_device_load(&s->dev, f)) < 0) + return ret; + if (version_id == 1) + qemu_get_sbe32s(f, &i); /* once some unused instance id */ + qemu_get_be32s(f, &s->mmio_base); + qemu_get_be32s(f, &s->rxbuf_size); + qemu_get_be32s(f, &s->rxbuf_min_shift); + qemu_get_be32s(f, &s->eecd_state.val_in); + qemu_get_be16s(f, &s->eecd_state.bitnum_in); + qemu_get_be16s(f, &s->eecd_state.bitnum_out); + qemu_get_be16s(f, &s->eecd_state.reading); + qemu_get_be32s(f, &s->eecd_state.old_eecd); + qemu_get_8s(f, &s->tx.ipcss); + qemu_get_8s(f, &s->tx.ipcso); + qemu_get_be16s(f, &s->tx.ipcse); + qemu_get_8s(f, &s->tx.tucss); + qemu_get_8s(f, &s->tx.tucso); + qemu_get_be16s(f, &s->tx.tucse); + qemu_get_be32s(f, &s->tx.paylen); + qemu_get_8s(f, &s->tx.hdr_len); + qemu_get_be16s(f, &s->tx.mss); + qemu_get_be16s(f, &s->tx.size); + qemu_get_be16s(f, &s->tx.tso_frames); + qemu_get_8s(f, &s->tx.sum_needed); + qemu_get_s8s(f, &s->tx.ip); + qemu_get_s8s(f, &s->tx.tcp); + qemu_get_buffer(f, s->tx.header, sizeof s->tx.header); + qemu_get_buffer(f, s->tx.data, sizeof s->tx.data); + for (i = 0; i < 64; i++) + qemu_get_be16s(f, s->eeprom_data + i); + for (i = 0; i < 0x20; i++) + qemu_get_be16s(f, s->phy_reg + i); + for (i = 0; i < MAC_NSAVE; i++) + qemu_get_be32s(f, s->mac_reg + mac_regtosave[i]); + for (i = 0; i < MAC_NARRAYS; i++) + for (j = 0; j < mac_regarraystosave[i].size; j++) + qemu_get_be32s(f, + s->mac_reg + mac_regarraystosave[i].array0 + j); + return 0; +} + +static const uint16_t e1000_eeprom_template[64] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, + 0x3000, 0x1000, 0x6403, E1000_DEVID, 0x8086, E1000_DEVID, 0x8086, 0x3040, + 0x0008, 0x2000, 0x7e14, 0x0048, 0x1000, 0x00d8, 0x0000, 0x2700, + 0x6cc9, 0x3150, 0x0722, 0x040b, 0x0984, 0x0000, 0xc000, 0x0706, + 0x1008, 0x0000, 0x0f04, 0x7fff, 0x4d01, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0x0100, 0x4000, 0x121c, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, +}; + +static const uint16_t phy_reg_init[] = { + [PHY_CTRL] = 0x1140, [PHY_STATUS] = 0x796d, // link initially up + [PHY_ID1] = 0x141, [PHY_ID2] = PHY_ID2_INIT, + [PHY_1000T_CTRL] = 0x0e00, [M88E1000_PHY_SPEC_CTRL] = 0x360, + [M88E1000_EXT_PHY_SPEC_CTRL] = 0x0d60, [PHY_AUTONEG_ADV] = 0xde1, + [PHY_LP_ABILITY] = 0x1e0, [PHY_1000T_STATUS] = 0x3c00, + [M88E1000_PHY_SPEC_STATUS] = 0xac00, +}; + +static const uint32_t mac_reg_init[] = { + [PBA] = 0x00100030, + [LEDCTL] = 0x602, + [CTRL] = E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 | + E1000_CTRL_SPD_1000 | E1000_CTRL_SLU, + [STATUS] = 0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE | + E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK | + E1000_STATUS_SPEED_1000 | E1000_STATUS_FD | + E1000_STATUS_LU, + [MANC] = E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN | + E1000_MANC_ARP_EN | E1000_MANC_0298_EN | + E1000_MANC_RMCP_EN, +}; + +/* PCI interface */ + +static CPUWriteMemoryFunc *e1000_mmio_write[] = { + e1000_mmio_writeb, e1000_mmio_writew, e1000_mmio_writel +}; + +static CPUReadMemoryFunc *e1000_mmio_read[] = { + e1000_mmio_readb, e1000_mmio_readw, e1000_mmio_readl +}; + +static void +e1000_mmio_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + E1000State *d = (E1000State *)pci_dev; + + DBGOUT(MMIO, "e1000_mmio_map addr=0x%08x 0x%08x\n", addr, size); + + d->mmio_base = addr; + cpu_register_physical_memory(addr, PNPMMIO_SIZE, d->mmio_index); +} + +void +pci_e1000_init(PCIBus *bus, NICInfo *nd, int devfn) +{ + E1000State *d; + uint8_t *pci_conf; + uint16_t checksum = 0; + static const char info_str[] = "e1000"; + int i; + + d = (E1000State *)pci_register_device(bus, "e1000", + sizeof(E1000State), devfn, NULL, NULL); + + pci_conf = d->dev.config; + memset(pci_conf, 0, 256); + + *(uint16_t *)(pci_conf+0x00) = cpu_to_le16(0x8086); + *(uint16_t *)(pci_conf+0x02) = cpu_to_le16(E1000_DEVID); + *(uint16_t *)(pci_conf+0x04) = cpu_to_le16(0x0407); + *(uint16_t *)(pci_conf+0x06) = cpu_to_le16(0x0010); + pci_conf[0x08] = 0x03; + pci_conf[0x0a] = 0x00; // ethernet network controller + pci_conf[0x0b] = 0x02; + pci_conf[0x0c] = 0x10; + + pci_conf[0x3d] = 1; // interrupt pin 0 + + d->mmio_index = cpu_register_io_memory(0, e1000_mmio_read, + e1000_mmio_write, d); + + pci_register_io_region((PCIDevice *)d, 0, PNPMMIO_SIZE, + PCI_ADDRESS_SPACE_MEM, e1000_mmio_map); + + pci_register_io_region((PCIDevice *)d, 1, IOPORT_SIZE, + PCI_ADDRESS_SPACE_IO, ioport_map); + + d->nd = nd; + memmove(d->eeprom_data, e1000_eeprom_template, + sizeof e1000_eeprom_template); + for (i = 0; i < 3; i++) + d->eeprom_data[i] = (nd->macaddr[2*i+1]<<8) | nd->macaddr[2*i]; + for (i = 0; i < EEPROM_CHECKSUM_REG; i++) + checksum += d->eeprom_data[i]; + checksum = (uint16_t) EEPROM_SUM - checksum; + d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum; + + memset(d->phy_reg, 0, sizeof d->phy_reg); + memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init); + memset(d->mac_reg, 0, sizeof d->mac_reg); + memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init); + d->rxbuf_min_shift = 1; + memset(&d->tx, 0, sizeof d->tx); + + d->vc = qemu_new_vlan_client(nd->vlan, e1000_receive, + e1000_can_receive, d); + + snprintf(d->vc->info_str, sizeof(d->vc->info_str), + "%s macaddr=%02x:%02x:%02x:%02x:%02x:%02x", info_str, + d->nd->macaddr[0], d->nd->macaddr[1], d->nd->macaddr[2], + d->nd->macaddr[3], d->nd->macaddr[4], d->nd->macaddr[5]); + + register_savevm(info_str, -1, 2, nic_save, nic_load, d); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/e1000_hw.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/e1000_hw.h --- qemu-0.9.1/hw/e1000_hw.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/e1000_hw.h 2008-04-11 05:55:07.000000000 +0100 @@ -0,0 +1,865 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2006 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* e1000_hw.h + * Structures, enums, and macros for the MAC + */ + +#ifndef _E1000_HW_H_ +#define _E1000_HW_H_ + + +/* PCI Device IDs */ +#define E1000_DEV_ID_82542 0x1000 +#define E1000_DEV_ID_82543GC_FIBER 0x1001 +#define E1000_DEV_ID_82543GC_COPPER 0x1004 +#define E1000_DEV_ID_82544EI_COPPER 0x1008 +#define E1000_DEV_ID_82544EI_FIBER 0x1009 +#define E1000_DEV_ID_82544GC_COPPER 0x100C +#define E1000_DEV_ID_82544GC_LOM 0x100D +#define E1000_DEV_ID_82540EM 0x100E +#define E1000_DEV_ID_82540EM_LOM 0x1015 +#define E1000_DEV_ID_82540EP_LOM 0x1016 +#define E1000_DEV_ID_82540EP 0x1017 +#define E1000_DEV_ID_82540EP_LP 0x101E +#define E1000_DEV_ID_82545EM_COPPER 0x100F +#define E1000_DEV_ID_82545EM_FIBER 0x1011 +#define E1000_DEV_ID_82545GM_COPPER 0x1026 +#define E1000_DEV_ID_82545GM_FIBER 0x1027 +#define E1000_DEV_ID_82545GM_SERDES 0x1028 +#define E1000_DEV_ID_82546EB_COPPER 0x1010 +#define E1000_DEV_ID_82546EB_FIBER 0x1012 +#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D +#define E1000_DEV_ID_82541EI 0x1013 +#define E1000_DEV_ID_82541EI_MOBILE 0x1018 +#define E1000_DEV_ID_82541ER_LOM 0x1014 +#define E1000_DEV_ID_82541ER 0x1078 +#define E1000_DEV_ID_82547GI 0x1075 +#define E1000_DEV_ID_82541GI 0x1076 +#define E1000_DEV_ID_82541GI_MOBILE 0x1077 +#define E1000_DEV_ID_82541GI_LF 0x107C +#define E1000_DEV_ID_82546GB_COPPER 0x1079 +#define E1000_DEV_ID_82546GB_FIBER 0x107A +#define E1000_DEV_ID_82546GB_SERDES 0x107B +#define E1000_DEV_ID_82546GB_PCIE 0x108A +#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099 +#define E1000_DEV_ID_82547EI 0x1019 +#define E1000_DEV_ID_82547EI_MOBILE 0x101A +#define E1000_DEV_ID_82571EB_COPPER 0x105E +#define E1000_DEV_ID_82571EB_FIBER 0x105F +#define E1000_DEV_ID_82571EB_SERDES 0x1060 +#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4 +#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5 +#define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5 +#define E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE 0x10BC +#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9 +#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA +#define E1000_DEV_ID_82572EI_COPPER 0x107D +#define E1000_DEV_ID_82572EI_FIBER 0x107E +#define E1000_DEV_ID_82572EI_SERDES 0x107F +#define E1000_DEV_ID_82572EI 0x10B9 +#define E1000_DEV_ID_82573E 0x108B +#define E1000_DEV_ID_82573E_IAMT 0x108C +#define E1000_DEV_ID_82573L 0x109A +#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5 +#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096 +#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098 +#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA +#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB + +#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049 +#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A +#define E1000_DEV_ID_ICH8_IGP_C 0x104B +#define E1000_DEV_ID_ICH8_IFE 0x104C +#define E1000_DEV_ID_ICH8_IFE_GT 0x10C4 +#define E1000_DEV_ID_ICH8_IFE_G 0x10C5 +#define E1000_DEV_ID_ICH8_IGP_M 0x104D + +/* Register Set. (82543, 82544) + * + * Registers are defined to be 32 bits and should be accessed as 32 bit values. + * These registers are physically located on the NIC, but are mapped into the + * host memory address space. + * + * RW - register is both readable and writable + * RO - register is read only + * WO - register is write only + * R/clr - register is read only and is cleared when read + * A - register array + */ +#define E1000_CTRL 0x00000 /* Device Control - RW */ +#define E1000_CTRL_DUP 0x00004 /* Device Control Duplicate (Shadow) - RW */ +#define E1000_STATUS 0x00008 /* Device Status - RO */ +#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ +#define E1000_EERD 0x00014 /* EEPROM Read - RW */ +#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ +#define E1000_FLA 0x0001C /* Flash Access - RW */ +#define E1000_MDIC 0x00020 /* MDI Control - RW */ +#define E1000_SCTL 0x00024 /* SerDes Control - RW */ +#define E1000_FEXTNVM 0x00028 /* Future Extended NVM register */ +#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ +#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ +#define E1000_FCT 0x00030 /* Flow Control Type - RW */ +#define E1000_VET 0x00038 /* VLAN Ether Type - RW */ +#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */ +#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */ +#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */ +#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */ +#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ +#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ +#define E1000_RCTL 0x00100 /* RX Control - RW */ +#define E1000_RDTR1 0x02820 /* RX Delay Timer (1) - RW */ +#define E1000_RDBAL1 0x02900 /* RX Descriptor Base Address Low (1) - RW */ +#define E1000_RDBAH1 0x02904 /* RX Descriptor Base Address High (1) - RW */ +#define E1000_RDLEN1 0x02908 /* RX Descriptor Length (1) - RW */ +#define E1000_RDH1 0x02910 /* RX Descriptor Head (1) - RW */ +#define E1000_RDT1 0x02918 /* RX Descriptor Tail (1) - RW */ +#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ +#define E1000_TXCW 0x00178 /* TX Configuration Word - RW */ +#define E1000_RXCW 0x00180 /* RX Configuration Word - RO */ +#define E1000_TCTL 0x00400 /* TX Control - RW */ +#define E1000_TCTL_EXT 0x00404 /* Extended TX Control - RW */ +#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */ +#define E1000_TBT 0x00448 /* TX Burst Timer - RW */ +#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */ +#define E1000_LEDCTL 0x00E00 /* LED Control - RW */ +#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */ +#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */ +#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */ +#define FEXTNVM_SW_CONFIG 0x0001 +#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */ +#define E1000_PBS 0x01008 /* Packet Buffer Size */ +#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */ +#define E1000_FLASH_UPDATES 1000 +#define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */ +#define E1000_FLASHT 0x01028 /* FLASH Timer Register */ +#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */ +#define E1000_FLSWCTL 0x01030 /* FLASH control register */ +#define E1000_FLSWDATA 0x01034 /* FLASH data register */ +#define E1000_FLSWCNT 0x01038 /* FLASH Access Counter */ +#define E1000_FLOP 0x0103C /* FLASH Opcode Register */ +#define E1000_ERT 0x02008 /* Early Rx Threshold - RW */ +#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */ +#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */ +#define E1000_PSRCTL 0x02170 /* Packet Split Receive Control - RW */ +#define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */ +#define E1000_RDBAH 0x02804 /* RX Descriptor Base Address High - RW */ +#define E1000_RDLEN 0x02808 /* RX Descriptor Length - RW */ +#define E1000_RDH 0x02810 /* RX Descriptor Head - RW */ +#define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */ +#define E1000_RDTR 0x02820 /* RX Delay Timer - RW */ +#define E1000_RDBAL0 E1000_RDBAL /* RX Desc Base Address Low (0) - RW */ +#define E1000_RDBAH0 E1000_RDBAH /* RX Desc Base Address High (0) - RW */ +#define E1000_RDLEN0 E1000_RDLEN /* RX Desc Length (0) - RW */ +#define E1000_RDH0 E1000_RDH /* RX Desc Head (0) - RW */ +#define E1000_RDT0 E1000_RDT /* RX Desc Tail (0) - RW */ +#define E1000_RDTR0 E1000_RDTR /* RX Delay Timer (0) - RW */ +#define E1000_RXDCTL 0x02828 /* RX Descriptor Control queue 0 - RW */ +#define E1000_RXDCTL1 0x02928 /* RX Descriptor Control queue 1 - RW */ +#define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */ +#define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */ +#define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */ +#define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */ +#define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */ +#define E1000_TDFH 0x03410 /* TX Data FIFO Head - RW */ +#define E1000_TDFT 0x03418 /* TX Data FIFO Tail - RW */ +#define E1000_TDFHS 0x03420 /* TX Data FIFO Head Saved - RW */ +#define E1000_TDFTS 0x03428 /* TX Data FIFO Tail Saved - RW */ +#define E1000_TDFPC 0x03430 /* TX Data FIFO Packet Count - RW */ +#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */ +#define E1000_TDBAH 0x03804 /* TX Descriptor Base Address High - RW */ +#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */ +#define E1000_TDH 0x03810 /* TX Descriptor Head - RW */ +#define E1000_TDT 0x03818 /* TX Descripotr Tail - RW */ +#define E1000_TIDV 0x03820 /* TX Interrupt Delay Value - RW */ +#define E1000_TXDCTL 0x03828 /* TX Descriptor Control - RW */ +#define E1000_TADV 0x0382C /* TX Interrupt Absolute Delay Val - RW */ +#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */ +#define E1000_TARC0 0x03840 /* TX Arbitration Count (0) */ +#define E1000_TDBAL1 0x03900 /* TX Desc Base Address Low (1) - RW */ +#define E1000_TDBAH1 0x03904 /* TX Desc Base Address High (1) - RW */ +#define E1000_TDLEN1 0x03908 /* TX Desc Length (1) - RW */ +#define E1000_TDH1 0x03910 /* TX Desc Head (1) - RW */ +#define E1000_TDT1 0x03918 /* TX Desc Tail (1) - RW */ +#define E1000_TXDCTL1 0x03928 /* TX Descriptor Control (1) - RW */ +#define E1000_TARC1 0x03940 /* TX Arbitration Count (1) */ +#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */ +#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ +#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ +#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */ +#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */ +#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */ +#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */ +#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */ +#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */ +#define E1000_COLC 0x04028 /* Collision Count - R/clr */ +#define E1000_DC 0x04030 /* Defer Count - R/clr */ +#define E1000_TNCRS 0x04034 /* TX-No CRS - R/clr */ +#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */ +#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */ +#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */ +#define E1000_XONRXC 0x04048 /* XON RX Count - R/clr */ +#define E1000_XONTXC 0x0404C /* XON TX Count - R/clr */ +#define E1000_XOFFRXC 0x04050 /* XOFF RX Count - R/clr */ +#define E1000_XOFFTXC 0x04054 /* XOFF TX Count - R/clr */ +#define E1000_FCRUC 0x04058 /* Flow Control RX Unsupported Count- R/clr */ +#define E1000_PRC64 0x0405C /* Packets RX (64 bytes) - R/clr */ +#define E1000_PRC127 0x04060 /* Packets RX (65-127 bytes) - R/clr */ +#define E1000_PRC255 0x04064 /* Packets RX (128-255 bytes) - R/clr */ +#define E1000_PRC511 0x04068 /* Packets RX (255-511 bytes) - R/clr */ +#define E1000_PRC1023 0x0406C /* Packets RX (512-1023 bytes) - R/clr */ +#define E1000_PRC1522 0x04070 /* Packets RX (1024-1522 bytes) - R/clr */ +#define E1000_GPRC 0x04074 /* Good Packets RX Count - R/clr */ +#define E1000_BPRC 0x04078 /* Broadcast Packets RX Count - R/clr */ +#define E1000_MPRC 0x0407C /* Multicast Packets RX Count - R/clr */ +#define E1000_GPTC 0x04080 /* Good Packets TX Count - R/clr */ +#define E1000_GORCL 0x04088 /* Good Octets RX Count Low - R/clr */ +#define E1000_GORCH 0x0408C /* Good Octets RX Count High - R/clr */ +#define E1000_GOTCL 0x04090 /* Good Octets TX Count Low - R/clr */ +#define E1000_GOTCH 0x04094 /* Good Octets TX Count High - R/clr */ +#define E1000_RNBC 0x040A0 /* RX No Buffers Count - R/clr */ +#define E1000_RUC 0x040A4 /* RX Undersize Count - R/clr */ +#define E1000_RFC 0x040A8 /* RX Fragment Count - R/clr */ +#define E1000_ROC 0x040AC /* RX Oversize Count - R/clr */ +#define E1000_RJC 0x040B0 /* RX Jabber Count - R/clr */ +#define E1000_MGTPRC 0x040B4 /* Management Packets RX Count - R/clr */ +#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */ +#define E1000_MGTPTC 0x040BC /* Management Packets TX Count - R/clr */ +#define E1000_TORL 0x040C0 /* Total Octets RX Low - R/clr */ +#define E1000_TORH 0x040C4 /* Total Octets RX High - R/clr */ +#define E1000_TOTL 0x040C8 /* Total Octets TX Low - R/clr */ +#define E1000_TOTH 0x040CC /* Total Octets TX High - R/clr */ +#define E1000_TPR 0x040D0 /* Total Packets RX - R/clr */ +#define E1000_TPT 0x040D4 /* Total Packets TX - R/clr */ +#define E1000_PTC64 0x040D8 /* Packets TX (64 bytes) - R/clr */ +#define E1000_PTC127 0x040DC /* Packets TX (65-127 bytes) - R/clr */ +#define E1000_PTC255 0x040E0 /* Packets TX (128-255 bytes) - R/clr */ +#define E1000_PTC511 0x040E4 /* Packets TX (256-511 bytes) - R/clr */ +#define E1000_PTC1023 0x040E8 /* Packets TX (512-1023 bytes) - R/clr */ +#define E1000_PTC1522 0x040EC /* Packets TX (1024-1522 Bytes) - R/clr */ +#define E1000_MPTC 0x040F0 /* Multicast Packets TX Count - R/clr */ +#define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */ +#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */ +#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */ +#define E1000_IAC 0x04100 /* Interrupt Assertion Count */ +#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Packet Timer Expire Count */ +#define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Absolute Timer Expire Count */ +#define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Packet Timer Expire Count */ +#define E1000_ICTXATC 0x04110 /* Interrupt Cause Tx Absolute Timer Expire Count */ +#define E1000_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */ +#define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Minimum Threshold Count */ +#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */ +#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */ +#define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */ +#define E1000_RFCTL 0x05008 /* Receive Filter Control*/ +#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ +#define E1000_RA 0x05400 /* Receive Address - RW Array */ +#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */ +#define E1000_WUC 0x05800 /* Wakeup Control - RW */ +#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */ +#define E1000_WUS 0x05810 /* Wakeup Status - RO */ +#define E1000_MANC 0x05820 /* Management Control - RW */ +#define E1000_IPAV 0x05838 /* IP Address Valid - RW */ +#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */ +#define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */ +#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */ +#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */ +#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */ +#define E1000_HOST_IF 0x08800 /* Host Interface */ +#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */ +#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */ + +#define E1000_KUMCTRLSTA 0x00034 /* MAC-PHY interface - RW */ +#define E1000_MDPHYA 0x0003C /* PHY address - RW */ +#define E1000_MANC2H 0x05860 /* Managment Control To Host - RW */ +#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */ + +#define E1000_GCR 0x05B00 /* PCI-Ex Control */ +#define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */ +#define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */ +#define E1000_GSCL_3 0x05B18 /* PCI-Ex Statistic Control #3 */ +#define E1000_GSCL_4 0x05B1C /* PCI-Ex Statistic Control #4 */ +#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */ +#define E1000_SWSM 0x05B50 /* SW Semaphore */ +#define E1000_FWSM 0x05B54 /* FW Semaphore */ +#define E1000_FFLT_DBG 0x05F04 /* Debug Register */ +#define E1000_HICR 0x08F00 /* Host Inteface Control */ + +/* RSS registers */ +#define E1000_CPUVEC 0x02C10 /* CPU Vector Register - RW */ +#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */ +#define E1000_RETA 0x05C00 /* Redirection Table - RW Array */ +#define E1000_RSSRK 0x05C80 /* RSS Random Key - RW Array */ +#define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */ +#define E1000_RSSIR 0x05868 /* RSS Interrupt Request */ + +/* PHY 1000 MII Register/Bit Definitions */ +/* PHY Registers defined by IEEE */ +#define PHY_CTRL 0x00 /* Control Register */ +#define PHY_STATUS 0x01 /* Status Regiser */ +#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ +#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ +#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ +#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ +#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */ +#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */ +#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */ +#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ +#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ +#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */ + +#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ +#define MAX_PHY_MULTI_PAGE_REG 0xF /* Registers equal on all pages */ + +/* M88E1000 Specific Registers */ +#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ +#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */ +#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */ +#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */ +#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ +#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */ + +#define M88E1000_PHY_EXT_CTRL 0x1A /* PHY extend control register */ +#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */ +#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */ +#define M88E1000_PHY_VCO_REG_BIT8 0x100 /* Bits 8 & 11 are adjusted for */ +#define M88E1000_PHY_VCO_REG_BIT11 0x800 /* improved BER performance */ + +/* Interrupt Cause Read */ +#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ +#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */ +#define E1000_ICR_LSC 0x00000004 /* Link Status Change */ +#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */ +#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ +#define E1000_ICR_RXO 0x00000040 /* rx overrun */ +#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ +#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */ +#define E1000_ICR_RXCFG 0x00000400 /* RX /c/ ordered set */ +#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */ +#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */ +#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */ +#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */ +#define E1000_ICR_TXD_LOW 0x00008000 +#define E1000_ICR_SRPD 0x00010000 +#define E1000_ICR_ACK 0x00020000 /* Receive Ack frame */ +#define E1000_ICR_MNG 0x00040000 /* Manageability event */ +#define E1000_ICR_DOCK 0x00080000 /* Dock/Undock */ +#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */ +#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* queue 0 Rx descriptor FIFO parity error */ +#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* queue 0 Tx descriptor FIFO parity error */ +#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity error */ +#define E1000_ICR_PB_PAR 0x00800000 /* packet buffer parity error */ +#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */ +#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */ +#define E1000_ICR_ALL_PARITY 0x03F00000 /* all parity error bits */ +#define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW bit in the FWSM */ +#define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates an interrupt */ +#define E1000_ICR_EPRST 0x00100000 /* ME handware reset occurs */ + +/* Interrupt Cause Set */ +#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ +#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW +#define E1000_ICS_SRPD E1000_ICR_SRPD +#define E1000_ICS_ACK E1000_ICR_ACK /* Receive Ack frame */ +#define E1000_ICS_MNG E1000_ICR_MNG /* Manageability event */ +#define E1000_ICS_DOCK E1000_ICR_DOCK /* Dock/Undock */ +#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */ +#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */ +#define E1000_ICS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */ +#define E1000_ICS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ +#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ +#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ +#define E1000_ICS_DSW E1000_ICR_DSW +#define E1000_ICS_PHYINT E1000_ICR_PHYINT +#define E1000_ICS_EPRST E1000_ICR_EPRST + +/* Interrupt Mask Set */ +#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ +#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW +#define E1000_IMS_SRPD E1000_ICR_SRPD +#define E1000_IMS_ACK E1000_ICR_ACK /* Receive Ack frame */ +#define E1000_IMS_MNG E1000_ICR_MNG /* Manageability event */ +#define E1000_IMS_DOCK E1000_ICR_DOCK /* Dock/Undock */ +#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */ +#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */ +#define E1000_IMS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */ +#define E1000_IMS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ +#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ +#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ +#define E1000_IMS_DSW E1000_ICR_DSW +#define E1000_IMS_PHYINT E1000_ICR_PHYINT +#define E1000_IMS_EPRST E1000_ICR_EPRST + +/* Interrupt Mask Clear */ +#define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_IMC_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_IMC_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_IMC_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_IMC_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_IMC_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_IMC_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_IMC_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_IMC_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ +#define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW +#define E1000_IMC_SRPD E1000_ICR_SRPD +#define E1000_IMC_ACK E1000_ICR_ACK /* Receive Ack frame */ +#define E1000_IMC_MNG E1000_ICR_MNG /* Manageability event */ +#define E1000_IMC_DOCK E1000_ICR_DOCK /* Dock/Undock */ +#define E1000_IMC_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */ +#define E1000_IMC_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */ +#define E1000_IMC_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */ +#define E1000_IMC_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ +#define E1000_IMC_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ +#define E1000_IMC_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ +#define E1000_IMC_DSW E1000_ICR_DSW +#define E1000_IMC_PHYINT E1000_ICR_PHYINT +#define E1000_IMC_EPRST E1000_ICR_EPRST + +/* Receive Control */ +#define E1000_RCTL_RST 0x00000001 /* Software reset */ +#define E1000_RCTL_EN 0x00000002 /* enable */ +#define E1000_RCTL_SBP 0x00000004 /* store bad packet */ +#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */ +#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */ +#define E1000_RCTL_LPE 0x00000020 /* long packet enable */ +#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ +#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ +#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */ +#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ +#define E1000_RCTL_DTYP_MASK 0x00000C00 /* Descriptor type mask */ +#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */ +#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ +#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min threshold size */ +#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min threshold size */ +#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ +#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */ +#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */ +#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */ +#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ +#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */ +#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ +#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ +#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ +#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ +#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ +#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ +#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ +#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ +#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ +#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ +#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ +#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ +#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ +#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ +#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ +#define E1000_RCTL_FLXBUF_MASK 0x78000000 /* Flexible buffer size */ +#define E1000_RCTL_FLXBUF_SHIFT 27 /* Flexible buffer shift */ + + +#define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */ +#define E1000_EEPROM_LED_LOGIC 0x0020 /* Led Logic Word */ +#define E1000_EEPROM_RW_REG_DATA 16 /* Offset to data in EEPROM read/write registers */ +#define E1000_EEPROM_RW_REG_DONE 0x10 /* Offset to READ/WRITE done bit */ +#define E1000_EEPROM_RW_REG_START 1 /* First bit for telling part to start operation */ +#define E1000_EEPROM_RW_ADDR_SHIFT 8 /* Shift to the address bits */ +#define E1000_EEPROM_POLL_WRITE 1 /* Flag for polling for write complete */ +#define E1000_EEPROM_POLL_READ 0 /* Flag for polling for read complete */ +/* Register Bit Masks */ +/* Device Control */ +#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ +#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */ +#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */ +#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */ +#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */ +#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */ +#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */ +#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */ +#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ +#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */ +#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */ +#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */ +#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */ +#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */ +#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */ +#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ +#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ +#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */ +#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */ +#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through PHYRST_N pin */ +#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */ +#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ +#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ +#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ +#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */ +#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */ +#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */ +#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */ +#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */ +#define E1000_CTRL_RST 0x04000000 /* Global reset */ +#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ +#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ +#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */ +#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ +#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ +#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to manageability engine */ + +/* Device Status */ +#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ +#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ +#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */ +#define E1000_STATUS_FUNC_SHIFT 2 +#define E1000_STATUS_FUNC_0 0x00000000 /* Function 0 */ +#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */ +#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */ +#define E1000_STATUS_TBIMODE 0x00000020 /* TBI mode */ +#define E1000_STATUS_SPEED_MASK 0x000000C0 +#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */ +#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ +#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ +#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion + by EEPROM/Flash */ +#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */ +#define E1000_STATUS_DOCK_CI 0x00000800 /* Change in Dock/Undock state. Clear on write '0'. */ +#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */ +#define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */ +#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */ +#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */ +#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */ +#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */ +#define E1000_STATUS_BMC_SKU_0 0x00100000 /* BMC USB redirect disabled */ +#define E1000_STATUS_BMC_SKU_1 0x00200000 /* BMC SRAM disabled */ +#define E1000_STATUS_BMC_SKU_2 0x00400000 /* BMC SDRAM disabled */ +#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */ +#define E1000_STATUS_BMC_LITE 0x01000000 /* BMC external code execution disabled */ +#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */ +#define E1000_STATUS_FUSE_8 0x04000000 +#define E1000_STATUS_FUSE_9 0x08000000 +#define E1000_STATUS_SERDES0_DIS 0x10000000 /* SERDES disabled on port 0 */ +#define E1000_STATUS_SERDES1_DIS 0x20000000 /* SERDES disabled on port 1 */ + +/* EEPROM/Flash Control */ +#define E1000_EECD_SK 0x00000001 /* EEPROM Clock */ +#define E1000_EECD_CS 0x00000002 /* EEPROM Chip Select */ +#define E1000_EECD_DI 0x00000004 /* EEPROM Data In */ +#define E1000_EECD_DO 0x00000008 /* EEPROM Data Out */ +#define E1000_EECD_FWE_MASK 0x00000030 +#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */ +#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */ +#define E1000_EECD_FWE_SHIFT 4 +#define E1000_EECD_REQ 0x00000040 /* EEPROM Access Request */ +#define E1000_EECD_GNT 0x00000080 /* EEPROM Access Grant */ +#define E1000_EECD_PRES 0x00000100 /* EEPROM Present */ +#define E1000_EECD_SIZE 0x00000200 /* EEPROM Size (0=64 word 1=256 word) */ +#define E1000_EECD_ADDR_BITS 0x00000400 /* EEPROM Addressing bits based on type + * (0-small, 1-large) */ +#define E1000_EECD_TYPE 0x00002000 /* EEPROM Type (1-SPI, 0-Microwire) */ +#ifndef E1000_EEPROM_GRANT_ATTEMPTS +#define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */ +#endif +#define E1000_EECD_AUTO_RD 0x00000200 /* EEPROM Auto Read done */ +#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* EEprom Size */ +#define E1000_EECD_SIZE_EX_SHIFT 11 +#define E1000_EECD_NVADDS 0x00018000 /* NVM Address Size */ +#define E1000_EECD_SELSHAD 0x00020000 /* Select Shadow RAM */ +#define E1000_EECD_INITSRAM 0x00040000 /* Initialize Shadow RAM */ +#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */ +#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */ +#define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */ +#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */ +#define E1000_EECD_SECVAL_SHIFT 22 +#define E1000_STM_OPCODE 0xDB00 +#define E1000_HICR_FW_RESET 0xC0 + +#define E1000_SHADOW_RAM_WORDS 2048 +#define E1000_ICH_NVM_SIG_WORD 0x13 +#define E1000_ICH_NVM_SIG_MASK 0xC0 + +/* MDI Control */ +#define E1000_MDIC_DATA_MASK 0x0000FFFF +#define E1000_MDIC_REG_MASK 0x001F0000 +#define E1000_MDIC_REG_SHIFT 16 +#define E1000_MDIC_PHY_MASK 0x03E00000 +#define E1000_MDIC_PHY_SHIFT 21 +#define E1000_MDIC_OP_WRITE 0x04000000 +#define E1000_MDIC_OP_READ 0x08000000 +#define E1000_MDIC_READY 0x10000000 +#define E1000_MDIC_INT_EN 0x20000000 +#define E1000_MDIC_ERROR 0x40000000 + +/* EEPROM Commands - Microwire */ +#define EEPROM_READ_OPCODE_MICROWIRE 0x6 /* EEPROM read opcode */ +#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5 /* EEPROM write opcode */ +#define EEPROM_ERASE_OPCODE_MICROWIRE 0x7 /* EEPROM erase opcode */ +#define EEPROM_EWEN_OPCODE_MICROWIRE 0x13 /* EEPROM erase/write enable */ +#define EEPROM_EWDS_OPCODE_MICROWIRE 0x10 /* EEPROM erast/write disable */ + +/* EEPROM Word Offsets */ +#define EEPROM_COMPAT 0x0003 +#define EEPROM_ID_LED_SETTINGS 0x0004 +#define EEPROM_VERSION 0x0005 +#define EEPROM_SERDES_AMPLITUDE 0x0006 /* For SERDES output amplitude adjustment. */ +#define EEPROM_PHY_CLASS_WORD 0x0007 +#define EEPROM_INIT_CONTROL1_REG 0x000A +#define EEPROM_INIT_CONTROL2_REG 0x000F +#define EEPROM_SWDEF_PINS_CTRL_PORT_1 0x0010 +#define EEPROM_INIT_CONTROL3_PORT_B 0x0014 +#define EEPROM_INIT_3GIO_3 0x001A +#define EEPROM_SWDEF_PINS_CTRL_PORT_0 0x0020 +#define EEPROM_INIT_CONTROL3_PORT_A 0x0024 +#define EEPROM_CFG 0x0012 +#define EEPROM_FLASH_VERSION 0x0032 +#define EEPROM_CHECKSUM_REG 0x003F + +#define E1000_EEPROM_CFG_DONE 0x00040000 /* MNG config cycle done */ +#define E1000_EEPROM_CFG_DONE_PORT_1 0x00080000 /* ...for second port */ + +/* Transmit Descriptor */ +struct e1000_tx_desc { + uint64_t buffer_addr; /* Address of the descriptor's data buffer */ + union { + uint32_t data; + struct { + uint16_t length; /* Data buffer length */ + uint8_t cso; /* Checksum offset */ + uint8_t cmd; /* Descriptor control */ + } flags; + } lower; + union { + uint32_t data; + struct { + uint8_t status; /* Descriptor status */ + uint8_t css; /* Checksum start */ + uint16_t special; + } fields; + } upper; +}; + +/* Transmit Descriptor bit definitions */ +#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */ +#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */ +#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ +#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ +#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */ +#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */ +#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ +#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ +#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ +#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ +#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ +#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ +#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */ +#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */ +#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */ +#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */ +#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ +#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ +#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ + +/* Transmit Control */ +#define E1000_TCTL_RST 0x00000001 /* software reset */ +#define E1000_TCTL_EN 0x00000002 /* enable tx */ +#define E1000_TCTL_BCE 0x00000004 /* busy check enable */ +#define E1000_TCTL_PSP 0x00000008 /* pad short packets */ +#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */ +#define E1000_TCTL_COLD 0x003ff000 /* collision distance */ +#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */ +#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */ +#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ +#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */ +#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */ + +/* Receive Descriptor */ +struct e1000_rx_desc { + uint64_t buffer_addr; /* Address of the descriptor's data buffer */ + uint16_t length; /* Length of data DMAed into data buffer */ + uint16_t csum; /* Packet checksum */ + uint8_t status; /* Descriptor status */ + uint8_t errors; /* Descriptor Errors */ + uint16_t special; +}; + +/* Receive Descriptor bit definitions */ +#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ +#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */ +#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */ +#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ +#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */ +#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ +#define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ +#define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */ +#define E1000_RXD_STAT_IPIDV 0x200 /* IP identification valid */ +#define E1000_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */ +#define E1000_RXD_STAT_ACK 0x8000 /* ACK Packet indication */ +#define E1000_RXD_ERR_CE 0x01 /* CRC Error */ +#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */ +#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */ +#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */ +#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */ +#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */ +#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */ +#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ +#define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */ +#define E1000_RXD_SPC_PRI_SHIFT 13 +#define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */ +#define E1000_RXD_SPC_CFI_SHIFT 12 + +#define E1000_RXDEXT_STATERR_CE 0x01000000 +#define E1000_RXDEXT_STATERR_SE 0x02000000 +#define E1000_RXDEXT_STATERR_SEQ 0x04000000 +#define E1000_RXDEXT_STATERR_CXE 0x10000000 +#define E1000_RXDEXT_STATERR_TCPE 0x20000000 +#define E1000_RXDEXT_STATERR_IPE 0x40000000 +#define E1000_RXDEXT_STATERR_RXE 0x80000000 + +#define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000 +#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF + +/* Receive Address */ +#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */ + +/* Offload Context Descriptor */ +struct e1000_context_desc { + union { + uint32_t ip_config; + struct { + uint8_t ipcss; /* IP checksum start */ + uint8_t ipcso; /* IP checksum offset */ + uint16_t ipcse; /* IP checksum end */ + } ip_fields; + } lower_setup; + union { + uint32_t tcp_config; + struct { + uint8_t tucss; /* TCP checksum start */ + uint8_t tucso; /* TCP checksum offset */ + uint16_t tucse; /* TCP checksum end */ + } tcp_fields; + } upper_setup; + uint32_t cmd_and_length; /* */ + union { + uint32_t data; + struct { + uint8_t status; /* Descriptor status */ + uint8_t hdr_len; /* Header length */ + uint16_t mss; /* Maximum segment size */ + } fields; + } tcp_seg_setup; +}; + +/* Offload data descriptor */ +struct e1000_data_desc { + uint64_t buffer_addr; /* Address of the descriptor's buffer address */ + union { + uint32_t data; + struct { + uint16_t length; /* Data buffer length */ + uint8_t typ_len_ext; /* */ + uint8_t cmd; /* */ + } flags; + } lower; + union { + uint32_t data; + struct { + uint8_t status; /* Descriptor status */ + uint8_t popts; /* Packet Options */ + uint16_t special; /* */ + } fields; + } upper; +}; + +/* Management Control */ +#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */ +#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */ +#define E1000_MANC_R_ON_FORCE 0x00000004 /* Reset on Force TCO - RO */ +#define E1000_MANC_RMCP_EN 0x00000100 /* Enable RCMP 026Fh Filtering */ +#define E1000_MANC_0298_EN 0x00000200 /* Enable RCMP 0298h Filtering */ +#define E1000_MANC_IPV4_EN 0x00000400 /* Enable IPv4 */ +#define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */ +#define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */ +#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */ +#define E1000_MANC_NEIGHBOR_EN 0x00004000 /* Enable Neighbor Discovery + * Filtering */ +#define E1000_MANC_ARP_RES_EN 0x00008000 /* Enable ARP response Filtering */ +#define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */ +#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ +#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */ +#define E1000_MANC_RCV_ALL 0x00080000 /* Receive All Enabled */ +#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */ +#define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000 /* Enable MAC address + * filtering */ +#define E1000_MANC_EN_MNG2HOST 0x00200000 /* Enable MNG packets to host + * memory */ +#define E1000_MANC_EN_IP_ADDR_FILTER 0x00400000 /* Enable IP address + * filtering */ +#define E1000_MANC_EN_XSUM_FILTER 0x00800000 /* Enable checksum filtering */ +#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */ +#define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */ +#define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */ +#define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */ +#define E1000_MANC_SMB_DATA_IN 0x08000000 /* SMBus Data In */ +#define E1000_MANC_SMB_DATA_OUT 0x10000000 /* SMBus Data Out */ +#define E1000_MANC_SMB_CLK_OUT 0x20000000 /* SMBus Clock Out */ + +#define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */ +#define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */ + +/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */ +#define EEPROM_SUM 0xBABA + +#endif /* _E1000_HW_H_ */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/eccmemctl.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/eccmemctl.c --- qemu-0.9.1/hw/eccmemctl.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/eccmemctl.c 2008-06-19 18:38:15.000000000 +0100 @@ -40,96 +40,124 @@ * SMC (version 0, implementation 2) SS-10SX and SS-20 */ -/* Register offsets */ -#define ECC_FCR_REG 0 -#define ECC_FSR_REG 8 -#define ECC_FAR0_REG 16 -#define ECC_FAR1_REG 20 -#define ECC_DIAG_REG 24 +/* Register indexes */ +#define ECC_MER 0 /* Memory Enable Register */ +#define ECC_MDR 1 /* Memory Delay Register */ +#define ECC_MFSR 2 /* Memory Fault Status Register */ +#define ECC_VCR 3 /* Video Configuration Register */ +#define ECC_MFAR0 4 /* Memory Fault Address Register 0 */ +#define ECC_MFAR1 5 /* Memory Fault Address Register 1 */ +#define ECC_DR 6 /* Diagnostic Register */ +#define ECC_ECR0 7 /* Event Count Register 0 */ +#define ECC_ECR1 8 /* Event Count Register 1 */ /* ECC fault control register */ -#define ECC_FCR_EE 0x00000001 /* Enable ECC checking */ -#define ECC_FCR_EI 0x00000010 /* Enable Interrupts on correctable errors */ -#define ECC_FCR_VER 0x0f000000 /* Version */ -#define ECC_FCR_IMPL 0xf0000000 /* Implementation */ +#define ECC_MER_EE 0x00000001 /* Enable ECC checking */ +#define ECC_MER_EI 0x00000002 /* Enable Interrupts on + correctable errors */ +#define ECC_MER_MRR0 0x00000004 /* SIMM 0 */ +#define ECC_MER_MRR1 0x00000008 /* SIMM 1 */ +#define ECC_MER_MRR2 0x00000010 /* SIMM 2 */ +#define ECC_MER_MRR3 0x00000020 /* SIMM 3 */ +#define ECC_MER_MRR4 0x00000040 /* SIMM 4 */ +#define ECC_MER_MRR5 0x00000080 /* SIMM 5 */ +#define ECC_MER_MRR6 0x00000100 /* SIMM 6 */ +#define ECC_MER_MRR7 0x00000200 /* SIMM 7 */ +#define ECC_MER_REU 0x00000200 /* Memory Refresh Enable (600MP) */ +#define ECC_MER_MRR 0x000003fc /* MRR mask */ +#define ECC_MEM_A 0x00000400 /* Memory controller addr map select */ +#define ECC_MER_DCI 0x00000800 /* Disables Coherent Invalidate ACK */ +#define ECC_MER_VER 0x0f000000 /* Version */ +#define ECC_MER_IMPL 0xf0000000 /* Implementation */ + +/* ECC memory delay register */ +#define ECC_MDR_RRI 0x000003ff /* Refresh Request Interval */ +#define ECC_MDR_MI 0x00001c00 /* MIH Delay */ +#define ECC_MDR_CI 0x0000e000 /* Coherent Invalidate Delay */ +#define ECC_MDR_MDL 0x001f0000 /* MBus Master arbitration delay */ +#define ECC_MDR_MDH 0x03e00000 /* MBus Master arbitration delay */ +#define ECC_MDR_GAD 0x7c000000 /* Graphics Arbitration Delay */ +#define ECC_MDR_RSC 0x80000000 /* Refresh load control */ +#define ECC_MDR_MASK 0x7fffffff /* ECC fault status register */ -#define ECC_FSR_CE 0x00000001 /* Correctable error */ -#define ECC_FSR_BS 0x00000002 /* C2 graphics bad slot access */ -#define ECC_FSR_TO 0x00000004 /* Timeout on write */ -#define ECC_FSR_UE 0x00000008 /* Uncorrectable error */ -#define ECC_FSR_DW 0x000000f0 /* Index of double word in block */ -#define ECC_FSR_SYND 0x0000ff00 /* Syndrome for correctable error */ -#define ECC_FSR_ME 0x00010000 /* Multiple errors */ -#define ECC_FSR_C2ERR 0x00020000 /* C2 graphics error */ +#define ECC_MFSR_CE 0x00000001 /* Correctable error */ +#define ECC_MFSR_BS 0x00000002 /* C2 graphics bad slot access */ +#define ECC_MFSR_TO 0x00000004 /* Timeout on write */ +#define ECC_MFSR_UE 0x00000008 /* Uncorrectable error */ +#define ECC_MFSR_DW 0x000000f0 /* Index of double word in block */ +#define ECC_MFSR_SYND 0x0000ff00 /* Syndrome for correctable error */ +#define ECC_MFSR_ME 0x00010000 /* Multiple errors */ +#define ECC_MFSR_C2ERR 0x00020000 /* C2 graphics error */ /* ECC fault address register 0 */ -#define ECC_FAR0_PADDR 0x0000000f /* PA[32-35] */ -#define ECC_FAR0_TYPE 0x000000f0 /* Transaction type */ -#define ECC_FAR0_SIZE 0x00000700 /* Transaction size */ -#define ECC_FAR0_CACHE 0x00000800 /* Mapped cacheable */ -#define ECC_FAR0_LOCK 0x00001000 /* Error occurred in attomic cycle */ -#define ECC_FAR0_BMODE 0x00002000 /* Boot mode */ -#define ECC_FAR0_VADDR 0x003fc000 /* VA[12-19] (superset bits) */ -#define ECC_FAR0_S 0x08000000 /* Supervisor mode */ -#define ECC_FARO_MID 0xf0000000 /* Module ID */ +#define ECC_MFAR0_PADDR 0x0000000f /* PA[32-35] */ +#define ECC_MFAR0_TYPE 0x000000f0 /* Transaction type */ +#define ECC_MFAR0_SIZE 0x00000700 /* Transaction size */ +#define ECC_MFAR0_CACHE 0x00000800 /* Mapped cacheable */ +#define ECC_MFAR0_LOCK 0x00001000 /* Error occurred in atomic cycle */ +#define ECC_MFAR0_BMODE 0x00002000 /* Boot mode */ +#define ECC_MFAR0_VADDR 0x003fc000 /* VA[12-19] (superset bits) */ +#define ECC_MFAR0_S 0x08000000 /* Supervisor mode */ +#define ECC_MFARO_MID 0xf0000000 /* Module ID */ /* ECC diagnostic register */ -#define ECC_DIAG_CBX 0x00000001 -#define ECC_DIAG_CB0 0x00000002 -#define ECC_DIAG_CB1 0x00000004 -#define ECC_DIAG_CB2 0x00000008 -#define ECC_DIAG_CB4 0x00000010 -#define ECC_DIAG_CB8 0x00000020 -#define ECC_DIAG_CB16 0x00000040 -#define ECC_DIAG_CB32 0x00000080 -#define ECC_DIAG_DMODE 0x00000c00 +#define ECC_DR_CBX 0x00000001 +#define ECC_DR_CB0 0x00000002 +#define ECC_DR_CB1 0x00000004 +#define ECC_DR_CB2 0x00000008 +#define ECC_DR_CB4 0x00000010 +#define ECC_DR_CB8 0x00000020 +#define ECC_DR_CB16 0x00000040 +#define ECC_DR_CB32 0x00000080 +#define ECC_DR_DMODE 0x00000c00 -#define ECC_NREGS 8 +#define ECC_NREGS 9 #define ECC_SIZE (ECC_NREGS * sizeof(uint32_t)) -#define ECC_ADDR_MASK (ECC_SIZE - 1) +#define ECC_ADDR_MASK 0x1f + +#define ECC_DIAG_SIZE 4 +#define ECC_DIAG_MASK (ECC_DIAG_SIZE - 1) typedef struct ECCState { + qemu_irq irq; uint32_t regs[ECC_NREGS]; + uint8_t diag[ECC_DIAG_SIZE]; } ECCState; static void ecc_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { ECCState *s = opaque; - switch (addr & ECC_ADDR_MASK) { - case ECC_FCR_REG: - s->regs[0] = (s->regs[0] & (ECC_FCR_VER | ECC_FCR_IMPL)) | - (val & ~(ECC_FCR_VER | ECC_FCR_IMPL)); - DPRINTF("Write fault control %08x\n", val); - break; - case 4: - s->regs[1] = val; - DPRINTF("Write reg[1] %08x\n", val); - break; - case ECC_FSR_REG: - s->regs[2] = val; - DPRINTF("Write fault status %08x\n", val); - break; - case 12: - s->regs[3] = val; - DPRINTF("Write reg[3] %08x\n", val); - break; - case ECC_FAR0_REG: - s->regs[4] = val; - DPRINTF("Write fault address 0 %08x\n", val); - break; - case ECC_FAR1_REG: - s->regs[5] = val; - DPRINTF("Write fault address 1 %08x\n", val); - break; - case ECC_DIAG_REG: - s->regs[6] = val; - DPRINTF("Write diag %08x\n", val); - break; - case 28: - s->regs[7] = val; - DPRINTF("Write reg[7] %08x\n", val); + switch ((addr & ECC_ADDR_MASK) >> 2) { + case ECC_MER: + s->regs[ECC_MER] = (s->regs[ECC_MER] & (ECC_MER_VER | ECC_MER_IMPL)) | + (val & ~(ECC_MER_VER | ECC_MER_IMPL)); + DPRINTF("Write memory enable %08x\n", val); + break; + case ECC_MDR: + s->regs[ECC_MDR] = val & ECC_MDR_MASK; + DPRINTF("Write memory delay %08x\n", val); + break; + case ECC_MFSR: + s->regs[ECC_MFSR] = val; + DPRINTF("Write memory fault status %08x\n", val); + break; + case ECC_VCR: + s->regs[ECC_VCR] = val; + DPRINTF("Write slot configuration %08x\n", val); + break; + case ECC_DR: + s->regs[ECC_DR] = val; + DPRINTF("Write diagnosiic %08x\n", val); + break; + case ECC_ECR0: + s->regs[ECC_ECR0] = val; + DPRINTF("Write event count 1 %08x\n", val); + break; + case ECC_ECR1: + s->regs[ECC_ECR0] = val; + DPRINTF("Write event count 2 %08x\n", val); break; } } @@ -139,38 +167,42 @@ ECCState *s = opaque; uint32_t ret = 0; - switch (addr & ECC_ADDR_MASK) { - case ECC_FCR_REG: - ret = s->regs[0]; - DPRINTF("Read enable %08x\n", ret); - break; - case 4: - ret = s->regs[1]; - DPRINTF("Read register[1] %08x\n", ret); - break; - case ECC_FSR_REG: - ret = s->regs[2]; - DPRINTF("Read fault status %08x\n", ret); - break; - case 12: - ret = s->regs[3]; - DPRINTF("Read reg[3] %08x\n", ret); - break; - case ECC_FAR0_REG: - ret = s->regs[4]; - DPRINTF("Read fault address 0 %08x\n", ret); - break; - case ECC_FAR1_REG: - ret = s->regs[5]; - DPRINTF("Read fault address 1 %08x\n", ret); - break; - case ECC_DIAG_REG: - ret = s->regs[6]; - DPRINTF("Read diag %08x\n", ret); - break; - case 28: - ret = s->regs[7]; - DPRINTF("Read reg[7] %08x\n", ret); + switch ((addr & ECC_ADDR_MASK) >> 2) { + case ECC_MER: + ret = s->regs[ECC_MER]; + DPRINTF("Read memory enable %08x\n", ret); + break; + case ECC_MDR: + ret = s->regs[ECC_MDR]; + DPRINTF("Read memory delay %08x\n", ret); + break; + case ECC_MFSR: + ret = s->regs[ECC_MFSR]; + DPRINTF("Read memory fault status %08x\n", ret); + break; + case ECC_VCR: + ret = s->regs[ECC_VCR]; + DPRINTF("Read slot configuration %08x\n", ret); + break; + case ECC_MFAR0: + ret = s->regs[ECC_MFAR0]; + DPRINTF("Read memory fault address 0 %08x\n", ret); + break; + case ECC_MFAR1: + ret = s->regs[ECC_MFAR1]; + DPRINTF("Read memory fault address 1 %08x\n", ret); + break; + case ECC_DR: + ret = s->regs[ECC_DR]; + DPRINTF("Read diagnostic %08x\n", ret); + break; + case ECC_ECR0: + ret = s->regs[ECC_ECR0]; + DPRINTF("Read event count 1 %08x\n", ret); + break; + case ECC_ECR1: + ret = s->regs[ECC_ECR0]; + DPRINTF("Read event count 2 %08x\n", ret); break; } return ret; @@ -188,17 +220,49 @@ ecc_mem_writel, }; +static void ecc_diag_mem_writeb(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + ECCState *s = opaque; + + DPRINTF("Write diagnostic[%d] = %02x\n", (int)(addr & ECC_DIAG_MASK), val); + s->diag[addr & ECC_DIAG_MASK] = val; +} + +static uint32_t ecc_diag_mem_readb(void *opaque, target_phys_addr_t addr) +{ + ECCState *s = opaque; + uint32_t ret = s->diag[addr & ECC_DIAG_MASK]; + DPRINTF("Read diagnostic[%d] = %02x\n", (int)(addr & ECC_DIAG_MASK), ret); + return ret; +} + +static CPUReadMemoryFunc *ecc_diag_mem_read[3] = { + ecc_diag_mem_readb, + NULL, + NULL, +}; + +static CPUWriteMemoryFunc *ecc_diag_mem_write[3] = { + ecc_diag_mem_writeb, + NULL, + NULL, +}; + static int ecc_load(QEMUFile *f, void *opaque, int version_id) { ECCState *s = opaque; int i; - if (version_id != 1) + if (version_id != 2) return -EINVAL; for (i = 0; i < ECC_NREGS; i++) qemu_get_be32s(f, &s->regs[i]); + for (i = 0; i < ECC_DIAG_SIZE; i++) + qemu_get_8s(f, &s->diag[i]); + return 0; } @@ -209,20 +273,28 @@ for (i = 0; i < ECC_NREGS; i++) qemu_put_be32s(f, &s->regs[i]); + + for (i = 0; i < ECC_DIAG_SIZE; i++) + qemu_put_8s(f, &s->diag[i]); } static void ecc_reset(void *opaque) { ECCState *s = opaque; - int i; - - s->regs[ECC_FCR_REG] &= (ECC_FCR_VER | ECC_FCR_IMPL); - for (i = 1; i < ECC_NREGS; i++) - s->regs[i] = 0; + s->regs[ECC_MER] &= (ECC_MER_VER | ECC_MER_IMPL); + s->regs[ECC_MER] |= ECC_MER_MRR; + s->regs[ECC_MDR] = 0x20; + s->regs[ECC_MFSR] = 0; + s->regs[ECC_VCR] = 0; + s->regs[ECC_MFAR0] = 0x07c00000; + s->regs[ECC_MFAR1] = 0; + s->regs[ECC_DR] = 0; + s->regs[ECC_ECR0] = 0; + s->regs[ECC_ECR1] = 0; } -void * ecc_init(target_phys_addr_t base, uint32_t version) +void * ecc_init(target_phys_addr_t base, qemu_irq irq, uint32_t version) { int ecc_io_memory; ECCState *s; @@ -232,10 +304,17 @@ return NULL; s->regs[0] = version; + s->irq = irq; ecc_io_memory = cpu_register_io_memory(0, ecc_mem_read, ecc_mem_write, s); cpu_register_physical_memory(base, ECC_SIZE, ecc_io_memory); - register_savevm("ECC", base, 1, ecc_save, ecc_load, s); + if (version == 0) { // SS-600MP only + ecc_io_memory = cpu_register_io_memory(0, ecc_diag_mem_read, + ecc_diag_mem_write, s); + cpu_register_physical_memory(base + 0x1000, ECC_DIAG_SIZE, + ecc_io_memory); + } + register_savevm("ECC", base, 2, ecc_save, ecc_load, s); qemu_register_reset(ecc_reset, s); ecc_reset(s); return s; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/eepro100.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/eepro100.c --- qemu-0.9.1/hw/eepro100.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/eepro100.c 2008-07-18 19:02:34.000000000 +0100 @@ -1792,8 +1792,7 @@ qemu_register_reset(nic_reset, s); - /* XXX: instance number ? */ - register_savevm(name, 0, 3, nic_save, nic_load, s); + register_savevm(name, -1, 3, nic_save, nic_load, s); } void pci_i82551_init(PCIBus * bus, NICInfo * nd, int devfn) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/es1370.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/es1370.c --- qemu-0.9.1/hw/es1370.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/es1370.c 2008-06-21 18:14:50.000000000 +0100 @@ -936,6 +936,7 @@ ES1370State *s = opaque; size_t i; + pci_device_save (s->pci_dev, f); for (i = 0; i < NB_CHANNELS; ++i) { struct chan *d = &s->chan[i]; qemu_put_be32s (f, &d->shift); @@ -953,13 +954,18 @@ static int es1370_load (QEMUFile *f, void *opaque, int version_id) { + int ret; uint32_t ctl, sctl; ES1370State *s = opaque; size_t i; - if (version_id != 1) + if (version_id != 2) return -EINVAL; + ret = pci_device_load (s->pci_dev, f); + if (ret) + return ret; + for (i = 0; i < NB_CHANNELS; ++i) { struct chan *d = &s->chan[i]; qemu_get_be32s (f, &d->shift); @@ -1056,7 +1062,7 @@ s->pci_dev = &d->dev; pci_register_io_region (&d->dev, 0, 256, PCI_ADDRESS_SPACE_IO, es1370_map); - register_savevm ("es1370", 0, 1, es1370_save, es1370_load, s); + register_savevm ("es1370", 0, 2, es1370_save, es1370_load, s); qemu_register_reset (es1370_on_reset, s); AUD_register_card (audio, "es1370", &s->card); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/esp.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/esp.c --- qemu-0.9.1/hw/esp.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/esp.c 2008-10-02 20:14:17.000000000 +0100 @@ -21,12 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #include "hw.h" -#include "block.h" #include "scsi-disk.h" -#include "sun4m.h" -/* FIXME: Only needed for MAX_DISKS, which is probably wrong. */ -#include "sysemu.h" +#include "scsi.h" /* debug ESP card */ //#define DEBUG_ESP @@ -43,30 +41,29 @@ #define DPRINTF(fmt, args...) \ do { printf("ESP: " fmt , ##args); } while (0) #else -#define DPRINTF(fmt, args...) +#define DPRINTF(fmt, args...) do {} while (0) #endif -#define ESP_MASK 0x3f #define ESP_REGS 16 -#define ESP_SIZE (ESP_REGS * 4) #define TI_BUFSZ 32 typedef struct ESPState ESPState; struct ESPState { + uint32_t it_shift; qemu_irq irq; uint8_t rregs[ESP_REGS]; uint8_t wregs[ESP_REGS]; int32_t ti_size; uint32_t ti_rptr, ti_wptr; uint8_t ti_buf[TI_BUFSZ]; - int sense; - int dma; + uint32_t sense; + uint32_t dma; SCSIDevice *scsi_dev[ESP_MAX_DEVS]; SCSIDevice *current_dev; uint8_t cmdbuf[TI_BUFSZ]; - int cmdlen; - int do_cmd; + uint32_t cmdlen; + uint32_t do_cmd; /* The amount of data left in the current DMA transfer. */ uint32_t dma_left; @@ -75,6 +72,9 @@ uint32_t dma_counter; uint8_t *async_buf; uint32_t async_len; + + espdma_memory_read_write dma_memory_read; + espdma_memory_read_write dma_memory_write; void *dma_opaque; }; @@ -127,7 +127,7 @@ #define STAT_TC 0x10 #define STAT_PE 0x20 #define STAT_GE 0x40 -#define STAT_IN 0x80 +#define STAT_INT 0x80 #define INTR_FC 0x08 #define INTR_BS 0x10 @@ -143,7 +143,23 @@ #define TCHI_FAS100A 0x4 -static int get_cmd(ESPState *s, uint8_t *buf) +static void esp_raise_irq(ESPState *s) +{ + if (!(s->rregs[ESP_RSTAT] & STAT_INT)) { + s->rregs[ESP_RSTAT] |= STAT_INT; + qemu_irq_raise(s->irq); + } +} + +static void esp_lower_irq(ESPState *s) +{ + if (s->rregs[ESP_RSTAT] & STAT_INT) { + s->rregs[ESP_RSTAT] &= ~STAT_INT; + qemu_irq_lower(s->irq); + } +} + +static uint32_t get_cmd(ESPState *s, uint8_t *buf) { uint32_t dmalen; int target; @@ -152,7 +168,7 @@ target = s->wregs[ESP_WBUSID] & 7; DPRINTF("get_cmd: len %d target %d\n", dmalen, target); if (s->dma) { - espdma_memory_read(s->dma_opaque, buf, dmalen); + s->dma_memory_read(s->dma_opaque, buf, dmalen); } else { buf[0] = 0; memcpy(&buf[1], s->ti_buf, dmalen); @@ -171,10 +187,10 @@ if (target >= ESP_MAX_DEVS || !s->scsi_dev[target]) { // No such drive - s->rregs[ESP_RSTAT] = STAT_IN; + s->rregs[ESP_RSTAT] = 0; s->rregs[ESP_RINTR] = INTR_DC; s->rregs[ESP_RSEQ] = SEQ_0; - qemu_irq_raise(s->irq); + esp_raise_irq(s); return 0; } s->current_dev = s->scsi_dev[target]; @@ -191,7 +207,7 @@ datalen = s->current_dev->send_command(s->current_dev, 0, &buf[1], lun); s->ti_size = datalen; if (datalen != 0) { - s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC; + s->rregs[ESP_RSTAT] = STAT_TC; s->dma_left = 0; s->dma_counter = 0; if (datalen > 0) { @@ -204,7 +220,7 @@ } s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; s->rregs[ESP_RSEQ] = SEQ_CD; - qemu_irq_raise(s->irq); + esp_raise_irq(s); } static void handle_satn(ESPState *s) @@ -223,10 +239,10 @@ if (s->cmdlen) { DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen); s->do_cmd = 1; - s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC | STAT_CD; + s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; s->rregs[ESP_RSEQ] = SEQ_CD; - qemu_irq_raise(s->irq); + esp_raise_irq(s); } } @@ -236,8 +252,8 @@ s->ti_buf[0] = s->sense; s->ti_buf[1] = 0; if (s->dma) { - espdma_memory_write(s->dma_opaque, s->ti_buf, 2); - s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC | STAT_ST; + s->dma_memory_write(s->dma_opaque, s->ti_buf, 2); + s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; s->rregs[ESP_RSEQ] = SEQ_CD; } else { @@ -246,18 +262,18 @@ s->ti_wptr = 0; s->rregs[ESP_RFLAGS] = 2; } - qemu_irq_raise(s->irq); + esp_raise_irq(s); } static void esp_dma_done(ESPState *s) { - s->rregs[ESP_RSTAT] |= STAT_IN | STAT_TC; + s->rregs[ESP_RSTAT] |= STAT_TC; s->rregs[ESP_RINTR] = INTR_BS; s->rregs[ESP_RSEQ] = 0; s->rregs[ESP_RFLAGS] = 0; s->rregs[ESP_TCLO] = 0; s->rregs[ESP_TCMID] = 0; - qemu_irq_raise(s->irq); + esp_raise_irq(s); } static void esp_do_dma(ESPState *s) @@ -269,7 +285,7 @@ len = s->dma_left; if (s->do_cmd) { DPRINTF("command len %d + %d\n", s->cmdlen, len); - espdma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len); + s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len); s->ti_size = 0; s->cmdlen = 0; s->do_cmd = 0; @@ -284,9 +300,9 @@ len = s->async_len; } if (to_device) { - espdma_memory_read(s->dma_opaque, s->async_buf, len); + s->dma_memory_read(s->dma_opaque, s->async_buf, len); } else { - espdma_memory_write(s->dma_opaque, s->async_buf, len); + s->dma_memory_write(s->dma_opaque, s->async_buf, len); } s->dma_left -= len; s->async_buf += len; @@ -381,6 +397,8 @@ { ESPState *s = opaque; + esp_lower_irq(s); + memset(s->rregs, 0, ESP_REGS); memset(s->wregs, 0, ESP_REGS); s->rregs[ESP_TCHI] = TCHI_FAS100A; // Indicate fas100a @@ -402,7 +420,7 @@ ESPState *s = opaque; uint32_t saddr; - saddr = (addr & ESP_MASK) >> 2; + saddr = (addr >> s->it_shift) & (ESP_REGS - 1); DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]); switch (saddr) { case ESP_FIFO: @@ -415,7 +433,7 @@ } else { s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++]; } - qemu_irq_raise(s->irq); + esp_raise_irq(s); } if (s->ti_size == 0) { s->ti_rptr = 0; @@ -424,8 +442,8 @@ break; case ESP_RINTR: // Clear interrupt/error status bits - s->rregs[ESP_RSTAT] &= ~(STAT_IN | STAT_GE | STAT_PE); - qemu_irq_lower(s->irq); + s->rregs[ESP_RSTAT] &= ~(STAT_GE | STAT_PE); + esp_lower_irq(s); break; default: break; @@ -438,7 +456,7 @@ ESPState *s = opaque; uint32_t saddr; - saddr = (addr & ESP_MASK) >> 2; + saddr = (addr >> s->it_shift) & (ESP_REGS - 1); DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val); switch (saddr) { @@ -478,6 +496,7 @@ //s->ti_size = 0; s->rregs[ESP_RINTR] = INTR_FC; s->rregs[ESP_RSEQ] = 0; + s->rregs[ESP_RFLAGS] = 0; break; case CMD_RESET: DPRINTF("Chip reset (%2.2x)\n", val); @@ -487,7 +506,7 @@ DPRINTF("Bus reset (%2.2x)\n", val); s->rregs[ESP_RINTR] = INTR_RST; if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) { - qemu_irq_raise(s->irq); + esp_raise_irq(s); } break; case CMD_TI: @@ -550,7 +569,7 @@ static CPUWriteMemoryFunc *esp_mem_write[3] = { esp_mem_writeb, NULL, - NULL, + esp_mem_writeb, }; static void esp_save(QEMUFile *f, void *opaque) @@ -559,7 +578,7 @@ qemu_put_buffer(f, s->rregs, ESP_REGS); qemu_put_buffer(f, s->wregs, ESP_REGS); - qemu_put_be32s(f, &s->ti_size); + qemu_put_sbe32s(f, &s->ti_size); qemu_put_be32s(f, &s->ti_rptr); qemu_put_be32s(f, &s->ti_wptr); qemu_put_buffer(f, s->ti_buf, TI_BUFSZ); @@ -581,7 +600,7 @@ qemu_get_buffer(f, s->rregs, ESP_REGS); qemu_get_buffer(f, s->wregs, ESP_REGS); - qemu_get_be32s(f, &s->ti_size); + qemu_get_sbe32s(f, &s->ti_size); qemu_get_be32s(f, &s->ti_rptr); qemu_get_be32s(f, &s->ti_wptr); qemu_get_buffer(f, s->ti_buf, TI_BUFSZ); @@ -620,7 +639,9 @@ s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s); } -void *esp_init(target_phys_addr_t espaddr, +void *esp_init(target_phys_addr_t espaddr, int it_shift, + espdma_memory_read_write dma_memory_read, + espdma_memory_read_write dma_memory_write, void *dma_opaque, qemu_irq irq, qemu_irq *reset) { ESPState *s; @@ -631,10 +652,13 @@ return NULL; s->irq = irq; + s->it_shift = it_shift; + s->dma_memory_read = dma_memory_read; + s->dma_memory_write = dma_memory_write; s->dma_opaque = dma_opaque; esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s); - cpu_register_physical_memory(espaddr, ESP_SIZE, esp_io_memory); + cpu_register_physical_memory(espaddr, ESP_REGS << it_shift, esp_io_memory); esp_reset(s); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/etraxfs.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/etraxfs.c --- qemu-0.9.1/hw/etraxfs.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/etraxfs.c 2008-10-28 10:59:59.000000000 +0000 @@ -24,157 +24,137 @@ #include #include #include "hw.h" +#include "net.h" +#include "flash.h" #include "sysemu.h" +#include "devices.h" #include "boards.h" -extern FILE *logfile; +#include "etraxfs.h" + +#define FLASH_SIZE 0x2000000 +#define INTMEM_SIZE (128 * 1024) + +static uint32_t bootstrap_pc; static void main_cpu_reset(void *opaque) { CPUState *env = opaque; cpu_reset(env); -} -static uint32_t fs_mmio_readb (void *opaque, target_phys_addr_t addr) -{ - CPUState *env = opaque; - uint32_t r = 0; - printf ("%s %x pc=%x\n", __func__, addr, env->pc); - return r; -} -static uint32_t fs_mmio_readw (void *opaque, target_phys_addr_t addr) -{ - CPUState *env = opaque; - uint32_t r = 0; - printf ("%s %x pc=%x\n", __func__, addr, env->pc); - return r; -} - -static uint32_t fs_mmio_readl (void *opaque, target_phys_addr_t addr) -{ - CPUState *env = opaque; - uint32_t r = 0; - printf ("%s %x p=%x\n", __func__, addr, env->pc); - return r; -} - -static void -fs_mmio_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - CPUState *env = opaque; - printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); -} -static void -fs_mmio_writew (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - CPUState *env = opaque; - printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); -} -static void -fs_mmio_writel (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - CPUState *env = opaque; - printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); -} - -static CPUReadMemoryFunc *fs_mmio_read[] = { - &fs_mmio_readb, - &fs_mmio_readw, - &fs_mmio_readl, -}; - -static CPUWriteMemoryFunc *fs_mmio_write[] = { - &fs_mmio_writeb, - &fs_mmio_writew, - &fs_mmio_writel, -}; - - -/* Init functions for different blocks. */ -extern void etraxfs_timer_init(CPUState *env, qemu_irq *irqs); -extern void etraxfs_ser_init(CPUState *env, qemu_irq *irqs); - -void etrax_ack_irq(CPUState *env, uint32_t mask) -{ - env->pending_interrupts &= ~mask; -} - -static void dummy_cpu_set_irq(void *opaque, int irq, int level) -{ - CPUState *env = opaque; - - /* Hmm, should this really be done here? */ - env->pending_interrupts |= 1 << irq; - cpu_interrupt(env, CPU_INTERRUPT_HARD); + env->pregs[PR_CCS] &= ~I_FLAG; + env->pc = bootstrap_pc; } static -void bareetraxfs_init (int ram_size, int vga_ram_size, +void bareetraxfs_init (ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { CPUState *env; - qemu_irq *irqs; + struct etraxfs_pic *pic; + void *etraxfs_dmac; + struct etraxfs_dma_client *eth[2] = {NULL, NULL}; int kernel_size; - int internal_regs; + int i; + ram_addr_t phys_ram; + ram_addr_t phys_flash; + ram_addr_t phys_intmem; /* init CPUs */ if (cpu_model == NULL) { cpu_model = "crisv32"; } env = cpu_init(cpu_model); -/* register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); */ qemu_register_reset(main_cpu_reset, env); - irqs = qemu_allocate_irqs(dummy_cpu_set_irq, env, 32); - internal_regs = cpu_register_io_memory(0, - fs_mmio_read, fs_mmio_write, env); - /* 0xb0050000 is the last reg. */ - cpu_register_physical_memory (0xac000000, 0x4010000, internal_regs); /* allocate RAM */ - cpu_register_physical_memory(0x40000000, ram_size, IO_MEM_RAM); + phys_ram = qemu_ram_alloc(ram_size); + cpu_register_physical_memory(0x40000000, ram_size, phys_ram | IO_MEM_RAM); - etraxfs_timer_init(env, irqs); - etraxfs_ser_init(env, irqs); - - kernel_size = load_image(kernel_filename, phys_ram_base + 0x4000); - /* magic for boot. */ - env->regs[8] = 0x56902387; - env->regs[9] = 0x40004000 + kernel_size; - env->pc = 0x40004000; - - { - unsigned char *ptr = phys_ram_base + 0x4000; - int i; - for (i = 0; i < 8; i++) - { - printf ("%2.2x ", ptr[i]); - } - printf("\n"); + /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the + internal memory. */ + phys_intmem = qemu_ram_alloc(INTMEM_SIZE); + cpu_register_physical_memory(0x38000000, INTMEM_SIZE, + phys_intmem | IO_MEM_RAM); + + + phys_flash = qemu_ram_alloc(FLASH_SIZE); + i = drive_get_index(IF_PFLASH, 0, 0); + pflash_cfi02_register(0x0, phys_flash, + drives_table[i].bdrv, (64 * 1024), + FLASH_SIZE >> 16, + 1, 2, 0x0000, 0x0000, 0x0000, 0x0000, + 0x555, 0x2aa); + pic = etraxfs_pic_init(env, 0x3001c000); + etraxfs_dmac = etraxfs_dmac_init(env, 0x30000000, 10); + for (i = 0; i < 10; i++) { + /* On ETRAX, odd numbered channels are inputs. */ + etraxfs_dmac_connect(etraxfs_dmac, i, pic->irq + 7 + i, i & 1); } - printf ("pc =%x\n", env->pc); - printf ("ram size =%d\n", ram_size); - printf ("kernel name =%s\n", kernel_filename); - printf ("kernel size =%d\n", kernel_size); - printf ("cpu haltd =%d\n", env->halted); -} + /* Add the two ethernet blocks. */ + eth[0] = etraxfs_eth_init(&nd_table[0], env, pic->irq + 25, 0x30034000); + if (nb_nics > 1) + eth[1] = etraxfs_eth_init(&nd_table[1], env, pic->irq + 26, 0x30036000); + + /* The DMA Connector block is missing, hardwire things for now. */ + etraxfs_dmac_connect_client(etraxfs_dmac, 0, eth[0]); + etraxfs_dmac_connect_client(etraxfs_dmac, 1, eth[0] + 1); + if (eth[1]) { + etraxfs_dmac_connect_client(etraxfs_dmac, 6, eth[1]); + etraxfs_dmac_connect_client(etraxfs_dmac, 7, eth[1] + 1); + } -void DMA_run(void) -{ -} + /* 2 timers. */ + etraxfs_timer_init(env, pic->irq + 0x1b, pic->nmi + 1, 0x3001e000); + etraxfs_timer_init(env, pic->irq + 0x1b, pic->nmi + 1, 0x3005e000); + + for (i = 0; i < 4; i++) { + if (serial_hds[i]) { + etraxfs_ser_init(env, pic->irq + 0x14 + i, + serial_hds[i], 0x30026000 + i * 0x2000); + } + } -void pic_info() -{ -} + if (kernel_filename) { + uint64_t entry, high; + int kcmdline_len; + + /* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis + devboard SDK. */ + kernel_size = load_elf(kernel_filename, -0x80000000LL, + &entry, NULL, &high); + bootstrap_pc = entry; + if (kernel_size < 0) { + /* Takes a kimage from the axis devboard SDK. */ + kernel_size = load_image(kernel_filename, phys_ram_base + 0x4000); + bootstrap_pc = 0x40004000; + env->regs[9] = 0x40004000 + kernel_size; + } + env->regs[8] = 0x56902387; /* RAM init magic. */ + + if (kernel_cmdline && (kcmdline_len = strlen(kernel_cmdline))) { + if (kcmdline_len > 256) { + fprintf(stderr, "Too long CRIS kernel cmdline (max 256)\n"); + exit(1); + } + pstrcpy_targphys(high, 256, kernel_cmdline); + /* Let the kernel know we are modifying the cmdline. */ + env->regs[10] = 0x87109563; + env->regs[11] = high; + } + } + env->pc = bootstrap_pc; -void irq_info() -{ + printf ("pc =%x\n", env->pc); + printf ("ram size =%ld\n", ram_size); } QEMUMachine bareetraxfs_machine = { - "bareetraxfs", - "Bare ETRAX FS board", - bareetraxfs_init, + .name = "bareetraxfs", + .desc = "Bare ETRAX FS board", + .init = bareetraxfs_init, + .ram_require = 0x8000000, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/etraxfs_dma.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/etraxfs_dma.c --- qemu-0.9.1/hw/etraxfs_dma.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/etraxfs_dma.c 2008-11-04 20:29:29.000000000 +0000 @@ -0,0 +1,766 @@ +/* + * QEMU ETRAX DMA Controller. + * + * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB. + * + * 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 +#include +#include "hw.h" +#include "qemu-common.h" +#include "sysemu.h" + +#include "etraxfs_dma.h" + +#define D(x) + +#define RW_DATA 0x0 +#define RW_SAVED_DATA 0x58 +#define RW_SAVED_DATA_BUF 0x5c +#define RW_GROUP 0x60 +#define RW_GROUP_DOWN 0x7c +#define RW_CMD 0x80 +#define RW_CFG 0x84 +#define RW_STAT 0x88 +#define RW_INTR_MASK 0x8c +#define RW_ACK_INTR 0x90 +#define R_INTR 0x94 +#define R_MASKED_INTR 0x98 +#define RW_STREAM_CMD 0x9c + +#define DMA_REG_MAX 0x100 + +/* descriptors */ + +// ------------------------------------------------------------ dma_descr_group +typedef struct dma_descr_group { + struct dma_descr_group *next; + unsigned eol : 1; + unsigned tol : 1; + unsigned bol : 1; + unsigned : 1; + unsigned intr : 1; + unsigned : 2; + unsigned en : 1; + unsigned : 7; + unsigned dis : 1; + unsigned md : 16; + struct dma_descr_group *up; + union { + struct dma_descr_context *context; + struct dma_descr_group *group; + } down; +} dma_descr_group; + +// ---------------------------------------------------------- dma_descr_context +typedef struct dma_descr_context { + struct dma_descr_context *next; + unsigned eol : 1; + unsigned : 3; + unsigned intr : 1; + unsigned : 1; + unsigned store_mode : 1; + unsigned en : 1; + unsigned : 7; + unsigned dis : 1; + unsigned md0 : 16; + unsigned md1; + unsigned md2; + unsigned md3; + unsigned md4; + struct dma_descr_data *saved_data; + char *saved_data_buf; +} dma_descr_context; + +// ------------------------------------------------------------- dma_descr_data +typedef struct dma_descr_data { + struct dma_descr_data *next; + char *buf; + unsigned eol : 1; + unsigned : 2; + unsigned out_eop : 1; + unsigned intr : 1; + unsigned wait : 1; + unsigned : 2; + unsigned : 3; + unsigned in_eop : 1; + unsigned : 4; + unsigned md : 16; + char *after; +} dma_descr_data; + +/* Constants */ +enum { + regk_dma_ack_pkt = 0x00000100, + regk_dma_anytime = 0x00000001, + regk_dma_array = 0x00000008, + regk_dma_burst = 0x00000020, + regk_dma_client = 0x00000002, + regk_dma_copy_next = 0x00000010, + regk_dma_copy_up = 0x00000020, + regk_dma_data_at_eol = 0x00000001, + regk_dma_dis_c = 0x00000010, + regk_dma_dis_g = 0x00000020, + regk_dma_idle = 0x00000001, + regk_dma_intern = 0x00000004, + regk_dma_load_c = 0x00000200, + regk_dma_load_c_n = 0x00000280, + regk_dma_load_c_next = 0x00000240, + regk_dma_load_d = 0x00000140, + regk_dma_load_g = 0x00000300, + regk_dma_load_g_down = 0x000003c0, + regk_dma_load_g_next = 0x00000340, + regk_dma_load_g_up = 0x00000380, + regk_dma_next_en = 0x00000010, + regk_dma_next_pkt = 0x00000010, + regk_dma_no = 0x00000000, + regk_dma_only_at_wait = 0x00000000, + regk_dma_restore = 0x00000020, + regk_dma_rst = 0x00000001, + regk_dma_running = 0x00000004, + regk_dma_rw_cfg_default = 0x00000000, + regk_dma_rw_cmd_default = 0x00000000, + regk_dma_rw_intr_mask_default = 0x00000000, + regk_dma_rw_stat_default = 0x00000101, + regk_dma_rw_stream_cmd_default = 0x00000000, + regk_dma_save_down = 0x00000020, + regk_dma_save_up = 0x00000020, + regk_dma_set_reg = 0x00000050, + regk_dma_set_w_size1 = 0x00000190, + regk_dma_set_w_size2 = 0x000001a0, + regk_dma_set_w_size4 = 0x000001c0, + regk_dma_stopped = 0x00000002, + regk_dma_store_c = 0x00000002, + regk_dma_store_descr = 0x00000000, + regk_dma_store_g = 0x00000004, + regk_dma_store_md = 0x00000001, + regk_dma_sw = 0x00000008, + regk_dma_update_down = 0x00000020, + regk_dma_yes = 0x00000001 +}; + +enum dma_ch_state +{ + RST = 1, + STOPPED = 2, + RUNNING = 4 +}; + +struct fs_dma_channel +{ + int regmap; + qemu_irq *irq; + struct etraxfs_dma_client *client; + + + /* Internal status. */ + int stream_cmd_src; + enum dma_ch_state state; + + unsigned int input : 1; + unsigned int eol : 1; + + struct dma_descr_group current_g; + struct dma_descr_context current_c; + struct dma_descr_data current_d; + + /* Controll registers. */ + uint32_t regs[DMA_REG_MAX]; +}; + +struct fs_dma_ctrl +{ + CPUState *env; + target_phys_addr_t base; + + int nr_channels; + struct fs_dma_channel *channels; + + QEMUBH *bh; +}; + +static inline uint32_t channel_reg(struct fs_dma_ctrl *ctrl, int c, int reg) +{ + return ctrl->channels[c].regs[reg]; +} + +static inline int channel_stopped(struct fs_dma_ctrl *ctrl, int c) +{ + return channel_reg(ctrl, c, RW_CFG) & 2; +} + +static inline int channel_en(struct fs_dma_ctrl *ctrl, int c) +{ + return (channel_reg(ctrl, c, RW_CFG) & 1) + && ctrl->channels[c].client; +} + +static inline int fs_channel(target_phys_addr_t base, target_phys_addr_t addr) +{ + /* Every channel has a 0x2000 ctrl register map. */ + return (addr - base) >> 13; +} + +#ifdef USE_THIS_DEAD_CODE +static void channel_load_g(struct fs_dma_ctrl *ctrl, int c) +{ + target_phys_addr_t addr = channel_reg(ctrl, c, RW_GROUP); + + /* Load and decode. FIXME: handle endianness. */ + cpu_physical_memory_read (addr, + (void *) &ctrl->channels[c].current_g, + sizeof ctrl->channels[c].current_g); +} + +static void dump_c(int ch, struct dma_descr_context *c) +{ + printf("%s ch=%d\n", __func__, ch); + printf("next=%p\n", c->next); + printf("saved_data=%p\n", c->saved_data); + printf("saved_data_buf=%p\n", c->saved_data_buf); + printf("eol=%x\n", (uint32_t) c->eol); +} + +static void dump_d(int ch, struct dma_descr_data *d) +{ + printf("%s ch=%d\n", __func__, ch); + printf("next=%p\n", d->next); + printf("buf=%p\n", d->buf); + printf("after=%p\n", d->after); + printf("intr=%x\n", (uint32_t) d->intr); + printf("out_eop=%x\n", (uint32_t) d->out_eop); + printf("in_eop=%x\n", (uint32_t) d->in_eop); + printf("eol=%x\n", (uint32_t) d->eol); +} +#endif + +static void channel_load_c(struct fs_dma_ctrl *ctrl, int c) +{ + target_phys_addr_t addr = channel_reg(ctrl, c, RW_GROUP_DOWN); + + /* Load and decode. FIXME: handle endianness. */ + cpu_physical_memory_read (addr, + (void *) &ctrl->channels[c].current_c, + sizeof ctrl->channels[c].current_c); + + D(dump_c(c, &ctrl->channels[c].current_c)); + /* I guess this should update the current pos. */ + ctrl->channels[c].regs[RW_SAVED_DATA] = + (uint32_t)(unsigned long)ctrl->channels[c].current_c.saved_data; + ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = + (uint32_t)(unsigned long)ctrl->channels[c].current_c.saved_data_buf; +} + +static void channel_load_d(struct fs_dma_ctrl *ctrl, int c) +{ + target_phys_addr_t addr = channel_reg(ctrl, c, RW_SAVED_DATA); + + /* Load and decode. FIXME: handle endianness. */ + D(printf("%s ch=%d addr=%x\n", __func__, c, addr)); + cpu_physical_memory_read (addr, + (void *) &ctrl->channels[c].current_d, + sizeof ctrl->channels[c].current_d); + + D(dump_d(c, &ctrl->channels[c].current_d)); + ctrl->channels[c].regs[RW_DATA] = addr; +} + +static void channel_store_c(struct fs_dma_ctrl *ctrl, int c) +{ + target_phys_addr_t addr = channel_reg(ctrl, c, RW_GROUP_DOWN); + + /* Encode and store. FIXME: handle endianness. */ + D(printf("%s ch=%d addr=%x\n", __func__, c, addr)); + D(dump_d(c, &ctrl->channels[c].current_d)); + cpu_physical_memory_write (addr, + (void *) &ctrl->channels[c].current_c, + sizeof ctrl->channels[c].current_c); +} + +static void channel_store_d(struct fs_dma_ctrl *ctrl, int c) +{ + target_phys_addr_t addr = channel_reg(ctrl, c, RW_SAVED_DATA); + + /* Encode and store. FIXME: handle endianness. */ + D(printf("%s ch=%d addr=%x\n", __func__, c, addr)); + cpu_physical_memory_write (addr, + (void *) &ctrl->channels[c].current_d, + sizeof ctrl->channels[c].current_d); +} + +static inline void channel_stop(struct fs_dma_ctrl *ctrl, int c) +{ + /* FIXME: */ +} + +static inline void channel_start(struct fs_dma_ctrl *ctrl, int c) +{ + if (ctrl->channels[c].client) + { + ctrl->channels[c].eol = 0; + ctrl->channels[c].state = RUNNING; + } else + printf("WARNING: starting DMA ch %d with no client\n", c); +} + +static void channel_continue(struct fs_dma_ctrl *ctrl, int c) +{ + if (!channel_en(ctrl, c) + || channel_stopped(ctrl, c) + || ctrl->channels[c].state != RUNNING + /* Only reload the current data descriptor if it has eol set. */ + || !ctrl->channels[c].current_d.eol) { + D(printf("continue failed ch=%d state=%d stopped=%d en=%d eol=%d\n", + c, ctrl->channels[c].state, + channel_stopped(ctrl, c), + channel_en(ctrl,c), + ctrl->channels[c].eol)); + D(dump_d(c, &ctrl->channels[c].current_d)); + return; + } + + /* Reload the current descriptor. */ + channel_load_d(ctrl, c); + + /* If the current descriptor cleared the eol flag and we had already + reached eol state, do the continue. */ + if (!ctrl->channels[c].current_d.eol && ctrl->channels[c].eol) { + D(printf("continue %d ok %p\n", c, + ctrl->channels[c].current_d.next)); + ctrl->channels[c].regs[RW_SAVED_DATA] = + (uint32_t)(unsigned long)ctrl->channels[c].current_d.next; + channel_load_d(ctrl, c); + channel_start(ctrl, c); + } + ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = + (uint32_t)(unsigned long)ctrl->channels[c].current_d.buf; +} + +static void channel_stream_cmd(struct fs_dma_ctrl *ctrl, int c, uint32_t v) +{ + unsigned int cmd = v & ((1 << 10) - 1); + + D(printf("%s ch=%d cmd=%x\n", + __func__, c, cmd)); + if (cmd & regk_dma_load_d) { + channel_load_d(ctrl, c); + if (cmd & regk_dma_burst) + channel_start(ctrl, c); + } + + if (cmd & regk_dma_load_c) { + channel_load_c(ctrl, c); + channel_start(ctrl, c); + } +} + +static void channel_update_irq(struct fs_dma_ctrl *ctrl, int c) +{ + D(printf("%s %d\n", __func__, c)); + ctrl->channels[c].regs[R_INTR] &= + ~(ctrl->channels[c].regs[RW_ACK_INTR]); + + ctrl->channels[c].regs[R_MASKED_INTR] = + ctrl->channels[c].regs[R_INTR] + & ctrl->channels[c].regs[RW_INTR_MASK]; + + D(printf("%s: chan=%d masked_intr=%x\n", __func__, + c, + ctrl->channels[c].regs[R_MASKED_INTR])); + + if (ctrl->channels[c].regs[R_MASKED_INTR]) + qemu_irq_raise(ctrl->channels[c].irq[0]); + else + qemu_irq_lower(ctrl->channels[c].irq[0]); +} + +static void channel_out_run(struct fs_dma_ctrl *ctrl, int c) +{ + uint32_t len; + uint32_t saved_data_buf; + unsigned char buf[2 * 1024]; + + while (ctrl->channels[c].eol != 1) { + saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF); + + D(printf("ch=%d buf=%x after=%x saved_data_buf=%x\n", + c, + (uint32_t)ctrl->channels[c].current_d.buf, + (uint32_t)ctrl->channels[c].current_d.after, + saved_data_buf)); + + len = (uint32_t)(unsigned long) + ctrl->channels[c].current_d.after; + len -= saved_data_buf; + + if (len > sizeof buf) + len = sizeof buf; + cpu_physical_memory_read (saved_data_buf, buf, len); + + D(printf("channel %d pushes %x %u bytes\n", c, + saved_data_buf, len)); + + if (ctrl->channels[c].client->client.push) + ctrl->channels[c].client->client.push( + ctrl->channels[c].client->client.opaque, + buf, len); + else + printf("WARNING: DMA ch%d dataloss," + " no attached client.\n", c); + + saved_data_buf += len; + + if (saved_data_buf == (uint32_t)(unsigned long) + ctrl->channels[c].current_d.after) { + /* Done. Step to next. */ + if (ctrl->channels[c].current_d.out_eop) { + /* TODO: signal eop to the client. */ + D(printf("signal eop\n")); + } + if (ctrl->channels[c].current_d.intr) { + /* TODO: signal eop to the client. */ + /* data intr. */ + D(printf("signal intr\n")); + ctrl->channels[c].regs[R_INTR] |= (1 << 2); + channel_update_irq(ctrl, c); + } + if (ctrl->channels[c].current_d.eol) { + D(printf("channel %d EOL\n", c)); + ctrl->channels[c].eol = 1; + + /* Mark the context as disabled. */ + ctrl->channels[c].current_c.dis = 1; + channel_store_c(ctrl, c); + + channel_stop(ctrl, c); + } else { + ctrl->channels[c].regs[RW_SAVED_DATA] = + (uint32_t)(unsigned long)ctrl-> + channels[c].current_d.next; + /* Load new descriptor. */ + channel_load_d(ctrl, c); + saved_data_buf = (uint32_t)(unsigned long) + ctrl->channels[c].current_d.buf; + } + + channel_store_d(ctrl, c); + ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = + saved_data_buf; + D(dump_d(c, &ctrl->channels[c].current_d)); + } + ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf; + } +} + +static int channel_in_process(struct fs_dma_ctrl *ctrl, int c, + unsigned char *buf, int buflen, int eop) +{ + uint32_t len; + uint32_t saved_data_buf; + + if (ctrl->channels[c].eol == 1) + return 0; + + saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF); + len = (uint32_t)(unsigned long)ctrl->channels[c].current_d.after; + len -= saved_data_buf; + + if (len > buflen) + len = buflen; + + cpu_physical_memory_write (saved_data_buf, buf, len); + saved_data_buf += len; + + if (saved_data_buf == + (uint32_t)(unsigned long)ctrl->channels[c].current_d.after + || eop) { + uint32_t r_intr = ctrl->channels[c].regs[R_INTR]; + + D(printf("in dscr end len=%d\n", + ctrl->channels[c].current_d.after + - ctrl->channels[c].current_d.buf)); + ctrl->channels[c].current_d.after = + (void *)(unsigned long) saved_data_buf; + + /* Done. Step to next. */ + if (ctrl->channels[c].current_d.intr) { + /* TODO: signal eop to the client. */ + /* data intr. */ + ctrl->channels[c].regs[R_INTR] |= 3; + } + if (eop) { + ctrl->channels[c].current_d.in_eop = 1; + ctrl->channels[c].regs[R_INTR] |= 8; + } + if (r_intr != ctrl->channels[c].regs[R_INTR]) + channel_update_irq(ctrl, c); + + channel_store_d(ctrl, c); + D(dump_d(c, &ctrl->channels[c].current_d)); + + if (ctrl->channels[c].current_d.eol) { + D(printf("channel %d EOL\n", c)); + ctrl->channels[c].eol = 1; + + /* Mark the context as disabled. */ + ctrl->channels[c].current_c.dis = 1; + channel_store_c(ctrl, c); + + channel_stop(ctrl, c); + } else { + ctrl->channels[c].regs[RW_SAVED_DATA] = + (uint32_t)(unsigned long)ctrl-> + channels[c].current_d.next; + /* Load new descriptor. */ + channel_load_d(ctrl, c); + saved_data_buf = (uint32_t)(unsigned long) + ctrl->channels[c].current_d.buf; + } + } + + ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf; + return len; +} + +static inline void channel_in_run(struct fs_dma_ctrl *ctrl, int c) +{ + if (ctrl->channels[c].client->client.pull) + ctrl->channels[c].client->client.pull( + ctrl->channels[c].client->client.opaque); +} + +static uint32_t dma_rinvalid (void *opaque, target_phys_addr_t addr) +{ + struct fs_dma_ctrl *ctrl = opaque; + CPUState *env = ctrl->env; + cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n", + addr); + return 0; +} + +static uint32_t +dma_readl (void *opaque, target_phys_addr_t addr) +{ + struct fs_dma_ctrl *ctrl = opaque; + int c; + uint32_t r = 0; + + /* Make addr relative to this instances base. */ + c = fs_channel(ctrl->base, addr); + addr &= 0x1fff; + switch (addr) + { + case RW_STAT: + r = ctrl->channels[c].state & 7; + r |= ctrl->channels[c].eol << 5; + r |= ctrl->channels[c].stream_cmd_src << 8; + break; + + default: + r = ctrl->channels[c].regs[addr]; + D(printf ("%s c=%d addr=%x\n", + __func__, c, addr)); + break; + } + return r; +} + +static void +dma_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + struct fs_dma_ctrl *ctrl = opaque; + CPUState *env = ctrl->env; + cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n", + addr); +} + +static void +dma_update_state(struct fs_dma_ctrl *ctrl, int c) +{ + if ((ctrl->channels[c].regs[RW_CFG] & 1) != 3) { + if (ctrl->channels[c].regs[RW_CFG] & 2) + ctrl->channels[c].state = STOPPED; + if (!(ctrl->channels[c].regs[RW_CFG] & 1)) + ctrl->channels[c].state = RST; + } +} + +static void +dma_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + struct fs_dma_ctrl *ctrl = opaque; + int c; + + /* Make addr relative to this instances base. */ + c = fs_channel(ctrl->base, addr); + addr &= 0x1fff; + switch (addr) + { + case RW_DATA: + ctrl->channels[c].regs[addr] = value; + break; + + case RW_CFG: + ctrl->channels[c].regs[addr] = value; + dma_update_state(ctrl, c); + break; + case RW_CMD: + /* continue. */ + if (value & ~1) + printf("Invalid store to ch=%d RW_CMD %x\n", + c, value); + ctrl->channels[c].regs[addr] = value; + channel_continue(ctrl, c); + break; + + case RW_SAVED_DATA: + case RW_SAVED_DATA_BUF: + case RW_GROUP: + case RW_GROUP_DOWN: + ctrl->channels[c].regs[addr] = value; + break; + + case RW_ACK_INTR: + case RW_INTR_MASK: + ctrl->channels[c].regs[addr] = value; + channel_update_irq(ctrl, c); + if (addr == RW_ACK_INTR) + ctrl->channels[c].regs[RW_ACK_INTR] = 0; + break; + + case RW_STREAM_CMD: + if (value & ~1023) + printf("Invalid store to ch=%d " + "RW_STREAMCMD %x\n", + c, value); + ctrl->channels[c].regs[addr] = value; + D(printf("stream_cmd ch=%d\n", c)); + channel_stream_cmd(ctrl, c, value); + break; + + default: + D(printf ("%s c=%d %x %x\n", __func__, c, addr)); + break; + } +} + +static CPUReadMemoryFunc *dma_read[] = { + &dma_rinvalid, + &dma_rinvalid, + &dma_readl, +}; + +static CPUWriteMemoryFunc *dma_write[] = { + &dma_winvalid, + &dma_winvalid, + &dma_writel, +}; + +static void etraxfs_dmac_run(void *opaque) +{ + struct fs_dma_ctrl *ctrl = opaque; + int i; + int p = 0; + + for (i = 0; + i < ctrl->nr_channels; + i++) + { + if (ctrl->channels[i].state == RUNNING) + { + p++; + if (ctrl->channels[i].input) + channel_in_run(ctrl, i); + else + channel_out_run(ctrl, i); + } + } +} + +int etraxfs_dmac_input(struct etraxfs_dma_client *client, + void *buf, int len, int eop) +{ + return channel_in_process(client->ctrl, client->channel, + buf, len, eop); +} + +/* Connect an IRQ line with a channel. */ +void etraxfs_dmac_connect(void *opaque, int c, qemu_irq *line, int input) +{ + struct fs_dma_ctrl *ctrl = opaque; + ctrl->channels[c].irq = line; + ctrl->channels[c].input = input; +} + +void etraxfs_dmac_connect_client(void *opaque, int c, + struct etraxfs_dma_client *cl) +{ + struct fs_dma_ctrl *ctrl = opaque; + cl->ctrl = ctrl; + cl->channel = c; + ctrl->channels[c].client = cl; +} + + +static void DMA_run(void *opaque) +{ + struct fs_dma_ctrl *etraxfs_dmac = opaque; + if (vm_running) + etraxfs_dmac_run(etraxfs_dmac); + qemu_bh_schedule_idle(etraxfs_dmac->bh); +} + +void *etraxfs_dmac_init(CPUState *env, + target_phys_addr_t base, int nr_channels) +{ + struct fs_dma_ctrl *ctrl = NULL; + int i; + + ctrl = qemu_mallocz(sizeof *ctrl); + if (!ctrl) + return NULL; + + ctrl->bh = qemu_bh_new(DMA_run, ctrl); + qemu_bh_schedule_idle(ctrl->bh); + + ctrl->base = base; + ctrl->env = env; + ctrl->nr_channels = nr_channels; + ctrl->channels = qemu_mallocz(sizeof ctrl->channels[0] * nr_channels); + if (!ctrl->channels) + goto err; + + for (i = 0; i < nr_channels; i++) + { + ctrl->channels[i].regmap = cpu_register_io_memory(0, + dma_read, + dma_write, + ctrl); + cpu_register_physical_memory (base + i * 0x2000, + sizeof ctrl->channels[i].regs, + ctrl->channels[i].regmap); + } + + return ctrl; + err: + qemu_free(ctrl->channels); + qemu_free(ctrl); + return NULL; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/etraxfs_dma.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/etraxfs_dma.h --- qemu-0.9.1/hw/etraxfs_dma.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/etraxfs_dma.h 2008-11-04 20:29:29.000000000 +0000 @@ -0,0 +1,23 @@ +struct etraxfs_dma_client +{ + /* DMA controller. */ + int channel; + void *ctrl; + + /* client. */ + struct + { + int (*push)(void *opaque, unsigned char *buf, int len); + void (*pull)(void *opaque); + void *opaque; + } client; +}; + +void *etraxfs_dmac_init(CPUState *env, target_phys_addr_t base, + int nr_channels); +void etraxfs_dmac_connect(void *opaque, int channel, qemu_irq *line, + int input); +void etraxfs_dmac_connect_client(void *opaque, int c, + struct etraxfs_dma_client *cl); +int etraxfs_dmac_input(struct etraxfs_dma_client *client, + void *buf, int len, int eop); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/etraxfs_eth.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/etraxfs_eth.c --- qemu-0.9.1/hw/etraxfs_eth.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/etraxfs_eth.c 2008-10-24 10:18:39.000000000 +0100 @@ -0,0 +1,613 @@ +/* + * QEMU ETRAX Ethernet Controller. + * + * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB. + * + * 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 +#include "hw.h" +#include "net.h" + +#include "etraxfs_dma.h" + +#define D(x) + +/* Advertisement control register. */ +#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ +#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ +#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ +#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ + +/* + * The MDIO extensions in the TDK PHY model were reversed engineered from the + * linux driver (PHYID and Diagnostics reg). + * TODO: Add friendly names for the register nums. + */ +struct qemu_phy +{ + uint32_t regs[32]; + + unsigned int (*read)(struct qemu_phy *phy, unsigned int req); + void (*write)(struct qemu_phy *phy, unsigned int req, + unsigned int data); +}; + +static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req) +{ + int regnum; + unsigned r = 0; + + regnum = req & 0x1f; + + switch (regnum) { + case 1: + /* MR1. */ + /* Speeds and modes. */ + r |= (1 << 13) | (1 << 14); + r |= (1 << 11) | (1 << 12); + r |= (1 << 5); /* Autoneg complete. */ + r |= (1 << 3); /* Autoneg able. */ + r |= (1 << 2); /* Link. */ + break; + case 5: + /* Link partner ability. + We are kind; always agree with whatever best mode + the guest advertises. */ + r = 1 << 14; /* Success. */ + /* Copy advertised modes. */ + r |= phy->regs[4] & (15 << 5); + /* Autoneg support. */ + r |= 1; + break; + case 18: + { + /* Diagnostics reg. */ + int duplex = 0; + int speed_100 = 0; + + /* Are we advertising 100 half or 100 duplex ? */ + speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF); + speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL); + + /* Are we advertising 10 duplex or 100 duplex ? */ + duplex = !!(phy->regs[4] & ADVERTISE_100FULL); + duplex |= !!(phy->regs[4] & ADVERTISE_10FULL); + r = (speed_100 << 10) | (duplex << 11); + } + break; + + default: + r = phy->regs[regnum]; + break; + } + D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum)); + return r; +} + +static void +tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data) +{ + int regnum; + + regnum = req & 0x1f; + D(printf("%s reg[%d] = %x\n", __func__, regnum, data)); + switch (regnum) { + default: + phy->regs[regnum] = data; + break; + } +} + +static void +tdk_init(struct qemu_phy *phy) +{ + phy->regs[0] = 0x3100; + /* PHY Id. */ + phy->regs[2] = 0x0300; + phy->regs[3] = 0xe400; + /* Autonegotiation advertisement reg. */ + phy->regs[4] = 0x01E1; + + phy->read = tdk_read; + phy->write = tdk_write; +} + +struct qemu_mdio +{ + /* bus. */ + int mdc; + int mdio; + + /* decoder. */ + enum { + PREAMBLE, + SOF, + OPC, + ADDR, + REQ, + TURNAROUND, + DATA + } state; + unsigned int drive; + + unsigned int cnt; + unsigned int addr; + unsigned int opc; + unsigned int req; + unsigned int data; + + struct qemu_phy *devs[32]; +}; + +static void +mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr) +{ + bus->devs[addr & 0x1f] = phy; +} + +#ifdef USE_THIS_DEAD_CODE +static void +mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr) +{ + bus->devs[addr & 0x1f] = NULL; +} +#endif + +static void mdio_read_req(struct qemu_mdio *bus) +{ + struct qemu_phy *phy; + + phy = bus->devs[bus->addr]; + if (phy && phy->read) + bus->data = phy->read(phy, bus->req); + else + bus->data = 0xffff; +} + +static void mdio_write_req(struct qemu_mdio *bus) +{ + struct qemu_phy *phy; + + phy = bus->devs[bus->addr]; + if (phy && phy->write) + phy->write(phy, bus->req, bus->data); +} + +static void mdio_cycle(struct qemu_mdio *bus) +{ + bus->cnt++; + + D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n", + bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive)); +#if 0 + if (bus->mdc) + printf("%d", bus->mdio); +#endif + switch (bus->state) + { + case PREAMBLE: + if (bus->mdc) { + if (bus->cnt >= (32 * 2) && !bus->mdio) { + bus->cnt = 0; + bus->state = SOF; + bus->data = 0; + } + } + break; + case SOF: + if (bus->mdc) { + if (bus->mdio != 1) + printf("WARNING: no SOF\n"); + if (bus->cnt == 1*2) { + bus->cnt = 0; + bus->opc = 0; + bus->state = OPC; + } + } + break; + case OPC: + if (bus->mdc) { + bus->opc <<= 1; + bus->opc |= bus->mdio & 1; + if (bus->cnt == 2*2) { + bus->cnt = 0; + bus->addr = 0; + bus->state = ADDR; + } + } + break; + case ADDR: + if (bus->mdc) { + bus->addr <<= 1; + bus->addr |= bus->mdio & 1; + + if (bus->cnt == 5*2) { + bus->cnt = 0; + bus->req = 0; + bus->state = REQ; + } + } + break; + case REQ: + if (bus->mdc) { + bus->req <<= 1; + bus->req |= bus->mdio & 1; + if (bus->cnt == 5*2) { + bus->cnt = 0; + bus->state = TURNAROUND; + } + } + break; + case TURNAROUND: + if (bus->mdc && bus->cnt == 2*2) { + bus->mdio = 0; + bus->cnt = 0; + + if (bus->opc == 2) { + bus->drive = 1; + mdio_read_req(bus); + bus->mdio = bus->data & 1; + } + bus->state = DATA; + } + break; + case DATA: + if (!bus->mdc) { + if (bus->drive) { + bus->mdio = !!(bus->data & (1 << 15)); + bus->data <<= 1; + } + } else { + if (!bus->drive) { + bus->data <<= 1; + bus->data |= bus->mdio; + } + if (bus->cnt == 16 * 2) { + bus->cnt = 0; + bus->state = PREAMBLE; + if (!bus->drive) + mdio_write_req(bus); + bus->drive = 0; + } + } + break; + default: + break; + } +} + +/* ETRAX-FS Ethernet MAC block starts here. */ + +#define RW_MA0_LO 0x00 +#define RW_MA0_HI 0x04 +#define RW_MA1_LO 0x08 +#define RW_MA1_HI 0x0c +#define RW_GA_LO 0x10 +#define RW_GA_HI 0x14 +#define RW_GEN_CTRL 0x18 +#define RW_REC_CTRL 0x1c +#define RW_TR_CTRL 0x20 +#define RW_CLR_ERR 0x24 +#define RW_MGM_CTRL 0x28 +#define R_STAT 0x2c +#define FS_ETH_MAX_REGS 0x5c + +struct fs_eth +{ + CPUState *env; + qemu_irq *irq; + target_phys_addr_t base; + VLANClientState *vc; + int ethregs; + + /* Two addrs in the filter. */ + uint8_t macaddr[2][6]; + uint32_t regs[FS_ETH_MAX_REGS]; + + struct etraxfs_dma_client *dma_out; + struct etraxfs_dma_client *dma_in; + + /* MDIO bus. */ + struct qemu_mdio mdio_bus; + unsigned int phyaddr; + int duplex_mismatch; + + /* PHY. */ + struct qemu_phy phy; +}; + +static void eth_validate_duplex(struct fs_eth *eth) +{ + struct qemu_phy *phy; + unsigned int phy_duplex; + unsigned int mac_duplex; + int new_mm = 0; + + phy = eth->mdio_bus.devs[eth->phyaddr]; + phy_duplex = !!(phy->read(phy, 18) & (1 << 11)); + mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128); + + if (mac_duplex != phy_duplex) + new_mm = 1; + + if (eth->regs[RW_GEN_CTRL] & 1) { + if (new_mm != eth->duplex_mismatch) { + if (new_mm) + printf("HW: WARNING " + "ETH duplex mismatch MAC=%d PHY=%d\n", + mac_duplex, phy_duplex); + else + printf("HW: ETH duplex ok.\n"); + } + eth->duplex_mismatch = new_mm; + } +} + +static uint32_t eth_rinvalid (void *opaque, target_phys_addr_t addr) +{ + struct fs_eth *eth = opaque; + CPUState *env = eth->env; + cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n", + addr); + return 0; +} + +static uint32_t eth_readl (void *opaque, target_phys_addr_t addr) +{ + struct fs_eth *eth = opaque; + uint32_t r = 0; + + /* Make addr relative to this instances base. */ + addr -= eth->base; + switch (addr) { + case R_STAT: + /* Attach an MDIO/PHY abstraction. */ + r = eth->mdio_bus.mdio & 1; + break; + default: + r = eth->regs[addr]; + D(printf ("%s %x\n", __func__, addr)); + break; + } + return r; +} + +static void +eth_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + struct fs_eth *eth = opaque; + CPUState *env = eth->env; + cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n", + addr); +} + +static void eth_update_ma(struct fs_eth *eth, int ma) +{ + int reg; + int i = 0; + + ma &= 1; + + reg = RW_MA0_LO; + if (ma) + reg = RW_MA1_LO; + + eth->macaddr[ma][i++] = eth->regs[reg]; + eth->macaddr[ma][i++] = eth->regs[reg] >> 8; + eth->macaddr[ma][i++] = eth->regs[reg] >> 16; + eth->macaddr[ma][i++] = eth->regs[reg] >> 24; + eth->macaddr[ma][i++] = eth->regs[reg + 4]; + eth->macaddr[ma][i++] = eth->regs[reg + 4] >> 8; + + D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma, + eth->macaddr[ma][0], eth->macaddr[ma][1], + eth->macaddr[ma][2], eth->macaddr[ma][3], + eth->macaddr[ma][4], eth->macaddr[ma][5])); +} + +static void +eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + struct fs_eth *eth = opaque; + + /* Make addr relative to this instances base. */ + addr -= eth->base; + switch (addr) + { + case RW_MA0_LO: + eth->regs[addr] = value; + eth_update_ma(eth, 0); + break; + case RW_MA0_HI: + eth->regs[addr] = value; + eth_update_ma(eth, 0); + break; + case RW_MA1_LO: + eth->regs[addr] = value; + eth_update_ma(eth, 1); + break; + case RW_MA1_HI: + eth->regs[addr] = value; + eth_update_ma(eth, 1); + break; + + case RW_MGM_CTRL: + /* Attach an MDIO/PHY abstraction. */ + if (value & 2) + eth->mdio_bus.mdio = value & 1; + if (eth->mdio_bus.mdc != (value & 4)) { + mdio_cycle(ð->mdio_bus); + eth_validate_duplex(eth); + } + eth->mdio_bus.mdc = !!(value & 4); + break; + + case RW_REC_CTRL: + eth->regs[addr] = value; + eth_validate_duplex(eth); + break; + + default: + eth->regs[addr] = value; + D(printf ("%s %x %x\n", + __func__, addr, value)); + break; + } +} + +/* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom + filter dropping group addresses we have not joined. The filter has 64 + bits (m). The has function is a simple nible xor of the group addr. */ +static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa) +{ + unsigned int hsh; + int m_individual = eth->regs[RW_REC_CTRL] & 4; + int match; + + /* First bit on the wire of a MAC address signals multicast or + physical address. */ + if (!m_individual && !sa[0] & 1) + return 0; + + /* Calculate the hash index for the GA registers. */ + hsh = 0; + hsh ^= (*sa) & 0x3f; + hsh ^= ((*sa) >> 6) & 0x03; + ++sa; + hsh ^= ((*sa) << 2) & 0x03c; + hsh ^= ((*sa) >> 4) & 0xf; + ++sa; + hsh ^= ((*sa) << 4) & 0x30; + hsh ^= ((*sa) >> 2) & 0x3f; + ++sa; + hsh ^= (*sa) & 0x3f; + hsh ^= ((*sa) >> 6) & 0x03; + ++sa; + hsh ^= ((*sa) << 2) & 0x03c; + hsh ^= ((*sa) >> 4) & 0xf; + ++sa; + hsh ^= ((*sa) << 4) & 0x30; + hsh ^= ((*sa) >> 2) & 0x3f; + + hsh &= 63; + if (hsh > 31) + match = eth->regs[RW_GA_HI] & (1 << (hsh - 32)); + else + match = eth->regs[RW_GA_LO] & (1 << hsh); + D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh, + eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match)); + return match; +} + +static int eth_can_receive(void *opaque) +{ + return 1; +} + +static void eth_receive(void *opaque, const uint8_t *buf, int size) +{ + unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + struct fs_eth *eth = opaque; + int use_ma0 = eth->regs[RW_REC_CTRL] & 1; + int use_ma1 = eth->regs[RW_REC_CTRL] & 2; + int r_bcast = eth->regs[RW_REC_CTRL] & 8; + + if (size < 12) + return; + + D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], + use_ma0, use_ma1, r_bcast)); + + /* Does the frame get through the address filters? */ + if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6)) + && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6)) + && (!r_bcast || memcmp(buf, sa_bcast, 6)) + && !eth_match_groupaddr(eth, buf)) + return; + + /* FIXME: Find another way to pass on the fake csum. */ + etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1); +} + +static int eth_tx_push(void *opaque, unsigned char *buf, int len) +{ + struct fs_eth *eth = opaque; + + D(printf("%s buf=%p len=%d\n", __func__, buf, len)); + qemu_send_packet(eth->vc, buf, len); + return len; +} + +static CPUReadMemoryFunc *eth_read[] = { + ð_rinvalid, + ð_rinvalid, + ð_readl, +}; + +static CPUWriteMemoryFunc *eth_write[] = { + ð_winvalid, + ð_winvalid, + ð_writel, +}; + +void *etraxfs_eth_init(NICInfo *nd, CPUState *env, + qemu_irq *irq, target_phys_addr_t base) +{ + struct etraxfs_dma_client *dma = NULL; + struct fs_eth *eth = NULL; + + dma = qemu_mallocz(sizeof *dma * 2); + if (!dma) + return NULL; + + eth = qemu_mallocz(sizeof *eth); + if (!eth) + goto err; + + dma[0].client.push = eth_tx_push; + dma[0].client.opaque = eth; + dma[1].client.opaque = eth; + dma[1].client.pull = NULL; + + eth->env = env; + eth->base = base; + eth->irq = irq; + eth->dma_out = dma; + eth->dma_in = dma + 1; + + /* Connect the phy. */ + eth->phyaddr = 1; + tdk_init(ð->phy); + mdio_attach(ð->mdio_bus, ð->phy, eth->phyaddr); + + eth->ethregs = cpu_register_io_memory(0, eth_read, eth_write, eth); + cpu_register_physical_memory (base, 0x5c, eth->ethregs); + + eth->vc = qemu_new_vlan_client(nd->vlan, + eth_receive, eth_can_receive, eth); + + return dma; + err: + qemu_free(eth); + qemu_free(dma); + return NULL; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/etraxfs.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/etraxfs.h --- qemu-0.9.1/hw/etraxfs.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/etraxfs.h 2008-06-10 00:33:30.000000000 +0100 @@ -0,0 +1,42 @@ +/* + * QEMU ETRAX System Emulator + * + * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB. + * + * 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 "etraxfs_dma.h" + +struct etraxfs_pic +{ + qemu_irq *irq; + qemu_irq *nmi; + qemu_irq *guru; + + void *internal; +}; + +struct etraxfs_pic *etraxfs_pic_init(CPUState *env, target_phys_addr_t base); +void etraxfs_timer_init(CPUState *env, qemu_irq *irqs, qemu_irq *nmi, + target_phys_addr_t base); +void *etraxfs_eth_init(NICInfo *nd, CPUState *env, + qemu_irq *irq, target_phys_addr_t base); +void etraxfs_ser_init(CPUState *env, qemu_irq *irq, CharDriverState *chr, + target_phys_addr_t base); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/etraxfs_pic.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/etraxfs_pic.c --- qemu-0.9.1/hw/etraxfs_pic.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/etraxfs_pic.c 2008-06-10 00:33:30.000000000 +0100 @@ -0,0 +1,243 @@ +/* + * QEMU ETRAX Interrupt Controller. + * + * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB. + * + * 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 +#include "hw.h" +#include "etraxfs.h" + +#define D(x) + +struct fs_pic_state_t +{ + CPUState *env; + target_phys_addr_t base; + + uint32_t rw_mask; + /* Active interrupt lines. */ + uint32_t r_vect; + /* Active lines, gated through the mask. */ + uint32_t r_masked_vect; + uint32_t r_nmi; + uint32_t r_guru; +}; + +static uint32_t pic_readb (void *opaque, target_phys_addr_t addr) +{ + return 0; +} +static uint32_t pic_readw (void *opaque, target_phys_addr_t addr) +{ + return 0; +} + +static uint32_t pic_readl (void *opaque, target_phys_addr_t addr) +{ + struct fs_pic_state_t *fs = opaque; + uint32_t rval; + + /* Transform this to a relative addr. */ + addr -= fs->base; + switch (addr) + { + case 0x0: + rval = fs->rw_mask; + break; + case 0x4: + rval = fs->r_vect; + break; + case 0x8: + rval = fs->r_masked_vect; + break; + case 0xc: + rval = fs->r_nmi; + break; + case 0x10: + rval = fs->r_guru; + break; + default: + cpu_abort(fs->env, "invalid PIC register.\n"); + break; + + } + D(printf("%s %x=%x\n", __func__, addr, rval)); + return rval; +} + +static void +pic_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +{ +} + +static void +pic_writew (void *opaque, target_phys_addr_t addr, uint32_t value) +{ +} + +static void +pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + struct fs_pic_state_t *fs = opaque; + D(printf("%s addr=%x val=%x\n", __func__, addr, value)); + /* Transform this to a relative addr. */ + addr -= fs->base; + switch (addr) + { + case 0x0: + fs->rw_mask = value; + break; + case 0x4: + fs->r_vect = value; + break; + case 0x8: + fs->r_masked_vect = value; + break; + case 0xc: + fs->r_nmi = value; + break; + case 0x10: + fs->r_guru = value; + break; + default: + cpu_abort(fs->env, "invalid PIC register.\n"); + break; + } +} + +static CPUReadMemoryFunc *pic_read[] = { + &pic_readb, + &pic_readw, + &pic_readl, +}; + +static CPUWriteMemoryFunc *pic_write[] = { + &pic_writeb, + &pic_writew, + &pic_writel, +}; + +void pic_info(void) +{ +} + +void irq_info(void) +{ +} + +static void irq_handler(void *opaque, int irq, int level) +{ + struct fs_pic_state_t *fs = (void *)opaque; + CPUState *env = fs->env; + int i; + uint32_t vector = 0; + + D(printf("%s irq=%d level=%d mask=%x v=%x mv=%x\n", + __func__, irq, level, + fs->rw_mask, fs->r_vect, fs->r_masked_vect)); + + irq -= 1; + fs->r_vect &= ~(1 << irq); + fs->r_vect |= (!!level << irq); + fs->r_masked_vect = fs->r_vect & fs->rw_mask; + + /* The ETRAX interrupt controller signals interrupts to teh core + through an interrupt request wire and an irq vector bus. If + multiple interrupts are simultaneously active it chooses vector + 0x30 and lets the sw choose the priorities. */ + if (fs->r_masked_vect) { + uint32_t mv = fs->r_masked_vect; + for (i = 0; i < 31; i++) { + if (mv & 1) { + vector = 0x31 + i; + /* Check for multiple interrupts. */ + if (mv > 1) + vector = 0x30; + break; + } + mv >>= 1; + } + if (vector) { + env->interrupt_vector = vector; + D(printf("%s vector=%x\n", __func__, vector)); + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } + } else { + env->interrupt_vector = 0; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + D(printf("%s reset irqs\n", __func__)); + } +} + +static void nmi_handler(void *opaque, int irq, int level) +{ + struct fs_pic_state_t *fs = (void *)opaque; + CPUState *env = fs->env; + uint32_t mask; + + mask = 1 << irq; + if (level) + fs->r_nmi |= mask; + else + fs->r_nmi &= ~mask; + + if (fs->r_nmi) + cpu_interrupt(env, CPU_INTERRUPT_NMI); + else + cpu_reset_interrupt(env, CPU_INTERRUPT_NMI); +} + +static void guru_handler(void *opaque, int irq, int level) +{ + struct fs_pic_state_t *fs = (void *)opaque; + CPUState *env = fs->env; + cpu_abort(env, "%s unsupported exception\n", __func__); + +} + + +struct etraxfs_pic *etraxfs_pic_init(CPUState *env, target_phys_addr_t base) +{ + struct fs_pic_state_t *fs = NULL; + struct etraxfs_pic *pic = NULL; + int intr_vect_regs; + + pic = qemu_mallocz(sizeof *pic); + pic->internal = fs = qemu_mallocz(sizeof *fs); + if (!fs || !pic) + goto err; + + fs->env = env; + pic->irq = qemu_allocate_irqs(irq_handler, fs, 30); + pic->nmi = qemu_allocate_irqs(nmi_handler, fs, 2); + pic->guru = qemu_allocate_irqs(guru_handler, fs, 1); + + intr_vect_regs = cpu_register_io_memory(0, pic_read, pic_write, fs); + cpu_register_physical_memory(base, 0x14, intr_vect_regs); + fs->base = base; + + return pic; + err: + free(pic); + free(fs); + return NULL; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/etraxfs_ser.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/etraxfs_ser.c --- qemu-0.9.1/hw/etraxfs_ser.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/etraxfs_ser.c 2008-06-30 12:51:12.000000000 +0100 @@ -25,43 +25,114 @@ #include #include #include "hw.h" +#include "qemu-char.h" -#define RW_TR_DMA_EN 0xb0026004 -#define RW_DOUT 0xb002601c -#define RW_STAT_DIN 0xb0026020 -#define R_STAT_DIN 0xb0026024 +#define D(x) -static uint32_t ser_readb (void *opaque, target_phys_addr_t addr) +#define RW_TR_CTRL 0x00 +#define RW_TR_DMA_EN 0x04 +#define RW_REC_CTRL 0x08 +#define RW_DOUT 0x1c +#define RS_STAT_DIN 0x20 +#define R_STAT_DIN 0x24 +#define RW_INTR_MASK 0x2c +#define RW_ACK_INTR 0x30 +#define R_INTR 0x34 +#define R_MASKED_INTR 0x38 + +#define STAT_DAV 16 +#define STAT_TR_IDLE 22 +#define STAT_TR_RDY 24 + +struct etrax_serial_t +{ + CPUState *env; + CharDriverState *chr; + qemu_irq *irq; + + target_phys_addr_t base; + + int pending_tx; + + /* Control registers. */ + uint32_t rw_tr_ctrl; + uint32_t rw_tr_dma_en; + uint32_t rw_rec_ctrl; + uint32_t rs_stat_din; + uint32_t r_stat_din; + uint32_t rw_intr_mask; + uint32_t rw_ack_intr; + uint32_t r_intr; + uint32_t r_masked_intr; +}; + +static void ser_update_irq(struct etrax_serial_t *s) { - CPUState *env = opaque; - uint32_t r = 0; - printf ("%s %x pc=%x\n", __func__, addr, env->pc); - return r; + uint32_t o_irq = s->r_masked_intr; + + s->r_intr &= ~(s->rw_ack_intr); + s->r_masked_intr = s->r_intr & s->rw_intr_mask; + + if (o_irq != s->r_masked_intr) { + D(printf("irq_mask=%x r_intr=%x rmi=%x airq=%x \n", + s->rw_intr_mask, s->r_intr, + s->r_masked_intr, s->rw_ack_intr)); + if (s->r_masked_intr) + qemu_irq_raise(s->irq[0]); + else + qemu_irq_lower(s->irq[0]); + } + s->rw_ack_intr = 0; } -static uint32_t ser_readw (void *opaque, target_phys_addr_t addr) + + +static uint32_t ser_readb (void *opaque, target_phys_addr_t addr) { - CPUState *env = opaque; - uint32_t r = 0; - printf ("%s %x pc=%x\n", __func__, addr, env->pc); - return r; + D(CPUState *env = opaque); + D(printf ("%s %x\n", __func__, addr)); + return 0; } static uint32_t ser_readl (void *opaque, target_phys_addr_t addr) { - CPUState *env = opaque; + struct etrax_serial_t *s = opaque; + D(CPUState *env = s->env); uint32_t r = 0; - switch (addr) + switch (addr & 0xfff) { + case RW_TR_CTRL: + r = s->rw_tr_ctrl; + break; case RW_TR_DMA_EN: + r = s->rw_tr_dma_en; + break; + case RS_STAT_DIN: + r = s->rs_stat_din; + /* clear dav. */ + s->rs_stat_din &= ~(1 << STAT_DAV); break; case R_STAT_DIN: - r |= 1 << 24; /* set tr_rdy. */ - r |= 1 << 22; /* set tr_idle. */ + r = s->rs_stat_din; + break; + case RW_ACK_INTR: + D(printf("load rw_ack_intr=%x\n", s->rw_ack_intr)); + r = s->rw_ack_intr; + break; + case RW_INTR_MASK: + r = s->rw_intr_mask; + break; + case R_INTR: + D(printf("load r_intr=%x\n", s->r_intr)); + r = s->r_intr; + break; + case R_MASKED_INTR: + D(printf("load r_maked_intr=%x\n", s->r_masked_intr)); + r = s->r_masked_intr; break; default: - printf ("%s %x p=%x\n", __func__, addr, env->pc); + D(printf ("%s %x\n", __func__, addr)); break; } return r; @@ -70,53 +141,116 @@ static void ser_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { - CPUState *env = opaque; - printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); -} -static void -ser_writew (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - CPUState *env = opaque; - printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); + D(struct etrax_serial_t *s = opaque); + D(CPUState *env = s->env); + D(printf ("%s %x %x\n", __func__, addr, value)); } static void ser_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { - CPUState *env = opaque; + struct etrax_serial_t *s = opaque; + unsigned char ch = value; + D(CPUState *env = s->env); - switch (addr) + switch (addr & 0xfff) { + case RW_TR_CTRL: + D(printf("rw_tr_ctrl=%x\n", value)); + s->rw_tr_ctrl = value; + break; case RW_TR_DMA_EN: + D(printf("rw_tr_dma_en=%x\n", value)); + s->rw_tr_dma_en = value; break; case RW_DOUT: - if (isprint(value) || isspace(value)) - putchar(value); - else - putchar('.'); + qemu_chr_write(s->chr, &ch, 1); + s->r_intr |= 1; + s->pending_tx = 1; + break; + case RW_ACK_INTR: + D(printf("rw_ack_intr=%x\n", value)); + s->rw_ack_intr = value; + if (s->pending_tx && (s->rw_ack_intr & 1)) { + s->r_intr |= 1; + s->pending_tx = 0; + s->rw_ack_intr &= ~1; + } + break; + case RW_INTR_MASK: + D(printf("r_intr_mask=%x\n", value)); + s->rw_intr_mask = value; break; default: - printf ("%s %x %x pc=%x\n", - __func__, addr, value, env->pc); + D(printf ("%s %x %x\n", __func__, addr, value)); break; } + ser_update_irq(s); } static CPUReadMemoryFunc *ser_read[] = { - &ser_readb, - &ser_readw, - &ser_readl, + &ser_readb, + &ser_readb, + &ser_readl, }; static CPUWriteMemoryFunc *ser_write[] = { - &ser_writeb, - &ser_writew, - &ser_writel, + &ser_writeb, + &ser_writeb, + &ser_writel, }; -void etraxfs_ser_init(CPUState *env, qemu_irq *irqs) +static void serial_receive(void *opaque, const uint8_t *buf, int size) { + struct etrax_serial_t *s = opaque; + + s->r_intr |= 8; + s->rs_stat_din &= ~0xff; + s->rs_stat_din |= (buf[0] & 0xff); + s->rs_stat_din |= (1 << STAT_DAV); /* dav. */ + ser_update_irq(s); +} + +static int serial_can_receive(void *opaque) +{ + struct etrax_serial_t *s = opaque; + int r; + + /* Is the receiver enabled? */ + r = s->rw_rec_ctrl & 1; + + /* Pending rx data? */ + r |= !(s->r_intr & 8); + return r; +} + +static void serial_event(void *opaque, int event) +{ + +} + +void etraxfs_ser_init(CPUState *env, qemu_irq *irq, CharDriverState *chr, + target_phys_addr_t base) +{ + struct etrax_serial_t *s; int ser_regs; - ser_regs = cpu_register_io_memory(0, ser_read, ser_write, env); - cpu_register_physical_memory (0xb0026000, 0x3c, ser_regs); + s = qemu_mallocz(sizeof *s); + if (!s) + return; + + s->env = env; + s->irq = irq; + s->base = base; + + s->chr = chr; + + /* transmitter begins ready and idle. */ + s->rs_stat_din |= (1 << STAT_TR_RDY); + s->rs_stat_din |= (1 << STAT_TR_IDLE); + + qemu_chr_add_handlers(chr, serial_can_receive, serial_receive, + serial_event, s); + + ser_regs = cpu_register_io_memory(0, ser_read, ser_write, s); + cpu_register_physical_memory (base, 0x3c, ser_regs); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/etraxfs_timer.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/etraxfs_timer.c --- qemu-0.9.1/hw/etraxfs_timer.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/etraxfs_timer.c 2008-06-30 12:51:12.000000000 +0100 @@ -1,5 +1,5 @@ /* - * QEMU ETRAX System Emulator + * QEMU ETRAX Timers * * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB. * @@ -24,162 +24,166 @@ #include #include #include "hw.h" +#include "sysemu.h" #include "qemu-timer.h" -void etrax_ack_irq(CPUState *env, uint32_t mask); +#define D(x) -#define R_TIME 0xb001e038 -#define RW_TMR0_DIV 0xb001e000 -#define R_TMR0_DATA 0xb001e004 -#define RW_TMR0_CTRL 0xb001e008 -#define RW_TMR1_DIV 0xb001e010 -#define R_TMR1_DATA 0xb001e014 -#define RW_TMR1_CTRL 0xb001e018 - -#define RW_INTR_MASK 0xb001e048 -#define RW_ACK_INTR 0xb001e04c -#define R_INTR 0xb001e050 -#define R_MASKED_INTR 0xb001e054 - - -uint32_t rw_intr_mask; -uint32_t rw_ack_intr; -uint32_t r_intr; +#define RW_TMR0_DIV 0x00 +#define R_TMR0_DATA 0x04 +#define RW_TMR0_CTRL 0x08 +#define RW_TMR1_DIV 0x10 +#define R_TMR1_DATA 0x14 +#define RW_TMR1_CTRL 0x18 +#define R_TIME 0x38 +#define RW_WD_CTRL 0x40 +#define R_WD_STAT 0x44 +#define RW_INTR_MASK 0x48 +#define RW_ACK_INTR 0x4c +#define R_INTR 0x50 +#define R_MASKED_INTR 0x54 struct fs_timer_t { - QEMUBH *bh; - unsigned int limit; - int scale; - ptimer_state *ptimer; CPUState *env; qemu_irq *irq; - uint32_t mask; -}; - -static struct fs_timer_t timer0; - -/* diff two timevals. Return a single int in us. */ -int diff_timeval_us(struct timeval *a, struct timeval *b) -{ - int diff; + qemu_irq *nmi; + target_phys_addr_t base; - /* assume these values are signed. */ - diff = (a->tv_sec - b->tv_sec) * 1000 * 1000; - diff += (a->tv_usec - b->tv_usec); - return diff; -} + QEMUBH *bh_t0; + QEMUBH *bh_t1; + QEMUBH *bh_wd; + ptimer_state *ptimer_t0; + ptimer_state *ptimer_t1; + ptimer_state *ptimer_wd; + struct timeval last; + + int wd_hits; + + /* Control registers. */ + uint32_t rw_tmr0_div; + uint32_t r_tmr0_data; + uint32_t rw_tmr0_ctrl; + + uint32_t rw_tmr1_div; + uint32_t r_tmr1_data; + uint32_t rw_tmr1_ctrl; + + uint32_t rw_wd_ctrl; + + uint32_t rw_intr_mask; + uint32_t rw_ack_intr; + uint32_t r_intr; + uint32_t r_masked_intr; +}; -static uint32_t timer_readb (void *opaque, target_phys_addr_t addr) +static uint32_t timer_rinvalid (void *opaque, target_phys_addr_t addr) { - CPUState *env = opaque; - uint32_t r = 0; - printf ("%s %x pc=%x\n", __func__, addr, env->pc); - return r; -} -static uint32_t timer_readw (void *opaque, target_phys_addr_t addr) -{ - CPUState *env = opaque; - uint32_t r = 0; - printf ("%s %x pc=%x\n", __func__, addr, env->pc); - return r; + struct fs_timer_t *t = opaque; + CPUState *env = t->env; + cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n", + addr); + return 0; } static uint32_t timer_readl (void *opaque, target_phys_addr_t addr) { - CPUState *env = opaque; + struct fs_timer_t *t = opaque; uint32_t r = 0; + /* Make addr relative to this instances base. */ + addr -= t->base; switch (addr) { case R_TMR0_DATA: break; case R_TMR1_DATA: - printf ("R_TMR1_DATA\n"); + D(printf ("R_TMR1_DATA\n")); break; case R_TIME: - { - static struct timeval last; - struct timeval now; - gettimeofday(&now, NULL); - if (!(last.tv_sec == 0 && last.tv_usec == 0)) { - r = diff_timeval_us(&now, &last); - r *= 1000; /* convert to ns. */ - r++; /* make sure we increase for each call. */ - } - last = now; + r = qemu_get_clock(vm_clock) * 10; break; - } - case RW_INTR_MASK: - r = rw_intr_mask; + r = t->rw_intr_mask; break; case R_MASKED_INTR: - r = r_intr & rw_intr_mask; + r = t->r_intr & t->rw_intr_mask; break; default: - printf ("%s %x p=%x\n", __func__, addr, env->pc); + D(printf ("%s %x\n", __func__, addr)); break; } return r; } static void -timer_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +timer_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value) { - CPUState *env = opaque; - printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); -} -static void -timer_writew (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - CPUState *env = opaque; - printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); -} + struct fs_timer_t *t = opaque; + CPUState *env = t->env; + cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n", + addr); +} + +#define TIMER_SLOWDOWN 1 +static void update_ctrl(struct fs_timer_t *t, int tnum) +{ + unsigned int op; + unsigned int freq; + unsigned int freq_hz; + unsigned int div; + uint32_t ctrl; + + ptimer_state *timer; + + if (tnum == 0) { + ctrl = t->rw_tmr0_ctrl; + div = t->rw_tmr0_div; + timer = t->ptimer_t0; + } else { + ctrl = t->rw_tmr1_ctrl; + div = t->rw_tmr1_div; + timer = t->ptimer_t1; + } -static void write_ctrl(struct fs_timer_t *t, uint32_t v) -{ - int op; - int freq; - int freq_hz; - op = v & 3; - freq = v >> 2; + op = ctrl & 3; + freq = ctrl >> 2; freq_hz = 32000000; switch (freq) { case 0: case 1: - printf ("extern or disabled timer clock?\n"); + D(printf ("extern or disabled timer clock?\n")); break; case 4: freq_hz = 29493000; break; case 5: freq_hz = 32000000; break; case 6: freq_hz = 32768000; break; - case 7: freq_hz = 100000000; break; + case 7: freq_hz = 100001000; break; default: abort(); break; } - printf ("freq_hz=%d limit=%d\n", freq_hz, t->limit); - t->scale = 0; - if (t->limit > 2048) - { - t->scale = 2048; - ptimer_set_period(timer0.ptimer, freq_hz / t->scale); - } + D(printf ("freq_hz=%d div=%d\n", freq_hz, div)); + div = div * TIMER_SLOWDOWN; + div >>= 10; + freq_hz >>= 10; + ptimer_set_freq(timer, freq_hz); + ptimer_set_limit(timer, div, 0); - printf ("op=%d\n", op); switch (op) { case 0: - printf ("limit=%d %d\n", t->limit, t->limit/t->scale); - ptimer_set_limit(t->ptimer, t->limit / t->scale, 1); + /* Load. */ + ptimer_set_limit(timer, div, 1); break; case 1: - ptimer_stop(t->ptimer); + /* Hold. */ + ptimer_stop(timer); break; case 2: - ptimer_run(t->ptimer, 0); + /* Run. */ + ptimer_run(timer, 0); break; default: abort(); @@ -187,83 +191,176 @@ } } -static void timer_ack_irq(void) +static void timer_update_irq(struct fs_timer_t *t) { - if (!(r_intr & timer0.mask & rw_intr_mask)) { - qemu_irq_lower(timer0.irq[0]); - etrax_ack_irq(timer0.env, 1 << 0x1b); + t->r_intr &= ~(t->rw_ack_intr); + t->r_masked_intr = t->r_intr & t->rw_intr_mask; + + D(printf("%s: masked_intr=%x\n", __func__, t->r_masked_intr)); + if (t->r_masked_intr) + qemu_irq_raise(t->irq[0]); + else + qemu_irq_lower(t->irq[0]); +} + +static void timer0_hit(void *opaque) +{ + struct fs_timer_t *t = opaque; + t->r_intr |= 1; + timer_update_irq(t); +} + +static void timer1_hit(void *opaque) +{ + struct fs_timer_t *t = opaque; + t->r_intr |= 2; + timer_update_irq(t); +} + +static void watchdog_hit(void *opaque) +{ + struct fs_timer_t *t = opaque; + if (t->wd_hits == 0) { + /* real hw gives a single tick before reseting but we are + a bit friendlier to compensate for our slower execution. */ + ptimer_set_count(t->ptimer_wd, 10); + ptimer_run(t->ptimer_wd, 1); + qemu_irq_raise(t->nmi[0]); } + else + qemu_system_reset_request(); + + t->wd_hits++; +} + +static inline void timer_watchdog_update(struct fs_timer_t *t, uint32_t value) +{ + unsigned int wd_en = t->rw_wd_ctrl & (1 << 8); + unsigned int wd_key = t->rw_wd_ctrl >> 9; + unsigned int wd_cnt = t->rw_wd_ctrl & 511; + unsigned int new_key = value >> 9 & ((1 << 7) - 1); + unsigned int new_cmd = (value >> 8) & 1; + + /* If the watchdog is enabled, they written key must match the + complement of the previous. */ + wd_key = ~wd_key & ((1 << 7) - 1); + + if (wd_en && wd_key != new_key) + return; + + D(printf("en=%d new_key=%x oldkey=%x cmd=%d cnt=%d\n", + wd_en, new_key, wd_key, new_cmd, wd_cnt)); + + if (t->wd_hits) + qemu_irq_lower(t->nmi[0]); + + t->wd_hits = 0; + + ptimer_set_freq(t->ptimer_wd, 760); + if (wd_cnt == 0) + wd_cnt = 256; + ptimer_set_count(t->ptimer_wd, wd_cnt); + if (new_cmd) + ptimer_run(t->ptimer_wd, 1); + else + ptimer_stop(t->ptimer_wd); + + t->rw_wd_ctrl = value; } static void timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { - CPUState *env = opaque; - printf ("%s %x %x pc=%x\n", - __func__, addr, value, env->pc); + struct fs_timer_t *t = opaque; + + /* Make addr relative to this instances base. */ + addr -= t->base; switch (addr) { case RW_TMR0_DIV: - printf ("RW_TMR0_DIV=%x\n", value); - timer0.limit = value; + t->rw_tmr0_div = value; break; case RW_TMR0_CTRL: - printf ("RW_TMR0_CTRL=%x\n", value); - write_ctrl(&timer0, value); + D(printf ("RW_TMR0_CTRL=%x\n", value)); + t->rw_tmr0_ctrl = value; + update_ctrl(t, 0); break; case RW_TMR1_DIV: - printf ("RW_TMR1_DIV=%x\n", value); + t->rw_tmr1_div = value; break; case RW_TMR1_CTRL: - printf ("RW_TMR1_CTRL=%x\n", value); + D(printf ("RW_TMR1_CTRL=%x\n", value)); + t->rw_tmr1_ctrl = value; + update_ctrl(t, 1); break; case RW_INTR_MASK: - printf ("RW_INTR_MASK=%x\n", value); - rw_intr_mask = value; + D(printf ("RW_INTR_MASK=%x\n", value)); + t->rw_intr_mask = value; + timer_update_irq(t); + break; + case RW_WD_CTRL: + timer_watchdog_update(t, value); break; case RW_ACK_INTR: - r_intr &= ~value; - timer_ack_irq(); + t->rw_ack_intr = value; + timer_update_irq(t); + t->rw_ack_intr = 0; break; default: - printf ("%s %x %x pc=%x\n", - __func__, addr, value, env->pc); + printf ("%s " TARGET_FMT_plx " %x\n", + __func__, addr, value); break; } } static CPUReadMemoryFunc *timer_read[] = { - &timer_readb, - &timer_readw, - &timer_readl, + &timer_rinvalid, + &timer_rinvalid, + &timer_readl, }; static CPUWriteMemoryFunc *timer_write[] = { - &timer_writeb, - &timer_writew, - &timer_writel, + &timer_winvalid, + &timer_winvalid, + &timer_writel, }; -static void timer_irq(void *opaque) +static void etraxfs_timer_reset(void *opaque) { struct fs_timer_t *t = opaque; - r_intr |= t->mask; - if (t->mask & rw_intr_mask) { - qemu_irq_raise(t->irq[0]); - } + ptimer_stop(t->ptimer_t0); + ptimer_stop(t->ptimer_t1); + ptimer_stop(t->ptimer_wd); + t->rw_wd_ctrl = 0; + t->r_intr = 0; + t->rw_intr_mask = 0; + qemu_irq_lower(t->irq[0]); } -void etraxfs_timer_init(CPUState *env, qemu_irq *irqs) +void etraxfs_timer_init(CPUState *env, qemu_irq *irqs, qemu_irq *nmi, + target_phys_addr_t base) { + static struct fs_timer_t *t; int timer_regs; - timer0.bh = qemu_bh_new(timer_irq, &timer0); - timer0.ptimer = ptimer_init(timer0.bh); - timer0.irq = irqs + 0x1b; - timer0.mask = 1; - timer0.env = env; + t = qemu_mallocz(sizeof *t); + if (!t) + return; + + t->bh_t0 = qemu_bh_new(timer0_hit, t); + t->bh_t1 = qemu_bh_new(timer1_hit, t); + t->bh_wd = qemu_bh_new(watchdog_hit, t); + t->ptimer_t0 = ptimer_init(t->bh_t0); + t->ptimer_t1 = ptimer_init(t->bh_t1); + t->ptimer_wd = ptimer_init(t->bh_wd); + t->irq = irqs; + t->nmi = nmi; + t->env = env; + t->base = base; + + timer_regs = cpu_register_io_memory(0, timer_read, timer_write, t); + cpu_register_physical_memory (base, 0x5c, timer_regs); - timer_regs = cpu_register_io_memory(0, timer_read, timer_write, env); - cpu_register_physical_memory (0xb001e000, 0x5c, timer_regs); + qemu_register_reset(etraxfs_timer_reset, t); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/fdc.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/fdc.c --- qemu-0.9.1/hw/fdc.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/fdc.c 2008-05-01 20:05:12.000000000 +0100 @@ -2,6 +2,7 @@ * QEMU Floppy disk emulator (Intel 82078) * * Copyright (c) 2003, 2007 Jocelyn Mayer + * Copyright (c) 2008 Hervé Poussineau * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -48,6 +49,9 @@ /********************************************************/ /* Floppy drive emulation */ +#define GET_CUR_DRV(fdctrl) ((fdctrl)->cur_drv) +#define SET_CUR_DRV(fdctrl, drive) ((fdctrl)->cur_drv = (drive)) + /* Will always be a fixed parameter for us */ #define FD_SECTOR_LEN 512 #define FD_SECTOR_SC 2 /* Sector size code */ @@ -68,10 +72,6 @@ FDRIVE_DRV_NONE = 0x03, /* No drive connected */ } fdrive_type_t; -typedef enum fdrive_flags_t { - FDRIVE_MOTOR_ON = 0x01, /* motor on/off */ -} fdrive_flags_t; - typedef enum fdisk_flags_t { FDISK_DBL_SIDES = 0x01, } fdisk_flags_t; @@ -80,15 +80,11 @@ BlockDriverState *bs; /* Drive status */ fdrive_type_t drive; - fdrive_flags_t drflags; uint8_t perpendicular; /* 2.88 MB access mode */ /* Position */ uint8_t head; uint8_t track; uint8_t sect; - /* Last operation status */ - uint8_t dir; /* Direction */ - uint8_t rw; /* Read/write */ /* Media */ fdisk_flags_t flags; uint8_t last_sect; /* Nb sector per track */ @@ -102,7 +98,6 @@ /* Drive */ drv->bs = bs; drv->drive = FDRIVE_DRV_NONE; - drv->drflags = 0; drv->perpendicular = 0; /* Disk */ drv->last_sect = 0; @@ -121,6 +116,13 @@ return _fd_sector(drv->head, drv->track, drv->sect, drv->last_sect); } +/* Seek to a new position: + * returns 0 if already on right track + * returns 1 if track changed + * returns 2 if track is invalid + * returns 3 if sector is invalid + * returns 4 if seek is disabled + */ static int fd_seek (fdrive_t *drv, uint8_t head, uint8_t track, uint8_t sect, int enable_seek) { @@ -169,8 +171,6 @@ drv->head = 0; drv->track = 0; drv->sect = 1; - drv->dir = 1; - drv->rw = 0; } /* Recognize floppy formats */ @@ -295,24 +295,6 @@ } } -/* Motor control */ -static void fd_start (fdrive_t *drv) -{ - drv->drflags |= FDRIVE_MOTOR_ON; -} - -static void fd_stop (fdrive_t *drv) -{ - drv->drflags &= ~FDRIVE_MOTOR_ON; -} - -/* Re-initialise a drives (motor off, repositioned) */ -static void fd_reset (fdrive_t *drv) -{ - fd_stop(drv); - fd_recalibrate(drv); -} - /********************************************************/ /* Intel 82078 floppy disk controller emulation */ @@ -320,9 +302,9 @@ static void fdctrl_reset_fifo (fdctrl_t *fdctrl); static int fdctrl_transfer_handler (void *opaque, int nchan, int dma_pos, int dma_len); -static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status); -static void fdctrl_result_timer(void *opaque); +static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status0); +static uint32_t fdctrl_read_statusA (fdctrl_t *fdctrl); static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl); static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl); static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value); @@ -335,14 +317,6 @@ static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl); enum { - FD_CTRL_ACTIVE = 0x01, /* XXX: suppress that */ - FD_CTRL_RESET = 0x02, - FD_CTRL_SLEEP = 0x04, /* XXX: suppress that */ - FD_CTRL_BUSY = 0x08, /* dma transfer in progress */ - FD_CTRL_INTR = 0x10, -}; - -enum { FD_DIR_WRITE = 0, FD_DIR_READ = 1, FD_DIR_SCANE = 2, @@ -351,24 +325,148 @@ }; enum { - FD_STATE_CMD = 0x00, - FD_STATE_STATUS = 0x01, - FD_STATE_DATA = 0x02, - FD_STATE_STATE = 0x03, - FD_STATE_MULTI = 0x10, - FD_STATE_SEEK = 0x20, - FD_STATE_FORMAT = 0x40, + FD_STATE_MULTI = 0x01, /* multi track flag */ + FD_STATE_FORMAT = 0x02, /* format flag */ + FD_STATE_SEEK = 0x04, /* seek flag */ +}; + +enum { + FD_REG_SRA = 0x00, + FD_REG_SRB = 0x01, + FD_REG_DOR = 0x02, + FD_REG_TDR = 0x03, + FD_REG_MSR = 0x04, + FD_REG_DSR = 0x04, + FD_REG_FIFO = 0x05, + FD_REG_DIR = 0x07, +}; + +enum { + FD_CMD_READ_TRACK = 0x02, + FD_CMD_SPECIFY = 0x03, + FD_CMD_SENSE_DRIVE_STATUS = 0x04, + FD_CMD_WRITE = 0x05, + FD_CMD_READ = 0x06, + FD_CMD_RECALIBRATE = 0x07, + FD_CMD_SENSE_INTERRUPT_STATUS = 0x08, + FD_CMD_WRITE_DELETED = 0x09, + FD_CMD_READ_ID = 0x0a, + FD_CMD_READ_DELETED = 0x0c, + FD_CMD_FORMAT_TRACK = 0x0d, + FD_CMD_DUMPREG = 0x0e, + FD_CMD_SEEK = 0x0f, + FD_CMD_VERSION = 0x10, + FD_CMD_SCAN_EQUAL = 0x11, + FD_CMD_PERPENDICULAR_MODE = 0x12, + FD_CMD_CONFIGURE = 0x13, + FD_CMD_LOCK = 0x14, + FD_CMD_VERIFY = 0x16, + FD_CMD_POWERDOWN_MODE = 0x17, + FD_CMD_PART_ID = 0x18, + FD_CMD_SCAN_LOW_OR_EQUAL = 0x19, + FD_CMD_SCAN_HIGH_OR_EQUAL = 0x1d, + FD_CMD_SAVE = 0x2c, + FD_CMD_OPTION = 0x33, + FD_CMD_RESTORE = 0x4c, + FD_CMD_DRIVE_SPECIFICATION_COMMAND = 0x8e, + FD_CMD_RELATIVE_SEEK_OUT = 0x8f, + FD_CMD_FORMAT_AND_WRITE = 0xcd, + FD_CMD_RELATIVE_SEEK_IN = 0xcf, +}; + +enum { + FD_CONFIG_PRETRK = 0xff, /* Pre-compensation set to track 0 */ + FD_CONFIG_FIFOTHR = 0x0f, /* FIFO threshold set to 1 byte */ + FD_CONFIG_POLL = 0x10, /* Poll enabled */ + FD_CONFIG_EFIFO = 0x20, /* FIFO disabled */ + FD_CONFIG_EIS = 0x40, /* No implied seeks */ +}; + +enum { + FD_SR0_EQPMT = 0x10, + FD_SR0_SEEK = 0x20, + FD_SR0_ABNTERM = 0x40, + FD_SR0_INVCMD = 0x80, + FD_SR0_RDYCHG = 0xc0, +}; + +enum { + FD_SR1_EC = 0x80, /* End of cylinder */ +}; + +enum { + FD_SR2_SNS = 0x04, /* Scan not satisfied */ + FD_SR2_SEH = 0x08, /* Scan equal hit */ +}; + +enum { + FD_SRA_DIR = 0x01, + FD_SRA_nWP = 0x02, + FD_SRA_nINDX = 0x04, + FD_SRA_HDSEL = 0x08, + FD_SRA_nTRK0 = 0x10, + FD_SRA_STEP = 0x20, + FD_SRA_nDRV2 = 0x40, + FD_SRA_INTPEND = 0x80, +}; + +enum { + FD_SRB_MTR0 = 0x01, + FD_SRB_MTR1 = 0x02, + FD_SRB_WGATE = 0x04, + FD_SRB_RDATA = 0x08, + FD_SRB_WDATA = 0x10, + FD_SRB_DR0 = 0x20, +}; + +enum { +#if MAX_FD == 4 + FD_DOR_SELMASK = 0x03, +#else + FD_DOR_SELMASK = 0x01, +#endif + FD_DOR_nRESET = 0x04, + FD_DOR_DMAEN = 0x08, + FD_DOR_MOTEN0 = 0x10, + FD_DOR_MOTEN1 = 0x20, + FD_DOR_MOTEN2 = 0x40, + FD_DOR_MOTEN3 = 0x80, +}; + +enum { +#if MAX_FD == 4 + FD_TDR_BOOTSEL = 0x0c, +#else + FD_TDR_BOOTSEL = 0x04, +#endif +}; + +enum { + FD_DSR_DRATEMASK= 0x03, + FD_DSR_PWRDOWN = 0x40, + FD_DSR_SWRESET = 0x80, +}; + +enum { + FD_MSR_DRV0BUSY = 0x01, + FD_MSR_DRV1BUSY = 0x02, + FD_MSR_DRV2BUSY = 0x04, + FD_MSR_DRV3BUSY = 0x08, + FD_MSR_CMDBUSY = 0x10, + FD_MSR_NONDMA = 0x20, + FD_MSR_DIO = 0x40, + FD_MSR_RQM = 0x80, +}; + +enum { + FD_DIR_DSKCHG = 0x80, }; -#define FD_STATE(state) ((state) & FD_STATE_STATE) -#define FD_SET_STATE(state, new_state) \ -do { (state) = ((state) & ~FD_STATE_STATE) | (new_state); } while (0) #define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI) #define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK) #define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT) struct fdctrl_t { - fdctrl_t *fdctrl; /* Controller's identification */ uint8_t version; /* HW */ @@ -377,17 +475,22 @@ target_phys_addr_t io_base; /* Controller state */ QEMUTimer *result_timer; - uint8_t state; - uint8_t dma_en; + uint8_t sra; + uint8_t srb; + uint8_t dor; + uint8_t tdr; + uint8_t dsr; + uint8_t msr; uint8_t cur_drv; - uint8_t bootsel; + uint8_t status0; + uint8_t status1; + uint8_t status2; /* Command FIFO */ uint8_t *fifo; uint32_t data_pos; uint32_t data_len; uint8_t data_state; uint8_t data_dir; - uint8_t int_status; uint8_t eot; /* last wanted sector */ /* States kept only to be returned back */ /* Timers state */ @@ -402,7 +505,7 @@ /* Sun4m quirks? */ int sun4m; /* Floppy drives */ - fdrive_t drives[2]; + fdrive_t drives[MAX_FD]; }; static uint32_t fdctrl_read (void *opaque, uint32_t reg) @@ -411,30 +514,25 @@ uint32_t retval; switch (reg & 0x07) { - case 0x00: - if (fdctrl->sun4m) { - // Identify to Linux as S82078B - retval = fdctrl_read_statusB(fdctrl); - } else { - retval = (uint32_t)(-1); - } + case FD_REG_SRA: + retval = fdctrl_read_statusA(fdctrl); break; - case 0x01: + case FD_REG_SRB: retval = fdctrl_read_statusB(fdctrl); break; - case 0x02: + case FD_REG_DOR: retval = fdctrl_read_dor(fdctrl); break; - case 0x03: + case FD_REG_TDR: retval = fdctrl_read_tape(fdctrl); break; - case 0x04: + case FD_REG_MSR: retval = fdctrl_read_main_status(fdctrl); break; - case 0x05: + case FD_REG_FIFO: retval = fdctrl_read_data(fdctrl); break; - case 0x07: + case FD_REG_DIR: retval = fdctrl_read_dir(fdctrl); break; default: @@ -453,16 +551,16 @@ FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value); switch (reg & 0x07) { - case 0x02: + case FD_REG_DOR: fdctrl_write_dor(fdctrl, value); break; - case 0x03: + case FD_REG_TDR: fdctrl_write_tape(fdctrl, value); break; - case 0x04: + case FD_REG_DSR: fdctrl_write_rate(fdctrl, value); break; - case 0x05: + case FD_REG_FIFO: fdctrl_write_data(fdctrl, value); break; default: @@ -507,53 +605,54 @@ static void fd_save (QEMUFile *f, fdrive_t *fd) { - uint8_t tmp; - - tmp = fd->drflags; - qemu_put_8s(f, &tmp); qemu_put_8s(f, &fd->head); qemu_put_8s(f, &fd->track); qemu_put_8s(f, &fd->sect); - qemu_put_8s(f, &fd->dir); - qemu_put_8s(f, &fd->rw); } static void fdc_save (QEMUFile *f, void *opaque) { fdctrl_t *s = opaque; + uint8_t tmp; + int i; + uint8_t dor = s->dor | GET_CUR_DRV(s); - qemu_put_8s(f, &s->state); - qemu_put_8s(f, &s->dma_en); - qemu_put_8s(f, &s->cur_drv); - qemu_put_8s(f, &s->bootsel); + /* Controller state */ + qemu_put_8s(f, &s->sra); + qemu_put_8s(f, &s->srb); + qemu_put_8s(f, &dor); + qemu_put_8s(f, &s->tdr); + qemu_put_8s(f, &s->dsr); + qemu_put_8s(f, &s->msr); + qemu_put_8s(f, &s->status0); + qemu_put_8s(f, &s->status1); + qemu_put_8s(f, &s->status2); + /* Command FIFO */ qemu_put_buffer(f, s->fifo, FD_SECTOR_LEN); qemu_put_be32s(f, &s->data_pos); qemu_put_be32s(f, &s->data_len); qemu_put_8s(f, &s->data_state); qemu_put_8s(f, &s->data_dir); - qemu_put_8s(f, &s->int_status); qemu_put_8s(f, &s->eot); + /* States kept only to be returned back */ qemu_put_8s(f, &s->timer0); qemu_put_8s(f, &s->timer1); qemu_put_8s(f, &s->precomp_trk); qemu_put_8s(f, &s->config); qemu_put_8s(f, &s->lock); qemu_put_8s(f, &s->pwrd); - fd_save(f, &s->drives[0]); - fd_save(f, &s->drives[1]); + + tmp = MAX_FD; + qemu_put_8s(f, &tmp); + for (i = 0; i < MAX_FD; i++) + fd_save(f, &s->drives[i]); } static int fd_load (QEMUFile *f, fdrive_t *fd) { - uint8_t tmp; - - qemu_get_8s(f, &tmp); - fd->drflags = tmp; qemu_get_8s(f, &fd->head); qemu_get_8s(f, &fd->track); qemu_get_8s(f, &fd->sect); - qemu_get_8s(f, &fd->dir); - qemu_get_8s(f, &fd->rw); return 0; } @@ -561,32 +660,48 @@ static int fdc_load (QEMUFile *f, void *opaque, int version_id) { fdctrl_t *s = opaque; - int ret; + int i, ret = 0; + uint8_t n; - if (version_id != 1) + if (version_id != 2) return -EINVAL; - qemu_get_8s(f, &s->state); - qemu_get_8s(f, &s->dma_en); - qemu_get_8s(f, &s->cur_drv); - qemu_get_8s(f, &s->bootsel); + /* Controller state */ + qemu_get_8s(f, &s->sra); + qemu_get_8s(f, &s->srb); + qemu_get_8s(f, &s->dor); + SET_CUR_DRV(s, s->dor & FD_DOR_SELMASK); + s->dor &= ~FD_DOR_SELMASK; + qemu_get_8s(f, &s->tdr); + qemu_get_8s(f, &s->dsr); + qemu_get_8s(f, &s->msr); + qemu_get_8s(f, &s->status0); + qemu_get_8s(f, &s->status1); + qemu_get_8s(f, &s->status2); + /* Command FIFO */ qemu_get_buffer(f, s->fifo, FD_SECTOR_LEN); qemu_get_be32s(f, &s->data_pos); qemu_get_be32s(f, &s->data_len); qemu_get_8s(f, &s->data_state); qemu_get_8s(f, &s->data_dir); - qemu_get_8s(f, &s->int_status); qemu_get_8s(f, &s->eot); + /* States kept only to be returned back */ qemu_get_8s(f, &s->timer0); qemu_get_8s(f, &s->timer1); qemu_get_8s(f, &s->precomp_trk); qemu_get_8s(f, &s->config); qemu_get_8s(f, &s->lock); qemu_get_8s(f, &s->pwrd); + qemu_get_8s(f, &n); + + if (n > MAX_FD) + return -EINVAL; - ret = fd_load(f, &s->drives[0]); - if (ret == 0) - ret = fd_load(f, &s->drives[1]); + for (i = 0; i < n; i++) { + ret = fd_load(f, &s->drives[i]); + if (ret != 0) + break; + } return ret; } @@ -598,92 +713,14 @@ fdctrl_reset(s, 0); } -static fdctrl_t *fdctrl_init_common (qemu_irq irq, int dma_chann, - target_phys_addr_t io_base, - BlockDriverState **fds) -{ - fdctrl_t *fdctrl; - int i; - - FLOPPY_DPRINTF("init controller\n"); - fdctrl = qemu_mallocz(sizeof(fdctrl_t)); - if (!fdctrl) - return NULL; - fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN); - if (fdctrl->fifo == NULL) { - qemu_free(fdctrl); - return NULL; - } - fdctrl->result_timer = qemu_new_timer(vm_clock, - fdctrl_result_timer, fdctrl); - - fdctrl->version = 0x90; /* Intel 82078 controller */ - fdctrl->irq = irq; - fdctrl->dma_chann = dma_chann; - fdctrl->io_base = io_base; - 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); - } else { - fdctrl->dma_en = 0; - } - for (i = 0; i < 2; i++) { - fd_init(&fdctrl->drives[i], fds[i]); - } - fdctrl_reset(fdctrl, 0); - fdctrl->state = FD_CTRL_ACTIVE; - register_savevm("fdc", io_base, 1, fdc_save, fdc_load, fdctrl); - qemu_register_reset(fdctrl_external_reset, fdctrl); - for (i = 0; i < 2; i++) { - fd_revalidate(&fdctrl->drives[i]); - } - - return fdctrl; -} - -fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, - target_phys_addr_t io_base, - BlockDriverState **fds) +static void fdctrl_handle_tc(void *opaque, int irq, int level) { - fdctrl_t *fdctrl; - int io_mem; - - fdctrl = fdctrl_init_common(irq, dma_chann, io_base, fds); + //fdctrl_t *s = opaque; - fdctrl->sun4m = 0; - if (mem_mapped) { - io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, - fdctrl); - cpu_register_physical_memory(io_base, 0x08, io_mem); - } else { - register_ioport_read((uint32_t)io_base + 0x01, 5, 1, &fdctrl_read, - fdctrl); - register_ioport_read((uint32_t)io_base + 0x07, 1, 1, &fdctrl_read, - fdctrl); - register_ioport_write((uint32_t)io_base + 0x01, 5, 1, &fdctrl_write, - fdctrl); - register_ioport_write((uint32_t)io_base + 0x07, 1, 1, &fdctrl_write, - fdctrl); + if (level) { + // XXX + FLOPPY_DPRINTF("TC pulsed\n"); } - - return fdctrl; -} - -fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base, - BlockDriverState **fds) -{ - fdctrl_t *fdctrl; - int io_mem; - - fdctrl = fdctrl_init_common(irq, 0, io_base, fds); - fdctrl->sun4m = 1; - io_mem = cpu_register_io_memory(0, fdctrl_mem_read_strict, - fdctrl_mem_write_strict, - fdctrl); - cpu_register_physical_memory(io_base, 0x08, io_mem); - - return fdctrl; } /* XXX: may change if moved to bdrv */ @@ -695,25 +732,29 @@ /* Change IRQ state */ static void fdctrl_reset_irq (fdctrl_t *fdctrl) { + if (!(fdctrl->sra & FD_SRA_INTPEND)) + return; FLOPPY_DPRINTF("Reset interrupt\n"); qemu_set_irq(fdctrl->irq, 0); - fdctrl->state &= ~FD_CTRL_INTR; + fdctrl->sra &= ~FD_SRA_INTPEND; } -static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status) +static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status0) { - // Sparc mutation - if (fdctrl->sun4m && !fdctrl->dma_en) { - fdctrl->state &= ~FD_CTRL_BUSY; - fdctrl->int_status = status; + /* Sparc mutation */ + if (fdctrl->sun4m && (fdctrl->msr & FD_MSR_CMDBUSY)) { + /* XXX: not sure */ + fdctrl->msr &= ~FD_MSR_CMDBUSY; + fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO; + fdctrl->status0 = status0; return; } - if (~(fdctrl->state & FD_CTRL_INTR)) { + if (!(fdctrl->sra & FD_SRA_INTPEND)) { qemu_set_irq(fdctrl->irq, 1); - fdctrl->state |= FD_CTRL_INTR; + fdctrl->sra |= FD_SRA_INTPEND; } - FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", status); - fdctrl->int_status = status; + fdctrl->status0 = status0; + FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", fdctrl->status0); } /* Reset controller */ @@ -724,55 +765,96 @@ FLOPPY_DPRINTF("reset controller\n"); fdctrl_reset_irq(fdctrl); /* Initialise controller */ + fdctrl->sra = 0; + fdctrl->srb = 0xc0; + if (!fdctrl->drives[1].bs) + fdctrl->sra |= FD_SRA_nDRV2; fdctrl->cur_drv = 0; + fdctrl->dor = FD_DOR_nRESET; + fdctrl->dor |= (fdctrl->dma_chann != -1) ? FD_DOR_DMAEN : 0; + fdctrl->msr = FD_MSR_RQM; /* FIFO state */ fdctrl->data_pos = 0; fdctrl->data_len = 0; - fdctrl->data_state = FD_STATE_CMD; + fdctrl->data_state = 0; fdctrl->data_dir = FD_DIR_WRITE; for (i = 0; i < MAX_FD; i++) - fd_reset(&fdctrl->drives[i]); + fd_recalibrate(&fdctrl->drives[i]); fdctrl_reset_fifo(fdctrl); - if (do_irq) - fdctrl_raise_irq(fdctrl, 0xc0); + if (do_irq) { + fdctrl_raise_irq(fdctrl, FD_SR0_RDYCHG); + } } static inline fdrive_t *drv0 (fdctrl_t *fdctrl) { - return &fdctrl->drives[fdctrl->bootsel]; + return &fdctrl->drives[(fdctrl->tdr & FD_TDR_BOOTSEL) >> 2]; } static inline fdrive_t *drv1 (fdctrl_t *fdctrl) { - return &fdctrl->drives[1 - fdctrl->bootsel]; + if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (1 << 2)) + return &fdctrl->drives[1]; + else + return &fdctrl->drives[0]; +} + +#if MAX_FD == 4 +static inline fdrive_t *drv2 (fdctrl_t *fdctrl) +{ + if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (2 << 2)) + return &fdctrl->drives[2]; + else + return &fdctrl->drives[1]; +} + +static inline fdrive_t *drv3 (fdctrl_t *fdctrl) +{ + if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (3 << 2)) + return &fdctrl->drives[3]; + else + return &fdctrl->drives[2]; } +#endif static fdrive_t *get_cur_drv (fdctrl_t *fdctrl) { - return fdctrl->cur_drv == 0 ? drv0(fdctrl) : drv1(fdctrl); + switch (fdctrl->cur_drv) { + case 0: return drv0(fdctrl); + case 1: return drv1(fdctrl); +#if MAX_FD == 4 + case 2: return drv2(fdctrl); + case 3: return drv3(fdctrl); +#endif + default: return NULL; + } +} + +/* Status A register : 0x00 (read-only) */ +static uint32_t fdctrl_read_statusA (fdctrl_t *fdctrl) +{ + uint32_t retval = fdctrl->sra; + + FLOPPY_DPRINTF("status register A: 0x%02x\n", retval); + + return retval; } /* Status B register : 0x01 (read-only) */ static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl) { - FLOPPY_DPRINTF("status register: 0x00\n"); - return 0; + uint32_t retval = fdctrl->srb; + + FLOPPY_DPRINTF("status register B: 0x%02x\n", retval); + + return retval; } /* Digital output register : 0x02 */ static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl) { - uint32_t retval = 0; + uint32_t retval = fdctrl->dor; - /* Drive motors state indicators */ - if (drv0(fdctrl)->drflags & FDRIVE_MOTOR_ON) - retval |= 1 << 5; - if (drv1(fdctrl)->drflags & FDRIVE_MOTOR_ON) - retval |= 1 << 4; - /* DMA enable */ - retval |= fdctrl->dma_en << 3; - /* Reset indicator */ - retval |= (fdctrl->state & FD_CTRL_RESET) == 0 ? 0x04 : 0; /* Selected drive */ retval |= fdctrl->cur_drv; FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval); @@ -782,53 +864,47 @@ static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value) { - /* Reset mode */ - if (fdctrl->state & FD_CTRL_RESET) { - if (!(value & 0x04)) { - FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); - return; - } - } FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value); - /* Drive motors state indicators */ - if (value & 0x20) - fd_start(drv1(fdctrl)); + + /* Motors */ + if (value & FD_DOR_MOTEN0) + fdctrl->srb |= FD_SRB_MTR0; else - fd_stop(drv1(fdctrl)); - if (value & 0x10) - fd_start(drv0(fdctrl)); + fdctrl->srb &= ~FD_SRB_MTR0; + if (value & FD_DOR_MOTEN1) + fdctrl->srb |= FD_SRB_MTR1; else - fd_stop(drv0(fdctrl)); - /* DMA enable */ -#if 0 - if (fdctrl->dma_chann != -1) - fdctrl->dma_en = 1 - ((value >> 3) & 1); -#endif + fdctrl->srb &= ~FD_SRB_MTR1; + + /* Drive */ + if (value & 1) + fdctrl->srb |= FD_SRB_DR0; + else + fdctrl->srb &= ~FD_SRB_DR0; + /* Reset */ - if (!(value & 0x04)) { - if (!(fdctrl->state & FD_CTRL_RESET)) { + if (!(value & FD_DOR_nRESET)) { + if (fdctrl->dor & FD_DOR_nRESET) { FLOPPY_DPRINTF("controller enter RESET state\n"); - fdctrl->state |= FD_CTRL_RESET; } } else { - if (fdctrl->state & FD_CTRL_RESET) { + if (!(fdctrl->dor & FD_DOR_nRESET)) { FLOPPY_DPRINTF("controller out of RESET state\n"); fdctrl_reset(fdctrl, 1); - fdctrl->state &= ~(FD_CTRL_RESET | FD_CTRL_SLEEP); + fdctrl->dsr &= ~FD_DSR_PWRDOWN; } } /* Selected drive */ - fdctrl->cur_drv = value & 1; + fdctrl->cur_drv = value & FD_DOR_SELMASK; + + fdctrl->dor = value; } /* Tape drive register : 0x03 */ static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl) { - uint32_t retval = 0; + uint32_t retval = fdctrl->tdr; - /* Disk boot selection indicator */ - retval |= fdctrl->bootsel << 2; - /* Tape indicators: never allowed */ FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval); return retval; @@ -837,34 +913,24 @@ static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value) { /* Reset mode */ - if (fdctrl->state & FD_CTRL_RESET) { + if (!(fdctrl->dor & FD_DOR_nRESET)) { FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); return; } FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value); /* Disk boot selection indicator */ - fdctrl->bootsel = (value >> 2) & 1; + fdctrl->tdr = value & FD_TDR_BOOTSEL; /* Tape indicators: never allow */ } /* Main status register : 0x04 (read) */ static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl) { - uint32_t retval = 0; + uint32_t retval = fdctrl->msr; + + fdctrl->dsr &= ~FD_DSR_PWRDOWN; + fdctrl->dor |= FD_DOR_nRESET; - fdctrl->state &= ~(FD_CTRL_SLEEP | FD_CTRL_RESET); - if (!(fdctrl->state & FD_CTRL_BUSY)) { - /* Data transfer allowed */ - retval |= 0x80; - /* Data transfer direction indicator */ - if (fdctrl->data_dir == FD_DIR_READ) - retval |= 0x40; - } - /* Should handle 0x20 for SPECIFY command */ - /* Command busy indicator */ - if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA || - FD_STATE(fdctrl->data_state) == FD_STATE_STATUS) - retval |= 0x10; FLOPPY_DPRINTF("main status register: 0x%02x\n", retval); return retval; @@ -874,22 +940,21 @@ static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value) { /* Reset mode */ - if (fdctrl->state & FD_CTRL_RESET) { + if (!(fdctrl->dor & FD_DOR_nRESET)) { FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); return; } FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value); /* Reset: autoclear */ - if (value & 0x80) { - fdctrl->state |= FD_CTRL_RESET; + if (value & FD_DSR_SWRESET) { + fdctrl->dor &= ~FD_DOR_nRESET; fdctrl_reset(fdctrl, 1); - fdctrl->state &= ~FD_CTRL_RESET; + fdctrl->dor |= FD_DOR_nRESET; } - if (value & 0x40) { - fdctrl->state |= FD_CTRL_SLEEP; + if (value & FD_DSR_PWRDOWN) { fdctrl_reset(fdctrl, 1); } -// fdctrl.precomp = (value >> 2) & 0x07; + fdctrl->dsr = value; } static int fdctrl_media_changed(fdrive_t *drv) @@ -910,9 +975,14 @@ { uint32_t retval = 0; - if (fdctrl_media_changed(drv0(fdctrl)) || - fdctrl_media_changed(drv1(fdctrl))) - retval |= 0x80; + if (fdctrl_media_changed(drv0(fdctrl)) + || fdctrl_media_changed(drv1(fdctrl)) +#if MAX_FD == 4 + || fdctrl_media_changed(drv2(fdctrl)) + || fdctrl_media_changed(drv3(fdctrl)) +#endif + ) + retval |= FD_DIR_DSKCHG; if (retval != 0) FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval); @@ -924,7 +994,7 @@ { fdctrl->data_dir = FD_DIR_WRITE; fdctrl->data_pos = 0; - FD_SET_STATE(fdctrl->data_state, FD_STATE_CMD); + fdctrl->msr &= ~(FD_MSR_CMDBUSY | FD_MSR_DIO); } /* Set FIFO status for the host to read */ @@ -933,27 +1003,51 @@ fdctrl->data_dir = FD_DIR_READ; fdctrl->data_len = fifo_len; fdctrl->data_pos = 0; - FD_SET_STATE(fdctrl->data_state, FD_STATE_STATUS); + fdctrl->msr |= FD_MSR_CMDBUSY | FD_MSR_RQM | FD_MSR_DIO; if (do_irq) fdctrl_raise_irq(fdctrl, 0x00); } /* Set an error: unimplemented/unknown command */ -static void fdctrl_unimplemented (fdctrl_t *fdctrl) +static void fdctrl_unimplemented (fdctrl_t *fdctrl, int direction) { -#if 0 - fdrive_t *cur_drv; - - cur_drv = get_cur_drv(fdctrl); - fdctrl->fifo[0] = 0x60 | (cur_drv->head << 2) | fdctrl->cur_drv; - fdctrl->fifo[1] = 0x00; - fdctrl->fifo[2] = 0x00; - fdctrl_set_fifo(fdctrl, 3, 1); -#else - // fdctrl_reset_fifo(fdctrl); - fdctrl->fifo[0] = 0x80; + FLOPPY_ERROR("unimplemented command 0x%02x\n", fdctrl->fifo[0]); + fdctrl->fifo[0] = FD_SR0_INVCMD; fdctrl_set_fifo(fdctrl, 1, 0); -#endif +} + +/* Seek to next sector */ +static int fdctrl_seek_to_next_sect (fdctrl_t *fdctrl, fdrive_t *cur_drv) +{ + FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d)\n", + cur_drv->head, cur_drv->track, cur_drv->sect, + fd_sector(cur_drv)); + /* XXX: cur_drv->sect >= cur_drv->last_sect should be an + error in fact */ + if (cur_drv->sect >= cur_drv->last_sect || + cur_drv->sect == fdctrl->eot) { + cur_drv->sect = 1; + if (FD_MULTI_TRACK(fdctrl->data_state)) { + if (cur_drv->head == 0 && + (cur_drv->flags & FDISK_DBL_SIDES) != 0) { + cur_drv->head = 1; + } else { + cur_drv->head = 0; + cur_drv->track++; + if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) + return 0; + } + } else { + cur_drv->track++; + return 0; + } + FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n", + cur_drv->head, cur_drv->track, + cur_drv->sect, fd_sector(cur_drv)); + } else { + cur_drv->sect++; + } + return 1; } /* Callback for transfer end (stop or abort) */ @@ -965,8 +1059,8 @@ cur_drv = get_cur_drv(fdctrl); FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n", status0, status1, status2, - status0 | (cur_drv->head << 2) | fdctrl->cur_drv); - fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | fdctrl->cur_drv; + status0 | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl)); + fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl); fdctrl->fifo[1] = status1; fdctrl->fifo[2] = status2; fdctrl->fifo[3] = cur_drv->track; @@ -974,10 +1068,11 @@ fdctrl->fifo[5] = cur_drv->sect; fdctrl->fifo[6] = FD_SECTOR_SC; fdctrl->data_dir = FD_DIR_READ; - if (fdctrl->state & FD_CTRL_BUSY) { + if (!(fdctrl->msr & FD_MSR_NONDMA)) { DMA_release_DREQ(fdctrl->dma_chann); - fdctrl->state &= ~FD_CTRL_BUSY; } + fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO; + fdctrl->msr &= ~FD_MSR_NONDMA; fdctrl_set_fifo(fdctrl, 7, 1); } @@ -986,35 +1081,34 @@ { fdrive_t *cur_drv; uint8_t kh, kt, ks; - int did_seek; + int did_seek = 0; - fdctrl->cur_drv = fdctrl->fifo[1] & 1; + SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK); cur_drv = get_cur_drv(fdctrl); kt = fdctrl->fifo[2]; kh = fdctrl->fifo[3]; ks = fdctrl->fifo[4]; FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n", - fdctrl->cur_drv, kh, kt, ks, + GET_CUR_DRV(fdctrl), kh, kt, ks, _fd_sector(kh, kt, ks, cur_drv->last_sect)); - did_seek = 0; - switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) { + switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) { case 2: /* sect too big */ - fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00); fdctrl->fifo[3] = kt; fdctrl->fifo[4] = kh; fdctrl->fifo[5] = ks; return; case 3: /* track too big */ - fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00); + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00); fdctrl->fifo[3] = kt; fdctrl->fifo[4] = kh; fdctrl->fifo[5] = ks; return; case 4: /* No seek enabled */ - fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00); fdctrl->fifo[3] = kt; fdctrl->fifo[4] = kh; fdctrl->fifo[5] = ks; @@ -1025,10 +1119,11 @@ default: break; } + /* Set the FIFO state */ fdctrl->data_dir = direction; fdctrl->data_pos = 0; - FD_SET_STATE(fdctrl->data_state, FD_STATE_DATA); /* FIFO ready for data */ + fdctrl->msr |= FD_MSR_CMDBUSY; if (fdctrl->fifo[0] & 0x80) fdctrl->data_state |= FD_STATE_MULTI; else @@ -1042,13 +1137,13 @@ } else { int tmp; fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]); - tmp = (cur_drv->last_sect - ks + 1); + tmp = (fdctrl->fifo[6] - ks + 1); if (fdctrl->fifo[0] & 0x80) - tmp += cur_drv->last_sect; + tmp += fdctrl->fifo[6]; fdctrl->data_len *= tmp; } fdctrl->eot = fdctrl->fifo[6]; - if (fdctrl->dma_en) { + if (fdctrl->dor & FD_DOR_DMAEN) { int dma_mode; /* DMA transfer are enabled. Check if DMA channel is well programmed */ dma_mode = DMA_get_channel_mode(fdctrl->dma_chann); @@ -1062,7 +1157,7 @@ (direction == FD_DIR_WRITE && dma_mode == 2) || (direction == FD_DIR_READ && dma_mode == 1)) { /* No access is allowed until DMA transfer has completed */ - fdctrl->state |= FD_CTRL_BUSY; + fdctrl->msr &= ~FD_MSR_RQM; /* Now, we just have to wait for the DMA controller to * recall us... */ @@ -1074,6 +1169,9 @@ } } FLOPPY_DPRINTF("start non-DMA transfer\n"); + fdctrl->msr |= FD_MSR_NONDMA; + if (direction != FD_DIR_WRITE) + fdctrl->msr |= FD_MSR_DIO; /* IO based transfer: calculate len */ fdctrl_raise_irq(fdctrl, 0x00); @@ -1083,10 +1181,12 @@ /* Prepare a transfer of deleted data */ static void fdctrl_start_transfer_del (fdctrl_t *fdctrl, int direction) { + FLOPPY_ERROR("fdctrl_start_transfer_del() unimplemented\n"); + /* We don't handle deleted data, * so we don't return *ANYTHING* */ - fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00); } /* handlers for DMA transfers */ @@ -1099,21 +1199,21 @@ uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00; fdctrl = opaque; - if (!(fdctrl->state & FD_CTRL_BUSY)) { + if (fdctrl->msr & FD_MSR_RQM) { FLOPPY_DPRINTF("Not in DMA transfer mode !\n"); return 0; } cur_drv = get_cur_drv(fdctrl); if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL || fdctrl->data_dir == FD_DIR_SCANH) - status2 = 0x04; + status2 = FD_SR2_SNS; if (dma_len > fdctrl->data_len) dma_len = fdctrl->data_len; if (cur_drv->bs == NULL) { if (fdctrl->data_dir == FD_DIR_WRITE) - fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00); else - fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00); len = 0; goto transfer_error; } @@ -1124,9 +1224,9 @@ len = FD_SECTOR_LEN - rel_pos; FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x " "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos, - fdctrl->data_len, fdctrl->cur_drv, cur_drv->head, + fdctrl->data_len, GET_CUR_DRV(fdctrl), cur_drv->head, cur_drv->track, cur_drv->sect, fd_sector(cur_drv), - fd_sector(cur_drv) * 512); + fd_sector(cur_drv) * FD_SECTOR_LEN); if (fdctrl->data_dir != FD_DIR_WRITE || len < FD_SECTOR_LEN || rel_pos != 0) { /* READ & SCAN commands and realign to a sector for WRITE */ @@ -1150,8 +1250,8 @@ fdctrl->data_pos, len); if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) { - FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv)); - fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); + FLOPPY_ERROR("writing sector %d\n", fd_sector(cur_drv)); + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00); goto transfer_error; } break; @@ -1163,7 +1263,7 @@ DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len); ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len); if (ret == 0) { - status2 = 0x08; + status2 = FD_SR2_SEH; goto end_transfer; } if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) || @@ -1178,35 +1278,8 @@ rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; if (rel_pos == 0) { /* Seek to next sector */ - FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n", - cur_drv->head, cur_drv->track, cur_drv->sect, - fd_sector(cur_drv), - fdctrl->data_pos - len); - /* XXX: cur_drv->sect >= cur_drv->last_sect should be an - error in fact */ - if (cur_drv->sect >= cur_drv->last_sect || - cur_drv->sect == fdctrl->eot) { - cur_drv->sect = 1; - if (FD_MULTI_TRACK(fdctrl->data_state)) { - if (cur_drv->head == 0 && - (cur_drv->flags & FDISK_DBL_SIDES) != 0) { - cur_drv->head = 1; - } else { - cur_drv->head = 0; - cur_drv->track++; - if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) - break; - } - } else { - cur_drv->track++; - break; - } - FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n", - cur_drv->head, cur_drv->track, - cur_drv->sect, fd_sector(cur_drv)); - } else { - cur_drv->sect++; - } + if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) + break; } } end_transfer: @@ -1216,11 +1289,10 @@ if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL || fdctrl->data_dir == FD_DIR_SCANH) - status2 = 0x08; + status2 = FD_SR2_SEH; if (FD_DID_SEEK(fdctrl->data_state)) - status0 |= 0x20; + status0 |= FD_SR0_SEEK; fdctrl->data_len -= len; - // if (fdctrl->data_len == 0) fdctrl_stop_transfer(fdctrl, status0, status1, status2); transfer_error: @@ -1232,22 +1304,30 @@ { fdrive_t *cur_drv; uint32_t retval = 0; - int pos, len; + int pos; cur_drv = get_cur_drv(fdctrl); - fdctrl->state &= ~FD_CTRL_SLEEP; - if (FD_STATE(fdctrl->data_state) == FD_STATE_CMD) { - FLOPPY_ERROR("can't read data in CMD state\n"); + fdctrl->dsr &= ~FD_DSR_PWRDOWN; + if (!(fdctrl->msr & FD_MSR_RQM) || !(fdctrl->msr & FD_MSR_DIO)) { + FLOPPY_ERROR("controller not ready for reading\n"); return 0; } pos = fdctrl->data_pos; - if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) { + if (fdctrl->msr & FD_MSR_NONDMA) { pos %= FD_SECTOR_LEN; if (pos == 0) { - len = fdctrl->data_len - fdctrl->data_pos; - if (len > FD_SECTOR_LEN) - len = FD_SECTOR_LEN; - bdrv_read(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1); + if (fdctrl->data_pos != 0) + if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) { + FLOPPY_DPRINTF("error seeking to next sector %d\n", + fd_sector(cur_drv)); + return 0; + } + if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) { + FLOPPY_DPRINTF("error getting sector %d\n", + fd_sector(cur_drv)); + /* Sure, image size is too small... */ + memset(fdctrl->fifo, 0, FD_SECTOR_LEN); + } } } retval = fdctrl->fifo[pos]; @@ -1256,8 +1336,8 @@ /* Switch from transfer mode to status mode * then from status mode to command mode */ - if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) { - fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00); + if (fdctrl->msr & FD_MSR_NONDMA) { + fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00); } else { fdctrl_reset_fifo(fdctrl); fdctrl_reset_irq(fdctrl); @@ -1272,41 +1352,38 @@ { fdrive_t *cur_drv; uint8_t kh, kt, ks; - int did_seek; - fdctrl->cur_drv = fdctrl->fifo[1] & 1; + SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK); cur_drv = get_cur_drv(fdctrl); kt = fdctrl->fifo[6]; kh = fdctrl->fifo[7]; ks = fdctrl->fifo[8]; FLOPPY_DPRINTF("format sector at %d %d %02x %02x (%d)\n", - fdctrl->cur_drv, kh, kt, ks, + GET_CUR_DRV(fdctrl), kh, kt, ks, _fd_sector(kh, kt, ks, cur_drv->last_sect)); - did_seek = 0; - switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) { + switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) { case 2: /* sect too big */ - fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00); fdctrl->fifo[3] = kt; fdctrl->fifo[4] = kh; fdctrl->fifo[5] = ks; return; case 3: /* track too big */ - fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00); + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00); fdctrl->fifo[3] = kt; fdctrl->fifo[4] = kh; fdctrl->fifo[5] = ks; return; case 4: /* No seek enabled */ - fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00); fdctrl->fifo[3] = kt; fdctrl->fifo[4] = kh; fdctrl->fifo[5] = ks; return; case 1: - did_seek = 1; fdctrl->data_state |= FD_STATE_SEEK; break; default: @@ -1316,13 +1393,13 @@ if (cur_drv->bs == NULL || bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) { FLOPPY_ERROR("formatting sector %d\n", fd_sector(cur_drv)); - fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00); } else { if (cur_drv->sect == cur_drv->last_sect) { fdctrl->data_state &= ~FD_STATE_FORMAT; /* Last sector done */ if (FD_DID_SEEK(fdctrl->data_state)) - fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00); + fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00); else fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); } else { @@ -1333,295 +1410,399 @@ } } -static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) +static void fdctrl_handle_lock (fdctrl_t *fdctrl, int direction) { - fdrive_t *cur_drv; + fdctrl->lock = (fdctrl->fifo[0] & 0x80) ? 1 : 0; + fdctrl->fifo[0] = fdctrl->lock << 4; + fdctrl_set_fifo(fdctrl, 1, fdctrl->lock); +} - cur_drv = get_cur_drv(fdctrl); - /* Reset mode */ - if (fdctrl->state & FD_CTRL_RESET) { - FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); - return; - } - fdctrl->state &= ~FD_CTRL_SLEEP; - if (FD_STATE(fdctrl->data_state) == FD_STATE_STATUS) { - FLOPPY_ERROR("can't write data in status mode\n"); - return; - } - /* Is it write command time ? */ - if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) { - /* FIFO data write */ - fdctrl->fifo[fdctrl->data_pos++] = value; - if (fdctrl->data_pos % FD_SECTOR_LEN == (FD_SECTOR_LEN - 1) || - fdctrl->data_pos == fdctrl->data_len) { - bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1); - } - /* Switch from transfer mode to status mode - * then from status mode to command mode - */ - if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) - fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00); - return; - } - if (fdctrl->data_pos == 0) { - /* Command */ - switch (value & 0x5F) { - case 0x46: - /* READ variants */ - FLOPPY_DPRINTF("READ command\n"); - /* 8 parameters cmd */ - fdctrl->data_len = 9; - goto enqueue; - case 0x4C: - /* READ_DELETED variants */ - FLOPPY_DPRINTF("READ_DELETED command\n"); - /* 8 parameters cmd */ - fdctrl->data_len = 9; - goto enqueue; - case 0x50: - /* SCAN_EQUAL variants */ - FLOPPY_DPRINTF("SCAN_EQUAL command\n"); - /* 8 parameters cmd */ - fdctrl->data_len = 9; - goto enqueue; - case 0x56: - /* VERIFY variants */ - FLOPPY_DPRINTF("VERIFY command\n"); - /* 8 parameters cmd */ - fdctrl->data_len = 9; - goto enqueue; - case 0x59: - /* SCAN_LOW_OR_EQUAL variants */ - FLOPPY_DPRINTF("SCAN_LOW_OR_EQUAL command\n"); - /* 8 parameters cmd */ - fdctrl->data_len = 9; - goto enqueue; - case 0x5D: - /* SCAN_HIGH_OR_EQUAL variants */ - FLOPPY_DPRINTF("SCAN_HIGH_OR_EQUAL command\n"); - /* 8 parameters cmd */ - fdctrl->data_len = 9; - goto enqueue; - default: - break; - } - switch (value & 0x7F) { - case 0x45: - /* WRITE variants */ - FLOPPY_DPRINTF("WRITE command\n"); - /* 8 parameters cmd */ - fdctrl->data_len = 9; - goto enqueue; - case 0x49: - /* WRITE_DELETED variants */ - FLOPPY_DPRINTF("WRITE_DELETED command\n"); - /* 8 parameters cmd */ - fdctrl->data_len = 9; - goto enqueue; - default: - break; - } - switch (value) { - case 0x03: - /* SPECIFY */ - FLOPPY_DPRINTF("SPECIFY command\n"); - /* 1 parameter cmd */ - fdctrl->data_len = 3; - goto enqueue; - case 0x04: - /* SENSE_DRIVE_STATUS */ - FLOPPY_DPRINTF("SENSE_DRIVE_STATUS command\n"); - /* 1 parameter cmd */ - fdctrl->data_len = 2; - goto enqueue; - case 0x07: - /* RECALIBRATE */ - FLOPPY_DPRINTF("RECALIBRATE command\n"); - /* 1 parameter cmd */ - fdctrl->data_len = 2; - goto enqueue; - case 0x08: - /* SENSE_INTERRUPT_STATUS */ - FLOPPY_DPRINTF("SENSE_INTERRUPT_STATUS command (%02x)\n", - fdctrl->int_status); - /* No parameters cmd: returns status if no interrupt */ -#if 0 - fdctrl->fifo[0] = - fdctrl->int_status | (cur_drv->head << 2) | fdctrl->cur_drv; -#else - /* XXX: int_status handling is broken for read/write - commands, so we do this hack. It should be suppressed - ASAP */ - fdctrl->fifo[0] = - 0x20 | (cur_drv->head << 2) | fdctrl->cur_drv; -#endif - fdctrl->fifo[1] = cur_drv->track; - fdctrl_set_fifo(fdctrl, 2, 0); - fdctrl_reset_irq(fdctrl); - fdctrl->int_status = 0xC0; - return; - case 0x0E: - /* DUMPREG */ - FLOPPY_DPRINTF("DUMPREG command\n"); - /* Drives position */ - fdctrl->fifo[0] = drv0(fdctrl)->track; - fdctrl->fifo[1] = drv1(fdctrl)->track; +static void fdctrl_handle_dumpreg (fdctrl_t *fdctrl, int direction) +{ + fdrive_t *cur_drv = get_cur_drv(fdctrl); + + /* Drives position */ + fdctrl->fifo[0] = drv0(fdctrl)->track; + fdctrl->fifo[1] = drv1(fdctrl)->track; +#if MAX_FD == 4 + fdctrl->fifo[2] = drv2(fdctrl)->track; + fdctrl->fifo[3] = drv3(fdctrl)->track; +#else + fdctrl->fifo[2] = 0; + fdctrl->fifo[3] = 0; +#endif + /* timers */ + fdctrl->fifo[4] = fdctrl->timer0; + fdctrl->fifo[5] = (fdctrl->timer1 << 1) | (fdctrl->dor & FD_DOR_DMAEN ? 1 : 0); + fdctrl->fifo[6] = cur_drv->last_sect; + fdctrl->fifo[7] = (fdctrl->lock << 7) | + (cur_drv->perpendicular << 2); + fdctrl->fifo[8] = fdctrl->config; + fdctrl->fifo[9] = fdctrl->precomp_trk; + fdctrl_set_fifo(fdctrl, 10, 0); +} + +static void fdctrl_handle_version (fdctrl_t *fdctrl, int direction) +{ + /* Controller's version */ + fdctrl->fifo[0] = fdctrl->version; + fdctrl_set_fifo(fdctrl, 1, 1); +} + +static void fdctrl_handle_partid (fdctrl_t *fdctrl, int direction) +{ + fdctrl->fifo[0] = 0x41; /* Stepping 1 */ + fdctrl_set_fifo(fdctrl, 1, 0); +} + +static void fdctrl_handle_restore (fdctrl_t *fdctrl, int direction) +{ + fdrive_t *cur_drv = get_cur_drv(fdctrl); + + /* Drives position */ + drv0(fdctrl)->track = fdctrl->fifo[3]; + drv1(fdctrl)->track = fdctrl->fifo[4]; +#if MAX_FD == 4 + drv2(fdctrl)->track = fdctrl->fifo[5]; + drv3(fdctrl)->track = fdctrl->fifo[6]; +#endif + /* timers */ + fdctrl->timer0 = fdctrl->fifo[7]; + fdctrl->timer1 = fdctrl->fifo[8]; + cur_drv->last_sect = fdctrl->fifo[9]; + fdctrl->lock = fdctrl->fifo[10] >> 7; + cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF; + fdctrl->config = fdctrl->fifo[11]; + fdctrl->precomp_trk = fdctrl->fifo[12]; + fdctrl->pwrd = fdctrl->fifo[13]; + fdctrl_reset_fifo(fdctrl); +} + +static void fdctrl_handle_save (fdctrl_t *fdctrl, int direction) +{ + fdrive_t *cur_drv = get_cur_drv(fdctrl); + + fdctrl->fifo[0] = 0; + fdctrl->fifo[1] = 0; + /* Drives position */ + fdctrl->fifo[2] = drv0(fdctrl)->track; + fdctrl->fifo[3] = drv1(fdctrl)->track; +#if MAX_FD == 4 + fdctrl->fifo[4] = drv2(fdctrl)->track; + fdctrl->fifo[5] = drv3(fdctrl)->track; +#else + fdctrl->fifo[4] = 0; + fdctrl->fifo[5] = 0; +#endif + /* timers */ + fdctrl->fifo[6] = fdctrl->timer0; + fdctrl->fifo[7] = fdctrl->timer1; + fdctrl->fifo[8] = cur_drv->last_sect; + fdctrl->fifo[9] = (fdctrl->lock << 7) | + (cur_drv->perpendicular << 2); + fdctrl->fifo[10] = fdctrl->config; + fdctrl->fifo[11] = fdctrl->precomp_trk; + fdctrl->fifo[12] = fdctrl->pwrd; + fdctrl->fifo[13] = 0; + fdctrl->fifo[14] = 0; + fdctrl_set_fifo(fdctrl, 15, 1); +} + +static void fdctrl_handle_readid (fdctrl_t *fdctrl, int direction) +{ + fdrive_t *cur_drv = get_cur_drv(fdctrl); + + /* XXX: should set main status register to busy */ + cur_drv->head = (fdctrl->fifo[1] >> 2) & 1; + qemu_mod_timer(fdctrl->result_timer, + qemu_get_clock(vm_clock) + (ticks_per_sec / 50)); +} + +static void fdctrl_handle_format_track (fdctrl_t *fdctrl, int direction) +{ + fdrive_t *cur_drv; + + SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK); + cur_drv = get_cur_drv(fdctrl); + fdctrl->data_state |= FD_STATE_FORMAT; + if (fdctrl->fifo[0] & 0x80) + fdctrl->data_state |= FD_STATE_MULTI; + else + fdctrl->data_state &= ~FD_STATE_MULTI; + fdctrl->data_state &= ~FD_STATE_SEEK; + cur_drv->bps = + fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2]; +#if 0 + cur_drv->last_sect = + cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] : + fdctrl->fifo[3] / 2; +#else + cur_drv->last_sect = fdctrl->fifo[3]; +#endif + /* TODO: implement format using DMA expected by the Bochs BIOS + * and Linux fdformat (read 3 bytes per sector via DMA and fill + * the sector with the specified fill byte + */ + fdctrl->data_state &= ~FD_STATE_FORMAT; + fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); +} + +static void fdctrl_handle_specify (fdctrl_t *fdctrl, int direction) +{ + fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF; + fdctrl->timer1 = fdctrl->fifo[2] >> 1; + if (fdctrl->fifo[2] & 1) + fdctrl->dor &= ~FD_DOR_DMAEN; + else + fdctrl->dor |= FD_DOR_DMAEN; + /* No result back */ + fdctrl_reset_fifo(fdctrl); +} + +static void fdctrl_handle_sense_drive_status (fdctrl_t *fdctrl, int direction) +{ + fdrive_t *cur_drv; + + SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK); + cur_drv = get_cur_drv(fdctrl); + cur_drv->head = (fdctrl->fifo[1] >> 2) & 1; + /* 1 Byte status back */ + fdctrl->fifo[0] = (cur_drv->ro << 6) | + (cur_drv->track == 0 ? 0x10 : 0x00) | + (cur_drv->head << 2) | + GET_CUR_DRV(fdctrl) | + 0x28; + fdctrl_set_fifo(fdctrl, 1, 0); +} + +static void fdctrl_handle_recalibrate (fdctrl_t *fdctrl, int direction) +{ + fdrive_t *cur_drv; + + SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK); + cur_drv = get_cur_drv(fdctrl); + fd_recalibrate(cur_drv); + fdctrl_reset_fifo(fdctrl); + /* Raise Interrupt */ + fdctrl_raise_irq(fdctrl, FD_SR0_SEEK); +} + +static void fdctrl_handle_sense_interrupt_status (fdctrl_t *fdctrl, int direction) +{ + fdrive_t *cur_drv = get_cur_drv(fdctrl); + +#if 0 + fdctrl->fifo[0] = + fdctrl->status0 | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl); +#else + /* XXX: status0 handling is broken for read/write + commands, so we do this hack. It should be suppressed + ASAP */ + fdctrl->fifo[0] = + FD_SR0_SEEK | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl); +#endif + fdctrl->fifo[1] = cur_drv->track; + fdctrl_set_fifo(fdctrl, 2, 0); + fdctrl_reset_irq(fdctrl); + fdctrl->status0 = FD_SR0_RDYCHG; +} + +static void fdctrl_handle_seek (fdctrl_t *fdctrl, int direction) +{ + fdrive_t *cur_drv; + + SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK); + cur_drv = get_cur_drv(fdctrl); + fdctrl_reset_fifo(fdctrl); + if (fdctrl->fifo[2] > cur_drv->max_track) { + fdctrl_raise_irq(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK); + } else { + cur_drv->track = fdctrl->fifo[2]; + /* Raise Interrupt */ + fdctrl_raise_irq(fdctrl, FD_SR0_SEEK); + } +} + +static void fdctrl_handle_perpendicular_mode (fdctrl_t *fdctrl, int direction) +{ + fdrive_t *cur_drv = get_cur_drv(fdctrl); + + if (fdctrl->fifo[1] & 0x80) + cur_drv->perpendicular = fdctrl->fifo[1] & 0x7; + /* No result back */ + fdctrl_reset_fifo(fdctrl); +} + +static void fdctrl_handle_configure (fdctrl_t *fdctrl, int direction) +{ + fdctrl->config = fdctrl->fifo[2]; + fdctrl->precomp_trk = fdctrl->fifo[3]; + /* No result back */ + fdctrl_reset_fifo(fdctrl); +} + +static void fdctrl_handle_powerdown_mode (fdctrl_t *fdctrl, int direction) +{ + fdctrl->pwrd = fdctrl->fifo[1]; + fdctrl->fifo[0] = fdctrl->fifo[1]; + fdctrl_set_fifo(fdctrl, 1, 1); +} + +static void fdctrl_handle_option (fdctrl_t *fdctrl, int direction) +{ + /* No result back */ + fdctrl_reset_fifo(fdctrl); +} + +static void fdctrl_handle_drive_specification_command (fdctrl_t *fdctrl, int direction) +{ + fdrive_t *cur_drv = get_cur_drv(fdctrl); + + if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) { + /* Command parameters done */ + if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) { + fdctrl->fifo[0] = fdctrl->fifo[1]; fdctrl->fifo[2] = 0; fdctrl->fifo[3] = 0; - /* timers */ - fdctrl->fifo[4] = fdctrl->timer0; - fdctrl->fifo[5] = (fdctrl->timer1 << 1) | fdctrl->dma_en; - fdctrl->fifo[6] = cur_drv->last_sect; - fdctrl->fifo[7] = (fdctrl->lock << 7) | - (cur_drv->perpendicular << 2); - fdctrl->fifo[8] = fdctrl->config; - fdctrl->fifo[9] = fdctrl->precomp_trk; - fdctrl_set_fifo(fdctrl, 10, 0); - return; - case 0x0F: - /* SEEK */ - FLOPPY_DPRINTF("SEEK command\n"); - /* 2 parameters cmd */ - fdctrl->data_len = 3; - goto enqueue; - case 0x10: - /* VERSION */ - FLOPPY_DPRINTF("VERSION command\n"); - /* No parameters cmd */ - /* Controller's version */ - fdctrl->fifo[0] = fdctrl->version; - fdctrl_set_fifo(fdctrl, 1, 1); - return; - case 0x12: - /* PERPENDICULAR_MODE */ - FLOPPY_DPRINTF("PERPENDICULAR_MODE command\n"); - /* 1 parameter cmd */ - fdctrl->data_len = 2; - goto enqueue; - case 0x13: - /* CONFIGURE */ - FLOPPY_DPRINTF("CONFIGURE command\n"); - /* 3 parameters cmd */ - fdctrl->data_len = 4; - goto enqueue; - case 0x14: - /* UNLOCK */ - FLOPPY_DPRINTF("UNLOCK command\n"); - /* No parameters cmd */ - fdctrl->lock = 0; - fdctrl->fifo[0] = 0; - fdctrl_set_fifo(fdctrl, 1, 0); - return; - case 0x17: - /* POWERDOWN_MODE */ - FLOPPY_DPRINTF("POWERDOWN_MODE command\n"); - /* 2 parameters cmd */ - fdctrl->data_len = 3; - goto enqueue; - case 0x18: - /* PART_ID */ - FLOPPY_DPRINTF("PART_ID command\n"); - /* No parameters cmd */ - fdctrl->fifo[0] = 0x41; /* Stepping 1 */ - fdctrl_set_fifo(fdctrl, 1, 0); - return; - case 0x2C: - /* SAVE */ - FLOPPY_DPRINTF("SAVE command\n"); - /* No parameters cmd */ - fdctrl->fifo[0] = 0; - fdctrl->fifo[1] = 0; - /* Drives position */ - fdctrl->fifo[2] = drv0(fdctrl)->track; - fdctrl->fifo[3] = drv1(fdctrl)->track; - fdctrl->fifo[4] = 0; - fdctrl->fifo[5] = 0; - /* timers */ - fdctrl->fifo[6] = fdctrl->timer0; - fdctrl->fifo[7] = fdctrl->timer1; - fdctrl->fifo[8] = cur_drv->last_sect; - fdctrl->fifo[9] = (fdctrl->lock << 7) | - (cur_drv->perpendicular << 2); - fdctrl->fifo[10] = fdctrl->config; - fdctrl->fifo[11] = fdctrl->precomp_trk; - fdctrl->fifo[12] = fdctrl->pwrd; - fdctrl->fifo[13] = 0; - fdctrl->fifo[14] = 0; - fdctrl_set_fifo(fdctrl, 15, 1); - return; - case 0x33: - /* OPTION */ - FLOPPY_DPRINTF("OPTION command\n"); - /* 1 parameter cmd */ - fdctrl->data_len = 2; - goto enqueue; - case 0x42: - /* READ_TRACK */ - FLOPPY_DPRINTF("READ_TRACK command\n"); - /* 8 parameters cmd */ - fdctrl->data_len = 9; - goto enqueue; - case 0x4A: - /* READ_ID */ - FLOPPY_DPRINTF("READ_ID command\n"); - /* 1 parameter cmd */ - fdctrl->data_len = 2; - goto enqueue; - case 0x4C: - /* RESTORE */ - FLOPPY_DPRINTF("RESTORE command\n"); - /* 17 parameters cmd */ - fdctrl->data_len = 18; - goto enqueue; - case 0x4D: - /* FORMAT_TRACK */ - FLOPPY_DPRINTF("FORMAT_TRACK command\n"); - /* 5 parameters cmd */ - fdctrl->data_len = 6; - goto enqueue; - case 0x8E: - /* DRIVE_SPECIFICATION_COMMAND */ - FLOPPY_DPRINTF("DRIVE_SPECIFICATION_COMMAND command\n"); - /* 5 parameters cmd */ - fdctrl->data_len = 6; - goto enqueue; - case 0x8F: - /* RELATIVE_SEEK_OUT */ - FLOPPY_DPRINTF("RELATIVE_SEEK_OUT command\n"); - /* 2 parameters cmd */ - fdctrl->data_len = 3; - goto enqueue; - case 0x94: - /* LOCK */ - FLOPPY_DPRINTF("LOCK command\n"); - /* No parameters cmd */ - fdctrl->lock = 1; - fdctrl->fifo[0] = 0x10; - fdctrl_set_fifo(fdctrl, 1, 1); - return; - case 0xCD: - /* FORMAT_AND_WRITE */ - FLOPPY_DPRINTF("FORMAT_AND_WRITE command\n"); - /* 10 parameters cmd */ - fdctrl->data_len = 11; - goto enqueue; - case 0xCF: - /* RELATIVE_SEEK_IN */ - FLOPPY_DPRINTF("RELATIVE_SEEK_IN command\n"); - /* 2 parameters cmd */ - fdctrl->data_len = 3; - goto enqueue; - default: - /* Unknown command */ - FLOPPY_ERROR("unknown command: 0x%02x\n", value); - fdctrl_unimplemented(fdctrl); - return; + fdctrl_set_fifo(fdctrl, 4, 1); + } else { + fdctrl_reset_fifo(fdctrl); + } + } else if (fdctrl->data_len > 7) { + /* ERROR */ + fdctrl->fifo[0] = 0x80 | + (cur_drv->head << 2) | GET_CUR_DRV(fdctrl); + fdctrl_set_fifo(fdctrl, 1, 1); + } +} + +static void fdctrl_handle_relative_seek_out (fdctrl_t *fdctrl, int direction) +{ + fdrive_t *cur_drv; + + SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK); + cur_drv = get_cur_drv(fdctrl); + if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) { + cur_drv->track = cur_drv->max_track - 1; + } else { + cur_drv->track += fdctrl->fifo[2]; + } + fdctrl_reset_fifo(fdctrl); + /* Raise Interrupt */ + fdctrl_raise_irq(fdctrl, FD_SR0_SEEK); +} + +static void fdctrl_handle_relative_seek_in (fdctrl_t *fdctrl, int direction) +{ + fdrive_t *cur_drv; + + SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK); + cur_drv = get_cur_drv(fdctrl); + if (fdctrl->fifo[2] > cur_drv->track) { + cur_drv->track = 0; + } else { + cur_drv->track -= fdctrl->fifo[2]; + } + fdctrl_reset_fifo(fdctrl); + /* Raise Interrupt */ + fdctrl_raise_irq(fdctrl, FD_SR0_SEEK); +} + +static const struct { + uint8_t value; + uint8_t mask; + const char* name; + int parameters; + void (*handler)(fdctrl_t *fdctrl, int direction); + int direction; +} handlers[] = { + { FD_CMD_READ, 0x1f, "READ", 8, fdctrl_start_transfer, FD_DIR_READ }, + { FD_CMD_WRITE, 0x3f, "WRITE", 8, fdctrl_start_transfer, FD_DIR_WRITE }, + { FD_CMD_SEEK, 0xff, "SEEK", 2, fdctrl_handle_seek }, + { FD_CMD_SENSE_INTERRUPT_STATUS, 0xff, "SENSE INTERRUPT STATUS", 0, fdctrl_handle_sense_interrupt_status }, + { FD_CMD_RECALIBRATE, 0xff, "RECALIBRATE", 1, fdctrl_handle_recalibrate }, + { FD_CMD_FORMAT_TRACK, 0xbf, "FORMAT TRACK", 5, fdctrl_handle_format_track }, + { FD_CMD_READ_TRACK, 0xbf, "READ TRACK", 8, fdctrl_start_transfer, FD_DIR_READ }, + { FD_CMD_RESTORE, 0xff, "RESTORE", 17, fdctrl_handle_restore }, /* part of READ DELETED DATA */ + { FD_CMD_SAVE, 0xff, "SAVE", 0, fdctrl_handle_save }, /* part of READ DELETED DATA */ + { FD_CMD_READ_DELETED, 0x1f, "READ DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_READ }, + { FD_CMD_SCAN_EQUAL, 0x1f, "SCAN EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANE }, + { FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_unimplemented }, + { FD_CMD_SCAN_LOW_OR_EQUAL, 0x1f, "SCAN LOW OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANL }, + { FD_CMD_SCAN_HIGH_OR_EQUAL, 0x1f, "SCAN HIGH OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANH }, + { FD_CMD_WRITE_DELETED, 0x3f, "WRITE DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_WRITE }, + { FD_CMD_READ_ID, 0xbf, "READ ID", 1, fdctrl_handle_readid }, + { FD_CMD_SPECIFY, 0xff, "SPECIFY", 2, fdctrl_handle_specify }, + { FD_CMD_SENSE_DRIVE_STATUS, 0xff, "SENSE DRIVE STATUS", 1, fdctrl_handle_sense_drive_status }, + { FD_CMD_PERPENDICULAR_MODE, 0xff, "PERPENDICULAR MODE", 1, fdctrl_handle_perpendicular_mode }, + { FD_CMD_CONFIGURE, 0xff, "CONFIGURE", 3, fdctrl_handle_configure }, + { FD_CMD_POWERDOWN_MODE, 0xff, "POWERDOWN MODE", 2, fdctrl_handle_powerdown_mode }, + { FD_CMD_OPTION, 0xff, "OPTION", 1, fdctrl_handle_option }, + { FD_CMD_DRIVE_SPECIFICATION_COMMAND, 0xff, "DRIVE SPECIFICATION COMMAND", 5, fdctrl_handle_drive_specification_command }, + { FD_CMD_RELATIVE_SEEK_OUT, 0xff, "RELATIVE SEEK OUT", 2, fdctrl_handle_relative_seek_out }, + { FD_CMD_FORMAT_AND_WRITE, 0xff, "FORMAT AND WRITE", 10, fdctrl_unimplemented }, + { FD_CMD_RELATIVE_SEEK_IN, 0xff, "RELATIVE SEEK IN", 2, fdctrl_handle_relative_seek_in }, + { FD_CMD_LOCK, 0x7f, "LOCK", 0, fdctrl_handle_lock }, + { FD_CMD_DUMPREG, 0xff, "DUMPREG", 0, fdctrl_handle_dumpreg }, + { FD_CMD_VERSION, 0xff, "VERSION", 0, fdctrl_handle_version }, + { FD_CMD_PART_ID, 0xff, "PART ID", 0, fdctrl_handle_partid }, + { FD_CMD_WRITE, 0x1f, "WRITE (BeOS)", 8, fdctrl_start_transfer, FD_DIR_WRITE }, /* not in specification ; BeOS 4.5 bug */ + { 0, 0, "unknown", 0, fdctrl_unimplemented }, /* default handler */ +}; +/* Associate command to an index in the 'handlers' array */ +static uint8_t command_to_handler[256]; + +static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) +{ + fdrive_t *cur_drv; + int pos; + + /* Reset mode */ + if (!(fdctrl->dor & FD_DOR_nRESET)) { + FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); + return; + } + if (!(fdctrl->msr & FD_MSR_RQM) || (fdctrl->msr & FD_MSR_DIO)) { + FLOPPY_ERROR("controller not ready for writing\n"); + return; + } + fdctrl->dsr &= ~FD_DSR_PWRDOWN; + /* Is it write command time ? */ + if (fdctrl->msr & FD_MSR_NONDMA) { + /* FIFO data write */ + pos = fdctrl->data_pos++; + pos %= FD_SECTOR_LEN; + fdctrl->fifo[pos] = value; + if (pos == FD_SECTOR_LEN - 1 || + fdctrl->data_pos == fdctrl->data_len) { + cur_drv = get_cur_drv(fdctrl); + if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) { + FLOPPY_ERROR("writing sector %d\n", fd_sector(cur_drv)); + return; + } + if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) { + FLOPPY_DPRINTF("error seeking to next sector %d\n", + fd_sector(cur_drv)); + return; + } } + /* Switch from transfer mode to status mode + * then from status mode to command mode + */ + if (fdctrl->data_pos == fdctrl->data_len) + fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00); + return; + } + if (fdctrl->data_pos == 0) { + /* Command */ + pos = command_to_handler[value & 0xff]; + FLOPPY_DPRINTF("%s command\n", handlers[pos].name); + fdctrl->data_len = handlers[pos].parameters + 1; } - enqueue: + FLOPPY_DPRINTF("%s: %02x\n", __func__, value); - fdctrl->fifo[fdctrl->data_pos] = value; - if (++fdctrl->data_pos == fdctrl->data_len) { + fdctrl->fifo[fdctrl->data_pos++] = value; + if (fdctrl->data_pos == fdctrl->data_len) { /* We now have all parameters * and will be able to treat the command */ @@ -1629,260 +1810,10 @@ fdctrl_format_sector(fdctrl); return; } - switch (fdctrl->fifo[0] & 0x1F) { - case 0x06: - { - /* READ variants */ - FLOPPY_DPRINTF("treat READ command\n"); - fdctrl_start_transfer(fdctrl, FD_DIR_READ); - return; - } - case 0x0C: - /* READ_DELETED variants */ -// FLOPPY_DPRINTF("treat READ_DELETED command\n"); - FLOPPY_ERROR("treat READ_DELETED command\n"); - fdctrl_start_transfer_del(fdctrl, FD_DIR_READ); - return; - case 0x16: - /* VERIFY variants */ -// FLOPPY_DPRINTF("treat VERIFY command\n"); - FLOPPY_ERROR("treat VERIFY command\n"); - fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00); - return; - case 0x10: - /* SCAN_EQUAL variants */ -// FLOPPY_DPRINTF("treat SCAN_EQUAL command\n"); - FLOPPY_ERROR("treat SCAN_EQUAL command\n"); - fdctrl_start_transfer(fdctrl, FD_DIR_SCANE); - return; - case 0x19: - /* SCAN_LOW_OR_EQUAL variants */ -// FLOPPY_DPRINTF("treat SCAN_LOW_OR_EQUAL command\n"); - FLOPPY_ERROR("treat SCAN_LOW_OR_EQUAL command\n"); - fdctrl_start_transfer(fdctrl, FD_DIR_SCANL); - return; - case 0x1D: - /* SCAN_HIGH_OR_EQUAL variants */ -// FLOPPY_DPRINTF("treat SCAN_HIGH_OR_EQUAL command\n"); - FLOPPY_ERROR("treat SCAN_HIGH_OR_EQUAL command\n"); - fdctrl_start_transfer(fdctrl, FD_DIR_SCANH); - return; - default: - break; - } - switch (fdctrl->fifo[0] & 0x3F) { - case 0x05: - /* WRITE variants */ - FLOPPY_DPRINTF("treat WRITE command (%02x)\n", fdctrl->fifo[0]); - fdctrl_start_transfer(fdctrl, FD_DIR_WRITE); - return; - case 0x09: - /* WRITE_DELETED variants */ -// FLOPPY_DPRINTF("treat WRITE_DELETED command\n"); - FLOPPY_ERROR("treat WRITE_DELETED command\n"); - fdctrl_start_transfer_del(fdctrl, FD_DIR_WRITE); - return; - default: - break; - } - switch (fdctrl->fifo[0]) { - case 0x03: - /* SPECIFY */ - FLOPPY_DPRINTF("treat SPECIFY command\n"); - fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF; - fdctrl->timer1 = fdctrl->fifo[2] >> 1; - fdctrl->dma_en = 1 - (fdctrl->fifo[2] & 1) ; - /* No result back */ - fdctrl_reset_fifo(fdctrl); - break; - case 0x04: - /* SENSE_DRIVE_STATUS */ - FLOPPY_DPRINTF("treat SENSE_DRIVE_STATUS command\n"); - fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); - cur_drv->head = (fdctrl->fifo[1] >> 2) & 1; - /* 1 Byte status back */ - fdctrl->fifo[0] = (cur_drv->ro << 6) | - (cur_drv->track == 0 ? 0x10 : 0x00) | - (cur_drv->head << 2) | - fdctrl->cur_drv | - 0x28; - fdctrl_set_fifo(fdctrl, 1, 0); - break; - case 0x07: - /* RECALIBRATE */ - FLOPPY_DPRINTF("treat RECALIBRATE command\n"); - fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); - fd_recalibrate(cur_drv); - fdctrl_reset_fifo(fdctrl); - /* Raise Interrupt */ - fdctrl_raise_irq(fdctrl, 0x20); - break; - case 0x0F: - /* SEEK */ - FLOPPY_DPRINTF("treat SEEK command\n"); - fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); - fd_start(cur_drv); - if (fdctrl->fifo[2] <= cur_drv->track) - cur_drv->dir = 1; - else - cur_drv->dir = 0; - fdctrl_reset_fifo(fdctrl); - if (fdctrl->fifo[2] > cur_drv->max_track) { - fdctrl_raise_irq(fdctrl, 0x60); - } else { - cur_drv->track = fdctrl->fifo[2]; - /* Raise Interrupt */ - fdctrl_raise_irq(fdctrl, 0x20); - } - break; - case 0x12: - /* PERPENDICULAR_MODE */ - FLOPPY_DPRINTF("treat PERPENDICULAR_MODE command\n"); - if (fdctrl->fifo[1] & 0x80) - cur_drv->perpendicular = fdctrl->fifo[1] & 0x7; - /* No result back */ - fdctrl_reset_fifo(fdctrl); - break; - case 0x13: - /* CONFIGURE */ - FLOPPY_DPRINTF("treat CONFIGURE command\n"); - fdctrl->config = fdctrl->fifo[2]; - fdctrl->precomp_trk = fdctrl->fifo[3]; - /* No result back */ - fdctrl_reset_fifo(fdctrl); - break; - case 0x17: - /* POWERDOWN_MODE */ - FLOPPY_DPRINTF("treat POWERDOWN_MODE command\n"); - fdctrl->pwrd = fdctrl->fifo[1]; - fdctrl->fifo[0] = fdctrl->fifo[1]; - fdctrl_set_fifo(fdctrl, 1, 1); - break; - case 0x33: - /* OPTION */ - FLOPPY_DPRINTF("treat OPTION command\n"); - /* No result back */ - fdctrl_reset_fifo(fdctrl); - break; - case 0x42: - /* READ_TRACK */ -// FLOPPY_DPRINTF("treat READ_TRACK command\n"); - FLOPPY_ERROR("treat READ_TRACK command\n"); - fdctrl_start_transfer(fdctrl, FD_DIR_READ); - break; - case 0x4A: - /* READ_ID */ - FLOPPY_DPRINTF("treat READ_ID command\n"); - /* XXX: should set main status register to busy */ - cur_drv->head = (fdctrl->fifo[1] >> 2) & 1; - qemu_mod_timer(fdctrl->result_timer, - qemu_get_clock(vm_clock) + (ticks_per_sec / 50)); - break; - case 0x4C: - /* RESTORE */ - FLOPPY_DPRINTF("treat RESTORE command\n"); - /* Drives position */ - drv0(fdctrl)->track = fdctrl->fifo[3]; - drv1(fdctrl)->track = fdctrl->fifo[4]; - /* timers */ - fdctrl->timer0 = fdctrl->fifo[7]; - fdctrl->timer1 = fdctrl->fifo[8]; - cur_drv->last_sect = fdctrl->fifo[9]; - fdctrl->lock = fdctrl->fifo[10] >> 7; - cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF; - fdctrl->config = fdctrl->fifo[11]; - fdctrl->precomp_trk = fdctrl->fifo[12]; - fdctrl->pwrd = fdctrl->fifo[13]; - fdctrl_reset_fifo(fdctrl); - break; - case 0x4D: - /* FORMAT_TRACK */ - FLOPPY_DPRINTF("treat FORMAT_TRACK command\n"); - fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); - fdctrl->data_state |= FD_STATE_FORMAT; - if (fdctrl->fifo[0] & 0x80) - fdctrl->data_state |= FD_STATE_MULTI; - else - fdctrl->data_state &= ~FD_STATE_MULTI; - fdctrl->data_state &= ~FD_STATE_SEEK; - cur_drv->bps = - fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2]; -#if 0 - cur_drv->last_sect = - cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] : - fdctrl->fifo[3] / 2; -#else - cur_drv->last_sect = fdctrl->fifo[3]; -#endif - /* TODO: implement format using DMA expected by the Bochs BIOS - * and Linux fdformat (read 3 bytes per sector via DMA and fill - * the sector with the specified fill byte - */ - fdctrl->data_state &= ~FD_STATE_FORMAT; - fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); - break; - case 0x8E: - /* DRIVE_SPECIFICATION_COMMAND */ - FLOPPY_DPRINTF("treat DRIVE_SPECIFICATION_COMMAND command\n"); - if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) { - /* Command parameters done */ - if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) { - fdctrl->fifo[0] = fdctrl->fifo[1]; - fdctrl->fifo[2] = 0; - fdctrl->fifo[3] = 0; - fdctrl_set_fifo(fdctrl, 4, 1); - } else { - fdctrl_reset_fifo(fdctrl); - } - } else if (fdctrl->data_len > 7) { - /* ERROR */ - fdctrl->fifo[0] = 0x80 | - (cur_drv->head << 2) | fdctrl->cur_drv; - fdctrl_set_fifo(fdctrl, 1, 1); - } - break; - case 0x8F: - /* RELATIVE_SEEK_OUT */ - FLOPPY_DPRINTF("treat RELATIVE_SEEK_OUT command\n"); - fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); - fd_start(cur_drv); - cur_drv->dir = 0; - if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) { - cur_drv->track = cur_drv->max_track - 1; - } else { - cur_drv->track += fdctrl->fifo[2]; - } - fdctrl_reset_fifo(fdctrl); - fdctrl_raise_irq(fdctrl, 0x20); - break; - case 0xCD: - /* FORMAT_AND_WRITE */ -// FLOPPY_DPRINTF("treat FORMAT_AND_WRITE command\n"); - FLOPPY_ERROR("treat FORMAT_AND_WRITE command\n"); - fdctrl_unimplemented(fdctrl); - break; - case 0xCF: - /* RELATIVE_SEEK_IN */ - FLOPPY_DPRINTF("treat RELATIVE_SEEK_IN command\n"); - fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); - fd_start(cur_drv); - cur_drv->dir = 1; - if (fdctrl->fifo[2] > cur_drv->track) { - cur_drv->track = 0; - } else { - cur_drv->track -= fdctrl->fifo[2]; - } - fdctrl_reset_fifo(fdctrl); - /* Raise Interrupt */ - fdctrl_raise_irq(fdctrl, 0x20); - break; - } + + pos = command_to_handler[fdctrl->fifo[0] & 0xff]; + FLOPPY_DPRINTF("treat %s command\n", handlers[pos].name); + (*handlers[pos].handler)(fdctrl, handlers[pos].direction); } } @@ -1900,3 +1831,97 @@ } fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); } + +/* Init functions */ +static fdctrl_t *fdctrl_init_common (qemu_irq irq, int dma_chann, + target_phys_addr_t io_base, + BlockDriverState **fds) +{ + fdctrl_t *fdctrl; + int i, j; + + /* Fill 'command_to_handler' lookup table */ + for (i = sizeof(handlers)/sizeof(handlers[0]) - 1; i >= 0; i--) { + for (j = 0; j < sizeof(command_to_handler); j++) { + if ((j & handlers[i].mask) == handlers[i].value) + command_to_handler[j] = i; + } + } + + FLOPPY_DPRINTF("init controller\n"); + fdctrl = qemu_mallocz(sizeof(fdctrl_t)); + if (!fdctrl) + return NULL; + fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN); + if (fdctrl->fifo == NULL) { + qemu_free(fdctrl); + return NULL; + } + fdctrl->result_timer = qemu_new_timer(vm_clock, + fdctrl_result_timer, fdctrl); + + fdctrl->version = 0x90; /* Intel 82078 controller */ + fdctrl->irq = irq; + fdctrl->dma_chann = dma_chann; + fdctrl->io_base = io_base; + fdctrl->config = FD_CONFIG_EIS | FD_CONFIG_EFIFO; /* Implicit seek, polling & FIFO enabled */ + if (fdctrl->dma_chann != -1) { + DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl); + } + for (i = 0; i < MAX_FD; i++) { + fd_init(&fdctrl->drives[i], fds[i]); + } + fdctrl_external_reset(fdctrl); + register_savevm("fdc", io_base, 2, fdc_save, fdc_load, fdctrl); + qemu_register_reset(fdctrl_external_reset, fdctrl); + for (i = 0; i < MAX_FD; i++) { + fd_revalidate(&fdctrl->drives[i]); + } + + return fdctrl; +} + +fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, + target_phys_addr_t io_base, + BlockDriverState **fds) +{ + fdctrl_t *fdctrl; + int io_mem; + + fdctrl = fdctrl_init_common(irq, dma_chann, io_base, fds); + + fdctrl->sun4m = 0; + if (mem_mapped) { + io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, + fdctrl); + cpu_register_physical_memory(io_base, 0x08, io_mem); + } else { + register_ioport_read((uint32_t)io_base + 0x01, 5, 1, &fdctrl_read, + fdctrl); + register_ioport_read((uint32_t)io_base + 0x07, 1, 1, &fdctrl_read, + fdctrl); + register_ioport_write((uint32_t)io_base + 0x01, 5, 1, &fdctrl_write, + fdctrl); + register_ioport_write((uint32_t)io_base + 0x07, 1, 1, &fdctrl_write, + fdctrl); + } + + return fdctrl; +} + +fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base, + BlockDriverState **fds, qemu_irq *fdc_tc) +{ + fdctrl_t *fdctrl; + int io_mem; + + fdctrl = fdctrl_init_common(irq, -1, io_base, fds); + fdctrl->sun4m = 1; + io_mem = cpu_register_io_memory(0, fdctrl_mem_read_strict, + fdctrl_mem_write_strict, + fdctrl); + cpu_register_physical_memory(io_base, 0x08, io_mem); + *fdc_tc = *qemu_allocate_irqs(fdctrl_handle_tc, fdctrl, 1); + + return fdctrl; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/fdc.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/fdc.h --- qemu-0.9.1/hw/fdc.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/fdc.h 2008-03-21 18:05:23.000000000 +0000 @@ -1,6 +1,5 @@ /* fdc.c */ #define MAX_FD 2 -extern BlockDriverState *fd_table[MAX_FD]; typedef struct fdctrl_t fdctrl_t; @@ -8,5 +7,5 @@ target_phys_addr_t io_base, BlockDriverState **fds); fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base, - BlockDriverState **fds); + BlockDriverState **fds, qemu_irq *fdc_tc); int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/firmware_abi.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/firmware_abi.h --- qemu-0.9.1/hw/firmware_abi.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/firmware_abi.h 2008-06-23 18:52:43.000000000 +0100 @@ -139,7 +139,7 @@ } static inline uint32_t -OpenBIOS_set_var(uint8_t *nvram, uint32_t addr, const unsigned char *str) +OpenBIOS_set_var(uint8_t *nvram, uint32_t addr, const char *str) { uint32_t len; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/flash.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/flash.h --- qemu-0.9.1/hw/flash.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/flash.h 2008-07-29 15:19:16.000000000 +0100 @@ -11,9 +11,10 @@ /* pflash_cfi02.c */ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off, BlockDriverState *bs, uint32_t sector_len, - int nb_blocs, int width, + int nb_blocs, int nb_mappings, int width, uint16_t id0, uint16_t id1, - uint16_t id2, uint16_t id3); + uint16_t id2, uint16_t id3, + uint16_t unlock_addr0, uint16_t unlock_addr1); /* nand.c */ struct nand_flash_s; @@ -34,6 +35,12 @@ #define NAND_MFR_HYNIX 0xad #define NAND_MFR_MICRON 0x2c +/* onenand.c */ +void onenand_base_update(void *opaque, target_phys_addr_t new); +void onenand_base_unmap(void *opaque); +void *onenand_init(uint32_t id, int regshift, qemu_irq irq); +void *onenand_raw_otp(void *opaque); + /* ecc.c */ struct ecc_state_s { uint8_t cp; /* Column parity */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/fw_cfg.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/fw_cfg.c --- qemu-0.9.1/hw/fw_cfg.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/fw_cfg.c 2008-10-04 08:22:29.000000000 +0100 @@ -0,0 +1,294 @@ +/* + * QEMU Firmware configuration device emulation + * + * Copyright (c) 2008 Gleb Natapov + * + * 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 "hw.h" +#include "sysemu.h" +#include "isa.h" +#include "fw_cfg.h" + +/* debug firmware config */ +//#define DEBUG_FW_CFG + +#ifdef DEBUG_FW_CFG +#define FW_CFG_DPRINTF(fmt, args...) \ + do { printf("FW_CFG: " fmt , ##args); } while (0) +#else +#define FW_CFG_DPRINTF(fmt, args...) +#endif + +#define FW_CFG_SIZE 2 + +typedef struct _FWCfgEntry { + uint16_t len; + uint8_t *data; + void *callback_opaque; + FWCfgCallback callback; +} FWCfgEntry; + +typedef struct _FWCfgState { + FWCfgEntry entries[2][FW_CFG_MAX_ENTRY]; + uint16_t cur_entry; + uint16_t cur_offset; +} FWCfgState; + +static void fw_cfg_write(FWCfgState *s, uint8_t value) +{ + int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL); + FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK]; + + FW_CFG_DPRINTF("write %d\n", value); + + if (s->cur_entry & FW_CFG_WRITE_CHANNEL && s->cur_offset < e->len) { + e->data[s->cur_offset++] = value; + if (s->cur_offset == e->len) { + e->callback(e->callback_opaque, e->data); + s->cur_offset = 0; + } + } +} + +static int fw_cfg_select(FWCfgState *s, uint16_t key) +{ + int ret; + + s->cur_offset = 0; + if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) { + s->cur_entry = FW_CFG_INVALID; + ret = 0; + } else { + s->cur_entry = key; + ret = 1; + } + + FW_CFG_DPRINTF("select key %d (%sfound)\n", key, ret ? "" : "not "); + + return ret; +} + +static uint8_t fw_cfg_read(FWCfgState *s) +{ + int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL); + FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK]; + uint8_t ret; + + if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len) + ret = 0; + else + ret = e->data[s->cur_offset++]; + + FW_CFG_DPRINTF("read %d\n", ret); + + return ret; +} + +static uint32_t fw_cfg_io_readb(void *opaque, uint32_t addr) +{ + return fw_cfg_read(opaque); +} + +static void fw_cfg_io_writeb(void *opaque, uint32_t addr, uint32_t value) +{ + return fw_cfg_write(opaque, (uint8_t)value); +} + +static void fw_cfg_io_writew(void *opaque, uint32_t addr, uint32_t value) +{ + fw_cfg_select(opaque, (uint16_t)value); +} + +static uint32_t fw_cfg_mem_readb(void *opaque, target_phys_addr_t addr) +{ + return fw_cfg_read(opaque); +} + +static void fw_cfg_mem_writeb(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + return fw_cfg_write(opaque, (uint8_t)value); +} + +static void fw_cfg_mem_writew(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + fw_cfg_select(opaque, (uint16_t)value); +} + +static CPUReadMemoryFunc *fw_cfg_ctl_mem_read[3] = { + NULL, + NULL, + NULL, +}; + +static CPUWriteMemoryFunc *fw_cfg_ctl_mem_write[3] = { + NULL, + fw_cfg_mem_writew, + NULL, +}; + +static CPUReadMemoryFunc *fw_cfg_data_mem_read[3] = { + fw_cfg_mem_readb, + NULL, + NULL, +}; + +static CPUWriteMemoryFunc *fw_cfg_data_mem_write[3] = { + fw_cfg_mem_writeb, + NULL, + NULL, +}; + +static void fw_cfg_reset(void *opaque) +{ + FWCfgState *s = opaque; + + fw_cfg_select(s, 0); +} + +static void fw_cfg_save(QEMUFile *f, void *opaque) +{ + FWCfgState *s = opaque; + + qemu_put_be16s(f, &s->cur_entry); + qemu_put_be16s(f, &s->cur_offset); +} + +static int fw_cfg_load(QEMUFile *f, void *opaque, int version_id) +{ + FWCfgState *s = opaque; + + if (version_id > 1) + return -EINVAL; + + qemu_get_be16s(f, &s->cur_entry); + qemu_get_be16s(f, &s->cur_offset); + + return 0; +} + +int fw_cfg_add_bytes(void *opaque, uint16_t key, uint8_t *data, uint16_t len) +{ + FWCfgState *s = opaque; + int arch = !!(key & FW_CFG_ARCH_LOCAL); + + key &= FW_CFG_ENTRY_MASK; + + if (key >= FW_CFG_MAX_ENTRY) + return 0; + + s->entries[arch][key].data = data; + s->entries[arch][key].len = len; + + return 1; +} + +int fw_cfg_add_i16(void *opaque, uint16_t key, uint16_t value) +{ + uint16_t *copy; + + copy = qemu_malloc(sizeof(value)); + if (!copy) + return 0; + *copy = cpu_to_le16(value); + return fw_cfg_add_bytes(opaque, key, (uint8_t *)copy, sizeof(value)); +} + +int fw_cfg_add_i32(void *opaque, uint16_t key, uint32_t value) +{ + uint32_t *copy; + + copy = qemu_malloc(sizeof(value)); + if (!copy) + return 0; + *copy = cpu_to_le32(value); + return fw_cfg_add_bytes(opaque, key, (uint8_t *)copy, sizeof(value)); +} + +int fw_cfg_add_i64(void *opaque, uint16_t key, uint64_t value) +{ + uint64_t *copy; + + copy = qemu_malloc(sizeof(value)); + if (!copy) + return 0; + *copy = cpu_to_le64(value); + return fw_cfg_add_bytes(opaque, key, (uint8_t *)copy, sizeof(value)); +} + +int fw_cfg_add_callback(void *opaque, uint16_t key, FWCfgCallback callback, + void *callback_opaque, uint8_t *data, size_t len) +{ + FWCfgState *s = opaque; + int arch = !!(key & FW_CFG_ARCH_LOCAL); + + key &= FW_CFG_ENTRY_MASK; + + if (key >= FW_CFG_MAX_ENTRY || !(key & FW_CFG_WRITE_CHANNEL) + || len > 65535) + return 0; + + s->entries[arch][key].data = data; + s->entries[arch][key].len = len; + s->entries[arch][key].callback_opaque = callback_opaque; + s->entries[arch][key].callback = callback; + + return 1; +} + +void *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, + target_phys_addr_t ctl_addr, target_phys_addr_t data_addr) +{ + FWCfgState *s; + int io_ctl_memory, io_data_memory; + + s = qemu_mallocz(sizeof(FWCfgState)); + if (!s) + return NULL; + + if (ctl_port) { + register_ioport_write(ctl_port, 2, 2, fw_cfg_io_writew, s); + } + if (data_port) { + register_ioport_read(data_port, 1, 1, fw_cfg_io_readb, s); + register_ioport_write(data_port, 1, 1, fw_cfg_io_writeb, s); + } + if (ctl_addr) { + io_ctl_memory = cpu_register_io_memory(0, fw_cfg_ctl_mem_read, + fw_cfg_ctl_mem_write, s); + cpu_register_physical_memory(ctl_addr, FW_CFG_SIZE, io_ctl_memory); + } + if (data_addr) { + io_data_memory = cpu_register_io_memory(0, fw_cfg_data_mem_read, + fw_cfg_data_mem_write, s); + cpu_register_physical_memory(data_addr, FW_CFG_SIZE, io_data_memory); + } + fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (uint8_t *)"QEMU", 4); + fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16); + fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)nographic); + fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); + + register_savevm("fw_cfg", -1, 1, fw_cfg_save, fw_cfg_load, s); + qemu_register_reset(fw_cfg_reset, s); + fw_cfg_reset(s); + + return s; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/fw_cfg.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/fw_cfg.h --- qemu-0.9.1/hw/fw_cfg.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/fw_cfg.h 2008-09-18 19:33:18.000000000 +0100 @@ -0,0 +1,33 @@ +#ifndef FW_CFG_H +#define FW_CFG_H + +#define FW_CFG_SIGNATURE 0x00 +#define FW_CFG_ID 0x01 +#define FW_CFG_UUID 0x02 +#define FW_CFG_RAM_SIZE 0x03 +#define FW_CFG_NOGRAPHIC 0x04 +#define FW_CFG_NB_CPUS 0x05 +#define FW_CFG_MACHINE_ID 0x06 +#define FW_CFG_MAX_ENTRY 0x10 + +#define FW_CFG_WRITE_CHANNEL 0x4000 +#define FW_CFG_ARCH_LOCAL 0x8000 +#define FW_CFG_ENTRY_MASK ~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL) + +#define FW_CFG_INVALID 0xffff + +#ifndef NO_QEMU_PROTOS +typedef void (*FWCfgCallback)(void *opaque, uint8_t *data); + +int fw_cfg_add_bytes(void *opaque, uint16_t key, uint8_t *data, uint16_t len); +int fw_cfg_add_i16(void *opaque, uint16_t key, uint16_t value); +int fw_cfg_add_i32(void *opaque, uint16_t key, uint32_t value); +int fw_cfg_add_i64(void *opaque, uint16_t key, uint64_t value); +int fw_cfg_add_callback(void *opaque, uint16_t key, FWCfgCallback callback, + void *callback_opaque, uint8_t *data, size_t len); +void *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, + target_phys_addr_t crl_addr, target_phys_addr_t data_addr); + +#endif /* NO_QEMU_PROTOS */ + +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/g364fb.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/g364fb.c --- qemu-0.9.1/hw/g364fb.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/g364fb.c 2008-08-17 02:44:53.000000000 +0100 @@ -0,0 +1,391 @@ +/* + * QEMU G364 framebuffer Emulator. + * + * Copyright (c) 2007-2008 Hervé Poussineau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "hw.h" +#include "console.h" +#include "pixel_ops.h" + +//#define DEBUG_G364 + +typedef struct G364State { + target_phys_addr_t vram_base; + unsigned int vram_size; + uint8_t *vram_buffer; + uint32_t ctla; + uint8_t palette[256][3]; + /* display refresh support */ + DisplayState *ds; + QEMUConsole *console; + int graphic_mode; + uint32_t scr_width, scr_height; /* in pixels */ +} G364State; + +/* + * graphic modes + */ +#define BPP 8 +#define PIXEL_WIDTH 8 +#include "g364fb_template.h" +#undef BPP +#undef PIXEL_WIDTH + +#define BPP 15 +#define PIXEL_WIDTH 16 +#include "g364fb_template.h" +#undef BPP +#undef PIXEL_WIDTH + +#define BPP 16 +#define PIXEL_WIDTH 16 +#include "g364fb_template.h" +#undef BPP +#undef PIXEL_WIDTH + +#define BPP 32 +#define PIXEL_WIDTH 32 +#include "g364fb_template.h" +#undef BPP +#undef PIXEL_WIDTH + +#define REG_DISPLAYX 0x0918 +#define REG_DISPLAYY 0x0940 + +#define CTLA_FORCE_BLANK 0x400 + +static void g364fb_draw_graphic(G364State *s, int full_update) +{ + switch (s->ds->depth) { + case 8: + g364fb_draw_graphic8(s, full_update); + break; + case 15: + g364fb_draw_graphic15(s, full_update); + break; + case 16: + g364fb_draw_graphic16(s, full_update); + break; + case 32: + g364fb_draw_graphic32(s, full_update); + break; + default: + printf("g364fb: unknown depth %d\n", s->ds->depth); + return; + } + + dpy_update(s->ds, 0, 0, s->scr_width, s->scr_height); +} + +static void g364fb_draw_blank(G364State *s, int full_update) +{ + int i, w; + uint8_t *d; + + if (!full_update) + return; + + w = s->scr_width * ((s->ds->depth + 7) >> 3); + d = s->ds->data; + for(i = 0; i < s->scr_height; i++) { + memset(d, 0, w); + d += s->ds->linesize; + } + + dpy_update(s->ds, 0, 0, s->scr_width, s->scr_height); +} + +#define GMODE_GRAPH 0 +#define GMODE_BLANK 1 + +static void g364fb_update_display(void *opaque) +{ + G364State *s = opaque; + int full_update, graphic_mode; + + if (s->scr_width == 0 || s->scr_height == 0) + return; + + if (s->ctla & CTLA_FORCE_BLANK) + graphic_mode = GMODE_BLANK; + else + graphic_mode = GMODE_GRAPH; + full_update = 0; + if (graphic_mode != s->graphic_mode) { + s->graphic_mode = graphic_mode; + full_update = 1; + } + if (s->scr_width != s->ds->width || s->scr_height != s->ds->height) { + qemu_console_resize(s->console, s->scr_width, s->scr_height); + full_update = 1; + } + switch(graphic_mode) { + case GMODE_GRAPH: + g364fb_draw_graphic(s, full_update); + break; + case GMODE_BLANK: + default: + g364fb_draw_blank(s, full_update); + break; + } +} + +/* force a full display refresh */ +static void g364fb_invalidate_display(void *opaque) +{ + G364State *s = opaque; + s->graphic_mode = -1; /* force full update */ +} + +static void g364fb_reset(void *opaque) +{ + G364State *s = opaque; + + memset(s->palette, 0, sizeof(s->palette)); + s->scr_width = s->scr_height = 0; + memset(s->vram_buffer, 0, s->vram_size); + s->graphic_mode = -1; /* force full update */ +} + +static void g364fb_screen_dump(void *opaque, const char *filename) +{ + G364State *s = opaque; + int y, x; + uint8_t index; + uint8_t *data_buffer; + FILE *f; + + f = fopen(filename, "wb"); + if (!f) + return; + + data_buffer = s->vram_buffer; + fprintf(f, "P6\n%d %d\n%d\n", + s->scr_width, s->scr_height, 255); + for(y = 0; y < s->scr_height; y++) + for(x = 0; x < s->scr_width; x++, data_buffer++) { + index = *data_buffer; + fputc(s->palette[index][0], f); + fputc(s->palette[index][1], f); + fputc(s->palette[index][2], f); + } + fclose(f); +} + +/* called for accesses to io ports */ +static uint32_t g364fb_ctrl_readb(void *opaque, target_phys_addr_t addr) +{ + //G364State *s = opaque; + uint32_t val; + + addr &= 0xffff; + + switch (addr) { + default: +#ifdef DEBUG_G364 + printf("g364fb/ctrl: invalid read at [" TARGET_FMT_lx "]\n", addr); +#endif + val = 0; + break; + } + +#ifdef DEBUG_G364 + printf("g364fb/ctrl: read 0x%02x at [" TARGET_FMT_lx "]\n", val, addr); +#endif + + return val; +} + +static uint32_t g364fb_ctrl_readw(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; + v = g364fb_ctrl_readb(opaque, addr); + v |= g364fb_ctrl_readb(opaque, addr + 1) << 8; + return v; +} + +static uint32_t g364fb_ctrl_readl(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; + v = g364fb_ctrl_readb(opaque, addr); + v |= g364fb_ctrl_readb(opaque, addr + 1) << 8; + v |= g364fb_ctrl_readb(opaque, addr + 2) << 16; + v |= g364fb_ctrl_readb(opaque, addr + 3) << 24; + return v; +} + +static void g364fb_ctrl_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + G364State *s = opaque; + + addr &= 0xffff; + +#ifdef DEBUG_G364 + printf("g364fb/ctrl: write 0x%02x at [" TARGET_FMT_lx "]\n", val, addr); +#endif + + if (addr < 0x0800) { + /* color palette */ + int idx = addr >> 3; + int c = addr & 7; + if (c < 3) + s->palette[idx][c] = (uint8_t)val; + } else { + switch (addr) { + case REG_DISPLAYX: + s->scr_width = (s->scr_width & 0xfffffc03) | (val << 2); + break; + case REG_DISPLAYX + 1: + s->scr_width = (s->scr_width & 0xfffc03ff) | (val << 10); + break; + case REG_DISPLAYY: + s->scr_height = (s->scr_height & 0xffffff80) | (val >> 1); + break; + case REG_DISPLAYY + 1: + s->scr_height = (s->scr_height & 0xffff801f) | (val << 7); + break; + default: +#ifdef DEBUG_G364 + printf("g364fb/ctrl: invalid write of 0x%02x at [" TARGET_FMT_lx "]\n", val, addr); +#endif + break; + } + } + s->graphic_mode = -1; /* force full update */ +} + +static void g364fb_ctrl_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + g364fb_ctrl_writeb(opaque, addr, val & 0xff); + g364fb_ctrl_writeb(opaque, addr + 1, (val >> 8) & 0xff); +} + +static void g364fb_ctrl_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + g364fb_ctrl_writeb(opaque, addr, val & 0xff); + g364fb_ctrl_writeb(opaque, addr + 1, (val >> 8) & 0xff); + g364fb_ctrl_writeb(opaque, addr + 2, (val >> 16) & 0xff); + g364fb_ctrl_writeb(opaque, addr + 3, (val >> 24) & 0xff); +} + +static CPUReadMemoryFunc *g364fb_ctrl_read[3] = { + g364fb_ctrl_readb, + g364fb_ctrl_readw, + g364fb_ctrl_readl, +}; + +static CPUWriteMemoryFunc *g364fb_ctrl_write[3] = { + g364fb_ctrl_writeb, + g364fb_ctrl_writew, + g364fb_ctrl_writel, +}; + +/* called for accesses to video ram */ +static uint32_t g364fb_mem_readb(void *opaque, target_phys_addr_t addr) +{ + G364State *s = opaque; + target_phys_addr_t relative_addr = addr - s->vram_base; + + return s->vram_buffer[relative_addr]; +} + +static uint32_t g364fb_mem_readw(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; + v = g364fb_mem_readb(opaque, addr); + v |= g364fb_mem_readb(opaque, addr + 1) << 8; + return v; +} + +static uint32_t g364fb_mem_readl(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; + v = g364fb_mem_readb(opaque, addr); + v |= g364fb_mem_readb(opaque, addr + 1) << 8; + v |= g364fb_mem_readb(opaque, addr + 2) << 16; + v |= g364fb_mem_readb(opaque, addr + 3) << 24; + return v; +} + +static void g364fb_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + G364State *s = opaque; + target_phys_addr_t relative_addr = addr - s->vram_base; + + s->vram_buffer[relative_addr] = val; +} + +static void g364fb_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + g364fb_mem_writeb(opaque, addr, val & 0xff); + g364fb_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); +} + +static void g364fb_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + g364fb_mem_writeb(opaque, addr, val & 0xff); + g364fb_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); + g364fb_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff); + g364fb_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff); +} + +static CPUReadMemoryFunc *g364fb_mem_read[3] = { + g364fb_mem_readb, + g364fb_mem_readw, + g364fb_mem_readl, +}; + +static CPUWriteMemoryFunc *g364fb_mem_write[3] = { + g364fb_mem_writeb, + g364fb_mem_writew, + g364fb_mem_writel, +}; + +int g364fb_mm_init(DisplayState *ds, + int vram_size, int it_shift, + target_phys_addr_t vram_base, target_phys_addr_t ctrl_base) +{ + G364State *s; + int io_vram, io_ctrl; + + s = qemu_mallocz(sizeof(G364State)); + if (!s) + return -1; + + s->vram_size = vram_size; + s->vram_buffer = qemu_mallocz(s->vram_size); + + qemu_register_reset(g364fb_reset, s); + g364fb_reset(s); + + s->ds = ds; + s->vram_base = vram_base; + + s->console = graphic_console_init(ds, g364fb_update_display, + g364fb_invalidate_display, + g364fb_screen_dump, NULL, s); + + io_vram = cpu_register_io_memory(0, g364fb_mem_read, g364fb_mem_write, s); + cpu_register_physical_memory(s->vram_base, vram_size, io_vram); + + io_ctrl = cpu_register_io_memory(0, g364fb_ctrl_read, g364fb_ctrl_write, s); + cpu_register_physical_memory(ctrl_base, 0x10000, io_ctrl); + + return 0; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/g364fb_template.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/g364fb_template.h --- qemu-0.9.1/hw/g364fb_template.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/g364fb_template.h 2008-08-17 02:44:53.000000000 +0100 @@ -0,0 +1,43 @@ +/* + * QEMU G364 framebuffer Emulator. + * + * Copyright (c) 2007 Hervé Poussineau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +static void glue(g364fb_draw_graphic, BPP)(G364State *s, int full_update) +{ + int i, j; + int w_display; + uint8_t *data_buffer; + uint8_t *data_display, *dd; + + data_buffer = s->vram_buffer; + w_display = s->scr_width * PIXEL_WIDTH / 8; + data_display = s->ds->data; + for(i = 0; i < s->scr_height; i++) { + dd = data_display; + for (j = 0; j < s->scr_width; j++, dd += PIXEL_WIDTH / 8, data_buffer++) { + uint8_t index = *data_buffer; + *((glue(glue(uint, PIXEL_WIDTH), _t) *)dd) = glue(rgb_to_pixel, BPP)( + s->palette[index][0], + s->palette[index][1], + s->palette[index][2]); + } + data_display += s->ds->linesize; + } +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/gt64xxx.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/gt64xxx.c --- qemu-0.9.1/hw/gt64xxx.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/gt64xxx.c 2008-10-26 13:43:07.000000000 +0000 @@ -309,7 +309,7 @@ GT64120State *s = opaque; uint32_t saddr; - if (!(s->regs[GT_PCI0_CMD] & 1)) + if (!(s->regs[GT_CPU] & 0x00001000)) val = bswap32(val); saddr = (addr & 0xfff) >> 2; @@ -530,7 +530,10 @@ s->pci->config_reg = val & 0x80fffffc; break; case GT_PCI0_CFGDATA: - pci_host_data_writel(s->pci, 0, val); + if (!(s->regs[GT_PCI0_CMD] & 1) && (s->pci->config_reg & 0x00fff800)) + val = bswap32(val); + if (s->pci->config_reg & (1u << 31)) + pci_data_write(s->pci->bus, s->pci->config_reg, val, 4); break; /* Interrupts */ @@ -767,7 +770,12 @@ val = s->pci->config_reg; break; case GT_PCI0_CFGDATA: - val = pci_host_data_readl(s->pci, 0); + if (!(s->pci->config_reg & (1 << 31))) + val = 0xffffffff; + else + val = pci_data_read(s->pci->bus, s->pci->config_reg, 4); + if (!(s->regs[GT_PCI0_CMD] & 1) && (s->pci->config_reg & 0x00fff800)) + val = bswap32(val); break; case GT_PCI0_CMD: @@ -840,7 +848,7 @@ break; } - if (!(s->regs[GT_PCI0_CMD] & 1)) + if (!(s->regs[GT_CPU] & 0x00001000)) val = bswap32(val); return val; @@ -883,7 +891,6 @@ } } -extern PCIDevice *piix4_dev; static int pci_irq_levels[4]; static void pci_gt64120_set_irq(qemu_irq *pic, int irq_num, int level) @@ -1069,7 +1076,6 @@ s->regs[GT_PCI1_CFGADDR] = 0x00000000; s->regs[GT_PCI1_CFGDATA] = 0x00000000; s->regs[GT_PCI0_CFGADDR] = 0x00000000; - s->regs[GT_PCI0_CFGDATA] = 0x00000000; /* Interrupt registers are all zeroed at reset */ @@ -1114,8 +1120,10 @@ (void)&pci_host_data_writeb; /* avoid warning */ (void)&pci_host_data_writew; /* avoid warning */ + (void)&pci_host_data_writel; /* avoid warning */ (void)&pci_host_data_readb; /* avoid warning */ (void)&pci_host_data_readw; /* avoid warning */ + (void)&pci_host_data_readl; /* avoid warning */ s = qemu_mallocz(sizeof(GT64120State)); s->pci = qemu_mallocz(sizeof(GT64120PCIState)); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/gumstix.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/gumstix.c --- qemu-0.9.1/hw/gumstix.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/gumstix.c 2008-10-28 10:59:59.000000000 +0000 @@ -41,7 +41,7 @@ static const int sector_len = 128 * 1024; -static void connex_init(int ram_size, int vga_ram_size, +static void connex_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -81,7 +81,7 @@ pxa2xx_gpio_in_get(cpu->gpio)[36]); } -static void verdex_init(int ram_size, int vga_ram_size, +static void verdex_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -122,13 +122,15 @@ } QEMUMachine connex_machine = { - "connex", - "Gumstix Connex (PXA255)", - connex_init, + .name = "connex", + .desc = "Gumstix Connex (PXA255)", + .init = connex_init, + .ram_require = (0x05000000 + PXA2XX_INTERNAL_SIZE) | RAMSIZE_FIXED, }; QEMUMachine verdex_machine = { - "verdex", - "Gumstix Verdex (PXA270)", - verdex_init, + .name = "verdex", + .desc = "Gumstix Verdex (PXA270)", + .init = verdex_init, + .ram_require = (0x12000000 + PXA2XX_INTERNAL_SIZE) | RAMSIZE_FIXED, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/gus.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/gus.c --- qemu-0.9.1/hw/gus.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/gus.c 2008-07-05 14:40:58.000000000 +0100 @@ -0,0 +1,332 @@ +/* + * QEMU Proxy for Gravis Ultrasound GF1 emulation by Tibor "TS" Schütz + * + * Copyright (c) 2002-2005 Vassili Karpov (malc) + * + * 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 "hw.h" +#include "audiodev.h" +#include "audio/audio.h" +#include "isa.h" +#include "gusemu.h" +#include "gustate.h" + +#define dolog(...) AUD_log ("audio", __VA_ARGS__) +#ifdef DEBUG +#define ldebug(...) dolog (__VA_ARGS__) +#else +#define ldebug(...) +#endif + +#ifdef WORDS_BIGENDIAN +#define GUS_ENDIANNESS 1 +#else +#define GUS_ENDIANNESS 0 +#endif + +#define IO_READ_PROTO(name) \ + uint32_t name (void *opaque, uint32_t nport) +#define IO_WRITE_PROTO(name) \ + void name (void *opaque, uint32_t nport, uint32_t val) + +static struct { + int port; + int irq; + int dma; + int freq; +} conf = {0x240, 7, 3, 44100}; + +typedef struct GUSState { + GUSEmuState emu; + QEMUSoundCard card; + int freq; + int pos, left, shift, irqs; + GUSsample *mixbuf; + uint8_t himem[1024 * 1024 + 32 + 4096]; + int samples; + SWVoiceOut *voice; + int64_t last_ticks; + qemu_irq *pic; +} GUSState; + +IO_READ_PROTO (gus_readb) +{ + GUSState *s = opaque; + + return gus_read (&s->emu, nport, 1); +} + +IO_READ_PROTO (gus_readw) +{ + GUSState *s = opaque; + + return gus_read (&s->emu, nport, 2); +} + +IO_WRITE_PROTO (gus_writeb) +{ + GUSState *s = opaque; + + gus_write (&s->emu, nport, 1, val); +} + +IO_WRITE_PROTO (gus_writew) +{ + GUSState *s = opaque; + + gus_write (&s->emu, nport, 2, val); +} + +static int write_audio (GUSState *s, int samples) +{ + int net = 0; + int pos = s->pos; + + while (samples) { + int nbytes, wbytes, wsampl; + + nbytes = samples << s->shift; + wbytes = AUD_write ( + s->voice, + s->mixbuf + (pos << (s->shift - 1)), + nbytes + ); + + if (wbytes) { + wsampl = wbytes >> s->shift; + + samples -= wsampl; + pos = (pos + wsampl) % s->samples; + + net += wsampl; + } + else { + break; + } + } + + return net; +} + +static void GUS_callback (void *opaque, int free) +{ + int samples, to_play, net = 0; + GUSState *s = opaque; + + samples = free >> s->shift; + to_play = audio_MIN (samples, s->left); + + while (to_play) { + int written = write_audio (s, to_play); + + if (!written) { + goto reset; + } + + s->left -= written; + to_play -= written; + samples -= written; + net += written; + } + + samples = audio_MIN (samples, s->samples); + if (samples) { + gus_mixvoices (&s->emu, s->freq, samples, s->mixbuf); + + while (samples) { + int written = write_audio (s, samples); + if (!written) { + break; + } + samples -= written; + net += written; + } + } + s->left = samples; + +reset: + gus_irqgen (&s->emu, (double) (net * 1000000) / s->freq); +} + +int GUS_irqrequest (GUSEmuState *emu, int hwirq, int n) +{ + GUSState *s = emu->opaque; + /* qemu_irq_lower (s->pic[hwirq]); */ + qemu_irq_raise (s->pic[hwirq]); + s->irqs += n; + ldebug ("irqrequest %d %d %d\n", hwirq, n, s->irqs); + return n; +} + +void GUS_irqclear (GUSEmuState *emu, int hwirq) +{ + GUSState *s = emu->opaque; + ldebug ("irqclear %d %d\n", hwirq, s->irqs); + qemu_irq_lower (s->pic[hwirq]); + s->irqs -= 1; +#ifdef IRQ_STORM + if (s->irqs > 0) { + qemu_irq_raise (s->pic[hwirq]); + } +#endif +} + +void GUS_dmarequest (GUSEmuState *der) +{ + /* GUSState *s = (GUSState *) der; */ + ldebug ("dma request %d\n", der->gusdma); + DMA_hold_DREQ (der->gusdma); +} + +int GUS_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len) +{ + GUSState *s = opaque; + char tmpbuf[4096]; + int pos = dma_pos, mode, left = dma_len - dma_pos; + + ldebug ("read DMA %#x %d\n", dma_pos, dma_len); + mode = DMA_get_channel_mode (s->emu.gusdma); + while (left) { + int to_copy = audio_MIN ((size_t) left, sizeof (tmpbuf)); + int copied; + + ldebug ("left=%d to_copy=%d pos=%d\n", left, to_copy, pos); + copied = DMA_read_memory (nchan, tmpbuf, pos, to_copy); + gus_dma_transferdata (&s->emu, tmpbuf, copied, left == copied); + left -= copied; + pos += copied; + } + + if (0 == ((mode >> 4) & 1)) { + DMA_release_DREQ (s->emu.gusdma); + } + return dma_len; +} + +static void GUS_save (QEMUFile *f, void *opaque) +{ + GUSState *s = opaque; + + qemu_put_be32 (f, s->pos); + qemu_put_be32 (f, s->left); + qemu_put_be32 (f, s->shift); + qemu_put_be32 (f, s->irqs); + qemu_put_be32 (f, s->samples); + qemu_put_be64 (f, s->last_ticks); + qemu_put_buffer (f, s->himem, sizeof (s->himem)); +} + +static int GUS_load (QEMUFile *f, void *opaque, int version_id) +{ + GUSState *s = opaque; + + if (version_id != 2) + return -EINVAL; + + s->pos = qemu_get_be32 (f); + s->left = qemu_get_be32 (f); + s->shift = qemu_get_be32 (f); + s->irqs = qemu_get_be32 (f); + s->samples = qemu_get_be32 (f); + s->last_ticks = qemu_get_be64 (f); + qemu_get_buffer (f, s->himem, sizeof (s->himem)); + return 0; +} + +int GUS_init (AudioState *audio, qemu_irq *pic) +{ + GUSState *s; + audsettings_t as; + + if (!audio) { + dolog ("No audio state\n"); + return -1; + } + + s = qemu_mallocz (sizeof (*s)); + if (!s) { + dolog ("Could not allocate memory for GUS (%zu bytes)\n", + sizeof (*s)); + return -1; + } + + AUD_register_card (audio, "gus", &s->card); + + as.freq = conf.freq; + as.nchannels = 2; + as.fmt = AUD_FMT_S16; + as.endianness = GUS_ENDIANNESS; + + s->voice = AUD_open_out ( + &s->card, + NULL, + "gus", + s, + GUS_callback, + &as + ); + + if (!s->voice) { + AUD_remove_card (&s->card); + qemu_free (s); + return -1; + } + + s->shift = 2; + s->samples = AUD_get_buffer_size_out (s->voice) >> s->shift; + s->mixbuf = qemu_mallocz (s->samples << s->shift); + if (!s->mixbuf) { + AUD_close_out (&s->card, s->voice); + AUD_remove_card (&s->card); + qemu_free (s); + return -1; + } + + register_ioport_write (conf.port, 1, 1, gus_writeb, s); + register_ioport_write (conf.port, 1, 2, gus_writew, s); + + register_ioport_read ((conf.port + 0x100) & 0xf00, 1, 1, gus_readb, s); + register_ioport_read ((conf.port + 0x100) & 0xf00, 1, 2, gus_readw, s); + + register_ioport_write (conf.port + 6, 10, 1, gus_writeb, s); + register_ioport_write (conf.port + 6, 10, 2, gus_writew, s); + register_ioport_read (conf.port + 6, 10, 1, gus_readb, s); + register_ioport_read (conf.port + 6, 10, 2, gus_readw, s); + + + register_ioport_write (conf.port + 0x100, 8, 1, gus_writeb, s); + register_ioport_write (conf.port + 0x100, 8, 2, gus_writew, s); + register_ioport_read (conf.port + 0x100, 8, 1, gus_readb, s); + register_ioport_read (conf.port + 0x100, 8, 2, gus_readw, s); + + DMA_register_channel (conf.dma, GUS_read_DMA, s); + s->emu.gusirq = conf.irq; + s->emu.gusdma = conf.dma; + s->emu.himemaddr = s->himem; + s->emu.gusdatapos = s->emu.himemaddr + 1024 * 1024 + 32; + s->emu.opaque = s; + s->freq = conf.freq; + s->pic = pic; + + AUD_set_active_out (s->voice, 1); + + register_savevm ("gus", 0, 2, GUS_save, GUS_load, s); + return 0; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/gusemu.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/gusemu.h --- qemu-0.9.1/hw/gusemu.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/gusemu.h 2008-06-08 02:42:47.000000000 +0100 @@ -0,0 +1,105 @@ +/* + * GUSEMU32 - API + * + * Copyright (C) 2000-2007 Tibor "TS" Schütz + * + * 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. + */ + +#ifndef GUSEMU_H +#define GUSEMU_H + +/* data types (need to be adjusted if neither a VC6 nor a C99 compatible compiler is used) */ + +#if defined _WIN32 && defined _MSC_VER /* doesnt support other win32 compilers yet, do it yourself... */ + typedef unsigned char GUSbyte; + typedef unsigned short GUSword; + typedef unsigned int GUSdword; + typedef signed char GUSchar; + typedef signed short GUSsample; +#else + #include + typedef int8_t GUSchar; + typedef uint8_t GUSbyte; + typedef uint16_t GUSword; + typedef uint32_t GUSdword; + typedef int16_t GUSsample; +#endif + +typedef struct _GUSEmuState +{ + GUSbyte *himemaddr; /* 1024*1024 bytes used for storing uploaded samples (+32 additional bytes for read padding) */ + GUSbyte *gusdatapos; /* (gusdataend-gusdata) bytes used for storing emulated GF1/mixer register states (32*32+4 bytes in initial GUSemu32 version) */ + int gusirq; + int gusdma; + unsigned int timer1fraction; + unsigned int timer2fraction; + void *opaque; +} GUSEmuState; + +/* ** Callback functions needed: */ +/* NMI is defined as hwirq=-1 (not supported (yet?)) */ +/* GUS_irqrequest returns the number of IRQs actually scheduled into the virtual machine */ +/* Level triggered IRQ simulations normally return 1 */ +/* Event triggered IRQ simulation can safely ignore GUS_irqclear calls */ +int GUS_irqrequest(GUSEmuState *state, int hwirq, int num);/* needed in both mixer and bus emulation functions. */ +void GUS_irqclear( GUSEmuState *state, int hwirq); /* used by gus_write() only - can be left empty for mixer functions */ +void GUS_dmarequest(GUSEmuState *state); /* used by gus_write() only - can be left empty for mixer functions */ + +/* ** ISA bus interface functions: */ + +/* Port I/O handlers */ +/* support the following ports: */ +/* 2x0,2x6,2x8...2xF,3x0...3x7; */ +/* optional: 388,389 (at least writes should be forwarded or some GUS detection algorithms will fail) */ +/* data is passed in host byte order */ +unsigned int gus_read( GUSEmuState *state, int port, int size); +void gus_write(GUSEmuState *state, int port, int size, unsigned int data); +/* size is given in bytes (1 for byte, 2 for word) */ + +/* DMA data transfer function */ +/* data pointed to is passed in native x86 order */ +void gus_dma_transferdata(GUSEmuState *state, char *dma_addr, unsigned int count, int TC); +/* Called back by GUS_start_DMA as soon as the emulated DMA controller is ready for a transfer to or from GUS */ +/* (might be immediately if the DMA controller was programmed first) */ +/* dma_addr is an already translated address directly pointing to the beginning of the memory block */ +/* do not forget to update DMA states after the call, including the DREQ and TC flags */ +/* it is possible to break down a single transfer into multiple ones, but take care that: */ +/* -dma_count is actually count-1 */ +/* -before and during a transfer, DREQ is set and TC cleared */ +/* -when calling gus_dma_transferdata(), TC is only set true for call transfering the last byte */ +/* -after the last transfer, DREQ is cleared and TC is set */ + +/* ** GF1 mixer emulation functions: */ +/* Usually, gus_irqgen should be called directly after gus_mixvoices if you can meet the recommended ranges. */ +/* If the interrupts are executed immediately (i.e., are synchronous), it may be useful to break this */ +/* down into a sequence of gus_mixvoice();gus_irqgen(); calls while mixing an audio block. */ +/* If the interrupts are asynchronous, it may be needed to use a separate thread mixing into a temporary */ +/* audio buffer in order to avoid quality loss caused by large numsamples and elapsed_time values. */ + +void gus_mixvoices(GUSEmuState *state, unsigned int playback_freq, unsigned int numsamples, GUSsample *bufferpos); +/* recommended range: 10 < numsamples < 100 */ +/* lower values may result in increased rounding error, higher values often cause audible timing delays */ + +void gus_irqgen(GUSEmuState *state, unsigned int elapsed_time); +/* recommended range: 80us < elapsed_time < max(1000us, numsamples/playback_freq) */ +/* lower values won´t provide any benefit at all, higher values can cause audible timing delays */ +/* note: masked timers are also calculated by this function, thus it might be needed even without any IRQs in use! */ + +#endif /* gusemu.h */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/gusemu_hal.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/gusemu_hal.c --- qemu-0.9.1/hw/gusemu_hal.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/gusemu_hal.c 2008-01-14 22:09:11.000000000 +0000 @@ -0,0 +1,554 @@ +/* + * GUSEMU32 - bus interface part + * + * Copyright (C) 2000-2007 Tibor "TS" Schütz + * + * 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. + */ + +/* + * TODO: check mixer: see 7.20 of sdk for panning pos (applies to all gus models?)? + */ + +#include "gustate.h" +#include "gusemu.h" + +#define GUSregb(position) (* (gusptr+(position))) +#define GUSregw(position) (*(GUSword *) (gusptr+(position))) +#define GUSregd(position) (*(GUSdword *)(gusptr+(position))) + +/* size given in bytes */ +unsigned int gus_read(GUSEmuState * state, int port, int size) +{ + int value_read = 0; + + GUSbyte *gusptr; + gusptr = state->gusdatapos; + GUSregd(portaccesses)++; + + switch (port & 0xff0f) + { + /* MixerCtrlReg (read not supported on GUS classic) */ + /* case 0x200: return GUSregb(MixerCtrlReg2x0); */ + case 0x206: /* IRQstatReg / SB2x6IRQ */ + /* adlib/sb bits set in port handlers */ + /* timer/voice bits set in gus_irqgen() */ + /* dma bit set in gus_dma_transferdata */ + /* midi not implemented yet */ + return GUSregb(IRQStatReg2x6); + /* case 0x308: */ /* AdLib388 */ + case 0x208: + if (GUSregb(GUS45TimerCtrl) & 1) + return GUSregb(TimerStatus2x8); + return GUSregb(AdLibStatus2x8); /* AdLibStatus */ + case 0x309: /* AdLib389 */ + case 0x209: + return GUSregb(AdLibData2x9); /* AdLibData */ + case 0x20A: + return GUSregb(AdLibCommand2xA); /* AdLib2x8_2xA */ + +#if 0 + case 0x20B: /* GUS hidden registers (read not supported on GUS classic) */ + switch (GUSregb(RegCtrl_2xF) & 0x07) + { + case 0: /* IRQ/DMA select */ + if (GUSregb(MixerCtrlReg2x0) & 0x40) + return GUSregb(IRQ_2xB); /* control register select bit */ + else + return GUSregb(DMA_2xB); + /* case 1-5: */ /* general purpose emulation regs */ + /* return ... */ /* + status reset reg (write only) */ + case 6: + return GUSregb(Jumper_2xB); /* Joystick/MIDI enable (JumperReg) */ + default:; + } + break; +#endif + + case 0x20C: /* SB2xCd */ + value_read = GUSregb(SB2xCd); + if (GUSregb(StatRead_2xF) & 0x20) + GUSregb(SB2xCd) ^= 0x80; /* toggle MSB on read */ + return value_read; + /* case 0x20D: */ /* SB2xD is write only -> 2xE writes to it*/ + case 0x20E: + if (GUSregb(RegCtrl_2xF) & 0x80) /* 2xE read IRQ enabled? */ + { + GUSregb(StatRead_2xF) |= 0x80; + GUS_irqrequest(state, state->gusirq, 1); + } + return GUSregb(SB2xE); /* SB2xE */ + case 0x20F: /* StatRead_2xF */ + /*set/clear fixed bits */ + /*value_read = (GUSregb(StatRead_2xF) & 0xf9)|1; */ /*(LSB not set on GUS classic!)*/ + value_read = (GUSregb(StatRead_2xF) & 0xf9); + if (GUSregb(MixerCtrlReg2x0) & 0x08) + value_read |= 2; /* DMA/IRQ enabled flag */ + return value_read; + /* case 0x300: */ /* MIDI (not implemented) */ + /* case 0x301: */ /* MIDI (not implemented) */ + case 0x302: + return GUSregb(VoiceSelReg3x2); /* VoiceSelReg */ + case 0x303: + return GUSregb(FunkSelReg3x3); /* FunkSelReg */ + case 0x304: /* DataRegLoByte3x4 + DataRegWord3x4 */ + case 0x305: /* DataRegHiByte3x5 */ + switch (GUSregb(FunkSelReg3x3)) + { + /* common functions */ + case 0x41: /* DramDMAContrReg */ + value_read = GUSregb(GUS41DMACtrl); /* &0xfb */ + GUSregb(GUS41DMACtrl) &= 0xbb; + if (state->gusdma >= 4) + value_read |= 0x04; + if (GUSregb(IRQStatReg2x6) & 0x80) + { + value_read |= 0x40; + GUSregb(IRQStatReg2x6) &= 0x7f; + if (!GUSregb(IRQStatReg2x6)) + GUS_irqclear(state, state->gusirq); + } + return (GUSbyte) value_read; + /* DramDMAmemPosReg */ + /* case 0x42: value_read=GUSregw(GUS42DMAStart); break;*/ + /* 43h+44h write only */ + case 0x45: + return GUSregb(GUS45TimerCtrl); /* TimerCtrlReg */ + /* 46h+47h write only */ + /* 48h: samp freq - write only */ + case 0x49: + return GUSregb(GUS49SampCtrl) & 0xbf; /* SampCtrlReg */ + /* case 4bh: */ /* joystick trim not supported */ + /* case 0x4c: return GUSregb(GUS4cReset); */ /* GUSreset: write only*/ + /* voice specific functions */ + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8a: + case 0x8b: + case 0x8c: + case 0x8d: + { + int offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f); + offset += ((int) GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */ + value_read = GUSregw(offset); + } + break; + /* voice unspecific functions */ + case 0x8e: /* NumVoice */ + return GUSregb(NumVoices); + case 0x8f: /* irqstatreg */ + /* (pseudo IRQ-FIFO is processed during a gus_write(0x3X3,0x8f)) */ + return GUSregb(SynVoiceIRQ8f); + default: + return 0xffff; + } + if (size == 1) + { + if ((port & 0xff0f) == 0x305) + value_read = value_read >> 8; + value_read &= 0xff; + } + return (GUSword) value_read; + /* case 0x306: */ /* Mixer/Version info */ + /* return 0xff; */ /* Pre 3.6 boards, ICS mixer NOT present */ + case 0x307: /* DRAMaccess */ + { + GUSbyte *adr; + adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff); + return *adr; + } + default:; + } + return 0xffff; +} + +void gus_write(GUSEmuState * state, int port, int size, unsigned int data) +{ + GUSbyte *gusptr; + gusptr = state->gusdatapos; + GUSregd(portaccesses)++; + + switch (port & 0xff0f) + { + case 0x200: /* MixerCtrlReg */ + GUSregb(MixerCtrlReg2x0) = (GUSbyte) data; + break; + case 0x206: /* IRQstatReg / SB2x6IRQ */ + if (GUSregb(GUS45TimerCtrl) & 0x20) /* SB IRQ enabled? -> set 2x6IRQ bit */ + { + GUSregb(TimerStatus2x8) |= 0x08; + GUSregb(IRQStatReg2x6) = 0x10; + GUS_irqrequest(state, state->gusirq, 1); + } + break; + case 0x308: /* AdLib 388h */ + case 0x208: /* AdLibCommandReg */ + GUSregb(AdLibCommand2xA) = (GUSbyte) data; + break; + case 0x309: /* AdLib 389h */ + case 0x209: /* AdLibDataReg */ + if ((GUSregb(AdLibCommand2xA) == 0x04) && (!(GUSregb(GUS45TimerCtrl) & 1))) /* GUS auto timer mode enabled? */ + { + if (data & 0x80) + GUSregb(TimerStatus2x8) &= 0x1f; /* AdLib IRQ reset? -> clear maskable adl. timer int regs */ + else + GUSregb(TimerDataReg2x9) = (GUSbyte) data; + } + else + { + GUSregb(AdLibData2x9) = (GUSbyte) data; + if (GUSregb(GUS45TimerCtrl) & 0x02) + { + GUSregb(TimerStatus2x8) |= 0x01; + GUSregb(IRQStatReg2x6) = 0x10; + GUS_irqrequest(state, state->gusirq, 1); + } + } + break; + case 0x20A: + GUSregb(AdLibStatus2x8) = (GUSbyte) data; + break; /* AdLibStatus2x8 */ + case 0x20B: /* GUS hidden registers */ + switch (GUSregb(RegCtrl_2xF) & 0x7) + { + case 0: + if (GUSregb(MixerCtrlReg2x0) & 0x40) + GUSregb(IRQ_2xB) = (GUSbyte) data; /* control register select bit */ + else + GUSregb(DMA_2xB) = (GUSbyte) data; + break; + /* case 1-4: general purpose emulation regs */ + case 5: /* clear stat reg 2xF */ + GUSregb(StatRead_2xF) = 0; /* ToDo: is this identical with GUS classic? */ + if (!GUSregb(IRQStatReg2x6)) + GUS_irqclear(state, state->gusirq); + break; + case 6: /* Jumper reg (Joystick/MIDI enable) */ + GUSregb(Jumper_2xB) = (GUSbyte) data; + break; + default:; + } + break; + case 0x20C: /* SB2xCd */ + if (GUSregb(GUS45TimerCtrl) & 0x20) + { + GUSregb(TimerStatus2x8) |= 0x10; /* SB IRQ enabled? -> set 2xCIRQ bit */ + GUSregb(IRQStatReg2x6) = 0x10; + GUS_irqrequest(state, state->gusirq, 1); + } + case 0x20D: /* SB2xCd no IRQ */ + GUSregb(SB2xCd) = (GUSbyte) data; + break; + case 0x20E: /* SB2xE */ + GUSregb(SB2xE) = (GUSbyte) data; + break; + case 0x20F: + GUSregb(RegCtrl_2xF) = (GUSbyte) data; + break; /* CtrlReg2xF */ + case 0x302: /* VoiceSelReg */ + GUSregb(VoiceSelReg3x2) = (GUSbyte) data; + break; + case 0x303: /* FunkSelReg */ + GUSregb(FunkSelReg3x3) = (GUSbyte) data; + if ((GUSbyte) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */ + { + int voice; + if (GUSregd(voicewavetableirq)) /* WavetableIRQ */ + { + for (voice = 0; voice < 31; voice++) + { + if (GUSregd(voicewavetableirq) & (1 << voice)) + { + GUSregd(voicewavetableirq) ^= (1 << voice); /* clear IRQ bit */ + GUSregb(voice << 5) &= 0x7f; /* clear voice reg irq bit */ + if (!GUSregd(voicewavetableirq)) + GUSregb(IRQStatReg2x6) &= 0xdf; + if (!GUSregb(IRQStatReg2x6)) + GUS_irqclear(state, state->gusirq); + GUSregb(SynVoiceIRQ8f) = voice | 0x60; /* (bit==0 => IRQ wartend) */ + return; + } + } + } + else if (GUSregd(voicevolrampirq)) /* VolRamp IRQ */ + { + for (voice = 0; voice < 31; voice++) + { + if (GUSregd(voicevolrampirq) & (1 << voice)) + { + GUSregd(voicevolrampirq) ^= (1 << voice); /* clear IRQ bit */ + GUSregb((voice << 5) + VSRVolRampControl) &= 0x7f; /* clear voice volume reg irq bit */ + if (!GUSregd(voicevolrampirq)) + GUSregb(IRQStatReg2x6) &= 0xbf; + if (!GUSregb(IRQStatReg2x6)) + GUS_irqclear(state, state->gusirq); + GUSregb(SynVoiceIRQ8f) = voice | 0x80; /* (bit==0 => IRQ wartend) */ + return; + } + } + } + GUSregb(SynVoiceIRQ8f) = 0xe8; /* kein IRQ wartet */ + } + break; + case 0x304: + case 0x305: + { + GUSword writedata = (GUSword) data; + GUSword readmask = 0x0000; + if (size == 1) + { + readmask = 0xff00; + writedata &= 0xff; + if ((port & 0xff0f) == 0x305) + { + writedata = (GUSword) (writedata << 8); + readmask = 0x00ff; + } + } + switch (GUSregb(FunkSelReg3x3)) + { + /* voice specific functions */ + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + { + int offset; + if (!(GUSregb(GUS4cReset) & 0x01)) + break; /* reset flag active? */ + offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f); + offset += (GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */ + GUSregw(offset) = (GUSword) ((GUSregw(offset) & readmask) | writedata); + } + break; + /* voice unspecific functions */ + case 0x0e: /* NumVoices */ + GUSregb(NumVoices) = (GUSbyte) data; + break; + /* case 0x0f: */ /* read only */ + /* common functions */ + case 0x41: /* DramDMAContrReg */ + GUSregb(GUS41DMACtrl) = (GUSbyte) data; + if (data & 0x01) + GUS_dmarequest(state); + break; + case 0x42: /* DramDMAmemPosReg */ + GUSregw(GUS42DMAStart) = (GUSregw(GUS42DMAStart) & readmask) | writedata; + GUSregb(GUS50DMAHigh) &= 0xf; /* compatibility stuff... */ + break; + case 0x43: /* DRAMaddrLo */ + GUSregd(GUSDRAMPOS24bit) = + (GUSregd(GUSDRAMPOS24bit) & (readmask | 0xff0000)) | writedata; + break; + case 0x44: /* DRAMaddrHi */ + GUSregd(GUSDRAMPOS24bit) = + (GUSregd(GUSDRAMPOS24bit) & 0xffff) | ((data & 0x0f) << 16); + break; + case 0x45: /* TCtrlReg */ + GUSregb(GUS45TimerCtrl) = (GUSbyte) data; + if (!(data & 0x20)) + GUSregb(TimerStatus2x8) &= 0xe7; /* sb IRQ dis? -> clear 2x8/2xC sb IRQ flags */ + if (!(data & 0x02)) + GUSregb(TimerStatus2x8) &= 0xfe; /* adlib data IRQ dis? -> clear 2x8 adlib IRQ flag */ + if (!(GUSregb(TimerStatus2x8) & 0x19)) + GUSregb(IRQStatReg2x6) &= 0xef; /* 0xe6; $$clear IRQ if both IRQ bits are inactive or cleared */ + /* catch up delayed timer IRQs: */ + if ((GUSregw(TimerIRQs) > 1) && (GUSregb(TimerDataReg2x9) & 3)) + { + if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */ + { + if (!(GUSregb(TimerDataReg2x9) & 0x40)) + GUSregb(TimerStatus2x8) |= 0xc0; /* maskable bits */ + if (data & 4) /* timer1 irq enable */ + { + GUSregb(TimerStatus2x8) |= 4; /* nonmaskable bit */ + GUSregb(IRQStatReg2x6) |= 4; /* timer 1 irq pending */ + } + } + if (GUSregb(TimerDataReg2x9) & 2) /* start timer 2 (320us decrement rate) */ + { + if (!(GUSregb(TimerDataReg2x9) & 0x20)) + GUSregb(TimerStatus2x8) |= 0xa0; /* maskable bits */ + if (data & 8) /* timer2 irq enable */ + { + GUSregb(TimerStatus2x8) |= 2; /* nonmaskable bit */ + GUSregb(IRQStatReg2x6) |= 8; /* timer 2 irq pending */ + } + } + GUSregw(TimerIRQs)--; + if (GUSregw(BusyTimerIRQs) > 1) + GUSregw(BusyTimerIRQs)--; + else + GUSregw(BusyTimerIRQs) = + GUS_irqrequest(state, state->gusirq, GUSregw(TimerIRQs)); + } + else + GUSregw(TimerIRQs) = 0; + + if (!(data & 0x04)) + { + GUSregb(TimerStatus2x8) &= 0xfb; /* clear non-maskable timer1 bit */ + GUSregb(IRQStatReg2x6) &= 0xfb; + } + if (!(data & 0x08)) + { + GUSregb(TimerStatus2x8) &= 0xfd; /* clear non-maskable timer2 bit */ + GUSregb(IRQStatReg2x6) &= 0xf7; + } + if (!GUSregb(IRQStatReg2x6)) + GUS_irqclear(state, state->gusirq); + break; + case 0x46: /* Counter1 */ + GUSregb(GUS46Counter1) = (GUSbyte) data; + break; + case 0x47: /* Counter2 */ + GUSregb(GUS47Counter2) = (GUSbyte) data; + break; + /* case 0x48: */ /* sampling freq reg not emulated (same as interwave) */ + case 0x49: /* SampCtrlReg */ + GUSregb(GUS49SampCtrl) = (GUSbyte) data; + break; + /* case 0x4b: */ /* joystick trim not emulated */ + case 0x4c: /* GUSreset */ + GUSregb(GUS4cReset) = (GUSbyte) data; + if (!(GUSregb(GUS4cReset) & 1)) /* reset... */ + { + GUSregd(voicewavetableirq) = 0; + GUSregd(voicevolrampirq) = 0; + GUSregw(TimerIRQs) = 0; + GUSregw(BusyTimerIRQs) = 0; + GUSregb(NumVoices) = 0xcd; + GUSregb(IRQStatReg2x6) = 0; + GUSregb(TimerStatus2x8) = 0; + GUSregb(AdLibData2x9) = 0; + GUSregb(TimerDataReg2x9) = 0; + GUSregb(GUS41DMACtrl) = 0; + GUSregb(GUS45TimerCtrl) = 0; + GUSregb(GUS49SampCtrl) = 0; + GUSregb(GUS4cReset) &= 0xf9; /* clear IRQ and DAC enable bits */ + GUS_irqclear(state, state->gusirq); + } + /* IRQ enable bit checked elsewhere */ + /* EnableDAC bit may be used by external callers */ + break; + } + } + break; + case 0x307: /* DRAMaccess */ + { + GUSbyte *adr; + adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff); + *adr = (GUSbyte) data; + } + break; + } +} + +/* Attention when breaking up a single DMA transfer to multiple ones: + * it may lead to multiple terminal count interrupts and broken transfers: + * + * 1. Whenever you transfer a piece of data, the gusemu callback is invoked + * 2. The callback may generate a TC irq (if the register was set up to do so) + * 3. The irq may result in the program using the GUS to reprogram the GUS + * + * Some programs also decide to upload by just checking if TC occurs + * (via interrupt or a cleared GUS dma flag) + * and then start the next transfer, without checking DMA state + * + * Thus: Always make sure to set the TC flag correctly! + * + * Note that the genuine GUS had a granularity of 16 bytes/words for low/high DMA + * while later cards had atomic granularity provided by an additional GUS50DMAHigh register + * GUSemu also uses this register to support byte-granular transfers for better compatibility + * with emulators other than GUSemu32 + */ + +void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int count, int TC) +{ + /* this function gets called by the callback function as soon as a DMA transfer is about to start + * dma_addr is a translated address within accessible memory, not the physical one, + * count is (real dma count register)+1 + * note that the amount of bytes transfered is fully determined by values in the DMA registers + * do not forget to update DMA states after transferring the entire block: + * DREQ cleared & TC asserted after the _whole_ transfer */ + + char *srcaddr; + char *destaddr; + char msbmask = 0; + GUSbyte *gusptr; + gusptr = state->gusdatapos; + + srcaddr = dma_addr; /* system memory address */ + { + int offset = (GUSregw(GUS42DMAStart) << 4) + (GUSregb(GUS50DMAHigh) & 0xf); + if (state->gusdma >= 4) + offset = (offset & 0xc0000) + (2 * (offset & 0x1fff0)); /* 16 bit address translation */ + destaddr = (char *) state->himemaddr + offset; /* wavetable RAM adress */ + } + + GUSregw(GUS42DMAStart) += (GUSword) (count >> 4); /* ToDo: add 16bit GUS page limit? */ + GUSregb(GUS50DMAHigh) = (GUSbyte) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */ + + if (GUSregb(GUS41DMACtrl) & 0x02) /* direction, 0 := sysram->gusram */ + { + char *tmpaddr = destaddr; + destaddr = srcaddr; + srcaddr = tmpaddr; + } + + if ((GUSregb(GUS41DMACtrl) & 0x80) && (!(GUSregb(GUS41DMACtrl) & 0x02))) + msbmask = (const char) 0x80; /* invert MSB */ + for (; count > 0; count--) + { + if (GUSregb(GUS41DMACtrl) & 0x40) + *(destaddr++) = *(srcaddr++); /* 16 bit lobyte */ + else + *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 8 bit */ + if (state->gusdma >= 4) + *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 16 bit hibyte */ + } + + if (TC) + { + (GUSregb(GUS41DMACtrl)) &= 0xfe; /* clear DMA request bit */ + if (GUSregb(GUS41DMACtrl) & 0x20) /* DMA terminal count IRQ */ + { + GUSregb(IRQStatReg2x6) |= 0x80; + GUS_irqrequest(state, state->gusirq, 1); + } + } +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/gusemu_mixer.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/gusemu_mixer.c --- qemu-0.9.1/hw/gusemu_mixer.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/gusemu_mixer.c 2008-06-08 02:42:47.000000000 +0100 @@ -0,0 +1,240 @@ +/* + * GUSEMU32 - mixing engine (similar to Interwave GF1 compatibility) + * + * Copyright (C) 2000-2007 Tibor "TS" Schütz + * + * 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 "gusemu.h" +#include "gustate.h" + +#define GUSregb(position) (* (gusptr+(position))) +#define GUSregw(position) (*(GUSword *) (gusptr+(position))) +#define GUSregd(position) (*(GUSdword *)(gusptr+(position))) + +#define GUSvoice(position) (*(GUSword *)(voiceptr+(position))) + +/* samples are always 16bit stereo (4 bytes each, first right then left interleaved) */ +void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int numsamples, + GUSsample *bufferpos) +{ + /* note that byte registers are stored in the upper half of each voice register! */ + GUSbyte *gusptr; + int Voice; + GUSword *voiceptr; + + unsigned int count; + for (count = 0; count < numsamples * 2; count++) + *(bufferpos + count) = 0; /* clear */ + + gusptr = state->gusdatapos; + voiceptr = (GUSword *) gusptr; + if (!(GUSregb(GUS4cReset) & 0x01)) /* reset flag active? */ + return; + + for (Voice = 0; Voice <= (GUSregb(NumVoices) & 31); Voice++) + { + if (GUSvoice(wVSRControl) & 0x200) + GUSvoice(wVSRControl) |= 0x100; /* voice stop request */ + if (GUSvoice(wVSRVolRampControl) & 0x200) + GUSvoice(wVSRVolRampControl) |= 0x100; /* Volume ramp stop request */ + if (!(GUSvoice(wVSRControl) & GUSvoice(wVSRVolRampControl) & 0x100)) /* neither voice nor volume calculation active - save some time here ;) */ + { + unsigned int sample; + + unsigned int LoopStart = (GUSvoice(wVSRLoopStartHi) << 16) | GUSvoice(wVSRLoopStartLo); /* 23.9 format */ + unsigned int LoopEnd = (GUSvoice(wVSRLoopEndHi) << 16) | GUSvoice(wVSRLoopEndLo); /* 23.9 format */ + unsigned int CurrPos = (GUSvoice(wVSRCurrPosHi) << 16) | GUSvoice(wVSRCurrPosLo); /* 23.9 format */ + int VoiceIncrement = ((((unsigned long) GUSvoice(wVSRFreq) * 44100) / playback_freq) * (14 >> 1)) / + ((GUSregb(NumVoices) & 31) + 1); /* 6.10 increment/frame to 23.9 increment/sample */ + + int PanningPos = (GUSvoice(wVSRPanning) >> 8) & 0xf; + + unsigned int Volume32 = 32 * GUSvoice(wVSRCurrVol); /* 32 times larger than original gus for maintaining precision while ramping */ + unsigned int StartVol32 = (GUSvoice(wVSRVolRampStartVol) & 0xff00) * 32; + unsigned int EndVol32 = (GUSvoice(wVSRVolRampEndVol) & 0xff00) * 32; + int VolumeIncrement32 = (32 * 16 * (GUSvoice(wVSRVolRampRate) & 0x3f00) >> 8) >> ((((GUSvoice(wVSRVolRampRate) & 0xc000) >> 8) >> 6) * 3); /* including 1/8/64/512 volume speed divisor */ + VolumeIncrement32 = (((VolumeIncrement32 * 44100 / 2) / playback_freq) * 14) / ((GUSregb(NumVoices) & 31) + 1); /* adjust ramping speed to playback speed */ + + if (GUSvoice(wVSRControl) & 0x4000) + VoiceIncrement = -VoiceIncrement; /* reverse playback */ + if (GUSvoice(wVSRVolRampControl) & 0x4000) + VolumeIncrement32 = -VolumeIncrement32; /* reverse ramping */ + + for (sample = 0; sample < numsamples; sample++) + { + int sample1, sample2, Volume; + if (GUSvoice(wVSRControl) & 0x400) /* 16bit */ + { + int offset = ((CurrPos >> 9) & 0xc0000) + (((CurrPos >> 9) & 0x1ffff) << 1); + GUSchar *adr; + adr = (GUSchar *) state->himemaddr + offset; + sample1 = (*adr & 0xff) + (*(adr + 1) * 256); + sample2 = (*(adr + 2) & 0xff) + (*(adr + 2 + 1) * 256); + } + else /* 8bit */ + { + int offset = (CurrPos >> 9) & 0xfffff; + GUSchar *adr; + adr = (GUSchar *) state->himemaddr + offset; + sample1 = (*adr) * 256; + sample2 = (*(adr + 1)) * 256; + } + + Volume = ((((Volume32 >> (4 + 5)) & 0xff) + 256) << (Volume32 >> ((4 + 8) + 5))) / 512; /* semi-logarithmic volume, +5 due to additional precision */ + sample1 = (((sample1 * Volume) >> 16) * (512 - (CurrPos % 512))) / 512; + sample2 = (((sample2 * Volume) >> 16) * (CurrPos % 512)) / 512; + sample1 += sample2; + + if (!(GUSvoice(wVSRVolRampControl) & 0x100)) + { + Volume32 += VolumeIncrement32; + if ((GUSvoice(wVSRVolRampControl) & 0x4000) ? (Volume32 <= StartVol32) : (Volume32 >= EndVol32)) /* ramp up boundary cross */ + { + if (GUSvoice(wVSRVolRampControl) & 0x2000) + GUSvoice(wVSRVolRampControl) |= 0x8000; /* volramp IRQ enabled? -> IRQ wait flag */ + if (GUSvoice(wVSRVolRampControl) & 0x800) /* loop enabled */ + { + if (GUSvoice(wVSRVolRampControl) & 0x1000) /* bidir. loop */ + { + GUSvoice(wVSRVolRampControl) ^= 0x4000; /* toggle dir */ + VolumeIncrement32 = -VolumeIncrement32; + } + else + Volume32 = (GUSvoice(wVSRVolRampControl) & 0x4000) ? EndVol32 : StartVol32; /* unidir. loop ramp */ + } + else + { + GUSvoice(wVSRVolRampControl) |= 0x100; + Volume32 = + (GUSvoice(wVSRVolRampControl) & 0x4000) ? StartVol32 : EndVol32; + } + } + } + if ((GUSvoice(wVSRVolRampControl) & 0xa000) == 0xa000) /* volramp IRQ set and enabled? */ + { + GUSregd(voicevolrampirq) |= 1 << Voice; /* set irq slot */ + } + else + { + GUSregd(voicevolrampirq) &= (~(1 << Voice)); /* clear irq slot */ + GUSvoice(wVSRVolRampControl) &= 0x7f00; + } + + if (!(GUSvoice(wVSRControl) & 0x100)) + { + CurrPos += VoiceIncrement; + if ((GUSvoice(wVSRControl) & 0x4000) ? (CurrPos <= LoopStart) : (CurrPos >= LoopEnd)) /* playback boundary cross */ + { + if (GUSvoice(wVSRControl) & 0x2000) + GUSvoice(wVSRControl) |= 0x8000; /* voice IRQ enabled -> IRQ wait flag */ + if (GUSvoice(wVSRControl) & 0x800) /* loop enabled */ + { + if (GUSvoice(wVSRControl) & 0x1000) /* pingpong loop */ + { + GUSvoice(wVSRControl) ^= 0x4000; /* toggle dir */ + VoiceIncrement = -VoiceIncrement; + } + else + CurrPos = (GUSvoice(wVSRControl) & 0x4000) ? LoopEnd : LoopStart; /* unidir. loop */ + } + else if (!(GUSvoice(wVSRVolRampControl) & 0x400)) + GUSvoice(wVSRControl) |= 0x100; /* loop disabled, rollover check */ + } + } + if ((GUSvoice(wVSRControl) & 0xa000) == 0xa000) /* wavetable IRQ set and enabled? */ + { + GUSregd(voicewavetableirq) |= 1 << Voice; /* set irq slot */ + } + else + { + GUSregd(voicewavetableirq) &= (~(1 << Voice)); /* clear irq slot */ + GUSvoice(wVSRControl) &= 0x7f00; + } + + /* mix samples into buffer */ + *(bufferpos + 2 * sample) += (GUSsample) ((sample1 * PanningPos) >> 4); /* right */ + *(bufferpos + 2 * sample + 1) += (GUSsample) ((sample1 * (15 - PanningPos)) >> 4); /* left */ + } + /* write back voice and volume */ + GUSvoice(wVSRCurrVol) = Volume32 / 32; + GUSvoice(wVSRCurrPosHi) = CurrPos >> 16; + GUSvoice(wVSRCurrPosLo) = CurrPos & 0xffff; + } + voiceptr += 16; /* next voice */ + } +} + +void gus_irqgen(GUSEmuState * state, unsigned int elapsed_time) +/* time given in microseconds */ +{ + int requestedIRQs = 0; + GUSbyte *gusptr; + gusptr = state->gusdatapos; + if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */ + { + unsigned int timer1fraction = state->timer1fraction; + int newtimerirqs; + newtimerirqs = (elapsed_time + timer1fraction) / (80 * (256 - GUSregb(GUS46Counter1))); + state->timer1fraction = (elapsed_time + timer1fraction) % (80 * (256 - GUSregb(GUS46Counter1))); + if (newtimerirqs) + { + if (!(GUSregb(TimerDataReg2x9) & 0x40)) + GUSregb(TimerStatus2x8) |= 0xc0; /* maskable bits */ + if (GUSregb(GUS45TimerCtrl) & 4) /* timer1 irq enable */ + { + GUSregb(TimerStatus2x8) |= 4; /* nonmaskable bit */ + GUSregb(IRQStatReg2x6) |= 4; /* timer 1 irq pending */ + GUSregw(TimerIRQs) += newtimerirqs; + requestedIRQs += newtimerirqs; + } + } + } + if (GUSregb(TimerDataReg2x9) & 2) /* start timer 2 (320us decrement rate) */ + { + unsigned int timer2fraction = state->timer2fraction; + int newtimerirqs; + newtimerirqs = (elapsed_time + timer2fraction) / (320 * (256 - GUSregb(GUS47Counter2))); + state->timer2fraction = (elapsed_time + timer2fraction) % (320 * (256 - GUSregb(GUS47Counter2))); + if (newtimerirqs) + { + if (!(GUSregb(TimerDataReg2x9) & 0x20)) + GUSregb(TimerStatus2x8) |= 0xa0; /* maskable bits */ + if (GUSregb(GUS45TimerCtrl) & 8) /* timer2 irq enable */ + { + GUSregb(TimerStatus2x8) |= 2; /* nonmaskable bit */ + GUSregb(IRQStatReg2x6) |= 8; /* timer 2 irq pending */ + GUSregw(TimerIRQs) += newtimerirqs; + requestedIRQs += newtimerirqs; + } + } + } + if (GUSregb(GUS4cReset) & 0x4) /* synth IRQ enable */ + { + if (GUSregd(voicewavetableirq)) + GUSregb(IRQStatReg2x6) |= 0x20; + if (GUSregd(voicevolrampirq)) + GUSregb(IRQStatReg2x6) |= 0x40; + } + if ((!requestedIRQs) && GUSregb(IRQStatReg2x6)) + requestedIRQs++; + if (GUSregb(IRQStatReg2x6)) + GUSregw(BusyTimerIRQs) = GUS_irqrequest(state, state->gusirq, requestedIRQs); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/gustate.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/gustate.h --- qemu-0.9.1/hw/gustate.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/gustate.h 2008-01-14 22:09:11.000000000 +0000 @@ -0,0 +1,132 @@ +/* + * GUSEMU32 - persistent GUS register state + * + * Copyright (C) 2000-2007 Tibor "TS" Schütz + * + * 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. + */ + +#ifndef GUSTATE_H +#define GUSTATE_H + +/*state block offset*/ +#define gusdata (0) + +/* data stored using this structure is in host byte order! */ + +/*access type*/ +#define PortRead (0) +#define PortWrite (1) + +#define Port8Bitacc (0) +#define Port16Bitacc (1) + +/*voice register offsets (in bytes)*/ +#define VSRegs (0) +#define VSRControl (0) +#define VSRegsEnd (VSRControl+VSRegs + 32*(16*2)) +#define VSRFreq (2) +#define VSRLoopStartHi (4) +#define VSRLoopStartLo (6) +#define VSRLoopEndHi (8) +#define VSRLoopEndLo (10) +#define VSRVolRampRate (12) +#define VSRVolRampStartVol (14) +#define VSRVolRampEndVol (16) +#define VSRCurrVol (18) +#define VSRCurrPosHi (20) +#define VSRCurrPosLo (22) +#define VSRPanning (24) +#define VSRVolRampControl (26) + +/*voice register offsets (in words)*/ +#define wVSRegs (0) +#define wVSRControl (0) +#define wVSRegsEnd (wVSRControl+wVSRegs + 32*(16)) +#define wVSRFreq (1) +#define wVSRLoopStartHi (2) +#define wVSRLoopStartLo (3) +#define wVSRLoopEndHi (4) +#define wVSRLoopEndLo (5) +#define wVSRVolRampRate (6) +#define wVSRVolRampStartVol (7) +#define wVSRVolRampEndVol (8) +#define wVSRCurrVol (9) +#define wVSRCurrPosHi (10) +#define wVSRCurrPosLo (11) +#define wVSRPanning (12) +#define wVSRVolRampControl (13) + +/*GUS register state block: 32 voices, padding filled with remaining registers*/ +#define DataRegLoByte3x4 (VSRVolRampControl+2) +#define DataRegWord3x4 (DataRegLoByte3x4) +#define DataRegHiByte3x5 (VSRVolRampControl+2 +1) +#define DMA_2xB (VSRVolRampControl+2+2) +#define IRQ_2xB (VSRVolRampControl+2+3) + +#define RegCtrl_2xF (VSRVolRampControl+2+(16*2)) +#define Jumper_2xB (VSRVolRampControl+2+(16*2)+1) +#define GUS42DMAStart (VSRVolRampControl+2+(16*2)+2) + +#define GUS43DRAMIOlo (VSRVolRampControl+2+(16*2)*2) +#define GUSDRAMPOS24bit (GUS43DRAMIOlo) +#define GUS44DRAMIOhi (VSRVolRampControl+2+(16*2)*2+2) + +#define voicewavetableirq (VSRVolRampControl+2+(16*2)*3) /* voice IRQ pseudoqueue: 1 bit per voice */ + +#define voicevolrampirq (VSRVolRampControl+2+(16*2)*4) /* voice IRQ pseudoqueue: 1 bit per voice */ + +#define startvoices (VSRVolRampControl+2+(16*2)*5) /* statistics / optimizations */ + +#define IRQStatReg2x6 (VSRVolRampControl+2+(16*2)*6) +#define TimerStatus2x8 (VSRVolRampControl+2+(16*2)*6+1) +#define TimerDataReg2x9 (VSRVolRampControl+2+(16*2)*6+2) +#define MixerCtrlReg2x0 (VSRVolRampControl+2+(16*2)*6+3) + +#define VoiceSelReg3x2 (VSRVolRampControl+2+(16*2)*7) +#define FunkSelReg3x3 (VSRVolRampControl+2+(16*2)*7+1) +#define AdLibStatus2x8 (VSRVolRampControl+2+(16*2)*7+2) +#define StatRead_2xF (VSRVolRampControl+2+(16*2)*7+3) + +#define GUS48SampSpeed (VSRVolRampControl+2+(16*2)*8) +#define GUS41DMACtrl (VSRVolRampControl+2+(16*2)*8+1) +#define GUS45TimerCtrl (VSRVolRampControl+2+(16*2)*8+2) +#define GUS46Counter1 (VSRVolRampControl+2+(16*2)*8+3) + +#define GUS47Counter2 (VSRVolRampControl+2+(16*2)*9) +#define GUS49SampCtrl (VSRVolRampControl+2+(16*2)*9+1) +#define GUS4cReset (VSRVolRampControl+2+(16*2)*9+2) +#define NumVoices (VSRVolRampControl+2+(16*2)*9+3) + +#define TimerIRQs (VSRVolRampControl+2+(16*2)*10) /* delayed IRQ, statistics */ +#define BusyTimerIRQs (VSRVolRampControl+2+(16*2)*10+2) /* delayed IRQ, statistics */ + +#define AdLibCommand2xA (VSRVolRampControl+2+(16*2)*11) +#define AdLibData2x9 (VSRVolRampControl+2+(16*2)*11+1) +#define SB2xCd (VSRVolRampControl+2+(16*2)*11+2) +#define SB2xE (VSRVolRampControl+2+(16*2)*11+3) + +#define SynVoiceIRQ8f (VSRVolRampControl+2+(16*2)*12) +#define GUS50DMAHigh (VSRVolRampControl+2+(16*2)*12+1) + +#define portaccesses (VSRegsEnd) /* statistics / suspend mode */ + +#define gusdataend (VSRegsEnd+4) + +#endif /* gustate.h */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/hw.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/hw.h --- qemu-0.9.1/hw/hw.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/hw.h 2008-11-11 16:46:33.000000000 +0000 @@ -7,19 +7,71 @@ /* VM Load/Save */ +/* This function writes a chunk of data to a file at the given position. + * The pos argument can be ignored if the file is only being used for + * streaming. The handler should try to write all of the data it can. + */ +typedef int (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf, + int64_t pos, int size); + +/* Read a chunk of data from a file at the given position. The pos argument + * can be ignored if the file is only be used for streaming. The number of + * bytes actually read should be returned. + */ +typedef int (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf, + int64_t pos, int size); + +/* Close a file and return an error code */ +typedef int (QEMUFileCloseFunc)(void *opaque); + +/* Called to determine if the file has exceeded it's bandwidth allocation. The + * bandwidth capping is a soft limit, not a hard limit. + */ +typedef int (QEMUFileRateLimit)(void *opaque); + +QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer, + QEMUFileGetBufferFunc *get_buffer, + QEMUFileCloseFunc *close, + QEMUFileRateLimit *rate_limit); QEMUFile *qemu_fopen(const char *filename, const char *mode); +QEMUFile *qemu_fopen_socket(int fd); +QEMUFile *qemu_popen(FILE *popen_file, const char *mode); +QEMUFile *qemu_popen_cmd(const char *command, const char *mode); void qemu_fflush(QEMUFile *f); -void qemu_fclose(QEMUFile *f); +int qemu_fclose(QEMUFile *f); void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size); void qemu_put_byte(QEMUFile *f, int v); + +static inline void qemu_put_ubyte(QEMUFile *f, unsigned int v) +{ + qemu_put_byte(f, (int)v); +} + +#define qemu_put_sbyte qemu_put_byte + void qemu_put_be16(QEMUFile *f, unsigned int v); void qemu_put_be32(QEMUFile *f, unsigned int v); void qemu_put_be64(QEMUFile *f, uint64_t v); int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size); int qemu_get_byte(QEMUFile *f); + +static inline unsigned int qemu_get_ubyte(QEMUFile *f) +{ + return (unsigned int)qemu_get_byte(f); +} + +#define qemu_get_sbyte qemu_get_byte + unsigned int qemu_get_be16(QEMUFile *f); unsigned int qemu_get_be32(QEMUFile *f); uint64_t qemu_get_be64(QEMUFile *f); +int qemu_file_rate_limit(QEMUFile *f); +int qemu_file_has_error(QEMUFile *f); + +/* Try to send any outstanding data. This function is useful when output is + * halted due to rate limiting or EAGAIN errors occur as it can be used to + * resume output. */ +void qemu_file_put_notify(QEMUFile *f); static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv) { @@ -61,17 +113,106 @@ *pv = qemu_get_byte(f); } +// Signed versions for type safety +static inline void qemu_put_sbuffer(QEMUFile *f, const int8_t *buf, int size) +{ + qemu_put_buffer(f, (const uint8_t *)buf, size); +} + +static inline void qemu_put_sbe16(QEMUFile *f, int v) +{ + qemu_put_be16(f, (unsigned int)v); +} + +static inline void qemu_put_sbe32(QEMUFile *f, int v) +{ + qemu_put_be32(f, (unsigned int)v); +} + +static inline void qemu_put_sbe64(QEMUFile *f, int64_t v) +{ + qemu_put_be64(f, (uint64_t)v); +} + +static inline size_t qemu_get_sbuffer(QEMUFile *f, int8_t *buf, int size) +{ + return qemu_get_buffer(f, (uint8_t *)buf, size); +} + +static inline int qemu_get_sbe16(QEMUFile *f) +{ + return (int)qemu_get_be16(f); +} + +static inline int qemu_get_sbe32(QEMUFile *f) +{ + return (int)qemu_get_be32(f); +} + +static inline int64_t qemu_get_sbe64(QEMUFile *f) +{ + return (int64_t)qemu_get_be64(f); +} + +static inline void qemu_put_s8s(QEMUFile *f, const int8_t *pv) +{ + qemu_put_8s(f, (const uint8_t *)pv); +} + +static inline void qemu_put_sbe16s(QEMUFile *f, const int16_t *pv) +{ + qemu_put_be16s(f, (const uint16_t *)pv); +} + +static inline void qemu_put_sbe32s(QEMUFile *f, const int32_t *pv) +{ + qemu_put_be32s(f, (const uint32_t *)pv); +} + +static inline void qemu_put_sbe64s(QEMUFile *f, const int64_t *pv) +{ + qemu_put_be64s(f, (const uint64_t *)pv); +} + +static inline void qemu_get_s8s(QEMUFile *f, int8_t *pv) +{ + qemu_get_8s(f, (uint8_t *)pv); +} + +static inline void qemu_get_sbe16s(QEMUFile *f, int16_t *pv) +{ + qemu_get_be16s(f, (uint16_t *)pv); +} + +static inline void qemu_get_sbe32s(QEMUFile *f, int32_t *pv) +{ + qemu_get_be32s(f, (uint32_t *)pv); +} + +static inline void qemu_get_sbe64s(QEMUFile *f, int64_t *pv) +{ + qemu_get_be64s(f, (uint64_t *)pv); +} + #ifdef NEED_CPU_H #if TARGET_LONG_BITS == 64 #define qemu_put_betl qemu_put_be64 #define qemu_get_betl qemu_get_be64 #define qemu_put_betls qemu_put_be64s #define qemu_get_betls qemu_get_be64s +#define qemu_put_sbetl qemu_put_sbe64 +#define qemu_get_sbetl qemu_get_sbe64 +#define qemu_put_sbetls qemu_put_sbe64s +#define qemu_get_sbetls qemu_get_sbe64s #else #define qemu_put_betl qemu_put_be32 #define qemu_get_betl qemu_get_be32 #define qemu_put_betls qemu_put_be32s #define qemu_get_betls qemu_get_be32s +#define qemu_put_sbetl qemu_put_sbe32 +#define qemu_get_sbetl qemu_get_sbe32 +#define qemu_put_sbetls qemu_put_sbe32s +#define qemu_get_sbetls qemu_get_sbe32s #endif #endif @@ -79,6 +220,7 @@ int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence); typedef void SaveStateHandler(QEMUFile *f, void *opaque); +typedef int SaveLiveStateHandler(QEMUFile *f, int stage, void *opaque); typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); int register_savevm(const char *idstr, @@ -88,10 +230,23 @@ LoadStateHandler *load_state, void *opaque); +int register_savevm_live(const char *idstr, + int instance_id, + int version_id, + SaveLiveStateHandler *save_live_state, + SaveStateHandler *save_state, + LoadStateHandler *load_state, + void *opaque); + typedef void QEMUResetHandler(void *opaque); void qemu_register_reset(QEMUResetHandler *func, void *opaque); +/* handler to set the boot_device for a specific type of QEMUMachine */ +/* return 0 if success */ +typedef int QEMUBootSetHandler(void *opaque, const char *boot_device); +void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque); + /* These should really be in isa.h, but are here to make pc.h happy. */ typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data); typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/i2c.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/i2c.c --- qemu-0.9.1/hw/i2c.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/i2c.c 2008-07-29 14:57:48.000000000 +0100 @@ -14,14 +14,38 @@ { i2c_slave *current_dev; i2c_slave *dev; + int saved_address; }; +static void i2c_bus_save(QEMUFile *f, void *opaque) +{ + i2c_bus *bus = (i2c_bus *)opaque; + + qemu_put_byte(f, bus->current_dev ? bus->current_dev->address : -1); +} + +static int i2c_bus_load(QEMUFile *f, void *opaque, int version_id) +{ + i2c_bus *bus = (i2c_bus *)opaque; + + if (version_id != 1) + return -EINVAL; + + /* The bus is loaded before attached devices, so load and save the + current device id. Devices will check themselves as loaded. */ + bus->saved_address = (int8_t) qemu_get_byte(f); + bus->current_dev = NULL; + + return 0; +} + /* Create a new I2C bus. */ i2c_bus *i2c_init_bus(void) { i2c_bus *bus; bus = (i2c_bus *)qemu_mallocz(sizeof(i2c_bus)); + register_savevm("i2c_bus", -1, 1, i2c_bus_save, i2c_bus_load, bus); return bus; } @@ -37,6 +61,7 @@ dev->address = address; dev->next = bus->dev; bus->dev = dev; + dev->bus = bus; return dev; } @@ -115,28 +140,6 @@ dev->event(dev, I2C_NACK); } -void i2c_bus_save(QEMUFile *f, i2c_bus *bus) -{ - qemu_put_byte(f, bus->current_dev ? bus->current_dev->address : 0x00); -} - -void i2c_bus_load(QEMUFile *f, i2c_bus *bus) -{ - i2c_slave *dev; - uint8_t address = qemu_get_byte(f); - - if (address) { - for (dev = bus->dev; dev; dev = dev->next) - if (dev->address == address) { - bus->current_dev = dev; - return; - } - - fprintf(stderr, "%s: I2C slave with address %02x disappeared\n", - __FUNCTION__, address); - } -} - void i2c_slave_save(QEMUFile *f, i2c_slave *dev) { qemu_put_byte(f, dev->address); @@ -145,4 +148,6 @@ void i2c_slave_load(QEMUFile *f, i2c_slave *dev) { dev->address = qemu_get_byte(f); + if (dev->bus->saved_address == dev->address) + dev->bus->current_dev = dev; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/i2c.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/i2c.h --- qemu-0.9.1/hw/i2c.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/i2c.h 2008-07-02 00:16:53.000000000 +0100 @@ -30,6 +30,7 @@ /* Remaining fields for internal use by the I2C code. */ int address; void *next; + i2c_bus *bus; }; i2c_bus *i2c_init_bus(void); @@ -41,8 +42,6 @@ void i2c_nack(i2c_bus *bus); int i2c_send(i2c_bus *bus, uint8_t data); int i2c_recv(i2c_bus *bus); -void i2c_bus_save(QEMUFile *f, i2c_bus *bus); -void i2c_bus_load(QEMUFile *f, i2c_bus *bus); void i2c_slave_save(QEMUFile *f, i2c_slave *dev); void i2c_slave_load(QEMUFile *f, i2c_slave *dev); @@ -67,8 +66,25 @@ void (*data_req)(void *, int, int), void *opaque); void wm8750_dac_dat(void *opaque, uint32_t sample); uint32_t wm8750_adc_dat(void *opaque); +void *wm8750_dac_buffer(void *opaque, int samples); +void wm8750_dac_commit(void *opaque); +void wm8750_set_bclk_in(void *opaque, int hz); /* ssd0303.c */ void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address); +/* twl92230.c */ +i2c_slave *twl92230_init(i2c_bus *bus, qemu_irq irq); +qemu_irq *twl92230_gpio_in_get(i2c_slave *i2c); +void twl92230_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler); + +/* tmp105.c */ +struct i2c_slave *tmp105_init(i2c_bus *bus, qemu_irq alarm); +void tmp105_reset(i2c_slave *i2c); +void tmp105_set(i2c_slave *i2c, int temp); + +/* lm832x.c */ +struct i2c_slave *lm8323_init(i2c_bus *bus, qemu_irq nirq); +void lm832x_key_event(struct i2c_slave *i2c, int key, int state); + #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/i8259.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/i8259.c --- qemu-0.9.1/hw/i8259.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/i8259.c 2008-07-19 10:18:48.000000000 +0100 @@ -123,6 +123,8 @@ master, the IRQ coming from the slave is not taken into account for the priority computation. */ mask = s->isr; + if (s->special_mask) + mask &= ~s->imr; if (s->special_fully_nested_mode && s == &s->pics_state->pics[0]) mask &= ~(1 << 2); cur_priority = get_priority(s, mask); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ide.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ide.c --- qemu-0.9.1/hw/ide.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/ide.c 2008-11-11 20:57:30.000000000 +0000 @@ -1,5 +1,5 @@ /* - * QEMU IDE disk and CD-ROM Emulator + * QEMU IDE disk and CD/DVD-ROM Emulator * * Copyright (c) 2003 Fabrice Bellard * Copyright (c) 2006 Openedhand Ltd. @@ -202,6 +202,12 @@ /* set to 1 set disable mult support */ #define MAX_MULT_SECTORS 16 +#define IDE_DMA_BUF_SECTORS 256 + +#if (IDE_DMA_BUF_SECTORS < MAX_MULT_SECTORS) +#error "IDE_DMA_BUF_SECTORS must be bigger or equal to MAX_MULT_SECTORS" +#endif + /* ATAPI defines */ #define ATAPI_PACKET_SIZE 12 @@ -284,6 +290,58 @@ * of MODE_SENSE_POWER_PAGE */ #define GPMODE_CDROM_PAGE 0x0d +/* + * Based on values from but extending CD_MINS + * to the maximum common size allowed by the Orange's Book ATIP + * + * 90 and 99 min CDs are also available but using them as the + * upper limit reduces the effectiveness of the heuristic to + * detect DVDs burned to less than 25% of their maximum capacity + */ + +/* Some generally useful CD-ROM information */ +#define CD_MINS 80 /* max. minutes per CD */ +#define CD_SECS 60 /* seconds per minute */ +#define CD_FRAMES 75 /* frames per second */ +#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ +#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE) +#define CD_MAX_SECTORS (CD_MAX_BYTES / 512) + +/* + * The MMC values are not IDE specific and might need to be moved + * to a common header if they are also needed for the SCSI emulation + */ + +/* Profile list from MMC-6 revision 1 table 91 */ +#define MMC_PROFILE_NONE 0x0000 +#define MMC_PROFILE_CD_ROM 0x0008 +#define MMC_PROFILE_CD_R 0x0009 +#define MMC_PROFILE_CD_RW 0x000A +#define MMC_PROFILE_DVD_ROM 0x0010 +#define MMC_PROFILE_DVD_R_SR 0x0011 +#define MMC_PROFILE_DVD_RAM 0x0012 +#define MMC_PROFILE_DVD_RW_RO 0x0013 +#define MMC_PROFILE_DVD_RW_SR 0x0014 +#define MMC_PROFILE_DVD_R_DL_SR 0x0015 +#define MMC_PROFILE_DVD_R_DL_JR 0x0016 +#define MMC_PROFILE_DVD_RW_DL 0x0017 +#define MMC_PROFILE_DVD_DDR 0x0018 +#define MMC_PROFILE_DVD_PLUS_RW 0x001A +#define MMC_PROFILE_DVD_PLUS_R 0x001B +#define MMC_PROFILE_DVD_PLUS_RW_DL 0x002A +#define MMC_PROFILE_DVD_PLUS_R_DL 0x002B +#define MMC_PROFILE_BD_ROM 0x0040 +#define MMC_PROFILE_BD_R_SRM 0x0041 +#define MMC_PROFILE_BD_R_RRM 0x0042 +#define MMC_PROFILE_BD_RE 0x0043 +#define MMC_PROFILE_HDDVD_ROM 0x0050 +#define MMC_PROFILE_HDDVD_R 0x0051 +#define MMC_PROFILE_HDDVD_RAM 0x0052 +#define MMC_PROFILE_HDDVD_RW 0x0053 +#define MMC_PROFILE_HDDVD_R_DL 0x0058 +#define MMC_PROFILE_HDDVD_RW_DL 0x005A +#define MMC_PROFILE_INVALID 0xFFFF + #define ATAPI_INT_REASON_CD 0x01 /* 0 = data transfer */ #define ATAPI_INT_REASON_IO 0x02 /* 1 = transfer to the host */ #define ATAPI_INT_REASON_REL 0x04 @@ -293,6 +351,8 @@ #define ASC_ILLEGAL_OPCODE 0x20 #define ASC_LOGICAL_BLOCK_OOR 0x21 #define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 +#define ASC_INCOMPATIBLE_FORMAT 0x30 #define ASC_MEDIUM_NOT_PRESENT 0x3a #define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39 @@ -376,6 +436,22 @@ int media_changed; } IDEState; +/* XXX: DVDs that could fit on a CD will be reported as a CD */ +static inline int media_present(IDEState *s) +{ + return (s->nb_sectors > 0); +} + +static inline int media_is_dvd(IDEState *s) +{ + return (media_present(s) && s->nb_sectors > CD_MAX_SECTORS); +} + +static inline int media_is_cd(IDEState *s) +{ + return (media_present(s) && s->nb_sectors <= CD_MAX_SECTORS); +} + #define BM_STATUS_DMAING 0x01 #define BM_STATUS_ERROR 0x02 #define BM_STATUS_INT 0x04 @@ -494,6 +570,7 @@ put_le16(p + 59, 0x100 | s->mult_sectors); put_le16(p + 60, s->nb_sectors); put_le16(p + 61, s->nb_sectors >> 16); + put_le16(p + 62, 0x07); /* single word dma0-2 supported */ put_le16(p + 63, 0x07); /* mdma0-2 supported */ put_le16(p + 65, 120); put_le16(p + 66, 120); @@ -540,11 +617,12 @@ put_le16(p + 21, 512); /* cache size in sectors */ put_le16(p + 22, 4); /* ecc bytes */ padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */ - padstr((char *)(p + 27), "QEMU CD-ROM", 40); /* model */ + padstr((char *)(p + 27), "QEMU DVD-ROM", 40); /* model */ put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */ #ifdef USE_DMA_CDROM put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */ put_le16(p + 53, 7); /* words 64-70, 54-58, 88 valid */ + put_le16(p + 62, 7); /* single word dma0-2 supported */ put_le16(p + 63, 7); /* mdma0-2 supported */ put_le16(p + 64, 0x3f); /* PIO modes supported */ #else @@ -661,6 +739,14 @@ s->error = ABRT_ERR; } +static inline void ide_dma_submit_check(IDEState *s, + BlockDriverCompletionFunc *dma_cb, BMDMAState *bm) +{ + if (bm->aiocb) + return; + dma_cb(bm, -1); +} + static inline void ide_set_irq(IDEState *s) { BMDMAState *bm = s->bmdma; @@ -740,6 +826,11 @@ } } +static void ide_rw_error(IDEState *s) { + ide_abort_command(s); + ide_set_irq(s); +} + static void ide_sector_read(IDEState *s) { int64_t sector_num; @@ -754,11 +845,15 @@ ide_transfer_stop(s); } else { #if defined(DEBUG_IDE) - printf("read sector=%Ld\n", sector_num); + printf("read sector=%" PRId64 "\n", sector_num); #endif if (n > s->req_nb_sectors) n = s->req_nb_sectors; ret = bdrv_read(s->bs, sector_num, s->io_buffer, n); + if (ret != 0) { + ide_rw_error(s); + return; + } ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read); ide_set_irq(s); ide_set_sector(s, sector_num + n); @@ -766,6 +861,14 @@ } } +static void ide_dma_error(IDEState *s) +{ + ide_transfer_stop(s); + s->error = ABRT_ERR; + s->status = READY_STAT | ERR_STAT; + ide_set_irq(s); +} + /* return 0 if buffer completed */ static int dma_buf_rw(BMDMAState *bm, int is_write) { @@ -814,7 +917,6 @@ return 1; } -/* XXX: handle errors */ static void ide_read_dma_cb(void *opaque, int ret) { BMDMAState *bm = opaque; @@ -822,6 +924,11 @@ int n; int64_t sector_num; + if (ret < 0) { + ide_dma_error(s); + return; + } + n = s->io_buffer_size >> 9; sector_num = ide_get_sector(s); if (n > 0) { @@ -847,8 +954,8 @@ /* launch next transfer */ n = s->nsector; - if (n > MAX_MULT_SECTORS) - n = MAX_MULT_SECTORS; + if (n > IDE_DMA_BUF_SECTORS) + n = IDE_DMA_BUF_SECTORS; s->io_buffer_index = 0; s->io_buffer_size = n * 512; #ifdef DEBUG_AIO @@ -856,6 +963,7 @@ #endif bm->aiocb = bdrv_aio_read(s->bs, sector_num, s->io_buffer, n, ide_read_dma_cb, bm); + ide_dma_submit_check(s, ide_read_dma_cb, bm); } static void ide_sector_read_dma(IDEState *s) @@ -880,12 +988,17 @@ s->status = READY_STAT | SEEK_STAT; sector_num = ide_get_sector(s); #if defined(DEBUG_IDE) - printf("write sector=%Ld\n", sector_num); + printf("write sector=%" PRId64 "\n", sector_num); #endif n = s->nsector; if (n > s->req_nb_sectors) n = s->req_nb_sectors; ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); + if (ret != 0) { + ide_rw_error(s); + return; + } + s->nsector -= n; if (s->nsector == 0) { /* no more sectors to write */ @@ -915,7 +1028,6 @@ } } -/* XXX: handle errors */ static void ide_write_dma_cb(void *opaque, int ret) { BMDMAState *bm = opaque; @@ -923,6 +1035,11 @@ int n; int64_t sector_num; + if (ret < 0) { + ide_dma_error(s); + return; + } + n = s->io_buffer_size >> 9; sector_num = ide_get_sector(s); if (n > 0) { @@ -946,8 +1063,8 @@ /* launch next transfer */ n = s->nsector; - if (n > MAX_MULT_SECTORS) - n = MAX_MULT_SECTORS; + if (n > IDE_DMA_BUF_SECTORS) + n = IDE_DMA_BUF_SECTORS; s->io_buffer_index = 0; s->io_buffer_size = n * 512; @@ -958,6 +1075,7 @@ #endif bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n, ide_write_dma_cb, bm); + ide_dma_submit_check(s, ide_write_dma_cb, bm); } static void ide_sector_write_dma(IDEState *s) @@ -971,7 +1089,7 @@ static void ide_atapi_cmd_ok(IDEState *s) { s->error = 0; - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; ide_set_irq(s); } @@ -989,6 +1107,17 @@ ide_set_irq(s); } +static void ide_atapi_cmd_check_status(IDEState *s) +{ +#ifdef DEBUG_IDE_ATAPI + printf("atapi_cmd_check_status\n"); +#endif + s->error = MC_ERR | (SENSE_UNIT_ATTENTION << 4); + s->status = ERR_STAT; + s->nsector = 0; + ide_set_irq(s); +} + static inline void cpu_to_ube16(uint8_t *buf, int val) { buf[0] = val >> 8; @@ -1085,7 +1214,7 @@ if (s->packet_transfer_size <= 0) { /* end of transfer */ ide_transfer_stop(s); - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; ide_set_irq(s); #ifdef DEBUG_IDE_ATAPI @@ -1163,10 +1292,10 @@ s->io_buffer_index = 0; if (s->atapi_dma) { - s->status = READY_STAT | DRQ_STAT; + s->status = READY_STAT | SEEK_STAT | DRQ_STAT; ide_dma_start(s, ide_atapi_cmd_read_dma_cb); } else { - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; ide_atapi_cmd_reply_end(s); } } @@ -1181,7 +1310,7 @@ s->io_buffer_index = sector_size; s->cd_sector_size = sector_size; - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; ide_atapi_cmd_reply_end(s); } @@ -1222,7 +1351,7 @@ } if (s->packet_transfer_size <= 0) { - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; ide_set_irq(s); eot: @@ -1241,8 +1370,8 @@ data_offset = 16; } else { n = s->packet_transfer_size >> 11; - if (n > (MAX_MULT_SECTORS / 4)) - n = (MAX_MULT_SECTORS / 4); + if (n > (IDE_DMA_BUF_SECTORS / 4)) + n = (IDE_DMA_BUF_SECTORS / 4); s->io_buffer_size = n * 2048; data_offset = 0; } @@ -1272,7 +1401,7 @@ s->cd_sector_size = sector_size; /* XXX: check if BUSY_STAT should be set */ - s->status = READY_STAT | DRQ_STAT | BUSY_STAT; + s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT; ide_dma_start(s, ide_atapi_cmd_read_dma_cb); } @@ -1290,6 +1419,109 @@ } } +static inline uint8_t ide_atapi_set_profile(uint8_t *buf, uint8_t *index, + uint16_t profile) +{ + uint8_t *buf_profile = buf + 12; /* start of profiles */ + + buf_profile += ((*index) * 4); /* start of indexed profile */ + cpu_to_ube16 (buf_profile, profile); + buf_profile[2] = ((buf_profile[0] == buf[6]) && (buf_profile[1] == buf[7])); + + /* each profile adds 4 bytes to the response */ + (*index)++; + buf[11] += 4; /* Additional Length */ + + return 4; +} + +static int ide_dvd_read_structure(IDEState *s, int format, + const uint8_t *packet, uint8_t *buf) +{ + switch (format) { + case 0x0: /* Physical format information */ + { + int layer = packet[6]; + uint64_t total_sectors; + + if (layer != 0) + return -ASC_INV_FIELD_IN_CMD_PACKET; + + bdrv_get_geometry(s->bs, &total_sectors); + total_sectors >>= 2; + if (total_sectors == 0) + return -ASC_MEDIUM_NOT_PRESENT; + + buf[4] = 1; /* DVD-ROM, part version 1 */ + buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ + buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ + buf[7] = 0; /* default densities */ + + /* FIXME: 0x30000 per spec? */ + cpu_to_ube32(buf + 8, 0); /* start sector */ + cpu_to_ube32(buf + 12, total_sectors - 1); /* end sector */ + cpu_to_ube32(buf + 16, total_sectors - 1); /* l0 end sector */ + + /* Size of buffer, not including 2 byte size field */ + cpu_to_be16wu((uint16_t *)buf, 2048 + 2); + + /* 2k data + 4 byte header */ + return (2048 + 4); + } + + case 0x01: /* DVD copyright information */ + buf[4] = 0; /* no copyright data */ + buf[5] = 0; /* no region restrictions */ + + /* Size of buffer, not including 2 byte size field */ + cpu_to_be16wu((uint16_t *)buf, 4 + 2); + + /* 4 byte header + 4 byte data */ + return (4 + 4); + + case 0x03: /* BCA information - invalid field for no BCA info */ + return -ASC_INV_FIELD_IN_CMD_PACKET; + + case 0x04: /* DVD disc manufacturing information */ + /* Size of buffer, not including 2 byte size field */ + cpu_to_be16wu((uint16_t *)buf, 2048 + 2); + + /* 2k data + 4 byte header */ + return (2048 + 4); + + case 0xff: + /* + * This lists all the command capabilities above. Add new ones + * in order and update the length and buffer return values. + */ + + buf[4] = 0x00; /* Physical format */ + buf[5] = 0x40; /* Not writable, is readable */ + cpu_to_be16wu((uint16_t *)(buf + 6), 2048 + 4); + + buf[8] = 0x01; /* Copyright info */ + buf[9] = 0x40; /* Not writable, is readable */ + cpu_to_be16wu((uint16_t *)(buf + 10), 4 + 4); + + buf[12] = 0x03; /* BCA info */ + buf[13] = 0x40; /* Not writable, is readable */ + cpu_to_be16wu((uint16_t *)(buf + 14), 188 + 4); + + buf[16] = 0x04; /* Manufacturing info */ + buf[17] = 0x40; /* Not writable, is readable */ + cpu_to_be16wu((uint16_t *)(buf + 18), 2048 + 4); + + /* Size of buffer, not including 2 byte size field */ + cpu_to_be16wu((uint16_t *)buf, 16 + 2); + + /* data written + 4 byte header */ + return (16 + 4); + + default: /* TODO: formats beyond DVD-ROM requires */ + return -ASC_INV_FIELD_IN_CMD_PACKET; + } +} + static void ide_atapi_cmd(IDEState *s) { const uint8_t *packet; @@ -1308,6 +1540,14 @@ printf("\n"); } #endif + /* If there's a UNIT_ATTENTION condition pending, only + REQUEST_SENSE and INQUIRY commands are allowed to complete. */ + if (s->sense_key == SENSE_UNIT_ATTENTION && + s->io_buffer[0] != GPCMD_REQUEST_SENSE && + s->io_buffer[0] != GPCMD_INQUIRY) { + ide_atapi_cmd_check_status(s); + return; + } switch(s->io_buffer[0]) { case GPCMD_TEST_UNIT_READY: if (bdrv_is_inserted(s->bs)) { @@ -1403,6 +1643,8 @@ buf[2] = s->sense_key; buf[7] = 10; buf[12] = s->asc; + if (s->sense_key == SENSE_UNIT_ATTENTION) + s->sense_key = SENSE_NONE; ide_atapi_cmd_reply(s, 18, max_len); break; case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: @@ -1577,42 +1819,48 @@ case GPCMD_READ_DVD_STRUCTURE: { int media = packet[1]; - int layer = packet[6]; - int format = packet[2]; - uint64_t total_sectors; + int format = packet[7]; + int ret; - if (media != 0 || layer != 0) - { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); + max_len = ube16_to_cpu(packet + 8); + + if (format < 0xff) { + if (media_is_cd(s)) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INCOMPATIBLE_FORMAT); + break; + } else if (!media_present(s)) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + break; + } } + memset(buf, 0, max_len > IDE_DMA_BUF_SECTORS * 512 + 4 ? + IDE_DMA_BUF_SECTORS * 512 + 4 : max_len); + switch (format) { - case 0: - bdrv_get_geometry(s->bs, &total_sectors); - total_sectors >>= 2; - if (total_sectors == 0) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); + case 0x00 ... 0x7f: + case 0xff: + if (media == 0) { + ret = ide_dvd_read_structure(s, format, packet, buf); + + if (ret < 0) + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, -ret); + else + ide_atapi_cmd_reply(s, ret, max_len); + break; } + /* TODO: BD support, fall through for now */ - memset(buf, 0, 2052); - - buf[4] = 1; // DVD-ROM, part version 1 - buf[5] = 0xf; // 120mm disc, maximum rate unspecified - buf[6] = 0; // one layer, embossed data - buf[7] = 0; - - cpu_to_ube32(buf + 8, 0); - cpu_to_ube32(buf + 12, total_sectors - 1); - cpu_to_ube32(buf + 16, total_sectors - 1); - - cpu_to_be16wu((uint16_t *)buf, 2048 + 4); - - ide_atapi_cmd_reply(s, 2048 + 3, 2048 + 4); - break; - + /* Generic disk structures */ + case 0x80: /* TODO: AACS volume identifier */ + case 0x81: /* TODO: AACS media serial number */ + case 0x82: /* TODO: AACS media identifier */ + case 0x83: /* TODO: AACS media key block */ + case 0x90: /* TODO: List of recognized format layers */ + case 0xc0: /* TODO: Write protection status */ default: ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); @@ -1634,13 +1882,14 @@ buf[6] = 0; /* reserved */ buf[7] = 0; /* reserved */ padstr8(buf + 8, 8, "QEMU"); - padstr8(buf + 16, 16, "QEMU CD-ROM"); + padstr8(buf + 16, 16, "QEMU DVD-ROM"); padstr8(buf + 32, 4, QEMU_VERSION); ide_atapi_cmd_reply(s, 36, max_len); break; case GPCMD_GET_CONFIGURATION: { - uint64_t total_sectors; + uint32_t len; + uint8_t index = 0; /* only feature 0 is supported */ if (packet[2] != 0 || packet[3] != 0) { @@ -1648,17 +1897,37 @@ ASC_INV_FIELD_IN_CMD_PACKET); break; } - memset(buf, 0, 32); - bdrv_get_geometry(s->bs, &total_sectors); - buf[3] = 16; - buf[7] = total_sectors <= 1433600 ? 0x08 : 0x10; /* current profile */ - buf[10] = 0x10 | 0x1; - buf[11] = 0x08; /* size of profile list */ - buf[13] = 0x10; /* DVD-ROM profile */ - buf[14] = buf[7] == 0x10; /* (in)active */ - buf[17] = 0x08; /* CD-ROM profile */ - buf[18] = buf[7] == 0x08; /* (in)active */ - ide_atapi_cmd_reply(s, 32, 32); + + /* XXX: could result in alignment problems in some architectures */ + max_len = ube16_to_cpu(packet + 7); + + /* + * XXX: avoid overflow for io_buffer if max_len is bigger than + * the size of that buffer (dimensioned to max number of + * sectors to transfer at once) + * + * Only a problem if the feature/profiles grow. + */ + if (max_len > 512) /* XXX: assume 1 sector */ + max_len = 512; + + memset(buf, 0, max_len); + /* + * the number of sectors from the media tells us which profile + * to use as current. 0 means there is no media + */ + if (media_is_dvd(s)) + cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM); + else if (media_is_cd(s)) + cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM); + + buf[10] = 0x02 | 0x01; /* persistent and current */ + len = 12; /* headers: 8 + 4 */ + len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_DVD_ROM); + len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_CD_ROM); + cpu_to_ube32(buf, len - 4); /* data length */ + + ide_atapi_cmd_reply(s, len, max_len); break; } default: @@ -1727,9 +1996,13 @@ IDEState *s = opaque; uint64_t nb_sectors; - /* XXX: send interrupt too */ bdrv_get_geometry(s->bs, &nb_sectors); s->nb_sectors = nb_sectors; + + s->sense_key = SENSE_UNIT_ATTENTION; + s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED; + + ide_set_irq(s); } static void ide_cmd_lba48_transform(IDEState *s, int lba48) @@ -1774,6 +2047,11 @@ #endif addr &= 7; + + /* ignore writes to command block while busy with previous command */ + if (addr != 7 && (ide_if->cur_drive->status & (BUSY_STAT|DRQ_STAT))) + return; + switch(addr) { case 0: break; @@ -1833,6 +2111,10 @@ if (s != ide_if && !s->bs) break; + /* Only DEVICE RESET is allowed while BSY or/and DRQ are set */ + if ((s->status & (BUSY_STAT|DRQ_STAT)) && val != WIN_DEVICE_RESET) + break; + switch(val) { case WIN_IDENTIFY: if (s->bs && !s->is_cdrom) { @@ -1860,14 +2142,14 @@ if (s->is_cf && s->nsector == 0) { /* Disable Read and Write Multiple */ s->mult_sectors = 0; - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; } else if ((s->nsector & 0xff) != 0 && ((s->nsector & 0xff) > MAX_MULT_SECTORS || (s->nsector & (s->nsector - 1)) != 0)) { ide_abort_command(s); } else { s->mult_sectors = s->nsector & 0xff; - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; } ide_set_irq(s); break; @@ -1877,7 +2159,7 @@ case WIN_VERIFY_ONCE: /* do sector number check ? */ ide_cmd_lba48_transform(s, lba48); - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); break; case WIN_READ_EXT: @@ -1952,13 +2234,13 @@ case WIN_READ_NATIVE_MAX: ide_cmd_lba48_transform(s, lba48); ide_set_sector(s, s->nb_sectors - 1); - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); break; case WIN_CHECKPOWERMODE1: case WIN_CHECKPOWERMODE2: s->nsector = 0xff; /* device active or idle */ - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); break; case WIN_SETFEATURES: @@ -1989,14 +2271,22 @@ switch (s->nsector >> 3) { case 0x00: /* pio default */ case 0x01: /* pio mode */ + put_le16(s->identify_data + 62,0x07); + put_le16(s->identify_data + 63,0x07); + put_le16(s->identify_data + 88,0x3f); + break; + case 0x02: /* sigle word dma mode*/ + put_le16(s->identify_data + 62,0x07 | (1 << (val + 8))); put_le16(s->identify_data + 63,0x07); put_le16(s->identify_data + 88,0x3f); break; case 0x04: /* mdma mode */ + put_le16(s->identify_data + 62,0x07); put_le16(s->identify_data + 63,0x07 | (1 << (val + 8))); put_le16(s->identify_data + 88,0x3f); break; case 0x08: /* udma mode */ + put_le16(s->identify_data + 62,0x07); put_le16(s->identify_data + 63,0x07); put_le16(s->identify_data + 88,0x3f | (1 << (val + 8))); break; @@ -2015,7 +2305,7 @@ case WIN_FLUSH_CACHE_EXT: if (s->bs) bdrv_flush(s->bs); - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); break; case WIN_STANDBY: @@ -2044,8 +2334,15 @@ break; case WIN_DIAGNOSE: ide_set_signature(s); - s->status = 0x00; /* NOTE: READY is _not_ set */ - s->error = 0x01; + if (s->is_cdrom) + s->status = 0; /* ATAPI spec (v6) section 9.10 defines packet + * devices to return a clear status register + * with READY_STAT *not* set. */ + else + s->status = READY_STAT | SEEK_STAT; + s->error = 0x01; /* Device 0 passed, Device 1 passed or not + * present. + */ ide_set_irq(s); break; case WIN_SRST: @@ -2061,7 +2358,7 @@ /* overlapping commands not supported */ if (s->feature & 0x02) goto abort_cmd; - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; s->atapi_dma = s->feature & 1; s->nsector = 1; ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE, @@ -2072,7 +2369,7 @@ if (!s->is_cf) goto abort_cmd; s->error = 0x09; /* miscellaneous error */ - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); break; case CFA_ERASE_SECTORS: @@ -2084,14 +2381,14 @@ if (val == CFA_ERASE_SECTORS) s->media_changed = 1; s->error = 0x00; - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); break; case CFA_TRANSLATE_SECTOR: if (!s->is_cf) goto abort_cmd; s->error = 0x00; - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; memset(s->io_buffer, 0, 0x200); s->io_buffer[0x00] = s->hcyl; /* Cyl MSB */ s->io_buffer[0x01] = s->lcyl; /* Cyl LSB */ @@ -2137,7 +2434,7 @@ default: goto abort_cmd; } - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); break; default: @@ -2283,6 +2580,10 @@ IDEState *s = ((IDEState *)opaque)->cur_drive; uint8_t *p; + /* PIO data access allowed only when DRQ bit is set */ + if (!(s->status & DRQ_STAT)) + return; + p = s->data_ptr; *(uint16_t *)p = le16_to_cpu(val); p += 2; @@ -2296,6 +2597,11 @@ IDEState *s = ((IDEState *)opaque)->cur_drive; uint8_t *p; int ret; + + /* PIO data access allowed only when DRQ bit is set */ + if (!(s->status & DRQ_STAT)) + return 0; + p = s->data_ptr; ret = cpu_to_le16(*(uint16_t *)p); p += 2; @@ -2310,6 +2616,10 @@ IDEState *s = ((IDEState *)opaque)->cur_drive; uint8_t *p; + /* PIO data access allowed only when DRQ bit is set */ + if (!(s->status & DRQ_STAT)) + return; + p = s->data_ptr; *(uint32_t *)p = le32_to_cpu(val); p += 4; @@ -2324,6 +2634,10 @@ uint8_t *p; int ret; + /* PIO data access allowed only when DRQ bit is set */ + if (!(s->status & DRQ_STAT)) + return 0; + p = s->data_ptr; ret = cpu_to_le32(*(uint32_t *)p); p += 4; @@ -2351,7 +2665,7 @@ s->mult_sectors = MAX_MULT_SECTORS; s->cur_drive = s; s->select = 0xa0; - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; ide_set_signature(s); /* init the transfer handler so that 0xffff is returned on data accesses */ @@ -2377,22 +2691,17 @@ static int guess_disk_lchs(IDEState *s, int *pcylinders, int *pheads, int *psectors) { - uint8_t *buf; + uint8_t *buf = s->io_buffer; int ret, i, heads, sectors, cylinders; struct partition *p; uint32_t nr_sects; - buf = qemu_memalign(512, 512); - if (buf == NULL) - return -1; ret = bdrv_read(s->bs, 0, buf, 1); if (ret < 0) { - qemu_free(buf); return -1; } /* test msdos magic */ if (buf[510] != 0x55 || buf[511] != 0xaa) { - qemu_free(buf); return -1; } for(i = 0; i < 4; i++) { @@ -2415,11 +2724,9 @@ printf("guessed geometry: LCHS=%d %d %d\n", cylinders, heads, sectors); #endif - qemu_free(buf); return 0; } } - qemu_free(buf); return -1; } @@ -2434,7 +2741,7 @@ for(i = 0; i < 2; i++) { s = ide_state + i; - s->io_buffer = qemu_memalign(512, MAX_MULT_SECTORS*512 + 4); + s->io_buffer = qemu_memalign(512, IDE_DMA_BUF_SECTORS*512 + 4); if (i == 0) s->bs = hd0; else @@ -2636,6 +2943,23 @@ } } +static void ide_dma_cancel(BMDMAState *bm) +{ + if (bm->status & BM_STATUS_DMAING) { + bm->status &= ~BM_STATUS_DMAING; + /* cancel DMA request */ + bm->ide_if = NULL; + bm->dma_cb = NULL; + if (bm->aiocb) { +#ifdef DEBUG_AIO + printf("aio_cancel\n"); +#endif + bdrv_aio_cancel(bm->aiocb); + bm->aiocb = NULL; + } + } +} + static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) { BMDMAState *bm = opaque; @@ -2644,19 +2968,7 @@ #endif if (!(val & BM_CMD_START)) { /* XXX: do it better */ - if (bm->status & BM_STATUS_DMAING) { - bm->status &= ~BM_STATUS_DMAING; - /* cancel DMA request */ - bm->ide_if = NULL; - bm->dma_cb = NULL; - if (bm->aiocb) { -#ifdef DEBUG_AIO - printf("aio_cancel\n"); -#endif - bdrv_aio_cancel(bm->aiocb); - bm->aiocb = NULL; - } - } + ide_dma_cancel(bm); bm->cmd = val & 0x09; } else { if (!(bm->status & BM_STATUS_DMAING)) { @@ -2742,6 +3054,52 @@ } } +static uint32_t bmdma_addr_readb(void *opaque, uint32_t addr) +{ + BMDMAState *bm = opaque; + uint32_t val; + val = (bm->addr >> ((addr & 3) * 8)) & 0xff; +#ifdef DEBUG_IDE + printf("%s: 0x%08x\n", __func__, val); +#endif + return val; +} + +static void bmdma_addr_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + BMDMAState *bm = opaque; + int shift = (addr & 3) * 8; +#ifdef DEBUG_IDE + printf("%s: 0x%08x\n", __func__, val); +#endif + bm->addr &= ~(0xFF << shift); + bm->addr |= ((val & 0xFF) << shift) & ~3; + bm->cur_addr = bm->addr; +} + +static uint32_t bmdma_addr_readw(void *opaque, uint32_t addr) +{ + BMDMAState *bm = opaque; + uint32_t val; + val = (bm->addr >> ((addr & 3) * 8)) & 0xffff; +#ifdef DEBUG_IDE + printf("%s: 0x%08x\n", __func__, val); +#endif + return val; +} + +static void bmdma_addr_writew(void *opaque, uint32_t addr, uint32_t val) +{ + BMDMAState *bm = opaque; + int shift = (addr & 3) * 8; +#ifdef DEBUG_IDE + printf("%s: 0x%08x\n", __func__, val); +#endif + bm->addr &= ~(0xFFFF << shift); + bm->addr |= ((val & 0xFFFF) << shift) & ~3; + bm->cur_addr = bm->addr; +} + static uint32_t bmdma_addr_readl(void *opaque, uint32_t addr) { BMDMAState *bm = opaque; @@ -2780,6 +3138,10 @@ register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm); register_ioport_read(addr, 4, 1, bmdma_readb, bm); + register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm); + register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm); + register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm); + register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm); register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm); register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm); addr += 8; @@ -2930,9 +3292,14 @@ return 0; } -static void piix3_reset(PCIIDEState *d) +static void piix3_reset(void *opaque) { + PCIIDEState *d = opaque; uint8_t *pci_conf = d->dev.config; + int i; + + for (i = 0; i < 2; i++) + ide_dma_cancel(&d->bmdma[i]); pci_conf[0x04] = 0x00; pci_conf[0x05] = 0x00; @@ -2966,6 +3333,7 @@ pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage pci_conf[0x0e] = 0x00; // header_type + qemu_register_reset(piix3_reset, d); piix3_reset(d); pci_register_io_region((PCIDevice *)d, 4, 0x10, @@ -3004,6 +3372,7 @@ pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage pci_conf[0x0e] = 0x00; // header_type + qemu_register_reset(piix3_reset, d); piix3_reset(d); pci_register_io_region((PCIDevice *)d, 4, 0x10, @@ -3453,8 +3822,6 @@ return 0; } -static int md_iid = 0; - static const uint8_t dscm1xxxx_cis[0x14a] = { [0x000] = CISTPL_DEVICE, /* 5V Device Information */ [0x002] = 0x03, /* Tuple length = 4 bytes */ @@ -3681,7 +4048,7 @@ md->ide->mdata_size = METADATA_SIZE; md->ide->mdata_storage = (uint8_t *) qemu_mallocz(METADATA_SIZE); - register_savevm("microdrive", md_iid ++, 0, md_save, md_load, md); + register_savevm("microdrive", -1, 0, md_save, md_load, md); return &md->card; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/integratorcp.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/integratorcp.c --- qemu-0.9.1/hw/integratorcp.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/integratorcp.c 2008-10-31 17:25:56.000000000 +0000 @@ -15,10 +15,6 @@ #include "arm-misc.h" #include "net.h" -void DMA_run (void) -{ -} - typedef struct { uint32_t flash_offset; uint32_t cm_osc; @@ -231,7 +227,7 @@ integratorcm_write }; -static void integratorcm_init(int memsz, uint32_t flash_offset) +static void integratorcm_init(int memsz) { int iomemtype; integratorcm_state *s; @@ -258,7 +254,7 @@ } memcpy(integrator_spd + 73, "QEMU-MEMORY", 11); s->cm_init = 0x00000112; - s->flash_offset = flash_offset; + s->flash_offset = qemu_ram_alloc(0x100000); iomemtype = cpu_register_io_memory(0, integratorcm_readfn, integratorcm_writefn, s); @@ -469,13 +465,18 @@ /* Board init. */ -static void integratorcp_init(int ram_size, int vga_ram_size, +static struct arm_boot_info integrator_binfo = { + .loader_start = 0x0, + .board_id = 0x113, +}; + +static void integratorcp_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { CPUState *env; - uint32_t bios_offset; + uint32_t ram_offset; qemu_irq *pic; qemu_irq *cpu_pic; int sd; @@ -487,15 +488,15 @@ fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - bios_offset = ram_size + vga_ram_size; + ram_offset = qemu_ram_alloc(ram_size); /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */ - /* ??? RAM shoud repeat to fill physical memory space. */ + /* ??? RAM should repeat to fill physical memory space. */ /* SDRAM at address zero*/ - cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM); /* And again at address 0x80000000 */ - cpu_register_physical_memory(0x80000000, ram_size, IO_MEM_RAM); + cpu_register_physical_memory(0x80000000, ram_size, ram_offset | IO_MEM_RAM); - integratorcm_init(ram_size >> 20, bios_offset); + integratorcm_init(ram_size >> 20); cpu_pic = arm_pic_init_cpu(env); pic = icp_pic_init(0x14000000, cpu_pic[ARM_PIC_CPU_IRQ], cpu_pic[ARM_PIC_CPU_FIQ]); @@ -527,12 +528,16 @@ } pl110_init(ds, 0xc0000000, pic[22], 0); - arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline, - initrd_filename, 0x113, 0x0); + integrator_binfo.ram_size = ram_size; + integrator_binfo.kernel_filename = kernel_filename; + integrator_binfo.kernel_cmdline = kernel_cmdline; + integrator_binfo.initrd_filename = initrd_filename; + arm_load_kernel(env, &integrator_binfo); } QEMUMachine integratorcp_machine = { - "integratorcp", - "ARM Integrator/CP (ARM926EJ-S)", - integratorcp_init, + .name = "integratorcp", + .desc = "ARM Integrator/CP (ARM926EJ-S)", + .init = integratorcp_init, + .ram_require = 0x100000, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/iommu.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/iommu.c --- qemu-0.9.1/hw/iommu.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/iommu.c 2008-07-01 20:28:23.000000000 +0100 @@ -34,7 +34,7 @@ #define DPRINTF(fmt, args...) #endif -#define IOMMU_NREGS (3*4096/4) +#define IOMMU_NREGS (4*4096/4) #define IOMMU_CTRL (0x0000 >> 2) #define IOMMU_CTRL_IMPL 0xf0000000 /* Implementation */ #define IOMMU_CTRL_VERS 0x0f000000 /* Version */ @@ -95,6 +95,12 @@ #define IOMMU_ARBEN_MASK 0x001f0000 #define IOMMU_MID 0x00000008 +#define IOMMU_MASK_ID (0x3018 >> 2) /* Mask ID */ +#define IOMMU_MASK_ID_MASK 0x00ffffff + +#define IOMMU_MSII_MASK 0x26000000 /* microSPARC II mask number */ +#define IOMMU_TS_MASK 0x23000000 /* turboSPARC mask number */ + /* The format of an iopte in the page tables */ #define IOPTE_PAGE 0xffffff00 /* Physical page number (PA[35:12]) */ #define IOPTE_CACHE 0x00000080 /* Cached (in vme IOCACHE or @@ -206,6 +212,9 @@ // addresses, fault cause and address stored to MMU/IOMMU s->regs[saddr] = (val & IOMMU_ARBEN_MASK) | IOMMU_MID; break; + case IOMMU_MASK_ID: + s->regs[saddr] |= val & IOMMU_MASK_ID_MASK; + break; default: s->regs[saddr] = val; break; @@ -243,8 +252,7 @@ return ret; } -static target_phys_addr_t iommu_translate_pa(IOMMUState *s, - target_phys_addr_t addr, +static target_phys_addr_t iommu_translate_pa(target_phys_addr_t addr, uint32_t pte) { uint32_t tmppte; @@ -287,15 +295,15 @@ iommu_bad_addr(opaque, page, is_write); return; } - phys_addr = iommu_translate_pa(opaque, addr, flags); + phys_addr = iommu_translate_pa(addr, flags); if (is_write) { if (!(flags & IOPTE_WRITE)) { iommu_bad_addr(opaque, page, is_write); return; } - cpu_physical_memory_write(phys_addr, buf, len); + cpu_physical_memory_write(phys_addr, buf, l); } else { - cpu_physical_memory_read(phys_addr, buf, len); + cpu_physical_memory_read(phys_addr, buf, l); } len -= l; buf += l; @@ -337,6 +345,7 @@ s->regs[IOMMU_CTRL] = s->version; s->regs[IOMMU_ARBEN] = IOMMU_MID; s->regs[IOMMU_AFSR] = IOMMU_AFSR_RESV; + s->regs[IOMMU_MASK_ID] = IOMMU_TS_MASK; qemu_irq_lower(s->irq); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/isa.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/isa.h --- qemu-0.9.1/hw/isa.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/isa.h 2008-10-31 17:25:56.000000000 +0000 @@ -1,3 +1,5 @@ +#ifndef HW_ISA_H +#define HW_ISA_H /* ISA bus */ extern target_phys_addr_t isa_mem_base; @@ -17,8 +19,8 @@ void DMA_hold_DREQ (int nchan); void DMA_release_DREQ (int nchan); void DMA_schedule(int nchan); -void DMA_run (void); void DMA_init (int high_page_enable); void DMA_register_channel (int nchan, DMA_transfer_handler transfer_handler, void *opaque); +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/jazz_led.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/jazz_led.c --- qemu-0.9.1/hw/jazz_led.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/jazz_led.c 2008-07-01 17:24:38.000000000 +0100 @@ -37,6 +37,7 @@ target_phys_addr_t base; uint8_t segments; DisplayState *ds; + QEMUConsole *console; screen_state_t state; } LedState; @@ -285,6 +286,22 @@ printf("jazz_led_screen_dump() not implemented\n"); } +static void jazz_led_text_update(void *opaque, console_ch_t *chardata) +{ + LedState *s = opaque; + char buf[2]; + + dpy_cursor(s->ds, -1, -1); + qemu_console_resize(s->console, 2, 1); + + /* TODO: draw the segments */ + snprintf(buf, 2, "%02hhx\n", s->segments); + console_write_ch(chardata++, 0x00200100 | buf[0]); + console_write_ch(chardata++, 0x00200100 | buf[1]); + + dpy_update(s->ds, 0, 0, 2, 1); +} + void jazz_led_init(DisplayState *ds, target_phys_addr_t base) { LedState *s; @@ -301,5 +318,9 @@ io = cpu_register_io_memory(0, led_read, led_write, s); cpu_register_physical_memory(s->base, 1, io); - graphic_console_init(ds, jazz_led_update_display, jazz_led_invalidate_display, jazz_led_screen_dump, s); + s->console = graphic_console_init(ds, jazz_led_update_display, + jazz_led_invalidate_display, + jazz_led_screen_dump, + jazz_led_text_update, s); + qemu_console_resize(s->console, 60, 80); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/lm832x.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/lm832x.c --- qemu-0.9.1/hw/lm832x.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/lm832x.c 2008-07-01 22:31:54.000000000 +0100 @@ -0,0 +1,532 @@ +/* + * National Semiconductor LM8322/8323 GPIO keyboard & PWM chips. + * + * Copyright (C) 2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "hw.h" +#include "i2c.h" +#include "qemu-timer.h" +#include "console.h" + +struct lm_kbd_s { + i2c_slave i2c; + int i2c_dir; + int i2c_cycle; + int reg; + + qemu_irq nirq; + uint16_t model; + + struct { + qemu_irq out[2]; + int in[2][2]; + } mux; + + uint8_t config; + uint8_t status; + uint8_t acttime; + uint8_t error; + uint8_t clock; + + struct { + uint16_t pull; + uint16_t mask; + uint16_t dir; + uint16_t level; + qemu_irq out[16]; + } gpio; + + struct { + uint8_t dbnctime; + uint8_t size; + int start; + int len; + uint8_t fifo[16]; + } kbd; + + struct { + uint16_t file[256]; + uint8_t faddr; + uint8_t addr[3]; + QEMUTimer *tm[3]; + } pwm; +}; + +#define INT_KEYPAD (1 << 0) +#define INT_ERROR (1 << 3) +#define INT_NOINIT (1 << 4) +#define INT_PWMEND(n) (1 << (5 + n)) + +#define ERR_BADPAR (1 << 0) +#define ERR_CMDUNK (1 << 1) +#define ERR_KEYOVR (1 << 2) +#define ERR_FIFOOVR (1 << 6) + +static void lm_kbd_irq_update(struct lm_kbd_s *s) +{ + qemu_set_irq(s->nirq, !s->status); +} + +static void lm_kbd_gpio_update(struct lm_kbd_s *s) +{ +} + +static void lm_kbd_reset(struct lm_kbd_s *s) +{ + s->config = 0x80; + s->status = INT_NOINIT; + s->acttime = 125; + s->kbd.dbnctime = 3; + s->kbd.size = 0x33; + s->clock = 0x08; + + lm_kbd_irq_update(s); + lm_kbd_gpio_update(s); +} + +static void lm_kbd_error(struct lm_kbd_s *s, int err) +{ + s->error |= err; + s->status |= INT_ERROR; + lm_kbd_irq_update(s); +} + +static void lm_kbd_pwm_tick(struct lm_kbd_s *s, int line) +{ +} + +static void lm_kbd_pwm_start(struct lm_kbd_s *s, int line) +{ + lm_kbd_pwm_tick(s, line); +} + +static void lm_kbd_pwm0_tick(void *opaque) +{ + lm_kbd_pwm_tick(opaque, 0); +} +static void lm_kbd_pwm1_tick(void *opaque) +{ + lm_kbd_pwm_tick(opaque, 1); +} +static void lm_kbd_pwm2_tick(void *opaque) +{ + lm_kbd_pwm_tick(opaque, 2); +} + +enum { + LM832x_CMD_READ_ID = 0x80, /* Read chip ID. */ + LM832x_CMD_WRITE_CFG = 0x81, /* Set configuration item. */ + LM832x_CMD_READ_INT = 0x82, /* Get interrupt status. */ + LM832x_CMD_RESET = 0x83, /* Reset, same as external one */ + LM823x_CMD_WRITE_PULL_DOWN = 0x84, /* Select GPIO pull-up/down. */ + LM832x_CMD_WRITE_PORT_SEL = 0x85, /* Select GPIO in/out. */ + LM832x_CMD_WRITE_PORT_STATE = 0x86, /* Set GPIO pull-up/down. */ + LM832x_CMD_READ_PORT_SEL = 0x87, /* Get GPIO in/out. */ + LM832x_CMD_READ_PORT_STATE = 0x88, /* Get GPIO pull-up/down. */ + LM832x_CMD_READ_FIFO = 0x89, /* Read byte from FIFO. */ + LM832x_CMD_RPT_READ_FIFO = 0x8a, /* Read FIFO (no increment). */ + LM832x_CMD_SET_ACTIVE = 0x8b, /* Set active time. */ + LM832x_CMD_READ_ERROR = 0x8c, /* Get error status. */ + LM832x_CMD_READ_ROTATOR = 0x8e, /* Read rotator status. */ + LM832x_CMD_SET_DEBOUNCE = 0x8f, /* Set debouncing time. */ + LM832x_CMD_SET_KEY_SIZE = 0x90, /* Set keypad size. */ + LM832x_CMD_READ_KEY_SIZE = 0x91, /* Get keypad size. */ + LM832x_CMD_READ_CFG = 0x92, /* Get configuration item. */ + LM832x_CMD_WRITE_CLOCK = 0x93, /* Set clock config. */ + LM832x_CMD_READ_CLOCK = 0x94, /* Get clock config. */ + LM832x_CMD_PWM_WRITE = 0x95, /* Write PWM script. */ + LM832x_CMD_PWM_START = 0x96, /* Start PWM engine. */ + LM832x_CMD_PWM_STOP = 0x97, /* Stop PWM engine. */ +}; + +#define LM832x_MAX_KPX 8 +#define LM832x_MAX_KPY 12 + +static uint8_t lm_kbd_read(struct lm_kbd_s *s, int reg, int byte) +{ + int ret; + + switch (reg) { + case LM832x_CMD_READ_ID: + ret = 0x0400; + break; + + case LM832x_CMD_READ_INT: + ret = s->status; + if (!(s->status & INT_NOINIT)) { + s->status = 0; + lm_kbd_irq_update(s); + } + break; + + case LM832x_CMD_READ_PORT_SEL: + ret = s->gpio.dir; + break; + case LM832x_CMD_READ_PORT_STATE: + ret = s->gpio.mask; + break; + + case LM832x_CMD_READ_FIFO: + if (s->kbd.len <= 1) + return 0x00; + + /* Example response from the two commands after a INT_KEYPAD + * interrupt caused by the key 0x3c being pressed: + * RPT_READ_FIFO: 55 bc 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01 + * READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01 + * RPT_READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01 + * + * 55 is the code of the key release event serviced in the previous + * interrupt handling. + * + * TODO: find out whether the FIFO is advanced a single character + * before reading every byte or the whole size of the FIFO at the + * last LM832x_CMD_READ_FIFO. This affects LM832x_CMD_RPT_READ_FIFO + * output in cases where there are more than one event in the FIFO. + * Assume 0xbc and 0x3c events are in the FIFO: + * RPT_READ_FIFO: 55 bc 3c 00 4e ff 0a 50 08 00 29 d9 08 01 c9 + * READ_FIFO: bc 3c 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 + * Does RPT_READ_FIFO now return 0xbc and 0x3c or only 0x3c? + */ + s->kbd.start ++; + s->kbd.start &= sizeof(s->kbd.fifo) - 1; + s->kbd.len --; + + return s->kbd.fifo[s->kbd.start]; + case LM832x_CMD_RPT_READ_FIFO: + if (byte >= s->kbd.len) + return 0x00; + + return s->kbd.fifo[(s->kbd.start + byte) & (sizeof(s->kbd.fifo) - 1)]; + + case LM832x_CMD_READ_ERROR: + return s->error; + + case LM832x_CMD_READ_ROTATOR: + return 0; + + case LM832x_CMD_READ_KEY_SIZE: + return s->kbd.size; + + case LM832x_CMD_READ_CFG: + return s->config & 0xf; + + case LM832x_CMD_READ_CLOCK: + return (s->clock & 0xfc) | 2; + + default: + lm_kbd_error(s, ERR_CMDUNK); + fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, reg); + return 0x00; + } + + return ret >> (byte << 3); +} + +static void lm_kbd_write(struct lm_kbd_s *s, int reg, int byte, uint8_t value) +{ + switch (reg) { + case LM832x_CMD_WRITE_CFG: + s->config = value; + /* This must be done whenever s->mux.in is updated (never). */ + if ((s->config >> 1) & 1) /* MUX1EN */ + qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 0) & 1]); + if ((s->config >> 3) & 1) /* MUX2EN */ + qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 2) & 1]); + /* TODO: check that this is issued only following the chip reset + * and not in the middle of operation and that it is followed by + * the GPIO ports re-resablishing through WRITE_PORT_SEL and + * WRITE_PORT_STATE (using a timer perhaps) and otherwise output + * warnings. */ + s->status = 0; + lm_kbd_irq_update(s); + s->kbd.len = 0; + s->kbd.start = 0; + s->reg = -1; + break; + + case LM832x_CMD_RESET: + if (value == 0xaa) + lm_kbd_reset(s); + else + lm_kbd_error(s, ERR_BADPAR); + s->reg = -1; + break; + + case LM823x_CMD_WRITE_PULL_DOWN: + if (!byte) + s->gpio.pull = value; + else { + s->gpio.pull |= value << 8; + lm_kbd_gpio_update(s); + s->reg = -1; + } + break; + case LM832x_CMD_WRITE_PORT_SEL: + if (!byte) + s->gpio.dir = value; + else { + s->gpio.dir |= value << 8; + lm_kbd_gpio_update(s); + s->reg = -1; + } + break; + case LM832x_CMD_WRITE_PORT_STATE: + if (!byte) + s->gpio.mask = value; + else { + s->gpio.mask |= value << 8; + lm_kbd_gpio_update(s); + s->reg = -1; + } + break; + + case LM832x_CMD_SET_ACTIVE: + s->acttime = value; + s->reg = -1; + break; + + case LM832x_CMD_SET_DEBOUNCE: + s->kbd.dbnctime = value; + s->reg = -1; + if (!value) + lm_kbd_error(s, ERR_BADPAR); + break; + + case LM832x_CMD_SET_KEY_SIZE: + s->kbd.size = value; + s->reg = -1; + if ( + (value & 0xf) < 3 || (value & 0xf) > LM832x_MAX_KPY || + (value >> 4) < 3 || (value >> 4) > LM832x_MAX_KPX) + lm_kbd_error(s, ERR_BADPAR); + break; + + case LM832x_CMD_WRITE_CLOCK: + s->clock = value; + s->reg = -1; + if ((value & 3) && (value & 3) != 3) { + lm_kbd_error(s, ERR_BADPAR); + fprintf(stderr, "%s: invalid clock setting in RCPWM\n", + __FUNCTION__); + } + /* TODO: Validate that the command is only issued once */ + break; + + case LM832x_CMD_PWM_WRITE: + if (byte == 0) { + if (!(value & 3) || (value >> 2) > 59) { + lm_kbd_error(s, ERR_BADPAR); + s->reg = -1; + break; + } + + s->pwm.faddr = value; + s->pwm.file[s->pwm.faddr] = 0; + } else if (byte == 1) { + s->pwm.file[s->pwm.faddr] |= value << 8; + } else if (byte == 2) { + s->pwm.file[s->pwm.faddr] |= value << 0; + s->reg = -1; + } + break; + case LM832x_CMD_PWM_START: + s->reg = -1; + if (!(value & 3) || (value >> 2) > 59) { + lm_kbd_error(s, ERR_BADPAR); + break; + } + + s->pwm.addr[(value & 3) - 1] = value >> 2; + lm_kbd_pwm_start(s, (value & 3) - 1); + break; + case LM832x_CMD_PWM_STOP: + s->reg = -1; + if (!(value & 3)) { + lm_kbd_error(s, ERR_BADPAR); + break; + } + + qemu_del_timer(s->pwm.tm[(value & 3) - 1]); + break; + + case -1: + lm_kbd_error(s, ERR_BADPAR); + break; + default: + lm_kbd_error(s, ERR_CMDUNK); + fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, reg); + break; + } +} + +static void lm_i2c_event(i2c_slave *i2c, enum i2c_event event) +{ + struct lm_kbd_s *s = (struct lm_kbd_s *) i2c; + + switch (event) { + case I2C_START_RECV: + case I2C_START_SEND: + s->i2c_cycle = 0; + s->i2c_dir = (event == I2C_START_SEND); + break; + + default: + break; + } +} + +static int lm_i2c_rx(i2c_slave *i2c) +{ + struct lm_kbd_s *s = (struct lm_kbd_s *) i2c; + + return lm_kbd_read(s, s->reg, s->i2c_cycle ++); +} + +static int lm_i2c_tx(i2c_slave *i2c, uint8_t data) +{ + struct lm_kbd_s *s = (struct lm_kbd_s *) i2c; + + if (!s->i2c_cycle) + s->reg = data; + else + lm_kbd_write(s, s->reg, s->i2c_cycle - 1, data); + s->i2c_cycle ++; + + return 0; +} + +static void lm_kbd_save(QEMUFile *f, void *opaque) +{ + struct lm_kbd_s *s = (struct lm_kbd_s *) opaque; + int i; + + i2c_slave_save(f, &s->i2c); + qemu_put_byte(f, s->i2c_dir); + qemu_put_byte(f, s->i2c_cycle); + qemu_put_byte(f, (uint8_t) s->reg); + + qemu_put_8s(f, &s->config); + qemu_put_8s(f, &s->status); + qemu_put_8s(f, &s->acttime); + qemu_put_8s(f, &s->error); + qemu_put_8s(f, &s->clock); + + qemu_put_be16s(f, &s->gpio.pull); + qemu_put_be16s(f, &s->gpio.mask); + qemu_put_be16s(f, &s->gpio.dir); + qemu_put_be16s(f, &s->gpio.level); + + qemu_put_byte(f, s->kbd.dbnctime); + qemu_put_byte(f, s->kbd.size); + qemu_put_byte(f, s->kbd.start); + qemu_put_byte(f, s->kbd.len); + qemu_put_buffer(f, s->kbd.fifo, sizeof(s->kbd.fifo)); + + for (i = 0; i < sizeof(s->pwm.file); i ++) + qemu_put_be16s(f, &s->pwm.file[i]); + qemu_put_8s(f, &s->pwm.faddr); + qemu_put_buffer(f, s->pwm.addr, sizeof(s->pwm.addr)); + qemu_put_timer(f, s->pwm.tm[0]); + qemu_put_timer(f, s->pwm.tm[1]); + qemu_put_timer(f, s->pwm.tm[2]); +} + +static int lm_kbd_load(QEMUFile *f, void *opaque, int version_id) +{ + struct lm_kbd_s *s = (struct lm_kbd_s *) opaque; + int i; + + i2c_slave_load(f, &s->i2c); + s->i2c_dir = qemu_get_byte(f); + s->i2c_cycle = qemu_get_byte(f); + s->reg = (int8_t) qemu_get_byte(f); + + qemu_get_8s(f, &s->config); + qemu_get_8s(f, &s->status); + qemu_get_8s(f, &s->acttime); + qemu_get_8s(f, &s->error); + qemu_get_8s(f, &s->clock); + + qemu_get_be16s(f, &s->gpio.pull); + qemu_get_be16s(f, &s->gpio.mask); + qemu_get_be16s(f, &s->gpio.dir); + qemu_get_be16s(f, &s->gpio.level); + + s->kbd.dbnctime = qemu_get_byte(f); + s->kbd.size = qemu_get_byte(f); + s->kbd.start = qemu_get_byte(f); + s->kbd.len = qemu_get_byte(f); + qemu_get_buffer(f, s->kbd.fifo, sizeof(s->kbd.fifo)); + + for (i = 0; i < sizeof(s->pwm.file); i ++) + qemu_get_be16s(f, &s->pwm.file[i]); + qemu_get_8s(f, &s->pwm.faddr); + qemu_get_buffer(f, s->pwm.addr, sizeof(s->pwm.addr)); + qemu_get_timer(f, s->pwm.tm[0]); + qemu_get_timer(f, s->pwm.tm[1]); + qemu_get_timer(f, s->pwm.tm[2]); + + lm_kbd_irq_update(s); + lm_kbd_gpio_update(s); + + return 0; +} + +struct i2c_slave *lm8323_init(i2c_bus *bus, qemu_irq nirq) +{ + struct lm_kbd_s *s; + + s = (struct lm_kbd_s *) i2c_slave_init(bus, 0, sizeof(struct lm_kbd_s)); + s->model = 0x8323; + s->pwm.tm[0] = qemu_new_timer(vm_clock, lm_kbd_pwm0_tick, s); + s->pwm.tm[1] = qemu_new_timer(vm_clock, lm_kbd_pwm1_tick, s); + s->pwm.tm[2] = qemu_new_timer(vm_clock, lm_kbd_pwm2_tick, s); + s->nirq = nirq; + + s->i2c.event = lm_i2c_event; + s->i2c.recv = lm_i2c_rx; + s->i2c.send = lm_i2c_tx; + + lm_kbd_reset(s); + + qemu_register_reset((void *) lm_kbd_reset, s); + register_savevm("LM8323", -1, 0, lm_kbd_save, lm_kbd_load, s); + + return &s->i2c; +} + +void lm832x_key_event(struct i2c_slave *i2c, int key, int state) +{ + struct lm_kbd_s *s = (struct lm_kbd_s *) i2c; + + if ((s->status & INT_ERROR) && (s->error & ERR_FIFOOVR)) + return; + + if (s->kbd.len >= sizeof(s->kbd.fifo)) + return lm_kbd_error(s, ERR_FIFOOVR); + + s->kbd.fifo[(s->kbd.start + s->kbd.len ++) & (sizeof(s->kbd.fifo) - 1)] = + key | (state << 7); + + /* We never set ERR_KEYOVR because we support multiple keys fine. */ + s->status |= INT_KEYPAD; + lm_kbd_irq_update(s); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/lsi53c895a.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/lsi53c895a.c --- qemu-0.9.1/hw/lsi53c895a.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/lsi53c895a.c 2008-09-22 17:30:29.000000000 +0100 @@ -501,7 +501,7 @@ DPRINTF("Queueing tag=0x%x\n", s->current_tag); if (s->queue_len == s->active_commands) { s->queue_len++; - s->queue = realloc(s->queue, s->queue_len * sizeof(lsi_queue)); + s->queue = qemu_realloc(s->queue, s->queue_len * sizeof(lsi_queue)); } p = &s->queue[s->active_commands++]; p->tag = s->current_tag; @@ -839,9 +839,11 @@ uint32_t insn; uint32_t addr; int opcode; + int insn_processed = 0; s->istat1 |= LSI_ISTAT1_SRUN; again: + insn_processed++; insn = read_dword(s, s->dsp); addr = read_dword(s, s->dsp + 4); DPRINTF("SCRIPTS dsp=%08x opcode %08x arg %08x\n", s->dsp, insn, addr); @@ -1196,8 +1198,17 @@ } } } - /* ??? Need to avoid infinite loops. */ - if (s->istat1 & LSI_ISTAT1_SRUN && !s->waiting) { + if (insn_processed > 10000 && !s->waiting) { + /* Some windows drivers make the device spin waiting for a memory + location to change. If we have been executed a lot of code then + assume this is the case and force an unexpected device disconnect. + This is apparently sufficient to beat the drivers into submission. + */ + if (!(s->sien0 & LSI_SIST0_UDC)) + fprintf(stderr, "inf. loop with UDC masked\n"); + lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0); + lsi_disconnect(s); + } else if (s->istat1 & LSI_ISTAT1_SRUN && !s->waiting) { if (s->dcntl & LSI_DCNTL_SSM) { lsi_script_dma_interrupt(s, LSI_DSTAT_SSI); } else { diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/m48t59.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/m48t59.c --- qemu-0.9.1/hw/m48t59.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/m48t59.c 2008-02-17 11:42:19.000000000 +0000 @@ -53,7 +53,7 @@ time_t time_offset; time_t stop_time; /* Alarm & watchdog */ - time_t alarm; + struct tm alarm; struct QEMUTimer *alrm_timer; struct QEMUTimer *wd_timer; /* NVRAM storage */ @@ -74,35 +74,10 @@ 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; -#ifdef _WIN32 - memcpy(tm,localtime(&t),sizeof(*tm)); -#else - if (rtc_utc) - gmtime_r (&t, tm); - else - localtime_r (&t, tm) ; -#endif -} - -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; + struct tm tm; uint64_t next_time; m48t59_t *NVRAM = opaque; @@ -111,62 +86,62 @@ (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); + /* Repeat once a month */ + qemu_get_timedate(&tm, NVRAM->time_offset); + tm.tm_mon++; + if (tm.tm_mon == 13) { + tm.tm_mon = 1; + tm.tm_year++; + } + next_time = qemu_timedate_diff(&tm) - NVRAM->time_offset; } 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); + /* Repeat once a day */ + next_time = 24 * 60 * 60; } 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); + /* Repeat once an hour */ + next_time = 60 * 60; } 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); + /* Repeat once a minute */ + next_time = 60; } else { - /* Repeat once a second */ - next_time = 1 + mktime(&tm_now); + /* Repeat once a second */ + next_time = 1; } - qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000); + qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock(vm_clock) + + next_time * 1000); qemu_set_irq(NVRAM->IRQ, 0); } +static void set_alarm (m48t59_t *NVRAM) +{ + int diff; + if (NVRAM->alrm_timer != NULL) { + qemu_del_timer(NVRAM->alrm_timer); + diff = qemu_timedate_diff(&NVRAM->alarm) - NVRAM->time_offset; + if (diff > 0) + qemu_mod_timer(NVRAM->alrm_timer, diff * 1000); + } +} -static void get_alarm (m48t59_t *NVRAM, struct tm *tm) +/* RTC management helpers */ +static inline void get_time (m48t59_t *NVRAM, struct tm *tm) { -#ifdef _WIN32 - memcpy(tm,localtime(&NVRAM->alarm),sizeof(*tm)); -#else - if (rtc_utc) - gmtime_r (&NVRAM->alarm, tm); - else - localtime_r (&NVRAM->alarm, tm); -#endif + qemu_get_timedate(tm, NVRAM->time_offset); } -static void set_alarm (m48t59_t *NVRAM, struct tm *tm) +static void set_time (m48t59_t *NVRAM, struct tm *tm) { - NVRAM->alarm = mktime(tm); - if (NVRAM->alrm_timer != NULL) { - qemu_del_timer(NVRAM->alrm_timer); - if (NVRAM->alarm - time(NULL) > 0) - qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000); - } + NVRAM->time_offset = qemu_timedate_diff(tm); + set_alarm(NVRAM); } /* Watchdog management */ @@ -229,40 +204,36 @@ /* alarm seconds */ tmp = fromBCD(val & 0x7F); if (tmp >= 0 && tmp <= 59) { - get_alarm(NVRAM, &tm); - tm.tm_sec = tmp; + NVRAM->alarm.tm_sec = tmp; NVRAM->buffer[0x1FF2] = val; - set_alarm(NVRAM, &tm); + set_alarm(NVRAM); } break; case 0x1FF3: /* alarm minutes */ tmp = fromBCD(val & 0x7F); if (tmp >= 0 && tmp <= 59) { - get_alarm(NVRAM, &tm); - tm.tm_min = tmp; + NVRAM->alarm.tm_min = tmp; NVRAM->buffer[0x1FF3] = val; - set_alarm(NVRAM, &tm); + set_alarm(NVRAM); } break; case 0x1FF4: /* alarm hours */ tmp = fromBCD(val & 0x3F); if (tmp >= 0 && tmp <= 23) { - get_alarm(NVRAM, &tm); - tm.tm_hour = tmp; + NVRAM->alarm.tm_hour = tmp; NVRAM->buffer[0x1FF4] = val; - set_alarm(NVRAM, &tm); + set_alarm(NVRAM); } break; case 0x1FF5: /* alarm date */ tmp = fromBCD(val & 0x1F); if (tmp != 0) { - get_alarm(NVRAM, &tm); - tm.tm_mday = tmp; + NVRAM->alarm.tm_mday = tmp; NVRAM->buffer[0x1FF5] = val; - set_alarm(NVRAM, &tm); + set_alarm(NVRAM); } break; case 0x1FF6: @@ -288,7 +259,7 @@ tm.tm_sec = tmp; set_time(NVRAM, &tm); } - if ((val & 0x80) ^ (NVRAM->buffer[addr] & 0x80)) { + if ((val & 0x80) ^ (NVRAM->buffer[addr] & 0x80)) { if (val & 0x80) { NVRAM->stop_time = time(NULL); } else { @@ -296,7 +267,7 @@ NVRAM->stop_time = 0; } } - NVRAM->buffer[addr] = val & 0x80; + NVRAM->buffer[addr] = val & 0x80; break; case 0x1FFA: case 0x07FA: @@ -682,6 +653,7 @@ s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s); } s->lock = 0; + qemu_get_timedate(&s->alarm, 0); qemu_register_reset(m48t59_reset, s); save_base = mem_base ? mem_base : io_base; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/mainstone.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/mainstone.c --- qemu-0.9.1/hw/mainstone.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/mainstone.c 2008-10-28 10:59:59.000000000 +0000 @@ -59,14 +59,20 @@ enum mainstone_model_e { mainstone }; -static void mainstone_common_init(int ram_size, int vga_ram_size, +#define MAINSTONE_RAM 0x04000000 +#define MAINSTONE_ROM 0x00800000 +#define MAINSTONE_FLASH 0x02000000 + +static struct arm_boot_info mainstone_binfo = { + .loader_start = PXA2XX_SDRAM_BASE, + .ram_size = 0x04000000, +}; + +static void mainstone_common_init(ram_addr_t ram_size, int vga_ram_size, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model, enum mainstone_model_e model, int arm_id) { - uint32_t mainstone_ram = 0x04000000; - uint32_t mainstone_rom = 0x00800000; - uint32_t mainstone_flash = 0x02000000; uint32_t sector_len = 256 * 1024; target_phys_addr_t mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 }; struct pxa2xx_state_s *cpu; @@ -77,20 +83,20 @@ cpu_model = "pxa270-c5"; /* Setup CPU & memory */ - if (ram_size < mainstone_ram + mainstone_rom + 2 * mainstone_flash + + if (ram_size < MAINSTONE_RAM + MAINSTONE_ROM + 2 * MAINSTONE_FLASH + PXA2XX_INTERNAL_SIZE) { fprintf(stderr, "This platform requires %i bytes of memory\n", - mainstone_ram + mainstone_rom + 2 * mainstone_flash + + MAINSTONE_RAM + MAINSTONE_ROM + 2 * MAINSTONE_FLASH + PXA2XX_INTERNAL_SIZE); exit(1); } - cpu = pxa270_init(mainstone_ram, ds, cpu_model); - cpu_register_physical_memory(0, mainstone_rom, - qemu_ram_alloc(mainstone_rom) | IO_MEM_ROM); + cpu = pxa270_init(mainstone_binfo.ram_size, ds, cpu_model); + cpu_register_physical_memory(0, MAINSTONE_ROM, + qemu_ram_alloc(MAINSTONE_ROM) | IO_MEM_ROM); /* Setup initial (reset) machine state */ - cpu->env->regs[15] = PXA2XX_SDRAM_BASE; + cpu->env->regs[15] = mainstone_binfo.loader_start; /* There are two 32MiB flash devices on the board */ for (i = 0; i < 2; i ++) { @@ -102,9 +108,9 @@ } if (!pflash_cfi01_register(mainstone_flash_base[i], - qemu_ram_alloc(mainstone_flash), + qemu_ram_alloc(MAINSTONE_FLASH), drives_table[index].bdrv, sector_len, - mainstone_flash / sector_len, 4, 0, 0, 0, 0)) { + MAINSTONE_FLASH / sector_len, 4, 0, 0, 0, 0)) { fprintf(stderr, "qemu: Error registering flash memory.\n"); exit(1); } @@ -121,11 +127,14 @@ smc91c111_init(&nd_table[0], MST_ETH_PHYS, mst_irq[ETHERNET_IRQ]); - arm_load_kernel(cpu->env, mainstone_ram, kernel_filename, kernel_cmdline, - initrd_filename, arm_id, PXA2XX_SDRAM_BASE); + mainstone_binfo.kernel_filename = kernel_filename; + mainstone_binfo.kernel_cmdline = kernel_cmdline; + mainstone_binfo.initrd_filename = initrd_filename; + mainstone_binfo.board_id = arm_id; + arm_load_kernel(cpu->env, &mainstone_binfo); } -static void mainstone_init(int ram_size, int vga_ram_size, +static void mainstone_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -135,7 +144,9 @@ } QEMUMachine mainstone2_machine = { - "mainstone", - "Mainstone II (PXA27x)", - mainstone_init, + .name = "mainstone", + .desc = "Mainstone II (PXA27x)", + .init = mainstone_init, + .ram_require = (MAINSTONE_RAM + MAINSTONE_ROM + 2 * MAINSTONE_FLASH + + PXA2XX_INTERNAL_SIZE) | RAMSIZE_FIXED, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/max111x.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/max111x.c --- qemu-0.9.1/hw/max111x.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/max111x.c 2008-07-01 22:31:54.000000000 +0100 @@ -121,8 +121,6 @@ return 0; } -static int max111x_iid = 0; - static struct max111x_s *max111x_init(qemu_irq cb) { struct max111x_s *s; @@ -143,8 +141,7 @@ s->input[7] = 0x80; s->com = 0; - register_savevm("max111x", max111x_iid ++, 0, - max111x_save, max111x_load, s); + register_savevm("max111x", -1, 0, max111x_save, max111x_load, s); return s; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/max7310.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/max7310.c --- qemu-0.9.1/hw/max7310.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/max7310.c 2008-07-01 22:31:54.000000000 +0100 @@ -134,8 +134,8 @@ s->i2c_command_byte = 1; break; case I2C_FINISH: - if (s->len == 1) #ifdef VERBOSE + if (s->len == 1) printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len); #endif break; @@ -177,8 +177,6 @@ return 0; } -static int max7310_iid = 0; - static void max7310_gpio_set(void *opaque, int line, int level) { struct max7310_s *s = (struct max7310_s *) opaque; @@ -205,8 +203,7 @@ max7310_reset(&s->i2c); - register_savevm("max7310", max7310_iid ++, 0, - max7310_save, max7310_load, s); + register_savevm("max7310", -1, 0, max7310_save, max7310_load, s); return &s->i2c; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/mc146818rtc.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/mc146818rtc.c --- qemu-0.9.1/hw/mc146818rtc.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/mc146818rtc.c 2008-02-17 11:42:19.000000000 +0000 @@ -392,24 +392,14 @@ static void rtc_set_date_from_host(RTCState *s) { - time_t ti; - struct tm *tm; + struct tm tm; int val; /* set the CMOS date */ - if (rtc_start_date == -1) { - time(&ti); - if (rtc_utc) - tm = gmtime(&ti); - else - tm = localtime(&ti); - } else { - ti = rtc_start_date; - tm = gmtime(&ti); - } - rtc_set_date(s, tm); + qemu_get_timedate(&tm, 0); + rtc_set_date(s, &tm); - val = to_bcd(s, (tm->tm_year / 100) + 19); + val = to_bcd(s, (tm.tm_year / 100) + 19); rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val); rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/mcf5208.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/mcf5208.c --- qemu-0.9.1/hw/mcf5208.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/mcf5208.c 2008-10-28 10:59:59.000000000 +0000 @@ -202,7 +202,7 @@ } } -static void mcf5208evb_init(int ram_size, int vga_ram_size, +static void mcf5208evb_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -305,7 +305,8 @@ } QEMUMachine mcf5208evb_machine = { - "mcf5208evb", - "MCF5206EVB", - mcf5208evb_init, + .name = "mcf5208evb", + .desc = "MCF5206EVB", + .init = mcf5208evb_init, + .ram_require = 16384, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/mips.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/mips.h --- qemu-0.9.1/hw/mips.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/mips.h 2008-09-14 17:38:57.000000000 +0100 @@ -6,8 +6,13 @@ PCIBus *pci_gt64120_init(qemu_irq *pic); /* ds1225y.c */ -typedef struct ds1225y_t ds1225y_t; -ds1225y_t *ds1225y_init(target_phys_addr_t mem_base, const char *filename); +void *ds1225y_init(target_phys_addr_t mem_base, const char *filename); +void ds1225y_set_protection(void *opaque, int protection); + +/* g364fb.c */ +int g364fb_mm_init(DisplayState *ds, + int vram_size, int it_shift, + target_phys_addr_t vram_base, target_phys_addr_t ctrl_base); /* mipsnet.c */ void mipsnet_init(int base, qemu_irq irq, NICInfo *nd); @@ -20,6 +25,8 @@ /* mips_timer.c */ extern void cpu_mips_clock_init(CPUState *); -extern void cpu_mips_irqctrl_init (void); + +/* rc4030.c */ +qemu_irq *rc4030_init(qemu_irq timer, qemu_irq jazz_bus); #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/mips_jazz.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/mips_jazz.c --- qemu-0.9.1/hw/mips_jazz.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/mips_jazz.c 2008-10-28 10:59:59.000000000 +0000 @@ -0,0 +1,289 @@ +/* + * QEMU MIPS Jazz support + * + * Copyright (c) 2007-2008 Hervé Poussineau + * + * 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 "hw.h" +#include "mips.h" +#include "pc.h" +#include "isa.h" +#include "fdc.h" +#include "sysemu.h" +#include "audio/audio.h" +#include "boards.h" +#include "net.h" +#include "scsi.h" + +#ifdef TARGET_WORDS_BIGENDIAN +#define BIOS_FILENAME "mips_bios.bin" +#else +#define BIOS_FILENAME "mipsel_bios.bin" +#endif + +enum jazz_model_e +{ + JAZZ_MAGNUM, + JAZZ_PICA61, +}; + +static void main_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + cpu_reset(env); +} + +static uint32_t rtc_readb(void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + return cpu_inw(env, 0x71); +} + +static void rtc_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + CPUState *env = opaque; + cpu_outw(env, 0x71, val & 0xff); +} + +static CPUReadMemoryFunc *rtc_read[3] = { + rtc_readb, + rtc_readb, + rtc_readb, +}; + +static CPUWriteMemoryFunc *rtc_write[3] = { + rtc_writeb, + rtc_writeb, + rtc_writeb, +}; + +#ifdef HAS_AUDIO +static void audio_init(qemu_irq *pic) +{ + struct soundhw *c; + int audio_enabled = 0; + + for (c = soundhw; !audio_enabled && c->name; ++c) { + audio_enabled = c->enabled; + } + + if (audio_enabled) { + AudioState *s; + + s = AUD_init(); + if (s) { + for (c = soundhw; c->name; ++c) { + if (c->enabled) { + if (c->isa) { + c->init.init_isa(s, pic); + } + } + } + } + } +} +#endif + +void espdma_memory_read(void *opaque, uint8_t *buf, int len) +{ + printf("espdma_memory_read(buf %p, len %d) not implemented\n", buf, len); +} + +void espdma_memory_write(void *opaque, uint8_t *buf, int len) +{ + printf("espdma_memory_write(buf %p, len %d) not implemented\n", buf, len); +} + +#define MAGNUM_BIOS_SIZE_MAX 0x7e000 +#define MAGNUM_BIOS_SIZE (BIOS_SIZE < MAGNUM_BIOS_SIZE_MAX ? BIOS_SIZE : MAGNUM_BIOS_SIZE_MAX) + +static +void mips_jazz_init (ram_addr_t ram_size, int vga_ram_size, + DisplayState *ds, const char *cpu_model, + enum jazz_model_e jazz_model) +{ + char buf[1024]; + unsigned long bios_offset; + int bios_size, n; + CPUState *env; + qemu_irq *rc4030, *i8259; + void *scsi_hba; + int hd; + int s_rtc; + PITState *pit; + BlockDriverState *fds[MAX_FD]; + qemu_irq esp_reset; + + /* init CPUs */ + if (cpu_model == NULL) { +#ifdef TARGET_MIPS64 + cpu_model = "R4000"; +#else + /* FIXME: All wrong, this maybe should be R3000 for the older JAZZs. */ + cpu_model = "24Kf"; +#endif + } + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + qemu_register_reset(main_cpu_reset, env); + + /* allocate RAM */ + cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + + /* load the BIOS image. */ + bios_offset = ram_size + vga_ram_size; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + bios_size = load_image(buf, phys_ram_base + bios_offset); + if (bios_size < 0 || bios_size > MAGNUM_BIOS_SIZE) { + fprintf(stderr, "qemu: Could not load MIPS bios '%s'\n", + buf); + exit(1); + } + + cpu_register_physical_memory(0x1fc00000LL, + MAGNUM_BIOS_SIZE, bios_offset | IO_MEM_ROM); + cpu_register_physical_memory(0xfff00000LL, + MAGNUM_BIOS_SIZE, bios_offset | IO_MEM_ROM); + + /* Init CPU internal devices */ + cpu_mips_irq_init_cpu(env); + cpu_mips_clock_init(env); + + /* Chipset */ + rc4030 = rc4030_init(env->irq[6], env->irq[3]); + + /* ISA devices */ + i8259 = i8259_init(env->irq[4]); + pit = pit_init(0x40, i8259[0]); + pcspk_init(pit); + + /* ISA IO space at 0x90000000 */ + isa_mmio_init(0x90000000, 0x01000000); + isa_mem_base = 0x11000000; + + /* Video card */ + switch (jazz_model) { + case JAZZ_MAGNUM: + g364fb_mm_init(ds, vga_ram_size, 0, 0x40000000, 0x60000000); + break; + case JAZZ_PICA61: + isa_vga_mm_init(ds, phys_ram_base + ram_size, ram_size, vga_ram_size, + 0x40000000, 0x60000000, 0); + break; + default: + break; + } + + /* Network controller */ + /* FIXME: missing NS SONIC DP83932 */ + + /* SCSI adapter */ + scsi_hba = esp_init(0x80002000, 0, + espdma_memory_read, espdma_memory_write, NULL, + rc4030[5], &esp_reset); + for (n = 0; n < ESP_MAX_DEVS; n++) { + hd = drive_get_index(IF_SCSI, 0, n); + if (hd != -1) { + esp_scsi_attach(scsi_hba, drives_table[hd].bdrv, n); + } + } + + /* Floppy */ + if (drive_get_max_bus(IF_FLOPPY) >= MAX_FD) { + fprintf(stderr, "qemu: too many floppy drives\n"); + exit(1); + } + for (n = 0; n < MAX_FD; n++) { + int fd = drive_get_index(IF_FLOPPY, 0, n); + if (fd != -1) + fds[n] = drives_table[fd].bdrv; + else + fds[n] = NULL; + } + fdctrl_init(rc4030[1], 0, 1, 0x80003000, fds); + + /* Real time clock */ + rtc_init(0x70, i8259[8]); + s_rtc = cpu_register_io_memory(0, rtc_read, rtc_write, env); + cpu_register_physical_memory(0x80004000, 0x00001000, s_rtc); + + /* Keyboard (i8042) */ + i8042_mm_init(rc4030[6], rc4030[7], 0x80005000, 0); + + /* Serial ports */ + if (serial_hds[0]) + serial_mm_init(0x80006000, 0, rc4030[8], 8000000/16, serial_hds[0], 1); + if (serial_hds[1]) + serial_mm_init(0x80007000, 0, rc4030[9], 8000000/16, serial_hds[1], 1); + + /* Parallel port */ + if (parallel_hds[0]) + parallel_mm_init(0x80008000, 0, rc4030[0], parallel_hds[0]); + + /* Sound card */ + /* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */ +#ifdef HAS_AUDIO + audio_init(i8259); +#endif + + /* NVRAM: Unprotected at 0x9000, Protected at 0xa000, Read only at 0xb000 */ + ds1225y_init(0x80009000, "nvram"); + + /* LED indicator */ + jazz_led_init(ds, 0x8000f000); +} + +static +void mips_magnum_init (ram_addr_t ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + mips_jazz_init(ram_size, vga_ram_size, ds, cpu_model, JAZZ_MAGNUM); +} + +static +void mips_pica61_init (ram_addr_t ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + mips_jazz_init(ram_size, vga_ram_size, ds, cpu_model, JAZZ_PICA61); +} + +QEMUMachine mips_magnum_machine = { + .name = "magnum", + .desc = "MIPS Magnum", + .init = mips_magnum_init, + .ram_require = MAGNUM_BIOS_SIZE + VGA_RAM_SIZE, + .nodisk_ok = 1, +}; + +QEMUMachine mips_pica61_machine = { + .name = "pica61", + .desc = "Acer Pica 61", + .init = mips_pica61_init, + .ram_require = MAGNUM_BIOS_SIZE + VGA_RAM_SIZE, + .nodisk_ok = 1, +}; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/mips_malta.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/mips_malta.c --- qemu-0.9.1/hw/mips_malta.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/mips_malta.c 2008-11-01 00:53:19.000000000 +0000 @@ -36,6 +36,7 @@ #include "sysemu.h" #include "audio/audio.h" #include "boards.h" +#include "qemu-log.h" //#define DEBUG_BOARD_INIT @@ -59,8 +60,6 @@ #define MAX_IDE_BUS 2 -extern FILE *logfile; - typedef struct { uint32_t leds; uint32_t brk; @@ -155,7 +154,7 @@ }, }; -static uint8_t eeprom24c0x_read() +static uint8_t eeprom24c0x_read(void) { logout("%u: scl = %u, sda = %u, data = 0x%02x\n", eeprom.tick, eeprom.scl, eeprom.sda, eeprom.data); @@ -436,7 +435,7 @@ cpu_register_physical_memory(base, 0x900, malta); cpu_register_physical_memory(base + 0xa00, 0x100000 - 0xa00, malta); - s->display = qemu_chr_open("vc"); + s->display = qemu_chr_open("fpga", "vc:320x200"); qemu_chr_printf(s->display, "\e[HMalta LEDBAR\r\n"); qemu_chr_printf(s->display, "+--------+\r\n"); qemu_chr_printf(s->display, "+ +\r\n"); @@ -447,9 +446,10 @@ qemu_chr_printf(s->display, "+ +\r\n"); qemu_chr_printf(s->display, "+--------+\r\n"); - uart_chr = qemu_chr_open("vc"); + uart_chr = qemu_chr_open("cbus", "vc:80Cx24C"); qemu_chr_printf(uart_chr, "CBUS UART\r\n"); - s->uart = serial_mm_init(base + 0x900, 3, env->irq[2], uart_chr, 1); + s->uart = + serial_mm_init(base + 0x900, 3, env->irq[2], 230400, uart_chr, 1); malta_fpga_reset(s); qemu_register_reset(malta_fpga_reset, s); @@ -700,7 +700,8 @@ ram_addr_t initrd_offset; if (load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND, - &kernel_entry, &kernel_low, &kernel_high) < 0) { + (uint64_t *)&kernel_entry, (uint64_t *)&kernel_low, + (uint64_t *)&kernel_high) < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", loaderparams.kernel_filename); exit(1); @@ -763,7 +764,7 @@ } static -void mips_malta_init (int ram_size, int vga_ram_size, +void mips_malta_init (ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -801,7 +802,6 @@ fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); /* allocate RAM */ @@ -878,7 +878,6 @@ /* Init internal devices */ cpu_mips_irq_init_cpu(env); cpu_mips_clock_init(env); - cpu_mips_irqctrl_init(); /* Interrupt controller */ /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */ @@ -905,7 +904,7 @@ piix4_devfn = piix4_init(pci_bus, 80); pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1, i8259); usb_uhci_piix4_init(pci_bus, piix4_devfn + 2); - smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100); + smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100, i8259[9]); eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */ for (i = 0; i < 8; i++) { /* TODO: Populate SPD eeprom data. */ @@ -918,9 +917,9 @@ i8042_init(i8259[1], i8259[12], 0x60); rtc_state = rtc_init(0x70, i8259[8]); if (serial_hds[0]) - serial_init(0x3f8, i8259[4], serial_hds[0]); + serial_init(0x3f8, i8259[4], 115200, serial_hds[0]); if (serial_hds[1]) - serial_init(0x2f8, i8259[3], serial_hds[1]); + serial_init(0x2f8, i8259[3], 115200, serial_hds[1]); if (parallel_hds[0]) parallel_init(0x378, i8259[7], parallel_hds[0]); for(i = 0; i < MAX_FD; i++) { @@ -946,7 +945,9 @@ } QEMUMachine mips_malta_machine = { - "malta", - "MIPS Malta Core LV", - mips_malta_init, + .name = "malta", + .desc = "MIPS Malta Core LV", + .init = mips_malta_init, + .ram_require = VGA_RAM_SIZE + BIOS_SIZE, + .nodisk_ok = 1, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/mips_mipssim.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/mips_mipssim.c --- qemu-0.9.1/hw/mips_mipssim.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/mips_mipssim.c 2008-10-28 10:59:59.000000000 +0000 @@ -61,11 +61,12 @@ ram_addr_t initrd_offset; kernel_size = load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND, - &entry, &kernel_low, &kernel_high); + (uint64_t *)&entry, (uint64_t *)&kernel_low, + (uint64_t *)&kernel_high); if (kernel_size >= 0) { if ((entry & ~0x7fffffffULL) == 0x80000000) entry = (int32_t)entry; - env->PC[env->current_tc] = entry; + env->active_tc.PC = entry; } else { fprintf(stderr, "qemu: could not load kernel '%s'\n", loaderparams.kernel_filename); @@ -106,7 +107,7 @@ } static void -mips_mipssim_init (int ram_size, int vga_ram_size, +mips_mipssim_init (ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -129,7 +130,6 @@ fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); /* Allocate RAM. */ @@ -152,7 +152,7 @@ cpu_register_physical_memory(0x1fc00000LL, bios_size, bios_offset | IO_MEM_ROM); /* We have a boot vector start address. */ - env->PC[env->current_tc] = (target_long)(int32_t)0xbfc00000; + env->active_tc.PC = (target_long)(int32_t)0xbfc00000; } if (kernel_filename) { @@ -166,7 +166,6 @@ /* Init CPU internal devices. */ cpu_mips_irq_init_cpu(env); cpu_mips_clock_init(env); - cpu_mips_irqctrl_init(); /* Register 64 KB of ISA IO space at 0x1fd00000. */ isa_mmio_init(0x1fd00000, 0x00010000); @@ -174,7 +173,7 @@ /* A single 16450 sits at offset 0x3f8. It is attached to MIPS CPU INT2, which is interrupt 4. */ if (serial_hds[0]) - serial_init(0x3f8, env->irq[4], serial_hds[0]); + serial_init(0x3f8, env->irq[4], 115200, serial_hds[0]); if (nd_table[0].vlan) { if (nd_table[0].model == NULL @@ -192,7 +191,9 @@ } QEMUMachine mips_mipssim_machine = { - "mipssim", - "MIPS MIPSsim platform", - mips_mipssim_init, + .name = "mipssim", + .desc = "MIPS MIPSsim platform", + .init = mips_mipssim_init, + .ram_require = BIOS_SIZE + VGA_RAM_SIZE /* unused */, + .nodisk_ok = 1, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/mipsnet.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/mipsnet.c --- qemu-0.9.1/hw/mipsnet.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/mipsnet.c 2008-03-28 22:29:33.000000000 +0000 @@ -11,7 +11,6 @@ /* MIPSnet register offsets */ #define MIPSNET_DEV_ID 0x00 -# define MIPSNET_DEV_ID_STRING "MIPSNET0" #define MIPSNET_BUSY 0x08 #define MIPSNET_RX_DATA_COUNT 0x0c #define MIPSNET_TX_DATA_COUNT 0x10 @@ -105,15 +104,14 @@ { MIPSnetState *s = opaque; int ret = 0; - const char *devid = MIPSNET_DEV_ID_STRING; addr &= 0x3f; switch (addr) { case MIPSNET_DEV_ID: - ret = *((uint32_t *)&devid); + ret = be32_to_cpu(0x4d495053); /* MIPS */ break; case MIPSNET_DEV_ID + 4: - ret = *((uint32_t *)(&devid + 4)); + ret = be32_to_cpu(0x4e455430); /* NET0 */ break; case MIPSNET_BUSY: ret = s->busy; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/mips_pica61.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/mips_pica61.c --- qemu-0.9.1/hw/mips_pica61.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/mips_pica61.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,211 +0,0 @@ -/* - * QEMU Acer Pica Machine support - * - * Copyright (c) 2007 Hervé Poussineau - * - * 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 "hw.h" -#include "mips.h" -#include "isa.h" -#include "pc.h" -#include "fdc.h" -#include "sysemu.h" -#include "boards.h" - -#ifdef TARGET_WORDS_BIGENDIAN -#define BIOS_FILENAME "mips_bios.bin" -#else -#define BIOS_FILENAME "mipsel_bios.bin" -#endif - -#ifdef TARGET_MIPS64 -#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL) -#else -#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU) -#endif - -#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000)) - -#define MAX_IDE_BUS 2 -#define MAX_FD 2 - -static const int ide_iobase[2] = { 0x1f0, 0x170 }; -static const int ide_iobase2[2] = { 0x3f6, 0x376 }; -static const int ide_irq[2] = { 14, 15 }; - -static uint32_t serial_base[MAX_SERIAL_PORTS] = { 0x80006000, 0x80007000 }; -static int serial_irq[MAX_SERIAL_PORTS] = { 8, 9 }; - -extern FILE *logfile; - -static void main_cpu_reset(void *opaque) -{ - CPUState *env = opaque; - cpu_reset(env); -} - -static -void mips_pica61_init (int ram_size, int vga_ram_size, - const char *boot_device, DisplayState *ds, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) -{ - char buf[1024]; - unsigned long bios_offset; - int bios_size; - CPUState *env; - int i; - int available_ram; - qemu_irq *i8259; - int index; - BlockDriverState *fd[MAX_FD]; - - /* init CPUs */ - if (cpu_model == NULL) { -#ifdef TARGET_MIPS64 - cpu_model = "R4000"; -#else - /* FIXME: All wrong, this maybe should be R3000 for the older PICAs. */ - cpu_model = "24Kf"; -#endif - } - env = cpu_init(cpu_model); - if (!env) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); - qemu_register_reset(main_cpu_reset, env); - - /* allocate RAM (limited to 256 MB) */ - if (ram_size < 256 * 1024 * 1024) - available_ram = ram_size; - else - available_ram = 256 * 1024 * 1024; - cpu_register_physical_memory(0, available_ram, IO_MEM_RAM); - - /* load a BIOS image */ - bios_offset = ram_size + vga_ram_size; - if (bios_name == NULL) - bios_name = BIOS_FILENAME; - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); - bios_size = load_image(buf, phys_ram_base + bios_offset); - if ((bios_size <= 0) || (bios_size > BIOS_SIZE)) { - /* fatal */ - fprintf(stderr, "qemu: Error, could not load MIPS bios '%s'\n", - buf); - exit(1); - } - cpu_register_physical_memory(0x1fc00000, - BIOS_SIZE, bios_offset | IO_MEM_ROM); - - /* Device map - * - * addr 0xe0004000: mc146818 - * addr 0xe0005000 intr 6: ps2 keyboard - * addr 0xe0005000 intr 7: ps2 mouse - * addr 0xe0006000 intr 8: ns16550a, - * addr 0xe0007000 intr 9: ns16550a - * isa_io_base 0xe2000000 isa_mem_base 0xe3000000 - */ - - /* Init CPU internal devices */ - cpu_mips_irq_init_cpu(env); - cpu_mips_clock_init(env); - cpu_mips_irqctrl_init(); - - /* Register 64 KB of ISA IO space at 0x10000000 */ - isa_mmio_init(0x10000000, 0x00010000); - isa_mem_base = 0x11000000; - - /* PC style IRQ (i8259/i8254) and DMA (i8257) */ - /* The PIC is attached to the MIPS CPU INT0 pin */ - i8259 = i8259_init(env->irq[2]); - rtc_mm_init(0x80004070, 1, i8259[14]); - pit_init(0x40, 0); - - /* Keyboard (i8042) */ - i8042_mm_init(i8259[6], i8259[7], 0x80005060, 0); - - /* IDE controller */ - - if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { - fprintf(stderr, "qemu: too many IDE bus\n"); - exit(1); - } - - for(i = 0; i < MAX_IDE_BUS; i++) { - int hd0, hd1; - hd0 = drive_get_index(IF_IDE, i, 0); - hd1 = drive_get_index(IF_IDE, i, 1); - isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]], - hd0 == -1 ? NULL : drives_table[hd0].bdrv, - hd1 == -1 ? NULL : drives_table[hd1].bdrv); - } - - /* Network controller */ - /* FIXME: missing NS SONIC DP83932 */ - - /* SCSI adapter */ - /* FIXME: missing NCR 53C94 */ - - /* ISA devices (floppy, serial, parallel) */ - - for (i = 0; i < MAX_FD; i++) { - index = drive_get_index(IF_FLOPPY, 0, i); - if (index == -1) - fd[i] = NULL; - else - fd[i] = drives_table[index].bdrv; - } - fdctrl_init(i8259[1], 1, 1, 0x80003000, fd); - for(i = 0; i < MAX_SERIAL_PORTS; i++) { - if (serial_hds[i]) { - serial_mm_init(serial_base[i], 0, i8259[serial_irq[i]], serial_hds[i], 1); - } - } - /* Parallel port */ - if (parallel_hds[0]) parallel_mm_init(0x80008000, 0, i8259[1], parallel_hds[0]); - - /* Sound card */ - /* FIXME: missing Jazz sound, IRQ 18 */ - - /* LED indicator */ - /* FIXME: missing LED indicator */ - - /* NVRAM */ - ds1225y_init(0x80009000, "nvram"); - - /* Video card */ - /* FIXME: This card is not the real one which was in the original PICA, - * but let's do with what Qemu currenly emulates... */ - isa_vga_mm_init(ds, phys_ram_base + ram_size, ram_size, vga_ram_size, - 0x40000000, 0x60000000, 0); - - /* LED indicator */ - jazz_led_init(ds, 0x8000f000); -} - -QEMUMachine mips_pica61_machine = { - "pica61", - "Acer Pica 61", - mips_pica61_init, -}; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/mips_r4k.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/mips_r4k.c --- qemu-0.9.1/hw/mips_r4k.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/mips_r4k.c 2008-10-28 10:59:59.000000000 +0000 @@ -14,6 +14,8 @@ #include "net.h" #include "sysemu.h" #include "boards.h" +#include "flash.h" +#include "qemu-log.h" #ifdef TARGET_WORDS_BIGENDIAN #define BIOS_FILENAME "mips_bios.bin" @@ -34,8 +36,6 @@ static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 }; -extern FILE *logfile; - static PITState *pit; /* PIT i8254 */ /* i8254 PIT is attached to the IRQ0 at PIC i8259 */ @@ -82,11 +82,12 @@ ram_addr_t initrd_offset; kernel_size = load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND, - &entry, &kernel_low, &kernel_high); + (uint64_t *)&entry, (uint64_t *)&kernel_low, + (uint64_t *)&kernel_high); if (kernel_size >= 0) { if ((entry & ~0x7fffffffULL) == 0x80000000) entry = (int32_t)entry; - env->PC[env->current_tc] = entry; + env->active_tc.PC = entry; } else { fprintf(stderr, "qemu: could not load kernel '%s'\n", loaderparams.kernel_filename); @@ -119,15 +120,15 @@ /* Store command line. */ if (initrd_size > 0) { int ret; - ret = sprintf(phys_ram_base + (16 << 20) - 256, + ret = sprintf((char *)(phys_ram_base + (16 << 20) - 256), "rd_start=0x" TARGET_FMT_lx " rd_size=%li ", PHYS_TO_VIRT((uint32_t)initrd_offset), initrd_size); - strcpy (phys_ram_base + (16 << 20) - 256 + ret, + strcpy ((char *)(phys_ram_base + (16 << 20) - 256 + ret), loaderparams.kernel_cmdline); } else { - strcpy (phys_ram_base + (16 << 20) - 256, + strcpy ((char *)(phys_ram_base + (16 << 20) - 256), loaderparams.kernel_cmdline); } @@ -144,8 +145,9 @@ load_kernel (env); } +static const int sector_len = 32 * 1024; static -void mips_r4k_init (int ram_size, int vga_ram_size, +void mips_r4k_init (ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -173,7 +175,6 @@ fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); /* allocate RAM */ @@ -197,7 +198,17 @@ if ((bios_size > 0) && (bios_size <= BIOS_SIZE)) { cpu_register_physical_memory(0x1fc00000, BIOS_SIZE, bios_offset | IO_MEM_ROM); - } else { + } else if ((index = drive_get_index(IF_PFLASH, 0, 0)) > -1) { + uint32_t mips_rom = 0x00400000; + cpu_register_physical_memory(0x1fc00000, mips_rom, + qemu_ram_alloc(mips_rom) | IO_MEM_ROM); + if (!pflash_cfi01_register(0x1fc00000, qemu_ram_alloc(mips_rom), + drives_table[index].bdrv, sector_len, mips_rom / sector_len, + 4, 0, 0, 0, 0)) { + fprintf(stderr, "qemu: Error registering flash memory.\n"); + } + } + else { /* not fatal */ fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n", buf); @@ -214,7 +225,6 @@ /* Init CPU internal devices */ cpu_mips_irq_init_cpu(env); cpu_mips_clock_init(env); - cpu_mips_irqctrl_init(); /* The PIC is attached to the MIPS CPU INT0 pin */ i8259 = i8259_init(env->irq[2]); @@ -229,7 +239,8 @@ for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { - serial_init(serial_io[i], i8259[serial_irq[i]], serial_hds[i]); + serial_init(serial_io[i], i8259[serial_irq[i]], 115200, + serial_hds[i]); } } @@ -271,7 +282,9 @@ } QEMUMachine mips_machine = { - "mips", - "mips r4k platform", - mips_r4k_init, + .name = "mips", + .desc = "mips r4k platform", + .init = mips_r4k_init, + .ram_require = VGA_RAM_SIZE + BIOS_SIZE, + .nodisk_ok = 1, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/mips_timer.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/mips_timer.c --- qemu-0.9.1/hw/mips_timer.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/mips_timer.c 2008-09-14 17:38:57.000000000 +0100 @@ -2,9 +2,7 @@ #include "mips.h" #include "qemu-timer.h" -void cpu_mips_irqctrl_init (void) -{ -} +#define TIMER_FREQ 100 * 1000 * 1000 /* XXX: do not use a global */ uint32_t cpu_mips_get_random (CPUState *env) @@ -24,49 +22,41 @@ else return env->CP0_Count + (uint32_t)muldiv64(qemu_get_clock(vm_clock), - 100 * 1000 * 1000, ticks_per_sec); + TIMER_FREQ, ticks_per_sec); } -void cpu_mips_store_count (CPUState *env, uint32_t count) +static void cpu_mips_timer_update(CPUState *env) { uint64_t now, next; - uint32_t tmp; - uint32_t compare = env->CP0_Compare; + uint32_t wait; - tmp = count; - if (count == compare) - tmp++; now = qemu_get_clock(vm_clock); - next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000); - if (next == now) - next++; -#if 0 - if (logfile) { - fprintf(logfile, "%s: 0x%08" PRIx64 " %08x %08x => 0x%08" PRIx64 "\n", - __func__, now, count, compare, next - now); - } -#endif - /* Store new count and compare registers */ - env->CP0_Compare = compare; - env->CP0_Count = - count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec); - /* Adjust timer */ + wait = env->CP0_Compare - env->CP0_Count - + (uint32_t)muldiv64(now, TIMER_FREQ, ticks_per_sec); + next = now + muldiv64(wait, ticks_per_sec, TIMER_FREQ); qemu_mod_timer(env->timer, next); } -static void cpu_mips_update_count (CPUState *env, uint32_t count) +void cpu_mips_store_count (CPUState *env, uint32_t count) { if (env->CP0_Cause & (1 << CP0Ca_DC)) - return; - - cpu_mips_store_count(env, count); + env->CP0_Count = count; + else { + /* Store new count register */ + env->CP0_Count = + count - (uint32_t)muldiv64(qemu_get_clock(vm_clock), + TIMER_FREQ, ticks_per_sec); + /* Update timer timer */ + cpu_mips_timer_update(env); + } } void cpu_mips_store_compare (CPUState *env, uint32_t value) { env->CP0_Compare = value; - cpu_mips_update_count(env, cpu_mips_get_count(env)); - if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) + if (!(env->CP0_Cause & (1 << CP0Ca_DC))) + cpu_mips_timer_update(env); + if (env->insn_flags & ISA_MIPS32R2) env->CP0_Cause &= ~(1 << CP0Ca_TI); qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); } @@ -80,7 +70,7 @@ { /* Store the current value */ env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock(vm_clock), - 100 * 1000 * 1000, ticks_per_sec); + TIMER_FREQ, ticks_per_sec); } static void mips_timer_cb (void *opaque) @@ -97,8 +87,13 @@ if (env->CP0_Cause & (1 << CP0Ca_DC)) return; - cpu_mips_update_count(env, cpu_mips_get_count(env)); - if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) + /* ??? This callback should occur when the counter is exactly equal to + the comparator value. Offset the count by one to avoid immediately + retriggering the callback before any virtual time has passed. */ + env->CP0_Count++; + cpu_mips_timer_update(env); + env->CP0_Count--; + if (env->insn_flags & ISA_MIPS32R2) env->CP0_Cause |= 1 << CP0Ca_TI; qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); } @@ -107,5 +102,5 @@ { env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env); env->CP0_Compare = 0; - cpu_mips_update_count(env, 1); + cpu_mips_store_count(env, 1); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/mst_fpga.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/mst_fpga.c --- qemu-0.9.1/hw/mst_fpga.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/mst_fpga.c 2008-10-26 13:43:07.000000000 +0000 @@ -168,12 +168,12 @@ } } -CPUReadMemoryFunc *mst_fpga_readfn[] = { +static CPUReadMemoryFunc *mst_fpga_readfn[] = { mst_fpga_readb, mst_fpga_readb, mst_fpga_readb, }; -CPUWriteMemoryFunc *mst_fpga_writefn[] = { +static CPUWriteMemoryFunc *mst_fpga_writefn[] = { mst_fpga_writeb, mst_fpga_writeb, mst_fpga_writeb, diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/musicpal.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/musicpal.c --- qemu-0.9.1/hw/musicpal.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/musicpal.c 2008-10-28 10:59:59.000000000 +0000 @@ -0,0 +1,1517 @@ +/* + * Marvell MV88W8618 / Freecom MusicPal emulation. + * + * Copyright (c) 2008 Jan Kiszka + * + * This code is licenced under the GNU GPL v2. + */ + +#include "hw.h" +#include "arm-misc.h" +#include "devices.h" +#include "net.h" +#include "sysemu.h" +#include "boards.h" +#include "pc.h" +#include "qemu-timer.h" +#include "block.h" +#include "flash.h" +#include "console.h" +#include "audio/audio.h" +#include "i2c.h" + +#define MP_ETH_BASE 0x80008000 +#define MP_ETH_SIZE 0x00001000 + +#define MP_UART1_BASE 0x8000C840 +#define MP_UART2_BASE 0x8000C940 + +#define MP_FLASHCFG_BASE 0x90006000 +#define MP_FLASHCFG_SIZE 0x00001000 + +#define MP_AUDIO_BASE 0x90007000 +#define MP_AUDIO_SIZE 0x00001000 + +#define MP_PIC_BASE 0x90008000 +#define MP_PIC_SIZE 0x00001000 + +#define MP_PIT_BASE 0x90009000 +#define MP_PIT_SIZE 0x00001000 + +#define MP_LCD_BASE 0x9000c000 +#define MP_LCD_SIZE 0x00001000 + +#define MP_SRAM_BASE 0xC0000000 +#define MP_SRAM_SIZE 0x00020000 + +#define MP_RAM_DEFAULT_SIZE 32*1024*1024 +#define MP_FLASH_SIZE_MAX 32*1024*1024 + +#define MP_TIMER1_IRQ 4 +/* ... */ +#define MP_TIMER4_IRQ 7 +#define MP_EHCI_IRQ 8 +#define MP_ETH_IRQ 9 +#define MP_UART1_IRQ 11 +#define MP_UART2_IRQ 11 +#define MP_GPIO_IRQ 12 +#define MP_RTC_IRQ 28 +#define MP_AUDIO_IRQ 30 + +static uint32_t gpio_in_state = 0xffffffff; +static uint32_t gpio_isr; +static uint32_t gpio_out_state; +static ram_addr_t sram_off; + +/* Address conversion helpers */ +static void *target2host_addr(uint32_t addr) +{ + if (addr < MP_SRAM_BASE) { + if (addr >= MP_RAM_DEFAULT_SIZE) + return NULL; + return (void *)(phys_ram_base + addr); + } else { + if (addr >= MP_SRAM_BASE + MP_SRAM_SIZE) + return NULL; + return (void *)(phys_ram_base + sram_off + addr - MP_SRAM_BASE); + } +} + +static uint32_t host2target_addr(void *addr) +{ + if (addr < ((void *)phys_ram_base) + sram_off) + return (unsigned long)addr - (unsigned long)phys_ram_base; + else + return (unsigned long)addr - (unsigned long)phys_ram_base - + sram_off + MP_SRAM_BASE; +} + + +typedef enum i2c_state { + STOPPED = 0, + INITIALIZING, + SENDING_BIT7, + SENDING_BIT6, + SENDING_BIT5, + SENDING_BIT4, + SENDING_BIT3, + SENDING_BIT2, + SENDING_BIT1, + SENDING_BIT0, + WAITING_FOR_ACK, + RECEIVING_BIT7, + RECEIVING_BIT6, + RECEIVING_BIT5, + RECEIVING_BIT4, + RECEIVING_BIT3, + RECEIVING_BIT2, + RECEIVING_BIT1, + RECEIVING_BIT0, + SENDING_ACK +} i2c_state; + +typedef struct i2c_interface { + i2c_bus *bus; + i2c_state state; + int last_data; + int last_clock; + uint8_t buffer; + int current_addr; +} i2c_interface; + +static void i2c_enter_stop(i2c_interface *i2c) +{ + if (i2c->current_addr >= 0) + i2c_end_transfer(i2c->bus); + i2c->current_addr = -1; + i2c->state = STOPPED; +} + +static void i2c_state_update(i2c_interface *i2c, int data, int clock) +{ + if (!i2c) + return; + + switch (i2c->state) { + case STOPPED: + if (data == 0 && i2c->last_data == 1 && clock == 1) + i2c->state = INITIALIZING; + break; + + case INITIALIZING: + if (clock == 0 && i2c->last_clock == 1 && data == 0) + i2c->state = SENDING_BIT7; + else + i2c_enter_stop(i2c); + break; + + case SENDING_BIT7 ... SENDING_BIT0: + if (clock == 0 && i2c->last_clock == 1) { + i2c->buffer = (i2c->buffer << 1) | data; + i2c->state++; /* will end up in WAITING_FOR_ACK */ + } else if (data == 1 && i2c->last_data == 0 && clock == 1) + i2c_enter_stop(i2c); + break; + + case WAITING_FOR_ACK: + if (clock == 0 && i2c->last_clock == 1) { + if (i2c->current_addr < 0) { + i2c->current_addr = i2c->buffer; + i2c_start_transfer(i2c->bus, i2c->current_addr & 0xfe, + i2c->buffer & 1); + } else + i2c_send(i2c->bus, i2c->buffer); + if (i2c->current_addr & 1) { + i2c->state = RECEIVING_BIT7; + i2c->buffer = i2c_recv(i2c->bus); + } else + i2c->state = SENDING_BIT7; + } else if (data == 1 && i2c->last_data == 0 && clock == 1) + i2c_enter_stop(i2c); + break; + + case RECEIVING_BIT7 ... RECEIVING_BIT0: + if (clock == 0 && i2c->last_clock == 1) { + i2c->state++; /* will end up in SENDING_ACK */ + i2c->buffer <<= 1; + } else if (data == 1 && i2c->last_data == 0 && clock == 1) + i2c_enter_stop(i2c); + break; + + case SENDING_ACK: + if (clock == 0 && i2c->last_clock == 1) { + i2c->state = RECEIVING_BIT7; + if (data == 0) + i2c->buffer = i2c_recv(i2c->bus); + else + i2c_nack(i2c->bus); + } else if (data == 1 && i2c->last_data == 0 && clock == 1) + i2c_enter_stop(i2c); + break; + } + + i2c->last_data = data; + i2c->last_clock = clock; +} + +static int i2c_get_data(i2c_interface *i2c) +{ + if (!i2c) + return 0; + + switch (i2c->state) { + case RECEIVING_BIT7 ... RECEIVING_BIT0: + return (i2c->buffer >> 7); + + case WAITING_FOR_ACK: + default: + return 0; + } +} + +static i2c_interface *mixer_i2c; + +#ifdef HAS_AUDIO + +/* Audio register offsets */ +#define MP_AUDIO_PLAYBACK_MODE 0x00 +#define MP_AUDIO_CLOCK_DIV 0x18 +#define MP_AUDIO_IRQ_STATUS 0x20 +#define MP_AUDIO_IRQ_ENABLE 0x24 +#define MP_AUDIO_TX_START_LO 0x28 +#define MP_AUDIO_TX_THRESHOLD 0x2C +#define MP_AUDIO_TX_STATUS 0x38 +#define MP_AUDIO_TX_START_HI 0x40 + +/* Status register and IRQ enable bits */ +#define MP_AUDIO_TX_HALF (1 << 6) +#define MP_AUDIO_TX_FULL (1 << 7) + +/* Playback mode bits */ +#define MP_AUDIO_16BIT_SAMPLE (1 << 0) +#define MP_AUDIO_PLAYBACK_EN (1 << 7) +#define MP_AUDIO_CLOCK_24MHZ (1 << 9) +#define MP_AUDIO_MONO (1 << 14) + +/* Wolfson 8750 I2C address */ +#define MP_WM_ADDR 0x34 + +static const char audio_name[] = "mv88w8618"; + +typedef struct musicpal_audio_state { + uint32_t base; + qemu_irq irq; + uint32_t playback_mode; + uint32_t status; + uint32_t irq_enable; + unsigned long phys_buf; + int8_t *target_buffer; + unsigned int threshold; + unsigned int play_pos; + unsigned int last_free; + uint32_t clock_div; + i2c_slave *wm; +} musicpal_audio_state; + +static void audio_callback(void *opaque, int free_out, int free_in) +{ + musicpal_audio_state *s = opaque; + int16_t *codec_buffer; + int8_t *mem_buffer; + int pos, block_size; + + if (!(s->playback_mode & MP_AUDIO_PLAYBACK_EN)) + return; + + if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) + free_out <<= 1; + + if (!(s->playback_mode & MP_AUDIO_MONO)) + free_out <<= 1; + + block_size = s->threshold/2; + if (free_out - s->last_free < block_size) + return; + + mem_buffer = s->target_buffer + s->play_pos; + if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) { + if (s->playback_mode & MP_AUDIO_MONO) { + codec_buffer = wm8750_dac_buffer(s->wm, block_size >> 1); + for (pos = 0; pos < block_size; pos += 2) { + *codec_buffer++ = *(int16_t *)mem_buffer; + *codec_buffer++ = *(int16_t *)mem_buffer; + mem_buffer += 2; + } + } else + memcpy(wm8750_dac_buffer(s->wm, block_size >> 2), + (uint32_t *)mem_buffer, block_size); + } else { + if (s->playback_mode & MP_AUDIO_MONO) { + codec_buffer = wm8750_dac_buffer(s->wm, block_size); + for (pos = 0; pos < block_size; pos++) { + *codec_buffer++ = cpu_to_le16(256 * *mem_buffer); + *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++); + } + } else { + codec_buffer = wm8750_dac_buffer(s->wm, block_size >> 1); + for (pos = 0; pos < block_size; pos += 2) { + *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++); + *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++); + } + } + } + wm8750_dac_commit(s->wm); + + s->last_free = free_out - block_size; + + if (s->play_pos == 0) { + s->status |= MP_AUDIO_TX_HALF; + s->play_pos = block_size; + } else { + s->status |= MP_AUDIO_TX_FULL; + s->play_pos = 0; + } + + if (s->status & s->irq_enable) + qemu_irq_raise(s->irq); +} + +static void musicpal_audio_clock_update(musicpal_audio_state *s) +{ + int rate; + + if (s->playback_mode & MP_AUDIO_CLOCK_24MHZ) + rate = 24576000 / 64; /* 24.576MHz */ + else + rate = 11289600 / 64; /* 11.2896MHz */ + + rate /= ((s->clock_div >> 8) & 0xff) + 1; + + wm8750_set_bclk_in(s->wm, rate); +} + +static uint32_t musicpal_audio_read(void *opaque, target_phys_addr_t offset) +{ + musicpal_audio_state *s = opaque; + + offset -= s->base; + switch (offset) { + case MP_AUDIO_PLAYBACK_MODE: + return s->playback_mode; + + case MP_AUDIO_CLOCK_DIV: + return s->clock_div; + + case MP_AUDIO_IRQ_STATUS: + return s->status; + + case MP_AUDIO_IRQ_ENABLE: + return s->irq_enable; + + case MP_AUDIO_TX_STATUS: + return s->play_pos >> 2; + + default: + return 0; + } +} + +static void musicpal_audio_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + musicpal_audio_state *s = opaque; + + offset -= s->base; + switch (offset) { + case MP_AUDIO_PLAYBACK_MODE: + if (value & MP_AUDIO_PLAYBACK_EN && + !(s->playback_mode & MP_AUDIO_PLAYBACK_EN)) { + s->status = 0; + s->last_free = 0; + s->play_pos = 0; + } + s->playback_mode = value; + musicpal_audio_clock_update(s); + break; + + case MP_AUDIO_CLOCK_DIV: + s->clock_div = value; + s->last_free = 0; + s->play_pos = 0; + musicpal_audio_clock_update(s); + break; + + case MP_AUDIO_IRQ_STATUS: + s->status &= ~value; + break; + + case MP_AUDIO_IRQ_ENABLE: + s->irq_enable = value; + if (s->status & s->irq_enable) + qemu_irq_raise(s->irq); + break; + + case MP_AUDIO_TX_START_LO: + s->phys_buf = (s->phys_buf & 0xFFFF0000) | (value & 0xFFFF); + s->target_buffer = target2host_addr(s->phys_buf); + s->play_pos = 0; + s->last_free = 0; + break; + + case MP_AUDIO_TX_THRESHOLD: + s->threshold = (value + 1) * 4; + break; + + case MP_AUDIO_TX_START_HI: + s->phys_buf = (s->phys_buf & 0xFFFF) | (value << 16); + s->target_buffer = target2host_addr(s->phys_buf); + s->play_pos = 0; + s->last_free = 0; + break; + } +} + +static void musicpal_audio_reset(void *opaque) +{ + musicpal_audio_state *s = opaque; + + s->playback_mode = 0; + s->status = 0; + s->irq_enable = 0; +} + +static CPUReadMemoryFunc *musicpal_audio_readfn[] = { + musicpal_audio_read, + musicpal_audio_read, + musicpal_audio_read +}; + +static CPUWriteMemoryFunc *musicpal_audio_writefn[] = { + musicpal_audio_write, + musicpal_audio_write, + musicpal_audio_write +}; + +static i2c_interface *musicpal_audio_init(uint32_t base, qemu_irq irq) +{ + AudioState *audio; + musicpal_audio_state *s; + i2c_interface *i2c; + int iomemtype; + + audio = AUD_init(); + if (!audio) { + AUD_log(audio_name, "No audio state\n"); + return NULL; + } + + s = qemu_mallocz(sizeof(musicpal_audio_state)); + if (!s) + return NULL; + s->base = base; + s->irq = irq; + + i2c = qemu_mallocz(sizeof(i2c_interface)); + if (!i2c) + return NULL; + i2c->bus = i2c_init_bus(); + i2c->current_addr = -1; + + s->wm = wm8750_init(i2c->bus, audio); + if (!s->wm) + return NULL; + i2c_set_slave_address(s->wm, MP_WM_ADDR); + wm8750_data_req_set(s->wm, audio_callback, s); + + iomemtype = cpu_register_io_memory(0, musicpal_audio_readfn, + musicpal_audio_writefn, s); + cpu_register_physical_memory(base, MP_AUDIO_SIZE, iomemtype); + + qemu_register_reset(musicpal_audio_reset, s); + + return i2c; +} +#else /* !HAS_AUDIO */ +static i2c_interface *musicpal_audio_init(uint32_t base, qemu_irq irq) +{ + return NULL; +} +#endif /* !HAS_AUDIO */ + +/* Ethernet register offsets */ +#define MP_ETH_SMIR 0x010 +#define MP_ETH_PCXR 0x408 +#define MP_ETH_SDCMR 0x448 +#define MP_ETH_ICR 0x450 +#define MP_ETH_IMR 0x458 +#define MP_ETH_FRDP0 0x480 +#define MP_ETH_FRDP1 0x484 +#define MP_ETH_FRDP2 0x488 +#define MP_ETH_FRDP3 0x48C +#define MP_ETH_CRDP0 0x4A0 +#define MP_ETH_CRDP1 0x4A4 +#define MP_ETH_CRDP2 0x4A8 +#define MP_ETH_CRDP3 0x4AC +#define MP_ETH_CTDP0 0x4E0 +#define MP_ETH_CTDP1 0x4E4 +#define MP_ETH_CTDP2 0x4E8 +#define MP_ETH_CTDP3 0x4EC + +/* MII PHY access */ +#define MP_ETH_SMIR_DATA 0x0000FFFF +#define MP_ETH_SMIR_ADDR 0x03FF0000 +#define MP_ETH_SMIR_OPCODE (1 << 26) /* Read value */ +#define MP_ETH_SMIR_RDVALID (1 << 27) + +/* PHY registers */ +#define MP_ETH_PHY1_BMSR 0x00210000 +#define MP_ETH_PHY1_PHYSID1 0x00410000 +#define MP_ETH_PHY1_PHYSID2 0x00610000 + +#define MP_PHY_BMSR_LINK 0x0004 +#define MP_PHY_BMSR_AUTONEG 0x0008 + +#define MP_PHY_88E3015 0x01410E20 + +/* TX descriptor status */ +#define MP_ETH_TX_OWN (1 << 31) + +/* RX descriptor status */ +#define MP_ETH_RX_OWN (1 << 31) + +/* Interrupt cause/mask bits */ +#define MP_ETH_IRQ_RX_BIT 0 +#define MP_ETH_IRQ_RX (1 << MP_ETH_IRQ_RX_BIT) +#define MP_ETH_IRQ_TXHI_BIT 2 +#define MP_ETH_IRQ_TXLO_BIT 3 + +/* Port config bits */ +#define MP_ETH_PCXR_2BSM_BIT 28 /* 2-byte incoming suffix */ + +/* SDMA command bits */ +#define MP_ETH_CMD_TXHI (1 << 23) +#define MP_ETH_CMD_TXLO (1 << 22) + +typedef struct mv88w8618_tx_desc { + uint32_t cmdstat; + uint16_t res; + uint16_t bytes; + uint32_t buffer; + uint32_t next; +} mv88w8618_tx_desc; + +typedef struct mv88w8618_rx_desc { + uint32_t cmdstat; + uint16_t bytes; + uint16_t buffer_size; + uint32_t buffer; + uint32_t next; +} mv88w8618_rx_desc; + +typedef struct mv88w8618_eth_state { + uint32_t base; + qemu_irq irq; + uint32_t smir; + uint32_t icr; + uint32_t imr; + int vlan_header; + mv88w8618_tx_desc *tx_queue[2]; + mv88w8618_rx_desc *rx_queue[4]; + mv88w8618_rx_desc *frx_queue[4]; + mv88w8618_rx_desc *cur_rx[4]; + VLANClientState *vc; +} mv88w8618_eth_state; + +static int eth_can_receive(void *opaque) +{ + return 1; +} + +static void eth_receive(void *opaque, const uint8_t *buf, int size) +{ + mv88w8618_eth_state *s = opaque; + mv88w8618_rx_desc *desc; + int i; + + for (i = 0; i < 4; i++) { + desc = s->cur_rx[i]; + if (!desc) + continue; + do { + if (le32_to_cpu(desc->cmdstat) & MP_ETH_RX_OWN && + le16_to_cpu(desc->buffer_size) >= size) { + memcpy(target2host_addr(le32_to_cpu(desc->buffer) + + s->vlan_header), + buf, size); + desc->bytes = cpu_to_le16(size + s->vlan_header); + desc->cmdstat &= cpu_to_le32(~MP_ETH_RX_OWN); + s->cur_rx[i] = target2host_addr(le32_to_cpu(desc->next)); + + s->icr |= MP_ETH_IRQ_RX; + if (s->icr & s->imr) + qemu_irq_raise(s->irq); + return; + } + desc = target2host_addr(le32_to_cpu(desc->next)); + } while (desc != s->rx_queue[i]); + } +} + +static void eth_send(mv88w8618_eth_state *s, int queue_index) +{ + mv88w8618_tx_desc *desc = s->tx_queue[queue_index]; + + do { + if (le32_to_cpu(desc->cmdstat) & MP_ETH_TX_OWN) { + qemu_send_packet(s->vc, + target2host_addr(le32_to_cpu(desc->buffer)), + le16_to_cpu(desc->bytes)); + desc->cmdstat &= cpu_to_le32(~MP_ETH_TX_OWN); + s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index); + } + desc = target2host_addr(le32_to_cpu(desc->next)); + } while (desc != s->tx_queue[queue_index]); +} + +static uint32_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset) +{ + mv88w8618_eth_state *s = opaque; + + offset -= s->base; + switch (offset) { + case MP_ETH_SMIR: + if (s->smir & MP_ETH_SMIR_OPCODE) { + switch (s->smir & MP_ETH_SMIR_ADDR) { + case MP_ETH_PHY1_BMSR: + return MP_PHY_BMSR_LINK | MP_PHY_BMSR_AUTONEG | + MP_ETH_SMIR_RDVALID; + case MP_ETH_PHY1_PHYSID1: + return (MP_PHY_88E3015 >> 16) | MP_ETH_SMIR_RDVALID; + case MP_ETH_PHY1_PHYSID2: + return (MP_PHY_88E3015 & 0xFFFF) | MP_ETH_SMIR_RDVALID; + default: + return MP_ETH_SMIR_RDVALID; + } + } + return 0; + + case MP_ETH_ICR: + return s->icr; + + case MP_ETH_IMR: + return s->imr; + + case MP_ETH_FRDP0 ... MP_ETH_FRDP3: + return host2target_addr(s->frx_queue[(offset - MP_ETH_FRDP0)/4]); + + case MP_ETH_CRDP0 ... MP_ETH_CRDP3: + return host2target_addr(s->rx_queue[(offset - MP_ETH_CRDP0)/4]); + + case MP_ETH_CTDP0 ... MP_ETH_CTDP3: + return host2target_addr(s->tx_queue[(offset - MP_ETH_CTDP0)/4]); + + default: + return 0; + } +} + +static void mv88w8618_eth_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + mv88w8618_eth_state *s = opaque; + + offset -= s->base; + switch (offset) { + case MP_ETH_SMIR: + s->smir = value; + break; + + case MP_ETH_PCXR: + s->vlan_header = ((value >> MP_ETH_PCXR_2BSM_BIT) & 1) * 2; + break; + + case MP_ETH_SDCMR: + if (value & MP_ETH_CMD_TXHI) + eth_send(s, 1); + if (value & MP_ETH_CMD_TXLO) + eth_send(s, 0); + if (value & (MP_ETH_CMD_TXHI | MP_ETH_CMD_TXLO) && s->icr & s->imr) + qemu_irq_raise(s->irq); + break; + + case MP_ETH_ICR: + s->icr &= value; + break; + + case MP_ETH_IMR: + s->imr = value; + if (s->icr & s->imr) + qemu_irq_raise(s->irq); + break; + + case MP_ETH_FRDP0 ... MP_ETH_FRDP3: + s->frx_queue[(offset - MP_ETH_FRDP0)/4] = target2host_addr(value); + break; + + case MP_ETH_CRDP0 ... MP_ETH_CRDP3: + s->rx_queue[(offset - MP_ETH_CRDP0)/4] = + s->cur_rx[(offset - MP_ETH_CRDP0)/4] = target2host_addr(value); + break; + + case MP_ETH_CTDP0 ... MP_ETH_CTDP3: + s->tx_queue[(offset - MP_ETH_CTDP0)/4] = target2host_addr(value); + break; + } +} + +static CPUReadMemoryFunc *mv88w8618_eth_readfn[] = { + mv88w8618_eth_read, + mv88w8618_eth_read, + mv88w8618_eth_read +}; + +static CPUWriteMemoryFunc *mv88w8618_eth_writefn[] = { + mv88w8618_eth_write, + mv88w8618_eth_write, + mv88w8618_eth_write +}; + +static void mv88w8618_eth_init(NICInfo *nd, uint32_t base, qemu_irq irq) +{ + mv88w8618_eth_state *s; + int iomemtype; + + s = qemu_mallocz(sizeof(mv88w8618_eth_state)); + if (!s) + return; + s->base = base; + s->irq = irq; + s->vc = qemu_new_vlan_client(nd->vlan, eth_receive, eth_can_receive, s); + iomemtype = cpu_register_io_memory(0, mv88w8618_eth_readfn, + mv88w8618_eth_writefn, s); + cpu_register_physical_memory(base, MP_ETH_SIZE, iomemtype); +} + +/* LCD register offsets */ +#define MP_LCD_IRQCTRL 0x180 +#define MP_LCD_IRQSTAT 0x184 +#define MP_LCD_SPICTRL 0x1ac +#define MP_LCD_INST 0x1bc +#define MP_LCD_DATA 0x1c0 + +/* Mode magics */ +#define MP_LCD_SPI_DATA 0x00100011 +#define MP_LCD_SPI_CMD 0x00104011 +#define MP_LCD_SPI_INVALID 0x00000000 + +/* Commmands */ +#define MP_LCD_INST_SETPAGE0 0xB0 +/* ... */ +#define MP_LCD_INST_SETPAGE7 0xB7 + +#define MP_LCD_TEXTCOLOR 0xe0e0ff /* RRGGBB */ + +typedef struct musicpal_lcd_state { + uint32_t base; + uint32_t mode; + uint32_t irqctrl; + int page; + int page_off; + DisplayState *ds; + QEMUConsole *console; + uint8_t video_ram[128*64/8]; +} musicpal_lcd_state; + +static uint32_t lcd_brightness; + +static uint8_t scale_lcd_color(uint8_t col) +{ + int tmp = col; + + switch (lcd_brightness) { + case 0x00000007: /* 0 */ + return 0; + + case 0x00020000: /* 1 */ + return (tmp * 1) / 7; + + case 0x00020001: /* 2 */ + return (tmp * 2) / 7; + + case 0x00040000: /* 3 */ + return (tmp * 3) / 7; + + case 0x00010006: /* 4 */ + return (tmp * 4) / 7; + + case 0x00020005: /* 5 */ + return (tmp * 5) / 7; + + case 0x00040003: /* 6 */ + return (tmp * 6) / 7; + + case 0x00030004: /* 7 */ + default: + return col; + } +} + +#define SET_LCD_PIXEL(depth, type) \ +static inline void glue(set_lcd_pixel, depth) \ + (musicpal_lcd_state *s, int x, int y, type col) \ +{ \ + int dx, dy; \ + type *pixel = &((type *) s->ds->data)[(y * 128 * 3 + x) * 3]; \ +\ + for (dy = 0; dy < 3; dy++, pixel += 127 * 3) \ + for (dx = 0; dx < 3; dx++, pixel++) \ + *pixel = col; \ +} +SET_LCD_PIXEL(8, uint8_t) +SET_LCD_PIXEL(16, uint16_t) +SET_LCD_PIXEL(32, uint32_t) + +#include "pixel_ops.h" + +static void lcd_refresh(void *opaque) +{ + musicpal_lcd_state *s = opaque; + int x, y, col; + + switch (s->ds->depth) { + case 0: + return; +#define LCD_REFRESH(depth, func) \ + case depth: \ + col = func(scale_lcd_color((MP_LCD_TEXTCOLOR >> 16) & 0xff), \ + scale_lcd_color((MP_LCD_TEXTCOLOR >> 8) & 0xff), \ + scale_lcd_color(MP_LCD_TEXTCOLOR & 0xff)); \ + for (x = 0; x < 128; x++) \ + for (y = 0; y < 64; y++) \ + if (s->video_ram[x + (y/8)*128] & (1 << (y % 8))) \ + glue(set_lcd_pixel, depth)(s, x, y, col); \ + else \ + glue(set_lcd_pixel, depth)(s, x, y, 0); \ + break; + LCD_REFRESH(8, rgb_to_pixel8) + LCD_REFRESH(16, rgb_to_pixel16) + LCD_REFRESH(32, (s->ds->bgr ? rgb_to_pixel32bgr : rgb_to_pixel32)) + default: + cpu_abort(cpu_single_env, "unsupported colour depth %i\n", + s->ds->depth); + } + + dpy_update(s->ds, 0, 0, 128*3, 64*3); +} + +static void lcd_invalidate(void *opaque) +{ +} + +static uint32_t musicpal_lcd_read(void *opaque, target_phys_addr_t offset) +{ + musicpal_lcd_state *s = opaque; + + offset -= s->base; + switch (offset) { + case MP_LCD_IRQCTRL: + return s->irqctrl; + + default: + return 0; + } +} + +static void musicpal_lcd_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + musicpal_lcd_state *s = opaque; + + offset -= s->base; + switch (offset) { + case MP_LCD_IRQCTRL: + s->irqctrl = value; + break; + + case MP_LCD_SPICTRL: + if (value == MP_LCD_SPI_DATA || value == MP_LCD_SPI_CMD) + s->mode = value; + else + s->mode = MP_LCD_SPI_INVALID; + break; + + case MP_LCD_INST: + if (value >= MP_LCD_INST_SETPAGE0 && value <= MP_LCD_INST_SETPAGE7) { + s->page = value - MP_LCD_INST_SETPAGE0; + s->page_off = 0; + } + break; + + case MP_LCD_DATA: + if (s->mode == MP_LCD_SPI_CMD) { + if (value >= MP_LCD_INST_SETPAGE0 && + value <= MP_LCD_INST_SETPAGE7) { + s->page = value - MP_LCD_INST_SETPAGE0; + s->page_off = 0; + } + } else if (s->mode == MP_LCD_SPI_DATA) { + s->video_ram[s->page*128 + s->page_off] = value; + s->page_off = (s->page_off + 1) & 127; + } + break; + } +} + +static CPUReadMemoryFunc *musicpal_lcd_readfn[] = { + musicpal_lcd_read, + musicpal_lcd_read, + musicpal_lcd_read +}; + +static CPUWriteMemoryFunc *musicpal_lcd_writefn[] = { + musicpal_lcd_write, + musicpal_lcd_write, + musicpal_lcd_write +}; + +static void musicpal_lcd_init(DisplayState *ds, uint32_t base) +{ + musicpal_lcd_state *s; + int iomemtype; + + s = qemu_mallocz(sizeof(musicpal_lcd_state)); + if (!s) + return; + s->base = base; + s->ds = ds; + iomemtype = cpu_register_io_memory(0, musicpal_lcd_readfn, + musicpal_lcd_writefn, s); + cpu_register_physical_memory(base, MP_LCD_SIZE, iomemtype); + + s->console = graphic_console_init(ds, lcd_refresh, lcd_invalidate, + NULL, NULL, s); + qemu_console_resize(s->console, 128*3, 64*3); +} + +/* PIC register offsets */ +#define MP_PIC_STATUS 0x00 +#define MP_PIC_ENABLE_SET 0x08 +#define MP_PIC_ENABLE_CLR 0x0C + +typedef struct mv88w8618_pic_state +{ + uint32_t base; + uint32_t level; + uint32_t enabled; + qemu_irq parent_irq; +} mv88w8618_pic_state; + +static void mv88w8618_pic_update(mv88w8618_pic_state *s) +{ + qemu_set_irq(s->parent_irq, (s->level & s->enabled)); +} + +static void mv88w8618_pic_set_irq(void *opaque, int irq, int level) +{ + mv88w8618_pic_state *s = opaque; + + if (level) + s->level |= 1 << irq; + else + s->level &= ~(1 << irq); + mv88w8618_pic_update(s); +} + +static uint32_t mv88w8618_pic_read(void *opaque, target_phys_addr_t offset) +{ + mv88w8618_pic_state *s = opaque; + + offset -= s->base; + switch (offset) { + case MP_PIC_STATUS: + return s->level & s->enabled; + + default: + return 0; + } +} + +static void mv88w8618_pic_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + mv88w8618_pic_state *s = opaque; + + offset -= s->base; + switch (offset) { + case MP_PIC_ENABLE_SET: + s->enabled |= value; + break; + + case MP_PIC_ENABLE_CLR: + s->enabled &= ~value; + s->level &= ~value; + break; + } + mv88w8618_pic_update(s); +} + +static void mv88w8618_pic_reset(void *opaque) +{ + mv88w8618_pic_state *s = opaque; + + s->level = 0; + s->enabled = 0; +} + +static CPUReadMemoryFunc *mv88w8618_pic_readfn[] = { + mv88w8618_pic_read, + mv88w8618_pic_read, + mv88w8618_pic_read +}; + +static CPUWriteMemoryFunc *mv88w8618_pic_writefn[] = { + mv88w8618_pic_write, + mv88w8618_pic_write, + mv88w8618_pic_write +}; + +static qemu_irq *mv88w8618_pic_init(uint32_t base, qemu_irq parent_irq) +{ + mv88w8618_pic_state *s; + int iomemtype; + qemu_irq *qi; + + s = qemu_mallocz(sizeof(mv88w8618_pic_state)); + if (!s) + return NULL; + qi = qemu_allocate_irqs(mv88w8618_pic_set_irq, s, 32); + s->base = base; + s->parent_irq = parent_irq; + iomemtype = cpu_register_io_memory(0, mv88w8618_pic_readfn, + mv88w8618_pic_writefn, s); + cpu_register_physical_memory(base, MP_PIC_SIZE, iomemtype); + + qemu_register_reset(mv88w8618_pic_reset, s); + + return qi; +} + +/* PIT register offsets */ +#define MP_PIT_TIMER1_LENGTH 0x00 +/* ... */ +#define MP_PIT_TIMER4_LENGTH 0x0C +#define MP_PIT_CONTROL 0x10 +#define MP_PIT_TIMER1_VALUE 0x14 +/* ... */ +#define MP_PIT_TIMER4_VALUE 0x20 +#define MP_BOARD_RESET 0x34 + +/* Magic board reset value (probably some watchdog behind it) */ +#define MP_BOARD_RESET_MAGIC 0x10000 + +typedef struct mv88w8618_timer_state { + ptimer_state *timer; + uint32_t limit; + int freq; + qemu_irq irq; +} mv88w8618_timer_state; + +typedef struct mv88w8618_pit_state { + void *timer[4]; + uint32_t control; + uint32_t base; +} mv88w8618_pit_state; + +static void mv88w8618_timer_tick(void *opaque) +{ + mv88w8618_timer_state *s = opaque; + + qemu_irq_raise(s->irq); +} + +static void *mv88w8618_timer_init(uint32_t freq, qemu_irq irq) +{ + mv88w8618_timer_state *s; + QEMUBH *bh; + + s = qemu_mallocz(sizeof(mv88w8618_timer_state)); + s->irq = irq; + s->freq = freq; + + bh = qemu_bh_new(mv88w8618_timer_tick, s); + s->timer = ptimer_init(bh); + + return s; +} + +static uint32_t mv88w8618_pit_read(void *opaque, target_phys_addr_t offset) +{ + mv88w8618_pit_state *s = opaque; + mv88w8618_timer_state *t; + + offset -= s->base; + switch (offset) { + case MP_PIT_TIMER1_VALUE ... MP_PIT_TIMER4_VALUE: + t = s->timer[(offset-MP_PIT_TIMER1_VALUE) >> 2]; + return ptimer_get_count(t->timer); + + default: + return 0; + } +} + +static void mv88w8618_pit_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + mv88w8618_pit_state *s = opaque; + mv88w8618_timer_state *t; + int i; + + offset -= s->base; + switch (offset) { + case MP_PIT_TIMER1_LENGTH ... MP_PIT_TIMER4_LENGTH: + t = s->timer[offset >> 2]; + t->limit = value; + ptimer_set_limit(t->timer, t->limit, 1); + break; + + case MP_PIT_CONTROL: + for (i = 0; i < 4; i++) { + if (value & 0xf) { + t = s->timer[i]; + ptimer_set_limit(t->timer, t->limit, 0); + ptimer_set_freq(t->timer, t->freq); + ptimer_run(t->timer, 0); + } + value >>= 4; + } + break; + + case MP_BOARD_RESET: + if (value == MP_BOARD_RESET_MAGIC) + qemu_system_reset_request(); + break; + } +} + +static CPUReadMemoryFunc *mv88w8618_pit_readfn[] = { + mv88w8618_pit_read, + mv88w8618_pit_read, + mv88w8618_pit_read +}; + +static CPUWriteMemoryFunc *mv88w8618_pit_writefn[] = { + mv88w8618_pit_write, + mv88w8618_pit_write, + mv88w8618_pit_write +}; + +static void mv88w8618_pit_init(uint32_t base, qemu_irq *pic, int irq) +{ + int iomemtype; + mv88w8618_pit_state *s; + + s = qemu_mallocz(sizeof(mv88w8618_pit_state)); + if (!s) + return; + + s->base = base; + /* Letting them all run at 1 MHz is likely just a pragmatic + * simplification. */ + s->timer[0] = mv88w8618_timer_init(1000000, pic[irq]); + s->timer[1] = mv88w8618_timer_init(1000000, pic[irq + 1]); + s->timer[2] = mv88w8618_timer_init(1000000, pic[irq + 2]); + s->timer[3] = mv88w8618_timer_init(1000000, pic[irq + 3]); + + iomemtype = cpu_register_io_memory(0, mv88w8618_pit_readfn, + mv88w8618_pit_writefn, s); + cpu_register_physical_memory(base, MP_PIT_SIZE, iomemtype); +} + +/* Flash config register offsets */ +#define MP_FLASHCFG_CFGR0 0x04 + +typedef struct mv88w8618_flashcfg_state { + uint32_t base; + uint32_t cfgr0; +} mv88w8618_flashcfg_state; + +static uint32_t mv88w8618_flashcfg_read(void *opaque, + target_phys_addr_t offset) +{ + mv88w8618_flashcfg_state *s = opaque; + + offset -= s->base; + switch (offset) { + case MP_FLASHCFG_CFGR0: + return s->cfgr0; + + default: + return 0; + } +} + +static void mv88w8618_flashcfg_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + mv88w8618_flashcfg_state *s = opaque; + + offset -= s->base; + switch (offset) { + case MP_FLASHCFG_CFGR0: + s->cfgr0 = value; + break; + } +} + +static CPUReadMemoryFunc *mv88w8618_flashcfg_readfn[] = { + mv88w8618_flashcfg_read, + mv88w8618_flashcfg_read, + mv88w8618_flashcfg_read +}; + +static CPUWriteMemoryFunc *mv88w8618_flashcfg_writefn[] = { + mv88w8618_flashcfg_write, + mv88w8618_flashcfg_write, + mv88w8618_flashcfg_write +}; + +static void mv88w8618_flashcfg_init(uint32_t base) +{ + int iomemtype; + mv88w8618_flashcfg_state *s; + + s = qemu_mallocz(sizeof(mv88w8618_flashcfg_state)); + if (!s) + return; + + s->base = base; + s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */ + iomemtype = cpu_register_io_memory(0, mv88w8618_flashcfg_readfn, + mv88w8618_flashcfg_writefn, s); + cpu_register_physical_memory(base, MP_FLASHCFG_SIZE, iomemtype); +} + +/* Various registers in the 0x80000000 domain */ +#define MP_BOARD_REVISION 0x2018 + +#define MP_WLAN_MAGIC1 0xc11c +#define MP_WLAN_MAGIC2 0xc124 + +#define MP_GPIO_OE_LO 0xd008 +#define MP_GPIO_OUT_LO 0xd00c +#define MP_GPIO_IN_LO 0xd010 +#define MP_GPIO_ISR_LO 0xd020 +#define MP_GPIO_OE_HI 0xd508 +#define MP_GPIO_OUT_HI 0xd50c +#define MP_GPIO_IN_HI 0xd510 +#define MP_GPIO_ISR_HI 0xd520 + +/* GPIO bits & masks */ +#define MP_GPIO_WHEEL_VOL (1 << 8) +#define MP_GPIO_WHEEL_VOL_INV (1 << 9) +#define MP_GPIO_WHEEL_NAV (1 << 10) +#define MP_GPIO_WHEEL_NAV_INV (1 << 11) +#define MP_GPIO_LCD_BRIGHTNESS 0x00070000 +#define MP_GPIO_BTN_FAVORITS (1 << 19) +#define MP_GPIO_BTN_MENU (1 << 20) +#define MP_GPIO_BTN_VOLUME (1 << 21) +#define MP_GPIO_BTN_NAVIGATION (1 << 22) +#define MP_GPIO_I2C_DATA_BIT 29 +#define MP_GPIO_I2C_DATA (1 << MP_GPIO_I2C_DATA_BIT) +#define MP_GPIO_I2C_CLOCK_BIT 30 + +/* LCD brightness bits in GPIO_OE_HI */ +#define MP_OE_LCD_BRIGHTNESS 0x0007 + +static uint32_t musicpal_read(void *opaque, target_phys_addr_t offset) +{ + offset -= 0x80000000; + switch (offset) { + case MP_BOARD_REVISION: + return 0x0031; + + case MP_GPIO_OE_HI: /* used for LCD brightness control */ + return lcd_brightness & MP_OE_LCD_BRIGHTNESS; + + case MP_GPIO_OUT_LO: + return gpio_out_state & 0xFFFF; + case MP_GPIO_OUT_HI: + return gpio_out_state >> 16; + + case MP_GPIO_IN_LO: + return gpio_in_state & 0xFFFF; + case MP_GPIO_IN_HI: + /* Update received I2C data */ + gpio_in_state = (gpio_in_state & ~MP_GPIO_I2C_DATA) | + (i2c_get_data(mixer_i2c) << MP_GPIO_I2C_DATA_BIT); + return gpio_in_state >> 16; + + case MP_GPIO_ISR_LO: + return gpio_isr & 0xFFFF; + case MP_GPIO_ISR_HI: + return gpio_isr >> 16; + + /* Workaround to allow loading the binary-only wlandrv.ko crap + * from the original Freecom firmware. */ + case MP_WLAN_MAGIC1: + return ~3; + case MP_WLAN_MAGIC2: + return -1; + + default: + return 0; + } +} + +static void musicpal_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + offset -= 0x80000000; + switch (offset) { + case MP_GPIO_OE_HI: /* used for LCD brightness control */ + lcd_brightness = (lcd_brightness & MP_GPIO_LCD_BRIGHTNESS) | + (value & MP_OE_LCD_BRIGHTNESS); + break; + + case MP_GPIO_OUT_LO: + gpio_out_state = (gpio_out_state & 0xFFFF0000) | (value & 0xFFFF); + break; + case MP_GPIO_OUT_HI: + gpio_out_state = (gpio_out_state & 0xFFFF) | (value << 16); + lcd_brightness = (lcd_brightness & 0xFFFF) | + (gpio_out_state & MP_GPIO_LCD_BRIGHTNESS); + i2c_state_update(mixer_i2c, + (gpio_out_state >> MP_GPIO_I2C_DATA_BIT) & 1, + (gpio_out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1); + break; + + } +} + +/* Keyboard codes & masks */ +#define KEY_RELEASED 0x80 +#define KEY_CODE 0x7f + +#define KEYCODE_TAB 0x0f +#define KEYCODE_ENTER 0x1c +#define KEYCODE_F 0x21 +#define KEYCODE_M 0x32 + +#define KEYCODE_EXTENDED 0xe0 +#define KEYCODE_UP 0x48 +#define KEYCODE_DOWN 0x50 +#define KEYCODE_LEFT 0x4b +#define KEYCODE_RIGHT 0x4d + +static void musicpal_key_event(void *opaque, int keycode) +{ + qemu_irq irq = opaque; + uint32_t event = 0; + static int kbd_extended; + + if (keycode == KEYCODE_EXTENDED) { + kbd_extended = 1; + return; + } + + if (kbd_extended) + switch (keycode & KEY_CODE) { + case KEYCODE_UP: + event = MP_GPIO_WHEEL_NAV | MP_GPIO_WHEEL_NAV_INV; + break; + + case KEYCODE_DOWN: + event = MP_GPIO_WHEEL_NAV; + break; + + case KEYCODE_LEFT: + event = MP_GPIO_WHEEL_VOL | MP_GPIO_WHEEL_VOL_INV; + break; + + case KEYCODE_RIGHT: + event = MP_GPIO_WHEEL_VOL; + break; + } + else { + switch (keycode & KEY_CODE) { + case KEYCODE_F: + event = MP_GPIO_BTN_FAVORITS; + break; + + case KEYCODE_TAB: + event = MP_GPIO_BTN_VOLUME; + break; + + case KEYCODE_ENTER: + event = MP_GPIO_BTN_NAVIGATION; + break; + + case KEYCODE_M: + event = MP_GPIO_BTN_MENU; + break; + } + /* Do not repeat already pressed buttons */ + if (!(keycode & KEY_RELEASED) && !(gpio_in_state & event)) + event = 0; + } + + if (event) { + if (keycode & KEY_RELEASED) { + gpio_in_state |= event; + } else { + gpio_in_state &= ~event; + gpio_isr = event; + qemu_irq_raise(irq); + } + } + + kbd_extended = 0; +} + +static CPUReadMemoryFunc *musicpal_readfn[] = { + musicpal_read, + musicpal_read, + musicpal_read, +}; + +static CPUWriteMemoryFunc *musicpal_writefn[] = { + musicpal_write, + musicpal_write, + musicpal_write, +}; + +static struct arm_boot_info musicpal_binfo = { + .loader_start = 0x0, + .board_id = 0x20e, +}; + +static void musicpal_init(ram_addr_t ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + CPUState *env; + qemu_irq *pic; + int index; + int iomemtype; + unsigned long flash_size; + + if (!cpu_model) + cpu_model = "arm926"; + + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + pic = arm_pic_init_cpu(env); + + /* For now we use a fixed - the original - RAM size */ + cpu_register_physical_memory(0, MP_RAM_DEFAULT_SIZE, + qemu_ram_alloc(MP_RAM_DEFAULT_SIZE)); + + sram_off = qemu_ram_alloc(MP_SRAM_SIZE); + cpu_register_physical_memory(MP_SRAM_BASE, MP_SRAM_SIZE, sram_off); + + /* Catch various stuff not handled by separate subsystems */ + iomemtype = cpu_register_io_memory(0, musicpal_readfn, + musicpal_writefn, env); + cpu_register_physical_memory(0x80000000, 0x10000, iomemtype); + + pic = mv88w8618_pic_init(MP_PIC_BASE, pic[ARM_PIC_CPU_IRQ]); + mv88w8618_pit_init(MP_PIT_BASE, pic, MP_TIMER1_IRQ); + + if (serial_hds[0]) + serial_mm_init(MP_UART1_BASE, 2, pic[MP_UART1_IRQ], 1825000, + serial_hds[0], 1); + if (serial_hds[1]) + serial_mm_init(MP_UART2_BASE, 2, pic[MP_UART2_IRQ], 1825000, + serial_hds[1], 1); + + /* Register flash */ + index = drive_get_index(IF_PFLASH, 0, 0); + if (index != -1) { + flash_size = bdrv_getlength(drives_table[index].bdrv); + if (flash_size != 8*1024*1024 && flash_size != 16*1024*1024 && + flash_size != 32*1024*1024) { + fprintf(stderr, "Invalid flash image size\n"); + exit(1); + } + + /* + * The original U-Boot accesses the flash at 0xFE000000 instead of + * 0xFF800000 (if there is 8 MB flash). So remap flash access if the + * image is smaller than 32 MB. + */ + pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, qemu_ram_alloc(flash_size), + drives_table[index].bdrv, 0x10000, + (flash_size + 0xffff) >> 16, + MP_FLASH_SIZE_MAX / flash_size, + 2, 0x00BF, 0x236D, 0x0000, 0x0000, + 0x5555, 0x2AAA); + } + mv88w8618_flashcfg_init(MP_FLASHCFG_BASE); + + musicpal_lcd_init(ds, MP_LCD_BASE); + + qemu_add_kbd_event_handler(musicpal_key_event, pic[MP_GPIO_IRQ]); + + mv88w8618_eth_init(&nd_table[0], MP_ETH_BASE, pic[MP_ETH_IRQ]); + + mixer_i2c = musicpal_audio_init(MP_AUDIO_BASE, pic[MP_AUDIO_IRQ]); + + musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE; + musicpal_binfo.kernel_filename = kernel_filename; + musicpal_binfo.kernel_cmdline = kernel_cmdline; + musicpal_binfo.initrd_filename = initrd_filename; + arm_load_kernel(env, &musicpal_binfo); +} + +QEMUMachine musicpal_machine = { + .name = "musicpal", + .desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)", + .init = musicpal_init, + .ram_require = MP_RAM_DEFAULT_SIZE + MP_SRAM_SIZE + + MP_FLASH_SIZE_MAX + RAMSIZE_FIXED, +}; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/nand.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/nand.c --- qemu-0.9.1/hw/nand.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/nand.c 2008-10-26 13:43:07.000000000 +0000 @@ -106,7 +106,7 @@ # include "nand.c" /* Information based on Linux drivers/mtd/nand/nand_ids.c */ -struct nand_info_s { +static const struct nand_info_s { int size; int width; int page_shift; @@ -319,8 +319,6 @@ return 0; } -static int nand_iid = 0; - /* * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins. Chip * outputs are R/B and eight I/O pins. @@ -450,14 +448,11 @@ cpu_abort(cpu_single_env, "%s: Unsupported NAND chip ID.\n", __FUNCTION__); } - index = drive_get_index(IF_MTD, 0, 0); - if (index == -1) { - cpu_abort(cpu_single_env, "%s: missing MTD device\n", - __FUNCTION__); - } s = (struct nand_flash_s *) qemu_mallocz(sizeof(struct nand_flash_s)); - s->bdrv = drives_table[index].bdrv; + index = drive_get_index(IF_MTD, 0, 0); + if (index != -1) + s->bdrv = drives_table[index].bdrv; s->manf_id = manf_id; s->chip_id = chip_id; s->size = nand_flash_ids[s->chip_id].size << 20; @@ -498,7 +493,7 @@ s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize), 0xff, s->pages * pagesize); - register_savevm("nand", nand_iid ++, 0, nand_save, nand_load, s); + register_savevm("nand", -1, 0, nand_save, nand_load, s); return s; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ne2000.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ne2000.c --- qemu-0.9.1/hw/ne2000.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/ne2000.c 2008-07-18 19:02:34.000000000 +0100 @@ -753,7 +753,7 @@ s->macaddr[4], s->macaddr[5]); - register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s); + register_savevm("ne2000", -1, 2, ne2000_save, ne2000_load, s); } /***********************************************************/ @@ -823,6 +823,5 @@ s->macaddr[4], s->macaddr[5]); - /* XXX: instance number ? */ - register_savevm("ne2000", 0, 3, ne2000_save, ne2000_load, s); + register_savevm("ne2000", -1, 3, ne2000_save, ne2000_load, s); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/nseries.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/nseries.c --- qemu-0.9.1/hw/nseries.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/nseries.c 2008-10-28 10:59:59.000000000 +0000 @@ -0,0 +1,1420 @@ +/* + * Nokia N-series internet tablets. + * + * Copyright (C) 2007 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "qemu-common.h" +#include "sysemu.h" +#include "omap.h" +#include "arm-misc.h" +#include "irq.h" +#include "console.h" +#include "boards.h" +#include "i2c.h" +#include "devices.h" +#include "flash.h" +#include "hw.h" +#include "bt.h" + +/* Nokia N8x0 support */ +struct n800_s { + struct omap_mpu_state_s *cpu; + + struct rfbi_chip_s blizzard; + struct { + void *opaque; + uint32_t (*txrx)(void *opaque, uint32_t value, int len); + struct uwire_slave_s *chip; + } ts; + i2c_bus *i2c; + + int keymap[0x80]; + i2c_slave *kbd; + + struct tusb_s *usb; + void *retu; + void *tahvo; + void *nand; +}; + +/* GPIO pins */ +#define N8X0_TUSB_ENABLE_GPIO 0 +#define N800_MMC2_WP_GPIO 8 +#define N800_UNKNOWN_GPIO0 9 /* out */ +#define N810_MMC2_VIOSD_GPIO 9 +#define N810_HEADSET_AMP_GPIO 10 +#define N800_CAM_TURN_GPIO 12 +#define N810_GPS_RESET_GPIO 12 +#define N800_BLIZZARD_POWERDOWN_GPIO 15 +#define N800_MMC1_WP_GPIO 23 +#define N810_MMC2_VSD_GPIO 23 +#define N8X0_ONENAND_GPIO 26 +#define N810_BLIZZARD_RESET_GPIO 30 +#define N800_UNKNOWN_GPIO2 53 /* out */ +#define N8X0_TUSB_INT_GPIO 58 +#define N8X0_BT_WKUP_GPIO 61 +#define N8X0_STI_GPIO 62 +#define N8X0_CBUS_SEL_GPIO 64 +#define N8X0_CBUS_DAT_GPIO 65 +#define N8X0_CBUS_CLK_GPIO 66 +#define N8X0_WLAN_IRQ_GPIO 87 +#define N8X0_BT_RESET_GPIO 92 +#define N8X0_TEA5761_CS_GPIO 93 +#define N800_UNKNOWN_GPIO 94 +#define N810_TSC_RESET_GPIO 94 +#define N800_CAM_ACT_GPIO 95 +#define N810_GPS_WAKEUP_GPIO 95 +#define N8X0_MMC_CS_GPIO 96 +#define N8X0_WLAN_PWR_GPIO 97 +#define N8X0_BT_HOST_WKUP_GPIO 98 +#define N810_SPEAKER_AMP_GPIO 101 +#define N810_KB_LOCK_GPIO 102 +#define N800_TSC_TS_GPIO 103 +#define N810_TSC_TS_GPIO 106 +#define N8X0_HEADPHONE_GPIO 107 +#define N8X0_RETU_GPIO 108 +#define N800_TSC_KP_IRQ_GPIO 109 +#define N810_KEYBOARD_GPIO 109 +#define N800_BAT_COVER_GPIO 110 +#define N810_SLIDE_GPIO 110 +#define N8X0_TAHVO_GPIO 111 +#define N800_UNKNOWN_GPIO4 112 /* out */ +#define N810_SLEEPX_LED_GPIO 112 +#define N800_TSC_RESET_GPIO 118 /* ? */ +#define N810_AIC33_RESET_GPIO 118 +#define N800_TSC_UNKNOWN_GPIO 119 /* out */ +#define N8X0_TMP105_GPIO 125 + +/* Config */ +#define BT_UART 0 +#define XLDR_LL_UART 1 + +/* Addresses on the I2C bus 0 */ +#define N810_TLV320AIC33_ADDR 0x18 /* Audio CODEC */ +#define N8X0_TCM825x_ADDR 0x29 /* Camera */ +#define N810_LP5521_ADDR 0x32 /* LEDs */ +#define N810_TSL2563_ADDR 0x3d /* Light sensor */ +#define N810_LM8323_ADDR 0x45 /* Keyboard */ +/* Addresses on the I2C bus 1 */ +#define N8X0_TMP105_ADDR 0x48 /* Temperature sensor */ +#define N8X0_MENELAUS_ADDR 0x72 /* Power management */ + +/* Chipselects on GPMC NOR interface */ +#define N8X0_ONENAND_CS 0 +#define N8X0_USB_ASYNC_CS 1 +#define N8X0_USB_SYNC_CS 4 + +#define N8X0_BD_ADDR 0x00, 0x1a, 0x89, 0x9e, 0x3e, 0x81 + +static void n800_mmc_cs_cb(void *opaque, int line, int level) +{ + /* TODO: this seems to actually be connected to the menelaus, to + * which also both MMC slots connect. */ + omap_mmc_enable((struct omap_mmc_s *) opaque, !level); + + printf("%s: MMC slot %i active\n", __FUNCTION__, level + 1); +} + +static void n8x0_gpio_setup(struct n800_s *s) +{ + qemu_irq *mmc_cs = qemu_allocate_irqs(n800_mmc_cs_cb, s->cpu->mmc, 1); + omap2_gpio_out_set(s->cpu->gpif, N8X0_MMC_CS_GPIO, mmc_cs[0]); + + qemu_irq_lower(omap2_gpio_in_get(s->cpu->gpif, N800_BAT_COVER_GPIO)[0]); +} + +#define MAEMO_CAL_HEADER(...) \ + 'C', 'o', 'n', 'F', 0x02, 0x00, 0x04, 0x00, \ + __VA_ARGS__, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +static const uint8_t n8x0_cal_wlan_mac[] = { + MAEMO_CAL_HEADER('w', 'l', 'a', 'n', '-', 'm', 'a', 'c') + 0x1c, 0x00, 0x00, 0x00, 0x47, 0xd6, 0x69, 0xb3, + 0x30, 0x08, 0xa0, 0x83, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x89, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, + 0x5d, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, +}; + +static const uint8_t n8x0_cal_bt_id[] = { + MAEMO_CAL_HEADER('b', 't', '-', 'i', 'd', 0, 0, 0) + 0x0a, 0x00, 0x00, 0x00, 0xa3, 0x4b, 0xf6, 0x96, + 0xa8, 0xeb, 0xb2, 0x41, 0x00, 0x00, 0x00, 0x00, + N8X0_BD_ADDR, +}; + +static void n8x0_nand_setup(struct n800_s *s) +{ + char *otp_region; + + /* Either ec40xx or ec48xx are OK for the ID */ + omap_gpmc_attach(s->cpu->gpmc, N8X0_ONENAND_CS, 0, onenand_base_update, + onenand_base_unmap, + (s->nand = onenand_init(0xec4800, 1, + omap2_gpio_in_get(s->cpu->gpif, + N8X0_ONENAND_GPIO)[0]))); + otp_region = onenand_raw_otp(s->nand); + + memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac)); + memcpy(otp_region + 0x800, n8x0_cal_bt_id, sizeof(n8x0_cal_bt_id)); + /* XXX: in theory should also update the OOB for both pages */ +} + +static void n8x0_i2c_setup(struct n800_s *s) +{ + qemu_irq tmp_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TMP105_GPIO)[0]; + + /* Attach the CPU on one end of our I2C bus. */ + s->i2c = omap_i2c_bus(s->cpu->i2c[0]); + + /* Attach a menelaus PM chip */ + i2c_set_slave_address( + twl92230_init(s->i2c, + s->cpu->irq[0][OMAP_INT_24XX_SYS_NIRQ]), + N8X0_MENELAUS_ADDR); + + /* Attach a TMP105 PM chip (A0 wired to ground) */ + i2c_set_slave_address(tmp105_init(s->i2c, tmp_irq), N8X0_TMP105_ADDR); +} + +/* Touchscreen and keypad controller */ +static struct mouse_transform_info_s n800_pointercal = { + .x = 800, + .y = 480, + .a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 }, +}; + +static struct mouse_transform_info_s n810_pointercal = { + .x = 800, + .y = 480, + .a = { 15041, 148, -4731056, 171, -10238, 35933380, 65536 }, +}; + +#define RETU_KEYCODE 61 /* F3 */ + +static void n800_key_event(void *opaque, int keycode) +{ + struct n800_s *s = (struct n800_s *) opaque; + int code = s->keymap[keycode & 0x7f]; + + if (code == -1) { + if ((keycode & 0x7f) == RETU_KEYCODE) + retu_key_event(s->retu, !(keycode & 0x80)); + return; + } + + tsc210x_key_event(s->ts.chip, code, !(keycode & 0x80)); +} + +static const int n800_keys[16] = { + -1, + 72, /* Up */ + 63, /* Home (F5) */ + -1, + 75, /* Left */ + 28, /* Enter */ + 77, /* Right */ + -1, + 1, /* Cycle (ESC) */ + 80, /* Down */ + 62, /* Menu (F4) */ + -1, + 66, /* Zoom- (F8) */ + 64, /* FullScreen (F6) */ + 65, /* Zoom+ (F7) */ + -1, +}; + +static void n800_tsc_kbd_setup(struct n800_s *s) +{ + int i; + + /* XXX: are the three pins inverted inside the chip between the + * tsc and the cpu (N4111)? */ + qemu_irq penirq = 0; /* NC */ + qemu_irq kbirq = omap2_gpio_in_get(s->cpu->gpif, N800_TSC_KP_IRQ_GPIO)[0]; + qemu_irq dav = omap2_gpio_in_get(s->cpu->gpif, N800_TSC_TS_GPIO)[0]; + + s->ts.chip = tsc2301_init(penirq, kbirq, dav, 0); + s->ts.opaque = s->ts.chip->opaque; + s->ts.txrx = tsc210x_txrx; + + for (i = 0; i < 0x80; i ++) + s->keymap[i] = -1; + for (i = 0; i < 0x10; i ++) + if (n800_keys[i] >= 0) + s->keymap[n800_keys[i]] = i; + + qemu_add_kbd_event_handler(n800_key_event, s); + + tsc210x_set_transform(s->ts.chip, &n800_pointercal); +} + +static void n810_tsc_setup(struct n800_s *s) +{ + qemu_irq pintdav = omap2_gpio_in_get(s->cpu->gpif, N810_TSC_TS_GPIO)[0]; + + s->ts.opaque = tsc2005_init(pintdav); + s->ts.txrx = tsc2005_txrx; + + tsc2005_set_transform(s->ts.opaque, &n810_pointercal); +} + +/* N810 Keyboard controller */ +static void n810_key_event(void *opaque, int keycode) +{ + struct n800_s *s = (struct n800_s *) opaque; + int code = s->keymap[keycode & 0x7f]; + + if (code == -1) { + if ((keycode & 0x7f) == RETU_KEYCODE) + retu_key_event(s->retu, !(keycode & 0x80)); + return; + } + + lm832x_key_event(s->kbd, code, !(keycode & 0x80)); +} + +#define M 0 + +static int n810_keys[0x80] = { + [0x01] = 16, /* Q */ + [0x02] = 37, /* K */ + [0x03] = 24, /* O */ + [0x04] = 25, /* P */ + [0x05] = 14, /* Backspace */ + [0x06] = 30, /* A */ + [0x07] = 31, /* S */ + [0x08] = 32, /* D */ + [0x09] = 33, /* F */ + [0x0a] = 34, /* G */ + [0x0b] = 35, /* H */ + [0x0c] = 36, /* J */ + + [0x11] = 17, /* W */ + [0x12] = 62, /* Menu (F4) */ + [0x13] = 38, /* L */ + [0x14] = 40, /* ' (Apostrophe) */ + [0x16] = 44, /* Z */ + [0x17] = 45, /* X */ + [0x18] = 46, /* C */ + [0x19] = 47, /* V */ + [0x1a] = 48, /* B */ + [0x1b] = 49, /* N */ + [0x1c] = 42, /* Shift (Left shift) */ + [0x1f] = 65, /* Zoom+ (F7) */ + + [0x21] = 18, /* E */ + [0x22] = 39, /* ; (Semicolon) */ + [0x23] = 12, /* - (Minus) */ + [0x24] = 13, /* = (Equal) */ + [0x2b] = 56, /* Fn (Left Alt) */ + [0x2c] = 50, /* M */ + [0x2f] = 66, /* Zoom- (F8) */ + + [0x31] = 19, /* R */ + [0x32] = 29 | M, /* Right Ctrl */ + [0x34] = 57, /* Space */ + [0x35] = 51, /* , (Comma) */ + [0x37] = 72 | M, /* Up */ + [0x3c] = 82 | M, /* Compose (Insert) */ + [0x3f] = 64, /* FullScreen (F6) */ + + [0x41] = 20, /* T */ + [0x44] = 52, /* . (Dot) */ + [0x46] = 77 | M, /* Right */ + [0x4f] = 63, /* Home (F5) */ + [0x51] = 21, /* Y */ + [0x53] = 80 | M, /* Down */ + [0x55] = 28, /* Enter */ + [0x5f] = 1, /* Cycle (ESC) */ + + [0x61] = 22, /* U */ + [0x64] = 75 | M, /* Left */ + + [0x71] = 23, /* I */ +#if 0 + [0x75] = 28 | M, /* KP Enter (KP Enter) */ +#else + [0x75] = 15, /* KP Enter (Tab) */ +#endif +}; + +#undef M + +static void n810_kbd_setup(struct n800_s *s) +{ + qemu_irq kbd_irq = omap2_gpio_in_get(s->cpu->gpif, N810_KEYBOARD_GPIO)[0]; + int i; + + for (i = 0; i < 0x80; i ++) + s->keymap[i] = -1; + for (i = 0; i < 0x80; i ++) + if (n810_keys[i] > 0) + s->keymap[n810_keys[i]] = i; + + qemu_add_kbd_event_handler(n810_key_event, s); + + /* Attach the LM8322 keyboard to the I2C bus, + * should happen in n8x0_i2c_setup and s->kbd be initialised here. */ + s->kbd = lm8323_init(s->i2c, kbd_irq); + i2c_set_slave_address(s->kbd, N810_LM8323_ADDR); +} + +/* LCD MIPI DBI-C controller (URAL) */ +struct mipid_s { + int resp[4]; + int param[4]; + int p; + int pm; + int cmd; + + int sleep; + int booster; + int te; + int selfcheck; + int partial; + int normal; + int vscr; + int invert; + int onoff; + int gamma; + uint32_t id; +}; + +static void mipid_reset(struct mipid_s *s) +{ + if (!s->sleep) + fprintf(stderr, "%s: Display off\n", __FUNCTION__); + + s->pm = 0; + s->cmd = 0; + + s->sleep = 1; + s->booster = 0; + s->selfcheck = + (1 << 7) | /* Register loading OK. */ + (1 << 5) | /* The chip is attached. */ + (1 << 4); /* Display glass still in one piece. */ + s->te = 0; + s->partial = 0; + s->normal = 1; + s->vscr = 0; + s->invert = 0; + s->onoff = 1; + s->gamma = 0; +} + +static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len) +{ + struct mipid_s *s = (struct mipid_s *) opaque; + uint8_t ret; + + if (len > 9) + cpu_abort(cpu_single_env, "%s: FIXME: bad SPI word width %i\n", + __FUNCTION__, len); + + if (s->p >= sizeof(s->resp) / sizeof(*s->resp)) + ret = 0; + else + ret = s->resp[s->p ++]; + if (s->pm --> 0) + s->param[s->pm] = cmd; + else + s->cmd = cmd; + + switch (s->cmd) { + case 0x00: /* NOP */ + break; + + case 0x01: /* SWRESET */ + mipid_reset(s); + break; + + case 0x02: /* BSTROFF */ + s->booster = 0; + break; + case 0x03: /* BSTRON */ + s->booster = 1; + break; + + case 0x04: /* RDDID */ + s->p = 0; + s->resp[0] = (s->id >> 16) & 0xff; + s->resp[1] = (s->id >> 8) & 0xff; + s->resp[2] = (s->id >> 0) & 0xff; + break; + + case 0x06: /* RD_RED */ + case 0x07: /* RD_GREEN */ + /* XXX the bootloader sometimes issues RD_BLUE meaning RDDID so + * for the bootloader one needs to change this. */ + case 0x08: /* RD_BLUE */ + s->p = 0; + /* TODO: return first pixel components */ + s->resp[0] = 0x01; + break; + + case 0x09: /* RDDST */ + s->p = 0; + s->resp[0] = s->booster << 7; + s->resp[1] = (5 << 4) | (s->partial << 2) | + (s->sleep << 1) | s->normal; + s->resp[2] = (s->vscr << 7) | (s->invert << 5) | + (s->onoff << 2) | (s->te << 1) | (s->gamma >> 2); + s->resp[3] = s->gamma << 6; + break; + + case 0x0a: /* RDDPM */ + s->p = 0; + s->resp[0] = (s->onoff << 2) | (s->normal << 3) | (s->sleep << 4) | + (s->partial << 5) | (s->sleep << 6) | (s->booster << 7); + break; + case 0x0b: /* RDDMADCTR */ + s->p = 0; + s->resp[0] = 0; + break; + case 0x0c: /* RDDCOLMOD */ + s->p = 0; + s->resp[0] = 5; /* 65K colours */ + break; + case 0x0d: /* RDDIM */ + s->p = 0; + s->resp[0] = (s->invert << 5) | (s->vscr << 7) | s->gamma; + break; + case 0x0e: /* RDDSM */ + s->p = 0; + s->resp[0] = s->te << 7; + break; + case 0x0f: /* RDDSDR */ + s->p = 0; + s->resp[0] = s->selfcheck; + break; + + case 0x10: /* SLPIN */ + s->sleep = 1; + break; + case 0x11: /* SLPOUT */ + s->sleep = 0; + s->selfcheck ^= 1 << 6; /* POFF self-diagnosis Ok */ + break; + + case 0x12: /* PTLON */ + s->partial = 1; + s->normal = 0; + s->vscr = 0; + break; + case 0x13: /* NORON */ + s->partial = 0; + s->normal = 1; + s->vscr = 0; + break; + + case 0x20: /* INVOFF */ + s->invert = 0; + break; + case 0x21: /* INVON */ + s->invert = 1; + break; + + case 0x22: /* APOFF */ + case 0x23: /* APON */ + goto bad_cmd; + + case 0x25: /* WRCNTR */ + if (s->pm < 0) + s->pm = 1; + goto bad_cmd; + + case 0x26: /* GAMSET */ + if (!s->pm) + s->gamma = ffs(s->param[0] & 0xf) - 1; + else if (s->pm < 0) + s->pm = 1; + break; + + case 0x28: /* DISPOFF */ + s->onoff = 0; + fprintf(stderr, "%s: Display off\n", __FUNCTION__); + break; + case 0x29: /* DISPON */ + s->onoff = 1; + fprintf(stderr, "%s: Display on\n", __FUNCTION__); + break; + + case 0x2a: /* CASET */ + case 0x2b: /* RASET */ + case 0x2c: /* RAMWR */ + case 0x2d: /* RGBSET */ + case 0x2e: /* RAMRD */ + case 0x30: /* PTLAR */ + case 0x33: /* SCRLAR */ + goto bad_cmd; + + case 0x34: /* TEOFF */ + s->te = 0; + break; + case 0x35: /* TEON */ + if (!s->pm) + s->te = 1; + else if (s->pm < 0) + s->pm = 1; + break; + + case 0x36: /* MADCTR */ + goto bad_cmd; + + case 0x37: /* VSCSAD */ + s->partial = 0; + s->normal = 0; + s->vscr = 1; + break; + + case 0x38: /* IDMOFF */ + case 0x39: /* IDMON */ + case 0x3a: /* COLMOD */ + goto bad_cmd; + + case 0xb0: /* CLKINT / DISCTL */ + case 0xb1: /* CLKEXT */ + if (s->pm < 0) + s->pm = 2; + break; + + case 0xb4: /* FRMSEL */ + break; + + case 0xb5: /* FRM8SEL */ + case 0xb6: /* TMPRNG / INIESC */ + case 0xb7: /* TMPHIS / NOP2 */ + case 0xb8: /* TMPREAD / MADCTL */ + case 0xba: /* DISTCTR */ + case 0xbb: /* EPVOL */ + goto bad_cmd; + + case 0xbd: /* Unknown */ + s->p = 0; + s->resp[0] = 0; + s->resp[1] = 1; + break; + + case 0xc2: /* IFMOD */ + if (s->pm < 0) + s->pm = 2; + break; + + case 0xc6: /* PWRCTL */ + case 0xc7: /* PPWRCTL */ + case 0xd0: /* EPWROUT */ + case 0xd1: /* EPWRIN */ + case 0xd4: /* RDEV */ + case 0xd5: /* RDRR */ + goto bad_cmd; + + case 0xda: /* RDID1 */ + s->p = 0; + s->resp[0] = (s->id >> 16) & 0xff; + break; + case 0xdb: /* RDID2 */ + s->p = 0; + s->resp[0] = (s->id >> 8) & 0xff; + break; + case 0xdc: /* RDID3 */ + s->p = 0; + s->resp[0] = (s->id >> 0) & 0xff; + break; + + default: + bad_cmd: + fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, s->cmd); + break; + } + + return ret; +} + +static void *mipid_init(void) +{ + struct mipid_s *s = (struct mipid_s *) qemu_mallocz(sizeof(*s)); + + s->id = 0x838f03; + mipid_reset(s); + + return s; +} + +static void n8x0_spi_setup(struct n800_s *s) +{ + void *tsc = s->ts.opaque; + void *mipid = mipid_init(); + + omap_mcspi_attach(s->cpu->mcspi[0], s->ts.txrx, tsc, 0); + omap_mcspi_attach(s->cpu->mcspi[0], mipid_txrx, mipid, 1); +} + +/* This task is normally performed by the bootloader. If we're loading + * a kernel directly, we need to enable the Blizzard ourselves. */ +static void n800_dss_init(struct rfbi_chip_s *chip) +{ + uint8_t *fb_blank; + + chip->write(chip->opaque, 0, 0x2a); /* LCD Width register */ + chip->write(chip->opaque, 1, 0x64); + chip->write(chip->opaque, 0, 0x2c); /* LCD HNDP register */ + chip->write(chip->opaque, 1, 0x1e); + chip->write(chip->opaque, 0, 0x2e); /* LCD Height 0 register */ + chip->write(chip->opaque, 1, 0xe0); + chip->write(chip->opaque, 0, 0x30); /* LCD Height 1 register */ + chip->write(chip->opaque, 1, 0x01); + chip->write(chip->opaque, 0, 0x32); /* LCD VNDP register */ + chip->write(chip->opaque, 1, 0x06); + chip->write(chip->opaque, 0, 0x68); /* Display Mode register */ + chip->write(chip->opaque, 1, 1); /* Enable bit */ + + chip->write(chip->opaque, 0, 0x6c); + chip->write(chip->opaque, 1, 0x00); /* Input X Start Position */ + chip->write(chip->opaque, 1, 0x00); /* Input X Start Position */ + chip->write(chip->opaque, 1, 0x00); /* Input Y Start Position */ + chip->write(chip->opaque, 1, 0x00); /* Input Y Start Position */ + chip->write(chip->opaque, 1, 0x1f); /* Input X End Position */ + chip->write(chip->opaque, 1, 0x03); /* Input X End Position */ + chip->write(chip->opaque, 1, 0xdf); /* Input Y End Position */ + chip->write(chip->opaque, 1, 0x01); /* Input Y End Position */ + chip->write(chip->opaque, 1, 0x00); /* Output X Start Position */ + chip->write(chip->opaque, 1, 0x00); /* Output X Start Position */ + chip->write(chip->opaque, 1, 0x00); /* Output Y Start Position */ + chip->write(chip->opaque, 1, 0x00); /* Output Y Start Position */ + chip->write(chip->opaque, 1, 0x1f); /* Output X End Position */ + chip->write(chip->opaque, 1, 0x03); /* Output X End Position */ + chip->write(chip->opaque, 1, 0xdf); /* Output Y End Position */ + chip->write(chip->opaque, 1, 0x01); /* Output Y End Position */ + chip->write(chip->opaque, 1, 0x01); /* Input Data Format */ + chip->write(chip->opaque, 1, 0x01); /* Data Source Select */ + + fb_blank = memset(qemu_malloc(800 * 480 * 2), 0xff, 800 * 480 * 2); + /* Display Memory Data Port */ + chip->block(chip->opaque, 1, fb_blank, 800 * 480 * 2, 800); + free(fb_blank); +} + +static void n8x0_dss_setup(struct n800_s *s, DisplayState *ds) +{ + s->blizzard.opaque = s1d13745_init(0, ds); + s->blizzard.block = s1d13745_write_block; + s->blizzard.write = s1d13745_write; + s->blizzard.read = s1d13745_read; + + omap_rfbi_attach(s->cpu->dss, 0, &s->blizzard); +} + +static void n8x0_cbus_setup(struct n800_s *s) +{ + qemu_irq dat_out = omap2_gpio_in_get(s->cpu->gpif, N8X0_CBUS_DAT_GPIO)[0]; + qemu_irq retu_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_RETU_GPIO)[0]; + qemu_irq tahvo_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TAHVO_GPIO)[0]; + + struct cbus_s *cbus = cbus_init(dat_out); + + omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_CLK_GPIO, cbus->clk); + omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_DAT_GPIO, cbus->dat); + omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_SEL_GPIO, cbus->sel); + + cbus_attach(cbus, s->retu = retu_init(retu_irq, 1)); + cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1)); +} + +static void n8x0_uart_setup(struct n800_s *s) +{ + CharDriverState *radio = uart_hci_init( + omap2_gpio_in_get(s->cpu->gpif, + N8X0_BT_HOST_WKUP_GPIO)[0]); + + omap2_gpio_out_set(s->cpu->gpif, N8X0_BT_RESET_GPIO, + csrhci_pins_get(radio)[csrhci_pin_reset]); + omap2_gpio_out_set(s->cpu->gpif, N8X0_BT_WKUP_GPIO, + csrhci_pins_get(radio)[csrhci_pin_wakeup]); + + omap_uart_attach(s->cpu->uart[BT_UART], radio); +} + +static void n8x0_usb_power_cb(void *opaque, int line, int level) +{ + struct n800_s *s = opaque; + + tusb6010_power(s->usb, level); +} + +static void n8x0_usb_setup(struct n800_s *s) +{ + qemu_irq tusb_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TUSB_INT_GPIO)[0]; + qemu_irq tusb_pwr = qemu_allocate_irqs(n8x0_usb_power_cb, s, 1)[0]; + struct tusb_s *tusb = tusb6010_init(tusb_irq); + + /* Using the NOR interface */ + omap_gpmc_attach(s->cpu->gpmc, N8X0_USB_ASYNC_CS, + tusb6010_async_io(tusb), 0, 0, tusb); + omap_gpmc_attach(s->cpu->gpmc, N8X0_USB_SYNC_CS, + tusb6010_sync_io(tusb), 0, 0, tusb); + + s->usb = tusb; + omap2_gpio_out_set(s->cpu->gpif, N8X0_TUSB_ENABLE_GPIO, tusb_pwr); +} + +/* Setup done before the main bootloader starts by some early setup code + * - used when we want to run the main bootloader in emulation. This + * isn't documented. */ +static uint32_t n800_pinout[104] = { + 0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0, + 0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808, + 0x08080808, 0x180800c4, 0x00b80000, 0x08080808, + 0x080800bc, 0x00cc0808, 0x08081818, 0x18180128, + 0x01241800, 0x18181818, 0x000000f0, 0x01300000, + 0x00001b0b, 0x1b0f0138, 0x00e0181b, 0x1b031b0b, + 0x180f0078, 0x00740018, 0x0f0f0f1a, 0x00000080, + 0x007c0000, 0x00000000, 0x00000088, 0x00840000, + 0x00000000, 0x00000094, 0x00980300, 0x0f180003, + 0x0000008c, 0x00900f0f, 0x0f0f1b00, 0x0f00009c, + 0x01140000, 0x1b1b0f18, 0x0818013c, 0x01400008, + 0x00001818, 0x000b0110, 0x010c1800, 0x0b030b0f, + 0x181800f4, 0x00f81818, 0x00000018, 0x000000fc, + 0x00401808, 0x00000000, 0x0f1b0030, 0x003c0008, + 0x00000000, 0x00000038, 0x00340000, 0x00000000, + 0x1a080070, 0x00641a1a, 0x08080808, 0x08080060, + 0x005c0808, 0x08080808, 0x08080058, 0x00540808, + 0x08080808, 0x0808006c, 0x00680808, 0x08080808, + 0x000000a8, 0x00b00000, 0x08080808, 0x000000a0, + 0x00a40000, 0x00000000, 0x08ff0050, 0x004c0808, + 0xffffffff, 0xffff0048, 0x0044ffff, 0xffffffff, + 0x000000ac, 0x01040800, 0x08080b0f, 0x18180100, + 0x01081818, 0x0b0b1808, 0x1a0300e4, 0x012c0b1a, + 0x02020018, 0x0b000134, 0x011c0800, 0x0b1b1b00, + 0x0f0000c8, 0x00ec181b, 0x000f0f02, 0x00180118, + 0x01200000, 0x0f0b1b1b, 0x0f0200e8, 0x0000020b, +}; + +static void n800_setup_nolo_tags(void *sram_base) +{ + int i; + uint32_t *p = sram_base + 0x8000; + uint32_t *v = sram_base + 0xa000; + + memset(p, 0, 0x3000); + + strcpy((void *) (p + 0), "QEMU N800"); + + strcpy((void *) (p + 8), "F5"); + + stl_raw(p + 10, 0x04f70000); + strcpy((void *) (p + 9), "RX-34"); + + /* RAM size in MB? */ + stl_raw(p + 12, 0x80); + + /* Pointer to the list of tags */ + stl_raw(p + 13, OMAP2_SRAM_BASE + 0x9000); + + /* The NOLO tags start here */ + p = sram_base + 0x9000; +#define ADD_TAG(tag, len) \ + stw_raw((uint16_t *) p + 0, tag); \ + stw_raw((uint16_t *) p + 1, len); p ++; \ + stl_raw(p ++, OMAP2_SRAM_BASE | (((void *) v - sram_base) & 0xffff)); + + /* OMAP STI console? Pin out settings? */ + ADD_TAG(0x6e01, 414); + for (i = 0; i < sizeof(n800_pinout) / 4; i ++) + stl_raw(v ++, n800_pinout[i]); + + /* Kernel memsize? */ + ADD_TAG(0x6e05, 1); + stl_raw(v ++, 2); + + /* NOLO serial console */ + ADD_TAG(0x6e02, 4); + stl_raw(v ++, XLDR_LL_UART); /* UART number (1 - 3) */ + +#if 0 + /* CBUS settings (Retu/AVilma) */ + ADD_TAG(0x6e03, 6); + stw_raw((uint16_t *) v + 0, 65); /* CBUS GPIO0 */ + stw_raw((uint16_t *) v + 1, 66); /* CBUS GPIO1 */ + stw_raw((uint16_t *) v + 2, 64); /* CBUS GPIO2 */ + v += 2; +#endif + + /* Nokia ASIC BB5 (Retu/Tahvo) */ + ADD_TAG(0x6e0a, 4); + stw_raw((uint16_t *) v + 0, 111); /* "Retu" interrupt GPIO */ + stw_raw((uint16_t *) v + 1, 108); /* "Tahvo" interrupt GPIO */ + v ++; + + /* LCD console? */ + ADD_TAG(0x6e04, 4); + stw_raw((uint16_t *) v + 0, 30); /* ??? */ + stw_raw((uint16_t *) v + 1, 24); /* ??? */ + v ++; + +#if 0 + /* LCD settings */ + ADD_TAG(0x6e06, 2); + stw_raw((uint16_t *) (v ++), 15); /* ??? */ +#endif + + /* I^2C (Menelaus) */ + ADD_TAG(0x6e07, 4); + stl_raw(v ++, 0x00720000); /* ??? */ + + /* Unknown */ + ADD_TAG(0x6e0b, 6); + stw_raw((uint16_t *) v + 0, 94); /* ??? */ + stw_raw((uint16_t *) v + 1, 23); /* ??? */ + stw_raw((uint16_t *) v + 2, 0); /* ??? */ + v += 2; + + /* OMAP gpio switch info */ + ADD_TAG(0x6e0c, 80); + strcpy((void *) v, "bat_cover"); v += 3; + stw_raw((uint16_t *) v + 0, 110); /* GPIO num ??? */ + stw_raw((uint16_t *) v + 1, 1); /* GPIO num ??? */ + v += 2; + strcpy((void *) v, "cam_act"); v += 3; + stw_raw((uint16_t *) v + 0, 95); /* GPIO num ??? */ + stw_raw((uint16_t *) v + 1, 32); /* GPIO num ??? */ + v += 2; + strcpy((void *) v, "cam_turn"); v += 3; + stw_raw((uint16_t *) v + 0, 12); /* GPIO num ??? */ + stw_raw((uint16_t *) v + 1, 33); /* GPIO num ??? */ + v += 2; + strcpy((void *) v, "headphone"); v += 3; + stw_raw((uint16_t *) v + 0, 107); /* GPIO num ??? */ + stw_raw((uint16_t *) v + 1, 17); /* GPIO num ??? */ + v += 2; + + /* Bluetooth */ + ADD_TAG(0x6e0e, 12); + stl_raw(v ++, 0x5c623d01); /* ??? */ + stl_raw(v ++, 0x00000201); /* ??? */ + stl_raw(v ++, 0x00000000); /* ??? */ + + /* CX3110x WLAN settings */ + ADD_TAG(0x6e0f, 8); + stl_raw(v ++, 0x00610025); /* ??? */ + stl_raw(v ++, 0xffff0057); /* ??? */ + + /* MMC host settings */ + ADD_TAG(0x6e10, 12); + stl_raw(v ++, 0xffff000f); /* ??? */ + stl_raw(v ++, 0xffffffff); /* ??? */ + stl_raw(v ++, 0x00000060); /* ??? */ + + /* OneNAND chip select */ + ADD_TAG(0x6e11, 10); + stl_raw(v ++, 0x00000401); /* ??? */ + stl_raw(v ++, 0x0002003a); /* ??? */ + stl_raw(v ++, 0x00000002); /* ??? */ + + /* TEA5761 sensor settings */ + ADD_TAG(0x6e12, 2); + stl_raw(v ++, 93); /* GPIO num ??? */ + +#if 0 + /* Unknown tag */ + ADD_TAG(6e09, 0); + + /* Kernel UART / console */ + ADD_TAG(6e12, 0); +#endif + + /* End of the list */ + stl_raw(p ++, 0x00000000); + stl_raw(p ++, 0x00000000); +} + +/* This task is normally performed by the bootloader. If we're loading + * a kernel directly, we need to set up GPMC mappings ourselves. */ +static void n800_gpmc_init(struct n800_s *s) +{ + uint32_t config7 = + (0xf << 8) | /* MASKADDRESS */ + (1 << 6) | /* CSVALID */ + (4 << 0); /* BASEADDRESS */ + + cpu_physical_memory_write(0x6800a078, /* GPMC_CONFIG7_0 */ + (void *) &config7, sizeof(config7)); +} + +/* Setup sequence done by the bootloader */ +static void n8x0_boot_init(void *opaque) +{ + struct n800_s *s = (struct n800_s *) opaque; + uint32_t buf; + + /* PRCM setup */ +#define omap_writel(addr, val) \ + buf = (val); \ + cpu_physical_memory_write(addr, (void *) &buf, sizeof(buf)) + + omap_writel(0x48008060, 0x41); /* PRCM_CLKSRC_CTRL */ + omap_writel(0x48008070, 1); /* PRCM_CLKOUT_CTRL */ + omap_writel(0x48008078, 0); /* PRCM_CLKEMUL_CTRL */ + omap_writel(0x48008090, 0); /* PRCM_VOLTSETUP */ + omap_writel(0x48008094, 0); /* PRCM_CLKSSETUP */ + omap_writel(0x48008098, 0); /* PRCM_POLCTRL */ + omap_writel(0x48008140, 2); /* CM_CLKSEL_MPU */ + omap_writel(0x48008148, 0); /* CM_CLKSTCTRL_MPU */ + omap_writel(0x48008158, 1); /* RM_RSTST_MPU */ + omap_writel(0x480081c8, 0x15); /* PM_WKDEP_MPU */ + omap_writel(0x480081d4, 0x1d4); /* PM_EVGENCTRL_MPU */ + omap_writel(0x480081d8, 0); /* PM_EVEGENONTIM_MPU */ + omap_writel(0x480081dc, 0); /* PM_EVEGENOFFTIM_MPU */ + omap_writel(0x480081e0, 0xc); /* PM_PWSTCTRL_MPU */ + omap_writel(0x48008200, 0x047e7ff7); /* CM_FCLKEN1_CORE */ + omap_writel(0x48008204, 0x00000004); /* CM_FCLKEN2_CORE */ + omap_writel(0x48008210, 0x047e7ff1); /* CM_ICLKEN1_CORE */ + omap_writel(0x48008214, 0x00000004); /* CM_ICLKEN2_CORE */ + omap_writel(0x4800821c, 0x00000000); /* CM_ICLKEN4_CORE */ + omap_writel(0x48008230, 0); /* CM_AUTOIDLE1_CORE */ + omap_writel(0x48008234, 0); /* CM_AUTOIDLE2_CORE */ + omap_writel(0x48008238, 7); /* CM_AUTOIDLE3_CORE */ + omap_writel(0x4800823c, 0); /* CM_AUTOIDLE4_CORE */ + omap_writel(0x48008240, 0x04360626); /* CM_CLKSEL1_CORE */ + omap_writel(0x48008244, 0x00000014); /* CM_CLKSEL2_CORE */ + omap_writel(0x48008248, 0); /* CM_CLKSTCTRL_CORE */ + omap_writel(0x48008300, 0x00000000); /* CM_FCLKEN_GFX */ + omap_writel(0x48008310, 0x00000000); /* CM_ICLKEN_GFX */ + omap_writel(0x48008340, 0x00000001); /* CM_CLKSEL_GFX */ + omap_writel(0x48008400, 0x00000004); /* CM_FCLKEN_WKUP */ + omap_writel(0x48008410, 0x00000004); /* CM_ICLKEN_WKUP */ + omap_writel(0x48008440, 0x00000000); /* CM_CLKSEL_WKUP */ + omap_writel(0x48008500, 0x000000cf); /* CM_CLKEN_PLL */ + omap_writel(0x48008530, 0x0000000c); /* CM_AUTOIDLE_PLL */ + omap_writel(0x48008540, /* CM_CLKSEL1_PLL */ + (0x78 << 12) | (6 << 8)); + omap_writel(0x48008544, 2); /* CM_CLKSEL2_PLL */ + + /* GPMC setup */ + n800_gpmc_init(s); + + /* Video setup */ + n800_dss_init(&s->blizzard); + + /* CPU setup */ + s->cpu->env->regs[15] = s->cpu->env->boot_info->loader_start; + s->cpu->env->GE = 0x5; + + /* If the machine has a slided keyboard, open it */ + if (s->kbd) + qemu_irq_raise(omap2_gpio_in_get(s->cpu->gpif, N810_SLIDE_GPIO)[0]); +} + +#define OMAP_TAG_NOKIA_BT 0x4e01 +#define OMAP_TAG_WLAN_CX3110X 0x4e02 +#define OMAP_TAG_CBUS 0x4e03 +#define OMAP_TAG_EM_ASIC_BB5 0x4e04 + +static struct omap_gpiosw_info_s { + const char *name; + int line; + int type; +} n800_gpiosw_info[] = { + { + "bat_cover", N800_BAT_COVER_GPIO, + OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED, + }, { + "cam_act", N800_CAM_ACT_GPIO, + OMAP_GPIOSW_TYPE_ACTIVITY, + }, { + "cam_turn", N800_CAM_TURN_GPIO, + OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED, + }, { + "headphone", N8X0_HEADPHONE_GPIO, + OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED, + }, + { 0 } +}, n810_gpiosw_info[] = { + { + "gps_reset", N810_GPS_RESET_GPIO, + OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT, + }, { + "gps_wakeup", N810_GPS_WAKEUP_GPIO, + OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT, + }, { + "headphone", N8X0_HEADPHONE_GPIO, + OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED, + }, { + "kb_lock", N810_KB_LOCK_GPIO, + OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED, + }, { + "sleepx_led", N810_SLEEPX_LED_GPIO, + OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED | OMAP_GPIOSW_OUTPUT, + }, { + "slide", N810_SLIDE_GPIO, + OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED, + }, + { 0 } +}; + +static struct omap_partition_info_s { + uint32_t offset; + uint32_t size; + int mask; + const char *name; +} n800_part_info[] = { + { 0x00000000, 0x00020000, 0x3, "bootloader" }, + { 0x00020000, 0x00060000, 0x0, "config" }, + { 0x00080000, 0x00200000, 0x0, "kernel" }, + { 0x00280000, 0x00200000, 0x3, "initfs" }, + { 0x00480000, 0x0fb80000, 0x3, "rootfs" }, + + { 0, 0, 0, 0 } +}, n810_part_info[] = { + { 0x00000000, 0x00020000, 0x3, "bootloader" }, + { 0x00020000, 0x00060000, 0x0, "config" }, + { 0x00080000, 0x00220000, 0x0, "kernel" }, + { 0x002a0000, 0x00400000, 0x0, "initfs" }, + { 0x006a0000, 0x0f960000, 0x0, "rootfs" }, + + { 0, 0, 0, 0 } +}; + +static bdaddr_t n8x0_bd_addr = {{ N8X0_BD_ADDR }}; + +static int n8x0_atag_setup(void *p, int model) +{ + uint8_t *b; + uint16_t *w; + uint32_t *l; + struct omap_gpiosw_info_s *gpiosw; + struct omap_partition_info_s *partition; + const char *tag; + + w = p; + + stw_raw(w ++, OMAP_TAG_UART); /* u16 tag */ + stw_raw(w ++, 4); /* u16 len */ + stw_raw(w ++, (1 << 2) | (1 << 1) | (1 << 0)); /* uint enabled_uarts */ + w ++; + +#if 0 + stw_raw(w ++, OMAP_TAG_SERIAL_CONSOLE); /* u16 tag */ + stw_raw(w ++, 4); /* u16 len */ + stw_raw(w ++, XLDR_LL_UART + 1); /* u8 console_uart */ + stw_raw(w ++, 115200); /* u32 console_speed */ +#endif + + stw_raw(w ++, OMAP_TAG_LCD); /* u16 tag */ + stw_raw(w ++, 36); /* u16 len */ + strcpy((void *) w, "QEMU LCD panel"); /* char panel_name[16] */ + w += 8; + strcpy((void *) w, "blizzard"); /* char ctrl_name[16] */ + w += 8; + stw_raw(w ++, N810_BLIZZARD_RESET_GPIO); /* TODO: n800 s16 nreset_gpio */ + stw_raw(w ++, 24); /* u8 data_lines */ + + stw_raw(w ++, OMAP_TAG_CBUS); /* u16 tag */ + stw_raw(w ++, 8); /* u16 len */ + stw_raw(w ++, N8X0_CBUS_CLK_GPIO); /* s16 clk_gpio */ + stw_raw(w ++, N8X0_CBUS_DAT_GPIO); /* s16 dat_gpio */ + stw_raw(w ++, N8X0_CBUS_SEL_GPIO); /* s16 sel_gpio */ + w ++; + + stw_raw(w ++, OMAP_TAG_EM_ASIC_BB5); /* u16 tag */ + stw_raw(w ++, 4); /* u16 len */ + stw_raw(w ++, N8X0_RETU_GPIO); /* s16 retu_irq_gpio */ + stw_raw(w ++, N8X0_TAHVO_GPIO); /* s16 tahvo_irq_gpio */ + + gpiosw = (model == 810) ? n810_gpiosw_info : n800_gpiosw_info; + for (; gpiosw->name; gpiosw ++) { + stw_raw(w ++, OMAP_TAG_GPIO_SWITCH); /* u16 tag */ + stw_raw(w ++, 20); /* u16 len */ + strcpy((void *) w, gpiosw->name); /* char name[12] */ + w += 6; + stw_raw(w ++, gpiosw->line); /* u16 gpio */ + stw_raw(w ++, gpiosw->type); + stw_raw(w ++, 0); + stw_raw(w ++, 0); + } + + stw_raw(w ++, OMAP_TAG_NOKIA_BT); /* u16 tag */ + stw_raw(w ++, 12); /* u16 len */ + b = (void *) w; + stb_raw(b ++, 0x01); /* u8 chip_type (CSR) */ + stb_raw(b ++, N8X0_BT_WKUP_GPIO); /* u8 bt_wakeup_gpio */ + stb_raw(b ++, N8X0_BT_HOST_WKUP_GPIO); /* u8 host_wakeup_gpio */ + stb_raw(b ++, N8X0_BT_RESET_GPIO); /* u8 reset_gpio */ + stb_raw(b ++, BT_UART + 1); /* u8 bt_uart */ + memcpy(b, &n8x0_bd_addr, 6); /* u8 bd_addr[6] */ + b += 6; + stb_raw(b ++, 0x02); /* u8 bt_sysclk (38.4) */ + w = (void *) b; + + stw_raw(w ++, OMAP_TAG_WLAN_CX3110X); /* u16 tag */ + stw_raw(w ++, 8); /* u16 len */ + stw_raw(w ++, 0x25); /* u8 chip_type */ + stw_raw(w ++, N8X0_WLAN_PWR_GPIO); /* s16 power_gpio */ + stw_raw(w ++, N8X0_WLAN_IRQ_GPIO); /* s16 irq_gpio */ + stw_raw(w ++, -1); /* s16 spi_cs_gpio */ + + stw_raw(w ++, OMAP_TAG_MMC); /* u16 tag */ + stw_raw(w ++, 16); /* u16 len */ + if (model == 810) { + stw_raw(w ++, 0x23f); /* unsigned flags */ + stw_raw(w ++, -1); /* s16 power_pin */ + stw_raw(w ++, -1); /* s16 switch_pin */ + stw_raw(w ++, -1); /* s16 wp_pin */ + stw_raw(w ++, 0x240); /* unsigned flags */ + stw_raw(w ++, 0xc000); /* s16 power_pin */ + stw_raw(w ++, 0x0248); /* s16 switch_pin */ + stw_raw(w ++, 0xc000); /* s16 wp_pin */ + } else { + stw_raw(w ++, 0xf); /* unsigned flags */ + stw_raw(w ++, -1); /* s16 power_pin */ + stw_raw(w ++, -1); /* s16 switch_pin */ + stw_raw(w ++, -1); /* s16 wp_pin */ + stw_raw(w ++, 0); /* unsigned flags */ + stw_raw(w ++, 0); /* s16 power_pin */ + stw_raw(w ++, 0); /* s16 switch_pin */ + stw_raw(w ++, 0); /* s16 wp_pin */ + } + + stw_raw(w ++, OMAP_TAG_TEA5761); /* u16 tag */ + stw_raw(w ++, 4); /* u16 len */ + stw_raw(w ++, N8X0_TEA5761_CS_GPIO); /* u16 enable_gpio */ + w ++; + + partition = (model == 810) ? n810_part_info : n800_part_info; + for (; partition->name; partition ++) { + stw_raw(w ++, OMAP_TAG_PARTITION); /* u16 tag */ + stw_raw(w ++, 28); /* u16 len */ + strcpy((void *) w, partition->name); /* char name[16] */ + l = (void *) (w + 8); + stl_raw(l ++, partition->size); /* unsigned int size */ + stl_raw(l ++, partition->offset); /* unsigned int offset */ + stl_raw(l ++, partition->mask); /* unsigned int mask_flags */ + w = (void *) l; + } + + stw_raw(w ++, OMAP_TAG_BOOT_REASON); /* u16 tag */ + stw_raw(w ++, 12); /* u16 len */ +#if 0 + strcpy((void *) w, "por"); /* char reason_str[12] */ + strcpy((void *) w, "charger"); /* char reason_str[12] */ + strcpy((void *) w, "32wd_to"); /* char reason_str[12] */ + strcpy((void *) w, "sw_rst"); /* char reason_str[12] */ + strcpy((void *) w, "mbus"); /* char reason_str[12] */ + strcpy((void *) w, "unknown"); /* char reason_str[12] */ + strcpy((void *) w, "swdg_to"); /* char reason_str[12] */ + strcpy((void *) w, "sec_vio"); /* char reason_str[12] */ + strcpy((void *) w, "pwr_key"); /* char reason_str[12] */ + strcpy((void *) w, "rtc_alarm"); /* char reason_str[12] */ +#else + strcpy((void *) w, "pwr_key"); /* char reason_str[12] */ +#endif + w += 6; + + tag = (model == 810) ? "RX-44" : "RX-34"; + stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */ + stw_raw(w ++, 24); /* u16 len */ + strcpy((void *) w, "product"); /* char component[12] */ + w += 6; + strcpy((void *) w, tag); /* char version[12] */ + w += 6; + + stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */ + stw_raw(w ++, 24); /* u16 len */ + strcpy((void *) w, "hw-build"); /* char component[12] */ + w += 6; + strcpy((void *) w, "QEMU " QEMU_VERSION); /* char version[12] */ + w += 6; + + tag = (model == 810) ? "1.1.10-qemu" : "1.1.6-qemu"; + stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */ + stw_raw(w ++, 24); /* u16 len */ + strcpy((void *) w, "nolo"); /* char component[12] */ + w += 6; + strcpy((void *) w, tag); /* char version[12] */ + w += 6; + + return (void *) w - p; +} + +static int n800_atag_setup(struct arm_boot_info *info, void *p) +{ + return n8x0_atag_setup(p, 800); +} + +static int n810_atag_setup(struct arm_boot_info *info, void *p) +{ + return n8x0_atag_setup(p, 810); +} + +static void n8x0_init(ram_addr_t ram_size, const char *boot_device, + DisplayState *ds, const char *kernel_filename, + const char *kernel_cmdline, const char *initrd_filename, + const char *cpu_model, struct arm_boot_info *binfo, int model) +{ + struct n800_s *s = (struct n800_s *) qemu_mallocz(sizeof(*s)); + int sdram_size = binfo->ram_size; + int onenandram_size = 0x00010000; + + if (ram_size < sdram_size + onenandram_size + OMAP242X_SRAM_SIZE) { + fprintf(stderr, "This architecture uses %i bytes of memory\n", + sdram_size + onenandram_size + OMAP242X_SRAM_SIZE); + exit(1); + } + + s->cpu = omap2420_mpu_init(sdram_size, NULL, cpu_model); + + /* Setup peripherals + * + * Believed external peripherals layout in the N810: + * (spi bus 1) + * tsc2005 + * lcd_mipid + * (spi bus 2) + * Conexant cx3110x (WLAN) + * optional: pc2400m (WiMAX) + * (i2c bus 0) + * TLV320AIC33 (audio codec) + * TCM825x (camera by Toshiba) + * lp5521 (clever LEDs) + * tsl2563 (light sensor, hwmon, model 7, rev. 0) + * lm8323 (keypad, manf 00, rev 04) + * (i2c bus 1) + * tmp105 (temperature sensor, hwmon) + * menelaus (pm) + * (somewhere on i2c - maybe N800-only) + * tea5761 (FM tuner) + * (serial 0) + * GPS + * (some serial port) + * csr41814 (Bluetooth) + */ + n8x0_gpio_setup(s); + n8x0_nand_setup(s); + n8x0_i2c_setup(s); + if (model == 800) + n800_tsc_kbd_setup(s); + else if (model == 810) { + n810_tsc_setup(s); + n810_kbd_setup(s); + } + n8x0_spi_setup(s); + n8x0_dss_setup(s, ds); + n8x0_cbus_setup(s); + n8x0_uart_setup(s); + if (usb_enabled) + n8x0_usb_setup(s); + + /* Setup initial (reset) machine state */ + + /* Start at the OneNAND bootloader. */ + s->cpu->env->regs[15] = 0; + + if (kernel_filename) { + /* Or at the linux loader. */ + binfo->kernel_filename = kernel_filename; + binfo->kernel_cmdline = kernel_cmdline; + binfo->initrd_filename = initrd_filename; + arm_load_kernel(s->cpu->env, binfo); + + qemu_register_reset(n8x0_boot_init, s); + n8x0_boot_init(s); + } + + if (option_rom[0] && (boot_device[0] == 'n' || !kernel_filename)) { + /* No, wait, better start at the ROM. */ + s->cpu->env->regs[15] = OMAP2_Q2_BASE + 0x400000; + + /* This is intended for loading the `secondary.bin' program from + * Nokia images (the NOLO bootloader). The entry point seems + * to be at OMAP2_Q2_BASE + 0x400000. + * + * The `2nd.bin' files contain some kind of earlier boot code and + * for them the entry point needs to be set to OMAP2_SRAM_BASE. + * + * The code above is for loading the `zImage' file from Nokia + * images. */ + printf("%i bytes of image loaded\n", load_image(option_rom[0], + phys_ram_base + 0x400000)); + + n800_setup_nolo_tags(phys_ram_base + sdram_size); + } + /* FIXME: We shouldn't really be doing this here. The LCD controller + will set the size once configured, so this just sets an initial + size until the guest activates the display. */ + dpy_resize(ds, 800, 480); +} + +static struct arm_boot_info n800_binfo = { + .loader_start = OMAP2_Q2_BASE, + /* Actually two chips of 0x4000000 bytes each */ + .ram_size = 0x08000000, + .board_id = 0x4f7, + .atag_board = n800_atag_setup, +}; + +static struct arm_boot_info n810_binfo = { + .loader_start = OMAP2_Q2_BASE, + /* Actually two chips of 0x4000000 bytes each */ + .ram_size = 0x08000000, + /* 0x60c and 0x6bf (WiMAX Edition) have been assigned but are not + * used by some older versions of the bootloader and 5555 is used + * instead (including versions that shipped with many devices). */ + .board_id = 0x60c, + .atag_board = n810_atag_setup, +}; + +static void n800_init(ram_addr_t ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + return n8x0_init(ram_size, boot_device, ds, + kernel_filename, kernel_cmdline, initrd_filename, + cpu_model, &n800_binfo, 800); +} + +static void n810_init(ram_addr_t ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + return n8x0_init(ram_size, boot_device, ds, + kernel_filename, kernel_cmdline, initrd_filename, + cpu_model, &n810_binfo, 810); +} + +QEMUMachine n800_machine = { + .name = "n800", + .desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)", + .init = n800_init, + .ram_require = (0x08000000 + 0x00010000 + OMAP242X_SRAM_SIZE) | + RAMSIZE_FIXED, +}; + +QEMUMachine n810_machine = { + .name = "n810", + .desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)", + .init = n810_init, + .ram_require = (0x08000000 + 0x00010000 + OMAP242X_SRAM_SIZE) | + RAMSIZE_FIXED, +}; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/nvram.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/nvram.h --- qemu-0.9.1/hw/nvram.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/nvram.h 2008-09-20 09:07:15.000000000 +0100 @@ -17,12 +17,12 @@ void NVRAM_set_lword (nvram_t *nvram, uint32_t addr, uint32_t value); uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr); void NVRAM_set_string (nvram_t *nvram, uint32_t addr, - const unsigned char *str, uint32_t max); + const char *str, uint32_t max); int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max); void NVRAM_set_crc (nvram_t *nvram, uint32_t addr, uint32_t start, uint32_t count); int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size, - const unsigned char *arch, + const char *arch, uint32_t RAM_size, int boot_device, uint32_t kernel_image, uint32_t kernel_size, const char *cmdline, diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/omap1.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/omap1.c --- qemu-0.9.1/hw/omap1.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/omap1.c 2008-11-01 00:53:19.000000000 +0000 @@ -0,0 +1,4846 @@ +/* + * TI OMAP processors emulation. + * + * Copyright (C) 2006-2008 Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include "hw.h" +#include "arm-misc.h" +#include "omap.h" +#include "sysemu.h" +#include "qemu-timer.h" +#include "qemu-char.h" +#include "soc_dma.h" +/* We use pc-style serial ports. */ +#include "pc.h" + +/* Should signal the TCMI/GPMC */ +uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr) +{ + uint8_t ret; + + OMAP_8B_REG(addr); + cpu_physical_memory_read(addr, (void *) &ret, 1); + return ret; +} + +void omap_badwidth_write8(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + uint8_t val8 = value; + + OMAP_8B_REG(addr); + cpu_physical_memory_write(addr, (void *) &val8, 1); +} + +uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr) +{ + uint16_t ret; + + OMAP_16B_REG(addr); + cpu_physical_memory_read(addr, (void *) &ret, 2); + return ret; +} + +void omap_badwidth_write16(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + uint16_t val16 = value; + + OMAP_16B_REG(addr); + cpu_physical_memory_write(addr, (void *) &val16, 2); +} + +uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr) +{ + uint32_t ret; + + OMAP_32B_REG(addr); + cpu_physical_memory_read(addr, (void *) &ret, 4); + return ret; +} + +void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + OMAP_32B_REG(addr); + cpu_physical_memory_write(addr, (void *) &value, 4); +} + +/* Interrupt Handlers */ +struct omap_intr_handler_bank_s { + uint32_t irqs; + uint32_t inputs; + uint32_t mask; + uint32_t fiq; + uint32_t sens_edge; + uint32_t swi; + unsigned char priority[32]; +}; + +struct omap_intr_handler_s { + qemu_irq *pins; + qemu_irq parent_intr[2]; + target_phys_addr_t base; + unsigned char nbanks; + int level_only; + + /* state */ + uint32_t new_agr[2]; + int sir_intr[2]; + int autoidle; + uint32_t mask; + struct omap_intr_handler_bank_s bank[]; +}; + +static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq) +{ + int i, j, sir_intr, p_intr, p, f; + uint32_t level; + sir_intr = 0; + p_intr = 255; + + /* Find the interrupt line with the highest dynamic priority. + * Note: 0 denotes the hightest priority. + * If all interrupts have the same priority, the default order is IRQ_N, + * IRQ_N-1,...,IRQ_0. */ + for (j = 0; j < s->nbanks; ++j) { + level = s->bank[j].irqs & ~s->bank[j].mask & + (is_fiq ? s->bank[j].fiq : ~s->bank[j].fiq); + for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f, + level >>= f) { + p = s->bank[j].priority[i]; + if (p <= p_intr) { + p_intr = p; + sir_intr = 32 * j + i; + } + f = ffs(level >> 1); + } + } + s->sir_intr[is_fiq] = sir_intr; +} + +static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq) +{ + int i; + uint32_t has_intr = 0; + + for (i = 0; i < s->nbanks; ++i) + has_intr |= s->bank[i].irqs & ~s->bank[i].mask & + (is_fiq ? s->bank[i].fiq : ~s->bank[i].fiq); + + if (s->new_agr[is_fiq] & has_intr & s->mask) { + s->new_agr[is_fiq] = 0; + omap_inth_sir_update(s, is_fiq); + qemu_set_irq(s->parent_intr[is_fiq], 1); + } +} + +#define INT_FALLING_EDGE 0 +#define INT_LOW_LEVEL 1 + +static void omap_set_intr(void *opaque, int irq, int req) +{ + struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque; + uint32_t rise; + + struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5]; + int n = irq & 31; + + if (req) { + rise = ~bank->irqs & (1 << n); + if (~bank->sens_edge & (1 << n)) + rise &= ~bank->inputs; + + bank->inputs |= (1 << n); + if (rise) { + bank->irqs |= rise; + omap_inth_update(ih, 0); + omap_inth_update(ih, 1); + } + } else { + rise = bank->sens_edge & bank->irqs & (1 << n); + bank->irqs &= ~rise; + bank->inputs &= ~(1 << n); + } +} + +/* Simplified version with no edge detection */ +static void omap_set_intr_noedge(void *opaque, int irq, int req) +{ + struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque; + uint32_t rise; + + struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5]; + int n = irq & 31; + + if (req) { + rise = ~bank->inputs & (1 << n); + if (rise) { + bank->irqs |= bank->inputs |= rise; + omap_inth_update(ih, 0); + omap_inth_update(ih, 1); + } + } else + bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi; +} + +static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; + int i, offset = addr - s->base; + int bank_no = offset >> 8; + int line_no; + struct omap_intr_handler_bank_s *bank = &s->bank[bank_no]; + offset &= 0xff; + + switch (offset) { + case 0x00: /* ITR */ + return bank->irqs; + + case 0x04: /* MIR */ + return bank->mask; + + case 0x10: /* SIR_IRQ_CODE */ + case 0x14: /* SIR_FIQ_CODE */ + if (bank_no != 0) + break; + line_no = s->sir_intr[(offset - 0x10) >> 2]; + bank = &s->bank[line_no >> 5]; + i = line_no & 31; + if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE) + bank->irqs &= ~(1 << i); + return line_no; + + case 0x18: /* CONTROL_REG */ + if (bank_no != 0) + break; + return 0; + + case 0x1c: /* ILR0 */ + case 0x20: /* ILR1 */ + case 0x24: /* ILR2 */ + case 0x28: /* ILR3 */ + case 0x2c: /* ILR4 */ + case 0x30: /* ILR5 */ + case 0x34: /* ILR6 */ + case 0x38: /* ILR7 */ + case 0x3c: /* ILR8 */ + case 0x40: /* ILR9 */ + case 0x44: /* ILR10 */ + case 0x48: /* ILR11 */ + case 0x4c: /* ILR12 */ + case 0x50: /* ILR13 */ + case 0x54: /* ILR14 */ + case 0x58: /* ILR15 */ + case 0x5c: /* ILR16 */ + case 0x60: /* ILR17 */ + case 0x64: /* ILR18 */ + case 0x68: /* ILR19 */ + case 0x6c: /* ILR20 */ + case 0x70: /* ILR21 */ + case 0x74: /* ILR22 */ + case 0x78: /* ILR23 */ + case 0x7c: /* ILR24 */ + case 0x80: /* ILR25 */ + case 0x84: /* ILR26 */ + case 0x88: /* ILR27 */ + case 0x8c: /* ILR28 */ + case 0x90: /* ILR29 */ + case 0x94: /* ILR30 */ + case 0x98: /* ILR31 */ + i = (offset - 0x1c) >> 2; + return (bank->priority[i] << 2) | + (((bank->sens_edge >> i) & 1) << 1) | + ((bank->fiq >> i) & 1); + + case 0x9c: /* ISR */ + return 0x00000000; + + } + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_inth_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; + int i, offset = addr - s->base; + int bank_no = offset >> 8; + struct omap_intr_handler_bank_s *bank = &s->bank[bank_no]; + offset &= 0xff; + + switch (offset) { + case 0x00: /* ITR */ + /* Important: ignore the clearing if the IRQ is level-triggered and + the input bit is 1 */ + bank->irqs &= value | (bank->inputs & bank->sens_edge); + return; + + case 0x04: /* MIR */ + bank->mask = value; + omap_inth_update(s, 0); + omap_inth_update(s, 1); + return; + + case 0x10: /* SIR_IRQ_CODE */ + case 0x14: /* SIR_FIQ_CODE */ + OMAP_RO_REG(addr); + break; + + case 0x18: /* CONTROL_REG */ + if (bank_no != 0) + break; + if (value & 2) { + qemu_set_irq(s->parent_intr[1], 0); + s->new_agr[1] = ~0; + omap_inth_update(s, 1); + } + if (value & 1) { + qemu_set_irq(s->parent_intr[0], 0); + s->new_agr[0] = ~0; + omap_inth_update(s, 0); + } + return; + + case 0x1c: /* ILR0 */ + case 0x20: /* ILR1 */ + case 0x24: /* ILR2 */ + case 0x28: /* ILR3 */ + case 0x2c: /* ILR4 */ + case 0x30: /* ILR5 */ + case 0x34: /* ILR6 */ + case 0x38: /* ILR7 */ + case 0x3c: /* ILR8 */ + case 0x40: /* ILR9 */ + case 0x44: /* ILR10 */ + case 0x48: /* ILR11 */ + case 0x4c: /* ILR12 */ + case 0x50: /* ILR13 */ + case 0x54: /* ILR14 */ + case 0x58: /* ILR15 */ + case 0x5c: /* ILR16 */ + case 0x60: /* ILR17 */ + case 0x64: /* ILR18 */ + case 0x68: /* ILR19 */ + case 0x6c: /* ILR20 */ + case 0x70: /* ILR21 */ + case 0x74: /* ILR22 */ + case 0x78: /* ILR23 */ + case 0x7c: /* ILR24 */ + case 0x80: /* ILR25 */ + case 0x84: /* ILR26 */ + case 0x88: /* ILR27 */ + case 0x8c: /* ILR28 */ + case 0x90: /* ILR29 */ + case 0x94: /* ILR30 */ + case 0x98: /* ILR31 */ + i = (offset - 0x1c) >> 2; + bank->priority[i] = (value >> 2) & 0x1f; + bank->sens_edge &= ~(1 << i); + bank->sens_edge |= ((value >> 1) & 1) << i; + bank->fiq &= ~(1 << i); + bank->fiq |= (value & 1) << i; + return; + + case 0x9c: /* ISR */ + for (i = 0; i < 32; i ++) + if (value & (1 << i)) { + omap_set_intr(s, 32 * bank_no + i, 1); + return; + } + return; + } + OMAP_BAD_REG(addr); +} + +static CPUReadMemoryFunc *omap_inth_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_inth_read, +}; + +static CPUWriteMemoryFunc *omap_inth_writefn[] = { + omap_inth_write, + omap_inth_write, + omap_inth_write, +}; + +void omap_inth_reset(struct omap_intr_handler_s *s) +{ + int i; + + for (i = 0; i < s->nbanks; ++i){ + s->bank[i].irqs = 0x00000000; + s->bank[i].mask = 0xffffffff; + s->bank[i].sens_edge = 0x00000000; + s->bank[i].fiq = 0x00000000; + s->bank[i].inputs = 0x00000000; + s->bank[i].swi = 0x00000000; + memset(s->bank[i].priority, 0, sizeof(s->bank[i].priority)); + + if (s->level_only) + s->bank[i].sens_edge = 0xffffffff; + } + + s->new_agr[0] = ~0; + s->new_agr[1] = ~0; + s->sir_intr[0] = 0; + s->sir_intr[1] = 0; + s->autoidle = 0; + s->mask = ~0; + + qemu_set_irq(s->parent_intr[0], 0); + qemu_set_irq(s->parent_intr[1], 0); +} + +struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base, + unsigned long size, unsigned char nbanks, qemu_irq **pins, + qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk) +{ + int iomemtype; + struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) + qemu_mallocz(sizeof(struct omap_intr_handler_s) + + sizeof(struct omap_intr_handler_bank_s) * nbanks); + + s->parent_intr[0] = parent_irq; + s->parent_intr[1] = parent_fiq; + s->base = base; + s->nbanks = nbanks; + s->pins = qemu_allocate_irqs(omap_set_intr, s, nbanks * 32); + if (pins) + *pins = s->pins; + + omap_inth_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_inth_readfn, + omap_inth_writefn, s); + cpu_register_physical_memory(s->base, size, iomemtype); + + return s; +} + +static uint32_t omap2_inth_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; + int offset = addr - s->base; + int bank_no, line_no; + struct omap_intr_handler_bank_s *bank = 0; + + if ((offset & 0xf80) == 0x80) { + bank_no = (offset & 0x60) >> 5; + if (bank_no < s->nbanks) { + offset &= ~0x60; + bank = &s->bank[bank_no]; + } + } + + switch (offset) { + case 0x00: /* INTC_REVISION */ + return 0x21; + + case 0x10: /* INTC_SYSCONFIG */ + return (s->autoidle >> 2) & 1; + + case 0x14: /* INTC_SYSSTATUS */ + return 1; /* RESETDONE */ + + case 0x40: /* INTC_SIR_IRQ */ + return s->sir_intr[0]; + + case 0x44: /* INTC_SIR_FIQ */ + return s->sir_intr[1]; + + case 0x48: /* INTC_CONTROL */ + return (!s->mask) << 2; /* GLOBALMASK */ + + case 0x4c: /* INTC_PROTECTION */ + return 0; + + case 0x50: /* INTC_IDLE */ + return s->autoidle & 3; + + /* Per-bank registers */ + case 0x80: /* INTC_ITR */ + return bank->inputs; + + case 0x84: /* INTC_MIR */ + return bank->mask; + + case 0x88: /* INTC_MIR_CLEAR */ + case 0x8c: /* INTC_MIR_SET */ + return 0; + + case 0x90: /* INTC_ISR_SET */ + return bank->swi; + + case 0x94: /* INTC_ISR_CLEAR */ + return 0; + + case 0x98: /* INTC_PENDING_IRQ */ + return bank->irqs & ~bank->mask & ~bank->fiq; + + case 0x9c: /* INTC_PENDING_FIQ */ + return bank->irqs & ~bank->mask & bank->fiq; + + /* Per-line registers */ + case 0x100 ... 0x300: /* INTC_ILR */ + bank_no = (offset - 0x100) >> 7; + if (bank_no > s->nbanks) + break; + bank = &s->bank[bank_no]; + line_no = (offset & 0x7f) >> 2; + return (bank->priority[line_no] << 2) | + ((bank->fiq >> line_no) & 1); + } + OMAP_BAD_REG(addr); + return 0; +} + +static void omap2_inth_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; + int offset = addr - s->base; + int bank_no, line_no; + struct omap_intr_handler_bank_s *bank = 0; + + if ((offset & 0xf80) == 0x80) { + bank_no = (offset & 0x60) >> 5; + if (bank_no < s->nbanks) { + offset &= ~0x60; + bank = &s->bank[bank_no]; + } + } + + switch (offset) { + case 0x10: /* INTC_SYSCONFIG */ + s->autoidle &= 4; + s->autoidle |= (value & 1) << 2; + if (value & 2) /* SOFTRESET */ + omap_inth_reset(s); + return; + + case 0x48: /* INTC_CONTROL */ + s->mask = (value & 4) ? 0 : ~0; /* GLOBALMASK */ + if (value & 2) { /* NEWFIQAGR */ + qemu_set_irq(s->parent_intr[1], 0); + s->new_agr[1] = ~0; + omap_inth_update(s, 1); + } + if (value & 1) { /* NEWIRQAGR */ + qemu_set_irq(s->parent_intr[0], 0); + s->new_agr[0] = ~0; + omap_inth_update(s, 0); + } + return; + + case 0x4c: /* INTC_PROTECTION */ + /* TODO: Make a bitmap (or sizeof(char)map) of access privileges + * for every register, see Chapter 3 and 4 for privileged mode. */ + if (value & 1) + fprintf(stderr, "%s: protection mode enable attempt\n", + __FUNCTION__); + return; + + case 0x50: /* INTC_IDLE */ + s->autoidle &= ~3; + s->autoidle |= value & 3; + return; + + /* Per-bank registers */ + case 0x84: /* INTC_MIR */ + bank->mask = value; + omap_inth_update(s, 0); + omap_inth_update(s, 1); + return; + + case 0x88: /* INTC_MIR_CLEAR */ + bank->mask &= ~value; + omap_inth_update(s, 0); + omap_inth_update(s, 1); + return; + + case 0x8c: /* INTC_MIR_SET */ + bank->mask |= value; + return; + + case 0x90: /* INTC_ISR_SET */ + bank->irqs |= bank->swi |= value; + omap_inth_update(s, 0); + omap_inth_update(s, 1); + return; + + case 0x94: /* INTC_ISR_CLEAR */ + bank->swi &= ~value; + bank->irqs = bank->swi & bank->inputs; + return; + + /* Per-line registers */ + case 0x100 ... 0x300: /* INTC_ILR */ + bank_no = (offset - 0x100) >> 7; + if (bank_no > s->nbanks) + break; + bank = &s->bank[bank_no]; + line_no = (offset & 0x7f) >> 2; + bank->priority[line_no] = (value >> 2) & 0x3f; + bank->fiq &= ~(1 << line_no); + bank->fiq |= (value & 1) << line_no; + return; + + case 0x00: /* INTC_REVISION */ + case 0x14: /* INTC_SYSSTATUS */ + case 0x40: /* INTC_SIR_IRQ */ + case 0x44: /* INTC_SIR_FIQ */ + case 0x80: /* INTC_ITR */ + case 0x98: /* INTC_PENDING_IRQ */ + case 0x9c: /* INTC_PENDING_FIQ */ + OMAP_RO_REG(addr); + return; + } + OMAP_BAD_REG(addr); +} + +static CPUReadMemoryFunc *omap2_inth_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap2_inth_read, +}; + +static CPUWriteMemoryFunc *omap2_inth_writefn[] = { + omap2_inth_write, + omap2_inth_write, + omap2_inth_write, +}; + +struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base, + int size, int nbanks, qemu_irq **pins, + qemu_irq parent_irq, qemu_irq parent_fiq, + omap_clk fclk, omap_clk iclk) +{ + int iomemtype; + struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) + qemu_mallocz(sizeof(struct omap_intr_handler_s) + + sizeof(struct omap_intr_handler_bank_s) * nbanks); + + s->parent_intr[0] = parent_irq; + s->parent_intr[1] = parent_fiq; + s->base = base; + s->nbanks = nbanks; + s->level_only = 1; + s->pins = qemu_allocate_irqs(omap_set_intr_noedge, s, nbanks * 32); + if (pins) + *pins = s->pins; + + omap_inth_reset(s); + + iomemtype = cpu_register_io_memory(0, omap2_inth_readfn, + omap2_inth_writefn, s); + cpu_register_physical_memory(s->base, size, iomemtype); + + return s; +} + +/* MPU OS timers */ +struct omap_mpu_timer_s { + qemu_irq irq; + omap_clk clk; + target_phys_addr_t base; + uint32_t val; + int64_t time; + QEMUTimer *timer; + QEMUBH *tick; + int64_t rate; + int it_ena; + + int enable; + int ptv; + int ar; + int st; + uint32_t reset_val; +}; + +static inline uint32_t omap_timer_read(struct omap_mpu_timer_s *timer) +{ + uint64_t distance = qemu_get_clock(vm_clock) - timer->time; + + if (timer->st && timer->enable && timer->rate) + return timer->val - muldiv64(distance >> (timer->ptv + 1), + timer->rate, ticks_per_sec); + else + return timer->val; +} + +static inline void omap_timer_sync(struct omap_mpu_timer_s *timer) +{ + timer->val = omap_timer_read(timer); + timer->time = qemu_get_clock(vm_clock); +} + +static inline void omap_timer_update(struct omap_mpu_timer_s *timer) +{ + int64_t expires; + + if (timer->enable && timer->st && timer->rate) { + timer->val = timer->reset_val; /* Should skip this on clk enable */ + expires = muldiv64((uint64_t) timer->val << (timer->ptv + 1), + ticks_per_sec, timer->rate); + + /* If timer expiry would be sooner than in about 1 ms and + * auto-reload isn't set, then fire immediately. This is a hack + * to make systems like PalmOS run in acceptable time. PalmOS + * sets the interval to a very low value and polls the status bit + * in a busy loop when it wants to sleep just a couple of CPU + * ticks. */ + if (expires > (ticks_per_sec >> 10) || timer->ar) + qemu_mod_timer(timer->timer, timer->time + expires); + else + qemu_bh_schedule(timer->tick); + } else + qemu_del_timer(timer->timer); +} + +static void omap_timer_fire(void *opaque) +{ + struct omap_mpu_timer_s *timer = opaque; + + if (!timer->ar) { + timer->val = 0; + timer->st = 0; + } + + if (timer->it_ena) + /* Edge-triggered irq */ + qemu_irq_pulse(timer->irq); +} + +static void omap_timer_tick(void *opaque) +{ + struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque; + + omap_timer_sync(timer); + omap_timer_fire(timer); + omap_timer_update(timer); +} + +static void omap_timer_clk_update(void *opaque, int line, int on) +{ + struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque; + + omap_timer_sync(timer); + timer->rate = on ? omap_clk_getrate(timer->clk) : 0; + omap_timer_update(timer); +} + +static void omap_timer_clk_setup(struct omap_mpu_timer_s *timer) +{ + omap_clk_adduser(timer->clk, + qemu_allocate_irqs(omap_timer_clk_update, timer, 1)[0]); + timer->rate = omap_clk_getrate(timer->clk); +} + +static uint32_t omap_mpu_timer_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* CNTL_TIMER */ + return (s->enable << 5) | (s->ptv << 2) | (s->ar << 1) | s->st; + + case 0x04: /* LOAD_TIM */ + break; + + case 0x08: /* READ_TIM */ + return omap_timer_read(s); + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_mpu_timer_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* CNTL_TIMER */ + omap_timer_sync(s); + s->enable = (value >> 5) & 1; + s->ptv = (value >> 2) & 7; + s->ar = (value >> 1) & 1; + s->st = value & 1; + omap_timer_update(s); + return; + + case 0x04: /* LOAD_TIM */ + s->reset_val = value; + return; + + case 0x08: /* READ_TIM */ + OMAP_RO_REG(addr); + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_mpu_timer_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_mpu_timer_read, +}; + +static CPUWriteMemoryFunc *omap_mpu_timer_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_mpu_timer_write, +}; + +static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s) +{ + qemu_del_timer(s->timer); + s->enable = 0; + s->reset_val = 31337; + s->val = 0; + s->ptv = 0; + s->ar = 0; + s->st = 0; + s->it_ena = 1; +} + +struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base, + qemu_irq irq, omap_clk clk) +{ + int iomemtype; + struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) + qemu_mallocz(sizeof(struct omap_mpu_timer_s)); + + s->irq = irq; + s->clk = clk; + s->base = base; + s->timer = qemu_new_timer(vm_clock, omap_timer_tick, s); + s->tick = qemu_bh_new(omap_timer_fire, s); + omap_mpu_timer_reset(s); + omap_timer_clk_setup(s); + + iomemtype = cpu_register_io_memory(0, omap_mpu_timer_readfn, + omap_mpu_timer_writefn, s); + cpu_register_physical_memory(s->base, 0x100, iomemtype); + + return s; +} + +/* Watchdog timer */ +struct omap_watchdog_timer_s { + struct omap_mpu_timer_s timer; + uint8_t last_wr; + int mode; + int free; + int reset; +}; + +static uint32_t omap_wd_timer_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; + int offset = addr - s->timer.base; + + switch (offset) { + case 0x00: /* CNTL_TIMER */ + return (s->timer.ptv << 9) | (s->timer.ar << 8) | + (s->timer.st << 7) | (s->free << 1); + + case 0x04: /* READ_TIMER */ + return omap_timer_read(&s->timer); + + case 0x08: /* TIMER_MODE */ + return s->mode << 15; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_wd_timer_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; + int offset = addr - s->timer.base; + + switch (offset) { + case 0x00: /* CNTL_TIMER */ + omap_timer_sync(&s->timer); + s->timer.ptv = (value >> 9) & 7; + s->timer.ar = (value >> 8) & 1; + s->timer.st = (value >> 7) & 1; + s->free = (value >> 1) & 1; + omap_timer_update(&s->timer); + break; + + case 0x04: /* LOAD_TIMER */ + s->timer.reset_val = value & 0xffff; + break; + + case 0x08: /* TIMER_MODE */ + if (!s->mode && ((value >> 15) & 1)) + omap_clk_get(s->timer.clk); + s->mode |= (value >> 15) & 1; + if (s->last_wr == 0xf5) { + if ((value & 0xff) == 0xa0) { + if (s->mode) { + s->mode = 0; + omap_clk_put(s->timer.clk); + } + } else { + /* XXX: on T|E hardware somehow this has no effect, + * on Zire 71 it works as specified. */ + s->reset = 1; + qemu_system_reset_request(); + } + } + s->last_wr = value & 0xff; + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_wd_timer_readfn[] = { + omap_badwidth_read16, + omap_wd_timer_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_wd_timer_writefn[] = { + omap_badwidth_write16, + omap_wd_timer_write, + omap_badwidth_write16, +}; + +static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s) +{ + qemu_del_timer(s->timer.timer); + if (!s->mode) + omap_clk_get(s->timer.clk); + s->mode = 1; + s->free = 1; + s->reset = 0; + s->timer.enable = 1; + s->timer.it_ena = 1; + s->timer.reset_val = 0xffff; + s->timer.val = 0; + s->timer.st = 0; + s->timer.ptv = 0; + s->timer.ar = 0; + omap_timer_update(&s->timer); +} + +struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base, + qemu_irq irq, omap_clk clk) +{ + int iomemtype; + struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) + qemu_mallocz(sizeof(struct omap_watchdog_timer_s)); + + s->timer.irq = irq; + s->timer.clk = clk; + s->timer.base = base; + s->timer.timer = qemu_new_timer(vm_clock, omap_timer_tick, &s->timer); + omap_wd_timer_reset(s); + omap_timer_clk_setup(&s->timer); + + iomemtype = cpu_register_io_memory(0, omap_wd_timer_readfn, + omap_wd_timer_writefn, s); + cpu_register_physical_memory(s->timer.base, 0x100, iomemtype); + + return s; +} + +/* 32-kHz timer */ +struct omap_32khz_timer_s { + struct omap_mpu_timer_s timer; +}; + +static uint32_t omap_os_timer_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + switch (offset) { + case 0x00: /* TVR */ + return s->timer.reset_val; + + case 0x04: /* TCR */ + return omap_timer_read(&s->timer); + + case 0x08: /* CR */ + return (s->timer.ar << 3) | (s->timer.it_ena << 2) | s->timer.st; + + default: + break; + } + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_os_timer_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + switch (offset) { + case 0x00: /* TVR */ + s->timer.reset_val = value & 0x00ffffff; + break; + + case 0x04: /* TCR */ + OMAP_RO_REG(addr); + break; + + case 0x08: /* CR */ + s->timer.ar = (value >> 3) & 1; + s->timer.it_ena = (value >> 2) & 1; + if (s->timer.st != (value & 1) || (value & 2)) { + omap_timer_sync(&s->timer); + s->timer.enable = value & 1; + s->timer.st = value & 1; + omap_timer_update(&s->timer); + } + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_os_timer_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_os_timer_read, +}; + +static CPUWriteMemoryFunc *omap_os_timer_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_os_timer_write, +}; + +static void omap_os_timer_reset(struct omap_32khz_timer_s *s) +{ + qemu_del_timer(s->timer.timer); + s->timer.enable = 0; + s->timer.it_ena = 0; + s->timer.reset_val = 0x00ffffff; + s->timer.val = 0; + s->timer.st = 0; + s->timer.ptv = 0; + s->timer.ar = 1; +} + +struct omap_32khz_timer_s *omap_os_timer_init(target_phys_addr_t base, + qemu_irq irq, omap_clk clk) +{ + int iomemtype; + struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) + qemu_mallocz(sizeof(struct omap_32khz_timer_s)); + + s->timer.irq = irq; + s->timer.clk = clk; + s->timer.base = base; + s->timer.timer = qemu_new_timer(vm_clock, omap_timer_tick, &s->timer); + omap_os_timer_reset(s); + omap_timer_clk_setup(&s->timer); + + iomemtype = cpu_register_io_memory(0, omap_os_timer_readfn, + omap_os_timer_writefn, s); + cpu_register_physical_memory(s->timer.base, 0x800, iomemtype); + + return s; +} + +/* Ultra Low-Power Device Module */ +static uint32_t omap_ulpd_pm_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->ulpd_pm_base; + uint16_t ret; + + switch (offset) { + case 0x14: /* IT_STATUS */ + ret = s->ulpd_pm_regs[offset >> 2]; + s->ulpd_pm_regs[offset >> 2] = 0; + qemu_irq_lower(s->irq[1][OMAP_INT_GAUGE_32K]); + return ret; + + case 0x18: /* Reserved */ + case 0x1c: /* Reserved */ + case 0x20: /* Reserved */ + case 0x28: /* Reserved */ + case 0x2c: /* Reserved */ + OMAP_BAD_REG(addr); + case 0x00: /* COUNTER_32_LSB */ + case 0x04: /* COUNTER_32_MSB */ + case 0x08: /* COUNTER_HIGH_FREQ_LSB */ + case 0x0c: /* COUNTER_HIGH_FREQ_MSB */ + case 0x10: /* GAUGING_CTRL */ + case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ + case 0x30: /* CLOCK_CTRL */ + case 0x34: /* SOFT_REQ */ + case 0x38: /* COUNTER_32_FIQ */ + case 0x3c: /* DPLL_CTRL */ + case 0x40: /* STATUS_REQ */ + /* XXX: check clk::usecount state for every clock */ + case 0x48: /* LOCL_TIME */ + case 0x4c: /* APLL_CTRL */ + case 0x50: /* POWER_CTRL */ + return s->ulpd_pm_regs[offset >> 2]; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static inline void omap_ulpd_clk_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + if (diff & (1 << 4)) /* USB_MCLK_EN */ + omap_clk_onoff(omap_findclk(s, "usb_clk0"), (value >> 4) & 1); + if (diff & (1 << 5)) /* DIS_USB_PVCI_CLK */ + omap_clk_onoff(omap_findclk(s, "usb_w2fc_ck"), (~value >> 5) & 1); +} + +static inline void omap_ulpd_req_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + if (diff & (1 << 0)) /* SOFT_DPLL_REQ */ + omap_clk_canidle(omap_findclk(s, "dpll4"), (~value >> 0) & 1); + if (diff & (1 << 1)) /* SOFT_COM_REQ */ + omap_clk_canidle(omap_findclk(s, "com_mclk_out"), (~value >> 1) & 1); + if (diff & (1 << 2)) /* SOFT_SDW_REQ */ + omap_clk_canidle(omap_findclk(s, "bt_mclk_out"), (~value >> 2) & 1); + if (diff & (1 << 3)) /* SOFT_USB_REQ */ + omap_clk_canidle(omap_findclk(s, "usb_clk0"), (~value >> 3) & 1); +} + +static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->ulpd_pm_base; + int64_t now, ticks; + int div, mult; + static const int bypass_div[4] = { 1, 2, 4, 4 }; + uint16_t diff; + + switch (offset) { + case 0x00: /* COUNTER_32_LSB */ + case 0x04: /* COUNTER_32_MSB */ + case 0x08: /* COUNTER_HIGH_FREQ_LSB */ + case 0x0c: /* COUNTER_HIGH_FREQ_MSB */ + case 0x14: /* IT_STATUS */ + case 0x40: /* STATUS_REQ */ + OMAP_RO_REG(addr); + break; + + case 0x10: /* GAUGING_CTRL */ + /* Bits 0 and 1 seem to be confused in the OMAP 310 TRM */ + if ((s->ulpd_pm_regs[offset >> 2] ^ value) & 1) { + now = qemu_get_clock(vm_clock); + + if (value & 1) + s->ulpd_gauge_start = now; + else { + now -= s->ulpd_gauge_start; + + /* 32-kHz ticks */ + ticks = muldiv64(now, 32768, ticks_per_sec); + s->ulpd_pm_regs[0x00 >> 2] = (ticks >> 0) & 0xffff; + s->ulpd_pm_regs[0x04 >> 2] = (ticks >> 16) & 0xffff; + if (ticks >> 32) /* OVERFLOW_32K */ + s->ulpd_pm_regs[0x14 >> 2] |= 1 << 2; + + /* High frequency ticks */ + ticks = muldiv64(now, 12000000, ticks_per_sec); + s->ulpd_pm_regs[0x08 >> 2] = (ticks >> 0) & 0xffff; + s->ulpd_pm_regs[0x0c >> 2] = (ticks >> 16) & 0xffff; + if (ticks >> 32) /* OVERFLOW_HI_FREQ */ + s->ulpd_pm_regs[0x14 >> 2] |= 1 << 1; + + s->ulpd_pm_regs[0x14 >> 2] |= 1 << 0; /* IT_GAUGING */ + qemu_irq_raise(s->irq[1][OMAP_INT_GAUGE_32K]); + } + } + s->ulpd_pm_regs[offset >> 2] = value; + break; + + case 0x18: /* Reserved */ + case 0x1c: /* Reserved */ + case 0x20: /* Reserved */ + case 0x28: /* Reserved */ + case 0x2c: /* Reserved */ + OMAP_BAD_REG(addr); + case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ + case 0x38: /* COUNTER_32_FIQ */ + case 0x48: /* LOCL_TIME */ + case 0x50: /* POWER_CTRL */ + s->ulpd_pm_regs[offset >> 2] = value; + break; + + case 0x30: /* CLOCK_CTRL */ + diff = s->ulpd_pm_regs[offset >> 2] ^ value; + s->ulpd_pm_regs[offset >> 2] = value & 0x3f; + omap_ulpd_clk_update(s, diff, value); + break; + + case 0x34: /* SOFT_REQ */ + diff = s->ulpd_pm_regs[offset >> 2] ^ value; + s->ulpd_pm_regs[offset >> 2] = value & 0x1f; + omap_ulpd_req_update(s, diff, value); + break; + + case 0x3c: /* DPLL_CTRL */ + /* XXX: OMAP310 TRM claims bit 3 is PLL_ENABLE, and bit 4 is + * omitted altogether, probably a typo. */ + /* This register has identical semantics with DPLL(1:3) control + * registers, see omap_dpll_write() */ + diff = s->ulpd_pm_regs[offset >> 2] & value; + s->ulpd_pm_regs[offset >> 2] = value & 0x2fff; + if (diff & (0x3ff << 2)) { + if (value & (1 << 4)) { /* PLL_ENABLE */ + div = ((value >> 5) & 3) + 1; /* PLL_DIV */ + mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */ + } else { + div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */ + mult = 1; + } + omap_clk_setrate(omap_findclk(s, "dpll4"), div, mult); + } + + /* Enter the desired mode. */ + s->ulpd_pm_regs[offset >> 2] = + (s->ulpd_pm_regs[offset >> 2] & 0xfffe) | + ((s->ulpd_pm_regs[offset >> 2] >> 4) & 1); + + /* Act as if the lock is restored. */ + s->ulpd_pm_regs[offset >> 2] |= 2; + break; + + case 0x4c: /* APLL_CTRL */ + diff = s->ulpd_pm_regs[offset >> 2] & value; + s->ulpd_pm_regs[offset >> 2] = value & 0xf; + if (diff & (1 << 0)) /* APLL_NDPLL_SWITCH */ + omap_clk_reparent(omap_findclk(s, "ck_48m"), omap_findclk(s, + (value & (1 << 0)) ? "apll" : "dpll4")); + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_ulpd_pm_readfn[] = { + omap_badwidth_read16, + omap_ulpd_pm_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_ulpd_pm_writefn[] = { + omap_badwidth_write16, + omap_ulpd_pm_write, + omap_badwidth_write16, +}; + +static void omap_ulpd_pm_reset(struct omap_mpu_state_s *mpu) +{ + mpu->ulpd_pm_regs[0x00 >> 2] = 0x0001; + mpu->ulpd_pm_regs[0x04 >> 2] = 0x0000; + mpu->ulpd_pm_regs[0x08 >> 2] = 0x0001; + mpu->ulpd_pm_regs[0x0c >> 2] = 0x0000; + mpu->ulpd_pm_regs[0x10 >> 2] = 0x0000; + mpu->ulpd_pm_regs[0x18 >> 2] = 0x01; + mpu->ulpd_pm_regs[0x1c >> 2] = 0x01; + mpu->ulpd_pm_regs[0x20 >> 2] = 0x01; + mpu->ulpd_pm_regs[0x24 >> 2] = 0x03ff; + mpu->ulpd_pm_regs[0x28 >> 2] = 0x01; + mpu->ulpd_pm_regs[0x2c >> 2] = 0x01; + omap_ulpd_clk_update(mpu, mpu->ulpd_pm_regs[0x30 >> 2], 0x0000); + mpu->ulpd_pm_regs[0x30 >> 2] = 0x0000; + omap_ulpd_req_update(mpu, mpu->ulpd_pm_regs[0x34 >> 2], 0x0000); + mpu->ulpd_pm_regs[0x34 >> 2] = 0x0000; + mpu->ulpd_pm_regs[0x38 >> 2] = 0x0001; + mpu->ulpd_pm_regs[0x3c >> 2] = 0x2211; + mpu->ulpd_pm_regs[0x40 >> 2] = 0x0000; /* FIXME: dump a real STATUS_REQ */ + mpu->ulpd_pm_regs[0x48 >> 2] = 0x960; + mpu->ulpd_pm_regs[0x4c >> 2] = 0x08; + mpu->ulpd_pm_regs[0x50 >> 2] = 0x08; + omap_clk_setrate(omap_findclk(mpu, "dpll4"), 1, 4); + omap_clk_reparent(omap_findclk(mpu, "ck_48m"), omap_findclk(mpu, "dpll4")); +} + +static void omap_ulpd_pm_init(target_phys_addr_t base, + struct omap_mpu_state_s *mpu) +{ + int iomemtype = cpu_register_io_memory(0, omap_ulpd_pm_readfn, + omap_ulpd_pm_writefn, mpu); + + mpu->ulpd_pm_base = base; + cpu_register_physical_memory(mpu->ulpd_pm_base, 0x800, iomemtype); + omap_ulpd_pm_reset(mpu); +} + +/* OMAP Pin Configuration */ +static uint32_t omap_pin_cfg_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->pin_cfg_base; + + switch (offset) { + case 0x00: /* FUNC_MUX_CTRL_0 */ + case 0x04: /* FUNC_MUX_CTRL_1 */ + case 0x08: /* FUNC_MUX_CTRL_2 */ + return s->func_mux_ctrl[offset >> 2]; + + case 0x0c: /* COMP_MODE_CTRL_0 */ + return s->comp_mode_ctrl[0]; + + case 0x10: /* FUNC_MUX_CTRL_3 */ + case 0x14: /* FUNC_MUX_CTRL_4 */ + case 0x18: /* FUNC_MUX_CTRL_5 */ + case 0x1c: /* FUNC_MUX_CTRL_6 */ + case 0x20: /* FUNC_MUX_CTRL_7 */ + case 0x24: /* FUNC_MUX_CTRL_8 */ + case 0x28: /* FUNC_MUX_CTRL_9 */ + case 0x2c: /* FUNC_MUX_CTRL_A */ + case 0x30: /* FUNC_MUX_CTRL_B */ + case 0x34: /* FUNC_MUX_CTRL_C */ + case 0x38: /* FUNC_MUX_CTRL_D */ + return s->func_mux_ctrl[(offset >> 2) - 1]; + + case 0x40: /* PULL_DWN_CTRL_0 */ + case 0x44: /* PULL_DWN_CTRL_1 */ + case 0x48: /* PULL_DWN_CTRL_2 */ + case 0x4c: /* PULL_DWN_CTRL_3 */ + return s->pull_dwn_ctrl[(offset & 0xf) >> 2]; + + case 0x50: /* GATE_INH_CTRL_0 */ + return s->gate_inh_ctrl[0]; + + case 0x60: /* VOLTAGE_CTRL_0 */ + return s->voltage_ctrl[0]; + + case 0x70: /* TEST_DBG_CTRL_0 */ + return s->test_dbg_ctrl[0]; + + case 0x80: /* MOD_CONF_CTRL_0 */ + return s->mod_conf_ctrl[0]; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static inline void omap_pin_funcmux0_update(struct omap_mpu_state_s *s, + uint32_t diff, uint32_t value) +{ + if (s->compat1509) { + if (diff & (1 << 9)) /* BLUETOOTH */ + omap_clk_onoff(omap_findclk(s, "bt_mclk_out"), + (~value >> 9) & 1); + if (diff & (1 << 7)) /* USB.CLKO */ + omap_clk_onoff(omap_findclk(s, "usb.clko"), + (value >> 7) & 1); + } +} + +static inline void omap_pin_funcmux1_update(struct omap_mpu_state_s *s, + uint32_t diff, uint32_t value) +{ + if (s->compat1509) { + if (diff & (1 << 31)) /* MCBSP3_CLK_HIZ_DI */ + omap_clk_onoff(omap_findclk(s, "mcbsp3.clkx"), + (value >> 31) & 1); + if (diff & (1 << 1)) /* CLK32K */ + omap_clk_onoff(omap_findclk(s, "clk32k_out"), + (~value >> 1) & 1); + } +} + +static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s, + uint32_t diff, uint32_t value) +{ + if (diff & (1 << 31)) /* CONF_MOD_UART3_CLK_MODE_R */ + omap_clk_reparent(omap_findclk(s, "uart3_ck"), + omap_findclk(s, ((value >> 31) & 1) ? + "ck_48m" : "armper_ck")); + if (diff & (1 << 30)) /* CONF_MOD_UART2_CLK_MODE_R */ + omap_clk_reparent(omap_findclk(s, "uart2_ck"), + omap_findclk(s, ((value >> 30) & 1) ? + "ck_48m" : "armper_ck")); + if (diff & (1 << 29)) /* CONF_MOD_UART1_CLK_MODE_R */ + omap_clk_reparent(omap_findclk(s, "uart1_ck"), + omap_findclk(s, ((value >> 29) & 1) ? + "ck_48m" : "armper_ck")); + if (diff & (1 << 23)) /* CONF_MOD_MMC_SD_CLK_REQ_R */ + omap_clk_reparent(omap_findclk(s, "mmc_ck"), + omap_findclk(s, ((value >> 23) & 1) ? + "ck_48m" : "armper_ck")); + if (diff & (1 << 12)) /* CONF_MOD_COM_MCLK_12_48_S */ + omap_clk_reparent(omap_findclk(s, "com_mclk_out"), + omap_findclk(s, ((value >> 12) & 1) ? + "ck_48m" : "armper_ck")); + if (diff & (1 << 9)) /* CONF_MOD_USB_HOST_HHC_UHO */ + omap_clk_onoff(omap_findclk(s, "usb_hhc_ck"), (value >> 9) & 1); +} + +static void omap_pin_cfg_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->pin_cfg_base; + uint32_t diff; + + switch (offset) { + case 0x00: /* FUNC_MUX_CTRL_0 */ + diff = s->func_mux_ctrl[offset >> 2] ^ value; + s->func_mux_ctrl[offset >> 2] = value; + omap_pin_funcmux0_update(s, diff, value); + return; + + case 0x04: /* FUNC_MUX_CTRL_1 */ + diff = s->func_mux_ctrl[offset >> 2] ^ value; + s->func_mux_ctrl[offset >> 2] = value; + omap_pin_funcmux1_update(s, diff, value); + return; + + case 0x08: /* FUNC_MUX_CTRL_2 */ + s->func_mux_ctrl[offset >> 2] = value; + return; + + case 0x0c: /* COMP_MODE_CTRL_0 */ + s->comp_mode_ctrl[0] = value; + s->compat1509 = (value != 0x0000eaef); + omap_pin_funcmux0_update(s, ~0, s->func_mux_ctrl[0]); + omap_pin_funcmux1_update(s, ~0, s->func_mux_ctrl[1]); + return; + + case 0x10: /* FUNC_MUX_CTRL_3 */ + case 0x14: /* FUNC_MUX_CTRL_4 */ + case 0x18: /* FUNC_MUX_CTRL_5 */ + case 0x1c: /* FUNC_MUX_CTRL_6 */ + case 0x20: /* FUNC_MUX_CTRL_7 */ + case 0x24: /* FUNC_MUX_CTRL_8 */ + case 0x28: /* FUNC_MUX_CTRL_9 */ + case 0x2c: /* FUNC_MUX_CTRL_A */ + case 0x30: /* FUNC_MUX_CTRL_B */ + case 0x34: /* FUNC_MUX_CTRL_C */ + case 0x38: /* FUNC_MUX_CTRL_D */ + s->func_mux_ctrl[(offset >> 2) - 1] = value; + return; + + case 0x40: /* PULL_DWN_CTRL_0 */ + case 0x44: /* PULL_DWN_CTRL_1 */ + case 0x48: /* PULL_DWN_CTRL_2 */ + case 0x4c: /* PULL_DWN_CTRL_3 */ + s->pull_dwn_ctrl[(offset & 0xf) >> 2] = value; + return; + + case 0x50: /* GATE_INH_CTRL_0 */ + s->gate_inh_ctrl[0] = value; + return; + + case 0x60: /* VOLTAGE_CTRL_0 */ + s->voltage_ctrl[0] = value; + return; + + case 0x70: /* TEST_DBG_CTRL_0 */ + s->test_dbg_ctrl[0] = value; + return; + + case 0x80: /* MOD_CONF_CTRL_0 */ + diff = s->mod_conf_ctrl[0] ^ value; + s->mod_conf_ctrl[0] = value; + omap_pin_modconf1_update(s, diff, value); + return; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_pin_cfg_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_pin_cfg_read, +}; + +static CPUWriteMemoryFunc *omap_pin_cfg_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_pin_cfg_write, +}; + +static void omap_pin_cfg_reset(struct omap_mpu_state_s *mpu) +{ + /* Start in Compatibility Mode. */ + mpu->compat1509 = 1; + omap_pin_funcmux0_update(mpu, mpu->func_mux_ctrl[0], 0); + omap_pin_funcmux1_update(mpu, mpu->func_mux_ctrl[1], 0); + omap_pin_modconf1_update(mpu, mpu->mod_conf_ctrl[0], 0); + memset(mpu->func_mux_ctrl, 0, sizeof(mpu->func_mux_ctrl)); + memset(mpu->comp_mode_ctrl, 0, sizeof(mpu->comp_mode_ctrl)); + memset(mpu->pull_dwn_ctrl, 0, sizeof(mpu->pull_dwn_ctrl)); + memset(mpu->gate_inh_ctrl, 0, sizeof(mpu->gate_inh_ctrl)); + memset(mpu->voltage_ctrl, 0, sizeof(mpu->voltage_ctrl)); + memset(mpu->test_dbg_ctrl, 0, sizeof(mpu->test_dbg_ctrl)); + memset(mpu->mod_conf_ctrl, 0, sizeof(mpu->mod_conf_ctrl)); +} + +static void omap_pin_cfg_init(target_phys_addr_t base, + struct omap_mpu_state_s *mpu) +{ + int iomemtype = cpu_register_io_memory(0, omap_pin_cfg_readfn, + omap_pin_cfg_writefn, mpu); + + mpu->pin_cfg_base = base; + cpu_register_physical_memory(mpu->pin_cfg_base, 0x800, iomemtype); + omap_pin_cfg_reset(mpu); +} + +/* Device Identification, Die Identification */ +static uint32_t omap_id_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + + switch (addr) { + case 0xfffe1800: /* DIE_ID_LSB */ + return 0xc9581f0e; + case 0xfffe1804: /* DIE_ID_MSB */ + return 0xa8858bfa; + + case 0xfffe2000: /* PRODUCT_ID_LSB */ + return 0x00aaaafc; + case 0xfffe2004: /* PRODUCT_ID_MSB */ + return 0xcafeb574; + + case 0xfffed400: /* JTAG_ID_LSB */ + switch (s->mpu_model) { + case omap310: + return 0x03310315; + case omap1510: + return 0x03310115; + default: + cpu_abort(cpu_single_env, "%s: bad mpu model\n", __FUNCTION__); + } + break; + + case 0xfffed404: /* JTAG_ID_MSB */ + switch (s->mpu_model) { + case omap310: + return 0xfb57402f; + case omap1510: + return 0xfb47002f; + default: + cpu_abort(cpu_single_env, "%s: bad mpu model\n", __FUNCTION__); + } + break; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_id_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + OMAP_BAD_REG(addr); +} + +static CPUReadMemoryFunc *omap_id_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_id_read, +}; + +static CPUWriteMemoryFunc *omap_id_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_id_write, +}; + +static void omap_id_init(struct omap_mpu_state_s *mpu) +{ + int iomemtype = cpu_register_io_memory(0, omap_id_readfn, + omap_id_writefn, mpu); + cpu_register_physical_memory(0xfffe1800, 0x800, iomemtype); + cpu_register_physical_memory(0xfffed400, 0x100, iomemtype); + if (!cpu_is_omap15xx(mpu)) + cpu_register_physical_memory(0xfffe2000, 0x800, iomemtype); +} + +/* MPUI Control (Dummy) */ +static uint32_t omap_mpui_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->mpui_base; + + switch (offset) { + case 0x00: /* CTRL */ + return s->mpui_ctrl; + case 0x04: /* DEBUG_ADDR */ + return 0x01ffffff; + case 0x08: /* DEBUG_DATA */ + return 0xffffffff; + case 0x0c: /* DEBUG_FLAG */ + return 0x00000800; + case 0x10: /* STATUS */ + return 0x00000000; + + /* Not in OMAP310 */ + case 0x14: /* DSP_STATUS */ + case 0x18: /* DSP_BOOT_CONFIG */ + return 0x00000000; + case 0x1c: /* DSP_MPUI_CONFIG */ + return 0x0000ffff; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_mpui_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->mpui_base; + + switch (offset) { + case 0x00: /* CTRL */ + s->mpui_ctrl = value & 0x007fffff; + break; + + case 0x04: /* DEBUG_ADDR */ + case 0x08: /* DEBUG_DATA */ + case 0x0c: /* DEBUG_FLAG */ + case 0x10: /* STATUS */ + /* Not in OMAP310 */ + case 0x14: /* DSP_STATUS */ + OMAP_RO_REG(addr); + case 0x18: /* DSP_BOOT_CONFIG */ + case 0x1c: /* DSP_MPUI_CONFIG */ + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_mpui_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_mpui_read, +}; + +static CPUWriteMemoryFunc *omap_mpui_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_mpui_write, +}; + +static void omap_mpui_reset(struct omap_mpu_state_s *s) +{ + s->mpui_ctrl = 0x0003ff1b; +} + +static void omap_mpui_init(target_phys_addr_t base, + struct omap_mpu_state_s *mpu) +{ + int iomemtype = cpu_register_io_memory(0, omap_mpui_readfn, + omap_mpui_writefn, mpu); + + mpu->mpui_base = base; + cpu_register_physical_memory(mpu->mpui_base, 0x100, iomemtype); + + omap_mpui_reset(mpu); +} + +/* TIPB Bridges */ +struct omap_tipb_bridge_s { + target_phys_addr_t base; + qemu_irq abort; + + int width_intr; + uint16_t control; + uint16_t alloc; + uint16_t buffer; + uint16_t enh_control; +}; + +static uint32_t omap_tipb_bridge_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* TIPB_CNTL */ + return s->control; + case 0x04: /* TIPB_BUS_ALLOC */ + return s->alloc; + case 0x08: /* MPU_TIPB_CNTL */ + return s->buffer; + case 0x0c: /* ENHANCED_TIPB_CNTL */ + return s->enh_control; + case 0x10: /* ADDRESS_DBG */ + case 0x14: /* DATA_DEBUG_LOW */ + case 0x18: /* DATA_DEBUG_HIGH */ + return 0xffff; + case 0x1c: /* DEBUG_CNTR_SIG */ + return 0x00f8; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_tipb_bridge_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* TIPB_CNTL */ + s->control = value & 0xffff; + break; + + case 0x04: /* TIPB_BUS_ALLOC */ + s->alloc = value & 0x003f; + break; + + case 0x08: /* MPU_TIPB_CNTL */ + s->buffer = value & 0x0003; + break; + + case 0x0c: /* ENHANCED_TIPB_CNTL */ + s->width_intr = !(value & 2); + s->enh_control = value & 0x000f; + break; + + case 0x10: /* ADDRESS_DBG */ + case 0x14: /* DATA_DEBUG_LOW */ + case 0x18: /* DATA_DEBUG_HIGH */ + case 0x1c: /* DEBUG_CNTR_SIG */ + OMAP_RO_REG(addr); + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_tipb_bridge_readfn[] = { + omap_badwidth_read16, + omap_tipb_bridge_read, + omap_tipb_bridge_read, +}; + +static CPUWriteMemoryFunc *omap_tipb_bridge_writefn[] = { + omap_badwidth_write16, + omap_tipb_bridge_write, + omap_tipb_bridge_write, +}; + +static void omap_tipb_bridge_reset(struct omap_tipb_bridge_s *s) +{ + s->control = 0xffff; + s->alloc = 0x0009; + s->buffer = 0x0000; + s->enh_control = 0x000f; +} + +struct omap_tipb_bridge_s *omap_tipb_bridge_init(target_phys_addr_t base, + qemu_irq abort_irq, omap_clk clk) +{ + int iomemtype; + struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) + qemu_mallocz(sizeof(struct omap_tipb_bridge_s)); + + s->abort = abort_irq; + s->base = base; + omap_tipb_bridge_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_tipb_bridge_readfn, + omap_tipb_bridge_writefn, s); + cpu_register_physical_memory(s->base, 0x100, iomemtype); + + return s; +} + +/* Dummy Traffic Controller's Memory Interface */ +static uint32_t omap_tcmi_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->tcmi_base; + uint32_t ret; + + switch (offset) { + case 0x00: /* IMIF_PRIO */ + case 0x04: /* EMIFS_PRIO */ + case 0x08: /* EMIFF_PRIO */ + case 0x0c: /* EMIFS_CONFIG */ + case 0x10: /* EMIFS_CS0_CONFIG */ + case 0x14: /* EMIFS_CS1_CONFIG */ + case 0x18: /* EMIFS_CS2_CONFIG */ + case 0x1c: /* EMIFS_CS3_CONFIG */ + case 0x24: /* EMIFF_MRS */ + case 0x28: /* TIMEOUT1 */ + case 0x2c: /* TIMEOUT2 */ + case 0x30: /* TIMEOUT3 */ + case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */ + case 0x40: /* EMIFS_CFG_DYN_WAIT */ + return s->tcmi_regs[offset >> 2]; + + case 0x20: /* EMIFF_SDRAM_CONFIG */ + ret = s->tcmi_regs[offset >> 2]; + s->tcmi_regs[offset >> 2] &= ~1; /* XXX: Clear SLRF on SDRAM access */ + /* XXX: We can try using the VGA_DIRTY flag for this */ + return ret; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_tcmi_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->tcmi_base; + + switch (offset) { + case 0x00: /* IMIF_PRIO */ + case 0x04: /* EMIFS_PRIO */ + case 0x08: /* EMIFF_PRIO */ + case 0x10: /* EMIFS_CS0_CONFIG */ + case 0x14: /* EMIFS_CS1_CONFIG */ + case 0x18: /* EMIFS_CS2_CONFIG */ + case 0x1c: /* EMIFS_CS3_CONFIG */ + case 0x20: /* EMIFF_SDRAM_CONFIG */ + case 0x24: /* EMIFF_MRS */ + case 0x28: /* TIMEOUT1 */ + case 0x2c: /* TIMEOUT2 */ + case 0x30: /* TIMEOUT3 */ + case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */ + case 0x40: /* EMIFS_CFG_DYN_WAIT */ + s->tcmi_regs[offset >> 2] = value; + break; + case 0x0c: /* EMIFS_CONFIG */ + s->tcmi_regs[offset >> 2] = (value & 0xf) | (1 << 4); + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_tcmi_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_tcmi_read, +}; + +static CPUWriteMemoryFunc *omap_tcmi_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_tcmi_write, +}; + +static void omap_tcmi_reset(struct omap_mpu_state_s *mpu) +{ + mpu->tcmi_regs[0x00 >> 2] = 0x00000000; + mpu->tcmi_regs[0x04 >> 2] = 0x00000000; + mpu->tcmi_regs[0x08 >> 2] = 0x00000000; + mpu->tcmi_regs[0x0c >> 2] = 0x00000010; + mpu->tcmi_regs[0x10 >> 2] = 0x0010fffb; + mpu->tcmi_regs[0x14 >> 2] = 0x0010fffb; + mpu->tcmi_regs[0x18 >> 2] = 0x0010fffb; + mpu->tcmi_regs[0x1c >> 2] = 0x0010fffb; + mpu->tcmi_regs[0x20 >> 2] = 0x00618800; + mpu->tcmi_regs[0x24 >> 2] = 0x00000037; + mpu->tcmi_regs[0x28 >> 2] = 0x00000000; + mpu->tcmi_regs[0x2c >> 2] = 0x00000000; + mpu->tcmi_regs[0x30 >> 2] = 0x00000000; + mpu->tcmi_regs[0x3c >> 2] = 0x00000003; + mpu->tcmi_regs[0x40 >> 2] = 0x00000000; +} + +static void omap_tcmi_init(target_phys_addr_t base, + struct omap_mpu_state_s *mpu) +{ + int iomemtype = cpu_register_io_memory(0, omap_tcmi_readfn, + omap_tcmi_writefn, mpu); + + mpu->tcmi_base = base; + cpu_register_physical_memory(mpu->tcmi_base, 0x100, iomemtype); + omap_tcmi_reset(mpu); +} + +/* Digital phase-locked loops control */ +static uint32_t omap_dpll_read(void *opaque, target_phys_addr_t addr) +{ + struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque; + int offset = addr - s->base; + + if (offset == 0x00) /* CTL_REG */ + return s->mode; + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_dpll_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque; + uint16_t diff; + int offset = addr - s->base; + static const int bypass_div[4] = { 1, 2, 4, 4 }; + int div, mult; + + if (offset == 0x00) { /* CTL_REG */ + /* See omap_ulpd_pm_write() too */ + diff = s->mode & value; + s->mode = value & 0x2fff; + if (diff & (0x3ff << 2)) { + if (value & (1 << 4)) { /* PLL_ENABLE */ + div = ((value >> 5) & 3) + 1; /* PLL_DIV */ + mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */ + } else { + div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */ + mult = 1; + } + omap_clk_setrate(s->dpll, div, mult); + } + + /* Enter the desired mode. */ + s->mode = (s->mode & 0xfffe) | ((s->mode >> 4) & 1); + + /* Act as if the lock is restored. */ + s->mode |= 2; + } else { + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_dpll_readfn[] = { + omap_badwidth_read16, + omap_dpll_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_dpll_writefn[] = { + omap_badwidth_write16, + omap_dpll_write, + omap_badwidth_write16, +}; + +static void omap_dpll_reset(struct dpll_ctl_s *s) +{ + s->mode = 0x2002; + omap_clk_setrate(s->dpll, 1, 1); +} + +static void omap_dpll_init(struct dpll_ctl_s *s, target_phys_addr_t base, + omap_clk clk) +{ + int iomemtype = cpu_register_io_memory(0, omap_dpll_readfn, + omap_dpll_writefn, s); + + s->base = base; + s->dpll = clk; + omap_dpll_reset(s); + + cpu_register_physical_memory(s->base, 0x100, iomemtype); +} + +/* UARTs */ +struct omap_uart_s { + SerialState *serial; /* TODO */ + struct omap_target_agent_s *ta; + target_phys_addr_t base; + omap_clk fclk; + qemu_irq irq; + + uint8_t eblr; + uint8_t syscontrol; + uint8_t wkup; + uint8_t cfps; + uint8_t mdr[2]; + uint8_t scr; +}; + +void omap_uart_reset(struct omap_uart_s *s) +{ + s->eblr = 0x00; + s->syscontrol = 0; + s->wkup = 0x3f; + s->cfps = 0x69; +} + +struct omap_uart_s *omap_uart_init(target_phys_addr_t base, + qemu_irq irq, omap_clk fclk, omap_clk iclk, + qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr) +{ + struct omap_uart_s *s = (struct omap_uart_s *) + qemu_mallocz(sizeof(struct omap_uart_s)); + + s->base = base; + s->fclk = fclk; + s->irq = irq; + s->serial = serial_mm_init(base, 2, irq, omap_clk_getrate(fclk)/16, + chr ?: qemu_chr_open("null", "null"), 1); + + return s; +} + +static uint32_t omap_uart_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_uart_s *s = (struct omap_uart_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x20: /* MDR1 */ + return s->mdr[0]; + case 0x24: /* MDR2 */ + return s->mdr[1]; + case 0x40: /* SCR */ + return s->scr; + case 0x44: /* SSR */ + return 0x0; + case 0x48: /* EBLR */ + return s->eblr; + case 0x50: /* MVR */ + return 0x30; + case 0x54: /* SYSC */ + return s->syscontrol; + case 0x58: /* SYSS */ + return 1; + case 0x5c: /* WER */ + return s->wkup; + case 0x60: /* CFPS */ + return s->cfps; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_uart_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_uart_s *s = (struct omap_uart_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x20: /* MDR1 */ + s->mdr[0] = value & 0x7f; + break; + case 0x24: /* MDR2 */ + s->mdr[1] = value & 0xff; + break; + case 0x40: /* SCR */ + s->scr = value & 0xff; + break; + case 0x48: /* EBLR */ + s->eblr = value & 0xff; + break; + case 0x44: /* SSR */ + case 0x50: /* MVR */ + case 0x58: /* SYSS */ + OMAP_RO_REG(addr); + break; + case 0x54: /* SYSC */ + s->syscontrol = value & 0x1d; + if (value & 2) + omap_uart_reset(s); + break; + case 0x5c: /* WER */ + s->wkup = value & 0x7f; + break; + case 0x60: /* CFPS */ + s->cfps = value & 0xff; + break; + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_uart_readfn[] = { + omap_uart_read, + omap_uart_read, + omap_badwidth_read8, +}; + +static CPUWriteMemoryFunc *omap_uart_writefn[] = { + omap_uart_write, + omap_uart_write, + omap_badwidth_write8, +}; + +struct omap_uart_s *omap2_uart_init(struct omap_target_agent_s *ta, + qemu_irq irq, omap_clk fclk, omap_clk iclk, + qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr) +{ + target_phys_addr_t base = omap_l4_attach(ta, 0, 0); + struct omap_uart_s *s = omap_uart_init(base, irq, + fclk, iclk, txdma, rxdma, chr); + int iomemtype = cpu_register_io_memory(0, omap_uart_readfn, + omap_uart_writefn, s); + + s->ta = ta; + + cpu_register_physical_memory(s->base + 0x20, 0x100, iomemtype); + + return s; +} + +void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr) +{ + /* TODO: Should reuse or destroy current s->serial */ + s->serial = serial_mm_init(s->base, 2, s->irq, + omap_clk_getrate(s->fclk) / 16, + chr ?: qemu_chr_open("null", "null"), 1); +} + +/* MPU Clock/Reset/Power Mode Control */ +static uint32_t omap_clkm_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->clkm.mpu_base; + + switch (offset) { + case 0x00: /* ARM_CKCTL */ + return s->clkm.arm_ckctl; + + case 0x04: /* ARM_IDLECT1 */ + return s->clkm.arm_idlect1; + + case 0x08: /* ARM_IDLECT2 */ + return s->clkm.arm_idlect2; + + case 0x0c: /* ARM_EWUPCT */ + return s->clkm.arm_ewupct; + + case 0x10: /* ARM_RSTCT1 */ + return s->clkm.arm_rstct1; + + case 0x14: /* ARM_RSTCT2 */ + return s->clkm.arm_rstct2; + + case 0x18: /* ARM_SYSST */ + return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start; + + case 0x1c: /* ARM_CKOUT1 */ + return s->clkm.arm_ckout1; + + case 0x20: /* ARM_CKOUT2 */ + break; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static inline void omap_clkm_ckctl_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + omap_clk clk; + + if (diff & (1 << 14)) { /* ARM_INTHCK_SEL */ + if (value & (1 << 14)) + /* Reserved */; + else { + clk = omap_findclk(s, "arminth_ck"); + omap_clk_reparent(clk, omap_findclk(s, "tc_ck")); + } + } + if (diff & (1 << 12)) { /* ARM_TIMXO */ + clk = omap_findclk(s, "armtim_ck"); + if (value & (1 << 12)) + omap_clk_reparent(clk, omap_findclk(s, "clkin")); + else + omap_clk_reparent(clk, omap_findclk(s, "ck_gen1")); + } + /* XXX: en_dspck */ + if (diff & (3 << 10)) { /* DSPMMUDIV */ + clk = omap_findclk(s, "dspmmu_ck"); + omap_clk_setrate(clk, 1 << ((value >> 10) & 3), 1); + } + if (diff & (3 << 8)) { /* TCDIV */ + clk = omap_findclk(s, "tc_ck"); + omap_clk_setrate(clk, 1 << ((value >> 8) & 3), 1); + } + if (diff & (3 << 6)) { /* DSPDIV */ + clk = omap_findclk(s, "dsp_ck"); + omap_clk_setrate(clk, 1 << ((value >> 6) & 3), 1); + } + if (diff & (3 << 4)) { /* ARMDIV */ + clk = omap_findclk(s, "arm_ck"); + omap_clk_setrate(clk, 1 << ((value >> 4) & 3), 1); + } + if (diff & (3 << 2)) { /* LCDDIV */ + clk = omap_findclk(s, "lcd_ck"); + omap_clk_setrate(clk, 1 << ((value >> 2) & 3), 1); + } + if (diff & (3 << 0)) { /* PERDIV */ + clk = omap_findclk(s, "armper_ck"); + omap_clk_setrate(clk, 1 << ((value >> 0) & 3), 1); + } +} + +static inline void omap_clkm_idlect1_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + omap_clk clk; + + if (value & (1 << 11)) /* SETARM_IDLE */ + cpu_interrupt(s->env, CPU_INTERRUPT_HALT); + if (!(value & (1 << 10))) /* WKUP_MODE */ + qemu_system_shutdown_request(); /* XXX: disable wakeup from IRQ */ + +#define SET_CANIDLE(clock, bit) \ + if (diff & (1 << bit)) { \ + clk = omap_findclk(s, clock); \ + omap_clk_canidle(clk, (value >> bit) & 1); \ + } + SET_CANIDLE("mpuwd_ck", 0) /* IDLWDT_ARM */ + SET_CANIDLE("armxor_ck", 1) /* IDLXORP_ARM */ + SET_CANIDLE("mpuper_ck", 2) /* IDLPER_ARM */ + SET_CANIDLE("lcd_ck", 3) /* IDLLCD_ARM */ + SET_CANIDLE("lb_ck", 4) /* IDLLB_ARM */ + SET_CANIDLE("hsab_ck", 5) /* IDLHSAB_ARM */ + SET_CANIDLE("tipb_ck", 6) /* IDLIF_ARM */ + SET_CANIDLE("dma_ck", 6) /* IDLIF_ARM */ + SET_CANIDLE("tc_ck", 6) /* IDLIF_ARM */ + SET_CANIDLE("dpll1", 7) /* IDLDPLL_ARM */ + SET_CANIDLE("dpll2", 7) /* IDLDPLL_ARM */ + SET_CANIDLE("dpll3", 7) /* IDLDPLL_ARM */ + SET_CANIDLE("mpui_ck", 8) /* IDLAPI_ARM */ + SET_CANIDLE("armtim_ck", 9) /* IDLTIM_ARM */ +} + +static inline void omap_clkm_idlect2_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + omap_clk clk; + +#define SET_ONOFF(clock, bit) \ + if (diff & (1 << bit)) { \ + clk = omap_findclk(s, clock); \ + omap_clk_onoff(clk, (value >> bit) & 1); \ + } + SET_ONOFF("mpuwd_ck", 0) /* EN_WDTCK */ + SET_ONOFF("armxor_ck", 1) /* EN_XORPCK */ + SET_ONOFF("mpuper_ck", 2) /* EN_PERCK */ + SET_ONOFF("lcd_ck", 3) /* EN_LCDCK */ + SET_ONOFF("lb_ck", 4) /* EN_LBCK */ + SET_ONOFF("hsab_ck", 5) /* EN_HSABCK */ + SET_ONOFF("mpui_ck", 6) /* EN_APICK */ + SET_ONOFF("armtim_ck", 7) /* EN_TIMCK */ + SET_CANIDLE("dma_ck", 8) /* DMACK_REQ */ + SET_ONOFF("arm_gpio_ck", 9) /* EN_GPIOCK */ + SET_ONOFF("lbfree_ck", 10) /* EN_LBFREECK */ +} + +static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + omap_clk clk; + + if (diff & (3 << 4)) { /* TCLKOUT */ + clk = omap_findclk(s, "tclk_out"); + switch ((value >> 4) & 3) { + case 1: + omap_clk_reparent(clk, omap_findclk(s, "ck_gen3")); + omap_clk_onoff(clk, 1); + break; + case 2: + omap_clk_reparent(clk, omap_findclk(s, "tc_ck")); + omap_clk_onoff(clk, 1); + break; + default: + omap_clk_onoff(clk, 0); + } + } + if (diff & (3 << 2)) { /* DCLKOUT */ + clk = omap_findclk(s, "dclk_out"); + switch ((value >> 2) & 3) { + case 0: + omap_clk_reparent(clk, omap_findclk(s, "dspmmu_ck")); + break; + case 1: + omap_clk_reparent(clk, omap_findclk(s, "ck_gen2")); + break; + case 2: + omap_clk_reparent(clk, omap_findclk(s, "dsp_ck")); + break; + case 3: + omap_clk_reparent(clk, omap_findclk(s, "ck_ref14")); + break; + } + } + if (diff & (3 << 0)) { /* ACLKOUT */ + clk = omap_findclk(s, "aclk_out"); + switch ((value >> 0) & 3) { + case 1: + omap_clk_reparent(clk, omap_findclk(s, "ck_gen1")); + omap_clk_onoff(clk, 1); + break; + case 2: + omap_clk_reparent(clk, omap_findclk(s, "arm_ck")); + omap_clk_onoff(clk, 1); + break; + case 3: + omap_clk_reparent(clk, omap_findclk(s, "ck_ref14")); + omap_clk_onoff(clk, 1); + break; + default: + omap_clk_onoff(clk, 0); + } + } +} + +static void omap_clkm_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->clkm.mpu_base; + uint16_t diff; + omap_clk clk; + static const char *clkschemename[8] = { + "fully synchronous", "fully asynchronous", "synchronous scalable", + "mix mode 1", "mix mode 2", "bypass mode", "mix mode 3", "mix mode 4", + }; + + switch (offset) { + case 0x00: /* ARM_CKCTL */ + diff = s->clkm.arm_ckctl ^ value; + s->clkm.arm_ckctl = value & 0x7fff; + omap_clkm_ckctl_update(s, diff, value); + return; + + case 0x04: /* ARM_IDLECT1 */ + diff = s->clkm.arm_idlect1 ^ value; + s->clkm.arm_idlect1 = value & 0x0fff; + omap_clkm_idlect1_update(s, diff, value); + return; + + case 0x08: /* ARM_IDLECT2 */ + diff = s->clkm.arm_idlect2 ^ value; + s->clkm.arm_idlect2 = value & 0x07ff; + omap_clkm_idlect2_update(s, diff, value); + return; + + case 0x0c: /* ARM_EWUPCT */ + diff = s->clkm.arm_ewupct ^ value; + s->clkm.arm_ewupct = value & 0x003f; + return; + + case 0x10: /* ARM_RSTCT1 */ + diff = s->clkm.arm_rstct1 ^ value; + s->clkm.arm_rstct1 = value & 0x0007; + if (value & 9) { + qemu_system_reset_request(); + s->clkm.cold_start = 0xa; + } + if (diff & ~value & 4) { /* DSP_RST */ + omap_mpui_reset(s); + omap_tipb_bridge_reset(s->private_tipb); + omap_tipb_bridge_reset(s->public_tipb); + } + if (diff & 2) { /* DSP_EN */ + clk = omap_findclk(s, "dsp_ck"); + omap_clk_canidle(clk, (~value >> 1) & 1); + } + return; + + case 0x14: /* ARM_RSTCT2 */ + s->clkm.arm_rstct2 = value & 0x0001; + return; + + case 0x18: /* ARM_SYSST */ + if ((s->clkm.clocking_scheme ^ (value >> 11)) & 7) { + s->clkm.clocking_scheme = (value >> 11) & 7; + printf("%s: clocking scheme set to %s\n", __FUNCTION__, + clkschemename[s->clkm.clocking_scheme]); + } + s->clkm.cold_start &= value & 0x3f; + return; + + case 0x1c: /* ARM_CKOUT1 */ + diff = s->clkm.arm_ckout1 ^ value; + s->clkm.arm_ckout1 = value & 0x003f; + omap_clkm_ckout1_update(s, diff, value); + return; + + case 0x20: /* ARM_CKOUT2 */ + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_clkm_readfn[] = { + omap_badwidth_read16, + omap_clkm_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_clkm_writefn[] = { + omap_badwidth_write16, + omap_clkm_write, + omap_badwidth_write16, +}; + +static uint32_t omap_clkdsp_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->clkm.dsp_base; + + switch (offset) { + case 0x04: /* DSP_IDLECT1 */ + return s->clkm.dsp_idlect1; + + case 0x08: /* DSP_IDLECT2 */ + return s->clkm.dsp_idlect2; + + case 0x14: /* DSP_RSTCT2 */ + return s->clkm.dsp_rstct2; + + case 0x18: /* DSP_SYSST */ + return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start | + (s->env->halted << 6); /* Quite useless... */ + } + + OMAP_BAD_REG(addr); + return 0; +} + +static inline void omap_clkdsp_idlect1_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + omap_clk clk; + + SET_CANIDLE("dspxor_ck", 1); /* IDLXORP_DSP */ +} + +static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + omap_clk clk; + + SET_ONOFF("dspxor_ck", 1); /* EN_XORPCK */ +} + +static void omap_clkdsp_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->clkm.dsp_base; + uint16_t diff; + + switch (offset) { + case 0x04: /* DSP_IDLECT1 */ + diff = s->clkm.dsp_idlect1 ^ value; + s->clkm.dsp_idlect1 = value & 0x01f7; + omap_clkdsp_idlect1_update(s, diff, value); + break; + + case 0x08: /* DSP_IDLECT2 */ + s->clkm.dsp_idlect2 = value & 0x0037; + diff = s->clkm.dsp_idlect1 ^ value; + omap_clkdsp_idlect2_update(s, diff, value); + break; + + case 0x14: /* DSP_RSTCT2 */ + s->clkm.dsp_rstct2 = value & 0x0001; + break; + + case 0x18: /* DSP_SYSST */ + s->clkm.cold_start &= value & 0x3f; + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_clkdsp_readfn[] = { + omap_badwidth_read16, + omap_clkdsp_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_clkdsp_writefn[] = { + omap_badwidth_write16, + omap_clkdsp_write, + omap_badwidth_write16, +}; + +static void omap_clkm_reset(struct omap_mpu_state_s *s) +{ + if (s->wdt && s->wdt->reset) + s->clkm.cold_start = 0x6; + s->clkm.clocking_scheme = 0; + omap_clkm_ckctl_update(s, ~0, 0x3000); + s->clkm.arm_ckctl = 0x3000; + omap_clkm_idlect1_update(s, s->clkm.arm_idlect1 ^ 0x0400, 0x0400); + s->clkm.arm_idlect1 = 0x0400; + omap_clkm_idlect2_update(s, s->clkm.arm_idlect2 ^ 0x0100, 0x0100); + s->clkm.arm_idlect2 = 0x0100; + s->clkm.arm_ewupct = 0x003f; + s->clkm.arm_rstct1 = 0x0000; + s->clkm.arm_rstct2 = 0x0000; + s->clkm.arm_ckout1 = 0x0015; + s->clkm.dpll1_mode = 0x2002; + omap_clkdsp_idlect1_update(s, s->clkm.dsp_idlect1 ^ 0x0040, 0x0040); + s->clkm.dsp_idlect1 = 0x0040; + omap_clkdsp_idlect2_update(s, ~0, 0x0000); + s->clkm.dsp_idlect2 = 0x0000; + s->clkm.dsp_rstct2 = 0x0000; +} + +static void omap_clkm_init(target_phys_addr_t mpu_base, + target_phys_addr_t dsp_base, struct omap_mpu_state_s *s) +{ + int iomemtype[2] = { + cpu_register_io_memory(0, omap_clkm_readfn, omap_clkm_writefn, s), + cpu_register_io_memory(0, omap_clkdsp_readfn, omap_clkdsp_writefn, s), + }; + + s->clkm.mpu_base = mpu_base; + s->clkm.dsp_base = dsp_base; + s->clkm.arm_idlect1 = 0x03ff; + s->clkm.arm_idlect2 = 0x0100; + s->clkm.dsp_idlect1 = 0x0002; + omap_clkm_reset(s); + s->clkm.cold_start = 0x3a; + + cpu_register_physical_memory(s->clkm.mpu_base, 0x100, iomemtype[0]); + cpu_register_physical_memory(s->clkm.dsp_base, 0x1000, iomemtype[1]); +} + +/* MPU I/O */ +struct omap_mpuio_s { + target_phys_addr_t base; + qemu_irq irq; + qemu_irq kbd_irq; + qemu_irq *in; + qemu_irq handler[16]; + qemu_irq wakeup; + + uint16_t inputs; + uint16_t outputs; + uint16_t dir; + uint16_t edge; + uint16_t mask; + uint16_t ints; + + uint16_t debounce; + uint16_t latch; + uint8_t event; + + uint8_t buttons[5]; + uint8_t row_latch; + uint8_t cols; + int kbd_mask; + int clk; +}; + +static void omap_mpuio_set(void *opaque, int line, int level) +{ + struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; + uint16_t prev = s->inputs; + + if (level) + s->inputs |= 1 << line; + else + s->inputs &= ~(1 << line); + + if (((1 << line) & s->dir & ~s->mask) && s->clk) { + if ((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) { + s->ints |= 1 << line; + qemu_irq_raise(s->irq); + /* TODO: wakeup */ + } + if ((s->event & (1 << 0)) && /* SET_GPIO_EVENT_MODE */ + (s->event >> 1) == line) /* PIN_SELECT */ + s->latch = s->inputs; + } +} + +static void omap_mpuio_kbd_update(struct omap_mpuio_s *s) +{ + int i; + uint8_t *row, rows = 0, cols = ~s->cols; + + for (row = s->buttons + 4, i = 1 << 4; i; row --, i >>= 1) + if (*row & cols) + rows |= i; + + qemu_set_irq(s->kbd_irq, rows && !s->kbd_mask && s->clk); + s->row_latch = ~rows; +} + +static uint32_t omap_mpuio_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + uint16_t ret; + + switch (offset) { + case 0x00: /* INPUT_LATCH */ + return s->inputs; + + case 0x04: /* OUTPUT_REG */ + return s->outputs; + + case 0x08: /* IO_CNTL */ + return s->dir; + + case 0x10: /* KBR_LATCH */ + return s->row_latch; + + case 0x14: /* KBC_REG */ + return s->cols; + + case 0x18: /* GPIO_EVENT_MODE_REG */ + return s->event; + + case 0x1c: /* GPIO_INT_EDGE_REG */ + return s->edge; + + case 0x20: /* KBD_INT */ + return (~s->row_latch & 0x1f) && !s->kbd_mask; + + case 0x24: /* GPIO_INT */ + ret = s->ints; + s->ints &= s->mask; + if (ret) + qemu_irq_lower(s->irq); + return ret; + + case 0x28: /* KBD_MASKIT */ + return s->kbd_mask; + + case 0x2c: /* GPIO_MASKIT */ + return s->mask; + + case 0x30: /* GPIO_DEBOUNCING_REG */ + return s->debounce; + + case 0x34: /* GPIO_LATCH_REG */ + return s->latch; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_mpuio_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + uint16_t diff; + int ln; + + switch (offset) { + case 0x04: /* OUTPUT_REG */ + diff = (s->outputs ^ value) & ~s->dir; + s->outputs = value; + while ((ln = ffs(diff))) { + ln --; + if (s->handler[ln]) + qemu_set_irq(s->handler[ln], (value >> ln) & 1); + diff &= ~(1 << ln); + } + break; + + case 0x08: /* IO_CNTL */ + diff = s->outputs & (s->dir ^ value); + s->dir = value; + + value = s->outputs & ~s->dir; + while ((ln = ffs(diff))) { + ln --; + if (s->handler[ln]) + qemu_set_irq(s->handler[ln], (value >> ln) & 1); + diff &= ~(1 << ln); + } + break; + + case 0x14: /* KBC_REG */ + s->cols = value; + omap_mpuio_kbd_update(s); + break; + + case 0x18: /* GPIO_EVENT_MODE_REG */ + s->event = value & 0x1f; + break; + + case 0x1c: /* GPIO_INT_EDGE_REG */ + s->edge = value; + break; + + case 0x28: /* KBD_MASKIT */ + s->kbd_mask = value & 1; + omap_mpuio_kbd_update(s); + break; + + case 0x2c: /* GPIO_MASKIT */ + s->mask = value; + break; + + case 0x30: /* GPIO_DEBOUNCING_REG */ + s->debounce = value & 0x1ff; + break; + + case 0x00: /* INPUT_LATCH */ + case 0x10: /* KBR_LATCH */ + case 0x20: /* KBD_INT */ + case 0x24: /* GPIO_INT */ + case 0x34: /* GPIO_LATCH_REG */ + OMAP_RO_REG(addr); + return; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_mpuio_readfn[] = { + omap_badwidth_read16, + omap_mpuio_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_mpuio_writefn[] = { + omap_badwidth_write16, + omap_mpuio_write, + omap_badwidth_write16, +}; + +static void omap_mpuio_reset(struct omap_mpuio_s *s) +{ + s->inputs = 0; + s->outputs = 0; + s->dir = ~0; + s->event = 0; + s->edge = 0; + s->kbd_mask = 0; + s->mask = 0; + s->debounce = 0; + s->latch = 0; + s->ints = 0; + s->row_latch = 0x1f; + s->clk = 1; +} + +static void omap_mpuio_onoff(void *opaque, int line, int on) +{ + struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; + + s->clk = on; + if (on) + omap_mpuio_kbd_update(s); +} + +struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base, + qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup, + omap_clk clk) +{ + int iomemtype; + struct omap_mpuio_s *s = (struct omap_mpuio_s *) + qemu_mallocz(sizeof(struct omap_mpuio_s)); + + s->base = base; + s->irq = gpio_int; + s->kbd_irq = kbd_int; + s->wakeup = wakeup; + s->in = qemu_allocate_irqs(omap_mpuio_set, s, 16); + omap_mpuio_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_mpuio_readfn, + omap_mpuio_writefn, s); + cpu_register_physical_memory(s->base, 0x800, iomemtype); + + omap_clk_adduser(clk, qemu_allocate_irqs(omap_mpuio_onoff, s, 1)[0]); + + return s; +} + +qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s) +{ + return s->in; +} + +void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler) +{ + if (line >= 16 || line < 0) + cpu_abort(cpu_single_env, "%s: No GPIO line %i\n", __FUNCTION__, line); + s->handler[line] = handler; +} + +void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down) +{ + if (row >= 5 || row < 0) + cpu_abort(cpu_single_env, "%s: No key %i-%i\n", + __FUNCTION__, col, row); + + if (down) + s->buttons[row] |= 1 << col; + else + s->buttons[row] &= ~(1 << col); + + omap_mpuio_kbd_update(s); +} + +/* General-Purpose I/O */ +struct omap_gpio_s { + target_phys_addr_t base; + qemu_irq irq; + qemu_irq *in; + qemu_irq handler[16]; + + uint16_t inputs; + uint16_t outputs; + uint16_t dir; + uint16_t edge; + uint16_t mask; + uint16_t ints; + uint16_t pins; +}; + +static void omap_gpio_set(void *opaque, int line, int level) +{ + struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; + uint16_t prev = s->inputs; + + if (level) + s->inputs |= 1 << line; + else + s->inputs &= ~(1 << line); + + if (((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) & + (1 << line) & s->dir & ~s->mask) { + s->ints |= 1 << line; + qemu_irq_raise(s->irq); + } +} + +static uint32_t omap_gpio_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + switch (offset) { + case 0x00: /* DATA_INPUT */ + return s->inputs & s->pins; + + case 0x04: /* DATA_OUTPUT */ + return s->outputs; + + case 0x08: /* DIRECTION_CONTROL */ + return s->dir; + + case 0x0c: /* INTERRUPT_CONTROL */ + return s->edge; + + case 0x10: /* INTERRUPT_MASK */ + return s->mask; + + case 0x14: /* INTERRUPT_STATUS */ + return s->ints; + + case 0x18: /* PIN_CONTROL (not in OMAP310) */ + OMAP_BAD_REG(addr); + return s->pins; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_gpio_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + uint16_t diff; + int ln; + + switch (offset) { + case 0x00: /* DATA_INPUT */ + OMAP_RO_REG(addr); + return; + + case 0x04: /* DATA_OUTPUT */ + diff = (s->outputs ^ value) & ~s->dir; + s->outputs = value; + while ((ln = ffs(diff))) { + ln --; + if (s->handler[ln]) + qemu_set_irq(s->handler[ln], (value >> ln) & 1); + diff &= ~(1 << ln); + } + break; + + case 0x08: /* DIRECTION_CONTROL */ + diff = s->outputs & (s->dir ^ value); + s->dir = value; + + value = s->outputs & ~s->dir; + while ((ln = ffs(diff))) { + ln --; + if (s->handler[ln]) + qemu_set_irq(s->handler[ln], (value >> ln) & 1); + diff &= ~(1 << ln); + } + break; + + case 0x0c: /* INTERRUPT_CONTROL */ + s->edge = value; + break; + + case 0x10: /* INTERRUPT_MASK */ + s->mask = value; + break; + + case 0x14: /* INTERRUPT_STATUS */ + s->ints &= ~value; + if (!s->ints) + qemu_irq_lower(s->irq); + break; + + case 0x18: /* PIN_CONTROL (not in OMAP310 TRM) */ + OMAP_BAD_REG(addr); + s->pins = value; + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +/* *Some* sources say the memory region is 32-bit. */ +static CPUReadMemoryFunc *omap_gpio_readfn[] = { + omap_badwidth_read16, + omap_gpio_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_gpio_writefn[] = { + omap_badwidth_write16, + omap_gpio_write, + omap_badwidth_write16, +}; + +static void omap_gpio_reset(struct omap_gpio_s *s) +{ + s->inputs = 0; + s->outputs = ~0; + s->dir = ~0; + s->edge = ~0; + s->mask = ~0; + s->ints = 0; + s->pins = ~0; +} + +struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base, + qemu_irq irq, omap_clk clk) +{ + int iomemtype; + struct omap_gpio_s *s = (struct omap_gpio_s *) + qemu_mallocz(sizeof(struct omap_gpio_s)); + + s->base = base; + s->irq = irq; + s->in = qemu_allocate_irqs(omap_gpio_set, s, 16); + omap_gpio_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_gpio_readfn, + omap_gpio_writefn, s); + cpu_register_physical_memory(s->base, 0x1000, iomemtype); + + return s; +} + +qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s) +{ + return s->in; +} + +void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler) +{ + if (line >= 16 || line < 0) + cpu_abort(cpu_single_env, "%s: No GPIO line %i\n", __FUNCTION__, line); + s->handler[line] = handler; +} + +/* MicroWire Interface */ +struct omap_uwire_s { + target_phys_addr_t base; + qemu_irq txirq; + qemu_irq rxirq; + qemu_irq txdrq; + + uint16_t txbuf; + uint16_t rxbuf; + uint16_t control; + uint16_t setup[5]; + + struct uwire_slave_s *chip[4]; +}; + +static void omap_uwire_transfer_start(struct omap_uwire_s *s) +{ + int chipselect = (s->control >> 10) & 3; /* INDEX */ + struct uwire_slave_s *slave = s->chip[chipselect]; + + if ((s->control >> 5) & 0x1f) { /* NB_BITS_WR */ + if (s->control & (1 << 12)) /* CS_CMD */ + if (slave && slave->send) + slave->send(slave->opaque, + s->txbuf >> (16 - ((s->control >> 5) & 0x1f))); + s->control &= ~(1 << 14); /* CSRB */ + /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or + * a DRQ. When is the level IRQ supposed to be reset? */ + } + + if ((s->control >> 0) & 0x1f) { /* NB_BITS_RD */ + if (s->control & (1 << 12)) /* CS_CMD */ + if (slave && slave->receive) + s->rxbuf = slave->receive(slave->opaque); + s->control |= 1 << 15; /* RDRB */ + /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or + * a DRQ. When is the level IRQ supposed to be reset? */ + } +} + +static uint32_t omap_uwire_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + switch (offset) { + case 0x00: /* RDR */ + s->control &= ~(1 << 15); /* RDRB */ + return s->rxbuf; + + case 0x04: /* CSR */ + return s->control; + + case 0x08: /* SR1 */ + return s->setup[0]; + case 0x0c: /* SR2 */ + return s->setup[1]; + case 0x10: /* SR3 */ + return s->setup[2]; + case 0x14: /* SR4 */ + return s->setup[3]; + case 0x18: /* SR5 */ + return s->setup[4]; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_uwire_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + switch (offset) { + case 0x00: /* TDR */ + s->txbuf = value; /* TD */ + if ((s->setup[4] & (1 << 2)) && /* AUTO_TX_EN */ + ((s->setup[4] & (1 << 3)) || /* CS_TOGGLE_TX_EN */ + (s->control & (1 << 12)))) { /* CS_CMD */ + s->control |= 1 << 14; /* CSRB */ + omap_uwire_transfer_start(s); + } + break; + + case 0x04: /* CSR */ + s->control = value & 0x1fff; + if (value & (1 << 13)) /* START */ + omap_uwire_transfer_start(s); + break; + + case 0x08: /* SR1 */ + s->setup[0] = value & 0x003f; + break; + + case 0x0c: /* SR2 */ + s->setup[1] = value & 0x0fc0; + break; + + case 0x10: /* SR3 */ + s->setup[2] = value & 0x0003; + break; + + case 0x14: /* SR4 */ + s->setup[3] = value & 0x0001; + break; + + case 0x18: /* SR5 */ + s->setup[4] = value & 0x000f; + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_uwire_readfn[] = { + omap_badwidth_read16, + omap_uwire_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_uwire_writefn[] = { + omap_badwidth_write16, + omap_uwire_write, + omap_badwidth_write16, +}; + +static void omap_uwire_reset(struct omap_uwire_s *s) +{ + s->control = 0; + s->setup[0] = 0; + s->setup[1] = 0; + s->setup[2] = 0; + s->setup[3] = 0; + s->setup[4] = 0; +} + +struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base, + qemu_irq *irq, qemu_irq dma, omap_clk clk) +{ + int iomemtype; + struct omap_uwire_s *s = (struct omap_uwire_s *) + qemu_mallocz(sizeof(struct omap_uwire_s)); + + s->base = base; + s->txirq = irq[0]; + s->rxirq = irq[1]; + s->txdrq = dma; + omap_uwire_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_uwire_readfn, + omap_uwire_writefn, s); + cpu_register_physical_memory(s->base, 0x800, iomemtype); + + return s; +} + +void omap_uwire_attach(struct omap_uwire_s *s, + struct uwire_slave_s *slave, int chipselect) +{ + if (chipselect < 0 || chipselect > 3) { + fprintf(stderr, "%s: Bad chipselect %i\n", __FUNCTION__, chipselect); + exit(-1); + } + + s->chip[chipselect] = slave; +} + +/* Pseudonoise Pulse-Width Light Modulator */ +static void omap_pwl_update(struct omap_mpu_state_s *s) +{ + int output = (s->pwl.clk && s->pwl.enable) ? s->pwl.level : 0; + + if (output != s->pwl.output) { + s->pwl.output = output; + printf("%s: Backlight now at %i/256\n", __FUNCTION__, output); + } +} + +static uint32_t omap_pwl_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + switch (offset) { + case 0x00: /* PWL_LEVEL */ + return s->pwl.level; + case 0x04: /* PWL_CTRL */ + return s->pwl.enable; + } + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_pwl_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + switch (offset) { + case 0x00: /* PWL_LEVEL */ + s->pwl.level = value; + omap_pwl_update(s); + break; + case 0x04: /* PWL_CTRL */ + s->pwl.enable = value & 1; + omap_pwl_update(s); + break; + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_pwl_readfn[] = { + omap_pwl_read, + omap_badwidth_read8, + omap_badwidth_read8, +}; + +static CPUWriteMemoryFunc *omap_pwl_writefn[] = { + omap_pwl_write, + omap_badwidth_write8, + omap_badwidth_write8, +}; + +static void omap_pwl_reset(struct omap_mpu_state_s *s) +{ + s->pwl.output = 0; + s->pwl.level = 0; + s->pwl.enable = 0; + s->pwl.clk = 1; + omap_pwl_update(s); +} + +static void omap_pwl_clk_update(void *opaque, int line, int on) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + + s->pwl.clk = on; + omap_pwl_update(s); +} + +static void omap_pwl_init(target_phys_addr_t base, struct omap_mpu_state_s *s, + omap_clk clk) +{ + int iomemtype; + + omap_pwl_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_pwl_readfn, + omap_pwl_writefn, s); + cpu_register_physical_memory(base, 0x800, iomemtype); + + omap_clk_adduser(clk, qemu_allocate_irqs(omap_pwl_clk_update, s, 1)[0]); +} + +/* Pulse-Width Tone module */ +static uint32_t omap_pwt_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + switch (offset) { + case 0x00: /* FRC */ + return s->pwt.frc; + case 0x04: /* VCR */ + return s->pwt.vrc; + case 0x08: /* GCR */ + return s->pwt.gcr; + } + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_pwt_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + switch (offset) { + case 0x00: /* FRC */ + s->pwt.frc = value & 0x3f; + break; + case 0x04: /* VRC */ + if ((value ^ s->pwt.vrc) & 1) { + if (value & 1) + printf("%s: %iHz buzz on\n", __FUNCTION__, (int) + /* 1.5 MHz from a 12-MHz or 13-MHz PWT_CLK */ + ((omap_clk_getrate(s->pwt.clk) >> 3) / + /* Pre-multiplexer divider */ + ((s->pwt.gcr & 2) ? 1 : 154) / + /* Octave multiplexer */ + (2 << (value & 3)) * + /* 101/107 divider */ + ((value & (1 << 2)) ? 101 : 107) * + /* 49/55 divider */ + ((value & (1 << 3)) ? 49 : 55) * + /* 50/63 divider */ + ((value & (1 << 4)) ? 50 : 63) * + /* 80/127 divider */ + ((value & (1 << 5)) ? 80 : 127) / + (107 * 55 * 63 * 127))); + else + printf("%s: silence!\n", __FUNCTION__); + } + s->pwt.vrc = value & 0x7f; + break; + case 0x08: /* GCR */ + s->pwt.gcr = value & 3; + break; + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_pwt_readfn[] = { + omap_pwt_read, + omap_badwidth_read8, + omap_badwidth_read8, +}; + +static CPUWriteMemoryFunc *omap_pwt_writefn[] = { + omap_pwt_write, + omap_badwidth_write8, + omap_badwidth_write8, +}; + +static void omap_pwt_reset(struct omap_mpu_state_s *s) +{ + s->pwt.frc = 0; + s->pwt.vrc = 0; + s->pwt.gcr = 0; +} + +static void omap_pwt_init(target_phys_addr_t base, struct omap_mpu_state_s *s, + omap_clk clk) +{ + int iomemtype; + + s->pwt.clk = clk; + omap_pwt_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_pwt_readfn, + omap_pwt_writefn, s); + cpu_register_physical_memory(base, 0x800, iomemtype); +} + +/* Real-time Clock module */ +struct omap_rtc_s { + target_phys_addr_t base; + qemu_irq irq; + qemu_irq alarm; + QEMUTimer *clk; + + uint8_t interrupts; + uint8_t status; + int16_t comp_reg; + int running; + int pm_am; + int auto_comp; + int round; + struct tm alarm_tm; + time_t alarm_ti; + + struct tm current_tm; + time_t ti; + uint64_t tick; +}; + +static void omap_rtc_interrupts_update(struct omap_rtc_s *s) +{ + /* s->alarm is level-triggered */ + qemu_set_irq(s->alarm, (s->status >> 6) & 1); +} + +static void omap_rtc_alarm_update(struct omap_rtc_s *s) +{ + s->alarm_ti = mktime(&s->alarm_tm); + if (s->alarm_ti == -1) + printf("%s: conversion failed\n", __FUNCTION__); +} + +static inline uint8_t omap_rtc_bcd(int num) +{ + return ((num / 10) << 4) | (num % 10); +} + +static inline int omap_rtc_bin(uint8_t num) +{ + return (num & 15) + 10 * (num >> 4); +} + +static uint32_t omap_rtc_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + uint8_t i; + + switch (offset) { + case 0x00: /* SECONDS_REG */ + return omap_rtc_bcd(s->current_tm.tm_sec); + + case 0x04: /* MINUTES_REG */ + return omap_rtc_bcd(s->current_tm.tm_min); + + case 0x08: /* HOURS_REG */ + if (s->pm_am) + return ((s->current_tm.tm_hour > 11) << 7) | + omap_rtc_bcd(((s->current_tm.tm_hour - 1) % 12) + 1); + else + return omap_rtc_bcd(s->current_tm.tm_hour); + + case 0x0c: /* DAYS_REG */ + return omap_rtc_bcd(s->current_tm.tm_mday); + + case 0x10: /* MONTHS_REG */ + return omap_rtc_bcd(s->current_tm.tm_mon + 1); + + case 0x14: /* YEARS_REG */ + return omap_rtc_bcd(s->current_tm.tm_year % 100); + + case 0x18: /* WEEK_REG */ + return s->current_tm.tm_wday; + + case 0x20: /* ALARM_SECONDS_REG */ + return omap_rtc_bcd(s->alarm_tm.tm_sec); + + case 0x24: /* ALARM_MINUTES_REG */ + return omap_rtc_bcd(s->alarm_tm.tm_min); + + case 0x28: /* ALARM_HOURS_REG */ + if (s->pm_am) + return ((s->alarm_tm.tm_hour > 11) << 7) | + omap_rtc_bcd(((s->alarm_tm.tm_hour - 1) % 12) + 1); + else + return omap_rtc_bcd(s->alarm_tm.tm_hour); + + case 0x2c: /* ALARM_DAYS_REG */ + return omap_rtc_bcd(s->alarm_tm.tm_mday); + + case 0x30: /* ALARM_MONTHS_REG */ + return omap_rtc_bcd(s->alarm_tm.tm_mon + 1); + + case 0x34: /* ALARM_YEARS_REG */ + return omap_rtc_bcd(s->alarm_tm.tm_year % 100); + + case 0x40: /* RTC_CTRL_REG */ + return (s->pm_am << 3) | (s->auto_comp << 2) | + (s->round << 1) | s->running; + + case 0x44: /* RTC_STATUS_REG */ + i = s->status; + s->status &= ~0x3d; + return i; + + case 0x48: /* RTC_INTERRUPTS_REG */ + return s->interrupts; + + case 0x4c: /* RTC_COMP_LSB_REG */ + return ((uint16_t) s->comp_reg) & 0xff; + + case 0x50: /* RTC_COMP_MSB_REG */ + return ((uint16_t) s->comp_reg) >> 8; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_rtc_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + struct tm new_tm; + time_t ti[2]; + + switch (offset) { + case 0x00: /* SECONDS_REG */ +#ifdef ALMDEBUG + printf("RTC SEC_REG <-- %02x\n", value); +#endif + s->ti -= s->current_tm.tm_sec; + s->ti += omap_rtc_bin(value); + return; + + case 0x04: /* MINUTES_REG */ +#ifdef ALMDEBUG + printf("RTC MIN_REG <-- %02x\n", value); +#endif + s->ti -= s->current_tm.tm_min * 60; + s->ti += omap_rtc_bin(value) * 60; + return; + + case 0x08: /* HOURS_REG */ +#ifdef ALMDEBUG + printf("RTC HRS_REG <-- %02x\n", value); +#endif + s->ti -= s->current_tm.tm_hour * 3600; + if (s->pm_am) { + s->ti += (omap_rtc_bin(value & 0x3f) & 12) * 3600; + s->ti += ((value >> 7) & 1) * 43200; + } else + s->ti += omap_rtc_bin(value & 0x3f) * 3600; + return; + + case 0x0c: /* DAYS_REG */ +#ifdef ALMDEBUG + printf("RTC DAY_REG <-- %02x\n", value); +#endif + s->ti -= s->current_tm.tm_mday * 86400; + s->ti += omap_rtc_bin(value) * 86400; + return; + + case 0x10: /* MONTHS_REG */ +#ifdef ALMDEBUG + printf("RTC MTH_REG <-- %02x\n", value); +#endif + memcpy(&new_tm, &s->current_tm, sizeof(new_tm)); + new_tm.tm_mon = omap_rtc_bin(value); + ti[0] = mktime(&s->current_tm); + ti[1] = mktime(&new_tm); + + if (ti[0] != -1 && ti[1] != -1) { + s->ti -= ti[0]; + s->ti += ti[1]; + } else { + /* A less accurate version */ + s->ti -= s->current_tm.tm_mon * 2592000; + s->ti += omap_rtc_bin(value) * 2592000; + } + return; + + case 0x14: /* YEARS_REG */ +#ifdef ALMDEBUG + printf("RTC YRS_REG <-- %02x\n", value); +#endif + memcpy(&new_tm, &s->current_tm, sizeof(new_tm)); + new_tm.tm_year += omap_rtc_bin(value) - (new_tm.tm_year % 100); + ti[0] = mktime(&s->current_tm); + ti[1] = mktime(&new_tm); + + if (ti[0] != -1 && ti[1] != -1) { + s->ti -= ti[0]; + s->ti += ti[1]; + } else { + /* A less accurate version */ + s->ti -= (s->current_tm.tm_year % 100) * 31536000; + s->ti += omap_rtc_bin(value) * 31536000; + } + return; + + case 0x18: /* WEEK_REG */ + return; /* Ignored */ + + case 0x20: /* ALARM_SECONDS_REG */ +#ifdef ALMDEBUG + printf("ALM SEC_REG <-- %02x\n", value); +#endif + s->alarm_tm.tm_sec = omap_rtc_bin(value); + omap_rtc_alarm_update(s); + return; + + case 0x24: /* ALARM_MINUTES_REG */ +#ifdef ALMDEBUG + printf("ALM MIN_REG <-- %02x\n", value); +#endif + s->alarm_tm.tm_min = omap_rtc_bin(value); + omap_rtc_alarm_update(s); + return; + + case 0x28: /* ALARM_HOURS_REG */ +#ifdef ALMDEBUG + printf("ALM HRS_REG <-- %02x\n", value); +#endif + if (s->pm_am) + s->alarm_tm.tm_hour = + ((omap_rtc_bin(value & 0x3f)) % 12) + + ((value >> 7) & 1) * 12; + else + s->alarm_tm.tm_hour = omap_rtc_bin(value); + omap_rtc_alarm_update(s); + return; + + case 0x2c: /* ALARM_DAYS_REG */ +#ifdef ALMDEBUG + printf("ALM DAY_REG <-- %02x\n", value); +#endif + s->alarm_tm.tm_mday = omap_rtc_bin(value); + omap_rtc_alarm_update(s); + return; + + case 0x30: /* ALARM_MONTHS_REG */ +#ifdef ALMDEBUG + printf("ALM MON_REG <-- %02x\n", value); +#endif + s->alarm_tm.tm_mon = omap_rtc_bin(value); + omap_rtc_alarm_update(s); + return; + + case 0x34: /* ALARM_YEARS_REG */ +#ifdef ALMDEBUG + printf("ALM YRS_REG <-- %02x\n", value); +#endif + s->alarm_tm.tm_year = omap_rtc_bin(value); + omap_rtc_alarm_update(s); + return; + + case 0x40: /* RTC_CTRL_REG */ +#ifdef ALMDEBUG + printf("RTC CONTROL <-- %02x\n", value); +#endif + s->pm_am = (value >> 3) & 1; + s->auto_comp = (value >> 2) & 1; + s->round = (value >> 1) & 1; + s->running = value & 1; + s->status &= 0xfd; + s->status |= s->running << 1; + return; + + case 0x44: /* RTC_STATUS_REG */ +#ifdef ALMDEBUG + printf("RTC STATUSL <-- %02x\n", value); +#endif + s->status &= ~((value & 0xc0) ^ 0x80); + omap_rtc_interrupts_update(s); + return; + + case 0x48: /* RTC_INTERRUPTS_REG */ +#ifdef ALMDEBUG + printf("RTC INTRS <-- %02x\n", value); +#endif + s->interrupts = value; + return; + + case 0x4c: /* RTC_COMP_LSB_REG */ +#ifdef ALMDEBUG + printf("RTC COMPLSB <-- %02x\n", value); +#endif + s->comp_reg &= 0xff00; + s->comp_reg |= 0x00ff & value; + return; + + case 0x50: /* RTC_COMP_MSB_REG */ +#ifdef ALMDEBUG + printf("RTC COMPMSB <-- %02x\n", value); +#endif + s->comp_reg &= 0x00ff; + s->comp_reg |= 0xff00 & (value << 8); + return; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_rtc_readfn[] = { + omap_rtc_read, + omap_badwidth_read8, + omap_badwidth_read8, +}; + +static CPUWriteMemoryFunc *omap_rtc_writefn[] = { + omap_rtc_write, + omap_badwidth_write8, + omap_badwidth_write8, +}; + +static void omap_rtc_tick(void *opaque) +{ + struct omap_rtc_s *s = opaque; + + if (s->round) { + /* Round to nearest full minute. */ + if (s->current_tm.tm_sec < 30) + s->ti -= s->current_tm.tm_sec; + else + s->ti += 60 - s->current_tm.tm_sec; + + s->round = 0; + } + + memcpy(&s->current_tm, localtime(&s->ti), sizeof(s->current_tm)); + + if ((s->interrupts & 0x08) && s->ti == s->alarm_ti) { + s->status |= 0x40; + omap_rtc_interrupts_update(s); + } + + if (s->interrupts & 0x04) + switch (s->interrupts & 3) { + case 0: + s->status |= 0x04; + qemu_irq_pulse(s->irq); + break; + case 1: + if (s->current_tm.tm_sec) + break; + s->status |= 0x08; + qemu_irq_pulse(s->irq); + break; + case 2: + if (s->current_tm.tm_sec || s->current_tm.tm_min) + break; + s->status |= 0x10; + qemu_irq_pulse(s->irq); + break; + case 3: + if (s->current_tm.tm_sec || + s->current_tm.tm_min || s->current_tm.tm_hour) + break; + s->status |= 0x20; + qemu_irq_pulse(s->irq); + break; + } + + /* Move on */ + if (s->running) + s->ti ++; + s->tick += 1000; + + /* + * Every full hour add a rough approximation of the compensation + * register to the 32kHz Timer (which drives the RTC) value. + */ + if (s->auto_comp && !s->current_tm.tm_sec && !s->current_tm.tm_min) + s->tick += s->comp_reg * 1000 / 32768; + + qemu_mod_timer(s->clk, s->tick); +} + +static void omap_rtc_reset(struct omap_rtc_s *s) +{ + struct tm tm; + + s->interrupts = 0; + s->comp_reg = 0; + s->running = 0; + s->pm_am = 0; + s->auto_comp = 0; + s->round = 0; + s->tick = qemu_get_clock(rt_clock); + memset(&s->alarm_tm, 0, sizeof(s->alarm_tm)); + s->alarm_tm.tm_mday = 0x01; + s->status = 1 << 7; + qemu_get_timedate(&tm, 0); + s->ti = mktime(&tm); + + omap_rtc_alarm_update(s); + omap_rtc_tick(s); +} + +struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, + qemu_irq *irq, omap_clk clk) +{ + int iomemtype; + struct omap_rtc_s *s = (struct omap_rtc_s *) + qemu_mallocz(sizeof(struct omap_rtc_s)); + + s->base = base; + s->irq = irq[0]; + s->alarm = irq[1]; + s->clk = qemu_new_timer(rt_clock, omap_rtc_tick, s); + + omap_rtc_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_rtc_readfn, + omap_rtc_writefn, s); + cpu_register_physical_memory(s->base, 0x800, iomemtype); + + return s; +} + +/* Multi-channel Buffered Serial Port interfaces */ +struct omap_mcbsp_s { + target_phys_addr_t base; + qemu_irq txirq; + qemu_irq rxirq; + qemu_irq txdrq; + qemu_irq rxdrq; + + uint16_t spcr[2]; + uint16_t rcr[2]; + uint16_t xcr[2]; + uint16_t srgr[2]; + uint16_t mcr[2]; + uint16_t pcr; + uint16_t rcer[8]; + uint16_t xcer[8]; + int tx_rate; + int rx_rate; + int tx_req; + int rx_req; + + struct i2s_codec_s *codec; + QEMUTimer *source_timer; + QEMUTimer *sink_timer; +}; + +static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) +{ + int irq; + + switch ((s->spcr[0] >> 4) & 3) { /* RINTM */ + case 0: + irq = (s->spcr[0] >> 1) & 1; /* RRDY */ + break; + case 3: + irq = (s->spcr[0] >> 3) & 1; /* RSYNCERR */ + break; + default: + irq = 0; + break; + } + + if (irq) + qemu_irq_pulse(s->rxirq); + + switch ((s->spcr[1] >> 4) & 3) { /* XINTM */ + case 0: + irq = (s->spcr[1] >> 1) & 1; /* XRDY */ + break; + case 3: + irq = (s->spcr[1] >> 3) & 1; /* XSYNCERR */ + break; + default: + irq = 0; + break; + } + + if (irq) + qemu_irq_pulse(s->txirq); +} + +static void omap_mcbsp_rx_newdata(struct omap_mcbsp_s *s) +{ + if ((s->spcr[0] >> 1) & 1) /* RRDY */ + s->spcr[0] |= 1 << 2; /* RFULL */ + s->spcr[0] |= 1 << 1; /* RRDY */ + qemu_irq_raise(s->rxdrq); + omap_mcbsp_intr_update(s); +} + +static void omap_mcbsp_source_tick(void *opaque) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 }; + + if (!s->rx_rate) + return; + if (s->rx_req) + printf("%s: Rx FIFO overrun\n", __FUNCTION__); + + s->rx_req = s->rx_rate << bps[(s->rcr[0] >> 5) & 7]; + + omap_mcbsp_rx_newdata(s); + qemu_mod_timer(s->source_timer, qemu_get_clock(vm_clock) + ticks_per_sec); +} + +static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s) +{ + if (!s->codec || !s->codec->rts) + omap_mcbsp_source_tick(s); + else if (s->codec->in.len) { + s->rx_req = s->codec->in.len; + omap_mcbsp_rx_newdata(s); + } +} + +static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s) +{ + qemu_del_timer(s->source_timer); +} + +static void omap_mcbsp_rx_done(struct omap_mcbsp_s *s) +{ + s->spcr[0] &= ~(1 << 1); /* RRDY */ + qemu_irq_lower(s->rxdrq); + omap_mcbsp_intr_update(s); +} + +static void omap_mcbsp_tx_newdata(struct omap_mcbsp_s *s) +{ + s->spcr[1] |= 1 << 1; /* XRDY */ + qemu_irq_raise(s->txdrq); + omap_mcbsp_intr_update(s); +} + +static void omap_mcbsp_sink_tick(void *opaque) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 }; + + if (!s->tx_rate) + return; + if (s->tx_req) + printf("%s: Tx FIFO underrun\n", __FUNCTION__); + + s->tx_req = s->tx_rate << bps[(s->xcr[0] >> 5) & 7]; + + omap_mcbsp_tx_newdata(s); + qemu_mod_timer(s->sink_timer, qemu_get_clock(vm_clock) + ticks_per_sec); +} + +static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s) +{ + if (!s->codec || !s->codec->cts) + omap_mcbsp_sink_tick(s); + else if (s->codec->out.size) { + s->tx_req = s->codec->out.size; + omap_mcbsp_tx_newdata(s); + } +} + +static void omap_mcbsp_tx_done(struct omap_mcbsp_s *s) +{ + s->spcr[1] &= ~(1 << 1); /* XRDY */ + qemu_irq_lower(s->txdrq); + omap_mcbsp_intr_update(s); + if (s->codec && s->codec->cts) + s->codec->tx_swallow(s->codec->opaque); +} + +static void omap_mcbsp_tx_stop(struct omap_mcbsp_s *s) +{ + s->tx_req = 0; + omap_mcbsp_tx_done(s); + qemu_del_timer(s->sink_timer); +} + +static void omap_mcbsp_req_update(struct omap_mcbsp_s *s) +{ + int prev_rx_rate, prev_tx_rate; + int rx_rate = 0, tx_rate = 0; + int cpu_rate = 1500000; /* XXX */ + + /* TODO: check CLKSTP bit */ + if (s->spcr[1] & (1 << 6)) { /* GRST */ + if (s->spcr[0] & (1 << 0)) { /* RRST */ + if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ + (s->pcr & (1 << 8))) { /* CLKRM */ + if (~s->pcr & (1 << 7)) /* SCLKME */ + rx_rate = cpu_rate / + ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ + } else + if (s->codec) + rx_rate = s->codec->rx_rate; + } + + if (s->spcr[1] & (1 << 0)) { /* XRST */ + if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ + (s->pcr & (1 << 9))) { /* CLKXM */ + if (~s->pcr & (1 << 7)) /* SCLKME */ + tx_rate = cpu_rate / + ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ + } else + if (s->codec) + tx_rate = s->codec->tx_rate; + } + } + prev_tx_rate = s->tx_rate; + prev_rx_rate = s->rx_rate; + s->tx_rate = tx_rate; + s->rx_rate = rx_rate; + + if (s->codec) + s->codec->set_rate(s->codec->opaque, rx_rate, tx_rate); + + if (!prev_tx_rate && tx_rate) + omap_mcbsp_tx_start(s); + else if (s->tx_rate && !tx_rate) + omap_mcbsp_tx_stop(s); + + if (!prev_rx_rate && rx_rate) + omap_mcbsp_rx_start(s); + else if (prev_tx_rate && !tx_rate) + omap_mcbsp_rx_stop(s); +} + +static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + uint16_t ret; + + switch (offset) { + case 0x00: /* DRR2 */ + if (((s->rcr[0] >> 5) & 7) < 3) /* RWDLEN1 */ + return 0x0000; + /* Fall through. */ + case 0x02: /* DRR1 */ + if (s->rx_req < 2) { + printf("%s: Rx FIFO underrun\n", __FUNCTION__); + omap_mcbsp_rx_done(s); + } else { + s->tx_req -= 2; + if (s->codec && s->codec->in.len >= 2) { + ret = s->codec->in.fifo[s->codec->in.start ++] << 8; + ret |= s->codec->in.fifo[s->codec->in.start ++]; + s->codec->in.len -= 2; + } else + ret = 0x0000; + if (!s->tx_req) + omap_mcbsp_rx_done(s); + return ret; + } + return 0x0000; + + case 0x04: /* DXR2 */ + case 0x06: /* DXR1 */ + return 0x0000; + + case 0x08: /* SPCR2 */ + return s->spcr[1]; + case 0x0a: /* SPCR1 */ + return s->spcr[0]; + case 0x0c: /* RCR2 */ + return s->rcr[1]; + case 0x0e: /* RCR1 */ + return s->rcr[0]; + case 0x10: /* XCR2 */ + return s->xcr[1]; + case 0x12: /* XCR1 */ + return s->xcr[0]; + case 0x14: /* SRGR2 */ + return s->srgr[1]; + case 0x16: /* SRGR1 */ + return s->srgr[0]; + case 0x18: /* MCR2 */ + return s->mcr[1]; + case 0x1a: /* MCR1 */ + return s->mcr[0]; + case 0x1c: /* RCERA */ + return s->rcer[0]; + case 0x1e: /* RCERB */ + return s->rcer[1]; + case 0x20: /* XCERA */ + return s->xcer[0]; + case 0x22: /* XCERB */ + return s->xcer[1]; + case 0x24: /* PCR0 */ + return s->pcr; + case 0x26: /* RCERC */ + return s->rcer[2]; + case 0x28: /* RCERD */ + return s->rcer[3]; + case 0x2a: /* XCERC */ + return s->xcer[2]; + case 0x2c: /* XCERD */ + return s->xcer[3]; + case 0x2e: /* RCERE */ + return s->rcer[4]; + case 0x30: /* RCERF */ + return s->rcer[5]; + case 0x32: /* XCERE */ + return s->xcer[4]; + case 0x34: /* XCERF */ + return s->xcer[5]; + case 0x36: /* RCERG */ + return s->rcer[6]; + case 0x38: /* RCERH */ + return s->rcer[7]; + case 0x3a: /* XCERG */ + return s->xcer[6]; + case 0x3c: /* XCERH */ + return s->xcer[7]; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_mcbsp_writeh(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + switch (offset) { + case 0x00: /* DRR2 */ + case 0x02: /* DRR1 */ + OMAP_RO_REG(addr); + return; + + case 0x04: /* DXR2 */ + if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ + return; + /* Fall through. */ + case 0x06: /* DXR1 */ + if (s->tx_req > 1) { + s->tx_req -= 2; + if (s->codec && s->codec->cts) { + s->codec->out.fifo[s->codec->out.len ++] = (value >> 8) & 0xff; + s->codec->out.fifo[s->codec->out.len ++] = (value >> 0) & 0xff; + } + if (s->tx_req < 2) + omap_mcbsp_tx_done(s); + } else + printf("%s: Tx FIFO overrun\n", __FUNCTION__); + return; + + case 0x08: /* SPCR2 */ + s->spcr[1] &= 0x0002; + s->spcr[1] |= 0x03f9 & value; + s->spcr[1] |= 0x0004 & (value << 2); /* XEMPTY := XRST */ + if (~value & 1) /* XRST */ + s->spcr[1] &= ~6; + omap_mcbsp_req_update(s); + return; + case 0x0a: /* SPCR1 */ + s->spcr[0] &= 0x0006; + s->spcr[0] |= 0xf8f9 & value; + if (value & (1 << 15)) /* DLB */ + printf("%s: Digital Loopback mode enable attempt\n", __FUNCTION__); + if (~value & 1) { /* RRST */ + s->spcr[0] &= ~6; + s->rx_req = 0; + omap_mcbsp_rx_done(s); + } + omap_mcbsp_req_update(s); + return; + + case 0x0c: /* RCR2 */ + s->rcr[1] = value & 0xffff; + return; + case 0x0e: /* RCR1 */ + s->rcr[0] = value & 0x7fe0; + return; + case 0x10: /* XCR2 */ + s->xcr[1] = value & 0xffff; + return; + case 0x12: /* XCR1 */ + s->xcr[0] = value & 0x7fe0; + return; + case 0x14: /* SRGR2 */ + s->srgr[1] = value & 0xffff; + omap_mcbsp_req_update(s); + return; + case 0x16: /* SRGR1 */ + s->srgr[0] = value & 0xffff; + omap_mcbsp_req_update(s); + return; + case 0x18: /* MCR2 */ + s->mcr[1] = value & 0x03e3; + if (value & 3) /* XMCM */ + printf("%s: Tx channel selection mode enable attempt\n", + __FUNCTION__); + return; + case 0x1a: /* MCR1 */ + s->mcr[0] = value & 0x03e1; + if (value & 1) /* RMCM */ + printf("%s: Rx channel selection mode enable attempt\n", + __FUNCTION__); + return; + case 0x1c: /* RCERA */ + s->rcer[0] = value & 0xffff; + return; + case 0x1e: /* RCERB */ + s->rcer[1] = value & 0xffff; + return; + case 0x20: /* XCERA */ + s->xcer[0] = value & 0xffff; + return; + case 0x22: /* XCERB */ + s->xcer[1] = value & 0xffff; + return; + case 0x24: /* PCR0 */ + s->pcr = value & 0x7faf; + return; + case 0x26: /* RCERC */ + s->rcer[2] = value & 0xffff; + return; + case 0x28: /* RCERD */ + s->rcer[3] = value & 0xffff; + return; + case 0x2a: /* XCERC */ + s->xcer[2] = value & 0xffff; + return; + case 0x2c: /* XCERD */ + s->xcer[3] = value & 0xffff; + return; + case 0x2e: /* RCERE */ + s->rcer[4] = value & 0xffff; + return; + case 0x30: /* RCERF */ + s->rcer[5] = value & 0xffff; + return; + case 0x32: /* XCERE */ + s->xcer[4] = value & 0xffff; + return; + case 0x34: /* XCERF */ + s->xcer[5] = value & 0xffff; + return; + case 0x36: /* RCERG */ + s->rcer[6] = value & 0xffff; + return; + case 0x38: /* RCERH */ + s->rcer[7] = value & 0xffff; + return; + case 0x3a: /* XCERG */ + s->xcer[6] = value & 0xffff; + return; + case 0x3c: /* XCERH */ + s->xcer[7] = value & 0xffff; + return; + } + + OMAP_BAD_REG(addr); +} + +static void omap_mcbsp_writew(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + if (offset == 0x04) { /* DXR */ + if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ + return; + if (s->tx_req > 3) { + s->tx_req -= 4; + if (s->codec && s->codec->cts) { + s->codec->out.fifo[s->codec->out.len ++] = + (value >> 24) & 0xff; + s->codec->out.fifo[s->codec->out.len ++] = + (value >> 16) & 0xff; + s->codec->out.fifo[s->codec->out.len ++] = + (value >> 8) & 0xff; + s->codec->out.fifo[s->codec->out.len ++] = + (value >> 0) & 0xff; + } + if (s->tx_req < 4) + omap_mcbsp_tx_done(s); + } else + printf("%s: Tx FIFO overrun\n", __FUNCTION__); + return; + } + + omap_badwidth_write16(opaque, addr, value); +} + +static CPUReadMemoryFunc *omap_mcbsp_readfn[] = { + omap_badwidth_read16, + omap_mcbsp_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_mcbsp_writefn[] = { + omap_badwidth_write16, + omap_mcbsp_writeh, + omap_mcbsp_writew, +}; + +static void omap_mcbsp_reset(struct omap_mcbsp_s *s) +{ + memset(&s->spcr, 0, sizeof(s->spcr)); + memset(&s->rcr, 0, sizeof(s->rcr)); + memset(&s->xcr, 0, sizeof(s->xcr)); + s->srgr[0] = 0x0001; + s->srgr[1] = 0x2000; + memset(&s->mcr, 0, sizeof(s->mcr)); + memset(&s->pcr, 0, sizeof(s->pcr)); + memset(&s->rcer, 0, sizeof(s->rcer)); + memset(&s->xcer, 0, sizeof(s->xcer)); + s->tx_req = 0; + s->rx_req = 0; + s->tx_rate = 0; + s->rx_rate = 0; + qemu_del_timer(s->source_timer); + qemu_del_timer(s->sink_timer); +} + +struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, + qemu_irq *irq, qemu_irq *dma, omap_clk clk) +{ + int iomemtype; + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) + qemu_mallocz(sizeof(struct omap_mcbsp_s)); + + s->base = base; + s->txirq = irq[0]; + s->rxirq = irq[1]; + s->txdrq = dma[0]; + s->rxdrq = dma[1]; + s->sink_timer = qemu_new_timer(vm_clock, omap_mcbsp_sink_tick, s); + s->source_timer = qemu_new_timer(vm_clock, omap_mcbsp_source_tick, s); + omap_mcbsp_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_mcbsp_readfn, + omap_mcbsp_writefn, s); + cpu_register_physical_memory(s->base, 0x800, iomemtype); + + return s; +} + +static void omap_mcbsp_i2s_swallow(void *opaque, int line, int level) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + + if (s->rx_rate) { + s->rx_req = s->codec->in.len; + omap_mcbsp_rx_newdata(s); + } +} + +static void omap_mcbsp_i2s_start(void *opaque, int line, int level) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + + if (s->tx_rate) { + s->tx_req = s->codec->out.size; + omap_mcbsp_tx_newdata(s); + } +} + +void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave) +{ + s->codec = slave; + slave->rx_swallow = qemu_allocate_irqs(omap_mcbsp_i2s_swallow, s, 1)[0]; + slave->tx_start = qemu_allocate_irqs(omap_mcbsp_i2s_start, s, 1)[0]; +} + +/* LED Pulse Generators */ +struct omap_lpg_s { + target_phys_addr_t base; + QEMUTimer *tm; + + uint8_t control; + uint8_t power; + int64_t on; + int64_t period; + int clk; + int cycle; +}; + +static void omap_lpg_tick(void *opaque) +{ + struct omap_lpg_s *s = opaque; + + if (s->cycle) + qemu_mod_timer(s->tm, qemu_get_clock(rt_clock) + s->period - s->on); + else + qemu_mod_timer(s->tm, qemu_get_clock(rt_clock) + s->on); + + s->cycle = !s->cycle; + printf("%s: LED is %s\n", __FUNCTION__, s->cycle ? "on" : "off"); +} + +static void omap_lpg_update(struct omap_lpg_s *s) +{ + int64_t on, period = 1, ticks = 1000; + static const int per[8] = { 1, 2, 4, 8, 12, 16, 20, 24 }; + + if (~s->control & (1 << 6)) /* LPGRES */ + on = 0; + else if (s->control & (1 << 7)) /* PERM_ON */ + on = period; + else { + period = muldiv64(ticks, per[s->control & 7], /* PERCTRL */ + 256 / 32); + on = (s->clk && s->power) ? muldiv64(ticks, + per[(s->control >> 3) & 7], 256) : 0; /* ONCTRL */ + } + + qemu_del_timer(s->tm); + if (on == period && s->on < s->period) + printf("%s: LED is on\n", __FUNCTION__); + else if (on == 0 && s->on) + printf("%s: LED is off\n", __FUNCTION__); + else if (on && (on != s->on || period != s->period)) { + s->cycle = 0; + s->on = on; + s->period = period; + omap_lpg_tick(s); + return; + } + + s->on = on; + s->period = period; +} + +static void omap_lpg_reset(struct omap_lpg_s *s) +{ + s->control = 0x00; + s->power = 0x00; + s->clk = 1; + omap_lpg_update(s); +} + +static uint32_t omap_lpg_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + switch (offset) { + case 0x00: /* LCR */ + return s->control; + + case 0x04: /* PMR */ + return s->power; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_lpg_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + switch (offset) { + case 0x00: /* LCR */ + if (~value & (1 << 6)) /* LPGRES */ + omap_lpg_reset(s); + s->control = value & 0xff; + omap_lpg_update(s); + return; + + case 0x04: /* PMR */ + s->power = value & 0x01; + omap_lpg_update(s); + return; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_lpg_readfn[] = { + omap_lpg_read, + omap_badwidth_read8, + omap_badwidth_read8, +}; + +static CPUWriteMemoryFunc *omap_lpg_writefn[] = { + omap_lpg_write, + omap_badwidth_write8, + omap_badwidth_write8, +}; + +static void omap_lpg_clk_update(void *opaque, int line, int on) +{ + struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; + + s->clk = on; + omap_lpg_update(s); +} + +struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk) +{ + int iomemtype; + struct omap_lpg_s *s = (struct omap_lpg_s *) + qemu_mallocz(sizeof(struct omap_lpg_s)); + + s->base = base; + s->tm = qemu_new_timer(rt_clock, omap_lpg_tick, s); + + omap_lpg_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_lpg_readfn, + omap_lpg_writefn, s); + cpu_register_physical_memory(s->base, 0x800, iomemtype); + + omap_clk_adduser(clk, qemu_allocate_irqs(omap_lpg_clk_update, s, 1)[0]); + + return s; +} + +/* MPUI Peripheral Bridge configuration */ +static uint32_t omap_mpui_io_read(void *opaque, target_phys_addr_t addr) +{ + if (addr == OMAP_MPUI_BASE) /* CMR */ + return 0xfe4d; + + OMAP_BAD_REG(addr); + return 0; +} + +static CPUReadMemoryFunc *omap_mpui_io_readfn[] = { + omap_badwidth_read16, + omap_mpui_io_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_mpui_io_writefn[] = { + omap_badwidth_write16, + omap_badwidth_write16, + omap_badwidth_write16, +}; + +static void omap_setup_mpui_io(struct omap_mpu_state_s *mpu) +{ + int iomemtype = cpu_register_io_memory(0, omap_mpui_io_readfn, + omap_mpui_io_writefn, mpu); + cpu_register_physical_memory(OMAP_MPUI_BASE, 0x7fff, iomemtype); +} + +/* General chip reset */ +static void omap1_mpu_reset(void *opaque) +{ + struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; + + omap_inth_reset(mpu->ih[0]); + omap_inth_reset(mpu->ih[1]); + omap_dma_reset(mpu->dma); + omap_mpu_timer_reset(mpu->timer[0]); + omap_mpu_timer_reset(mpu->timer[1]); + omap_mpu_timer_reset(mpu->timer[2]); + omap_wd_timer_reset(mpu->wdt); + omap_os_timer_reset(mpu->os_timer); + omap_lcdc_reset(mpu->lcd); + omap_ulpd_pm_reset(mpu); + omap_pin_cfg_reset(mpu); + omap_mpui_reset(mpu); + omap_tipb_bridge_reset(mpu->private_tipb); + omap_tipb_bridge_reset(mpu->public_tipb); + omap_dpll_reset(&mpu->dpll[0]); + omap_dpll_reset(&mpu->dpll[1]); + omap_dpll_reset(&mpu->dpll[2]); + omap_uart_reset(mpu->uart[0]); + omap_uart_reset(mpu->uart[1]); + omap_uart_reset(mpu->uart[2]); + omap_mmc_reset(mpu->mmc); + omap_mpuio_reset(mpu->mpuio); + omap_gpio_reset(mpu->gpio); + omap_uwire_reset(mpu->microwire); + omap_pwl_reset(mpu); + omap_pwt_reset(mpu); + omap_i2c_reset(mpu->i2c[0]); + omap_rtc_reset(mpu->rtc); + omap_mcbsp_reset(mpu->mcbsp1); + omap_mcbsp_reset(mpu->mcbsp2); + omap_mcbsp_reset(mpu->mcbsp3); + omap_lpg_reset(mpu->led[0]); + omap_lpg_reset(mpu->led[1]); + omap_clkm_reset(mpu); + cpu_reset(mpu->env); +} + +static const struct omap_map_s { + target_phys_addr_t phys_dsp; + target_phys_addr_t phys_mpu; + uint32_t size; + const char *name; +} omap15xx_dsp_mm[] = { + /* Strobe 0 */ + { 0xe1010000, 0xfffb0000, 0x800, "UART1 BT" }, /* CS0 */ + { 0xe1010800, 0xfffb0800, 0x800, "UART2 COM" }, /* CS1 */ + { 0xe1011800, 0xfffb1800, 0x800, "McBSP1 audio" }, /* CS3 */ + { 0xe1012000, 0xfffb2000, 0x800, "MCSI2 communication" }, /* CS4 */ + { 0xe1012800, 0xfffb2800, 0x800, "MCSI1 BT u-Law" }, /* CS5 */ + { 0xe1013000, 0xfffb3000, 0x800, "uWire" }, /* CS6 */ + { 0xe1013800, 0xfffb3800, 0x800, "I^2C" }, /* CS7 */ + { 0xe1014000, 0xfffb4000, 0x800, "USB W2FC" }, /* CS8 */ + { 0xe1014800, 0xfffb4800, 0x800, "RTC" }, /* CS9 */ + { 0xe1015000, 0xfffb5000, 0x800, "MPUIO" }, /* CS10 */ + { 0xe1015800, 0xfffb5800, 0x800, "PWL" }, /* CS11 */ + { 0xe1016000, 0xfffb6000, 0x800, "PWT" }, /* CS12 */ + { 0xe1017000, 0xfffb7000, 0x800, "McBSP3" }, /* CS14 */ + { 0xe1017800, 0xfffb7800, 0x800, "MMC" }, /* CS15 */ + { 0xe1019000, 0xfffb9000, 0x800, "32-kHz timer" }, /* CS18 */ + { 0xe1019800, 0xfffb9800, 0x800, "UART3" }, /* CS19 */ + { 0xe101c800, 0xfffbc800, 0x800, "TIPB switches" }, /* CS25 */ + /* Strobe 1 */ + { 0xe101e000, 0xfffce000, 0x800, "GPIOs" }, /* CS28 */ + + { 0 } +}; + +static void omap_setup_dsp_mapping(const struct omap_map_s *map) +{ + int io; + + for (; map->phys_dsp; map ++) { + io = cpu_get_physical_page_desc(map->phys_mpu); + + cpu_register_physical_memory(map->phys_dsp, map->size, io); + } +} + +void omap_mpu_wakeup(void *opaque, int irq, int req) +{ + struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; + + if (mpu->env->halted) + cpu_interrupt(mpu->env, CPU_INTERRUPT_EXITTB); +} + +static const struct dma_irq_map omap1_dma_irq_map[] = { + { 0, OMAP_INT_DMA_CH0_6 }, + { 0, OMAP_INT_DMA_CH1_7 }, + { 0, OMAP_INT_DMA_CH2_8 }, + { 0, OMAP_INT_DMA_CH3 }, + { 0, OMAP_INT_DMA_CH4 }, + { 0, OMAP_INT_DMA_CH5 }, + { 1, OMAP_INT_1610_DMA_CH6 }, + { 1, OMAP_INT_1610_DMA_CH7 }, + { 1, OMAP_INT_1610_DMA_CH8 }, + { 1, OMAP_INT_1610_DMA_CH9 }, + { 1, OMAP_INT_1610_DMA_CH10 }, + { 1, OMAP_INT_1610_DMA_CH11 }, + { 1, OMAP_INT_1610_DMA_CH12 }, + { 1, OMAP_INT_1610_DMA_CH13 }, + { 1, OMAP_INT_1610_DMA_CH14 }, + { 1, OMAP_INT_1610_DMA_CH15 } +}; + +/* DMA ports for OMAP1 */ +static int omap_validate_emiff_addr(struct omap_mpu_state_s *s, + target_phys_addr_t addr) +{ + return addr >= OMAP_EMIFF_BASE && addr < OMAP_EMIFF_BASE + s->sdram_size; +} + +static int omap_validate_emifs_addr(struct omap_mpu_state_s *s, + target_phys_addr_t addr) +{ + return addr >= OMAP_EMIFS_BASE && addr < OMAP_EMIFF_BASE; +} + +static int omap_validate_imif_addr(struct omap_mpu_state_s *s, + target_phys_addr_t addr) +{ + return addr >= OMAP_IMIF_BASE && addr < OMAP_IMIF_BASE + s->sram_size; +} + +static int omap_validate_tipb_addr(struct omap_mpu_state_s *s, + target_phys_addr_t addr) +{ + return addr >= 0xfffb0000 && addr < 0xffff0000; +} + +static int omap_validate_local_addr(struct omap_mpu_state_s *s, + target_phys_addr_t addr) +{ + return addr >= OMAP_LOCALBUS_BASE && addr < OMAP_LOCALBUS_BASE + 0x1000000; +} + +static int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s, + target_phys_addr_t addr) +{ + return addr >= 0xe1010000 && addr < 0xe1020004; +} + +struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, + DisplayState *ds, const char *core) +{ + int i; + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) + qemu_mallocz(sizeof(struct omap_mpu_state_s)); + ram_addr_t imif_base, emiff_base; + qemu_irq *cpu_irq; + qemu_irq dma_irqs[6]; + int sdindex; + + if (!core) + core = "ti925t"; + + /* Core */ + s->mpu_model = omap310; + s->env = cpu_init(core); + if (!s->env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + s->sdram_size = sdram_size; + s->sram_size = OMAP15XX_SRAM_SIZE; + + s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0]; + + /* Clocks */ + omap_clk_init(s); + + /* Memory-mapped stuff */ + cpu_register_physical_memory(OMAP_EMIFF_BASE, s->sdram_size, + (emiff_base = qemu_ram_alloc(s->sdram_size)) | IO_MEM_RAM); + cpu_register_physical_memory(OMAP_IMIF_BASE, s->sram_size, + (imif_base = qemu_ram_alloc(s->sram_size)) | IO_MEM_RAM); + + omap_clkm_init(0xfffece00, 0xe1008000, s); + + cpu_irq = arm_pic_init_cpu(s->env); + s->ih[0] = omap_inth_init(0xfffecb00, 0x100, 1, &s->irq[0], + cpu_irq[ARM_PIC_CPU_IRQ], cpu_irq[ARM_PIC_CPU_FIQ], + omap_findclk(s, "arminth_ck")); + s->ih[1] = omap_inth_init(0xfffe0000, 0x800, 1, &s->irq[1], + s->ih[0]->pins[OMAP_INT_15XX_IH2_IRQ], NULL, + omap_findclk(s, "arminth_ck")); + + for (i = 0; i < 6; i ++) + dma_irqs[i] = + s->irq[omap1_dma_irq_map[i].ih][omap1_dma_irq_map[i].intr]; + s->dma = omap_dma_init(0xfffed800, dma_irqs, s->irq[0][OMAP_INT_DMA_LCD], + s, omap_findclk(s, "dma_ck"), omap_dma_3_1); + + s->port[emiff ].addr_valid = omap_validate_emiff_addr; + s->port[emifs ].addr_valid = omap_validate_emifs_addr; + s->port[imif ].addr_valid = omap_validate_imif_addr; + s->port[tipb ].addr_valid = omap_validate_tipb_addr; + s->port[local ].addr_valid = omap_validate_local_addr; + s->port[tipb_mpui].addr_valid = omap_validate_tipb_mpui_addr; + + /* Register SDRAM and SRAM DMA ports for fast transfers. */ + soc_dma_port_add_mem_ram(s->dma, + emiff_base, OMAP_EMIFF_BASE, s->sdram_size); + soc_dma_port_add_mem_ram(s->dma, + imif_base, OMAP_IMIF_BASE, s->sram_size); + + s->timer[0] = omap_mpu_timer_init(0xfffec500, + s->irq[0][OMAP_INT_TIMER1], + omap_findclk(s, "mputim_ck")); + s->timer[1] = omap_mpu_timer_init(0xfffec600, + s->irq[0][OMAP_INT_TIMER2], + omap_findclk(s, "mputim_ck")); + s->timer[2] = omap_mpu_timer_init(0xfffec700, + s->irq[0][OMAP_INT_TIMER3], + omap_findclk(s, "mputim_ck")); + + s->wdt = omap_wd_timer_init(0xfffec800, + s->irq[0][OMAP_INT_WD_TIMER], + omap_findclk(s, "armwdt_ck")); + + s->os_timer = omap_os_timer_init(0xfffb9000, + s->irq[1][OMAP_INT_OS_TIMER], + omap_findclk(s, "clk32-kHz")); + + s->lcd = omap_lcdc_init(0xfffec000, s->irq[0][OMAP_INT_LCD_CTRL], + omap_dma_get_lcdch(s->dma), ds, imif_base, emiff_base, + omap_findclk(s, "lcd_ck")); + + omap_ulpd_pm_init(0xfffe0800, s); + omap_pin_cfg_init(0xfffe1000, s); + omap_id_init(s); + + omap_mpui_init(0xfffec900, s); + + s->private_tipb = omap_tipb_bridge_init(0xfffeca00, + s->irq[0][OMAP_INT_BRIDGE_PRIV], + omap_findclk(s, "tipb_ck")); + s->public_tipb = omap_tipb_bridge_init(0xfffed300, + s->irq[0][OMAP_INT_BRIDGE_PUB], + omap_findclk(s, "tipb_ck")); + + omap_tcmi_init(0xfffecc00, s); + + s->uart[0] = omap_uart_init(0xfffb0000, s->irq[1][OMAP_INT_UART1], + omap_findclk(s, "uart1_ck"), + omap_findclk(s, "uart1_ck"), + s->drq[OMAP_DMA_UART1_TX], s->drq[OMAP_DMA_UART1_RX], + serial_hds[0]); + s->uart[1] = omap_uart_init(0xfffb0800, s->irq[1][OMAP_INT_UART2], + omap_findclk(s, "uart2_ck"), + omap_findclk(s, "uart2_ck"), + s->drq[OMAP_DMA_UART2_TX], s->drq[OMAP_DMA_UART2_RX], + serial_hds[0] ? serial_hds[1] : 0); + s->uart[2] = omap_uart_init(0xe1019800, s->irq[0][OMAP_INT_UART3], + omap_findclk(s, "uart3_ck"), + omap_findclk(s, "uart3_ck"), + s->drq[OMAP_DMA_UART3_TX], s->drq[OMAP_DMA_UART3_RX], + serial_hds[0] && serial_hds[1] ? serial_hds[2] : 0); + + omap_dpll_init(&s->dpll[0], 0xfffecf00, omap_findclk(s, "dpll1")); + omap_dpll_init(&s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2")); + omap_dpll_init(&s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3")); + + sdindex = drive_get_index(IF_SD, 0, 0); + if (sdindex == -1) { + fprintf(stderr, "qemu: missing SecureDigital device\n"); + exit(1); + } + s->mmc = omap_mmc_init(0xfffb7800, drives_table[sdindex].bdrv, + s->irq[1][OMAP_INT_OQN], &s->drq[OMAP_DMA_MMC_TX], + omap_findclk(s, "mmc_ck")); + + s->mpuio = omap_mpuio_init(0xfffb5000, + s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO], + s->wakeup, omap_findclk(s, "clk32-kHz")); + + s->gpio = omap_gpio_init(0xfffce000, s->irq[0][OMAP_INT_GPIO_BANK1], + omap_findclk(s, "arm_gpio_ck")); + + s->microwire = omap_uwire_init(0xfffb3000, &s->irq[1][OMAP_INT_uWireTX], + s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck")); + + omap_pwl_init(0xfffb5800, s, omap_findclk(s, "armxor_ck")); + omap_pwt_init(0xfffb6000, s, omap_findclk(s, "armxor_ck")); + + s->i2c[0] = omap_i2c_init(0xfffb3800, s->irq[1][OMAP_INT_I2C], + &s->drq[OMAP_DMA_I2C_RX], omap_findclk(s, "mpuper_ck")); + + s->rtc = omap_rtc_init(0xfffb4800, &s->irq[1][OMAP_INT_RTC_TIMER], + omap_findclk(s, "clk32-kHz")); + + s->mcbsp1 = omap_mcbsp_init(0xfffb1800, &s->irq[1][OMAP_INT_McBSP1TX], + &s->drq[OMAP_DMA_MCBSP1_TX], omap_findclk(s, "dspxor_ck")); + s->mcbsp2 = omap_mcbsp_init(0xfffb1000, &s->irq[0][OMAP_INT_310_McBSP2_TX], + &s->drq[OMAP_DMA_MCBSP2_TX], omap_findclk(s, "mpuper_ck")); + s->mcbsp3 = omap_mcbsp_init(0xfffb7000, &s->irq[1][OMAP_INT_McBSP3TX], + &s->drq[OMAP_DMA_MCBSP3_TX], omap_findclk(s, "dspxor_ck")); + + s->led[0] = omap_lpg_init(0xfffbd000, omap_findclk(s, "clk32-kHz")); + s->led[1] = omap_lpg_init(0xfffbd800, omap_findclk(s, "clk32-kHz")); + + /* Register mappings not currenlty implemented: + * MCSI2 Comm fffb2000 - fffb27ff (not mapped on OMAP310) + * MCSI1 Bluetooth fffb2800 - fffb2fff (not mapped on OMAP310) + * USB W2FC fffb4000 - fffb47ff + * Camera Interface fffb6800 - fffb6fff + * USB Host fffba000 - fffba7ff + * FAC fffba800 - fffbafff + * HDQ/1-Wire fffbc000 - fffbc7ff + * TIPB switches fffbc800 - fffbcfff + * Mailbox fffcf000 - fffcf7ff + * Local bus IF fffec100 - fffec1ff + * Local bus MMU fffec200 - fffec2ff + * DSP MMU fffed200 - fffed2ff + */ + + omap_setup_dsp_mapping(omap15xx_dsp_mm); + omap_setup_mpui_io(s); + + qemu_register_reset(omap1_mpu_reset, s); + + return s; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/omap1_clk.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/omap1_clk.c --- qemu-0.9.1/hw/omap1_clk.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/omap1_clk.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,758 +0,0 @@ -/* - * OMAP clocks. - * - * Copyright (C) 2006-2007 Andrzej Zaborowski - * - * Clocks data comes in part from arch/arm/mach-omap1/clock.h in Linux. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ -#include "hw.h" -#include "omap.h" - -struct clk { - const char *name; - const char *alias; - struct clk *parent; - struct clk *child1; - struct clk *sibling; -#define ALWAYS_ENABLED (1 << 0) -#define CLOCK_IN_OMAP310 (1 << 10) -#define CLOCK_IN_OMAP730 (1 << 11) -#define CLOCK_IN_OMAP1510 (1 << 12) -#define CLOCK_IN_OMAP16XX (1 << 13) - uint32_t flags; - int id; - - int running; /* Is currently ticking */ - int enabled; /* Is enabled, regardless of its input clk */ - unsigned long rate; /* Current rate (if .running) */ - unsigned int divisor; /* Rate relative to input (if .enabled) */ - unsigned int multiplier; /* Rate relative to input (if .enabled) */ - qemu_irq users[16]; /* Who to notify on change */ - int usecount; /* Automatically idle when unused */ -}; - -static struct clk xtal_osc12m = { - .name = "xtal_osc_12m", - .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk xtal_osc32k = { - .name = "xtal_osc_32k", - .rate = 32768, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk ck_ref = { - .name = "ck_ref", - .alias = "clkin", - .parent = &xtal_osc12m, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -/* If a dpll is disabled it becomes a bypass, child clocks don't stop */ -static struct clk dpll1 = { - .name = "dpll1", - .parent = &ck_ref, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -static struct clk dpll2 = { - .name = "dpll2", - .parent = &ck_ref, - .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED, -}; - -static struct clk dpll3 = { - .name = "dpll3", - .parent = &ck_ref, - .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED, -}; - -static struct clk dpll4 = { - .name = "dpll4", - .parent = &ck_ref, - .multiplier = 4, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk apll = { - .name = "apll", - .parent = &ck_ref, - .multiplier = 48, - .divisor = 12, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk ck_48m = { - .name = "ck_48m", - .parent = &dpll4, /* either dpll4 or apll */ - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk ck_dpll1out = { - .name = "ck_dpll1out", - .parent = &dpll1, - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk sossi_ck = { - .name = "ck_sossi", - .parent = &ck_dpll1out, - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk clkm1 = { - .name = "clkm1", - .alias = "ck_gen1", - .parent = &dpll1, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -static struct clk clkm2 = { - .name = "clkm2", - .alias = "ck_gen2", - .parent = &dpll1, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -static struct clk clkm3 = { - .name = "clkm3", - .alias = "ck_gen3", - .parent = &dpll1, /* either dpll1 or ck_ref */ - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -static struct clk arm_ck = { - .name = "arm_ck", - .alias = "mpu_ck", - .parent = &clkm1, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -static struct clk armper_ck = { - .name = "armper_ck", - .alias = "mpuper_ck", - .parent = &clkm1, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk arm_gpio_ck = { - .name = "arm_gpio_ck", - .alias = "mpu_gpio_ck", - .parent = &clkm1, - .divisor = 1, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, -}; - -static struct clk armxor_ck = { - .name = "armxor_ck", - .alias = "mpuxor_ck", - .parent = &ck_ref, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk armtim_ck = { - .name = "armtim_ck", - .alias = "mputim_ck", - .parent = &ck_ref, /* either CLKIN or DPLL1 */ - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk armwdt_ck = { - .name = "armwdt_ck", - .alias = "mpuwd_ck", - .parent = &clkm1, - .divisor = 14, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -static struct clk arminth_ck16xx = { - .name = "arminth_ck", - .parent = &arm_ck, - .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, - /* Note: On 16xx the frequency can be divided by 2 by programming - * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1 - * - * 1510 version is in TC clocks. - */ -}; - -static struct clk dsp_ck = { - .name = "dsp_ck", - .parent = &clkm2, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, -}; - -static struct clk dspmmu_ck = { - .name = "dspmmu_ck", - .parent = &clkm2, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - ALWAYS_ENABLED, -}; - -static struct clk dspper_ck = { - .name = "dspper_ck", - .parent = &clkm2, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, -}; - -static struct clk dspxor_ck = { - .name = "dspxor_ck", - .parent = &ck_ref, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, -}; - -static struct clk dsptim_ck = { - .name = "dsptim_ck", - .parent = &ck_ref, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, -}; - -static struct clk tc_ck = { - .name = "tc_ck", - .parent = &clkm3, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - CLOCK_IN_OMAP730 | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -static struct clk arminth_ck15xx = { - .name = "arminth_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, - /* Note: On 1510 the frequency follows TC_CK - * - * 16xx version is in MPU clocks. - */ -}; - -static struct clk tipb_ck = { - /* No-idle controlled by "tc_ck" */ - .name = "tipb_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, -}; - -static struct clk l3_ocpi_ck = { - /* No-idle controlled by "tc_ck" */ - .name = "l3_ocpi_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk tc1_ck = { - .name = "tc1_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk tc2_ck = { - .name = "tc2_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk dma_ck = { - /* No-idle controlled by "tc_ck" */ - .name = "dma_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -static struct clk dma_lcdfree_ck = { - .name = "dma_lcdfree_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, -}; - -static struct clk api_ck = { - .name = "api_ck", - .alias = "mpui_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk lb_ck = { - .name = "lb_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, -}; - -static struct clk lbfree_ck = { - .name = "lbfree_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, -}; - -static struct clk hsab_ck = { - .name = "hsab_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, -}; - -static struct clk rhea1_ck = { - .name = "rhea1_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, -}; - -static struct clk rhea2_ck = { - .name = "rhea2_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, -}; - -static struct clk lcd_ck_16xx = { - .name = "lcd_ck", - .parent = &clkm3, - .flags = CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730, -}; - -static struct clk lcd_ck_1510 = { - .name = "lcd_ck", - .parent = &clkm3, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, -}; - -static struct clk uart1_1510 = { - .name = "uart1_ck", - /* Direct from ULPD, no real parent */ - .parent = &armper_ck, /* either armper_ck or dpll4 */ - .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, -}; - -static struct clk uart1_16xx = { - .name = "uart1_ck", - /* Direct from ULPD, no real parent */ - .parent = &armper_ck, - .rate = 48000000, - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk uart2_ck = { - .name = "uart2_ck", - /* Direct from ULPD, no real parent */ - .parent = &armper_ck, /* either armper_ck or dpll4 */ - .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -static struct clk uart3_1510 = { - .name = "uart3_ck", - /* Direct from ULPD, no real parent */ - .parent = &armper_ck, /* either armper_ck or dpll4 */ - .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, -}; - -static struct clk uart3_16xx = { - .name = "uart3_ck", - /* Direct from ULPD, no real parent */ - .parent = &armper_ck, - .rate = 48000000, - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk usb_clk0 = { /* 6 MHz output on W4_USB_CLK0 */ - .name = "usb_clk0", - .alias = "usb.clko", - /* Direct from ULPD, no parent */ - .rate = 6000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk usb_hhc_ck1510 = { - .name = "usb_hhc_ck", - /* Direct from ULPD, no parent */ - .rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */ - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, -}; - -static struct clk usb_hhc_ck16xx = { - .name = "usb_hhc_ck", - /* Direct from ULPD, no parent */ - .rate = 48000000, - /* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */ - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk usb_w2fc_mclk = { - .name = "usb_w2fc_mclk", - .alias = "usb_w2fc_ck", - .parent = &ck_48m, - .rate = 48000000, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, -}; - -static struct clk mclk_1510 = { - .name = "mclk", - /* Direct from ULPD, no parent. May be enabled by ext hardware. */ - .rate = 12000000, - .flags = CLOCK_IN_OMAP1510, -}; - -static struct clk bclk_310 = { - .name = "bt_mclk_out", /* Alias midi_mclk_out? */ - .parent = &armper_ck, - .flags = CLOCK_IN_OMAP310, -}; - -static struct clk mclk_310 = { - .name = "com_mclk_out", - .parent = &armper_ck, - .flags = CLOCK_IN_OMAP310, -}; - -static struct clk mclk_16xx = { - .name = "mclk", - /* Direct from ULPD, no parent. May be enabled by ext hardware. */ - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk bclk_1510 = { - .name = "bclk", - /* Direct from ULPD, no parent. May be enabled by ext hardware. */ - .rate = 12000000, - .flags = CLOCK_IN_OMAP1510, -}; - -static struct clk bclk_16xx = { - .name = "bclk", - /* Direct from ULPD, no parent. May be enabled by ext hardware. */ - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk mmc1_ck = { - .name = "mmc_ck", - .id = 1, - /* Functional clock is direct from ULPD, interface clock is ARMPER */ - .parent = &armper_ck, /* either armper_ck or dpll4 */ - .rate = 48000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk mmc2_ck = { - .name = "mmc_ck", - .id = 2, - /* Functional clock is direct from ULPD, interface clock is ARMPER */ - .parent = &armper_ck, - .rate = 48000000, - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk cam_mclk = { - .name = "cam.mclk", - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, - .rate = 12000000, -}; - -static struct clk cam_exclk = { - .name = "cam.exclk", - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, - /* Either 12M from cam.mclk or 48M from dpll4 */ - .parent = &cam_mclk, -}; - -static struct clk cam_lclk = { - .name = "cam.lclk", - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, -}; - -static struct clk i2c_fck = { - .name = "i2c_fck", - .id = 1, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - ALWAYS_ENABLED, - .parent = &armxor_ck, -}; - -static struct clk i2c_ick = { - .name = "i2c_ick", - .id = 1, - .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, - .parent = &armper_ck, -}; - -static struct clk clk32k = { - .name = "clk32-kHz", - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - ALWAYS_ENABLED, - .parent = &xtal_osc32k, -}; - -static struct clk *onchip_clks[] = { - /* non-ULPD clocks */ - &xtal_osc12m, - &xtal_osc32k, - &ck_ref, - &dpll1, - &dpll2, - &dpll3, - &dpll4, - &apll, - &ck_48m, - /* CK_GEN1 clocks */ - &clkm1, - &ck_dpll1out, - &sossi_ck, - &arm_ck, - &armper_ck, - &arm_gpio_ck, - &armxor_ck, - &armtim_ck, - &armwdt_ck, - &arminth_ck15xx, &arminth_ck16xx, - /* CK_GEN2 clocks */ - &clkm2, - &dsp_ck, - &dspmmu_ck, - &dspper_ck, - &dspxor_ck, - &dsptim_ck, - /* CK_GEN3 clocks */ - &clkm3, - &tc_ck, - &tipb_ck, - &l3_ocpi_ck, - &tc1_ck, - &tc2_ck, - &dma_ck, - &dma_lcdfree_ck, - &api_ck, - &lb_ck, - &lbfree_ck, - &hsab_ck, - &rhea1_ck, - &rhea2_ck, - &lcd_ck_16xx, - &lcd_ck_1510, - /* ULPD clocks */ - &uart1_1510, - &uart1_16xx, - &uart2_ck, - &uart3_1510, - &uart3_16xx, - &usb_clk0, - &usb_hhc_ck1510, &usb_hhc_ck16xx, - &mclk_1510, &mclk_16xx, &mclk_310, - &bclk_1510, &bclk_16xx, &bclk_310, - &mmc1_ck, - &mmc2_ck, - &cam_mclk, - &cam_exclk, - &cam_lclk, - &clk32k, - &usb_w2fc_mclk, - /* Virtual clocks */ - &i2c_fck, - &i2c_ick, - 0 -}; - -void omap_clk_adduser(struct clk *clk, qemu_irq user) -{ - qemu_irq *i; - - for (i = clk->users; *i; i ++); - *i = user; -} - -/* If a clock is allowed to idle, it is disabled automatically when - * all of clock domains using it are disabled. */ -int omap_clk_is_idle(struct clk *clk) -{ - struct clk *chld; - - if (!clk->enabled && (!clk->usecount || !(clk->flags && ALWAYS_ENABLED))) - return 1; - if (clk->usecount) - return 0; - - for (chld = clk->child1; chld; chld = chld->sibling) - if (!omap_clk_is_idle(chld)) - return 0; - return 1; -} - -struct clk *omap_findclk(struct omap_mpu_state_s *mpu, const char *name) -{ - struct clk *i; - - for (i = mpu->clks; i->name; i ++) - if (!strcmp(i->name, name) || (i->alias && !strcmp(i->alias, name))) - return i; - cpu_abort(mpu->env, "%s: %s not found\n", __FUNCTION__, name); -} - -void omap_clk_get(struct clk *clk) -{ - clk->usecount ++; -} - -void omap_clk_put(struct clk *clk) -{ - if (!(clk->usecount --)) - cpu_abort(cpu_single_env, "%s: %s is not in use\n", - __FUNCTION__, clk->name); -} - -static void omap_clk_update(struct clk *clk) -{ - int parent, running; - qemu_irq *user; - struct clk *i; - - if (clk->parent) - parent = clk->parent->running; - else - parent = 1; - - running = parent && (clk->enabled || - ((clk->flags & ALWAYS_ENABLED) && clk->usecount)); - if (clk->running != running) { - clk->running = running; - for (user = clk->users; *user; user ++) - qemu_set_irq(*user, running); - for (i = clk->child1; i; i = i->sibling) - omap_clk_update(i); - } -} - -static void omap_clk_rate_update_full(struct clk *clk, unsigned long int rate, - unsigned long int div, unsigned long int mult) -{ - struct clk *i; - qemu_irq *user; - - clk->rate = muldiv64(rate, mult, div); - if (clk->running) - for (user = clk->users; *user; user ++) - qemu_irq_raise(*user); - for (i = clk->child1; i; i = i->sibling) - omap_clk_rate_update_full(i, rate, - div * i->divisor, mult * i->multiplier); -} - -static void omap_clk_rate_update(struct clk *clk) -{ - struct clk *i; - unsigned long int div, mult = div = 1; - - for (i = clk; i->parent; i = i->parent) { - div *= i->divisor; - mult *= i->multiplier; - } - - omap_clk_rate_update_full(clk, i->rate, div, mult); -} - -void omap_clk_reparent(struct clk *clk, struct clk *parent) -{ - struct clk **p; - - if (clk->parent) { - for (p = &clk->parent->child1; *p != clk; p = &(*p)->sibling); - *p = clk->sibling; - } - - clk->parent = parent; - if (parent) { - clk->sibling = parent->child1; - parent->child1 = clk; - omap_clk_update(clk); - omap_clk_rate_update(clk); - } else - clk->sibling = 0; -} - -void omap_clk_onoff(struct clk *clk, int on) -{ - clk->enabled = on; - omap_clk_update(clk); -} - -void omap_clk_canidle(struct clk *clk, int can) -{ - if (can) - omap_clk_put(clk); - else - omap_clk_get(clk); -} - -void omap_clk_setrate(struct clk *clk, int divide, int multiply) -{ - clk->divisor = divide; - clk->multiplier = multiply; - omap_clk_rate_update(clk); -} - -int64_t omap_clk_getrate(omap_clk clk) -{ - return clk->rate; -} - -void omap_clk_init(struct omap_mpu_state_s *mpu) -{ - struct clk **i, *j, *k; - int count; - int flag; - - if (cpu_is_omap310(mpu)) - flag = CLOCK_IN_OMAP310; - else if (cpu_is_omap1510(mpu)) - flag = CLOCK_IN_OMAP1510; - else - return; - - for (i = onchip_clks, count = 0; *i; i ++) - if ((*i)->flags & flag) - count ++; - mpu->clks = (struct clk *) qemu_mallocz(sizeof(struct clk) * (count + 1)); - for (i = onchip_clks, j = mpu->clks; *i; i ++) - if ((*i)->flags & flag) { - memcpy(j, *i, sizeof(struct clk)); - for (k = mpu->clks; k < j; k ++) - if (j->parent && !strcmp(j->parent->name, k->name)) { - j->parent = k; - j->sibling = k->child1; - k->child1 = j; - } else if (k->parent && !strcmp(k->parent->name, j->name)) { - k->parent = j; - k->sibling = j->child1; - j->child1 = k; - } - j->divisor = j->divisor ?: 1; - j->multiplier = j->multiplier ?: 1; - j ++; - } - for (j = mpu->clks; count --; j ++) { - omap_clk_update(j); - omap_clk_rate_update(j); - } -} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/omap2.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/omap2.c --- qemu-0.9.1/hw/omap2.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/omap2.c 2008-11-01 00:53:19.000000000 +0000 @@ -0,0 +1,4923 @@ +/* + * TI OMAP processors emulation. + * + * Copyright (C) 2007-2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include "hw.h" +#include "arm-misc.h" +#include "omap.h" +#include "sysemu.h" +#include "qemu-timer.h" +#include "qemu-char.h" +#include "flash.h" +#include "soc_dma.h" +#include "audio/audio.h" + +/* GP timers */ +struct omap_gp_timer_s { + qemu_irq irq; + qemu_irq wkup; + qemu_irq in; + qemu_irq out; + omap_clk clk; + target_phys_addr_t base; + QEMUTimer *timer; + QEMUTimer *match; + struct omap_target_agent_s *ta; + + int in_val; + int out_val; + int64_t time; + int64_t rate; + int64_t ticks_per_sec; + + int16_t config; + int status; + int it_ena; + int wu_ena; + int enable; + int inout; + int capt2; + int pt; + enum { + gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both + } trigger; + enum { + gpt_capture_none, gpt_capture_rising, + gpt_capture_falling, gpt_capture_both + } capture; + int scpwm; + int ce; + int pre; + int ptv; + int ar; + int st; + int posted; + uint32_t val; + uint32_t load_val; + uint32_t capture_val[2]; + uint32_t match_val; + int capt_num; + + uint16_t writeh; /* LSB */ + uint16_t readh; /* MSB */ +}; + +#define GPT_TCAR_IT (1 << 2) +#define GPT_OVF_IT (1 << 1) +#define GPT_MAT_IT (1 << 0) + +static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it) +{ + if (timer->it_ena & it) { + if (!timer->status) + qemu_irq_raise(timer->irq); + + timer->status |= it; + /* Or are the status bits set even when masked? + * i.e. is masking applied before or after the status register? */ + } + + if (timer->wu_ena & it) + qemu_irq_pulse(timer->wkup); +} + +static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level) +{ + if (!timer->inout && timer->out_val != level) { + timer->out_val = level; + qemu_set_irq(timer->out, level); + } +} + +static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer) +{ + uint64_t distance; + + if (timer->st && timer->rate) { + distance = qemu_get_clock(vm_clock) - timer->time; + distance = muldiv64(distance, timer->rate, timer->ticks_per_sec); + + if (distance >= 0xffffffff - timer->val) + return 0xffffffff; + else + return timer->val + distance; + } else + return timer->val; +} + +static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer) +{ + if (timer->st) { + timer->val = omap_gp_timer_read(timer); + timer->time = qemu_get_clock(vm_clock); + } +} + +static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer) +{ + int64_t expires, matches; + + if (timer->st && timer->rate) { + expires = muldiv64(0x100000000ll - timer->val, + timer->ticks_per_sec, timer->rate); + qemu_mod_timer(timer->timer, timer->time + expires); + + if (timer->ce && timer->match_val >= timer->val) { + matches = muldiv64(timer->match_val - timer->val, + timer->ticks_per_sec, timer->rate); + qemu_mod_timer(timer->match, timer->time + matches); + } else + qemu_del_timer(timer->match); + } else { + qemu_del_timer(timer->timer); + qemu_del_timer(timer->match); + omap_gp_timer_out(timer, timer->scpwm); + } +} + +static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer) +{ + if (timer->pt) + /* TODO in overflow-and-match mode if the first event to + * occur is the match, don't toggle. */ + omap_gp_timer_out(timer, !timer->out_val); + else + /* TODO inverted pulse on timer->out_val == 1? */ + qemu_irq_pulse(timer->out); +} + +static void omap_gp_timer_tick(void *opaque) +{ + struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; + + if (!timer->ar) { + timer->st = 0; + timer->val = 0; + } else { + timer->val = timer->load_val; + timer->time = qemu_get_clock(vm_clock); + } + + if (timer->trigger == gpt_trigger_overflow || + timer->trigger == gpt_trigger_both) + omap_gp_timer_trigger(timer); + + omap_gp_timer_intr(timer, GPT_OVF_IT); + omap_gp_timer_update(timer); +} + +static void omap_gp_timer_match(void *opaque) +{ + struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; + + if (timer->trigger == gpt_trigger_both) + omap_gp_timer_trigger(timer); + + omap_gp_timer_intr(timer, GPT_MAT_IT); +} + +static void omap_gp_timer_input(void *opaque, int line, int on) +{ + struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; + int trigger; + + switch (s->capture) { + default: + case gpt_capture_none: + trigger = 0; + break; + case gpt_capture_rising: + trigger = !s->in_val && on; + break; + case gpt_capture_falling: + trigger = s->in_val && !on; + break; + case gpt_capture_both: + trigger = (s->in_val == !on); + break; + } + s->in_val = on; + + if (s->inout && trigger && s->capt_num < 2) { + s->capture_val[s->capt_num] = omap_gp_timer_read(s); + + if (s->capt2 == s->capt_num ++) + omap_gp_timer_intr(s, GPT_TCAR_IT); + } +} + +static void omap_gp_timer_clk_update(void *opaque, int line, int on) +{ + struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; + + omap_gp_timer_sync(timer); + timer->rate = on ? omap_clk_getrate(timer->clk) : 0; + omap_gp_timer_update(timer); +} + +static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer) +{ + omap_clk_adduser(timer->clk, + qemu_allocate_irqs(omap_gp_timer_clk_update, timer, 1)[0]); + timer->rate = omap_clk_getrate(timer->clk); +} + +static void omap_gp_timer_reset(struct omap_gp_timer_s *s) +{ + s->config = 0x000; + s->status = 0; + s->it_ena = 0; + s->wu_ena = 0; + s->inout = 0; + s->capt2 = 0; + s->capt_num = 0; + s->pt = 0; + s->trigger = gpt_trigger_none; + s->capture = gpt_capture_none; + s->scpwm = 0; + s->ce = 0; + s->pre = 0; + s->ptv = 0; + s->ar = 0; + s->st = 0; + s->posted = 1; + s->val = 0x00000000; + s->load_val = 0x00000000; + s->capture_val[0] = 0x00000000; + s->capture_val[1] = 0x00000000; + s->match_val = 0x00000000; + omap_gp_timer_update(s); +} + +static uint32_t omap_gp_timer_readw(void *opaque, target_phys_addr_t addr) +{ + struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* TIDR */ + return 0x21; + + case 0x10: /* TIOCP_CFG */ + return s->config; + + case 0x14: /* TISTAT */ + /* ??? When's this bit reset? */ + return 1; /* RESETDONE */ + + case 0x18: /* TISR */ + return s->status; + + case 0x1c: /* TIER */ + return s->it_ena; + + case 0x20: /* TWER */ + return s->wu_ena; + + case 0x24: /* TCLR */ + return (s->inout << 14) | + (s->capt2 << 13) | + (s->pt << 12) | + (s->trigger << 10) | + (s->capture << 8) | + (s->scpwm << 7) | + (s->ce << 6) | + (s->pre << 5) | + (s->ptv << 2) | + (s->ar << 1) | + (s->st << 0); + + case 0x28: /* TCRR */ + return omap_gp_timer_read(s); + + case 0x2c: /* TLDR */ + return s->load_val; + + case 0x30: /* TTGR */ + return 0xffffffff; + + case 0x34: /* TWPS */ + return 0x00000000; /* No posted writes pending. */ + + case 0x38: /* TMAR */ + return s->match_val; + + case 0x3c: /* TCAR1 */ + return s->capture_val[0]; + + case 0x40: /* TSICR */ + return s->posted << 2; + + case 0x44: /* TCAR2 */ + return s->capture_val[1]; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static uint32_t omap_gp_timer_readh(void *opaque, target_phys_addr_t addr) +{ + struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; + uint32_t ret; + + if (addr & 2) + return s->readh; + else { + ret = omap_gp_timer_readw(opaque, addr); + s->readh = ret >> 16; + return ret & 0xffff; + } +} + +static CPUReadMemoryFunc *omap_gp_timer_readfn[] = { + omap_badwidth_read32, + omap_gp_timer_readh, + omap_gp_timer_readw, +}; + +static void omap_gp_timer_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* TIDR */ + case 0x14: /* TISTAT */ + case 0x34: /* TWPS */ + case 0x3c: /* TCAR1 */ + case 0x44: /* TCAR2 */ + OMAP_RO_REG(addr); + break; + + case 0x10: /* TIOCP_CFG */ + s->config = value & 0x33d; + if (((value >> 3) & 3) == 3) /* IDLEMODE */ + fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n", + __FUNCTION__); + if (value & 2) /* SOFTRESET */ + omap_gp_timer_reset(s); + break; + + case 0x18: /* TISR */ + if (value & GPT_TCAR_IT) + s->capt_num = 0; + if (s->status && !(s->status &= ~value)) + qemu_irq_lower(s->irq); + break; + + case 0x1c: /* TIER */ + s->it_ena = value & 7; + break; + + case 0x20: /* TWER */ + s->wu_ena = value & 7; + break; + + case 0x24: /* TCLR */ + omap_gp_timer_sync(s); + s->inout = (value >> 14) & 1; + s->capt2 = (value >> 13) & 1; + s->pt = (value >> 12) & 1; + s->trigger = (value >> 10) & 3; + if (s->capture == gpt_capture_none && + ((value >> 8) & 3) != gpt_capture_none) + s->capt_num = 0; + s->capture = (value >> 8) & 3; + s->scpwm = (value >> 7) & 1; + s->ce = (value >> 6) & 1; + s->pre = (value >> 5) & 1; + s->ptv = (value >> 2) & 7; + s->ar = (value >> 1) & 1; + s->st = (value >> 0) & 1; + if (s->inout && s->trigger != gpt_trigger_none) + fprintf(stderr, "%s: GP timer pin must be an output " + "for this trigger mode\n", __FUNCTION__); + if (!s->inout && s->capture != gpt_capture_none) + fprintf(stderr, "%s: GP timer pin must be an input " + "for this capture mode\n", __FUNCTION__); + if (s->trigger == gpt_trigger_none) + omap_gp_timer_out(s, s->scpwm); + /* TODO: make sure this doesn't overflow 32-bits */ + s->ticks_per_sec = ticks_per_sec << (s->pre ? s->ptv + 1 : 0); + omap_gp_timer_update(s); + break; + + case 0x28: /* TCRR */ + s->time = qemu_get_clock(vm_clock); + s->val = value; + omap_gp_timer_update(s); + break; + + case 0x2c: /* TLDR */ + s->load_val = value; + break; + + case 0x30: /* TTGR */ + s->time = qemu_get_clock(vm_clock); + s->val = s->load_val; + omap_gp_timer_update(s); + break; + + case 0x38: /* TMAR */ + omap_gp_timer_sync(s); + s->match_val = value; + omap_gp_timer_update(s); + break; + + case 0x40: /* TSICR */ + s->posted = (value >> 2) & 1; + if (value & 2) /* How much exactly are we supposed to reset? */ + omap_gp_timer_reset(s); + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static void omap_gp_timer_writeh(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; + + if (addr & 2) + return omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh); + else + s->writeh = (uint16_t) value; +} + +static CPUWriteMemoryFunc *omap_gp_timer_writefn[] = { + omap_badwidth_write32, + omap_gp_timer_writeh, + omap_gp_timer_write, +}; + +struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta, + qemu_irq irq, omap_clk fclk, omap_clk iclk) +{ + int iomemtype; + struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) + qemu_mallocz(sizeof(struct omap_gp_timer_s)); + + s->ta = ta; + s->irq = irq; + s->clk = fclk; + s->timer = qemu_new_timer(vm_clock, omap_gp_timer_tick, s); + s->match = qemu_new_timer(vm_clock, omap_gp_timer_match, s); + s->in = qemu_allocate_irqs(omap_gp_timer_input, s, 1)[0]; + omap_gp_timer_reset(s); + omap_gp_timer_clk_setup(s); + + iomemtype = l4_register_io_memory(0, omap_gp_timer_readfn, + omap_gp_timer_writefn, s); + s->base = omap_l4_attach(ta, 0, iomemtype); + + return s; +} + +/* 32-kHz Sync Timer of the OMAP2 */ +static uint32_t omap_synctimer_read(struct omap_synctimer_s *s) { + return muldiv64(qemu_get_clock(vm_clock), 0x8000, ticks_per_sec); +} + +static void omap_synctimer_reset(struct omap_synctimer_s *s) +{ + s->val = omap_synctimer_read(s); +} + +static uint32_t omap_synctimer_readw(void *opaque, target_phys_addr_t addr) +{ + struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* 32KSYNCNT_REV */ + return 0x21; + + case 0x10: /* CR */ + return omap_synctimer_read(s) - s->val; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static uint32_t omap_synctimer_readh(void *opaque, target_phys_addr_t addr) +{ + struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque; + uint32_t ret; + + if (addr & 2) + return s->readh; + else { + ret = omap_synctimer_readw(opaque, addr); + s->readh = ret >> 16; + return ret & 0xffff; + } +} + +static CPUReadMemoryFunc *omap_synctimer_readfn[] = { + omap_badwidth_read32, + omap_synctimer_readh, + omap_synctimer_readw, +}; + +static void omap_synctimer_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + OMAP_BAD_REG(addr); +} + +static CPUWriteMemoryFunc *omap_synctimer_writefn[] = { + omap_badwidth_write32, + omap_synctimer_write, + omap_synctimer_write, +}; + +void omap_synctimer_init(struct omap_target_agent_s *ta, + struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk) +{ + struct omap_synctimer_s *s = &mpu->synctimer; + + omap_synctimer_reset(s); + s->base = omap_l4_attach(ta, 0, l4_register_io_memory(0, + omap_synctimer_readfn, omap_synctimer_writefn, s)); +} + +/* General-Purpose Interface of OMAP2 */ +struct omap2_gpio_s { + target_phys_addr_t base; + qemu_irq irq[2]; + qemu_irq wkup; + qemu_irq *in; + qemu_irq handler[32]; + + uint8_t config[2]; + uint32_t inputs; + uint32_t outputs; + uint32_t dir; + uint32_t level[2]; + uint32_t edge[2]; + uint32_t mask[2]; + uint32_t wumask; + uint32_t ints[2]; + uint32_t debounce; + uint8_t delay; +}; + +static inline void omap_gpio_module_int_update(struct omap2_gpio_s *s, + int line) +{ + qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]); +} + +static void omap_gpio_module_wake(struct omap2_gpio_s *s, int line) +{ + if (!(s->config[0] & (1 << 2))) /* ENAWAKEUP */ + return; + if (!(s->config[0] & (3 << 3))) /* Force Idle */ + return; + if (!(s->wumask & (1 << line))) + return; + + qemu_irq_raise(s->wkup); +} + +static inline void omap_gpio_module_out_update(struct omap2_gpio_s *s, + uint32_t diff) +{ + int ln; + + s->outputs ^= diff; + diff &= ~s->dir; + while ((ln = ffs(diff))) { + ln --; + qemu_set_irq(s->handler[ln], (s->outputs >> ln) & 1); + diff &= ~(1 << ln); + } +} + +static void omap_gpio_module_level_update(struct omap2_gpio_s *s, int line) +{ + s->ints[line] |= s->dir & + ((s->inputs & s->level[1]) | (~s->inputs & s->level[0])); + omap_gpio_module_int_update(s, line); +} + +static inline void omap_gpio_module_int(struct omap2_gpio_s *s, int line) +{ + s->ints[0] |= 1 << line; + omap_gpio_module_int_update(s, 0); + s->ints[1] |= 1 << line; + omap_gpio_module_int_update(s, 1); + omap_gpio_module_wake(s, line); +} + +static void omap_gpio_module_set(void *opaque, int line, int level) +{ + struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; + + if (level) { + if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1])) + omap_gpio_module_int(s, line); + s->inputs |= 1 << line; + } else { + if (s->dir & (1 << line) & ((s->inputs & s->edge[1]) | s->level[0])) + omap_gpio_module_int(s, line); + s->inputs &= ~(1 << line); + } +} + +static void omap_gpio_module_reset(struct omap2_gpio_s *s) +{ + s->config[0] = 0; + s->config[1] = 2; + s->ints[0] = 0; + s->ints[1] = 0; + s->mask[0] = 0; + s->mask[1] = 0; + s->wumask = 0; + s->dir = ~0; + s->level[0] = 0; + s->level[1] = 0; + s->edge[0] = 0; + s->edge[1] = 0; + s->debounce = 0; + s->delay = 0; +} + +static uint32_t omap_gpio_module_read(void *opaque, target_phys_addr_t addr) +{ + struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* GPIO_REVISION */ + return 0x18; + + case 0x10: /* GPIO_SYSCONFIG */ + return s->config[0]; + + case 0x14: /* GPIO_SYSSTATUS */ + return 0x01; + + case 0x18: /* GPIO_IRQSTATUS1 */ + return s->ints[0]; + + case 0x1c: /* GPIO_IRQENABLE1 */ + case 0x60: /* GPIO_CLEARIRQENABLE1 */ + case 0x64: /* GPIO_SETIRQENABLE1 */ + return s->mask[0]; + + case 0x20: /* GPIO_WAKEUPENABLE */ + case 0x80: /* GPIO_CLEARWKUENA */ + case 0x84: /* GPIO_SETWKUENA */ + return s->wumask; + + case 0x28: /* GPIO_IRQSTATUS2 */ + return s->ints[1]; + + case 0x2c: /* GPIO_IRQENABLE2 */ + case 0x70: /* GPIO_CLEARIRQENABLE2 */ + case 0x74: /* GPIO_SETIREQNEABLE2 */ + return s->mask[1]; + + case 0x30: /* GPIO_CTRL */ + return s->config[1]; + + case 0x34: /* GPIO_OE */ + return s->dir; + + case 0x38: /* GPIO_DATAIN */ + return s->inputs; + + case 0x3c: /* GPIO_DATAOUT */ + case 0x90: /* GPIO_CLEARDATAOUT */ + case 0x94: /* GPIO_SETDATAOUT */ + return s->outputs; + + case 0x40: /* GPIO_LEVELDETECT0 */ + return s->level[0]; + + case 0x44: /* GPIO_LEVELDETECT1 */ + return s->level[1]; + + case 0x48: /* GPIO_RISINGDETECT */ + return s->edge[0]; + + case 0x4c: /* GPIO_FALLINGDETECT */ + return s->edge[1]; + + case 0x50: /* GPIO_DEBOUNCENABLE */ + return s->debounce; + + case 0x54: /* GPIO_DEBOUNCINGTIME */ + return s->delay; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_gpio_module_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; + int offset = addr - s->base; + uint32_t diff; + int ln; + + switch (offset) { + case 0x00: /* GPIO_REVISION */ + case 0x14: /* GPIO_SYSSTATUS */ + case 0x38: /* GPIO_DATAIN */ + OMAP_RO_REG(addr); + break; + + case 0x10: /* GPIO_SYSCONFIG */ + if (((value >> 3) & 3) == 3) + fprintf(stderr, "%s: bad IDLEMODE value\n", __FUNCTION__); + if (value & 2) + omap_gpio_module_reset(s); + s->config[0] = value & 0x1d; + break; + + case 0x18: /* GPIO_IRQSTATUS1 */ + if (s->ints[0] & value) { + s->ints[0] &= ~value; + omap_gpio_module_level_update(s, 0); + } + break; + + case 0x1c: /* GPIO_IRQENABLE1 */ + s->mask[0] = value; + omap_gpio_module_int_update(s, 0); + break; + + case 0x20: /* GPIO_WAKEUPENABLE */ + s->wumask = value; + break; + + case 0x28: /* GPIO_IRQSTATUS2 */ + if (s->ints[1] & value) { + s->ints[1] &= ~value; + omap_gpio_module_level_update(s, 1); + } + break; + + case 0x2c: /* GPIO_IRQENABLE2 */ + s->mask[1] = value; + omap_gpio_module_int_update(s, 1); + break; + + case 0x30: /* GPIO_CTRL */ + s->config[1] = value & 7; + break; + + case 0x34: /* GPIO_OE */ + diff = s->outputs & (s->dir ^ value); + s->dir = value; + + value = s->outputs & ~s->dir; + while ((ln = ffs(diff))) { + diff &= ~(1 <<-- ln); + qemu_set_irq(s->handler[ln], (value >> ln) & 1); + } + + omap_gpio_module_level_update(s, 0); + omap_gpio_module_level_update(s, 1); + break; + + case 0x3c: /* GPIO_DATAOUT */ + omap_gpio_module_out_update(s, s->outputs ^ value); + break; + + case 0x40: /* GPIO_LEVELDETECT0 */ + s->level[0] = value; + omap_gpio_module_level_update(s, 0); + omap_gpio_module_level_update(s, 1); + break; + + case 0x44: /* GPIO_LEVELDETECT1 */ + s->level[1] = value; + omap_gpio_module_level_update(s, 0); + omap_gpio_module_level_update(s, 1); + break; + + case 0x48: /* GPIO_RISINGDETECT */ + s->edge[0] = value; + break; + + case 0x4c: /* GPIO_FALLINGDETECT */ + s->edge[1] = value; + break; + + case 0x50: /* GPIO_DEBOUNCENABLE */ + s->debounce = value; + break; + + case 0x54: /* GPIO_DEBOUNCINGTIME */ + s->delay = value; + break; + + case 0x60: /* GPIO_CLEARIRQENABLE1 */ + s->mask[0] &= ~value; + omap_gpio_module_int_update(s, 0); + break; + + case 0x64: /* GPIO_SETIRQENABLE1 */ + s->mask[0] |= value; + omap_gpio_module_int_update(s, 0); + break; + + case 0x70: /* GPIO_CLEARIRQENABLE2 */ + s->mask[1] &= ~value; + omap_gpio_module_int_update(s, 1); + break; + + case 0x74: /* GPIO_SETIREQNEABLE2 */ + s->mask[1] |= value; + omap_gpio_module_int_update(s, 1); + break; + + case 0x80: /* GPIO_CLEARWKUENA */ + s->wumask &= ~value; + break; + + case 0x84: /* GPIO_SETWKUENA */ + s->wumask |= value; + break; + + case 0x90: /* GPIO_CLEARDATAOUT */ + omap_gpio_module_out_update(s, s->outputs & value); + break; + + case 0x94: /* GPIO_SETDATAOUT */ + omap_gpio_module_out_update(s, ~s->outputs & value); + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static uint32_t omap_gpio_module_readp(void *opaque, target_phys_addr_t addr) +{ + return omap_gpio_module_readp(opaque, addr) >> ((addr & 3) << 3); +} + +static void omap_gpio_module_writep(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; + int offset = addr - s->base; + uint32_t cur = 0; + uint32_t mask = 0xffff; + + switch (offset & ~3) { + case 0x00: /* GPIO_REVISION */ + case 0x14: /* GPIO_SYSSTATUS */ + case 0x38: /* GPIO_DATAIN */ + OMAP_RO_REG(addr); + break; + + case 0x10: /* GPIO_SYSCONFIG */ + case 0x1c: /* GPIO_IRQENABLE1 */ + case 0x20: /* GPIO_WAKEUPENABLE */ + case 0x2c: /* GPIO_IRQENABLE2 */ + case 0x30: /* GPIO_CTRL */ + case 0x34: /* GPIO_OE */ + case 0x3c: /* GPIO_DATAOUT */ + case 0x40: /* GPIO_LEVELDETECT0 */ + case 0x44: /* GPIO_LEVELDETECT1 */ + case 0x48: /* GPIO_RISINGDETECT */ + case 0x4c: /* GPIO_FALLINGDETECT */ + case 0x50: /* GPIO_DEBOUNCENABLE */ + case 0x54: /* GPIO_DEBOUNCINGTIME */ + cur = omap_gpio_module_read(opaque, addr & ~3) & + ~(mask << ((addr & 3) << 3)); + + /* Fall through. */ + case 0x18: /* GPIO_IRQSTATUS1 */ + case 0x28: /* GPIO_IRQSTATUS2 */ + case 0x60: /* GPIO_CLEARIRQENABLE1 */ + case 0x64: /* GPIO_SETIRQENABLE1 */ + case 0x70: /* GPIO_CLEARIRQENABLE2 */ + case 0x74: /* GPIO_SETIREQNEABLE2 */ + case 0x80: /* GPIO_CLEARWKUENA */ + case 0x84: /* GPIO_SETWKUENA */ + case 0x90: /* GPIO_CLEARDATAOUT */ + case 0x94: /* GPIO_SETDATAOUT */ + value <<= (addr & 3) << 3; + omap_gpio_module_write(opaque, addr, cur | value); + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_gpio_module_readfn[] = { + omap_gpio_module_readp, + omap_gpio_module_readp, + omap_gpio_module_read, +}; + +static CPUWriteMemoryFunc *omap_gpio_module_writefn[] = { + omap_gpio_module_writep, + omap_gpio_module_writep, + omap_gpio_module_write, +}; + +static void omap_gpio_module_init(struct omap2_gpio_s *s, + struct omap_target_agent_s *ta, int region, + qemu_irq mpu, qemu_irq dsp, qemu_irq wkup, + omap_clk fclk, omap_clk iclk) +{ + int iomemtype; + + s->irq[0] = mpu; + s->irq[1] = dsp; + s->wkup = wkup; + s->in = qemu_allocate_irqs(omap_gpio_module_set, s, 32); + + iomemtype = l4_register_io_memory(0, omap_gpio_module_readfn, + omap_gpio_module_writefn, s); + s->base = omap_l4_attach(ta, region, iomemtype); +} + +struct omap_gpif_s { + struct omap2_gpio_s module[5]; + int modules; + + target_phys_addr_t topbase; + int autoidle; + int gpo; +}; + +static void omap_gpif_reset(struct omap_gpif_s *s) +{ + int i; + + for (i = 0; i < s->modules; i ++) + omap_gpio_module_reset(s->module + i); + + s->autoidle = 0; + s->gpo = 0; +} + +static uint32_t omap_gpif_top_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_gpif_s *s = (struct omap_gpif_s *) opaque; + int offset = addr - s->topbase; + + switch (offset) { + case 0x00: /* IPGENERICOCPSPL_REVISION */ + return 0x18; + + case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */ + return s->autoidle; + + case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */ + return 0x01; + + case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */ + return 0x00; + + case 0x40: /* IPGENERICOCPSPL_GPO */ + return s->gpo; + + case 0x50: /* IPGENERICOCPSPL_GPI */ + return 0x00; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_gpif_s *s = (struct omap_gpif_s *) opaque; + int offset = addr - s->topbase; + + switch (offset) { + case 0x00: /* IPGENERICOCPSPL_REVISION */ + case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */ + case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */ + case 0x50: /* IPGENERICOCPSPL_GPI */ + OMAP_RO_REG(addr); + break; + + case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */ + if (value & (1 << 1)) /* SOFTRESET */ + omap_gpif_reset(s); + s->autoidle = value & 1; + break; + + case 0x40: /* IPGENERICOCPSPL_GPO */ + s->gpo = value & 1; + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_gpif_top_readfn[] = { + omap_gpif_top_read, + omap_gpif_top_read, + omap_gpif_top_read, +}; + +static CPUWriteMemoryFunc *omap_gpif_top_writefn[] = { + omap_gpif_top_write, + omap_gpif_top_write, + omap_gpif_top_write, +}; + +struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta, + qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules) +{ + int iomemtype, i; + struct omap_gpif_s *s = (struct omap_gpif_s *) + qemu_mallocz(sizeof(struct omap_gpif_s)); + int region[4] = { 0, 2, 4, 5 }; + + s->modules = modules; + for (i = 0; i < modules; i ++) + omap_gpio_module_init(s->module + i, ta, region[i], + irq[i], 0, 0, fclk[i], iclk); + + omap_gpif_reset(s); + + iomemtype = l4_register_io_memory(0, omap_gpif_top_readfn, + omap_gpif_top_writefn, s); + s->topbase = omap_l4_attach(ta, 1, iomemtype); + + return s; +} + +qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start) +{ + if (start >= s->modules * 32 || start < 0) + cpu_abort(cpu_single_env, "%s: No GPIO line %i\n", + __FUNCTION__, start); + return s->module[start >> 5].in + (start & 31); +} + +void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler) +{ + if (line >= s->modules * 32 || line < 0) + cpu_abort(cpu_single_env, "%s: No GPIO line %i\n", __FUNCTION__, line); + s->module[line >> 5].handler[line & 31] = handler; +} + +/* Multichannel SPI */ +struct omap_mcspi_s { + target_phys_addr_t base; + qemu_irq irq; + int chnum; + + uint32_t sysconfig; + uint32_t systest; + uint32_t irqst; + uint32_t irqen; + uint32_t wken; + uint32_t control; + + struct omap_mcspi_ch_s { + qemu_irq txdrq; + qemu_irq rxdrq; + uint32_t (*txrx)(void *opaque, uint32_t, int); + void *opaque; + + uint32_t tx; + uint32_t rx; + + uint32_t config; + uint32_t status; + uint32_t control; + } ch[4]; +}; + +static inline void omap_mcspi_interrupt_update(struct omap_mcspi_s *s) +{ + qemu_set_irq(s->irq, s->irqst & s->irqen); +} + +static inline void omap_mcspi_dmarequest_update(struct omap_mcspi_ch_s *ch) +{ + qemu_set_irq(ch->txdrq, + (ch->control & 1) && /* EN */ + (ch->config & (1 << 14)) && /* DMAW */ + (ch->status & (1 << 1)) && /* TXS */ + ((ch->config >> 12) & 3) != 1); /* TRM */ + qemu_set_irq(ch->rxdrq, + (ch->control & 1) && /* EN */ + (ch->config & (1 << 15)) && /* DMAW */ + (ch->status & (1 << 0)) && /* RXS */ + ((ch->config >> 12) & 3) != 2); /* TRM */ +} + +static void omap_mcspi_transfer_run(struct omap_mcspi_s *s, int chnum) +{ + struct omap_mcspi_ch_s *ch = s->ch + chnum; + + if (!(ch->control & 1)) /* EN */ + return; + if ((ch->status & (1 << 0)) && /* RXS */ + ((ch->config >> 12) & 3) != 2 && /* TRM */ + !(ch->config & (1 << 19))) /* TURBO */ + goto intr_update; + if ((ch->status & (1 << 1)) && /* TXS */ + ((ch->config >> 12) & 3) != 1) /* TRM */ + goto intr_update; + + if (!(s->control & 1) || /* SINGLE */ + (ch->config & (1 << 20))) { /* FORCE */ + if (ch->txrx) + ch->rx = ch->txrx(ch->opaque, ch->tx, /* WL */ + 1 + (0x1f & (ch->config >> 7))); + } + + ch->tx = 0; + ch->status |= 1 << 2; /* EOT */ + ch->status |= 1 << 1; /* TXS */ + if (((ch->config >> 12) & 3) != 2) /* TRM */ + ch->status |= 1 << 0; /* RXS */ + +intr_update: + if ((ch->status & (1 << 0)) && /* RXS */ + ((ch->config >> 12) & 3) != 2 && /* TRM */ + !(ch->config & (1 << 19))) /* TURBO */ + s->irqst |= 1 << (2 + 4 * chnum); /* RX_FULL */ + if ((ch->status & (1 << 1)) && /* TXS */ + ((ch->config >> 12) & 3) != 1) /* TRM */ + s->irqst |= 1 << (0 + 4 * chnum); /* TX_EMPTY */ + omap_mcspi_interrupt_update(s); + omap_mcspi_dmarequest_update(ch); +} + +static void omap_mcspi_reset(struct omap_mcspi_s *s) +{ + int ch; + + s->sysconfig = 0; + s->systest = 0; + s->irqst = 0; + s->irqen = 0; + s->wken = 0; + s->control = 4; + + for (ch = 0; ch < 4; ch ++) { + s->ch[ch].config = 0x060000; + s->ch[ch].status = 2; /* TXS */ + s->ch[ch].control = 0; + + omap_mcspi_dmarequest_update(s->ch + ch); + } + + omap_mcspi_interrupt_update(s); +} + +static uint32_t omap_mcspi_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque; + int offset = addr - s->base; + int ch = 0; + uint32_t ret; + + switch (offset) { + case 0x00: /* MCSPI_REVISION */ + return 0x91; + + case 0x10: /* MCSPI_SYSCONFIG */ + return s->sysconfig; + + case 0x14: /* MCSPI_SYSSTATUS */ + return 1; /* RESETDONE */ + + case 0x18: /* MCSPI_IRQSTATUS */ + return s->irqst; + + case 0x1c: /* MCSPI_IRQENABLE */ + return s->irqen; + + case 0x20: /* MCSPI_WAKEUPENABLE */ + return s->wken; + + case 0x24: /* MCSPI_SYST */ + return s->systest; + + case 0x28: /* MCSPI_MODULCTRL */ + return s->control; + + case 0x68: ch ++; + case 0x54: ch ++; + case 0x40: ch ++; + case 0x2c: /* MCSPI_CHCONF */ + return s->ch[ch].config; + + case 0x6c: ch ++; + case 0x58: ch ++; + case 0x44: ch ++; + case 0x30: /* MCSPI_CHSTAT */ + return s->ch[ch].status; + + case 0x70: ch ++; + case 0x5c: ch ++; + case 0x48: ch ++; + case 0x34: /* MCSPI_CHCTRL */ + return s->ch[ch].control; + + case 0x74: ch ++; + case 0x60: ch ++; + case 0x4c: ch ++; + case 0x38: /* MCSPI_TX */ + return s->ch[ch].tx; + + case 0x78: ch ++; + case 0x64: ch ++; + case 0x50: ch ++; + case 0x3c: /* MCSPI_RX */ + s->ch[ch].status &= ~(1 << 0); /* RXS */ + ret = s->ch[ch].rx; + omap_mcspi_transfer_run(s, ch); + return ret; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_mcspi_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque; + int offset = addr - s->base; + int ch = 0; + + switch (offset) { + case 0x00: /* MCSPI_REVISION */ + case 0x14: /* MCSPI_SYSSTATUS */ + case 0x30: /* MCSPI_CHSTAT0 */ + case 0x3c: /* MCSPI_RX0 */ + case 0x44: /* MCSPI_CHSTAT1 */ + case 0x50: /* MCSPI_RX1 */ + case 0x58: /* MCSPI_CHSTAT2 */ + case 0x64: /* MCSPI_RX2 */ + case 0x6c: /* MCSPI_CHSTAT3 */ + case 0x78: /* MCSPI_RX3 */ + OMAP_RO_REG(addr); + return; + + case 0x10: /* MCSPI_SYSCONFIG */ + if (value & (1 << 1)) /* SOFTRESET */ + omap_mcspi_reset(s); + s->sysconfig = value & 0x31d; + break; + + case 0x18: /* MCSPI_IRQSTATUS */ + if (!((s->control & (1 << 3)) && (s->systest & (1 << 11)))) { + s->irqst &= ~value; + omap_mcspi_interrupt_update(s); + } + break; + + case 0x1c: /* MCSPI_IRQENABLE */ + s->irqen = value & 0x1777f; + omap_mcspi_interrupt_update(s); + break; + + case 0x20: /* MCSPI_WAKEUPENABLE */ + s->wken = value & 1; + break; + + case 0x24: /* MCSPI_SYST */ + if (s->control & (1 << 3)) /* SYSTEM_TEST */ + if (value & (1 << 11)) { /* SSB */ + s->irqst |= 0x1777f; + omap_mcspi_interrupt_update(s); + } + s->systest = value & 0xfff; + break; + + case 0x28: /* MCSPI_MODULCTRL */ + if (value & (1 << 3)) /* SYSTEM_TEST */ + if (s->systest & (1 << 11)) { /* SSB */ + s->irqst |= 0x1777f; + omap_mcspi_interrupt_update(s); + } + s->control = value & 0xf; + break; + + case 0x68: ch ++; + case 0x54: ch ++; + case 0x40: ch ++; + case 0x2c: /* MCSPI_CHCONF */ + if ((value ^ s->ch[ch].config) & (3 << 14)) /* DMAR | DMAW */ + omap_mcspi_dmarequest_update(s->ch + ch); + if (((value >> 12) & 3) == 3) /* TRM */ + fprintf(stderr, "%s: invalid TRM value (3)\n", __FUNCTION__); + if (((value >> 7) & 0x1f) < 3) /* WL */ + fprintf(stderr, "%s: invalid WL value (%i)\n", + __FUNCTION__, (value >> 7) & 0x1f); + s->ch[ch].config = value & 0x7fffff; + break; + + case 0x70: ch ++; + case 0x5c: ch ++; + case 0x48: ch ++; + case 0x34: /* MCSPI_CHCTRL */ + if (value & ~s->ch[ch].control & 1) { /* EN */ + s->ch[ch].control |= 1; + omap_mcspi_transfer_run(s, ch); + } else + s->ch[ch].control = value & 1; + break; + + case 0x74: ch ++; + case 0x60: ch ++; + case 0x4c: ch ++; + case 0x38: /* MCSPI_TX */ + s->ch[ch].tx = value; + s->ch[ch].status &= ~(1 << 1); /* TXS */ + omap_mcspi_transfer_run(s, ch); + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_mcspi_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_mcspi_read, +}; + +static CPUWriteMemoryFunc *omap_mcspi_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_mcspi_write, +}; + +struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum, + qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk) +{ + int iomemtype; + struct omap_mcspi_s *s = (struct omap_mcspi_s *) + qemu_mallocz(sizeof(struct omap_mcspi_s)); + struct omap_mcspi_ch_s *ch = s->ch; + + s->irq = irq; + s->chnum = chnum; + while (chnum --) { + ch->txdrq = *drq ++; + ch->rxdrq = *drq ++; + ch ++; + } + omap_mcspi_reset(s); + + iomemtype = l4_register_io_memory(0, omap_mcspi_readfn, + omap_mcspi_writefn, s); + s->base = omap_l4_attach(ta, 0, iomemtype); + + return s; +} + +void omap_mcspi_attach(struct omap_mcspi_s *s, + uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque, + int chipselect) +{ + if (chipselect < 0 || chipselect >= s->chnum) + cpu_abort(cpu_single_env, "%s: Bad chipselect %i\n", + __FUNCTION__, chipselect); + + s->ch[chipselect].txrx = txrx; + s->ch[chipselect].opaque = opaque; +} + +/* Enhanced Audio Controller (CODEC only) */ +struct omap_eac_s { + target_phys_addr_t base; + qemu_irq irq; + + uint16_t sysconfig; + uint8_t config[4]; + uint8_t control; + uint8_t address; + uint16_t data; + uint8_t vtol; + uint8_t vtsl; + uint16_t mixer; + uint16_t gain[4]; + uint8_t att; + uint16_t max[7]; + + struct { + qemu_irq txdrq; + qemu_irq rxdrq; + uint32_t (*txrx)(void *opaque, uint32_t, int); + void *opaque; + +#define EAC_BUF_LEN 1024 + uint32_t rxbuf[EAC_BUF_LEN]; + int rxoff; + int rxlen; + int rxavail; + uint32_t txbuf[EAC_BUF_LEN]; + int txlen; + int txavail; + + int enable; + int rate; + + uint16_t config[4]; + + /* These need to be moved to the actual codec */ + QEMUSoundCard card; + SWVoiceIn *in_voice; + SWVoiceOut *out_voice; + int hw_enable; + } codec; + + struct { + uint8_t control; + uint16_t config; + } modem, bt; +}; + +static inline void omap_eac_interrupt_update(struct omap_eac_s *s) +{ + qemu_set_irq(s->irq, (s->codec.config[1] >> 14) & 1); /* AURDI */ +} + +static inline void omap_eac_in_dmarequest_update(struct omap_eac_s *s) +{ + qemu_set_irq(s->codec.rxdrq, (s->codec.rxavail || s->codec.rxlen) && + ((s->codec.config[1] >> 12) & 1)); /* DMAREN */ +} + +static inline void omap_eac_out_dmarequest_update(struct omap_eac_s *s) +{ + qemu_set_irq(s->codec.txdrq, s->codec.txlen < s->codec.txavail && + ((s->codec.config[1] >> 11) & 1)); /* DMAWEN */ +} + +static inline void omap_eac_in_refill(struct omap_eac_s *s) +{ + int left = MIN(EAC_BUF_LEN - s->codec.rxlen, s->codec.rxavail) << 2; + int start = ((s->codec.rxoff + s->codec.rxlen) & (EAC_BUF_LEN - 1)) << 2; + int leftwrap = MIN(left, (EAC_BUF_LEN << 2) - start); + int recv = 1; + uint8_t *buf = (uint8_t *) s->codec.rxbuf + start; + + left -= leftwrap; + start = 0; + while (leftwrap && (recv = AUD_read(s->codec.in_voice, buf + start, + leftwrap)) > 0) { /* Be defensive */ + start += recv; + leftwrap -= recv; + } + if (recv <= 0) + s->codec.rxavail = 0; + else + s->codec.rxavail -= start >> 2; + s->codec.rxlen += start >> 2; + + if (recv > 0 && left > 0) { + start = 0; + while (left && (recv = AUD_read(s->codec.in_voice, + (uint8_t *) s->codec.rxbuf + start, + left)) > 0) { /* Be defensive */ + start += recv; + left -= recv; + } + if (recv <= 0) + s->codec.rxavail = 0; + else + s->codec.rxavail -= start >> 2; + s->codec.rxlen += start >> 2; + } +} + +static inline void omap_eac_out_empty(struct omap_eac_s *s) +{ + int left = s->codec.txlen << 2; + int start = 0; + int sent = 1; + + while (left && (sent = AUD_write(s->codec.out_voice, + (uint8_t *) s->codec.txbuf + start, + left)) > 0) { /* Be defensive */ + start += sent; + left -= sent; + } + + if (!sent) { + s->codec.txavail = 0; + omap_eac_out_dmarequest_update(s); + } + + if (start) + s->codec.txlen = 0; +} + +static void omap_eac_in_cb(void *opaque, int avail_b) +{ + struct omap_eac_s *s = (struct omap_eac_s *) opaque; + + s->codec.rxavail = avail_b >> 2; + omap_eac_in_refill(s); + /* TODO: possibly discard current buffer if overrun */ + omap_eac_in_dmarequest_update(s); +} + +static void omap_eac_out_cb(void *opaque, int free_b) +{ + struct omap_eac_s *s = (struct omap_eac_s *) opaque; + + s->codec.txavail = free_b >> 2; + if (s->codec.txlen) + omap_eac_out_empty(s); + else + omap_eac_out_dmarequest_update(s); +} + +static void omap_eac_enable_update(struct omap_eac_s *s) +{ + s->codec.enable = !(s->codec.config[1] & 1) && /* EACPWD */ + (s->codec.config[1] & 2) && /* AUDEN */ + s->codec.hw_enable; +} + +static const int omap_eac_fsint[4] = { + 8000, + 11025, + 22050, + 44100, +}; + +static const int omap_eac_fsint2[8] = { + 8000, + 11025, + 22050, + 44100, + 48000, + 0, 0, 0, +}; + +static const int omap_eac_fsint3[16] = { + 8000, + 11025, + 16000, + 22050, + 24000, + 32000, + 44100, + 48000, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static void omap_eac_rate_update(struct omap_eac_s *s) +{ + int fsint[3]; + + fsint[2] = (s->codec.config[3] >> 9) & 0xf; + fsint[1] = (s->codec.config[2] >> 0) & 0x7; + fsint[0] = (s->codec.config[0] >> 6) & 0x3; + if (fsint[2] < 0xf) + s->codec.rate = omap_eac_fsint3[fsint[2]]; + else if (fsint[1] < 0x7) + s->codec.rate = omap_eac_fsint2[fsint[1]]; + else + s->codec.rate = omap_eac_fsint[fsint[0]]; +} + +static void omap_eac_volume_update(struct omap_eac_s *s) +{ + /* TODO */ +} + +static void omap_eac_format_update(struct omap_eac_s *s) +{ + audsettings_t fmt; + + /* The hardware buffers at most one sample */ + if (s->codec.rxlen) + s->codec.rxlen = 1; + + if (s->codec.in_voice) { + AUD_set_active_in(s->codec.in_voice, 0); + AUD_close_in(&s->codec.card, s->codec.in_voice); + s->codec.in_voice = 0; + } + if (s->codec.out_voice) { + omap_eac_out_empty(s); + AUD_set_active_out(s->codec.out_voice, 0); + AUD_close_out(&s->codec.card, s->codec.out_voice); + s->codec.out_voice = 0; + s->codec.txavail = 0; + } + /* Discard what couldn't be written */ + s->codec.txlen = 0; + + omap_eac_enable_update(s); + if (!s->codec.enable) + return; + + omap_eac_rate_update(s); + fmt.endianness = ((s->codec.config[0] >> 8) & 1); /* LI_BI */ + fmt.nchannels = ((s->codec.config[0] >> 10) & 1) ? 2 : 1; /* MN_ST */ + fmt.freq = s->codec.rate; + /* TODO: signedness possibly depends on the CODEC hardware - or + * does I2S specify it? */ + /* All register writes are 16 bits so we we store 16-bit samples + * in the buffers regardless of AGCFR[B8_16] value. */ + fmt.fmt = AUD_FMT_U16; + + s->codec.in_voice = AUD_open_in(&s->codec.card, s->codec.in_voice, + "eac.codec.in", s, omap_eac_in_cb, &fmt); + s->codec.out_voice = AUD_open_out(&s->codec.card, s->codec.out_voice, + "eac.codec.out", s, omap_eac_out_cb, &fmt); + + omap_eac_volume_update(s); + + AUD_set_active_in(s->codec.in_voice, 1); + AUD_set_active_out(s->codec.out_voice, 1); +} + +static void omap_eac_reset(struct omap_eac_s *s) +{ + s->sysconfig = 0; + s->config[0] = 0x0c; + s->config[1] = 0x09; + s->config[2] = 0xab; + s->config[3] = 0x03; + s->control = 0x00; + s->address = 0x00; + s->data = 0x0000; + s->vtol = 0x00; + s->vtsl = 0x00; + s->mixer = 0x0000; + s->gain[0] = 0xe7e7; + s->gain[1] = 0x6767; + s->gain[2] = 0x6767; + s->gain[3] = 0x6767; + s->att = 0xce; + s->max[0] = 0; + s->max[1] = 0; + s->max[2] = 0; + s->max[3] = 0; + s->max[4] = 0; + s->max[5] = 0; + s->max[6] = 0; + + s->modem.control = 0x00; + s->modem.config = 0x0000; + s->bt.control = 0x00; + s->bt.config = 0x0000; + s->codec.config[0] = 0x0649; + s->codec.config[1] = 0x0000; + s->codec.config[2] = 0x0007; + s->codec.config[3] = 0x1ffc; + s->codec.rxoff = 0; + s->codec.rxlen = 0; + s->codec.txlen = 0; + s->codec.rxavail = 0; + s->codec.txavail = 0; + + omap_eac_format_update(s); + omap_eac_interrupt_update(s); +} + +static uint32_t omap_eac_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_eac_s *s = (struct omap_eac_s *) opaque; + int offset = addr - s->base; + uint32_t ret; + + switch (offset) { + case 0x000: /* CPCFR1 */ + return s->config[0]; + case 0x004: /* CPCFR2 */ + return s->config[1]; + case 0x008: /* CPCFR3 */ + return s->config[2]; + case 0x00c: /* CPCFR4 */ + return s->config[3]; + + case 0x010: /* CPTCTL */ + return s->control | ((s->codec.rxavail + s->codec.rxlen > 0) << 7) | + ((s->codec.txlen < s->codec.txavail) << 5); + + case 0x014: /* CPTTADR */ + return s->address; + case 0x018: /* CPTDATL */ + return s->data & 0xff; + case 0x01c: /* CPTDATH */ + return s->data >> 8; + case 0x020: /* CPTVSLL */ + return s->vtol; + case 0x024: /* CPTVSLH */ + return s->vtsl | (3 << 5); /* CRDY1 | CRDY2 */ + case 0x040: /* MPCTR */ + return s->modem.control; + case 0x044: /* MPMCCFR */ + return s->modem.config; + case 0x060: /* BPCTR */ + return s->bt.control; + case 0x064: /* BPMCCFR */ + return s->bt.config; + case 0x080: /* AMSCFR */ + return s->mixer; + case 0x084: /* AMVCTR */ + return s->gain[0]; + case 0x088: /* AM1VCTR */ + return s->gain[1]; + case 0x08c: /* AM2VCTR */ + return s->gain[2]; + case 0x090: /* AM3VCTR */ + return s->gain[3]; + case 0x094: /* ASTCTR */ + return s->att; + case 0x098: /* APD1LCR */ + return s->max[0]; + case 0x09c: /* APD1RCR */ + return s->max[1]; + case 0x0a0: /* APD2LCR */ + return s->max[2]; + case 0x0a4: /* APD2RCR */ + return s->max[3]; + case 0x0a8: /* APD3LCR */ + return s->max[4]; + case 0x0ac: /* APD3RCR */ + return s->max[5]; + case 0x0b0: /* APD4R */ + return s->max[6]; + case 0x0b4: /* ADWR */ + /* This should be write-only? Docs list it as read-only. */ + return 0x0000; + case 0x0b8: /* ADRDR */ + if (likely(s->codec.rxlen > 1)) { + ret = s->codec.rxbuf[s->codec.rxoff ++]; + s->codec.rxlen --; + s->codec.rxoff &= EAC_BUF_LEN - 1; + return ret; + } else if (s->codec.rxlen) { + ret = s->codec.rxbuf[s->codec.rxoff ++]; + s->codec.rxlen --; + s->codec.rxoff &= EAC_BUF_LEN - 1; + if (s->codec.rxavail) + omap_eac_in_refill(s); + omap_eac_in_dmarequest_update(s); + return ret; + } + return 0x0000; + case 0x0bc: /* AGCFR */ + return s->codec.config[0]; + case 0x0c0: /* AGCTR */ + return s->codec.config[1] | ((s->codec.config[1] & 2) << 14); + case 0x0c4: /* AGCFR2 */ + return s->codec.config[2]; + case 0x0c8: /* AGCFR3 */ + return s->codec.config[3]; + case 0x0cc: /* MBPDMACTR */ + case 0x0d0: /* MPDDMARR */ + case 0x0d8: /* MPUDMARR */ + case 0x0e4: /* BPDDMARR */ + case 0x0ec: /* BPUDMARR */ + return 0x0000; + + case 0x100: /* VERSION_NUMBER */ + return 0x0010; + + case 0x104: /* SYSCONFIG */ + return s->sysconfig; + + case 0x108: /* SYSSTATUS */ + return 1 | 0xe; /* RESETDONE | stuff */ + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_eac_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_eac_s *s = (struct omap_eac_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x098: /* APD1LCR */ + case 0x09c: /* APD1RCR */ + case 0x0a0: /* APD2LCR */ + case 0x0a4: /* APD2RCR */ + case 0x0a8: /* APD3LCR */ + case 0x0ac: /* APD3RCR */ + case 0x0b0: /* APD4R */ + case 0x0b8: /* ADRDR */ + case 0x0d0: /* MPDDMARR */ + case 0x0d8: /* MPUDMARR */ + case 0x0e4: /* BPDDMARR */ + case 0x0ec: /* BPUDMARR */ + case 0x100: /* VERSION_NUMBER */ + case 0x108: /* SYSSTATUS */ + OMAP_RO_REG(addr); + return; + + case 0x000: /* CPCFR1 */ + s->config[0] = value & 0xff; + omap_eac_format_update(s); + break; + case 0x004: /* CPCFR2 */ + s->config[1] = value & 0xff; + omap_eac_format_update(s); + break; + case 0x008: /* CPCFR3 */ + s->config[2] = value & 0xff; + omap_eac_format_update(s); + break; + case 0x00c: /* CPCFR4 */ + s->config[3] = value & 0xff; + omap_eac_format_update(s); + break; + + case 0x010: /* CPTCTL */ + /* Assuming TXF and TXE bits are read-only... */ + s->control = value & 0x5f; + omap_eac_interrupt_update(s); + break; + + case 0x014: /* CPTTADR */ + s->address = value & 0xff; + break; + case 0x018: /* CPTDATL */ + s->data &= 0xff00; + s->data |= value & 0xff; + break; + case 0x01c: /* CPTDATH */ + s->data &= 0x00ff; + s->data |= value << 8; + break; + case 0x020: /* CPTVSLL */ + s->vtol = value & 0xf8; + break; + case 0x024: /* CPTVSLH */ + s->vtsl = value & 0x9f; + break; + case 0x040: /* MPCTR */ + s->modem.control = value & 0x8f; + break; + case 0x044: /* MPMCCFR */ + s->modem.config = value & 0x7fff; + break; + case 0x060: /* BPCTR */ + s->bt.control = value & 0x8f; + break; + case 0x064: /* BPMCCFR */ + s->bt.config = value & 0x7fff; + break; + case 0x080: /* AMSCFR */ + s->mixer = value & 0x0fff; + break; + case 0x084: /* AMVCTR */ + s->gain[0] = value & 0xffff; + break; + case 0x088: /* AM1VCTR */ + s->gain[1] = value & 0xff7f; + break; + case 0x08c: /* AM2VCTR */ + s->gain[2] = value & 0xff7f; + break; + case 0x090: /* AM3VCTR */ + s->gain[3] = value & 0xff7f; + break; + case 0x094: /* ASTCTR */ + s->att = value & 0xff; + break; + + case 0x0b4: /* ADWR */ + s->codec.txbuf[s->codec.txlen ++] = value; + if (unlikely(s->codec.txlen == EAC_BUF_LEN || + s->codec.txlen == s->codec.txavail)) { + if (s->codec.txavail) + omap_eac_out_empty(s); + /* Discard what couldn't be written */ + s->codec.txlen = 0; + } + break; + + case 0x0bc: /* AGCFR */ + s->codec.config[0] = value & 0x07ff; + omap_eac_format_update(s); + break; + case 0x0c0: /* AGCTR */ + s->codec.config[1] = value & 0x780f; + omap_eac_format_update(s); + break; + case 0x0c4: /* AGCFR2 */ + s->codec.config[2] = value & 0x003f; + omap_eac_format_update(s); + break; + case 0x0c8: /* AGCFR3 */ + s->codec.config[3] = value & 0xffff; + omap_eac_format_update(s); + break; + case 0x0cc: /* MBPDMACTR */ + case 0x0d4: /* MPDDMAWR */ + case 0x0e0: /* MPUDMAWR */ + case 0x0e8: /* BPDDMAWR */ + case 0x0f0: /* BPUDMAWR */ + break; + + case 0x104: /* SYSCONFIG */ + if (value & (1 << 1)) /* SOFTRESET */ + omap_eac_reset(s); + s->sysconfig = value & 0x31d; + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_eac_readfn[] = { + omap_badwidth_read16, + omap_eac_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_eac_writefn[] = { + omap_badwidth_write16, + omap_eac_write, + omap_badwidth_write16, +}; + +struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta, + qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk) +{ + int iomemtype; + struct omap_eac_s *s = (struct omap_eac_s *) + qemu_mallocz(sizeof(struct omap_eac_s)); + + s->irq = irq; + s->codec.rxdrq = *drq ++; + s->codec.txdrq = *drq ++; + omap_eac_reset(s); + +#ifdef HAS_AUDIO + /* TODO: do AUD_init globally for machine */ + AUD_register_card(AUD_init(), "OMAP EAC", &s->codec.card); + + iomemtype = cpu_register_io_memory(0, omap_eac_readfn, + omap_eac_writefn, s); + s->base = omap_l4_attach(ta, 0, iomemtype); +#endif + + return s; +} + +/* STI/XTI (emulation interface) console - reverse engineered only */ +struct omap_sti_s { + target_phys_addr_t base; + target_phys_addr_t channel_base; + qemu_irq irq; + CharDriverState *chr; + + uint32_t sysconfig; + uint32_t systest; + uint32_t irqst; + uint32_t irqen; + uint32_t clkcontrol; + uint32_t serial_config; +}; + +#define STI_TRACE_CONSOLE_CHANNEL 239 +#define STI_TRACE_CONTROL_CHANNEL 253 + +static inline void omap_sti_interrupt_update(struct omap_sti_s *s) +{ + qemu_set_irq(s->irq, s->irqst & s->irqen); +} + +static void omap_sti_reset(struct omap_sti_s *s) +{ + s->sysconfig = 0; + s->irqst = 0; + s->irqen = 0; + s->clkcontrol = 0; + s->serial_config = 0; + + omap_sti_interrupt_update(s); +} + +static uint32_t omap_sti_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_sti_s *s = (struct omap_sti_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* STI_REVISION */ + return 0x10; + + case 0x10: /* STI_SYSCONFIG */ + return s->sysconfig; + + case 0x14: /* STI_SYSSTATUS / STI_RX_STATUS / XTI_SYSSTATUS */ + return 0x00; + + case 0x18: /* STI_IRQSTATUS */ + return s->irqst; + + case 0x1c: /* STI_IRQSETEN / STI_IRQCLREN */ + return s->irqen; + + case 0x24: /* STI_ER / STI_DR / XTI_TRACESELECT */ + case 0x28: /* STI_RX_DR / XTI_RXDATA */ + /* TODO */ + return 0; + + case 0x2c: /* STI_CLK_CTRL / XTI_SCLKCRTL */ + return s->clkcontrol; + + case 0x30: /* STI_SERIAL_CFG / XTI_SCONFIG */ + return s->serial_config; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_sti_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_sti_s *s = (struct omap_sti_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* STI_REVISION */ + case 0x14: /* STI_SYSSTATUS / STI_RX_STATUS / XTI_SYSSTATUS */ + OMAP_RO_REG(addr); + return; + + case 0x10: /* STI_SYSCONFIG */ + if (value & (1 << 1)) /* SOFTRESET */ + omap_sti_reset(s); + s->sysconfig = value & 0xfe; + break; + + case 0x18: /* STI_IRQSTATUS */ + s->irqst &= ~value; + omap_sti_interrupt_update(s); + break; + + case 0x1c: /* STI_IRQSETEN / STI_IRQCLREN */ + s->irqen = value & 0xffff; + omap_sti_interrupt_update(s); + break; + + case 0x2c: /* STI_CLK_CTRL / XTI_SCLKCRTL */ + s->clkcontrol = value & 0xff; + break; + + case 0x30: /* STI_SERIAL_CFG / XTI_SCONFIG */ + s->serial_config = value & 0xff; + break; + + case 0x24: /* STI_ER / STI_DR / XTI_TRACESELECT */ + case 0x28: /* STI_RX_DR / XTI_RXDATA */ + /* TODO */ + return; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_sti_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_sti_read, +}; + +static CPUWriteMemoryFunc *omap_sti_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_sti_write, +}; + +static uint32_t omap_sti_fifo_read(void *opaque, target_phys_addr_t addr) +{ + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_sti_fifo_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_sti_s *s = (struct omap_sti_s *) opaque; + int offset = addr - s->channel_base; + int ch = offset >> 6; + uint8_t byte = value; + + if (ch == STI_TRACE_CONTROL_CHANNEL) { + /* Flush channel value. */ + qemu_chr_write(s->chr, (const uint8_t *) "\r", 1); + } else if (ch == STI_TRACE_CONSOLE_CHANNEL || 1) { + if (value == 0xc0 || value == 0xc3) { + /* Open channel ch. */ + } else if (value == 0x00) + qemu_chr_write(s->chr, (const uint8_t *) "\n", 1); + else + qemu_chr_write(s->chr, &byte, 1); + } +} + +static CPUReadMemoryFunc *omap_sti_fifo_readfn[] = { + omap_sti_fifo_read, + omap_badwidth_read8, + omap_badwidth_read8, +}; + +static CPUWriteMemoryFunc *omap_sti_fifo_writefn[] = { + omap_sti_fifo_write, + omap_badwidth_write8, + omap_badwidth_write8, +}; + +static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta, + target_phys_addr_t channel_base, qemu_irq irq, omap_clk clk, + CharDriverState *chr) +{ + int iomemtype; + struct omap_sti_s *s = (struct omap_sti_s *) + qemu_mallocz(sizeof(struct omap_sti_s)); + + s->irq = irq; + omap_sti_reset(s); + + s->chr = chr ?: qemu_chr_open("null", "null"); + + iomemtype = l4_register_io_memory(0, omap_sti_readfn, + omap_sti_writefn, s); + s->base = omap_l4_attach(ta, 0, iomemtype); + + iomemtype = cpu_register_io_memory(0, omap_sti_fifo_readfn, + omap_sti_fifo_writefn, s); + s->channel_base = channel_base; + cpu_register_physical_memory(s->channel_base, 0x10000, iomemtype); + + return s; +} + +/* L4 Interconnect */ +struct omap_target_agent_s { + struct omap_l4_s *bus; + int regions; + struct omap_l4_region_s *start; + target_phys_addr_t base; + uint32_t component; + uint32_t control; + uint32_t status; +}; + +struct omap_l4_s { + target_phys_addr_t base; + int ta_num; + struct omap_target_agent_s ta[0]; +}; + +#ifdef L4_MUX_HACK +static int omap_l4_io_entries; +static int omap_cpu_io_entry; +static struct omap_l4_entry { + CPUReadMemoryFunc **mem_read; + CPUWriteMemoryFunc **mem_write; + void *opaque; +} *omap_l4_io_entry; +static CPUReadMemoryFunc **omap_l4_io_readb_fn; +static CPUReadMemoryFunc **omap_l4_io_readh_fn; +static CPUReadMemoryFunc **omap_l4_io_readw_fn; +static CPUWriteMemoryFunc **omap_l4_io_writeb_fn; +static CPUWriteMemoryFunc **omap_l4_io_writeh_fn; +static CPUWriteMemoryFunc **omap_l4_io_writew_fn; +static void **omap_l4_io_opaque; + +int l4_register_io_memory(int io_index, CPUReadMemoryFunc **mem_read, + CPUWriteMemoryFunc **mem_write, void *opaque) +{ + omap_l4_io_entry[omap_l4_io_entries].mem_read = mem_read; + omap_l4_io_entry[omap_l4_io_entries].mem_write = mem_write; + omap_l4_io_entry[omap_l4_io_entries].opaque = opaque; + + return omap_l4_io_entries ++; +} + +static uint32_t omap_l4_io_readb(void *opaque, target_phys_addr_t addr) +{ + unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS; + + return omap_l4_io_readb_fn[i](omap_l4_io_opaque[i], addr); +} + +static uint32_t omap_l4_io_readh(void *opaque, target_phys_addr_t addr) +{ + unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS; + + return omap_l4_io_readh_fn[i](omap_l4_io_opaque[i], addr); +} + +static uint32_t omap_l4_io_readw(void *opaque, target_phys_addr_t addr) +{ + unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS; + + return omap_l4_io_readw_fn[i](omap_l4_io_opaque[i], addr); +} + +static void omap_l4_io_writeb(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS; + + return omap_l4_io_writeb_fn[i](omap_l4_io_opaque[i], addr, value); +} + +static void omap_l4_io_writeh(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS; + + return omap_l4_io_writeh_fn[i](omap_l4_io_opaque[i], addr, value); +} + +static void omap_l4_io_writew(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS; + + return omap_l4_io_writew_fn[i](omap_l4_io_opaque[i], addr, value); +} + +static CPUReadMemoryFunc *omap_l4_io_readfn[] = { + omap_l4_io_readb, + omap_l4_io_readh, + omap_l4_io_readw, +}; + +static CPUWriteMemoryFunc *omap_l4_io_writefn[] = { + omap_l4_io_writeb, + omap_l4_io_writeh, + omap_l4_io_writew, +}; +#endif + +struct omap_l4_s *omap_l4_init(target_phys_addr_t base, int ta_num) +{ + struct omap_l4_s *bus = qemu_mallocz( + sizeof(*bus) + ta_num * sizeof(*bus->ta)); + + bus->ta_num = ta_num; + bus->base = base; + +#ifdef L4_MUX_HACK + omap_l4_io_entries = 1; + omap_l4_io_entry = qemu_mallocz(125 * sizeof(*omap_l4_io_entry)); + + omap_cpu_io_entry = + cpu_register_io_memory(0, omap_l4_io_readfn, + omap_l4_io_writefn, bus); +# define L4_PAGES (0xb4000 / TARGET_PAGE_SIZE) + omap_l4_io_readb_fn = qemu_mallocz(sizeof(void *) * L4_PAGES); + omap_l4_io_readh_fn = qemu_mallocz(sizeof(void *) * L4_PAGES); + omap_l4_io_readw_fn = qemu_mallocz(sizeof(void *) * L4_PAGES); + omap_l4_io_writeb_fn = qemu_mallocz(sizeof(void *) * L4_PAGES); + omap_l4_io_writeh_fn = qemu_mallocz(sizeof(void *) * L4_PAGES); + omap_l4_io_writew_fn = qemu_mallocz(sizeof(void *) * L4_PAGES); + omap_l4_io_opaque = qemu_mallocz(sizeof(void *) * L4_PAGES); +#endif + + return bus; +} + +static uint32_t omap_l4ta_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque; + target_phys_addr_t reg = addr - s->base; + + switch (reg) { + case 0x00: /* COMPONENT */ + return s->component; + + case 0x20: /* AGENT_CONTROL */ + return s->control; + + case 0x28: /* AGENT_STATUS */ + return s->status; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_l4ta_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque; + target_phys_addr_t reg = addr - s->base; + + switch (reg) { + case 0x00: /* COMPONENT */ + case 0x28: /* AGENT_STATUS */ + OMAP_RO_REG(addr); + break; + + case 0x20: /* AGENT_CONTROL */ + s->control = value & 0x01000700; + if (value & 1) /* OCP_RESET */ + s->status &= ~1; /* REQ_TIMEOUT */ + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_l4ta_readfn[] = { + omap_badwidth_read16, + omap_l4ta_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_l4ta_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_l4ta_write, +}; + +#define L4TA(n) (n) +#define L4TAO(n) ((n) + 39) + +static struct omap_l4_region_s { + target_phys_addr_t offset; + size_t size; + int access; +} omap_l4_region[125] = { + [ 1] = { 0x40800, 0x800, 32 }, /* Initiator agent */ + [ 2] = { 0x41000, 0x1000, 32 }, /* Link agent */ + [ 0] = { 0x40000, 0x800, 32 }, /* Address and protection */ + [ 3] = { 0x00000, 0x1000, 32 | 16 | 8 }, /* System Control and Pinout */ + [ 4] = { 0x01000, 0x1000, 32 | 16 | 8 }, /* L4TAO1 */ + [ 5] = { 0x04000, 0x1000, 32 | 16 }, /* 32K Timer */ + [ 6] = { 0x05000, 0x1000, 32 | 16 | 8 }, /* L4TAO2 */ + [ 7] = { 0x08000, 0x800, 32 }, /* PRCM Region A */ + [ 8] = { 0x08800, 0x800, 32 }, /* PRCM Region B */ + [ 9] = { 0x09000, 0x1000, 32 | 16 | 8 }, /* L4TAO */ + [ 10] = { 0x12000, 0x1000, 32 | 16 | 8 }, /* Test (BCM) */ + [ 11] = { 0x13000, 0x1000, 32 | 16 | 8 }, /* L4TA1 */ + [ 12] = { 0x14000, 0x1000, 32 }, /* Test/emulation (TAP) */ + [ 13] = { 0x15000, 0x1000, 32 | 16 | 8 }, /* L4TA2 */ + [ 14] = { 0x18000, 0x1000, 32 | 16 | 8 }, /* GPIO1 */ + [ 16] = { 0x1a000, 0x1000, 32 | 16 | 8 }, /* GPIO2 */ + [ 18] = { 0x1c000, 0x1000, 32 | 16 | 8 }, /* GPIO3 */ + [ 19] = { 0x1e000, 0x1000, 32 | 16 | 8 }, /* GPIO4 */ + [ 15] = { 0x19000, 0x1000, 32 | 16 | 8 }, /* Quad GPIO TOP */ + [ 17] = { 0x1b000, 0x1000, 32 | 16 | 8 }, /* L4TA3 */ + [ 20] = { 0x20000, 0x1000, 32 | 16 | 8 }, /* WD Timer 1 (Secure) */ + [ 22] = { 0x22000, 0x1000, 32 | 16 | 8 }, /* WD Timer 2 (OMAP) */ + [ 21] = { 0x21000, 0x1000, 32 | 16 | 8 }, /* Dual WD timer TOP */ + [ 23] = { 0x23000, 0x1000, 32 | 16 | 8 }, /* L4TA4 */ + [ 24] = { 0x28000, 0x1000, 32 | 16 | 8 }, /* GP Timer 1 */ + [ 25] = { 0x29000, 0x1000, 32 | 16 | 8 }, /* L4TA7 */ + [ 26] = { 0x48000, 0x2000, 32 | 16 | 8 }, /* Emulation (ARM11ETB) */ + [ 27] = { 0x4a000, 0x1000, 32 | 16 | 8 }, /* L4TA9 */ + [ 28] = { 0x50000, 0x400, 32 | 16 | 8 }, /* Display top */ + [ 29] = { 0x50400, 0x400, 32 | 16 | 8 }, /* Display control */ + [ 30] = { 0x50800, 0x400, 32 | 16 | 8 }, /* Display RFBI */ + [ 31] = { 0x50c00, 0x400, 32 | 16 | 8 }, /* Display encoder */ + [ 32] = { 0x51000, 0x1000, 32 | 16 | 8 }, /* L4TA10 */ + [ 33] = { 0x52000, 0x400, 32 | 16 | 8 }, /* Camera top */ + [ 34] = { 0x52400, 0x400, 32 | 16 | 8 }, /* Camera core */ + [ 35] = { 0x52800, 0x400, 32 | 16 | 8 }, /* Camera DMA */ + [ 36] = { 0x52c00, 0x400, 32 | 16 | 8 }, /* Camera MMU */ + [ 37] = { 0x53000, 0x1000, 32 | 16 | 8 }, /* L4TA11 */ + [ 38] = { 0x56000, 0x1000, 32 | 16 | 8 }, /* sDMA */ + [ 39] = { 0x57000, 0x1000, 32 | 16 | 8 }, /* L4TA12 */ + [ 40] = { 0x58000, 0x1000, 32 | 16 | 8 }, /* SSI top */ + [ 41] = { 0x59000, 0x1000, 32 | 16 | 8 }, /* SSI GDD */ + [ 42] = { 0x5a000, 0x1000, 32 | 16 | 8 }, /* SSI Port1 */ + [ 43] = { 0x5b000, 0x1000, 32 | 16 | 8 }, /* SSI Port2 */ + [ 44] = { 0x5c000, 0x1000, 32 | 16 | 8 }, /* L4TA13 */ + [ 45] = { 0x5e000, 0x1000, 32 | 16 | 8 }, /* USB OTG */ + [ 46] = { 0x5f000, 0x1000, 32 | 16 | 8 }, /* L4TAO4 */ + [ 47] = { 0x60000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER1SDRC) */ + [ 48] = { 0x61000, 0x1000, 32 | 16 | 8 }, /* L4TA14 */ + [ 49] = { 0x62000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER2GPMC) */ + [ 50] = { 0x63000, 0x1000, 32 | 16 | 8 }, /* L4TA15 */ + [ 51] = { 0x64000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER3OCM) */ + [ 52] = { 0x65000, 0x1000, 32 | 16 | 8 }, /* L4TA16 */ + [ 53] = { 0x66000, 0x300, 32 | 16 | 8 }, /* Emulation (WIN_TRACER4L4) */ + [ 54] = { 0x67000, 0x1000, 32 | 16 | 8 }, /* L4TA17 */ + [ 55] = { 0x68000, 0x1000, 32 | 16 | 8 }, /* Emulation (XTI) */ + [ 56] = { 0x69000, 0x1000, 32 | 16 | 8 }, /* L4TA18 */ + [ 57] = { 0x6a000, 0x1000, 16 | 8 }, /* UART1 */ + [ 58] = { 0x6b000, 0x1000, 32 | 16 | 8 }, /* L4TA19 */ + [ 59] = { 0x6c000, 0x1000, 16 | 8 }, /* UART2 */ + [ 60] = { 0x6d000, 0x1000, 32 | 16 | 8 }, /* L4TA20 */ + [ 61] = { 0x6e000, 0x1000, 16 | 8 }, /* UART3 */ + [ 62] = { 0x6f000, 0x1000, 32 | 16 | 8 }, /* L4TA21 */ + [ 63] = { 0x70000, 0x1000, 16 }, /* I2C1 */ + [ 64] = { 0x71000, 0x1000, 32 | 16 | 8 }, /* L4TAO5 */ + [ 65] = { 0x72000, 0x1000, 16 }, /* I2C2 */ + [ 66] = { 0x73000, 0x1000, 32 | 16 | 8 }, /* L4TAO6 */ + [ 67] = { 0x74000, 0x1000, 16 }, /* McBSP1 */ + [ 68] = { 0x75000, 0x1000, 32 | 16 | 8 }, /* L4TAO7 */ + [ 69] = { 0x76000, 0x1000, 16 }, /* McBSP2 */ + [ 70] = { 0x77000, 0x1000, 32 | 16 | 8 }, /* L4TAO8 */ + [ 71] = { 0x24000, 0x1000, 32 | 16 | 8 }, /* WD Timer 3 (DSP) */ + [ 72] = { 0x25000, 0x1000, 32 | 16 | 8 }, /* L4TA5 */ + [ 73] = { 0x26000, 0x1000, 32 | 16 | 8 }, /* WD Timer 4 (IVA) */ + [ 74] = { 0x27000, 0x1000, 32 | 16 | 8 }, /* L4TA6 */ + [ 75] = { 0x2a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 2 */ + [ 76] = { 0x2b000, 0x1000, 32 | 16 | 8 }, /* L4TA8 */ + [ 77] = { 0x78000, 0x1000, 32 | 16 | 8 }, /* GP Timer 3 */ + [ 78] = { 0x79000, 0x1000, 32 | 16 | 8 }, /* L4TA22 */ + [ 79] = { 0x7a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 4 */ + [ 80] = { 0x7b000, 0x1000, 32 | 16 | 8 }, /* L4TA23 */ + [ 81] = { 0x7c000, 0x1000, 32 | 16 | 8 }, /* GP Timer 5 */ + [ 82] = { 0x7d000, 0x1000, 32 | 16 | 8 }, /* L4TA24 */ + [ 83] = { 0x7e000, 0x1000, 32 | 16 | 8 }, /* GP Timer 6 */ + [ 84] = { 0x7f000, 0x1000, 32 | 16 | 8 }, /* L4TA25 */ + [ 85] = { 0x80000, 0x1000, 32 | 16 | 8 }, /* GP Timer 7 */ + [ 86] = { 0x81000, 0x1000, 32 | 16 | 8 }, /* L4TA26 */ + [ 87] = { 0x82000, 0x1000, 32 | 16 | 8 }, /* GP Timer 8 */ + [ 88] = { 0x83000, 0x1000, 32 | 16 | 8 }, /* L4TA27 */ + [ 89] = { 0x84000, 0x1000, 32 | 16 | 8 }, /* GP Timer 9 */ + [ 90] = { 0x85000, 0x1000, 32 | 16 | 8 }, /* L4TA28 */ + [ 91] = { 0x86000, 0x1000, 32 | 16 | 8 }, /* GP Timer 10 */ + [ 92] = { 0x87000, 0x1000, 32 | 16 | 8 }, /* L4TA29 */ + [ 93] = { 0x88000, 0x1000, 32 | 16 | 8 }, /* GP Timer 11 */ + [ 94] = { 0x89000, 0x1000, 32 | 16 | 8 }, /* L4TA30 */ + [ 95] = { 0x8a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 12 */ + [ 96] = { 0x8b000, 0x1000, 32 | 16 | 8 }, /* L4TA31 */ + [ 97] = { 0x90000, 0x1000, 16 }, /* EAC */ + [ 98] = { 0x91000, 0x1000, 32 | 16 | 8 }, /* L4TA32 */ + [ 99] = { 0x92000, 0x1000, 16 }, /* FAC */ + [100] = { 0x93000, 0x1000, 32 | 16 | 8 }, /* L4TA33 */ + [101] = { 0x94000, 0x1000, 32 | 16 | 8 }, /* IPC (MAILBOX) */ + [102] = { 0x95000, 0x1000, 32 | 16 | 8 }, /* L4TA34 */ + [103] = { 0x98000, 0x1000, 32 | 16 | 8 }, /* SPI1 */ + [104] = { 0x99000, 0x1000, 32 | 16 | 8 }, /* L4TA35 */ + [105] = { 0x9a000, 0x1000, 32 | 16 | 8 }, /* SPI2 */ + [106] = { 0x9b000, 0x1000, 32 | 16 | 8 }, /* L4TA36 */ + [107] = { 0x9c000, 0x1000, 16 | 8 }, /* MMC SDIO */ + [108] = { 0x9d000, 0x1000, 32 | 16 | 8 }, /* L4TAO9 */ + [109] = { 0x9e000, 0x1000, 32 | 16 | 8 }, /* MS_PRO */ + [110] = { 0x9f000, 0x1000, 32 | 16 | 8 }, /* L4TAO10 */ + [111] = { 0xa0000, 0x1000, 32 }, /* RNG */ + [112] = { 0xa1000, 0x1000, 32 | 16 | 8 }, /* L4TAO11 */ + [113] = { 0xa2000, 0x1000, 32 }, /* DES3DES */ + [114] = { 0xa3000, 0x1000, 32 | 16 | 8 }, /* L4TAO12 */ + [115] = { 0xa4000, 0x1000, 32 }, /* SHA1MD5 */ + [116] = { 0xa5000, 0x1000, 32 | 16 | 8 }, /* L4TAO13 */ + [117] = { 0xa6000, 0x1000, 32 }, /* AES */ + [118] = { 0xa7000, 0x1000, 32 | 16 | 8 }, /* L4TA37 */ + [119] = { 0xa8000, 0x2000, 32 }, /* PKA */ + [120] = { 0xaa000, 0x1000, 32 | 16 | 8 }, /* L4TA38 */ + [121] = { 0xb0000, 0x1000, 32 }, /* MG */ + [122] = { 0xb1000, 0x1000, 32 | 16 | 8 }, + [123] = { 0xb2000, 0x1000, 32 }, /* HDQ/1-Wire */ + [124] = { 0xb3000, 0x1000, 32 | 16 | 8 }, /* L4TA39 */ +}; + +static struct omap_l4_agent_info_s { + int ta; + int region; + int regions; + int ta_region; +} omap_l4_agent_info[54] = { + { 0, 0, 3, 2 }, /* L4IA initiatior agent */ + { L4TAO(1), 3, 2, 1 }, /* Control and pinout module */ + { L4TAO(2), 5, 2, 1 }, /* 32K timer */ + { L4TAO(3), 7, 3, 2 }, /* PRCM */ + { L4TA(1), 10, 2, 1 }, /* BCM */ + { L4TA(2), 12, 2, 1 }, /* Test JTAG */ + { L4TA(3), 14, 6, 3 }, /* Quad GPIO */ + { L4TA(4), 20, 4, 3 }, /* WD timer 1/2 */ + { L4TA(7), 24, 2, 1 }, /* GP timer 1 */ + { L4TA(9), 26, 2, 1 }, /* ATM11 ETB */ + { L4TA(10), 28, 5, 4 }, /* Display subsystem */ + { L4TA(11), 33, 5, 4 }, /* Camera subsystem */ + { L4TA(12), 38, 2, 1 }, /* sDMA */ + { L4TA(13), 40, 5, 4 }, /* SSI */ + { L4TAO(4), 45, 2, 1 }, /* USB */ + { L4TA(14), 47, 2, 1 }, /* Win Tracer1 */ + { L4TA(15), 49, 2, 1 }, /* Win Tracer2 */ + { L4TA(16), 51, 2, 1 }, /* Win Tracer3 */ + { L4TA(17), 53, 2, 1 }, /* Win Tracer4 */ + { L4TA(18), 55, 2, 1 }, /* XTI */ + { L4TA(19), 57, 2, 1 }, /* UART1 */ + { L4TA(20), 59, 2, 1 }, /* UART2 */ + { L4TA(21), 61, 2, 1 }, /* UART3 */ + { L4TAO(5), 63, 2, 1 }, /* I2C1 */ + { L4TAO(6), 65, 2, 1 }, /* I2C2 */ + { L4TAO(7), 67, 2, 1 }, /* McBSP1 */ + { L4TAO(8), 69, 2, 1 }, /* McBSP2 */ + { L4TA(5), 71, 2, 1 }, /* WD Timer 3 (DSP) */ + { L4TA(6), 73, 2, 1 }, /* WD Timer 4 (IVA) */ + { L4TA(8), 75, 2, 1 }, /* GP Timer 2 */ + { L4TA(22), 77, 2, 1 }, /* GP Timer 3 */ + { L4TA(23), 79, 2, 1 }, /* GP Timer 4 */ + { L4TA(24), 81, 2, 1 }, /* GP Timer 5 */ + { L4TA(25), 83, 2, 1 }, /* GP Timer 6 */ + { L4TA(26), 85, 2, 1 }, /* GP Timer 7 */ + { L4TA(27), 87, 2, 1 }, /* GP Timer 8 */ + { L4TA(28), 89, 2, 1 }, /* GP Timer 9 */ + { L4TA(29), 91, 2, 1 }, /* GP Timer 10 */ + { L4TA(30), 93, 2, 1 }, /* GP Timer 11 */ + { L4TA(31), 95, 2, 1 }, /* GP Timer 12 */ + { L4TA(32), 97, 2, 1 }, /* EAC */ + { L4TA(33), 99, 2, 1 }, /* FAC */ + { L4TA(34), 101, 2, 1 }, /* IPC */ + { L4TA(35), 103, 2, 1 }, /* SPI1 */ + { L4TA(36), 105, 2, 1 }, /* SPI2 */ + { L4TAO(9), 107, 2, 1 }, /* MMC SDIO */ + { L4TAO(10), 109, 2, 1 }, + { L4TAO(11), 111, 2, 1 }, /* RNG */ + { L4TAO(12), 113, 2, 1 }, /* DES3DES */ + { L4TAO(13), 115, 2, 1 }, /* SHA1MD5 */ + { L4TA(37), 117, 2, 1 }, /* AES */ + { L4TA(38), 119, 2, 1 }, /* PKA */ + { -1, 121, 2, 1 }, + { L4TA(39), 123, 2, 1 }, /* HDQ/1-Wire */ +}; + +#define omap_l4ta(bus, cs) omap_l4ta_get(bus, L4TA(cs)) +#define omap_l4tao(bus, cs) omap_l4ta_get(bus, L4TAO(cs)) + +struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus, int cs) +{ + int i, iomemtype; + struct omap_target_agent_s *ta = 0; + struct omap_l4_agent_info_s *info = 0; + + for (i = 0; i < bus->ta_num; i ++) + if (omap_l4_agent_info[i].ta == cs) { + ta = &bus->ta[i]; + info = &omap_l4_agent_info[i]; + break; + } + if (!ta) { + fprintf(stderr, "%s: bad target agent (%i)\n", __FUNCTION__, cs); + exit(-1); + } + + ta->bus = bus; + ta->start = &omap_l4_region[info->region]; + ta->regions = info->regions; + + ta->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0); + ta->status = 0x00000000; + ta->control = 0x00000200; /* XXX 01000200 for L4TAO */ + + iomemtype = l4_register_io_memory(0, omap_l4ta_readfn, + omap_l4ta_writefn, ta); + ta->base = omap_l4_attach(ta, info->ta_region, iomemtype); + + return ta; +} + +target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, int region, + int iotype) +{ + target_phys_addr_t base; + ssize_t size; +#ifdef L4_MUX_HACK + int i; +#endif + + if (region < 0 || region >= ta->regions) { + fprintf(stderr, "%s: bad io region (%i)\n", __FUNCTION__, region); + exit(-1); + } + + base = ta->bus->base + ta->start[region].offset; + size = ta->start[region].size; + if (iotype) { +#ifndef L4_MUX_HACK + cpu_register_physical_memory(base, size, iotype); +#else + cpu_register_physical_memory(base, size, omap_cpu_io_entry); + i = (base - ta->bus->base) / TARGET_PAGE_SIZE; + for (; size > 0; size -= TARGET_PAGE_SIZE, i ++) { + omap_l4_io_readb_fn[i] = omap_l4_io_entry[iotype].mem_read[0]; + omap_l4_io_readh_fn[i] = omap_l4_io_entry[iotype].mem_read[1]; + omap_l4_io_readw_fn[i] = omap_l4_io_entry[iotype].mem_read[2]; + omap_l4_io_writeb_fn[i] = omap_l4_io_entry[iotype].mem_write[0]; + omap_l4_io_writeh_fn[i] = omap_l4_io_entry[iotype].mem_write[1]; + omap_l4_io_writew_fn[i] = omap_l4_io_entry[iotype].mem_write[2]; + omap_l4_io_opaque[i] = omap_l4_io_entry[iotype].opaque; + } +#endif + } + + return base; +} + +/* TEST-Chip-level TAP */ +static uint32_t omap_tap_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + target_phys_addr_t reg = addr - s->tap_base; + + switch (reg) { + case 0x204: /* IDCODE_reg */ + switch (s->mpu_model) { + case omap2420: + case omap2422: + case omap2423: + return 0x5b5d902f; /* ES 2.2 */ + case omap2430: + return 0x5b68a02f; /* ES 2.2 */ + case omap3430: + return 0x1b7ae02f; /* ES 2 */ + default: + cpu_abort(cpu_single_env, "%s: Bad mpu model\n", __FUNCTION__); + } + + case 0x208: /* PRODUCTION_ID_reg for OMAP2 */ + case 0x210: /* PRODUCTION_ID_reg for OMAP3 */ + switch (s->mpu_model) { + case omap2420: + return 0x000254f0; /* POP ESHS2.1.1 in N91/93/95, ES2 in N800 */ + case omap2422: + return 0x000400f0; + case omap2423: + return 0x000800f0; + case omap2430: + return 0x000000f0; + case omap3430: + return 0x000000f0; + default: + cpu_abort(cpu_single_env, "%s: Bad mpu model\n", __FUNCTION__); + } + + case 0x20c: + switch (s->mpu_model) { + case omap2420: + case omap2422: + case omap2423: + return 0xcafeb5d9; /* ES 2.2 */ + case omap2430: + return 0xcafeb68a; /* ES 2.2 */ + case omap3430: + return 0xcafeb7ae; /* ES 2 */ + default: + cpu_abort(cpu_single_env, "%s: Bad mpu model\n", __FUNCTION__); + } + + case 0x218: /* DIE_ID_reg */ + return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0); + case 0x21c: /* DIE_ID_reg */ + return 0x54 << 24; + case 0x220: /* DIE_ID_reg */ + return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0); + case 0x224: /* DIE_ID_reg */ + return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0); + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_tap_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + OMAP_BAD_REG(addr); +} + +static CPUReadMemoryFunc *omap_tap_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_tap_read, +}; + +static CPUWriteMemoryFunc *omap_tap_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_tap_write, +}; + +void omap_tap_init(struct omap_target_agent_s *ta, + struct omap_mpu_state_s *mpu) +{ + mpu->tap_base = omap_l4_attach(ta, 0, l4_register_io_memory(0, + omap_tap_readfn, omap_tap_writefn, mpu)); +} + +/* Power, Reset, and Clock Management */ +struct omap_prcm_s { + target_phys_addr_t base; + qemu_irq irq[3]; + struct omap_mpu_state_s *mpu; + + uint32_t irqst[3]; + uint32_t irqen[3]; + + uint32_t sysconfig; + uint32_t voltctrl; + uint32_t scratch[20]; + + uint32_t clksrc[1]; + uint32_t clkout[1]; + uint32_t clkemul[1]; + uint32_t clkpol[1]; + uint32_t clksel[8]; + uint32_t clken[12]; + uint32_t clkctrl[4]; + uint32_t clkidle[7]; + uint32_t setuptime[2]; + + uint32_t wkup[3]; + uint32_t wken[3]; + uint32_t wkst[3]; + uint32_t rst[4]; + uint32_t rstctrl[1]; + uint32_t power[4]; + uint32_t rsttime_wkup; + + uint32_t ev; + uint32_t evtime[2]; + + int dpll_lock, apll_lock[2]; +}; + +static void omap_prcm_int_update(struct omap_prcm_s *s, int dom) +{ + qemu_set_irq(s->irq[dom], s->irqst[dom] & s->irqen[dom]); + /* XXX or is the mask applied before PRCM_IRQSTATUS_* ? */ +} + +static uint32_t omap_prcm_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_prcm_s *s = (struct omap_prcm_s *) opaque; + int offset = addr - s->base; + uint32_t ret; + + switch (offset) { + case 0x000: /* PRCM_REVISION */ + return 0x10; + + case 0x010: /* PRCM_SYSCONFIG */ + return s->sysconfig; + + case 0x018: /* PRCM_IRQSTATUS_MPU */ + return s->irqst[0]; + + case 0x01c: /* PRCM_IRQENABLE_MPU */ + return s->irqen[0]; + + case 0x050: /* PRCM_VOLTCTRL */ + return s->voltctrl; + case 0x054: /* PRCM_VOLTST */ + return s->voltctrl & 3; + + case 0x060: /* PRCM_CLKSRC_CTRL */ + return s->clksrc[0]; + case 0x070: /* PRCM_CLKOUT_CTRL */ + return s->clkout[0]; + case 0x078: /* PRCM_CLKEMUL_CTRL */ + return s->clkemul[0]; + case 0x080: /* PRCM_CLKCFG_CTRL */ + case 0x084: /* PRCM_CLKCFG_STATUS */ + return 0; + + case 0x090: /* PRCM_VOLTSETUP */ + return s->setuptime[0]; + + case 0x094: /* PRCM_CLKSSETUP */ + return s->setuptime[1]; + + case 0x098: /* PRCM_POLCTRL */ + return s->clkpol[0]; + + case 0x0b0: /* GENERAL_PURPOSE1 */ + case 0x0b4: /* GENERAL_PURPOSE2 */ + case 0x0b8: /* GENERAL_PURPOSE3 */ + case 0x0bc: /* GENERAL_PURPOSE4 */ + case 0x0c0: /* GENERAL_PURPOSE5 */ + case 0x0c4: /* GENERAL_PURPOSE6 */ + case 0x0c8: /* GENERAL_PURPOSE7 */ + case 0x0cc: /* GENERAL_PURPOSE8 */ + case 0x0d0: /* GENERAL_PURPOSE9 */ + case 0x0d4: /* GENERAL_PURPOSE10 */ + case 0x0d8: /* GENERAL_PURPOSE11 */ + case 0x0dc: /* GENERAL_PURPOSE12 */ + case 0x0e0: /* GENERAL_PURPOSE13 */ + case 0x0e4: /* GENERAL_PURPOSE14 */ + case 0x0e8: /* GENERAL_PURPOSE15 */ + case 0x0ec: /* GENERAL_PURPOSE16 */ + case 0x0f0: /* GENERAL_PURPOSE17 */ + case 0x0f4: /* GENERAL_PURPOSE18 */ + case 0x0f8: /* GENERAL_PURPOSE19 */ + case 0x0fc: /* GENERAL_PURPOSE20 */ + return s->scratch[(offset - 0xb0) >> 2]; + + case 0x140: /* CM_CLKSEL_MPU */ + return s->clksel[0]; + case 0x148: /* CM_CLKSTCTRL_MPU */ + return s->clkctrl[0]; + + case 0x158: /* RM_RSTST_MPU */ + return s->rst[0]; + case 0x1c8: /* PM_WKDEP_MPU */ + return s->wkup[0]; + case 0x1d4: /* PM_EVGENCTRL_MPU */ + return s->ev; + case 0x1d8: /* PM_EVEGENONTIM_MPU */ + return s->evtime[0]; + case 0x1dc: /* PM_EVEGENOFFTIM_MPU */ + return s->evtime[1]; + case 0x1e0: /* PM_PWSTCTRL_MPU */ + return s->power[0]; + case 0x1e4: /* PM_PWSTST_MPU */ + return 0; + + case 0x200: /* CM_FCLKEN1_CORE */ + return s->clken[0]; + case 0x204: /* CM_FCLKEN2_CORE */ + return s->clken[1]; + case 0x210: /* CM_ICLKEN1_CORE */ + return s->clken[2]; + case 0x214: /* CM_ICLKEN2_CORE */ + return s->clken[3]; + case 0x21c: /* CM_ICLKEN4_CORE */ + return s->clken[4]; + + case 0x220: /* CM_IDLEST1_CORE */ + /* TODO: check the actual iclk status */ + return 0x7ffffff9; + case 0x224: /* CM_IDLEST2_CORE */ + /* TODO: check the actual iclk status */ + return 0x00000007; + case 0x22c: /* CM_IDLEST4_CORE */ + /* TODO: check the actual iclk status */ + return 0x0000001f; + + case 0x230: /* CM_AUTOIDLE1_CORE */ + return s->clkidle[0]; + case 0x234: /* CM_AUTOIDLE2_CORE */ + return s->clkidle[1]; + case 0x238: /* CM_AUTOIDLE3_CORE */ + return s->clkidle[2]; + case 0x23c: /* CM_AUTOIDLE4_CORE */ + return s->clkidle[3]; + + case 0x240: /* CM_CLKSEL1_CORE */ + return s->clksel[1]; + case 0x244: /* CM_CLKSEL2_CORE */ + return s->clksel[2]; + + case 0x248: /* CM_CLKSTCTRL_CORE */ + return s->clkctrl[1]; + + case 0x2a0: /* PM_WKEN1_CORE */ + return s->wken[0]; + case 0x2a4: /* PM_WKEN2_CORE */ + return s->wken[1]; + + case 0x2b0: /* PM_WKST1_CORE */ + return s->wkst[0]; + case 0x2b4: /* PM_WKST2_CORE */ + return s->wkst[1]; + case 0x2c8: /* PM_WKDEP_CORE */ + return 0x1e; + + case 0x2e0: /* PM_PWSTCTRL_CORE */ + return s->power[1]; + case 0x2e4: /* PM_PWSTST_CORE */ + return 0x000030 | (s->power[1] & 0xfc00); + + case 0x300: /* CM_FCLKEN_GFX */ + return s->clken[5]; + case 0x310: /* CM_ICLKEN_GFX */ + return s->clken[6]; + case 0x320: /* CM_IDLEST_GFX */ + /* TODO: check the actual iclk status */ + return 0x00000001; + case 0x340: /* CM_CLKSEL_GFX */ + return s->clksel[3]; + case 0x348: /* CM_CLKSTCTRL_GFX */ + return s->clkctrl[2]; + case 0x350: /* RM_RSTCTRL_GFX */ + return s->rstctrl[0]; + case 0x358: /* RM_RSTST_GFX */ + return s->rst[1]; + case 0x3c8: /* PM_WKDEP_GFX */ + return s->wkup[1]; + + case 0x3e0: /* PM_PWSTCTRL_GFX */ + return s->power[2]; + case 0x3e4: /* PM_PWSTST_GFX */ + return s->power[2] & 3; + + case 0x400: /* CM_FCLKEN_WKUP */ + return s->clken[7]; + case 0x410: /* CM_ICLKEN_WKUP */ + return s->clken[8]; + case 0x420: /* CM_IDLEST_WKUP */ + /* TODO: check the actual iclk status */ + return 0x0000003f; + case 0x430: /* CM_AUTOIDLE_WKUP */ + return s->clkidle[4]; + case 0x440: /* CM_CLKSEL_WKUP */ + return s->clksel[4]; + case 0x450: /* RM_RSTCTRL_WKUP */ + return 0; + case 0x454: /* RM_RSTTIME_WKUP */ + return s->rsttime_wkup; + case 0x458: /* RM_RSTST_WKUP */ + return s->rst[2]; + case 0x4a0: /* PM_WKEN_WKUP */ + return s->wken[2]; + case 0x4b0: /* PM_WKST_WKUP */ + return s->wkst[2]; + + case 0x500: /* CM_CLKEN_PLL */ + return s->clken[9]; + case 0x520: /* CM_IDLEST_CKGEN */ + ret = 0x0000070 | (s->apll_lock[0] << 9) | (s->apll_lock[1] << 8); + if (!(s->clksel[6] & 3)) + /* Core uses 32-kHz clock */ + ret |= 3 << 0; + else if (!s->dpll_lock) + /* DPLL not locked, core uses ref_clk */ + ret |= 1 << 0; + else + /* Core uses DPLL */ + ret |= 2 << 0; + return ret; + case 0x530: /* CM_AUTOIDLE_PLL */ + return s->clkidle[5]; + case 0x540: /* CM_CLKSEL1_PLL */ + return s->clksel[5]; + case 0x544: /* CM_CLKSEL2_PLL */ + return s->clksel[6]; + + case 0x800: /* CM_FCLKEN_DSP */ + return s->clken[10]; + case 0x810: /* CM_ICLKEN_DSP */ + return s->clken[11]; + case 0x820: /* CM_IDLEST_DSP */ + /* TODO: check the actual iclk status */ + return 0x00000103; + case 0x830: /* CM_AUTOIDLE_DSP */ + return s->clkidle[6]; + case 0x840: /* CM_CLKSEL_DSP */ + return s->clksel[7]; + case 0x848: /* CM_CLKSTCTRL_DSP */ + return s->clkctrl[3]; + case 0x850: /* RM_RSTCTRL_DSP */ + return 0; + case 0x858: /* RM_RSTST_DSP */ + return s->rst[3]; + case 0x8c8: /* PM_WKDEP_DSP */ + return s->wkup[2]; + case 0x8e0: /* PM_PWSTCTRL_DSP */ + return s->power[3]; + case 0x8e4: /* PM_PWSTST_DSP */ + return 0x008030 | (s->power[3] & 0x3003); + + case 0x8f0: /* PRCM_IRQSTATUS_DSP */ + return s->irqst[1]; + case 0x8f4: /* PRCM_IRQENABLE_DSP */ + return s->irqen[1]; + + case 0x8f8: /* PRCM_IRQSTATUS_IVA */ + return s->irqst[2]; + case 0x8fc: /* PRCM_IRQENABLE_IVA */ + return s->irqen[2]; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_prcm_apll_update(struct omap_prcm_s *s) +{ + int mode[2]; + + mode[0] = (s->clken[9] >> 6) & 3; + s->apll_lock[0] = (mode[0] == 3); + mode[1] = (s->clken[9] >> 2) & 3; + s->apll_lock[1] = (mode[1] == 3); + /* TODO: update clocks */ + + if (mode[0] == 1 || mode[0] == 2 || mode[1] == 1 || mode[2] == 2) + fprintf(stderr, "%s: bad EN_54M_PLL or bad EN_96M_PLL\n", + __FUNCTION__); +} + +static void omap_prcm_dpll_update(struct omap_prcm_s *s) +{ + omap_clk dpll = omap_findclk(s->mpu, "dpll"); + omap_clk dpll_x2 = omap_findclk(s->mpu, "dpll"); + omap_clk core = omap_findclk(s->mpu, "core_clk"); + int mode = (s->clken[9] >> 0) & 3; + int mult, div; + + mult = (s->clksel[5] >> 12) & 0x3ff; + div = (s->clksel[5] >> 8) & 0xf; + if (mult == 0 || mult == 1) + mode = 1; /* Bypass */ + + s->dpll_lock = 0; + switch (mode) { + case 0: + fprintf(stderr, "%s: bad EN_DPLL\n", __FUNCTION__); + break; + case 1: /* Low-power bypass mode (Default) */ + case 2: /* Fast-relock bypass mode */ + omap_clk_setrate(dpll, 1, 1); + omap_clk_setrate(dpll_x2, 1, 1); + break; + case 3: /* Lock mode */ + s->dpll_lock = 1; /* After 20 FINT cycles (ref_clk / (div + 1)). */ + + omap_clk_setrate(dpll, div + 1, mult); + omap_clk_setrate(dpll_x2, div + 1, mult * 2); + break; + } + + switch ((s->clksel[6] >> 0) & 3) { + case 0: + omap_clk_reparent(core, omap_findclk(s->mpu, "clk32-kHz")); + break; + case 1: + omap_clk_reparent(core, dpll); + break; + case 2: + /* Default */ + omap_clk_reparent(core, dpll_x2); + break; + case 3: + fprintf(stderr, "%s: bad CORE_CLK_SRC\n", __FUNCTION__); + break; + } +} + +static void omap_prcm_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_prcm_s *s = (struct omap_prcm_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x000: /* PRCM_REVISION */ + case 0x054: /* PRCM_VOLTST */ + case 0x084: /* PRCM_CLKCFG_STATUS */ + case 0x1e4: /* PM_PWSTST_MPU */ + case 0x220: /* CM_IDLEST1_CORE */ + case 0x224: /* CM_IDLEST2_CORE */ + case 0x22c: /* CM_IDLEST4_CORE */ + case 0x2c8: /* PM_WKDEP_CORE */ + case 0x2e4: /* PM_PWSTST_CORE */ + case 0x320: /* CM_IDLEST_GFX */ + case 0x3e4: /* PM_PWSTST_GFX */ + case 0x420: /* CM_IDLEST_WKUP */ + case 0x520: /* CM_IDLEST_CKGEN */ + case 0x820: /* CM_IDLEST_DSP */ + case 0x8e4: /* PM_PWSTST_DSP */ + OMAP_RO_REG(addr); + return; + + case 0x010: /* PRCM_SYSCONFIG */ + s->sysconfig = value & 1; + break; + + case 0x018: /* PRCM_IRQSTATUS_MPU */ + s->irqst[0] &= ~value; + omap_prcm_int_update(s, 0); + break; + case 0x01c: /* PRCM_IRQENABLE_MPU */ + s->irqen[0] = value & 0x3f; + omap_prcm_int_update(s, 0); + break; + + case 0x050: /* PRCM_VOLTCTRL */ + s->voltctrl = value & 0xf1c3; + break; + + case 0x060: /* PRCM_CLKSRC_CTRL */ + s->clksrc[0] = value & 0xdb; + /* TODO update clocks */ + break; + + case 0x070: /* PRCM_CLKOUT_CTRL */ + s->clkout[0] = value & 0xbbbb; + /* TODO update clocks */ + break; + + case 0x078: /* PRCM_CLKEMUL_CTRL */ + s->clkemul[0] = value & 1; + /* TODO update clocks */ + break; + + case 0x080: /* PRCM_CLKCFG_CTRL */ + break; + + case 0x090: /* PRCM_VOLTSETUP */ + s->setuptime[0] = value & 0xffff; + break; + case 0x094: /* PRCM_CLKSSETUP */ + s->setuptime[1] = value & 0xffff; + break; + + case 0x098: /* PRCM_POLCTRL */ + s->clkpol[0] = value & 0x701; + break; + + case 0x0b0: /* GENERAL_PURPOSE1 */ + case 0x0b4: /* GENERAL_PURPOSE2 */ + case 0x0b8: /* GENERAL_PURPOSE3 */ + case 0x0bc: /* GENERAL_PURPOSE4 */ + case 0x0c0: /* GENERAL_PURPOSE5 */ + case 0x0c4: /* GENERAL_PURPOSE6 */ + case 0x0c8: /* GENERAL_PURPOSE7 */ + case 0x0cc: /* GENERAL_PURPOSE8 */ + case 0x0d0: /* GENERAL_PURPOSE9 */ + case 0x0d4: /* GENERAL_PURPOSE10 */ + case 0x0d8: /* GENERAL_PURPOSE11 */ + case 0x0dc: /* GENERAL_PURPOSE12 */ + case 0x0e0: /* GENERAL_PURPOSE13 */ + case 0x0e4: /* GENERAL_PURPOSE14 */ + case 0x0e8: /* GENERAL_PURPOSE15 */ + case 0x0ec: /* GENERAL_PURPOSE16 */ + case 0x0f0: /* GENERAL_PURPOSE17 */ + case 0x0f4: /* GENERAL_PURPOSE18 */ + case 0x0f8: /* GENERAL_PURPOSE19 */ + case 0x0fc: /* GENERAL_PURPOSE20 */ + s->scratch[(offset - 0xb0) >> 2] = value; + break; + + case 0x140: /* CM_CLKSEL_MPU */ + s->clksel[0] = value & 0x1f; + /* TODO update clocks */ + break; + case 0x148: /* CM_CLKSTCTRL_MPU */ + s->clkctrl[0] = value & 0x1f; + break; + + case 0x158: /* RM_RSTST_MPU */ + s->rst[0] &= ~value; + break; + case 0x1c8: /* PM_WKDEP_MPU */ + s->wkup[0] = value & 0x15; + break; + + case 0x1d4: /* PM_EVGENCTRL_MPU */ + s->ev = value & 0x1f; + break; + case 0x1d8: /* PM_EVEGENONTIM_MPU */ + s->evtime[0] = value; + break; + case 0x1dc: /* PM_EVEGENOFFTIM_MPU */ + s->evtime[1] = value; + break; + + case 0x1e0: /* PM_PWSTCTRL_MPU */ + s->power[0] = value & 0xc0f; + break; + + case 0x200: /* CM_FCLKEN1_CORE */ + s->clken[0] = value & 0xbfffffff; + /* TODO update clocks */ + /* The EN_EAC bit only gets/puts func_96m_clk. */ + break; + case 0x204: /* CM_FCLKEN2_CORE */ + s->clken[1] = value & 0x00000007; + /* TODO update clocks */ + break; + case 0x210: /* CM_ICLKEN1_CORE */ + s->clken[2] = value & 0xfffffff9; + /* TODO update clocks */ + /* The EN_EAC bit only gets/puts core_l4_iclk. */ + break; + case 0x214: /* CM_ICLKEN2_CORE */ + s->clken[3] = value & 0x00000007; + /* TODO update clocks */ + break; + case 0x21c: /* CM_ICLKEN4_CORE */ + s->clken[4] = value & 0x0000001f; + /* TODO update clocks */ + break; + + case 0x230: /* CM_AUTOIDLE1_CORE */ + s->clkidle[0] = value & 0xfffffff9; + /* TODO update clocks */ + break; + case 0x234: /* CM_AUTOIDLE2_CORE */ + s->clkidle[1] = value & 0x00000007; + /* TODO update clocks */ + break; + case 0x238: /* CM_AUTOIDLE3_CORE */ + s->clkidle[2] = value & 0x00000007; + /* TODO update clocks */ + break; + case 0x23c: /* CM_AUTOIDLE4_CORE */ + s->clkidle[3] = value & 0x0000001f; + /* TODO update clocks */ + break; + + case 0x240: /* CM_CLKSEL1_CORE */ + s->clksel[1] = value & 0x0fffbf7f; + /* TODO update clocks */ + break; + + case 0x244: /* CM_CLKSEL2_CORE */ + s->clksel[2] = value & 0x00fffffc; + /* TODO update clocks */ + break; + + case 0x248: /* CM_CLKSTCTRL_CORE */ + s->clkctrl[1] = value & 0x7; + break; + + case 0x2a0: /* PM_WKEN1_CORE */ + s->wken[0] = value & 0x04667ff8; + break; + case 0x2a4: /* PM_WKEN2_CORE */ + s->wken[1] = value & 0x00000005; + break; + + case 0x2b0: /* PM_WKST1_CORE */ + s->wkst[0] &= ~value; + break; + case 0x2b4: /* PM_WKST2_CORE */ + s->wkst[1] &= ~value; + break; + + case 0x2e0: /* PM_PWSTCTRL_CORE */ + s->power[1] = (value & 0x00fc3f) | (1 << 2); + break; + + case 0x300: /* CM_FCLKEN_GFX */ + s->clken[5] = value & 6; + /* TODO update clocks */ + break; + case 0x310: /* CM_ICLKEN_GFX */ + s->clken[6] = value & 1; + /* TODO update clocks */ + break; + case 0x340: /* CM_CLKSEL_GFX */ + s->clksel[3] = value & 7; + /* TODO update clocks */ + break; + case 0x348: /* CM_CLKSTCTRL_GFX */ + s->clkctrl[2] = value & 1; + break; + case 0x350: /* RM_RSTCTRL_GFX */ + s->rstctrl[0] = value & 1; + /* TODO: reset */ + break; + case 0x358: /* RM_RSTST_GFX */ + s->rst[1] &= ~value; + break; + case 0x3c8: /* PM_WKDEP_GFX */ + s->wkup[1] = value & 0x13; + break; + case 0x3e0: /* PM_PWSTCTRL_GFX */ + s->power[2] = (value & 0x00c0f) | (3 << 2); + break; + + case 0x400: /* CM_FCLKEN_WKUP */ + s->clken[7] = value & 0xd; + /* TODO update clocks */ + break; + case 0x410: /* CM_ICLKEN_WKUP */ + s->clken[8] = value & 0x3f; + /* TODO update clocks */ + break; + case 0x430: /* CM_AUTOIDLE_WKUP */ + s->clkidle[4] = value & 0x0000003f; + /* TODO update clocks */ + break; + case 0x440: /* CM_CLKSEL_WKUP */ + s->clksel[4] = value & 3; + /* TODO update clocks */ + break; + case 0x450: /* RM_RSTCTRL_WKUP */ + /* TODO: reset */ + if (value & 2) + qemu_system_reset_request(); + break; + case 0x454: /* RM_RSTTIME_WKUP */ + s->rsttime_wkup = value & 0x1fff; + break; + case 0x458: /* RM_RSTST_WKUP */ + s->rst[2] &= ~value; + break; + case 0x4a0: /* PM_WKEN_WKUP */ + s->wken[2] = value & 0x00000005; + break; + case 0x4b0: /* PM_WKST_WKUP */ + s->wkst[2] &= ~value; + break; + + case 0x500: /* CM_CLKEN_PLL */ + if (value & 0xffffff30) + fprintf(stderr, "%s: write 0s in CM_CLKEN_PLL for " + "future compatiblity\n", __FUNCTION__); + if ((s->clken[9] ^ value) & 0xcc) { + s->clken[9] &= ~0xcc; + s->clken[9] |= value & 0xcc; + omap_prcm_apll_update(s); + } + if ((s->clken[9] ^ value) & 3) { + s->clken[9] &= ~3; + s->clken[9] |= value & 3; + omap_prcm_dpll_update(s); + } + break; + case 0x530: /* CM_AUTOIDLE_PLL */ + s->clkidle[5] = value & 0x000000cf; + /* TODO update clocks */ + break; + case 0x540: /* CM_CLKSEL1_PLL */ + if (value & 0xfc4000d7) + fprintf(stderr, "%s: write 0s in CM_CLKSEL1_PLL for " + "future compatiblity\n", __FUNCTION__); + if ((s->clksel[5] ^ value) & 0x003fff00) { + s->clksel[5] = value & 0x03bfff28; + omap_prcm_dpll_update(s); + } + /* TODO update the other clocks */ + + s->clksel[5] = value & 0x03bfff28; + break; + case 0x544: /* CM_CLKSEL2_PLL */ + if (value & ~3) + fprintf(stderr, "%s: write 0s in CM_CLKSEL2_PLL[31:2] for " + "future compatiblity\n", __FUNCTION__); + if (s->clksel[6] != (value & 3)) { + s->clksel[6] = value & 3; + omap_prcm_dpll_update(s); + } + break; + + case 0x800: /* CM_FCLKEN_DSP */ + s->clken[10] = value & 0x501; + /* TODO update clocks */ + break; + case 0x810: /* CM_ICLKEN_DSP */ + s->clken[11] = value & 0x2; + /* TODO update clocks */ + break; + case 0x830: /* CM_AUTOIDLE_DSP */ + s->clkidle[6] = value & 0x2; + /* TODO update clocks */ + break; + case 0x840: /* CM_CLKSEL_DSP */ + s->clksel[7] = value & 0x3fff; + /* TODO update clocks */ + break; + case 0x848: /* CM_CLKSTCTRL_DSP */ + s->clkctrl[3] = value & 0x101; + break; + case 0x850: /* RM_RSTCTRL_DSP */ + /* TODO: reset */ + break; + case 0x858: /* RM_RSTST_DSP */ + s->rst[3] &= ~value; + break; + case 0x8c8: /* PM_WKDEP_DSP */ + s->wkup[2] = value & 0x13; + break; + case 0x8e0: /* PM_PWSTCTRL_DSP */ + s->power[3] = (value & 0x03017) | (3 << 2); + break; + + case 0x8f0: /* PRCM_IRQSTATUS_DSP */ + s->irqst[1] &= ~value; + omap_prcm_int_update(s, 1); + break; + case 0x8f4: /* PRCM_IRQENABLE_DSP */ + s->irqen[1] = value & 0x7; + omap_prcm_int_update(s, 1); + break; + + case 0x8f8: /* PRCM_IRQSTATUS_IVA */ + s->irqst[2] &= ~value; + omap_prcm_int_update(s, 2); + break; + case 0x8fc: /* PRCM_IRQENABLE_IVA */ + s->irqen[2] = value & 0x7; + omap_prcm_int_update(s, 2); + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_prcm_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_prcm_read, +}; + +static CPUWriteMemoryFunc *omap_prcm_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_prcm_write, +}; + +static void omap_prcm_reset(struct omap_prcm_s *s) +{ + s->sysconfig = 0; + s->irqst[0] = 0; + s->irqst[1] = 0; + s->irqst[2] = 0; + s->irqen[0] = 0; + s->irqen[1] = 0; + s->irqen[2] = 0; + s->voltctrl = 0x1040; + s->ev = 0x14; + s->evtime[0] = 0; + s->evtime[1] = 0; + s->clkctrl[0] = 0; + s->clkctrl[1] = 0; + s->clkctrl[2] = 0; + s->clkctrl[3] = 0; + s->clken[1] = 7; + s->clken[3] = 7; + s->clken[4] = 0; + s->clken[5] = 0; + s->clken[6] = 0; + s->clken[7] = 0xc; + s->clken[8] = 0x3e; + s->clken[9] = 0x0d; + s->clken[10] = 0; + s->clken[11] = 0; + s->clkidle[0] = 0; + s->clkidle[2] = 7; + s->clkidle[3] = 0; + s->clkidle[4] = 0; + s->clkidle[5] = 0x0c; + s->clkidle[6] = 0; + s->clksel[0] = 0x01; + s->clksel[1] = 0x02100121; + s->clksel[2] = 0x00000000; + s->clksel[3] = 0x01; + s->clksel[4] = 0; + s->clksel[7] = 0x0121; + s->wkup[0] = 0x15; + s->wkup[1] = 0x13; + s->wkup[2] = 0x13; + s->wken[0] = 0x04667ff8; + s->wken[1] = 0x00000005; + s->wken[2] = 5; + s->wkst[0] = 0; + s->wkst[1] = 0; + s->wkst[2] = 0; + s->power[0] = 0x00c; + s->power[1] = 4; + s->power[2] = 0x0000c; + s->power[3] = 0x14; + s->rstctrl[0] = 1; + s->rst[3] = 1; + omap_prcm_apll_update(s); + omap_prcm_dpll_update(s); +} + +static void omap_prcm_coldreset(struct omap_prcm_s *s) +{ + s->setuptime[0] = 0; + s->setuptime[1] = 0; + memset(&s->scratch, 0, sizeof(s->scratch)); + s->rst[0] = 0x01; + s->rst[1] = 0x00; + s->rst[2] = 0x01; + s->clken[0] = 0; + s->clken[2] = 0; + s->clkidle[1] = 0; + s->clksel[5] = 0; + s->clksel[6] = 2; + s->clksrc[0] = 0x43; + s->clkout[0] = 0x0303; + s->clkemul[0] = 0; + s->clkpol[0] = 0x100; + s->rsttime_wkup = 0x1002; + + omap_prcm_reset(s); +} + +struct omap_prcm_s *omap_prcm_init(struct omap_target_agent_s *ta, + qemu_irq mpu_int, qemu_irq dsp_int, qemu_irq iva_int, + struct omap_mpu_state_s *mpu) +{ + int iomemtype; + struct omap_prcm_s *s = (struct omap_prcm_s *) + qemu_mallocz(sizeof(struct omap_prcm_s)); + + s->irq[0] = mpu_int; + s->irq[1] = dsp_int; + s->irq[2] = iva_int; + s->mpu = mpu; + omap_prcm_coldreset(s); + + iomemtype = l4_register_io_memory(0, omap_prcm_readfn, + omap_prcm_writefn, s); + s->base = omap_l4_attach(ta, 0, iomemtype); + omap_l4_attach(ta, 1, iomemtype); + + return s; +} + +/* System and Pinout control */ +struct omap_sysctl_s { + target_phys_addr_t base; + struct omap_mpu_state_s *mpu; + + uint32_t sysconfig; + uint32_t devconfig; + uint32_t psaconfig; + uint32_t padconf[0x45]; + uint8_t obs; + uint32_t msuspendmux[5]; +}; + +static uint32_t omap_sysctl_read8(void *opaque, target_phys_addr_t addr) +{ + + struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; + int offset = addr - s->base; + int pad_offset, byte_offset; + int value; + + switch (offset) { + case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */ + pad_offset = (offset - 0x30) >> 2; + byte_offset = (offset - 0x30) & (4 - 1); + + value = s->padconf[pad_offset]; + value = (value >> (byte_offset * 8)) & 0xff; + + return value; + + default: + break; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static uint32_t omap_sysctl_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x000: /* CONTROL_REVISION */ + return 0x20; + + case 0x010: /* CONTROL_SYSCONFIG */ + return s->sysconfig; + + case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */ + return s->padconf[(offset - 0x30) >> 2]; + + case 0x270: /* CONTROL_DEBOBS */ + return s->obs; + + case 0x274: /* CONTROL_DEVCONF */ + return s->devconfig; + + case 0x28c: /* CONTROL_EMU_SUPPORT */ + return 0; + + case 0x290: /* CONTROL_MSUSPENDMUX_0 */ + return s->msuspendmux[0]; + case 0x294: /* CONTROL_MSUSPENDMUX_1 */ + return s->msuspendmux[1]; + case 0x298: /* CONTROL_MSUSPENDMUX_2 */ + return s->msuspendmux[2]; + case 0x29c: /* CONTROL_MSUSPENDMUX_3 */ + return s->msuspendmux[3]; + case 0x2a0: /* CONTROL_MSUSPENDMUX_4 */ + return s->msuspendmux[4]; + case 0x2a4: /* CONTROL_MSUSPENDMUX_5 */ + return 0; + + case 0x2b8: /* CONTROL_PSA_CTRL */ + return s->psaconfig; + case 0x2bc: /* CONTROL_PSA_CMD */ + case 0x2c0: /* CONTROL_PSA_VALUE */ + return 0; + + case 0x2b0: /* CONTROL_SEC_CTRL */ + return 0x800000f1; + case 0x2d0: /* CONTROL_SEC_EMU */ + return 0x80000015; + case 0x2d4: /* CONTROL_SEC_TAP */ + return 0x8000007f; + case 0x2b4: /* CONTROL_SEC_TEST */ + case 0x2f0: /* CONTROL_SEC_STATUS */ + case 0x2f4: /* CONTROL_SEC_ERR_STATUS */ + /* Secure mode is not present on general-pusrpose device. Outside + * secure mode these values cannot be read or written. */ + return 0; + + case 0x2d8: /* CONTROL_OCM_RAM_PERM */ + return 0xff; + case 0x2dc: /* CONTROL_OCM_PUB_RAM_ADD */ + case 0x2e0: /* CONTROL_EXT_SEC_RAM_START_ADD */ + case 0x2e4: /* CONTROL_EXT_SEC_RAM_STOP_ADD */ + /* No secure mode so no Extended Secure RAM present. */ + return 0; + + case 0x2f8: /* CONTROL_STATUS */ + /* Device Type => General-purpose */ + return 0x0300; + case 0x2fc: /* CONTROL_GENERAL_PURPOSE_STATUS */ + + case 0x300: /* CONTROL_RPUB_KEY_H_0 */ + case 0x304: /* CONTROL_RPUB_KEY_H_1 */ + case 0x308: /* CONTROL_RPUB_KEY_H_2 */ + case 0x30c: /* CONTROL_RPUB_KEY_H_3 */ + return 0xdecafbad; + + case 0x310: /* CONTROL_RAND_KEY_0 */ + case 0x314: /* CONTROL_RAND_KEY_1 */ + case 0x318: /* CONTROL_RAND_KEY_2 */ + case 0x31c: /* CONTROL_RAND_KEY_3 */ + case 0x320: /* CONTROL_CUST_KEY_0 */ + case 0x324: /* CONTROL_CUST_KEY_1 */ + case 0x330: /* CONTROL_TEST_KEY_0 */ + case 0x334: /* CONTROL_TEST_KEY_1 */ + case 0x338: /* CONTROL_TEST_KEY_2 */ + case 0x33c: /* CONTROL_TEST_KEY_3 */ + case 0x340: /* CONTROL_TEST_KEY_4 */ + case 0x344: /* CONTROL_TEST_KEY_5 */ + case 0x348: /* CONTROL_TEST_KEY_6 */ + case 0x34c: /* CONTROL_TEST_KEY_7 */ + case 0x350: /* CONTROL_TEST_KEY_8 */ + case 0x354: /* CONTROL_TEST_KEY_9 */ + /* Can only be accessed in secure mode and when C_FieldAccEnable + * bit is set in CONTROL_SEC_CTRL. + * TODO: otherwise an interconnect access error is generated. */ + return 0; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_sysctl_write8(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; + int offset = addr - s->base; + int pad_offset, byte_offset; + int prev_value; + + switch (offset) { + case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */ + pad_offset = (offset - 0x30) >> 2; + byte_offset = (offset - 0x30) & (4 - 1); + + prev_value = s->padconf[pad_offset]; + prev_value &= ~(0xff << (byte_offset * 8)); + prev_value |= ((value & 0x1f1f1f1f) << (byte_offset * 8)) & 0x1f1f1f1f; + s->padconf[pad_offset] = prev_value; + break; + + default: + OMAP_BAD_REG(addr); + break; + } +} + +static void omap_sysctl_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x000: /* CONTROL_REVISION */ + case 0x2a4: /* CONTROL_MSUSPENDMUX_5 */ + case 0x2c0: /* CONTROL_PSA_VALUE */ + case 0x2f8: /* CONTROL_STATUS */ + case 0x2fc: /* CONTROL_GENERAL_PURPOSE_STATUS */ + case 0x300: /* CONTROL_RPUB_KEY_H_0 */ + case 0x304: /* CONTROL_RPUB_KEY_H_1 */ + case 0x308: /* CONTROL_RPUB_KEY_H_2 */ + case 0x30c: /* CONTROL_RPUB_KEY_H_3 */ + case 0x310: /* CONTROL_RAND_KEY_0 */ + case 0x314: /* CONTROL_RAND_KEY_1 */ + case 0x318: /* CONTROL_RAND_KEY_2 */ + case 0x31c: /* CONTROL_RAND_KEY_3 */ + case 0x320: /* CONTROL_CUST_KEY_0 */ + case 0x324: /* CONTROL_CUST_KEY_1 */ + case 0x330: /* CONTROL_TEST_KEY_0 */ + case 0x334: /* CONTROL_TEST_KEY_1 */ + case 0x338: /* CONTROL_TEST_KEY_2 */ + case 0x33c: /* CONTROL_TEST_KEY_3 */ + case 0x340: /* CONTROL_TEST_KEY_4 */ + case 0x344: /* CONTROL_TEST_KEY_5 */ + case 0x348: /* CONTROL_TEST_KEY_6 */ + case 0x34c: /* CONTROL_TEST_KEY_7 */ + case 0x350: /* CONTROL_TEST_KEY_8 */ + case 0x354: /* CONTROL_TEST_KEY_9 */ + OMAP_RO_REG(addr); + return; + + case 0x010: /* CONTROL_SYSCONFIG */ + s->sysconfig = value & 0x1e; + break; + + case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */ + /* XXX: should check constant bits */ + s->padconf[(offset - 0x30) >> 2] = value & 0x1f1f1f1f; + break; + + case 0x270: /* CONTROL_DEBOBS */ + s->obs = value & 0xff; + break; + + case 0x274: /* CONTROL_DEVCONF */ + s->devconfig = value & 0xffffc7ff; + break; + + case 0x28c: /* CONTROL_EMU_SUPPORT */ + break; + + case 0x290: /* CONTROL_MSUSPENDMUX_0 */ + s->msuspendmux[0] = value & 0x3fffffff; + break; + case 0x294: /* CONTROL_MSUSPENDMUX_1 */ + s->msuspendmux[1] = value & 0x3fffffff; + break; + case 0x298: /* CONTROL_MSUSPENDMUX_2 */ + s->msuspendmux[2] = value & 0x3fffffff; + break; + case 0x29c: /* CONTROL_MSUSPENDMUX_3 */ + s->msuspendmux[3] = value & 0x3fffffff; + break; + case 0x2a0: /* CONTROL_MSUSPENDMUX_4 */ + s->msuspendmux[4] = value & 0x3fffffff; + break; + + case 0x2b8: /* CONTROL_PSA_CTRL */ + s->psaconfig = value & 0x1c; + s->psaconfig |= (value & 0x20) ? 2 : 1; + break; + case 0x2bc: /* CONTROL_PSA_CMD */ + break; + + case 0x2b0: /* CONTROL_SEC_CTRL */ + case 0x2b4: /* CONTROL_SEC_TEST */ + case 0x2d0: /* CONTROL_SEC_EMU */ + case 0x2d4: /* CONTROL_SEC_TAP */ + case 0x2d8: /* CONTROL_OCM_RAM_PERM */ + case 0x2dc: /* CONTROL_OCM_PUB_RAM_ADD */ + case 0x2e0: /* CONTROL_EXT_SEC_RAM_START_ADD */ + case 0x2e4: /* CONTROL_EXT_SEC_RAM_STOP_ADD */ + case 0x2f0: /* CONTROL_SEC_STATUS */ + case 0x2f4: /* CONTROL_SEC_ERR_STATUS */ + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_sysctl_readfn[] = { + omap_sysctl_read8, + omap_badwidth_read32, /* TODO */ + omap_sysctl_read, +}; + +static CPUWriteMemoryFunc *omap_sysctl_writefn[] = { + omap_sysctl_write8, + omap_badwidth_write32, /* TODO */ + omap_sysctl_write, +}; + +static void omap_sysctl_reset(struct omap_sysctl_s *s) +{ + /* (power-on reset) */ + s->sysconfig = 0; + s->obs = 0; + s->devconfig = 0x0c000000; + s->msuspendmux[0] = 0x00000000; + s->msuspendmux[1] = 0x00000000; + s->msuspendmux[2] = 0x00000000; + s->msuspendmux[3] = 0x00000000; + s->msuspendmux[4] = 0x00000000; + s->psaconfig = 1; + + s->padconf[0x00] = 0x000f0f0f; + s->padconf[0x01] = 0x00000000; + s->padconf[0x02] = 0x00000000; + s->padconf[0x03] = 0x00000000; + s->padconf[0x04] = 0x00000000; + s->padconf[0x05] = 0x00000000; + s->padconf[0x06] = 0x00000000; + s->padconf[0x07] = 0x00000000; + s->padconf[0x08] = 0x08080800; + s->padconf[0x09] = 0x08080808; + s->padconf[0x0a] = 0x08080808; + s->padconf[0x0b] = 0x08080808; + s->padconf[0x0c] = 0x08080808; + s->padconf[0x0d] = 0x08080800; + s->padconf[0x0e] = 0x08080808; + s->padconf[0x0f] = 0x08080808; + s->padconf[0x10] = 0x18181808; /* | 0x07070700 if SBoot3 */ + s->padconf[0x11] = 0x18181818; /* | 0x07070707 if SBoot3 */ + s->padconf[0x12] = 0x18181818; /* | 0x07070707 if SBoot3 */ + s->padconf[0x13] = 0x18181818; /* | 0x07070707 if SBoot3 */ + s->padconf[0x14] = 0x18181818; /* | 0x00070707 if SBoot3 */ + s->padconf[0x15] = 0x18181818; + s->padconf[0x16] = 0x18181818; /* | 0x07000000 if SBoot3 */ + s->padconf[0x17] = 0x1f001f00; + s->padconf[0x18] = 0x1f1f1f1f; + s->padconf[0x19] = 0x00000000; + s->padconf[0x1a] = 0x1f180000; + s->padconf[0x1b] = 0x00001f1f; + s->padconf[0x1c] = 0x1f001f00; + s->padconf[0x1d] = 0x00000000; + s->padconf[0x1e] = 0x00000000; + s->padconf[0x1f] = 0x08000000; + s->padconf[0x20] = 0x08080808; + s->padconf[0x21] = 0x08080808; + s->padconf[0x22] = 0x0f080808; + s->padconf[0x23] = 0x0f0f0f0f; + s->padconf[0x24] = 0x000f0f0f; + s->padconf[0x25] = 0x1f1f1f0f; + s->padconf[0x26] = 0x080f0f1f; + s->padconf[0x27] = 0x070f1808; + s->padconf[0x28] = 0x0f070707; + s->padconf[0x29] = 0x000f0f1f; + s->padconf[0x2a] = 0x0f0f0f1f; + s->padconf[0x2b] = 0x08000000; + s->padconf[0x2c] = 0x0000001f; + s->padconf[0x2d] = 0x0f0f1f00; + s->padconf[0x2e] = 0x1f1f0f0f; + s->padconf[0x2f] = 0x0f1f1f1f; + s->padconf[0x30] = 0x0f0f0f0f; + s->padconf[0x31] = 0x0f1f0f1f; + s->padconf[0x32] = 0x0f0f0f0f; + s->padconf[0x33] = 0x0f1f0f1f; + s->padconf[0x34] = 0x1f1f0f0f; + s->padconf[0x35] = 0x0f0f1f1f; + s->padconf[0x36] = 0x0f0f1f0f; + s->padconf[0x37] = 0x0f0f0f0f; + s->padconf[0x38] = 0x1f18180f; + s->padconf[0x39] = 0x1f1f1f1f; + s->padconf[0x3a] = 0x00001f1f; + s->padconf[0x3b] = 0x00000000; + s->padconf[0x3c] = 0x00000000; + s->padconf[0x3d] = 0x0f0f0f0f; + s->padconf[0x3e] = 0x18000f0f; + s->padconf[0x3f] = 0x00070000; + s->padconf[0x40] = 0x00000707; + s->padconf[0x41] = 0x0f1f0700; + s->padconf[0x42] = 0x1f1f070f; + s->padconf[0x43] = 0x0008081f; + s->padconf[0x44] = 0x00000800; +} + +struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta, + omap_clk iclk, struct omap_mpu_state_s *mpu) +{ + int iomemtype; + struct omap_sysctl_s *s = (struct omap_sysctl_s *) + qemu_mallocz(sizeof(struct omap_sysctl_s)); + + s->mpu = mpu; + omap_sysctl_reset(s); + + iomemtype = l4_register_io_memory(0, omap_sysctl_readfn, + omap_sysctl_writefn, s); + s->base = omap_l4_attach(ta, 0, iomemtype); + omap_l4_attach(ta, 0, iomemtype); + + return s; +} + +/* SDRAM Controller Subsystem */ +struct omap_sdrc_s { + target_phys_addr_t base; + + uint8_t config; +}; + +static void omap_sdrc_reset(struct omap_sdrc_s *s) +{ + s->config = 0x10; +} + +static uint32_t omap_sdrc_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* SDRC_REVISION */ + return 0x20; + + case 0x10: /* SDRC_SYSCONFIG */ + return s->config; + + case 0x14: /* SDRC_SYSSTATUS */ + return 1; /* RESETDONE */ + + case 0x40: /* SDRC_CS_CFG */ + case 0x44: /* SDRC_SHARING */ + case 0x48: /* SDRC_ERR_ADDR */ + case 0x4c: /* SDRC_ERR_TYPE */ + case 0x60: /* SDRC_DLLA_SCTRL */ + case 0x64: /* SDRC_DLLA_STATUS */ + case 0x68: /* SDRC_DLLB_CTRL */ + case 0x6c: /* SDRC_DLLB_STATUS */ + case 0x70: /* SDRC_POWER */ + case 0x80: /* SDRC_MCFG_0 */ + case 0x84: /* SDRC_MR_0 */ + case 0x88: /* SDRC_EMR1_0 */ + case 0x8c: /* SDRC_EMR2_0 */ + case 0x90: /* SDRC_EMR3_0 */ + case 0x94: /* SDRC_DCDL1_CTRL */ + case 0x98: /* SDRC_DCDL2_CTRL */ + case 0x9c: /* SDRC_ACTIM_CTRLA_0 */ + case 0xa0: /* SDRC_ACTIM_CTRLB_0 */ + case 0xa4: /* SDRC_RFR_CTRL_0 */ + case 0xa8: /* SDRC_MANUAL_0 */ + case 0xb0: /* SDRC_MCFG_1 */ + case 0xb4: /* SDRC_MR_1 */ + case 0xb8: /* SDRC_EMR1_1 */ + case 0xbc: /* SDRC_EMR2_1 */ + case 0xc0: /* SDRC_EMR3_1 */ + case 0xc4: /* SDRC_ACTIM_CTRLA_1 */ + case 0xc8: /* SDRC_ACTIM_CTRLB_1 */ + case 0xd4: /* SDRC_RFR_CTRL_1 */ + case 0xd8: /* SDRC_MANUAL_1 */ + return 0x00; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_sdrc_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* SDRC_REVISION */ + case 0x14: /* SDRC_SYSSTATUS */ + case 0x48: /* SDRC_ERR_ADDR */ + case 0x64: /* SDRC_DLLA_STATUS */ + case 0x6c: /* SDRC_DLLB_STATUS */ + OMAP_RO_REG(addr); + return; + + case 0x10: /* SDRC_SYSCONFIG */ + if ((value >> 3) != 0x2) + fprintf(stderr, "%s: bad SDRAM idle mode %i\n", + __FUNCTION__, value >> 3); + if (value & 2) + omap_sdrc_reset(s); + s->config = value & 0x18; + break; + + case 0x40: /* SDRC_CS_CFG */ + case 0x44: /* SDRC_SHARING */ + case 0x4c: /* SDRC_ERR_TYPE */ + case 0x60: /* SDRC_DLLA_SCTRL */ + case 0x68: /* SDRC_DLLB_CTRL */ + case 0x70: /* SDRC_POWER */ + case 0x80: /* SDRC_MCFG_0 */ + case 0x84: /* SDRC_MR_0 */ + case 0x88: /* SDRC_EMR1_0 */ + case 0x8c: /* SDRC_EMR2_0 */ + case 0x90: /* SDRC_EMR3_0 */ + case 0x94: /* SDRC_DCDL1_CTRL */ + case 0x98: /* SDRC_DCDL2_CTRL */ + case 0x9c: /* SDRC_ACTIM_CTRLA_0 */ + case 0xa0: /* SDRC_ACTIM_CTRLB_0 */ + case 0xa4: /* SDRC_RFR_CTRL_0 */ + case 0xa8: /* SDRC_MANUAL_0 */ + case 0xb0: /* SDRC_MCFG_1 */ + case 0xb4: /* SDRC_MR_1 */ + case 0xb8: /* SDRC_EMR1_1 */ + case 0xbc: /* SDRC_EMR2_1 */ + case 0xc0: /* SDRC_EMR3_1 */ + case 0xc4: /* SDRC_ACTIM_CTRLA_1 */ + case 0xc8: /* SDRC_ACTIM_CTRLB_1 */ + case 0xd4: /* SDRC_RFR_CTRL_1 */ + case 0xd8: /* SDRC_MANUAL_1 */ + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_sdrc_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_sdrc_read, +}; + +static CPUWriteMemoryFunc *omap_sdrc_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_sdrc_write, +}; + +struct omap_sdrc_s *omap_sdrc_init(target_phys_addr_t base) +{ + int iomemtype; + struct omap_sdrc_s *s = (struct omap_sdrc_s *) + qemu_mallocz(sizeof(struct omap_sdrc_s)); + + s->base = base; + omap_sdrc_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_sdrc_readfn, + omap_sdrc_writefn, s); + cpu_register_physical_memory(s->base, 0x1000, iomemtype); + + return s; +} + +/* General-Purpose Memory Controller */ +struct omap_gpmc_s { + target_phys_addr_t base; + qemu_irq irq; + + uint8_t sysconfig; + uint16_t irqst; + uint16_t irqen; + uint16_t timeout; + uint16_t config; + uint32_t prefconfig[2]; + int prefcontrol; + int preffifo; + int prefcount; + struct omap_gpmc_cs_file_s { + uint32_t config[7]; + target_phys_addr_t base; + size_t size; + int iomemtype; + void (*base_update)(void *opaque, target_phys_addr_t new); + void (*unmap)(void *opaque); + void *opaque; + } cs_file[8]; + int ecc_cs; + int ecc_ptr; + uint32_t ecc_cfg; + struct ecc_state_s ecc[9]; +}; + +static void omap_gpmc_int_update(struct omap_gpmc_s *s) +{ + qemu_set_irq(s->irq, s->irqen & s->irqst); +} + +static void omap_gpmc_cs_map(struct omap_gpmc_cs_file_s *f, int base, int mask) +{ + /* TODO: check for overlapping regions and report access errors */ + if ((mask != 0x8 && mask != 0xc && mask != 0xe && mask != 0xf) || + (base < 0 || base >= 0x40) || + (base & 0x0f & ~mask)) { + fprintf(stderr, "%s: wrong cs address mapping/decoding!\n", + __FUNCTION__); + return; + } + + if (!f->opaque) + return; + + f->base = base << 24; + f->size = (0x0fffffff & ~(mask << 24)) + 1; + /* TODO: rather than setting the size of the mapping (which should be + * constant), the mask should cause wrapping of the address space, so + * that the same memory becomes accessible at every size bytes + * starting from base. */ + if (f->iomemtype) + cpu_register_physical_memory(f->base, f->size, f->iomemtype); + + if (f->base_update) + f->base_update(f->opaque, f->base); +} + +static void omap_gpmc_cs_unmap(struct omap_gpmc_cs_file_s *f) +{ + if (f->size) { + if (f->unmap) + f->unmap(f->opaque); + if (f->iomemtype) + cpu_register_physical_memory(f->base, f->size, IO_MEM_UNASSIGNED); + f->base = 0; + f->size = 0; + } +} + +static void omap_gpmc_reset(struct omap_gpmc_s *s) +{ + int i; + + s->sysconfig = 0; + s->irqst = 0; + s->irqen = 0; + omap_gpmc_int_update(s); + s->timeout = 0; + s->config = 0xa00; + s->prefconfig[0] = 0x00004000; + s->prefconfig[1] = 0x00000000; + s->prefcontrol = 0; + s->preffifo = 0; + s->prefcount = 0; + for (i = 0; i < 8; i ++) { + if (s->cs_file[i].config[6] & (1 << 6)) /* CSVALID */ + omap_gpmc_cs_unmap(s->cs_file + i); + s->cs_file[i].config[0] = i ? 1 << 12 : 0; + s->cs_file[i].config[1] = 0x101001; + s->cs_file[i].config[2] = 0x020201; + s->cs_file[i].config[3] = 0x10031003; + s->cs_file[i].config[4] = 0x10f1111; + s->cs_file[i].config[5] = 0; + s->cs_file[i].config[6] = 0xf00 | (i ? 0 : 1 << 6); + if (s->cs_file[i].config[6] & (1 << 6)) /* CSVALID */ + omap_gpmc_cs_map(&s->cs_file[i], + s->cs_file[i].config[6] & 0x1f, /* MASKADDR */ + (s->cs_file[i].config[6] >> 8 & 0xf)); /* BASEADDR */ + } + omap_gpmc_cs_map(s->cs_file, 0, 0xf); + s->ecc_cs = 0; + s->ecc_ptr = 0; + s->ecc_cfg = 0x3fcff000; + for (i = 0; i < 9; i ++) + ecc_reset(&s->ecc[i]); +} + +static uint32_t omap_gpmc_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; + int offset = addr - s->base; + int cs; + struct omap_gpmc_cs_file_s *f; + + switch (offset) { + case 0x000: /* GPMC_REVISION */ + return 0x20; + + case 0x010: /* GPMC_SYSCONFIG */ + return s->sysconfig; + + case 0x014: /* GPMC_SYSSTATUS */ + return 1; /* RESETDONE */ + + case 0x018: /* GPMC_IRQSTATUS */ + return s->irqst; + + case 0x01c: /* GPMC_IRQENABLE */ + return s->irqen; + + case 0x040: /* GPMC_TIMEOUT_CONTROL */ + return s->timeout; + + case 0x044: /* GPMC_ERR_ADDRESS */ + case 0x048: /* GPMC_ERR_TYPE */ + return 0; + + case 0x050: /* GPMC_CONFIG */ + return s->config; + + case 0x054: /* GPMC_STATUS */ + return 0x001; + + case 0x060 ... 0x1d4: + cs = (offset - 0x060) / 0x30; + offset -= cs * 0x30; + f = s->cs_file + cs; + switch (offset) { + case 0x60: /* GPMC_CONFIG1 */ + return f->config[0]; + case 0x64: /* GPMC_CONFIG2 */ + return f->config[1]; + case 0x68: /* GPMC_CONFIG3 */ + return f->config[2]; + case 0x6c: /* GPMC_CONFIG4 */ + return f->config[3]; + case 0x70: /* GPMC_CONFIG5 */ + return f->config[4]; + case 0x74: /* GPMC_CONFIG6 */ + return f->config[5]; + case 0x78: /* GPMC_CONFIG7 */ + return f->config[6]; + case 0x84: /* GPMC_NAND_DATA */ + return 0; + } + break; + + case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */ + return s->prefconfig[0]; + case 0x1e4: /* GPMC_PREFETCH_CONFIG2 */ + return s->prefconfig[1]; + case 0x1ec: /* GPMC_PREFETCH_CONTROL */ + return s->prefcontrol; + case 0x1f0: /* GPMC_PREFETCH_STATUS */ + return (s->preffifo << 24) | + ((s->preffifo > + ((s->prefconfig[0] >> 8) & 0x7f) ? 1 : 0) << 16) | + s->prefcount; + + case 0x1f4: /* GPMC_ECC_CONFIG */ + return s->ecc_cs; + case 0x1f8: /* GPMC_ECC_CONTROL */ + return s->ecc_ptr; + case 0x1fc: /* GPMC_ECC_SIZE_CONFIG */ + return s->ecc_cfg; + case 0x200 ... 0x220: /* GPMC_ECC_RESULT */ + cs = (offset & 0x1f) >> 2; + /* TODO: check correctness */ + return + ((s->ecc[cs].cp & 0x07) << 0) | + ((s->ecc[cs].cp & 0x38) << 13) | + ((s->ecc[cs].lp[0] & 0x1ff) << 3) | + ((s->ecc[cs].lp[1] & 0x1ff) << 19); + + case 0x230: /* GPMC_TESTMODE_CTRL */ + return 0; + case 0x234: /* GPMC_PSA_LSB */ + case 0x238: /* GPMC_PSA_MSB */ + return 0x00000000; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_gpmc_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; + int offset = addr - s->base; + int cs; + struct omap_gpmc_cs_file_s *f; + + switch (offset) { + case 0x000: /* GPMC_REVISION */ + case 0x014: /* GPMC_SYSSTATUS */ + case 0x054: /* GPMC_STATUS */ + case 0x1f0: /* GPMC_PREFETCH_STATUS */ + case 0x200 ... 0x220: /* GPMC_ECC_RESULT */ + case 0x234: /* GPMC_PSA_LSB */ + case 0x238: /* GPMC_PSA_MSB */ + OMAP_RO_REG(addr); + break; + + case 0x010: /* GPMC_SYSCONFIG */ + if ((value >> 3) == 0x3) + fprintf(stderr, "%s: bad SDRAM idle mode %i\n", + __FUNCTION__, value >> 3); + if (value & 2) + omap_gpmc_reset(s); + s->sysconfig = value & 0x19; + break; + + case 0x018: /* GPMC_IRQSTATUS */ + s->irqen = ~value; + omap_gpmc_int_update(s); + break; + + case 0x01c: /* GPMC_IRQENABLE */ + s->irqen = value & 0xf03; + omap_gpmc_int_update(s); + break; + + case 0x040: /* GPMC_TIMEOUT_CONTROL */ + s->timeout = value & 0x1ff1; + break; + + case 0x044: /* GPMC_ERR_ADDRESS */ + case 0x048: /* GPMC_ERR_TYPE */ + break; + + case 0x050: /* GPMC_CONFIG */ + s->config = value & 0xf13; + break; + + case 0x060 ... 0x1d4: + cs = (offset - 0x060) / 0x30; + offset -= cs * 0x30; + f = s->cs_file + cs; + switch (offset) { + case 0x60: /* GPMC_CONFIG1 */ + f->config[0] = value & 0xffef3e13; + break; + case 0x64: /* GPMC_CONFIG2 */ + f->config[1] = value & 0x001f1f8f; + break; + case 0x68: /* GPMC_CONFIG3 */ + f->config[2] = value & 0x001f1f8f; + break; + case 0x6c: /* GPMC_CONFIG4 */ + f->config[3] = value & 0x1f8f1f8f; + break; + case 0x70: /* GPMC_CONFIG5 */ + f->config[4] = value & 0x0f1f1f1f; + break; + case 0x74: /* GPMC_CONFIG6 */ + f->config[5] = value & 0x00000fcf; + break; + case 0x78: /* GPMC_CONFIG7 */ + if ((f->config[6] ^ value) & 0xf7f) { + if (f->config[6] & (1 << 6)) /* CSVALID */ + omap_gpmc_cs_unmap(f); + if (value & (1 << 6)) /* CSVALID */ + omap_gpmc_cs_map(f, value & 0x1f, /* MASKADDR */ + (value >> 8 & 0xf)); /* BASEADDR */ + } + f->config[6] = value & 0x00000f7f; + break; + case 0x7c: /* GPMC_NAND_COMMAND */ + case 0x80: /* GPMC_NAND_ADDRESS */ + case 0x84: /* GPMC_NAND_DATA */ + break; + + default: + goto bad_reg; + } + break; + + case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */ + s->prefconfig[0] = value & 0x7f8f7fbf; + /* TODO: update interrupts, fifos, dmas */ + break; + + case 0x1e4: /* GPMC_PREFETCH_CONFIG2 */ + s->prefconfig[1] = value & 0x3fff; + break; + + case 0x1ec: /* GPMC_PREFETCH_CONTROL */ + s->prefcontrol = value & 1; + if (s->prefcontrol) { + if (s->prefconfig[0] & 1) + s->preffifo = 0x40; + else + s->preffifo = 0x00; + } + /* TODO: start */ + break; + + case 0x1f4: /* GPMC_ECC_CONFIG */ + s->ecc_cs = 0x8f; + break; + case 0x1f8: /* GPMC_ECC_CONTROL */ + if (value & (1 << 8)) + for (cs = 0; cs < 9; cs ++) + ecc_reset(&s->ecc[cs]); + s->ecc_ptr = value & 0xf; + if (s->ecc_ptr == 0 || s->ecc_ptr > 9) { + s->ecc_ptr = 0; + s->ecc_cs &= ~1; + } + break; + case 0x1fc: /* GPMC_ECC_SIZE_CONFIG */ + s->ecc_cfg = value & 0x3fcff1ff; + break; + case 0x230: /* GPMC_TESTMODE_CTRL */ + if (value & 7) + fprintf(stderr, "%s: test mode enable attempt\n", __FUNCTION__); + break; + + default: + bad_reg: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_gpmc_readfn[] = { + omap_badwidth_read32, /* TODO */ + omap_badwidth_read32, /* TODO */ + omap_gpmc_read, +}; + +static CPUWriteMemoryFunc *omap_gpmc_writefn[] = { + omap_badwidth_write32, /* TODO */ + omap_badwidth_write32, /* TODO */ + omap_gpmc_write, +}; + +struct omap_gpmc_s *omap_gpmc_init(target_phys_addr_t base, qemu_irq irq) +{ + int iomemtype; + struct omap_gpmc_s *s = (struct omap_gpmc_s *) + qemu_mallocz(sizeof(struct omap_gpmc_s)); + + s->base = base; + omap_gpmc_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_gpmc_readfn, + omap_gpmc_writefn, s); + cpu_register_physical_memory(s->base, 0x1000, iomemtype); + + return s; +} + +void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, int iomemtype, + void (*base_upd)(void *opaque, target_phys_addr_t new), + void (*unmap)(void *opaque), void *opaque) +{ + struct omap_gpmc_cs_file_s *f; + + if (cs < 0 || cs >= 8) { + fprintf(stderr, "%s: bad chip-select %i\n", __FUNCTION__, cs); + exit(-1); + } + f = &s->cs_file[cs]; + + f->iomemtype = iomemtype; + f->base_update = base_upd; + f->unmap = unmap; + f->opaque = opaque; + + if (f->config[6] & (1 << 6)) /* CSVALID */ + omap_gpmc_cs_map(f, f->config[6] & 0x1f, /* MASKADDR */ + (f->config[6] >> 8 & 0xf)); /* BASEADDR */ +} + +/* General chip reset */ +static void omap2_mpu_reset(void *opaque) +{ + struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; + + omap_inth_reset(mpu->ih[0]); + omap_dma_reset(mpu->dma); + omap_prcm_reset(mpu->prcm); + omap_sysctl_reset(mpu->sysc); + omap_gp_timer_reset(mpu->gptimer[0]); + omap_gp_timer_reset(mpu->gptimer[1]); + omap_gp_timer_reset(mpu->gptimer[2]); + omap_gp_timer_reset(mpu->gptimer[3]); + omap_gp_timer_reset(mpu->gptimer[4]); + omap_gp_timer_reset(mpu->gptimer[5]); + omap_gp_timer_reset(mpu->gptimer[6]); + omap_gp_timer_reset(mpu->gptimer[7]); + omap_gp_timer_reset(mpu->gptimer[8]); + omap_gp_timer_reset(mpu->gptimer[9]); + omap_gp_timer_reset(mpu->gptimer[10]); + omap_gp_timer_reset(mpu->gptimer[11]); + omap_synctimer_reset(&mpu->synctimer); + omap_sdrc_reset(mpu->sdrc); + omap_gpmc_reset(mpu->gpmc); + omap_dss_reset(mpu->dss); + omap_uart_reset(mpu->uart[0]); + omap_uart_reset(mpu->uart[1]); + omap_uart_reset(mpu->uart[2]); + omap_mmc_reset(mpu->mmc); + omap_gpif_reset(mpu->gpif); + omap_mcspi_reset(mpu->mcspi[0]); + omap_mcspi_reset(mpu->mcspi[1]); + omap_i2c_reset(mpu->i2c[0]); + omap_i2c_reset(mpu->i2c[1]); + cpu_reset(mpu->env); +} + +static int omap2_validate_addr(struct omap_mpu_state_s *s, + target_phys_addr_t addr) +{ + return 1; +} + +static const struct dma_irq_map omap2_dma_irq_map[] = { + { 0, OMAP_INT_24XX_SDMA_IRQ0 }, + { 0, OMAP_INT_24XX_SDMA_IRQ1 }, + { 0, OMAP_INT_24XX_SDMA_IRQ2 }, + { 0, OMAP_INT_24XX_SDMA_IRQ3 }, +}; + +struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size, + DisplayState *ds, const char *core) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) + qemu_mallocz(sizeof(struct omap_mpu_state_s)); + ram_addr_t sram_base, q2_base; + qemu_irq *cpu_irq; + qemu_irq dma_irqs[4]; + omap_clk gpio_clks[4]; + int sdindex; + int i; + + /* Core */ + s->mpu_model = omap2420; + s->env = cpu_init(core ?: "arm1136-r2"); + if (!s->env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + s->sdram_size = sdram_size; + s->sram_size = OMAP242X_SRAM_SIZE; + + s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0]; + + /* Clocks */ + omap_clk_init(s); + + /* Memory-mapped stuff */ + cpu_register_physical_memory(OMAP2_Q2_BASE, s->sdram_size, + (q2_base = qemu_ram_alloc(s->sdram_size)) | IO_MEM_RAM); + cpu_register_physical_memory(OMAP2_SRAM_BASE, s->sram_size, + (sram_base = qemu_ram_alloc(s->sram_size)) | IO_MEM_RAM); + + s->l4 = omap_l4_init(OMAP2_L4_BASE, 54); + + /* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */ + cpu_irq = arm_pic_init_cpu(s->env); + s->ih[0] = omap2_inth_init(0x480fe000, 0x1000, 3, &s->irq[0], + cpu_irq[ARM_PIC_CPU_IRQ], cpu_irq[ARM_PIC_CPU_FIQ], + omap_findclk(s, "mpu_intc_fclk"), + omap_findclk(s, "mpu_intc_iclk")); + + s->prcm = omap_prcm_init(omap_l4tao(s->l4, 3), + s->irq[0][OMAP_INT_24XX_PRCM_MPU_IRQ], NULL, NULL, s); + + s->sysc = omap_sysctl_init(omap_l4tao(s->l4, 1), + omap_findclk(s, "omapctrl_iclk"), s); + + for (i = 0; i < 4; i ++) + dma_irqs[i] = + s->irq[omap2_dma_irq_map[i].ih][omap2_dma_irq_map[i].intr]; + s->dma = omap_dma4_init(0x48056000, dma_irqs, s, 256, 32, + omap_findclk(s, "sdma_iclk"), + omap_findclk(s, "sdma_fclk")); + s->port->addr_valid = omap2_validate_addr; + + /* Register SDRAM and SRAM ports for fast DMA transfers. */ + soc_dma_port_add_mem_ram(s->dma, q2_base, OMAP2_Q2_BASE, s->sdram_size); + soc_dma_port_add_mem_ram(s->dma, sram_base, OMAP2_SRAM_BASE, s->sram_size); + + s->uart[0] = omap2_uart_init(omap_l4ta(s->l4, 19), + s->irq[0][OMAP_INT_24XX_UART1_IRQ], + omap_findclk(s, "uart1_fclk"), + omap_findclk(s, "uart1_iclk"), + s->drq[OMAP24XX_DMA_UART1_TX], + s->drq[OMAP24XX_DMA_UART1_RX], serial_hds[0]); + s->uart[1] = omap2_uart_init(omap_l4ta(s->l4, 20), + s->irq[0][OMAP_INT_24XX_UART2_IRQ], + omap_findclk(s, "uart2_fclk"), + omap_findclk(s, "uart2_iclk"), + s->drq[OMAP24XX_DMA_UART2_TX], + s->drq[OMAP24XX_DMA_UART2_RX], + serial_hds[0] ? serial_hds[1] : 0); + s->uart[2] = omap2_uart_init(omap_l4ta(s->l4, 21), + s->irq[0][OMAP_INT_24XX_UART3_IRQ], + omap_findclk(s, "uart3_fclk"), + omap_findclk(s, "uart3_iclk"), + s->drq[OMAP24XX_DMA_UART3_TX], + s->drq[OMAP24XX_DMA_UART3_RX], + serial_hds[0] && serial_hds[1] ? serial_hds[2] : 0); + + s->gptimer[0] = omap_gp_timer_init(omap_l4ta(s->l4, 7), + s->irq[0][OMAP_INT_24XX_GPTIMER1], + omap_findclk(s, "wu_gpt1_clk"), + omap_findclk(s, "wu_l4_iclk")); + s->gptimer[1] = omap_gp_timer_init(omap_l4ta(s->l4, 8), + s->irq[0][OMAP_INT_24XX_GPTIMER2], + omap_findclk(s, "core_gpt2_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[2] = omap_gp_timer_init(omap_l4ta(s->l4, 22), + s->irq[0][OMAP_INT_24XX_GPTIMER3], + omap_findclk(s, "core_gpt3_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[3] = omap_gp_timer_init(omap_l4ta(s->l4, 23), + s->irq[0][OMAP_INT_24XX_GPTIMER4], + omap_findclk(s, "core_gpt4_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[4] = omap_gp_timer_init(omap_l4ta(s->l4, 24), + s->irq[0][OMAP_INT_24XX_GPTIMER5], + omap_findclk(s, "core_gpt5_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[5] = omap_gp_timer_init(omap_l4ta(s->l4, 25), + s->irq[0][OMAP_INT_24XX_GPTIMER6], + omap_findclk(s, "core_gpt6_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[6] = omap_gp_timer_init(omap_l4ta(s->l4, 26), + s->irq[0][OMAP_INT_24XX_GPTIMER7], + omap_findclk(s, "core_gpt7_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[7] = omap_gp_timer_init(omap_l4ta(s->l4, 27), + s->irq[0][OMAP_INT_24XX_GPTIMER8], + omap_findclk(s, "core_gpt8_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[8] = omap_gp_timer_init(omap_l4ta(s->l4, 28), + s->irq[0][OMAP_INT_24XX_GPTIMER9], + omap_findclk(s, "core_gpt9_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[9] = omap_gp_timer_init(omap_l4ta(s->l4, 29), + s->irq[0][OMAP_INT_24XX_GPTIMER10], + omap_findclk(s, "core_gpt10_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[10] = omap_gp_timer_init(omap_l4ta(s->l4, 30), + s->irq[0][OMAP_INT_24XX_GPTIMER11], + omap_findclk(s, "core_gpt11_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[11] = omap_gp_timer_init(omap_l4ta(s->l4, 31), + s->irq[0][OMAP_INT_24XX_GPTIMER12], + omap_findclk(s, "core_gpt12_clk"), + omap_findclk(s, "core_l4_iclk")); + + omap_tap_init(omap_l4ta(s->l4, 2), s); + + omap_synctimer_init(omap_l4tao(s->l4, 2), s, + omap_findclk(s, "clk32-kHz"), + omap_findclk(s, "core_l4_iclk")); + + s->i2c[0] = omap2_i2c_init(omap_l4tao(s->l4, 5), + s->irq[0][OMAP_INT_24XX_I2C1_IRQ], + &s->drq[OMAP24XX_DMA_I2C1_TX], + omap_findclk(s, "i2c1.fclk"), + omap_findclk(s, "i2c1.iclk")); + s->i2c[1] = omap2_i2c_init(omap_l4tao(s->l4, 6), + s->irq[0][OMAP_INT_24XX_I2C2_IRQ], + &s->drq[OMAP24XX_DMA_I2C2_TX], + omap_findclk(s, "i2c2.fclk"), + omap_findclk(s, "i2c2.iclk")); + + gpio_clks[0] = omap_findclk(s, "gpio1_dbclk"); + gpio_clks[1] = omap_findclk(s, "gpio2_dbclk"); + gpio_clks[2] = omap_findclk(s, "gpio3_dbclk"); + gpio_clks[3] = omap_findclk(s, "gpio4_dbclk"); + s->gpif = omap2_gpio_init(omap_l4ta(s->l4, 3), + &s->irq[0][OMAP_INT_24XX_GPIO_BANK1], + gpio_clks, omap_findclk(s, "gpio_iclk"), 4); + + s->sdrc = omap_sdrc_init(0x68009000); + s->gpmc = omap_gpmc_init(0x6800a000, s->irq[0][OMAP_INT_24XX_GPMC_IRQ]); + + sdindex = drive_get_index(IF_SD, 0, 0); + if (sdindex == -1) { + fprintf(stderr, "qemu: missing SecureDigital device\n"); + exit(1); + } + s->mmc = omap2_mmc_init(omap_l4tao(s->l4, 9), drives_table[sdindex].bdrv, + s->irq[0][OMAP_INT_24XX_MMC_IRQ], + &s->drq[OMAP24XX_DMA_MMC1_TX], + omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk")); + + s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), 4, + s->irq[0][OMAP_INT_24XX_MCSPI1_IRQ], + &s->drq[OMAP24XX_DMA_SPI1_TX0], + omap_findclk(s, "spi1_fclk"), + omap_findclk(s, "spi1_iclk")); + s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), 2, + s->irq[0][OMAP_INT_24XX_MCSPI2_IRQ], + &s->drq[OMAP24XX_DMA_SPI2_TX0], + omap_findclk(s, "spi2_fclk"), + omap_findclk(s, "spi2_iclk")); + + s->dss = omap_dss_init(omap_l4ta(s->l4, 10), 0x68000800, ds, + /* XXX wire M_IRQ_25, D_L2_IRQ_30 and I_IRQ_13 together */ + s->irq[0][OMAP_INT_24XX_DSS_IRQ], s->drq[OMAP24XX_DMA_DSS], + omap_findclk(s, "dss_clk1"), omap_findclk(s, "dss_clk2"), + omap_findclk(s, "dss_54m_clk"), + omap_findclk(s, "dss_l3_iclk"), + omap_findclk(s, "dss_l4_iclk")); + + omap_sti_init(omap_l4ta(s->l4, 18), 0x54000000, + s->irq[0][OMAP_INT_24XX_STI], omap_findclk(s, "emul_ck"), + serial_hds[0] && serial_hds[1] && serial_hds[2] ? + serial_hds[3] : 0); + + s->eac = omap_eac_init(omap_l4ta(s->l4, 32), + s->irq[0][OMAP_INT_24XX_EAC_IRQ], + /* Ten consecutive lines */ + &s->drq[OMAP24XX_DMA_EAC_AC_RD], + omap_findclk(s, "func_96m_clk"), + omap_findclk(s, "core_l4_iclk")); + + /* All register mappings (includin those not currenlty implemented): + * SystemControlMod 48000000 - 48000fff + * SystemControlL4 48001000 - 48001fff + * 32kHz Timer Mod 48004000 - 48004fff + * 32kHz Timer L4 48005000 - 48005fff + * PRCM ModA 48008000 - 480087ff + * PRCM ModB 48008800 - 48008fff + * PRCM L4 48009000 - 48009fff + * TEST-BCM Mod 48012000 - 48012fff + * TEST-BCM L4 48013000 - 48013fff + * TEST-TAP Mod 48014000 - 48014fff + * TEST-TAP L4 48015000 - 48015fff + * GPIO1 Mod 48018000 - 48018fff + * GPIO Top 48019000 - 48019fff + * GPIO2 Mod 4801a000 - 4801afff + * GPIO L4 4801b000 - 4801bfff + * GPIO3 Mod 4801c000 - 4801cfff + * GPIO4 Mod 4801e000 - 4801efff + * WDTIMER1 Mod 48020000 - 48010fff + * WDTIMER Top 48021000 - 48011fff + * WDTIMER2 Mod 48022000 - 48012fff + * WDTIMER L4 48023000 - 48013fff + * WDTIMER3 Mod 48024000 - 48014fff + * WDTIMER3 L4 48025000 - 48015fff + * WDTIMER4 Mod 48026000 - 48016fff + * WDTIMER4 L4 48027000 - 48017fff + * GPTIMER1 Mod 48028000 - 48018fff + * GPTIMER1 L4 48029000 - 48019fff + * GPTIMER2 Mod 4802a000 - 4801afff + * GPTIMER2 L4 4802b000 - 4801bfff + * L4-Config AP 48040000 - 480407ff + * L4-Config IP 48040800 - 48040fff + * L4-Config LA 48041000 - 48041fff + * ARM11ETB Mod 48048000 - 48049fff + * ARM11ETB L4 4804a000 - 4804afff + * DISPLAY Top 48050000 - 480503ff + * DISPLAY DISPC 48050400 - 480507ff + * DISPLAY RFBI 48050800 - 48050bff + * DISPLAY VENC 48050c00 - 48050fff + * DISPLAY L4 48051000 - 48051fff + * CAMERA Top 48052000 - 480523ff + * CAMERA core 48052400 - 480527ff + * CAMERA DMA 48052800 - 48052bff + * CAMERA MMU 48052c00 - 48052fff + * CAMERA L4 48053000 - 48053fff + * SDMA Mod 48056000 - 48056fff + * SDMA L4 48057000 - 48057fff + * SSI Top 48058000 - 48058fff + * SSI GDD 48059000 - 48059fff + * SSI Port1 4805a000 - 4805afff + * SSI Port2 4805b000 - 4805bfff + * SSI L4 4805c000 - 4805cfff + * USB Mod 4805e000 - 480fefff + * USB L4 4805f000 - 480fffff + * WIN_TRACER1 Mod 48060000 - 48060fff + * WIN_TRACER1 L4 48061000 - 48061fff + * WIN_TRACER2 Mod 48062000 - 48062fff + * WIN_TRACER2 L4 48063000 - 48063fff + * WIN_TRACER3 Mod 48064000 - 48064fff + * WIN_TRACER3 L4 48065000 - 48065fff + * WIN_TRACER4 Top 48066000 - 480660ff + * WIN_TRACER4 ETT 48066100 - 480661ff + * WIN_TRACER4 WT 48066200 - 480662ff + * WIN_TRACER4 L4 48067000 - 48067fff + * XTI Mod 48068000 - 48068fff + * XTI L4 48069000 - 48069fff + * UART1 Mod 4806a000 - 4806afff + * UART1 L4 4806b000 - 4806bfff + * UART2 Mod 4806c000 - 4806cfff + * UART2 L4 4806d000 - 4806dfff + * UART3 Mod 4806e000 - 4806efff + * UART3 L4 4806f000 - 4806ffff + * I2C1 Mod 48070000 - 48070fff + * I2C1 L4 48071000 - 48071fff + * I2C2 Mod 48072000 - 48072fff + * I2C2 L4 48073000 - 48073fff + * McBSP1 Mod 48074000 - 48074fff + * McBSP1 L4 48075000 - 48075fff + * McBSP2 Mod 48076000 - 48076fff + * McBSP2 L4 48077000 - 48077fff + * GPTIMER3 Mod 48078000 - 48078fff + * GPTIMER3 L4 48079000 - 48079fff + * GPTIMER4 Mod 4807a000 - 4807afff + * GPTIMER4 L4 4807b000 - 4807bfff + * GPTIMER5 Mod 4807c000 - 4807cfff + * GPTIMER5 L4 4807d000 - 4807dfff + * GPTIMER6 Mod 4807e000 - 4807efff + * GPTIMER6 L4 4807f000 - 4807ffff + * GPTIMER7 Mod 48080000 - 48080fff + * GPTIMER7 L4 48081000 - 48081fff + * GPTIMER8 Mod 48082000 - 48082fff + * GPTIMER8 L4 48083000 - 48083fff + * GPTIMER9 Mod 48084000 - 48084fff + * GPTIMER9 L4 48085000 - 48085fff + * GPTIMER10 Mod 48086000 - 48086fff + * GPTIMER10 L4 48087000 - 48087fff + * GPTIMER11 Mod 48088000 - 48088fff + * GPTIMER11 L4 48089000 - 48089fff + * GPTIMER12 Mod 4808a000 - 4808afff + * GPTIMER12 L4 4808b000 - 4808bfff + * EAC Mod 48090000 - 48090fff + * EAC L4 48091000 - 48091fff + * FAC Mod 48092000 - 48092fff + * FAC L4 48093000 - 48093fff + * MAILBOX Mod 48094000 - 48094fff + * MAILBOX L4 48095000 - 48095fff + * SPI1 Mod 48098000 - 48098fff + * SPI1 L4 48099000 - 48099fff + * SPI2 Mod 4809a000 - 4809afff + * SPI2 L4 4809b000 - 4809bfff + * MMC/SDIO Mod 4809c000 - 4809cfff + * MMC/SDIO L4 4809d000 - 4809dfff + * MS_PRO Mod 4809e000 - 4809efff + * MS_PRO L4 4809f000 - 4809ffff + * RNG Mod 480a0000 - 480a0fff + * RNG L4 480a1000 - 480a1fff + * DES3DES Mod 480a2000 - 480a2fff + * DES3DES L4 480a3000 - 480a3fff + * SHA1MD5 Mod 480a4000 - 480a4fff + * SHA1MD5 L4 480a5000 - 480a5fff + * AES Mod 480a6000 - 480a6fff + * AES L4 480a7000 - 480a7fff + * PKA Mod 480a8000 - 480a9fff + * PKA L4 480aa000 - 480aafff + * MG Mod 480b0000 - 480b0fff + * MG L4 480b1000 - 480b1fff + * HDQ/1-wire Mod 480b2000 - 480b2fff + * HDQ/1-wire L4 480b3000 - 480b3fff + * MPU interrupt 480fe000 - 480fefff + * STI channel base 54000000 - 5400ffff + * IVA RAM 5c000000 - 5c01ffff + * IVA ROM 5c020000 - 5c027fff + * IMG_BUF_A 5c040000 - 5c040fff + * IMG_BUF_B 5c042000 - 5c042fff + * VLCDS 5c048000 - 5c0487ff + * IMX_COEF 5c049000 - 5c04afff + * IMX_CMD 5c051000 - 5c051fff + * VLCDQ 5c053000 - 5c0533ff + * VLCDH 5c054000 - 5c054fff + * SEQ_CMD 5c055000 - 5c055fff + * IMX_REG 5c056000 - 5c0560ff + * VLCD_REG 5c056100 - 5c0561ff + * SEQ_REG 5c056200 - 5c0562ff + * IMG_BUF_REG 5c056300 - 5c0563ff + * SEQIRQ_REG 5c056400 - 5c0564ff + * OCP_REG 5c060000 - 5c060fff + * SYSC_REG 5c070000 - 5c070fff + * MMU_REG 5d000000 - 5d000fff + * sDMA R 68000400 - 680005ff + * sDMA W 68000600 - 680007ff + * Display Control 68000800 - 680009ff + * DSP subsystem 68000a00 - 68000bff + * MPU subsystem 68000c00 - 68000dff + * IVA subsystem 68001000 - 680011ff + * USB 68001200 - 680013ff + * Camera 68001400 - 680015ff + * VLYNQ (firewall) 68001800 - 68001bff + * VLYNQ 68001e00 - 68001fff + * SSI 68002000 - 680021ff + * L4 68002400 - 680025ff + * DSP (firewall) 68002800 - 68002bff + * DSP subsystem 68002e00 - 68002fff + * IVA (firewall) 68003000 - 680033ff + * IVA 68003600 - 680037ff + * GFX 68003a00 - 68003bff + * CMDWR emulation 68003c00 - 68003dff + * SMS 68004000 - 680041ff + * OCM 68004200 - 680043ff + * GPMC 68004400 - 680045ff + * RAM (firewall) 68005000 - 680053ff + * RAM (err login) 68005400 - 680057ff + * ROM (firewall) 68005800 - 68005bff + * ROM (err login) 68005c00 - 68005fff + * GPMC (firewall) 68006000 - 680063ff + * GPMC (err login) 68006400 - 680067ff + * SMS (err login) 68006c00 - 68006fff + * SMS registers 68008000 - 68008fff + * SDRC registers 68009000 - 68009fff + * GPMC registers 6800a000 6800afff + */ + + qemu_register_reset(omap2_mpu_reset, s); + + return s; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/omap.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/omap.c --- qemu-0.9.1/hw/omap.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/omap.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,5772 +0,0 @@ -/* - * TI OMAP processors emulation. - * - * Copyright (C) 2006-2007 Andrzej Zaborowski - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ -#include "hw.h" -#include "arm-misc.h" -#include "omap.h" -#include "sysemu.h" -#include "qemu-timer.h" -/* We use pc-style serial ports. */ -#include "pc.h" - -/* Should signal the TCMI */ -uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr) -{ - uint8_t ret; - - OMAP_8B_REG(addr); - cpu_physical_memory_read(addr, (void *) &ret, 1); - return ret; -} - -void omap_badwidth_write8(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - uint8_t val8 = value; - - OMAP_8B_REG(addr); - cpu_physical_memory_write(addr, (void *) &val8, 1); -} - -uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr) -{ - uint16_t ret; - - OMAP_16B_REG(addr); - cpu_physical_memory_read(addr, (void *) &ret, 2); - return ret; -} - -void omap_badwidth_write16(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - uint16_t val16 = value; - - OMAP_16B_REG(addr); - cpu_physical_memory_write(addr, (void *) &val16, 2); -} - -uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr) -{ - uint32_t ret; - - OMAP_32B_REG(addr); - cpu_physical_memory_read(addr, (void *) &ret, 4); - return ret; -} - -void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - OMAP_32B_REG(addr); - cpu_physical_memory_write(addr, (void *) &value, 4); -} - -/* Interrupt Handlers */ -struct omap_intr_handler_bank_s { - uint32_t irqs; - uint32_t inputs; - uint32_t mask; - uint32_t fiq; - uint32_t sens_edge; - unsigned char priority[32]; -}; - -struct omap_intr_handler_s { - qemu_irq *pins; - qemu_irq parent_intr[2]; - target_phys_addr_t base; - unsigned char nbanks; - - /* state */ - uint32_t new_agr[2]; - int sir_intr[2]; - struct omap_intr_handler_bank_s banks[]; -}; - -static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq) -{ - int i, j, sir_intr, p_intr, p, f; - uint32_t level; - sir_intr = 0; - p_intr = 255; - - /* Find the interrupt line with the highest dynamic priority. - * Note: 0 denotes the hightest priority. - * If all interrupts have the same priority, the default order is IRQ_N, - * IRQ_N-1,...,IRQ_0. */ - for (j = 0; j < s->nbanks; ++j) { - level = s->banks[j].irqs & ~s->banks[j].mask & - (is_fiq ? s->banks[j].fiq : ~s->banks[j].fiq); - for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f, - level >>= f) { - p = s->banks[j].priority[i]; - if (p <= p_intr) { - p_intr = p; - sir_intr = 32 * j + i; - } - f = ffs(level >> 1); - } - } - s->sir_intr[is_fiq] = sir_intr; -} - -static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq) -{ - int i; - uint32_t has_intr = 0; - - for (i = 0; i < s->nbanks; ++i) - has_intr |= s->banks[i].irqs & ~s->banks[i].mask & - (is_fiq ? s->banks[i].fiq : ~s->banks[i].fiq); - - if (s->new_agr[is_fiq] && has_intr) { - s->new_agr[is_fiq] = 0; - omap_inth_sir_update(s, is_fiq); - qemu_set_irq(s->parent_intr[is_fiq], 1); - } -} - -#define INT_FALLING_EDGE 0 -#define INT_LOW_LEVEL 1 - -static void omap_set_intr(void *opaque, int irq, int req) -{ - struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque; - uint32_t rise; - - struct omap_intr_handler_bank_s *bank = &ih->banks[irq >> 5]; - int n = irq & 31; - - if (req) { - rise = ~bank->irqs & (1 << n); - if (~bank->sens_edge & (1 << n)) - rise &= ~bank->inputs & (1 << n); - - bank->inputs |= (1 << n); - if (rise) { - bank->irqs |= rise; - omap_inth_update(ih, 0); - omap_inth_update(ih, 1); - } - } else { - rise = bank->sens_edge & bank->irqs & (1 << n); - bank->irqs &= ~rise; - bank->inputs &= ~(1 << n); - } -} - -static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; - int i, offset = addr - s->base; - int bank_no = offset >> 8; - int line_no; - struct omap_intr_handler_bank_s *bank = &s->banks[bank_no]; - offset &= 0xff; - - switch (offset) { - case 0x00: /* ITR */ - return bank->irqs; - - case 0x04: /* MIR */ - return bank->mask; - - case 0x10: /* SIR_IRQ_CODE */ - case 0x14: /* SIR_FIQ_CODE */ - if (bank_no != 0) - break; - line_no = s->sir_intr[(offset - 0x10) >> 2]; - bank = &s->banks[line_no >> 5]; - i = line_no & 31; - if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE) - bank->irqs &= ~(1 << i); - return line_no; - - case 0x18: /* CONTROL_REG */ - if (bank_no != 0) - break; - return 0; - - case 0x1c: /* ILR0 */ - case 0x20: /* ILR1 */ - case 0x24: /* ILR2 */ - case 0x28: /* ILR3 */ - case 0x2c: /* ILR4 */ - case 0x30: /* ILR5 */ - case 0x34: /* ILR6 */ - case 0x38: /* ILR7 */ - case 0x3c: /* ILR8 */ - case 0x40: /* ILR9 */ - case 0x44: /* ILR10 */ - case 0x48: /* ILR11 */ - case 0x4c: /* ILR12 */ - case 0x50: /* ILR13 */ - case 0x54: /* ILR14 */ - case 0x58: /* ILR15 */ - case 0x5c: /* ILR16 */ - case 0x60: /* ILR17 */ - case 0x64: /* ILR18 */ - case 0x68: /* ILR19 */ - case 0x6c: /* ILR20 */ - case 0x70: /* ILR21 */ - case 0x74: /* ILR22 */ - case 0x78: /* ILR23 */ - case 0x7c: /* ILR24 */ - case 0x80: /* ILR25 */ - case 0x84: /* ILR26 */ - case 0x88: /* ILR27 */ - case 0x8c: /* ILR28 */ - case 0x90: /* ILR29 */ - case 0x94: /* ILR30 */ - case 0x98: /* ILR31 */ - i = (offset - 0x1c) >> 2; - return (bank->priority[i] << 2) | - (((bank->sens_edge >> i) & 1) << 1) | - ((bank->fiq >> i) & 1); - - case 0x9c: /* ISR */ - return 0x00000000; - - } - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_inth_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; - int i, offset = addr - s->base; - int bank_no = offset >> 8; - struct omap_intr_handler_bank_s *bank = &s->banks[bank_no]; - offset &= 0xff; - - switch (offset) { - case 0x00: /* ITR */ - /* Important: ignore the clearing if the IRQ is level-triggered and - the input bit is 1 */ - bank->irqs &= value | (bank->inputs & bank->sens_edge); - return; - - case 0x04: /* MIR */ - bank->mask = value; - omap_inth_update(s, 0); - omap_inth_update(s, 1); - return; - - case 0x10: /* SIR_IRQ_CODE */ - case 0x14: /* SIR_FIQ_CODE */ - OMAP_RO_REG(addr); - break; - - case 0x18: /* CONTROL_REG */ - if (bank_no != 0) - break; - if (value & 2) { - qemu_set_irq(s->parent_intr[1], 0); - s->new_agr[1] = ~0; - omap_inth_update(s, 1); - } - if (value & 1) { - qemu_set_irq(s->parent_intr[0], 0); - s->new_agr[0] = ~0; - omap_inth_update(s, 0); - } - return; - - case 0x1c: /* ILR0 */ - case 0x20: /* ILR1 */ - case 0x24: /* ILR2 */ - case 0x28: /* ILR3 */ - case 0x2c: /* ILR4 */ - case 0x30: /* ILR5 */ - case 0x34: /* ILR6 */ - case 0x38: /* ILR7 */ - case 0x3c: /* ILR8 */ - case 0x40: /* ILR9 */ - case 0x44: /* ILR10 */ - case 0x48: /* ILR11 */ - case 0x4c: /* ILR12 */ - case 0x50: /* ILR13 */ - case 0x54: /* ILR14 */ - case 0x58: /* ILR15 */ - case 0x5c: /* ILR16 */ - case 0x60: /* ILR17 */ - case 0x64: /* ILR18 */ - case 0x68: /* ILR19 */ - case 0x6c: /* ILR20 */ - case 0x70: /* ILR21 */ - case 0x74: /* ILR22 */ - case 0x78: /* ILR23 */ - case 0x7c: /* ILR24 */ - case 0x80: /* ILR25 */ - case 0x84: /* ILR26 */ - case 0x88: /* ILR27 */ - case 0x8c: /* ILR28 */ - case 0x90: /* ILR29 */ - case 0x94: /* ILR30 */ - case 0x98: /* ILR31 */ - i = (offset - 0x1c) >> 2; - bank->priority[i] = (value >> 2) & 0x1f; - bank->sens_edge &= ~(1 << i); - bank->sens_edge |= ((value >> 1) & 1) << i; - bank->fiq &= ~(1 << i); - bank->fiq |= (value & 1) << i; - return; - - case 0x9c: /* ISR */ - for (i = 0; i < 32; i ++) - if (value & (1 << i)) { - omap_set_intr(s, 32 * bank_no + i, 1); - return; - } - return; - } - OMAP_BAD_REG(addr); -} - -static CPUReadMemoryFunc *omap_inth_readfn[] = { - omap_badwidth_read32, - omap_badwidth_read32, - omap_inth_read, -}; - -static CPUWriteMemoryFunc *omap_inth_writefn[] = { - omap_inth_write, - omap_inth_write, - omap_inth_write, -}; - -void omap_inth_reset(struct omap_intr_handler_s *s) -{ - int i; - - for (i = 0; i < s->nbanks; ++i){ - s->banks[i].irqs = 0x00000000; - s->banks[i].mask = 0xffffffff; - s->banks[i].sens_edge = 0x00000000; - s->banks[i].fiq = 0x00000000; - s->banks[i].inputs = 0x00000000; - memset(s->banks[i].priority, 0, sizeof(s->banks[i].priority)); - } - - s->new_agr[0] = ~0; - s->new_agr[1] = ~0; - s->sir_intr[0] = 0; - s->sir_intr[1] = 0; - - qemu_set_irq(s->parent_intr[0], 0); - qemu_set_irq(s->parent_intr[1], 0); -} - -struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base, - unsigned long size, unsigned char nbanks, - qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk) -{ - int iomemtype; - struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) - qemu_mallocz(sizeof(struct omap_intr_handler_s) + - sizeof(struct omap_intr_handler_bank_s) * nbanks); - - s->parent_intr[0] = parent_irq; - s->parent_intr[1] = parent_fiq; - s->base = base; - s->nbanks = nbanks; - s->pins = qemu_allocate_irqs(omap_set_intr, s, nbanks * 32); - - omap_inth_reset(s); - - iomemtype = cpu_register_io_memory(0, omap_inth_readfn, - omap_inth_writefn, s); - cpu_register_physical_memory(s->base, size, iomemtype); - - return s; -} - -/* OMAP1 DMA module */ -struct omap_dma_channel_s { - /* transfer data */ - int burst[2]; - int pack[2]; - enum omap_dma_port port[2]; - target_phys_addr_t addr[2]; - omap_dma_addressing_t mode[2]; - uint16_t elements; - uint16_t frames; - int16_t frame_index[2]; - int16_t element_index[2]; - int data_type; - - /* transfer type */ - int transparent_copy; - int constant_fill; - uint32_t color; - - /* auto init and linked channel data */ - int end_prog; - int repeat; - int auto_init; - int link_enabled; - int link_next_ch; - - /* interruption data */ - int interrupts; - int status; - - /* state data */ - int active; - int enable; - int sync; - int pending_request; - int waiting_end_prog; - uint16_t cpc; - - /* sync type */ - int fs; - int bs; - - /* compatibility */ - int omap_3_1_compatible_disable; - - qemu_irq irq; - struct omap_dma_channel_s *sibling; - - struct omap_dma_reg_set_s { - target_phys_addr_t src, dest; - int frame; - int element; - int frame_delta[2]; - int elem_delta[2]; - int frames; - int elements; - } active_set; - - /* unused parameters */ - int priority; - int interleave_disabled; - int type; -}; - -struct omap_dma_s { - QEMUTimer *tm; - struct omap_mpu_state_s *mpu; - target_phys_addr_t base; - omap_clk clk; - int64_t delay; - uint32_t drq; - enum omap_dma_model model; - int omap_3_1_mapping_disabled; - - uint16_t gcr; - int run_count; - - int chans; - struct omap_dma_channel_s ch[16]; - struct omap_dma_lcd_channel_s lcd_ch; -}; - -/* Interrupts */ -#define TIMEOUT_INTR (1 << 0) -#define EVENT_DROP_INTR (1 << 1) -#define HALF_FRAME_INTR (1 << 2) -#define END_FRAME_INTR (1 << 3) -#define LAST_FRAME_INTR (1 << 4) -#define END_BLOCK_INTR (1 << 5) -#define SYNC (1 << 6) - -static void omap_dma_interrupts_update(struct omap_dma_s *s) -{ - struct omap_dma_channel_s *ch = s->ch; - int i; - - if (s->omap_3_1_mapping_disabled) { - for (i = 0; i < s->chans; i ++, ch ++) - if (ch->status) - qemu_irq_raise(ch->irq); - } else { - /* First three interrupts are shared between two channels each. */ - for (i = 0; i < 6; i ++, ch ++) { - if (ch->status || (ch->sibling && ch->sibling->status)) - qemu_irq_raise(ch->irq); - } - } -} - -static void omap_dma_channel_load(struct omap_dma_s *s, - struct omap_dma_channel_s *ch) -{ - struct omap_dma_reg_set_s *a = &ch->active_set; - int i; - int omap_3_1 = !ch->omap_3_1_compatible_disable; - - /* - * TODO: verify address ranges and alignment - * TODO: port endianness - */ - - a->src = ch->addr[0]; - a->dest = ch->addr[1]; - a->frames = ch->frames; - a->elements = ch->elements; - a->frame = 0; - a->element = 0; - - if (unlikely(!ch->elements || !ch->frames)) { - printf("%s: bad DMA request\n", __FUNCTION__); - return; - } - - for (i = 0; i < 2; i ++) - switch (ch->mode[i]) { - case constant: - a->elem_delta[i] = 0; - a->frame_delta[i] = 0; - break; - case post_incremented: - a->elem_delta[i] = ch->data_type; - a->frame_delta[i] = 0; - break; - case single_index: - a->elem_delta[i] = ch->data_type + - ch->element_index[omap_3_1 ? 0 : i] - 1; - a->frame_delta[i] = 0; - break; - case double_index: - a->elem_delta[i] = ch->data_type + - ch->element_index[omap_3_1 ? 0 : i] - 1; - a->frame_delta[i] = ch->frame_index[omap_3_1 ? 0 : i] - - ch->element_index[omap_3_1 ? 0 : i]; - break; - default: - break; - } -} - -static void omap_dma_activate_channel(struct omap_dma_s *s, - struct omap_dma_channel_s *ch) -{ - if (!ch->active) { - ch->active = 1; - if (ch->sync) - ch->status |= SYNC; - s->run_count ++; - } - - if (s->delay && !qemu_timer_pending(s->tm)) - qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay); -} - -static void omap_dma_deactivate_channel(struct omap_dma_s *s, - struct omap_dma_channel_s *ch) -{ - /* Update cpc */ - ch->cpc = ch->active_set.dest & 0xffff; - - if (ch->pending_request && !ch->waiting_end_prog) { - /* Don't deactivate the channel */ - ch->pending_request = 0; - return; - } - - /* Don't deactive the channel if it is synchronized and the DMA request is - active */ - if (ch->sync && (s->drq & (1 << ch->sync))) - return; - - if (ch->active) { - ch->active = 0; - ch->status &= ~SYNC; - s->run_count --; - } - - if (!s->run_count) - qemu_del_timer(s->tm); -} - -static void omap_dma_enable_channel(struct omap_dma_s *s, - struct omap_dma_channel_s *ch) -{ - if (!ch->enable) { - ch->enable = 1; - ch->waiting_end_prog = 0; - omap_dma_channel_load(s, ch); - if ((!ch->sync) || (s->drq & (1 << ch->sync))) - omap_dma_activate_channel(s, ch); - } -} - -static void omap_dma_disable_channel(struct omap_dma_s *s, - struct omap_dma_channel_s *ch) -{ - if (ch->enable) { - ch->enable = 0; - /* Discard any pending request */ - ch->pending_request = 0; - omap_dma_deactivate_channel(s, ch); - } -} - -static void omap_dma_channel_end_prog(struct omap_dma_s *s, - struct omap_dma_channel_s *ch) -{ - if (ch->waiting_end_prog) { - ch->waiting_end_prog = 0; - if (!ch->sync || ch->pending_request) { - ch->pending_request = 0; - omap_dma_activate_channel(s, ch); - } - } -} - -static void omap_dma_enable_3_1_mapping(struct omap_dma_s *s) -{ - s->omap_3_1_mapping_disabled = 0; - s->chans = 9; -} - -static void omap_dma_disable_3_1_mapping(struct omap_dma_s *s) -{ - s->omap_3_1_mapping_disabled = 1; - s->chans = 16; -} - -static void omap_dma_process_request(struct omap_dma_s *s, int request) -{ - int channel; - int drop_event = 0; - struct omap_dma_channel_s *ch = s->ch; - - for (channel = 0; channel < s->chans; channel ++, ch ++) { - if (ch->enable && ch->sync == request) { - if (!ch->active) - omap_dma_activate_channel(s, ch); - else if (!ch->pending_request) - ch->pending_request = 1; - else { - /* Request collision */ - /* Second request received while processing other request */ - ch->status |= EVENT_DROP_INTR; - drop_event = 1; - } - } - } - - if (drop_event) - omap_dma_interrupts_update(s); -} - -static void omap_dma_channel_run(struct omap_dma_s *s) -{ - int n = s->chans; - uint16_t status; - uint8_t value[4]; - struct omap_dma_port_if_s *src_p, *dest_p; - struct omap_dma_reg_set_s *a; - struct omap_dma_channel_s *ch; - - for (ch = s->ch; n; n --, ch ++) { - if (!ch->active) - continue; - - a = &ch->active_set; - - src_p = &s->mpu->port[ch->port[0]]; - dest_p = &s->mpu->port[ch->port[1]]; - if ((!ch->constant_fill && !src_p->addr_valid(s->mpu, a->src)) || - (!dest_p->addr_valid(s->mpu, a->dest))) { -#if 0 - /* Bus time-out */ - if (ch->interrupts & TIMEOUT_INTR) - ch->status |= TIMEOUT_INTR; - omap_dma_deactivate_channel(s, ch); - continue; -#endif - printf("%s: Bus time-out in DMA%i operation\n", - __FUNCTION__, s->chans - n); - } - - status = ch->status; - while (status == ch->status && ch->active) { - /* Transfer a single element */ - /* FIXME: check the endianness */ - if (!ch->constant_fill) - cpu_physical_memory_read(a->src, value, ch->data_type); - else - *(uint32_t *) value = ch->color; - - if (!ch->transparent_copy || - *(uint32_t *) value != ch->color) - cpu_physical_memory_write(a->dest, value, ch->data_type); - - a->src += a->elem_delta[0]; - a->dest += a->elem_delta[1]; - a->element ++; - - /* If the channel is element synchronized, deactivate it */ - if (ch->sync && !ch->fs && !ch->bs) - omap_dma_deactivate_channel(s, ch); - - /* If it is the last frame, set the LAST_FRAME interrupt */ - if (a->element == 1 && a->frame == a->frames - 1) - if (ch->interrupts & LAST_FRAME_INTR) - ch->status |= LAST_FRAME_INTR; - - /* If the half of the frame was reached, set the HALF_FRAME - interrupt */ - if (a->element == (a->elements >> 1)) - if (ch->interrupts & HALF_FRAME_INTR) - ch->status |= HALF_FRAME_INTR; - - if (a->element == a->elements) { - /* End of Frame */ - a->element = 0; - a->src += a->frame_delta[0]; - a->dest += a->frame_delta[1]; - a->frame ++; - - /* If the channel is frame synchronized, deactivate it */ - if (ch->sync && ch->fs) - omap_dma_deactivate_channel(s, ch); - - /* If the channel is async, update cpc */ - if (!ch->sync) - ch->cpc = a->dest & 0xffff; - - /* Set the END_FRAME interrupt */ - if (ch->interrupts & END_FRAME_INTR) - ch->status |= END_FRAME_INTR; - - if (a->frame == a->frames) { - /* End of Block */ - /* Disable the channel */ - - if (ch->omap_3_1_compatible_disable) { - omap_dma_disable_channel(s, ch); - if (ch->link_enabled) - omap_dma_enable_channel(s, - &s->ch[ch->link_next_ch]); - } else { - if (!ch->auto_init) - omap_dma_disable_channel(s, ch); - else if (ch->repeat || ch->end_prog) - omap_dma_channel_load(s, ch); - else { - ch->waiting_end_prog = 1; - omap_dma_deactivate_channel(s, ch); - } - } - - if (ch->interrupts & END_BLOCK_INTR) - ch->status |= END_BLOCK_INTR; - } - } - } - } - - omap_dma_interrupts_update(s); - if (s->run_count && s->delay) - qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay); -} - -static void omap_dma_reset(struct omap_dma_s *s) -{ - int i; - - qemu_del_timer(s->tm); - s->gcr = 0x0004; - s->drq = 0x00000000; - s->run_count = 0; - s->lcd_ch.src = emiff; - s->lcd_ch.condition = 0; - s->lcd_ch.interrupts = 0; - s->lcd_ch.dual = 0; - omap_dma_enable_3_1_mapping(s); - for (i = 0; i < s->chans; i ++) { - memset(&s->ch[i].burst, 0, sizeof(s->ch[i].burst)); - memset(&s->ch[i].port, 0, sizeof(s->ch[i].port)); - memset(&s->ch[i].mode, 0, sizeof(s->ch[i].mode)); - memset(&s->ch[i].elements, 0, sizeof(s->ch[i].elements)); - memset(&s->ch[i].frames, 0, sizeof(s->ch[i].frames)); - memset(&s->ch[i].frame_index, 0, sizeof(s->ch[i].frame_index)); - memset(&s->ch[i].element_index, 0, sizeof(s->ch[i].element_index)); - memset(&s->ch[i].data_type, 0, sizeof(s->ch[i].data_type)); - memset(&s->ch[i].transparent_copy, 0, - sizeof(s->ch[i].transparent_copy)); - memset(&s->ch[i].constant_fill, 0, sizeof(s->ch[i].constant_fill)); - memset(&s->ch[i].color, 0, sizeof(s->ch[i].color)); - memset(&s->ch[i].end_prog, 0, sizeof(s->ch[i].end_prog)); - memset(&s->ch[i].repeat, 0, sizeof(s->ch[i].repeat)); - memset(&s->ch[i].auto_init, 0, sizeof(s->ch[i].auto_init)); - memset(&s->ch[i].link_enabled, 0, sizeof(s->ch[i].link_enabled)); - memset(&s->ch[i].link_next_ch, 0, sizeof(s->ch[i].link_next_ch)); - s->ch[i].interrupts = 0x0003; - memset(&s->ch[i].status, 0, sizeof(s->ch[i].status)); - memset(&s->ch[i].active, 0, sizeof(s->ch[i].active)); - memset(&s->ch[i].enable, 0, sizeof(s->ch[i].enable)); - memset(&s->ch[i].sync, 0, sizeof(s->ch[i].sync)); - memset(&s->ch[i].pending_request, 0, sizeof(s->ch[i].pending_request)); - memset(&s->ch[i].waiting_end_prog, 0, - sizeof(s->ch[i].waiting_end_prog)); - memset(&s->ch[i].cpc, 0, sizeof(s->ch[i].cpc)); - memset(&s->ch[i].fs, 0, sizeof(s->ch[i].fs)); - memset(&s->ch[i].bs, 0, sizeof(s->ch[i].bs)); - memset(&s->ch[i].omap_3_1_compatible_disable, 0, - sizeof(s->ch[i].omap_3_1_compatible_disable)); - memset(&s->ch[i].active_set, 0, sizeof(s->ch[i].active_set)); - memset(&s->ch[i].priority, 0, sizeof(s->ch[i].priority)); - memset(&s->ch[i].interleave_disabled, 0, - sizeof(s->ch[i].interleave_disabled)); - memset(&s->ch[i].type, 0, sizeof(s->ch[i].type)); - } -} - -static int omap_dma_ch_reg_read(struct omap_dma_s *s, - struct omap_dma_channel_s *ch, int reg, uint16_t *value) -{ - switch (reg) { - case 0x00: /* SYS_DMA_CSDP_CH0 */ - *value = (ch->burst[1] << 14) | - (ch->pack[1] << 13) | - (ch->port[1] << 9) | - (ch->burst[0] << 7) | - (ch->pack[0] << 6) | - (ch->port[0] << 2) | - (ch->data_type >> 1); - break; - - case 0x02: /* SYS_DMA_CCR_CH0 */ - if (s->model == omap_dma_3_1) - *value = 0 << 10; /* FIFO_FLUSH reads as 0 */ - else - *value = ch->omap_3_1_compatible_disable << 10; - *value |= (ch->mode[1] << 14) | - (ch->mode[0] << 12) | - (ch->end_prog << 11) | - (ch->repeat << 9) | - (ch->auto_init << 8) | - (ch->enable << 7) | - (ch->priority << 6) | - (ch->fs << 5) | ch->sync; - break; - - case 0x04: /* SYS_DMA_CICR_CH0 */ - *value = ch->interrupts; - break; - - case 0x06: /* SYS_DMA_CSR_CH0 */ - *value = ch->status; - ch->status &= SYNC; - if (!ch->omap_3_1_compatible_disable && ch->sibling) { - *value |= (ch->sibling->status & 0x3f) << 6; - ch->sibling->status &= SYNC; - } - qemu_irq_lower(ch->irq); - break; - - case 0x08: /* SYS_DMA_CSSA_L_CH0 */ - *value = ch->addr[0] & 0x0000ffff; - break; - - case 0x0a: /* SYS_DMA_CSSA_U_CH0 */ - *value = ch->addr[0] >> 16; - break; - - case 0x0c: /* SYS_DMA_CDSA_L_CH0 */ - *value = ch->addr[1] & 0x0000ffff; - break; - - case 0x0e: /* SYS_DMA_CDSA_U_CH0 */ - *value = ch->addr[1] >> 16; - break; - - case 0x10: /* SYS_DMA_CEN_CH0 */ - *value = ch->elements; - break; - - case 0x12: /* SYS_DMA_CFN_CH0 */ - *value = ch->frames; - break; - - case 0x14: /* SYS_DMA_CFI_CH0 */ - *value = ch->frame_index[0]; - break; - - case 0x16: /* SYS_DMA_CEI_CH0 */ - *value = ch->element_index[0]; - break; - - case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */ - if (ch->omap_3_1_compatible_disable) - *value = ch->active_set.src & 0xffff; /* CSAC */ - else - *value = ch->cpc; - break; - - case 0x1a: /* DMA_CDAC */ - *value = ch->active_set.dest & 0xffff; /* CDAC */ - break; - - case 0x1c: /* DMA_CDEI */ - *value = ch->element_index[1]; - break; - - case 0x1e: /* DMA_CDFI */ - *value = ch->frame_index[1]; - break; - - case 0x20: /* DMA_COLOR_L */ - *value = ch->color & 0xffff; - break; - - case 0x22: /* DMA_COLOR_U */ - *value = ch->color >> 16; - break; - - case 0x24: /* DMA_CCR2 */ - *value = (ch->bs << 2) | - (ch->transparent_copy << 1) | - ch->constant_fill; - break; - - case 0x28: /* DMA_CLNK_CTRL */ - *value = (ch->link_enabled << 15) | - (ch->link_next_ch & 0xf); - break; - - case 0x2a: /* DMA_LCH_CTRL */ - *value = (ch->interleave_disabled << 15) | - ch->type; - break; - - default: - return 1; - } - return 0; -} - -static int omap_dma_ch_reg_write(struct omap_dma_s *s, - struct omap_dma_channel_s *ch, int reg, uint16_t value) -{ - switch (reg) { - case 0x00: /* SYS_DMA_CSDP_CH0 */ - ch->burst[1] = (value & 0xc000) >> 14; - ch->pack[1] = (value & 0x2000) >> 13; - ch->port[1] = (enum omap_dma_port) ((value & 0x1e00) >> 9); - ch->burst[0] = (value & 0x0180) >> 7; - ch->pack[0] = (value & 0x0040) >> 6; - ch->port[0] = (enum omap_dma_port) ((value & 0x003c) >> 2); - ch->data_type = (1 << (value & 3)); - if (ch->port[0] >= omap_dma_port_last) - printf("%s: invalid DMA port %i\n", __FUNCTION__, - ch->port[0]); - if (ch->port[1] >= omap_dma_port_last) - printf("%s: invalid DMA port %i\n", __FUNCTION__, - ch->port[1]); - if ((value & 3) == 3) - printf("%s: bad data_type for DMA channel\n", __FUNCTION__); - break; - - case 0x02: /* SYS_DMA_CCR_CH0 */ - ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14); - ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12); - ch->end_prog = (value & 0x0800) >> 11; - if (s->model > omap_dma_3_1) - ch->omap_3_1_compatible_disable = (value >> 10) & 0x1; - ch->repeat = (value & 0x0200) >> 9; - ch->auto_init = (value & 0x0100) >> 8; - ch->priority = (value & 0x0040) >> 6; - ch->fs = (value & 0x0020) >> 5; - ch->sync = value & 0x001f; - - if (value & 0x0080) - omap_dma_enable_channel(s, ch); - else - omap_dma_disable_channel(s, ch); - - if (ch->end_prog) - omap_dma_channel_end_prog(s, ch); - - break; - - case 0x04: /* SYS_DMA_CICR_CH0 */ - ch->interrupts = value; - break; - - case 0x06: /* SYS_DMA_CSR_CH0 */ - OMAP_RO_REG((target_phys_addr_t) reg); - break; - - case 0x08: /* SYS_DMA_CSSA_L_CH0 */ - ch->addr[0] &= 0xffff0000; - ch->addr[0] |= value; - break; - - case 0x0a: /* SYS_DMA_CSSA_U_CH0 */ - ch->addr[0] &= 0x0000ffff; - ch->addr[0] |= (uint32_t) value << 16; - break; - - case 0x0c: /* SYS_DMA_CDSA_L_CH0 */ - ch->addr[1] &= 0xffff0000; - ch->addr[1] |= value; - break; - - case 0x0e: /* SYS_DMA_CDSA_U_CH0 */ - ch->addr[1] &= 0x0000ffff; - ch->addr[1] |= (uint32_t) value << 16; - break; - - case 0x10: /* SYS_DMA_CEN_CH0 */ - ch->elements = value; - break; - - case 0x12: /* SYS_DMA_CFN_CH0 */ - ch->frames = value; - break; - - case 0x14: /* SYS_DMA_CFI_CH0 */ - ch->frame_index[0] = (int16_t) value; - break; - - case 0x16: /* SYS_DMA_CEI_CH0 */ - ch->element_index[0] = (int16_t) value; - break; - - case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */ - OMAP_RO_REG((target_phys_addr_t) reg); - break; - - case 0x1c: /* DMA_CDEI */ - ch->element_index[1] = (int16_t) value; - break; - - case 0x1e: /* DMA_CDFI */ - ch->frame_index[1] = (int16_t) value; - break; - - case 0x20: /* DMA_COLOR_L */ - ch->color &= 0xffff0000; - ch->color |= value; - break; - - case 0x22: /* DMA_COLOR_U */ - ch->color &= 0xffff; - ch->color |= value << 16; - break; - - case 0x24: /* DMA_CCR2 */ - ch->bs = (value >> 2) & 0x1; - ch->transparent_copy = (value >> 1) & 0x1; - ch->constant_fill = value & 0x1; - break; - - case 0x28: /* DMA_CLNK_CTRL */ - ch->link_enabled = (value >> 15) & 0x1; - if (value & (1 << 14)) { /* Stop_Lnk */ - ch->link_enabled = 0; - omap_dma_disable_channel(s, ch); - } - ch->link_next_ch = value & 0x1f; - break; - - case 0x2a: /* DMA_LCH_CTRL */ - ch->interleave_disabled = (value >> 15) & 0x1; - ch->type = value & 0xf; - break; - - default: - return 1; - } - return 0; -} - -static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, - uint16_t value) -{ - switch (offset) { - case 0xbc0: /* DMA_LCD_CSDP */ - s->brust_f2 = (value >> 14) & 0x3; - s->pack_f2 = (value >> 13) & 0x1; - s->data_type_f2 = (1 << ((value >> 11) & 0x3)); - s->brust_f1 = (value >> 7) & 0x3; - s->pack_f1 = (value >> 6) & 0x1; - s->data_type_f1 = (1 << ((value >> 0) & 0x3)); - break; - - case 0xbc2: /* DMA_LCD_CCR */ - s->mode_f2 = (value >> 14) & 0x3; - s->mode_f1 = (value >> 12) & 0x3; - s->end_prog = (value >> 11) & 0x1; - s->omap_3_1_compatible_disable = (value >> 10) & 0x1; - s->repeat = (value >> 9) & 0x1; - s->auto_init = (value >> 8) & 0x1; - s->running = (value >> 7) & 0x1; - s->priority = (value >> 6) & 0x1; - s->bs = (value >> 4) & 0x1; - break; - - case 0xbc4: /* DMA_LCD_CTRL */ - s->dst = (value >> 8) & 0x1; - s->src = ((value >> 6) & 0x3) << 1; - s->condition = 0; - /* Assume no bus errors and thus no BUS_ERROR irq bits. */ - s->interrupts = (value >> 1) & 1; - s->dual = value & 1; - break; - - case 0xbc8: /* TOP_B1_L */ - s->src_f1_top &= 0xffff0000; - s->src_f1_top |= 0x0000ffff & value; - break; - - case 0xbca: /* TOP_B1_U */ - s->src_f1_top &= 0x0000ffff; - s->src_f1_top |= value << 16; - break; - - case 0xbcc: /* BOT_B1_L */ - s->src_f1_bottom &= 0xffff0000; - s->src_f1_bottom |= 0x0000ffff & value; - break; - - case 0xbce: /* BOT_B1_U */ - s->src_f1_bottom &= 0x0000ffff; - s->src_f1_bottom |= (uint32_t) value << 16; - break; - - case 0xbd0: /* TOP_B2_L */ - s->src_f2_top &= 0xffff0000; - s->src_f2_top |= 0x0000ffff & value; - break; - - case 0xbd2: /* TOP_B2_U */ - s->src_f2_top &= 0x0000ffff; - s->src_f2_top |= (uint32_t) value << 16; - break; - - case 0xbd4: /* BOT_B2_L */ - s->src_f2_bottom &= 0xffff0000; - s->src_f2_bottom |= 0x0000ffff & value; - break; - - case 0xbd6: /* BOT_B2_U */ - s->src_f2_bottom &= 0x0000ffff; - s->src_f2_bottom |= (uint32_t) value << 16; - break; - - case 0xbd8: /* DMA_LCD_SRC_EI_B1 */ - s->element_index_f1 = value; - break; - - case 0xbda: /* DMA_LCD_SRC_FI_B1_L */ - s->frame_index_f1 &= 0xffff0000; - s->frame_index_f1 |= 0x0000ffff & value; - break; - - case 0xbf4: /* DMA_LCD_SRC_FI_B1_U */ - s->frame_index_f1 &= 0x0000ffff; - s->frame_index_f1 |= (uint32_t) value << 16; - break; - - case 0xbdc: /* DMA_LCD_SRC_EI_B2 */ - s->element_index_f2 = value; - break; - - case 0xbde: /* DMA_LCD_SRC_FI_B2_L */ - s->frame_index_f2 &= 0xffff0000; - s->frame_index_f2 |= 0x0000ffff & value; - break; - - case 0xbf6: /* DMA_LCD_SRC_FI_B2_U */ - s->frame_index_f2 &= 0x0000ffff; - s->frame_index_f2 |= (uint32_t) value << 16; - break; - - case 0xbe0: /* DMA_LCD_SRC_EN_B1 */ - s->elements_f1 = value; - break; - - case 0xbe4: /* DMA_LCD_SRC_FN_B1 */ - s->frames_f1 = value; - break; - - case 0xbe2: /* DMA_LCD_SRC_EN_B2 */ - s->elements_f2 = value; - break; - - case 0xbe6: /* DMA_LCD_SRC_FN_B2 */ - s->frames_f2 = value; - break; - - case 0xbea: /* DMA_LCD_LCH_CTRL */ - s->lch_type = value & 0xf; - break; - - default: - return 1; - } - return 0; -} - -static int omap_dma_3_2_lcd_read(struct omap_dma_lcd_channel_s *s, int offset, - uint16_t *ret) -{ - switch (offset) { - case 0xbc0: /* DMA_LCD_CSDP */ - *ret = (s->brust_f2 << 14) | - (s->pack_f2 << 13) | - ((s->data_type_f2 >> 1) << 11) | - (s->brust_f1 << 7) | - (s->pack_f1 << 6) | - ((s->data_type_f1 >> 1) << 0); - break; - - case 0xbc2: /* DMA_LCD_CCR */ - *ret = (s->mode_f2 << 14) | - (s->mode_f1 << 12) | - (s->end_prog << 11) | - (s->omap_3_1_compatible_disable << 10) | - (s->repeat << 9) | - (s->auto_init << 8) | - (s->running << 7) | - (s->priority << 6) | - (s->bs << 4); - break; - - case 0xbc4: /* DMA_LCD_CTRL */ - qemu_irq_lower(s->irq); - *ret = (s->dst << 8) | - ((s->src & 0x6) << 5) | - (s->condition << 3) | - (s->interrupts << 1) | - s->dual; - break; - - case 0xbc8: /* TOP_B1_L */ - *ret = s->src_f1_top & 0xffff; - break; - - case 0xbca: /* TOP_B1_U */ - *ret = s->src_f1_top >> 16; - break; - - case 0xbcc: /* BOT_B1_L */ - *ret = s->src_f1_bottom & 0xffff; - break; - - case 0xbce: /* BOT_B1_U */ - *ret = s->src_f1_bottom >> 16; - break; - - case 0xbd0: /* TOP_B2_L */ - *ret = s->src_f2_top & 0xffff; - break; - - case 0xbd2: /* TOP_B2_U */ - *ret = s->src_f2_top >> 16; - break; - - case 0xbd4: /* BOT_B2_L */ - *ret = s->src_f2_bottom & 0xffff; - break; - - case 0xbd6: /* BOT_B2_U */ - *ret = s->src_f2_bottom >> 16; - break; - - case 0xbd8: /* DMA_LCD_SRC_EI_B1 */ - *ret = s->element_index_f1; - break; - - case 0xbda: /* DMA_LCD_SRC_FI_B1_L */ - *ret = s->frame_index_f1 & 0xffff; - break; - - case 0xbf4: /* DMA_LCD_SRC_FI_B1_U */ - *ret = s->frame_index_f1 >> 16; - break; - - case 0xbdc: /* DMA_LCD_SRC_EI_B2 */ - *ret = s->element_index_f2; - break; - - case 0xbde: /* DMA_LCD_SRC_FI_B2_L */ - *ret = s->frame_index_f2 & 0xffff; - break; - - case 0xbf6: /* DMA_LCD_SRC_FI_B2_U */ - *ret = s->frame_index_f2 >> 16; - break; - - case 0xbe0: /* DMA_LCD_SRC_EN_B1 */ - *ret = s->elements_f1; - break; - - case 0xbe4: /* DMA_LCD_SRC_FN_B1 */ - *ret = s->frames_f1; - break; - - case 0xbe2: /* DMA_LCD_SRC_EN_B2 */ - *ret = s->elements_f2; - break; - - case 0xbe6: /* DMA_LCD_SRC_FN_B2 */ - *ret = s->frames_f2; - break; - - case 0xbea: /* DMA_LCD_LCH_CTRL */ - *ret = s->lch_type; - break; - - default: - return 1; - } - return 0; -} - -static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, - uint16_t value) -{ - switch (offset) { - case 0x300: /* SYS_DMA_LCD_CTRL */ - s->src = (value & 0x40) ? imif : emiff; - s->condition = 0; - /* Assume no bus errors and thus no BUS_ERROR irq bits. */ - s->interrupts = (value >> 1) & 1; - s->dual = value & 1; - break; - - case 0x302: /* SYS_DMA_LCD_TOP_F1_L */ - s->src_f1_top &= 0xffff0000; - s->src_f1_top |= 0x0000ffff & value; - break; - - case 0x304: /* SYS_DMA_LCD_TOP_F1_U */ - s->src_f1_top &= 0x0000ffff; - s->src_f1_top |= value << 16; - break; - - case 0x306: /* SYS_DMA_LCD_BOT_F1_L */ - s->src_f1_bottom &= 0xffff0000; - s->src_f1_bottom |= 0x0000ffff & value; - break; - - case 0x308: /* SYS_DMA_LCD_BOT_F1_U */ - s->src_f1_bottom &= 0x0000ffff; - s->src_f1_bottom |= value << 16; - break; - - case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */ - s->src_f2_top &= 0xffff0000; - s->src_f2_top |= 0x0000ffff & value; - break; - - case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */ - s->src_f2_top &= 0x0000ffff; - s->src_f2_top |= value << 16; - break; - - case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */ - s->src_f2_bottom &= 0xffff0000; - s->src_f2_bottom |= 0x0000ffff & value; - break; - - case 0x310: /* SYS_DMA_LCD_BOT_F2_U */ - s->src_f2_bottom &= 0x0000ffff; - s->src_f2_bottom |= value << 16; - break; - - default: - return 1; - } - return 0; -} - -static int omap_dma_3_1_lcd_read(struct omap_dma_lcd_channel_s *s, int offset, - uint16_t *ret) -{ - int i; - - switch (offset) { - case 0x300: /* SYS_DMA_LCD_CTRL */ - i = s->condition; - s->condition = 0; - qemu_irq_lower(s->irq); - *ret = ((s->src == imif) << 6) | (i << 3) | - (s->interrupts << 1) | s->dual; - break; - - case 0x302: /* SYS_DMA_LCD_TOP_F1_L */ - *ret = s->src_f1_top & 0xffff; - break; - - case 0x304: /* SYS_DMA_LCD_TOP_F1_U */ - *ret = s->src_f1_top >> 16; - break; - - case 0x306: /* SYS_DMA_LCD_BOT_F1_L */ - *ret = s->src_f1_bottom & 0xffff; - break; - - case 0x308: /* SYS_DMA_LCD_BOT_F1_U */ - *ret = s->src_f1_bottom >> 16; - break; - - case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */ - *ret = s->src_f2_top & 0xffff; - break; - - case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */ - *ret = s->src_f2_top >> 16; - break; - - case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */ - *ret = s->src_f2_bottom & 0xffff; - break; - - case 0x310: /* SYS_DMA_LCD_BOT_F2_U */ - *ret = s->src_f2_bottom >> 16; - break; - - default: - return 1; - } - return 0; -} - -static int omap_dma_sys_write(struct omap_dma_s *s, int offset, uint16_t value) -{ - switch (offset) { - case 0x400: /* SYS_DMA_GCR */ - s->gcr = value; - break; - - case 0x404: /* DMA_GSCR */ - if (value & 0x8) - omap_dma_disable_3_1_mapping(s); - else - omap_dma_enable_3_1_mapping(s); - break; - - case 0x408: /* DMA_GRST */ - if (value & 0x1) - omap_dma_reset(s); - break; - - default: - return 1; - } - return 0; -} - -static int omap_dma_sys_read(struct omap_dma_s *s, int offset, - uint16_t *ret) -{ - switch (offset) { - case 0x400: /* SYS_DMA_GCR */ - *ret = s->gcr; - break; - - case 0x404: /* DMA_GSCR */ - *ret = s->omap_3_1_mapping_disabled << 3; - break; - - case 0x408: /* DMA_GRST */ - *ret = 0; - break; - - case 0x442: /* DMA_HW_ID */ - case 0x444: /* DMA_PCh2_ID */ - case 0x446: /* DMA_PCh0_ID */ - case 0x448: /* DMA_PCh1_ID */ - case 0x44a: /* DMA_PChG_ID */ - case 0x44c: /* DMA_PChD_ID */ - *ret = 1; - break; - - case 0x44e: /* DMA_CAPS_0_U */ - *ret = (1 << 3) | /* Constant Fill Capacity */ - (1 << 2); /* Transparent BLT Capacity */ - break; - - case 0x450: /* DMA_CAPS_0_L */ - case 0x452: /* DMA_CAPS_1_U */ - *ret = 0; - break; - - case 0x454: /* DMA_CAPS_1_L */ - *ret = (1 << 1); /* 1-bit palletized capability */ - break; - - case 0x456: /* DMA_CAPS_2 */ - *ret = (1 << 8) | /* SSDIC */ - (1 << 7) | /* DDIAC */ - (1 << 6) | /* DSIAC */ - (1 << 5) | /* DPIAC */ - (1 << 4) | /* DCAC */ - (1 << 3) | /* SDIAC */ - (1 << 2) | /* SSIAC */ - (1 << 1) | /* SPIAC */ - 1; /* SCAC */ - break; - - case 0x458: /* DMA_CAPS_3 */ - *ret = (1 << 5) | /* CCC */ - (1 << 4) | /* IC */ - (1 << 3) | /* ARC */ - (1 << 2) | /* AEC */ - (1 << 1) | /* FSC */ - 1; /* ESC */ - break; - - case 0x45a: /* DMA_CAPS_4 */ - *ret = (1 << 6) | /* SSC */ - (1 << 5) | /* BIC */ - (1 << 4) | /* LFIC */ - (1 << 3) | /* FIC */ - (1 << 2) | /* HFIC */ - (1 << 1) | /* EDIC */ - 1; /* TOIC */ - break; - - case 0x460: /* DMA_PCh2_SR */ - case 0x480: /* DMA_PCh0_SR */ - case 0x482: /* DMA_PCh1_SR */ - case 0x4c0: /* DMA_PChD_SR_0 */ - printf("%s: Physical Channel Status Registers not implemented.\n", - __FUNCTION__); - *ret = 0xff; - break; - - default: - return 1; - } - return 0; -} - -static uint32_t omap_dma_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_dma_s *s = (struct omap_dma_s *) opaque; - int reg, ch, offset = addr - s->base; - uint16_t ret; - - switch (offset) { - case 0x300 ... 0x3fe: - if (s->model == omap_dma_3_1 || !s->omap_3_1_mapping_disabled) { - if (omap_dma_3_1_lcd_read(&s->lcd_ch, offset, &ret)) - break; - return ret; - } - /* Fall through. */ - case 0x000 ... 0x2fe: - reg = offset & 0x3f; - ch = (offset >> 6) & 0x0f; - if (omap_dma_ch_reg_read(s, &s->ch[ch], reg, &ret)) - break; - return ret; - - case 0x404 ... 0x4fe: - if (s->model == omap_dma_3_1) - break; - /* Fall through. */ - case 0x400: - if (omap_dma_sys_read(s, offset, &ret)) - break; - return ret; - - case 0xb00 ... 0xbfe: - if (s->model == omap_dma_3_2 && s->omap_3_1_mapping_disabled) { - if (omap_dma_3_2_lcd_read(&s->lcd_ch, offset, &ret)) - break; - return ret; - } - break; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_dma_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_dma_s *s = (struct omap_dma_s *) opaque; - int reg, ch, offset = addr - s->base; - - switch (offset) { - case 0x300 ... 0x3fe: - if (s->model == omap_dma_3_1 || !s->omap_3_1_mapping_disabled) { - if (omap_dma_3_1_lcd_write(&s->lcd_ch, offset, value)) - break; - return; - } - /* Fall through. */ - case 0x000 ... 0x2fe: - reg = offset & 0x3f; - ch = (offset >> 6) & 0x0f; - if (omap_dma_ch_reg_write(s, &s->ch[ch], reg, value)) - break; - return; - - case 0x404 ... 0x4fe: - if (s->model == omap_dma_3_1) - break; - case 0x400: - /* Fall through. */ - if (omap_dma_sys_write(s, offset, value)) - break; - return; - - case 0xb00 ... 0xbfe: - if (s->model == omap_dma_3_2 && s->omap_3_1_mapping_disabled) { - if (omap_dma_3_2_lcd_write(&s->lcd_ch, offset, value)) - break; - return; - } - break; - } - - OMAP_BAD_REG(addr); -} - -static CPUReadMemoryFunc *omap_dma_readfn[] = { - omap_badwidth_read16, - omap_dma_read, - omap_badwidth_read16, -}; - -static CPUWriteMemoryFunc *omap_dma_writefn[] = { - omap_badwidth_write16, - omap_dma_write, - omap_badwidth_write16, -}; - -static void omap_dma_request(void *opaque, int drq, int req) -{ - struct omap_dma_s *s = (struct omap_dma_s *) opaque; - /* The request pins are level triggered. */ - if (req) { - if (~s->drq & (1 << drq)) { - s->drq |= 1 << drq; - omap_dma_process_request(s, drq); - } - } else - s->drq &= ~(1 << drq); -} - -static void omap_dma_clk_update(void *opaque, int line, int on) -{ - struct omap_dma_s *s = (struct omap_dma_s *) opaque; - - if (on) { - /* TODO: make a clever calculation */ - s->delay = ticks_per_sec >> 8; - if (s->run_count) - qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay); - } else { - s->delay = 0; - qemu_del_timer(s->tm); - } -} - -struct omap_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs, - qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk, - enum omap_dma_model model) -{ - int iomemtype, num_irqs, memsize, i; - struct omap_dma_s *s = (struct omap_dma_s *) - qemu_mallocz(sizeof(struct omap_dma_s)); - - if (model == omap_dma_3_1) { - num_irqs = 6; - memsize = 0x800; - } else { - num_irqs = 16; - memsize = 0xc00; - } - s->base = base; - s->model = model; - s->mpu = mpu; - s->clk = clk; - s->lcd_ch.irq = lcd_irq; - s->lcd_ch.mpu = mpu; - while (num_irqs --) - s->ch[num_irqs].irq = irqs[num_irqs]; - for (i = 0; i < 3; i ++) { - s->ch[i].sibling = &s->ch[i + 6]; - s->ch[i + 6].sibling = &s->ch[i]; - } - s->tm = qemu_new_timer(vm_clock, (QEMUTimerCB *) omap_dma_channel_run, s); - omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]); - mpu->drq = qemu_allocate_irqs(omap_dma_request, s, 32); - omap_dma_reset(s); - omap_dma_clk_update(s, 0, 1); - - iomemtype = cpu_register_io_memory(0, omap_dma_readfn, - omap_dma_writefn, s); - cpu_register_physical_memory(s->base, memsize, iomemtype); - - return s; -} - -/* DMA ports */ -static int omap_validate_emiff_addr(struct omap_mpu_state_s *s, - target_phys_addr_t addr) -{ - return addr >= OMAP_EMIFF_BASE && addr < OMAP_EMIFF_BASE + s->sdram_size; -} - -static int omap_validate_emifs_addr(struct omap_mpu_state_s *s, - target_phys_addr_t addr) -{ - return addr >= OMAP_EMIFS_BASE && addr < OMAP_EMIFF_BASE; -} - -static int omap_validate_imif_addr(struct omap_mpu_state_s *s, - target_phys_addr_t addr) -{ - return addr >= OMAP_IMIF_BASE && addr < OMAP_IMIF_BASE + s->sram_size; -} - -static int omap_validate_tipb_addr(struct omap_mpu_state_s *s, - target_phys_addr_t addr) -{ - return addr >= 0xfffb0000 && addr < 0xffff0000; -} - -static int omap_validate_local_addr(struct omap_mpu_state_s *s, - target_phys_addr_t addr) -{ - return addr >= OMAP_LOCALBUS_BASE && addr < OMAP_LOCALBUS_BASE + 0x1000000; -} - -static int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s, - target_phys_addr_t addr) -{ - return addr >= 0xe1010000 && addr < 0xe1020004; -} - -/* MPU OS timers */ -struct omap_mpu_timer_s { - qemu_irq irq; - omap_clk clk; - target_phys_addr_t base; - uint32_t val; - int64_t time; - QEMUTimer *timer; - int64_t rate; - int it_ena; - - int enable; - int ptv; - int ar; - int st; - uint32_t reset_val; -}; - -static inline uint32_t omap_timer_read(struct omap_mpu_timer_s *timer) -{ - uint64_t distance = qemu_get_clock(vm_clock) - timer->time; - - if (timer->st && timer->enable && timer->rate) - return timer->val - muldiv64(distance >> (timer->ptv + 1), - timer->rate, ticks_per_sec); - else - return timer->val; -} - -static inline void omap_timer_sync(struct omap_mpu_timer_s *timer) -{ - timer->val = omap_timer_read(timer); - timer->time = qemu_get_clock(vm_clock); -} - -static inline void omap_timer_update(struct omap_mpu_timer_s *timer) -{ - int64_t expires; - - if (timer->enable && timer->st && timer->rate) { - timer->val = timer->reset_val; /* Should skip this on clk enable */ - expires = muldiv64(timer->val << (timer->ptv + 1), - ticks_per_sec, timer->rate); - - /* If timer expiry would be sooner than in about 1 ms and - * auto-reload isn't set, then fire immediately. This is a hack - * to make systems like PalmOS run in acceptable time. PalmOS - * sets the interval to a very low value and polls the status bit - * in a busy loop when it wants to sleep just a couple of CPU - * ticks. */ - if (expires > (ticks_per_sec >> 10) || timer->ar) - qemu_mod_timer(timer->timer, timer->time + expires); - else { - timer->val = 0; - timer->st = 0; - if (timer->it_ena) - /* Edge-triggered irq */ - qemu_irq_pulse(timer->irq); - } - } else - qemu_del_timer(timer->timer); -} - -static void omap_timer_tick(void *opaque) -{ - struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque; - omap_timer_sync(timer); - - if (!timer->ar) { - timer->val = 0; - timer->st = 0; - } - - if (timer->it_ena) - /* Edge-triggered irq */ - qemu_irq_pulse(timer->irq); - omap_timer_update(timer); -} - -static void omap_timer_clk_update(void *opaque, int line, int on) -{ - struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque; - - omap_timer_sync(timer); - timer->rate = on ? omap_clk_getrate(timer->clk) : 0; - omap_timer_update(timer); -} - -static void omap_timer_clk_setup(struct omap_mpu_timer_s *timer) -{ - omap_clk_adduser(timer->clk, - qemu_allocate_irqs(omap_timer_clk_update, timer, 1)[0]); - timer->rate = omap_clk_getrate(timer->clk); -} - -static uint32_t omap_mpu_timer_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; - int offset = addr - s->base; - - switch (offset) { - case 0x00: /* CNTL_TIMER */ - return (s->enable << 5) | (s->ptv << 2) | (s->ar << 1) | s->st; - - case 0x04: /* LOAD_TIM */ - break; - - case 0x08: /* READ_TIM */ - return omap_timer_read(s); - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_mpu_timer_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; - int offset = addr - s->base; - - switch (offset) { - case 0x00: /* CNTL_TIMER */ - omap_timer_sync(s); - s->enable = (value >> 5) & 1; - s->ptv = (value >> 2) & 7; - s->ar = (value >> 1) & 1; - s->st = value & 1; - omap_timer_update(s); - return; - - case 0x04: /* LOAD_TIM */ - s->reset_val = value; - return; - - case 0x08: /* READ_TIM */ - OMAP_RO_REG(addr); - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static CPUReadMemoryFunc *omap_mpu_timer_readfn[] = { - omap_badwidth_read32, - omap_badwidth_read32, - omap_mpu_timer_read, -}; - -static CPUWriteMemoryFunc *omap_mpu_timer_writefn[] = { - omap_badwidth_write32, - omap_badwidth_write32, - omap_mpu_timer_write, -}; - -static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s) -{ - qemu_del_timer(s->timer); - s->enable = 0; - s->reset_val = 31337; - s->val = 0; - s->ptv = 0; - s->ar = 0; - s->st = 0; - s->it_ena = 1; -} - -struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base, - qemu_irq irq, omap_clk clk) -{ - int iomemtype; - struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) - qemu_mallocz(sizeof(struct omap_mpu_timer_s)); - - s->irq = irq; - s->clk = clk; - s->base = base; - s->timer = qemu_new_timer(vm_clock, omap_timer_tick, s); - omap_mpu_timer_reset(s); - omap_timer_clk_setup(s); - - iomemtype = cpu_register_io_memory(0, omap_mpu_timer_readfn, - omap_mpu_timer_writefn, s); - cpu_register_physical_memory(s->base, 0x100, iomemtype); - - return s; -} - -/* Watchdog timer */ -struct omap_watchdog_timer_s { - struct omap_mpu_timer_s timer; - uint8_t last_wr; - int mode; - int free; - int reset; -}; - -static uint32_t omap_wd_timer_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; - int offset = addr - s->timer.base; - - switch (offset) { - case 0x00: /* CNTL_TIMER */ - return (s->timer.ptv << 9) | (s->timer.ar << 8) | - (s->timer.st << 7) | (s->free << 1); - - case 0x04: /* READ_TIMER */ - return omap_timer_read(&s->timer); - - case 0x08: /* TIMER_MODE */ - return s->mode << 15; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_wd_timer_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; - int offset = addr - s->timer.base; - - switch (offset) { - case 0x00: /* CNTL_TIMER */ - omap_timer_sync(&s->timer); - s->timer.ptv = (value >> 9) & 7; - s->timer.ar = (value >> 8) & 1; - s->timer.st = (value >> 7) & 1; - s->free = (value >> 1) & 1; - omap_timer_update(&s->timer); - break; - - case 0x04: /* LOAD_TIMER */ - s->timer.reset_val = value & 0xffff; - break; - - case 0x08: /* TIMER_MODE */ - if (!s->mode && ((value >> 15) & 1)) - omap_clk_get(s->timer.clk); - s->mode |= (value >> 15) & 1; - if (s->last_wr == 0xf5) { - if ((value & 0xff) == 0xa0) { - if (s->mode) { - s->mode = 0; - omap_clk_put(s->timer.clk); - } - } else { - /* XXX: on T|E hardware somehow this has no effect, - * on Zire 71 it works as specified. */ - s->reset = 1; - qemu_system_reset_request(); - } - } - s->last_wr = value & 0xff; - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static CPUReadMemoryFunc *omap_wd_timer_readfn[] = { - omap_badwidth_read16, - omap_wd_timer_read, - omap_badwidth_read16, -}; - -static CPUWriteMemoryFunc *omap_wd_timer_writefn[] = { - omap_badwidth_write16, - omap_wd_timer_write, - omap_badwidth_write16, -}; - -static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s) -{ - qemu_del_timer(s->timer.timer); - if (!s->mode) - omap_clk_get(s->timer.clk); - s->mode = 1; - s->free = 1; - s->reset = 0; - s->timer.enable = 1; - s->timer.it_ena = 1; - s->timer.reset_val = 0xffff; - s->timer.val = 0; - s->timer.st = 0; - s->timer.ptv = 0; - s->timer.ar = 0; - omap_timer_update(&s->timer); -} - -struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base, - qemu_irq irq, omap_clk clk) -{ - int iomemtype; - struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) - qemu_mallocz(sizeof(struct omap_watchdog_timer_s)); - - s->timer.irq = irq; - s->timer.clk = clk; - s->timer.base = base; - s->timer.timer = qemu_new_timer(vm_clock, omap_timer_tick, &s->timer); - omap_wd_timer_reset(s); - omap_timer_clk_setup(&s->timer); - - iomemtype = cpu_register_io_memory(0, omap_wd_timer_readfn, - omap_wd_timer_writefn, s); - cpu_register_physical_memory(s->timer.base, 0x100, iomemtype); - - return s; -} - -/* 32-kHz timer */ -struct omap_32khz_timer_s { - struct omap_mpu_timer_s timer; -}; - -static uint32_t omap_os_timer_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - switch (offset) { - case 0x00: /* TVR */ - return s->timer.reset_val; - - case 0x04: /* TCR */ - return omap_timer_read(&s->timer); - - case 0x08: /* CR */ - return (s->timer.ar << 3) | (s->timer.it_ena << 2) | s->timer.st; - - default: - break; - } - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_os_timer_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - switch (offset) { - case 0x00: /* TVR */ - s->timer.reset_val = value & 0x00ffffff; - break; - - case 0x04: /* TCR */ - OMAP_RO_REG(addr); - break; - - case 0x08: /* CR */ - s->timer.ar = (value >> 3) & 1; - s->timer.it_ena = (value >> 2) & 1; - if (s->timer.st != (value & 1) || (value & 2)) { - omap_timer_sync(&s->timer); - s->timer.enable = value & 1; - s->timer.st = value & 1; - omap_timer_update(&s->timer); - } - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static CPUReadMemoryFunc *omap_os_timer_readfn[] = { - omap_badwidth_read32, - omap_badwidth_read32, - omap_os_timer_read, -}; - -static CPUWriteMemoryFunc *omap_os_timer_writefn[] = { - omap_badwidth_write32, - omap_badwidth_write32, - omap_os_timer_write, -}; - -static void omap_os_timer_reset(struct omap_32khz_timer_s *s) -{ - qemu_del_timer(s->timer.timer); - s->timer.enable = 0; - s->timer.it_ena = 0; - s->timer.reset_val = 0x00ffffff; - s->timer.val = 0; - s->timer.st = 0; - s->timer.ptv = 0; - s->timer.ar = 1; -} - -struct omap_32khz_timer_s *omap_os_timer_init(target_phys_addr_t base, - qemu_irq irq, omap_clk clk) -{ - int iomemtype; - struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) - qemu_mallocz(sizeof(struct omap_32khz_timer_s)); - - s->timer.irq = irq; - s->timer.clk = clk; - s->timer.base = base; - s->timer.timer = qemu_new_timer(vm_clock, omap_timer_tick, &s->timer); - omap_os_timer_reset(s); - omap_timer_clk_setup(&s->timer); - - iomemtype = cpu_register_io_memory(0, omap_os_timer_readfn, - omap_os_timer_writefn, s); - cpu_register_physical_memory(s->timer.base, 0x800, iomemtype); - - return s; -} - -/* Ultra Low-Power Device Module */ -static uint32_t omap_ulpd_pm_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr - s->ulpd_pm_base; - uint16_t ret; - - switch (offset) { - case 0x14: /* IT_STATUS */ - ret = s->ulpd_pm_regs[offset >> 2]; - s->ulpd_pm_regs[offset >> 2] = 0; - qemu_irq_lower(s->irq[1][OMAP_INT_GAUGE_32K]); - return ret; - - case 0x18: /* Reserved */ - case 0x1c: /* Reserved */ - case 0x20: /* Reserved */ - case 0x28: /* Reserved */ - case 0x2c: /* Reserved */ - OMAP_BAD_REG(addr); - case 0x00: /* COUNTER_32_LSB */ - case 0x04: /* COUNTER_32_MSB */ - case 0x08: /* COUNTER_HIGH_FREQ_LSB */ - case 0x0c: /* COUNTER_HIGH_FREQ_MSB */ - case 0x10: /* GAUGING_CTRL */ - case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ - case 0x30: /* CLOCK_CTRL */ - case 0x34: /* SOFT_REQ */ - case 0x38: /* COUNTER_32_FIQ */ - case 0x3c: /* DPLL_CTRL */ - case 0x40: /* STATUS_REQ */ - /* XXX: check clk::usecount state for every clock */ - case 0x48: /* LOCL_TIME */ - case 0x4c: /* APLL_CTRL */ - case 0x50: /* POWER_CTRL */ - return s->ulpd_pm_regs[offset >> 2]; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static inline void omap_ulpd_clk_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - if (diff & (1 << 4)) /* USB_MCLK_EN */ - omap_clk_onoff(omap_findclk(s, "usb_clk0"), (value >> 4) & 1); - if (diff & (1 << 5)) /* DIS_USB_PVCI_CLK */ - omap_clk_onoff(omap_findclk(s, "usb_w2fc_ck"), (~value >> 5) & 1); -} - -static inline void omap_ulpd_req_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - if (diff & (1 << 0)) /* SOFT_DPLL_REQ */ - omap_clk_canidle(omap_findclk(s, "dpll4"), (~value >> 0) & 1); - if (diff & (1 << 1)) /* SOFT_COM_REQ */ - omap_clk_canidle(omap_findclk(s, "com_mclk_out"), (~value >> 1) & 1); - if (diff & (1 << 2)) /* SOFT_SDW_REQ */ - omap_clk_canidle(omap_findclk(s, "bt_mclk_out"), (~value >> 2) & 1); - if (diff & (1 << 3)) /* SOFT_USB_REQ */ - omap_clk_canidle(omap_findclk(s, "usb_clk0"), (~value >> 3) & 1); -} - -static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr - s->ulpd_pm_base; - int64_t now, ticks; - int div, mult; - static const int bypass_div[4] = { 1, 2, 4, 4 }; - uint16_t diff; - - switch (offset) { - case 0x00: /* COUNTER_32_LSB */ - case 0x04: /* COUNTER_32_MSB */ - case 0x08: /* COUNTER_HIGH_FREQ_LSB */ - case 0x0c: /* COUNTER_HIGH_FREQ_MSB */ - case 0x14: /* IT_STATUS */ - case 0x40: /* STATUS_REQ */ - OMAP_RO_REG(addr); - break; - - case 0x10: /* GAUGING_CTRL */ - /* Bits 0 and 1 seem to be confused in the OMAP 310 TRM */ - if ((s->ulpd_pm_regs[offset >> 2] ^ value) & 1) { - now = qemu_get_clock(vm_clock); - - if (value & 1) - s->ulpd_gauge_start = now; - else { - now -= s->ulpd_gauge_start; - - /* 32-kHz ticks */ - ticks = muldiv64(now, 32768, ticks_per_sec); - s->ulpd_pm_regs[0x00 >> 2] = (ticks >> 0) & 0xffff; - s->ulpd_pm_regs[0x04 >> 2] = (ticks >> 16) & 0xffff; - if (ticks >> 32) /* OVERFLOW_32K */ - s->ulpd_pm_regs[0x14 >> 2] |= 1 << 2; - - /* High frequency ticks */ - ticks = muldiv64(now, 12000000, ticks_per_sec); - s->ulpd_pm_regs[0x08 >> 2] = (ticks >> 0) & 0xffff; - s->ulpd_pm_regs[0x0c >> 2] = (ticks >> 16) & 0xffff; - if (ticks >> 32) /* OVERFLOW_HI_FREQ */ - s->ulpd_pm_regs[0x14 >> 2] |= 1 << 1; - - s->ulpd_pm_regs[0x14 >> 2] |= 1 << 0; /* IT_GAUGING */ - qemu_irq_raise(s->irq[1][OMAP_INT_GAUGE_32K]); - } - } - s->ulpd_pm_regs[offset >> 2] = value; - break; - - case 0x18: /* Reserved */ - case 0x1c: /* Reserved */ - case 0x20: /* Reserved */ - case 0x28: /* Reserved */ - case 0x2c: /* Reserved */ - OMAP_BAD_REG(addr); - case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ - case 0x38: /* COUNTER_32_FIQ */ - case 0x48: /* LOCL_TIME */ - case 0x50: /* POWER_CTRL */ - s->ulpd_pm_regs[offset >> 2] = value; - break; - - case 0x30: /* CLOCK_CTRL */ - diff = s->ulpd_pm_regs[offset >> 2] ^ value; - s->ulpd_pm_regs[offset >> 2] = value & 0x3f; - omap_ulpd_clk_update(s, diff, value); - break; - - case 0x34: /* SOFT_REQ */ - diff = s->ulpd_pm_regs[offset >> 2] ^ value; - s->ulpd_pm_regs[offset >> 2] = value & 0x1f; - omap_ulpd_req_update(s, diff, value); - break; - - case 0x3c: /* DPLL_CTRL */ - /* XXX: OMAP310 TRM claims bit 3 is PLL_ENABLE, and bit 4 is - * omitted altogether, probably a typo. */ - /* This register has identical semantics with DPLL(1:3) control - * registers, see omap_dpll_write() */ - diff = s->ulpd_pm_regs[offset >> 2] & value; - s->ulpd_pm_regs[offset >> 2] = value & 0x2fff; - if (diff & (0x3ff << 2)) { - if (value & (1 << 4)) { /* PLL_ENABLE */ - div = ((value >> 5) & 3) + 1; /* PLL_DIV */ - mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */ - } else { - div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */ - mult = 1; - } - omap_clk_setrate(omap_findclk(s, "dpll4"), div, mult); - } - - /* Enter the desired mode. */ - s->ulpd_pm_regs[offset >> 2] = - (s->ulpd_pm_regs[offset >> 2] & 0xfffe) | - ((s->ulpd_pm_regs[offset >> 2] >> 4) & 1); - - /* Act as if the lock is restored. */ - s->ulpd_pm_regs[offset >> 2] |= 2; - break; - - case 0x4c: /* APLL_CTRL */ - diff = s->ulpd_pm_regs[offset >> 2] & value; - s->ulpd_pm_regs[offset >> 2] = value & 0xf; - if (diff & (1 << 0)) /* APLL_NDPLL_SWITCH */ - omap_clk_reparent(omap_findclk(s, "ck_48m"), omap_findclk(s, - (value & (1 << 0)) ? "apll" : "dpll4")); - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static CPUReadMemoryFunc *omap_ulpd_pm_readfn[] = { - omap_badwidth_read16, - omap_ulpd_pm_read, - omap_badwidth_read16, -}; - -static CPUWriteMemoryFunc *omap_ulpd_pm_writefn[] = { - omap_badwidth_write16, - omap_ulpd_pm_write, - omap_badwidth_write16, -}; - -static void omap_ulpd_pm_reset(struct omap_mpu_state_s *mpu) -{ - mpu->ulpd_pm_regs[0x00 >> 2] = 0x0001; - mpu->ulpd_pm_regs[0x04 >> 2] = 0x0000; - mpu->ulpd_pm_regs[0x08 >> 2] = 0x0001; - mpu->ulpd_pm_regs[0x0c >> 2] = 0x0000; - mpu->ulpd_pm_regs[0x10 >> 2] = 0x0000; - mpu->ulpd_pm_regs[0x18 >> 2] = 0x01; - mpu->ulpd_pm_regs[0x1c >> 2] = 0x01; - mpu->ulpd_pm_regs[0x20 >> 2] = 0x01; - mpu->ulpd_pm_regs[0x24 >> 2] = 0x03ff; - mpu->ulpd_pm_regs[0x28 >> 2] = 0x01; - mpu->ulpd_pm_regs[0x2c >> 2] = 0x01; - omap_ulpd_clk_update(mpu, mpu->ulpd_pm_regs[0x30 >> 2], 0x0000); - mpu->ulpd_pm_regs[0x30 >> 2] = 0x0000; - omap_ulpd_req_update(mpu, mpu->ulpd_pm_regs[0x34 >> 2], 0x0000); - mpu->ulpd_pm_regs[0x34 >> 2] = 0x0000; - mpu->ulpd_pm_regs[0x38 >> 2] = 0x0001; - mpu->ulpd_pm_regs[0x3c >> 2] = 0x2211; - mpu->ulpd_pm_regs[0x40 >> 2] = 0x0000; /* FIXME: dump a real STATUS_REQ */ - mpu->ulpd_pm_regs[0x48 >> 2] = 0x960; - mpu->ulpd_pm_regs[0x4c >> 2] = 0x08; - mpu->ulpd_pm_regs[0x50 >> 2] = 0x08; - omap_clk_setrate(omap_findclk(mpu, "dpll4"), 1, 4); - omap_clk_reparent(omap_findclk(mpu, "ck_48m"), omap_findclk(mpu, "dpll4")); -} - -static void omap_ulpd_pm_init(target_phys_addr_t base, - struct omap_mpu_state_s *mpu) -{ - int iomemtype = cpu_register_io_memory(0, omap_ulpd_pm_readfn, - omap_ulpd_pm_writefn, mpu); - - mpu->ulpd_pm_base = base; - cpu_register_physical_memory(mpu->ulpd_pm_base, 0x800, iomemtype); - omap_ulpd_pm_reset(mpu); -} - -/* OMAP Pin Configuration */ -static uint32_t omap_pin_cfg_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr - s->pin_cfg_base; - - switch (offset) { - case 0x00: /* FUNC_MUX_CTRL_0 */ - case 0x04: /* FUNC_MUX_CTRL_1 */ - case 0x08: /* FUNC_MUX_CTRL_2 */ - return s->func_mux_ctrl[offset >> 2]; - - case 0x0c: /* COMP_MODE_CTRL_0 */ - return s->comp_mode_ctrl[0]; - - case 0x10: /* FUNC_MUX_CTRL_3 */ - case 0x14: /* FUNC_MUX_CTRL_4 */ - case 0x18: /* FUNC_MUX_CTRL_5 */ - case 0x1c: /* FUNC_MUX_CTRL_6 */ - case 0x20: /* FUNC_MUX_CTRL_7 */ - case 0x24: /* FUNC_MUX_CTRL_8 */ - case 0x28: /* FUNC_MUX_CTRL_9 */ - case 0x2c: /* FUNC_MUX_CTRL_A */ - case 0x30: /* FUNC_MUX_CTRL_B */ - case 0x34: /* FUNC_MUX_CTRL_C */ - case 0x38: /* FUNC_MUX_CTRL_D */ - return s->func_mux_ctrl[(offset >> 2) - 1]; - - case 0x40: /* PULL_DWN_CTRL_0 */ - case 0x44: /* PULL_DWN_CTRL_1 */ - case 0x48: /* PULL_DWN_CTRL_2 */ - case 0x4c: /* PULL_DWN_CTRL_3 */ - return s->pull_dwn_ctrl[(offset & 0xf) >> 2]; - - case 0x50: /* GATE_INH_CTRL_0 */ - return s->gate_inh_ctrl[0]; - - case 0x60: /* VOLTAGE_CTRL_0 */ - return s->voltage_ctrl[0]; - - case 0x70: /* TEST_DBG_CTRL_0 */ - return s->test_dbg_ctrl[0]; - - case 0x80: /* MOD_CONF_CTRL_0 */ - return s->mod_conf_ctrl[0]; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static inline void omap_pin_funcmux0_update(struct omap_mpu_state_s *s, - uint32_t diff, uint32_t value) -{ - if (s->compat1509) { - if (diff & (1 << 9)) /* BLUETOOTH */ - omap_clk_onoff(omap_findclk(s, "bt_mclk_out"), - (~value >> 9) & 1); - if (diff & (1 << 7)) /* USB.CLKO */ - omap_clk_onoff(omap_findclk(s, "usb.clko"), - (value >> 7) & 1); - } -} - -static inline void omap_pin_funcmux1_update(struct omap_mpu_state_s *s, - uint32_t diff, uint32_t value) -{ - if (s->compat1509) { - if (diff & (1 << 31)) /* MCBSP3_CLK_HIZ_DI */ - omap_clk_onoff(omap_findclk(s, "mcbsp3.clkx"), - (value >> 31) & 1); - if (diff & (1 << 1)) /* CLK32K */ - omap_clk_onoff(omap_findclk(s, "clk32k_out"), - (~value >> 1) & 1); - } -} - -static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s, - uint32_t diff, uint32_t value) -{ - if (diff & (1 << 31)) /* CONF_MOD_UART3_CLK_MODE_R */ - omap_clk_reparent(omap_findclk(s, "uart3_ck"), - omap_findclk(s, ((value >> 31) & 1) ? - "ck_48m" : "armper_ck")); - if (diff & (1 << 30)) /* CONF_MOD_UART2_CLK_MODE_R */ - omap_clk_reparent(omap_findclk(s, "uart2_ck"), - omap_findclk(s, ((value >> 30) & 1) ? - "ck_48m" : "armper_ck")); - if (diff & (1 << 29)) /* CONF_MOD_UART1_CLK_MODE_R */ - omap_clk_reparent(omap_findclk(s, "uart1_ck"), - omap_findclk(s, ((value >> 29) & 1) ? - "ck_48m" : "armper_ck")); - if (diff & (1 << 23)) /* CONF_MOD_MMC_SD_CLK_REQ_R */ - omap_clk_reparent(omap_findclk(s, "mmc_ck"), - omap_findclk(s, ((value >> 23) & 1) ? - "ck_48m" : "armper_ck")); - if (diff & (1 << 12)) /* CONF_MOD_COM_MCLK_12_48_S */ - omap_clk_reparent(omap_findclk(s, "com_mclk_out"), - omap_findclk(s, ((value >> 12) & 1) ? - "ck_48m" : "armper_ck")); - if (diff & (1 << 9)) /* CONF_MOD_USB_HOST_HHC_UHO */ - omap_clk_onoff(omap_findclk(s, "usb_hhc_ck"), (value >> 9) & 1); -} - -static void omap_pin_cfg_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr - s->pin_cfg_base; - uint32_t diff; - - switch (offset) { - case 0x00: /* FUNC_MUX_CTRL_0 */ - diff = s->func_mux_ctrl[offset >> 2] ^ value; - s->func_mux_ctrl[offset >> 2] = value; - omap_pin_funcmux0_update(s, diff, value); - return; - - case 0x04: /* FUNC_MUX_CTRL_1 */ - diff = s->func_mux_ctrl[offset >> 2] ^ value; - s->func_mux_ctrl[offset >> 2] = value; - omap_pin_funcmux1_update(s, diff, value); - return; - - case 0x08: /* FUNC_MUX_CTRL_2 */ - s->func_mux_ctrl[offset >> 2] = value; - return; - - case 0x0c: /* COMP_MODE_CTRL_0 */ - s->comp_mode_ctrl[0] = value; - s->compat1509 = (value != 0x0000eaef); - omap_pin_funcmux0_update(s, ~0, s->func_mux_ctrl[0]); - omap_pin_funcmux1_update(s, ~0, s->func_mux_ctrl[1]); - return; - - case 0x10: /* FUNC_MUX_CTRL_3 */ - case 0x14: /* FUNC_MUX_CTRL_4 */ - case 0x18: /* FUNC_MUX_CTRL_5 */ - case 0x1c: /* FUNC_MUX_CTRL_6 */ - case 0x20: /* FUNC_MUX_CTRL_7 */ - case 0x24: /* FUNC_MUX_CTRL_8 */ - case 0x28: /* FUNC_MUX_CTRL_9 */ - case 0x2c: /* FUNC_MUX_CTRL_A */ - case 0x30: /* FUNC_MUX_CTRL_B */ - case 0x34: /* FUNC_MUX_CTRL_C */ - case 0x38: /* FUNC_MUX_CTRL_D */ - s->func_mux_ctrl[(offset >> 2) - 1] = value; - return; - - case 0x40: /* PULL_DWN_CTRL_0 */ - case 0x44: /* PULL_DWN_CTRL_1 */ - case 0x48: /* PULL_DWN_CTRL_2 */ - case 0x4c: /* PULL_DWN_CTRL_3 */ - s->pull_dwn_ctrl[(offset & 0xf) >> 2] = value; - return; - - case 0x50: /* GATE_INH_CTRL_0 */ - s->gate_inh_ctrl[0] = value; - return; - - case 0x60: /* VOLTAGE_CTRL_0 */ - s->voltage_ctrl[0] = value; - return; - - case 0x70: /* TEST_DBG_CTRL_0 */ - s->test_dbg_ctrl[0] = value; - return; - - case 0x80: /* MOD_CONF_CTRL_0 */ - diff = s->mod_conf_ctrl[0] ^ value; - s->mod_conf_ctrl[0] = value; - omap_pin_modconf1_update(s, diff, value); - return; - - default: - OMAP_BAD_REG(addr); - } -} - -static CPUReadMemoryFunc *omap_pin_cfg_readfn[] = { - omap_badwidth_read32, - omap_badwidth_read32, - omap_pin_cfg_read, -}; - -static CPUWriteMemoryFunc *omap_pin_cfg_writefn[] = { - omap_badwidth_write32, - omap_badwidth_write32, - omap_pin_cfg_write, -}; - -static void omap_pin_cfg_reset(struct omap_mpu_state_s *mpu) -{ - /* Start in Compatibility Mode. */ - mpu->compat1509 = 1; - omap_pin_funcmux0_update(mpu, mpu->func_mux_ctrl[0], 0); - omap_pin_funcmux1_update(mpu, mpu->func_mux_ctrl[1], 0); - omap_pin_modconf1_update(mpu, mpu->mod_conf_ctrl[0], 0); - memset(mpu->func_mux_ctrl, 0, sizeof(mpu->func_mux_ctrl)); - memset(mpu->comp_mode_ctrl, 0, sizeof(mpu->comp_mode_ctrl)); - memset(mpu->pull_dwn_ctrl, 0, sizeof(mpu->pull_dwn_ctrl)); - memset(mpu->gate_inh_ctrl, 0, sizeof(mpu->gate_inh_ctrl)); - memset(mpu->voltage_ctrl, 0, sizeof(mpu->voltage_ctrl)); - memset(mpu->test_dbg_ctrl, 0, sizeof(mpu->test_dbg_ctrl)); - memset(mpu->mod_conf_ctrl, 0, sizeof(mpu->mod_conf_ctrl)); -} - -static void omap_pin_cfg_init(target_phys_addr_t base, - struct omap_mpu_state_s *mpu) -{ - int iomemtype = cpu_register_io_memory(0, omap_pin_cfg_readfn, - omap_pin_cfg_writefn, mpu); - - mpu->pin_cfg_base = base; - cpu_register_physical_memory(mpu->pin_cfg_base, 0x800, iomemtype); - omap_pin_cfg_reset(mpu); -} - -/* Device Identification, Die Identification */ -static uint32_t omap_id_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - - switch (addr) { - case 0xfffe1800: /* DIE_ID_LSB */ - return 0xc9581f0e; - case 0xfffe1804: /* DIE_ID_MSB */ - return 0xa8858bfa; - - case 0xfffe2000: /* PRODUCT_ID_LSB */ - return 0x00aaaafc; - case 0xfffe2004: /* PRODUCT_ID_MSB */ - return 0xcafeb574; - - case 0xfffed400: /* JTAG_ID_LSB */ - switch (s->mpu_model) { - case omap310: - return 0x03310315; - case omap1510: - return 0x03310115; - } - break; - - case 0xfffed404: /* JTAG_ID_MSB */ - switch (s->mpu_model) { - case omap310: - return 0xfb57402f; - case omap1510: - return 0xfb47002f; - } - break; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_id_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - OMAP_BAD_REG(addr); -} - -static CPUReadMemoryFunc *omap_id_readfn[] = { - omap_badwidth_read32, - omap_badwidth_read32, - omap_id_read, -}; - -static CPUWriteMemoryFunc *omap_id_writefn[] = { - omap_badwidth_write32, - omap_badwidth_write32, - omap_id_write, -}; - -static void omap_id_init(struct omap_mpu_state_s *mpu) -{ - int iomemtype = cpu_register_io_memory(0, omap_id_readfn, - omap_id_writefn, mpu); - cpu_register_physical_memory(0xfffe1800, 0x800, iomemtype); - cpu_register_physical_memory(0xfffed400, 0x100, iomemtype); - if (!cpu_is_omap15xx(mpu)) - cpu_register_physical_memory(0xfffe2000, 0x800, iomemtype); -} - -/* MPUI Control (Dummy) */ -static uint32_t omap_mpui_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr - s->mpui_base; - - switch (offset) { - case 0x00: /* CTRL */ - return s->mpui_ctrl; - case 0x04: /* DEBUG_ADDR */ - return 0x01ffffff; - case 0x08: /* DEBUG_DATA */ - return 0xffffffff; - case 0x0c: /* DEBUG_FLAG */ - return 0x00000800; - case 0x10: /* STATUS */ - return 0x00000000; - - /* Not in OMAP310 */ - case 0x14: /* DSP_STATUS */ - case 0x18: /* DSP_BOOT_CONFIG */ - return 0x00000000; - case 0x1c: /* DSP_MPUI_CONFIG */ - return 0x0000ffff; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_mpui_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr - s->mpui_base; - - switch (offset) { - case 0x00: /* CTRL */ - s->mpui_ctrl = value & 0x007fffff; - break; - - case 0x04: /* DEBUG_ADDR */ - case 0x08: /* DEBUG_DATA */ - case 0x0c: /* DEBUG_FLAG */ - case 0x10: /* STATUS */ - /* Not in OMAP310 */ - case 0x14: /* DSP_STATUS */ - OMAP_RO_REG(addr); - case 0x18: /* DSP_BOOT_CONFIG */ - case 0x1c: /* DSP_MPUI_CONFIG */ - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static CPUReadMemoryFunc *omap_mpui_readfn[] = { - omap_badwidth_read32, - omap_badwidth_read32, - omap_mpui_read, -}; - -static CPUWriteMemoryFunc *omap_mpui_writefn[] = { - omap_badwidth_write32, - omap_badwidth_write32, - omap_mpui_write, -}; - -static void omap_mpui_reset(struct omap_mpu_state_s *s) -{ - s->mpui_ctrl = 0x0003ff1b; -} - -static void omap_mpui_init(target_phys_addr_t base, - struct omap_mpu_state_s *mpu) -{ - int iomemtype = cpu_register_io_memory(0, omap_mpui_readfn, - omap_mpui_writefn, mpu); - - mpu->mpui_base = base; - cpu_register_physical_memory(mpu->mpui_base, 0x100, iomemtype); - - omap_mpui_reset(mpu); -} - -/* TIPB Bridges */ -struct omap_tipb_bridge_s { - target_phys_addr_t base; - qemu_irq abort; - - int width_intr; - uint16_t control; - uint16_t alloc; - uint16_t buffer; - uint16_t enh_control; -}; - -static uint32_t omap_tipb_bridge_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque; - int offset = addr - s->base; - - switch (offset) { - case 0x00: /* TIPB_CNTL */ - return s->control; - case 0x04: /* TIPB_BUS_ALLOC */ - return s->alloc; - case 0x08: /* MPU_TIPB_CNTL */ - return s->buffer; - case 0x0c: /* ENHANCED_TIPB_CNTL */ - return s->enh_control; - case 0x10: /* ADDRESS_DBG */ - case 0x14: /* DATA_DEBUG_LOW */ - case 0x18: /* DATA_DEBUG_HIGH */ - return 0xffff; - case 0x1c: /* DEBUG_CNTR_SIG */ - return 0x00f8; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_tipb_bridge_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque; - int offset = addr - s->base; - - switch (offset) { - case 0x00: /* TIPB_CNTL */ - s->control = value & 0xffff; - break; - - case 0x04: /* TIPB_BUS_ALLOC */ - s->alloc = value & 0x003f; - break; - - case 0x08: /* MPU_TIPB_CNTL */ - s->buffer = value & 0x0003; - break; - - case 0x0c: /* ENHANCED_TIPB_CNTL */ - s->width_intr = !(value & 2); - s->enh_control = value & 0x000f; - break; - - case 0x10: /* ADDRESS_DBG */ - case 0x14: /* DATA_DEBUG_LOW */ - case 0x18: /* DATA_DEBUG_HIGH */ - case 0x1c: /* DEBUG_CNTR_SIG */ - OMAP_RO_REG(addr); - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static CPUReadMemoryFunc *omap_tipb_bridge_readfn[] = { - omap_badwidth_read16, - omap_tipb_bridge_read, - omap_tipb_bridge_read, -}; - -static CPUWriteMemoryFunc *omap_tipb_bridge_writefn[] = { - omap_badwidth_write16, - omap_tipb_bridge_write, - omap_tipb_bridge_write, -}; - -static void omap_tipb_bridge_reset(struct omap_tipb_bridge_s *s) -{ - s->control = 0xffff; - s->alloc = 0x0009; - s->buffer = 0x0000; - s->enh_control = 0x000f; -} - -struct omap_tipb_bridge_s *omap_tipb_bridge_init(target_phys_addr_t base, - qemu_irq abort_irq, omap_clk clk) -{ - int iomemtype; - struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) - qemu_mallocz(sizeof(struct omap_tipb_bridge_s)); - - s->abort = abort_irq; - s->base = base; - omap_tipb_bridge_reset(s); - - iomemtype = cpu_register_io_memory(0, omap_tipb_bridge_readfn, - omap_tipb_bridge_writefn, s); - cpu_register_physical_memory(s->base, 0x100, iomemtype); - - return s; -} - -/* Dummy Traffic Controller's Memory Interface */ -static uint32_t omap_tcmi_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr - s->tcmi_base; - uint32_t ret; - - switch (offset) { - case 0x00: /* IMIF_PRIO */ - case 0x04: /* EMIFS_PRIO */ - case 0x08: /* EMIFF_PRIO */ - case 0x0c: /* EMIFS_CONFIG */ - case 0x10: /* EMIFS_CS0_CONFIG */ - case 0x14: /* EMIFS_CS1_CONFIG */ - case 0x18: /* EMIFS_CS2_CONFIG */ - case 0x1c: /* EMIFS_CS3_CONFIG */ - case 0x24: /* EMIFF_MRS */ - case 0x28: /* TIMEOUT1 */ - case 0x2c: /* TIMEOUT2 */ - case 0x30: /* TIMEOUT3 */ - case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */ - case 0x40: /* EMIFS_CFG_DYN_WAIT */ - return s->tcmi_regs[offset >> 2]; - - case 0x20: /* EMIFF_SDRAM_CONFIG */ - ret = s->tcmi_regs[offset >> 2]; - s->tcmi_regs[offset >> 2] &= ~1; /* XXX: Clear SLRF on SDRAM access */ - /* XXX: We can try using the VGA_DIRTY flag for this */ - return ret; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_tcmi_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr - s->tcmi_base; - - switch (offset) { - case 0x00: /* IMIF_PRIO */ - case 0x04: /* EMIFS_PRIO */ - case 0x08: /* EMIFF_PRIO */ - case 0x10: /* EMIFS_CS0_CONFIG */ - case 0x14: /* EMIFS_CS1_CONFIG */ - case 0x18: /* EMIFS_CS2_CONFIG */ - case 0x1c: /* EMIFS_CS3_CONFIG */ - case 0x20: /* EMIFF_SDRAM_CONFIG */ - case 0x24: /* EMIFF_MRS */ - case 0x28: /* TIMEOUT1 */ - case 0x2c: /* TIMEOUT2 */ - case 0x30: /* TIMEOUT3 */ - case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */ - case 0x40: /* EMIFS_CFG_DYN_WAIT */ - s->tcmi_regs[offset >> 2] = value; - break; - case 0x0c: /* EMIFS_CONFIG */ - s->tcmi_regs[offset >> 2] = (value & 0xf) | (1 << 4); - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static CPUReadMemoryFunc *omap_tcmi_readfn[] = { - omap_badwidth_read32, - omap_badwidth_read32, - omap_tcmi_read, -}; - -static CPUWriteMemoryFunc *omap_tcmi_writefn[] = { - omap_badwidth_write32, - omap_badwidth_write32, - omap_tcmi_write, -}; - -static void omap_tcmi_reset(struct omap_mpu_state_s *mpu) -{ - mpu->tcmi_regs[0x00 >> 2] = 0x00000000; - mpu->tcmi_regs[0x04 >> 2] = 0x00000000; - mpu->tcmi_regs[0x08 >> 2] = 0x00000000; - mpu->tcmi_regs[0x0c >> 2] = 0x00000010; - mpu->tcmi_regs[0x10 >> 2] = 0x0010fffb; - mpu->tcmi_regs[0x14 >> 2] = 0x0010fffb; - mpu->tcmi_regs[0x18 >> 2] = 0x0010fffb; - mpu->tcmi_regs[0x1c >> 2] = 0x0010fffb; - mpu->tcmi_regs[0x20 >> 2] = 0x00618800; - mpu->tcmi_regs[0x24 >> 2] = 0x00000037; - mpu->tcmi_regs[0x28 >> 2] = 0x00000000; - mpu->tcmi_regs[0x2c >> 2] = 0x00000000; - mpu->tcmi_regs[0x30 >> 2] = 0x00000000; - mpu->tcmi_regs[0x3c >> 2] = 0x00000003; - mpu->tcmi_regs[0x40 >> 2] = 0x00000000; -} - -static void omap_tcmi_init(target_phys_addr_t base, - struct omap_mpu_state_s *mpu) -{ - int iomemtype = cpu_register_io_memory(0, omap_tcmi_readfn, - omap_tcmi_writefn, mpu); - - mpu->tcmi_base = base; - cpu_register_physical_memory(mpu->tcmi_base, 0x100, iomemtype); - omap_tcmi_reset(mpu); -} - -/* Digital phase-locked loops control */ -static uint32_t omap_dpll_read(void *opaque, target_phys_addr_t addr) -{ - struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque; - int offset = addr - s->base; - - if (offset == 0x00) /* CTL_REG */ - return s->mode; - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_dpll_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque; - uint16_t diff; - int offset = addr - s->base; - static const int bypass_div[4] = { 1, 2, 4, 4 }; - int div, mult; - - if (offset == 0x00) { /* CTL_REG */ - /* See omap_ulpd_pm_write() too */ - diff = s->mode & value; - s->mode = value & 0x2fff; - if (diff & (0x3ff << 2)) { - if (value & (1 << 4)) { /* PLL_ENABLE */ - div = ((value >> 5) & 3) + 1; /* PLL_DIV */ - mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */ - } else { - div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */ - mult = 1; - } - omap_clk_setrate(s->dpll, div, mult); - } - - /* Enter the desired mode. */ - s->mode = (s->mode & 0xfffe) | ((s->mode >> 4) & 1); - - /* Act as if the lock is restored. */ - s->mode |= 2; - } else { - OMAP_BAD_REG(addr); - } -} - -static CPUReadMemoryFunc *omap_dpll_readfn[] = { - omap_badwidth_read16, - omap_dpll_read, - omap_badwidth_read16, -}; - -static CPUWriteMemoryFunc *omap_dpll_writefn[] = { - omap_badwidth_write16, - omap_dpll_write, - omap_badwidth_write16, -}; - -static void omap_dpll_reset(struct dpll_ctl_s *s) -{ - s->mode = 0x2002; - omap_clk_setrate(s->dpll, 1, 1); -} - -static void omap_dpll_init(struct dpll_ctl_s *s, target_phys_addr_t base, - omap_clk clk) -{ - int iomemtype = cpu_register_io_memory(0, omap_dpll_readfn, - omap_dpll_writefn, s); - - s->base = base; - s->dpll = clk; - omap_dpll_reset(s); - - cpu_register_physical_memory(s->base, 0x100, iomemtype); -} - -/* UARTs */ -struct omap_uart_s { - SerialState *serial; /* TODO */ -}; - -static void omap_uart_reset(struct omap_uart_s *s) -{ -} - -struct omap_uart_s *omap_uart_init(target_phys_addr_t base, - qemu_irq irq, omap_clk clk, CharDriverState *chr) -{ - struct omap_uart_s *s = (struct omap_uart_s *) - qemu_mallocz(sizeof(struct omap_uart_s)); - if (chr) - s->serial = serial_mm_init(base, 2, irq, chr, 1); - return s; -} - -/* MPU Clock/Reset/Power Mode Control */ -static uint32_t omap_clkm_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr - s->clkm.mpu_base; - - switch (offset) { - case 0x00: /* ARM_CKCTL */ - return s->clkm.arm_ckctl; - - case 0x04: /* ARM_IDLECT1 */ - return s->clkm.arm_idlect1; - - case 0x08: /* ARM_IDLECT2 */ - return s->clkm.arm_idlect2; - - case 0x0c: /* ARM_EWUPCT */ - return s->clkm.arm_ewupct; - - case 0x10: /* ARM_RSTCT1 */ - return s->clkm.arm_rstct1; - - case 0x14: /* ARM_RSTCT2 */ - return s->clkm.arm_rstct2; - - case 0x18: /* ARM_SYSST */ - return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start; - - case 0x1c: /* ARM_CKOUT1 */ - return s->clkm.arm_ckout1; - - case 0x20: /* ARM_CKOUT2 */ - break; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static inline void omap_clkm_ckctl_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - omap_clk clk; - - if (diff & (1 << 14)) { /* ARM_INTHCK_SEL */ - if (value & (1 << 14)) - /* Reserved */; - else { - clk = omap_findclk(s, "arminth_ck"); - omap_clk_reparent(clk, omap_findclk(s, "tc_ck")); - } - } - if (diff & (1 << 12)) { /* ARM_TIMXO */ - clk = omap_findclk(s, "armtim_ck"); - if (value & (1 << 12)) - omap_clk_reparent(clk, omap_findclk(s, "clkin")); - else - omap_clk_reparent(clk, omap_findclk(s, "ck_gen1")); - } - /* XXX: en_dspck */ - if (diff & (3 << 10)) { /* DSPMMUDIV */ - clk = omap_findclk(s, "dspmmu_ck"); - omap_clk_setrate(clk, 1 << ((value >> 10) & 3), 1); - } - if (diff & (3 << 8)) { /* TCDIV */ - clk = omap_findclk(s, "tc_ck"); - omap_clk_setrate(clk, 1 << ((value >> 8) & 3), 1); - } - if (diff & (3 << 6)) { /* DSPDIV */ - clk = omap_findclk(s, "dsp_ck"); - omap_clk_setrate(clk, 1 << ((value >> 6) & 3), 1); - } - if (diff & (3 << 4)) { /* ARMDIV */ - clk = omap_findclk(s, "arm_ck"); - omap_clk_setrate(clk, 1 << ((value >> 4) & 3), 1); - } - if (diff & (3 << 2)) { /* LCDDIV */ - clk = omap_findclk(s, "lcd_ck"); - omap_clk_setrate(clk, 1 << ((value >> 2) & 3), 1); - } - if (diff & (3 << 0)) { /* PERDIV */ - clk = omap_findclk(s, "armper_ck"); - omap_clk_setrate(clk, 1 << ((value >> 0) & 3), 1); - } -} - -static inline void omap_clkm_idlect1_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - omap_clk clk; - - if (value & (1 << 11)) /* SETARM_IDLE */ - cpu_interrupt(s->env, CPU_INTERRUPT_HALT); - if (!(value & (1 << 10))) /* WKUP_MODE */ - qemu_system_shutdown_request(); /* XXX: disable wakeup from IRQ */ - -#define SET_CANIDLE(clock, bit) \ - if (diff & (1 << bit)) { \ - clk = omap_findclk(s, clock); \ - omap_clk_canidle(clk, (value >> bit) & 1); \ - } - SET_CANIDLE("mpuwd_ck", 0) /* IDLWDT_ARM */ - SET_CANIDLE("armxor_ck", 1) /* IDLXORP_ARM */ - SET_CANIDLE("mpuper_ck", 2) /* IDLPER_ARM */ - SET_CANIDLE("lcd_ck", 3) /* IDLLCD_ARM */ - SET_CANIDLE("lb_ck", 4) /* IDLLB_ARM */ - SET_CANIDLE("hsab_ck", 5) /* IDLHSAB_ARM */ - SET_CANIDLE("tipb_ck", 6) /* IDLIF_ARM */ - SET_CANIDLE("dma_ck", 6) /* IDLIF_ARM */ - SET_CANIDLE("tc_ck", 6) /* IDLIF_ARM */ - SET_CANIDLE("dpll1", 7) /* IDLDPLL_ARM */ - SET_CANIDLE("dpll2", 7) /* IDLDPLL_ARM */ - SET_CANIDLE("dpll3", 7) /* IDLDPLL_ARM */ - SET_CANIDLE("mpui_ck", 8) /* IDLAPI_ARM */ - SET_CANIDLE("armtim_ck", 9) /* IDLTIM_ARM */ -} - -static inline void omap_clkm_idlect2_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - omap_clk clk; - -#define SET_ONOFF(clock, bit) \ - if (diff & (1 << bit)) { \ - clk = omap_findclk(s, clock); \ - omap_clk_onoff(clk, (value >> bit) & 1); \ - } - SET_ONOFF("mpuwd_ck", 0) /* EN_WDTCK */ - SET_ONOFF("armxor_ck", 1) /* EN_XORPCK */ - SET_ONOFF("mpuper_ck", 2) /* EN_PERCK */ - SET_ONOFF("lcd_ck", 3) /* EN_LCDCK */ - SET_ONOFF("lb_ck", 4) /* EN_LBCK */ - SET_ONOFF("hsab_ck", 5) /* EN_HSABCK */ - SET_ONOFF("mpui_ck", 6) /* EN_APICK */ - SET_ONOFF("armtim_ck", 7) /* EN_TIMCK */ - SET_CANIDLE("dma_ck", 8) /* DMACK_REQ */ - SET_ONOFF("arm_gpio_ck", 9) /* EN_GPIOCK */ - SET_ONOFF("lbfree_ck", 10) /* EN_LBFREECK */ -} - -static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - omap_clk clk; - - if (diff & (3 << 4)) { /* TCLKOUT */ - clk = omap_findclk(s, "tclk_out"); - switch ((value >> 4) & 3) { - case 1: - omap_clk_reparent(clk, omap_findclk(s, "ck_gen3")); - omap_clk_onoff(clk, 1); - break; - case 2: - omap_clk_reparent(clk, omap_findclk(s, "tc_ck")); - omap_clk_onoff(clk, 1); - break; - default: - omap_clk_onoff(clk, 0); - } - } - if (diff & (3 << 2)) { /* DCLKOUT */ - clk = omap_findclk(s, "dclk_out"); - switch ((value >> 2) & 3) { - case 0: - omap_clk_reparent(clk, omap_findclk(s, "dspmmu_ck")); - break; - case 1: - omap_clk_reparent(clk, omap_findclk(s, "ck_gen2")); - break; - case 2: - omap_clk_reparent(clk, omap_findclk(s, "dsp_ck")); - break; - case 3: - omap_clk_reparent(clk, omap_findclk(s, "ck_ref14")); - break; - } - } - if (diff & (3 << 0)) { /* ACLKOUT */ - clk = omap_findclk(s, "aclk_out"); - switch ((value >> 0) & 3) { - case 1: - omap_clk_reparent(clk, omap_findclk(s, "ck_gen1")); - omap_clk_onoff(clk, 1); - break; - case 2: - omap_clk_reparent(clk, omap_findclk(s, "arm_ck")); - omap_clk_onoff(clk, 1); - break; - case 3: - omap_clk_reparent(clk, omap_findclk(s, "ck_ref14")); - omap_clk_onoff(clk, 1); - break; - default: - omap_clk_onoff(clk, 0); - } - } -} - -static void omap_clkm_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr - s->clkm.mpu_base; - uint16_t diff; - omap_clk clk; - static const char *clkschemename[8] = { - "fully synchronous", "fully asynchronous", "synchronous scalable", - "mix mode 1", "mix mode 2", "bypass mode", "mix mode 3", "mix mode 4", - }; - - switch (offset) { - case 0x00: /* ARM_CKCTL */ - diff = s->clkm.arm_ckctl ^ value; - s->clkm.arm_ckctl = value & 0x7fff; - omap_clkm_ckctl_update(s, diff, value); - return; - - case 0x04: /* ARM_IDLECT1 */ - diff = s->clkm.arm_idlect1 ^ value; - s->clkm.arm_idlect1 = value & 0x0fff; - omap_clkm_idlect1_update(s, diff, value); - return; - - case 0x08: /* ARM_IDLECT2 */ - diff = s->clkm.arm_idlect2 ^ value; - s->clkm.arm_idlect2 = value & 0x07ff; - omap_clkm_idlect2_update(s, diff, value); - return; - - case 0x0c: /* ARM_EWUPCT */ - diff = s->clkm.arm_ewupct ^ value; - s->clkm.arm_ewupct = value & 0x003f; - return; - - case 0x10: /* ARM_RSTCT1 */ - diff = s->clkm.arm_rstct1 ^ value; - s->clkm.arm_rstct1 = value & 0x0007; - if (value & 9) { - qemu_system_reset_request(); - s->clkm.cold_start = 0xa; - } - if (diff & ~value & 4) { /* DSP_RST */ - omap_mpui_reset(s); - omap_tipb_bridge_reset(s->private_tipb); - omap_tipb_bridge_reset(s->public_tipb); - } - if (diff & 2) { /* DSP_EN */ - clk = omap_findclk(s, "dsp_ck"); - omap_clk_canidle(clk, (~value >> 1) & 1); - } - return; - - case 0x14: /* ARM_RSTCT2 */ - s->clkm.arm_rstct2 = value & 0x0001; - return; - - case 0x18: /* ARM_SYSST */ - if ((s->clkm.clocking_scheme ^ (value >> 11)) & 7) { - s->clkm.clocking_scheme = (value >> 11) & 7; - printf("%s: clocking scheme set to %s\n", __FUNCTION__, - clkschemename[s->clkm.clocking_scheme]); - } - s->clkm.cold_start &= value & 0x3f; - return; - - case 0x1c: /* ARM_CKOUT1 */ - diff = s->clkm.arm_ckout1 ^ value; - s->clkm.arm_ckout1 = value & 0x003f; - omap_clkm_ckout1_update(s, diff, value); - return; - - case 0x20: /* ARM_CKOUT2 */ - default: - OMAP_BAD_REG(addr); - } -} - -static CPUReadMemoryFunc *omap_clkm_readfn[] = { - omap_badwidth_read16, - omap_clkm_read, - omap_badwidth_read16, -}; - -static CPUWriteMemoryFunc *omap_clkm_writefn[] = { - omap_badwidth_write16, - omap_clkm_write, - omap_badwidth_write16, -}; - -static uint32_t omap_clkdsp_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr - s->clkm.dsp_base; - - switch (offset) { - case 0x04: /* DSP_IDLECT1 */ - return s->clkm.dsp_idlect1; - - case 0x08: /* DSP_IDLECT2 */ - return s->clkm.dsp_idlect2; - - case 0x14: /* DSP_RSTCT2 */ - return s->clkm.dsp_rstct2; - - case 0x18: /* DSP_SYSST */ - return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start | - (s->env->halted << 6); /* Quite useless... */ - } - - OMAP_BAD_REG(addr); - return 0; -} - -static inline void omap_clkdsp_idlect1_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - omap_clk clk; - - SET_CANIDLE("dspxor_ck", 1); /* IDLXORP_DSP */ -} - -static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - omap_clk clk; - - SET_ONOFF("dspxor_ck", 1); /* EN_XORPCK */ -} - -static void omap_clkdsp_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr - s->clkm.dsp_base; - uint16_t diff; - - switch (offset) { - case 0x04: /* DSP_IDLECT1 */ - diff = s->clkm.dsp_idlect1 ^ value; - s->clkm.dsp_idlect1 = value & 0x01f7; - omap_clkdsp_idlect1_update(s, diff, value); - break; - - case 0x08: /* DSP_IDLECT2 */ - s->clkm.dsp_idlect2 = value & 0x0037; - diff = s->clkm.dsp_idlect1 ^ value; - omap_clkdsp_idlect2_update(s, diff, value); - break; - - case 0x14: /* DSP_RSTCT2 */ - s->clkm.dsp_rstct2 = value & 0x0001; - break; - - case 0x18: /* DSP_SYSST */ - s->clkm.cold_start &= value & 0x3f; - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static CPUReadMemoryFunc *omap_clkdsp_readfn[] = { - omap_badwidth_read16, - omap_clkdsp_read, - omap_badwidth_read16, -}; - -static CPUWriteMemoryFunc *omap_clkdsp_writefn[] = { - omap_badwidth_write16, - omap_clkdsp_write, - omap_badwidth_write16, -}; - -static void omap_clkm_reset(struct omap_mpu_state_s *s) -{ - if (s->wdt && s->wdt->reset) - s->clkm.cold_start = 0x6; - s->clkm.clocking_scheme = 0; - omap_clkm_ckctl_update(s, ~0, 0x3000); - s->clkm.arm_ckctl = 0x3000; - omap_clkm_idlect1_update(s, s->clkm.arm_idlect1 ^ 0x0400, 0x0400); - s->clkm.arm_idlect1 = 0x0400; - omap_clkm_idlect2_update(s, s->clkm.arm_idlect2 ^ 0x0100, 0x0100); - s->clkm.arm_idlect2 = 0x0100; - s->clkm.arm_ewupct = 0x003f; - s->clkm.arm_rstct1 = 0x0000; - s->clkm.arm_rstct2 = 0x0000; - s->clkm.arm_ckout1 = 0x0015; - s->clkm.dpll1_mode = 0x2002; - omap_clkdsp_idlect1_update(s, s->clkm.dsp_idlect1 ^ 0x0040, 0x0040); - s->clkm.dsp_idlect1 = 0x0040; - omap_clkdsp_idlect2_update(s, ~0, 0x0000); - s->clkm.dsp_idlect2 = 0x0000; - s->clkm.dsp_rstct2 = 0x0000; -} - -static void omap_clkm_init(target_phys_addr_t mpu_base, - target_phys_addr_t dsp_base, struct omap_mpu_state_s *s) -{ - int iomemtype[2] = { - cpu_register_io_memory(0, omap_clkm_readfn, omap_clkm_writefn, s), - cpu_register_io_memory(0, omap_clkdsp_readfn, omap_clkdsp_writefn, s), - }; - - s->clkm.mpu_base = mpu_base; - s->clkm.dsp_base = dsp_base; - s->clkm.arm_idlect1 = 0x03ff; - s->clkm.arm_idlect2 = 0x0100; - s->clkm.dsp_idlect1 = 0x0002; - omap_clkm_reset(s); - s->clkm.cold_start = 0x3a; - - cpu_register_physical_memory(s->clkm.mpu_base, 0x100, iomemtype[0]); - cpu_register_physical_memory(s->clkm.dsp_base, 0x1000, iomemtype[1]); -} - -/* MPU I/O */ -struct omap_mpuio_s { - target_phys_addr_t base; - qemu_irq irq; - qemu_irq kbd_irq; - qemu_irq *in; - qemu_irq handler[16]; - qemu_irq wakeup; - - uint16_t inputs; - uint16_t outputs; - uint16_t dir; - uint16_t edge; - uint16_t mask; - uint16_t ints; - - uint16_t debounce; - uint16_t latch; - uint8_t event; - - uint8_t buttons[5]; - uint8_t row_latch; - uint8_t cols; - int kbd_mask; - int clk; -}; - -static void omap_mpuio_set(void *opaque, int line, int level) -{ - struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; - uint16_t prev = s->inputs; - - if (level) - s->inputs |= 1 << line; - else - s->inputs &= ~(1 << line); - - if (((1 << line) & s->dir & ~s->mask) && s->clk) { - if ((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) { - s->ints |= 1 << line; - qemu_irq_raise(s->irq); - /* TODO: wakeup */ - } - if ((s->event & (1 << 0)) && /* SET_GPIO_EVENT_MODE */ - (s->event >> 1) == line) /* PIN_SELECT */ - s->latch = s->inputs; - } -} - -static void omap_mpuio_kbd_update(struct omap_mpuio_s *s) -{ - int i; - uint8_t *row, rows = 0, cols = ~s->cols; - - for (row = s->buttons + 4, i = 1 << 4; i; row --, i >>= 1) - if (*row & cols) - rows |= i; - - qemu_set_irq(s->kbd_irq, rows && !s->kbd_mask && s->clk); - s->row_latch = ~rows; -} - -static uint32_t omap_mpuio_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - uint16_t ret; - - switch (offset) { - case 0x00: /* INPUT_LATCH */ - return s->inputs; - - case 0x04: /* OUTPUT_REG */ - return s->outputs; - - case 0x08: /* IO_CNTL */ - return s->dir; - - case 0x10: /* KBR_LATCH */ - return s->row_latch; - - case 0x14: /* KBC_REG */ - return s->cols; - - case 0x18: /* GPIO_EVENT_MODE_REG */ - return s->event; - - case 0x1c: /* GPIO_INT_EDGE_REG */ - return s->edge; - - case 0x20: /* KBD_INT */ - return (~s->row_latch & 0x1f) && !s->kbd_mask; - - case 0x24: /* GPIO_INT */ - ret = s->ints; - s->ints &= s->mask; - if (ret) - qemu_irq_lower(s->irq); - return ret; - - case 0x28: /* KBD_MASKIT */ - return s->kbd_mask; - - case 0x2c: /* GPIO_MASKIT */ - return s->mask; - - case 0x30: /* GPIO_DEBOUNCING_REG */ - return s->debounce; - - case 0x34: /* GPIO_LATCH_REG */ - return s->latch; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_mpuio_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - uint16_t diff; - int ln; - - switch (offset) { - case 0x04: /* OUTPUT_REG */ - diff = (s->outputs ^ value) & ~s->dir; - s->outputs = value; - while ((ln = ffs(diff))) { - ln --; - if (s->handler[ln]) - qemu_set_irq(s->handler[ln], (value >> ln) & 1); - diff &= ~(1 << ln); - } - break; - - case 0x08: /* IO_CNTL */ - diff = s->outputs & (s->dir ^ value); - s->dir = value; - - value = s->outputs & ~s->dir; - while ((ln = ffs(diff))) { - ln --; - if (s->handler[ln]) - qemu_set_irq(s->handler[ln], (value >> ln) & 1); - diff &= ~(1 << ln); - } - break; - - case 0x14: /* KBC_REG */ - s->cols = value; - omap_mpuio_kbd_update(s); - break; - - case 0x18: /* GPIO_EVENT_MODE_REG */ - s->event = value & 0x1f; - break; - - case 0x1c: /* GPIO_INT_EDGE_REG */ - s->edge = value; - break; - - case 0x28: /* KBD_MASKIT */ - s->kbd_mask = value & 1; - omap_mpuio_kbd_update(s); - break; - - case 0x2c: /* GPIO_MASKIT */ - s->mask = value; - break; - - case 0x30: /* GPIO_DEBOUNCING_REG */ - s->debounce = value & 0x1ff; - break; - - case 0x00: /* INPUT_LATCH */ - case 0x10: /* KBR_LATCH */ - case 0x20: /* KBD_INT */ - case 0x24: /* GPIO_INT */ - case 0x34: /* GPIO_LATCH_REG */ - OMAP_RO_REG(addr); - return; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static CPUReadMemoryFunc *omap_mpuio_readfn[] = { - omap_badwidth_read16, - omap_mpuio_read, - omap_badwidth_read16, -}; - -static CPUWriteMemoryFunc *omap_mpuio_writefn[] = { - omap_badwidth_write16, - omap_mpuio_write, - omap_badwidth_write16, -}; - -static void omap_mpuio_reset(struct omap_mpuio_s *s) -{ - s->inputs = 0; - s->outputs = 0; - s->dir = ~0; - s->event = 0; - s->edge = 0; - s->kbd_mask = 0; - s->mask = 0; - s->debounce = 0; - s->latch = 0; - s->ints = 0; - s->row_latch = 0x1f; - s->clk = 1; -} - -static void omap_mpuio_onoff(void *opaque, int line, int on) -{ - struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; - - s->clk = on; - if (on) - omap_mpuio_kbd_update(s); -} - -struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base, - qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup, - omap_clk clk) -{ - int iomemtype; - struct omap_mpuio_s *s = (struct omap_mpuio_s *) - qemu_mallocz(sizeof(struct omap_mpuio_s)); - - s->base = base; - s->irq = gpio_int; - s->kbd_irq = kbd_int; - s->wakeup = wakeup; - s->in = qemu_allocate_irqs(omap_mpuio_set, s, 16); - omap_mpuio_reset(s); - - iomemtype = cpu_register_io_memory(0, omap_mpuio_readfn, - omap_mpuio_writefn, s); - cpu_register_physical_memory(s->base, 0x800, iomemtype); - - omap_clk_adduser(clk, qemu_allocate_irqs(omap_mpuio_onoff, s, 1)[0]); - - return s; -} - -qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s) -{ - return s->in; -} - -void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler) -{ - if (line >= 16 || line < 0) - cpu_abort(cpu_single_env, "%s: No GPIO line %i\n", __FUNCTION__, line); - s->handler[line] = handler; -} - -void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down) -{ - if (row >= 5 || row < 0) - cpu_abort(cpu_single_env, "%s: No key %i-%i\n", - __FUNCTION__, col, row); - - if (down) - s->buttons[row] |= 1 << col; - else - s->buttons[row] &= ~(1 << col); - - omap_mpuio_kbd_update(s); -} - -/* General-Purpose I/O */ -struct omap_gpio_s { - target_phys_addr_t base; - qemu_irq irq; - qemu_irq *in; - qemu_irq handler[16]; - - uint16_t inputs; - uint16_t outputs; - uint16_t dir; - uint16_t edge; - uint16_t mask; - uint16_t ints; - uint16_t pins; -}; - -static void omap_gpio_set(void *opaque, int line, int level) -{ - struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; - uint16_t prev = s->inputs; - - if (level) - s->inputs |= 1 << line; - else - s->inputs &= ~(1 << line); - - if (((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) & - (1 << line) & s->dir & ~s->mask) { - s->ints |= 1 << line; - qemu_irq_raise(s->irq); - } -} - -static uint32_t omap_gpio_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - switch (offset) { - case 0x00: /* DATA_INPUT */ - return s->inputs & s->pins; - - case 0x04: /* DATA_OUTPUT */ - return s->outputs; - - case 0x08: /* DIRECTION_CONTROL */ - return s->dir; - - case 0x0c: /* INTERRUPT_CONTROL */ - return s->edge; - - case 0x10: /* INTERRUPT_MASK */ - return s->mask; - - case 0x14: /* INTERRUPT_STATUS */ - return s->ints; - - case 0x18: /* PIN_CONTROL (not in OMAP310) */ - OMAP_BAD_REG(addr); - return s->pins; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_gpio_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - uint16_t diff; - int ln; - - switch (offset) { - case 0x00: /* DATA_INPUT */ - OMAP_RO_REG(addr); - return; - - case 0x04: /* DATA_OUTPUT */ - diff = (s->outputs ^ value) & ~s->dir; - s->outputs = value; - while ((ln = ffs(diff))) { - ln --; - if (s->handler[ln]) - qemu_set_irq(s->handler[ln], (value >> ln) & 1); - diff &= ~(1 << ln); - } - break; - - case 0x08: /* DIRECTION_CONTROL */ - diff = s->outputs & (s->dir ^ value); - s->dir = value; - - value = s->outputs & ~s->dir; - while ((ln = ffs(diff))) { - ln --; - if (s->handler[ln]) - qemu_set_irq(s->handler[ln], (value >> ln) & 1); - diff &= ~(1 << ln); - } - break; - - case 0x0c: /* INTERRUPT_CONTROL */ - s->edge = value; - break; - - case 0x10: /* INTERRUPT_MASK */ - s->mask = value; - break; - - case 0x14: /* INTERRUPT_STATUS */ - s->ints &= ~value; - if (!s->ints) - qemu_irq_lower(s->irq); - break; - - case 0x18: /* PIN_CONTROL (not in OMAP310 TRM) */ - OMAP_BAD_REG(addr); - s->pins = value; - break; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -/* *Some* sources say the memory region is 32-bit. */ -static CPUReadMemoryFunc *omap_gpio_readfn[] = { - omap_badwidth_read16, - omap_gpio_read, - omap_badwidth_read16, -}; - -static CPUWriteMemoryFunc *omap_gpio_writefn[] = { - omap_badwidth_write16, - omap_gpio_write, - omap_badwidth_write16, -}; - -static void omap_gpio_reset(struct omap_gpio_s *s) -{ - s->inputs = 0; - s->outputs = ~0; - s->dir = ~0; - s->edge = ~0; - s->mask = ~0; - s->ints = 0; - s->pins = ~0; -} - -struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base, - qemu_irq irq, omap_clk clk) -{ - int iomemtype; - struct omap_gpio_s *s = (struct omap_gpio_s *) - qemu_mallocz(sizeof(struct omap_gpio_s)); - - s->base = base; - s->irq = irq; - s->in = qemu_allocate_irqs(omap_gpio_set, s, 16); - omap_gpio_reset(s); - - iomemtype = cpu_register_io_memory(0, omap_gpio_readfn, - omap_gpio_writefn, s); - cpu_register_physical_memory(s->base, 0x1000, iomemtype); - - return s; -} - -qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s) -{ - return s->in; -} - -void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler) -{ - if (line >= 16 || line < 0) - cpu_abort(cpu_single_env, "%s: No GPIO line %i\n", __FUNCTION__, line); - s->handler[line] = handler; -} - -/* MicroWire Interface */ -struct omap_uwire_s { - target_phys_addr_t base; - qemu_irq txirq; - qemu_irq rxirq; - qemu_irq txdrq; - - uint16_t txbuf; - uint16_t rxbuf; - uint16_t control; - uint16_t setup[5]; - - struct uwire_slave_s *chip[4]; -}; - -static void omap_uwire_transfer_start(struct omap_uwire_s *s) -{ - int chipselect = (s->control >> 10) & 3; /* INDEX */ - struct uwire_slave_s *slave = s->chip[chipselect]; - - if ((s->control >> 5) & 0x1f) { /* NB_BITS_WR */ - if (s->control & (1 << 12)) /* CS_CMD */ - if (slave && slave->send) - slave->send(slave->opaque, - s->txbuf >> (16 - ((s->control >> 5) & 0x1f))); - s->control &= ~(1 << 14); /* CSRB */ - /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or - * a DRQ. When is the level IRQ supposed to be reset? */ - } - - if ((s->control >> 0) & 0x1f) { /* NB_BITS_RD */ - if (s->control & (1 << 12)) /* CS_CMD */ - if (slave && slave->receive) - s->rxbuf = slave->receive(slave->opaque); - s->control |= 1 << 15; /* RDRB */ - /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or - * a DRQ. When is the level IRQ supposed to be reset? */ - } -} - -static uint32_t omap_uwire_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - switch (offset) { - case 0x00: /* RDR */ - s->control &= ~(1 << 15); /* RDRB */ - return s->rxbuf; - - case 0x04: /* CSR */ - return s->control; - - case 0x08: /* SR1 */ - return s->setup[0]; - case 0x0c: /* SR2 */ - return s->setup[1]; - case 0x10: /* SR3 */ - return s->setup[2]; - case 0x14: /* SR4 */ - return s->setup[3]; - case 0x18: /* SR5 */ - return s->setup[4]; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_uwire_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - switch (offset) { - case 0x00: /* TDR */ - s->txbuf = value; /* TD */ - if ((s->setup[4] & (1 << 2)) && /* AUTO_TX_EN */ - ((s->setup[4] & (1 << 3)) || /* CS_TOGGLE_TX_EN */ - (s->control & (1 << 12)))) { /* CS_CMD */ - s->control |= 1 << 14; /* CSRB */ - omap_uwire_transfer_start(s); - } - break; - - case 0x04: /* CSR */ - s->control = value & 0x1fff; - if (value & (1 << 13)) /* START */ - omap_uwire_transfer_start(s); - break; - - case 0x08: /* SR1 */ - s->setup[0] = value & 0x003f; - break; - - case 0x0c: /* SR2 */ - s->setup[1] = value & 0x0fc0; - break; - - case 0x10: /* SR3 */ - s->setup[2] = value & 0x0003; - break; - - case 0x14: /* SR4 */ - s->setup[3] = value & 0x0001; - break; - - case 0x18: /* SR5 */ - s->setup[4] = value & 0x000f; - break; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static CPUReadMemoryFunc *omap_uwire_readfn[] = { - omap_badwidth_read16, - omap_uwire_read, - omap_badwidth_read16, -}; - -static CPUWriteMemoryFunc *omap_uwire_writefn[] = { - omap_badwidth_write16, - omap_uwire_write, - omap_badwidth_write16, -}; - -static void omap_uwire_reset(struct omap_uwire_s *s) -{ - s->control = 0; - s->setup[0] = 0; - s->setup[1] = 0; - s->setup[2] = 0; - s->setup[3] = 0; - s->setup[4] = 0; -} - -struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base, - qemu_irq *irq, qemu_irq dma, omap_clk clk) -{ - int iomemtype; - struct omap_uwire_s *s = (struct omap_uwire_s *) - qemu_mallocz(sizeof(struct omap_uwire_s)); - - s->base = base; - s->txirq = irq[0]; - s->rxirq = irq[1]; - s->txdrq = dma; - omap_uwire_reset(s); - - iomemtype = cpu_register_io_memory(0, omap_uwire_readfn, - omap_uwire_writefn, s); - cpu_register_physical_memory(s->base, 0x800, iomemtype); - - return s; -} - -void omap_uwire_attach(struct omap_uwire_s *s, - struct uwire_slave_s *slave, int chipselect) -{ - if (chipselect < 0 || chipselect > 3) - cpu_abort(cpu_single_env, "%s: Bad chipselect %i\n", __FUNCTION__, - chipselect); - - s->chip[chipselect] = slave; -} - -/* Pseudonoise Pulse-Width Light Modulator */ -static void omap_pwl_update(struct omap_mpu_state_s *s) -{ - int output = (s->pwl.clk && s->pwl.enable) ? s->pwl.level : 0; - - if (output != s->pwl.output) { - s->pwl.output = output; - printf("%s: Backlight now at %i/256\n", __FUNCTION__, output); - } -} - -static uint32_t omap_pwl_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - switch (offset) { - case 0x00: /* PWL_LEVEL */ - return s->pwl.level; - case 0x04: /* PWL_CTRL */ - return s->pwl.enable; - } - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_pwl_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - switch (offset) { - case 0x00: /* PWL_LEVEL */ - s->pwl.level = value; - omap_pwl_update(s); - break; - case 0x04: /* PWL_CTRL */ - s->pwl.enable = value & 1; - omap_pwl_update(s); - break; - default: - OMAP_BAD_REG(addr); - return; - } -} - -static CPUReadMemoryFunc *omap_pwl_readfn[] = { - omap_pwl_read, - omap_badwidth_read8, - omap_badwidth_read8, -}; - -static CPUWriteMemoryFunc *omap_pwl_writefn[] = { - omap_pwl_write, - omap_badwidth_write8, - omap_badwidth_write8, -}; - -static void omap_pwl_reset(struct omap_mpu_state_s *s) -{ - s->pwl.output = 0; - s->pwl.level = 0; - s->pwl.enable = 0; - s->pwl.clk = 1; - omap_pwl_update(s); -} - -static void omap_pwl_clk_update(void *opaque, int line, int on) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - - s->pwl.clk = on; - omap_pwl_update(s); -} - -static void omap_pwl_init(target_phys_addr_t base, struct omap_mpu_state_s *s, - omap_clk clk) -{ - int iomemtype; - - omap_pwl_reset(s); - - iomemtype = cpu_register_io_memory(0, omap_pwl_readfn, - omap_pwl_writefn, s); - cpu_register_physical_memory(base, 0x800, iomemtype); - - omap_clk_adduser(clk, qemu_allocate_irqs(omap_pwl_clk_update, s, 1)[0]); -} - -/* Pulse-Width Tone module */ -static uint32_t omap_pwt_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - switch (offset) { - case 0x00: /* FRC */ - return s->pwt.frc; - case 0x04: /* VCR */ - return s->pwt.vrc; - case 0x08: /* GCR */ - return s->pwt.gcr; - } - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_pwt_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - switch (offset) { - case 0x00: /* FRC */ - s->pwt.frc = value & 0x3f; - break; - case 0x04: /* VRC */ - if ((value ^ s->pwt.vrc) & 1) { - if (value & 1) - printf("%s: %iHz buzz on\n", __FUNCTION__, (int) - /* 1.5 MHz from a 12-MHz or 13-MHz PWT_CLK */ - ((omap_clk_getrate(s->pwt.clk) >> 3) / - /* Pre-multiplexer divider */ - ((s->pwt.gcr & 2) ? 1 : 154) / - /* Octave multiplexer */ - (2 << (value & 3)) * - /* 101/107 divider */ - ((value & (1 << 2)) ? 101 : 107) * - /* 49/55 divider */ - ((value & (1 << 3)) ? 49 : 55) * - /* 50/63 divider */ - ((value & (1 << 4)) ? 50 : 63) * - /* 80/127 divider */ - ((value & (1 << 5)) ? 80 : 127) / - (107 * 55 * 63 * 127))); - else - printf("%s: silence!\n", __FUNCTION__); - } - s->pwt.vrc = value & 0x7f; - break; - case 0x08: /* GCR */ - s->pwt.gcr = value & 3; - break; - default: - OMAP_BAD_REG(addr); - return; - } -} - -static CPUReadMemoryFunc *omap_pwt_readfn[] = { - omap_pwt_read, - omap_badwidth_read8, - omap_badwidth_read8, -}; - -static CPUWriteMemoryFunc *omap_pwt_writefn[] = { - omap_pwt_write, - omap_badwidth_write8, - omap_badwidth_write8, -}; - -static void omap_pwt_reset(struct omap_mpu_state_s *s) -{ - s->pwt.frc = 0; - s->pwt.vrc = 0; - s->pwt.gcr = 0; -} - -static void omap_pwt_init(target_phys_addr_t base, struct omap_mpu_state_s *s, - omap_clk clk) -{ - int iomemtype; - - s->pwt.clk = clk; - omap_pwt_reset(s); - - iomemtype = cpu_register_io_memory(0, omap_pwt_readfn, - omap_pwt_writefn, s); - cpu_register_physical_memory(base, 0x800, iomemtype); -} - -/* Real-time Clock module */ -struct omap_rtc_s { - target_phys_addr_t base; - qemu_irq irq; - qemu_irq alarm; - QEMUTimer *clk; - - uint8_t interrupts; - uint8_t status; - int16_t comp_reg; - int running; - int pm_am; - int auto_comp; - int round; - struct tm *(*convert)(const time_t *timep, struct tm *result); - struct tm alarm_tm; - time_t alarm_ti; - - struct tm current_tm; - time_t ti; - uint64_t tick; -}; - -static void omap_rtc_interrupts_update(struct omap_rtc_s *s) -{ - /* s->alarm is level-triggered */ - qemu_set_irq(s->alarm, (s->status >> 6) & 1); -} - -static void omap_rtc_alarm_update(struct omap_rtc_s *s) -{ - s->alarm_ti = mktime(&s->alarm_tm); - if (s->alarm_ti == -1) - printf("%s: conversion failed\n", __FUNCTION__); -} - -static inline uint8_t omap_rtc_bcd(int num) -{ - return ((num / 10) << 4) | (num % 10); -} - -static inline int omap_rtc_bin(uint8_t num) -{ - return (num & 15) + 10 * (num >> 4); -} - -static uint32_t omap_rtc_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - uint8_t i; - - switch (offset) { - case 0x00: /* SECONDS_REG */ - return omap_rtc_bcd(s->current_tm.tm_sec); - - case 0x04: /* MINUTES_REG */ - return omap_rtc_bcd(s->current_tm.tm_min); - - case 0x08: /* HOURS_REG */ - if (s->pm_am) - return ((s->current_tm.tm_hour > 11) << 7) | - omap_rtc_bcd(((s->current_tm.tm_hour - 1) % 12) + 1); - else - return omap_rtc_bcd(s->current_tm.tm_hour); - - case 0x0c: /* DAYS_REG */ - return omap_rtc_bcd(s->current_tm.tm_mday); - - case 0x10: /* MONTHS_REG */ - return omap_rtc_bcd(s->current_tm.tm_mon + 1); - - case 0x14: /* YEARS_REG */ - return omap_rtc_bcd(s->current_tm.tm_year % 100); - - case 0x18: /* WEEK_REG */ - return s->current_tm.tm_wday; - - case 0x20: /* ALARM_SECONDS_REG */ - return omap_rtc_bcd(s->alarm_tm.tm_sec); - - case 0x24: /* ALARM_MINUTES_REG */ - return omap_rtc_bcd(s->alarm_tm.tm_min); - - case 0x28: /* ALARM_HOURS_REG */ - if (s->pm_am) - return ((s->alarm_tm.tm_hour > 11) << 7) | - omap_rtc_bcd(((s->alarm_tm.tm_hour - 1) % 12) + 1); - else - return omap_rtc_bcd(s->alarm_tm.tm_hour); - - case 0x2c: /* ALARM_DAYS_REG */ - return omap_rtc_bcd(s->alarm_tm.tm_mday); - - case 0x30: /* ALARM_MONTHS_REG */ - return omap_rtc_bcd(s->alarm_tm.tm_mon + 1); - - case 0x34: /* ALARM_YEARS_REG */ - return omap_rtc_bcd(s->alarm_tm.tm_year % 100); - - case 0x40: /* RTC_CTRL_REG */ - return (s->pm_am << 3) | (s->auto_comp << 2) | - (s->round << 1) | s->running; - - case 0x44: /* RTC_STATUS_REG */ - i = s->status; - s->status &= ~0x3d; - return i; - - case 0x48: /* RTC_INTERRUPTS_REG */ - return s->interrupts; - - case 0x4c: /* RTC_COMP_LSB_REG */ - return ((uint16_t) s->comp_reg) & 0xff; - - case 0x50: /* RTC_COMP_MSB_REG */ - return ((uint16_t) s->comp_reg) >> 8; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_rtc_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - struct tm new_tm; - time_t ti[2]; - - switch (offset) { - case 0x00: /* SECONDS_REG */ -#if ALMDEBUG - printf("RTC SEC_REG <-- %02x\n", value); -#endif - s->ti -= s->current_tm.tm_sec; - s->ti += omap_rtc_bin(value); - return; - - case 0x04: /* MINUTES_REG */ -#if ALMDEBUG - printf("RTC MIN_REG <-- %02x\n", value); -#endif - s->ti -= s->current_tm.tm_min * 60; - s->ti += omap_rtc_bin(value) * 60; - return; - - case 0x08: /* HOURS_REG */ -#if ALMDEBUG - printf("RTC HRS_REG <-- %02x\n", value); -#endif - s->ti -= s->current_tm.tm_hour * 3600; - if (s->pm_am) { - s->ti += (omap_rtc_bin(value & 0x3f) & 12) * 3600; - s->ti += ((value >> 7) & 1) * 43200; - } else - s->ti += omap_rtc_bin(value & 0x3f) * 3600; - return; - - case 0x0c: /* DAYS_REG */ -#if ALMDEBUG - printf("RTC DAY_REG <-- %02x\n", value); -#endif - s->ti -= s->current_tm.tm_mday * 86400; - s->ti += omap_rtc_bin(value) * 86400; - return; - - case 0x10: /* MONTHS_REG */ -#if ALMDEBUG - printf("RTC MTH_REG <-- %02x\n", value); -#endif - memcpy(&new_tm, &s->current_tm, sizeof(new_tm)); - new_tm.tm_mon = omap_rtc_bin(value); - ti[0] = mktime(&s->current_tm); - ti[1] = mktime(&new_tm); - - if (ti[0] != -1 && ti[1] != -1) { - s->ti -= ti[0]; - s->ti += ti[1]; - } else { - /* A less accurate version */ - s->ti -= s->current_tm.tm_mon * 2592000; - s->ti += omap_rtc_bin(value) * 2592000; - } - return; - - case 0x14: /* YEARS_REG */ -#if ALMDEBUG - printf("RTC YRS_REG <-- %02x\n", value); -#endif - memcpy(&new_tm, &s->current_tm, sizeof(new_tm)); - new_tm.tm_year += omap_rtc_bin(value) - (new_tm.tm_year % 100); - ti[0] = mktime(&s->current_tm); - ti[1] = mktime(&new_tm); - - if (ti[0] != -1 && ti[1] != -1) { - s->ti -= ti[0]; - s->ti += ti[1]; - } else { - /* A less accurate version */ - s->ti -= (s->current_tm.tm_year % 100) * 31536000; - s->ti += omap_rtc_bin(value) * 31536000; - } - return; - - case 0x18: /* WEEK_REG */ - return; /* Ignored */ - - case 0x20: /* ALARM_SECONDS_REG */ -#if ALMDEBUG - printf("ALM SEC_REG <-- %02x\n", value); -#endif - s->alarm_tm.tm_sec = omap_rtc_bin(value); - omap_rtc_alarm_update(s); - return; - - case 0x24: /* ALARM_MINUTES_REG */ -#if ALMDEBUG - printf("ALM MIN_REG <-- %02x\n", value); -#endif - s->alarm_tm.tm_min = omap_rtc_bin(value); - omap_rtc_alarm_update(s); - return; - - case 0x28: /* ALARM_HOURS_REG */ -#if ALMDEBUG - printf("ALM HRS_REG <-- %02x\n", value); -#endif - if (s->pm_am) - s->alarm_tm.tm_hour = - ((omap_rtc_bin(value & 0x3f)) % 12) + - ((value >> 7) & 1) * 12; - else - s->alarm_tm.tm_hour = omap_rtc_bin(value); - omap_rtc_alarm_update(s); - return; - - case 0x2c: /* ALARM_DAYS_REG */ -#if ALMDEBUG - printf("ALM DAY_REG <-- %02x\n", value); -#endif - s->alarm_tm.tm_mday = omap_rtc_bin(value); - omap_rtc_alarm_update(s); - return; - - case 0x30: /* ALARM_MONTHS_REG */ -#if ALMDEBUG - printf("ALM MON_REG <-- %02x\n", value); -#endif - s->alarm_tm.tm_mon = omap_rtc_bin(value); - omap_rtc_alarm_update(s); - return; - - case 0x34: /* ALARM_YEARS_REG */ -#if ALMDEBUG - printf("ALM YRS_REG <-- %02x\n", value); -#endif - s->alarm_tm.tm_year = omap_rtc_bin(value); - omap_rtc_alarm_update(s); - return; - - case 0x40: /* RTC_CTRL_REG */ -#if ALMDEBUG - printf("RTC CONTROL <-- %02x\n", value); -#endif - s->pm_am = (value >> 3) & 1; - s->auto_comp = (value >> 2) & 1; - s->round = (value >> 1) & 1; - s->running = value & 1; - s->status &= 0xfd; - s->status |= s->running << 1; - return; - - case 0x44: /* RTC_STATUS_REG */ -#if ALMDEBUG - printf("RTC STATUSL <-- %02x\n", value); -#endif - s->status &= ~((value & 0xc0) ^ 0x80); - omap_rtc_interrupts_update(s); - return; - - case 0x48: /* RTC_INTERRUPTS_REG */ -#if ALMDEBUG - printf("RTC INTRS <-- %02x\n", value); -#endif - s->interrupts = value; - return; - - case 0x4c: /* RTC_COMP_LSB_REG */ -#if ALMDEBUG - printf("RTC COMPLSB <-- %02x\n", value); -#endif - s->comp_reg &= 0xff00; - s->comp_reg |= 0x00ff & value; - return; - - case 0x50: /* RTC_COMP_MSB_REG */ -#if ALMDEBUG - printf("RTC COMPMSB <-- %02x\n", value); -#endif - s->comp_reg &= 0x00ff; - s->comp_reg |= 0xff00 & (value << 8); - return; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static CPUReadMemoryFunc *omap_rtc_readfn[] = { - omap_rtc_read, - omap_badwidth_read8, - omap_badwidth_read8, -}; - -static CPUWriteMemoryFunc *omap_rtc_writefn[] = { - omap_rtc_write, - omap_badwidth_write8, - omap_badwidth_write8, -}; - -static void omap_rtc_tick(void *opaque) -{ - struct omap_rtc_s *s = opaque; - - if (s->round) { - /* Round to nearest full minute. */ - if (s->current_tm.tm_sec < 30) - s->ti -= s->current_tm.tm_sec; - else - s->ti += 60 - s->current_tm.tm_sec; - - s->round = 0; - } - - localtime_r(&s->ti, &s->current_tm); - - if ((s->interrupts & 0x08) && s->ti == s->alarm_ti) { - s->status |= 0x40; - omap_rtc_interrupts_update(s); - } - - if (s->interrupts & 0x04) - switch (s->interrupts & 3) { - case 0: - s->status |= 0x04; - qemu_irq_pulse(s->irq); - break; - case 1: - if (s->current_tm.tm_sec) - break; - s->status |= 0x08; - qemu_irq_pulse(s->irq); - break; - case 2: - if (s->current_tm.tm_sec || s->current_tm.tm_min) - break; - s->status |= 0x10; - qemu_irq_pulse(s->irq); - break; - case 3: - if (s->current_tm.tm_sec || - s->current_tm.tm_min || s->current_tm.tm_hour) - break; - s->status |= 0x20; - qemu_irq_pulse(s->irq); - break; - } - - /* Move on */ - if (s->running) - s->ti ++; - s->tick += 1000; - - /* - * Every full hour add a rough approximation of the compensation - * register to the 32kHz Timer (which drives the RTC) value. - */ - if (s->auto_comp && !s->current_tm.tm_sec && !s->current_tm.tm_min) - s->tick += s->comp_reg * 1000 / 32768; - - qemu_mod_timer(s->clk, s->tick); -} - -static void omap_rtc_reset(struct omap_rtc_s *s) -{ - s->interrupts = 0; - s->comp_reg = 0; - s->running = 0; - s->pm_am = 0; - s->auto_comp = 0; - s->round = 0; - s->tick = qemu_get_clock(rt_clock); - memset(&s->alarm_tm, 0, sizeof(s->alarm_tm)); - s->alarm_tm.tm_mday = 0x01; - s->status = 1 << 7; - time(&s->ti); - s->ti = mktime(s->convert(&s->ti, &s->current_tm)); - - omap_rtc_alarm_update(s); - omap_rtc_tick(s); -} - -struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, - qemu_irq *irq, omap_clk clk) -{ - int iomemtype; - struct omap_rtc_s *s = (struct omap_rtc_s *) - qemu_mallocz(sizeof(struct omap_rtc_s)); - - s->base = base; - s->irq = irq[0]; - s->alarm = irq[1]; - s->clk = qemu_new_timer(rt_clock, omap_rtc_tick, s); - s->convert = rtc_utc ? gmtime_r : localtime_r; - - omap_rtc_reset(s); - - iomemtype = cpu_register_io_memory(0, omap_rtc_readfn, - omap_rtc_writefn, s); - cpu_register_physical_memory(s->base, 0x800, iomemtype); - - return s; -} - -/* Multi-channel Buffered Serial Port interfaces */ -struct omap_mcbsp_s { - target_phys_addr_t base; - qemu_irq txirq; - qemu_irq rxirq; - qemu_irq txdrq; - qemu_irq rxdrq; - - uint16_t spcr[2]; - uint16_t rcr[2]; - uint16_t xcr[2]; - uint16_t srgr[2]; - uint16_t mcr[2]; - uint16_t pcr; - uint16_t rcer[8]; - uint16_t xcer[8]; - int tx_rate; - int rx_rate; - int tx_req; - int rx_req; - - struct i2s_codec_s *codec; - QEMUTimer *source_timer; - QEMUTimer *sink_timer; -}; - -static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) -{ - int irq; - - switch ((s->spcr[0] >> 4) & 3) { /* RINTM */ - case 0: - irq = (s->spcr[0] >> 1) & 1; /* RRDY */ - break; - case 3: - irq = (s->spcr[0] >> 3) & 1; /* RSYNCERR */ - break; - default: - irq = 0; - break; - } - - if (irq) - qemu_irq_pulse(s->rxirq); - - switch ((s->spcr[1] >> 4) & 3) { /* XINTM */ - case 0: - irq = (s->spcr[1] >> 1) & 1; /* XRDY */ - break; - case 3: - irq = (s->spcr[1] >> 3) & 1; /* XSYNCERR */ - break; - default: - irq = 0; - break; - } - - if (irq) - qemu_irq_pulse(s->txirq); -} - -static void omap_mcbsp_rx_newdata(struct omap_mcbsp_s *s) -{ - if ((s->spcr[0] >> 1) & 1) /* RRDY */ - s->spcr[0] |= 1 << 2; /* RFULL */ - s->spcr[0] |= 1 << 1; /* RRDY */ - qemu_irq_raise(s->rxdrq); - omap_mcbsp_intr_update(s); -} - -static void omap_mcbsp_source_tick(void *opaque) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 }; - - if (!s->rx_rate) - return; - if (s->rx_req) - printf("%s: Rx FIFO overrun\n", __FUNCTION__); - - s->rx_req = s->rx_rate << bps[(s->rcr[0] >> 5) & 7]; - - omap_mcbsp_rx_newdata(s); - qemu_mod_timer(s->source_timer, qemu_get_clock(vm_clock) + ticks_per_sec); -} - -static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s) -{ - if (!s->codec || !s->codec->rts) - omap_mcbsp_source_tick(s); - else if (s->codec->in.len) { - s->rx_req = s->codec->in.len; - omap_mcbsp_rx_newdata(s); - } -} - -static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s) -{ - qemu_del_timer(s->source_timer); -} - -static void omap_mcbsp_rx_done(struct omap_mcbsp_s *s) -{ - s->spcr[0] &= ~(1 << 1); /* RRDY */ - qemu_irq_lower(s->rxdrq); - omap_mcbsp_intr_update(s); -} - -static void omap_mcbsp_tx_newdata(struct omap_mcbsp_s *s) -{ - s->spcr[1] |= 1 << 1; /* XRDY */ - qemu_irq_raise(s->txdrq); - omap_mcbsp_intr_update(s); -} - -static void omap_mcbsp_sink_tick(void *opaque) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 }; - - if (!s->tx_rate) - return; - if (s->tx_req) - printf("%s: Tx FIFO underrun\n", __FUNCTION__); - - s->tx_req = s->tx_rate << bps[(s->xcr[0] >> 5) & 7]; - - omap_mcbsp_tx_newdata(s); - qemu_mod_timer(s->sink_timer, qemu_get_clock(vm_clock) + ticks_per_sec); -} - -static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s) -{ - if (!s->codec || !s->codec->cts) - omap_mcbsp_sink_tick(s); - else if (s->codec->out.size) { - s->tx_req = s->codec->out.size; - omap_mcbsp_tx_newdata(s); - } -} - -static void omap_mcbsp_tx_done(struct omap_mcbsp_s *s) -{ - s->spcr[1] &= ~(1 << 1); /* XRDY */ - qemu_irq_lower(s->txdrq); - omap_mcbsp_intr_update(s); - if (s->codec && s->codec->cts) - s->codec->tx_swallow(s->codec->opaque); -} - -static void omap_mcbsp_tx_stop(struct omap_mcbsp_s *s) -{ - s->tx_req = 0; - omap_mcbsp_tx_done(s); - qemu_del_timer(s->sink_timer); -} - -static void omap_mcbsp_req_update(struct omap_mcbsp_s *s) -{ - int prev_rx_rate, prev_tx_rate; - int rx_rate = 0, tx_rate = 0; - int cpu_rate = 1500000; /* XXX */ - - /* TODO: check CLKSTP bit */ - if (s->spcr[1] & (1 << 6)) { /* GRST */ - if (s->spcr[0] & (1 << 0)) { /* RRST */ - if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ - (s->pcr & (1 << 8))) { /* CLKRM */ - if (~s->pcr & (1 << 7)) /* SCLKME */ - rx_rate = cpu_rate / - ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ - } else - if (s->codec) - rx_rate = s->codec->rx_rate; - } - - if (s->spcr[1] & (1 << 0)) { /* XRST */ - if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ - (s->pcr & (1 << 9))) { /* CLKXM */ - if (~s->pcr & (1 << 7)) /* SCLKME */ - tx_rate = cpu_rate / - ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ - } else - if (s->codec) - tx_rate = s->codec->tx_rate; - } - } - prev_tx_rate = s->tx_rate; - prev_rx_rate = s->rx_rate; - s->tx_rate = tx_rate; - s->rx_rate = rx_rate; - - if (s->codec) - s->codec->set_rate(s->codec->opaque, rx_rate, tx_rate); - - if (!prev_tx_rate && tx_rate) - omap_mcbsp_tx_start(s); - else if (s->tx_rate && !tx_rate) - omap_mcbsp_tx_stop(s); - - if (!prev_rx_rate && rx_rate) - omap_mcbsp_rx_start(s); - else if (prev_tx_rate && !tx_rate) - omap_mcbsp_rx_stop(s); -} - -static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - uint16_t ret; - - switch (offset) { - case 0x00: /* DRR2 */ - if (((s->rcr[0] >> 5) & 7) < 3) /* RWDLEN1 */ - return 0x0000; - /* Fall through. */ - case 0x02: /* DRR1 */ - if (s->rx_req < 2) { - printf("%s: Rx FIFO underrun\n", __FUNCTION__); - omap_mcbsp_rx_done(s); - } else { - s->tx_req -= 2; - if (s->codec && s->codec->in.len >= 2) { - ret = s->codec->in.fifo[s->codec->in.start ++] << 8; - ret |= s->codec->in.fifo[s->codec->in.start ++]; - s->codec->in.len -= 2; - } else - ret = 0x0000; - if (!s->tx_req) - omap_mcbsp_rx_done(s); - return ret; - } - return 0x0000; - - case 0x04: /* DXR2 */ - case 0x06: /* DXR1 */ - return 0x0000; - - case 0x08: /* SPCR2 */ - return s->spcr[1]; - case 0x0a: /* SPCR1 */ - return s->spcr[0]; - case 0x0c: /* RCR2 */ - return s->rcr[1]; - case 0x0e: /* RCR1 */ - return s->rcr[0]; - case 0x10: /* XCR2 */ - return s->xcr[1]; - case 0x12: /* XCR1 */ - return s->xcr[0]; - case 0x14: /* SRGR2 */ - return s->srgr[1]; - case 0x16: /* SRGR1 */ - return s->srgr[0]; - case 0x18: /* MCR2 */ - return s->mcr[1]; - case 0x1a: /* MCR1 */ - return s->mcr[0]; - case 0x1c: /* RCERA */ - return s->rcer[0]; - case 0x1e: /* RCERB */ - return s->rcer[1]; - case 0x20: /* XCERA */ - return s->xcer[0]; - case 0x22: /* XCERB */ - return s->xcer[1]; - case 0x24: /* PCR0 */ - return s->pcr; - case 0x26: /* RCERC */ - return s->rcer[2]; - case 0x28: /* RCERD */ - return s->rcer[3]; - case 0x2a: /* XCERC */ - return s->xcer[2]; - case 0x2c: /* XCERD */ - return s->xcer[3]; - case 0x2e: /* RCERE */ - return s->rcer[4]; - case 0x30: /* RCERF */ - return s->rcer[5]; - case 0x32: /* XCERE */ - return s->xcer[4]; - case 0x34: /* XCERF */ - return s->xcer[5]; - case 0x36: /* RCERG */ - return s->rcer[6]; - case 0x38: /* RCERH */ - return s->rcer[7]; - case 0x3a: /* XCERG */ - return s->xcer[6]; - case 0x3c: /* XCERH */ - return s->xcer[7]; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_mcbsp_writeh(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - switch (offset) { - case 0x00: /* DRR2 */ - case 0x02: /* DRR1 */ - OMAP_RO_REG(addr); - return; - - case 0x04: /* DXR2 */ - if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ - return; - /* Fall through. */ - case 0x06: /* DXR1 */ - if (s->tx_req > 1) { - s->tx_req -= 2; - if (s->codec && s->codec->cts) { - s->codec->out.fifo[s->codec->out.len ++] = (value >> 8) & 0xff; - s->codec->out.fifo[s->codec->out.len ++] = (value >> 0) & 0xff; - } - if (s->tx_req < 2) - omap_mcbsp_tx_done(s); - } else - printf("%s: Tx FIFO overrun\n", __FUNCTION__); - return; - - case 0x08: /* SPCR2 */ - s->spcr[1] &= 0x0002; - s->spcr[1] |= 0x03f9 & value; - s->spcr[1] |= 0x0004 & (value << 2); /* XEMPTY := XRST */ - if (~value & 1) /* XRST */ - s->spcr[1] &= ~6; - omap_mcbsp_req_update(s); - return; - case 0x0a: /* SPCR1 */ - s->spcr[0] &= 0x0006; - s->spcr[0] |= 0xf8f9 & value; - if (value & (1 << 15)) /* DLB */ - printf("%s: Digital Loopback mode enable attempt\n", __FUNCTION__); - if (~value & 1) { /* RRST */ - s->spcr[0] &= ~6; - s->rx_req = 0; - omap_mcbsp_rx_done(s); - } - omap_mcbsp_req_update(s); - return; - - case 0x0c: /* RCR2 */ - s->rcr[1] = value & 0xffff; - return; - case 0x0e: /* RCR1 */ - s->rcr[0] = value & 0x7fe0; - return; - case 0x10: /* XCR2 */ - s->xcr[1] = value & 0xffff; - return; - case 0x12: /* XCR1 */ - s->xcr[0] = value & 0x7fe0; - return; - case 0x14: /* SRGR2 */ - s->srgr[1] = value & 0xffff; - omap_mcbsp_req_update(s); - return; - case 0x16: /* SRGR1 */ - s->srgr[0] = value & 0xffff; - omap_mcbsp_req_update(s); - return; - case 0x18: /* MCR2 */ - s->mcr[1] = value & 0x03e3; - if (value & 3) /* XMCM */ - printf("%s: Tx channel selection mode enable attempt\n", - __FUNCTION__); - return; - case 0x1a: /* MCR1 */ - s->mcr[0] = value & 0x03e1; - if (value & 1) /* RMCM */ - printf("%s: Rx channel selection mode enable attempt\n", - __FUNCTION__); - return; - case 0x1c: /* RCERA */ - s->rcer[0] = value & 0xffff; - return; - case 0x1e: /* RCERB */ - s->rcer[1] = value & 0xffff; - return; - case 0x20: /* XCERA */ - s->xcer[0] = value & 0xffff; - return; - case 0x22: /* XCERB */ - s->xcer[1] = value & 0xffff; - return; - case 0x24: /* PCR0 */ - s->pcr = value & 0x7faf; - return; - case 0x26: /* RCERC */ - s->rcer[2] = value & 0xffff; - return; - case 0x28: /* RCERD */ - s->rcer[3] = value & 0xffff; - return; - case 0x2a: /* XCERC */ - s->xcer[2] = value & 0xffff; - return; - case 0x2c: /* XCERD */ - s->xcer[3] = value & 0xffff; - return; - case 0x2e: /* RCERE */ - s->rcer[4] = value & 0xffff; - return; - case 0x30: /* RCERF */ - s->rcer[5] = value & 0xffff; - return; - case 0x32: /* XCERE */ - s->xcer[4] = value & 0xffff; - return; - case 0x34: /* XCERF */ - s->xcer[5] = value & 0xffff; - return; - case 0x36: /* RCERG */ - s->rcer[6] = value & 0xffff; - return; - case 0x38: /* RCERH */ - s->rcer[7] = value & 0xffff; - return; - case 0x3a: /* XCERG */ - s->xcer[6] = value & 0xffff; - return; - case 0x3c: /* XCERH */ - s->xcer[7] = value & 0xffff; - return; - } - - OMAP_BAD_REG(addr); -} - -static void omap_mcbsp_writew(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (offset == 0x04) { /* DXR */ - if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ - return; - if (s->tx_req > 3) { - s->tx_req -= 4; - if (s->codec && s->codec->cts) { - s->codec->out.fifo[s->codec->out.len ++] = - (value >> 24) & 0xff; - s->codec->out.fifo[s->codec->out.len ++] = - (value >> 16) & 0xff; - s->codec->out.fifo[s->codec->out.len ++] = - (value >> 8) & 0xff; - s->codec->out.fifo[s->codec->out.len ++] = - (value >> 0) & 0xff; - } - if (s->tx_req < 4) - omap_mcbsp_tx_done(s); - } else - printf("%s: Tx FIFO overrun\n", __FUNCTION__); - return; - } - - omap_badwidth_write16(opaque, addr, value); -} - -static CPUReadMemoryFunc *omap_mcbsp_readfn[] = { - omap_badwidth_read16, - omap_mcbsp_read, - omap_badwidth_read16, -}; - -static CPUWriteMemoryFunc *omap_mcbsp_writefn[] = { - omap_badwidth_write16, - omap_mcbsp_writeh, - omap_mcbsp_writew, -}; - -static void omap_mcbsp_reset(struct omap_mcbsp_s *s) -{ - memset(&s->spcr, 0, sizeof(s->spcr)); - memset(&s->rcr, 0, sizeof(s->rcr)); - memset(&s->xcr, 0, sizeof(s->xcr)); - s->srgr[0] = 0x0001; - s->srgr[1] = 0x2000; - memset(&s->mcr, 0, sizeof(s->mcr)); - memset(&s->pcr, 0, sizeof(s->pcr)); - memset(&s->rcer, 0, sizeof(s->rcer)); - memset(&s->xcer, 0, sizeof(s->xcer)); - s->tx_req = 0; - s->rx_req = 0; - s->tx_rate = 0; - s->rx_rate = 0; - qemu_del_timer(s->source_timer); - qemu_del_timer(s->sink_timer); -} - -struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, - qemu_irq *irq, qemu_irq *dma, omap_clk clk) -{ - int iomemtype; - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) - qemu_mallocz(sizeof(struct omap_mcbsp_s)); - - s->base = base; - s->txirq = irq[0]; - s->rxirq = irq[1]; - s->txdrq = dma[0]; - s->rxdrq = dma[1]; - s->sink_timer = qemu_new_timer(vm_clock, omap_mcbsp_sink_tick, s); - s->source_timer = qemu_new_timer(vm_clock, omap_mcbsp_source_tick, s); - omap_mcbsp_reset(s); - - iomemtype = cpu_register_io_memory(0, omap_mcbsp_readfn, - omap_mcbsp_writefn, s); - cpu_register_physical_memory(s->base, 0x800, iomemtype); - - return s; -} - -static void omap_mcbsp_i2s_swallow(void *opaque, int line, int level) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - - if (s->rx_rate) { - s->rx_req = s->codec->in.len; - omap_mcbsp_rx_newdata(s); - } -} - -static void omap_mcbsp_i2s_start(void *opaque, int line, int level) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - - if (s->tx_rate) { - s->tx_req = s->codec->out.size; - omap_mcbsp_tx_newdata(s); - } -} - -void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave) -{ - s->codec = slave; - slave->rx_swallow = qemu_allocate_irqs(omap_mcbsp_i2s_swallow, s, 1)[0]; - slave->tx_start = qemu_allocate_irqs(omap_mcbsp_i2s_start, s, 1)[0]; -} - -/* LED Pulse Generators */ -struct omap_lpg_s { - target_phys_addr_t base; - QEMUTimer *tm; - - uint8_t control; - uint8_t power; - int64_t on; - int64_t period; - int clk; - int cycle; -}; - -static void omap_lpg_tick(void *opaque) -{ - struct omap_lpg_s *s = opaque; - - if (s->cycle) - qemu_mod_timer(s->tm, qemu_get_clock(rt_clock) + s->period - s->on); - else - qemu_mod_timer(s->tm, qemu_get_clock(rt_clock) + s->on); - - s->cycle = !s->cycle; - printf("%s: LED is %s\n", __FUNCTION__, s->cycle ? "on" : "off"); -} - -static void omap_lpg_update(struct omap_lpg_s *s) -{ - int64_t on, period = 1, ticks = 1000; - static const int per[8] = { 1, 2, 4, 8, 12, 16, 20, 24 }; - - if (~s->control & (1 << 6)) /* LPGRES */ - on = 0; - else if (s->control & (1 << 7)) /* PERM_ON */ - on = period; - else { - period = muldiv64(ticks, per[s->control & 7], /* PERCTRL */ - 256 / 32); - on = (s->clk && s->power) ? muldiv64(ticks, - per[(s->control >> 3) & 7], 256) : 0; /* ONCTRL */ - } - - qemu_del_timer(s->tm); - if (on == period && s->on < s->period) - printf("%s: LED is on\n", __FUNCTION__); - else if (on == 0 && s->on) - printf("%s: LED is off\n", __FUNCTION__); - else if (on && (on != s->on || period != s->period)) { - s->cycle = 0; - s->on = on; - s->period = period; - omap_lpg_tick(s); - return; - } - - s->on = on; - s->period = period; -} - -static void omap_lpg_reset(struct omap_lpg_s *s) -{ - s->control = 0x00; - s->power = 0x00; - s->clk = 1; - omap_lpg_update(s); -} - -static uint32_t omap_lpg_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - switch (offset) { - case 0x00: /* LCR */ - return s->control; - - case 0x04: /* PMR */ - return s->power; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_lpg_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - switch (offset) { - case 0x00: /* LCR */ - if (~value & (1 << 6)) /* LPGRES */ - omap_lpg_reset(s); - s->control = value & 0xff; - omap_lpg_update(s); - return; - - case 0x04: /* PMR */ - s->power = value & 0x01; - omap_lpg_update(s); - return; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static CPUReadMemoryFunc *omap_lpg_readfn[] = { - omap_lpg_read, - omap_badwidth_read8, - omap_badwidth_read8, -}; - -static CPUWriteMemoryFunc *omap_lpg_writefn[] = { - omap_lpg_write, - omap_badwidth_write8, - omap_badwidth_write8, -}; - -static void omap_lpg_clk_update(void *opaque, int line, int on) -{ - struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; - - s->clk = on; - omap_lpg_update(s); -} - -struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk) -{ - int iomemtype; - struct omap_lpg_s *s = (struct omap_lpg_s *) - qemu_mallocz(sizeof(struct omap_lpg_s)); - - s->base = base; - s->tm = qemu_new_timer(rt_clock, omap_lpg_tick, s); - - omap_lpg_reset(s); - - iomemtype = cpu_register_io_memory(0, omap_lpg_readfn, - omap_lpg_writefn, s); - cpu_register_physical_memory(s->base, 0x800, iomemtype); - - omap_clk_adduser(clk, qemu_allocate_irqs(omap_lpg_clk_update, s, 1)[0]); - - return s; -} - -/* MPUI Peripheral Bridge configuration */ -static uint32_t omap_mpui_io_read(void *opaque, target_phys_addr_t addr) -{ - if (addr == OMAP_MPUI_BASE) /* CMR */ - return 0xfe4d; - - OMAP_BAD_REG(addr); - return 0; -} - -static CPUReadMemoryFunc *omap_mpui_io_readfn[] = { - omap_badwidth_read16, - omap_mpui_io_read, - omap_badwidth_read16, -}; - -static CPUWriteMemoryFunc *omap_mpui_io_writefn[] = { - omap_badwidth_write16, - omap_badwidth_write16, - omap_badwidth_write16, -}; - -static void omap_setup_mpui_io(struct omap_mpu_state_s *mpu) -{ - int iomemtype = cpu_register_io_memory(0, omap_mpui_io_readfn, - omap_mpui_io_writefn, mpu); - cpu_register_physical_memory(OMAP_MPUI_BASE, 0x7fff, iomemtype); -} - -/* General chip reset */ -static void omap_mpu_reset(void *opaque) -{ - struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; - - omap_inth_reset(mpu->ih[0]); - omap_inth_reset(mpu->ih[1]); - omap_dma_reset(mpu->dma); - omap_mpu_timer_reset(mpu->timer[0]); - omap_mpu_timer_reset(mpu->timer[1]); - omap_mpu_timer_reset(mpu->timer[2]); - omap_wd_timer_reset(mpu->wdt); - omap_os_timer_reset(mpu->os_timer); - omap_lcdc_reset(mpu->lcd); - omap_ulpd_pm_reset(mpu); - omap_pin_cfg_reset(mpu); - omap_mpui_reset(mpu); - omap_tipb_bridge_reset(mpu->private_tipb); - omap_tipb_bridge_reset(mpu->public_tipb); - omap_dpll_reset(&mpu->dpll[0]); - omap_dpll_reset(&mpu->dpll[1]); - omap_dpll_reset(&mpu->dpll[2]); - omap_uart_reset(mpu->uart[0]); - omap_uart_reset(mpu->uart[1]); - omap_uart_reset(mpu->uart[2]); - omap_mmc_reset(mpu->mmc); - omap_mpuio_reset(mpu->mpuio); - omap_gpio_reset(mpu->gpio); - omap_uwire_reset(mpu->microwire); - omap_pwl_reset(mpu); - omap_pwt_reset(mpu); - omap_i2c_reset(mpu->i2c); - omap_rtc_reset(mpu->rtc); - omap_mcbsp_reset(mpu->mcbsp1); - omap_mcbsp_reset(mpu->mcbsp2); - omap_mcbsp_reset(mpu->mcbsp3); - omap_lpg_reset(mpu->led[0]); - omap_lpg_reset(mpu->led[1]); - omap_clkm_reset(mpu); - cpu_reset(mpu->env); -} - -static const struct omap_map_s { - target_phys_addr_t phys_dsp; - target_phys_addr_t phys_mpu; - uint32_t size; - const char *name; -} omap15xx_dsp_mm[] = { - /* Strobe 0 */ - { 0xe1010000, 0xfffb0000, 0x800, "UART1 BT" }, /* CS0 */ - { 0xe1010800, 0xfffb0800, 0x800, "UART2 COM" }, /* CS1 */ - { 0xe1011800, 0xfffb1800, 0x800, "McBSP1 audio" }, /* CS3 */ - { 0xe1012000, 0xfffb2000, 0x800, "MCSI2 communication" }, /* CS4 */ - { 0xe1012800, 0xfffb2800, 0x800, "MCSI1 BT u-Law" }, /* CS5 */ - { 0xe1013000, 0xfffb3000, 0x800, "uWire" }, /* CS6 */ - { 0xe1013800, 0xfffb3800, 0x800, "I^2C" }, /* CS7 */ - { 0xe1014000, 0xfffb4000, 0x800, "USB W2FC" }, /* CS8 */ - { 0xe1014800, 0xfffb4800, 0x800, "RTC" }, /* CS9 */ - { 0xe1015000, 0xfffb5000, 0x800, "MPUIO" }, /* CS10 */ - { 0xe1015800, 0xfffb5800, 0x800, "PWL" }, /* CS11 */ - { 0xe1016000, 0xfffb6000, 0x800, "PWT" }, /* CS12 */ - { 0xe1017000, 0xfffb7000, 0x800, "McBSP3" }, /* CS14 */ - { 0xe1017800, 0xfffb7800, 0x800, "MMC" }, /* CS15 */ - { 0xe1019000, 0xfffb9000, 0x800, "32-kHz timer" }, /* CS18 */ - { 0xe1019800, 0xfffb9800, 0x800, "UART3" }, /* CS19 */ - { 0xe101c800, 0xfffbc800, 0x800, "TIPB switches" }, /* CS25 */ - /* Strobe 1 */ - { 0xe101e000, 0xfffce000, 0x800, "GPIOs" }, /* CS28 */ - - { 0 } -}; - -static void omap_setup_dsp_mapping(const struct omap_map_s *map) -{ - int io; - - for (; map->phys_dsp; map ++) { - io = cpu_get_physical_page_desc(map->phys_mpu); - - cpu_register_physical_memory(map->phys_dsp, map->size, io); - } -} - -static void omap_mpu_wakeup(void *opaque, int irq, int req) -{ - struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; - - if (mpu->env->halted) - cpu_interrupt(mpu->env, CPU_INTERRUPT_EXITTB); -} - -struct dma_irq_map { - int ih; - int intr; -}; - -static const struct dma_irq_map omap_dma_irq_map[] = { - { 0, OMAP_INT_DMA_CH0_6 }, - { 0, OMAP_INT_DMA_CH1_7 }, - { 0, OMAP_INT_DMA_CH2_8 }, - { 0, OMAP_INT_DMA_CH3 }, - { 0, OMAP_INT_DMA_CH4 }, - { 0, OMAP_INT_DMA_CH5 }, - { 1, OMAP_INT_1610_DMA_CH6 }, - { 1, OMAP_INT_1610_DMA_CH7 }, - { 1, OMAP_INT_1610_DMA_CH8 }, - { 1, OMAP_INT_1610_DMA_CH9 }, - { 1, OMAP_INT_1610_DMA_CH10 }, - { 1, OMAP_INT_1610_DMA_CH11 }, - { 1, OMAP_INT_1610_DMA_CH12 }, - { 1, OMAP_INT_1610_DMA_CH13 }, - { 1, OMAP_INT_1610_DMA_CH14 }, - { 1, OMAP_INT_1610_DMA_CH15 } -}; - -struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, - DisplayState *ds, const char *core) -{ - int i; - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) - qemu_mallocz(sizeof(struct omap_mpu_state_s)); - ram_addr_t imif_base, emiff_base; - qemu_irq *cpu_irq; - qemu_irq dma_irqs[6]; - int sdindex; - - if (!core) - core = "ti925t"; - - /* Core */ - s->mpu_model = omap310; - s->env = cpu_init(core); - if (!s->env) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - s->sdram_size = sdram_size; - s->sram_size = OMAP15XX_SRAM_SIZE; - - s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0]; - - /* Clocks */ - omap_clk_init(s); - - /* Memory-mapped stuff */ - cpu_register_physical_memory(OMAP_EMIFF_BASE, s->sdram_size, - (emiff_base = qemu_ram_alloc(s->sdram_size)) | IO_MEM_RAM); - cpu_register_physical_memory(OMAP_IMIF_BASE, s->sram_size, - (imif_base = qemu_ram_alloc(s->sram_size)) | IO_MEM_RAM); - - omap_clkm_init(0xfffece00, 0xe1008000, s); - - cpu_irq = arm_pic_init_cpu(s->env); - s->ih[0] = omap_inth_init(0xfffecb00, 0x100, 1, - cpu_irq[ARM_PIC_CPU_IRQ], cpu_irq[ARM_PIC_CPU_FIQ], - omap_findclk(s, "arminth_ck")); - s->ih[1] = omap_inth_init(0xfffe0000, 0x800, 1, - s->ih[0]->pins[OMAP_INT_15XX_IH2_IRQ], NULL, - omap_findclk(s, "arminth_ck")); - s->irq[0] = s->ih[0]->pins; - s->irq[1] = s->ih[1]->pins; - - for (i = 0; i < 6; i ++) - dma_irqs[i] = s->irq[omap_dma_irq_map[i].ih][omap_dma_irq_map[i].intr]; - s->dma = omap_dma_init(0xfffed800, dma_irqs, s->irq[0][OMAP_INT_DMA_LCD], - s, omap_findclk(s, "dma_ck"), omap_dma_3_1); - - s->port[emiff ].addr_valid = omap_validate_emiff_addr; - s->port[emifs ].addr_valid = omap_validate_emifs_addr; - s->port[imif ].addr_valid = omap_validate_imif_addr; - s->port[tipb ].addr_valid = omap_validate_tipb_addr; - s->port[local ].addr_valid = omap_validate_local_addr; - s->port[tipb_mpui].addr_valid = omap_validate_tipb_mpui_addr; - - s->timer[0] = omap_mpu_timer_init(0xfffec500, - s->irq[0][OMAP_INT_TIMER1], - omap_findclk(s, "mputim_ck")); - s->timer[1] = omap_mpu_timer_init(0xfffec600, - s->irq[0][OMAP_INT_TIMER2], - omap_findclk(s, "mputim_ck")); - s->timer[2] = omap_mpu_timer_init(0xfffec700, - s->irq[0][OMAP_INT_TIMER3], - omap_findclk(s, "mputim_ck")); - - s->wdt = omap_wd_timer_init(0xfffec800, - s->irq[0][OMAP_INT_WD_TIMER], - omap_findclk(s, "armwdt_ck")); - - s->os_timer = omap_os_timer_init(0xfffb9000, - s->irq[1][OMAP_INT_OS_TIMER], - omap_findclk(s, "clk32-kHz")); - - s->lcd = omap_lcdc_init(0xfffec000, s->irq[0][OMAP_INT_LCD_CTRL], - &s->dma->lcd_ch, ds, imif_base, emiff_base, - omap_findclk(s, "lcd_ck")); - - omap_ulpd_pm_init(0xfffe0800, s); - omap_pin_cfg_init(0xfffe1000, s); - omap_id_init(s); - - omap_mpui_init(0xfffec900, s); - - s->private_tipb = omap_tipb_bridge_init(0xfffeca00, - s->irq[0][OMAP_INT_BRIDGE_PRIV], - omap_findclk(s, "tipb_ck")); - s->public_tipb = omap_tipb_bridge_init(0xfffed300, - s->irq[0][OMAP_INT_BRIDGE_PUB], - omap_findclk(s, "tipb_ck")); - - omap_tcmi_init(0xfffecc00, s); - - s->uart[0] = omap_uart_init(0xfffb0000, s->irq[1][OMAP_INT_UART1], - omap_findclk(s, "uart1_ck"), - serial_hds[0]); - s->uart[1] = omap_uart_init(0xfffb0800, s->irq[1][OMAP_INT_UART2], - omap_findclk(s, "uart2_ck"), - serial_hds[0] ? serial_hds[1] : 0); - s->uart[2] = omap_uart_init(0xe1019800, s->irq[0][OMAP_INT_UART3], - omap_findclk(s, "uart3_ck"), - serial_hds[0] && serial_hds[1] ? serial_hds[2] : 0); - - omap_dpll_init(&s->dpll[0], 0xfffecf00, omap_findclk(s, "dpll1")); - omap_dpll_init(&s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2")); - omap_dpll_init(&s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3")); - - sdindex = drive_get_index(IF_SD, 0, 0); - if (sdindex == -1) { - fprintf(stderr, "qemu: missing SecureDigital device\n"); - exit(1); - } - s->mmc = omap_mmc_init(0xfffb7800, drives_table[sdindex].bdrv, - s->irq[1][OMAP_INT_OQN], &s->drq[OMAP_DMA_MMC_TX], - omap_findclk(s, "mmc_ck")); - - s->mpuio = omap_mpuio_init(0xfffb5000, - s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO], - s->wakeup, omap_findclk(s, "clk32-kHz")); - - s->gpio = omap_gpio_init(0xfffce000, s->irq[0][OMAP_INT_GPIO_BANK1], - omap_findclk(s, "arm_gpio_ck")); - - s->microwire = omap_uwire_init(0xfffb3000, &s->irq[1][OMAP_INT_uWireTX], - s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck")); - - omap_pwl_init(0xfffb5800, s, omap_findclk(s, "armxor_ck")); - omap_pwt_init(0xfffb6000, s, omap_findclk(s, "armxor_ck")); - - s->i2c = omap_i2c_init(0xfffb3800, s->irq[1][OMAP_INT_I2C], - &s->drq[OMAP_DMA_I2C_RX], omap_findclk(s, "mpuper_ck")); - - s->rtc = omap_rtc_init(0xfffb4800, &s->irq[1][OMAP_INT_RTC_TIMER], - omap_findclk(s, "clk32-kHz")); - - s->mcbsp1 = omap_mcbsp_init(0xfffb1800, &s->irq[1][OMAP_INT_McBSP1TX], - &s->drq[OMAP_DMA_MCBSP1_TX], omap_findclk(s, "dspxor_ck")); - s->mcbsp2 = omap_mcbsp_init(0xfffb1000, &s->irq[0][OMAP_INT_310_McBSP2_TX], - &s->drq[OMAP_DMA_MCBSP2_TX], omap_findclk(s, "mpuper_ck")); - s->mcbsp3 = omap_mcbsp_init(0xfffb7000, &s->irq[1][OMAP_INT_McBSP3TX], - &s->drq[OMAP_DMA_MCBSP3_TX], omap_findclk(s, "dspxor_ck")); - - s->led[0] = omap_lpg_init(0xfffbd000, omap_findclk(s, "clk32-kHz")); - s->led[1] = omap_lpg_init(0xfffbd800, omap_findclk(s, "clk32-kHz")); - - /* Register mappings not currenlty implemented: - * MCSI2 Comm fffb2000 - fffb27ff (not mapped on OMAP310) - * MCSI1 Bluetooth fffb2800 - fffb2fff (not mapped on OMAP310) - * USB W2FC fffb4000 - fffb47ff - * Camera Interface fffb6800 - fffb6fff - * USB Host fffba000 - fffba7ff - * FAC fffba800 - fffbafff - * HDQ/1-Wire fffbc000 - fffbc7ff - * TIPB switches fffbc800 - fffbcfff - * Mailbox fffcf000 - fffcf7ff - * Local bus IF fffec100 - fffec1ff - * Local bus MMU fffec200 - fffec2ff - * DSP MMU fffed200 - fffed2ff - */ - - omap_setup_dsp_mapping(omap15xx_dsp_mm); - omap_setup_mpui_io(s); - - qemu_register_reset(omap_mpu_reset, s); - - return s; -} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/omap_clk.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/omap_clk.c --- qemu-0.9.1/hw/omap_clk.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/omap_clk.c 2008-10-26 13:43:07.000000000 +0000 @@ -0,0 +1,1280 @@ +/* + * OMAP clocks. + * + * Copyright (C) 2006-2008 Andrzej Zaborowski + * + * Clocks data comes in part from arch/arm/mach-omap1/clock.h in Linux. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include "hw.h" +#include "omap.h" + +struct clk { + const char *name; + const char *alias; + struct clk *parent; + struct clk *child1; + struct clk *sibling; +#define ALWAYS_ENABLED (1 << 0) +#define CLOCK_IN_OMAP310 (1 << 10) +#define CLOCK_IN_OMAP730 (1 << 11) +#define CLOCK_IN_OMAP1510 (1 << 12) +#define CLOCK_IN_OMAP16XX (1 << 13) +#define CLOCK_IN_OMAP242X (1 << 14) +#define CLOCK_IN_OMAP243X (1 << 15) +#define CLOCK_IN_OMAP343X (1 << 16) + uint32_t flags; + int id; + + int running; /* Is currently ticking */ + int enabled; /* Is enabled, regardless of its input clk */ + unsigned long rate; /* Current rate (if .running) */ + unsigned int divisor; /* Rate relative to input (if .enabled) */ + unsigned int multiplier; /* Rate relative to input (if .enabled) */ + qemu_irq users[16]; /* Who to notify on change */ + int usecount; /* Automatically idle when unused */ +}; + +static struct clk xtal_osc12m = { + .name = "xtal_osc_12m", + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk xtal_osc32k = { + .name = "xtal_osc_32k", + .rate = 32768, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, +}; + +static struct clk ck_ref = { + .name = "ck_ref", + .alias = "clkin", + .parent = &xtal_osc12m, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +/* If a dpll is disabled it becomes a bypass, child clocks don't stop */ +static struct clk dpll1 = { + .name = "dpll1", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk dpll2 = { + .name = "dpll2", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED, +}; + +static struct clk dpll3 = { + .name = "dpll3", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED, +}; + +static struct clk dpll4 = { + .name = "dpll4", + .parent = &ck_ref, + .multiplier = 4, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk apll = { + .name = "apll", + .parent = &ck_ref, + .multiplier = 48, + .divisor = 12, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk ck_48m = { + .name = "ck_48m", + .parent = &dpll4, /* either dpll4 or apll */ + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk ck_dpll1out = { + .name = "ck_dpll1out", + .parent = &dpll1, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk sossi_ck = { + .name = "ck_sossi", + .parent = &ck_dpll1out, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk clkm1 = { + .name = "clkm1", + .alias = "ck_gen1", + .parent = &dpll1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk clkm2 = { + .name = "clkm2", + .alias = "ck_gen2", + .parent = &dpll1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk clkm3 = { + .name = "clkm3", + .alias = "ck_gen3", + .parent = &dpll1, /* either dpll1 or ck_ref */ + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk arm_ck = { + .name = "arm_ck", + .alias = "mpu_ck", + .parent = &clkm1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk armper_ck = { + .name = "armper_ck", + .alias = "mpuper_ck", + .parent = &clkm1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk arm_gpio_ck = { + .name = "arm_gpio_ck", + .alias = "mpu_gpio_ck", + .parent = &clkm1, + .divisor = 1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, +}; + +static struct clk armxor_ck = { + .name = "armxor_ck", + .alias = "mpuxor_ck", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk armtim_ck = { + .name = "armtim_ck", + .alias = "mputim_ck", + .parent = &ck_ref, /* either CLKIN or DPLL1 */ + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk armwdt_ck = { + .name = "armwdt_ck", + .alias = "mpuwd_ck", + .parent = &clkm1, + .divisor = 14, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk arminth_ck16xx = { + .name = "arminth_ck", + .parent = &arm_ck, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, + /* Note: On 16xx the frequency can be divided by 2 by programming + * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1 + * + * 1510 version is in TC clocks. + */ +}; + +static struct clk dsp_ck = { + .name = "dsp_ck", + .parent = &clkm2, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, +}; + +static struct clk dspmmu_ck = { + .name = "dspmmu_ck", + .parent = &clkm2, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + ALWAYS_ENABLED, +}; + +static struct clk dspper_ck = { + .name = "dspper_ck", + .parent = &clkm2, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, +}; + +static struct clk dspxor_ck = { + .name = "dspxor_ck", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, +}; + +static struct clk dsptim_ck = { + .name = "dsptim_ck", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, +}; + +static struct clk tc_ck = { + .name = "tc_ck", + .parent = &clkm3, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + CLOCK_IN_OMAP730 | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk arminth_ck15xx = { + .name = "arminth_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, + /* Note: On 1510 the frequency follows TC_CK + * + * 16xx version is in MPU clocks. + */ +}; + +static struct clk tipb_ck = { + /* No-idle controlled by "tc_ck" */ + .name = "tipb_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, +}; + +static struct clk l3_ocpi_ck = { + /* No-idle controlled by "tc_ck" */ + .name = "l3_ocpi_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk tc1_ck = { + .name = "tc1_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk tc2_ck = { + .name = "tc2_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk dma_ck = { + /* No-idle controlled by "tc_ck" */ + .name = "dma_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk dma_lcdfree_ck = { + .name = "dma_lcdfree_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, +}; + +static struct clk api_ck = { + .name = "api_ck", + .alias = "mpui_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk lb_ck = { + .name = "lb_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, +}; + +static struct clk lbfree_ck = { + .name = "lbfree_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, +}; + +static struct clk hsab_ck = { + .name = "hsab_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, +}; + +static struct clk rhea1_ck = { + .name = "rhea1_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, +}; + +static struct clk rhea2_ck = { + .name = "rhea2_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, +}; + +static struct clk lcd_ck_16xx = { + .name = "lcd_ck", + .parent = &clkm3, + .flags = CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730, +}; + +static struct clk lcd_ck_1510 = { + .name = "lcd_ck", + .parent = &clkm3, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, +}; + +static struct clk uart1_1510 = { + .name = "uart1_ck", + /* Direct from ULPD, no real parent */ + .parent = &armper_ck, /* either armper_ck or dpll4 */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, +}; + +static struct clk uart1_16xx = { + .name = "uart1_ck", + /* Direct from ULPD, no real parent */ + .parent = &armper_ck, + .rate = 48000000, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk uart2_ck = { + .name = "uart2_ck", + /* Direct from ULPD, no real parent */ + .parent = &armper_ck, /* either armper_ck or dpll4 */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk uart3_1510 = { + .name = "uart3_ck", + /* Direct from ULPD, no real parent */ + .parent = &armper_ck, /* either armper_ck or dpll4 */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, +}; + +static struct clk uart3_16xx = { + .name = "uart3_ck", + /* Direct from ULPD, no real parent */ + .parent = &armper_ck, + .rate = 48000000, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk usb_clk0 = { /* 6 MHz output on W4_USB_CLK0 */ + .name = "usb_clk0", + .alias = "usb.clko", + /* Direct from ULPD, no parent */ + .rate = 6000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk usb_hhc_ck1510 = { + .name = "usb_hhc_ck", + /* Direct from ULPD, no parent */ + .rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */ + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, +}; + +static struct clk usb_hhc_ck16xx = { + .name = "usb_hhc_ck", + /* Direct from ULPD, no parent */ + .rate = 48000000, + /* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */ + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk usb_w2fc_mclk = { + .name = "usb_w2fc_mclk", + .alias = "usb_w2fc_ck", + .parent = &ck_48m, + .rate = 48000000, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, +}; + +static struct clk mclk_1510 = { + .name = "mclk", + /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510, +}; + +static struct clk bclk_310 = { + .name = "bt_mclk_out", /* Alias midi_mclk_out? */ + .parent = &armper_ck, + .flags = CLOCK_IN_OMAP310, +}; + +static struct clk mclk_310 = { + .name = "com_mclk_out", + .parent = &armper_ck, + .flags = CLOCK_IN_OMAP310, +}; + +static struct clk mclk_16xx = { + .name = "mclk", + /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk bclk_1510 = { + .name = "bclk", + /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510, +}; + +static struct clk bclk_16xx = { + .name = "bclk", + /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk mmc1_ck = { + .name = "mmc_ck", + .id = 1, + /* Functional clock is direct from ULPD, interface clock is ARMPER */ + .parent = &armper_ck, /* either armper_ck or dpll4 */ + .rate = 48000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk mmc2_ck = { + .name = "mmc_ck", + .id = 2, + /* Functional clock is direct from ULPD, interface clock is ARMPER */ + .parent = &armper_ck, + .rate = 48000000, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk cam_mclk = { + .name = "cam.mclk", + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, + .rate = 12000000, +}; + +static struct clk cam_exclk = { + .name = "cam.exclk", + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, + /* Either 12M from cam.mclk or 48M from dpll4 */ + .parent = &cam_mclk, +}; + +static struct clk cam_lclk = { + .name = "cam.lclk", + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, +}; + +static struct clk i2c_fck = { + .name = "i2c_fck", + .id = 1, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + ALWAYS_ENABLED, + .parent = &armxor_ck, +}; + +static struct clk i2c_ick = { + .name = "i2c_ick", + .id = 1, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, + .parent = &armper_ck, +}; + +static struct clk clk32k = { + .name = "clk32-kHz", + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, + .parent = &xtal_osc32k, +}; + +static struct clk ref_clk = { + .name = "ref_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, + .rate = 12000000, /* 12 MHz or 13 MHz or 19.2 MHz */ + /*.parent = sys.xtalin */ +}; + +static struct clk apll_96m = { + .name = "apll_96m", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, + .rate = 96000000, + /*.parent = ref_clk */ +}; + +static struct clk apll_54m = { + .name = "apll_54m", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, + .rate = 54000000, + /*.parent = ref_clk */ +}; + +static struct clk sys_clk = { + .name = "sys_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, + .rate = 32768, + /*.parent = sys.xtalin */ +}; + +static struct clk sleep_clk = { + .name = "sleep_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, + .rate = 32768, + /*.parent = sys.xtalin */ +}; + +static struct clk dpll_ck = { + .name = "dpll", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, + .parent = &ref_clk, +}; + +static struct clk dpll_x2_ck = { + .name = "dpll_x2", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, + .parent = &ref_clk, +}; + +static struct clk wdt1_sys_clk = { + .name = "wdt1_sys_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, + .rate = 32768, + /*.parent = sys.xtalin */ +}; + +static struct clk func_96m_clk = { + .name = "func_96m_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .divisor = 1, + .parent = &apll_96m, +}; + +static struct clk func_48m_clk = { + .name = "func_48m_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .divisor = 2, + .parent = &apll_96m, +}; + +static struct clk func_12m_clk = { + .name = "func_12m_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .divisor = 8, + .parent = &apll_96m, +}; + +static struct clk func_54m_clk = { + .name = "func_54m_clk", + .flags = CLOCK_IN_OMAP242X, + .divisor = 1, + .parent = &apll_54m, +}; + +static struct clk sys_clkout = { + .name = "clkout", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk sys_clkout2 = { + .name = "clkout2", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_clk = { + .name = "core_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &dpll_x2_ck, /* Switchable between dpll_ck and clk32k */ +}; + +static struct clk l3_clk = { + .name = "l3_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_clk, +}; + +static struct clk core_l4_iclk = { + .name = "core_l4_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &l3_clk, +}; + +static struct clk wu_l4_iclk = { + .name = "wu_l4_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &l3_clk, +}; + +static struct clk core_l3_iclk = { + .name = "core_l3_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_clk, +}; + +static struct clk core_l4_usb_clk = { + .name = "core_l4_usb_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &l3_clk, +}; + +static struct clk wu_gpt1_clk = { + .name = "wu_gpt1_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk wu_32k_clk = { + .name = "wu_32k_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk uart1_fclk = { + .name = "uart1_fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &func_48m_clk, +}; + +static struct clk uart1_iclk = { + .name = "uart1_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l4_iclk, +}; + +static struct clk uart2_fclk = { + .name = "uart2_fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &func_48m_clk, +}; + +static struct clk uart2_iclk = { + .name = "uart2_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l4_iclk, +}; + +static struct clk uart3_fclk = { + .name = "uart3_fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &func_48m_clk, +}; + +static struct clk uart3_iclk = { + .name = "uart3_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l4_iclk, +}; + +static struct clk mpu_fclk = { + .name = "mpu_fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_clk, +}; + +static struct clk mpu_iclk = { + .name = "mpu_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_clk, +}; + +static struct clk int_m_fclk = { + .name = "int_m_fclk", + .alias = "mpu_intc_fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_clk, +}; + +static struct clk int_m_iclk = { + .name = "int_m_iclk", + .alias = "mpu_intc_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_clk, +}; + +static struct clk core_gpt2_clk = { + .name = "core_gpt2_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt3_clk = { + .name = "core_gpt3_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt4_clk = { + .name = "core_gpt4_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt5_clk = { + .name = "core_gpt5_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt6_clk = { + .name = "core_gpt6_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt7_clk = { + .name = "core_gpt7_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt8_clk = { + .name = "core_gpt8_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt9_clk = { + .name = "core_gpt9_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt10_clk = { + .name = "core_gpt10_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt11_clk = { + .name = "core_gpt11_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt12_clk = { + .name = "core_gpt12_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk mcbsp1_clk = { + .name = "mcbsp1_cg", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .divisor = 2, + .parent = &func_96m_clk, +}; + +static struct clk mcbsp2_clk = { + .name = "mcbsp2_cg", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .divisor = 2, + .parent = &func_96m_clk, +}; + +static struct clk emul_clk = { + .name = "emul_ck", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &func_54m_clk, +}; + +static struct clk sdma_fclk = { + .name = "sdma_fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &l3_clk, +}; + +static struct clk sdma_iclk = { + .name = "sdma_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l3_iclk, /* core_l4_iclk for the configuration port */ +}; + +static struct clk i2c1_fclk = { + .name = "i2c1.fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &func_12m_clk, + .divisor = 1, +}; + +static struct clk i2c1_iclk = { + .name = "i2c1.iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l4_iclk, +}; + +static struct clk i2c2_fclk = { + .name = "i2c2.fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &func_12m_clk, + .divisor = 1, +}; + +static struct clk i2c2_iclk = { + .name = "i2c2.iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l4_iclk, +}; + +static struct clk gpio_dbclk[4] = { + { + .name = "gpio1_dbclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &wu_32k_clk, + }, { + .name = "gpio2_dbclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &wu_32k_clk, + }, { + .name = "gpio3_dbclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &wu_32k_clk, + }, { + .name = "gpio4_dbclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &wu_32k_clk, + }, +}; + +static struct clk gpio_iclk = { + .name = "gpio_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &wu_l4_iclk, +}; + +static struct clk mmc_fck = { + .name = "mmc_fclk", + .flags = CLOCK_IN_OMAP242X, + .parent = &func_96m_clk, +}; + +static struct clk mmc_ick = { + .name = "mmc_iclk", + .flags = CLOCK_IN_OMAP242X, + .parent = &core_l4_iclk, +}; + +static struct clk spi_fclk[3] = { + { + .name = "spi1_fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &func_48m_clk, + }, { + .name = "spi2_fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &func_48m_clk, + }, { + .name = "spi3_fclk", + .flags = CLOCK_IN_OMAP243X, + .parent = &func_48m_clk, + }, +}; + +static struct clk dss_clk[2] = { + { + .name = "dss_clk1", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_clk, + }, { + .name = "dss_clk2", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, + }, +}; + +static struct clk dss_54m_clk = { + .name = "dss_54m_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &func_54m_clk, +}; + +static struct clk dss_l3_iclk = { + .name = "dss_l3_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l3_iclk, +}; + +static struct clk dss_l4_iclk = { + .name = "dss_l4_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l4_iclk, +}; + +static struct clk spi_iclk[3] = { + { + .name = "spi1_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l4_iclk, + }, { + .name = "spi2_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l4_iclk, + }, { + .name = "spi3_iclk", + .flags = CLOCK_IN_OMAP243X, + .parent = &core_l4_iclk, + }, +}; + +static struct clk omapctrl_clk = { + .name = "omapctrl_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + /* XXX Should be in WKUP domain */ + .parent = &core_l4_iclk, +}; + +static struct clk *onchip_clks[] = { + /* OMAP 1 */ + + /* non-ULPD clocks */ + &xtal_osc12m, + &xtal_osc32k, + &ck_ref, + &dpll1, + &dpll2, + &dpll3, + &dpll4, + &apll, + &ck_48m, + /* CK_GEN1 clocks */ + &clkm1, + &ck_dpll1out, + &sossi_ck, + &arm_ck, + &armper_ck, + &arm_gpio_ck, + &armxor_ck, + &armtim_ck, + &armwdt_ck, + &arminth_ck15xx, &arminth_ck16xx, + /* CK_GEN2 clocks */ + &clkm2, + &dsp_ck, + &dspmmu_ck, + &dspper_ck, + &dspxor_ck, + &dsptim_ck, + /* CK_GEN3 clocks */ + &clkm3, + &tc_ck, + &tipb_ck, + &l3_ocpi_ck, + &tc1_ck, + &tc2_ck, + &dma_ck, + &dma_lcdfree_ck, + &api_ck, + &lb_ck, + &lbfree_ck, + &hsab_ck, + &rhea1_ck, + &rhea2_ck, + &lcd_ck_16xx, + &lcd_ck_1510, + /* ULPD clocks */ + &uart1_1510, + &uart1_16xx, + &uart2_ck, + &uart3_1510, + &uart3_16xx, + &usb_clk0, + &usb_hhc_ck1510, &usb_hhc_ck16xx, + &mclk_1510, &mclk_16xx, &mclk_310, + &bclk_1510, &bclk_16xx, &bclk_310, + &mmc1_ck, + &mmc2_ck, + &cam_mclk, + &cam_exclk, + &cam_lclk, + &clk32k, + &usb_w2fc_mclk, + /* Virtual clocks */ + &i2c_fck, + &i2c_ick, + + /* OMAP 2 */ + + &ref_clk, + &apll_96m, + &apll_54m, + &sys_clk, + &sleep_clk, + &dpll_ck, + &dpll_x2_ck, + &wdt1_sys_clk, + &func_96m_clk, + &func_48m_clk, + &func_12m_clk, + &func_54m_clk, + &sys_clkout, + &sys_clkout2, + &core_clk, + &l3_clk, + &core_l4_iclk, + &wu_l4_iclk, + &core_l3_iclk, + &core_l4_usb_clk, + &wu_gpt1_clk, + &wu_32k_clk, + &uart1_fclk, + &uart1_iclk, + &uart2_fclk, + &uart2_iclk, + &uart3_fclk, + &uart3_iclk, + &mpu_fclk, + &mpu_iclk, + &int_m_fclk, + &int_m_iclk, + &core_gpt2_clk, + &core_gpt3_clk, + &core_gpt4_clk, + &core_gpt5_clk, + &core_gpt6_clk, + &core_gpt7_clk, + &core_gpt8_clk, + &core_gpt9_clk, + &core_gpt10_clk, + &core_gpt11_clk, + &core_gpt12_clk, + &mcbsp1_clk, + &mcbsp2_clk, + &emul_clk, + &sdma_fclk, + &sdma_iclk, + &i2c1_fclk, + &i2c1_iclk, + &i2c2_fclk, + &i2c2_iclk, + &gpio_dbclk[0], + &gpio_dbclk[1], + &gpio_dbclk[2], + &gpio_dbclk[3], + &gpio_iclk, + &mmc_fck, + &mmc_ick, + &spi_fclk[0], + &spi_iclk[0], + &spi_fclk[1], + &spi_iclk[1], + &spi_fclk[2], + &spi_iclk[2], + &dss_clk[0], + &dss_clk[1], + &dss_54m_clk, + &dss_l3_iclk, + &dss_l4_iclk, + &omapctrl_clk, + + 0 +}; + +void omap_clk_adduser(struct clk *clk, qemu_irq user) +{ + qemu_irq *i; + + for (i = clk->users; *i; i ++); + *i = user; +} + +/* If a clock is allowed to idle, it is disabled automatically when + * all of clock domains using it are disabled. */ +static int omap_clk_is_idle(struct clk *clk) +{ + struct clk *chld; + + if (!clk->enabled && (!clk->usecount || !(clk->flags && ALWAYS_ENABLED))) + return 1; + if (clk->usecount) + return 0; + + for (chld = clk->child1; chld; chld = chld->sibling) + if (!omap_clk_is_idle(chld)) + return 0; + return 1; +} + +struct clk *omap_findclk(struct omap_mpu_state_s *mpu, const char *name) +{ + struct clk *i; + + for (i = mpu->clks; i->name; i ++) + if (!strcmp(i->name, name) || (i->alias && !strcmp(i->alias, name))) + return i; + cpu_abort(mpu->env, "%s: %s not found\n", __FUNCTION__, name); +} + +void omap_clk_get(struct clk *clk) +{ + clk->usecount ++; +} + +void omap_clk_put(struct clk *clk) +{ + if (!(clk->usecount --)) + cpu_abort(cpu_single_env, "%s: %s is not in use\n", + __FUNCTION__, clk->name); +} + +static void omap_clk_update(struct clk *clk) +{ + int parent, running; + qemu_irq *user; + struct clk *i; + + if (clk->parent) + parent = clk->parent->running; + else + parent = 1; + + running = parent && (clk->enabled || + ((clk->flags & ALWAYS_ENABLED) && clk->usecount)); + if (clk->running != running) { + clk->running = running; + for (user = clk->users; *user; user ++) + qemu_set_irq(*user, running); + for (i = clk->child1; i; i = i->sibling) + omap_clk_update(i); + } +} + +static void omap_clk_rate_update_full(struct clk *clk, unsigned long int rate, + unsigned long int div, unsigned long int mult) +{ + struct clk *i; + qemu_irq *user; + + clk->rate = muldiv64(rate, mult, div); + if (clk->running) + for (user = clk->users; *user; user ++) + qemu_irq_raise(*user); + for (i = clk->child1; i; i = i->sibling) + omap_clk_rate_update_full(i, rate, + div * i->divisor, mult * i->multiplier); +} + +static void omap_clk_rate_update(struct clk *clk) +{ + struct clk *i; + unsigned long int div, mult = div = 1; + + for (i = clk; i->parent; i = i->parent) { + div *= i->divisor; + mult *= i->multiplier; + } + + omap_clk_rate_update_full(clk, i->rate, div, mult); +} + +void omap_clk_reparent(struct clk *clk, struct clk *parent) +{ + struct clk **p; + + if (clk->parent) { + for (p = &clk->parent->child1; *p != clk; p = &(*p)->sibling); + *p = clk->sibling; + } + + clk->parent = parent; + if (parent) { + clk->sibling = parent->child1; + parent->child1 = clk; + omap_clk_update(clk); + omap_clk_rate_update(clk); + } else + clk->sibling = 0; +} + +void omap_clk_onoff(struct clk *clk, int on) +{ + clk->enabled = on; + omap_clk_update(clk); +} + +void omap_clk_canidle(struct clk *clk, int can) +{ + if (can) + omap_clk_put(clk); + else + omap_clk_get(clk); +} + +void omap_clk_setrate(struct clk *clk, int divide, int multiply) +{ + clk->divisor = divide; + clk->multiplier = multiply; + omap_clk_rate_update(clk); +} + +int64_t omap_clk_getrate(omap_clk clk) +{ + return clk->rate; +} + +void omap_clk_init(struct omap_mpu_state_s *mpu) +{ + struct clk **i, *j, *k; + int count; + int flag; + + if (cpu_is_omap310(mpu)) + flag = CLOCK_IN_OMAP310; + else if (cpu_is_omap1510(mpu)) + flag = CLOCK_IN_OMAP1510; + else if (cpu_is_omap2410(mpu) || cpu_is_omap2420(mpu)) + flag = CLOCK_IN_OMAP242X; + else if (cpu_is_omap2430(mpu)) + flag = CLOCK_IN_OMAP243X; + else if (cpu_is_omap3430(mpu)) + flag = CLOCK_IN_OMAP243X; + else + return; + + for (i = onchip_clks, count = 0; *i; i ++) + if ((*i)->flags & flag) + count ++; + mpu->clks = (struct clk *) qemu_mallocz(sizeof(struct clk) * (count + 1)); + for (i = onchip_clks, j = mpu->clks; *i; i ++) + if ((*i)->flags & flag) { + memcpy(j, *i, sizeof(struct clk)); + for (k = mpu->clks; k < j; k ++) + if (j->parent && !strcmp(j->parent->name, k->name)) { + j->parent = k; + j->sibling = k->child1; + k->child1 = j; + } else if (k->parent && !strcmp(k->parent->name, j->name)) { + k->parent = j; + k->sibling = j->child1; + j->child1 = k; + } + j->divisor = j->divisor ?: 1; + j->multiplier = j->multiplier ?: 1; + j ++; + } + for (j = mpu->clks; count --; j ++) { + omap_clk_update(j); + omap_clk_rate_update(j); + } +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/omap_dma.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/omap_dma.c --- qemu-0.9.1/hw/omap_dma.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/omap_dma.c 2008-07-22 02:57:42.000000000 +0100 @@ -0,0 +1,2083 @@ +/* + * TI OMAP DMA gigacell. + * + * Copyright (C) 2006-2008 Andrzej Zaborowski + * Copyright (C) 2007-2008 Lauro Ramos Venancio + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include "qemu-common.h" +#include "qemu-timer.h" +#include "omap.h" +#include "irq.h" +#include "soc_dma.h" + +struct omap_dma_channel_s { + /* transfer data */ + int burst[2]; + int pack[2]; + int endian[2]; + int endian_lock[2]; + int translate[2]; + enum omap_dma_port port[2]; + target_phys_addr_t addr[2]; + omap_dma_addressing_t mode[2]; + uint32_t elements; + uint16_t frames; + int32_t frame_index[2]; + int16_t element_index[2]; + int data_type; + + /* transfer type */ + int transparent_copy; + int constant_fill; + uint32_t color; + int prefetch; + + /* auto init and linked channel data */ + int end_prog; + int repeat; + int auto_init; + int link_enabled; + int link_next_ch; + + /* interruption data */ + int interrupts; + int status; + int cstatus; + + /* state data */ + int active; + int enable; + int sync; + int src_sync; + int pending_request; + int waiting_end_prog; + uint16_t cpc; + int set_update; + + /* sync type */ + int fs; + int bs; + + /* compatibility */ + int omap_3_1_compatible_disable; + + qemu_irq irq; + struct omap_dma_channel_s *sibling; + + struct omap_dma_reg_set_s { + target_phys_addr_t src, dest; + int frame; + int element; + int pck_element; + int frame_delta[2]; + int elem_delta[2]; + int frames; + int elements; + int pck_elements; + } active_set; + + struct soc_dma_ch_s *dma; + + /* unused parameters */ + int write_mode; + int priority; + int interleave_disabled; + int type; + int suspend; + int buf_disable; +}; + +struct omap_dma_s { + struct soc_dma_s *dma; + + struct omap_mpu_state_s *mpu; + target_phys_addr_t base; + omap_clk clk; + qemu_irq irq[4]; + void (*intr_update)(struct omap_dma_s *s); + enum omap_dma_model model; + int omap_3_1_mapping_disabled; + + uint32_t gcr; + uint32_t ocp; + uint32_t caps[5]; + uint32_t irqen[4]; + uint32_t irqstat[4]; + + int chans; + struct omap_dma_channel_s ch[32]; + struct omap_dma_lcd_channel_s lcd_ch; +}; + +/* Interrupts */ +#define TIMEOUT_INTR (1 << 0) +#define EVENT_DROP_INTR (1 << 1) +#define HALF_FRAME_INTR (1 << 2) +#define END_FRAME_INTR (1 << 3) +#define LAST_FRAME_INTR (1 << 4) +#define END_BLOCK_INTR (1 << 5) +#define SYNC (1 << 6) +#define END_PKT_INTR (1 << 7) +#define TRANS_ERR_INTR (1 << 8) +#define MISALIGN_INTR (1 << 11) + +static inline void omap_dma_interrupts_update(struct omap_dma_s *s) +{ + return s->intr_update(s); +} + +static void omap_dma_channel_load(struct omap_dma_channel_s *ch) +{ + struct omap_dma_reg_set_s *a = &ch->active_set; + int i, normal; + int omap_3_1 = !ch->omap_3_1_compatible_disable; + + /* + * TODO: verify address ranges and alignment + * TODO: port endianness + */ + + a->src = ch->addr[0]; + a->dest = ch->addr[1]; + a->frames = ch->frames; + a->elements = ch->elements; + a->pck_elements = ch->frame_index[!ch->src_sync]; + a->frame = 0; + a->element = 0; + a->pck_element = 0; + + if (unlikely(!ch->elements || !ch->frames)) { + printf("%s: bad DMA request\n", __FUNCTION__); + return; + } + + for (i = 0; i < 2; i ++) + switch (ch->mode[i]) { + case constant: + a->elem_delta[i] = 0; + a->frame_delta[i] = 0; + break; + case post_incremented: + a->elem_delta[i] = ch->data_type; + a->frame_delta[i] = 0; + break; + case single_index: + a->elem_delta[i] = ch->data_type + + ch->element_index[omap_3_1 ? 0 : i] - 1; + a->frame_delta[i] = 0; + break; + case double_index: + a->elem_delta[i] = ch->data_type + + ch->element_index[omap_3_1 ? 0 : i] - 1; + a->frame_delta[i] = ch->frame_index[omap_3_1 ? 0 : i] - + ch->element_index[omap_3_1 ? 0 : i]; + break; + default: + break; + } + + normal = !ch->transparent_copy && !ch->constant_fill && + /* FIFO is big-endian so either (ch->endian[n] == 1) OR + * (ch->endian_lock[n] == 1) mean no endianism conversion. */ + (ch->endian[0] | ch->endian_lock[0]) == + (ch->endian[1] | ch->endian_lock[1]); + for (i = 0; i < 2; i ++) { + /* TODO: for a->frame_delta[i] > 0 still use the fast path, just + * limit min_elems in omap_dma_transfer_setup to the nearest frame + * end. */ + if (!a->elem_delta[i] && normal && + (a->frames == 1 || !a->frame_delta[i])) + ch->dma->type[i] = soc_dma_access_const; + else if (a->elem_delta[i] == ch->data_type && normal && + (a->frames == 1 || !a->frame_delta[i])) + ch->dma->type[i] = soc_dma_access_linear; + else + ch->dma->type[i] = soc_dma_access_other; + + ch->dma->vaddr[i] = ch->addr[i]; + } + soc_dma_ch_update(ch->dma); +} + +static void omap_dma_activate_channel(struct omap_dma_s *s, + struct omap_dma_channel_s *ch) +{ + if (!ch->active) { + if (ch->set_update) { + /* It's not clear when the active set is supposed to be + * loaded from registers. We're already loading it when the + * channel is enabled, and for some guests this is not enough + * but that may be also because of a race condition (no + * delays in qemu) in the guest code, which we're just + * working around here. */ + omap_dma_channel_load(ch); + ch->set_update = 0; + } + + ch->active = 1; + soc_dma_set_request(ch->dma, 1); + if (ch->sync) + ch->status |= SYNC; + } +} + +static void omap_dma_deactivate_channel(struct omap_dma_s *s, + struct omap_dma_channel_s *ch) +{ + /* Update cpc */ + ch->cpc = ch->active_set.dest & 0xffff; + + if (ch->pending_request && !ch->waiting_end_prog && ch->enable) { + /* Don't deactivate the channel */ + ch->pending_request = 0; + return; + } + + /* Don't deactive the channel if it is synchronized and the DMA request is + active */ + if (ch->sync && ch->enable && (s->dma->drqbmp & (1 << ch->sync))) + return; + + if (ch->active) { + ch->active = 0; + ch->status &= ~SYNC; + soc_dma_set_request(ch->dma, 0); + } +} + +static void omap_dma_enable_channel(struct omap_dma_s *s, + struct omap_dma_channel_s *ch) +{ + if (!ch->enable) { + ch->enable = 1; + ch->waiting_end_prog = 0; + omap_dma_channel_load(ch); + /* TODO: theoretically if ch->sync && ch->prefetch && + * !s->dma->drqbmp[ch->sync], we should also activate and fetch + * from source and then stall until signalled. */ + if ((!ch->sync) || (s->dma->drqbmp & (1 << ch->sync))) + omap_dma_activate_channel(s, ch); + } +} + +static void omap_dma_disable_channel(struct omap_dma_s *s, + struct omap_dma_channel_s *ch) +{ + if (ch->enable) { + ch->enable = 0; + /* Discard any pending request */ + ch->pending_request = 0; + omap_dma_deactivate_channel(s, ch); + } +} + +static void omap_dma_channel_end_prog(struct omap_dma_s *s, + struct omap_dma_channel_s *ch) +{ + if (ch->waiting_end_prog) { + ch->waiting_end_prog = 0; + if (!ch->sync || ch->pending_request) { + ch->pending_request = 0; + omap_dma_activate_channel(s, ch); + } + } +} + +static void omap_dma_interrupts_3_1_update(struct omap_dma_s *s) +{ + struct omap_dma_channel_s *ch = s->ch; + + /* First three interrupts are shared between two channels each. */ + if (ch[0].status | ch[6].status) + qemu_irq_raise(ch[0].irq); + if (ch[1].status | ch[7].status) + qemu_irq_raise(ch[1].irq); + if (ch[2].status | ch[8].status) + qemu_irq_raise(ch[2].irq); + if (ch[3].status) + qemu_irq_raise(ch[3].irq); + if (ch[4].status) + qemu_irq_raise(ch[4].irq); + if (ch[5].status) + qemu_irq_raise(ch[5].irq); +} + +static void omap_dma_interrupts_3_2_update(struct omap_dma_s *s) +{ + struct omap_dma_channel_s *ch = s->ch; + int i; + + for (i = s->chans; i; ch ++, i --) + if (ch->status) + qemu_irq_raise(ch->irq); +} + +static void omap_dma_enable_3_1_mapping(struct omap_dma_s *s) +{ + s->omap_3_1_mapping_disabled = 0; + s->chans = 9; + s->intr_update = omap_dma_interrupts_3_1_update; +} + +static void omap_dma_disable_3_1_mapping(struct omap_dma_s *s) +{ + s->omap_3_1_mapping_disabled = 1; + s->chans = 16; + s->intr_update = omap_dma_interrupts_3_2_update; +} + +static void omap_dma_process_request(struct omap_dma_s *s, int request) +{ + int channel; + int drop_event = 0; + struct omap_dma_channel_s *ch = s->ch; + + for (channel = 0; channel < s->chans; channel ++, ch ++) { + if (ch->enable && ch->sync == request) { + if (!ch->active) + omap_dma_activate_channel(s, ch); + else if (!ch->pending_request) + ch->pending_request = 1; + else { + /* Request collision */ + /* Second request received while processing other request */ + ch->status |= EVENT_DROP_INTR; + drop_event = 1; + } + } + } + + if (drop_event) + omap_dma_interrupts_update(s); +} + +static void omap_dma_transfer_generic(struct soc_dma_ch_s *dma) +{ + uint8_t value[4]; + struct omap_dma_channel_s *ch = dma->opaque; + struct omap_dma_reg_set_s *a = &ch->active_set; + int bytes = dma->bytes; +#ifdef MULTI_REQ + uint16_t status = ch->status; +#endif + + do { + /* Transfer a single element */ + /* FIXME: check the endianness */ + if (!ch->constant_fill) + cpu_physical_memory_read(a->src, value, ch->data_type); + else + *(uint32_t *) value = ch->color; + + if (!ch->transparent_copy || *(uint32_t *) value != ch->color) + cpu_physical_memory_write(a->dest, value, ch->data_type); + + a->src += a->elem_delta[0]; + a->dest += a->elem_delta[1]; + a->element ++; + +#ifndef MULTI_REQ + if (a->element == a->elements) { + /* End of Frame */ + a->element = 0; + a->src += a->frame_delta[0]; + a->dest += a->frame_delta[1]; + a->frame ++; + + /* If the channel is async, update cpc */ + if (!ch->sync) + ch->cpc = a->dest & 0xffff; + } + } while ((bytes -= ch->data_type)); +#else + /* If the channel is element synchronized, deactivate it */ + if (ch->sync && !ch->fs && !ch->bs) + omap_dma_deactivate_channel(s, ch); + + /* If it is the last frame, set the LAST_FRAME interrupt */ + if (a->element == 1 && a->frame == a->frames - 1) + if (ch->interrupts & LAST_FRAME_INTR) + ch->status |= LAST_FRAME_INTR; + + /* If the half of the frame was reached, set the HALF_FRAME + interrupt */ + if (a->element == (a->elements >> 1)) + if (ch->interrupts & HALF_FRAME_INTR) + ch->status |= HALF_FRAME_INTR; + + if (ch->fs && ch->bs) { + a->pck_element ++; + /* Check if a full packet has beed transferred. */ + if (a->pck_element == a->pck_elements) { + a->pck_element = 0; + + /* Set the END_PKT interrupt */ + if ((ch->interrupts & END_PKT_INTR) && !ch->src_sync) + ch->status |= END_PKT_INTR; + + /* If the channel is packet-synchronized, deactivate it */ + if (ch->sync) + omap_dma_deactivate_channel(s, ch); + } + } + + if (a->element == a->elements) { + /* End of Frame */ + a->element = 0; + a->src += a->frame_delta[0]; + a->dest += a->frame_delta[1]; + a->frame ++; + + /* If the channel is frame synchronized, deactivate it */ + if (ch->sync && ch->fs && !ch->bs) + omap_dma_deactivate_channel(s, ch); + + /* If the channel is async, update cpc */ + if (!ch->sync) + ch->cpc = a->dest & 0xffff; + + /* Set the END_FRAME interrupt */ + if (ch->interrupts & END_FRAME_INTR) + ch->status |= END_FRAME_INTR; + + if (a->frame == a->frames) { + /* End of Block */ + /* Disable the channel */ + + if (ch->omap_3_1_compatible_disable) { + omap_dma_disable_channel(s, ch); + if (ch->link_enabled) + omap_dma_enable_channel(s, + &s->ch[ch->link_next_ch]); + } else { + if (!ch->auto_init) + omap_dma_disable_channel(s, ch); + else if (ch->repeat || ch->end_prog) + omap_dma_channel_load(ch); + else { + ch->waiting_end_prog = 1; + omap_dma_deactivate_channel(s, ch); + } + } + + if (ch->interrupts & END_BLOCK_INTR) + ch->status |= END_BLOCK_INTR; + } + } + } while (status == ch->status && ch->active); + + omap_dma_interrupts_update(s); +#endif +} + +enum { + omap_dma_intr_element_sync, + omap_dma_intr_last_frame, + omap_dma_intr_half_frame, + omap_dma_intr_frame, + omap_dma_intr_frame_sync, + omap_dma_intr_packet, + omap_dma_intr_packet_sync, + omap_dma_intr_block, + __omap_dma_intr_last, +}; + +static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma) +{ + struct omap_dma_port_if_s *src_p, *dest_p; + struct omap_dma_reg_set_s *a; + struct omap_dma_channel_s *ch = dma->opaque; + struct omap_dma_s *s = dma->dma->opaque; + int frames, min_elems, elements[__omap_dma_intr_last]; + + a = &ch->active_set; + + src_p = &s->mpu->port[ch->port[0]]; + dest_p = &s->mpu->port[ch->port[1]]; + if ((!ch->constant_fill && !src_p->addr_valid(s->mpu, a->src)) || + (!dest_p->addr_valid(s->mpu, a->dest))) { +#if 0 + /* Bus time-out */ + if (ch->interrupts & TIMEOUT_INTR) + ch->status |= TIMEOUT_INTR; + omap_dma_deactivate_channel(s, ch); + continue; +#endif + printf("%s: Bus time-out in DMA%i operation\n", + __FUNCTION__, dma->num); + } + + min_elems = INT_MAX; + + /* Check all the conditions that terminate the transfer starting + * with those that can occur the soonest. */ +#define INTR_CHECK(cond, id, nelements) \ + if (cond) { \ + elements[id] = nelements; \ + if (elements[id] < min_elems) \ + min_elems = elements[id]; \ + } else \ + elements[id] = INT_MAX; + + /* Elements */ + INTR_CHECK( + ch->sync && !ch->fs && !ch->bs, + omap_dma_intr_element_sync, + 1) + + /* Frames */ + /* TODO: for transfers where entire frames can be read and written + * using memcpy() but a->frame_delta is non-zero, try to still do + * transfers using soc_dma but limit min_elems to a->elements - ... + * See also the TODO in omap_dma_channel_load. */ + INTR_CHECK( + (ch->interrupts & LAST_FRAME_INTR) && + ((a->frame < a->frames - 1) || !a->element), + omap_dma_intr_last_frame, + (a->frames - a->frame - 2) * a->elements + + (a->elements - a->element + 1)) + INTR_CHECK( + ch->interrupts & HALF_FRAME_INTR, + omap_dma_intr_half_frame, + (a->elements >> 1) + + (a->element >= (a->elements >> 1) ? a->elements : 0) - + a->element) + INTR_CHECK( + ch->sync && ch->fs && (ch->interrupts & END_FRAME_INTR), + omap_dma_intr_frame, + a->elements - a->element) + INTR_CHECK( + ch->sync && ch->fs && !ch->bs, + omap_dma_intr_frame_sync, + a->elements - a->element) + + /* Packets */ + INTR_CHECK( + ch->fs && ch->bs && + (ch->interrupts & END_PKT_INTR) && !ch->src_sync, + omap_dma_intr_packet, + a->pck_elements - a->pck_element) + INTR_CHECK( + ch->fs && ch->bs && ch->sync, + omap_dma_intr_packet_sync, + a->pck_elements - a->pck_element) + + /* Blocks */ + INTR_CHECK( + 1, + omap_dma_intr_block, + (a->frames - a->frame - 1) * a->elements + + (a->elements - a->element)) + + dma->bytes = min_elems * ch->data_type; + + /* Set appropriate interrupts and/or deactivate channels */ + +#ifdef MULTI_REQ + /* TODO: should all of this only be done if dma->update, and otherwise + * inside omap_dma_transfer_generic below - check what's faster. */ + if (dma->update) { +#endif + + /* If the channel is element synchronized, deactivate it */ + if (min_elems == elements[omap_dma_intr_element_sync]) + omap_dma_deactivate_channel(s, ch); + + /* If it is the last frame, set the LAST_FRAME interrupt */ + if (min_elems == elements[omap_dma_intr_last_frame]) + ch->status |= LAST_FRAME_INTR; + + /* If exactly half of the frame was reached, set the HALF_FRAME + interrupt */ + if (min_elems == elements[omap_dma_intr_half_frame]) + ch->status |= HALF_FRAME_INTR; + + /* If a full packet has been transferred, set the END_PKT interrupt */ + if (min_elems == elements[omap_dma_intr_packet]) + ch->status |= END_PKT_INTR; + + /* If the channel is packet-synchronized, deactivate it */ + if (min_elems == elements[omap_dma_intr_packet_sync]) + omap_dma_deactivate_channel(s, ch); + + /* If the channel is frame synchronized, deactivate it */ + if (min_elems == elements[omap_dma_intr_frame_sync]) + omap_dma_deactivate_channel(s, ch); + + /* Set the END_FRAME interrupt */ + if (min_elems == elements[omap_dma_intr_frame]) + ch->status |= END_FRAME_INTR; + + if (min_elems == elements[omap_dma_intr_block]) { + /* End of Block */ + /* Disable the channel */ + + if (ch->omap_3_1_compatible_disable) { + omap_dma_disable_channel(s, ch); + if (ch->link_enabled) + omap_dma_enable_channel(s, &s->ch[ch->link_next_ch]); + } else { + if (!ch->auto_init) + omap_dma_disable_channel(s, ch); + else if (ch->repeat || ch->end_prog) + omap_dma_channel_load(ch); + else { + ch->waiting_end_prog = 1; + omap_dma_deactivate_channel(s, ch); + } + } + + if (ch->interrupts & END_BLOCK_INTR) + ch->status |= END_BLOCK_INTR; + } + + /* Update packet number */ + if (ch->fs && ch->bs) { + a->pck_element += min_elems; + a->pck_element %= a->pck_elements; + } + + /* TODO: check if we really need to update anything here or perhaps we + * can skip part of this. */ +#ifndef MULTI_REQ + if (dma->update) { +#endif + a->element += min_elems; + + frames = a->element / a->elements; + a->element = a->element % a->elements; + a->frame += frames; + a->src += min_elems * a->elem_delta[0] + frames * a->frame_delta[0]; + a->dest += min_elems * a->elem_delta[1] + frames * a->frame_delta[1]; + + /* If the channel is async, update cpc */ + if (!ch->sync && frames) + ch->cpc = a->dest & 0xffff; + + /* TODO: if the destination port is IMIF or EMIFF, set the dirty + * bits on it. */ + } + + omap_dma_interrupts_update(s); +} + +void omap_dma_reset(struct soc_dma_s *dma) +{ + int i; + struct omap_dma_s *s = dma->opaque; + + soc_dma_reset(s->dma); + if (s->model < omap_dma_4) + s->gcr = 0x0004; + else + s->gcr = 0x00010010; + s->ocp = 0x00000000; + memset(&s->irqstat, 0, sizeof(s->irqstat)); + memset(&s->irqen, 0, sizeof(s->irqen)); + s->lcd_ch.src = emiff; + s->lcd_ch.condition = 0; + s->lcd_ch.interrupts = 0; + s->lcd_ch.dual = 0; + if (s->model < omap_dma_4) + omap_dma_enable_3_1_mapping(s); + for (i = 0; i < s->chans; i ++) { + s->ch[i].suspend = 0; + s->ch[i].prefetch = 0; + s->ch[i].buf_disable = 0; + s->ch[i].src_sync = 0; + memset(&s->ch[i].burst, 0, sizeof(s->ch[i].burst)); + memset(&s->ch[i].port, 0, sizeof(s->ch[i].port)); + memset(&s->ch[i].mode, 0, sizeof(s->ch[i].mode)); + memset(&s->ch[i].frame_index, 0, sizeof(s->ch[i].frame_index)); + memset(&s->ch[i].element_index, 0, sizeof(s->ch[i].element_index)); + memset(&s->ch[i].endian, 0, sizeof(s->ch[i].endian)); + memset(&s->ch[i].endian_lock, 0, sizeof(s->ch[i].endian_lock)); + memset(&s->ch[i].translate, 0, sizeof(s->ch[i].translate)); + s->ch[i].write_mode = 0; + s->ch[i].data_type = 0; + s->ch[i].transparent_copy = 0; + s->ch[i].constant_fill = 0; + s->ch[i].color = 0x00000000; + s->ch[i].end_prog = 0; + s->ch[i].repeat = 0; + s->ch[i].auto_init = 0; + s->ch[i].link_enabled = 0; + if (s->model < omap_dma_4) + s->ch[i].interrupts = 0x0003; + else + s->ch[i].interrupts = 0x0000; + s->ch[i].status = 0; + s->ch[i].cstatus = 0; + s->ch[i].active = 0; + s->ch[i].enable = 0; + s->ch[i].sync = 0; + s->ch[i].pending_request = 0; + s->ch[i].waiting_end_prog = 0; + s->ch[i].cpc = 0x0000; + s->ch[i].fs = 0; + s->ch[i].bs = 0; + s->ch[i].omap_3_1_compatible_disable = 0; + memset(&s->ch[i].active_set, 0, sizeof(s->ch[i].active_set)); + s->ch[i].priority = 0; + s->ch[i].interleave_disabled = 0; + s->ch[i].type = 0; + } +} + +static int omap_dma_ch_reg_read(struct omap_dma_s *s, + struct omap_dma_channel_s *ch, int reg, uint16_t *value) +{ + switch (reg) { + case 0x00: /* SYS_DMA_CSDP_CH0 */ + *value = (ch->burst[1] << 14) | + (ch->pack[1] << 13) | + (ch->port[1] << 9) | + (ch->burst[0] << 7) | + (ch->pack[0] << 6) | + (ch->port[0] << 2) | + (ch->data_type >> 1); + break; + + case 0x02: /* SYS_DMA_CCR_CH0 */ + if (s->model <= omap_dma_3_1) + *value = 0 << 10; /* FIFO_FLUSH reads as 0 */ + else + *value = ch->omap_3_1_compatible_disable << 10; + *value |= (ch->mode[1] << 14) | + (ch->mode[0] << 12) | + (ch->end_prog << 11) | + (ch->repeat << 9) | + (ch->auto_init << 8) | + (ch->enable << 7) | + (ch->priority << 6) | + (ch->fs << 5) | ch->sync; + break; + + case 0x04: /* SYS_DMA_CICR_CH0 */ + *value = ch->interrupts; + break; + + case 0x06: /* SYS_DMA_CSR_CH0 */ + *value = ch->status; + ch->status &= SYNC; + if (!ch->omap_3_1_compatible_disable && ch->sibling) { + *value |= (ch->sibling->status & 0x3f) << 6; + ch->sibling->status &= SYNC; + } + qemu_irq_lower(ch->irq); + break; + + case 0x08: /* SYS_DMA_CSSA_L_CH0 */ + *value = ch->addr[0] & 0x0000ffff; + break; + + case 0x0a: /* SYS_DMA_CSSA_U_CH0 */ + *value = ch->addr[0] >> 16; + break; + + case 0x0c: /* SYS_DMA_CDSA_L_CH0 */ + *value = ch->addr[1] & 0x0000ffff; + break; + + case 0x0e: /* SYS_DMA_CDSA_U_CH0 */ + *value = ch->addr[1] >> 16; + break; + + case 0x10: /* SYS_DMA_CEN_CH0 */ + *value = ch->elements; + break; + + case 0x12: /* SYS_DMA_CFN_CH0 */ + *value = ch->frames; + break; + + case 0x14: /* SYS_DMA_CFI_CH0 */ + *value = ch->frame_index[0]; + break; + + case 0x16: /* SYS_DMA_CEI_CH0 */ + *value = ch->element_index[0]; + break; + + case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */ + if (ch->omap_3_1_compatible_disable) + *value = ch->active_set.src & 0xffff; /* CSAC */ + else + *value = ch->cpc; + break; + + case 0x1a: /* DMA_CDAC */ + *value = ch->active_set.dest & 0xffff; /* CDAC */ + break; + + case 0x1c: /* DMA_CDEI */ + *value = ch->element_index[1]; + break; + + case 0x1e: /* DMA_CDFI */ + *value = ch->frame_index[1]; + break; + + case 0x20: /* DMA_COLOR_L */ + *value = ch->color & 0xffff; + break; + + case 0x22: /* DMA_COLOR_U */ + *value = ch->color >> 16; + break; + + case 0x24: /* DMA_CCR2 */ + *value = (ch->bs << 2) | + (ch->transparent_copy << 1) | + ch->constant_fill; + break; + + case 0x28: /* DMA_CLNK_CTRL */ + *value = (ch->link_enabled << 15) | + (ch->link_next_ch & 0xf); + break; + + case 0x2a: /* DMA_LCH_CTRL */ + *value = (ch->interleave_disabled << 15) | + ch->type; + break; + + default: + return 1; + } + return 0; +} + +static int omap_dma_ch_reg_write(struct omap_dma_s *s, + struct omap_dma_channel_s *ch, int reg, uint16_t value) +{ + switch (reg) { + case 0x00: /* SYS_DMA_CSDP_CH0 */ + ch->burst[1] = (value & 0xc000) >> 14; + ch->pack[1] = (value & 0x2000) >> 13; + ch->port[1] = (enum omap_dma_port) ((value & 0x1e00) >> 9); + ch->burst[0] = (value & 0x0180) >> 7; + ch->pack[0] = (value & 0x0040) >> 6; + ch->port[0] = (enum omap_dma_port) ((value & 0x003c) >> 2); + ch->data_type = 1 << (value & 3); + if (ch->port[0] >= __omap_dma_port_last) + printf("%s: invalid DMA port %i\n", __FUNCTION__, + ch->port[0]); + if (ch->port[1] >= __omap_dma_port_last) + printf("%s: invalid DMA port %i\n", __FUNCTION__, + ch->port[1]); + if ((value & 3) == 3) + printf("%s: bad data_type for DMA channel\n", __FUNCTION__); + break; + + case 0x02: /* SYS_DMA_CCR_CH0 */ + ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14); + ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12); + ch->end_prog = (value & 0x0800) >> 11; + if (s->model >= omap_dma_3_2) + ch->omap_3_1_compatible_disable = (value >> 10) & 0x1; + ch->repeat = (value & 0x0200) >> 9; + ch->auto_init = (value & 0x0100) >> 8; + ch->priority = (value & 0x0040) >> 6; + ch->fs = (value & 0x0020) >> 5; + ch->sync = value & 0x001f; + + if (value & 0x0080) + omap_dma_enable_channel(s, ch); + else + omap_dma_disable_channel(s, ch); + + if (ch->end_prog) + omap_dma_channel_end_prog(s, ch); + + break; + + case 0x04: /* SYS_DMA_CICR_CH0 */ + ch->interrupts = value & 0x3f; + break; + + case 0x06: /* SYS_DMA_CSR_CH0 */ + OMAP_RO_REG((target_phys_addr_t) reg); + break; + + case 0x08: /* SYS_DMA_CSSA_L_CH0 */ + ch->addr[0] &= 0xffff0000; + ch->addr[0] |= value; + break; + + case 0x0a: /* SYS_DMA_CSSA_U_CH0 */ + ch->addr[0] &= 0x0000ffff; + ch->addr[0] |= (uint32_t) value << 16; + break; + + case 0x0c: /* SYS_DMA_CDSA_L_CH0 */ + ch->addr[1] &= 0xffff0000; + ch->addr[1] |= value; + break; + + case 0x0e: /* SYS_DMA_CDSA_U_CH0 */ + ch->addr[1] &= 0x0000ffff; + ch->addr[1] |= (uint32_t) value << 16; + break; + + case 0x10: /* SYS_DMA_CEN_CH0 */ + ch->elements = value; + break; + + case 0x12: /* SYS_DMA_CFN_CH0 */ + ch->frames = value; + break; + + case 0x14: /* SYS_DMA_CFI_CH0 */ + ch->frame_index[0] = (int16_t) value; + break; + + case 0x16: /* SYS_DMA_CEI_CH0 */ + ch->element_index[0] = (int16_t) value; + break; + + case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */ + OMAP_RO_REG((target_phys_addr_t) reg); + break; + + case 0x1c: /* DMA_CDEI */ + ch->element_index[1] = (int16_t) value; + break; + + case 0x1e: /* DMA_CDFI */ + ch->frame_index[1] = (int16_t) value; + break; + + case 0x20: /* DMA_COLOR_L */ + ch->color &= 0xffff0000; + ch->color |= value; + break; + + case 0x22: /* DMA_COLOR_U */ + ch->color &= 0xffff; + ch->color |= value << 16; + break; + + case 0x24: /* DMA_CCR2 */ + ch->bs = (value >> 2) & 0x1; + ch->transparent_copy = (value >> 1) & 0x1; + ch->constant_fill = value & 0x1; + break; + + case 0x28: /* DMA_CLNK_CTRL */ + ch->link_enabled = (value >> 15) & 0x1; + if (value & (1 << 14)) { /* Stop_Lnk */ + ch->link_enabled = 0; + omap_dma_disable_channel(s, ch); + } + ch->link_next_ch = value & 0x1f; + break; + + case 0x2a: /* DMA_LCH_CTRL */ + ch->interleave_disabled = (value >> 15) & 0x1; + ch->type = value & 0xf; + break; + + default: + return 1; + } + return 0; +} + +static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, + uint16_t value) +{ + switch (offset) { + case 0xbc0: /* DMA_LCD_CSDP */ + s->brust_f2 = (value >> 14) & 0x3; + s->pack_f2 = (value >> 13) & 0x1; + s->data_type_f2 = (1 << ((value >> 11) & 0x3)); + s->brust_f1 = (value >> 7) & 0x3; + s->pack_f1 = (value >> 6) & 0x1; + s->data_type_f1 = (1 << ((value >> 0) & 0x3)); + break; + + case 0xbc2: /* DMA_LCD_CCR */ + s->mode_f2 = (value >> 14) & 0x3; + s->mode_f1 = (value >> 12) & 0x3; + s->end_prog = (value >> 11) & 0x1; + s->omap_3_1_compatible_disable = (value >> 10) & 0x1; + s->repeat = (value >> 9) & 0x1; + s->auto_init = (value >> 8) & 0x1; + s->running = (value >> 7) & 0x1; + s->priority = (value >> 6) & 0x1; + s->bs = (value >> 4) & 0x1; + break; + + case 0xbc4: /* DMA_LCD_CTRL */ + s->dst = (value >> 8) & 0x1; + s->src = ((value >> 6) & 0x3) << 1; + s->condition = 0; + /* Assume no bus errors and thus no BUS_ERROR irq bits. */ + s->interrupts = (value >> 1) & 1; + s->dual = value & 1; + break; + + case 0xbc8: /* TOP_B1_L */ + s->src_f1_top &= 0xffff0000; + s->src_f1_top |= 0x0000ffff & value; + break; + + case 0xbca: /* TOP_B1_U */ + s->src_f1_top &= 0x0000ffff; + s->src_f1_top |= value << 16; + break; + + case 0xbcc: /* BOT_B1_L */ + s->src_f1_bottom &= 0xffff0000; + s->src_f1_bottom |= 0x0000ffff & value; + break; + + case 0xbce: /* BOT_B1_U */ + s->src_f1_bottom &= 0x0000ffff; + s->src_f1_bottom |= (uint32_t) value << 16; + break; + + case 0xbd0: /* TOP_B2_L */ + s->src_f2_top &= 0xffff0000; + s->src_f2_top |= 0x0000ffff & value; + break; + + case 0xbd2: /* TOP_B2_U */ + s->src_f2_top &= 0x0000ffff; + s->src_f2_top |= (uint32_t) value << 16; + break; + + case 0xbd4: /* BOT_B2_L */ + s->src_f2_bottom &= 0xffff0000; + s->src_f2_bottom |= 0x0000ffff & value; + break; + + case 0xbd6: /* BOT_B2_U */ + s->src_f2_bottom &= 0x0000ffff; + s->src_f2_bottom |= (uint32_t) value << 16; + break; + + case 0xbd8: /* DMA_LCD_SRC_EI_B1 */ + s->element_index_f1 = value; + break; + + case 0xbda: /* DMA_LCD_SRC_FI_B1_L */ + s->frame_index_f1 &= 0xffff0000; + s->frame_index_f1 |= 0x0000ffff & value; + break; + + case 0xbf4: /* DMA_LCD_SRC_FI_B1_U */ + s->frame_index_f1 &= 0x0000ffff; + s->frame_index_f1 |= (uint32_t) value << 16; + break; + + case 0xbdc: /* DMA_LCD_SRC_EI_B2 */ + s->element_index_f2 = value; + break; + + case 0xbde: /* DMA_LCD_SRC_FI_B2_L */ + s->frame_index_f2 &= 0xffff0000; + s->frame_index_f2 |= 0x0000ffff & value; + break; + + case 0xbf6: /* DMA_LCD_SRC_FI_B2_U */ + s->frame_index_f2 &= 0x0000ffff; + s->frame_index_f2 |= (uint32_t) value << 16; + break; + + case 0xbe0: /* DMA_LCD_SRC_EN_B1 */ + s->elements_f1 = value; + break; + + case 0xbe4: /* DMA_LCD_SRC_FN_B1 */ + s->frames_f1 = value; + break; + + case 0xbe2: /* DMA_LCD_SRC_EN_B2 */ + s->elements_f2 = value; + break; + + case 0xbe6: /* DMA_LCD_SRC_FN_B2 */ + s->frames_f2 = value; + break; + + case 0xbea: /* DMA_LCD_LCH_CTRL */ + s->lch_type = value & 0xf; + break; + + default: + return 1; + } + return 0; +} + +static int omap_dma_3_2_lcd_read(struct omap_dma_lcd_channel_s *s, int offset, + uint16_t *ret) +{ + switch (offset) { + case 0xbc0: /* DMA_LCD_CSDP */ + *ret = (s->brust_f2 << 14) | + (s->pack_f2 << 13) | + ((s->data_type_f2 >> 1) << 11) | + (s->brust_f1 << 7) | + (s->pack_f1 << 6) | + ((s->data_type_f1 >> 1) << 0); + break; + + case 0xbc2: /* DMA_LCD_CCR */ + *ret = (s->mode_f2 << 14) | + (s->mode_f1 << 12) | + (s->end_prog << 11) | + (s->omap_3_1_compatible_disable << 10) | + (s->repeat << 9) | + (s->auto_init << 8) | + (s->running << 7) | + (s->priority << 6) | + (s->bs << 4); + break; + + case 0xbc4: /* DMA_LCD_CTRL */ + qemu_irq_lower(s->irq); + *ret = (s->dst << 8) | + ((s->src & 0x6) << 5) | + (s->condition << 3) | + (s->interrupts << 1) | + s->dual; + break; + + case 0xbc8: /* TOP_B1_L */ + *ret = s->src_f1_top & 0xffff; + break; + + case 0xbca: /* TOP_B1_U */ + *ret = s->src_f1_top >> 16; + break; + + case 0xbcc: /* BOT_B1_L */ + *ret = s->src_f1_bottom & 0xffff; + break; + + case 0xbce: /* BOT_B1_U */ + *ret = s->src_f1_bottom >> 16; + break; + + case 0xbd0: /* TOP_B2_L */ + *ret = s->src_f2_top & 0xffff; + break; + + case 0xbd2: /* TOP_B2_U */ + *ret = s->src_f2_top >> 16; + break; + + case 0xbd4: /* BOT_B2_L */ + *ret = s->src_f2_bottom & 0xffff; + break; + + case 0xbd6: /* BOT_B2_U */ + *ret = s->src_f2_bottom >> 16; + break; + + case 0xbd8: /* DMA_LCD_SRC_EI_B1 */ + *ret = s->element_index_f1; + break; + + case 0xbda: /* DMA_LCD_SRC_FI_B1_L */ + *ret = s->frame_index_f1 & 0xffff; + break; + + case 0xbf4: /* DMA_LCD_SRC_FI_B1_U */ + *ret = s->frame_index_f1 >> 16; + break; + + case 0xbdc: /* DMA_LCD_SRC_EI_B2 */ + *ret = s->element_index_f2; + break; + + case 0xbde: /* DMA_LCD_SRC_FI_B2_L */ + *ret = s->frame_index_f2 & 0xffff; + break; + + case 0xbf6: /* DMA_LCD_SRC_FI_B2_U */ + *ret = s->frame_index_f2 >> 16; + break; + + case 0xbe0: /* DMA_LCD_SRC_EN_B1 */ + *ret = s->elements_f1; + break; + + case 0xbe4: /* DMA_LCD_SRC_FN_B1 */ + *ret = s->frames_f1; + break; + + case 0xbe2: /* DMA_LCD_SRC_EN_B2 */ + *ret = s->elements_f2; + break; + + case 0xbe6: /* DMA_LCD_SRC_FN_B2 */ + *ret = s->frames_f2; + break; + + case 0xbea: /* DMA_LCD_LCH_CTRL */ + *ret = s->lch_type; + break; + + default: + return 1; + } + return 0; +} + +static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, + uint16_t value) +{ + switch (offset) { + case 0x300: /* SYS_DMA_LCD_CTRL */ + s->src = (value & 0x40) ? imif : emiff; + s->condition = 0; + /* Assume no bus errors and thus no BUS_ERROR irq bits. */ + s->interrupts = (value >> 1) & 1; + s->dual = value & 1; + break; + + case 0x302: /* SYS_DMA_LCD_TOP_F1_L */ + s->src_f1_top &= 0xffff0000; + s->src_f1_top |= 0x0000ffff & value; + break; + + case 0x304: /* SYS_DMA_LCD_TOP_F1_U */ + s->src_f1_top &= 0x0000ffff; + s->src_f1_top |= value << 16; + break; + + case 0x306: /* SYS_DMA_LCD_BOT_F1_L */ + s->src_f1_bottom &= 0xffff0000; + s->src_f1_bottom |= 0x0000ffff & value; + break; + + case 0x308: /* SYS_DMA_LCD_BOT_F1_U */ + s->src_f1_bottom &= 0x0000ffff; + s->src_f1_bottom |= value << 16; + break; + + case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */ + s->src_f2_top &= 0xffff0000; + s->src_f2_top |= 0x0000ffff & value; + break; + + case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */ + s->src_f2_top &= 0x0000ffff; + s->src_f2_top |= value << 16; + break; + + case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */ + s->src_f2_bottom &= 0xffff0000; + s->src_f2_bottom |= 0x0000ffff & value; + break; + + case 0x310: /* SYS_DMA_LCD_BOT_F2_U */ + s->src_f2_bottom &= 0x0000ffff; + s->src_f2_bottom |= value << 16; + break; + + default: + return 1; + } + return 0; +} + +static int omap_dma_3_1_lcd_read(struct omap_dma_lcd_channel_s *s, int offset, + uint16_t *ret) +{ + int i; + + switch (offset) { + case 0x300: /* SYS_DMA_LCD_CTRL */ + i = s->condition; + s->condition = 0; + qemu_irq_lower(s->irq); + *ret = ((s->src == imif) << 6) | (i << 3) | + (s->interrupts << 1) | s->dual; + break; + + case 0x302: /* SYS_DMA_LCD_TOP_F1_L */ + *ret = s->src_f1_top & 0xffff; + break; + + case 0x304: /* SYS_DMA_LCD_TOP_F1_U */ + *ret = s->src_f1_top >> 16; + break; + + case 0x306: /* SYS_DMA_LCD_BOT_F1_L */ + *ret = s->src_f1_bottom & 0xffff; + break; + + case 0x308: /* SYS_DMA_LCD_BOT_F1_U */ + *ret = s->src_f1_bottom >> 16; + break; + + case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */ + *ret = s->src_f2_top & 0xffff; + break; + + case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */ + *ret = s->src_f2_top >> 16; + break; + + case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */ + *ret = s->src_f2_bottom & 0xffff; + break; + + case 0x310: /* SYS_DMA_LCD_BOT_F2_U */ + *ret = s->src_f2_bottom >> 16; + break; + + default: + return 1; + } + return 0; +} + +static int omap_dma_sys_write(struct omap_dma_s *s, int offset, uint16_t value) +{ + switch (offset) { + case 0x400: /* SYS_DMA_GCR */ + s->gcr = value; + break; + + case 0x404: /* DMA_GSCR */ + if (value & 0x8) + omap_dma_disable_3_1_mapping(s); + else + omap_dma_enable_3_1_mapping(s); + break; + + case 0x408: /* DMA_GRST */ + if (value & 0x1) + omap_dma_reset(s->dma); + break; + + default: + return 1; + } + return 0; +} + +static int omap_dma_sys_read(struct omap_dma_s *s, int offset, + uint16_t *ret) +{ + switch (offset) { + case 0x400: /* SYS_DMA_GCR */ + *ret = s->gcr; + break; + + case 0x404: /* DMA_GSCR */ + *ret = s->omap_3_1_mapping_disabled << 3; + break; + + case 0x408: /* DMA_GRST */ + *ret = 0; + break; + + case 0x442: /* DMA_HW_ID */ + case 0x444: /* DMA_PCh2_ID */ + case 0x446: /* DMA_PCh0_ID */ + case 0x448: /* DMA_PCh1_ID */ + case 0x44a: /* DMA_PChG_ID */ + case 0x44c: /* DMA_PChD_ID */ + *ret = 1; + break; + + case 0x44e: /* DMA_CAPS_0_U */ + *ret = (s->caps[0] >> 16) & 0xffff; + break; + case 0x450: /* DMA_CAPS_0_L */ + *ret = (s->caps[0] >> 0) & 0xffff; + break; + + case 0x452: /* DMA_CAPS_1_U */ + *ret = (s->caps[1] >> 16) & 0xffff; + break; + case 0x454: /* DMA_CAPS_1_L */ + *ret = (s->caps[1] >> 0) & 0xffff; + break; + + case 0x456: /* DMA_CAPS_2 */ + *ret = s->caps[2]; + break; + + case 0x458: /* DMA_CAPS_3 */ + *ret = s->caps[3]; + break; + + case 0x45a: /* DMA_CAPS_4 */ + *ret = s->caps[4]; + break; + + case 0x460: /* DMA_PCh2_SR */ + case 0x480: /* DMA_PCh0_SR */ + case 0x482: /* DMA_PCh1_SR */ + case 0x4c0: /* DMA_PChD_SR_0 */ + printf("%s: Physical Channel Status Registers not implemented.\n", + __FUNCTION__); + *ret = 0xff; + break; + + default: + return 1; + } + return 0; +} + +static uint32_t omap_dma_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_dma_s *s = (struct omap_dma_s *) opaque; + int reg, ch, offset = addr - s->base; + uint16_t ret; + + switch (offset) { + case 0x300 ... 0x3fe: + if (s->model <= omap_dma_3_1 || !s->omap_3_1_mapping_disabled) { + if (omap_dma_3_1_lcd_read(&s->lcd_ch, offset, &ret)) + break; + return ret; + } + /* Fall through. */ + case 0x000 ... 0x2fe: + reg = offset & 0x3f; + ch = (offset >> 6) & 0x0f; + if (omap_dma_ch_reg_read(s, &s->ch[ch], reg, &ret)) + break; + return ret; + + case 0x404 ... 0x4fe: + if (s->model <= omap_dma_3_1) + break; + /* Fall through. */ + case 0x400: + if (omap_dma_sys_read(s, offset, &ret)) + break; + return ret; + + case 0xb00 ... 0xbfe: + if (s->model == omap_dma_3_2 && s->omap_3_1_mapping_disabled) { + if (omap_dma_3_2_lcd_read(&s->lcd_ch, offset, &ret)) + break; + return ret; + } + break; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_dma_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_dma_s *s = (struct omap_dma_s *) opaque; + int reg, ch, offset = addr - s->base; + + switch (offset) { + case 0x300 ... 0x3fe: + if (s->model <= omap_dma_3_1 || !s->omap_3_1_mapping_disabled) { + if (omap_dma_3_1_lcd_write(&s->lcd_ch, offset, value)) + break; + return; + } + /* Fall through. */ + case 0x000 ... 0x2fe: + reg = offset & 0x3f; + ch = (offset >> 6) & 0x0f; + if (omap_dma_ch_reg_write(s, &s->ch[ch], reg, value)) + break; + return; + + case 0x404 ... 0x4fe: + if (s->model <= omap_dma_3_1) + break; + case 0x400: + /* Fall through. */ + if (omap_dma_sys_write(s, offset, value)) + break; + return; + + case 0xb00 ... 0xbfe: + if (s->model == omap_dma_3_2 && s->omap_3_1_mapping_disabled) { + if (omap_dma_3_2_lcd_write(&s->lcd_ch, offset, value)) + break; + return; + } + break; + } + + OMAP_BAD_REG(addr); +} + +static CPUReadMemoryFunc *omap_dma_readfn[] = { + omap_badwidth_read16, + omap_dma_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_dma_writefn[] = { + omap_badwidth_write16, + omap_dma_write, + omap_badwidth_write16, +}; + +static void omap_dma_request(void *opaque, int drq, int req) +{ + struct omap_dma_s *s = (struct omap_dma_s *) opaque; + /* The request pins are level triggered in QEMU. */ + if (req) { + if (~s->dma->drqbmp & (1 << drq)) { + s->dma->drqbmp |= 1 << drq; + omap_dma_process_request(s, drq); + } + } else + s->dma->drqbmp &= ~(1 << drq); +} + +/* XXX: this won't be needed once soc_dma knows about clocks. */ +static void omap_dma_clk_update(void *opaque, int line, int on) +{ + struct omap_dma_s *s = (struct omap_dma_s *) opaque; + int i; + + s->dma->freq = omap_clk_getrate(s->clk); + + for (i = 0; i < s->chans; i ++) + if (s->ch[i].active) + soc_dma_set_request(s->ch[i].dma, on); +} + +static void omap_dma_setcaps(struct omap_dma_s *s) +{ + switch (s->model) { + default: + case omap_dma_3_1: + break; + case omap_dma_3_2: + case omap_dma_4: + /* XXX Only available for sDMA */ + s->caps[0] = + (1 << 19) | /* Constant Fill Capability */ + (1 << 18); /* Transparent BLT Capability */ + s->caps[1] = + (1 << 1); /* 1-bit palettized capability (DMA 3.2 only) */ + s->caps[2] = + (1 << 8) | /* SEPARATE_SRC_AND_DST_INDEX_CPBLTY */ + (1 << 7) | /* DST_DOUBLE_INDEX_ADRS_CPBLTY */ + (1 << 6) | /* DST_SINGLE_INDEX_ADRS_CPBLTY */ + (1 << 5) | /* DST_POST_INCRMNT_ADRS_CPBLTY */ + (1 << 4) | /* DST_CONST_ADRS_CPBLTY */ + (1 << 3) | /* SRC_DOUBLE_INDEX_ADRS_CPBLTY */ + (1 << 2) | /* SRC_SINGLE_INDEX_ADRS_CPBLTY */ + (1 << 1) | /* SRC_POST_INCRMNT_ADRS_CPBLTY */ + (1 << 0); /* SRC_CONST_ADRS_CPBLTY */ + s->caps[3] = + (1 << 6) | /* BLOCK_SYNCHR_CPBLTY (DMA 4 only) */ + (1 << 7) | /* PKT_SYNCHR_CPBLTY (DMA 4 only) */ + (1 << 5) | /* CHANNEL_CHAINING_CPBLTY */ + (1 << 4) | /* LCh_INTERLEAVE_CPBLTY */ + (1 << 3) | /* AUTOINIT_REPEAT_CPBLTY (DMA 3.2 only) */ + (1 << 2) | /* AUTOINIT_ENDPROG_CPBLTY (DMA 3.2 only) */ + (1 << 1) | /* FRAME_SYNCHR_CPBLTY */ + (1 << 0); /* ELMNT_SYNCHR_CPBLTY */ + s->caps[4] = + (1 << 7) | /* PKT_INTERRUPT_CPBLTY (DMA 4 only) */ + (1 << 6) | /* SYNC_STATUS_CPBLTY */ + (1 << 5) | /* BLOCK_INTERRUPT_CPBLTY */ + (1 << 4) | /* LAST_FRAME_INTERRUPT_CPBLTY */ + (1 << 3) | /* FRAME_INTERRUPT_CPBLTY */ + (1 << 2) | /* HALF_FRAME_INTERRUPT_CPBLTY */ + (1 << 1) | /* EVENT_DROP_INTERRUPT_CPBLTY */ + (1 << 0); /* TIMEOUT_INTERRUPT_CPBLTY (DMA 3.2 only) */ + break; + } +} + +struct soc_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs, + qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk, + enum omap_dma_model model) +{ + int iomemtype, num_irqs, memsize, i; + struct omap_dma_s *s = (struct omap_dma_s *) + qemu_mallocz(sizeof(struct omap_dma_s)); + + if (model <= omap_dma_3_1) { + num_irqs = 6; + memsize = 0x800; + } else { + num_irqs = 16; + memsize = 0xc00; + } + s->base = base; + s->model = model; + s->mpu = mpu; + s->clk = clk; + s->lcd_ch.irq = lcd_irq; + s->lcd_ch.mpu = mpu; + + s->dma = soc_dma_init((model <= omap_dma_3_1) ? 9 : 16); + s->dma->freq = omap_clk_getrate(clk); + s->dma->transfer_fn = omap_dma_transfer_generic; + s->dma->setup_fn = omap_dma_transfer_setup; + s->dma->drq = qemu_allocate_irqs(omap_dma_request, s, 32); + s->dma->opaque = s; + + while (num_irqs --) + s->ch[num_irqs].irq = irqs[num_irqs]; + for (i = 0; i < 3; i ++) { + s->ch[i].sibling = &s->ch[i + 6]; + s->ch[i + 6].sibling = &s->ch[i]; + } + for (i = (model <= omap_dma_3_1) ? 8 : 15; i >= 0; i --) { + s->ch[i].dma = &s->dma->ch[i]; + s->dma->ch[i].opaque = &s->ch[i]; + } + + omap_dma_setcaps(s); + omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]); + omap_dma_reset(s->dma); + omap_dma_clk_update(s, 0, 1); + + iomemtype = cpu_register_io_memory(0, omap_dma_readfn, + omap_dma_writefn, s); + cpu_register_physical_memory(s->base, memsize, iomemtype); + + mpu->drq = s->dma->drq; + + return s->dma; +} + +static void omap_dma_interrupts_4_update(struct omap_dma_s *s) +{ + struct omap_dma_channel_s *ch = s->ch; + uint32_t bmp, bit; + + for (bmp = 0, bit = 1; bit; ch ++, bit <<= 1) + if (ch->status) { + bmp |= bit; + ch->cstatus |= ch->status; + ch->status = 0; + } + if ((s->irqstat[0] |= s->irqen[0] & bmp)) + qemu_irq_raise(s->irq[0]); + if ((s->irqstat[1] |= s->irqen[1] & bmp)) + qemu_irq_raise(s->irq[1]); + if ((s->irqstat[2] |= s->irqen[2] & bmp)) + qemu_irq_raise(s->irq[2]); + if ((s->irqstat[3] |= s->irqen[3] & bmp)) + qemu_irq_raise(s->irq[3]); +} + +static uint32_t omap_dma4_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_dma_s *s = (struct omap_dma_s *) opaque; + int irqn = 0, chnum, offset = addr - s->base; + struct omap_dma_channel_s *ch; + + switch (offset) { + case 0x00: /* DMA4_REVISION */ + return 0x40; + + case 0x14: /* DMA4_IRQSTATUS_L3 */ + irqn ++; + case 0x10: /* DMA4_IRQSTATUS_L2 */ + irqn ++; + case 0x0c: /* DMA4_IRQSTATUS_L1 */ + irqn ++; + case 0x08: /* DMA4_IRQSTATUS_L0 */ + return s->irqstat[irqn]; + + case 0x24: /* DMA4_IRQENABLE_L3 */ + irqn ++; + case 0x20: /* DMA4_IRQENABLE_L2 */ + irqn ++; + case 0x1c: /* DMA4_IRQENABLE_L1 */ + irqn ++; + case 0x18: /* DMA4_IRQENABLE_L0 */ + return s->irqen[irqn]; + + case 0x28: /* DMA4_SYSSTATUS */ + return 1; /* RESETDONE */ + + case 0x2c: /* DMA4_OCP_SYSCONFIG */ + return s->ocp; + + case 0x64: /* DMA4_CAPS_0 */ + return s->caps[0]; + case 0x6c: /* DMA4_CAPS_2 */ + return s->caps[2]; + case 0x70: /* DMA4_CAPS_3 */ + return s->caps[3]; + case 0x74: /* DMA4_CAPS_4 */ + return s->caps[4]; + + case 0x78: /* DMA4_GCR */ + return s->gcr; + + case 0x80 ... 0xfff: + offset -= 0x80; + chnum = offset / 0x60; + ch = s->ch + chnum; + offset -= chnum * 0x60; + break; + + default: + OMAP_BAD_REG(addr); + return 0; + } + + /* Per-channel registers */ + switch (offset) { + case 0x00: /* DMA4_CCR */ + return (ch->buf_disable << 25) | + (ch->src_sync << 24) | + (ch->prefetch << 23) | + ((ch->sync & 0x60) << 14) | + (ch->bs << 18) | + (ch->transparent_copy << 17) | + (ch->constant_fill << 16) | + (ch->mode[1] << 14) | + (ch->mode[0] << 12) | + (0 << 10) | (0 << 9) | + (ch->suspend << 8) | + (ch->enable << 7) | + (ch->priority << 6) | + (ch->fs << 5) | (ch->sync & 0x1f); + + case 0x04: /* DMA4_CLNK_CTRL */ + return (ch->link_enabled << 15) | ch->link_next_ch; + + case 0x08: /* DMA4_CICR */ + return ch->interrupts; + + case 0x0c: /* DMA4_CSR */ + return ch->cstatus; + + case 0x10: /* DMA4_CSDP */ + return (ch->endian[0] << 21) | + (ch->endian_lock[0] << 20) | + (ch->endian[1] << 19) | + (ch->endian_lock[1] << 18) | + (ch->write_mode << 16) | + (ch->burst[1] << 14) | + (ch->pack[1] << 13) | + (ch->translate[1] << 9) | + (ch->burst[0] << 7) | + (ch->pack[0] << 6) | + (ch->translate[0] << 2) | + (ch->data_type >> 1); + + case 0x14: /* DMA4_CEN */ + return ch->elements; + + case 0x18: /* DMA4_CFN */ + return ch->frames; + + case 0x1c: /* DMA4_CSSA */ + return ch->addr[0]; + + case 0x20: /* DMA4_CDSA */ + return ch->addr[1]; + + case 0x24: /* DMA4_CSEI */ + return ch->element_index[0]; + + case 0x28: /* DMA4_CSFI */ + return ch->frame_index[0]; + + case 0x2c: /* DMA4_CDEI */ + return ch->element_index[1]; + + case 0x30: /* DMA4_CDFI */ + return ch->frame_index[1]; + + case 0x34: /* DMA4_CSAC */ + return ch->active_set.src & 0xffff; + + case 0x38: /* DMA4_CDAC */ + return ch->active_set.dest & 0xffff; + + case 0x3c: /* DMA4_CCEN */ + return ch->active_set.element; + + case 0x40: /* DMA4_CCFN */ + return ch->active_set.frame; + + case 0x44: /* DMA4_COLOR */ + /* XXX only in sDMA */ + return ch->color; + + default: + OMAP_BAD_REG(addr); + return 0; + } +} + +static void omap_dma4_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_dma_s *s = (struct omap_dma_s *) opaque; + int chnum, irqn = 0, offset = addr - s->base; + struct omap_dma_channel_s *ch; + + switch (offset) { + case 0x14: /* DMA4_IRQSTATUS_L3 */ + irqn ++; + case 0x10: /* DMA4_IRQSTATUS_L2 */ + irqn ++; + case 0x0c: /* DMA4_IRQSTATUS_L1 */ + irqn ++; + case 0x08: /* DMA4_IRQSTATUS_L0 */ + s->irqstat[irqn] &= ~value; + if (!s->irqstat[irqn]) + qemu_irq_lower(s->irq[irqn]); + return; + + case 0x24: /* DMA4_IRQENABLE_L3 */ + irqn ++; + case 0x20: /* DMA4_IRQENABLE_L2 */ + irqn ++; + case 0x1c: /* DMA4_IRQENABLE_L1 */ + irqn ++; + case 0x18: /* DMA4_IRQENABLE_L0 */ + s->irqen[irqn] = value; + return; + + case 0x2c: /* DMA4_OCP_SYSCONFIG */ + if (value & 2) /* SOFTRESET */ + omap_dma_reset(s->dma); + s->ocp = value & 0x3321; + if (((s->ocp >> 12) & 3) == 3) /* MIDLEMODE */ + fprintf(stderr, "%s: invalid DMA power mode\n", __FUNCTION__); + return; + + case 0x78: /* DMA4_GCR */ + s->gcr = value & 0x00ff00ff; + if ((value & 0xff) == 0x00) /* MAX_CHANNEL_FIFO_DEPTH */ + fprintf(stderr, "%s: wrong FIFO depth in GCR\n", __FUNCTION__); + return; + + case 0x80 ... 0xfff: + offset -= 0x80; + chnum = offset / 0x60; + ch = s->ch + chnum; + offset -= chnum * 0x60; + break; + + case 0x00: /* DMA4_REVISION */ + case 0x28: /* DMA4_SYSSTATUS */ + case 0x64: /* DMA4_CAPS_0 */ + case 0x6c: /* DMA4_CAPS_2 */ + case 0x70: /* DMA4_CAPS_3 */ + case 0x74: /* DMA4_CAPS_4 */ + OMAP_RO_REG(addr); + return; + + default: + OMAP_BAD_REG(addr); + return; + } + + /* Per-channel registers */ + switch (offset) { + case 0x00: /* DMA4_CCR */ + ch->buf_disable = (value >> 25) & 1; + ch->src_sync = (value >> 24) & 1; /* XXX For CamDMA must be 1 */ + if (ch->buf_disable && !ch->src_sync) + fprintf(stderr, "%s: Buffering disable is not allowed in " + "destination synchronised mode\n", __FUNCTION__); + ch->prefetch = (value >> 23) & 1; + ch->bs = (value >> 18) & 1; + ch->transparent_copy = (value >> 17) & 1; + ch->constant_fill = (value >> 16) & 1; + ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14); + ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12); + ch->suspend = (value & 0x0100) >> 8; + ch->priority = (value & 0x0040) >> 6; + ch->fs = (value & 0x0020) >> 5; + if (ch->fs && ch->bs && ch->mode[0] && ch->mode[1]) + fprintf(stderr, "%s: For a packet transfer at least one port " + "must be constant-addressed\n", __FUNCTION__); + ch->sync = (value & 0x001f) | ((value >> 14) & 0x0060); + /* XXX must be 0x01 for CamDMA */ + + if (value & 0x0080) + omap_dma_enable_channel(s, ch); + else + omap_dma_disable_channel(s, ch); + + break; + + case 0x04: /* DMA4_CLNK_CTRL */ + ch->link_enabled = (value >> 15) & 0x1; + ch->link_next_ch = value & 0x1f; + break; + + case 0x08: /* DMA4_CICR */ + ch->interrupts = value & 0x09be; + break; + + case 0x0c: /* DMA4_CSR */ + ch->cstatus &= ~value; + break; + + case 0x10: /* DMA4_CSDP */ + ch->endian[0] =(value >> 21) & 1; + ch->endian_lock[0] =(value >> 20) & 1; + ch->endian[1] =(value >> 19) & 1; + ch->endian_lock[1] =(value >> 18) & 1; + if (ch->endian[0] != ch->endian[1]) + fprintf(stderr, "%s: DMA endiannes conversion enable attempt\n", + __FUNCTION__); + ch->write_mode = (value >> 16) & 3; + ch->burst[1] = (value & 0xc000) >> 14; + ch->pack[1] = (value & 0x2000) >> 13; + ch->translate[1] = (value & 0x1e00) >> 9; + ch->burst[0] = (value & 0x0180) >> 7; + ch->pack[0] = (value & 0x0040) >> 6; + ch->translate[0] = (value & 0x003c) >> 2; + if (ch->translate[0] | ch->translate[1]) + fprintf(stderr, "%s: bad MReqAddressTranslate sideband signal\n", + __FUNCTION__); + ch->data_type = 1 << (value & 3); + if ((value & 3) == 3) + printf("%s: bad data_type for DMA channel\n", __FUNCTION__); + break; + + case 0x14: /* DMA4_CEN */ + ch->set_update = 1; + ch->elements = value & 0xffffff; + break; + + case 0x18: /* DMA4_CFN */ + ch->frames = value & 0xffff; + ch->set_update = 1; + break; + + case 0x1c: /* DMA4_CSSA */ + ch->addr[0] = (target_phys_addr_t) (uint32_t) value; + ch->set_update = 1; + break; + + case 0x20: /* DMA4_CDSA */ + ch->addr[1] = (target_phys_addr_t) (uint32_t) value; + ch->set_update = 1; + break; + + case 0x24: /* DMA4_CSEI */ + ch->element_index[0] = (int16_t) value; + ch->set_update = 1; + break; + + case 0x28: /* DMA4_CSFI */ + ch->frame_index[0] = (int32_t) value; + ch->set_update = 1; + break; + + case 0x2c: /* DMA4_CDEI */ + ch->element_index[1] = (int16_t) value; + ch->set_update = 1; + break; + + case 0x30: /* DMA4_CDFI */ + ch->frame_index[1] = (int32_t) value; + ch->set_update = 1; + break; + + case 0x44: /* DMA4_COLOR */ + /* XXX only in sDMA */ + ch->color = value; + break; + + case 0x34: /* DMA4_CSAC */ + case 0x38: /* DMA4_CDAC */ + case 0x3c: /* DMA4_CCEN */ + case 0x40: /* DMA4_CCFN */ + OMAP_RO_REG(addr); + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_dma4_readfn[] = { + omap_badwidth_read16, + omap_dma4_read, + omap_dma4_read, +}; + +static CPUWriteMemoryFunc *omap_dma4_writefn[] = { + omap_badwidth_write16, + omap_dma4_write, + omap_dma4_write, +}; + +struct soc_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs, + struct omap_mpu_state_s *mpu, int fifo, + int chans, omap_clk iclk, omap_clk fclk) +{ + int iomemtype, i; + struct omap_dma_s *s = (struct omap_dma_s *) + qemu_mallocz(sizeof(struct omap_dma_s)); + + s->base = base; + s->model = omap_dma_4; + s->chans = chans; + s->mpu = mpu; + s->clk = fclk; + + s->dma = soc_dma_init(s->chans); + s->dma->freq = omap_clk_getrate(fclk); + s->dma->transfer_fn = omap_dma_transfer_generic; + s->dma->setup_fn = omap_dma_transfer_setup; + s->dma->drq = qemu_allocate_irqs(omap_dma_request, s, 64); + s->dma->opaque = s; + for (i = 0; i < s->chans; i ++) { + s->ch[i].dma = &s->dma->ch[i]; + s->dma->ch[i].opaque = &s->ch[i]; + } + + memcpy(&s->irq, irqs, sizeof(s->irq)); + s->intr_update = omap_dma_interrupts_4_update; + + omap_dma_setcaps(s); + omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]); + omap_dma_reset(s->dma); + omap_dma_clk_update(s, 0, !!s->dma->freq); + + iomemtype = cpu_register_io_memory(0, omap_dma4_readfn, + omap_dma4_writefn, s); + cpu_register_physical_memory(s->base, 0x1000, iomemtype); + + mpu->drq = s->dma->drq; + + return s->dma; +} + +struct omap_dma_lcd_channel_s *omap_dma_get_lcdch(struct soc_dma_s *dma) +{ + struct omap_dma_s *s = dma->opaque; + + return &s->lcd_ch; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/omap_dss.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/omap_dss.c --- qemu-0.9.1/hw/omap_dss.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/omap_dss.c 2008-08-22 09:57:19.000000000 +0100 @@ -0,0 +1,1094 @@ +/* + * OMAP2 Display Subsystem. + * + * Copyright (C) 2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include "hw.h" +#include "console.h" +#include "omap.h" + +struct omap_dss_s { + target_phys_addr_t diss_base; + target_phys_addr_t disc_base; + target_phys_addr_t rfbi_base; + target_phys_addr_t venc_base; + target_phys_addr_t im3_base; + qemu_irq irq; + qemu_irq drq; + DisplayState *state; + + int autoidle; + int control; + int enable; + + struct omap_dss_panel_s { + int enable; + int nx; + int ny; + + int x; + int y; + } dig, lcd; + + struct { + uint32_t idlemode; + uint32_t irqst; + uint32_t irqen; + uint32_t control; + uint32_t config; + uint32_t capable; + uint32_t timing[4]; + int line; + uint32_t bg[2]; + uint32_t trans[2]; + + struct omap_dss_plane_s { + int enable; + int bpp; + int posx; + int posy; + int nx; + int ny; + + target_phys_addr_t addr[3]; + + uint32_t attr; + uint32_t tresh; + int rowinc; + int colinc; + int wininc; + } l[3]; + + int invalidate; + uint16_t palette[256]; + } dispc; + + struct { + int idlemode; + uint32_t control; + int enable; + int pixels; + int busy; + int skiplines; + uint16_t rxbuf; + uint32_t config[2]; + uint32_t time[4]; + uint32_t data[6]; + uint16_t vsync; + uint16_t hsync; + struct rfbi_chip_s *chip[2]; + } rfbi; +}; + +static void omap_dispc_interrupt_update(struct omap_dss_s *s) +{ + qemu_set_irq(s->irq, s->dispc.irqst & s->dispc.irqen); +} + +static void omap_rfbi_reset(struct omap_dss_s *s) +{ + s->rfbi.idlemode = 0; + s->rfbi.control = 2; + s->rfbi.enable = 0; + s->rfbi.pixels = 0; + s->rfbi.skiplines = 0; + s->rfbi.busy = 0; + s->rfbi.config[0] = 0x00310000; + s->rfbi.config[1] = 0x00310000; + s->rfbi.time[0] = 0; + s->rfbi.time[1] = 0; + s->rfbi.time[2] = 0; + s->rfbi.time[3] = 0; + s->rfbi.data[0] = 0; + s->rfbi.data[1] = 0; + s->rfbi.data[2] = 0; + s->rfbi.data[3] = 0; + s->rfbi.data[4] = 0; + s->rfbi.data[5] = 0; + s->rfbi.vsync = 0; + s->rfbi.hsync = 0; +} + +void omap_dss_reset(struct omap_dss_s *s) +{ + s->autoidle = 0; + s->control = 0; + s->enable = 0; + + s->dig.enable = 0; + s->dig.nx = 1; + s->dig.ny = 1; + + s->lcd.enable = 0; + s->lcd.nx = 1; + s->lcd.ny = 1; + + s->dispc.idlemode = 0; + s->dispc.irqst = 0; + s->dispc.irqen = 0; + s->dispc.control = 0; + s->dispc.config = 0; + s->dispc.capable = 0x161; + s->dispc.timing[0] = 0; + s->dispc.timing[1] = 0; + s->dispc.timing[2] = 0; + s->dispc.timing[3] = 0; + s->dispc.line = 0; + s->dispc.bg[0] = 0; + s->dispc.bg[1] = 0; + s->dispc.trans[0] = 0; + s->dispc.trans[1] = 0; + + s->dispc.l[0].enable = 0; + s->dispc.l[0].bpp = 0; + s->dispc.l[0].addr[0] = 0; + s->dispc.l[0].addr[1] = 0; + s->dispc.l[0].addr[2] = 0; + s->dispc.l[0].posx = 0; + s->dispc.l[0].posy = 0; + s->dispc.l[0].nx = 1; + s->dispc.l[0].ny = 1; + s->dispc.l[0].attr = 0; + s->dispc.l[0].tresh = 0; + s->dispc.l[0].rowinc = 1; + s->dispc.l[0].colinc = 1; + s->dispc.l[0].wininc = 0; + + omap_rfbi_reset(s); + omap_dispc_interrupt_update(s); +} + +static uint32_t omap_diss_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_dss_s *s = (struct omap_dss_s *) opaque; + int offset = addr - s->diss_base; + + switch (offset) { + case 0x00: /* DSS_REVISIONNUMBER */ + return 0x20; + + case 0x10: /* DSS_SYSCONFIG */ + return s->autoidle; + + case 0x14: /* DSS_SYSSTATUS */ + return 1; /* RESETDONE */ + + case 0x40: /* DSS_CONTROL */ + return s->control; + + case 0x50: /* DSS_PSA_LCD_REG_1 */ + case 0x54: /* DSS_PSA_LCD_REG_2 */ + case 0x58: /* DSS_PSA_VIDEO_REG */ + /* TODO: fake some values when appropriate s->control bits are set */ + return 0; + + case 0x5c: /* DSS_STATUS */ + return 1 + (s->control & 1); + + default: + break; + } + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_diss_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_dss_s *s = (struct omap_dss_s *) opaque; + int offset = addr - s->diss_base; + + switch (offset) { + case 0x00: /* DSS_REVISIONNUMBER */ + case 0x14: /* DSS_SYSSTATUS */ + case 0x50: /* DSS_PSA_LCD_REG_1 */ + case 0x54: /* DSS_PSA_LCD_REG_2 */ + case 0x58: /* DSS_PSA_VIDEO_REG */ + case 0x5c: /* DSS_STATUS */ + OMAP_RO_REG(addr); + break; + + case 0x10: /* DSS_SYSCONFIG */ + if (value & 2) /* SOFTRESET */ + omap_dss_reset(s); + s->autoidle = value & 1; + break; + + case 0x40: /* DSS_CONTROL */ + s->control = value & 0x3dd; + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_diss1_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_diss_read, +}; + +static CPUWriteMemoryFunc *omap_diss1_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_diss_write, +}; + +static uint32_t omap_disc_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_dss_s *s = (struct omap_dss_s *) opaque; + int offset = addr - s->disc_base; + + switch (offset) { + case 0x000: /* DISPC_REVISION */ + return 0x20; + + case 0x010: /* DISPC_SYSCONFIG */ + return s->dispc.idlemode; + + case 0x014: /* DISPC_SYSSTATUS */ + return 1; /* RESETDONE */ + + case 0x018: /* DISPC_IRQSTATUS */ + return s->dispc.irqst; + + case 0x01c: /* DISPC_IRQENABLE */ + return s->dispc.irqen; + + case 0x040: /* DISPC_CONTROL */ + return s->dispc.control; + + case 0x044: /* DISPC_CONFIG */ + return s->dispc.config; + + case 0x048: /* DISPC_CAPABLE */ + return s->dispc.capable; + + case 0x04c: /* DISPC_DEFAULT_COLOR0 */ + return s->dispc.bg[0]; + case 0x050: /* DISPC_DEFAULT_COLOR1 */ + return s->dispc.bg[1]; + case 0x054: /* DISPC_TRANS_COLOR0 */ + return s->dispc.trans[0]; + case 0x058: /* DISPC_TRANS_COLOR1 */ + return s->dispc.trans[1]; + + case 0x05c: /* DISPC_LINE_STATUS */ + return 0x7ff; + case 0x060: /* DISPC_LINE_NUMBER */ + return s->dispc.line; + + case 0x064: /* DISPC_TIMING_H */ + return s->dispc.timing[0]; + case 0x068: /* DISPC_TIMING_V */ + return s->dispc.timing[1]; + case 0x06c: /* DISPC_POL_FREQ */ + return s->dispc.timing[2]; + case 0x070: /* DISPC_DIVISOR */ + return s->dispc.timing[3]; + + case 0x078: /* DISPC_SIZE_DIG */ + return ((s->dig.ny - 1) << 16) | (s->dig.nx - 1); + case 0x07c: /* DISPC_SIZE_LCD */ + return ((s->lcd.ny - 1) << 16) | (s->lcd.nx - 1); + + case 0x080: /* DISPC_GFX_BA0 */ + return s->dispc.l[0].addr[0]; + case 0x084: /* DISPC_GFX_BA1 */ + return s->dispc.l[0].addr[1]; + case 0x088: /* DISPC_GFX_POSITION */ + return (s->dispc.l[0].posy << 16) | s->dispc.l[0].posx; + case 0x08c: /* DISPC_GFX_SIZE */ + return ((s->dispc.l[0].ny - 1) << 16) | (s->dispc.l[0].nx - 1); + case 0x0a0: /* DISPC_GFX_ATTRIBUTES */ + return s->dispc.l[0].attr; + case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */ + return s->dispc.l[0].tresh; + case 0x0a8: /* DISPC_GFX_FIFO_SIZE_STATUS */ + return 256; + case 0x0ac: /* DISPC_GFX_ROW_INC */ + return s->dispc.l[0].rowinc; + case 0x0b0: /* DISPC_GFX_PIXEL_INC */ + return s->dispc.l[0].colinc; + case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */ + return s->dispc.l[0].wininc; + case 0x0b8: /* DISPC_GFX_TABLE_BA */ + return s->dispc.l[0].addr[2]; + + case 0x0bc: /* DISPC_VID1_BA0 */ + case 0x0c0: /* DISPC_VID1_BA1 */ + case 0x0c4: /* DISPC_VID1_POSITION */ + case 0x0c8: /* DISPC_VID1_SIZE */ + case 0x0cc: /* DISPC_VID1_ATTRIBUTES */ + case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */ + case 0x0d4: /* DISPC_VID1_FIFO_SIZE_STATUS */ + case 0x0d8: /* DISPC_VID1_ROW_INC */ + case 0x0dc: /* DISPC_VID1_PIXEL_INC */ + case 0x0e0: /* DISPC_VID1_FIR */ + case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */ + case 0x0e8: /* DISPC_VID1_ACCU0 */ + case 0x0ec: /* DISPC_VID1_ACCU1 */ + case 0x0f0 ... 0x140: /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */ + case 0x14c: /* DISPC_VID2_BA0 */ + case 0x150: /* DISPC_VID2_BA1 */ + case 0x154: /* DISPC_VID2_POSITION */ + case 0x158: /* DISPC_VID2_SIZE */ + case 0x15c: /* DISPC_VID2_ATTRIBUTES */ + case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */ + case 0x164: /* DISPC_VID2_FIFO_SIZE_STATUS */ + case 0x168: /* DISPC_VID2_ROW_INC */ + case 0x16c: /* DISPC_VID2_PIXEL_INC */ + case 0x170: /* DISPC_VID2_FIR */ + case 0x174: /* DISPC_VID2_PICTURE_SIZE */ + case 0x178: /* DISPC_VID2_ACCU0 */ + case 0x17c: /* DISPC_VID2_ACCU1 */ + case 0x180 ... 0x1d0: /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */ + case 0x1d4: /* DISPC_DATA_CYCLE1 */ + case 0x1d8: /* DISPC_DATA_CYCLE2 */ + case 0x1dc: /* DISPC_DATA_CYCLE3 */ + return 0; + + default: + break; + } + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_disc_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_dss_s *s = (struct omap_dss_s *) opaque; + int offset = addr - s->disc_base; + + switch (offset) { + case 0x010: /* DISPC_SYSCONFIG */ + if (value & 2) /* SOFTRESET */ + omap_dss_reset(s); + s->dispc.idlemode = value & 0x301b; + break; + + case 0x018: /* DISPC_IRQSTATUS */ + s->dispc.irqst &= ~value; + omap_dispc_interrupt_update(s); + break; + + case 0x01c: /* DISPC_IRQENABLE */ + s->dispc.irqen = value & 0xffff; + omap_dispc_interrupt_update(s); + break; + + case 0x040: /* DISPC_CONTROL */ + s->dispc.control = value & 0x07ff9fff; + s->dig.enable = (value >> 1) & 1; + s->lcd.enable = (value >> 0) & 1; + if (value & (1 << 12)) /* OVERLAY_OPTIMIZATION */ + if (~((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1)) + fprintf(stderr, "%s: Overlay Optimization when no overlay " + "region effectively exists leads to " + "unpredictable behaviour!\n", __FUNCTION__); + if (value & (1 << 6)) { /* GODIGITAL */ + /* XXX: Shadowed fields are: + * s->dispc.config + * s->dispc.capable + * s->dispc.bg[0] + * s->dispc.bg[1] + * s->dispc.trans[0] + * s->dispc.trans[1] + * s->dispc.line + * s->dispc.timing[0] + * s->dispc.timing[1] + * s->dispc.timing[2] + * s->dispc.timing[3] + * s->lcd.nx + * s->lcd.ny + * s->dig.nx + * s->dig.ny + * s->dispc.l[0].addr[0] + * s->dispc.l[0].addr[1] + * s->dispc.l[0].addr[2] + * s->dispc.l[0].posx + * s->dispc.l[0].posy + * s->dispc.l[0].nx + * s->dispc.l[0].ny + * s->dispc.l[0].tresh + * s->dispc.l[0].rowinc + * s->dispc.l[0].colinc + * s->dispc.l[0].wininc + * All they need to be loaded here from their shadow registers. + */ + } + if (value & (1 << 5)) { /* GOLCD */ + /* XXX: Likewise for LCD here. */ + } + s->dispc.invalidate = 1; + break; + + case 0x044: /* DISPC_CONFIG */ + s->dispc.config = value & 0x3fff; + /* XXX: + * bits 2:1 (LOADMODE) reset to 0 after set to 1 and palette loaded + * bits 2:1 (LOADMODE) reset to 2 after set to 3 and palette loaded + */ + s->dispc.invalidate = 1; + break; + + case 0x048: /* DISPC_CAPABLE */ + s->dispc.capable = value & 0x3ff; + break; + + case 0x04c: /* DISPC_DEFAULT_COLOR0 */ + s->dispc.bg[0] = value & 0xffffff; + s->dispc.invalidate = 1; + break; + case 0x050: /* DISPC_DEFAULT_COLOR1 */ + s->dispc.bg[1] = value & 0xffffff; + s->dispc.invalidate = 1; + break; + case 0x054: /* DISPC_TRANS_COLOR0 */ + s->dispc.trans[0] = value & 0xffffff; + s->dispc.invalidate = 1; + break; + case 0x058: /* DISPC_TRANS_COLOR1 */ + s->dispc.trans[1] = value & 0xffffff; + s->dispc.invalidate = 1; + break; + + case 0x060: /* DISPC_LINE_NUMBER */ + s->dispc.line = value & 0x7ff; + break; + + case 0x064: /* DISPC_TIMING_H */ + s->dispc.timing[0] = value & 0x0ff0ff3f; + break; + case 0x068: /* DISPC_TIMING_V */ + s->dispc.timing[1] = value & 0x0ff0ff3f; + break; + case 0x06c: /* DISPC_POL_FREQ */ + s->dispc.timing[2] = value & 0x0003ffff; + break; + case 0x070: /* DISPC_DIVISOR */ + s->dispc.timing[3] = value & 0x00ff00ff; + break; + + case 0x078: /* DISPC_SIZE_DIG */ + s->dig.nx = ((value >> 0) & 0x7ff) + 1; /* PPL */ + s->dig.ny = ((value >> 16) & 0x7ff) + 1; /* LPP */ + s->dispc.invalidate = 1; + break; + case 0x07c: /* DISPC_SIZE_LCD */ + s->lcd.nx = ((value >> 0) & 0x7ff) + 1; /* PPL */ + s->lcd.ny = ((value >> 16) & 0x7ff) + 1; /* LPP */ + s->dispc.invalidate = 1; + break; + case 0x080: /* DISPC_GFX_BA0 */ + s->dispc.l[0].addr[0] = (target_phys_addr_t) value; + s->dispc.invalidate = 1; + break; + case 0x084: /* DISPC_GFX_BA1 */ + s->dispc.l[0].addr[1] = (target_phys_addr_t) value; + s->dispc.invalidate = 1; + break; + case 0x088: /* DISPC_GFX_POSITION */ + s->dispc.l[0].posx = ((value >> 0) & 0x7ff); /* GFXPOSX */ + s->dispc.l[0].posy = ((value >> 16) & 0x7ff); /* GFXPOSY */ + s->dispc.invalidate = 1; + break; + case 0x08c: /* DISPC_GFX_SIZE */ + s->dispc.l[0].nx = ((value >> 0) & 0x7ff) + 1; /* GFXSIZEX */ + s->dispc.l[0].ny = ((value >> 16) & 0x7ff) + 1; /* GFXSIZEY */ + s->dispc.invalidate = 1; + break; + case 0x0a0: /* DISPC_GFX_ATTRIBUTES */ + s->dispc.l[0].attr = value & 0x7ff; + if (value & (3 << 9)) + fprintf(stderr, "%s: Big-endian pixel format not supported\n", + __FUNCTION__); + s->dispc.l[0].enable = value & 1; + s->dispc.l[0].bpp = (value >> 1) & 0xf; + s->dispc.invalidate = 1; + break; + case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */ + s->dispc.l[0].tresh = value & 0x01ff01ff; + break; + case 0x0ac: /* DISPC_GFX_ROW_INC */ + s->dispc.l[0].rowinc = value; + s->dispc.invalidate = 1; + break; + case 0x0b0: /* DISPC_GFX_PIXEL_INC */ + s->dispc.l[0].colinc = value; + s->dispc.invalidate = 1; + break; + case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */ + s->dispc.l[0].wininc = value; + break; + case 0x0b8: /* DISPC_GFX_TABLE_BA */ + s->dispc.l[0].addr[2] = (target_phys_addr_t) value; + s->dispc.invalidate = 1; + break; + + case 0x0bc: /* DISPC_VID1_BA0 */ + case 0x0c0: /* DISPC_VID1_BA1 */ + case 0x0c4: /* DISPC_VID1_POSITION */ + case 0x0c8: /* DISPC_VID1_SIZE */ + case 0x0cc: /* DISPC_VID1_ATTRIBUTES */ + case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */ + case 0x0d8: /* DISPC_VID1_ROW_INC */ + case 0x0dc: /* DISPC_VID1_PIXEL_INC */ + case 0x0e0: /* DISPC_VID1_FIR */ + case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */ + case 0x0e8: /* DISPC_VID1_ACCU0 */ + case 0x0ec: /* DISPC_VID1_ACCU1 */ + case 0x0f0 ... 0x140: /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */ + case 0x14c: /* DISPC_VID2_BA0 */ + case 0x150: /* DISPC_VID2_BA1 */ + case 0x154: /* DISPC_VID2_POSITION */ + case 0x158: /* DISPC_VID2_SIZE */ + case 0x15c: /* DISPC_VID2_ATTRIBUTES */ + case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */ + case 0x168: /* DISPC_VID2_ROW_INC */ + case 0x16c: /* DISPC_VID2_PIXEL_INC */ + case 0x170: /* DISPC_VID2_FIR */ + case 0x174: /* DISPC_VID2_PICTURE_SIZE */ + case 0x178: /* DISPC_VID2_ACCU0 */ + case 0x17c: /* DISPC_VID2_ACCU1 */ + case 0x180 ... 0x1d0: /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */ + case 0x1d4: /* DISPC_DATA_CYCLE1 */ + case 0x1d8: /* DISPC_DATA_CYCLE2 */ + case 0x1dc: /* DISPC_DATA_CYCLE3 */ + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_disc1_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_disc_read, +}; + +static CPUWriteMemoryFunc *omap_disc1_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_disc_write, +}; + +static void *omap_rfbi_get_buffer(struct omap_dss_s *s) +{ + target_phys_addr_t fb; + uint32_t pd; + + /* TODO */ + fb = s->dispc.l[0].addr[0]; + + pd = cpu_get_physical_page_desc(fb); + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) + /* TODO */ + cpu_abort(cpu_single_env, "%s: framebuffer outside RAM!\n", + __FUNCTION__); + else + return phys_ram_base + + (pd & TARGET_PAGE_MASK) + + (fb & ~TARGET_PAGE_MASK); +} + +static void omap_rfbi_transfer_stop(struct omap_dss_s *s) +{ + if (!s->rfbi.busy) + return; + + /* TODO: in non-Bypass mode we probably need to just deassert the DRQ. */ + + s->rfbi.busy = 0; +} + +static void omap_rfbi_transfer_start(struct omap_dss_s *s) +{ + void *data; + size_t len; + int pitch; + + if (!s->rfbi.enable || s->rfbi.busy) + return; + + if (s->rfbi.control & (1 << 1)) { /* BYPASS */ + /* TODO: in non-Bypass mode we probably need to just assert the + * DRQ and wait for DMA to write the pixels. */ + fprintf(stderr, "%s: Bypass mode unimplemented\n", __FUNCTION__); + return; + } + + if (!(s->dispc.control & (1 << 11))) /* RFBIMODE */ + return; + /* TODO: check that LCD output is enabled in DISPC. */ + + s->rfbi.busy = 1; + + data = omap_rfbi_get_buffer(s); + + /* TODO bpp */ + len = s->rfbi.pixels * 2; + s->rfbi.pixels = 0; + + /* TODO: negative values */ + pitch = s->dispc.l[0].nx + (s->dispc.l[0].rowinc - 1) / 2; + + if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) + s->rfbi.chip[0]->block(s->rfbi.chip[0]->opaque, 1, data, len, pitch); + if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) + s->rfbi.chip[1]->block(s->rfbi.chip[1]->opaque, 1, data, len, pitch); + + omap_rfbi_transfer_stop(s); + + /* TODO */ + s->dispc.irqst |= 1; /* FRAMEDONE */ + omap_dispc_interrupt_update(s); +} + +static uint32_t omap_rfbi_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_dss_s *s = (struct omap_dss_s *) opaque; + int offset = addr - s->rfbi_base; + + switch (offset) { + case 0x00: /* RFBI_REVISION */ + return 0x10; + + case 0x10: /* RFBI_SYSCONFIG */ + return s->rfbi.idlemode; + + case 0x14: /* RFBI_SYSSTATUS */ + return 1 | (s->rfbi.busy << 8); /* RESETDONE */ + + case 0x40: /* RFBI_CONTROL */ + return s->rfbi.control; + + case 0x44: /* RFBI_PIXELCNT */ + return s->rfbi.pixels; + + case 0x48: /* RFBI_LINE_NUMBER */ + return s->rfbi.skiplines; + + case 0x58: /* RFBI_READ */ + case 0x5c: /* RFBI_STATUS */ + return s->rfbi.rxbuf; + + case 0x60: /* RFBI_CONFIG0 */ + return s->rfbi.config[0]; + case 0x64: /* RFBI_ONOFF_TIME0 */ + return s->rfbi.time[0]; + case 0x68: /* RFBI_CYCLE_TIME0 */ + return s->rfbi.time[1]; + case 0x6c: /* RFBI_DATA_CYCLE1_0 */ + return s->rfbi.data[0]; + case 0x70: /* RFBI_DATA_CYCLE2_0 */ + return s->rfbi.data[1]; + case 0x74: /* RFBI_DATA_CYCLE3_0 */ + return s->rfbi.data[2]; + + case 0x78: /* RFBI_CONFIG1 */ + return s->rfbi.config[1]; + case 0x7c: /* RFBI_ONOFF_TIME1 */ + return s->rfbi.time[2]; + case 0x80: /* RFBI_CYCLE_TIME1 */ + return s->rfbi.time[3]; + case 0x84: /* RFBI_DATA_CYCLE1_1 */ + return s->rfbi.data[3]; + case 0x88: /* RFBI_DATA_CYCLE2_1 */ + return s->rfbi.data[4]; + case 0x8c: /* RFBI_DATA_CYCLE3_1 */ + return s->rfbi.data[5]; + + case 0x90: /* RFBI_VSYNC_WIDTH */ + return s->rfbi.vsync; + case 0x94: /* RFBI_HSYNC_WIDTH */ + return s->rfbi.hsync; + } + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_rfbi_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_dss_s *s = (struct omap_dss_s *) opaque; + int offset = addr - s->rfbi_base; + + switch (offset) { + case 0x10: /* RFBI_SYSCONFIG */ + if (value & 2) /* SOFTRESET */ + omap_rfbi_reset(s); + s->rfbi.idlemode = value & 0x19; + break; + + case 0x40: /* RFBI_CONTROL */ + s->rfbi.control = value & 0xf; + s->rfbi.enable = value & 1; + if (value & (1 << 4) && /* ITE */ + !(s->rfbi.config[0] & s->rfbi.config[1] & 0xc)) + omap_rfbi_transfer_start(s); + break; + + case 0x44: /* RFBI_PIXELCNT */ + s->rfbi.pixels = value; + break; + + case 0x48: /* RFBI_LINE_NUMBER */ + s->rfbi.skiplines = value & 0x7ff; + break; + + case 0x4c: /* RFBI_CMD */ + if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) + s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 0, value & 0xffff); + if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) + s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 0, value & 0xffff); + break; + case 0x50: /* RFBI_PARAM */ + if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) + s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff); + if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) + s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff); + break; + case 0x54: /* RFBI_DATA */ + /* TODO: take into account the format set up in s->rfbi.config[?] and + * s->rfbi.data[?], but special-case the most usual scenario so that + * speed doesn't suffer. */ + if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) { + s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff); + s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value >> 16); + } + if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) { + s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff); + s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value >> 16); + } + if (!-- s->rfbi.pixels) + omap_rfbi_transfer_stop(s); + break; + case 0x58: /* RFBI_READ */ + if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) + s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1); + else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) + s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1); + if (!-- s->rfbi.pixels) + omap_rfbi_transfer_stop(s); + break; + + case 0x5c: /* RFBI_STATUS */ + if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) + s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0); + else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) + s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0); + if (!-- s->rfbi.pixels) + omap_rfbi_transfer_stop(s); + break; + + case 0x60: /* RFBI_CONFIG0 */ + s->rfbi.config[0] = value & 0x003f1fff; + break; + + case 0x64: /* RFBI_ONOFF_TIME0 */ + s->rfbi.time[0] = value & 0x3fffffff; + break; + case 0x68: /* RFBI_CYCLE_TIME0 */ + s->rfbi.time[1] = value & 0x0fffffff; + break; + case 0x6c: /* RFBI_DATA_CYCLE1_0 */ + s->rfbi.data[0] = value & 0x0f1f0f1f; + break; + case 0x70: /* RFBI_DATA_CYCLE2_0 */ + s->rfbi.data[1] = value & 0x0f1f0f1f; + break; + case 0x74: /* RFBI_DATA_CYCLE3_0 */ + s->rfbi.data[2] = value & 0x0f1f0f1f; + break; + case 0x78: /* RFBI_CONFIG1 */ + s->rfbi.config[1] = value & 0x003f1fff; + break; + + case 0x7c: /* RFBI_ONOFF_TIME1 */ + s->rfbi.time[2] = value & 0x3fffffff; + break; + case 0x80: /* RFBI_CYCLE_TIME1 */ + s->rfbi.time[3] = value & 0x0fffffff; + break; + case 0x84: /* RFBI_DATA_CYCLE1_1 */ + s->rfbi.data[3] = value & 0x0f1f0f1f; + break; + case 0x88: /* RFBI_DATA_CYCLE2_1 */ + s->rfbi.data[4] = value & 0x0f1f0f1f; + break; + case 0x8c: /* RFBI_DATA_CYCLE3_1 */ + s->rfbi.data[5] = value & 0x0f1f0f1f; + break; + + case 0x90: /* RFBI_VSYNC_WIDTH */ + s->rfbi.vsync = value & 0xffff; + break; + case 0x94: /* RFBI_HSYNC_WIDTH */ + s->rfbi.hsync = value & 0xffff; + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_rfbi1_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_rfbi_read, +}; + +static CPUWriteMemoryFunc *omap_rfbi1_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_rfbi_write, +}; + +static uint32_t omap_venc_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_dss_s *s = (struct omap_dss_s *) opaque; + int offset = addr - s->venc_base; + + switch (offset) { + case 0x00: /* REV_ID */ + case 0x04: /* STATUS */ + case 0x08: /* F_CONTROL */ + case 0x10: /* VIDOUT_CTRL */ + case 0x14: /* SYNC_CTRL */ + case 0x1c: /* LLEN */ + case 0x20: /* FLENS */ + case 0x24: /* HFLTR_CTRL */ + case 0x28: /* CC_CARR_WSS_CARR */ + case 0x2c: /* C_PHASE */ + case 0x30: /* GAIN_U */ + case 0x34: /* GAIN_V */ + case 0x38: /* GAIN_Y */ + case 0x3c: /* BLACK_LEVEL */ + case 0x40: /* BLANK_LEVEL */ + case 0x44: /* X_COLOR */ + case 0x48: /* M_CONTROL */ + case 0x4c: /* BSTAMP_WSS_DATA */ + case 0x50: /* S_CARR */ + case 0x54: /* LINE21 */ + case 0x58: /* LN_SEL */ + case 0x5c: /* L21__WC_CTL */ + case 0x60: /* HTRIGGER_VTRIGGER */ + case 0x64: /* SAVID__EAVID */ + case 0x68: /* FLEN__FAL */ + case 0x6c: /* LAL__PHASE_RESET */ + case 0x70: /* HS_INT_START_STOP_X */ + case 0x74: /* HS_EXT_START_STOP_X */ + case 0x78: /* VS_INT_START_X */ + case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */ + case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */ + case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */ + case 0x88: /* VS_EXT_STOP_Y */ + case 0x90: /* AVID_START_STOP_X */ + case 0x94: /* AVID_START_STOP_Y */ + case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */ + case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */ + case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */ + case 0xb0: /* TVDETGP_INT_START_STOP_X */ + case 0xb4: /* TVDETGP_INT_START_STOP_Y */ + case 0xb8: /* GEN_CTRL */ + case 0xc4: /* DAC_TST__DAC_A */ + case 0xc8: /* DAC_B__DAC_C */ + return 0; + + default: + break; + } + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_venc_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_dss_s *s = (struct omap_dss_s *) opaque; + int offset = addr - s->venc_base; + + switch (offset) { + case 0x08: /* F_CONTROL */ + case 0x10: /* VIDOUT_CTRL */ + case 0x14: /* SYNC_CTRL */ + case 0x1c: /* LLEN */ + case 0x20: /* FLENS */ + case 0x24: /* HFLTR_CTRL */ + case 0x28: /* CC_CARR_WSS_CARR */ + case 0x2c: /* C_PHASE */ + case 0x30: /* GAIN_U */ + case 0x34: /* GAIN_V */ + case 0x38: /* GAIN_Y */ + case 0x3c: /* BLACK_LEVEL */ + case 0x40: /* BLANK_LEVEL */ + case 0x44: /* X_COLOR */ + case 0x48: /* M_CONTROL */ + case 0x4c: /* BSTAMP_WSS_DATA */ + case 0x50: /* S_CARR */ + case 0x54: /* LINE21 */ + case 0x58: /* LN_SEL */ + case 0x5c: /* L21__WC_CTL */ + case 0x60: /* HTRIGGER_VTRIGGER */ + case 0x64: /* SAVID__EAVID */ + case 0x68: /* FLEN__FAL */ + case 0x6c: /* LAL__PHASE_RESET */ + case 0x70: /* HS_INT_START_STOP_X */ + case 0x74: /* HS_EXT_START_STOP_X */ + case 0x78: /* VS_INT_START_X */ + case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */ + case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */ + case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */ + case 0x88: /* VS_EXT_STOP_Y */ + case 0x90: /* AVID_START_STOP_X */ + case 0x94: /* AVID_START_STOP_Y */ + case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */ + case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */ + case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */ + case 0xb0: /* TVDETGP_INT_START_STOP_X */ + case 0xb4: /* TVDETGP_INT_START_STOP_Y */ + case 0xb8: /* GEN_CTRL */ + case 0xc4: /* DAC_TST__DAC_A */ + case 0xc8: /* DAC_B__DAC_C */ + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_venc1_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_venc_read, +}; + +static CPUWriteMemoryFunc *omap_venc1_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_venc_write, +}; + +static uint32_t omap_im3_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_dss_s *s = (struct omap_dss_s *) opaque; + int offset = addr - s->im3_base; + + switch (offset) { + case 0x0a8: /* SBIMERRLOGA */ + case 0x0b0: /* SBIMERRLOG */ + case 0x190: /* SBIMSTATE */ + case 0x198: /* SBTMSTATE_L */ + case 0x19c: /* SBTMSTATE_H */ + case 0x1a8: /* SBIMCONFIG_L */ + case 0x1ac: /* SBIMCONFIG_H */ + case 0x1f8: /* SBID_L */ + case 0x1fc: /* SBID_H */ + return 0; + + default: + break; + } + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_im3_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_dss_s *s = (struct omap_dss_s *) opaque; + int offset = addr - s->im3_base; + + switch (offset) { + case 0x0b0: /* SBIMERRLOG */ + case 0x190: /* SBIMSTATE */ + case 0x198: /* SBTMSTATE_L */ + case 0x19c: /* SBTMSTATE_H */ + case 0x1a8: /* SBIMCONFIG_L */ + case 0x1ac: /* SBIMCONFIG_H */ + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_im3_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_im3_read, +}; + +static CPUWriteMemoryFunc *omap_im3_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_im3_write, +}; + +struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta, + target_phys_addr_t l3_base, DisplayState *ds, + qemu_irq irq, qemu_irq drq, + omap_clk fck1, omap_clk fck2, omap_clk ck54m, + omap_clk ick1, omap_clk ick2) +{ + int iomemtype[5]; + struct omap_dss_s *s = (struct omap_dss_s *) + qemu_mallocz(sizeof(struct omap_dss_s)); + + s->irq = irq; + s->drq = drq; + s->state = ds; + omap_dss_reset(s); + + iomemtype[0] = l4_register_io_memory(0, omap_diss1_readfn, + omap_diss1_writefn, s); + iomemtype[1] = l4_register_io_memory(0, omap_disc1_readfn, + omap_disc1_writefn, s); + iomemtype[2] = l4_register_io_memory(0, omap_rfbi1_readfn, + omap_rfbi1_writefn, s); + iomemtype[3] = l4_register_io_memory(0, omap_venc1_readfn, + omap_venc1_writefn, s); + iomemtype[4] = cpu_register_io_memory(0, omap_im3_readfn, + omap_im3_writefn, s); + s->diss_base = omap_l4_attach(ta, 0, iomemtype[0]); + s->disc_base = omap_l4_attach(ta, 1, iomemtype[1]); + s->rfbi_base = omap_l4_attach(ta, 2, iomemtype[2]); + s->venc_base = omap_l4_attach(ta, 3, iomemtype[3]); + s->im3_base = l3_base; + cpu_register_physical_memory(s->im3_base, 0x1000, iomemtype[4]); + +#if 0 + if (ds) + graphic_console_init(ds, omap_update_display, + omap_invalidate_display, omap_screen_dump, s); +#endif + + return s; +} + +void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip) +{ + if (cs < 0 || cs > 1) + cpu_abort(cpu_single_env, "%s: wrong CS %i\n", __FUNCTION__, cs); + s->rfbi.chip[cs] = chip; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/omap.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/omap.h --- qemu-0.9.1/hw/omap.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/omap.h 2008-09-20 02:10:32.000000000 +0100 @@ -1,12 +1,12 @@ /* * Texas Instruments OMAP processors. * - * Copyright (C) 2006-2007 Andrzej Zaborowski + * Copyright (C) 2006-2008 Andrzej Zaborowski * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -22,6 +22,7 @@ # define hw_omap_h "omap.h" # define OMAP_EMIFS_BASE 0x00000000 +# define OMAP2_Q0_BASE 0x00000000 # define OMAP_CS0_BASE 0x00000000 # define OMAP_CS1_BASE 0x04000000 # define OMAP_CS2_BASE 0x08000000 @@ -29,18 +30,26 @@ # define OMAP_EMIFF_BASE 0x10000000 # define OMAP_IMIF_BASE 0x20000000 # define OMAP_LOCALBUS_BASE 0x30000000 +# define OMAP2_Q1_BASE 0x40000000 +# define OMAP2_L4_BASE 0x48000000 +# define OMAP2_SRAM_BASE 0x40200000 +# define OMAP2_L3_BASE 0x68000000 +# define OMAP2_Q2_BASE 0x80000000 +# define OMAP2_Q3_BASE 0xc0000000 # define OMAP_MPUI_BASE 0xe1000000 # define OMAP730_SRAM_SIZE 0x00032000 # define OMAP15XX_SRAM_SIZE 0x00030000 # define OMAP16XX_SRAM_SIZE 0x00004000 # define OMAP1611_SRAM_SIZE 0x0003e800 +# define OMAP242X_SRAM_SIZE 0x000a0000 +# define OMAP243X_SRAM_SIZE 0x00010000 # define OMAP_CS0_SIZE 0x04000000 # define OMAP_CS1_SIZE 0x04000000 # define OMAP_CS2_SIZE 0x04000000 # define OMAP_CS3_SIZE 0x04000000 -/* omap1_clk.c */ +/* omap_clk.c */ struct omap_mpu_state_s; typedef struct clk *omap_clk; omap_clk omap_findclk(struct omap_mpu_state_s *mpu, const char *name); @@ -54,11 +63,43 @@ int64_t omap_clk_getrate(omap_clk clk); void omap_clk_reparent(omap_clk clk, omap_clk parent); -/* omap.c */ +/* omap[123].c */ +struct omap_l4_s; +struct omap_l4_s *omap_l4_init(target_phys_addr_t base, int ta_num); + +struct omap_target_agent_s; +struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus, int cs); +target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, int region, + int iotype); +# define l4_register_io_memory cpu_register_io_memory + struct omap_intr_handler_s; struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base, - unsigned long size, unsigned char nbanks, + unsigned long size, unsigned char nbanks, qemu_irq **pins, qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk); +struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base, + int size, int nbanks, qemu_irq **pins, + qemu_irq parent_irq, qemu_irq parent_fiq, + omap_clk fclk, omap_clk iclk); +void omap_inth_reset(struct omap_intr_handler_s *s); + +struct omap_prcm_s; +struct omap_prcm_s *omap_prcm_init(struct omap_target_agent_s *ta, + qemu_irq mpu_int, qemu_irq dsp_int, qemu_irq iva_int, + struct omap_mpu_state_s *mpu); + +struct omap_sysctl_s; +struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta, + omap_clk iclk, struct omap_mpu_state_s *mpu); + +struct omap_sdrc_s; +struct omap_sdrc_s *omap_sdrc_init(target_phys_addr_t base); + +struct omap_gpmc_s; +struct omap_gpmc_s *omap_gpmc_init(target_phys_addr_t base, qemu_irq irq); +void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, int iomemtype, + void (*base_upd)(void *opaque, target_phys_addr_t new), + void (*unmap)(void *opaque), void *opaque); /* * Common IRQ numbers for level 1 interrupt handler @@ -290,11 +331,22 @@ /* * OMAP-24xx common IRQ numbers */ +# define OMAP_INT_24XX_STI 4 # define OMAP_INT_24XX_SYS_NIRQ 7 +# define OMAP_INT_24XX_L3_IRQ 10 +# define OMAP_INT_24XX_PRCM_MPU_IRQ 11 # define OMAP_INT_24XX_SDMA_IRQ0 12 # define OMAP_INT_24XX_SDMA_IRQ1 13 # define OMAP_INT_24XX_SDMA_IRQ2 14 # define OMAP_INT_24XX_SDMA_IRQ3 15 +# define OMAP_INT_243X_MCBSP2_IRQ 16 +# define OMAP_INT_243X_MCBSP3_IRQ 17 +# define OMAP_INT_243X_MCBSP4_IRQ 18 +# define OMAP_INT_243X_MCBSP5_IRQ 19 +# define OMAP_INT_24XX_GPMC_IRQ 20 +# define OMAP_INT_24XX_GUFFAW_IRQ 21 +# define OMAP_INT_24XX_IVA_IRQ 22 +# define OMAP_INT_24XX_EAC_IRQ 23 # define OMAP_INT_24XX_CAM_IRQ 24 # define OMAP_INT_24XX_DSS_IRQ 25 # define OMAP_INT_24XX_MAIL_U0_MPU 26 @@ -304,8 +356,10 @@ # define OMAP_INT_24XX_GPIO_BANK2 30 # define OMAP_INT_24XX_GPIO_BANK3 31 # define OMAP_INT_24XX_GPIO_BANK4 32 -# define OMAP_INT_24XX_GPIO_BANK5 33 +# define OMAP_INT_243X_GPIO_BANK5 33 # define OMAP_INT_24XX_MAIL_U3_MPU 34 +# define OMAP_INT_24XX_WDT3 35 +# define OMAP_INT_24XX_WDT4 36 # define OMAP_INT_24XX_GPTIMER1 37 # define OMAP_INT_24XX_GPTIMER2 38 # define OMAP_INT_24XX_GPTIMER3 39 @@ -318,10 +372,24 @@ # define OMAP_INT_24XX_GPTIMER10 46 # define OMAP_INT_24XX_GPTIMER11 47 # define OMAP_INT_24XX_GPTIMER12 48 +# define OMAP_INT_24XX_PKA_IRQ 50 +# define OMAP_INT_24XX_SHA1MD5_IRQ 51 +# define OMAP_INT_24XX_RNG_IRQ 52 +# define OMAP_INT_24XX_MG_IRQ 53 +# define OMAP_INT_24XX_I2C1_IRQ 56 +# define OMAP_INT_24XX_I2C2_IRQ 57 # define OMAP_INT_24XX_MCBSP1_IRQ_TX 59 # define OMAP_INT_24XX_MCBSP1_IRQ_RX 60 # define OMAP_INT_24XX_MCBSP2_IRQ_TX 62 # define OMAP_INT_24XX_MCBSP2_IRQ_RX 63 +# define OMAP_INT_243X_MCBSP1_IRQ 64 +# define OMAP_INT_24XX_MCSPI1_IRQ 65 +# define OMAP_INT_24XX_MCSPI2_IRQ 66 +# define OMAP_INT_24XX_SSI1_IRQ0 67 +# define OMAP_INT_24XX_SSI1_IRQ1 68 +# define OMAP_INT_24XX_SSI2_IRQ0 69 +# define OMAP_INT_24XX_SSI2_IRQ1 70 +# define OMAP_INT_24XX_SSI_GDD_IRQ 71 # define OMAP_INT_24XX_UART1_IRQ 72 # define OMAP_INT_24XX_UART2_IRQ 73 # define OMAP_INT_24XX_UART3_IRQ 74 @@ -331,21 +399,39 @@ # define OMAP_INT_24XX_USB_IRQ_HGEN 78 # define OMAP_INT_24XX_USB_IRQ_HSOF 79 # define OMAP_INT_24XX_USB_IRQ_OTG 80 +# define OMAP_INT_24XX_VLYNQ_IRQ 81 # define OMAP_INT_24XX_MMC_IRQ 83 +# define OMAP_INT_24XX_MS_IRQ 84 +# define OMAP_INT_24XX_FAC_IRQ 85 +# define OMAP_INT_24XX_MCSPI3_IRQ 91 # define OMAP_INT_243X_HS_USB_MC 92 # define OMAP_INT_243X_HS_USB_DMA 93 # define OMAP_INT_243X_CARKIT 94 +# define OMAP_INT_34XX_GPTIMER12 95 +/* omap_dma.c */ enum omap_dma_model { - omap_dma_3_1 = 0, - omap_dma_3_2 + omap_dma_3_0, + omap_dma_3_1, + omap_dma_3_2, + omap_dma_4, }; -struct omap_dma_s; -struct omap_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs, +struct soc_dma_s; +struct soc_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs, qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk, enum omap_dma_model model); +struct soc_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs, + struct omap_mpu_state_s *mpu, int fifo, + int chans, omap_clk iclk, omap_clk fclk); +void omap_dma_reset(struct soc_dma_s *s); + +struct dma_irq_map { + int ih; + int intr; +}; +/* Only used in OMAP DMA 3.x gigacells */ enum omap_dma_port { emiff = 0, emifs, @@ -353,7 +439,7 @@ tipb, local, /* omap16xx: ocp_t2 */ tipb_mpui, - omap_dma_port_last, + __omap_dma_port_last, }; typedef enum { @@ -363,6 +449,7 @@ double_index, } omap_dma_addressing_t; +/* Only used in OMAP DMA 3.x gigacells */ struct omap_dma_lcd_channel_s { enum omap_dma_port src; target_phys_addr_t src_f1_top; @@ -407,7 +494,7 @@ ram_addr_t phys_framebuffer[2]; qemu_irq irq; struct omap_mpu_state_s *mpu; -}; +} *omap_dma_get_lcdch(struct soc_dma_s *s); /* * DMA request numbers for OMAP1 @@ -473,10 +560,83 @@ # define OMAP_DMA_MMC2_RX 55 # define OMAP_DMA_CRYPTO_DES_OUT 56 +/* + * DMA request numbers for the OMAP2 + */ +# define OMAP24XX_DMA_NO_DEVICE 0 +# define OMAP24XX_DMA_XTI_DMA 1 /* Not in OMAP2420 */ +# define OMAP24XX_DMA_EXT_DMAREQ0 2 +# define OMAP24XX_DMA_EXT_DMAREQ1 3 +# define OMAP24XX_DMA_GPMC 4 +# define OMAP24XX_DMA_GFX 5 /* Not in OMAP2420 */ +# define OMAP24XX_DMA_DSS 6 +# define OMAP24XX_DMA_VLYNQ_TX 7 /* Not in OMAP2420 */ +# define OMAP24XX_DMA_CWT 8 /* Not in OMAP2420 */ +# define OMAP24XX_DMA_AES_TX 9 /* Not in OMAP2420 */ +# define OMAP24XX_DMA_AES_RX 10 /* Not in OMAP2420 */ +# define OMAP24XX_DMA_DES_TX 11 /* Not in OMAP2420 */ +# define OMAP24XX_DMA_DES_RX 12 /* Not in OMAP2420 */ +# define OMAP24XX_DMA_SHA1MD5_RX 13 /* Not in OMAP2420 */ +# define OMAP24XX_DMA_EXT_DMAREQ2 14 +# define OMAP24XX_DMA_EXT_DMAREQ3 15 +# define OMAP24XX_DMA_EXT_DMAREQ4 16 +# define OMAP24XX_DMA_EAC_AC_RD 17 +# define OMAP24XX_DMA_EAC_AC_WR 18 +# define OMAP24XX_DMA_EAC_MD_UL_RD 19 +# define OMAP24XX_DMA_EAC_MD_UL_WR 20 +# define OMAP24XX_DMA_EAC_MD_DL_RD 21 +# define OMAP24XX_DMA_EAC_MD_DL_WR 22 +# define OMAP24XX_DMA_EAC_BT_UL_RD 23 +# define OMAP24XX_DMA_EAC_BT_UL_WR 24 +# define OMAP24XX_DMA_EAC_BT_DL_RD 25 +# define OMAP24XX_DMA_EAC_BT_DL_WR 26 +# define OMAP24XX_DMA_I2C1_TX 27 +# define OMAP24XX_DMA_I2C1_RX 28 +# define OMAP24XX_DMA_I2C2_TX 29 +# define OMAP24XX_DMA_I2C2_RX 30 +# define OMAP24XX_DMA_MCBSP1_TX 31 +# define OMAP24XX_DMA_MCBSP1_RX 32 +# define OMAP24XX_DMA_MCBSP2_TX 33 +# define OMAP24XX_DMA_MCBSP2_RX 34 +# define OMAP24XX_DMA_SPI1_TX0 35 +# define OMAP24XX_DMA_SPI1_RX0 36 +# define OMAP24XX_DMA_SPI1_TX1 37 +# define OMAP24XX_DMA_SPI1_RX1 38 +# define OMAP24XX_DMA_SPI1_TX2 39 +# define OMAP24XX_DMA_SPI1_RX2 40 +# define OMAP24XX_DMA_SPI1_TX3 41 +# define OMAP24XX_DMA_SPI1_RX3 42 +# define OMAP24XX_DMA_SPI2_TX0 43 +# define OMAP24XX_DMA_SPI2_RX0 44 +# define OMAP24XX_DMA_SPI2_TX1 45 +# define OMAP24XX_DMA_SPI2_RX1 46 + +# define OMAP24XX_DMA_UART1_TX 49 +# define OMAP24XX_DMA_UART1_RX 50 +# define OMAP24XX_DMA_UART2_TX 51 +# define OMAP24XX_DMA_UART2_RX 52 +# define OMAP24XX_DMA_UART3_TX 53 +# define OMAP24XX_DMA_UART3_RX 54 +# define OMAP24XX_DMA_USB_W2FC_TX0 55 +# define OMAP24XX_DMA_USB_W2FC_RX0 56 +# define OMAP24XX_DMA_USB_W2FC_TX1 57 +# define OMAP24XX_DMA_USB_W2FC_RX1 58 +# define OMAP24XX_DMA_USB_W2FC_TX2 59 +# define OMAP24XX_DMA_USB_W2FC_RX2 60 +# define OMAP24XX_DMA_MMC1_TX 61 +# define OMAP24XX_DMA_MMC1_RX 62 +# define OMAP24XX_DMA_MS 63 /* Not in OMAP2420 */ +# define OMAP24XX_DMA_EXT_DMAREQ5 64 + +/* omap[123].c */ struct omap_mpu_timer_s; struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base, qemu_irq irq, omap_clk clk); +struct omap_gp_timer_s; +struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta, + qemu_irq irq, omap_clk fclk, omap_clk iclk); + struct omap_watchdog_timer_s; struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base, qemu_irq irq, omap_clk clk); @@ -485,13 +645,22 @@ struct omap_32khz_timer_s *omap_os_timer_init(target_phys_addr_t base, qemu_irq irq, omap_clk clk); +void omap_synctimer_init(struct omap_target_agent_s *ta, + struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk); + struct omap_tipb_bridge_s; struct omap_tipb_bridge_s *omap_tipb_bridge_init(target_phys_addr_t base, qemu_irq abort_irq, omap_clk clk); struct omap_uart_s; struct omap_uart_s *omap_uart_init(target_phys_addr_t base, - qemu_irq irq, omap_clk clk, CharDriverState *chr); + qemu_irq irq, omap_clk fclk, omap_clk iclk, + qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr); +struct omap_uart_s *omap2_uart_init(struct omap_target_agent_s *ta, + qemu_irq irq, omap_clk fclk, omap_clk iclk, + qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr); +void omap_uart_reset(struct omap_uart_s *s); +void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr); struct omap_mpuio_s; struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base, @@ -507,6 +676,12 @@ qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s); void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler); +struct omap_gpif_s; +struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta, + qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules); +qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start); +void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler); + struct uwire_slave_s { uint16_t (*receive)(void *opaque); void (*send)(void *opaque, uint16_t data); @@ -518,6 +693,13 @@ void omap_uwire_attach(struct omap_uwire_s *s, struct uwire_slave_s *slave, int chipselect); +struct omap_mcspi_s; +struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum, + qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk); +void omap_mcspi_attach(struct omap_mcspi_s *s, + uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque, + int chipselect); + struct omap_rtc_s; struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, qemu_irq *irq, omap_clk clk); @@ -554,6 +736,13 @@ struct omap_lpg_s; struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk); +void omap_tap_init(struct omap_target_agent_s *ta, + struct omap_mpu_state_s *mpu); + +struct omap_eac_s; +struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta, + qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk); + /* omap_lcdc.c */ struct omap_lcd_panel_s; void omap_lcdc_reset(struct omap_lcd_panel_s *s); @@ -561,31 +750,76 @@ struct omap_dma_lcd_channel_s *dma, DisplayState *ds, ram_addr_t imif_base, ram_addr_t emiff_base, omap_clk clk); +/* omap_dss.c */ +struct rfbi_chip_s { + void *opaque; + void (*write)(void *opaque, int dc, uint16_t value); + void (*block)(void *opaque, int dc, void *buf, size_t len, int pitch); + uint16_t (*read)(void *opaque, int dc); +}; +struct omap_dss_s; +void omap_dss_reset(struct omap_dss_s *s); +struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta, + target_phys_addr_t l3_base, DisplayState *ds, + qemu_irq irq, qemu_irq drq, + omap_clk fck1, omap_clk fck2, omap_clk ck54m, + omap_clk ick1, omap_clk ick2); +void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip); + /* omap_mmc.c */ struct omap_mmc_s; struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, BlockDriverState *bd, qemu_irq irq, qemu_irq dma[], omap_clk clk); +struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta, + BlockDriverState *bd, qemu_irq irq, qemu_irq dma[], + omap_clk fclk, omap_clk iclk); void omap_mmc_reset(struct omap_mmc_s *s); void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover); +void omap_mmc_enable(struct omap_mmc_s *s, int enable); /* omap_i2c.c */ struct omap_i2c_s; struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base, qemu_irq irq, qemu_irq *dma, omap_clk clk); +struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta, + qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk); void omap_i2c_reset(struct omap_i2c_s *s); i2c_bus *omap_i2c_bus(struct omap_i2c_s *s); # define cpu_is_omap310(cpu) (cpu->mpu_model == omap310) # define cpu_is_omap1510(cpu) (cpu->mpu_model == omap1510) +# define cpu_is_omap1610(cpu) (cpu->mpu_model == omap1610) +# define cpu_is_omap1710(cpu) (cpu->mpu_model == omap1710) +# define cpu_is_omap2410(cpu) (cpu->mpu_model == omap2410) +# define cpu_is_omap2420(cpu) (cpu->mpu_model == omap2420) +# define cpu_is_omap2430(cpu) (cpu->mpu_model == omap2430) +# define cpu_is_omap3430(cpu) (cpu->mpu_model == omap3430) + # define cpu_is_omap15xx(cpu) \ (cpu_is_omap310(cpu) || cpu_is_omap1510(cpu)) -# define cpu_class_omap1(cpu) 1 +# define cpu_is_omap16xx(cpu) \ + (cpu_is_omap1610(cpu) || cpu_is_omap1710(cpu)) +# define cpu_is_omap24xx(cpu) \ + (cpu_is_omap2410(cpu) || cpu_is_omap2420(cpu) || cpu_is_omap2430(cpu)) + +# define cpu_class_omap1(cpu) \ + (cpu_is_omap15xx(cpu) || cpu_is_omap16xx(cpu)) +# define cpu_class_omap2(cpu) cpu_is_omap24xx(cpu) +# define cpu_class_omap3(cpu) cpu_is_omap3430(cpu) struct omap_mpu_state_s { - enum omap1_mpu_model { + enum omap_mpu_model { omap310, omap1510, + omap1610, + omap1710, + omap2410, + omap2420, + omap2422, + omap2423, + omap2430, + omap3430, } mpu_model; CPUState *env; @@ -602,7 +836,7 @@ target_phys_addr_t offset, uint32_t value); int (*addr_valid)(struct omap_mpu_state_s *s, target_phys_addr_t addr); - } port[omap_dma_port_last]; + } port[__omap_dma_port_last]; unsigned long sdram_size; unsigned long sram_size; @@ -638,7 +872,7 @@ omap_clk clk; } pwt; - struct omap_i2c_s *i2c; + struct omap_i2c_s *i2c[2]; struct omap_rtc_s *rtc; @@ -649,7 +883,7 @@ /* MPU private TIPB peripherals */ struct omap_intr_handler_s *ih[2]; - struct omap_dma_s *dma; + struct soc_dma_s *dma; struct omap_mpu_timer_s *timer[3]; struct omap_watchdog_timer_s *wdt; @@ -704,7 +938,40 @@ uint16_t dsp_idlect2; uint16_t dsp_rstct2; } clkm; -} *omap310_mpu_init(unsigned long sdram_size, + + /* OMAP2-only peripherals */ + struct omap_l4_s *l4; + + struct omap_gp_timer_s *gptimer[12]; + + target_phys_addr_t tap_base; + + struct omap_synctimer_s { + target_phys_addr_t base; + uint32_t val; + uint16_t readh; + } synctimer; + + struct omap_prcm_s *prcm; + struct omap_sdrc_s *sdrc; + struct omap_gpmc_s *gpmc; + struct omap_sysctl_s *sysc; + + struct omap_gpif_s *gpif; + + struct omap_mcspi_s *mcspi[2]; + + struct omap_dss_s *dss; + + struct omap_eac_s *eac; +}; + +/* omap1.c */ +struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, + DisplayState *ds, const char *core); + +/* omap2.c */ +struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size, DisplayState *ds, const char *core); # if TARGET_PHYS_ADDR_BITS == 32 @@ -725,24 +992,55 @@ void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, uint32_t value); +void omap_mpu_wakeup(void *opaque, int irq, int req); + # define OMAP_BAD_REG(paddr) \ - printf("%s: Bad register " OMAP_FMT_plx "\n", __FUNCTION__, paddr) + fprintf(stderr, "%s: Bad register " OMAP_FMT_plx "\n", \ + __FUNCTION__, paddr) # define OMAP_RO_REG(paddr) \ - printf("%s: Read-only register " OMAP_FMT_plx "\n", \ + fprintf(stderr, "%s: Read-only register " OMAP_FMT_plx "\n", \ __FUNCTION__, paddr) +/* OMAP-specific Linux bootloader tags for the ATAG_BOARD area + (Board-specifc tags are not here) */ +#define OMAP_TAG_CLOCK 0x4f01 +#define OMAP_TAG_MMC 0x4f02 +#define OMAP_TAG_SERIAL_CONSOLE 0x4f03 +#define OMAP_TAG_USB 0x4f04 +#define OMAP_TAG_LCD 0x4f05 +#define OMAP_TAG_GPIO_SWITCH 0x4f06 +#define OMAP_TAG_UART 0x4f07 +#define OMAP_TAG_FBMEM 0x4f08 +#define OMAP_TAG_STI_CONSOLE 0x4f09 +#define OMAP_TAG_CAMERA_SENSOR 0x4f0a +#define OMAP_TAG_PARTITION 0x4f0b +#define OMAP_TAG_TEA5761 0x4f10 +#define OMAP_TAG_TMP105 0x4f11 +#define OMAP_TAG_BOOT_REASON 0x4f80 +#define OMAP_TAG_FLASH_PART_STR 0x4f81 +#define OMAP_TAG_VERSION_STR 0x4f82 + +enum { + OMAP_GPIOSW_TYPE_COVER = 0 << 4, + OMAP_GPIOSW_TYPE_CONNECTION = 1 << 4, + OMAP_GPIOSW_TYPE_ACTIVITY = 2 << 4, +}; + +#define OMAP_GPIOSW_INVERTED 0x0001 +#define OMAP_GPIOSW_OUTPUT 0x0002 + # define TCMI_VERBOSE 1 //# define MEM_VERBOSE 1 # ifdef TCMI_VERBOSE # define OMAP_8B_REG(paddr) \ - printf("%s: 8-bit register " OMAP_FMT_plx "\n", \ + fprintf(stderr, "%s: 8-bit register " OMAP_FMT_plx "\n", \ __FUNCTION__, paddr) # define OMAP_16B_REG(paddr) \ - printf("%s: 16-bit register " OMAP_FMT_plx "\n", \ + fprintf(stderr, "%s: 16-bit register " OMAP_FMT_plx "\n", \ __FUNCTION__, paddr) # define OMAP_32B_REG(paddr) \ - printf("%s: 32-bit register " OMAP_FMT_plx "\n", \ + fprintf(stderr, "%s: 32-bit register " OMAP_FMT_plx "\n", \ __FUNCTION__, paddr) # else # define OMAP_8B_REG(paddr) @@ -845,10 +1143,13 @@ # define cpu_register_io_memory debug_register_io_memory # endif -/* Not really omap specific, but is the only thing that uses the - uwire interface. */ -/* tsc210x.c */ -struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio); -struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip); +/* Define when we want to reduce the number of IO regions registered. */ +/*# define L4_MUX_HACK*/ + +# ifdef L4_MUX_HACK +# undef l4_register_io_memory +int l4_register_io_memory(int io_index, CPUReadMemoryFunc **mem_read, + CPUWriteMemoryFunc **mem_write, void *opaque); +# endif #endif /* hw_omap_h */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/omap_i2c.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/omap_i2c.c --- qemu-0.9.1/hw/omap_i2c.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/omap_i2c.c 2008-07-21 20:52:54.000000000 +0100 @@ -29,6 +29,7 @@ i2c_slave slave; i2c_bus *bus; + uint8_t revision; uint8_t mask; uint16_t stat; uint16_t dma; @@ -44,6 +45,9 @@ uint16_t test; }; +#define OMAP2_INTR_REV 0x34 +#define OMAP2_GC_REV 0x34 + static void omap_i2c_interrupts_update(struct omap_i2c_s *s) { qemu_set_irq(s->irq, s->stat & s->mask); @@ -124,6 +128,7 @@ i2c_end_transfer(s->bus); s->control &= ~(1 << 1); /* STP */ s->count_cur = s->count; + s->txlen = 0; } else if ((s->control >> 9) & 1) { /* TRX */ while (ack && s->txlen) ack = (i2c_send(s->bus, @@ -145,6 +150,8 @@ } if (ack && s->count_cur) s->stat |= 1 << 4; /* XRDY */ + else + s->stat &= ~(1 << 4); /* XRDY */ if (!s->count_cur) { s->stat |= 1 << 2; /* ARDY */ s->control &= ~(1 << 10); /* MST */ @@ -156,12 +163,15 @@ } if (s->rxlen) s->stat |= 1 << 3; /* RRDY */ + else + s->stat &= ~(1 << 3); /* RRDY */ } if (!s->count_cur) { if ((s->control >> 1) & 1) { /* STP */ i2c_end_transfer(s->bus); s->control &= ~(1 << 1); /* STP */ s->count_cur = s->count; + s->txlen = 0; } else { s->stat |= 1 << 2; /* ARDY */ s->control &= ~(1 << 10); /* MST */ @@ -201,8 +211,7 @@ switch (offset) { case 0x00: /* I2C_REV */ - /* TODO: set a value greater or equal to real hardware */ - return 0x11; /* REV */ + return s->revision; /* REV */ case 0x04: /* I2C_IE */ return s->mask; @@ -211,12 +220,17 @@ return s->stat | (i2c_bus_busy(s->bus) << 12); case 0x0c: /* I2C_IV */ + if (s->revision >= OMAP2_INTR_REV) + break; ret = ffs(s->stat & s->mask); if (ret) s->stat ^= 1 << (ret - 1); omap_i2c_interrupts_update(s); return ret; + case 0x10: /* I2C_SYSS */ + return (s->control >> 15) & 1; /* I2C_EN */ + case 0x14: /* I2C_BUF */ return s->dma; @@ -242,7 +256,7 @@ } else /* XXX: remote access (qualifier) error - what's that? */; if (!s->rxlen) { - s->stat |= ~(1 << 3); /* RRDY */ + s->stat &= ~(1 << 3); /* RRDY */ if (((s->control >> 10) & 1) && /* MST */ ((~s->control >> 9) & 1)) { /* TRX */ s->stat |= 1 << 2; /* ARDY */ @@ -254,6 +268,9 @@ omap_i2c_interrupts_update(s); return ret; + case 0x20: /* I2C_SYSC */ + return 0; + case 0x24: /* I2C_CON */ return s->control; @@ -293,13 +310,24 @@ switch (offset) { case 0x00: /* I2C_REV */ - case 0x08: /* I2C_STAT */ case 0x0c: /* I2C_IV */ - OMAP_BAD_REG(addr); + case 0x10: /* I2C_SYSS */ + OMAP_RO_REG(addr); return; case 0x04: /* I2C_IE */ - s->mask = value & 0x1f; + s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f); + break; + + case 0x08: /* I2C_STAT */ + if (s->revision < OMAP2_INTR_REV) { + OMAP_RO_REG(addr); + return; + } + + /* RRDY and XRDY are reset by hardware. (in all versions???) */ + s->stat &= ~(value & 0x27); + omap_i2c_interrupts_update(s); break; case 0x14: /* I2C_BUF */ @@ -335,29 +363,45 @@ omap_i2c_interrupts_update(s); break; + case 0x20: /* I2C_SYSC */ + if (s->revision < OMAP2_INTR_REV) { + OMAP_BAD_REG(addr); + return; + } + + if (value & 2) + omap_i2c_reset(s); + break; + case 0x24: /* I2C_CON */ - s->control = value & 0xcf07; + s->control = value & 0xcf87; if (~value & (1 << 15)) { /* I2C_EN */ - omap_i2c_reset(s); + if (s->revision < OMAP2_INTR_REV) + omap_i2c_reset(s); break; } - if (~value & (1 << 10)) { /* MST */ - printf("%s: I^2C slave mode not supported\n", __FUNCTION__); + if ((value & (1 << 15)) && !(value & (1 << 10))) { /* MST */ + fprintf(stderr, "%s: I^2C slave mode not supported\n", + __FUNCTION__); break; } - if (value & (1 << 9)) { /* XA */ - printf("%s: 10-bit addressing mode not supported\n", __FUNCTION__); + if ((value & (1 << 15)) && value & (1 << 8)) { /* XA */ + fprintf(stderr, "%s: 10-bit addressing mode not supported\n", + __FUNCTION__); break; } - if (value & (1 << 0)) { /* STT */ + if ((value & (1 << 15)) && value & (1 << 0)) { /* STT */ nack = !!i2c_start_transfer(s->bus, s->addr[1], /* SA */ (~value >> 9) & 1); /* TRX */ s->stat |= nack << 1; /* NACK */ s->control &= ~(1 << 0); /* STT */ + s->fifo = 0; if (nack) s->control &= ~(1 << 1); /* STP */ - else + else { + s->count_cur = s->count; omap_i2c_fifo_run(s); + } omap_i2c_interrupts_update(s); } break; @@ -384,9 +428,42 @@ break; case 0x3c: /* I2C_SYSTEST */ - s->test = value & 0xf00f; + s->test = value & 0xf80f; + if (value & (1 << 11)) /* SBB */ + if (s->revision >= OMAP2_INTR_REV) { + s->stat |= 0x3f; + omap_i2c_interrupts_update(s); + } if (value & (1 << 15)) /* ST_EN */ - printf("%s: System Test not supported\n", __FUNCTION__); + fprintf(stderr, "%s: System Test not supported\n", __FUNCTION__); + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static void omap_i2c_writeb(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_i2c_s *s = (struct omap_i2c_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + switch (offset) { + case 0x1c: /* I2C_DATA */ + if (s->txlen > 2) { + /* XXX: remote access (qualifier) error - what's that? */ + break; + } + s->fifo <<= 8; + s->txlen += 1; + s->fifo |= value & 0xff; + s->stat &= ~(1 << 10); /* XUDF */ + if (s->txlen > 2) + s->stat &= ~(1 << 4); /* XRDY */ + omap_i2c_fifo_run(s); + omap_i2c_interrupts_update(s); break; default: @@ -402,9 +479,9 @@ }; static CPUWriteMemoryFunc *omap_i2c_writefn[] = { - omap_badwidth_write16, + omap_i2c_writeb, /* Only the last fifo write can be 8 bit. */ omap_i2c_write, - omap_i2c_write, /* TODO: Only the last fifo write can be 8 bit. */ + omap_badwidth_write16, }; struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base, @@ -414,6 +491,8 @@ struct omap_i2c_s *s = (struct omap_i2c_s *) qemu_mallocz(sizeof(struct omap_i2c_s)); + /* TODO: set a value greater or equal to real hardware */ + s->revision = 0x11; s->base = base; s->irq = irq; s->drq[0] = dma[0]; @@ -431,6 +510,30 @@ return s; } +struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta, + qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk) +{ + int iomemtype; + struct omap_i2c_s *s = (struct omap_i2c_s *) + qemu_mallocz(sizeof(struct omap_i2c_s)); + + s->revision = 0x34; + s->irq = irq; + s->drq[0] = dma[0]; + s->drq[1] = dma[1]; + s->slave.event = omap_i2c_event; + s->slave.recv = omap_i2c_rx; + s->slave.send = omap_i2c_tx; + s->bus = i2c_init_bus(); + omap_i2c_reset(s); + + iomemtype = l4_register_io_memory(0, omap_i2c_readfn, + omap_i2c_writefn, s); + s->base = omap_l4_attach(ta, 0, iomemtype); + + return s; +} + i2c_bus *omap_i2c_bus(struct omap_i2c_s *s) { return s->bus; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/omap_lcdc.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/omap_lcdc.c --- qemu-0.9.1/hw/omap_lcdc.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/omap_lcdc.c 2008-07-01 17:24:38.000000000 +0100 @@ -26,6 +26,7 @@ target_phys_addr_t base; qemu_irq irq; DisplayState *state; + QEMUConsole *console; ram_addr_t imif_base; ram_addr_t emiff_base; @@ -175,8 +176,8 @@ width = omap_lcd->width; if (width != omap_lcd->state->width || omap_lcd->height != omap_lcd->state->height) { - dpy_resize(omap_lcd->state, - omap_lcd->width, omap_lcd->height); + qemu_console_resize(omap_lcd->console, + omap_lcd->width, omap_lcd->height); omap_lcd->invalidate = 1; } @@ -494,8 +495,9 @@ omap_lcdc_writefn, s); cpu_register_physical_memory(s->base, 0x100, iomemtype); - graphic_console_init(ds, omap_update_display, - omap_invalidate_display, omap_screen_dump, s); + s->console = graphic_console_init(ds, omap_update_display, + omap_invalidate_display, + omap_screen_dump, NULL, s); return s; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/omap_mmc.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/omap_mmc.c --- qemu-0.9.1/hw/omap_mmc.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/omap_mmc.c 2008-05-18 13:14:41.000000000 +0100 @@ -5,8 +5,8 @@ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -26,19 +26,24 @@ target_phys_addr_t base; qemu_irq irq; qemu_irq *dma; + qemu_irq coverswitch; omap_clk clk; SDState *card; uint16_t last_cmd; uint16_t sdio; uint16_t rsp[8]; uint32_t arg; + int lines; int dw; int mode; int enable; + int be; + int rev; uint16_t status; uint16_t mask; uint8_t cto; uint16_t dto; + int clkdiv; uint16_t fifo[32]; int fifo_start; int fifo_len; @@ -53,6 +58,11 @@ int ddir; int transfer; + + int cdet_wakeup; + int cdet_enable; + int cdet_state; + qemu_irq cdet; }; static void omap_mmc_interrupts_update(struct omap_mmc_s *s) @@ -107,6 +117,11 @@ struct sd_request_s request; uint8_t response[16]; + if (init && cmd == 0) { + host->status |= 0x0001; + return; + } + if (resptype == sd_r1 && busy) resptype = sd_r1b; @@ -265,6 +280,34 @@ omap_mmc_interrupts_update(s); } +void omap_mmc_reset(struct omap_mmc_s *host) +{ + host->last_cmd = 0; + memset(host->rsp, 0, sizeof(host->rsp)); + host->arg = 0; + host->dw = 0; + host->mode = 0; + host->enable = 0; + host->status = 0; + host->mask = 0; + host->cto = 0; + host->dto = 0; + host->fifo_len = 0; + host->blen = 0; + host->blen_counter = 0; + host->nblk = 0; + host->nblk_counter = 0; + host->tx_dma = 0; + host->rx_dma = 0; + host->ae_level = 0x00; + host->af_level = 0x1f; + host->transfer = 0; + host->cdet_wakeup = 0; + host->cdet_enable = 0; + qemu_set_irq(host->coverswitch, host->cdet_state); + host->clkdiv = 0; +} + static uint32_t omap_mmc_read(void *opaque, target_phys_addr_t offset) { uint16_t i; @@ -282,7 +325,8 @@ return s->arg >> 16; case 0x0c: /* MMC_CON */ - return (s->dw << 15) | (s->mode << 12) | (s->enable << 11); + return (s->dw << 15) | (s->mode << 12) | (s->enable << 11) | + (s->be << 10) | s->clkdiv; case 0x10: /* MMC_STAT */ return s->status; @@ -324,12 +368,12 @@ case 0x30: /* MMC_SPI */ return 0x0000; case 0x34: /* MMC_SDIO */ - return s->sdio; + return (s->cdet_wakeup << 2) | (s->cdet_enable) | s->sdio; case 0x38: /* MMC_SYST */ return 0x0000; case 0x3c: /* MMC_REV */ - return 0x0001; + return s->rev; case 0x40: /* MMC_RSP0 */ case 0x44: /* MMC_RSP1 */ @@ -340,6 +384,13 @@ case 0x58: /* MMC_RSP6 */ case 0x5c: /* MMC_RSP7 */ return s->rsp[(offset - 0x40) >> 2]; + + /* OMAP2-specific */ + case 0x60: /* MMC_IOSR */ + case 0x64: /* MMC_SYSC */ + return 0; + case 0x68: /* MMC_SYSS */ + return 1; /* RSTD */ } OMAP_BAD_REG(offset); @@ -383,10 +434,16 @@ s->dw = (value >> 15) & 1; s->mode = (value >> 12) & 3; s->enable = (value >> 11) & 1; + s->be = (value >> 10) & 1; + s->clkdiv = (value >> 0) & (s->rev >= 2 ? 0x3ff : 0xff); if (s->mode != 0) printf("SD mode %i unimplemented!\n", s->mode); - if (s->dw != 0) + if (s->be != 0) + printf("SD FIFO byte sex unimplemented!\n"); + if (s->dw != 0 && s->lines < 4) printf("4-bit SD bus enabled\n"); + if (!s->enable) + omap_mmc_reset(s); break; case 0x10: /* MMC_STAT */ @@ -395,13 +452,13 @@ break; case 0x14: /* MMC_IE */ - s->mask = value; + s->mask = value & 0x7fff; omap_mmc_interrupts_update(s); break; case 0x18: /* MMC_CTO */ s->cto = value & 0xff; - if (s->cto > 0xfd) + if (s->cto > 0xfd && s->rev <= 1) printf("MMC: CTO of 0xff and 0xfe cannot be used!\n"); break; @@ -446,10 +503,12 @@ break; /* SPI, SDIO and TEST modes unimplemented */ - case 0x30: /* MMC_SPI */ + case 0x30: /* MMC_SPI (OMAP1 only) */ break; case 0x34: /* MMC_SDIO */ - s->sdio = value & 0x2020; + s->sdio = value & (s->rev >= 2 ? 0xfbf3 : 0x2020); + s->cdet_wakeup = (value >> 9) & 1; + s->cdet_enable = (value >> 2) & 1; break; case 0x38: /* MMC_SYST */ break; @@ -466,6 +525,19 @@ OMAP_RO_REG(offset); break; + /* OMAP2-specific */ + case 0x60: /* MMC_IOSR */ + if (value & 0xf) + printf("MMC: SDIO bits used!\n"); + break; + case 0x64: /* MMC_SYSC */ + if (value & (1 << 2)) /* SRTS */ + omap_mmc_reset(s); + break; + case 0x68: /* MMC_SYSS */ + OMAP_RO_REG(offset); + break; + default: OMAP_BAD_REG(offset); } @@ -483,28 +555,21 @@ omap_badwidth_write16, }; -void omap_mmc_reset(struct omap_mmc_s *host) +static void omap_mmc_cover_cb(void *opaque, int line, int level) { - host->last_cmd = 0; - memset(host->rsp, 0, sizeof(host->rsp)); - host->arg = 0; - host->dw = 0; - host->mode = 0; - host->enable = 0; - host->status = 0; - host->mask = 0; - host->cto = 0; - host->dto = 0; - host->fifo_len = 0; - host->blen = 0; - host->blen_counter = 0; - host->nblk = 0; - host->nblk_counter = 0; - host->tx_dma = 0; - host->rx_dma = 0; - host->ae_level = 0x00; - host->af_level = 0x1f; - host->transfer = 0; + struct omap_mmc_s *host = (struct omap_mmc_s *) opaque; + + if (!host->cdet_state && level) { + host->status |= 0x0002; + omap_mmc_interrupts_update(host); + if (host->cdet_wakeup) + /* TODO: Assert wake-up */; + } + + if (host->cdet_state != level) { + qemu_set_irq(host->coverswitch, level); + host->cdet_state = level; + } } struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, @@ -519,6 +584,10 @@ s->base = base; s->dma = dma; s->clk = clk; + s->lines = 1; /* TODO: needs to be settable per-board */ + s->rev = 1; + + omap_mmc_reset(s); iomemtype = cpu_register_io_memory(0, omap_mmc_readfn, omap_mmc_writefn, s); @@ -530,7 +599,46 @@ return s; } +struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta, + BlockDriverState *bd, qemu_irq irq, qemu_irq dma[], + omap_clk fclk, omap_clk iclk) +{ + int iomemtype; + struct omap_mmc_s *s = (struct omap_mmc_s *) + qemu_mallocz(sizeof(struct omap_mmc_s)); + + s->irq = irq; + s->dma = dma; + s->clk = fclk; + s->lines = 4; + s->rev = 2; + + omap_mmc_reset(s); + + iomemtype = l4_register_io_memory(0, omap_mmc_readfn, + omap_mmc_writefn, s); + s->base = omap_l4_attach(ta, 0, iomemtype); + + /* Instantiate the storage */ + s->card = sd_init(bd, 0); + + s->cdet = qemu_allocate_irqs(omap_mmc_cover_cb, s, 1)[0]; + sd_set_cb(s->card, 0, s->cdet); + + return s; +} + void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover) { - sd_set_cb(s->card, ro, cover); + if (s->cdet) { + sd_set_cb(s->card, ro, s->cdet); + s->coverswitch = cover; + qemu_set_irq(cover, s->cdet_state); + } else + sd_set_cb(s->card, ro, cover); +} + +void omap_mmc_enable(struct omap_mmc_s *s, int enable) +{ + sd_enable(s->card, enable); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/onenand.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/onenand.c --- qemu-0.9.1/hw/onenand.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/onenand.c 2008-07-29 15:19:16.000000000 +0100 @@ -0,0 +1,664 @@ +/* + * OneNAND flash memories emulation. + * + * Copyright (C) 2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "qemu-common.h" +#include "flash.h" +#include "irq.h" +#include "sysemu.h" +#include "block.h" + +/* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */ +#define PAGE_SHIFT 11 + +/* Fixed */ +#define BLOCK_SHIFT (PAGE_SHIFT + 6) + +struct onenand_s { + uint32_t id; + int shift; + target_phys_addr_t base; + qemu_irq intr; + qemu_irq rdy; + BlockDriverState *bdrv; + BlockDriverState *bdrv_cur; + uint8_t *image; + uint8_t *otp; + uint8_t *current; + ram_addr_t ram; + uint8_t *boot[2]; + uint8_t *data[2][2]; + int iomemtype; + int cycle; + int otpmode; + + uint16_t addr[8]; + uint16_t unladdr[8]; + int bufaddr; + int count; + uint16_t command; + uint16_t config[2]; + uint16_t status; + uint16_t intstatus; + uint16_t wpstatus; + + struct ecc_state_s ecc; + + int density_mask; + int secs; + int secs_cur; + int blocks; + uint8_t *blockwp; +}; + +enum { + ONEN_BUF_BLOCK = 0, + ONEN_BUF_BLOCK2 = 1, + ONEN_BUF_DEST_BLOCK = 2, + ONEN_BUF_DEST_PAGE = 3, + ONEN_BUF_PAGE = 7, +}; + +enum { + ONEN_ERR_CMD = 1 << 10, + ONEN_ERR_ERASE = 1 << 11, + ONEN_ERR_PROG = 1 << 12, + ONEN_ERR_LOAD = 1 << 13, +}; + +enum { + ONEN_INT_RESET = 1 << 4, + ONEN_INT_ERASE = 1 << 5, + ONEN_INT_PROG = 1 << 6, + ONEN_INT_LOAD = 1 << 7, + ONEN_INT = 1 << 15, +}; + +enum { + ONEN_LOCK_LOCKTIGHTEN = 1 << 0, + ONEN_LOCK_LOCKED = 1 << 1, + ONEN_LOCK_UNLOCKED = 1 << 2, +}; + +void onenand_base_update(void *opaque, target_phys_addr_t new) +{ + struct onenand_s *s = (struct onenand_s *) opaque; + + s->base = new; + + /* XXX: We should use IO_MEM_ROMD but we broke it earlier... + * Both 0x0000 ... 0x01ff and 0x8000 ... 0x800f can be used to + * write boot commands. Also take note of the BWPS bit. */ + cpu_register_physical_memory(s->base + (0x0000 << s->shift), + 0x0200 << s->shift, s->iomemtype); + cpu_register_physical_memory(s->base + (0x0200 << s->shift), + 0xbe00 << s->shift, + (s->ram +(0x0200 << s->shift)) | IO_MEM_RAM); + if (s->iomemtype) + cpu_register_physical_memory(s->base + (0xc000 << s->shift), + 0x4000 << s->shift, s->iomemtype); +} + +void onenand_base_unmap(void *opaque) +{ + struct onenand_s *s = (struct onenand_s *) opaque; + + cpu_register_physical_memory(s->base, + 0x10000 << s->shift, IO_MEM_UNASSIGNED); +} + +static void onenand_intr_update(struct onenand_s *s) +{ + qemu_set_irq(s->intr, ((s->intstatus >> 15) ^ (~s->config[0] >> 6)) & 1); +} + +/* Hot reset (Reset OneNAND command) or warm reset (RP pin low) */ +static void onenand_reset(struct onenand_s *s, int cold) +{ + memset(&s->addr, 0, sizeof(s->addr)); + s->command = 0; + s->count = 1; + s->bufaddr = 0; + s->config[0] = 0x40c0; + s->config[1] = 0x0000; + onenand_intr_update(s); + qemu_irq_raise(s->rdy); + s->status = 0x0000; + s->intstatus = cold ? 0x8080 : 0x8010; + s->unladdr[0] = 0; + s->unladdr[1] = 0; + s->wpstatus = 0x0002; + s->cycle = 0; + s->otpmode = 0; + s->bdrv_cur = s->bdrv; + s->current = s->image; + s->secs_cur = s->secs; + + if (cold) { + /* Lock the whole flash */ + memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks); + + if (s->bdrv && bdrv_read(s->bdrv, 0, s->boot[0], 8) < 0) + cpu_abort(cpu_single_env, "%s: Loading the BootRAM failed.\n", + __FUNCTION__); + } +} + +static inline int onenand_load_main(struct onenand_s *s, int sec, int secn, + void *dest) +{ + if (s->bdrv_cur) + return bdrv_read(s->bdrv_cur, sec, dest, secn) < 0; + else if (sec + secn > s->secs_cur) + return 1; + + memcpy(dest, s->current + (sec << 9), secn << 9); + + return 0; +} + +static inline int onenand_prog_main(struct onenand_s *s, int sec, int secn, + void *src) +{ + if (s->bdrv_cur) + return bdrv_write(s->bdrv_cur, sec, src, secn) < 0; + else if (sec + secn > s->secs_cur) + return 1; + + memcpy(s->current + (sec << 9), src, secn << 9); + + return 0; +} + +static inline int onenand_load_spare(struct onenand_s *s, int sec, int secn, + void *dest) +{ + uint8_t buf[512]; + + if (s->bdrv_cur) { + if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0) + return 1; + memcpy(dest, buf + ((sec & 31) << 4), secn << 4); + } else if (sec + secn > s->secs_cur) + return 1; + else + memcpy(dest, s->current + (s->secs_cur << 9) + (sec << 4), secn << 4); + + return 0; +} + +static inline int onenand_prog_spare(struct onenand_s *s, int sec, int secn, + void *src) +{ + uint8_t buf[512]; + + if (s->bdrv_cur) { + if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0) + return 1; + memcpy(buf + ((sec & 31) << 4), src, secn << 4); + return bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0; + } else if (sec + secn > s->secs_cur) + return 1; + + memcpy(s->current + (s->secs_cur << 9) + (sec << 4), src, secn << 4); + + return 0; +} + +static inline int onenand_erase(struct onenand_s *s, int sec, int num) +{ + /* TODO: optimise */ + uint8_t buf[512]; + + memset(buf, 0xff, sizeof(buf)); + for (; num > 0; num --, sec ++) { + if (onenand_prog_main(s, sec, 1, buf)) + return 1; + if (onenand_prog_spare(s, sec, 1, buf)) + return 1; + } + + return 0; +} + +static void onenand_command(struct onenand_s *s, int cmd) +{ + int b; + int sec; + void *buf; +#define SETADDR(block, page) \ + sec = (s->addr[page] & 3) + \ + ((((s->addr[page] >> 2) & 0x3f) + \ + (((s->addr[block] & 0xfff) | \ + (s->addr[block] >> 15 ? \ + s->density_mask : 0)) << 6)) << (PAGE_SHIFT - 9)); +#define SETBUF_M() \ + buf = (s->bufaddr & 8) ? \ + s->data[(s->bufaddr >> 2) & 1][0] : s->boot[0]; \ + buf += (s->bufaddr & 3) << 9; +#define SETBUF_S() \ + buf = (s->bufaddr & 8) ? \ + s->data[(s->bufaddr >> 2) & 1][1] : s->boot[1]; \ + buf += (s->bufaddr & 3) << 4; + + switch (cmd) { + case 0x00: /* Load single/multiple sector data unit into buffer */ + SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE) + + SETBUF_M() + if (onenand_load_main(s, sec, s->count, buf)) + s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD; + +#if 0 + SETBUF_S() + if (onenand_load_spare(s, sec, s->count, buf)) + s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD; +#endif + + /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages) + * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages) + * then we need two split the read/write into two chunks. + */ + s->intstatus |= ONEN_INT | ONEN_INT_LOAD; + break; + case 0x13: /* Load single/multiple spare sector into buffer */ + SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE) + + SETBUF_S() + if (onenand_load_spare(s, sec, s->count, buf)) + s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD; + + /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages) + * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages) + * then we need two split the read/write into two chunks. + */ + s->intstatus |= ONEN_INT | ONEN_INT_LOAD; + break; + case 0x80: /* Program single/multiple sector data unit from buffer */ + SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE) + + SETBUF_M() + if (onenand_prog_main(s, sec, s->count, buf)) + s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG; + +#if 0 + SETBUF_S() + if (onenand_prog_spare(s, sec, s->count, buf)) + s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG; +#endif + + /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages) + * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages) + * then we need two split the read/write into two chunks. + */ + s->intstatus |= ONEN_INT | ONEN_INT_PROG; + break; + case 0x1a: /* Program single/multiple spare area sector from buffer */ + SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE) + + SETBUF_S() + if (onenand_prog_spare(s, sec, s->count, buf)) + s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG; + + /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages) + * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages) + * then we need two split the read/write into two chunks. + */ + s->intstatus |= ONEN_INT | ONEN_INT_PROG; + break; + case 0x1b: /* Copy-back program */ + SETBUF_S() + + SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE) + if (onenand_load_main(s, sec, s->count, buf)) + s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG; + + SETADDR(ONEN_BUF_DEST_BLOCK, ONEN_BUF_DEST_PAGE) + if (onenand_prog_main(s, sec, s->count, buf)) + s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG; + + /* TODO: spare areas */ + + s->intstatus |= ONEN_INT | ONEN_INT_PROG; + break; + + case 0x23: /* Unlock NAND array block(s) */ + s->intstatus |= ONEN_INT; + + /* XXX the previous (?) area should be locked automatically */ + for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) { + if (b >= s->blocks) { + s->status |= ONEN_ERR_CMD; + break; + } + if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN) + break; + + s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED; + } + break; + case 0x27: /* Unlock All NAND array blocks */ + s->intstatus |= ONEN_INT; + + for (b = 0; b < s->blocks; b ++) { + if (b >= s->blocks) { + s->status |= ONEN_ERR_CMD; + break; + } + if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN) + break; + + s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED; + } + break; + + case 0x2a: /* Lock NAND array block(s) */ + s->intstatus |= ONEN_INT; + + for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) { + if (b >= s->blocks) { + s->status |= ONEN_ERR_CMD; + break; + } + if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN) + break; + + s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKED; + } + break; + case 0x2c: /* Lock-tight NAND array block(s) */ + s->intstatus |= ONEN_INT; + + for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) { + if (b >= s->blocks) { + s->status |= ONEN_ERR_CMD; + break; + } + if (s->blockwp[b] == ONEN_LOCK_UNLOCKED) + continue; + + s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKTIGHTEN; + } + break; + + case 0x71: /* Erase-Verify-Read */ + s->intstatus |= ONEN_INT; + break; + case 0x95: /* Multi-block erase */ + qemu_irq_pulse(s->intr); + /* Fall through. */ + case 0x94: /* Block erase */ + sec = ((s->addr[ONEN_BUF_BLOCK] & 0xfff) | + (s->addr[ONEN_BUF_BLOCK] >> 15 ? s->density_mask : 0)) + << (BLOCK_SHIFT - 9); + if (onenand_erase(s, sec, 1 << (BLOCK_SHIFT - 9))) + s->status |= ONEN_ERR_CMD | ONEN_ERR_ERASE; + + s->intstatus |= ONEN_INT | ONEN_INT_ERASE; + break; + case 0xb0: /* Erase suspend */ + break; + case 0x30: /* Erase resume */ + s->intstatus |= ONEN_INT | ONEN_INT_ERASE; + break; + + case 0xf0: /* Reset NAND Flash core */ + onenand_reset(s, 0); + break; + case 0xf3: /* Reset OneNAND */ + onenand_reset(s, 0); + break; + + case 0x65: /* OTP Access */ + s->intstatus |= ONEN_INT; + s->bdrv_cur = 0; + s->current = s->otp; + s->secs_cur = 1 << (BLOCK_SHIFT - 9); + s->addr[ONEN_BUF_BLOCK] = 0; + s->otpmode = 1; + break; + + default: + s->status |= ONEN_ERR_CMD; + s->intstatus |= ONEN_INT; + fprintf(stderr, "%s: unknown OneNAND command %x\n", + __FUNCTION__, cmd); + } + + onenand_intr_update(s); +} + +static uint32_t onenand_read(void *opaque, target_phys_addr_t addr) +{ + struct onenand_s *s = (struct onenand_s *) opaque; + int offset = (addr - s->base) >> s->shift; + + switch (offset) { + case 0x0000 ... 0xc000: + return lduw_le_p(s->boot[0] + (addr - s->base)); + + case 0xf000: /* Manufacturer ID */ + return (s->id >> 16) & 0xff; + case 0xf001: /* Device ID */ + return (s->id >> 8) & 0xff; + /* TODO: get the following values from a real chip! */ + case 0xf002: /* Version ID */ + return (s->id >> 0) & 0xff; + case 0xf003: /* Data Buffer size */ + return 1 << PAGE_SHIFT; + case 0xf004: /* Boot Buffer size */ + return 0x200; + case 0xf005: /* Amount of buffers */ + return 1 | (2 << 8); + case 0xf006: /* Technology */ + return 0; + + case 0xf100 ... 0xf107: /* Start addresses */ + return s->addr[offset - 0xf100]; + + case 0xf200: /* Start buffer */ + return (s->bufaddr << 8) | ((s->count - 1) & (1 << (PAGE_SHIFT - 10))); + + case 0xf220: /* Command */ + return s->command; + case 0xf221: /* System Configuration 1 */ + return s->config[0] & 0xffe0; + case 0xf222: /* System Configuration 2 */ + return s->config[1]; + + case 0xf240: /* Controller Status */ + return s->status; + case 0xf241: /* Interrupt */ + return s->intstatus; + case 0xf24c: /* Unlock Start Block Address */ + return s->unladdr[0]; + case 0xf24d: /* Unlock End Block Address */ + return s->unladdr[1]; + case 0xf24e: /* Write Protection Status */ + return s->wpstatus; + + case 0xff00: /* ECC Status */ + return 0x00; + case 0xff01: /* ECC Result of main area data */ + case 0xff02: /* ECC Result of spare area data */ + case 0xff03: /* ECC Result of main area data */ + case 0xff04: /* ECC Result of spare area data */ + cpu_abort(cpu_single_env, "%s: imeplement ECC\n", __FUNCTION__); + return 0x0000; + } + + fprintf(stderr, "%s: unknown OneNAND register %x\n", + __FUNCTION__, offset); + return 0; +} + +static void onenand_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct onenand_s *s = (struct onenand_s *) opaque; + int offset = (addr - s->base) >> s->shift; + int sec; + + switch (offset) { + case 0x0000 ... 0x01ff: + case 0x8000 ... 0x800f: + if (s->cycle) { + s->cycle = 0; + + if (value == 0x0000) { + SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE) + onenand_load_main(s, sec, + 1 << (PAGE_SHIFT - 9), s->data[0][0]); + s->addr[ONEN_BUF_PAGE] += 4; + s->addr[ONEN_BUF_PAGE] &= 0xff; + } + break; + } + + switch (value) { + case 0x00f0: /* Reset OneNAND */ + onenand_reset(s, 0); + break; + + case 0x00e0: /* Load Data into Buffer */ + s->cycle = 1; + break; + + case 0x0090: /* Read Identification Data */ + memset(s->boot[0], 0, 3 << s->shift); + s->boot[0][0 << s->shift] = (s->id >> 16) & 0xff; + s->boot[0][1 << s->shift] = (s->id >> 8) & 0xff; + s->boot[0][2 << s->shift] = s->wpstatus & 0xff; + break; + + default: + fprintf(stderr, "%s: unknown OneNAND boot command %x\n", + __FUNCTION__, value); + } + break; + + case 0xf100 ... 0xf107: /* Start addresses */ + s->addr[offset - 0xf100] = value; + break; + + case 0xf200: /* Start buffer */ + s->bufaddr = (value >> 8) & 0xf; + if (PAGE_SHIFT == 11) + s->count = (value & 3) ?: 4; + else if (PAGE_SHIFT == 10) + s->count = (value & 1) ?: 2; + break; + + case 0xf220: /* Command */ + if (s->intstatus & (1 << 15)) + break; + s->command = value; + onenand_command(s, s->command); + break; + case 0xf221: /* System Configuration 1 */ + s->config[0] = value; + onenand_intr_update(s); + qemu_set_irq(s->rdy, (s->config[0] >> 7) & 1); + break; + case 0xf222: /* System Configuration 2 */ + s->config[1] = value; + break; + + case 0xf241: /* Interrupt */ + s->intstatus &= value; + if ((1 << 15) & ~s->intstatus) + s->status &= ~(ONEN_ERR_CMD | ONEN_ERR_ERASE | + ONEN_ERR_PROG | ONEN_ERR_LOAD); + onenand_intr_update(s); + break; + case 0xf24c: /* Unlock Start Block Address */ + s->unladdr[0] = value & (s->blocks - 1); + /* For some reason we have to set the end address to by default + * be same as start because the software forgets to write anything + * in there. */ + s->unladdr[1] = value & (s->blocks - 1); + break; + case 0xf24d: /* Unlock End Block Address */ + s->unladdr[1] = value & (s->blocks - 1); + break; + + default: + fprintf(stderr, "%s: unknown OneNAND register %x\n", + __FUNCTION__, offset); + } +} + +static CPUReadMemoryFunc *onenand_readfn[] = { + onenand_read, /* TODO */ + onenand_read, + onenand_read, +}; + +static CPUWriteMemoryFunc *onenand_writefn[] = { + onenand_write, /* TODO */ + onenand_write, + onenand_write, +}; + +void *onenand_init(uint32_t id, int regshift, qemu_irq irq) +{ + struct onenand_s *s = (struct onenand_s *) qemu_mallocz(sizeof(*s)); + int bdrv_index = drive_get_index(IF_MTD, 0, 0); + uint32_t size = 1 << (24 + ((id >> 12) & 7)); + void *ram; + + s->shift = regshift; + s->intr = irq; + s->rdy = 0; + s->id = id; + s->blocks = size >> BLOCK_SHIFT; + s->secs = size >> 9; + s->blockwp = qemu_malloc(s->blocks); + s->density_mask = (id & (1 << 11)) ? (1 << (6 + ((id >> 12) & 7))) : 0; + s->iomemtype = cpu_register_io_memory(0, onenand_readfn, + onenand_writefn, s); + if (bdrv_index == -1) + s->image = memset(qemu_malloc(size + (size >> 5)), + 0xff, size + (size >> 5)); + else + s->bdrv = drives_table[bdrv_index].bdrv; + s->otp = memset(qemu_malloc((64 + 2) << PAGE_SHIFT), + 0xff, (64 + 2) << PAGE_SHIFT); + s->ram = qemu_ram_alloc(0xc000 << s->shift); + ram = phys_ram_base + s->ram; + s->boot[0] = ram + (0x0000 << s->shift); + s->boot[1] = ram + (0x8000 << s->shift); + s->data[0][0] = ram + ((0x0200 + (0 << (PAGE_SHIFT - 1))) << s->shift); + s->data[0][1] = ram + ((0x8010 + (0 << (PAGE_SHIFT - 6))) << s->shift); + s->data[1][0] = ram + ((0x0200 + (1 << (PAGE_SHIFT - 1))) << s->shift); + s->data[1][1] = ram + ((0x8010 + (1 << (PAGE_SHIFT - 6))) << s->shift); + + onenand_reset(s, 1); + + return s; +} + +void *onenand_raw_otp(void *opaque) +{ + struct onenand_s *s = (struct onenand_s *) opaque; + + return s->otp; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/openpic.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/openpic.c --- qemu-0.9.1/hw/openpic.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/openpic.c 2008-10-26 13:43:07.000000000 +0000 @@ -128,7 +128,7 @@ IRQ_INTERNAL = 0x02, IRQ_TIMER = 0x04, IRQ_SPECIAL = 0x08, -} IRQ_src_type; +}; typedef struct IRQ_queue_t { uint32_t queue[BF_WIDTH(MAX_IRQ)]; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/palm.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/palm.c --- qemu-0.9.1/hw/palm.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/palm.c 2008-10-28 10:59:59.000000000 +0000 @@ -5,8 +5,8 @@ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -25,6 +25,7 @@ #include "omap.h" #include "boards.h" #include "arm-misc.h" +#include "devices.h" static uint32_t static_readb(void *opaque, target_phys_addr_t offset) { @@ -32,12 +33,14 @@ return *val >> ((offset & 3) << 3); } -static uint32_t static_readh(void *opaque, target_phys_addr_t offset) { +static uint32_t static_readh(void *opaque, target_phys_addr_t offset) +{ uint32_t *val = (uint32_t *) opaque; return *val >> ((offset & 1) << 3); } -static uint32_t static_readw(void *opaque, target_phys_addr_t offset) { +static uint32_t static_readw(void *opaque, target_phys_addr_t offset) +{ uint32_t *val = (uint32_t *) opaque; return *val >> ((offset & 0) << 3); } @@ -82,6 +85,12 @@ #define PALMTE_MMC2_GPIO 7 #define PALMTE_MMC3_GPIO 11 +static struct mouse_transform_info_s palmte_pointercal = { + .x = 320, + .y = 320, + .a = { -5909, 8, 22465308, 104, 7644, -1219972, 65536 }, +}; + static void palmte_microwire_setup(struct omap_mpu_state_s *cpu) { struct uwire_slave_s *tsc; @@ -96,6 +105,8 @@ omap_uwire_attach(cpu->microwire, tsc, 0); omap_mcbsp_i2s_attach(cpu->mcbsp1, tsc210x_codec(tsc)); + + tsc210x_set_transform(tsc, &palmte_pointercal); } static struct { @@ -183,14 +194,20 @@ qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[11]); } -static void palmte_init(int ram_size, int vga_ram_size, +static struct arm_boot_info palmte_binfo = { + .loader_start = OMAP_EMIFF_BASE, + .ram_size = 0x02000000, + .board_id = 0x331, +}; + +static void palmte_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { struct omap_mpu_state_s *cpu; int flash_size = 0x00800000; - int sdram_size = 0x02000000; + int sdram_size = palmte_binfo.ram_size; int io; static uint32_t cs0val = 0xffffffff; static uint32_t cs1val = 0x0000e1a0; @@ -250,17 +267,24 @@ /* Load the kernel. */ if (kernel_filename) { /* Start at bootloader. */ - cpu->env->regs[15] = OMAP_EMIFF_BASE; + cpu->env->regs[15] = palmte_binfo.loader_start; - arm_load_kernel(cpu->env, sdram_size, kernel_filename, kernel_cmdline, - initrd_filename, 0x331, OMAP_EMIFF_BASE); + palmte_binfo.kernel_filename = kernel_filename; + palmte_binfo.kernel_cmdline = kernel_cmdline; + palmte_binfo.initrd_filename = initrd_filename; + arm_load_kernel(cpu->env, &palmte_binfo); } + /* FIXME: We shouldn't really be doing this here. The LCD controller + will set the size once configured, so this just sets an initial + size until the guest activates the display. */ dpy_resize(ds, 320, 320); } QEMUMachine palmte_machine = { - "cheetah", - "Palm Tungsten|E aka. Cheetah PDA (OMAP310)", - palmte_init, + .name = "cheetah", + .desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)", + .init = palmte_init, + .ram_require = (0x02000000 + 0x00800000 + OMAP15XX_SRAM_SIZE) | + RAMSIZE_FIXED, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/parallel.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/parallel.c --- qemu-0.9.1/hw/parallel.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/parallel.c 2008-08-22 09:57:09.000000000 +0100 @@ -101,6 +101,7 @@ parallel_update_irq(s); break; case PARA_REG_CTR: + val |= 0xc0; if ((val & PARA_CTR_INIT) == 0 ) { s->status = PARA_STS_BUSY; s->status |= PARA_STS_ACK; @@ -128,6 +129,7 @@ { ParallelState *s = opaque; uint8_t parm = val; + int dir; /* Sometimes programs do several writes for timing purposes on old HW. Take care not to waste time on writes that do nothing. */ @@ -153,6 +155,17 @@ if (s->control == val) return; pdebug("wc%02x\n", val); + + if ((val & PARA_CTR_DIR) != (s->control & PARA_CTR_DIR)) { + if (val & PARA_CTR_DIR) { + dir = 1; + } else { + dir = 0; + } + qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_DATA_DIR, &dir); + parm &= ~PARA_CTR_DIR; + } + qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm); s->control = val; break; @@ -414,8 +427,10 @@ s->status |= PARA_STS_ACK; s->status |= PARA_STS_ONLINE; s->status |= PARA_STS_ERROR; + s->status |= PARA_STS_TMOUT; s->control = PARA_CTR_SELECT; s->control |= PARA_CTR_INIT; + s->control |= 0xc0; s->irq = irq; s->irq_pending = 0; s->chr = chr; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pc.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pc.c --- qemu-0.9.1/hw/pc.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pc.c 2008-11-08 16:27:07.000000000 +0000 @@ -31,6 +31,8 @@ #include "net.h" #include "smbus.h" #include "boards.h" +#include "console.h" +#include "fw_cfg.h" /* output Bochs bios info messages */ //#define DEBUG_BIOS @@ -39,8 +41,11 @@ #define VGABIOS_FILENAME "vgabios.bin" #define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin" +#define PC_MAX_BIOS_SIZE (4 * 1024 * 1024) + /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */ #define ACPI_DATA_SIZE 0x10000 +#define BIOS_CFG_IOPORT 0x510 #define MAX_IDE_BUS 2 @@ -73,7 +78,7 @@ /* Note: when using kqemu, it is more logical to return the host TSC because kqemu does not trap the RDTSC instruction for performance reasons */ -#if USE_KQEMU +#ifdef USE_KQEMU if (env->kqemu_enabled) { return cpu_get_real_ticks(); } else @@ -113,9 +118,20 @@ static void pic_irq_request(void *opaque, int irq, int level) { - CPUState *env = opaque; - if (level && apic_accept_pic_intr(env)) - cpu_interrupt(env, CPU_INTERRUPT_HARD); + CPUState *env = first_cpu; + + if (env->apic_state) { + while (env) { + if (apic_accept_pic_intr(env)) + apic_deliver_pic_intr(env, level); + env = env->next_cpu; + } + } else { + if (level) + cpu_interrupt(env, CPU_INTERRUPT_HARD); + else + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } } /* PC cmos mappings */ @@ -180,8 +196,36 @@ return 0; } +/* copy/pasted from cmos_init, should be made a general function + and used there as well */ +static int pc_boot_set(void *opaque, const char *boot_device) +{ +#define PC_MAX_BOOT_DEVICES 3 + RTCState *s = (RTCState *)opaque; + int nbds, bds[3] = { 0, }; + int i; + + nbds = strlen(boot_device); + if (nbds > PC_MAX_BOOT_DEVICES) { + term_printf("Too many boot devices for PC\n"); + return(1); + } + for (i = 0; i < nbds; i++) { + bds[i] = boot_device2nibble(boot_device[i]); + if (bds[i] == 0) { + term_printf("Invalid boot device for PC: '%c'\n", + boot_device[i]); + return(1); + } + } + rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]); + rtc_set_memory(s, 0x38, (bds[2] << 4)); + return(0); +} + /* hd_table must contain 4 block drivers */ -static void cmos_init(int ram_size, const char *boot_device, BlockDriverState **hd_table) +static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, + const char *boot_device, BlockDriverState **hd_table) { RTCState *s = rtc_state; int nbds, bds[3] = { 0, }; @@ -204,6 +248,12 @@ rtc_set_memory(s, 0x30, val); rtc_set_memory(s, 0x31, val >> 8); + if (above_4g_mem_size) { + rtc_set_memory(s, 0x5b, (unsigned int)above_4g_mem_size >> 16); + rtc_set_memory(s, 0x5c, (unsigned int)above_4g_mem_size >> 24); + rtc_set_memory(s, 0x5d, (uint64_t)above_4g_mem_size >> 32); + } + if (ram_size > (16 * 1024 * 1024)) val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536); else @@ -213,6 +263,9 @@ rtc_set_memory(s, 0x34, val); rtc_set_memory(s, 0x35, val >> 8); + /* set the number of CPU */ + rtc_set_memory(s, 0x5f, smp_cpus - 1); + /* set boot devices, and disable floppy signature check if requested */ #define PC_MAX_BOOT_DEVICES 3 nbds = strlen(boot_device); @@ -365,6 +418,8 @@ static void bochs_bios_init(void) { + void *fw_cfg; + register_ioport_write(0x400, 1, 2, bochs_bios_write, NULL); register_ioport_write(0x401, 1, 2, bochs_bios_write, NULL); register_ioport_write(0x402, 1, 1, bochs_bios_write, NULL); @@ -375,34 +430,53 @@ register_ioport_write(0x502, 1, 2, bochs_bios_write, NULL); register_ioport_write(0x500, 1, 1, bochs_bios_write, NULL); register_ioport_write(0x503, 1, 1, bochs_bios_write, NULL); + + fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); + fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); } /* Generate an initial boot sector which sets state and jump to a specified vector */ -static void generate_bootsect(uint32_t gpr[8], uint16_t segs[6], uint16_t ip) +static void generate_bootsect(uint8_t *option_rom, + uint32_t gpr[8], uint16_t segs[6], uint16_t ip) { - uint8_t bootsect[512], *p; + uint8_t rom[512], *p, *reloc; + uint8_t sum; int i; - int hda; - - hda = drive_get_index(IF_IDE, 0, 0); - if (hda == -1) { - fprintf(stderr, "A disk image must be given for 'hda' when booting " - "a Linux kernel\n"); - exit(1); - } - - memset(bootsect, 0, sizeof(bootsect)); - - /* Copy the MSDOS partition table if possible */ - bdrv_read(drives_table[hda].bdrv, 0, bootsect, 1); - /* Make sure we have a partition signature */ - bootsect[510] = 0x55; - bootsect[511] = 0xaa; + memset(rom, 0, sizeof(rom)); + p = rom; + /* Make sure we have an option rom signature */ + *p++ = 0x55; + *p++ = 0xaa; + + /* ROM size in sectors*/ + *p++ = 1; + + /* Hook int19 */ + + *p++ = 0x50; /* push ax */ + *p++ = 0x1e; /* push ds */ + *p++ = 0x31; *p++ = 0xc0; /* xor ax, ax */ + *p++ = 0x8e; *p++ = 0xd8; /* mov ax, ds */ + + *p++ = 0xc7; *p++ = 0x06; /* movvw _start,0x64 */ + *p++ = 0x64; *p++ = 0x00; + reloc = p; + *p++ = 0x00; *p++ = 0x00; + + *p++ = 0x8c; *p++ = 0x0e; /* mov cs,0x66 */ + *p++ = 0x66; *p++ = 0x00; + + *p++ = 0x1f; /* pop ds */ + *p++ = 0x58; /* pop ax */ + *p++ = 0xcb; /* lret */ + /* Actual code */ - p = bootsect; + *reloc = (p - rom); + *p++ = 0xfa; /* CLI */ *p++ = 0xfc; /* CLD */ @@ -432,38 +506,13 @@ *p++ = segs[1]; /* CS */ *p++ = segs[1] >> 8; - bdrv_set_boot_sector(drives_table[hda].bdrv, bootsect, sizeof(bootsect)); -} - -static int load_kernel(const char *filename, uint8_t *addr, - uint8_t *real_addr) -{ - int fd, size; - int setup_sects; - - fd = open(filename, O_RDONLY | O_BINARY); - if (fd < 0) - return -1; + /* sign rom */ + sum = 0; + for (i = 0; i < (sizeof(rom) - 1); i++) + sum += rom[i]; + rom[sizeof(rom) - 1] = -sum; - /* load 16 bit code */ - if (read(fd, real_addr, 512) != 512) - goto fail; - setup_sects = real_addr[0x1F1]; - if (!setup_sects) - setup_sects = 4; - if (read(fd, real_addr + 512, setup_sects * 512) != - setup_sects * 512) - goto fail; - - /* load 32 bit code */ - size = read(fd, addr, 16 * 1024 * 1024); - if (size < 0) - goto fail; - close(fd); - return size; - fail: - close(fd); - return -1; + memcpy(option_rom, rom, sizeof(rom)); } static long get_file_size(FILE *f) @@ -480,7 +529,8 @@ return size; } -static void load_linux(const char *kernel_filename, +static void load_linux(uint8_t *option_rom, + const char *kernel_filename, const char *initrd_filename, const char *kernel_cmdline) { @@ -491,7 +541,7 @@ int setup_size, kernel_size, initrd_size, cmdline_size; uint32_t initrd_max; uint8_t header[1024]; - uint8_t *real_addr, *prot_addr, *cmdline_addr, *initrd_addr; + target_phys_addr_t real_addr, prot_addr, cmdline_addr, initrd_addr; FILE *f, *fi; /* Align to 16 bytes as a paranoia measure */ @@ -517,29 +567,29 @@ if (protocol < 0x200 || !(header[0x211] & 0x01)) { /* Low kernel */ - real_addr = phys_ram_base + 0x90000; - cmdline_addr = phys_ram_base + 0x9a000 - cmdline_size; - prot_addr = phys_ram_base + 0x10000; + real_addr = 0x90000; + cmdline_addr = 0x9a000 - cmdline_size; + prot_addr = 0x10000; } else if (protocol < 0x202) { /* High but ancient kernel */ - real_addr = phys_ram_base + 0x90000; - cmdline_addr = phys_ram_base + 0x9a000 - cmdline_size; - prot_addr = phys_ram_base + 0x100000; + real_addr = 0x90000; + cmdline_addr = 0x9a000 - cmdline_size; + prot_addr = 0x100000; } else { /* High and recent kernel */ - real_addr = phys_ram_base + 0x10000; - cmdline_addr = phys_ram_base + 0x20000; - prot_addr = phys_ram_base + 0x100000; + real_addr = 0x10000; + cmdline_addr = 0x20000; + prot_addr = 0x100000; } #if 0 fprintf(stderr, - "qemu: real_addr = %#zx\n" - "qemu: cmdline_addr = %#zx\n" - "qemu: prot_addr = %#zx\n", - real_addr-phys_ram_base, - cmdline_addr-phys_ram_base, - prot_addr-phys_ram_base); + "qemu: real_addr = 0x" TARGET_FMT_plx "\n" + "qemu: cmdline_addr = 0x" TARGET_FMT_plx "\n" + "qemu: prot_addr = 0x" TARGET_FMT_plx "\n", + real_addr, + cmdline_addr, + prot_addr); #endif /* highest address for loading the initrd */ @@ -552,10 +602,10 @@ initrd_max = ram_size-ACPI_DATA_SIZE-1; /* kernel command line */ - pstrcpy((char*)cmdline_addr, 4096, kernel_cmdline); + pstrcpy_targphys(cmdline_addr, 4096, kernel_cmdline); if (protocol >= 0x202) { - stl_p(header+0x228, cmdline_addr-phys_ram_base); + stl_p(header+0x228, cmdline_addr); } else { stw_p(header+0x20, 0xA33F); stw_p(header+0x22, cmdline_addr-real_addr); @@ -589,24 +639,24 @@ } initrd_size = get_file_size(fi); - initrd_addr = phys_ram_base + ((initrd_max-initrd_size) & ~4095); + initrd_addr = (initrd_max-initrd_size) & ~4095; - fprintf(stderr, "qemu: loading initrd (%#x bytes) at %#zx\n", - initrd_size, initrd_addr-phys_ram_base); + fprintf(stderr, "qemu: loading initrd (%#x bytes) at 0x" TARGET_FMT_plx + "\n", initrd_size, initrd_addr); - if (fread(initrd_addr, 1, initrd_size, fi) != initrd_size) { + if (!fread_targphys_ok(initrd_addr, initrd_size, fi)) { fprintf(stderr, "qemu: read error on initial ram disk '%s'\n", initrd_filename); exit(1); } fclose(fi); - stl_p(header+0x218, initrd_addr-phys_ram_base); + stl_p(header+0x218, initrd_addr); stl_p(header+0x21c, initrd_size); } /* store the finalized header and load the rest of the kernel */ - memcpy(real_addr, header, 1024); + cpu_physical_memory_write(real_addr, header, 1024); setup_size = header[0x1f1]; if (setup_size == 0) @@ -615,8 +665,8 @@ setup_size = (setup_size+1)*512; kernel_size -= setup_size; /* Size of protected-mode code */ - if (fread(real_addr+1024, 1, setup_size-1024, f) != setup_size-1024 || - fread(prot_addr, 1, kernel_size, f) != kernel_size) { + if (!fread_targphys_ok(real_addr+1024, setup_size-1024, f) || + !fread_targphys_ok(prot_addr, kernel_size, f)) { fprintf(stderr, "qemu: read error on kernel '%s'\n", kernel_filename); exit(1); @@ -624,13 +674,13 @@ fclose(f); /* generate bootsector to set up the initial register state */ - real_seg = (real_addr-phys_ram_base) >> 4; + real_seg = real_addr >> 4; seg[0] = seg[2] = seg[3] = seg[4] = seg[4] = real_seg; seg[1] = real_seg+0x20; /* CS */ memset(gpr, 0, sizeof gpr); gpr[4] = cmdline_addr-real_addr-16; /* SP (-16 is paranoia) */ - generate_bootsect(gpr, seg, 0); + generate_bootsect(option_rom, gpr, seg, 0); } static void main_cpu_reset(void *opaque) @@ -697,7 +747,7 @@ } /* PC hardware initialisation */ -static void pc_init1(int ram_size, int vga_ram_size, +static void pc_init1(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, @@ -706,6 +756,7 @@ char buf[1024]; int ret, linux_boot, i; ram_addr_t ram_addr, vga_ram_addr, bios_offset, vga_bios_offset; + ram_addr_t below_4g_mem_size, above_4g_mem_size = 0; int bios_size, isa_bios_size, vga_bios_size; PCIBus *pci_bus; int piix3_devfn = -1; @@ -717,6 +768,13 @@ BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; BlockDriverState *fd[MAX_FD]; + if (ram_size >= 0xe0000000 ) { + above_4g_mem_size = ram_size - 0xe0000000; + below_4g_mem_size = 0xe0000000; + } else { + below_4g_mem_size = ram_size; + } + linux_boot = (kernel_filename != NULL); /* init CPUs */ @@ -735,22 +793,41 @@ exit(1); } if (i != 0) - env->hflags |= HF_HALTED_MASK; + env->halted = 1; if (smp_cpus > 1) { /* XXX: enable it in all cases */ env->cpuid_features |= CPUID_APIC; } - register_savevm("cpu", i, 4, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); if (pci_enabled) { apic_init(env); } - vmport_init(env); } + vmport_init(); + /* allocate RAM */ - ram_addr = qemu_ram_alloc(ram_size); - cpu_register_physical_memory(0, ram_size, ram_addr); + ram_addr = qemu_ram_alloc(0xa0000); + cpu_register_physical_memory(0, 0xa0000, ram_addr); + + /* Allocate, even though we won't register, so we don't break the + * phys_ram_base + PA assumption. This range includes vga (0xa0000 - 0xc0000), + * and some bios areas, which will be registered later + */ + ram_addr = qemu_ram_alloc(0x100000 - 0xa0000); + ram_addr = qemu_ram_alloc(below_4g_mem_size - 0x100000); + cpu_register_physical_memory(0x100000, + below_4g_mem_size - 0x100000, + ram_addr); + + /* above 4giga memory allocation */ + if (above_4g_mem_size > 0) { + ram_addr = qemu_ram_alloc(above_4g_mem_size); + cpu_register_physical_memory(0x100000000ULL, + above_4g_mem_size, + ram_addr); + } + /* allocate VGA RAM */ vga_ram_addr = qemu_ram_alloc(vga_ram_size); @@ -798,8 +875,6 @@ isa_bios_size = bios_size; if (isa_bios_size > (128 * 1024)) isa_bios_size = 128 * 1024; - cpu_register_physical_memory(0xd0000, (192 * 1024) - isa_bios_size, - IO_MEM_UNASSIGNED); cpu_register_physical_memory(0x100000 - isa_bios_size, isa_bios_size, (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM); @@ -809,6 +884,15 @@ int size, offset; offset = 0; + if (linux_boot) { + option_rom_offset = qemu_ram_alloc(TARGET_PAGE_SIZE); + load_linux(phys_ram_base + option_rom_offset, + kernel_filename, initrd_filename, kernel_cmdline); + cpu_register_physical_memory(0xd0000, TARGET_PAGE_SIZE, + option_rom_offset | IO_MEM_ROM); + offset = TARGET_PAGE_SIZE; + } + for (i = 0; i < nb_option_roms; i++) { size = get_image_size(option_rom[i]); if (size < 0) { @@ -838,10 +922,7 @@ bochs_bios_init(); - if (linux_boot) - load_linux(kernel_filename, initrd_filename, kernel_cmdline); - - cpu_irq = qemu_allocate_irqs(pic_irq_request, first_cpu, 1); + cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1); i8259 = i8259_init(cpu_irq[0]); ferr_irq = i8259[13]; @@ -868,8 +949,8 @@ } } else if (vmsvga_enabled) { if (pci_enabled) - pci_vmsvga_init(pci_bus, ds, phys_ram_base + ram_size, - ram_size, vga_ram_size); + pci_vmsvga_init(pci_bus, ds, phys_ram_base + vga_ram_addr, + vga_ram_addr, vga_ram_size); else fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__); } else { @@ -884,6 +965,8 @@ rtc_state = rtc_init(0x70, i8259[8]); + qemu_register_boot_set(pc_boot_set, rtc_state); + register_ioport_read(0x92, 1, 1, ioport92_read, NULL); register_ioport_write(0x92, 1, 1, ioport92_write, NULL); @@ -898,7 +981,8 @@ for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { - serial_init(serial_io[i], i8259[serial_irq[i]], serial_hds[i]); + serial_init(serial_io[i], i8259[serial_irq[i]], 115200, + serial_hds[i]); } } @@ -970,7 +1054,7 @@ } floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd); - cmos_init(ram_size, boot_device, hd); + cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, hd); if (pci_enabled && usb_enabled) { usb_uhci_piix3_init(pci_bus, piix3_devfn + 2); @@ -981,7 +1065,7 @@ i2c_bus *smbus; /* TODO: Populate SPD eeprom data. */ - smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100); + smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, i8259[9]); for (i = 0; i < 8; i++) { smbus_eeprom_device_init(smbus, 0x50 + i, eeprom_buf + (i * 256)); } @@ -1010,7 +1094,7 @@ } } -static void pc_init_pci(int ram_size, int vga_ram_size, +static void pc_init_pci(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, @@ -1022,7 +1106,7 @@ initrd_filename, 1, cpu_model); } -static void pc_init_isa(int ram_size, int vga_ram_size, +static void pc_init_isa(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, @@ -1035,13 +1119,17 @@ } QEMUMachine pc_machine = { - "pc", - "Standard PC", - pc_init_pci, + .name = "pc", + .desc = "Standard PC", + .init = pc_init_pci, + .ram_require = VGA_RAM_SIZE + PC_MAX_BIOS_SIZE, + .max_cpus = 255, }; QEMUMachine isapc_machine = { - "isapc", - "ISA-only PC", - pc_init_isa, + .name = "isapc", + .desc = "ISA-only PC", + .init = pc_init_isa, + .ram_require = VGA_RAM_SIZE + PC_MAX_BIOS_SIZE, + .max_cpus = 1, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pc.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pc.h --- qemu-0.9.1/hw/pc.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pc.h 2008-10-26 13:43:07.000000000 +0000 @@ -4,10 +4,11 @@ /* serial.c */ -SerialState *serial_init(int base, qemu_irq irq, CharDriverState *chr); +SerialState *serial_init(int base, qemu_irq irq, int baudbase, + CharDriverState *chr); SerialState *serial_mm_init (target_phys_addr_t base, int it_shift, - qemu_irq irq, CharDriverState *chr, - int ioregister); + qemu_irq irq, int baudbase, + CharDriverState *chr, int ioregister); uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr); void serial_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value); uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr); @@ -41,6 +42,7 @@ int apic_init(CPUState *env); int apic_accept_pic_intr(CPUState *env); +void apic_deliver_pic_intr(CPUState *env, int level); int apic_get_interrupt(CPUState *env); IOAPICState *ioapic_init(void); void ioapic_set_irq(void *opaque, int vector, int level); @@ -59,7 +61,7 @@ int pit_get_out(PITState *pit, int channel, int64_t current_time); /* vmport.c */ -void vmport_init(CPUState *env); +void vmport_init(void); void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque); /* vmmouse.c */ @@ -88,7 +90,8 @@ /* acpi.c */ extern int acpi_enabled; -i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base); +i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, + qemu_irq sci_irq); void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr); void acpi_bios_init(void); @@ -102,9 +105,16 @@ int piix3_init(PCIBus *bus, int devfn); void i440fx_init_memory_mappings(PCIDevice *d); +extern PCIDevice *piix4_dev; int piix4_init(PCIBus *bus, int devfn); /* vga.c */ +enum vga_retrace_method { + VGA_RETRACE_DUMB, + VGA_RETRACE_PRECISE +}; + +extern enum vga_retrace_method vga_retrace_method; #ifndef TARGET_SPARC #define VGA_RAM_SIZE (8192 * 1024) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pci.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pci.c --- qemu-0.9.1/hw/pci.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pci.c 2008-10-02 19:33:50.000000000 +0100 @@ -515,7 +515,7 @@ const char *desc; } pci_class_desc; -static pci_class_desc pci_class_descriptions[] = +static const pci_class_desc pci_class_descriptions[] = { { 0x0100, "SCSI controller"}, { 0x0101, "IDE controller"}, @@ -559,7 +559,7 @@ { int i, class; PCIIORegion *r; - pci_class_desc *desc; + const pci_class_desc *desc; term_printf(" Bus %2d, device %3d, function %d:\n", d->bus->bus_num, d->devfn >> 3, d->devfn & 7); @@ -636,11 +636,13 @@ pci_i82559er_init(bus, nd, devfn); } else if (strcmp(nd->model, "rtl8139") == 0) { pci_rtl8139_init(bus, nd, devfn); + } else if (strcmp(nd->model, "e1000") == 0) { + pci_e1000_init(bus, nd, devfn); } else if (strcmp(nd->model, "pcnet") == 0) { pci_pcnet_init(bus, nd, devfn); } else if (strcmp(nd->model, "?") == 0) { fprintf(stderr, "qemu: Supported PCI NICs: i82551 i82557b i82559er" - " ne2k_pci pcnet rtl8139\n"); + " ne2k_pci pcnet rtl8139 e1000\n"); exit (1); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pci.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pci.h --- qemu-0.9.1/hw/pci.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pci.h 2008-02-03 02:20:18.000000000 +0000 @@ -126,6 +126,9 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn); +/* e1000.c */ +void pci_e1000_init(PCIBus *bus, NICInfo *nd, int devfn); + /* pcnet.c */ void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pckbd.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pckbd.c --- qemu-0.9.1/hw/pckbd.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pckbd.c 2008-10-26 13:43:07.000000000 +0000 @@ -30,9 +30,6 @@ /* debug PC keyboard */ //#define DEBUG_KBD -/* debug PC keyboard : only mouse */ -//#define DEBUG_MOUSE - /* Keyboard Controller Commands */ #define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ #define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ @@ -132,7 +129,7 @@ int it_shift; } KBDState; -KBDState kbd_state; +static KBDState kbd_state; /* update irq and KBD_STAT_[MOUSE_]OBF */ /* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be @@ -211,7 +208,7 @@ #endif switch(val) { case KBD_CCMD_READ_MODE: - kbd_queue(s, s->mode, 1); + kbd_queue(s, s->mode, 0); break; case KBD_CCMD_WRITE_MODE: case KBD_CCMD_WRITE_OBUF: @@ -283,11 +280,17 @@ static uint32_t kbd_read_data(void *opaque, uint32_t addr) { KBDState *s = opaque; + uint32_t val; if (s->pending == KBD_PENDING_AUX) - return ps2_read_data(s->mouse); + val = ps2_read_data(s->mouse); + else + val = ps2_read_data(s->kbd); - return ps2_read_data(s->kbd); +#if defined(DEBUG_KBD) + printf("kbd: read data=0x%02x\n", val); +#endif + return val; } static void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) @@ -439,7 +442,7 @@ kbd_reset(s); register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s); s_io_memory = cpu_register_io_memory(0, kbd_mm_read, kbd_mm_write, s); - cpu_register_physical_memory(base, 8 << it_shift, s_io_memory); + cpu_register_physical_memory(base, 2 << it_shift, s_io_memory); s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s); s->mouse = ps2_mouse_init(kbd_update_aux_irq, s); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pcnet.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pcnet.c --- qemu-0.9.1/hw/pcnet.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pcnet.c 2008-10-02 20:14:17.000000000 +0100 @@ -39,6 +39,7 @@ #include "pci.h" #include "net.h" #include "qemu-timer.h" +#include "qemu_socket.h" //#define PCNET_DEBUG //#define PCNET_DEBUG_IO @@ -52,6 +53,9 @@ #define PCNET_IOPORT_SIZE 0x20 #define PCNET_PNPMMIO_SIZE 0x20 +#define PCNET_LOOPTEST_CRC 1 +#define PCNET_LOOPTEST_NOCRC 2 + typedef struct PCNetState_st PCNetState; @@ -76,6 +80,7 @@ void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap); void *dma_opaque; + int looptest; }; struct qemu_ether_header { @@ -120,6 +125,7 @@ #define CSR_DRX(S) !!(((S)->csr[15])&0x0001) #define CSR_DTX(S) !!(((S)->csr[15])&0x0002) #define CSR_LOOP(S) !!(((S)->csr[15])&0x0004) +#define CSR_DXMTFCS(S) !!(((S)->csr[15])&0x0008) #define CSR_DRCVPA(S) !!(((S)->csr[15])&0x2000) #define CSR_DRCVBC(S) !!(((S)->csr[15])&0x4000) #define CSR_PROM(S) !!(((S)->csr[15])&0x8000) @@ -202,6 +208,8 @@ #define TMDS_LTINT_SH 12 #define TMDS_NOFCS_MASK 0x2000 #define TMDS_NOFCS_SH 13 +#define TMDS_ADDFCS_MASK TMDS_NOFCS_MASK +#define TMDS_ADDFCS_SH TMDS_NOFCS_SH #define TMDS_ERR_MASK 0x4000 #define TMDS_ERR_SH 14 #define TMDS_OWN_MASK 0x8000 @@ -971,11 +979,12 @@ s->csr[37] = nnrd >> 16; #ifdef PCNET_DEBUG if (bad) { - printf("pcnet: BAD RMD RECORDS AFTER 0x%08x\n", + printf("pcnet: BAD RMD RECORDS AFTER 0x" TARGET_FMT_plx "\n", PHYSADDR(s,crda)); } } else { - printf("pcnet: BAD RMD RDA=0x%08x\n", PHYSADDR(s,crda)); + printf("pcnet: BAD RMD RDA=0x" TARGET_FMT_plx "\n", + PHYSADDR(s,crda)); #endif } } @@ -1063,6 +1072,8 @@ PCNetState *s = opaque; int is_padr = 0, is_bcast = 0, is_ladr = 0; uint8_t buf1[60]; + int remaining; + int crc_err = 0; if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size) return; @@ -1116,37 +1127,36 @@ s->csr[0] |= 0x1000; /* Set MISS flag */ CSR_MISSC(s)++; } else { - uint8_t *src = &s->buffer[8]; + uint8_t *src = s->buffer; target_phys_addr_t crda = CSR_CRDA(s); struct pcnet_RMD rmd; int pktcount = 0; - memcpy(src, buf, size); - -#if 1 - /* no need to compute the CRC */ - src[size] = 0; - src[size + 1] = 0; - src[size + 2] = 0; - src[size + 3] = 0; - size += 4; -#else - /* XXX: avoid CRC generation */ - if (!CSR_ASTRP_RCV(s)) { + if (!s->looptest) { + memcpy(src, buf, size); + /* no need to compute the CRC */ + src[size] = 0; + src[size + 1] = 0; + src[size + 2] = 0; + src[size + 3] = 0; + size += 4; + } else if (s->looptest == PCNET_LOOPTEST_CRC || + !CSR_DXMTFCS(s) || size < MIN_BUF_SIZE+4) { uint32_t fcs = ~0; uint8_t *p = src; - while (size < 46) { - src[size++] = 0; - } + while (p != &src[size]) + CRC(fcs, *p++); + *(uint32_t *)p = htonl(fcs); + size += 4; + } else { + uint32_t fcs = ~0; + uint8_t *p = src; - while (p != &src[size]) { + while (p != &src[size-4]) CRC(fcs, *p++); - } - ((uint32_t *)&src[size])[0] = htonl(fcs); - size += 4; /* FCS at end of packet */ - } else size += 4; -#endif + crc_err = (*(uint32_t *)p != htonl(fcs)); + } #ifdef PCNET_DEBUG_MATCH PRINT_PKTHDR(buf); @@ -1157,24 +1167,30 @@ SET_FIELD(&rmd.status, RMDS, STP, 1); #define PCNET_RECV_STORE() do { \ - int count = MIN(4096 - GET_FIELD(rmd.buf_length, RMDL, BCNT),size); \ + int count = MIN(4096 - GET_FIELD(rmd.buf_length, RMDL, BCNT),remaining); \ target_phys_addr_t rbadr = PHYSADDR(s, rmd.rbadr); \ s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \ - src += count; size -= count; \ - SET_FIELD(&rmd.msg_length, RMDM, MCNT, count); \ + src += count; remaining -= count; \ SET_FIELD(&rmd.status, RMDS, OWN, 0); \ RMDSTORE(&rmd, PHYSADDR(s,crda)); \ pktcount++; \ } while (0) + remaining = size; PCNET_RECV_STORE(); - if ((size > 0) && CSR_NRDA(s)) { + if ((remaining > 0) && CSR_NRDA(s)) { target_phys_addr_t nrda = CSR_NRDA(s); +#ifdef PCNET_DEBUG_RMD + PRINT_RMD(&rmd); +#endif RMDLOAD(&rmd, PHYSADDR(s,nrda)); if (GET_FIELD(rmd.status, RMDS, OWN)) { crda = nrda; PCNET_RECV_STORE(); - if ((size > 0) && (nrda=CSR_NNRD(s))) { +#ifdef PCNET_DEBUG_RMD + PRINT_RMD(&rmd); +#endif + if ((remaining > 0) && (nrda=CSR_NNRD(s))) { RMDLOAD(&rmd, PHYSADDR(s,nrda)); if (GET_FIELD(rmd.status, RMDS, OWN)) { crda = nrda; @@ -1187,11 +1203,16 @@ #undef PCNET_RECV_STORE RMDLOAD(&rmd, PHYSADDR(s,crda)); - if (size == 0) { + if (remaining == 0) { + SET_FIELD(&rmd.msg_length, RMDM, MCNT, size); SET_FIELD(&rmd.status, RMDS, ENP, 1); SET_FIELD(&rmd.status, RMDS, PAM, !CSR_PROM(s) && is_padr); SET_FIELD(&rmd.status, RMDS, LFAM, !CSR_PROM(s) && is_ladr); SET_FIELD(&rmd.status, RMDS, BAM, !CSR_PROM(s) && is_bcast); + if (crc_err) { + SET_FIELD(&rmd.status, RMDS, CRC, 1); + SET_FIELD(&rmd.status, RMDS, ERR, 1); + } } else { SET_FIELD(&rmd.status, RMDS, OFLO, 1); SET_FIELD(&rmd.status, RMDS, BUFF, 1); @@ -1228,6 +1249,8 @@ { target_phys_addr_t xmit_cxda = 0; int count = CSR_XMTRL(s)-1; + int add_crc = 0; + s->xmit_pos = -1; if (!CSR_TXON(s)) { @@ -1249,15 +1272,16 @@ #endif if (GET_FIELD(tmd.status, TMDS, STP)) { s->xmit_pos = 0; - if (!GET_FIELD(tmd.status, TMDS, ENP)) { - int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT); - s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr), - s->buffer, bcnt, CSR_BSWP(s)); - s->xmit_pos += bcnt; - } xmit_cxda = PHYSADDR(s,CSR_CXDA(s)); + if (BCR_SWSTYLE(s) != 1) + add_crc = GET_FIELD(tmd.status, TMDS, ADDFCS); } - if (GET_FIELD(tmd.status, TMDS, ENP) && (s->xmit_pos >= 0)) { + if (!GET_FIELD(tmd.status, TMDS, ENP)) { + int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT); + s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr), + s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s)); + s->xmit_pos += bcnt; + } else if (s->xmit_pos >= 0) { int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT); s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr), s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s)); @@ -1265,9 +1289,13 @@ #ifdef PCNET_DEBUG printf("pcnet_transmit size=%d\n", s->xmit_pos); #endif - if (CSR_LOOP(s)) + if (CSR_LOOP(s)) { + if (BCR_SWSTYLE(s) == 1) + add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS); + s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC; pcnet_receive(s, s->buffer, s->xmit_pos); - else + s->looptest = 0; + } else if (s->vc) qemu_send_packet(s->vc, s->buffer, s->xmit_pos); @@ -1744,7 +1772,8 @@ { PCNetState *d = opaque; #ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_writeb addr=0x%08x val=0x%02x\n", addr, val); + printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr, + val); #endif if (!(addr & 0x10)) pcnet_aprom_writeb(d, addr & 0x0f, val); @@ -1757,7 +1786,8 @@ if (!(addr & 0x10)) val = pcnet_aprom_readb(d, addr & 0x0f); #ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_readb addr=0x%08x val=0x%02x\n", addr, val & 0xff); + printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr, + val & 0xff); #endif return val; } @@ -1766,7 +1796,8 @@ { PCNetState *d = opaque; #ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_writew addr=0x%08x val=0x%04x\n", addr, val); + printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr, + val); #endif if (addr & 0x10) pcnet_ioport_writew(d, addr & 0x0f, val); @@ -1790,7 +1821,8 @@ val |= pcnet_aprom_readb(d, addr); } #ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_readw addr=0x%08x val = 0x%04x\n", addr, val & 0xffff); + printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr, + val & 0xffff); #endif return val; } @@ -1799,7 +1831,8 @@ { PCNetState *d = opaque; #ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_writel addr=0x%08x val=0x%08x\n", addr, val); + printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr, + val); #endif if (addr & 0x10) pcnet_ioport_writel(d, addr & 0x0f, val); @@ -1829,7 +1862,8 @@ val |= pcnet_aprom_readb(d, addr); } #ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_readl addr=0x%08x val=0x%08x\n", addr, val); + printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, + val); #endif return val; } @@ -1843,9 +1877,9 @@ if (s->pci_dev) pci_device_save(s->pci_dev, f); - qemu_put_be32(f, s->rap); - qemu_put_be32(f, s->isr); - qemu_put_be32(f, s->lnkst); + qemu_put_sbe32(f, s->rap); + qemu_put_sbe32(f, s->isr); + qemu_put_sbe32(f, s->lnkst); qemu_put_be32s(f, &s->rdra); qemu_put_be32s(f, &s->tdra); qemu_put_buffer(f, s->prom, 16); @@ -1854,10 +1888,10 @@ for (i = 0; i < 32; i++) qemu_put_be16s(f, &s->bcr[i]); qemu_put_be64s(f, &s->timer); - qemu_put_be32(f, s->xmit_pos); - qemu_put_be32(f, s->recv_pos); + qemu_put_sbe32(f, s->xmit_pos); + qemu_put_sbe32(f, s->recv_pos); qemu_put_buffer(f, s->buffer, 4096); - qemu_put_be32(f, s->tx_busy); + qemu_put_sbe32(f, s->tx_busy); qemu_put_timer(f, s->poll_timer); } @@ -1875,9 +1909,9 @@ return ret; } - qemu_get_be32s(f, (uint32_t*)&s->rap); - qemu_get_be32s(f, (uint32_t*)&s->isr); - qemu_get_be32s(f, (uint32_t*)&s->lnkst); + qemu_get_sbe32s(f, &s->rap); + qemu_get_sbe32s(f, &s->isr); + qemu_get_sbe32s(f, &s->lnkst); qemu_get_be32s(f, &s->rdra); qemu_get_be32s(f, &s->tdra); qemu_get_buffer(f, s->prom, 16); @@ -1886,10 +1920,10 @@ for (i = 0; i < 32; i++) qemu_get_be16s(f, &s->bcr[i]); qemu_get_be64s(f, &s->timer); - qemu_get_be32s(f, (uint32_t*)&s->xmit_pos); - qemu_get_be32s(f, (uint32_t*)&s->recv_pos); + qemu_get_sbe32s(f, &s->xmit_pos); + qemu_get_sbe32s(f, &s->recv_pos); qemu_get_buffer(f, s->buffer, 4096); - qemu_get_be32s(f, (uint32_t*)&s->tx_busy); + qemu_get_sbe32s(f, &s->tx_busy); qemu_get_timer(f, s->poll_timer); return 0; @@ -1917,7 +1951,7 @@ d->vc = NULL; } pcnet_h_reset(d); - register_savevm("pcnet", 0, 2, pcnet_save, pcnet_load, d); + register_savevm("pcnet", -1, 2, pcnet_save, pcnet_load, d); } /* PCI interface */ @@ -1940,7 +1974,7 @@ PCNetState *d = (PCNetState *)pci_dev; #ifdef PCNET_DEBUG_IO - printf("pcnet_ioport_map addr=0x%08x 0x%08x\n", addr, size); + printf("pcnet_mmio_map addr=0x%08x 0x%08x\n", addr, size); #endif cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_index); @@ -2035,7 +2069,7 @@ val = pcnet_ioport_readw(opaque, addr & 7); #ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_readw addr=" TARGET_FMT_plx " val = 0x%04x\n", addr, + printf("lance_mem_readw addr=" TARGET_FMT_plx " val = 0x%04x\n", addr, val & 0xffff); #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pflash_cfi01.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pflash_cfi01.c --- qemu-0.9.1/hw/pflash_cfi01.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pflash_cfi01.c 2008-10-11 10:19:57.000000000 +0100 @@ -111,8 +111,8 @@ else if (pfl->width == 4) boff = boff >> 2; - DPRINTF("%s: reading offset " TARGET_FMT_lx " under cmd %02x\n", - __func__, boff, pfl->cmd); + DPRINTF("%s: reading offset " TARGET_FMT_lx " under cmd %02x width %d\n", + __func__, offset, pfl->cmd, width); switch (pfl->cmd) { case 0x00: @@ -202,16 +202,10 @@ uint8_t *p; uint8_t cmd; - /* WARNING: when the memory area is in ROMD mode, the offset is a - ram offset, not a physical address */ cmd = value; + offset -= pfl->base; - if (pfl->wcycle == 0) - offset -= (target_ulong)(long)pfl->storage; - else - offset -= pfl->base; - - DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d wcycle 0x%x\n", + DPRINTF("%s: writing offset " TARGET_FMT_lx " value %08x width %d wcycle 0x%x\n", __func__, offset, value, width, pfl->wcycle); /* Set the device in I/O access mode */ @@ -273,17 +267,17 @@ case 0x20: /* Block erase */ case 0x28: if (cmd == 0xd0) { /* confirm */ - pfl->wcycle = 1; + pfl->wcycle = 0; pfl->status |= 0x80; - } if (cmd == 0xff) { /* read array mode */ + } else if (cmd == 0xff) { /* read array mode */ goto reset_flash; } else goto error_flash; break; case 0xe8: - DPRINTF("%s: block write of %x bytes\n", __func__, cmd); - pfl->counter = cmd; + DPRINTF("%s: block write of %x bytes\n", __func__, value); + pfl->counter = value; pfl->wcycle++; break; case 0x60: @@ -387,7 +381,7 @@ error_flash: printf("%s: Unimplemented flash cmd sequence " - "(offset " TARGET_FMT_lx ", wcycle 0x%x cmd 0x%x value 0x%x\n", + "(offset " TARGET_FMT_lx ", wcycle 0x%x cmd 0x%x value 0x%x)\n", __func__, offset, pfl->wcycle, pfl->cmd, value); reset_flash: @@ -589,7 +583,7 @@ pfl->cfi_table[0x28] = 0x02; pfl->cfi_table[0x29] = 0x00; /* Max number of bytes in multi-bytes write */ - pfl->cfi_table[0x2A] = 0x04; + pfl->cfi_table[0x2A] = 0x0B; pfl->cfi_table[0x2B] = 0x00; /* Number of erase block regions (uniform) */ pfl->cfi_table[0x2C] = 0x01; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pflash_cfi02.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pflash_cfi02.c --- qemu-0.9.1/hw/pflash_cfi02.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pflash_cfi02.c 2008-06-09 01:20:13.000000000 +0100 @@ -55,7 +55,8 @@ BlockDriverState *bs; target_phys_addr_t base; uint32_t sector_len; - uint32_t total_len; + uint32_t chip_len; + int mappings; int width; int wcycle; /* if 0, the flash is read normally */ int bypass; @@ -63,14 +64,30 @@ uint8_t cmd; uint8_t status; uint16_t ident[4]; + uint16_t unlock_addr[2]; uint8_t cfi_len; uint8_t cfi_table[0x52]; QEMUTimer *timer; ram_addr_t off; int fl_mem; + int rom_mode; void *storage; }; +static void pflash_register_memory(pflash_t *pfl, int rom_mode) +{ + unsigned long phys_offset = pfl->fl_mem; + int i; + + if (rom_mode) + phys_offset |= pfl->off | IO_MEM_ROMD; + pfl->rom_mode = rom_mode; + + for (i = 0; i < pfl->mappings; i++) + cpu_register_physical_memory(pfl->base + i * pfl->chip_len, + pfl->chip_len, phys_offset); +} + static void pflash_timer (void *opaque) { pflash_t *pfl = opaque; @@ -81,8 +98,7 @@ if (pfl->bypass) { pfl->wcycle = 2; } else { - cpu_register_physical_memory(pfl->base, pfl->total_len, - pfl->off | IO_MEM_ROMD | pfl->fl_mem); + pflash_register_memory(pfl, 1); pfl->wcycle = 0; } pfl->cmd = 0; @@ -97,6 +113,12 @@ DPRINTF("%s: offset " TARGET_FMT_lx "\n", __func__, offset); ret = -1; offset -= pfl->base; + if (pfl->rom_mode) { + /* Lazy reset of to ROMD mode */ + if (pfl->wcycle == 0) + pflash_register_memory(pfl, 1); + } + offset &= pfl->chip_len - 1; boff = offset & 0xFF; if (pfl->width == 2) boff = boff >> 1; @@ -209,8 +231,6 @@ uint8_t *p; uint8_t cmd; - /* WARNING: when the memory area is in ROMD mode, the offset is a - ram offset, not a physical address */ cmd = value; if (pfl->cmd != 0xA0 && cmd == 0xF0) { #if 0 @@ -221,15 +241,11 @@ } DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d %d\n", __func__, offset, value, width, pfl->wcycle); - if (pfl->wcycle == 0) - offset -= (uint32_t)(long)pfl->storage; - else - offset -= pfl->base; + offset -= pfl->base; + offset &= pfl->chip_len - 1; DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d\n", __func__, offset, value, width); - /* Set the device in I/O access mode */ - cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem); boff = offset & (pfl->sector_len - 1); if (pfl->width == 2) boff = boff >> 1; @@ -237,6 +253,9 @@ boff = boff >> 2; switch (pfl->wcycle) { case 0: + /* Set the device in I/O access mode if required */ + if (pfl->rom_mode) + pflash_register_memory(pfl, 0); /* We're in read mode */ check_unlock0: if (boff == 0x55 && cmd == 0x98) { @@ -246,9 +265,9 @@ pfl->cmd = 0x98; return; } - if (boff != 0x555 || cmd != 0xAA) { + if (boff != pfl->unlock_addr[0] || cmd != 0xAA) { DPRINTF("%s: unlock0 failed " TARGET_FMT_lx " %02x %04x\n", - __func__, boff, cmd, 0x555); + __func__, boff, cmd, pfl->unlock_addr[0]); goto reset_flash; } DPRINTF("%s: unlock sequence started\n", __func__); @@ -256,7 +275,7 @@ case 1: /* We started an unlock sequence */ check_unlock1: - if (boff != 0x2AA || cmd != 0x55) { + if (boff != pfl->unlock_addr[1] || cmd != 0x55) { DPRINTF("%s: unlock1 failed " TARGET_FMT_lx " %02x\n", __func__, boff, cmd); goto reset_flash; @@ -265,7 +284,7 @@ break; case 2: /* We finished an unlock sequence */ - if (!pfl->bypass && boff != 0x555) { + if (!pfl->bypass && boff != pfl->unlock_addr[0]) { DPRINTF("%s: command failed " TARGET_FMT_lx " %02x\n", __func__, boff, cmd); goto reset_flash; @@ -361,16 +380,16 @@ case 5: switch (cmd) { case 0x10: - if (boff != 0x555) { + if (boff != pfl->unlock_addr[0]) { DPRINTF("%s: chip erase: invalid address " TARGET_FMT_lx "\n", __func__, offset); goto reset_flash; } /* Chip erase */ DPRINTF("%s: start chip erase\n", __func__); - memset(pfl->storage, 0xFF, pfl->total_len); + memset(pfl->storage, 0xFF, pfl->chip_len); pfl->status = 0x00; - pflash_update(pfl, 0, pfl->total_len); + pflash_update(pfl, 0, pfl->chip_len); /* Let's wait 5 seconds before chip erase is done */ qemu_mod_timer(pfl->timer, qemu_get_clock(vm_clock) + (ticks_per_sec * 5)); @@ -423,8 +442,6 @@ /* Reset flash */ reset_flash: - cpu_register_physical_memory(pfl->base, pfl->total_len, - pfl->off | IO_MEM_ROMD | pfl->fl_mem); pfl->bypass = 0; pfl->wcycle = 0; pfl->cmd = 0; @@ -526,14 +543,15 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off, BlockDriverState *bs, uint32_t sector_len, - int nb_blocs, int width, + int nb_blocs, int nb_mappings, int width, uint16_t id0, uint16_t id1, - uint16_t id2, uint16_t id3) + uint16_t id2, uint16_t id3, + uint16_t unlock_addr0, uint16_t unlock_addr1) { pflash_t *pfl; - int32_t total_len; + int32_t chip_len; - total_len = sector_len * nb_blocs; + chip_len = sector_len * nb_blocs; /* XXX: to be fixed */ #if 0 if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) && @@ -547,12 +565,14 @@ pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops, pfl); pfl->off = off; - cpu_register_physical_memory(base, total_len, - off | pfl->fl_mem | IO_MEM_ROMD); + pfl->base = base; + pfl->chip_len = chip_len; + pfl->mappings = nb_mappings; + pflash_register_memory(pfl, 1); pfl->bs = bs; if (pfl->bs) { /* read the initial flash content */ - bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9); + bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9); } #if 0 /* XXX: there should be a bit to set up read-only, * the same way the hardware does (with WP pin). @@ -562,9 +582,7 @@ pfl->ro = 0; #endif pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl); - pfl->base = base; pfl->sector_len = sector_len; - pfl->total_len = total_len; pfl->width = width; pfl->wcycle = 0; pfl->cmd = 0; @@ -573,6 +591,8 @@ pfl->ident[1] = id1; pfl->ident[2] = id2; pfl->ident[3] = id3; + pfl->unlock_addr[0] = unlock_addr0; + pfl->unlock_addr[1] = unlock_addr1; /* Hardcoded CFI table (mostly from SG29 Spansion flash) */ pfl->cfi_len = 0x52; /* Standard "QRY" string */ @@ -582,8 +602,8 @@ /* Command set (AMD/Fujitsu) */ pfl->cfi_table[0x13] = 0x02; pfl->cfi_table[0x14] = 0x00; - /* Primary extended table address (none) */ - pfl->cfi_table[0x15] = 0x00; + /* Primary extended table address */ + pfl->cfi_table[0x15] = 0x31; pfl->cfi_table[0x16] = 0x00; /* Alternate command set (none) */ pfl->cfi_table[0x17] = 0x00; @@ -601,22 +621,22 @@ pfl->cfi_table[0x1E] = 0x00; /* Reserved */ pfl->cfi_table[0x1F] = 0x07; - /* Timeout for min size buffer write (16 µs) */ - pfl->cfi_table[0x20] = 0x04; + /* Timeout for min size buffer write (NA) */ + pfl->cfi_table[0x20] = 0x00; /* Typical timeout for block erase (512 ms) */ pfl->cfi_table[0x21] = 0x09; /* Typical timeout for full chip erase (4096 ms) */ pfl->cfi_table[0x22] = 0x0C; /* Reserved */ pfl->cfi_table[0x23] = 0x01; - /* Max timeout for buffer write */ - pfl->cfi_table[0x24] = 0x04; + /* Max timeout for buffer write (NA) */ + pfl->cfi_table[0x24] = 0x00; /* Max timeout for block erase */ pfl->cfi_table[0x25] = 0x0A; /* Max timeout for chip erase */ pfl->cfi_table[0x26] = 0x0D; /* Device size */ - pfl->cfi_table[0x27] = ctz32(total_len) + 1; + pfl->cfi_table[0x27] = ctz32(chip_len); /* Flash device interface (8 & 16 bits) */ pfl->cfi_table[0x28] = 0x02; pfl->cfi_table[0x29] = 0x00; @@ -633,5 +653,23 @@ pfl->cfi_table[0x2F] = sector_len >> 8; pfl->cfi_table[0x30] = sector_len >> 16; + /* Extended */ + pfl->cfi_table[0x31] = 'P'; + pfl->cfi_table[0x32] = 'R'; + pfl->cfi_table[0x33] = 'I'; + + pfl->cfi_table[0x34] = '1'; + pfl->cfi_table[0x35] = '0'; + + pfl->cfi_table[0x36] = 0x00; + pfl->cfi_table[0x37] = 0x00; + pfl->cfi_table[0x38] = 0x00; + pfl->cfi_table[0x39] = 0x00; + + pfl->cfi_table[0x3a] = 0x00; + + pfl->cfi_table[0x3b] = 0x00; + pfl->cfi_table[0x3c] = 0x00; + return pfl; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/piix_pci.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/piix_pci.c --- qemu-0.9.1/hw/piix_pci.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/piix_pci.c 2008-10-26 13:43:07.000000000 +0000 @@ -55,7 +55,7 @@ return (irq_num + slot_addend) & 3; } -static uint32_t isa_page_descs[384 / 4]; +static target_phys_addr_t isa_page_descs[384 / 4]; static uint8_t smm_enabled; static int pci_irq_levels[4]; @@ -210,7 +210,7 @@ /* PIIX3 PCI to ISA bridge */ -PCIDevice *piix3_dev; +static PCIDevice *piix3_dev; PCIDevice *piix4_dev; /* just used for simpler irq handling. */ @@ -220,7 +220,6 @@ { int i, pic_irq, pic_level; - piix3_dev->config[0x60 + irq_num] &= ~0x80; // enable bit pci_irq_levels[irq_num] = level; /* now we change the pic irq level according to the piix irq mappings */ @@ -250,6 +249,9 @@ pci_conf[0x4e] = 0x03; pci_conf[0x4f] = 0x00; pci_conf[0x60] = 0x80; + pci_conf[0x61] = 0x80; + pci_conf[0x62] = 0x80; + pci_conf[0x63] = 0x80; pci_conf[0x69] = 0x02; pci_conf[0x70] = 0x80; pci_conf[0x76] = 0x0c; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pl011.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pl011.c --- qemu-0.9.1/hw/pl011.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pl011.c 2008-07-02 17:48:32.000000000 +0100 @@ -195,7 +195,7 @@ return s->read_count < 1; } -static void pl011_receive(void *opaque, const uint8_t *buf, int size) +static void pl011_put_fifo(void *opaque, uint32_t value) { pl011_state *s = (pl011_state *)opaque; int slot; @@ -203,7 +203,7 @@ slot = s->read_pos + s->read_count; if (slot >= 16) slot -= 16; - s->read_fifo[slot] = *buf; + s->read_fifo[slot] = value; s->read_count++; s->flags &= ~PL011_FLAG_RXFE; if (s->cr & 0x10 || s->read_count == 16) { @@ -215,9 +215,15 @@ } } +static void pl011_receive(void *opaque, const uint8_t *buf, int size) +{ + pl011_put_fifo(opaque, *buf); +} + static void pl011_event(void *opaque, int event) { - /* ??? Should probably implement break. */ + if (event == CHR_EVENT_BREAK) + pl011_put_fifo(opaque, 0x400); } static CPUReadMemoryFunc *pl011_readfn[] = { @@ -232,6 +238,57 @@ pl011_write }; +static void pl011_save(QEMUFile *f, void *opaque) +{ + pl011_state *s = (pl011_state *)opaque; + int i; + + qemu_put_be32(f, s->readbuff); + qemu_put_be32(f, s->flags); + qemu_put_be32(f, s->lcr); + qemu_put_be32(f, s->cr); + qemu_put_be32(f, s->dmacr); + qemu_put_be32(f, s->int_enabled); + qemu_put_be32(f, s->int_level); + for (i = 0; i < 16; i++) + qemu_put_be32(f, s->read_fifo[i]); + qemu_put_be32(f, s->ilpr); + qemu_put_be32(f, s->ibrd); + qemu_put_be32(f, s->fbrd); + qemu_put_be32(f, s->ifl); + qemu_put_be32(f, s->read_pos); + qemu_put_be32(f, s->read_count); + qemu_put_be32(f, s->read_trigger); +} + +static int pl011_load(QEMUFile *f, void *opaque, int version_id) +{ + pl011_state *s = (pl011_state *)opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + s->readbuff = qemu_get_be32(f); + s->flags = qemu_get_be32(f); + s->lcr = qemu_get_be32(f); + s->cr = qemu_get_be32(f); + s->dmacr = qemu_get_be32(f); + s->int_enabled = qemu_get_be32(f); + s->int_level = qemu_get_be32(f); + for (i = 0; i < 16; i++) + s->read_fifo[i] = qemu_get_be32(f); + s->ilpr = qemu_get_be32(f); + s->ibrd = qemu_get_be32(f); + s->fbrd = qemu_get_be32(f); + s->ifl = qemu_get_be32(f); + s->read_pos = qemu_get_be32(f); + s->read_count = qemu_get_be32(f); + s->read_trigger = qemu_get_be32(f); + + return 0; +} + void pl011_init(uint32_t base, qemu_irq irq, CharDriverState *chr, enum pl011_type type) { @@ -254,6 +311,6 @@ qemu_chr_add_handlers(chr, pl011_can_receive, pl011_receive, pl011_event, s); } - /* ??? Save/restore. */ + register_savevm("pl011_uart", -1, 1, pl011_save, pl011_load, s); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pl022.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pl022.c --- qemu-0.9.1/hw/pl022.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pl022.c 2008-07-02 17:48:32.000000000 +0100 @@ -244,6 +244,55 @@ pl022_write }; +static void pl022_save(QEMUFile *f, void *opaque) +{ + pl022_state *s = (pl022_state *)opaque; + int i; + + qemu_put_be32(f, s->cr0); + qemu_put_be32(f, s->cr1); + qemu_put_be32(f, s->bitmask); + qemu_put_be32(f, s->sr); + qemu_put_be32(f, s->cpsr); + qemu_put_be32(f, s->is); + qemu_put_be32(f, s->im); + qemu_put_be32(f, s->tx_fifo_head); + qemu_put_be32(f, s->rx_fifo_head); + qemu_put_be32(f, s->tx_fifo_len); + qemu_put_be32(f, s->rx_fifo_len); + for (i = 0; i < 8; i++) { + qemu_put_be16(f, s->tx_fifo[i]); + qemu_put_be16(f, s->rx_fifo[i]); + } +} + +static int pl022_load(QEMUFile *f, void *opaque, int version_id) +{ + pl022_state *s = (pl022_state *)opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + s->cr0 = qemu_get_be32(f); + s->cr1 = qemu_get_be32(f); + s->bitmask = qemu_get_be32(f); + s->sr = qemu_get_be32(f); + s->cpsr = qemu_get_be32(f); + s->is = qemu_get_be32(f); + s->im = qemu_get_be32(f); + s->tx_fifo_head = qemu_get_be32(f); + s->rx_fifo_head = qemu_get_be32(f); + s->tx_fifo_len = qemu_get_be32(f); + s->rx_fifo_len = qemu_get_be32(f); + for (i = 0; i < 8; i++) { + s->tx_fifo[i] = qemu_get_be16(f); + s->rx_fifo[i] = qemu_get_be16(f); + } + + return 0; +} + void pl022_init(uint32_t base, qemu_irq irq, int (*xfer_cb)(void *, int), void * opaque) { @@ -259,7 +308,7 @@ s->xfer_cb = xfer_cb; s->opaque = opaque; pl022_reset(s); - /* ??? Save/restore. */ + register_savevm("pl022_ssp", -1, 1, pl022_save, pl022_load, s); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pl031.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pl031.c --- qemu-0.9.1/hw/pl031.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pl031.c 2008-02-17 11:42:19.000000000 +0000 @@ -195,8 +195,7 @@ { int iomemtype; pl031_state *s; - time_t ti; - struct tm *tm; + struct tm tm; s = qemu_mallocz(sizeof(pl031_state)); if (!s) @@ -211,12 +210,8 @@ s->base = base; s->irq = irq; /* ??? We assume vm_clock is zero at this point. */ - time(&ti); - if (rtc_utc) - tm = gmtime(&ti); - else - tm = localtime(&ti); - s->tick_offset = mktime(tm); + qemu_get_timedate(&tm, 0); + s->tick_offset = mktime(&tm); s->timer = qemu_new_timer(vm_clock, pl031_interrupt, s); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pl061.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pl061.c --- qemu-0.9.1/hw/pl061.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pl061.c 2008-07-02 17:48:32.000000000 +0100 @@ -240,6 +240,62 @@ pl061_write }; +static void pl061_save(QEMUFile *f, void *opaque) +{ + pl061_state *s = (pl061_state *)opaque; + + qemu_put_be32(f, s->locked); + qemu_put_be32(f, s->data); + qemu_put_be32(f, s->old_data); + qemu_put_be32(f, s->dir); + qemu_put_be32(f, s->isense); + qemu_put_be32(f, s->ibe); + qemu_put_be32(f, s->iev); + qemu_put_be32(f, s->im); + qemu_put_be32(f, s->istate); + qemu_put_be32(f, s->afsel); + qemu_put_be32(f, s->dr2r); + qemu_put_be32(f, s->dr4r); + qemu_put_be32(f, s->dr8r); + qemu_put_be32(f, s->odr); + qemu_put_be32(f, s->pur); + qemu_put_be32(f, s->pdr); + qemu_put_be32(f, s->slr); + qemu_put_be32(f, s->den); + qemu_put_be32(f, s->cr); + qemu_put_be32(f, s->float_high); +} + +static int pl061_load(QEMUFile *f, void *opaque, int version_id) +{ + pl061_state *s = (pl061_state *)opaque; + if (version_id != 1) + return -EINVAL; + + s->locked = qemu_get_be32(f); + s->data = qemu_get_be32(f); + s->old_data = qemu_get_be32(f); + s->dir = qemu_get_be32(f); + s->isense = qemu_get_be32(f); + s->ibe = qemu_get_be32(f); + s->iev = qemu_get_be32(f); + s->im = qemu_get_be32(f); + s->istate = qemu_get_be32(f); + s->afsel = qemu_get_be32(f); + s->dr2r = qemu_get_be32(f); + s->dr4r = qemu_get_be32(f); + s->dr8r = qemu_get_be32(f); + s->odr = qemu_get_be32(f); + s->pur = qemu_get_be32(f); + s->pdr = qemu_get_be32(f); + s->slr = qemu_get_be32(f); + s->den = qemu_get_be32(f); + s->cr = qemu_get_be32(f); + s->float_high = qemu_get_be32(f); + + return 0; +} + /* Returns an array of inputs. */ qemu_irq *pl061_init(uint32_t base, qemu_irq irq, qemu_irq **out) { @@ -256,7 +312,7 @@ if (out) *out = s->out; - /* ??? Save/restore. */ + register_savevm("pl061_gpio", -1, 1, pl061_save, pl061_load, s); return qemu_allocate_irqs(pl061_set_irq, s, 8); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pl080.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pl080.c --- qemu-0.9.1/hw/pl080.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pl080.c 2008-09-20 09:07:15.000000000 +0100 @@ -80,7 +80,7 @@ int src_id; int dest_id; int size; - char buff[4]; + uint8_t buff[4]; uint32_t req; s->tc_mask = 0; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pl110.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pl110.c --- qemu-0.9.1/hw/pl110.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pl110.c 2008-07-01 17:24:38.000000000 +0100 @@ -30,6 +30,8 @@ typedef struct { uint32_t base; DisplayState *ds; + QEMUConsole *console; + /* The Versatile/PB uses a slightly modified PL110 controller. */ int versatile; uint32_t timing[4]; @@ -270,7 +272,7 @@ { if (width != s->cols || height != s->rows) { if (pl110_enabled(s)) { - dpy_resize(s->ds, width, height); + qemu_console_resize(s->console, width, height); } } s->cols = width; @@ -387,7 +389,7 @@ s->cr = val; s->bpp = (val >> 1) & 7; if (pl110_enabled(s)) { - dpy_resize(s->ds, s->cols, s->rows); + qemu_console_resize(s->console, s->cols, s->rows); } break; case 10: /* LCDICR */ @@ -425,8 +427,9 @@ s->ds = ds; s->versatile = versatile; s->irq = irq; - graphic_console_init(ds, pl110_update_display, pl110_invalidate_display, - NULL, s); + s->console = graphic_console_init(ds, pl110_update_display, + pl110_invalidate_display, + NULL, NULL, s); /* ??? Save/restore. */ return s; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pl190.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pl190.c --- qemu-0.9.1/hw/pl190.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pl190.c 2008-05-25 11:10:12.000000000 +0100 @@ -19,7 +19,6 @@ typedef struct { uint32_t base; - DisplayState *ds; uint32_t level; uint32_t soft_level; uint32_t irq_enable; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ppc405_boards.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ppc405_boards.c --- qemu-0.9.1/hw/ppc405_boards.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/ppc405_boards.c 2008-10-28 10:59:59.000000000 +0000 @@ -29,9 +29,7 @@ #include "sysemu.h" #include "block.h" #include "boards.h" - -extern int loglevel; -extern FILE *logfile; +#include "qemu-log.h" #define BIOS_FILENAME "ppc405_rom.bin" #undef BIOS_SIZE @@ -177,7 +175,7 @@ } } -static void ref405ep_init (int ram_size, int vga_ram_size, +static void ref405ep_init (ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, @@ -235,8 +233,8 @@ bdrv_get_device_name(drives_table[index].bdrv), fl_sectors); #endif pflash_cfi02_register((uint32_t)(-bios_size), bios_offset, - drives_table[index].bdrv, 65536, fl_sectors, 2, - 0x0001, 0x22DA, 0x0000, 0x0000); + drives_table[index].bdrv, 65536, fl_sectors, 1, + 2, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA); fl_idx++; } else #endif @@ -357,9 +355,10 @@ } QEMUMachine ref405ep_machine = { - "ref405ep", - "ref405ep", - ref405ep_init, + .name = "ref405ep", + .desc = "ref405ep", + .init = ref405ep_init, + .ram_require = (128 * 1024 * 1024 + 4096 + 512 * 1024 + BIOS_SIZE) | RAMSIZE_FIXED, }; /*****************************************************************************/ @@ -504,7 +503,7 @@ } } -static void taihu_405ep_init(int ram_size, int vga_ram_size, +static void taihu_405ep_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, @@ -552,8 +551,8 @@ bdrv_get_device_name(drives_table[index].bdrv), fl_sectors); #endif pflash_cfi02_register((uint32_t)(-bios_size), bios_offset, - drives_table[index].bdrv, 65536, fl_sectors, 4, - 0x0001, 0x22DA, 0x0000, 0x0000); + drives_table[index].bdrv, 65536, fl_sectors, 1, + 4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA); fl_idx++; } else #endif @@ -588,8 +587,8 @@ bdrv_get_device_name(drives_table[index].bdrv)); #endif pflash_cfi02_register(0xfc000000, bios_offset, - drives_table[index].bdrv, 65536, fl_sectors, 4, - 0x0001, 0x22DA, 0x0000, 0x0000); + drives_table[index].bdrv, 65536, fl_sectors, 1, + 4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA); fl_idx++; } /* Register CLPD & LCD display */ @@ -642,4 +641,5 @@ "taihu", "taihu", taihu_405ep_init, + (128 * 1024 * 1024 + 4096 + BIOS_SIZE + 32 * 1024 * 1024) | RAMSIZE_FIXED, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ppc405_uc.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ppc405_uc.c --- qemu-0.9.1/hw/ppc405_uc.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/ppc405_uc.c 2008-10-04 08:20:07.000000000 +0100 @@ -27,9 +27,7 @@ #include "pc.h" #include "qemu-timer.h" #include "sysemu.h" - -extern int loglevel; -extern FILE *logfile; +#include "qemu-log.h" #define DEBUG_OPBA #define DEBUG_SDRAM @@ -1223,7 +1221,7 @@ #ifdef DEBUG_SERIAL printf("%s: offset " PADDRX "\n", __func__, offset); #endif - serial = serial_mm_init(offset, 0, irq, chr, 0); + serial = serial_mm_init(offset, 0, irq, 399193, chr, 0); ppc4xx_mmio_register(env, mmio, offset, 0x008, serial_mm_read, serial_mm_write, serial); } @@ -2587,13 +2585,13 @@ ppc405_dma_init(env, dma_irqs); /* Serial ports */ if (serial_hds[0] != NULL) { - ppc405_serial_init(env, mmio, 0x300, pic[31], serial_hds[0]); + ppc405_serial_init(env, mmio, 0x300, pic[0], serial_hds[0]); } if (serial_hds[1] != NULL) { - ppc405_serial_init(env, mmio, 0x400, pic[30], serial_hds[1]); + ppc405_serial_init(env, mmio, 0x400, pic[1], serial_hds[1]); } /* IIC controller */ - ppc405_i2c_init(env, mmio, 0x500, pic[29]); + ppc405_i2c_init(env, mmio, 0x500, pic[2]); /* GPIO */ ppc405_gpio_init(env, mmio, 0x700); /* CPU control */ @@ -2930,49 +2928,50 @@ pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); *picp = pic; /* SDRAM controller */ - ppc405_sdram_init(env, pic[14], 2, ram_bases, ram_sizes, do_init); + /* XXX 405EP has no ECC interrupt */ + ppc405_sdram_init(env, pic[17], 2, ram_bases, ram_sizes, do_init); offset = 0; for (i = 0; i < 2; i++) offset += ram_sizes[i]; /* External bus controller */ ppc405_ebc_init(env); /* DMA controller */ - dma_irqs[0] = pic[26]; - dma_irqs[1] = pic[25]; - dma_irqs[2] = pic[24]; - dma_irqs[3] = pic[23]; + dma_irqs[0] = pic[5]; + dma_irqs[1] = pic[6]; + dma_irqs[2] = pic[7]; + dma_irqs[3] = pic[8]; ppc405_dma_init(env, dma_irqs); /* IIC controller */ - ppc405_i2c_init(env, mmio, 0x500, pic[29]); + ppc405_i2c_init(env, mmio, 0x500, pic[2]); /* GPIO */ ppc405_gpio_init(env, mmio, 0x700); /* Serial ports */ if (serial_hds[0] != NULL) { - ppc405_serial_init(env, mmio, 0x300, pic[31], serial_hds[0]); + ppc405_serial_init(env, mmio, 0x300, pic[0], serial_hds[0]); } if (serial_hds[1] != NULL) { - ppc405_serial_init(env, mmio, 0x400, pic[30], serial_hds[1]); + ppc405_serial_init(env, mmio, 0x400, pic[1], serial_hds[1]); } /* OCM */ ppc405_ocm_init(env, ram_sizes[0] + ram_sizes[1]); offset += 4096; /* GPT */ - gpt_irqs[0] = pic[12]; - gpt_irqs[1] = pic[11]; - gpt_irqs[2] = pic[10]; - gpt_irqs[3] = pic[9]; - gpt_irqs[4] = pic[8]; + gpt_irqs[0] = pic[19]; + gpt_irqs[1] = pic[20]; + gpt_irqs[2] = pic[21]; + gpt_irqs[3] = pic[22]; + gpt_irqs[4] = pic[23]; ppc4xx_gpt_init(env, mmio, 0x000, gpt_irqs); /* PCI */ - /* Uses pic[28], pic[15], pic[13] */ + /* Uses pic[3], pic[16], pic[18] */ /* MAL */ - mal_irqs[0] = pic[20]; - mal_irqs[1] = pic[19]; - mal_irqs[2] = pic[18]; - mal_irqs[3] = pic[17]; + mal_irqs[0] = pic[11]; + mal_irqs[1] = pic[12]; + mal_irqs[2] = pic[13]; + mal_irqs[3] = pic[14]; ppc405_mal_init(env, mal_irqs); /* Ethernet */ - /* Uses pic[22], pic[16], pic[14] */ + /* Uses pic[9], pic[15], pic[17] */ /* CPU control */ ppc405ep_cpc_init(env, clk_setup, sysclk); *offsetp = offset; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ppc4xx_devs.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ppc4xx_devs.c --- qemu-0.9.1/hw/ppc4xx_devs.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/ppc4xx_devs.c 2008-10-04 08:20:07.000000000 +0100 @@ -25,9 +25,7 @@ #include "ppc.h" #include "ppc4xx.h" #include "sysemu.h" - -extern int loglevel; -extern FILE *logfile; +#include "qemu-log.h" //#define DEBUG_MMIO //#define DEBUG_UNASSIGNED @@ -35,7 +33,7 @@ /*****************************************************************************/ /* Generic PowerPC 4xx processor instanciation */ -CPUState *ppc4xx_init (const unsigned char *cpu_model, +CPUState *ppc4xx_init (const char *cpu_model, clk_setup_t *cpu_clk, clk_setup_t *tb_clk, uint32_t sysclk) { @@ -56,7 +54,6 @@ ppc_dcr_init(env, NULL, NULL); /* Register qemu callbacks */ qemu_register_reset(&cpu_ppc_reset, env); - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); return env; } @@ -278,6 +275,7 @@ struct ppcuic_t { uint32_t dcr_base; int use_vectors; + uint32_t level; /* Remembers the state of level-triggered interrupts. */ uint32_t uicsr; /* Status register */ uint32_t uicer; /* Enable register */ uint32_t uiccr; /* Critical register */ @@ -365,7 +363,7 @@ uint32_t mask, sr; uic = opaque; - mask = 1 << irq_num; + mask = 1 << (31-irq_num); #ifdef DEBUG_UIC if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: irq %d level %d uicsr %08" PRIx32 @@ -377,10 +375,7 @@ if (irq_num < 0 || irq_num > 31) return; sr = uic->uicsr; - if (!(uic->uicpr & mask)) { - /* Negatively asserted IRQ */ - level = level == 0 ? 1 : 0; - } + /* Update status register */ if (uic->uictr & mask) { /* Edge sensitive interrupt */ @@ -388,10 +383,13 @@ uic->uicsr |= mask; } else { /* Level sensitive interrupt */ - if (level == 1) + if (level == 1) { uic->uicsr |= mask; - else + uic->level |= mask; + } else { uic->uicsr &= ~mask; + uic->level &= ~mask; + } } #ifdef DEBUG_UIC if (loglevel & CPU_LOG_INT) { @@ -463,6 +461,7 @@ switch (dcrn) { case DCR_UICSR: uic->uicsr &= ~val; + uic->uicsr |= uic->level; ppcuic_trigger_irq(uic); break; case DCR_UICSRS: @@ -479,7 +478,6 @@ break; case DCR_UICPR: uic->uicpr = val; - ppcuic_trigger_irq(uic); break; case DCR_UICTR: uic->uictr = val; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ppc4xx.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ppc4xx.h --- qemu-0.9.1/hw/ppc4xx.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/ppc4xx.h 2008-09-20 09:07:15.000000000 +0100 @@ -26,7 +26,7 @@ #define PPC_4XX_H /* PowerPC 4xx core initialization */ -CPUState *ppc4xx_init (const unsigned char *cpu_model, +CPUState *ppc4xx_init (const char *cpu_model, clk_setup_t *cpu_clk, clk_setup_t *tb_clk, uint32_t sysclk); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ppc.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ppc.c --- qemu-0.9.1/hw/ppc.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/ppc.c 2008-10-26 13:43:07.000000000 +0000 @@ -26,13 +26,11 @@ #include "qemu-timer.h" #include "sysemu.h" #include "nvram.h" +#include "qemu-log.h" //#define PPC_DEBUG_IRQ //#define PPC_DEBUG_TB -extern FILE *logfile; -extern int loglevel; - static void cpu_ppc_tb_stop (CPUState *env); static void cpu_ppc_tb_start (CPUState *env); @@ -808,10 +806,12 @@ } /* Specific helpers for POWER & PowerPC 601 RTC */ -clk_setup_cb cpu_ppc601_rtc_init (CPUState *env) +#if 0 +static clk_setup_cb cpu_ppc601_rtc_init (CPUState *env) { return cpu_ppc_tb_init(env, 7812500); } +#endif void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value) { @@ -1305,7 +1305,7 @@ } void NVRAM_set_string (nvram_t *nvram, uint32_t addr, - const unsigned char *str, uint32_t max) + const char *str, uint32_t max) { int i; @@ -1345,7 +1345,7 @@ return tmp; } -uint16_t NVRAM_compute_crc (nvram_t *nvram, uint32_t start, uint32_t count) +static uint16_t NVRAM_compute_crc (nvram_t *nvram, uint32_t start, uint32_t count) { uint32_t i; uint16_t crc = 0xFFFF; @@ -1366,7 +1366,7 @@ #define CMDLINE_ADDR 0x017ff000 int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size, - const unsigned char *arch, + const char *arch, uint32_t RAM_size, int boot_device, uint32_t kernel_image, uint32_t kernel_size, const char *cmdline, @@ -1387,7 +1387,7 @@ NVRAM_set_lword(nvram, 0x3C, kernel_size); if (cmdline) { /* XXX: put the cmdline in NVRAM too ? */ - strcpy(phys_ram_base + CMDLINE_ADDR, cmdline); + strcpy((char *)(phys_ram_base + CMDLINE_ADDR), cmdline); NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR); NVRAM_set_lword(nvram, 0x44, strlen(cmdline)); } else { diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ppc_chrp.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ppc_chrp.c --- qemu-0.9.1/hw/ppc_chrp.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/ppc_chrp.c 2008-10-28 10:59:59.000000000 +0000 @@ -57,7 +57,7 @@ }; /* PowerPC Mac99 hardware initialisation */ -static void ppc_core99_init (int ram_size, int vga_ram_size, +static void ppc_core99_init (ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, @@ -103,7 +103,6 @@ env->osi_call = vga_osi_call; #endif qemu_register_reset(&cpu_ppc_reset, env); - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); envs[i] = env; } if (env->nip < 0xFFF80000) { @@ -264,7 +263,7 @@ dummy_irq = i8259_init(NULL); /* XXX: use Mac Serial port */ - serial_init(0x3f8, dummy_irq[4], serial_hds[0]); + serial_init(0x3f8, dummy_irq[4], 115200, serial_hds[0]); for(i = 0; i < nb_nics; i++) { if (!nd_table[i].model) nd_table[i].model = "ne2k_pci"; @@ -332,7 +331,9 @@ } QEMUMachine core99_machine = { - "mac99", - "Mac99 based PowerMAC", - ppc_core99_init, + .name = "mac99", + .desc = "Mac99 based PowerMAC", + .init = ppc_core99_init, + .ram_require = BIOS_SIZE + VGA_RAM_SIZE, + .max_cpus = MAX_CPUS, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ppc.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ppc.h --- qemu-0.9.1/hw/ppc.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/ppc.h 2008-10-26 13:43:07.000000000 +0000 @@ -29,3 +29,7 @@ extern CPUWriteMemoryFunc *PPC_io_write[]; extern CPUReadMemoryFunc *PPC_io_read[]; void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); + +void ppc40x_irq_init (CPUState *env); +void ppc6xx_irq_init (CPUState *env); +void ppc970_irq_init (CPUState *env); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ppc_oldworld.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ppc_oldworld.c --- qemu-0.9.1/hw/ppc_oldworld.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/ppc_oldworld.c 2008-10-28 10:59:59.000000000 +0000 @@ -103,7 +103,7 @@ return 1; /* osi_call handled */ } -static void ppc_heathrow_init (int ram_size, int vga_ram_size, +static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, @@ -143,7 +143,6 @@ cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); env->osi_call = vga_osi_call; qemu_register_reset(&cpu_ppc_reset, env); - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); envs[i] = env; } if (env->nip < 0xFFF80000) { @@ -287,7 +286,7 @@ dummy_irq = i8259_init(NULL); /* XXX: use Mac Serial port */ - serial_init(0x3f8, dummy_irq[4], serial_hds[0]); + serial_init(0x3f8, dummy_irq[4], 115200, serial_hds[0]); for(i = 0; i < nb_nics; i++) { if (!nd_table[i].model) @@ -367,7 +366,9 @@ } QEMUMachine heathrow_machine = { - "g3bw", - "Heathrow based PowerMAC", - ppc_heathrow_init, + .name = "g3bw", + .desc = "Heathrow based PowerMAC", + .init = ppc_heathrow_init, + .ram_require = BIOS_SIZE + VGA_RAM_SIZE, + .max_cpus = MAX_CPUS, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ppc_prep.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ppc_prep.c --- qemu-0.9.1/hw/ppc_prep.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/ppc_prep.c 2008-10-28 10:59:59.000000000 +0000 @@ -31,6 +31,7 @@ #include "pci.h" #include "ppc.h" #include "boards.h" +#include "qemu-log.h" //#define HARD_DEBUG_PPC_IO //#define DEBUG_PPC_IO @@ -44,9 +45,6 @@ #define KERNEL_LOAD_ADDR 0x01000000 #define INITRD_LOAD_ADDR 0x01800000 -extern int loglevel; -extern FILE *logfile; - #if defined (HARD_DEBUG_PPC_IO) && !defined (DEBUG_PPC_IO) #define DEBUG_PPC_IO #endif @@ -86,9 +84,11 @@ /* ISA IO ports bridge */ #define PPC_IO_BASE 0x80000000 +#if 0 /* Speaker port 0x61 */ -int speaker_data_on; -int dummy_refresh_clock; +static int speaker_data_on; +static int dummy_refresh_clock; +#endif static void speaker_ioport_write (void *opaque, uint32_t addr, uint32_t val) { @@ -520,13 +520,13 @@ return ret; } -CPUWriteMemoryFunc *PPC_prep_io_write[] = { +static CPUWriteMemoryFunc *PPC_prep_io_write[] = { &PPC_prep_io_writeb, &PPC_prep_io_writew, &PPC_prep_io_writel, }; -CPUReadMemoryFunc *PPC_prep_io_read[] = { +static CPUReadMemoryFunc *PPC_prep_io_read[] = { &PPC_prep_io_readb, &PPC_prep_io_readw, &PPC_prep_io_readl, @@ -535,7 +535,7 @@ #define NVRAM_SIZE 0x2000 /* PowerPC PREP hardware initialisation */ -static void ppc_prep_init (int ram_size, int vga_ram_size, +static void ppc_prep_init (ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, @@ -580,7 +580,6 @@ cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); } qemu_register_reset(&cpu_ppc_reset, env); - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); envs[i] = env; } @@ -667,7 +666,7 @@ // pit = pit_init(0x40, i8259[0]); rtc_init(0x70, i8259[8]); - serial_init(0x3f8, i8259[4], serial_hds[0]); + serial_init(0x3f8, i8259[4], 115200, serial_hds[0]); nb_nics1 = nb_nics; if (nb_nics1 > NE2000_NB_MAX) nb_nics1 = NE2000_NB_MAX; @@ -761,7 +760,9 @@ } QEMUMachine prep_machine = { - "prep", - "PowerPC PREP platform", - ppc_prep_init, + .name = "prep", + .desc = "PowerPC PREP platform", + .init = ppc_prep_init, + .ram_require = BIOS_SIZE + VGA_RAM_SIZE, + .max_cpus = MAX_CPUS, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ps2.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ps2.c --- qemu-0.9.1/hw/ps2.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/ps2.c 2008-04-13 17:08:44.000000000 +0100 @@ -34,6 +34,7 @@ /* Keyboard Commands */ #define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ #define KBD_CMD_ECHO 0xEE +#define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */ #define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ #define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ #define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ @@ -43,6 +44,7 @@ /* Keyboard Replies */ #define KBD_REPLY_POR 0xAA /* Power on reset */ +#define KBD_REPLY_ID 0xAB /* Keyboard ID */ #define KBD_REPLY_ACK 0xFA /* Command ACK */ #define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ @@ -89,6 +91,7 @@ conversions we do the translation (if any) in the PS/2 emulation not the keyboard controller. */ int translate; + int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */ } PS2KbdState; typedef struct { @@ -131,10 +134,17 @@ s->update_irq(s->update_arg, 1); } +/* + keycode is expressed as follow: + bit 7 - 0 key pressed, 1 = key released + bits 6-0 - translated scancode set 2 + */ static void ps2_put_keycode(void *opaque, int keycode) { PS2KbdState *s = opaque; - if (!s->translate && keycode < 0xe0) + + /* XXX: add support for scancode sets 1 and 3 */ + if (!s->translate && keycode < 0xe0 && s->scancode_set == 2) { if (keycode & 0x80) ps2_queue(&s->common, 0xf0); @@ -174,6 +184,7 @@ static void ps2_reset_keyboard(PS2KbdState *s) { s->scan_enabled = 1; + s->scancode_set = 2; } void ps2_write_keyboard(void *opaque, int val) @@ -192,8 +203,12 @@ break; case KBD_CMD_GET_ID: ps2_queue(&s->common, KBD_REPLY_ACK); - ps2_queue(&s->common, 0xab); - ps2_queue(&s->common, 0x83); + /* We emulate a MF2 AT keyboard here */ + ps2_queue(&s->common, KBD_REPLY_ID); + if (s->translate) + ps2_queue(&s->common, 0x41); + else + ps2_queue(&s->common, 0x83); break; case KBD_CMD_ECHO: ps2_queue(&s->common, KBD_CMD_ECHO); @@ -202,6 +217,7 @@ s->scan_enabled = 1; ps2_queue(&s->common, KBD_REPLY_ACK); break; + case KBD_CMD_SCANCODE: case KBD_CMD_SET_LEDS: case KBD_CMD_SET_RATE: s->common.write_cmd = val; @@ -227,6 +243,21 @@ break; } break; + case KBD_CMD_SCANCODE: + if (val == 0) { + if (s->scancode_set == 1) + ps2_put_keycode(s, 0x43); + else if (s->scancode_set == 2) + ps2_put_keycode(s, 0x41); + else if (s->scancode_set == 3) + ps2_put_keycode(s, 0x3f); + } else { + if (val >= 1 && val <= 3) + s->scancode_set = val; + ps2_queue(&s->common, KBD_REPLY_ACK); + } + s->common.write_cmd = -1; + break; case KBD_CMD_SET_LEDS: ps2_queue(&s->common, KBD_REPLY_ACK); s->common.write_cmd = -1; @@ -493,6 +524,7 @@ ps2_common_save (f, &s->common); qemu_put_be32(f, s->scan_enabled); qemu_put_be32(f, s->translate); + qemu_put_be32(f, s->scancode_set); } static void ps2_mouse_save(QEMUFile* f, void* opaque) @@ -516,12 +548,16 @@ { PS2KbdState *s = (PS2KbdState*)opaque; - if (version_id != 2) + if (version_id != 2 && version_id != 3) return -EINVAL; ps2_common_load (f, &s->common); s->scan_enabled=qemu_get_be32(f); s->translate=qemu_get_be32(f); + if (version_id == 3) + s->scancode_set=qemu_get_be32(f); + else + s->scancode_set=2; return 0; } @@ -552,8 +588,9 @@ s->common.update_irq = update_irq; s->common.update_arg = update_arg; + s->scancode_set = 2; ps2_reset(&s->common); - register_savevm("ps2kbd", 0, 2, ps2_kbd_save, ps2_kbd_load, s); + register_savevm("ps2kbd", 0, 3, ps2_kbd_save, ps2_kbd_load, s); qemu_add_kbd_event_handler(ps2_put_keycode, s); qemu_register_reset(ps2_reset, &s->common); return s; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ptimer.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ptimer.c --- qemu-0.9.1/hw/ptimer.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/ptimer.c 2008-10-02 20:14:17.000000000 +0100 @@ -100,6 +100,9 @@ void ptimer_run(ptimer_state *s, int oneshot) { + if (s->enabled) { + return; + } if (s->period == 0) { fprintf(stderr, "Timer with period zero, disabling\n"); return; @@ -162,9 +165,9 @@ qemu_put_be64s(f, &s->limit); qemu_put_be64s(f, &s->delta); qemu_put_be32s(f, &s->period_frac); - qemu_put_be64s(f, &s->period); - qemu_put_be64s(f, &s->last_event); - qemu_put_be64s(f, &s->next_event); + qemu_put_sbe64s(f, &s->period); + qemu_put_sbe64s(f, &s->last_event); + qemu_put_sbe64s(f, &s->next_event); qemu_put_timer(f, s->timer); } @@ -174,9 +177,9 @@ qemu_get_be64s(f, &s->limit); qemu_get_be64s(f, &s->delta); qemu_get_be32s(f, &s->period_frac); - qemu_get_be64s(f, &s->period); - qemu_get_be64s(f, &s->last_event); - qemu_get_be64s(f, &s->next_event); + qemu_get_sbe64s(f, &s->period); + qemu_get_sbe64s(f, &s->last_event); + qemu_get_sbe64s(f, &s->next_event); qemu_get_timer(f, s->timer); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pxa2xx.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pxa2xx.c --- qemu-0.9.1/hw/pxa2xx.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pxa2xx.c 2008-10-02 20:14:17.000000000 +0100 @@ -1183,27 +1183,22 @@ static void pxa2xx_rtc_init(struct pxa2xx_state_s *s) { - struct tm *tm; - time_t ti; + struct tm tm; int wom; s->rttr = 0x7fff; s->rtsr = 0; - time(&ti); - if (rtc_utc) - tm = gmtime(&ti); - else - tm = localtime(&ti); - wom = ((tm->tm_mday - 1) / 7) + 1; + qemu_get_timedate(&tm, 0); + wom = ((tm.tm_mday - 1) / 7) + 1; - s->last_rcnr = (uint32_t) ti; - s->last_rdcr = (wom << 20) | ((tm->tm_wday + 1) << 17) | - (tm->tm_hour << 12) | (tm->tm_min << 6) | tm->tm_sec; - s->last_rycr = ((tm->tm_year + 1900) << 9) | - ((tm->tm_mon + 1) << 5) | tm->tm_mday; - s->last_swcr = (tm->tm_hour << 19) | - (tm->tm_min << 13) | (tm->tm_sec << 7); + s->last_rcnr = (uint32_t) mktime(&tm); + s->last_rdcr = (wom << 20) | ((tm.tm_wday + 1) << 17) | + (tm.tm_hour << 12) | (tm.tm_min << 6) | tm.tm_sec; + s->last_rycr = ((tm.tm_year + 1900) << 9) | + ((tm.tm_mon + 1) << 5) | tm.tm_mday; + s->last_swcr = (tm.tm_hour << 19) | + (tm.tm_min << 13) | (tm.tm_sec << 7); s->last_rtcpicr = 0; s->last_hz = s->last_sw = s->last_pi = qemu_get_clock(rt_clock); @@ -1238,9 +1233,9 @@ qemu_put_be32s(f, &s->last_rycr); qemu_put_be32s(f, &s->last_swcr); qemu_put_be32s(f, &s->last_rtcpicr); - qemu_put_be64s(f, &s->last_hz); - qemu_put_be64s(f, &s->last_sw); - qemu_put_be64s(f, &s->last_pi); + qemu_put_sbe64s(f, &s->last_hz); + qemu_put_sbe64s(f, &s->last_sw); + qemu_put_sbe64s(f, &s->last_pi); } static int pxa2xx_rtc_load(QEMUFile *f, void *opaque, int version_id) @@ -1262,9 +1257,9 @@ qemu_get_be32s(f, &s->last_rycr); qemu_get_be32s(f, &s->last_swcr); qemu_get_be32s(f, &s->last_rtcpicr); - qemu_get_be64s(f, &s->last_hz); - qemu_get_be64s(f, &s->last_sw); - qemu_get_be64s(f, &s->last_pi); + qemu_get_sbe64s(f, &s->last_hz); + qemu_get_sbe64s(f, &s->last_sw); + qemu_get_sbe64s(f, &s->last_pi); pxa2xx_rtc_alarm_update(s, s->rtsr); @@ -1471,7 +1466,6 @@ qemu_put_8s(f, &s->ibmr); qemu_put_8s(f, &s->data); - i2c_bus_save(f, s->bus); i2c_slave_save(f, &s->slave); } @@ -1479,12 +1473,14 @@ { struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) opaque; + if (version_id != 1) + return -EINVAL; + qemu_get_be16s(f, &s->control); qemu_get_be16s(f, &s->status); qemu_get_8s(f, &s->ibmr); qemu_get_8s(f, &s->data); - i2c_bus_load(f, s->bus); i2c_slave_load(f, &s->slave); return 0; } @@ -1493,6 +1489,7 @@ qemu_irq irq, uint32_t page_size) { int iomemtype; + /* FIXME: Should the slave device really be on a separate bus? */ struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) i2c_slave_init(i2c_init_bus(), 0, sizeof(struct pxa2xx_i2c_s)); @@ -1507,7 +1504,7 @@ pxa2xx_i2c_writefn, s); cpu_register_physical_memory(s->base & ~page_size, page_size, iomemtype); - register_savevm("pxa2xx_i2c", base, 0, + register_savevm("pxa2xx_i2c", base, 1, pxa2xx_i2c_save, pxa2xx_i2c_load, s); return s; @@ -2051,9 +2048,6 @@ fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - register_savevm("cpu", 0, ARM_CPU_SAVE_VERSION, cpu_save, cpu_load, - s->env); - s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0]; /* SDRAM & Internal Memory Storage */ @@ -2082,7 +2076,8 @@ for (i = 0; pxa270_serial[i].io_base; i ++) if (serial_hds[i]) serial_mm_init(pxa270_serial[i].io_base, 2, - s->pic[pxa270_serial[i].irqn], serial_hds[i], 1); + s->pic[pxa270_serial[i].irqn], 14857000/16, + serial_hds[i], 1); else break; if (serial_hds[i]) @@ -2177,9 +2172,6 @@ fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - register_savevm("cpu", 0, ARM_CPU_SAVE_VERSION, cpu_save, cpu_load, - s->env); - s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0]; /* SDRAM & Internal Memory Storage */ @@ -2207,7 +2199,8 @@ for (i = 0; pxa255_serial[i].io_base; i ++) if (serial_hds[i]) serial_mm_init(pxa255_serial[i].io_base, 2, - s->pic[pxa255_serial[i].irqn], serial_hds[i], 1); + s->pic[pxa255_serial[i].irqn], 14745600/16, + serial_hds[i], 1); else break; if (serial_hds[i]) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pxa2xx_dma.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pxa2xx_dma.c --- qemu-0.9.1/hw/pxa2xx_dma.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pxa2xx_dma.c 2008-09-20 09:07:15.000000000 +0100 @@ -177,7 +177,7 @@ uint32_t n, size; uint32_t width; uint32_t length; - char buffer[32]; + uint8_t buffer[32]; struct pxa2xx_dma_channel_s *ch; if (s->running ++) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pxa2xx_lcd.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pxa2xx_lcd.c --- qemu-0.9.1/hw/pxa2xx_lcd.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pxa2xx_lcd.c 2008-07-01 17:24:38.000000000 +0100 @@ -23,6 +23,7 @@ int invalidated; DisplayState *ds; + QEMUConsole *console; drawfn *line_fn[2]; int dest_width; int xres, yres; @@ -794,9 +795,9 @@ if (width != s->xres || height != s->yres) { if (s->orientation) - dpy_resize(s->ds, height, width); + qemu_console_resize(s->console, height, width); else - dpy_resize(s->ds, width, height); + qemu_console_resize(s->console, width, height); s->invalidated = 1; s->xres = width; s->yres = height; @@ -1001,8 +1002,9 @@ pxa2xx_lcdc_writefn, s); cpu_register_physical_memory(base, 0x00100000, iomemtype); - graphic_console_init(ds, pxa2xx_update_display, - pxa2xx_invalidate_display, pxa2xx_screen_dump, s); + s->console = graphic_console_init(ds, pxa2xx_update_display, + pxa2xx_invalidate_display, + pxa2xx_screen_dump, NULL, s); switch (s->ds->depth) { case 0: diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pxa2xx_template.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pxa2xx_template.h --- qemu-0.9.1/hw/pxa2xx_template.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pxa2xx_template.h 2008-11-03 01:08:14.000000000 +0000 @@ -156,6 +156,7 @@ g = (data & 0x1f) << 3; data >>= 5; r = (data & 0x1f) << 3; + data >>= 5; if (data & 1) SKIP_PIXEL(dest); else diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/pxa2xx_timer.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/pxa2xx_timer.c --- qemu-0.9.1/hw/pxa2xx_timer.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/pxa2xx_timer.c 2008-10-02 20:14:17.000000000 +0100 @@ -372,8 +372,8 @@ pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque; int i; - qemu_put_be32s(f, &s->clock); - qemu_put_be32s(f, &s->oldclock); + qemu_put_be32s(f, (uint32_t *) &s->clock); + qemu_put_be32s(f, (uint32_t *) &s->oldclock); qemu_put_be64s(f, &s->lastload); for (i = 0; i < 4; i ++) { @@ -384,8 +384,8 @@ for (i = 0; i < 8; i ++) { qemu_put_be32s(f, &s->tm4[i].tm.value); qemu_put_be32(f, s->tm4[i].tm.level); - qemu_put_be32s(f, &s->tm4[i].oldclock); - qemu_put_be32s(f, &s->tm4[i].clock); + qemu_put_sbe32s(f, &s->tm4[i].oldclock); + qemu_put_sbe32s(f, &s->tm4[i].clock); qemu_put_be64s(f, &s->tm4[i].lastload); qemu_put_be32s(f, &s->tm4[i].freq); qemu_put_be32s(f, &s->tm4[i].control); @@ -403,8 +403,8 @@ int64_t now; int i; - qemu_get_be32s(f, &s->clock); - qemu_get_be32s(f, &s->oldclock); + qemu_get_be32s(f, (uint32_t *) &s->clock); + qemu_get_be32s(f, (uint32_t *) &s->oldclock); qemu_get_be64s(f, &s->lastload); now = qemu_get_clock(vm_clock); @@ -418,8 +418,8 @@ for (i = 0; i < 8; i ++) { qemu_get_be32s(f, &s->tm4[i].tm.value); s->tm4[i].tm.level = qemu_get_be32(f); - qemu_get_be32s(f, &s->tm4[i].oldclock); - qemu_get_be32s(f, &s->tm4[i].clock); + qemu_get_sbe32s(f, &s->tm4[i].oldclock); + qemu_get_sbe32s(f, &s->tm4[i].clock); qemu_get_be64s(f, &s->tm4[i].lastload); qemu_get_be32s(f, &s->tm4[i].freq); qemu_get_be32s(f, &s->tm4[i].control); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/r2d.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/r2d.c --- qemu-0.9.1/hw/r2d.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/r2d.c 2008-11-05 20:24:35.000000000 +0000 @@ -2,6 +2,7 @@ * Renesas SH7751R R2D-PLUS emulation * * Copyright (c) 2007 Magnus Damm + * Copyright (c) 2008 Paul Mundt * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,22 +25,121 @@ #include "hw.h" #include "sh.h" +#include "devices.h" #include "sysemu.h" #include "boards.h" #define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */ #define SDRAM_SIZE 0x04000000 -static void r2d_init(int ram_size, int vga_ram_size, +#define SM501_VRAM_SIZE 0x800000 + +#define PA_POWOFF 0x30 +#define PA_VERREG 0x32 +#define PA_OUTPORT 0x36 + +typedef struct { + target_phys_addr_t base; + + uint16_t bcr; + uint16_t irlmon; + uint16_t cfctl; + uint16_t cfpow; + uint16_t dispctl; + uint16_t sdmpow; + uint16_t rtcce; + uint16_t pcicd; + uint16_t voyagerrts; + uint16_t cfrst; + uint16_t admrts; + uint16_t extrst; + uint16_t cfcdintclr; + uint16_t keyctlclr; + uint16_t pad0; + uint16_t pad1; + uint16_t powoff; + uint16_t verreg; + uint16_t inport; + uint16_t outport; + uint16_t bverreg; +} r2d_fpga_t; + +static uint32_t r2d_fpga_read(void *opaque, target_phys_addr_t addr) +{ + r2d_fpga_t *s = opaque; + + addr -= s->base; + + switch (addr) { + case PA_OUTPORT: + return s->outport; + case PA_POWOFF: + return s->powoff; + case PA_VERREG: + return 0x10; + } + + return 0; +} + +static void +r2d_fpga_write(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + r2d_fpga_t *s = opaque; + + addr -= s->base; + + switch (addr) { + case PA_OUTPORT: + s->outport = value; + break; + case PA_POWOFF: + s->powoff = value; + break; + case PA_VERREG: + /* Discard writes */ + break; + } +} + +static CPUReadMemoryFunc *r2d_fpga_readfn[] = { + r2d_fpga_read, + r2d_fpga_read, + NULL, +}; + +static CPUWriteMemoryFunc *r2d_fpga_writefn[] = { + r2d_fpga_write, + r2d_fpga_write, + NULL, +}; + +static void r2d_fpga_init(target_phys_addr_t base) +{ + int iomemtype; + r2d_fpga_t *s; + + s = qemu_mallocz(sizeof(r2d_fpga_t)); + if (!s) + return; + + s->base = base; + iomemtype = cpu_register_io_memory(0, r2d_fpga_readfn, + r2d_fpga_writefn, s); + cpu_register_physical_memory(base, 0x40, iomemtype); +} + +static void r2d_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState * ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { CPUState *env; struct SH7750State *s; + ram_addr_t sdram_addr, sm501_vga_ram_addr; if (!cpu_model) - cpu_model = "any"; + cpu_model = "SH7751R"; env = cpu_init(cpu_model); if (!env) { @@ -48,9 +148,14 @@ } /* Allocate memory space */ - cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, 0); + sdram_addr = qemu_ram_alloc(SDRAM_SIZE); + cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, sdram_addr); /* Register peripherals */ + r2d_fpga_init(0x04000000); s = sh7750_init(env); + sm501_vga_ram_addr = qemu_ram_alloc(SM501_VRAM_SIZE); + sm501_init(ds, 0x10000000, sm501_vga_ram_addr, SM501_VRAM_SIZE, + serial_hds[2]); /* Todo: register on board registers */ { int kernel_size; @@ -67,7 +172,8 @@ } QEMUMachine r2d_machine = { - "r2d", - "r2d-plus board", - r2d_init + .name = "r2d", + .desc = "r2d-plus board", + .init = r2d_init, + .ram_require = (SDRAM_SIZE + SM501_VRAM_SIZE) | RAMSIZE_FIXED, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/rc4030.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/rc4030.c --- qemu-0.9.1/hw/rc4030.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/rc4030.c 2008-04-07 22:07:01.000000000 +0100 @@ -0,0 +1,608 @@ +/* + * QEMU JAZZ RC4030 chipset + * + * Copyright (c) 2007-2008 Hervé Poussineau + * + * 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 "hw.h" +#include "qemu-timer.h" + +//#define DEBUG_RC4030 + +#ifdef DEBUG_RC4030 +static const char* irq_names[] = { "parallel", "floppy", "sound", "video", + "network", "scsi", "keyboard", "mouse", "serial0", "serial1" }; +#endif + +typedef struct rc4030State +{ + uint32_t config; /* 0x0000: RC4030 config register */ + uint32_t invalid_address_register; /* 0x0010: Invalid Address register */ + + /* DMA */ + uint32_t dma_regs[8][4]; + uint32_t dma_tl_base; /* 0x0018: DMA transl. table base */ + uint32_t dma_tl_limit; /* 0x0020: DMA transl. table limit */ + + /* cache */ + uint32_t remote_failed_address; /* 0x0038: Remote Failed Address */ + uint32_t memory_failed_address; /* 0x0040: Memory Failed Address */ + uint32_t cache_ptag; /* 0x0048: I/O Cache Physical Tag */ + uint32_t cache_ltag; /* 0x0050: I/O Cache Logical Tag */ + uint32_t cache_bmask; /* 0x0058: I/O Cache Byte Mask */ + uint32_t cache_bwin; /* 0x0060: I/O Cache Buffer Window */ + + uint32_t offset208; + uint32_t offset210; + uint32_t nvram_protect; /* 0x0220: NV ram protect register */ + uint32_t offset238; + uint32_t rem_speed[15]; + uint32_t imr_jazz; /* Local bus int enable mask */ + uint32_t isr_jazz; /* Local bus int source */ + + /* timer */ + QEMUTimer *periodic_timer; + uint32_t itr; /* Interval timer reload */ + + uint32_t dummy32; + qemu_irq timer_irq; + qemu_irq jazz_bus_irq; +} rc4030State; + +static void set_next_tick(rc4030State *s) +{ + qemu_irq_lower(s->timer_irq); + uint32_t hz; + + hz = 1000 / (s->itr + 1); + + qemu_mod_timer(s->periodic_timer, qemu_get_clock(vm_clock) + ticks_per_sec / hz); +} + +/* called for accesses to rc4030 */ +static uint32_t rc4030_readl(void *opaque, target_phys_addr_t addr) +{ + rc4030State *s = opaque; + uint32_t val; + + addr &= 0x3fff; + switch (addr & ~0x3) { + /* Global config register */ + case 0x0000: + val = s->config; + break; + /* Invalid Address register */ + case 0x0010: + val = s->invalid_address_register; + break; + /* DMA transl. table base */ + case 0x0018: + val = s->dma_tl_base; + break; + /* DMA transl. table limit */ + case 0x0020: + val = s->dma_tl_limit; + break; + /* Remote Failed Address */ + case 0x0038: + val = s->remote_failed_address; + break; + /* Memory Failed Address */ + case 0x0040: + val = s->memory_failed_address; + break; + /* I/O Cache Byte Mask */ + case 0x0058: + val = s->cache_bmask; + /* HACK */ + if (s->cache_bmask == (uint32_t)-1) + s->cache_bmask = 0; + break; + /* Remote Speed Registers */ + case 0x0070: + case 0x0078: + case 0x0080: + case 0x0088: + case 0x0090: + case 0x0098: + case 0x00a0: + case 0x00a8: + case 0x00b0: + case 0x00b8: + case 0x00c0: + case 0x00c8: + case 0x00d0: + case 0x00d8: + case 0x00e0: + val = s->rem_speed[(addr - 0x0070) >> 3]; + break; + /* DMA channel base address */ + case 0x0100: + case 0x0108: + case 0x0110: + case 0x0118: + case 0x0120: + case 0x0128: + case 0x0130: + case 0x0138: + case 0x0140: + case 0x0148: + case 0x0150: + case 0x0158: + case 0x0160: + case 0x0168: + case 0x0170: + case 0x0178: + case 0x0180: + case 0x0188: + case 0x0190: + case 0x0198: + case 0x01a0: + case 0x01a8: + case 0x01b0: + case 0x01b8: + case 0x01c0: + case 0x01c8: + case 0x01d0: + case 0x01d8: + case 0x01e0: + case 0x1e8: + case 0x01f0: + case 0x01f8: + { + int entry = (addr - 0x0100) >> 5; + int idx = (addr & 0x1f) >> 3; + val = s->dma_regs[entry][idx]; + } + break; + /* Offset 0x0208 */ + case 0x0208: + val = s->offset208; + break; + /* Offset 0x0210 */ + case 0x0210: + val = s->offset210; + break; + /* NV ram protect register */ + case 0x0220: + val = s->nvram_protect; + break; + /* Interval timer count */ + case 0x0230: + val = s->dummy32; + qemu_irq_lower(s->timer_irq); + break; + /* Offset 0x0238 */ + case 0x0238: + val = s->offset238; + break; + default: +#ifdef DEBUG_RC4030 + printf("rc4030: invalid read [" TARGET_FMT_lx "]\n", addr); +#endif + val = 0; + break; + } + +#ifdef DEBUG_RC4030 + if ((addr & ~3) != 0x230) + printf("rc4030: read 0x%02x at " TARGET_FMT_lx "\n", val, addr); +#endif + + return val; +} + +static uint32_t rc4030_readw(void *opaque, target_phys_addr_t addr) +{ + uint32_t v = rc4030_readl(opaque, addr & ~0x3); + if (addr & 0x2) + return v >> 16; + else + return v & 0xffff; +} + +static uint32_t rc4030_readb(void *opaque, target_phys_addr_t addr) +{ + uint32_t v = rc4030_readl(opaque, addr & ~0x3); + return (v >> (8 * (addr & 0x3))) & 0xff; +} + +static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + rc4030State *s = opaque; + addr &= 0x3fff; + +#ifdef DEBUG_RC4030 + printf("rc4030: write 0x%02x at " TARGET_FMT_lx "\n", val, addr); +#endif + + switch (addr & ~0x3) { + /* Global config register */ + case 0x0000: + s->config = val; + break; + /* DMA transl. table base */ + case 0x0018: + s->dma_tl_base = val; + break; + /* DMA transl. table limit */ + case 0x0020: + s->dma_tl_limit = val; + break; + /* I/O Cache Physical Tag */ + case 0x0048: + s->cache_ptag = val; + break; + /* I/O Cache Logical Tag */ + case 0x0050: + s->cache_ltag = val; + break; + /* I/O Cache Byte Mask */ + case 0x0058: + s->cache_bmask |= val; /* HACK */ + break; + /* I/O Cache Buffer Window */ + case 0x0060: + s->cache_bwin = val; + /* HACK */ + if (s->cache_ltag == 0x80000001 && s->cache_bmask == 0xf0f0f0f) { + target_phys_addr_t dests[] = { 4, 0, 8, 0x10 }; + static int current = 0; + target_phys_addr_t dest = 0 + dests[current]; + uint8_t buf; + current = (current + 1) % (sizeof(dests)/sizeof(dests[0])); + buf = s->cache_bwin - 1; + cpu_physical_memory_rw(dest, &buf, 1, 1); + } + break; + /* Remote Speed Registers */ + case 0x0070: + case 0x0078: + case 0x0080: + case 0x0088: + case 0x0090: + case 0x0098: + case 0x00a0: + case 0x00a8: + case 0x00b0: + case 0x00b8: + case 0x00c0: + case 0x00c8: + case 0x00d0: + case 0x00d8: + case 0x00e0: + s->rem_speed[(addr - 0x0070) >> 3] = val; + break; + /* DMA channel base address */ + case 0x0100: + case 0x0108: + case 0x0110: + case 0x0118: + case 0x0120: + case 0x0128: + case 0x0130: + case 0x0138: + case 0x0140: + case 0x0148: + case 0x0150: + case 0x0158: + case 0x0160: + case 0x0168: + case 0x0170: + case 0x0178: + case 0x0180: + case 0x0188: + case 0x0190: + case 0x0198: + case 0x01a0: + case 0x01a8: + case 0x01b0: + case 0x01b8: + case 0x01c0: + case 0x01c8: + case 0x01d0: + case 0x01d8: + case 0x01e0: + case 0x1e8: + case 0x01f0: + case 0x01f8: + { + int entry = (addr - 0x0100) >> 5; + int idx = (addr & 0x1f) >> 3; + s->dma_regs[entry][idx] = val; + } + break; + /* Offset 0x0210 */ + case 0x0210: + s->offset210 = val; + break; + /* Interval timer reload */ + case 0x0228: + s->itr = val; + qemu_irq_lower(s->timer_irq); + set_next_tick(s); + break; + default: +#ifdef DEBUG_RC4030 + printf("rc4030: invalid write of 0x%02x at [" TARGET_FMT_lx "]\n", val, addr); +#endif + break; + } +} + +static void rc4030_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + uint32_t old_val = rc4030_readl(opaque, addr & ~0x3); + + if (addr & 0x2) + val = (val << 16) | (old_val & 0x0000ffff); + else + val = val | (old_val & 0xffff0000); + rc4030_writel(opaque, addr & ~0x3, val); +} + +static void rc4030_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + uint32_t old_val = rc4030_readl(opaque, addr & ~0x3); + + switch (addr & 3) { + case 0: + val = val | (old_val & 0xffffff00); + break; + case 1: + val = (val << 8) | (old_val & 0xffff00ff); + break; + case 2: + val = (val << 16) | (old_val & 0xff00ffff); + break; + case 3: + val = (val << 24) | (old_val & 0x00ffffff); + break; + } + rc4030_writel(opaque, addr & ~0x3, val); +} + +static CPUReadMemoryFunc *rc4030_read[3] = { + rc4030_readb, + rc4030_readw, + rc4030_readl, +}; + +static CPUWriteMemoryFunc *rc4030_write[3] = { + rc4030_writeb, + rc4030_writew, + rc4030_writel, +}; + +static void update_jazz_irq(rc4030State *s) +{ + uint16_t pending; + + pending = s->isr_jazz & s->imr_jazz; + +#ifdef DEBUG_RC4030 + if (s->isr_jazz != 0) { + uint32_t irq = 0; + printf("jazz pending:"); + for (irq = 0; irq < sizeof(irq_names)/sizeof(irq_names[0]); irq++) { + if (s->isr_jazz & (1 << irq)) { + printf(" %s", irq_names[irq]); + if (!(s->imr_jazz & (1 << irq))) { + printf("(ignored)"); + } + } + } + printf("\n"); + } +#endif + + if (pending != 0) + qemu_irq_raise(s->jazz_bus_irq); + else + qemu_irq_lower(s->jazz_bus_irq); +} + +static void rc4030_irq_jazz_request(void *opaque, int irq, int level) +{ + rc4030State *s = opaque; + + if (level) { + s->isr_jazz |= 1 << irq; + } else { + s->isr_jazz &= ~(1 << irq); + } + + update_jazz_irq(s); +} + +static void rc4030_periodic_timer(void *opaque) +{ + rc4030State *s = opaque; + + set_next_tick(s); + qemu_irq_raise(s->timer_irq); +} + +static uint32_t int_readb(void *opaque, target_phys_addr_t addr) +{ + rc4030State *s = opaque; + uint32_t val; + uint32_t irq; + addr &= 0xfff; + + switch (addr) { + case 0x00: { + /* Local bus int source */ + uint32_t pending = s->isr_jazz & s->imr_jazz; + val = 0; + irq = 0; + while (pending) { + if (pending & 1) { + //printf("returning irq %s\n", irq_names[irq]); + val = (irq + 1) << 2; + break; + } + irq++; + pending >>= 1; + } + break; + } + default: +#ifdef DEBUG_RC4030 + printf("rc4030: (interrupt controller) invalid read [" TARGET_FMT_lx "]\n", addr); +#endif + val = 0; + } + +#ifdef DEBUG_RC4030 + printf("rc4030: (interrupt controller) read 0x%02x at " TARGET_FMT_lx "\n", val, addr); +#endif + + return val; +} + +static uint32_t int_readw(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; + v = int_readb(opaque, addr); + v |= int_readb(opaque, addr + 1) << 8; + return v; +} + +static uint32_t int_readl(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; + v = int_readb(opaque, addr); + v |= int_readb(opaque, addr + 1) << 8; + v |= int_readb(opaque, addr + 2) << 16; + v |= int_readb(opaque, addr + 3) << 24; + return v; +} + +static void int_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + rc4030State *s = opaque; + addr &= 0xfff; + +#ifdef DEBUG_RC4030 + printf("rc4030: (interrupt controller) write 0x%02x at " TARGET_FMT_lx "\n", val, addr); +#endif + + switch (addr) { + /* Local bus int enable mask */ + case 0x02: + s->imr_jazz = (s->imr_jazz & 0xff00) | (val << 0); update_jazz_irq(s); + break; + case 0x03: + s->imr_jazz = (s->imr_jazz & 0x00ff) | (val << 8); update_jazz_irq(s); + break; + default: +#ifdef DEBUG_RC4030 + printf("rc4030: (interrupt controller) invalid write of 0x%02x at [" TARGET_FMT_lx "]\n", val, addr); +#endif + break; + } +} + +static void int_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + int_writeb(opaque, addr, val & 0xff); + int_writeb(opaque, addr + 1, (val >> 8) & 0xff); +} + +static void int_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + int_writeb(opaque, addr, val & 0xff); + int_writeb(opaque, addr + 1, (val >> 8) & 0xff); + int_writeb(opaque, addr + 2, (val >> 16) & 0xff); + int_writeb(opaque, addr + 3, (val >> 24) & 0xff); +} + +static CPUReadMemoryFunc *int_read[3] = { + int_readb, + int_readw, + int_readl, +}; + +static CPUWriteMemoryFunc *int_write[3] = { + int_writeb, + int_writew, + int_writel, +}; + +#define G364_512KB_RAM (0x0) +#define G364_2MB_RAM (0x1) +#define G364_8MB_RAM (0x2) +#define G364_32MB_RAM (0x3) + +static void rc4030_reset(void *opaque) +{ + rc4030State *s = opaque; + int i; + + s->config = (G364_2MB_RAM << 8) | 0x04; + s->invalid_address_register = 0; + + memset(s->dma_regs, 0, sizeof(s->dma_regs)); + s->dma_tl_base = s->dma_tl_limit = 0; + + s->remote_failed_address = s->memory_failed_address = 0; + s->cache_ptag = s->cache_ltag = 0; + s->cache_bmask = s->cache_bwin = 0; + + s->offset208 = 0; + s->offset210 = 0x18186; + s->nvram_protect = 7; + s->offset238 = 7; + for (i = 0; i < 15; i++) + s->rem_speed[i] = 7; + s->imr_jazz = s->isr_jazz = 0; + + s->itr = 0; + s->dummy32 = 0; + + qemu_irq_lower(s->timer_irq); + qemu_irq_lower(s->jazz_bus_irq); +} + +qemu_irq *rc4030_init(qemu_irq timer, qemu_irq jazz_bus) +{ + rc4030State *s; + int s_chipset, s_int; + + s = qemu_mallocz(sizeof(rc4030State)); + if (!s) + return NULL; + + s->periodic_timer = qemu_new_timer(vm_clock, rc4030_periodic_timer, s); + s->timer_irq = timer; + s->jazz_bus_irq = jazz_bus; + + qemu_register_reset(rc4030_reset, s); + rc4030_reset(s); + + s_chipset = cpu_register_io_memory(0, rc4030_read, rc4030_write, s); + cpu_register_physical_memory(0x80000000, 0x300, s_chipset); + s_int = cpu_register_io_memory(0, int_read, int_write, s); + cpu_register_physical_memory(0xf0000000, 0x00001000, s_int); + + return qemu_allocate_irqs(rc4030_irq_jazz_request, s, 16); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/realview.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/realview.c --- qemu-0.9.1/hw/realview.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/realview.c 2008-10-28 10:59:59.000000000 +0000 @@ -18,7 +18,12 @@ /* Board init. */ -static void realview_init(int ram_size, int vga_ram_size, +static struct arm_boot_info realview_binfo = { + .loader_start = 0x0, + .board_id = 0x33b, +}; + +static void realview_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -59,7 +64,7 @@ } } - /* ??? RAM shoud repeat to fill physical memory space. */ + /* ??? RAM should repeat to fill physical memory space. */ /* SDRAM at address zero. */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); @@ -177,8 +182,12 @@ /* 0x68000000 PCI mem 1. */ /* 0x6c000000 PCI mem 2. */ - arm_load_kernel(first_cpu, ram_size, kernel_filename, kernel_cmdline, - initrd_filename, 0x33b, 0x0); + realview_binfo.ram_size = ram_size; + realview_binfo.kernel_filename = kernel_filename; + realview_binfo.kernel_cmdline = kernel_cmdline; + realview_binfo.initrd_filename = initrd_filename; + realview_binfo.nb_cpus = ncpu; + arm_load_kernel(first_cpu, &realview_binfo); /* ??? Hack to map an additional page of ram for the secondary CPU startup code. I guess this works on real hardware because the @@ -188,7 +197,9 @@ } QEMUMachine realview_machine = { - "realview", - "ARM RealView Emulation Baseboard (ARM926EJ-S)", - realview_init + .name = "realview", + .desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)", + .init = realview_init, + .ram_require = 0x1000, + .use_scsi = 1, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/rtl8139.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/rtl8139.c --- qemu-0.9.1/hw/rtl8139.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/rtl8139.c 2008-10-26 13:43:07.000000000 +0000 @@ -1255,7 +1255,7 @@ RTL8139TallyCounters_clear(&s->tally_counters); } -void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters) +static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters) { counters->TxOk = 0; counters->RxOk = 0; @@ -2001,7 +2001,7 @@ while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len) { s->cplus_txbuffer_len += CP_TX_BUFFER_SIZE; - s->cplus_txbuffer = realloc(s->cplus_txbuffer, s->cplus_txbuffer_len); + s->cplus_txbuffer = qemu_realloc(s->cplus_txbuffer, s->cplus_txbuffer_len); DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer space changed to %d\n", s->cplus_txbuffer_len)); } @@ -2735,13 +2735,8 @@ default: DEBUG_PRINT(("RTL8139: ioport write(w) addr=0x%x val=0x%04x via write(b)\n", addr, val)); -#ifdef TARGET_WORDS_BIGENDIAN - rtl8139_io_writeb(opaque, addr, (val >> 8) & 0xff); - rtl8139_io_writeb(opaque, addr + 1, val & 0xff); -#else rtl8139_io_writeb(opaque, addr, val & 0xff); rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff); -#endif break; } } @@ -2802,17 +2797,10 @@ default: DEBUG_PRINT(("RTL8139: ioport write(l) addr=0x%x val=0x%08x via write(b)\n", addr, val)); -#ifdef TARGET_WORDS_BIGENDIAN - rtl8139_io_writeb(opaque, addr, (val >> 24) & 0xff); - rtl8139_io_writeb(opaque, addr + 1, (val >> 16) & 0xff); - rtl8139_io_writeb(opaque, addr + 2, (val >> 8) & 0xff); - rtl8139_io_writeb(opaque, addr + 3, val & 0xff); -#else rtl8139_io_writeb(opaque, addr, val & 0xff); rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff); rtl8139_io_writeb(opaque, addr + 2, (val >> 16) & 0xff); rtl8139_io_writeb(opaque, addr + 3, (val >> 24) & 0xff); -#endif break; } } @@ -2958,13 +2946,8 @@ default: DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x via read(b)\n", addr)); -#ifdef TARGET_WORDS_BIGENDIAN - ret = rtl8139_io_readb(opaque, addr) << 8; - ret |= rtl8139_io_readb(opaque, addr + 1); -#else ret = rtl8139_io_readb(opaque, addr); ret |= rtl8139_io_readb(opaque, addr + 1) << 8; -#endif DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x val=0x%04x\n", addr, ret)); break; @@ -3031,17 +3014,10 @@ default: DEBUG_PRINT(("RTL8139: ioport read(l) addr=0x%x via read(b)\n", addr)); -#ifdef TARGET_WORDS_BIGENDIAN - ret = rtl8139_io_readb(opaque, addr) << 24; - ret |= rtl8139_io_readb(opaque, addr + 1) << 16; - ret |= rtl8139_io_readb(opaque, addr + 2) << 8; - ret |= rtl8139_io_readb(opaque, addr + 3); -#else ret = rtl8139_io_readb(opaque, addr); ret |= rtl8139_io_readb(opaque, addr + 1) << 8; ret |= rtl8139_io_readb(opaque, addr + 2) << 16; ret |= rtl8139_io_readb(opaque, addr + 3) << 24; -#endif DEBUG_PRINT(("RTL8139: read(l) addr=0x%x val=%08x\n", addr, ret)); break; @@ -3091,11 +3067,17 @@ static void rtl8139_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) { +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif rtl8139_io_writew(opaque, addr & 0xFF, val); } static void rtl8139_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif rtl8139_io_writel(opaque, addr & 0xFF, val); } @@ -3106,12 +3088,20 @@ static uint32_t rtl8139_mmio_readw(void *opaque, target_phys_addr_t addr) { - return rtl8139_io_readw(opaque, addr & 0xFF); + uint32_t val = rtl8139_io_readw(opaque, addr & 0xFF); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + return val; } static uint32_t rtl8139_mmio_readl(void *opaque, target_phys_addr_t addr) { - return rtl8139_io_readl(opaque, addr & 0xFF); + uint32_t val = rtl8139_io_readl(opaque, addr & 0xFF); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; } /* */ @@ -3366,7 +3356,7 @@ return next_time; } -#if RTL8139_ONBOARD_TIMER +#ifdef RTL8139_ONBOARD_TIMER static void rtl8139_timer(void *opaque) { RTL8139State *s = opaque; @@ -3464,10 +3454,9 @@ s->cplus_txbuffer_len = 0; s->cplus_txbuffer_offset = 0; - /* XXX: instance number ? */ - register_savevm("rtl8139", 0, 3, rtl8139_save, rtl8139_load, s); + register_savevm("rtl8139", -1, 3, rtl8139_save, rtl8139_load, s); -#if RTL8139_ONBOARD_TIMER +#ifdef RTL8139_ONBOARD_TIMER s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s); qemu_mod_timer(s->timer, diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/sb16.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/sb16.c --- qemu-0.9.1/hw/sb16.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/sb16.c 2008-01-14 04:24:29.000000000 +0000 @@ -1193,6 +1193,12 @@ SB16State *s = opaque; int till, copy, written, free; + if (s->block_size <= 0) { + dolog ("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n", + s->block_size, nchan, dma_pos, dma_len); + return dma_pos; + } + if (s->left_till_irq < 0) { s->left_till_irq = s->block_size; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/scsi-disk.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/scsi-disk.c --- qemu-0.9.1/hw/scsi-disk.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/scsi-disk.c 2008-10-11 10:33:03.000000000 +0100 @@ -9,8 +9,8 @@ * This code is licenced under the LGPL. * * Note that this file only handles the SCSI architecture model and device - * commands. Emultion of interface/link layer protocols is handled by - * the host adapter emulation. + * commands. Emulation of interface/link layer protocols is handled by + * the host adapter emulator. */ //#define DEBUG_SCSI @@ -34,7 +34,10 @@ #define SENSE_HARDWARE_ERROR 4 #define SENSE_ILLEGAL_REQUEST 5 -#define SCSI_DMA_BUF_SIZE 65536 +#define STATUS_GOOD 0 +#define STATUS_CHECK_CONDITION 2 + +#define SCSI_DMA_BUF_SIZE 131072 typedef struct SCSIRequest { SCSIDeviceState *dev; @@ -124,15 +127,15 @@ } /* Helper function for command completion. */ -static void scsi_command_complete(SCSIRequest *r, int sense) +static void scsi_command_complete(SCSIRequest *r, int status, int sense) { SCSIDeviceState *s = r->dev; uint32_t tag; - DPRINTF("Command complete tag=0x%x sense=%d\n", r->tag, sense); + DPRINTF("Command complete tag=0x%x status=%d sense=%d\n", r->tag, status, sense); s->sense = sense; tag = r->tag; scsi_remove_request(r); - s->completion(s->opaque, SCSI_REASON_DONE, tag, sense); + s->completion(s->opaque, SCSI_REASON_DONE, tag, status); } /* Cancel a pending data transfer. */ @@ -157,7 +160,8 @@ if (ret) { DPRINTF("IO error\n"); - scsi_command_complete(r, SENSE_HARDWARE_ERROR); + s->completion(s->opaque, SCSI_REASON_DATA, r->tag, 0); + scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NO_SENSE); return; } DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, r->buf_len); @@ -176,7 +180,7 @@ if (!r) { BADF("Bad read tag 0x%x\n", tag); /* ??? This is the wrong error. */ - scsi_command_complete(r, SENSE_HARDWARE_ERROR); + scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR); return; } if (r->sector_count == (uint32_t)-1) { @@ -187,7 +191,7 @@ } DPRINTF("Read sector_count=%d\n", r->sector_count); if (r->sector_count == 0) { - scsi_command_complete(r, SENSE_NO_SENSE); + scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE); return; } @@ -199,7 +203,7 @@ r->aiocb = bdrv_aio_read(s->bdrv, r->sector, r->dma_buf, n, scsi_read_complete, r); if (r->aiocb == NULL) - scsi_command_complete(r, SENSE_HARDWARE_ERROR); + scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR); r->sector += n; r->sector_count -= n; } @@ -217,7 +221,7 @@ r->aiocb = NULL; if (r->sector_count == 0) { - scsi_command_complete(r, SENSE_NO_SENSE); + scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE); } else { len = r->sector_count * 512; if (len > SCSI_DMA_BUF_SIZE) { @@ -241,7 +245,7 @@ r = scsi_find_request(s, tag); if (!r) { BADF("Bad write tag 0x%x\n", tag); - scsi_command_complete(r, SENSE_HARDWARE_ERROR); + scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR); return 1; } if (r->aiocb) @@ -251,7 +255,8 @@ r->aiocb = bdrv_aio_write(s->bdrv, r->sector, r->dma_buf, n, scsi_write_complete, r); if (r->aiocb == NULL) - scsi_command_complete(r, SENSE_HARDWARE_ERROR); + scsi_command_complete(r, STATUS_CHECK_CONDITION, + SENSE_HARDWARE_ERROR); r->sector += n; r->sector_count -= n; } else { @@ -344,7 +349,8 @@ if (lun || buf[1] >> 5) { /* Only LUN 0 supported. */ DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5); - goto fail; + if (command != 0x03 && command != 0x12) /* REQUEST SENSE and INQUIRY */ + goto fail; } switch (command) { case 0x0: @@ -362,11 +368,135 @@ break; case 0x12: DPRINTF("Inquiry (len %d)\n", len); - if (len < 36) { - BADF("Inquiry buffer too small (%d)\n", len); + if (buf[1] & 0x2) { + /* Command support data - optional, not implemented */ + BADF("optional INQUIRY command support request not implemented\n"); + goto fail; + } + else if (buf[1] & 0x1) { + /* Vital product data */ + uint8_t page_code = buf[2]; + if (len < 4) { + BADF("Error: Inquiry (EVPD[%02X]) buffer size %d is " + "less than 4\n", page_code, len); + goto fail; + } + + switch (page_code) { + case 0x00: + { + /* Supported page codes, mandatory */ + DPRINTF("Inquiry EVPD[Supported pages] " + "buffer size %d\n", len); + + r->buf_len = 0; + + if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { + outbuf[r->buf_len++] = 5; + } else { + outbuf[r->buf_len++] = 0; + } + + outbuf[r->buf_len++] = 0x00; // this page + outbuf[r->buf_len++] = 0x00; + outbuf[r->buf_len++] = 3; // number of pages + outbuf[r->buf_len++] = 0x00; // list of supported pages (this page) + outbuf[r->buf_len++] = 0x80; // unit serial number + outbuf[r->buf_len++] = 0x83; // device identification + } + break; + case 0x80: + { + /* Device serial number, optional */ + if (len < 4) { + BADF("Error: EVPD[Serial number] Inquiry buffer " + "size %d too small, %d needed\n", len, 4); + goto fail; + } + + DPRINTF("Inquiry EVPD[Serial number] buffer size %d\n", len); + + r->buf_len = 0; + + /* Supported page codes */ + if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { + outbuf[r->buf_len++] = 5; + } else { + outbuf[r->buf_len++] = 0; + } + + outbuf[r->buf_len++] = 0x80; // this page + outbuf[r->buf_len++] = 0x00; + outbuf[r->buf_len++] = 0x01; // 1 byte data follow + + outbuf[r->buf_len++] = '0'; // 1 byte data follow + } + + break; + case 0x83: + { + /* Device identification page, mandatory */ + int max_len = 255 - 8; + int id_len = strlen(bdrv_get_device_name(s->bdrv)); + if (id_len > max_len) + id_len = max_len; + + DPRINTF("Inquiry EVPD[Device identification] " + "buffer size %d\n", len); + r->buf_len = 0; + if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { + outbuf[r->buf_len++] = 5; + } else { + outbuf[r->buf_len++] = 0; + } + + outbuf[r->buf_len++] = 0x83; // this page + outbuf[r->buf_len++] = 0x00; + outbuf[r->buf_len++] = 3 + id_len; + + outbuf[r->buf_len++] = 0x2; // ASCII + outbuf[r->buf_len++] = 0; // not officially assigned + outbuf[r->buf_len++] = 0; // reserved + outbuf[r->buf_len++] = id_len; // length of data following + + memcpy(&outbuf[r->buf_len], + bdrv_get_device_name(s->bdrv), id_len); + r->buf_len += id_len; + } + break; + default: + BADF("Error: unsupported Inquiry (EVPD[%02X]) " + "buffer size %d\n", page_code, len); + goto fail; + } + /* done with EVPD */ + break; + } + else { + /* Standard INQUIRY data */ + if (buf[2] != 0) { + BADF("Error: Inquiry (STANDARD) page or code " + "is non-zero [%02X]\n", buf[2]); + goto fail; + } + + /* PAGE CODE == 0 */ + if (len < 5) { + BADF("Error: Inquiry (STANDARD) buffer size %d " + "is less than 5\n", len); + goto fail; + } + + if (len < 36) { + BADF("Error: Inquiry (STANDARD) buffer size %d " + "is less than 36 (TODO: only 5 required)\n", len); + } } memset(outbuf, 0, 36); - if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { + + if (lun || buf[1] >> 5) { + outbuf[0] = 0x7f; /* LUN not supported */ + } else if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { outbuf[0] = 5; outbuf[1] = 0x80; memcpy(&outbuf[16], "QEMU CD-ROM ", 16); @@ -411,7 +541,76 @@ outbuf[2] = 0x80; /* Readonly. */ } p += 4; - if ((page == 8 || page == 0x3f)) { + if (page == 4) { + int cylinders, heads, secs; + + /* Rigid disk device geometry page. */ + p[0] = 4; + p[1] = 0x16; + /* if a geometry hint is available, use it */ + bdrv_get_geometry_hint(s->bdrv, &cylinders, &heads, &secs); + p[2] = (cylinders >> 16) & 0xff; + p[3] = (cylinders >> 8) & 0xff; + p[4] = cylinders & 0xff; + p[5] = heads & 0xff; + /* Write precomp start cylinder, disabled */ + p[6] = (cylinders >> 16) & 0xff; + p[7] = (cylinders >> 8) & 0xff; + p[8] = cylinders & 0xff; + /* Reduced current start cylinder, disabled */ + p[9] = (cylinders >> 16) & 0xff; + p[10] = (cylinders >> 8) & 0xff; + p[11] = cylinders & 0xff; + /* Device step rate [ns], 200ns */ + p[12] = 0; + p[13] = 200; + /* Landing zone cylinder */ + p[14] = 0xff; + p[15] = 0xff; + p[16] = 0xff; + /* Medium rotation rate [rpm], 5400 rpm */ + p[20] = (5400 >> 8) & 0xff; + p[21] = 5400 & 0xff; + p += 0x16; + } else if (page == 5) { + int cylinders, heads, secs; + + /* Flexible disk device geometry page. */ + p[0] = 5; + p[1] = 0x1e; + /* Transfer rate [kbit/s], 5Mbit/s */ + p[2] = 5000 >> 8; + p[3] = 5000 & 0xff; + /* if a geometry hint is available, use it */ + bdrv_get_geometry_hint(s->bdrv, &cylinders, &heads, &secs); + p[4] = heads & 0xff; + p[5] = secs & 0xff; + p[6] = s->cluster_size * 2; + p[8] = (cylinders >> 8) & 0xff; + p[9] = cylinders & 0xff; + /* Write precomp start cylinder, disabled */ + p[10] = (cylinders >> 8) & 0xff; + p[11] = cylinders & 0xff; + /* Reduced current start cylinder, disabled */ + p[12] = (cylinders >> 8) & 0xff; + p[13] = cylinders & 0xff; + /* Device step rate [100us], 100us */ + p[14] = 0; + p[15] = 1; + /* Device step pulse width [us], 1us */ + p[16] = 1; + /* Device head settle delay [100us], 100us */ + p[17] = 0; + p[18] = 1; + /* Motor on delay [0.1s], 0.1s */ + p[19] = 1; + /* Motor off delay [0.1s], 0.1s */ + p[20] = 1; + /* Medium rotation rate [rpm], 5400 rpm */ + p[28] = (5400 >> 8) & 0xff; + p[29] = 5400 & 0xff; + p += 0x1e; + } else if ((page == 8 || page == 0x3f)) { /* Caching page. */ memset(p,0,20); p[0] = 8; @@ -480,7 +679,7 @@ outbuf[7] = 0; r->buf_len = 8; } else { - scsi_command_complete(r, SENSE_NOT_READY); + scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NOT_READY); return 0; } break; @@ -541,7 +740,7 @@ case 0x46: DPRINTF("Get Configuration (rt %d, maxlen %d)\n", buf[1] & 3, len); memset(outbuf, 0, 8); - /* ??? This shoud probably return much more information. For now + /* ??? This should probably return much more information. For now just return the basic header indicating the CD-ROM profile. */ outbuf[7] = 8; // CD-ROM r->buf_len = 8; @@ -564,14 +763,17 @@ outbuf[3] = 8; r->buf_len = 16; break; + case 0x2f: + DPRINTF("Verify (sector %d, count %d)\n", lba, len); + break; default: DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); fail: - scsi_command_complete(r, SENSE_ILLEGAL_REQUEST); + scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_ILLEGAL_REQUEST); return 0; } if (r->sector_count == 0 && r->buf_len == 0) { - scsi_command_complete(r, SENSE_NO_SENSE); + scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE); } len = r->sector_count * 512 + r->buf_len; if (is_write) { diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/scsi-generic.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/scsi-generic.c --- qemu-0.9.1/hw/scsi-generic.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/scsi-generic.c 2008-10-17 09:08:56.000000000 +0100 @@ -44,12 +44,14 @@ #include #include +#define REWIND 0x01 +#define REPORT_DENSITY_SUPPORT 0x44 #define LOAD_UNLOAD 0xa6 #define SET_CD_SPEED 0xbb #define BLANK 0xa1 #define SCSI_CMD_BUF_SIZE 16 -#define SCSI_SENSE_BUF_SIZE 32 +#define SCSI_SENSE_BUF_SIZE 96 #define SG_ERR_DRIVER_TIMEOUT 0x06 #define SG_ERR_DRIVER_SENSE 0x08 @@ -75,12 +77,14 @@ { SCSIRequest *requests; BlockDriverState *bdrv; + int type; int blocksize; int lun; scsi_completionfn completion; void *opaque; int driver_status; uint8_t sensebuf[SCSI_SENSE_BUF_SIZE]; + uint8_t senselen; }; /* Global pool of SCSIRequest structures. */ @@ -151,25 +155,30 @@ SCSIRequest *r = (SCSIRequest *)opaque; SCSIDeviceState *s = r->dev; uint32_t tag; - int sense; + int status; s->driver_status = r->io_header.driver_status; + if (s->driver_status & SG_ERR_DRIVER_SENSE) + s->senselen = r->io_header.sb_len_wr; + if (ret != 0) - sense = HARDWARE_ERROR; + status = BUSY << 1; else { if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) { - sense = HARDWARE_ERROR; + status = BUSY << 1; BADF("Driver Timeout\n"); - } else if ((s->driver_status & SG_ERR_DRIVER_SENSE) == 0) - sense = NO_SENSE; + } else if (r->io_header.status) + status = r->io_header.status; + else if (s->driver_status & SG_ERR_DRIVER_SENSE) + status = CHECK_CONDITION << 1; else - sense = s->sensebuf[2] & 0x0f; + status = GOOD << 1; } - - DPRINTF("Command complete 0x%p tag=0x%x sense=%d\n", r, r->tag, sense); + DPRINTF("Command complete 0x%p tag=0x%x status=%d\n", + r, r->tag, status); tag = r->tag; scsi_remove_request(r); - s->completion(s->opaque, SCSI_REASON_DONE, tag, sense); + s->completion(s->opaque, SCSI_REASON_DONE, tag, status); } /* Cancel a pending data transfer. */ @@ -248,6 +257,8 @@ r->len = -1; s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len); + if (len == 0) + scsi_command_complete(r, 0); } /* Read more data from scsi device into buffer. */ @@ -273,10 +284,17 @@ if (r->cmd[0] == REQUEST_SENSE && s->driver_status & SG_ERR_DRIVER_SENSE) { - memcpy(r->buf, s->sensebuf, 16); + s->senselen = MIN(r->len, s->senselen); + memcpy(r->buf, s->sensebuf, s->senselen); r->io_header.driver_status = 0; + r->io_header.status = 0; + r->io_header.dxfer_len = s->senselen; r->len = -1; - s->completion(s->opaque, SCSI_REASON_DATA, r->tag, 16); + DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, s->senselen); + DPRINTF("Sense: %d %d %d %d %d %d %d %d\n", + r->buf[0], r->buf[1], r->buf[2], r->buf[3], + r->buf[4], r->buf[5], r->buf[6], r->buf[7]); + s->completion(s->opaque, SCSI_REASON_DATA, r->tag, s->senselen); return; } @@ -298,6 +316,12 @@ return; } + if (r->cmd[0] == MODE_SELECT && r->cmd[4] == 12 && + r->dev->type == TYPE_TAPE) { + r->dev->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11]; + DPRINTF("block size %d\n", r->dev->blocksize); + } + scsi_command_complete(r, ret); } @@ -352,6 +376,9 @@ case 0: *len = cmd[4]; *cmdlen = 6; + /* length 0 means 256 blocks */ + if (*len == 0) + *len = 256; break; case 1: case 2: @@ -427,6 +454,35 @@ case READ_12: *len *= blocksize; break; + case INQUIRY: + *len = cmd[4] | (cmd[3] << 8); + break; + } + return 0; +} + +static int scsi_stream_length(uint8_t *cmd, int blocksize, int *cmdlen, uint32_t *len) +{ + switch(cmd[0]) { + /* stream commands */ + case READ_6: + case READ_REVERSE: + case RECOVER_BUFFERED_DATA: + case WRITE_6: + *cmdlen = 6; + *len = cmd[4] | (cmd[3] << 8) | (cmd[2] << 16); + if (cmd[1] & 0x01) /* fixed */ + *len *= blocksize; + break; + case REWIND: + case START_STOP: + *cmdlen = 6; + *len = 0; + cmd[1] = 0x01; /* force IMMED, otherwise qemu waits end of command */ + break; + /* generic commands */ + default: + return scsi_length(cmd, blocksize, cmdlen, len); } return 0; } @@ -478,28 +534,43 @@ uint8_t *cmd, int lun) { SCSIDeviceState *s = d->state; - uint32_t len; - int cmdlen; + uint32_t len=0; + int cmdlen=0; SCSIRequest *r; int ret; - /* ??? Tags are not unique for different luns. We only implement a - single lun, so this should not matter. */ + if (s->type == TYPE_TAPE) { + if (scsi_stream_length(cmd, s->blocksize, &cmdlen, &len) == -1) { + BADF("Unsupported command length, command %x\n", cmd[0]); + return 0; + } + } else { + if (scsi_length(cmd, s->blocksize, &cmdlen, &len) == -1) { + BADF("Unsupported command length, command %x\n", cmd[0]); + return 0; + } + } + + DPRINTF("Command: lun=%d tag=0x%x data=0x%02x len %d\n", lun, tag, + cmd[0], len); - if (lun != s->lun || (cmd[1] >> 5) != s->lun) { + if (cmd[0] != REQUEST_SENSE && + (lun != s->lun || (cmd[1] >> 5) != s->lun)) { DPRINTF("Unimplemented LUN %d\n", lun ? lun : cmd[1] >> 5); - s->completion(s->opaque, SCSI_REASON_DONE, tag, ILLEGAL_REQUEST); - return 0; - } - if (scsi_length(cmd, s->blocksize, &cmdlen, &len) == -1) { - BADF("Unsupported command length, command %x\n", cmd[0]); + s->sensebuf[0] = 0x70; + s->sensebuf[1] = 0x00; + s->sensebuf[2] = ILLEGAL_REQUEST; + s->sensebuf[3] = 0x00; + s->sensebuf[4] = 0x00; + s->sensebuf[5] = 0x00; + s->sensebuf[6] = 0x00; + s->senselen = 7; + s->driver_status = SG_ERR_DRIVER_SENSE; + s->completion(s->opaque, SCSI_REASON_DONE, tag, CHECK_CONDITION << 1); return 0; } - DPRINTF("Command: lun=%d tag=0x%x data=0x%02x len %d\n", lun, tag, - cmd[0], len); - r = scsi_find_request(s, tag); if (r) { BADF("Tag 0x%x already in use %p\n", tag, r); @@ -548,8 +619,8 @@ sg_io_hdr_t io_header; int ret; - memset(cmd, sizeof(cmd), 0); - memset(buf, sizeof(buf), 0); + memset(cmd, 0, sizeof(cmd)); + memset(buf, 0, sizeof(buf)); cmd[0] = READ_CAPACITY; memset(&io_header, 0, sizeof(io_header)); @@ -576,6 +647,43 @@ return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; } +static int get_stream_blocksize(BlockDriverState *bdrv) +{ + uint8_t cmd[6]; + uint8_t buf[12]; + uint8_t sensebuf[8]; + sg_io_hdr_t io_header; + int ret; + + memset(cmd, 0, sizeof(cmd)); + memset(buf, 0, sizeof(buf)); + cmd[0] = MODE_SENSE; + cmd[4] = sizeof(buf); + + memset(&io_header, 0, sizeof(io_header)); + io_header.interface_id = 'S'; + io_header.dxfer_direction = SG_DXFER_FROM_DEV; + io_header.dxfer_len = sizeof(buf); + io_header.dxferp = buf; + io_header.cmdp = cmd; + io_header.cmd_len = sizeof(cmd); + io_header.mx_sb_len = sizeof(sensebuf); + io_header.sbp = sensebuf; + io_header.timeout = 6000; /* XXX */ + + ret = bdrv_pwrite(bdrv, -1, &io_header, sizeof(io_header)); + if (ret == -1) + return -1; + + while ((ret = bdrv_pread(bdrv, -1, &io_header, sizeof(io_header))) == -1 && + errno == EINTR); + + if (ret == -1) + return -1; + + return (buf[9] << 16) | (buf[10] << 8) | buf[11]; +} + static void scsi_destroy(SCSIDevice *d) { SCSIRequest *r, *n; @@ -630,12 +738,26 @@ s->completion = completion; s->opaque = opaque; s->lun = scsiid.lun; - s->blocksize = get_blocksize(s->bdrv); + DPRINTF("LUN %d\n", s->lun); + s->type = scsiid.scsi_type; + DPRINTF("device type %d\n", s->type); + if (s->type == TYPE_TAPE) { + s->blocksize = get_stream_blocksize(s->bdrv); + if (s->blocksize == -1) + s->blocksize = 0; + } else { + s->blocksize = get_blocksize(s->bdrv); + /* removable media returns 0 if not present */ + if (s->blocksize <= 0) { + if (s->type == TYPE_ROM || s->type == TYPE_WORM) + s->blocksize = 2048; + else + s->blocksize = 512; + } + } + DPRINTF("block size %d\n", s->blocksize); s->driver_status = 0; memset(s->sensebuf, 0, sizeof(s->sensebuf)); - /* removable media returns 0 if not present */ - if (s->blocksize <= 0) - s->blocksize = 2048; /* define function to manage device */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/scsi.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/scsi.h --- qemu-0.9.1/hw/scsi.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/scsi.h 2008-04-09 17:32:48.000000000 +0100 @@ -0,0 +1,8 @@ +/* esp.c */ +#define ESP_MAX_DEVS 7 +typedef void (*espdma_memory_read_write)(void *opaque, uint8_t *buf, int len); +void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id); +void *esp_init(target_phys_addr_t espaddr, int it_shift, + espdma_memory_read_write dma_memory_read, + espdma_memory_read_write dma_memory_write, + void *dma_opaque, qemu_irq irq, qemu_irq *reset); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/sd.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/sd.c --- qemu-0.9.1/hw/sd.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/sd.c 2008-06-02 01:55:08.000000000 +0100 @@ -37,7 +37,7 @@ #ifdef DEBUG_SD #define DPRINTF(fmt, args...) \ -do { printf("SD: " fmt , ##args); } while (0) +do { fprintf(stderr, "SD: " fmt , ##args); } while (0) #else #define DPRINTF(fmt, args...) do {} while(0) #endif @@ -99,6 +99,8 @@ qemu_irq inserted_cb; BlockDriverState *bdrv; uint8_t *buf; + + int enable; }; static void sd_set_status(SDState *sd) @@ -419,6 +421,7 @@ sd = (SDState *) qemu_mallocz(sizeof(SDState)); sd->buf = qemu_memalign(512, 512); sd->spi = is_spi; + sd->enable = 1; sd_reset(sd, bs); bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd); return sd; @@ -530,7 +533,7 @@ sd->card_status &= ~CARD_IS_LOCKED; sd->pwd_len = 0; /* Erasing the entire card here! */ - printf("SD: Card force-erased by CMD42\n"); + fprintf(stderr, "SD: Card force-erased by CMD42\n"); return; } @@ -1076,7 +1079,7 @@ return sd_r1; case 56: /* CMD56: GEN_CMD */ - printf("SD: GEN_CMD 0x%08x\n", req.arg); + fprintf(stderr, "SD: GEN_CMD 0x%08x\n", req.arg); switch (sd->state) { case sd_transfer_state: @@ -1096,18 +1099,18 @@ bad_cmd: sd->card_status |= ILLEGAL_COMMAND; - printf("SD: Unknown CMD%i\n", req.cmd); + fprintf(stderr, "SD: Unknown CMD%i\n", req.cmd); return sd_r0; unimplemented_cmd: /* Commands that are recognised but not yet implemented in SPI mode. */ sd->card_status |= ILLEGAL_COMMAND; - printf ("SD: CMD%i not implemented in SPI mode\n", req.cmd); + fprintf(stderr, "SD: CMD%i not implemented in SPI mode\n", req.cmd); return sd_r0; } sd->card_status |= ILLEGAL_COMMAND; - printf("SD: CMD%i in a wrong state\n", req.cmd); + fprintf(stderr, "SD: CMD%i in a wrong state\n", req.cmd); return sd_r0; } @@ -1217,7 +1220,7 @@ return sd_normal_command(sd, req); } - printf("SD: ACMD%i in a wrong state\n", req.cmd); + fprintf(stderr, "SD: ACMD%i in a wrong state\n", req.cmd); return sd_r0; } @@ -1227,7 +1230,7 @@ sd_rsp_type_t rtype; int rsplen; - if (!bdrv_is_inserted(sd->bdrv)) { + if (!bdrv_is_inserted(sd->bdrv) || !sd->enable) { return 0; } @@ -1247,7 +1250,7 @@ sd_cmd_class[req->cmd] == 7 || req->cmd == 16 || req->cmd == 55))) { sd->card_status |= ILLEGAL_COMMAND; - printf("SD: Card is locked\n"); + fprintf(stderr, "SD: Card is locked\n"); return 0; } @@ -1321,7 +1324,7 @@ uint32_t end = addr + len; if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) == -1) { - printf("sd_blk_read: read error on host side\n"); + fprintf(stderr, "sd_blk_read: read error on host side\n"); return; } @@ -1329,7 +1332,7 @@ memcpy(sd->data, sd->buf + (addr & 511), 512 - (addr & 511)); if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) == -1) { - printf("sd_blk_read: read error on host side\n"); + fprintf(stderr, "sd_blk_read: read error on host side\n"); return; } memcpy(sd->data + 512 - (addr & 511), sd->buf, end & 511); @@ -1343,28 +1346,28 @@ if ((addr & 511) || len < 512) if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) == -1) { - printf("sd_blk_write: read error on host side\n"); + fprintf(stderr, "sd_blk_write: read error on host side\n"); return; } if (end > (addr & ~511) + 512) { memcpy(sd->buf + (addr & 511), sd->data, 512 - (addr & 511)); if (bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) == -1) { - printf("sd_blk_write: write error on host side\n"); + fprintf(stderr, "sd_blk_write: write error on host side\n"); return; } if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) == -1) { - printf("sd_blk_write: read error on host side\n"); + fprintf(stderr, "sd_blk_write: read error on host side\n"); return; } memcpy(sd->buf, sd->data + 512 - (addr & 511), end & 511); if (bdrv_write(sd->bdrv, end >> 9, sd->buf, 1) == -1) - printf("sd_blk_write: write error on host side\n"); + fprintf(stderr, "sd_blk_write: write error on host side\n"); } else { memcpy(sd->buf + (addr & 511), sd->data, len); if (!sd->bdrv || bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) == -1) - printf("sd_blk_write: write error on host side\n"); + fprintf(stderr, "sd_blk_write: write error on host side\n"); } } @@ -1377,11 +1380,11 @@ { int i; - if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv)) + if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv) || !sd->enable) return; if (sd->state != sd_receivingdata_state) { - printf("sd_write_data: not in Receiving-Data state\n"); + fprintf(stderr, "sd_write_data: not in Receiving-Data state\n"); return; } @@ -1489,7 +1492,7 @@ break; default: - printf("sd_write_data: unknown command\n"); + fprintf(stderr, "sd_write_data: unknown command\n"); break; } } @@ -1499,11 +1502,11 @@ /* TODO: Append CRCs */ uint8_t ret; - if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv)) + if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv) || !sd->enable) return 0x00; if (sd->state != sd_sendingdata_state) { - printf("sd_read_data: not in Sending-Data state\n"); + fprintf(stderr, "sd_read_data: not in Sending-Data state\n"); return 0x00; } @@ -1603,7 +1606,7 @@ break; default: - printf("sd_read_data: unknown command\n"); + fprintf(stderr, "sd_read_data: unknown command\n"); return 0x00; } @@ -1614,3 +1617,8 @@ { return sd->state == sd_sendingdata_state; } + +void sd_enable(SDState *sd, int enable) +{ + sd->enable = enable; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/sd.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/sd.h --- qemu-0.9.1/hw/sd.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/sd.h 2008-04-14 22:05:22.000000000 +0100 @@ -74,6 +74,7 @@ uint8_t sd_read_data(SDState *sd); void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert); int sd_data_ready(SDState *sd); +void sd_enable(SDState *sd, int enable); /* ssi-sd.c */ int ssi_sd_xfer(void *opaque, int val); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/serial.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/serial.c --- qemu-0.9.1/hw/serial.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/serial.c 2008-09-20 02:15:04.000000000 +0100 @@ -1,7 +1,8 @@ /* - * QEMU 16450 UART emulation + * QEMU 16550A UART emulation * * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2008 Citrix Systems, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,6 +26,7 @@ #include "qemu-char.h" #include "isa.h" #include "pc.h" +#include "qemu-timer.h" //#define DEBUG_SERIAL @@ -42,6 +44,10 @@ #define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ #define UART_IIR_RDI 0x04 /* Receiver data interrupt */ #define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ +#define UART_IIR_CTI 0x0C /* Character Timeout Indication */ + +#define UART_IIR_FENF 0x80 /* Fifo enabled, but not functionning */ +#define UART_IIR_FE 0xC0 /* Fifo enabled */ /* * These are the definitions for the Modem Control Register @@ -72,10 +78,39 @@ #define UART_LSR_PE 0x04 /* Parity error indicator */ #define UART_LSR_OE 0x02 /* Overrun error indicator */ #define UART_LSR_DR 0x01 /* Receiver data ready */ +#define UART_LSR_INT_ANY 0x1E /* Any of the lsr-interrupt-triggering status bits */ + +/* Interrupt trigger levels. The byte-counts are for 16550A - in newer UARTs the byte-count for each ITL is higher. */ + +#define UART_FCR_ITL_1 0x00 /* 1 byte ITL */ +#define UART_FCR_ITL_2 0x40 /* 4 bytes ITL */ +#define UART_FCR_ITL_3 0x80 /* 8 bytes ITL */ +#define UART_FCR_ITL_4 0xC0 /* 14 bytes ITL */ + +#define UART_FCR_DMS 0x08 /* DMA Mode Select */ +#define UART_FCR_XFR 0x04 /* XMIT Fifo Reset */ +#define UART_FCR_RFR 0x02 /* RCVR Fifo Reset */ +#define UART_FCR_FE 0x01 /* FIFO Enable */ + +#define UART_FIFO_LENGTH 16 /* 16550A Fifo Length */ + +#define XMIT_FIFO 0 +#define RECV_FIFO 1 +#define MAX_XMIT_RETRY 4 + +struct SerialFIFO { + uint8_t data[UART_FIFO_LENGTH]; + uint8_t count; + uint8_t itl; /* Interrupt Trigger Level */ + uint8_t tail; + uint8_t head; +} typedef SerialFIFO; struct SerialState { uint16_t divider; uint8_t rbr; /* receive register */ + uint8_t thr; /* transmit holding register */ + uint8_t tsr; /* transmit shift register */ uint8_t ier; uint8_t iir; /* read only */ uint8_t lcr; @@ -83,6 +118,7 @@ uint8_t lsr; /* read only */ uint8_t msr; /* read only */ uint8_t scr; + uint8_t fcr; /* NOTE: this hidden state is necessary for tx irq generation as it can be reset while reading iir */ int thr_ipending; @@ -91,18 +127,90 @@ int last_break_enable; target_phys_addr_t base; int it_shift; + int baudbase; + int tsr_retry; + + uint64_t last_xmit_ts; /* Time when the last byte was successfully sent out of the tsr */ + SerialFIFO recv_fifo; + SerialFIFO xmit_fifo; + + struct QEMUTimer *fifo_timeout_timer; + int timeout_ipending; /* timeout interrupt pending state */ + struct QEMUTimer *transmit_timer; + + + uint64_t char_transmit_time; /* time to transmit a char in ticks*/ + int poll_msl; + + struct QEMUTimer *modem_status_poll; }; +static void serial_receive1(void *opaque, const uint8_t *buf, int size); + +static void fifo_clear(SerialState *s, int fifo) +{ + SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; + memset(f->data, 0, UART_FIFO_LENGTH); + f->count = 0; + f->head = 0; + f->tail = 0; +} + +static int fifo_put(SerialState *s, int fifo, uint8_t chr) +{ + SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; + + f->data[f->head++] = chr; + + if (f->head == UART_FIFO_LENGTH) + f->head = 0; + f->count++; + + return 1; +} + +static uint8_t fifo_get(SerialState *s, int fifo) +{ + SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; + uint8_t c; + + if(f->count == 0) + return 0; + + c = f->data[f->tail++]; + if (f->tail == UART_FIFO_LENGTH) + f->tail = 0; + f->count--; + + return c; +} + static void serial_update_irq(SerialState *s) { - if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) { - s->iir = UART_IIR_RDI; - } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) { - s->iir = UART_IIR_THRI; - } else { - s->iir = UART_IIR_NO_INT; + uint8_t tmp_iir = UART_IIR_NO_INT; + + if ((s->ier & UART_IER_RLSI) && (s->lsr & UART_LSR_INT_ANY)) { + tmp_iir = UART_IIR_RLSI; + } else if ((s->ier & UART_IER_RDI) && s->timeout_ipending) { + /* Note that(s->ier & UART_IER_RDI) can mask this interrupt, + * this is not in the specification but is observed on existing + * hardware. */ + tmp_iir = UART_IIR_CTI; + } else if ((s->ier & UART_IER_RDI) && (s->lsr & UART_LSR_DR)) { + if (!(s->fcr & UART_FCR_FE)) { + tmp_iir = UART_IIR_RDI; + } else if (s->recv_fifo.count >= s->recv_fifo.itl) { + tmp_iir = UART_IIR_RDI; + } + } else if ((s->ier & UART_IER_THRI) && s->thr_ipending) { + tmp_iir = UART_IIR_THRI; + } else if ((s->ier & UART_IER_MSI) && (s->msr & UART_MSR_ANY_DELTA)) { + tmp_iir = UART_IIR_MSI; } - if (s->iir != UART_IIR_NO_INT) { + + s->iir = tmp_iir | (s->iir & 0xF0); + + if (tmp_iir != UART_IIR_NO_INT) { qemu_irq_raise(s->irq); } else { qemu_irq_lower(s->irq); @@ -111,9 +219,13 @@ static void serial_update_parameters(SerialState *s) { - int speed, parity, data_bits, stop_bits; + int speed, parity, data_bits, stop_bits, frame_size; QEMUSerialSetParams ssp; + if (s->divider == 0) + return; + + frame_size = 1; if (s->lcr & 0x08) { if (s->lcr & 0x10) parity = 'E'; @@ -121,19 +233,21 @@ parity = 'O'; } else { parity = 'N'; + frame_size = 0; } if (s->lcr & 0x04) stop_bits = 2; else stop_bits = 1; + data_bits = (s->lcr & 0x03) + 5; - if (s->divider == 0) - return; - speed = 115200 / s->divider; + frame_size += data_bits + stop_bits; + speed = s->baudbase / s->divider; ssp.speed = speed; ssp.parity = parity; ssp.data_bits = data_bits; ssp.stop_bits = stop_bits; + s->char_transmit_time = (ticks_per_sec / speed) * frame_size; qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); #if 0 printf("speed=%d parity=%c data=%d stop=%d\n", @@ -141,10 +255,91 @@ #endif } +static void serial_update_msl(SerialState *s) +{ + uint8_t omsr; + int flags; + + qemu_del_timer(s->modem_status_poll); + + if (qemu_chr_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) { + s->poll_msl = -1; + return; + } + + omsr = s->msr; + + s->msr = (flags & CHR_TIOCM_CTS) ? s->msr | UART_MSR_CTS : s->msr & ~UART_MSR_CTS; + s->msr = (flags & CHR_TIOCM_DSR) ? s->msr | UART_MSR_DSR : s->msr & ~UART_MSR_DSR; + s->msr = (flags & CHR_TIOCM_CAR) ? s->msr | UART_MSR_DCD : s->msr & ~UART_MSR_DCD; + s->msr = (flags & CHR_TIOCM_RI) ? s->msr | UART_MSR_RI : s->msr & ~UART_MSR_RI; + + if (s->msr != omsr) { + /* Set delta bits */ + s->msr = s->msr | ((s->msr >> 4) ^ (omsr >> 4)); + /* UART_MSR_TERI only if change was from 1 -> 0 */ + if ((s->msr & UART_MSR_TERI) && !(omsr & UART_MSR_RI)) + s->msr &= ~UART_MSR_TERI; + serial_update_irq(s); + } + + /* The real 16550A apparently has a 250ns response latency to line status changes. + We'll be lazy and poll only every 10ms, and only poll it at all if MSI interrupts are turned on */ + + if (s->poll_msl) + qemu_mod_timer(s->modem_status_poll, qemu_get_clock(vm_clock) + ticks_per_sec / 100); +} + +static void serial_xmit(void *opaque) +{ + SerialState *s = opaque; + uint64_t new_xmit_ts = qemu_get_clock(vm_clock); + + if (s->tsr_retry <= 0) { + if (s->fcr & UART_FCR_FE) { + s->tsr = fifo_get(s,XMIT_FIFO); + if (!s->xmit_fifo.count) + s->lsr |= UART_LSR_THRE; + } else { + s->tsr = s->thr; + s->lsr |= UART_LSR_THRE; + } + } + + if (s->mcr & UART_MCR_LOOP) { + /* in loopback mode, say that we just received a char */ + serial_receive1(s, &s->tsr, 1); + } else if (qemu_chr_write(s->chr, &s->tsr, 1) != 1) { + if ((s->tsr_retry > 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) { + s->tsr_retry++; + qemu_mod_timer(s->transmit_timer, new_xmit_ts + s->char_transmit_time); + return; + } else if (s->poll_msl < 0) { + /* If we exceed MAX_XMIT_RETRY and the backend is not a real serial port, then + drop any further failed writes instantly, until we get one that goes through. + This is to prevent guests that log to unconnected pipes or pty's from stalling. */ + s->tsr_retry = -1; + } + } + else { + s->tsr_retry = 0; + } + + s->last_xmit_ts = qemu_get_clock(vm_clock); + if (!(s->lsr & UART_LSR_THRE)) + qemu_mod_timer(s->transmit_timer, s->last_xmit_ts + s->char_transmit_time); + + if (s->lsr & UART_LSR_THRE) { + s->lsr |= UART_LSR_TEMT; + s->thr_ipending = 1; + serial_update_irq(s); + } +} + + static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) { SerialState *s = opaque; - unsigned char ch; addr &= 7; #ifdef DEBUG_SERIAL @@ -157,15 +352,19 @@ s->divider = (s->divider & 0xff00) | val; serial_update_parameters(s); } else { + s->thr = (uint8_t) val; + if(s->fcr & UART_FCR_FE) { + fifo_put(s, XMIT_FIFO, s->thr); s->thr_ipending = 0; + s->lsr &= ~UART_LSR_TEMT; s->lsr &= ~UART_LSR_THRE; serial_update_irq(s); - ch = val; - qemu_chr_write(s->chr, &ch, 1); - s->thr_ipending = 1; - s->lsr |= UART_LSR_THRE; - s->lsr |= UART_LSR_TEMT; - serial_update_irq(s); + } else { + s->thr_ipending = 0; + s->lsr &= ~UART_LSR_THRE; + serial_update_irq(s); + } + serial_xmit(s); } break; case 1: @@ -174,13 +373,68 @@ serial_update_parameters(s); } else { s->ier = val & 0x0f; + /* If the backend device is a real serial port, turn polling of the modem + status lines on physical port on or off depending on UART_IER_MSI state */ + if (s->poll_msl >= 0) { + if (s->ier & UART_IER_MSI) { + s->poll_msl = 1; + serial_update_msl(s); + } else { + qemu_del_timer(s->modem_status_poll); + s->poll_msl = 0; + } + } if (s->lsr & UART_LSR_THRE) { s->thr_ipending = 1; + serial_update_irq(s); } - serial_update_irq(s); } break; case 2: + val = val & 0xFF; + + if (s->fcr == val) + break; + + /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */ + if ((val ^ s->fcr) & UART_FCR_FE) + val |= UART_FCR_XFR | UART_FCR_RFR; + + /* FIFO clear */ + + if (val & UART_FCR_RFR) { + qemu_del_timer(s->fifo_timeout_timer); + s->timeout_ipending=0; + fifo_clear(s,RECV_FIFO); + } + + if (val & UART_FCR_XFR) { + fifo_clear(s,XMIT_FIFO); + } + + if (val & UART_FCR_FE) { + s->iir |= UART_IIR_FE; + /* Set RECV_FIFO trigger Level */ + switch (val & 0xC0) { + case UART_FCR_ITL_1: + s->recv_fifo.itl = 1; + break; + case UART_FCR_ITL_2: + s->recv_fifo.itl = 4; + break; + case UART_FCR_ITL_3: + s->recv_fifo.itl = 8; + break; + case UART_FCR_ITL_4: + s->recv_fifo.itl = 14; + break; + } + } else + s->iir &= ~UART_IIR_FE; + + /* Set fcr - or at least the bits in it that are supposed to "stick" */ + s->fcr = val & 0xC9; + serial_update_irq(s); break; case 3: { @@ -196,7 +450,30 @@ } break; case 4: - s->mcr = val & 0x1f; + { + int flags; + int old_mcr = s->mcr; + s->mcr = val & 0x1f; + if (val & UART_MCR_LOOP) + break; + + if (s->poll_msl >= 0 && old_mcr != s->mcr) { + + qemu_chr_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags); + + flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR); + + if (val & UART_MCR_RTS) + flags |= CHR_TIOCM_RTS; + if (val & UART_MCR_DTR) + flags |= CHR_TIOCM_DTR; + + qemu_chr_ioctl(s->chr,CHR_IOCTL_SERIAL_SET_TIOCM, &flags); + /* Update the modem status after a one-character-send wait-time, since there may be a response + from the device/computer at the other end of the serial line */ + qemu_mod_timer(s->modem_status_poll, qemu_get_clock(vm_clock) + s->char_transmit_time); + } + } break; case 5: break; @@ -220,10 +497,22 @@ if (s->lcr & UART_LCR_DLAB) { ret = s->divider & 0xff; } else { - ret = s->rbr; - s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); + if(s->fcr & UART_FCR_FE) { + ret = fifo_get(s,RECV_FIFO); + if (s->recv_fifo.count == 0) + s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); + else + qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock (vm_clock) + s->char_transmit_time * 4); + s->timeout_ipending = 0; + } else { + ret = s->rbr; + s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); + } serial_update_irq(s); - qemu_chr_accept_input(s->chr); + if (!(s->mcr & UART_MCR_LOOP)) { + /* in loopback mode, don't receive any data */ + qemu_chr_accept_input(s->chr); + } } break; case 1: @@ -235,8 +524,6 @@ break; case 2: ret = s->iir; - /* reset THR pending bit */ - if ((ret & 0x7) == UART_IIR_THRI) s->thr_ipending = 0; serial_update_irq(s); break; @@ -248,6 +535,11 @@ break; case 5: ret = s->lsr; + /* Clear break interrupt */ + if (s->lsr & UART_LSR_BI) { + s->lsr &= ~UART_LSR_BI; + serial_update_irq(s); + } break; case 6: if (s->mcr & UART_MCR_LOOP) { @@ -257,7 +549,14 @@ ret |= (s->mcr & 0x02) << 3; ret |= (s->mcr & 0x01) << 5; } else { + if (s->poll_msl >= 0) + serial_update_msl(s); ret = s->msr; + /* Clear delta bits & msr int after read, if they were set */ + if (s->msr & UART_MSR_ANY_DELTA) { + s->msr &= 0xF0; + serial_update_irq(s); + } } break; case 7: @@ -272,14 +571,17 @@ static int serial_can_receive(SerialState *s) { + if(s->fcr & UART_FCR_FE) { + if(s->recv_fifo.count < UART_FIFO_LENGTH) + /* Advertise (fifo.itl - fifo.count) bytes when count < ITL, and 1 if above. If UART_FIFO_LENGTH - fifo.count is + advertised the effect will be to almost always fill the fifo completely before the guest has a chance to respond, + effectively overriding the ITL that the guest has set. */ + return (s->recv_fifo.count <= s->recv_fifo.itl) ? s->recv_fifo.itl - s->recv_fifo.count : 1; + else + return 0; + } else { return !(s->lsr & UART_LSR_DR); -} - -static void serial_receive_byte(SerialState *s, int ch) -{ - s->rbr = ch; - s->lsr |= UART_LSR_DR; - serial_update_irq(s); + } } static void serial_receive_break(SerialState *s) @@ -289,6 +591,15 @@ serial_update_irq(s); } +/* There's data in recv_fifo and s->rbr has not been read for 4 char transmit times */ +static void fifo_timeout_int (void *opaque) { + SerialState *s = opaque; + if (s->recv_fifo.count) { + s->timeout_ipending = 1; + serial_update_irq(s); + } +} + static int serial_can_receive1(void *opaque) { SerialState *s = opaque; @@ -298,12 +609,27 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size) { SerialState *s = opaque; - serial_receive_byte(s, buf[0]); + if(s->fcr & UART_FCR_FE) { + int i; + for (i = 0; i < size; i++) { + fifo_put(s, RECV_FIFO, buf[i]); + } + s->lsr |= UART_LSR_DR; + /* call the timeout receive callback in 4 char transmit time */ + qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock (vm_clock) + s->char_transmit_time * 4); + } else { + s->rbr = buf[0]; + s->lsr |= UART_LSR_DR; + } + serial_update_irq(s); } static void serial_event(void *opaque, int event) { SerialState *s = opaque; +#ifdef DEBUG_SERIAL + printf("serial: event %x\n", event); +#endif if (event == CHR_EVENT_BREAK) serial_receive_break(s); } @@ -321,13 +647,15 @@ qemu_put_8s(f,&s->lsr); qemu_put_8s(f,&s->msr); qemu_put_8s(f,&s->scr); + qemu_put_8s(f,&s->fcr); } static int serial_load(QEMUFile *f, void *opaque, int version_id) { SerialState *s = opaque; + uint8_t fcr = 0; - if(version_id > 2) + if(version_id > 3) return -EINVAL; if (version_id >= 2) @@ -343,27 +671,75 @@ qemu_get_8s(f,&s->msr); qemu_get_8s(f,&s->scr); + if (version_id >= 3) + qemu_get_8s(f,&fcr); + + /* Initialize fcr via setter to perform essential side-effects */ + serial_ioport_write(s, 0x02, fcr); return 0; } +static void serial_reset(void *opaque) +{ + SerialState *s = opaque; + + s->rbr = 0; + s->ier = 0; + s->iir = UART_IIR_NO_INT; + s->lcr = 0; + s->lsr = UART_LSR_TEMT | UART_LSR_THRE; + s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; + /* Default to 9600 baud, no parity, one stop bit */ + s->divider = 0x0C; + s->mcr = UART_MCR_OUT2; + s->scr = 0; + s->tsr_retry = 0; + s->char_transmit_time = (ticks_per_sec / 9600) * 9; + s->poll_msl = 0; + + fifo_clear(s,RECV_FIFO); + fifo_clear(s,XMIT_FIFO); + + s->last_xmit_ts = qemu_get_clock(vm_clock); + + s->thr_ipending = 0; + s->last_break_enable = 0; + qemu_irq_lower(s->irq); +} + +static void serial_init_core(SerialState *s, qemu_irq irq, int baudbase, + CharDriverState *chr) +{ + s->irq = irq; + s->baudbase = baudbase; + s->chr = chr; + + s->modem_status_poll = qemu_new_timer(vm_clock, (QEMUTimerCB *) serial_update_msl, s); + + s->fifo_timeout_timer = qemu_new_timer(vm_clock, (QEMUTimerCB *) fifo_timeout_int, s); + s->transmit_timer = qemu_new_timer(vm_clock, (QEMUTimerCB *) serial_xmit, s); + + qemu_register_reset(serial_reset, s); + serial_reset(s); + +} + /* If fd is zero, it means that the serial device uses the console */ -SerialState *serial_init(int base, qemu_irq irq, CharDriverState *chr) +SerialState *serial_init(int base, qemu_irq irq, int baudbase, + CharDriverState *chr) { SerialState *s; s = qemu_mallocz(sizeof(SerialState)); if (!s) return NULL; - s->irq = irq; - s->lsr = UART_LSR_TEMT | UART_LSR_THRE; - s->iir = UART_IIR_NO_INT; - s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; - register_savevm("serial", base, 2, serial_save, serial_load, s); + serial_init_core(s, irq, baudbase, chr); + + register_savevm("serial", base, 3, serial_save, serial_load, s); register_ioport_write(base, 8, 1, serial_ioport_write, s); register_ioport_read(base, 8, 1, serial_ioport_read, s); - s->chr = chr; qemu_chr_add_handlers(chr, serial_can_receive1, serial_receive1, serial_event, s); return s; @@ -442,8 +818,8 @@ }; SerialState *serial_mm_init (target_phys_addr_t base, int it_shift, - qemu_irq irq, CharDriverState *chr, - int ioregister) + qemu_irq irq, int baudbase, + CharDriverState *chr, int ioregister) { SerialState *s; int s_io_memory; @@ -451,22 +827,20 @@ s = qemu_mallocz(sizeof(SerialState)); if (!s) return NULL; - s->irq = irq; - s->lsr = UART_LSR_TEMT | UART_LSR_THRE; - s->iir = UART_IIR_NO_INT; - s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; + s->base = base; s->it_shift = it_shift; - register_savevm("serial", base, 2, serial_save, serial_load, s); + serial_init_core(s, irq, baudbase, chr); + register_savevm("serial", base, 3, serial_save, serial_load, s); if (ioregister) { s_io_memory = cpu_register_io_memory(0, serial_mm_read, serial_mm_write, s); cpu_register_physical_memory(base, 8 << it_shift, s_io_memory); } - s->chr = chr; qemu_chr_add_handlers(chr, serial_can_receive1, serial_receive1, serial_event, s); + serial_update_msl(s); return s; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/sh7750.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/sh7750.c --- qemu-0.9.1/hw/sh7750.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/sh7750.c 2008-09-02 17:18:28.000000000 +0100 @@ -30,6 +30,8 @@ #include "sh7750_regs.h" #include "sh7750_regnames.h" #include "sh_intc.h" +#include "exec-all.h" +#include "cpu.h" #define NB_DEVICES 4 @@ -182,13 +184,13 @@ static void error_access(const char *kind, target_phys_addr_t addr) { - fprintf(stderr, "%s to %s (0x%08x) not supported\n", + fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") not supported\n", kind, regname(addr), addr); } static void ignore_access(const char *kind, target_phys_addr_t addr) { - fprintf(stderr, "%s to %s (0x%08x) ignored\n", + fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") ignored\n", kind, regname(addr), addr); } @@ -247,12 +249,12 @@ return s->cpu->intevt; case SH7750_CCR_A7: return s->ccr; - case 0x1f000030: /* Processor version PVR */ - return 0x00050000; /* SH7750R */ - case 0x1f000040: /* Processor version CVR */ - return 0x00110000; /* Minimum caches */ - case 0x1f000044: /* Processor version PRR */ - return 0x00000100; /* SH7750R */ + case 0x1f000030: /* Processor version */ + return s->cpu->pvr; + case 0x1f000040: /* Cache version */ + return s->cpu->cvr; + case 0x1f000044: /* Processor revision */ + return s->cpu->prr; default: error_access("long read", addr); assert(0); @@ -355,11 +357,17 @@ s->cpu->mmucr = mem_value; return; case SH7750_PTEH_A7: + /* If asid changes, clear all registered tlb entries. */ + if ((s->cpu->pteh & 0xff) != (mem_value & 0xff)) + tlb_flush(s->cpu, 1); s->cpu->pteh = mem_value; return; case SH7750_PTEL_A7: s->cpu->ptel = mem_value; return; + case SH7750_PTEA_A7: + s->cpu->ptea = mem_value & 0x0000000f; + return; case SH7750_TTB_A7: s->cpu->ttb = mem_value; return; @@ -521,19 +529,113 @@ PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3), }; -#define SH_CPU_SH7750 (1 << 0) -#define SH_CPU_SH7750S (1 << 1) -#define SH_CPU_SH7750R (1 << 2) -#define SH_CPU_SH7751 (1 << 3) -#define SH_CPU_SH7751R (1 << 4) -#define SH_CPU_SH7750_ALL (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7750R) -#define SH_CPU_SH7751_ALL (SH_CPU_SH7751 | SH_CPU_SH7751R) +/********************************************************************** + Memory mapped cache and TLB +**********************************************************************/ + +#define MM_REGION_MASK 0x07000000 +#define MM_ICACHE_ADDR (0) +#define MM_ICACHE_DATA (1) +#define MM_ITLB_ADDR (2) +#define MM_ITLB_DATA (3) +#define MM_OCACHE_ADDR (4) +#define MM_OCACHE_DATA (5) +#define MM_UTLB_ADDR (6) +#define MM_UTLB_DATA (7) +#define MM_REGION_TYPE(addr) ((addr & MM_REGION_MASK) >> 24) + +static uint32_t invalid_read(void *opaque, target_phys_addr_t addr) +{ + assert(0); + + return 0; +} + +static uint32_t sh7750_mmct_readl(void *opaque, target_phys_addr_t addr) +{ + uint32_t ret = 0; + + switch (MM_REGION_TYPE(addr)) { + case MM_ICACHE_ADDR: + case MM_ICACHE_DATA: + /* do nothing */ + break; + case MM_ITLB_ADDR: + case MM_ITLB_DATA: + /* XXXXX */ + assert(0); + break; + case MM_OCACHE_ADDR: + case MM_OCACHE_DATA: + /* do nothing */ + break; + case MM_UTLB_ADDR: + case MM_UTLB_DATA: + /* XXXXX */ + assert(0); + break; + default: + assert(0); + } + + return ret; +} + +static void invalid_write(void *opaque, target_phys_addr_t addr, + uint32_t mem_value) +{ + assert(0); +} + +static void sh7750_mmct_writel(void *opaque, target_phys_addr_t addr, + uint32_t mem_value) +{ + SH7750State *s = opaque; + + switch (MM_REGION_TYPE(addr)) { + case MM_ICACHE_ADDR: + case MM_ICACHE_DATA: + /* do nothing */ + break; + case MM_ITLB_ADDR: + case MM_ITLB_DATA: + /* XXXXX */ + assert(0); + break; + case MM_OCACHE_ADDR: + case MM_OCACHE_DATA: + /* do nothing */ + break; + case MM_UTLB_ADDR: + cpu_sh4_write_mmaped_utlb_addr(s->cpu, addr, mem_value); + break; + case MM_UTLB_DATA: + /* XXXXX */ + assert(0); + break; + default: + assert(0); + break; + } +} + +static CPUReadMemoryFunc *sh7750_mmct_read[] = { + invalid_read, + invalid_read, + sh7750_mmct_readl +}; + +static CPUWriteMemoryFunc *sh7750_mmct_write[] = { + invalid_write, + invalid_write, + sh7750_mmct_writel +}; SH7750State *sh7750_init(CPUSH4State * cpu) { SH7750State *s; int sh7750_io_memory; - int cpu_model = SH_CPU_SH7751R; /* for now */ + int sh7750_mm_cache_and_tlb; /* memory mapped cache and tlb */ s = qemu_mallocz(sizeof(SH7750State)); s->cpu = cpu; @@ -543,19 +645,35 @@ sh7750_mem_write, s); cpu_register_physical_memory(0x1c000000, 0x04000000, sh7750_io_memory); + sh7750_mm_cache_and_tlb = cpu_register_io_memory(0, + sh7750_mmct_read, + sh7750_mmct_write, s); + cpu_register_physical_memory(0xf0000000, 0x08000000, + sh7750_mm_cache_and_tlb); + sh_intc_init(&s->intc, NR_SOURCES, _INTC_ARRAY(mask_registers), _INTC_ARRAY(prio_registers)); - sh_intc_register_sources(&s->intc, + sh_intc_register_sources(&s->intc, _INTC_ARRAY(vectors), _INTC_ARRAY(groups)); cpu->intc_handle = &s->intc; - sh_serial_init(0x1fe00000, 0, s->periph_freq, serial_hds[0]); + sh_serial_init(0x1fe00000, 0, s->periph_freq, serial_hds[0], + sh_intc_source(&s->intc, SCI1_ERI), + sh_intc_source(&s->intc, SCI1_RXI), + sh_intc_source(&s->intc, SCI1_TXI), + sh_intc_source(&s->intc, SCI1_TEI), + NULL); sh_serial_init(0x1fe80000, SH_SERIAL_FEAT_SCIF, - s->periph_freq, serial_hds[1]); + s->periph_freq, serial_hds[1], + sh_intc_source(&s->intc, SCIF_ERI), + sh_intc_source(&s->intc, SCIF_RXI), + sh_intc_source(&s->intc, SCIF_TXI), + NULL, + sh_intc_source(&s->intc, SCIF_BRI)); tmu012_init(0x1fd80000, TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK, @@ -565,20 +683,20 @@ sh_intc_source(&s->intc, TMU2_TUNI), sh_intc_source(&s->intc, TMU2_TICPI)); - if (cpu_model & (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7751)) { - sh_intc_register_sources(&s->intc, + if (cpu->id & (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7751)) { + sh_intc_register_sources(&s->intc, _INTC_ARRAY(vectors_dma4), _INTC_ARRAY(groups_dma4)); } - if (cpu_model & (SH_CPU_SH7750R | SH_CPU_SH7751R)) { - sh_intc_register_sources(&s->intc, + if (cpu->id & (SH_CPU_SH7750R | SH_CPU_SH7751R)) { + sh_intc_register_sources(&s->intc, _INTC_ARRAY(vectors_dma8), _INTC_ARRAY(groups_dma8)); } - if (cpu_model & (SH_CPU_SH7750R | SH_CPU_SH7751 | SH_CPU_SH7751R)) { - sh_intc_register_sources(&s->intc, + if (cpu->id & (SH_CPU_SH7750R | SH_CPU_SH7751 | SH_CPU_SH7751R)) { + sh_intc_register_sources(&s->intc, _INTC_ARRAY(vectors_tmu34), NULL, 0); tmu012_init(0x1e100000, 0, s->periph_freq, @@ -587,14 +705,14 @@ NULL, NULL); } - if (cpu_model & (SH_CPU_SH7751_ALL)) { - sh_intc_register_sources(&s->intc, + if (cpu->id & (SH_CPU_SH7751_ALL)) { + sh_intc_register_sources(&s->intc, _INTC_ARRAY(vectors_pci), _INTC_ARRAY(groups_pci)); } - if (cpu_model & (SH_CPU_SH7750S | SH_CPU_SH7750R | SH_CPU_SH7751_ALL)) { - sh_intc_register_sources(&s->intc, + if (cpu->id & (SH_CPU_SH7750S | SH_CPU_SH7750R | SH_CPU_SH7751_ALL)) { + sh_intc_register_sources(&s->intc, _INTC_ARRAY(vectors_irlm), NULL, 0); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/sharpsl.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/sharpsl.h --- qemu-0.9.1/hw/sharpsl.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/sharpsl.h 2008-06-02 02:33:11.000000000 +0100 @@ -0,0 +1,23 @@ +/* + * Common declarations for the Zaurii. + * + * This file is licensed under the GNU GPL. + */ +#ifndef QEMU_SHARPSL_H +#define QEMU_SHARPSL_H + +#define zaurus_printf(format, ...) \ + fprintf(stderr, "%s: " format, __FUNCTION__, ##__VA_ARGS__) + +/* zaurus.c */ +struct scoop_info_s *scoop_init(struct pxa2xx_state_s *cpu, + int instance, target_phys_addr_t target_base); +void scoop_gpio_set(void *opaque, int line, int level); +qemu_irq *scoop_gpio_in_get(struct scoop_info_s *s); +void scoop_gpio_out_set(struct scoop_info_s *s, int line, + qemu_irq handler); + +#define SL_PXA_PARAM_BASE 0xa0000a00 +void sl_bootparam_write(uint32_t ptr); + +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/sh.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/sh.h --- qemu-0.9.1/hw/sh.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/sh.h 2008-09-14 07:45:34.000000000 +0100 @@ -35,9 +35,14 @@ /* sh_serial.c */ #define SH_SERIAL_FEAT_SCIF (1 << 0) void sh_serial_init (target_phys_addr_t base, int feat, - uint32_t freq, CharDriverState *chr); + uint32_t freq, CharDriverState *chr, + struct intc_source *eri_source, + struct intc_source *rxi_source, + struct intc_source *txi_source, + struct intc_source *tei_source, + struct intc_source *bri_source); /* tc58128.c */ -int tc58128_init(struct SH7750State *s, char *zone1, char *zone2); +int tc58128_init(struct SH7750State *s, const char *zone1, const char *zone2); #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/shix.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/shix.c --- qemu-0.9.1/hw/shix.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/shix.c 2008-10-31 17:25:56.000000000 +0000 @@ -35,27 +35,22 @@ #define BIOS_FILENAME "shix_bios.bin" #define BIOS_ADDRESS 0xA0000000 -void DMA_run(void) -{ - /* XXXXX */ -} - void irq_info(void) { /* XXXXX */ } -void pic_info() +void pic_info(void) { /* XXXXX */ } -void vga_update_display() +void vga_update_display(void) { /* XXXXX */ } -void vga_invalidate_display() +void vga_invalidate_display(void) { /* XXXXX */ } @@ -65,7 +60,7 @@ /* XXXXX */ } -static void shix_init(int ram_size, int vga_ram_size, +static void shix_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState * ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -108,7 +103,8 @@ } QEMUMachine shix_machine = { - "shix", - "shix card", - shix_init + .name = "shix", + .desc = "shix card", + .init = shix_init, + .ram_require = (0x00004000 + 0x01000000 + 0x01000000) | RAMSIZE_FIXED, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/sh_serial.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/sh_serial.c --- qemu-0.9.1/hw/sh_serial.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/sh_serial.c 2008-09-15 08:05:18.000000000 +0100 @@ -37,6 +37,8 @@ #define SH_SERIAL_FLAG_BRK (1 << 3) #define SH_SERIAL_FLAG_DR (1 << 4) +#define SH_RX_FIFO_LENGTH (16) + typedef struct { uint8_t smr; uint8_t brr; @@ -46,17 +48,34 @@ uint16_t fcr; uint8_t sptr; - uint8_t rx_fifo[16]; /* frdr / rdr */ + uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */ uint8_t rx_cnt; + uint8_t rx_tail; + uint8_t rx_head; target_phys_addr_t base; int freq; int feat; int flags; + int rtrg; CharDriverState *chr; + + struct intc_source *eri; + struct intc_source *rxi; + struct intc_source *txi; + struct intc_source *tei; + struct intc_source *bri; } sh_serial_state; +static void sh_serial_clear_fifo(sh_serial_state * s) +{ + memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH); + s->rx_cnt = 0; + s->rx_head = 0; + s->rx_tail = 0; +} + static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val) { sh_serial_state *s = opaque; @@ -74,9 +93,19 @@ s->brr = val; return; case 0x08: /* SCR */ - s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfb : 0xff); + /* TODO : For SH7751, SCIF mask should be 0xfb. */ + s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff); if (!(val & (1 << 5))) s->flags |= SH_SERIAL_FLAG_TEND; + if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) { + if ((val & (1 << 7)) && !(s->txi->asserted)) + sh_intc_toggle_source(s->txi, 0, 1); + else if (!(val & (1 << 7)) && s->txi->asserted) + sh_intc_toggle_source(s->txi, 0, -1); + } + if (!(val & (1 << 6)) && s->rxi->asserted) { + sh_intc_toggle_source(s->rxi, 0, -1); + } return; case 0x0c: /* FTDR / TDR */ if (s->chr) { @@ -105,12 +134,37 @@ s->flags &= ~SH_SERIAL_FLAG_RDF; if (!(val & (1 << 0))) s->flags &= ~SH_SERIAL_FLAG_DR; + + if (!(val & (1 << 1)) || !(val & (1 << 0))) { + if (s->rxi && s->rxi->asserted) { + sh_intc_toggle_source(s->rxi, 0, -1); + } + } return; case 0x18: /* FCR */ s->fcr = val; + switch ((val >> 6) & 3) { + case 0: + s->rtrg = 1; + break; + case 1: + s->rtrg = 4; + break; + case 2: + s->rtrg = 8; + break; + case 3: + s->rtrg = 14; + break; + } + if (val & (1 << 1)) { + sh_serial_clear_fifo(s); + s->sr &= ~(1 << 1); + } + return; case 0x20: /* SPTR */ - s->sptr = val; + s->sptr = val & 0xf3; return; case 0x24: /* LSR */ return; @@ -159,6 +213,12 @@ #endif if (s->feat & SH_SERIAL_FEAT_SCIF) { switch(offs) { + case 0x00: /* SMR */ + ret = s->smr; + break; + case 0x08: /* SCR */ + ret = s->scr; + break; case 0x10: /* FSR */ ret = 0; if (s->flags & SH_SERIAL_FLAG_TEND) @@ -172,10 +232,20 @@ if (s->flags & SH_SERIAL_FLAG_DR) ret |= (1 << 0); - if (s->scr & (1 << 5)) + if (s->scr & (1 << 5)) s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND; break; + case 0x14: + if (s->rx_cnt > 0) { + ret = s->rx_fifo[s->rx_tail++]; + s->rx_cnt--; + if (s->rx_tail == SH_RX_FIFO_LENGTH) + s->rx_tail = 0; + if (s->rx_cnt < s->rtrg) + s->flags &= ~SH_SERIAL_FLAG_RDF; + } + break; #if 0 case 0x18: ret = s->fcr; @@ -201,6 +271,9 @@ case 0x10: ret = 0; break; + case 0x14: + ret = s->rx_fifo[0]; + break; case 0x1c: ret = s->sptr; break; @@ -222,15 +295,33 @@ static int sh_serial_can_receive(sh_serial_state *s) { - return 0; + return s->scr & (1 << 4); } static void sh_serial_receive_byte(sh_serial_state *s, int ch) { + if (s->feat & SH_SERIAL_FEAT_SCIF) { + if (s->rx_cnt < SH_RX_FIFO_LENGTH) { + s->rx_fifo[s->rx_head++] = ch; + if (s->rx_head == SH_RX_FIFO_LENGTH) + s->rx_head = 0; + s->rx_cnt++; + if (s->rx_cnt >= s->rtrg) { + s->flags |= SH_SERIAL_FLAG_RDF; + if (s->scr & (1 << 6) && s->rxi) { + sh_intc_toggle_source(s->rxi, 0, 1); + } + } + } + } else { + s->rx_fifo[0] = ch; + } } static void sh_serial_receive_break(sh_serial_state *s) { + if (s->feat & SH_SERIAL_FEAT_SCIF) + s->sr |= (1 << 4); } static int sh_serial_can_receive1(void *opaque) @@ -278,7 +369,12 @@ }; void sh_serial_init (target_phys_addr_t base, int feat, - uint32_t freq, CharDriverState *chr) + uint32_t freq, CharDriverState *chr, + struct intc_source *eri_source, + struct intc_source *rxi_source, + struct intc_source *txi_source, + struct intc_source *tei_source, + struct intc_source *bri_source) { sh_serial_state *s; int s_io_memory; @@ -290,6 +386,7 @@ s->base = base; s->feat = feat; s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE; + s->rtrg = 1; s->smr = 0; s->brr = 0xff; @@ -303,7 +400,7 @@ s->dr = 0xff; } - s->rx_cnt = 0; + sh_serial_clear_fifo(s); s_io_memory = cpu_register_io_memory(0, sh_serial_readfn, sh_serial_writefn, s); @@ -314,4 +411,10 @@ if (chr) qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1, sh_serial_event, s); + + s->eri = eri_source; + s->rxi = rxi_source; + s->txi = txi_source; + s->tei = tei_source; + s->bri = bri_source; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/slavio_intctl.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/slavio_intctl.c --- qemu-0.9.1/hw/slavio_intctl.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/slavio_intctl.c 2008-05-12 17:13:33.000000000 +0100 @@ -99,7 +99,8 @@ return ret; } -static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, + uint32_t val) { SLAVIO_INTCTLState *s = opaque; uint32_t saddr; @@ -115,13 +116,15 @@ val &= CPU_SOFTIRQ_MASK; s->intreg_pending[cpu] &= ~val; slavio_check_interrupts(s); - DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); + DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, + s->intreg_pending[cpu]); break; case 2: // set softint val &= CPU_SOFTIRQ_MASK; s->intreg_pending[cpu] |= val; slavio_check_interrupts(s); - DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); + DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, + s->intreg_pending[cpu]); break; default: break; @@ -166,7 +169,8 @@ return ret; } -static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, + uint32_t val) { SLAVIO_INTCTLState *s = opaque; uint32_t saddr; @@ -178,7 +182,8 @@ // Force clear unused bits val &= MASTER_IRQ_MASK; s->intregm_disabled &= ~val; - DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); + DPRINTF("Enabled master irq mask %x, curmask %x\n", val, + s->intregm_disabled); slavio_check_interrupts(s); break; case 3: // set (disable, clear pending) @@ -187,7 +192,8 @@ s->intregm_disabled |= val; s->intregm_pending &= ~val; slavio_check_interrupts(s); - DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); + DPRINTF("Disabled master irq mask %x, curmask %x\n", val, + s->intregm_disabled); break; case 4: s->target_cpu = val & (MAX_CPUS - 1); @@ -219,7 +225,8 @@ for (i = 0; i < MAX_CPUS; i++) { term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]); } - term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled); + term_printf("master: pending 0x%08x, disabled 0x%08x\n", + s->intregm_pending, s->intregm_disabled); } void slavio_irq_info(void *opaque) @@ -376,16 +383,23 @@ s->intbit_to_level = intbit_to_level; for (i = 0; i < MAX_CPUS; i++) { - slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s); + slavio_intctl_io_memory = cpu_register_io_memory(0, + slavio_intctl_mem_read, + slavio_intctl_mem_write, + s); cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_SIZE, slavio_intctl_io_memory); s->cpu_irqs[i] = parent_irq[i]; } - slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s); + slavio_intctlm_io_memory = cpu_register_io_memory(0, + slavio_intctlm_mem_read, + slavio_intctlm_mem_write, + s); cpu_register_physical_memory(addrg, INTCTLM_SIZE, slavio_intctlm_io_memory); - register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s); + register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, + slavio_intctl_load, s); qemu_register_reset(slavio_intctl_reset, s); *irq = qemu_allocate_irqs(slavio_set_irq, s, 32); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/slavio_misc.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/slavio_misc.c --- qemu-0.9.1/hw/slavio_misc.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/slavio_misc.c 2008-11-02 10:51:05.000000000 +0000 @@ -50,7 +50,8 @@ uint8_t diag, mctrl; uint32_t sysctrl; uint16_t leds; - target_phys_addr_t power_base; + qemu_irq cpu_halt; + qemu_irq fdc_tc; } MiscState; #define MISC_SIZE 1 @@ -62,12 +63,12 @@ #define MISC_MASK 0x0fff0000 #define MISC_LEDS 0x01600000 #define MISC_CFG 0x01800000 -#define MISC_AUX1 0x01900000 -#define MISC_AUX2 0x01910000 #define MISC_DIAG 0x01a00000 #define MISC_MDM 0x01b00000 #define MISC_SYS 0x01f00000 +#define AUX1_TC 0x02 + #define AUX2_PWROFF 0x01 #define AUX2_PWRINTCLR 0x02 #define AUX2_PWRFAIL 0x20 @@ -122,21 +123,6 @@ s->config = val & 0xff; slavio_misc_update_irq(s); break; - case MISC_AUX1: - MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff); - s->aux1 = val & 0xff; - break; - case MISC_AUX2: - val &= AUX2_PWRINTCLR | AUX2_PWROFF; - MISC_DPRINTF("Write aux2 %2.2x\n", val); - val |= s->aux2 & AUX2_PWRFAIL; - if (val & AUX2_PWRINTCLR) // Clear Power Fail int - val &= AUX2_PWROFF; - s->aux2 = val; - if (val & AUX2_PWROFF) - qemu_system_shutdown_request(); - slavio_misc_update_irq(s); - break; case MISC_DIAG: MISC_DPRINTF("Write diag %2.2x\n", val & 0xff); s->diag = val & 0xff; @@ -146,10 +132,6 @@ s->mctrl = val & 0xff; break; default: - if (addr == s->power_base) { - MISC_DPRINTF("Write power management %2.2x\n", val & 0xff); - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); - } break; } } @@ -164,14 +146,6 @@ ret = s->config; MISC_DPRINTF("Read config %2.2x\n", ret); break; - case MISC_AUX1: - ret = s->aux1; - MISC_DPRINTF("Read aux1 %2.2x\n", ret); - break; - case MISC_AUX2: - ret = s->aux2; - MISC_DPRINTF("Read aux2 %2.2x\n", ret); - break; case MISC_DIAG: ret = s->diag; MISC_DPRINTF("Read diag %2.2x\n", ret); @@ -181,9 +155,6 @@ MISC_DPRINTF("Read modem control %2.2x\n", ret); break; default: - if (addr == s->power_base) { - MISC_DPRINTF("Read power management %2.2x\n", ret); - } break; } return ret; @@ -201,6 +172,113 @@ NULL, }; +static void slavio_aux1_mem_writeb(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + MiscState *s = opaque; + + MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff); + if (val & AUX1_TC) { + // Send a pulse to floppy terminal count line + if (s->fdc_tc) { + qemu_irq_raise(s->fdc_tc); + qemu_irq_lower(s->fdc_tc); + } + val &= ~AUX1_TC; + } + s->aux1 = val & 0xff; +} + +static uint32_t slavio_aux1_mem_readb(void *opaque, target_phys_addr_t addr) +{ + MiscState *s = opaque; + uint32_t ret = 0; + + ret = s->aux1; + MISC_DPRINTF("Read aux1 %2.2x\n", ret); + + return ret; +} + +static CPUReadMemoryFunc *slavio_aux1_mem_read[3] = { + slavio_aux1_mem_readb, + NULL, + NULL, +}; + +static CPUWriteMemoryFunc *slavio_aux1_mem_write[3] = { + slavio_aux1_mem_writeb, + NULL, + NULL, +}; + +static void slavio_aux2_mem_writeb(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + MiscState *s = opaque; + + val &= AUX2_PWRINTCLR | AUX2_PWROFF; + MISC_DPRINTF("Write aux2 %2.2x\n", val); + val |= s->aux2 & AUX2_PWRFAIL; + if (val & AUX2_PWRINTCLR) // Clear Power Fail int + val &= AUX2_PWROFF; + s->aux2 = val; + if (val & AUX2_PWROFF) + qemu_system_shutdown_request(); + slavio_misc_update_irq(s); +} + +static uint32_t slavio_aux2_mem_readb(void *opaque, target_phys_addr_t addr) +{ + MiscState *s = opaque; + uint32_t ret = 0; + + ret = s->aux2; + MISC_DPRINTF("Read aux2 %2.2x\n", ret); + + return ret; +} + +static CPUReadMemoryFunc *slavio_aux2_mem_read[3] = { + slavio_aux2_mem_readb, + NULL, + NULL, +}; + +static CPUWriteMemoryFunc *slavio_aux2_mem_write[3] = { + slavio_aux2_mem_writeb, + NULL, + NULL, +}; + +static void apc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + MiscState *s = opaque; + + MISC_DPRINTF("Write power management %2.2x\n", val & 0xff); + qemu_irq_raise(s->cpu_halt); +} + +static uint32_t apc_mem_readb(void *opaque, target_phys_addr_t addr) +{ + uint32_t ret = 0; + + MISC_DPRINTF("Read power management %2.2x\n", ret); + return ret; +} + +static CPUReadMemoryFunc *apc_mem_read[3] = { + apc_mem_readb, + NULL, + NULL, +}; + +static CPUWriteMemoryFunc *apc_mem_write[3] = { + apc_mem_writeb, + NULL, + NULL, +}; + static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr) { MiscState *s = opaque; @@ -303,10 +381,9 @@ static void slavio_misc_save(QEMUFile *f, void *opaque) { MiscState *s = opaque; - int tmp; + uint32_t tmp = 0; uint8_t tmp8; - tmp = 0; qemu_put_be32s(f, &tmp); /* ignored, was IRQ. */ qemu_put_8s(f, &s->config); qemu_put_8s(f, &s->aux1); @@ -320,7 +397,7 @@ static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id) { MiscState *s = opaque; - int tmp; + uint32_t tmp; uint8_t tmp8; if (version_id != 1) @@ -338,57 +415,69 @@ } void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, - qemu_irq irq) + target_phys_addr_t aux1_base, + target_phys_addr_t aux2_base, qemu_irq irq, + qemu_irq cpu_halt, qemu_irq **fdc_tc) { - int slavio_misc_io_memory; + int io; MiscState *s; s = qemu_mallocz(sizeof(MiscState)); if (!s) return NULL; - /* 8 bit registers */ - slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read, - slavio_misc_mem_write, s); - // Slavio control - cpu_register_physical_memory(base + MISC_CFG, MISC_SIZE, - slavio_misc_io_memory); - // AUX 1 - cpu_register_physical_memory(base + MISC_AUX1, MISC_SIZE, - slavio_misc_io_memory); - // AUX 2 - cpu_register_physical_memory(base + MISC_AUX2, MISC_SIZE, - slavio_misc_io_memory); - // Diagnostics - cpu_register_physical_memory(base + MISC_DIAG, MISC_SIZE, - slavio_misc_io_memory); - // Modem control - cpu_register_physical_memory(base + MISC_MDM, MISC_SIZE, - slavio_misc_io_memory); - // Power management - cpu_register_physical_memory(power_base, MISC_SIZE, slavio_misc_io_memory); - s->power_base = power_base; - - /* 16 bit registers */ - slavio_misc_io_memory = cpu_register_io_memory(0, slavio_led_mem_read, - slavio_led_mem_write, s); - /* ss600mp diag LEDs */ - cpu_register_physical_memory(base + MISC_LEDS, MISC_SIZE, - slavio_misc_io_memory); - - /* 32 bit registers */ - slavio_misc_io_memory = cpu_register_io_memory(0, slavio_sysctrl_mem_read, - slavio_sysctrl_mem_write, - s); - // System control - cpu_register_physical_memory(base + MISC_SYS, SYSCTRL_SIZE, - slavio_misc_io_memory); + if (base) { + /* 8 bit registers */ + io = cpu_register_io_memory(0, slavio_misc_mem_read, + slavio_misc_mem_write, s); + // Slavio control + cpu_register_physical_memory(base + MISC_CFG, MISC_SIZE, io); + // Diagnostics + cpu_register_physical_memory(base + MISC_DIAG, MISC_SIZE, io); + // Modem control + cpu_register_physical_memory(base + MISC_MDM, MISC_SIZE, io); + + /* 16 bit registers */ + io = cpu_register_io_memory(0, slavio_led_mem_read, + slavio_led_mem_write, s); + /* ss600mp diag LEDs */ + cpu_register_physical_memory(base + MISC_LEDS, MISC_SIZE, io); + + /* 32 bit registers */ + io = cpu_register_io_memory(0, slavio_sysctrl_mem_read, + slavio_sysctrl_mem_write, s); + // System control + cpu_register_physical_memory(base + MISC_SYS, SYSCTRL_SIZE, io); + } + + // AUX 1 (Misc System Functions) + if (aux1_base) { + io = cpu_register_io_memory(0, slavio_aux1_mem_read, + slavio_aux1_mem_write, s); + cpu_register_physical_memory(aux1_base, MISC_SIZE, io); + } + + // AUX 2 (Software Powerdown Control) + if (aux2_base) { + io = cpu_register_io_memory(0, slavio_aux2_mem_read, + slavio_aux2_mem_write, s); + cpu_register_physical_memory(aux2_base, MISC_SIZE, io); + } + + // Power management (APC) XXX: not a Slavio device + if (power_base) { + io = cpu_register_io_memory(0, apc_mem_read, apc_mem_write, s); + cpu_register_physical_memory(power_base, MISC_SIZE, io); + } s->irq = irq; + s->cpu_halt = cpu_halt; + *fdc_tc = &s->fdc_tc; register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load, s); qemu_register_reset(slavio_misc_reset, s); slavio_misc_reset(s); + return s; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/slavio_serial.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/slavio_serial.c --- qemu-0.9.1/hw/slavio_serial.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/slavio_serial.c 2008-07-02 16:17:21.000000000 +0100 @@ -92,8 +92,8 @@ #define SERIAL_REGS 16 typedef struct ChannelState { qemu_irq irq; - int reg; - int rxint, txint, rxint_under_svc, txint_under_svc; + uint32_t reg; + uint32_t rxint, txint, rxint_under_svc, txint_under_svc; chn_id_t chn; // this channel, A (base+4) or B (base+0) chn_type_t type; struct ChannelState *otherchn; @@ -215,7 +215,6 @@ static void handle_kbd_command(ChannelState *s, int val); static int serial_can_receive(void *opaque); static void serial_receive_byte(ChannelState *s, int ch); -static inline void set_txint(ChannelState *s); static void clear_queue(void *opaque) { @@ -261,8 +260,7 @@ static int slavio_serial_update_irq_chn(ChannelState *s) { - if ((s->wregs[W_INTR] & INTR_INTALL) && // interrupts enabled - (((s->wregs[W_INTR] & INTR_TXINT) && s->txint == 1) || + if ((((s->wregs[W_INTR] & INTR_TXINT) && s->txint == 1) || // tx ints enabled, pending ((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) || ((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) && @@ -321,28 +319,6 @@ slavio_serial_reset_chn(&s->chn[1]); } -static inline void clr_rxint(ChannelState *s) -{ - s->rxint = 0; - s->rxint_under_svc = 0; - if (s->chn == chn_a) { - if (s->wregs[W_MINTR] & MINTR_STATUSHI) - s->otherchn->rregs[R_IVEC] = IVEC_HINOINT; - else - s->otherchn->rregs[R_IVEC] = IVEC_LONOINT; - s->rregs[R_INTR] &= ~INTR_RXINTA; - } else { - if (s->wregs[W_MINTR] & MINTR_STATUSHI) - s->rregs[R_IVEC] = IVEC_HINOINT; - else - s->rregs[R_IVEC] = IVEC_LONOINT; - s->otherchn->rregs[R_INTR] &= ~INTR_RXINTB; - } - if (s->txint) - set_txint(s); - slavio_serial_update_irq(s); -} - static inline void set_rxint(ChannelState *s) { s->rxint = 1; @@ -367,6 +343,49 @@ slavio_serial_update_irq(s); } +static inline void set_txint(ChannelState *s) +{ + s->txint = 1; + if (!s->rxint_under_svc) { + s->txint_under_svc = 1; + if (s->chn == chn_a) { + if (s->wregs[W_MINTR] & MINTR_STATUSHI) + s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA; + else + s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA; + } else { + s->rregs[R_IVEC] = IVEC_TXINTB; + } + } + if (s->chn == chn_a) + s->rregs[R_INTR] |= INTR_TXINTA; + else + s->otherchn->rregs[R_INTR] |= INTR_TXINTB; + slavio_serial_update_irq(s); +} + +static inline void clr_rxint(ChannelState *s) +{ + s->rxint = 0; + s->rxint_under_svc = 0; + if (s->chn == chn_a) { + if (s->wregs[W_MINTR] & MINTR_STATUSHI) + s->otherchn->rregs[R_IVEC] = IVEC_HINOINT; + else + s->otherchn->rregs[R_IVEC] = IVEC_LONOINT; + s->rregs[R_INTR] &= ~INTR_RXINTA; + } else { + if (s->wregs[W_MINTR] & MINTR_STATUSHI) + s->rregs[R_IVEC] = IVEC_HINOINT; + else + s->rregs[R_IVEC] = IVEC_LONOINT; + s->otherchn->rregs[R_INTR] &= ~INTR_RXINTB; + } + if (s->txint) + set_txint(s); + slavio_serial_update_irq(s); +} + static inline void clr_txint(ChannelState *s) { s->txint = 0; @@ -389,27 +408,6 @@ slavio_serial_update_irq(s); } -static inline void set_txint(ChannelState *s) -{ - s->txint = 1; - if (!s->rxint_under_svc) { - s->txint_under_svc = 1; - if (s->chn == chn_a) { - if (s->wregs[W_MINTR] & MINTR_STATUSHI) - s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA; - else - s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA; - } else { - s->rregs[R_IVEC] = IVEC_TXINTB; - } - } - if (s->chn == chn_a) - s->rregs[R_INTR] |= INTR_TXINTA; - else - s->otherchn->rregs[R_INTR] |= INTR_TXINTB; - slavio_serial_update_irq(s); -} - static void slavio_serial_update_parameters(ChannelState *s) { int speed, parity, data_bits, stop_bits; @@ -515,9 +513,13 @@ break; case W_TXCTRL1: case W_TXCTRL2: + s->wregs[s->reg] = val; + slavio_serial_update_parameters(s); + break; case W_BRGLO: case W_BRGHI: s->wregs[s->reg] = val; + s->rregs[s->reg] = val; slavio_serial_update_parameters(s); break; case W_MINTR: @@ -526,10 +528,10 @@ default: break; case MINTR_RST_B: - slavio_serial_reset_chn(&serial->chn[1]); + slavio_serial_reset_chn(&serial->chn[0]); return; case MINTR_RST_A: - slavio_serial_reset_chn(&serial->chn[0]); + slavio_serial_reset_chn(&serial->chn[1]); return; case MINTR_RST_ALL: slavio_serial_reset(serial); @@ -653,8 +655,8 @@ static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s) { - int tmp; - tmp = 0; + uint32_t tmp = 0; + qemu_put_be32s(f, &tmp); /* unused, was IRQ. */ qemu_put_be32s(f, &s->reg); qemu_put_be32s(f, &s->rxint); @@ -677,7 +679,7 @@ static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id) { - int tmp; + uint32_t tmp; if (version_id > 2) return -EINVAL; @@ -767,7 +769,7 @@ 0, 0, 0, 0, 0, 0, 0, 68, 69, 70, 0, 91, 0, 93, 0, 112, 113, 114, 94, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 3, 25, 26, 49, 52, 72, 73, 97, 99, 111, 118, 120, 122, 67, 0, }; static void sunkbd_event(void *opaque, int ch) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/slavio_timer.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/slavio_timer.c --- qemu-0.9.1/hw/slavio_timer.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/slavio_timer.c 2008-05-12 17:13:33.000000000 +0100 @@ -31,7 +31,7 @@ #define DPRINTF(fmt, args...) \ do { printf("TIMER: " fmt , ##args); } while (0) #else -#define DPRINTF(fmt, args...) +#define DPRINTF(fmt, args...) do {} while (0) #endif /* @@ -57,11 +57,11 @@ uint32_t count, counthigh, reached; uint64_t limit; // processor only - int running; + uint32_t running; struct SLAVIO_TIMERState *master; - int slave_index; + uint32_t slave_index; // system only - unsigned int num_slaves; + uint32_t num_slaves; struct SLAVIO_TIMERState *slave[MAX_CPUS]; uint32_t slave_mode; } SLAVIO_TIMERState; @@ -122,10 +122,9 @@ slavio_timer_get_out(s); DPRINTF("callback: count %x%08x\n", s->counthigh, s->count); - if (!slavio_timer_is_user(s)) { - s->reached = TIMER_REACHED; + s->reached = TIMER_REACHED; + if (!slavio_timer_is_user(s)) qemu_irq_raise(s->irq); - } } static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) @@ -141,7 +140,7 @@ if (slavio_timer_is_user(s)) { // read user timer MSW slavio_timer_get_out(s); - ret = s->counthigh; + ret = s->counthigh | s->reached; } else { // read limit // clear irq @@ -155,7 +154,7 @@ // of counter (user mode) slavio_timer_get_out(s); if (slavio_timer_is_user(s)) // read user timer LSW - ret = s->count & TIMER_COUNT_MASK32; + ret = s->count & TIMER_MAX_COUNT64; else // read limit ret = (s->count & TIMER_MAX_COUNT32) | s->reached; break; @@ -190,19 +189,25 @@ switch (saddr) { case TIMER_LIMIT: if (slavio_timer_is_user(s)) { + uint64_t count; + // set user counter MSW, reset counter - qemu_irq_lower(s->irq); s->limit = TIMER_MAX_COUNT64; - DPRINTF("processor %d user timer reset\n", s->slave_index); + s->counthigh = val & (TIMER_MAX_COUNT64 >> 32); + s->reached = 0; + count = ((uint64_t)s->counthigh << 32) | s->count; + DPRINTF("processor %d user timer set to %016llx\n", s->slave_index, + count); if (s->timer) - ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1); + ptimer_set_count(s->timer, LIMIT_TO_PERIODS(s->limit - count)); } else { // set limit, reset counter qemu_irq_lower(s->irq); s->limit = val & TIMER_MAX_COUNT32; if (s->timer) { if (s->limit == 0) /* free-run */ - ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); + ptimer_set_limit(s->timer, + LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); else ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1); } @@ -210,12 +215,17 @@ break; case TIMER_COUNTER: if (slavio_timer_is_user(s)) { + uint64_t count; + // set user counter LSW, reset counter - qemu_irq_lower(s->irq); s->limit = TIMER_MAX_COUNT64; - DPRINTF("processor %d user timer reset\n", s->slave_index); + s->count = val & TIMER_MAX_COUNT64; + s->reached = 0; + count = ((uint64_t)s->counthigh) << 32 | s->count; + DPRINTF("processor %d user timer set to %016llx\n", s->slave_index, + count); if (s->timer) - ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1); + ptimer_set_count(s->timer, LIMIT_TO_PERIODS(s->limit - count)); } else DPRINTF("not user timer\n"); break; @@ -224,7 +234,8 @@ s->limit = val & TIMER_MAX_COUNT32; if (s->timer) { if (s->limit == 0) /* free-run */ - ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0); + ptimer_set_limit(s->timer, + LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0); else ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 0); } @@ -250,22 +261,40 @@ unsigned int i; for (i = 0; i < s->num_slaves; i++) { - if (val & (1 << i)) { - qemu_irq_lower(s->slave[i]->irq); - s->slave[i]->limit = -1ULL; - } else { - ptimer_stop(s->slave[i]->timer); - } - if ((val & (1 << i)) != (s->slave_mode & (1 << i))) { - ptimer_stop(s->slave[i]->timer); - ptimer_set_limit(s->slave[i]->timer, - LIMIT_TO_PERIODS(s->slave[i]->limit), 1); - DPRINTF("processor %d timer changed\n", - s->slave[i]->slave_index); - ptimer_run(s->slave[i]->timer, 0); + unsigned int processor = 1 << i; + + // check for a change in timer mode for this processor + if ((val & processor) != (s->slave_mode & processor)) { + if (val & processor) { // counter -> user timer + qemu_irq_lower(s->slave[i]->irq); + // counters are always running + ptimer_stop(s->slave[i]->timer); + s->slave[i]->running = 0; + // user timer limit is always the same + s->slave[i]->limit = TIMER_MAX_COUNT64; + ptimer_set_limit(s->slave[i]->timer, + LIMIT_TO_PERIODS(s->slave[i]->limit), + 1); + // set this processors user timer bit in config + // register + s->slave_mode |= processor; + DPRINTF("processor %d changed from counter to user " + "timer\n", s->slave[i]->slave_index); + } else { // user timer -> counter + // stop the user timer if it is running + if (s->slave[i]->running) + ptimer_stop(s->slave[i]->timer); + // start the counter + ptimer_run(s->slave[i]->timer, 0); + s->slave[i]->running = 1; + // clear this processors user timer bit in config + // register + s->slave_mode &= ~processor; + DPRINTF("processor %d changed from user timer to " + "counter\n", s->slave[i]->slave_index); + } } } - s->slave_mode = val & ((1 << s->num_slaves) - 1); } else DPRINTF("not system timer\n"); break; @@ -337,7 +366,7 @@ static SLAVIO_TIMERState *slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, SLAVIO_TIMERState *master, - int slave_index) + uint32_t slave_index) { int slavio_timer_io_memory; SLAVIO_TIMERState *s; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/sm501.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/sm501.c --- qemu-0.9.1/hw/sm501.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/sm501.c 2008-11-05 20:24:35.000000000 +0000 @@ -0,0 +1,1129 @@ +/* + * QEMU SM501 Device + * + * Copyright (c) 2008 Shin-ichiro KAWASAKI + * + * 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 +#include +#include "hw.h" +#include "pc.h" +#include "console.h" + +/* + * Status: 2008/11/02 + * - Minimum implementation for Linux console : mmio regs and CRT layer. + * - Always updates full screen. + * + * TODO: + * - Panel support + * - Hardware cursor support + * - Touch panel support + * - USB support + * - UART support + * - Performance tuning + */ + +//#define DEBUG_SM501 +//#define DEBUG_BITBLT + +#ifdef DEBUG_SM501 +#define SM501_DPRINTF(fmt...) printf(fmt) +#else +#define SM501_DPRINTF(fmt...) do {} while(0) +#endif + + +#define MMIO_BASE_OFFSET 0x3e00000 + +/* SM501 register definitions taken from "linux/include/linux/sm501-regs.h" */ + +/* System Configuration area */ +/* System config base */ +#define SM501_SYS_CONFIG (0x000000) + +/* config 1 */ +#define SM501_SYSTEM_CONTROL (0x000000) + +#define SM501_SYSCTRL_PANEL_TRISTATE (1<<0) +#define SM501_SYSCTRL_MEM_TRISTATE (1<<1) +#define SM501_SYSCTRL_CRT_TRISTATE (1<<2) + +#define SM501_SYSCTRL_PCI_SLAVE_BURST_MASK (3<<4) +#define SM501_SYSCTRL_PCI_SLAVE_BURST_1 (0<<4) +#define SM501_SYSCTRL_PCI_SLAVE_BURST_2 (1<<4) +#define SM501_SYSCTRL_PCI_SLAVE_BURST_4 (2<<4) +#define SM501_SYSCTRL_PCI_SLAVE_BURST_8 (3<<4) + +#define SM501_SYSCTRL_PCI_CLOCK_RUN_EN (1<<6) +#define SM501_SYSCTRL_PCI_RETRY_DISABLE (1<<7) +#define SM501_SYSCTRL_PCI_SUBSYS_LOCK (1<<11) +#define SM501_SYSCTRL_PCI_BURST_READ_EN (1<<15) + +/* miscellaneous control */ + +#define SM501_MISC_CONTROL (0x000004) + +#define SM501_MISC_BUS_SH (0x0) +#define SM501_MISC_BUS_PCI (0x1) +#define SM501_MISC_BUS_XSCALE (0x2) +#define SM501_MISC_BUS_NEC (0x6) +#define SM501_MISC_BUS_MASK (0x7) + +#define SM501_MISC_VR_62MB (1<<3) +#define SM501_MISC_CDR_RESET (1<<7) +#define SM501_MISC_USB_LB (1<<8) +#define SM501_MISC_USB_SLAVE (1<<9) +#define SM501_MISC_BL_1 (1<<10) +#define SM501_MISC_MC (1<<11) +#define SM501_MISC_DAC_POWER (1<<12) +#define SM501_MISC_IRQ_INVERT (1<<16) +#define SM501_MISC_SH (1<<17) + +#define SM501_MISC_HOLD_EMPTY (0<<18) +#define SM501_MISC_HOLD_8 (1<<18) +#define SM501_MISC_HOLD_16 (2<<18) +#define SM501_MISC_HOLD_24 (3<<18) +#define SM501_MISC_HOLD_32 (4<<18) +#define SM501_MISC_HOLD_MASK (7<<18) + +#define SM501_MISC_FREQ_12 (1<<24) +#define SM501_MISC_PNL_24BIT (1<<25) +#define SM501_MISC_8051_LE (1<<26) + + + +#define SM501_GPIO31_0_CONTROL (0x000008) +#define SM501_GPIO63_32_CONTROL (0x00000C) +#define SM501_DRAM_CONTROL (0x000010) + +/* command list */ +#define SM501_ARBTRTN_CONTROL (0x000014) + +/* command list */ +#define SM501_COMMAND_LIST_STATUS (0x000024) + +/* interrupt debug */ +#define SM501_RAW_IRQ_STATUS (0x000028) +#define SM501_RAW_IRQ_CLEAR (0x000028) +#define SM501_IRQ_STATUS (0x00002C) +#define SM501_IRQ_MASK (0x000030) +#define SM501_DEBUG_CONTROL (0x000034) + +/* power management */ +#define SM501_POWERMODE_P2X_SRC (1<<29) +#define SM501_POWERMODE_V2X_SRC (1<<20) +#define SM501_POWERMODE_M_SRC (1<<12) +#define SM501_POWERMODE_M1_SRC (1<<4) + +#define SM501_CURRENT_GATE (0x000038) +#define SM501_CURRENT_CLOCK (0x00003C) +#define SM501_POWER_MODE_0_GATE (0x000040) +#define SM501_POWER_MODE_0_CLOCK (0x000044) +#define SM501_POWER_MODE_1_GATE (0x000048) +#define SM501_POWER_MODE_1_CLOCK (0x00004C) +#define SM501_SLEEP_MODE_GATE (0x000050) +#define SM501_POWER_MODE_CONTROL (0x000054) + +/* power gates for units within the 501 */ +#define SM501_GATE_HOST (0) +#define SM501_GATE_MEMORY (1) +#define SM501_GATE_DISPLAY (2) +#define SM501_GATE_2D_ENGINE (3) +#define SM501_GATE_CSC (4) +#define SM501_GATE_ZVPORT (5) +#define SM501_GATE_GPIO (6) +#define SM501_GATE_UART0 (7) +#define SM501_GATE_UART1 (8) +#define SM501_GATE_SSP (10) +#define SM501_GATE_USB_HOST (11) +#define SM501_GATE_USB_GADGET (12) +#define SM501_GATE_UCONTROLLER (17) +#define SM501_GATE_AC97 (18) + +/* panel clock */ +#define SM501_CLOCK_P2XCLK (24) +/* crt clock */ +#define SM501_CLOCK_V2XCLK (16) +/* main clock */ +#define SM501_CLOCK_MCLK (8) +/* SDRAM controller clock */ +#define SM501_CLOCK_M1XCLK (0) + +/* config 2 */ +#define SM501_PCI_MASTER_BASE (0x000058) +#define SM501_ENDIAN_CONTROL (0x00005C) +#define SM501_DEVICEID (0x000060) +/* 0x050100A0 */ + +#define SM501_DEVICEID_SM501 (0x05010000) +#define SM501_DEVICEID_IDMASK (0xffff0000) +#define SM501_DEVICEID_REVMASK (0x000000ff) + +#define SM501_PLLCLOCK_COUNT (0x000064) +#define SM501_MISC_TIMING (0x000068) +#define SM501_CURRENT_SDRAM_CLOCK (0x00006C) + +#define SM501_PROGRAMMABLE_PLL_CONTROL (0x000074) + +/* GPIO base */ +#define SM501_GPIO (0x010000) +#define SM501_GPIO_DATA_LOW (0x00) +#define SM501_GPIO_DATA_HIGH (0x04) +#define SM501_GPIO_DDR_LOW (0x08) +#define SM501_GPIO_DDR_HIGH (0x0C) +#define SM501_GPIO_IRQ_SETUP (0x10) +#define SM501_GPIO_IRQ_STATUS (0x14) +#define SM501_GPIO_IRQ_RESET (0x14) + +/* I2C controller base */ +#define SM501_I2C (0x010040) +#define SM501_I2C_BYTE_COUNT (0x00) +#define SM501_I2C_CONTROL (0x01) +#define SM501_I2C_STATUS (0x02) +#define SM501_I2C_RESET (0x02) +#define SM501_I2C_SLAVE_ADDRESS (0x03) +#define SM501_I2C_DATA (0x04) + +/* SSP base */ +#define SM501_SSP (0x020000) + +/* Uart 0 base */ +#define SM501_UART0 (0x030000) + +/* Uart 1 base */ +#define SM501_UART1 (0x030020) + +/* USB host port base */ +#define SM501_USB_HOST (0x040000) + +/* USB slave/gadget base */ +#define SM501_USB_GADGET (0x060000) + +/* USB slave/gadget data port base */ +#define SM501_USB_GADGET_DATA (0x070000) + +/* Display controller/video engine base */ +#define SM501_DC (0x080000) + +/* common defines for the SM501 address registers */ +#define SM501_ADDR_FLIP (1<<31) +#define SM501_ADDR_EXT (1<<27) +#define SM501_ADDR_CS1 (1<<26) +#define SM501_ADDR_MASK (0x3f << 26) + +#define SM501_FIFO_MASK (0x3 << 16) +#define SM501_FIFO_1 (0x0 << 16) +#define SM501_FIFO_3 (0x1 << 16) +#define SM501_FIFO_7 (0x2 << 16) +#define SM501_FIFO_11 (0x3 << 16) + +/* common registers for panel and the crt */ +#define SM501_OFF_DC_H_TOT (0x000) +#define SM501_OFF_DC_V_TOT (0x008) +#define SM501_OFF_DC_H_SYNC (0x004) +#define SM501_OFF_DC_V_SYNC (0x00C) + +#define SM501_DC_PANEL_CONTROL (0x000) + +#define SM501_DC_PANEL_CONTROL_FPEN (1<<27) +#define SM501_DC_PANEL_CONTROL_BIAS (1<<26) +#define SM501_DC_PANEL_CONTROL_DATA (1<<25) +#define SM501_DC_PANEL_CONTROL_VDD (1<<24) +#define SM501_DC_PANEL_CONTROL_DP (1<<23) + +#define SM501_DC_PANEL_CONTROL_TFT_888 (0<<21) +#define SM501_DC_PANEL_CONTROL_TFT_333 (1<<21) +#define SM501_DC_PANEL_CONTROL_TFT_444 (2<<21) + +#define SM501_DC_PANEL_CONTROL_DE (1<<20) + +#define SM501_DC_PANEL_CONTROL_LCD_TFT (0<<18) +#define SM501_DC_PANEL_CONTROL_LCD_STN8 (1<<18) +#define SM501_DC_PANEL_CONTROL_LCD_STN12 (2<<18) + +#define SM501_DC_PANEL_CONTROL_CP (1<<14) +#define SM501_DC_PANEL_CONTROL_VSP (1<<13) +#define SM501_DC_PANEL_CONTROL_HSP (1<<12) +#define SM501_DC_PANEL_CONTROL_CK (1<<9) +#define SM501_DC_PANEL_CONTROL_TE (1<<8) +#define SM501_DC_PANEL_CONTROL_VPD (1<<7) +#define SM501_DC_PANEL_CONTROL_VP (1<<6) +#define SM501_DC_PANEL_CONTROL_HPD (1<<5) +#define SM501_DC_PANEL_CONTROL_HP (1<<4) +#define SM501_DC_PANEL_CONTROL_GAMMA (1<<3) +#define SM501_DC_PANEL_CONTROL_EN (1<<2) + +#define SM501_DC_PANEL_CONTROL_8BPP (0<<0) +#define SM501_DC_PANEL_CONTROL_16BPP (1<<0) +#define SM501_DC_PANEL_CONTROL_32BPP (2<<0) + + +#define SM501_DC_PANEL_PANNING_CONTROL (0x004) +#define SM501_DC_PANEL_COLOR_KEY (0x008) +#define SM501_DC_PANEL_FB_ADDR (0x00C) +#define SM501_DC_PANEL_FB_OFFSET (0x010) +#define SM501_DC_PANEL_FB_WIDTH (0x014) +#define SM501_DC_PANEL_FB_HEIGHT (0x018) +#define SM501_DC_PANEL_TL_LOC (0x01C) +#define SM501_DC_PANEL_BR_LOC (0x020) +#define SM501_DC_PANEL_H_TOT (0x024) +#define SM501_DC_PANEL_H_SYNC (0x028) +#define SM501_DC_PANEL_V_TOT (0x02C) +#define SM501_DC_PANEL_V_SYNC (0x030) +#define SM501_DC_PANEL_CUR_LINE (0x034) + +#define SM501_DC_VIDEO_CONTROL (0x040) +#define SM501_DC_VIDEO_FB0_ADDR (0x044) +#define SM501_DC_VIDEO_FB_WIDTH (0x048) +#define SM501_DC_VIDEO_FB0_LAST_ADDR (0x04C) +#define SM501_DC_VIDEO_TL_LOC (0x050) +#define SM501_DC_VIDEO_BR_LOC (0x054) +#define SM501_DC_VIDEO_SCALE (0x058) +#define SM501_DC_VIDEO_INIT_SCALE (0x05C) +#define SM501_DC_VIDEO_YUV_CONSTANTS (0x060) +#define SM501_DC_VIDEO_FB1_ADDR (0x064) +#define SM501_DC_VIDEO_FB1_LAST_ADDR (0x068) + +#define SM501_DC_VIDEO_ALPHA_CONTROL (0x080) +#define SM501_DC_VIDEO_ALPHA_FB_ADDR (0x084) +#define SM501_DC_VIDEO_ALPHA_FB_OFFSET (0x088) +#define SM501_DC_VIDEO_ALPHA_FB_LAST_ADDR (0x08C) +#define SM501_DC_VIDEO_ALPHA_TL_LOC (0x090) +#define SM501_DC_VIDEO_ALPHA_BR_LOC (0x094) +#define SM501_DC_VIDEO_ALPHA_SCALE (0x098) +#define SM501_DC_VIDEO_ALPHA_INIT_SCALE (0x09C) +#define SM501_DC_VIDEO_ALPHA_CHROMA_KEY (0x0A0) +#define SM501_DC_VIDEO_ALPHA_COLOR_LOOKUP (0x0A4) + +#define SM501_DC_PANEL_HWC_BASE (0x0F0) +#define SM501_DC_PANEL_HWC_ADDR (0x0F0) +#define SM501_DC_PANEL_HWC_LOC (0x0F4) +#define SM501_DC_PANEL_HWC_COLOR_1_2 (0x0F8) +#define SM501_DC_PANEL_HWC_COLOR_3 (0x0FC) + +#define SM501_HWC_EN (1<<31) + +#define SM501_OFF_HWC_ADDR (0x00) +#define SM501_OFF_HWC_LOC (0x04) +#define SM501_OFF_HWC_COLOR_1_2 (0x08) +#define SM501_OFF_HWC_COLOR_3 (0x0C) + +#define SM501_DC_ALPHA_CONTROL (0x100) +#define SM501_DC_ALPHA_FB_ADDR (0x104) +#define SM501_DC_ALPHA_FB_OFFSET (0x108) +#define SM501_DC_ALPHA_TL_LOC (0x10C) +#define SM501_DC_ALPHA_BR_LOC (0x110) +#define SM501_DC_ALPHA_CHROMA_KEY (0x114) +#define SM501_DC_ALPHA_COLOR_LOOKUP (0x118) + +#define SM501_DC_CRT_CONTROL (0x200) + +#define SM501_DC_CRT_CONTROL_TVP (1<<15) +#define SM501_DC_CRT_CONTROL_CP (1<<14) +#define SM501_DC_CRT_CONTROL_VSP (1<<13) +#define SM501_DC_CRT_CONTROL_HSP (1<<12) +#define SM501_DC_CRT_CONTROL_VS (1<<11) +#define SM501_DC_CRT_CONTROL_BLANK (1<<10) +#define SM501_DC_CRT_CONTROL_SEL (1<<9) +#define SM501_DC_CRT_CONTROL_TE (1<<8) +#define SM501_DC_CRT_CONTROL_PIXEL_MASK (0xF << 4) +#define SM501_DC_CRT_CONTROL_GAMMA (1<<3) +#define SM501_DC_CRT_CONTROL_ENABLE (1<<2) + +#define SM501_DC_CRT_CONTROL_8BPP (0<<0) +#define SM501_DC_CRT_CONTROL_16BPP (1<<0) +#define SM501_DC_CRT_CONTROL_32BPP (2<<0) + +#define SM501_DC_CRT_FB_ADDR (0x204) +#define SM501_DC_CRT_FB_OFFSET (0x208) +#define SM501_DC_CRT_H_TOT (0x20C) +#define SM501_DC_CRT_H_SYNC (0x210) +#define SM501_DC_CRT_V_TOT (0x214) +#define SM501_DC_CRT_V_SYNC (0x218) +#define SM501_DC_CRT_SIGNATURE_ANALYZER (0x21C) +#define SM501_DC_CRT_CUR_LINE (0x220) +#define SM501_DC_CRT_MONITOR_DETECT (0x224) + +#define SM501_DC_CRT_HWC_BASE (0x230) +#define SM501_DC_CRT_HWC_ADDR (0x230) +#define SM501_DC_CRT_HWC_LOC (0x234) +#define SM501_DC_CRT_HWC_COLOR_1_2 (0x238) +#define SM501_DC_CRT_HWC_COLOR_3 (0x23C) + +#define SM501_DC_PANEL_PALETTE (0x400) + +#define SM501_DC_VIDEO_PALETTE (0x800) + +#define SM501_DC_CRT_PALETTE (0xC00) + +/* Zoom Video port base */ +#define SM501_ZVPORT (0x090000) + +/* AC97/I2S base */ +#define SM501_AC97 (0x0A0000) + +/* 8051 micro controller base */ +#define SM501_UCONTROLLER (0x0B0000) + +/* 8051 micro controller SRAM base */ +#define SM501_UCONTROLLER_SRAM (0x0C0000) + +/* DMA base */ +#define SM501_DMA (0x0D0000) + +/* 2d engine base */ +#define SM501_2D_ENGINE (0x100000) +#define SM501_2D_SOURCE (0x00) +#define SM501_2D_DESTINATION (0x04) +#define SM501_2D_DIMENSION (0x08) +#define SM501_2D_CONTROL (0x0C) +#define SM501_2D_PITCH (0x10) +#define SM501_2D_FOREGROUND (0x14) +#define SM501_2D_BACKGROUND (0x18) +#define SM501_2D_STRETCH (0x1C) +#define SM501_2D_COLOR_COMPARE (0x20) +#define SM501_2D_COLOR_COMPARE_MASK (0x24) +#define SM501_2D_MASK (0x28) +#define SM501_2D_CLIP_TL (0x2C) +#define SM501_2D_CLIP_BR (0x30) +#define SM501_2D_MONO_PATTERN_LOW (0x34) +#define SM501_2D_MONO_PATTERN_HIGH (0x38) +#define SM501_2D_WINDOW_WIDTH (0x3C) +#define SM501_2D_SOURCE_BASE (0x40) +#define SM501_2D_DESTINATION_BASE (0x44) +#define SM501_2D_ALPHA (0x48) +#define SM501_2D_WRAP (0x4C) +#define SM501_2D_STATUS (0x50) + +#define SM501_CSC_Y_SOURCE_BASE (0xC8) +#define SM501_CSC_CONSTANTS (0xCC) +#define SM501_CSC_Y_SOURCE_X (0xD0) +#define SM501_CSC_Y_SOURCE_Y (0xD4) +#define SM501_CSC_U_SOURCE_BASE (0xD8) +#define SM501_CSC_V_SOURCE_BASE (0xDC) +#define SM501_CSC_SOURCE_DIMENSION (0xE0) +#define SM501_CSC_SOURCE_PITCH (0xE4) +#define SM501_CSC_DESTINATION (0xE8) +#define SM501_CSC_DESTINATION_DIMENSION (0xEC) +#define SM501_CSC_DESTINATION_PITCH (0xF0) +#define SM501_CSC_SCALE_FACTOR (0xF4) +#define SM501_CSC_DESTINATION_BASE (0xF8) +#define SM501_CSC_CONTROL (0xFC) + +/* 2d engine data port base */ +#define SM501_2D_ENGINE_DATA (0x110000) + +/* end of register definitions */ + + +/* SM501 local memory size taken from "linux/drivers/mfd/sm501.c" */ +static const uint32_t sm501_mem_local_size[] = { + [0] = 4*1024*1024, + [1] = 8*1024*1024, + [2] = 16*1024*1024, + [3] = 32*1024*1024, + [4] = 64*1024*1024, + [5] = 2*1024*1024, +}; +#define get_local_mem_size(s) sm501_mem_local_size[(s)->local_mem_size_index] + +typedef struct SM501State { + /* graphic console status */ + DisplayState *ds; + QEMUConsole *console; + + /* status & internal resources */ + target_phys_addr_t base; + uint32_t local_mem_size_index; + uint8_t * local_mem; + uint32_t last_width; + uint32_t last_height; + + /* mmio registers */ + uint32_t system_control; + uint32_t misc_control; + uint32_t gpio_31_0_control; + uint32_t gpio_63_32_control; + uint32_t dram_control; + uint32_t irq_mask; + uint32_t misc_timing; + uint32_t power_mode_control; + + uint32_t uart0_ier; + uint32_t uart0_lcr; + uint32_t uart0_mcr; + uint32_t uart0_scr; + + uint8_t dc_palette[0x400 * 3]; + + uint32_t dc_panel_control; + uint32_t dc_panel_panning_control; + uint32_t dc_panel_fb_addr; + uint32_t dc_panel_fb_offset; + uint32_t dc_panel_fb_width; + uint32_t dc_panel_fb_height; + uint32_t dc_panel_tl_location; + uint32_t dc_panel_br_location; + uint32_t dc_panel_h_total; + uint32_t dc_panel_h_sync; + uint32_t dc_panel_v_total; + uint32_t dc_panel_v_sync; + + uint32_t dc_panel_hwc_addr; + uint32_t dc_panel_hwc_location; + uint32_t dc_panel_hwc_color_1_2; + uint32_t dc_panel_hwc_color_3; + + uint32_t dc_crt_control; + uint32_t dc_crt_fb_addr; + uint32_t dc_crt_fb_offset; + uint32_t dc_crt_h_total; + uint32_t dc_crt_h_sync; + uint32_t dc_crt_v_total; + uint32_t dc_crt_v_sync; + + uint32_t dc_crt_hwc_addr; + uint32_t dc_crt_hwc_location; + uint32_t dc_crt_hwc_color_1_2; + uint32_t dc_crt_hwc_color_3; + +} SM501State; + +static uint32_t get_local_mem_size_index(uint32_t size) +{ + uint32_t norm_size = 0; + int i, index = 0; + + for (i = 0; i < sizeof(sm501_mem_local_size)/sizeof(uint32_t); i++) { + uint32_t new_size = sm501_mem_local_size[i]; + if (new_size >= size) { + if (norm_size == 0 || norm_size > new_size) { + norm_size = new_size; + index = i; + } + } + } + + return index; +} + +static uint32_t sm501_system_config_read(void *opaque, target_phys_addr_t addr) +{ + SM501State * s = (SM501State *)opaque; + uint32_t offset = addr - (s->base + MMIO_BASE_OFFSET); + uint32_t ret = 0; + SM501_DPRINTF("sm501 system config regs : read addr=%x, offset=%x\n", + addr, offset); + + switch(offset) { + case SM501_SYSTEM_CONTROL: + ret = s->system_control; + break; + case SM501_MISC_CONTROL: + ret = s->misc_control; + break; + case SM501_GPIO31_0_CONTROL: + ret = s->gpio_31_0_control; + break; + case SM501_GPIO63_32_CONTROL: + ret = s->gpio_63_32_control; + break; + case SM501_DEVICEID: + ret = 0x050100A0; + break; + case SM501_DRAM_CONTROL: + ret = (s->dram_control & 0x07F107C0) | s->local_mem_size_index << 13; + break; + case SM501_IRQ_MASK: + ret = s->irq_mask; + break; + case SM501_MISC_TIMING: + /* TODO : simulate gate control */ + ret = s->misc_timing; + break; + case SM501_CURRENT_GATE: + /* TODO : simulate gate control */ + ret = 0x00021807; + break; + case SM501_CURRENT_CLOCK: + ret = 0x2A1A0A09; + break; + case SM501_POWER_MODE_CONTROL: + ret = s->power_mode_control; + break; + + default: + printf("sm501 system config : not implemented register read." + " addr=%x, offset=%x\n", addr, offset); + assert(0); + } + + return ret; +} + +static void sm501_system_config_write(void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + SM501State * s = (SM501State *)opaque; + uint32_t offset = addr - (s->base + MMIO_BASE_OFFSET); + SM501_DPRINTF("sm501 system config regs : write addr=%x, ofs=%x, val=%x\n", + addr, offset, value); + + switch(offset) { + case SM501_SYSTEM_CONTROL: + s->system_control = value & 0xE300B8F7; + break; + case SM501_MISC_CONTROL: + s->misc_control = value & 0xFF7FFF20; + break; + case SM501_GPIO31_0_CONTROL: + s->gpio_31_0_control = value; + break; + case SM501_GPIO63_32_CONTROL: + s->gpio_63_32_control = value; + break; + case SM501_DRAM_CONTROL: + s->local_mem_size_index = (value >> 13) & 0x7; + /* rODO : check validity of size change */ + s->dram_control |= value & 0x7FFFFFC3; + break; + case SM501_IRQ_MASK: + s->irq_mask = value; + break; + case SM501_MISC_TIMING: + s->misc_timing = value & 0xF31F1FFF; + break; + case SM501_POWER_MODE_0_GATE: + case SM501_POWER_MODE_1_GATE: + case SM501_POWER_MODE_0_CLOCK: + case SM501_POWER_MODE_1_CLOCK: + /* TODO : simulate gate & clock control */ + break; + case SM501_POWER_MODE_CONTROL: + s->power_mode_control = value & 0x00000003; + break; + + default: + printf("sm501 system config : not implemented register write." + " addr=%x, val=%x\n", addr, value); + assert(0); + } +} + +static CPUReadMemoryFunc *sm501_system_config_readfn[] = { + NULL, + NULL, + &sm501_system_config_read, +}; + +static CPUWriteMemoryFunc *sm501_system_config_writefn[] = { + NULL, + NULL, + &sm501_system_config_write, +}; + +static uint32_t sm501_disp_ctrl_read(void *opaque, + target_phys_addr_t addr) +{ + SM501State * s = (SM501State *)opaque; + uint32_t offset = addr - (s->base + MMIO_BASE_OFFSET + SM501_DC); + uint32_t ret = 0; + SM501_DPRINTF("sm501 disp ctrl regs : read addr=%x, offset=%x\n", + addr, offset); + + switch(offset) { + + case SM501_DC_PANEL_CONTROL: + ret = s->dc_panel_control; + break; + case SM501_DC_PANEL_PANNING_CONTROL: + ret = s->dc_panel_panning_control; + break; + case SM501_DC_PANEL_FB_ADDR: + ret = s->dc_panel_fb_addr; + break; + case SM501_DC_PANEL_FB_OFFSET: + ret = s->dc_panel_fb_offset; + break; + case SM501_DC_PANEL_FB_WIDTH: + ret = s->dc_panel_fb_width; + break; + case SM501_DC_PANEL_FB_HEIGHT: + ret = s->dc_panel_fb_height; + break; + case SM501_DC_PANEL_TL_LOC: + ret = s->dc_panel_tl_location; + break; + case SM501_DC_PANEL_BR_LOC: + ret = s->dc_panel_br_location; + break; + + case SM501_DC_PANEL_H_TOT: + ret = s->dc_panel_h_total; + break; + case SM501_DC_PANEL_H_SYNC: + ret = s->dc_panel_h_sync; + break; + case SM501_DC_PANEL_V_TOT: + ret = s->dc_panel_v_total; + break; + case SM501_DC_PANEL_V_SYNC: + ret = s->dc_panel_v_sync; + break; + + case SM501_DC_CRT_CONTROL: + ret = s->dc_crt_control; + break; + case SM501_DC_CRT_FB_ADDR: + ret = s->dc_crt_fb_addr; + break; + case SM501_DC_CRT_FB_OFFSET: + ret = s->dc_crt_fb_offset; + break; + case SM501_DC_CRT_H_TOT: + ret = s->dc_crt_h_total; + break; + case SM501_DC_CRT_H_SYNC: + ret = s->dc_crt_h_sync; + break; + case SM501_DC_CRT_V_TOT: + ret = s->dc_crt_v_total; + break; + case SM501_DC_CRT_V_SYNC: + ret = s->dc_crt_v_sync; + break; + + case SM501_DC_CRT_HWC_ADDR: + ret = s->dc_crt_hwc_addr; + break; + case SM501_DC_CRT_HWC_LOC: + ret = s->dc_crt_hwc_addr; + break; + case SM501_DC_CRT_HWC_COLOR_1_2: + ret = s->dc_crt_hwc_addr; + break; + case SM501_DC_CRT_HWC_COLOR_3: + ret = s->dc_crt_hwc_addr; + break; + + default: + printf("sm501 disp ctrl : not implemented register read." + " addr=%x, offset=%x\n", addr, offset); + assert(0); + } + + return ret; +} + +static void sm501_disp_ctrl_write(void *opaque, + target_phys_addr_t addr, + uint32_t value) +{ + SM501State * s = (SM501State *)opaque; + uint32_t offset = addr - (s->base + MMIO_BASE_OFFSET + SM501_DC); + SM501_DPRINTF("sm501 disp ctrl regs : write addr=%x, ofs=%x, val=%x\n", + addr, offset, value); + + switch(offset) { + case SM501_DC_PANEL_CONTROL: + s->dc_panel_control = value & 0x0FFF73FF; + break; + case SM501_DC_PANEL_PANNING_CONTROL: + s->dc_panel_panning_control = value & 0xFF3FFF3F; + break; + case SM501_DC_PANEL_FB_ADDR: + s->dc_panel_fb_addr = value & 0x8FFFFFF0; + break; + case SM501_DC_PANEL_FB_OFFSET: + s->dc_panel_fb_offset = value & 0x3FF03FF0; + break; + case SM501_DC_PANEL_FB_WIDTH: + s->dc_panel_fb_width = value & 0x0FFF0FFF; + break; + case SM501_DC_PANEL_FB_HEIGHT: + s->dc_panel_fb_height = value & 0x0FFF0FFF; + break; + case SM501_DC_PANEL_TL_LOC: + s->dc_panel_tl_location = value & 0x07FF07FF; + break; + case SM501_DC_PANEL_BR_LOC: + s->dc_panel_br_location = value & 0x07FF07FF; + break; + + case SM501_DC_PANEL_H_TOT: + s->dc_panel_h_total = value & 0x0FFF0FFF; + break; + case SM501_DC_PANEL_H_SYNC: + s->dc_panel_h_sync = value & 0x00FF0FFF; + break; + case SM501_DC_PANEL_V_TOT: + s->dc_panel_v_total = value & 0x0FFF0FFF; + break; + case SM501_DC_PANEL_V_SYNC: + s->dc_panel_v_sync = value & 0x003F0FFF; + break; + + case SM501_DC_PANEL_HWC_ADDR: + s->dc_panel_hwc_addr = value & 0x8FFFFFF0; + break; + case SM501_DC_PANEL_HWC_LOC: + s->dc_panel_hwc_addr = value & 0x0FFF0FFF; + break; + case SM501_DC_PANEL_HWC_COLOR_1_2: + s->dc_panel_hwc_addr = value; + break; + case SM501_DC_PANEL_HWC_COLOR_3: + s->dc_panel_hwc_addr = value & 0x0000FFFF; + break; + + case SM501_DC_CRT_CONTROL: + s->dc_crt_control = value & 0x0003FFFF; + break; + case SM501_DC_CRT_FB_ADDR: + s->dc_crt_fb_addr = value & 0x8FFFFFF0; + break; + case SM501_DC_CRT_FB_OFFSET: + s->dc_crt_fb_offset = value & 0x3FF03FF0; + break; + case SM501_DC_CRT_H_TOT: + s->dc_crt_h_total = value & 0x0FFF0FFF; + break; + case SM501_DC_CRT_H_SYNC: + s->dc_crt_h_sync = value & 0x00FF0FFF; + break; + case SM501_DC_CRT_V_TOT: + s->dc_crt_v_total = value & 0x0FFF0FFF; + break; + case SM501_DC_CRT_V_SYNC: + s->dc_crt_v_sync = value & 0x003F0FFF; + break; + + case SM501_DC_CRT_HWC_ADDR: + s->dc_crt_hwc_addr = value & 0x8FFFFFF0; + break; + case SM501_DC_CRT_HWC_LOC: + s->dc_crt_hwc_addr = value & 0x0FFF0FFF; + break; + case SM501_DC_CRT_HWC_COLOR_1_2: + s->dc_crt_hwc_addr = value; + break; + case SM501_DC_CRT_HWC_COLOR_3: + s->dc_crt_hwc_addr = value & 0x0000FFFF; + break; + + default: + printf("sm501 disp ctrl : not implemented register write." + " addr=%x, val=%x\n", addr, value); + assert(0); + } +} + +static CPUReadMemoryFunc *sm501_disp_ctrl_readfn[] = { + NULL, + NULL, + &sm501_disp_ctrl_read, +}; + +static CPUWriteMemoryFunc *sm501_disp_ctrl_writefn[] = { + NULL, + NULL, + &sm501_disp_ctrl_write, +}; + +static uint32_t sm501_palette_read(void *opaque, target_phys_addr_t addr) +{ + SM501State * s = (SM501State *)opaque; + uint32_t offset = addr - (s->base + MMIO_BASE_OFFSET + + SM501_DC + SM501_DC_PANEL_PALETTE); + SM501_DPRINTF("sm501 palette read addr=%x, offset=%x\n", addr, offset); + + /* TODO : consider BYTE/WORD access */ + /* TODO : consider endian */ + + assert(0 <= offset && offset < 0x400 * 3); + return *(uint32_t*)&s->dc_palette[offset]; +} + +static void sm501_palette_write(void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + SM501State * s = (SM501State *)opaque; + uint32_t offset = addr - (s->base + MMIO_BASE_OFFSET + + SM501_DC + SM501_DC_PANEL_PALETTE); + SM501_DPRINTF("sm501 palette write addr=%x, ofs=%x, val=%x\n", + addr, offset, value); + + /* TODO : consider BYTE/WORD access */ + /* TODO : consider endian */ + + assert(0 <= offset && offset < 0x400 * 3); + *(uint32_t*)&s->dc_palette[offset] = value; +} + +static CPUReadMemoryFunc *sm501_palette_readfn[] = { + &sm501_palette_read, + &sm501_palette_read, + &sm501_palette_read, +}; + +static CPUWriteMemoryFunc *sm501_palette_writefn[] = { + &sm501_palette_write, + &sm501_palette_write, + &sm501_palette_write, +}; + + +/* draw line functions for all console modes */ + +#include "pixel_ops.h" + +typedef void draw_line_func(uint8_t *d, const uint8_t *s, + int width, const uint32_t *pal); + +#define DEPTH 8 +#include "sm501_template.h" + +#define DEPTH 15 +#include "sm501_template.h" + +#define BGR_FORMAT +#define DEPTH 15 +#include "sm501_template.h" + +#define DEPTH 16 +#include "sm501_template.h" + +#define BGR_FORMAT +#define DEPTH 16 +#include "sm501_template.h" + +#define DEPTH 32 +#include "sm501_template.h" + +#define BGR_FORMAT +#define DEPTH 32 +#include "sm501_template.h" + +static draw_line_func * draw_line8_funcs[] = { + draw_line8_8, + draw_line8_15, + draw_line8_16, + draw_line8_32, + draw_line8_32bgr, + draw_line8_15bgr, + draw_line8_16bgr, +}; + +static draw_line_func * draw_line16_funcs[] = { + draw_line16_8, + draw_line16_15, + draw_line16_16, + draw_line16_32, + draw_line16_32bgr, + draw_line16_15bgr, + draw_line16_16bgr, +}; + +static draw_line_func * draw_line32_funcs[] = { + draw_line32_8, + draw_line32_15, + draw_line32_16, + draw_line32_32, + draw_line32_32bgr, + draw_line32_15bgr, + draw_line32_16bgr, +}; + +static inline int get_depth_index(DisplayState *s) +{ + switch(s->depth) { + default: + case 8: + return 0; + case 15: + if (s->bgr) + return 5; + else + return 1; + case 16: + if (s->bgr) + return 6; + else + return 2; + case 32: + if (s->bgr) + return 4; + else + return 3; + } +} + +static void sm501_draw_crt(SM501State * s) +{ + int y; + int width = (s->dc_crt_h_total & 0x00000FFF) + 1; + int height = (s->dc_crt_v_total & 0x00000FFF) + 1; + + uint8_t * src = s->local_mem; + int src_bpp = 0; + int dst_bpp = s->ds->depth / 8 + (s->ds->depth % 8 ? 1 : 0); + uint32_t * palette = (uint32_t *)&s->dc_palette[SM501_DC_CRT_PALETTE + - SM501_DC_PANEL_PALETTE]; + int ds_depth_index = get_depth_index(s->ds); + draw_line_func * draw_line = NULL; + int full_update = 0; + int y_start = -1; + int page_min = 0x7fffffff; + int page_max = -1; + + /* choose draw_line function */ + switch (s->dc_crt_control & 3) { + case SM501_DC_CRT_CONTROL_8BPP: + src_bpp = 1; + draw_line = draw_line8_funcs[ds_depth_index]; + break; + case SM501_DC_CRT_CONTROL_16BPP: + src_bpp = 2; + draw_line = draw_line16_funcs[ds_depth_index]; + break; + case SM501_DC_CRT_CONTROL_32BPP: + src_bpp = 4; + draw_line = draw_line32_funcs[ds_depth_index]; + break; + default: + printf("sm501 draw crt : invalid DC_CRT_CONTROL=%x.\n", + s->dc_crt_control); + assert(0); + break; + } + + /* adjust console size */ + if (s->last_width != width || s->last_height != height) { + qemu_console_resize(s->console, width, height); + s->last_width = width; + s->last_height = height; + full_update = 1; + } + + /* draw each line according to conditions */ + for (y = 0; y < height; y++) { + int update = full_update; + uint8_t * line_end = &src[width * src_bpp - 1]; + int page0 = (src - phys_ram_base) & TARGET_PAGE_MASK; + int page1 = (line_end - phys_ram_base) & TARGET_PAGE_MASK; + int page; + + /* check dirty flags for each line */ + for (page = page0; page <= page1; page += TARGET_PAGE_SIZE) + if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) + update = 1; + + /* draw line and change status */ + if (update) { + draw_line(&s->ds->data[y * width * dst_bpp], src, width, palette); + if (y_start < 0) + y_start = y; + if (page0 < page_min) + page_min = page0; + if (page1 > page_max) + page_max = page1; + } else { + if (y_start >= 0) { + /* flush to display */ + dpy_update(s->ds, 0, y_start, width, y - y_start); + y_start = -1; + } + } + + src += width * src_bpp; + } + + /* complete flush to display */ + if (y_start >= 0) + dpy_update(s->ds, 0, y_start, width, y - y_start); + + /* clear dirty flags */ + if (page_max != -1) + cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE, + VGA_DIRTY_FLAG); +} + +static void sm501_update_display(void *opaque) +{ + SM501State * s = (SM501State *)opaque; + + if (s->dc_crt_control & SM501_DC_CRT_CONTROL_ENABLE) + sm501_draw_crt(s); +} + +void sm501_init(DisplayState *ds, uint32_t base, unsigned long local_mem_base, + uint32_t local_mem_bytes, CharDriverState *chr) +{ + SM501State * s; + int sm501_system_config_index; + int sm501_disp_ctrl_index; + int sm501_palette_index; + + /* allocate management data region */ + s = (SM501State *)qemu_mallocz(sizeof(SM501State)); + s->base = base; + s->local_mem_size_index + = get_local_mem_size_index(local_mem_bytes); + SM501_DPRINTF("local mem size=%x. index=%d\n", get_local_mem_size(s), + s->local_mem_size_index); + s->system_control = 0x00100000; + s->misc_control = 0x00001000; /* assumes SH, active=low */ + s->dc_panel_control = 0x00010000; + s->dc_crt_control = 0x00010000; + s->ds = ds; + + /* allocate local memory */ + s->local_mem = (uint8 *)phys_ram_base + local_mem_base; + cpu_register_physical_memory(base, local_mem_bytes, local_mem_base); + + /* map mmio */ + sm501_system_config_index + = cpu_register_io_memory(0, sm501_system_config_readfn, + sm501_system_config_writefn, s); + cpu_register_physical_memory(base + MMIO_BASE_OFFSET, + 0x6c, sm501_system_config_index); + sm501_disp_ctrl_index = cpu_register_io_memory(0, sm501_disp_ctrl_readfn, + sm501_disp_ctrl_writefn, s); + cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_DC, + 0x400, sm501_disp_ctrl_index); + + sm501_palette_index = cpu_register_io_memory(0, sm501_palette_readfn, + sm501_palette_writefn, s); + cpu_register_physical_memory(base + MMIO_BASE_OFFSET + + SM501_DC + SM501_DC_PANEL_PALETTE, + 0x400 * 3, sm501_palette_index); + + /* bridge to serial emulation module */ + if (chr) + serial_mm_init(base + MMIO_BASE_OFFSET + SM501_UART0, 2, + 0, /* TODO : chain irq to IRL */ + 115200, chr, 1); + + /* create qemu graphic console */ + s->console = graphic_console_init(s->ds, sm501_update_display, NULL, + NULL, NULL, s); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/sm501_template.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/sm501_template.h --- qemu-0.9.1/hw/sm501_template.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/sm501_template.h 2008-11-05 20:24:35.000000000 +0000 @@ -0,0 +1,104 @@ +/* + * Pixel drawing function templates for QEMU SM501 Device + * + * Copyright (c) 2008 Shin-ichiro KAWASAKI + * + * 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. + */ + +#if DEPTH == 8 +#define BPP 1 +#define PIXEL_TYPE uint8_t +#elif DEPTH == 15 || DEPTH == 16 +#define BPP 2 +#define PIXEL_TYPE uint16_t +#elif DEPTH == 32 +#define BPP 4 +#define PIXEL_TYPE uint32_t +#else +#error unsupport depth +#endif + +#ifdef BGR_FORMAT +#define PIXEL_NAME glue(DEPTH, bgr) +#else +#define PIXEL_NAME DEPTH +#endif /* BGR_FORMAT */ + + +static void glue(draw_line8_, PIXEL_NAME)( + uint8_t *d, const uint8_t *s, int width, const uint32_t *pal) +{ + uint8_t v, r, g, b; + do { + v = ldub_raw(s); + r = (pal[v] >> 16) & 0xff; + g = (pal[v] >> 8) & 0xff; + b = (pal[v] >> 0) & 0xff; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); + s ++; + d += BPP; + } while (-- width != 0); +} + +static void glue(draw_line16_, PIXEL_NAME)( + uint8_t *d, const uint8_t *s, int width, const uint32_t *pal) +{ + uint16_t rgb565; + uint8_t r, g, b; + + do { + rgb565 = lduw_raw(s); + r = ((rgb565 >> 11) & 0x1f) << 3; + g = ((rgb565 >> 5) & 0x3f) << 2; + b = ((rgb565 >> 0) & 0x1f) << 3; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); + s += 2; + d += BPP; + } while (-- width != 0); +} + +static void glue(draw_line32_, PIXEL_NAME)( + uint8_t *d, const uint8_t *s, int width, const uint32_t *pal) +{ + uint8_t r, g, b; + + do { + ldub_raw(s); +#if defined(TARGET_WORDS_BIGENDIAN) + r = s[1]; + g = s[2]; + b = s[3]; +#else + b = s[0]; + g = s[1]; + r = s[2]; +#endif + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); + s += 4; + d += BPP; + } while (-- width != 0); +} + +#undef DEPTH +#undef BPP +#undef PIXEL_TYPE +#undef PIXEL_NAME +#undef BGR_FORMAT + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/smbus_eeprom.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/smbus_eeprom.c --- qemu-0.9.1/hw/smbus_eeprom.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/smbus_eeprom.c 2008-06-02 02:48:27.000000000 +0100 @@ -37,7 +37,7 @@ static void eeprom_quick_cmd(SMBusDevice *dev, uint8_t read) { #ifdef DEBUG - printf("eeprom_quick_cmd: addr=0x%02x read=%d\n", dev->addr, read); + printf("eeprom_quick_cmd: addr=0x%02x read=%d\n", dev->i2c.address, read); #endif } @@ -45,7 +45,8 @@ { SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; #ifdef DEBUG - printf("eeprom_send_byte: addr=0x%02x val=0x%02x\n", dev->addr, val); + printf("eeprom_send_byte: addr=0x%02x val=0x%02x\n", + dev->i2c.address, val); #endif eeprom->offset = val; } @@ -55,7 +56,8 @@ SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; uint8_t val = eeprom->data[eeprom->offset++]; #ifdef DEBUG - printf("eeprom_receive_byte: addr=0x%02x val=0x%02x\n", dev->addr, val); + printf("eeprom_receive_byte: addr=0x%02x val=0x%02x\n", + dev->i2c.address, val); #endif return val; } @@ -65,8 +67,8 @@ SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; int n; #ifdef DEBUG - printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n", dev->addr, - cmd, buf[0]); + printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n", + dev->i2c.address, cmd, buf[0]); #endif /* An page write operation is not a valid SMBus command. It is a block write without a length byte. Fortunately we diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/soc_dma.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/soc_dma.c --- qemu-0.9.1/hw/soc_dma.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/soc_dma.c 2008-10-26 13:43:07.000000000 +0000 @@ -0,0 +1,367 @@ +/* + * On-chip DMA controller framework. + * + * Copyright (C) 2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include "qemu-common.h" +#include "qemu-timer.h" +#include "soc_dma.h" + +static void transfer_mem2mem(struct soc_dma_ch_s *ch) +{ + memcpy(ch->paddr[0], ch->paddr[1], ch->bytes); + ch->paddr[0] += ch->bytes; + ch->paddr[1] += ch->bytes; +} + +static void transfer_mem2fifo(struct soc_dma_ch_s *ch) +{ + ch->io_fn[1](ch->io_opaque[1], ch->paddr[0], ch->bytes); + ch->paddr[0] += ch->bytes; +} + +static void transfer_fifo2mem(struct soc_dma_ch_s *ch) +{ + ch->io_fn[0](ch->io_opaque[0], ch->paddr[1], ch->bytes); + ch->paddr[1] += ch->bytes; +} + +/* This is further optimisable but isn't very important because often + * DMA peripherals forbid this kind of transfers and even when they don't, + * oprating systems may not need to use them. */ +static void *fifo_buf; +static int fifo_size; +static void transfer_fifo2fifo(struct soc_dma_ch_s *ch) +{ + if (ch->bytes > fifo_size) + fifo_buf = qemu_realloc(fifo_buf, fifo_size = ch->bytes); + + /* Implement as transfer_fifo2linear + transfer_linear2fifo. */ + ch->io_fn[0](ch->io_opaque[0], fifo_buf, ch->bytes); + ch->io_fn[1](ch->io_opaque[1], fifo_buf, ch->bytes); +} + +struct dma_s { + struct soc_dma_s soc; + int chnum; + uint64_t ch_enable_mask; + int64_t channel_freq; + int enabled_count; + + struct memmap_entry_s { + enum soc_dma_port_type type; + target_phys_addr_t addr; + union { + struct { + void *opaque; + soc_dma_io_t fn; + int out; + } fifo; + struct { + void *base; + size_t size; + } mem; + } u; + } *memmap; + int memmap_size; + + struct soc_dma_ch_s ch[0]; +}; + +static void soc_dma_ch_schedule(struct soc_dma_ch_s *ch, int delay_bytes) +{ + int64_t now = qemu_get_clock(vm_clock); + struct dma_s *dma = (struct dma_s *) ch->dma; + + qemu_mod_timer(ch->timer, now + delay_bytes / dma->channel_freq); +} + +static void soc_dma_ch_run(void *opaque) +{ + struct soc_dma_ch_s *ch = (struct soc_dma_ch_s *) opaque; + + ch->running = 1; + ch->dma->setup_fn(ch); + ch->transfer_fn(ch); + ch->running = 0; + + if (ch->enable) + soc_dma_ch_schedule(ch, ch->bytes); + ch->bytes = 0; +} + +static inline struct memmap_entry_s *soc_dma_lookup(struct dma_s *dma, + target_phys_addr_t addr) +{ + struct memmap_entry_s *lo; + int hi; + + lo = dma->memmap; + hi = dma->memmap_size; + + while (hi > 1) { + hi /= 2; + if (lo[hi].addr <= addr) + lo += hi; + } + + return lo; +} + +static inline enum soc_dma_port_type soc_dma_ch_update_type( + struct soc_dma_ch_s *ch, int port) +{ + struct dma_s *dma = (struct dma_s *) ch->dma; + struct memmap_entry_s *entry = soc_dma_lookup(dma, ch->vaddr[port]); + + if (entry->type == soc_dma_port_fifo) { + while (entry < dma->memmap + dma->memmap_size && + entry->u.fifo.out != port) + entry ++; + if (entry->addr != ch->vaddr[port] || entry->u.fifo.out != port) + return soc_dma_port_other; + + if (ch->type[port] != soc_dma_access_const) + return soc_dma_port_other; + + ch->io_fn[port] = entry->u.fifo.fn; + ch->io_opaque[port] = entry->u.fifo.opaque; + return soc_dma_port_fifo; + } else if (entry->type == soc_dma_port_mem) { + if (entry->addr > ch->vaddr[port] || + entry->addr + entry->u.mem.size <= ch->vaddr[port]) + return soc_dma_port_other; + + /* TODO: support constant memory address for source port as used for + * drawing solid rectangles by PalmOS(R). */ + if (ch->type[port] != soc_dma_access_const) + return soc_dma_port_other; + + ch->paddr[port] = (uint8_t *) entry->u.mem.base + + (ch->vaddr[port] - entry->addr); + /* TODO: save bytes left to the end of the mapping somewhere so we + * can check we're not reading beyond it. */ + return soc_dma_port_mem; + } else + return soc_dma_port_other; +} + +void soc_dma_ch_update(struct soc_dma_ch_s *ch) +{ + enum soc_dma_port_type src, dst; + + src = soc_dma_ch_update_type(ch, 0); + if (src == soc_dma_port_other) { + ch->update = 0; + ch->transfer_fn = ch->dma->transfer_fn; + return; + } + dst = soc_dma_ch_update_type(ch, 1); + + /* TODO: use src and dst as array indices. */ + if (src == soc_dma_port_mem && dst == soc_dma_port_mem) + ch->transfer_fn = transfer_mem2mem; + else if (src == soc_dma_port_mem && dst == soc_dma_port_fifo) + ch->transfer_fn = transfer_mem2fifo; + else if (src == soc_dma_port_fifo && dst == soc_dma_port_mem) + ch->transfer_fn = transfer_fifo2mem; + else if (src == soc_dma_port_fifo && dst == soc_dma_port_fifo) + ch->transfer_fn = transfer_fifo2fifo; + else + ch->transfer_fn = ch->dma->transfer_fn; + + ch->update = (dst != soc_dma_port_other); +} + +static void soc_dma_ch_freq_update(struct dma_s *s) +{ + if (s->enabled_count) + /* We completely ignore channel priorities and stuff */ + s->channel_freq = s->soc.freq / s->enabled_count; + else + /* TODO: Signal that we want to disable the functional clock and let + * the platform code decide what to do with it, i.e. check that + * auto-idle is enabled in the clock controller and if we are stopping + * the clock, do the same with any parent clocks that had only one + * user keeping them on and auto-idle enabled. */; +} + +void soc_dma_set_request(struct soc_dma_ch_s *ch, int level) +{ + struct dma_s *dma = (struct dma_s *) ch->dma; + + dma->enabled_count += level - ch->enable; + + if (level) + dma->ch_enable_mask |= 1 << ch->num; + else + dma->ch_enable_mask &= ~(1 << ch->num); + + if (level != ch->enable) { + soc_dma_ch_freq_update(dma); + ch->enable = level; + + if (!ch->enable) + qemu_del_timer(ch->timer); + else if (!ch->running) + soc_dma_ch_run(ch); + else + soc_dma_ch_schedule(ch, 1); + } +} + +void soc_dma_reset(struct soc_dma_s *soc) +{ + struct dma_s *s = (struct dma_s *) soc; + + s->soc.drqbmp = 0; + s->ch_enable_mask = 0; + s->enabled_count = 0; + soc_dma_ch_freq_update(s); +} + +/* TODO: take a functional-clock argument */ +struct soc_dma_s *soc_dma_init(int n) +{ + int i; + struct dma_s *s = qemu_mallocz(sizeof(*s) + n * sizeof(*s->ch)); + + s->chnum = n; + s->soc.ch = s->ch; + for (i = 0; i < n; i ++) { + s->ch[i].dma = &s->soc; + s->ch[i].num = i; + s->ch[i].timer = qemu_new_timer(vm_clock, soc_dma_ch_run, &s->ch[i]); + } + + soc_dma_reset(&s->soc); + fifo_size = 0; + + return &s->soc; +} + +void soc_dma_port_add_fifo(struct soc_dma_s *soc, target_phys_addr_t virt_base, + soc_dma_io_t fn, void *opaque, int out) +{ + struct memmap_entry_s *entry; + struct dma_s *dma = (struct dma_s *) soc; + + dma->memmap = qemu_realloc(dma->memmap, sizeof(*entry) * + (dma->memmap_size + 1)); + entry = soc_dma_lookup(dma, virt_base); + + if (dma->memmap_size) { + if (entry->type == soc_dma_port_mem) { + if (entry->addr <= virt_base && + entry->addr + entry->u.mem.size > virt_base) { + fprintf(stderr, "%s: FIFO at " TARGET_FMT_lx + " collides with RAM region at " TARGET_FMT_lx + "-" TARGET_FMT_lx "\n", __FUNCTION__, + (target_ulong) virt_base, + (target_ulong) entry->addr, (target_ulong) + (entry->addr + entry->u.mem.size)); + exit(-1); + } + + if (entry->addr <= virt_base) + entry ++; + } else + while (entry < dma->memmap + dma->memmap_size && + entry->addr <= virt_base) { + if (entry->addr == virt_base && entry->u.fifo.out == out) { + fprintf(stderr, "%s: FIFO at " TARGET_FMT_lx + " collides FIFO at " TARGET_FMT_lx "\n", + __FUNCTION__, (target_ulong) virt_base, + (target_ulong) entry->addr); + exit(-1); + } + + entry ++; + } + + memmove(entry + 1, entry, + (uint8_t *) (dma->memmap + dma->memmap_size ++) - + (uint8_t *) entry); + } else + dma->memmap_size ++; + + entry->addr = virt_base; + entry->type = soc_dma_port_fifo; + entry->u.fifo.fn = fn; + entry->u.fifo.opaque = opaque; + entry->u.fifo.out = out; +} + +void soc_dma_port_add_mem(struct soc_dma_s *soc, uint8_t *phys_base, + target_phys_addr_t virt_base, size_t size) +{ + struct memmap_entry_s *entry; + struct dma_s *dma = (struct dma_s *) soc; + + dma->memmap = qemu_realloc(dma->memmap, sizeof(*entry) * + (dma->memmap_size + 1)); + entry = soc_dma_lookup(dma, virt_base); + + if (dma->memmap_size) { + if (entry->type == soc_dma_port_mem) { + if ((entry->addr >= virt_base && entry->addr < virt_base + size) || + (entry->addr <= virt_base && + entry->addr + entry->u.mem.size > virt_base)) { + fprintf(stderr, "%s: RAM at " TARGET_FMT_lx "-" TARGET_FMT_lx + " collides with RAM region at " TARGET_FMT_lx + "-" TARGET_FMT_lx "\n", __FUNCTION__, + (target_ulong) virt_base, + (target_ulong) (virt_base + size), + (target_ulong) entry->addr, (target_ulong) + (entry->addr + entry->u.mem.size)); + exit(-1); + } + + if (entry->addr <= virt_base) + entry ++; + } else { + if (entry->addr >= virt_base && + entry->addr < virt_base + size) { + fprintf(stderr, "%s: RAM at " TARGET_FMT_lx "-" TARGET_FMT_lx + " collides with FIFO at " TARGET_FMT_lx + "\n", __FUNCTION__, + (target_ulong) virt_base, + (target_ulong) (virt_base + size), + (target_ulong) entry->addr); + exit(-1); + } + + while (entry < dma->memmap + dma->memmap_size && + entry->addr <= virt_base) + entry ++; + } + + memmove(entry + 1, entry, + (uint8_t *) (dma->memmap + dma->memmap_size ++) - + (uint8_t *) entry); + } else + dma->memmap_size ++; + + entry->addr = virt_base; + entry->type = soc_dma_port_mem; + entry->u.mem.base = phys_base; + entry->u.mem.size = size; +} + +/* TODO: port removal for ports like PCMCIA memory */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/soc_dma.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/soc_dma.h --- qemu-0.9.1/hw/soc_dma.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/soc_dma.h 2008-07-21 21:40:22.000000000 +0100 @@ -0,0 +1,115 @@ +/* + * On-chip DMA controller framework. + * + * Copyright (C) 2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +struct soc_dma_s; +struct soc_dma_ch_s; +typedef void (*soc_dma_io_t)(void *opaque, uint8_t *buf, int len); +typedef void (*soc_dma_transfer_t)(struct soc_dma_ch_s *ch); + +enum soc_dma_port_type { + soc_dma_port_mem, + soc_dma_port_fifo, + soc_dma_port_other, +}; + +enum soc_dma_access_type { + soc_dma_access_const, + soc_dma_access_linear, + soc_dma_access_other, +}; + +struct soc_dma_ch_s { + /* Private */ + struct soc_dma_s *dma; + int num; + QEMUTimer *timer; + + /* Set by soc_dma.c */ + int enable; + int update; + + /* This should be set by dma->setup_fn(). */ + int bytes; + /* Initialised by the DMA module, call soc_dma_ch_update after writing. */ + enum soc_dma_access_type type[2]; + target_phys_addr_t vaddr[2]; /* Updated by .transfer_fn(). */ + /* Private */ + void *paddr[2]; + soc_dma_io_t io_fn[2]; + void *io_opaque[2]; + + int running; + soc_dma_transfer_t transfer_fn; + + /* Set and used by the DMA module. */ + void *opaque; +}; + +struct soc_dma_s { + /* Following fields are set by the SoC DMA module and can be used + * by anybody. */ + uint64_t drqbmp; /* Is zeroed by soc_dma_reset() */ + qemu_irq *drq; + void *opaque; + int64_t freq; + soc_dma_transfer_t transfer_fn; + soc_dma_transfer_t setup_fn; + /* Set by soc_dma_init() for use by the DMA module. */ + struct soc_dma_ch_s *ch; +}; + +/* Call to activate or stop a DMA channel. */ +void soc_dma_set_request(struct soc_dma_ch_s *ch, int level); +/* Call after every write to one of the following fields and before + * calling soc_dma_set_request(ch, 1): + * ch->type[0...1], + * ch->vaddr[0...1], + * ch->paddr[0...1], + * or after a soc_dma_port_add_fifo() or soc_dma_port_add_mem(). */ +void soc_dma_ch_update(struct soc_dma_ch_s *ch); + +/* The SoC should call this when the DMA module is being reset. */ +void soc_dma_reset(struct soc_dma_s *s); +struct soc_dma_s *soc_dma_init(int n); + +void soc_dma_port_add_fifo(struct soc_dma_s *dma, target_phys_addr_t virt_base, + soc_dma_io_t fn, void *opaque, int out); +void soc_dma_port_add_mem(struct soc_dma_s *dma, uint8_t *phys_base, + target_phys_addr_t virt_base, size_t size); + +static inline void soc_dma_port_add_fifo_in(struct soc_dma_s *dma, + target_phys_addr_t virt_base, soc_dma_io_t fn, void *opaque) +{ + return soc_dma_port_add_fifo(dma, virt_base, fn, opaque, 0); +} + +static inline void soc_dma_port_add_fifo_out(struct soc_dma_s *dma, + target_phys_addr_t virt_base, soc_dma_io_t fn, void *opaque) +{ + return soc_dma_port_add_fifo(dma, virt_base, fn, opaque, 1); +} + +static inline void soc_dma_port_add_mem_ram(struct soc_dma_s *dma, + ram_addr_t offset, target_phys_addr_t virt_base, size_t size) +{ + return soc_dma_port_add_mem(dma, phys_ram_base + offset, virt_base, size); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/spitz.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/spitz.c --- qemu-0.9.1/hw/spitz.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/spitz.c 2008-10-28 10:59:59.000000000 +0000 @@ -16,13 +16,12 @@ #include "flash.h" #include "qemu-timer.h" #include "devices.h" +#include "sharpsl.h" #include "console.h" #include "block.h" #include "audio/audio.h" #include "boards.h" -#define spitz_printf(format, ...) \ - fprintf(stderr, "%s: " format, __FUNCTION__, ##__VA_ARGS__) #undef REG_FMT #if TARGET_PHYS_ADDR_BITS == 32 #define REG_FMT "0x%02x" @@ -89,7 +88,7 @@ return ecc_digest(&s->ecc, nand_getio(s->nand)); default: - spitz_printf("Bad register offset " REG_FMT "\n", addr); + zaurus_printf("Bad register offset " REG_FMT "\n", addr); } return 0; } @@ -133,7 +132,7 @@ break; default: - spitz_printf("Bad register offset " REG_FMT "\n", addr); + zaurus_printf("Bad register offset " REG_FMT "\n", addr); } } @@ -520,238 +519,6 @@ spitz_keyboard_save, spitz_keyboard_load, s); } -/* SCOOP devices */ - -struct scoop_info_s { - target_phys_addr_t target_base; - qemu_irq handler[16]; - qemu_irq *in; - uint16_t status; - uint16_t power; - uint32_t gpio_level; - uint32_t gpio_dir; - uint32_t prev_level; - - uint16_t mcr; - uint16_t cdr; - uint16_t ccr; - uint16_t irr; - uint16_t imr; - uint16_t isr; - uint16_t gprr; -}; - -#define SCOOP_MCR 0x00 -#define SCOOP_CDR 0x04 -#define SCOOP_CSR 0x08 -#define SCOOP_CPR 0x0c -#define SCOOP_CCR 0x10 -#define SCOOP_IRR_IRM 0x14 -#define SCOOP_IMR 0x18 -#define SCOOP_ISR 0x1c -#define SCOOP_GPCR 0x20 -#define SCOOP_GPWR 0x24 -#define SCOOP_GPRR 0x28 - -static inline void scoop_gpio_handler_update(struct scoop_info_s *s) { - uint32_t level, diff; - int bit; - level = s->gpio_level & s->gpio_dir; - - for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { - bit = ffs(diff) - 1; - qemu_set_irq(s->handler[bit], (level >> bit) & 1); - } - - s->prev_level = level; -} - -static uint32_t scoop_readb(void *opaque, target_phys_addr_t addr) -{ - struct scoop_info_s *s = (struct scoop_info_s *) opaque; - addr -= s->target_base; - - switch (addr) { - case SCOOP_MCR: - return s->mcr; - case SCOOP_CDR: - return s->cdr; - case SCOOP_CSR: - return s->status; - case SCOOP_CPR: - return s->power; - case SCOOP_CCR: - return s->ccr; - case SCOOP_IRR_IRM: - return s->irr; - case SCOOP_IMR: - return s->imr; - case SCOOP_ISR: - return s->isr; - case SCOOP_GPCR: - return s->gpio_dir; - case SCOOP_GPWR: - return s->gpio_level; - case SCOOP_GPRR: - return s->gprr; - default: - spitz_printf("Bad register offset " REG_FMT "\n", addr); - } - - return 0; -} - -static void scoop_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) -{ - struct scoop_info_s *s = (struct scoop_info_s *) opaque; - addr -= s->target_base; - value &= 0xffff; - - switch (addr) { - case SCOOP_MCR: - s->mcr = value; - break; - case SCOOP_CDR: - s->cdr = value; - break; - case SCOOP_CPR: - s->power = value; - if (value & 0x80) - s->power |= 0x8040; - break; - case SCOOP_CCR: - s->ccr = value; - break; - case SCOOP_IRR_IRM: - s->irr = value; - break; - case SCOOP_IMR: - s->imr = value; - break; - case SCOOP_ISR: - s->isr = value; - break; - case SCOOP_GPCR: - s->gpio_dir = value; - scoop_gpio_handler_update(s); - break; - case SCOOP_GPWR: - s->gpio_level = value & s->gpio_dir; - scoop_gpio_handler_update(s); - break; - case SCOOP_GPRR: - s->gprr = value; - break; - default: - spitz_printf("Bad register offset " REG_FMT "\n", addr); - } -} - -CPUReadMemoryFunc *scoop_readfn[] = { - scoop_readb, - scoop_readb, - scoop_readb, -}; -CPUWriteMemoryFunc *scoop_writefn[] = { - scoop_writeb, - scoop_writeb, - scoop_writeb, -}; - -static void scoop_gpio_set(void *opaque, int line, int level) -{ - struct scoop_info_s *s = (struct scoop_info_s *) s; - - if (level) - s->gpio_level |= (1 << line); - else - s->gpio_level &= ~(1 << line); -} - -static inline qemu_irq *scoop_gpio_in_get(struct scoop_info_s *s) -{ - return s->in; -} - -static inline void scoop_gpio_out_set(struct scoop_info_s *s, int line, - qemu_irq handler) { - if (line >= 16) { - spitz_printf("No GPIO pin %i\n", line); - return; - } - - s->handler[line] = handler; -} - -static void scoop_save(QEMUFile *f, void *opaque) -{ - struct scoop_info_s *s = (struct scoop_info_s *) opaque; - qemu_put_be16s(f, &s->status); - qemu_put_be16s(f, &s->power); - qemu_put_be32s(f, &s->gpio_level); - qemu_put_be32s(f, &s->gpio_dir); - qemu_put_be32s(f, &s->prev_level); - qemu_put_be16s(f, &s->mcr); - qemu_put_be16s(f, &s->cdr); - qemu_put_be16s(f, &s->ccr); - qemu_put_be16s(f, &s->irr); - qemu_put_be16s(f, &s->imr); - qemu_put_be16s(f, &s->isr); - qemu_put_be16s(f, &s->gprr); -} - -static int scoop_load(QEMUFile *f, void *opaque, int version_id) -{ - struct scoop_info_s *s = (struct scoop_info_s *) opaque; - qemu_get_be16s(f, &s->status); - qemu_get_be16s(f, &s->power); - qemu_get_be32s(f, &s->gpio_level); - qemu_get_be32s(f, &s->gpio_dir); - qemu_get_be32s(f, &s->prev_level); - qemu_get_be16s(f, &s->mcr); - qemu_get_be16s(f, &s->cdr); - qemu_get_be16s(f, &s->ccr); - qemu_get_be16s(f, &s->irr); - qemu_get_be16s(f, &s->imr); - qemu_get_be16s(f, &s->isr); - qemu_get_be16s(f, &s->gprr); - - return 0; -} - -static struct scoop_info_s *spitz_scoop_init(struct pxa2xx_state_s *cpu, - int count) { - int iomemtype; - struct scoop_info_s *s; - - s = (struct scoop_info_s *) - qemu_mallocz(sizeof(struct scoop_info_s) * 2); - memset(s, 0, sizeof(struct scoop_info_s) * count); - s[0].target_base = 0x10800000; - s[1].target_base = 0x08800040; - - /* Ready */ - s[0].status = 0x02; - s[1].status = 0x02; - - s[0].in = qemu_allocate_irqs(scoop_gpio_set, &s[0], 16); - iomemtype = cpu_register_io_memory(0, scoop_readfn, - scoop_writefn, &s[0]); - cpu_register_physical_memory(s[0].target_base, 0x1000, iomemtype); - register_savevm("scoop", 0, 0, scoop_save, scoop_load, &s[0]); - - if (count < 2) - return s; - - s[1].in = qemu_allocate_irqs(scoop_gpio_set, &s[1], 16); - iomemtype = cpu_register_io_memory(0, scoop_readfn, - scoop_writefn, &s[1]); - cpu_register_physical_memory(s[1].target_base, 0x1000, iomemtype); - register_savevm("scoop", 1, 0, scoop_save, scoop_load, &s[1]); - - return s; -} - /* LCD backlight controller */ #define LCDTG_RESCTL 0x00 @@ -768,9 +535,9 @@ static void spitz_bl_update(struct pxa2xx_state_s *s) { if (bl_power && bl_intensity) - spitz_printf("LCD Backlight now at %i/63\n", bl_intensity); + zaurus_printf("LCD Backlight now at %i/63\n", bl_intensity); else - spitz_printf("LCD Backlight now off\n"); + zaurus_printf("LCD Backlight now off\n"); } static inline void spitz_bl_bit5(void *opaque, int line, int level) @@ -801,9 +568,9 @@ switch (addr) { case LCDTG_RESCTL: if (value) - spitz_printf("LCD in QVGA mode\n"); + zaurus_printf("LCD in QVGA mode\n"); else - spitz_printf("LCD in VGA mode\n"); + zaurus_printf("LCD in VGA mode\n"); break; case LCDTG_DUTYCTRL: @@ -1011,16 +778,16 @@ { switch (line) { case 0: - spitz_printf("Charging %s.\n", level ? "off" : "on"); + zaurus_printf("Charging %s.\n", level ? "off" : "on"); break; case 1: - spitz_printf("Discharging %s.\n", level ? "on" : "off"); + zaurus_printf("Discharging %s.\n", level ? "on" : "off"); break; case 2: - spitz_printf("Green LED %s.\n", level ? "on" : "off"); + zaurus_printf("Green LED %s.\n", level ? "on" : "off"); break; case 3: - spitz_printf("Orange LED %s.\n", level ? "on" : "off"); + zaurus_printf("Orange LED %s.\n", level ? "on" : "off"); break; case 4: spitz_bl_bit5(opaque, line, level); @@ -1050,21 +817,21 @@ #define SPITZ_SCP2_MIC_BIAS 9 static void spitz_scoop_gpio_setup(struct pxa2xx_state_s *cpu, - struct scoop_info_s *scp, int num) + struct scoop_info_s *scp0, struct scoop_info_s *scp1) { qemu_irq *outsignals = qemu_allocate_irqs(spitz_out_switch, cpu, 8); - scoop_gpio_out_set(&scp[0], SPITZ_SCP_CHRG_ON, outsignals[0]); - scoop_gpio_out_set(&scp[0], SPITZ_SCP_JK_B, outsignals[1]); - scoop_gpio_out_set(&scp[0], SPITZ_SCP_LED_GREEN, outsignals[2]); - scoop_gpio_out_set(&scp[0], SPITZ_SCP_LED_ORANGE, outsignals[3]); - - if (num >= 2) { - scoop_gpio_out_set(&scp[1], SPITZ_SCP2_BACKLIGHT_CONT, outsignals[4]); - scoop_gpio_out_set(&scp[1], SPITZ_SCP2_BACKLIGHT_ON, outsignals[5]); + scoop_gpio_out_set(scp0, SPITZ_SCP_CHRG_ON, outsignals[0]); + scoop_gpio_out_set(scp0, SPITZ_SCP_JK_B, outsignals[1]); + scoop_gpio_out_set(scp0, SPITZ_SCP_LED_GREEN, outsignals[2]); + scoop_gpio_out_set(scp0, SPITZ_SCP_LED_ORANGE, outsignals[3]); + + if (scp1) { + scoop_gpio_out_set(scp1, SPITZ_SCP2_BACKLIGHT_CONT, outsignals[4]); + scoop_gpio_out_set(scp1, SPITZ_SCP2_BACKLIGHT_ON, outsignals[5]); } - scoop_gpio_out_set(&scp[0], SPITZ_SCP_ADC_TEMP_ON, outsignals[6]); + scoop_gpio_out_set(scp0, SPITZ_SCP_ADC_TEMP_ON, outsignals[6]); } #define SPITZ_GPIO_HSYNC 22 @@ -1134,86 +901,52 @@ spitz_gpio_invert[4]); } -/* Write the bootloader parameters memory area. */ +/* Board init. */ +enum spitz_model_e { spitz, akita, borzoi, terrier }; -#define MAGIC_CHG(a, b, c, d) ((d << 24) | (c << 16) | (b << 8) | a) +#define SPITZ_RAM 0x04000000 +#define SPITZ_ROM 0x00800000 -struct __attribute__ ((__packed__)) sl_param_info { - uint32_t comadj_keyword; - int32_t comadj; - - uint32_t uuid_keyword; - char uuid[16]; - - uint32_t touch_keyword; - int32_t touch_xp; - int32_t touch_yp; - int32_t touch_xd; - int32_t touch_yd; - - uint32_t adadj_keyword; - int32_t adadj; - - uint32_t phad_keyword; - int32_t phadadj; -} spitz_bootparam = { - .comadj_keyword = MAGIC_CHG('C', 'M', 'A', 'D'), - .comadj = 125, - .uuid_keyword = MAGIC_CHG('U', 'U', 'I', 'D'), - .uuid = { -1 }, - .touch_keyword = MAGIC_CHG('T', 'U', 'C', 'H'), - .touch_xp = -1, - .adadj_keyword = MAGIC_CHG('B', 'V', 'A', 'D'), - .adadj = -1, - .phad_keyword = MAGIC_CHG('P', 'H', 'A', 'D'), - .phadadj = 0x01, +static struct arm_boot_info spitz_binfo = { + .loader_start = PXA2XX_SDRAM_BASE, + .ram_size = 0x04000000, }; -static void sl_bootparam_write(uint32_t ptr) -{ - memcpy(phys_ram_base + ptr, &spitz_bootparam, - sizeof(struct sl_param_info)); -} - -#define SL_PXA_PARAM_BASE 0xa0000a00 - -/* Board init. */ -enum spitz_model_e { spitz, akita, borzoi, terrier }; - -static void spitz_common_init(int ram_size, int vga_ram_size, +static void spitz_common_init(ram_addr_t ram_size, int vga_ram_size, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model, enum spitz_model_e model, int arm_id) { - uint32_t spitz_ram = 0x04000000; - uint32_t spitz_rom = 0x00800000; struct pxa2xx_state_s *cpu; - struct scoop_info_s *scp; + struct scoop_info_s *scp0, *scp1 = NULL; if (!cpu_model) cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0"; /* Setup CPU & memory */ - if (ram_size < spitz_ram + spitz_rom + PXA2XX_INTERNAL_SIZE) { + if (ram_size < SPITZ_RAM + SPITZ_ROM + PXA2XX_INTERNAL_SIZE) { fprintf(stderr, "This platform requires %i bytes of memory\n", - spitz_ram + spitz_rom + PXA2XX_INTERNAL_SIZE); + SPITZ_RAM + SPITZ_ROM + PXA2XX_INTERNAL_SIZE); exit(1); } - cpu = pxa270_init(spitz_ram, ds, cpu_model); + cpu = pxa270_init(spitz_binfo.ram_size, ds, cpu_model); sl_flash_register(cpu, (model == spitz) ? FLASH_128M : FLASH_1024M); - cpu_register_physical_memory(0, spitz_rom, - qemu_ram_alloc(spitz_rom) | IO_MEM_ROM); + cpu_register_physical_memory(0, SPITZ_ROM, + qemu_ram_alloc(SPITZ_ROM) | IO_MEM_ROM); /* Setup peripherals */ spitz_keyboard_register(cpu); spitz_ssp_attach(cpu); - scp = spitz_scoop_init(cpu, (model == akita) ? 1 : 2); + scp0 = scoop_init(cpu, 0, 0x10800000); + if (model != akita) { + scp1 = scoop_init(cpu, 1, 0x08800040); + } - spitz_scoop_gpio_setup(cpu, scp, (model == akita) ? 1 : 2); + spitz_scoop_gpio_setup(cpu, scp0, scp1); spitz_gpio_setup(cpu, (model == akita) ? 1 : 2); @@ -1230,14 +963,17 @@ spitz_microdrive_attach(cpu); /* Setup initial (reset) machine state */ - cpu->env->regs[15] = PXA2XX_SDRAM_BASE; + cpu->env->regs[15] = spitz_binfo.loader_start; - arm_load_kernel(cpu->env, spitz_ram, kernel_filename, kernel_cmdline, - initrd_filename, arm_id, PXA2XX_SDRAM_BASE); + spitz_binfo.kernel_filename = kernel_filename; + spitz_binfo.kernel_cmdline = kernel_cmdline; + spitz_binfo.initrd_filename = initrd_filename; + spitz_binfo.board_id = arm_id; + arm_load_kernel(cpu->env, &spitz_binfo); sl_bootparam_write(SL_PXA_PARAM_BASE - PXA2XX_SDRAM_BASE); } -static void spitz_init(int ram_size, int vga_ram_size, +static void spitz_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -1246,7 +982,7 @@ kernel_cmdline, initrd_filename, cpu_model, spitz, 0x2c9); } -static void borzoi_init(int ram_size, int vga_ram_size, +static void borzoi_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -1255,7 +991,7 @@ kernel_cmdline, initrd_filename, cpu_model, borzoi, 0x33f); } -static void akita_init(int ram_size, int vga_ram_size, +static void akita_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -1264,7 +1000,7 @@ kernel_cmdline, initrd_filename, cpu_model, akita, 0x2e8); } -static void terrier_init(int ram_size, int vga_ram_size, +static void terrier_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -1274,25 +1010,29 @@ } QEMUMachine akitapda_machine = { - "akita", - "Akita PDA (PXA270)", - akita_init, + .name = "akita", + .desc = "Akita PDA (PXA270)", + .init = akita_init, + .ram_require = SPITZ_RAM + SPITZ_ROM + PXA2XX_INTERNAL_SIZE + RAMSIZE_FIXED, }; QEMUMachine spitzpda_machine = { - "spitz", - "Spitz PDA (PXA270)", - spitz_init, + .name = "spitz", + .desc = "Spitz PDA (PXA270)", + .init = spitz_init, + .ram_require = SPITZ_RAM + SPITZ_ROM + PXA2XX_INTERNAL_SIZE + RAMSIZE_FIXED, }; QEMUMachine borzoipda_machine = { - "borzoi", - "Borzoi PDA (PXA270)", - borzoi_init, + .name = "borzoi", + .desc = "Borzoi PDA (PXA270)", + .init = borzoi_init, + .ram_require = SPITZ_RAM + SPITZ_ROM + PXA2XX_INTERNAL_SIZE + RAMSIZE_FIXED, }; QEMUMachine terrierpda_machine = { - "terrier", - "Terrier PDA (PXA270)", - terrier_init, + .name = "terrier", + .desc = "Terrier PDA (PXA270)", + .init = terrier_init, + .ram_require = SPITZ_RAM + SPITZ_ROM + PXA2XX_INTERNAL_SIZE + RAMSIZE_FIXED, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ssd0303.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ssd0303.c --- qemu-0.9.1/hw/ssd0303.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/ssd0303.c 2008-07-08 00:01:25.000000000 +0100 @@ -45,6 +45,7 @@ typedef struct { i2c_slave i2c; DisplayState *ds; + QEMUConsole *console; int row; int col; int start_line; @@ -202,55 +203,57 @@ int dest_width; uint8_t mask; - if (s->redraw) { - switch (s->ds->depth) { - case 0: - return; - case 15: - dest_width = 2; - break; - case 16: - dest_width = 2; - break; - case 24: - dest_width = 3; - break; - case 32: - dest_width = 4; - break; - default: - BADF("Bad color depth\n"); - return; - } - dest_width *= MAGNIFY; - memset(colortab, 0xff, dest_width); - memset(colortab + dest_width, 0, dest_width); - if (s->flash) { - colors[0] = colortab; - colors[1] = colortab; - } else if (s->inverse) { - colors[0] = colortab; - colors[1] = colortab + dest_width; - } else { - colors[0] = colortab + dest_width; - colors[1] = colortab; + if (!s->redraw) + return; + + switch (s->ds->depth) { + case 0: + return; + case 15: + dest_width = 2; + break; + case 16: + dest_width = 2; + break; + case 24: + dest_width = 3; + break; + case 32: + dest_width = 4; + break; + default: + BADF("Bad color depth\n"); + return; + } + dest_width *= MAGNIFY; + memset(colortab, 0xff, dest_width); + memset(colortab + dest_width, 0, dest_width); + if (s->flash) { + colors[0] = colortab; + colors[1] = colortab; + } else if (s->inverse) { + colors[0] = colortab; + colors[1] = colortab + dest_width; + } else { + colors[0] = colortab + dest_width; + colors[1] = colortab; + } + dest = s->ds->data; + for (y = 0; y < 16; y++) { + line = (y + s->start_line) & 63; + src = s->framebuffer + 132 * (line >> 3) + 36; + mask = 1 << (line & 7); + for (x = 0; x < 96; x++) { + memcpy(dest, colors[(*src & mask) != 0], dest_width); + dest += dest_width; + src++; } - dest = s->ds->data; - for (y = 0; y < 16; y++) { - line = (y + s->start_line) & 63; - src = s->framebuffer + 132 * (line >> 3) + 36; - mask = 1 << (line & 7); - for (x = 0; x < 96; x++) { - memcpy(dest, colors[(*src & mask) != 0], dest_width); - dest += dest_width; - src++; - } - for (x = 1; x < MAGNIFY; x++) { - memcpy(dest, dest - dest_width * 96, dest_width * 96); - dest += dest_width * 96; - } + for (x = 1; x < MAGNIFY; x++) { + memcpy(dest, dest - dest_width * 96, dest_width * 96); + dest += dest_width * 96; } } + s->redraw = 0; dpy_update(s->ds, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY); } @@ -260,6 +263,49 @@ s->redraw = 1; } +static void ssd0303_save(QEMUFile *f, void *opaque) +{ + ssd0303_state *s = (ssd0303_state *)opaque; + + qemu_put_be32(f, s->row); + qemu_put_be32(f, s->col); + qemu_put_be32(f, s->start_line); + qemu_put_be32(f, s->mirror); + qemu_put_be32(f, s->flash); + qemu_put_be32(f, s->enabled); + qemu_put_be32(f, s->inverse); + qemu_put_be32(f, s->redraw); + qemu_put_be32(f, s->mode); + qemu_put_be32(f, s->cmd_state); + qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer)); + + i2c_slave_save(f, &s->i2c); +} + +static int ssd0303_load(QEMUFile *f, void *opaque, int version_id) +{ + ssd0303_state *s = (ssd0303_state *)opaque; + + if (version_id != 1) + return -EINVAL; + + s->row = qemu_get_be32(f); + s->col = qemu_get_be32(f); + s->start_line = qemu_get_be32(f); + s->mirror = qemu_get_be32(f); + s->flash = qemu_get_be32(f); + s->enabled = qemu_get_be32(f); + s->inverse = qemu_get_be32(f); + s->redraw = qemu_get_be32(f); + s->mode = qemu_get_be32(f); + s->cmd_state = qemu_get_be32(f); + qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer)); + + i2c_slave_load(f, &s->i2c); + + return 0; +} + void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address) { ssd0303_state *s; @@ -269,7 +315,9 @@ s->i2c.event = ssd0303_event; s->i2c.recv = ssd0303_recv; s->i2c.send = ssd0303_send; - graphic_console_init(ds, ssd0303_update_display, ssd0303_invalidate_display, - NULL, s); - dpy_resize(s->ds, 96 * MAGNIFY, 16 * MAGNIFY); + s->console = graphic_console_init(ds, ssd0303_update_display, + ssd0303_invalidate_display, + NULL, NULL, s); + qemu_console_resize(s->console, 96 * MAGNIFY, 16 * MAGNIFY); + register_savevm("ssd0303_oled", -1, 1, ssd0303_save, ssd0303_load, s); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ssd0323.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ssd0323.c --- qemu-0.9.1/hw/ssd0323.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/ssd0323.c 2008-07-08 00:01:25.000000000 +0100 @@ -44,6 +44,7 @@ typedef struct { DisplayState *ds; + QEMUConsole *console; int cmd_len; int cmd; @@ -183,78 +184,80 @@ char *p; int dest_width; - if (s->redraw) { + if (!s->redraw) + return; + + switch (s->ds->depth) { + case 0: + return; + case 15: + dest_width = 2; + break; + case 16: + dest_width = 2; + break; + case 24: + dest_width = 3; + break; + case 32: + dest_width = 4; + break; + default: + BADF("Bad color depth\n"); + return; + } + p = colortab; + for (i = 0; i < 16; i++) { + int n; + colors[i] = p; switch (s->ds->depth) { - case 0: - return; case 15: - dest_width = 2; + n = i * 2 + (i >> 3); + p[0] = n | (n << 5); + p[1] = (n << 2) | (n >> 3); break; case 16: - dest_width = 2; + n = i * 2 + (i >> 3); + p[0] = n | (n << 6) | ((n << 1) & 0x20); + p[1] = (n << 3) | (n >> 2); break; case 24: - dest_width = 3; - break; case 32: - dest_width = 4; + n = (i << 4) | i; + p[0] = p[1] = p[2] = n; break; default: BADF("Bad color depth\n"); return; } - p = colortab; - for (i = 0; i < 16; i++) { - int n; - colors[i] = p; - switch (s->ds->depth) { - case 15: - n = i * 2 + (i >> 3); - p[0] = n | (n << 5); - p[1] = (n << 2) | (n >> 3); - break; - case 16: - n = i * 2 + (i >> 3); - p[0] = n | (n << 6) | ((n << 1) & 0x20); - p[1] = (n << 3) | (n >> 2); - break; - case 24: - case 32: - n = (i << 4) | i; - p[0] = p[1] = p[2] = n; - break; - default: - BADF("Bad color depth\n"); - return; - } - p += dest_width; - } - /* TODO: Implement row/column remapping. */ - dest = s->ds->data; - for (y = 0; y < 64; y++) { - line = y; - src = s->framebuffer + 64 * line; - for (x = 0; x < 64; x++) { - int val; - val = *src >> 4; - for (i = 0; i < MAGNIFY; i++) { - memcpy(dest, colors[val], dest_width); - dest += dest_width; - } - val = *src & 0xf; - for (i = 0; i < MAGNIFY; i++) { - memcpy(dest, colors[val], dest_width); - dest += dest_width; - } - src++; - } - for (i = 1; i < MAGNIFY; i++) { - memcpy(dest, dest - dest_width * MAGNIFY * 128, - dest_width * 128 * MAGNIFY); - dest += dest_width * 128 * MAGNIFY; + p += dest_width; + } + /* TODO: Implement row/column remapping. */ + dest = s->ds->data; + for (y = 0; y < 64; y++) { + line = y; + src = s->framebuffer + 64 * line; + for (x = 0; x < 64; x++) { + int val; + val = *src >> 4; + for (i = 0; i < MAGNIFY; i++) { + memcpy(dest, colors[val], dest_width); + dest += dest_width; + } + val = *src & 0xf; + for (i = 0; i < MAGNIFY; i++) { + memcpy(dest, colors[val], dest_width); + dest += dest_width; } + src++; + } + for (i = 1; i < MAGNIFY; i++) { + memcpy(dest, dest - dest_width * MAGNIFY * 128, + dest_width * 128 * MAGNIFY); + dest += dest_width * 128 * MAGNIFY; } } + s->redraw = 0; dpy_update(s->ds, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY); } @@ -272,21 +275,71 @@ s->mode = level ? SSD0323_DATA : SSD0323_CMD; } +static void ssd0323_save(QEMUFile *f, void *opaque) +{ + ssd0323_state *s = (ssd0323_state *)opaque; + int i; + + qemu_put_be32(f, s->cmd_len); + qemu_put_be32(f, s->cmd); + for (i = 0; i < 8; i++) + qemu_put_be32(f, s->cmd_data[i]); + qemu_put_be32(f, s->row); + qemu_put_be32(f, s->row_start); + qemu_put_be32(f, s->row_end); + qemu_put_be32(f, s->col); + qemu_put_be32(f, s->col_start); + qemu_put_be32(f, s->col_end); + qemu_put_be32(f, s->redraw); + qemu_put_be32(f, s->remap); + qemu_put_be32(f, s->mode); + qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer)); +} + +static int ssd0323_load(QEMUFile *f, void *opaque, int version_id) +{ + ssd0323_state *s = (ssd0323_state *)opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + s->cmd_len = qemu_get_be32(f); + s->cmd = qemu_get_be32(f); + for (i = 0; i < 8; i++) + s->cmd_data[i] = qemu_get_be32(f); + s->row = qemu_get_be32(f); + s->row_start = qemu_get_be32(f); + s->row_end = qemu_get_be32(f); + s->col = qemu_get_be32(f); + s->col_start = qemu_get_be32(f); + s->col_end = qemu_get_be32(f); + s->redraw = qemu_get_be32(f); + s->remap = qemu_get_be32(f); + s->mode = qemu_get_be32(f); + qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer)); + + return 0; +} + void *ssd0323_init(DisplayState *ds, qemu_irq *cmd_p) { ssd0323_state *s; qemu_irq *cmd; s = (ssd0323_state *)qemu_mallocz(sizeof(ssd0323_state)); - s->ds = ds; - graphic_console_init(ds, ssd0323_update_display, ssd0323_invalidate_display, - NULL, s); - dpy_resize(s->ds, 128 * MAGNIFY, 64 * MAGNIFY); s->col_end = 63; s->row_end = 79; + s->ds = ds; + s->console = graphic_console_init(ds, ssd0323_update_display, + ssd0323_invalidate_display, + NULL, NULL, s); + qemu_console_resize(s->console, 128 * MAGNIFY, 64 * MAGNIFY); cmd = qemu_allocate_irqs(ssd0323_cd, s, 1); *cmd_p = *cmd; + register_savevm("ssd0323_oled", -1, 1, ssd0323_save, ssd0323_load, s); + return s; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/ssi-sd.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/ssi-sd.c --- qemu-0.9.1/hw/ssi-sd.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/ssi-sd.c 2008-07-02 17:48:32.000000000 +0100 @@ -190,6 +190,43 @@ return 0xff; } +static void ssi_sd_save(QEMUFile *f, void *opaque) +{ + ssi_sd_state *s = (ssi_sd_state *)opaque; + int i; + + qemu_put_be32(f, s->mode); + qemu_put_be32(f, s->cmd); + for (i = 0; i < 4; i++) + qemu_put_be32(f, s->cmdarg[i]); + for (i = 0; i < 5; i++) + qemu_put_be32(f, s->response[i]); + qemu_put_be32(f, s->arglen); + qemu_put_be32(f, s->response_pos); + qemu_put_be32(f, s->stopping); +} + +static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id) +{ + ssi_sd_state *s = (ssi_sd_state *)opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + s->mode = qemu_get_be32(f); + s->cmd = qemu_get_be32(f); + for (i = 0; i < 4; i++) + s->cmdarg[i] = qemu_get_be32(f); + for (i = 0; i < 5; i++) + s->response[i] = qemu_get_be32(f); + s->arglen = qemu_get_be32(f); + s->response_pos = qemu_get_be32(f); + s->stopping = qemu_get_be32(f); + + return 0; +} + void *ssi_sd_init(BlockDriverState *bs) { ssi_sd_state *s; @@ -197,6 +234,7 @@ s = (ssi_sd_state *)qemu_mallocz(sizeof(ssi_sd_state)); s->mode = SSI_SD_CMD; s->sd = sd_init(bs, 1); + register_savevm("ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s); return s; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/stellaris.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/stellaris.c --- qemu-0.9.1/hw/stellaris.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/stellaris.c 2008-10-28 10:59:59.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Luminary Micro Stellaris preipherals + * Luminary Micro Stellaris peripherals * * Copyright (c) 2006 CodeSourcery. * Written by Paul Brook @@ -286,6 +286,65 @@ gptm_write }; +static void gptm_save(QEMUFile *f, void *opaque) +{ + gptm_state *s = (gptm_state *)opaque; + + qemu_put_be32(f, s->config); + qemu_put_be32(f, s->mode[0]); + qemu_put_be32(f, s->mode[1]); + qemu_put_be32(f, s->control); + qemu_put_be32(f, s->state); + qemu_put_be32(f, s->mask); + qemu_put_be32(f, s->mode[0]); + qemu_put_be32(f, s->mode[0]); + qemu_put_be32(f, s->load[0]); + qemu_put_be32(f, s->load[1]); + qemu_put_be32(f, s->match[0]); + qemu_put_be32(f, s->match[1]); + qemu_put_be32(f, s->prescale[0]); + qemu_put_be32(f, s->prescale[1]); + qemu_put_be32(f, s->match_prescale[0]); + qemu_put_be32(f, s->match_prescale[1]); + qemu_put_be32(f, s->rtc); + qemu_put_be64(f, s->tick[0]); + qemu_put_be64(f, s->tick[1]); + qemu_put_timer(f, s->timer[0]); + qemu_put_timer(f, s->timer[1]); +} + +static int gptm_load(QEMUFile *f, void *opaque, int version_id) +{ + gptm_state *s = (gptm_state *)opaque; + + if (version_id != 1) + return -EINVAL; + + s->config = qemu_get_be32(f); + s->mode[0] = qemu_get_be32(f); + s->mode[1] = qemu_get_be32(f); + s->control = qemu_get_be32(f); + s->state = qemu_get_be32(f); + s->mask = qemu_get_be32(f); + s->mode[0] = qemu_get_be32(f); + s->mode[0] = qemu_get_be32(f); + s->load[0] = qemu_get_be32(f); + s->load[1] = qemu_get_be32(f); + s->match[0] = qemu_get_be32(f); + s->match[1] = qemu_get_be32(f); + s->prescale[0] = qemu_get_be32(f); + s->prescale[1] = qemu_get_be32(f); + s->match_prescale[0] = qemu_get_be32(f); + s->match_prescale[1] = qemu_get_be32(f); + s->rtc = qemu_get_be32(f); + s->tick[0] = qemu_get_be64(f); + s->tick[1] = qemu_get_be64(f); + qemu_get_timer(f, s->timer[0]); + qemu_get_timer(f, s->timer[1]); + + return 0; +} + static void stellaris_gptm_init(uint32_t base, qemu_irq irq, qemu_irq trigger) { int iomemtype; @@ -302,7 +361,7 @@ cpu_register_physical_memory(base, 0x00001000, iomemtype); s->timer[0] = qemu_new_timer(vm_clock, gptm_tick, &s->opaque[0]); s->timer[1] = qemu_new_timer(vm_clock, gptm_tick, &s->opaque[1]); - /* ??? Save/restore. */ + register_savevm("stellaris_gptm", -1, 1, gptm_save, gptm_load, s); } @@ -452,6 +511,11 @@ } } +static void ssys_calculate_system_clock(ssys_state *s) +{ + system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1); +} + static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value) { ssys_state *s = (ssys_state *)opaque; @@ -484,7 +548,7 @@ s->int_status |= (1 << 6); } s->rcc = value; - system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1); + ssys_calculate_system_clock(s); break; case 0x100: /* RCGC0 */ s->rcgc[0] = value; @@ -548,6 +612,58 @@ s->dcgc[0] = 1; } +static void ssys_save(QEMUFile *f, void *opaque) +{ + ssys_state *s = (ssys_state *)opaque; + + qemu_put_be32(f, s->pborctl); + qemu_put_be32(f, s->ldopctl); + qemu_put_be32(f, s->int_mask); + qemu_put_be32(f, s->int_status); + qemu_put_be32(f, s->resc); + qemu_put_be32(f, s->rcc); + qemu_put_be32(f, s->rcgc[0]); + qemu_put_be32(f, s->rcgc[1]); + qemu_put_be32(f, s->rcgc[2]); + qemu_put_be32(f, s->scgc[0]); + qemu_put_be32(f, s->scgc[1]); + qemu_put_be32(f, s->scgc[2]); + qemu_put_be32(f, s->dcgc[0]); + qemu_put_be32(f, s->dcgc[1]); + qemu_put_be32(f, s->dcgc[2]); + qemu_put_be32(f, s->clkvclr); + qemu_put_be32(f, s->ldoarst); +} + +static int ssys_load(QEMUFile *f, void *opaque, int version_id) +{ + ssys_state *s = (ssys_state *)opaque; + + if (version_id != 1) + return -EINVAL; + + s->pborctl = qemu_get_be32(f); + s->ldopctl = qemu_get_be32(f); + s->int_mask = qemu_get_be32(f); + s->int_status = qemu_get_be32(f); + s->resc = qemu_get_be32(f); + s->rcc = qemu_get_be32(f); + s->rcgc[0] = qemu_get_be32(f); + s->rcgc[1] = qemu_get_be32(f); + s->rcgc[2] = qemu_get_be32(f); + s->scgc[0] = qemu_get_be32(f); + s->scgc[1] = qemu_get_be32(f); + s->scgc[2] = qemu_get_be32(f); + s->dcgc[0] = qemu_get_be32(f); + s->dcgc[1] = qemu_get_be32(f); + s->dcgc[2] = qemu_get_be32(f); + s->clkvclr = qemu_get_be32(f); + s->ldoarst = qemu_get_be32(f); + ssys_calculate_system_clock(s); + + return 0; +} + static void stellaris_sys_init(uint32_t base, qemu_irq irq, stellaris_board_info * board, uint8_t *macaddr) @@ -567,7 +683,7 @@ ssys_writefn, s); cpu_register_physical_memory(base, 0x00001000, iomemtype); ssys_reset(s); - /* ??? Save/restore. */ + register_savevm("stellaris_sys", -1, 1, ssys_save, ssys_load, s); } @@ -737,6 +853,37 @@ stellaris_i2c_write }; +static void stellaris_i2c_save(QEMUFile *f, void *opaque) +{ + stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; + + qemu_put_be32(f, s->msa); + qemu_put_be32(f, s->mcs); + qemu_put_be32(f, s->mdr); + qemu_put_be32(f, s->mtpr); + qemu_put_be32(f, s->mimr); + qemu_put_be32(f, s->mris); + qemu_put_be32(f, s->mcr); +} + +static int stellaris_i2c_load(QEMUFile *f, void *opaque, int version_id) +{ + stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; + + if (version_id != 1) + return -EINVAL; + + s->msa = qemu_get_be32(f); + s->mcs = qemu_get_be32(f); + s->mdr = qemu_get_be32(f); + s->mtpr = qemu_get_be32(f); + s->mimr = qemu_get_be32(f); + s->mris = qemu_get_be32(f); + s->mcr = qemu_get_be32(f); + + return 0; +} + static void stellaris_i2c_init(uint32_t base, qemu_irq irq, i2c_bus *bus) { stellaris_i2c_state *s; @@ -752,6 +899,8 @@ cpu_register_physical_memory(base, 0x00001000, iomemtype); /* ??? For now we only implement the master interface. */ stellaris_i2c_reset(s); + register_savevm("stellaris_i2c", -1, 1, + stellaris_i2c_save, stellaris_i2c_load, s); } /* Analogue to Digital Converter. This is only partially implemented, @@ -785,6 +934,7 @@ } fifo[4]; uint32_t ssmux[4]; uint32_t ssctl[4]; + uint32_t noise; qemu_irq irq; } stellaris_adc_state; @@ -833,17 +983,16 @@ static void stellaris_adc_trigger(void *opaque, int irq, int level) { stellaris_adc_state *s = (stellaris_adc_state *)opaque; - /* Some applications use the ADC as a random number source, so introduce - some variation into the signal. */ - static uint32_t noise = 0; if ((s->actss & 1) == 0) { return; } - noise = noise * 314159 + 1; + /* Some applications use the ADC as a random number source, so introduce + some variation into the signal. */ + s->noise = s->noise * 314159 + 1; /* ??? actual inputs not implemented. Return an arbitrary value. */ - stellaris_adc_fifo_write(s, 0, 0x200 + ((noise >> 16) & 7)); + stellaris_adc_fifo_write(s, 0, 0x200 + ((s->noise >> 16) & 7)); s->ris |= 1; stellaris_adc_update(s); } @@ -983,6 +1132,61 @@ stellaris_adc_write }; +static void stellaris_adc_save(QEMUFile *f, void *opaque) +{ + stellaris_adc_state *s = (stellaris_adc_state *)opaque; + int i; + int j; + + qemu_put_be32(f, s->actss); + qemu_put_be32(f, s->ris); + qemu_put_be32(f, s->im); + qemu_put_be32(f, s->emux); + qemu_put_be32(f, s->ostat); + qemu_put_be32(f, s->ustat); + qemu_put_be32(f, s->sspri); + qemu_put_be32(f, s->sac); + for (i = 0; i < 4; i++) { + qemu_put_be32(f, s->fifo[i].state); + for (j = 0; j < 16; j++) { + qemu_put_be32(f, s->fifo[i].data[j]); + } + qemu_put_be32(f, s->ssmux[i]); + qemu_put_be32(f, s->ssctl[i]); + } + qemu_put_be32(f, s->noise); +} + +static int stellaris_adc_load(QEMUFile *f, void *opaque, int version_id) +{ + stellaris_adc_state *s = (stellaris_adc_state *)opaque; + int i; + int j; + + if (version_id != 1) + return -EINVAL; + + s->actss = qemu_get_be32(f); + s->ris = qemu_get_be32(f); + s->im = qemu_get_be32(f); + s->emux = qemu_get_be32(f); + s->ostat = qemu_get_be32(f); + s->ustat = qemu_get_be32(f); + s->sspri = qemu_get_be32(f); + s->sac = qemu_get_be32(f); + for (i = 0; i < 4; i++) { + s->fifo[i].state = qemu_get_be32(f); + for (j = 0; j < 16; j++) { + s->fifo[i].data[j] = qemu_get_be32(f); + } + s->ssmux[i] = qemu_get_be32(f); + s->ssctl[i] = qemu_get_be32(f); + } + s->noise = qemu_get_be32(f); + + return 0; +} + static qemu_irq stellaris_adc_init(uint32_t base, qemu_irq irq) { stellaris_adc_state *s; @@ -998,6 +1202,8 @@ cpu_register_physical_memory(base, 0x00001000, iomemtype); stellaris_adc_reset(s); qi = qemu_allocate_irqs(stellaris_adc_trigger, s, 1); + register_savevm("stellaris_adc", -1, 1, + stellaris_adc_save, stellaris_adc_load, s); return qi[0]; } @@ -1029,6 +1235,25 @@ return s->xfer_cb[s->current_dev](s->opaque[s->current_dev], val); } +static void stellaris_ssi_bus_save(QEMUFile *f, void *opaque) +{ + stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; + + qemu_put_be32(f, s->current_dev); +} + +static int stellaris_ssi_bus_load(QEMUFile *f, void *opaque, int version_id) +{ + stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; + + if (version_id != 1) + return -EINVAL; + + s->current_dev = qemu_get_be32(f); + + return 0; +} + static void *stellaris_ssi_bus_init(qemu_irq *irqp, ssi_xfer_cb cb0, void *opaque0, ssi_xfer_cb cb1, void *opaque1) @@ -1043,6 +1268,8 @@ s->opaque[1] = opaque1; qi = qemu_allocate_irqs(stellaris_ssi_bus_select, s, 1); *irqp = *qi; + register_savevm("stellaris_ssi_bus", -1, 1, + stellaris_ssi_bus_save, stellaris_ssi_bus_load, s); return s; } @@ -1081,8 +1308,8 @@ static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31}; qemu_irq *pic; - qemu_irq *gpio_in[5]; - qemu_irq *gpio_out[5]; + qemu_irq *gpio_in[7]; + qemu_irq *gpio_out[7]; qemu_irq adc; int sram_size; int flash_size; @@ -1169,7 +1396,7 @@ } /* FIXME: Figure out how to generate these from stellaris_boards. */ -static void lm3s811evb_init(int ram_size, int vga_ram_size, +static void lm3s811evb_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -1177,7 +1404,7 @@ stellaris_init(kernel_filename, cpu_model, ds, &stellaris_boards[0]); } -static void lm3s6965evb_init(int ram_size, int vga_ram_size, +static void lm3s6965evb_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -1186,13 +1413,15 @@ } QEMUMachine lm3s811evb_machine = { - "lm3s811evb", - "Stellaris LM3S811EVB", - lm3s811evb_init, + .name = "lm3s811evb", + .desc = "Stellaris LM3S811EVB", + .init = lm3s811evb_init, + .ram_require = (64 * 1024 + 8 * 1024) | RAMSIZE_FIXED, }; QEMUMachine lm3s6965evb_machine = { - "lm3s6965evb", - "Stellaris LM3S6965EVB", - lm3s6965evb_init, + .name = "lm3s6965evb", + .desc = "Stellaris LM3S6965EVB", + .init = lm3s6965evb_init, + .ram_require = (256 * 1024 + 64 * 1024) | RAMSIZE_FIXED, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/stellaris_enet.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/stellaris_enet.c --- qemu-0.9.1/hw/stellaris_enet.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/stellaris_enet.c 2008-07-02 17:48:32.000000000 +0100 @@ -326,6 +326,67 @@ s->tx_frame_len = -1; } +static void stellaris_enet_save(QEMUFile *f, void *opaque) +{ + stellaris_enet_state *s = (stellaris_enet_state *)opaque; + int i; + + qemu_put_be32(f, s->ris); + qemu_put_be32(f, s->im); + qemu_put_be32(f, s->rctl); + qemu_put_be32(f, s->tctl); + qemu_put_be32(f, s->thr); + qemu_put_be32(f, s->mctl); + qemu_put_be32(f, s->mdv); + qemu_put_be32(f, s->mtxd); + qemu_put_be32(f, s->mrxd); + qemu_put_be32(f, s->np); + qemu_put_be32(f, s->tx_frame_len); + qemu_put_be32(f, s->tx_fifo_len); + qemu_put_buffer(f, s->tx_fifo, sizeof(s->tx_fifo)); + for (i = 0; i < 31; i++) { + qemu_put_be32(f, s->rx[i].len); + qemu_put_buffer(f, s->rx[i].data, sizeof(s->rx[i].data)); + + } + qemu_put_be32(f, s->next_packet); + qemu_put_be32(f, s->rx_fifo - s->rx[s->next_packet].data); + qemu_put_be32(f, s->rx_fifo_len); +} + +static int stellaris_enet_load(QEMUFile *f, void *opaque, int version_id) +{ + stellaris_enet_state *s = (stellaris_enet_state *)opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + s->ris = qemu_get_be32(f); + s->im = qemu_get_be32(f); + s->rctl = qemu_get_be32(f); + s->tctl = qemu_get_be32(f); + s->thr = qemu_get_be32(f); + s->mctl = qemu_get_be32(f); + s->mdv = qemu_get_be32(f); + s->mtxd = qemu_get_be32(f); + s->mrxd = qemu_get_be32(f); + s->np = qemu_get_be32(f); + s->tx_frame_len = qemu_get_be32(f); + s->tx_fifo_len = qemu_get_be32(f); + qemu_get_buffer(f, s->tx_fifo, sizeof(s->tx_fifo)); + for (i = 0; i < 31; i++) { + s->rx[i].len = qemu_get_be32(f); + qemu_get_buffer(f, s->rx[i].data, sizeof(s->rx[i].data)); + + } + s->next_packet = qemu_get_be32(f); + s->rx_fifo = s->rx[s->next_packet].data + qemu_get_be32(f); + s->rx_fifo_len = qemu_get_be32(f); + + return 0; +} + void stellaris_enet_init(NICInfo *nd, uint32_t base, qemu_irq irq) { stellaris_enet_state *s; @@ -344,4 +405,6 @@ stellaris_enet_can_receive, s); stellaris_enet_reset(s); + register_savevm("stellaris_enet", -1, 1, + stellaris_enet_save, stellaris_enet_load, s); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/stellaris_input.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/stellaris_input.c --- qemu-0.9.1/hw/stellaris_input.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/stellaris_input.c 2008-07-02 17:48:32.000000000 +0100 @@ -47,6 +47,31 @@ s->extension = 0; } +static void stellaris_gamepad_save(QEMUFile *f, void *opaque) +{ + gamepad_state *s = (gamepad_state *)opaque; + int i; + + qemu_put_be32(f, s->extension); + for (i = 0; i < s->num_buttons; i++) + qemu_put_byte(f, s->buttons[i].pressed); +} + +static int stellaris_gamepad_load(QEMUFile *f, void *opaque, int version_id) +{ + gamepad_state *s = (gamepad_state *)opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + s->extension = qemu_get_be32(f); + for (i = 0; i < s->num_buttons; i++) + s->buttons[i].pressed = qemu_get_byte(f); + + return 0; +} + /* Returns an array 5 ouput slots. */ void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode) { @@ -61,6 +86,8 @@ } s->num_buttons = n; qemu_add_kbd_event_handler(stellaris_gamepad_put_key, s); + register_savevm("stellaris_gamepad", -1, 1, + stellaris_gamepad_save, stellaris_gamepad_load, s); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/sun4c_intctl.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/sun4c_intctl.c --- qemu-0.9.1/hw/sun4c_intctl.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/sun4c_intctl.c 2008-05-12 17:13:33.000000000 +0100 @@ -68,7 +68,8 @@ return ret; } -static void sun4c_intctl_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static void sun4c_intctl_mem_writeb(void *opaque, target_phys_addr_t addr, + uint32_t val) { Sun4c_INTCTLState *s = opaque; @@ -94,7 +95,8 @@ { Sun4c_INTCTLState *s = opaque; - term_printf("master: pending 0x%2.2x, enabled 0x%2.2x\n", s->pending, s->reg); + term_printf("master: pending 0x%2.2x, enabled 0x%2.2x\n", s->pending, + s->reg); } void sun4c_irq_info(void *opaque) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/sun4m.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/sun4m.c --- qemu-0.9.1/hw/sun4m.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/sun4m.c 2008-11-05 19:25:39.000000000 +0000 @@ -31,6 +31,10 @@ #include "net.h" #include "boards.h" #include "firmware_abi.h" +#include "scsi.h" +#include "pc.h" +#include "isa.h" +#include "fw_cfg.h" //#define DEBUG_IRQ @@ -38,7 +42,8 @@ * Sun4m architecture was used in the following machines: * * SPARCserver 6xxMP/xx - * SPARCclassic (SPARCclassic Server)(SPARCstation LC) (4/15), SPARCclassic X (4/10) + * SPARCclassic (SPARCclassic Server)(SPARCstation LC) (4/15), + * SPARCclassic X (4/10) * SPARCstation LX/ZX (4/30) * SPARCstation Voyager * SPARCstation 10/xx, SPARCserver 10/xx @@ -71,28 +76,33 @@ #define KERNEL_LOAD_ADDR 0x00004000 #define CMDLINE_ADDR 0x007ff000 #define INITRD_LOAD_ADDR 0x00800000 -#define PROM_SIZE_MAX (512 * 1024) +#define PROM_SIZE_MAX (1024 * 1024) #define PROM_VADDR 0xffd00000 #define PROM_FILENAME "openbios-sparc32" +#define CFG_ADDR 0xd00000510ULL +#define FW_CFG_SUN4M_DEPTH (FW_CFG_ARCH_LOCAL + 0x00) + +// Control plane, 8-bit and 24-bit planes +#define TCX_SIZE (9 * 1024 * 1024) #define MAX_CPUS 16 #define MAX_PILS 16 -struct hwdef { +struct sun4m_hwdef { target_phys_addr_t iommu_base, slavio_base; target_phys_addr_t intctl_base, counter_base, nvram_base, ms_kb_base; target_phys_addr_t serial_base, fd_base; target_phys_addr_t idreg_base, dma_base, esp_base, le_base; - target_phys_addr_t tcx_base, cs_base, power_base; + target_phys_addr_t tcx_base, cs_base, apc_base, aux1_base, aux2_base; target_phys_addr_t ecc_base; uint32_t ecc_version; - target_phys_addr_t sun4c_intctl_base, sun4c_counter_base; long vram_size, nvram_size; // IRQ numbers are not PIL ones, but master interrupt controller // register bit numbers - int intctl_g_intr, esp_irq, le_irq, clock_irq, clock1_irq; - int ser_irq, ms_kb_irq, fd_irq, me_irq, cs_irq; - int machine_id; // For NVRAM + int esp_irq, le_irq, clock_irq, clock1_irq; + int ser_irq, ms_kb_irq, fd_irq, me_irq, cs_irq, ecc_irq; + uint8_t nvram_machine_id; + uint16_t machine_id; uint32_t iommu_version; uint32_t intbit_to_level[32]; uint64_t max_mem; @@ -113,18 +123,31 @@ // IRQ numbers are not PIL ones, but SBI register bit numbers int esp_irq, le_irq, clock_irq, clock1_irq; int ser_irq, ms_kb_irq, me_irq; - int machine_id; // For NVRAM + uint8_t nvram_machine_id; + uint16_t machine_id; uint32_t iounit_version; uint64_t max_mem; const char * const default_cpu_model; }; -/* TSC handling */ - -uint64_t cpu_get_tsc() -{ - return qemu_get_clock(vm_clock); -} +struct sun4c_hwdef { + target_phys_addr_t iommu_base, slavio_base; + target_phys_addr_t intctl_base, counter_base, nvram_base, ms_kb_base; + target_phys_addr_t serial_base, fd_base; + target_phys_addr_t idreg_base, dma_base, esp_base, le_base; + target_phys_addr_t tcx_base, aux1_base; + long vram_size, nvram_size; + // IRQ numbers are not PIL ones, but master interrupt controller + // register bit numbers + int esp_irq, le_irq, clock_irq, clock1_irq; + int ser_irq, ms_kb_irq, fd_irq, me_irq; + uint8_t nvram_machine_id; + uint16_t machine_id; + uint32_t iommu_version; + uint32_t intbit_to_level[32]; + uint64_t max_mem; + const char * const default_cpu_model; +}; int DMA_get_channel_mode (int nchan) { @@ -141,7 +164,6 @@ void DMA_hold_DREQ (int nchan) {} void DMA_release_DREQ (int nchan) {} void DMA_schedule(int nchan) {} -void DMA_run (void) {} void DMA_init (int high_page_enable) {} void DMA_register_channel (int nchan, DMA_transfer_handler transfer_handler, @@ -149,13 +171,32 @@ { } -extern int nographic; +static int nvram_boot_set(void *opaque, const char *boot_device) +{ + unsigned int i; + uint8_t image[sizeof(ohwcfg_v3_t)]; + ohwcfg_v3_t *header = (ohwcfg_v3_t *)ℑ + m48t59_t *nvram = (m48t59_t *)opaque; + + for (i = 0; i < sizeof(image); i++) + image[i] = m48t59_read(nvram, i) & 0xff; + + pstrcpy((char *)header->boot_devices, sizeof(header->boot_devices), + boot_device); + header->nboot_devices = strlen(boot_device) & 0xff; + header->crc = cpu_to_be16(OHW_compute_crc(header, 0x00, 0xF8)); + + for (i = 0; i < sizeof(image); i++) + m48t59_write(nvram, i, image[i]); + + return 0; +} static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline, - const char *boot_devices, uint32_t RAM_size, + const char *boot_devices, ram_addr_t RAM_size, uint32_t kernel_size, int width, int height, int depth, - int machine_id, const char *arch) + int nvram_machine_id, const char *arch) { unsigned int i; uint32_t start, end; @@ -167,22 +208,24 @@ memset(image, '\0', sizeof(image)); // Try to match PPC NVRAM - strcpy(header->struct_ident, "QEMU_BIOS"); + pstrcpy((char *)header->struct_ident, sizeof(header->struct_ident), + "QEMU_BIOS"); header->struct_version = cpu_to_be32(3); /* structure v3 */ header->nvram_size = cpu_to_be16(0x2000); header->nvram_arch_ptr = cpu_to_be16(sizeof(ohwcfg_v3_t)); header->nvram_arch_size = cpu_to_be16(sizeof(struct sparc_arch_cfg)); - strcpy(header->arch, arch); + pstrcpy((char *)header->arch, sizeof(header->arch), arch); header->nb_cpus = smp_cpus & 0xff; header->RAM0_base = 0; header->RAM0_size = cpu_to_be64((uint64_t)RAM_size); - strcpy(header->boot_devices, boot_devices); + pstrcpy((char *)header->boot_devices, sizeof(header->boot_devices), + boot_devices); header->nboot_devices = strlen(boot_devices) & 0xff; header->kernel_image = cpu_to_be64((uint64_t)KERNEL_LOAD_ADDR); header->kernel_size = cpu_to_be64((uint64_t)kernel_size); if (cmdline) { - strcpy(phys_ram_base + CMDLINE_ADDR, cmdline); + pstrcpy_targphys(CMDLINE_ADDR, TARGET_PAGE_SIZE, cmdline); header->cmdline = cpu_to_be64((uint64_t)CMDLINE_ADDR); header->cmdline_size = cpu_to_be64((uint64_t)strlen(cmdline)); } @@ -205,7 +248,7 @@ // Variable partition part_header = (struct OpenBIOS_nvpart_v1 *)&image[start]; part_header->signature = OPENBIOS_PART_SYSTEM; - strcpy(part_header->name, "system"); + pstrcpy(part_header->name, sizeof(part_header->name), "system"); end = start + sizeof(struct OpenBIOS_nvpart_v1); for (i = 0; i < nb_prom_envs; i++) @@ -221,26 +264,29 @@ start = end; part_header = (struct OpenBIOS_nvpart_v1 *)&image[start]; part_header->signature = OPENBIOS_PART_FREE; - strcpy(part_header->name, "free"); + pstrcpy(part_header->name, sizeof(part_header->name), "free"); end = 0x1fd0; OpenBIOS_finish_partition(part_header, end - start); - Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr, machine_id); + Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr, + nvram_machine_id); for (i = 0; i < sizeof(image); i++) m48t59_write(nvram, i, image[i]); + + qemu_register_boot_set(nvram_boot_set, nvram); } static void *slavio_intctl; -void pic_info() +void pic_info(void) { if (slavio_intctl) slavio_pic_info(slavio_intctl); } -void irq_info() +void irq_info(void) { if (slavio_intctl) slavio_irq_info(slavio_intctl); @@ -257,12 +303,15 @@ int old_interrupt = env->interrupt_index; env->interrupt_index = TT_EXTINT | i; - if (old_interrupt != env->interrupt_index) + if (old_interrupt != env->interrupt_index) { + DPRINTF("Set CPU IRQ %d\n", i); cpu_interrupt(env, CPU_INTERRUPT_HARD); + } break; } } } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) { + DPRINTF("Reset CPU IRQ %d\n", env->interrupt_index & 15); env->interrupt_index = 0; cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); } @@ -311,9 +360,15 @@ env->halted = 1; } +static void cpu_halt_signal(void *opaque, int irq, int level) +{ + if (level && cpu_single_env) + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); +} + static unsigned long sun4m_load_kernel(const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename) + const char *initrd_filename, + ram_addr_t RAM_size) { int linux_boot; unsigned int i; @@ -326,9 +381,12 @@ kernel_size = load_elf(kernel_filename, -0xf0000000ULL, NULL, NULL, NULL); if (kernel_size < 0) - kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR, + RAM_size - KERNEL_LOAD_ADDR); if (kernel_size < 0) - kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + kernel_size = load_image_targphys(kernel_filename, + KERNEL_LOAD_ADDR, + RAM_size - KERNEL_LOAD_ADDR); if (kernel_size < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); @@ -338,7 +396,9 @@ /* load initrd */ initrd_size = 0; if (initrd_filename) { - initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); + initrd_size = load_image_targphys(initrd_filename, + INITRD_LOAD_ADDR, + RAM_size - INITRD_LOAD_ADDR); if (initrd_size < 0) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); @@ -347,10 +407,9 @@ } if (initrd_size > 0) { for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { - if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i) - == 0x48647253) { // HdrS - stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR); - stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size); + if (ldl_phys(KERNEL_LOAD_ADDR + i) == 0x48647253) { // HdrS + stl_phys(KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR); + stl_phys(KERNEL_LOAD_ADDR + i + 20, initrd_size); break; } } @@ -359,7 +418,7 @@ return kernel_size; } -static void sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, +static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, @@ -372,11 +431,15 @@ qemu_irq *cpu_irqs[MAX_CPUS], *slavio_irq, *slavio_cpu_irq, *espdma_irq, *ledma_irq; qemu_irq *esp_reset, *le_reset; - unsigned long prom_offset, kernel_size; + qemu_irq *fdc_tc; + qemu_irq *cpu_halt; + ram_addr_t ram_offset, prom_offset, tcx_offset, idreg_offset; + unsigned long kernel_size; int ret; char buf[1024]; BlockDriverState *fd[MAX_FD]; - int index; + int drive_index; + void *fw_cfg; /* init CPUs */ if (!cpu_model) @@ -396,7 +459,6 @@ qemu_register_reset(secondary_cpu_reset, env); env->halted = 1; } - register_savevm("cpu", i, 3, cpu_save, cpu_load, env); cpu_irqs[i] = qemu_allocate_irqs(cpu_set_irq, envs[i], MAX_PILS); env->prom_addr = hwdef->slavio_base; } @@ -407,15 +469,17 @@ /* allocate RAM */ if ((uint64_t)RAM_size > hwdef->max_mem) { - fprintf(stderr, "qemu: Too much memory for this machine: %d, maximum %d\n", - (unsigned int)RAM_size / (1024 * 1024), + fprintf(stderr, + "qemu: Too much memory for this machine: %d, maximum %d\n", + (unsigned int)(RAM_size / (1024 * 1024)), (unsigned int)(hwdef->max_mem / (1024 * 1024))); exit(1); } - cpu_register_physical_memory(0, RAM_size, 0); + ram_offset = qemu_ram_alloc(RAM_size); + cpu_register_physical_memory(0, RAM_size, ram_offset); /* load boot prom */ - prom_offset = RAM_size + hwdef->vram_size; + prom_offset = qemu_ram_alloc(PROM_SIZE_MAX); cpu_register_physical_memory(hwdef->slavio_base, (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK, @@ -426,13 +490,12 @@ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); ret = load_elf(buf, hwdef->slavio_base - PROM_VADDR, NULL, NULL, NULL); if (ret < 0 || ret > PROM_SIZE_MAX) - ret = load_image(buf, phys_ram_base + prom_offset); + ret = load_image_targphys(buf, hwdef->slavio_base, PROM_SIZE_MAX); if (ret < 0 || ret > PROM_SIZE_MAX) { fprintf(stderr, "qemu: could not load prom '%s'\n", buf); exit(1); } - prom_offset += (ret + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; /* set up devices */ slavio_intctl = slavio_intctl_init(hwdef->intctl_base, @@ -443,10 +506,13 @@ hwdef->clock_irq); if (hwdef->idreg_base != (target_phys_addr_t)-1) { - stl_raw(phys_ram_base + prom_offset, 0xfe810103); + static const uint8_t idreg_data[] = { 0xfe, 0x81, 0x01, 0x03 }; - cpu_register_physical_memory(hwdef->idreg_base, sizeof(uint32_t), - prom_offset | IO_MEM_ROM); + idreg_offset = qemu_ram_alloc(sizeof(idreg_data)); + cpu_register_physical_memory(hwdef->idreg_base, sizeof(idreg_data), + idreg_offset | IO_MEM_ROM); + cpu_physical_memory_write_rom(hwdef->idreg_base, idreg_data, + sizeof(idreg_data)); } iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version, @@ -463,7 +529,8 @@ fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth); exit (1); } - tcx_init(ds, hwdef->tcx_base, phys_ram_base + RAM_size, RAM_size, + tcx_offset = qemu_ram_alloc(hwdef->vram_size); + tcx_init(ds, hwdef->tcx_base, phys_ram_base + tcx_offset, tcx_offset, hwdef->vram_size, graphic_width, graphic_height, graphic_depth); if (nd_table[0].model == NULL @@ -490,14 +557,21 @@ slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq], serial_hds[1], serial_hds[0]); + cpu_halt = qemu_allocate_irqs(cpu_halt_signal, NULL, 1); + slavio_misc = slavio_misc_init(hwdef->slavio_base, hwdef->apc_base, + hwdef->aux1_base, hwdef->aux2_base, + slavio_irq[hwdef->me_irq], cpu_halt[0], + &fdc_tc); + if (hwdef->fd_base != (target_phys_addr_t)-1) { /* there is zero or one floppy drive */ - fd[1] = fd[0] = NULL; - index = drive_get_index(IF_FLOPPY, 0, 0); - if (index != -1) - fd[0] = drives_table[index].bdrv; + memset(fd, 0, sizeof(fd)); + drive_index = drive_get_index(IF_FLOPPY, 0, 0); + if (drive_index != -1) + fd[0] = drives_table[drive_index].bdrv; - sun4m_fdctrl_init(slavio_irq[hwdef->fd_irq], hwdef->fd_base, fd); + sun4m_fdctrl_init(slavio_irq[hwdef->fd_irq], hwdef->fd_base, fd, + fdc_tc); } if (drive_get_max_bus(IF_SCSI) > 0) { @@ -505,171 +579,55 @@ exit(1); } - main_esp = esp_init(hwdef->esp_base, espdma, *espdma_irq, - esp_reset); + main_esp = esp_init(hwdef->esp_base, 2, + espdma_memory_read, espdma_memory_write, + espdma, *espdma_irq, esp_reset); for (i = 0; i < ESP_MAX_DEVS; i++) { - index = drive_get_index(IF_SCSI, 0, i); - if (index == -1) + drive_index = drive_get_index(IF_SCSI, 0, i); + if (drive_index == -1) continue; - esp_scsi_attach(main_esp, drives_table[index].bdrv, i); + esp_scsi_attach(main_esp, drives_table[drive_index].bdrv, i); } - slavio_misc = slavio_misc_init(hwdef->slavio_base, hwdef->power_base, - slavio_irq[hwdef->me_irq]); if (hwdef->cs_base != (target_phys_addr_t)-1) cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl); - kernel_size = sun4m_load_kernel(kernel_filename, kernel_cmdline, - initrd_filename); + kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename, + RAM_size); nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, RAM_size, kernel_size, graphic_width, - graphic_height, graphic_depth, hwdef->machine_id, "Sun4m"); + graphic_height, graphic_depth, hwdef->nvram_machine_id, + "Sun4m"); if (hwdef->ecc_base != (target_phys_addr_t)-1) - ecc_init(hwdef->ecc_base, hwdef->ecc_version); -} - -static void sun4c_hw_init(const struct hwdef *hwdef, int RAM_size, - const char *boot_device, - DisplayState *ds, const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) -{ - CPUState *env; - unsigned int i; - void *iommu, *espdma, *ledma, *main_esp, *nvram; - qemu_irq *cpu_irqs, *slavio_irq, *espdma_irq, *ledma_irq; - qemu_irq *esp_reset, *le_reset; - unsigned long prom_offset, kernel_size; - int ret; - char buf[1024]; - BlockDriverState *fd[MAX_FD]; - int index; - - /* init CPU */ - if (!cpu_model) - cpu_model = hwdef->default_cpu_model; - - env = cpu_init(cpu_model); - if (!env) { - fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n"); - exit(1); - } - - cpu_sparc_set_id(env, 0); - - qemu_register_reset(main_cpu_reset, env); - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); - cpu_irqs = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS); - env->prom_addr = hwdef->slavio_base; - - /* allocate RAM */ - if ((uint64_t)RAM_size > hwdef->max_mem) { - fprintf(stderr, "qemu: Too much memory for this machine: %d, maximum %d\n", - (unsigned int)RAM_size / (1024 * 1024), - (unsigned int)hwdef->max_mem / (1024 * 1024)); - exit(1); - } - cpu_register_physical_memory(0, RAM_size, 0); - - /* load boot prom */ - prom_offset = RAM_size + hwdef->vram_size; - cpu_register_physical_memory(hwdef->slavio_base, - (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & - TARGET_PAGE_MASK, - prom_offset | IO_MEM_ROM); - - if (bios_name == NULL) - bios_name = PROM_FILENAME; - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); - ret = load_elf(buf, hwdef->slavio_base - PROM_VADDR, NULL, NULL, NULL); - if (ret < 0 || ret > PROM_SIZE_MAX) - ret = load_image(buf, phys_ram_base + prom_offset); - if (ret < 0 || ret > PROM_SIZE_MAX) { - fprintf(stderr, "qemu: could not load prom '%s'\n", - buf); - exit(1); - } - prom_offset += (ret + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; - - /* set up devices */ - slavio_intctl = sun4c_intctl_init(hwdef->sun4c_intctl_base, - &slavio_irq, cpu_irqs); - - iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version, - slavio_irq[hwdef->me_irq]); - - espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq], - iommu, &espdma_irq, &esp_reset); - - ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, - slavio_irq[hwdef->le_irq], iommu, &ledma_irq, - &le_reset); - - if (graphic_depth != 8 && graphic_depth != 24) { - fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth); - exit (1); - } - tcx_init(ds, hwdef->tcx_base, phys_ram_base + RAM_size, RAM_size, - hwdef->vram_size, graphic_width, graphic_height, graphic_depth); - - if (nd_table[0].model == NULL - || strcmp(nd_table[0].model, "lance") == 0) { - lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset); - } else if (strcmp(nd_table[0].model, "?") == 0) { - fprintf(stderr, "qemu: Supported NICs: lance\n"); - exit (1); - } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); - exit (1); - } - - nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, - hwdef->nvram_size, 2); - - slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq], - nographic); - // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device - // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device - slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq], - serial_hds[1], serial_hds[0]); - - if (hwdef->fd_base != (target_phys_addr_t)-1) { - /* there is zero or one floppy drive */ - fd[1] = fd[0] = NULL; - index = drive_get_index(IF_FLOPPY, 0, 0); - if (index != -1) - fd[0] = drives_table[index].bdrv; - - sun4m_fdctrl_init(slavio_irq[hwdef->fd_irq], hwdef->fd_base, fd); - } - - if (drive_get_max_bus(IF_SCSI) > 0) { - fprintf(stderr, "qemu: too many SCSI bus\n"); - exit(1); - } - - main_esp = esp_init(hwdef->esp_base, espdma, *espdma_irq, - esp_reset); - - for (i = 0; i < ESP_MAX_DEVS; i++) { - index = drive_get_index(IF_SCSI, 0, i); - if (index == -1) - continue; - esp_scsi_attach(main_esp, drives_table[index].bdrv, i); - } - - kernel_size = sun4m_load_kernel(kernel_filename, kernel_cmdline, - initrd_filename); + ecc_init(hwdef->ecc_base, slavio_irq[hwdef->ecc_irq], + hwdef->ecc_version); - nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, - boot_device, RAM_size, kernel_size, graphic_width, - graphic_height, graphic_depth, hwdef->machine_id, "Sun4c"); -} + fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); + fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); + fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth); +} + +enum { + ss2_id = 0, + ss5_id = 32, + vger_id, + lx_id, + ss4_id, + scls_id, + sbook_id, + ss10_id = 64, + ss20_id, + ss600mp_id, + ss1000_id = 96, + ss2000_id, +}; -static const struct hwdef hwdefs[] = { +static const struct sun4m_hwdef sun4m_hwdefs[] = { /* SS-5 */ { .iommu_base = 0x10000000, @@ -686,10 +644,10 @@ .dma_base = 0x78400000, .esp_base = 0x78800000, .le_base = 0x78c00000, - .power_base = 0x7a000000, + .apc_base = 0x6a000000, + .aux1_base = 0x71900000, + .aux2_base = 0x71910000, .ecc_base = -1, - .sun4c_intctl_base = -1, - .sun4c_counter_base = -1, .vram_size = 0x00100000, .nvram_size = 0x2000, .esp_irq = 18, @@ -701,7 +659,8 @@ .fd_irq = 22, .me_irq = 30, .cs_irq = 5, - .machine_id = 0x80, + .nvram_machine_id = 0x80, + .machine_id = ss5_id, .iommu_version = 0x05000000, .intbit_to_level = { 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, @@ -726,11 +685,11 @@ .dma_base = 0xef0400000ULL, .esp_base = 0xef0800000ULL, .le_base = 0xef0c00000ULL, - .power_base = 0xefa000000ULL, + .apc_base = 0xefa000000ULL, // XXX should not exist + .aux1_base = 0xff1800000ULL, + .aux2_base = 0xff1a01000ULL, .ecc_base = 0xf00000000ULL, .ecc_version = 0x10000000, // version 0, implementation 1 - .sun4c_intctl_base = -1, - .sun4c_counter_base = -1, .vram_size = 0x00100000, .nvram_size = 0x2000, .esp_irq = 18, @@ -742,13 +701,15 @@ .fd_irq = 22, .me_irq = 30, .cs_irq = -1, - .machine_id = 0x72, + .ecc_irq = 28, + .nvram_machine_id = 0x72, + .machine_id = ss10_id, .iommu_version = 0x03000000, .intbit_to_level = { 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, }, - .max_mem = 0xffffffff, // XXX actually first 62GB ok + .max_mem = 0xf00000000ULL, .default_cpu_model = "TI SuperSparc II", }, /* SS-600MP */ @@ -767,11 +728,11 @@ .dma_base = 0xef0081000ULL, .esp_base = 0xef0080000ULL, .le_base = 0xef0060000ULL, - .power_base = 0xefa000000ULL, + .apc_base = 0xefa000000ULL, // XXX should not exist + .aux1_base = 0xff1800000ULL, + .aux2_base = 0xff1a01000ULL, // XXX should not exist .ecc_base = 0xf00000000ULL, .ecc_version = 0x00000000, // version 0, implementation 0 - .sun4c_intctl_base = -1, - .sun4c_counter_base = -1, .vram_size = 0x00100000, .nvram_size = 0x2000, .esp_irq = 18, @@ -783,13 +744,15 @@ .fd_irq = 22, .me_irq = 30, .cs_irq = -1, - .machine_id = 0x71, + .ecc_irq = 28, + .nvram_machine_id = 0x71, + .machine_id = ss600mp_id, .iommu_version = 0x01000000, .intbit_to_level = { 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, }, - .max_mem = 0xffffffff, // XXX actually first 62GB ok + .max_mem = 0xf00000000ULL, .default_cpu_model = "TI SuperSparc II", }, /* SS-20 */ @@ -808,11 +771,11 @@ .dma_base = 0xef0400000ULL, .esp_base = 0xef0800000ULL, .le_base = 0xef0c00000ULL, - .power_base = 0xefa000000ULL, + .apc_base = 0xefa000000ULL, // XXX should not exist + .aux1_base = 0xff1800000ULL, + .aux2_base = 0xff1a01000ULL, .ecc_base = 0xf00000000ULL, .ecc_version = 0x20000000, // version 0, implementation 2 - .sun4c_intctl_base = -1, - .sun4c_counter_base = -1, .vram_size = 0x00100000, .nvram_size = 0x2000, .esp_irq = 18, @@ -824,130 +787,399 @@ .fd_irq = 22, .me_irq = 30, .cs_irq = -1, - .machine_id = 0x72, + .ecc_irq = 28, + .nvram_machine_id = 0x72, + .machine_id = ss20_id, .iommu_version = 0x13000000, .intbit_to_level = { 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, }, - .max_mem = 0xffffffff, // XXX actually first 62GB ok + .max_mem = 0xf00000000ULL, .default_cpu_model = "TI SuperSparc II", }, - /* SS-2 */ + /* Voyager */ { - .iommu_base = 0xf8000000, - .tcx_base = 0xfe000000, + .iommu_base = 0x10000000, + .tcx_base = 0x50000000, .cs_base = -1, - .slavio_base = 0xf6000000, - .ms_kb_base = 0xf0000000, - .serial_base = 0xf1000000, - .nvram_base = 0xf2000000, - .fd_base = 0xf7200000, - .counter_base = -1, - .intctl_base = -1, - .dma_base = 0xf8400000, - .esp_base = 0xf8800000, - .le_base = 0xf8c00000, - .power_base = -1, - .sun4c_intctl_base = 0xf5000000, - .sun4c_counter_base = 0xf3000000, + .slavio_base = 0x70000000, + .ms_kb_base = 0x71000000, + .serial_base = 0x71100000, + .nvram_base = 0x71200000, + .fd_base = 0x71400000, + .counter_base = 0x71d00000, + .intctl_base = 0x71e00000, + .idreg_base = 0x78000000, + .dma_base = 0x78400000, + .esp_base = 0x78800000, + .le_base = 0x78c00000, + .apc_base = 0x71300000, // pmc + .aux1_base = 0x71900000, + .aux2_base = 0x71910000, + .ecc_base = -1, .vram_size = 0x00100000, - .nvram_size = 0x800, - .esp_irq = 2, - .le_irq = 3, - .clock_irq = 5, - .clock1_irq = 7, - .ms_kb_irq = 1, - .ser_irq = 1, - .fd_irq = 1, - .me_irq = 1, + .nvram_size = 0x2000, + .esp_irq = 18, + .le_irq = 16, + .clock_irq = 7, + .clock1_irq = 19, + .ms_kb_irq = 14, + .ser_irq = 15, + .fd_irq = 22, + .me_irq = 30, .cs_irq = -1, - .machine_id = 0x55, + .nvram_machine_id = 0x80, + .machine_id = vger_id, + .iommu_version = 0x05000000, + .intbit_to_level = { + 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, + 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, + }, .max_mem = 0x10000000, - .default_cpu_model = "Cypress CY7C601", + .default_cpu_model = "Fujitsu MB86904", + }, + /* LX */ + { + .iommu_base = 0x10000000, + .tcx_base = 0x50000000, + .cs_base = -1, + .slavio_base = 0x70000000, + .ms_kb_base = 0x71000000, + .serial_base = 0x71100000, + .nvram_base = 0x71200000, + .fd_base = 0x71400000, + .counter_base = 0x71d00000, + .intctl_base = 0x71e00000, + .idreg_base = 0x78000000, + .dma_base = 0x78400000, + .esp_base = 0x78800000, + .le_base = 0x78c00000, + .apc_base = -1, + .aux1_base = 0x71900000, + .aux2_base = 0x71910000, + .ecc_base = -1, + .vram_size = 0x00100000, + .nvram_size = 0x2000, + .esp_irq = 18, + .le_irq = 16, + .clock_irq = 7, + .clock1_irq = 19, + .ms_kb_irq = 14, + .ser_irq = 15, + .fd_irq = 22, + .me_irq = 30, + .cs_irq = -1, + .nvram_machine_id = 0x80, + .machine_id = lx_id, + .iommu_version = 0x04000000, + .intbit_to_level = { + 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, + 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, + }, + .max_mem = 0x10000000, + .default_cpu_model = "TI MicroSparc I", + }, + /* SS-4 */ + { + .iommu_base = 0x10000000, + .tcx_base = 0x50000000, + .cs_base = 0x6c000000, + .slavio_base = 0x70000000, + .ms_kb_base = 0x71000000, + .serial_base = 0x71100000, + .nvram_base = 0x71200000, + .fd_base = 0x71400000, + .counter_base = 0x71d00000, + .intctl_base = 0x71e00000, + .idreg_base = 0x78000000, + .dma_base = 0x78400000, + .esp_base = 0x78800000, + .le_base = 0x78c00000, + .apc_base = 0x6a000000, + .aux1_base = 0x71900000, + .aux2_base = 0x71910000, + .ecc_base = -1, + .vram_size = 0x00100000, + .nvram_size = 0x2000, + .esp_irq = 18, + .le_irq = 16, + .clock_irq = 7, + .clock1_irq = 19, + .ms_kb_irq = 14, + .ser_irq = 15, + .fd_irq = 22, + .me_irq = 30, + .cs_irq = 5, + .nvram_machine_id = 0x80, + .machine_id = ss4_id, + .iommu_version = 0x05000000, + .intbit_to_level = { + 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, + 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, + }, + .max_mem = 0x10000000, + .default_cpu_model = "Fujitsu MB86904", + }, + /* SPARCClassic */ + { + .iommu_base = 0x10000000, + .tcx_base = 0x50000000, + .cs_base = -1, + .slavio_base = 0x70000000, + .ms_kb_base = 0x71000000, + .serial_base = 0x71100000, + .nvram_base = 0x71200000, + .fd_base = 0x71400000, + .counter_base = 0x71d00000, + .intctl_base = 0x71e00000, + .idreg_base = 0x78000000, + .dma_base = 0x78400000, + .esp_base = 0x78800000, + .le_base = 0x78c00000, + .apc_base = 0x6a000000, + .aux1_base = 0x71900000, + .aux2_base = 0x71910000, + .ecc_base = -1, + .vram_size = 0x00100000, + .nvram_size = 0x2000, + .esp_irq = 18, + .le_irq = 16, + .clock_irq = 7, + .clock1_irq = 19, + .ms_kb_irq = 14, + .ser_irq = 15, + .fd_irq = 22, + .me_irq = 30, + .cs_irq = -1, + .nvram_machine_id = 0x80, + .machine_id = scls_id, + .iommu_version = 0x05000000, + .intbit_to_level = { + 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, + 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, + }, + .max_mem = 0x10000000, + .default_cpu_model = "TI MicroSparc I", + }, + /* SPARCbook */ + { + .iommu_base = 0x10000000, + .tcx_base = 0x50000000, // XXX + .cs_base = -1, + .slavio_base = 0x70000000, + .ms_kb_base = 0x71000000, + .serial_base = 0x71100000, + .nvram_base = 0x71200000, + .fd_base = 0x71400000, + .counter_base = 0x71d00000, + .intctl_base = 0x71e00000, + .idreg_base = 0x78000000, + .dma_base = 0x78400000, + .esp_base = 0x78800000, + .le_base = 0x78c00000, + .apc_base = 0x6a000000, + .aux1_base = 0x71900000, + .aux2_base = 0x71910000, + .ecc_base = -1, + .vram_size = 0x00100000, + .nvram_size = 0x2000, + .esp_irq = 18, + .le_irq = 16, + .clock_irq = 7, + .clock1_irq = 19, + .ms_kb_irq = 14, + .ser_irq = 15, + .fd_irq = 22, + .me_irq = 30, + .cs_irq = -1, + .nvram_machine_id = 0x80, + .machine_id = sbook_id, + .iommu_version = 0x05000000, + .intbit_to_level = { + 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, + 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, + }, + .max_mem = 0x10000000, + .default_cpu_model = "TI MicroSparc I", }, }; -/* SPARCstation 5 hardware initialisation */ -static void ss5_init(int RAM_size, int vga_ram_size, - const char *boot_device, DisplayState *ds, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) -{ - sun4m_hw_init(&hwdefs[0], RAM_size, boot_device, ds, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); -} - -/* SPARCstation 10 hardware initialisation */ -static void ss10_init(int RAM_size, int vga_ram_size, - const char *boot_device, DisplayState *ds, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) -{ - sun4m_hw_init(&hwdefs[1], RAM_size, boot_device, ds, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); -} - -/* SPARCserver 600MP hardware initialisation */ -static void ss600mp_init(int RAM_size, int vga_ram_size, - const char *boot_device, DisplayState *ds, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) -{ - sun4m_hw_init(&hwdefs[2], RAM_size, boot_device, ds, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); -} - -/* SPARCstation 20 hardware initialisation */ -static void ss20_init(int RAM_size, int vga_ram_size, - const char *boot_device, DisplayState *ds, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) -{ - sun4m_hw_init(&hwdefs[3], RAM_size, boot_device, ds, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); -} - -/* SPARCstation 2 hardware initialisation */ -static void ss2_init(int RAM_size, int vga_ram_size, - const char *boot_device, DisplayState *ds, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) -{ - sun4c_hw_init(&hwdefs[4], RAM_size, boot_device, ds, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); -} - -QEMUMachine ss5_machine = { - "SS-5", - "Sun4m platform, SPARCstation 5", - ss5_init, -}; - -QEMUMachine ss10_machine = { - "SS-10", - "Sun4m platform, SPARCstation 10", - ss10_init, -}; - -QEMUMachine ss600mp_machine = { - "SS-600MP", - "Sun4m platform, SPARCserver 600MP", - ss600mp_init, -}; - -QEMUMachine ss20_machine = { - "SS-20", - "Sun4m platform, SPARCstation 20", - ss20_init, -}; - -QEMUMachine ss2_machine = { - "SS-2", - "Sun4c platform, SPARCstation 2", - ss2_init, -}; - +/* SPARCstation 5 hardware initialisation */ +static void ss5_init(ram_addr_t RAM_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + sun4m_hw_init(&sun4m_hwdefs[0], RAM_size, boot_device, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +/* SPARCstation 10 hardware initialisation */ +static void ss10_init(ram_addr_t RAM_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + sun4m_hw_init(&sun4m_hwdefs[1], RAM_size, boot_device, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +/* SPARCserver 600MP hardware initialisation */ +static void ss600mp_init(ram_addr_t RAM_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + sun4m_hw_init(&sun4m_hwdefs[2], RAM_size, boot_device, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +/* SPARCstation 20 hardware initialisation */ +static void ss20_init(ram_addr_t RAM_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + sun4m_hw_init(&sun4m_hwdefs[3], RAM_size, boot_device, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +/* SPARCstation Voyager hardware initialisation */ +static void vger_init(ram_addr_t RAM_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + sun4m_hw_init(&sun4m_hwdefs[4], RAM_size, boot_device, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +/* SPARCstation LX hardware initialisation */ +static void ss_lx_init(ram_addr_t RAM_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + sun4m_hw_init(&sun4m_hwdefs[5], RAM_size, boot_device, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +/* SPARCstation 4 hardware initialisation */ +static void ss4_init(ram_addr_t RAM_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + sun4m_hw_init(&sun4m_hwdefs[6], RAM_size, boot_device, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +/* SPARCClassic hardware initialisation */ +static void scls_init(ram_addr_t RAM_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + sun4m_hw_init(&sun4m_hwdefs[7], RAM_size, boot_device, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +/* SPARCbook hardware initialisation */ +static void sbook_init(ram_addr_t RAM_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + sun4m_hw_init(&sun4m_hwdefs[8], RAM_size, boot_device, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +QEMUMachine ss5_machine = { + .name = "SS-5", + .desc = "Sun4m platform, SPARCstation 5", + .init = ss5_init, + .ram_require = PROM_SIZE_MAX + TCX_SIZE, + .nodisk_ok = 1, + .use_scsi = 1, +}; + +QEMUMachine ss10_machine = { + .name = "SS-10", + .desc = "Sun4m platform, SPARCstation 10", + .init = ss10_init, + .ram_require = PROM_SIZE_MAX + TCX_SIZE, + .nodisk_ok = 1, + .use_scsi = 1, + .max_cpus = 4, +}; + +QEMUMachine ss600mp_machine = { + .name = "SS-600MP", + .desc = "Sun4m platform, SPARCserver 600MP", + .init = ss600mp_init, + .ram_require = PROM_SIZE_MAX + TCX_SIZE, + .nodisk_ok = 1, + .use_scsi = 1, + .max_cpus = 4, +}; + +QEMUMachine ss20_machine = { + .name = "SS-20", + .desc = "Sun4m platform, SPARCstation 20", + .init = ss20_init, + .ram_require = PROM_SIZE_MAX + TCX_SIZE, + .nodisk_ok = 1, + .use_scsi = 1, + .max_cpus = 4, +}; + +QEMUMachine voyager_machine = { + .name = "Voyager", + .desc = "Sun4m platform, SPARCstation Voyager", + .init = vger_init, + .ram_require = PROM_SIZE_MAX + TCX_SIZE, + .nodisk_ok = 1, + .use_scsi = 1, +}; + +QEMUMachine ss_lx_machine = { + .name = "LX", + .desc = "Sun4m platform, SPARCstation LX", + .init = ss_lx_init, + .ram_require = PROM_SIZE_MAX + TCX_SIZE, + .nodisk_ok = 1, + .use_scsi = 1, +}; + +QEMUMachine ss4_machine = { + .name = "SS-4", + .desc = "Sun4m platform, SPARCstation 4", + .init = ss4_init, + .ram_require = PROM_SIZE_MAX + TCX_SIZE, + .nodisk_ok = 1, + .use_scsi = 1, +}; + +QEMUMachine scls_machine = { + .name = "SPARCClassic", + .desc = "Sun4m platform, SPARCClassic", + .init = scls_init, + .ram_require = PROM_SIZE_MAX + TCX_SIZE, + .nodisk_ok = 1, + .use_scsi = 1, +}; + +QEMUMachine sbook_machine = { + .name = "SPARCbook", + .desc = "Sun4m platform, SPARCbook", + .init = sbook_init, + .ram_require = PROM_SIZE_MAX + TCX_SIZE, + .nodisk_ok = 1, + .use_scsi = 1, +}; + static const struct sun4d_hwdef sun4d_hwdefs[] = { /* SS-1000 */ { @@ -977,9 +1209,10 @@ .clock1_irq = 10, .ms_kb_irq = 12, .ser_irq = 12, - .machine_id = 0x80, + .nvram_machine_id = 0x80, + .machine_id = ss1000_id, .iounit_version = 0x03000000, - .max_mem = 0xffffffff, // XXX actually first 62GB ok + .max_mem = 0xf00000000ULL, .default_cpu_model = "TI SuperSparc II", }, /* SS-2000 */ @@ -1010,14 +1243,15 @@ .clock1_irq = 10, .ms_kb_irq = 12, .ser_irq = 12, - .machine_id = 0x80, + .nvram_machine_id = 0x80, + .machine_id = ss2000_id, .iounit_version = 0x03000000, - .max_mem = 0xffffffff, // XXX actually first 62GB ok + .max_mem = 0xf00000000ULL, .default_cpu_model = "TI SuperSparc II", }, }; -static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, int RAM_size, +static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, @@ -1029,10 +1263,12 @@ qemu_irq *cpu_irqs[MAX_CPUS], *sbi_irq, *sbi_cpu_irq, *espdma_irq, *ledma_irq; qemu_irq *esp_reset, *le_reset; - unsigned long prom_offset, kernel_size; + ram_addr_t ram_offset, prom_offset, tcx_offset; + unsigned long kernel_size; int ret; char buf[1024]; - int index; + int drive_index; + void *fw_cfg; /* init CPUs */ if (!cpu_model) @@ -1052,7 +1288,6 @@ qemu_register_reset(secondary_cpu_reset, env); env->halted = 1; } - register_savevm("cpu", i, 3, cpu_save, cpu_load, env); cpu_irqs[i] = qemu_allocate_irqs(cpu_set_irq, envs[i], MAX_PILS); env->prom_addr = hwdef->slavio_base; } @@ -1062,15 +1297,17 @@ /* allocate RAM */ if ((uint64_t)RAM_size > hwdef->max_mem) { - fprintf(stderr, "qemu: Too much memory for this machine: %d, maximum %d\n", - (unsigned int)RAM_size / (1024 * 1024), + fprintf(stderr, + "qemu: Too much memory for this machine: %d, maximum %d\n", + (unsigned int)(RAM_size / (1024 * 1024)), (unsigned int)(hwdef->max_mem / (1024 * 1024))); exit(1); } - cpu_register_physical_memory(0, RAM_size, 0); + ram_offset = qemu_ram_alloc(RAM_size); + cpu_register_physical_memory(0, RAM_size, ram_offset); /* load boot prom */ - prom_offset = RAM_size + hwdef->vram_size; + prom_offset = qemu_ram_alloc(PROM_SIZE_MAX); cpu_register_physical_memory(hwdef->slavio_base, (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK, @@ -1081,7 +1318,7 @@ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); ret = load_elf(buf, hwdef->slavio_base - PROM_VADDR, NULL, NULL, NULL); if (ret < 0 || ret > PROM_SIZE_MAX) - ret = load_image(buf, phys_ram_base + prom_offset); + ret = load_image_targphys(buf, hwdef->slavio_base, PROM_SIZE_MAX); if (ret < 0 || ret > PROM_SIZE_MAX) { fprintf(stderr, "qemu: could not load prom '%s'\n", buf); @@ -1107,7 +1344,8 @@ fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth); exit (1); } - tcx_init(ds, hwdef->tcx_base, phys_ram_base + RAM_size, RAM_size, + tcx_offset = qemu_ram_alloc(hwdef->vram_size); + tcx_init(ds, hwdef->tcx_base, phys_ram_base + tcx_offset, tcx_offset, hwdef->vram_size, graphic_width, graphic_height, graphic_depth); if (nd_table[0].model == NULL @@ -1139,26 +1377,33 @@ exit(1); } - main_esp = esp_init(hwdef->esp_base, espdma, *espdma_irq, - esp_reset); + main_esp = esp_init(hwdef->esp_base, 2, + espdma_memory_read, espdma_memory_write, + espdma, *espdma_irq, esp_reset); for (i = 0; i < ESP_MAX_DEVS; i++) { - index = drive_get_index(IF_SCSI, 0, i); - if (index == -1) + drive_index = drive_get_index(IF_SCSI, 0, i); + if (drive_index == -1) continue; - esp_scsi_attach(main_esp, drives_table[index].bdrv, i); + esp_scsi_attach(main_esp, drives_table[drive_index].bdrv, i); } - kernel_size = sun4m_load_kernel(kernel_filename, kernel_cmdline, - initrd_filename); + kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename, + RAM_size); nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, RAM_size, kernel_size, graphic_width, - graphic_height, graphic_depth, hwdef->machine_id, "Sun4d"); + graphic_height, graphic_depth, hwdef->nvram_machine_id, + "Sun4d"); + + fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); + fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); } /* SPARCserver 1000 hardware initialisation */ -static void ss1000_init(int RAM_size, int vga_ram_size, +static void ss1000_init(ram_addr_t RAM_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -1168,7 +1413,7 @@ } /* SPARCcenter 2000 hardware initialisation */ -static void ss2000_init(int RAM_size, int vga_ram_size, +static void ss2000_init(ram_addr_t RAM_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -1178,13 +1423,227 @@ } QEMUMachine ss1000_machine = { - "SS-1000", - "Sun4d platform, SPARCserver 1000", - ss1000_init, + .name = "SS-1000", + .desc = "Sun4d platform, SPARCserver 1000", + .init = ss1000_init, + .ram_require = PROM_SIZE_MAX + TCX_SIZE, + .nodisk_ok = 1, + .use_scsi = 1, + .max_cpus = 8, }; QEMUMachine ss2000_machine = { - "SS-2000", - "Sun4d platform, SPARCcenter 2000", - ss2000_init, + .name = "SS-2000", + .desc = "Sun4d platform, SPARCcenter 2000", + .init = ss2000_init, + .ram_require = PROM_SIZE_MAX + TCX_SIZE, + .nodisk_ok = 1, + .use_scsi = 1, + .max_cpus = 20, +}; + +static const struct sun4c_hwdef sun4c_hwdefs[] = { + /* SS-2 */ + { + .iommu_base = 0xf8000000, + .tcx_base = 0xfe000000, + .slavio_base = 0xf6000000, + .intctl_base = 0xf5000000, + .counter_base = 0xf3000000, + .ms_kb_base = 0xf0000000, + .serial_base = 0xf1000000, + .nvram_base = 0xf2000000, + .fd_base = 0xf7200000, + .dma_base = 0xf8400000, + .esp_base = 0xf8800000, + .le_base = 0xf8c00000, + .aux1_base = 0xf7400003, + .vram_size = 0x00100000, + .nvram_size = 0x800, + .esp_irq = 2, + .le_irq = 3, + .clock_irq = 5, + .clock1_irq = 7, + .ms_kb_irq = 1, + .ser_irq = 1, + .fd_irq = 1, + .me_irq = 1, + .nvram_machine_id = 0x55, + .machine_id = ss2_id, + .max_mem = 0x10000000, + .default_cpu_model = "Cypress CY7C601", + }, +}; + +static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size, + const char *boot_device, + DisplayState *ds, const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + CPUState *env; + unsigned int i; + void *iommu, *espdma, *ledma, *main_esp, *nvram; + qemu_irq *cpu_irqs, *slavio_irq, *espdma_irq, *ledma_irq; + qemu_irq *esp_reset, *le_reset; + qemu_irq *fdc_tc; + ram_addr_t ram_offset, prom_offset, tcx_offset; + unsigned long kernel_size; + int ret; + char buf[1024]; + BlockDriverState *fd[MAX_FD]; + int drive_index; + void *fw_cfg; + + /* init CPU */ + if (!cpu_model) + cpu_model = hwdef->default_cpu_model; + + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n"); + exit(1); + } + + cpu_sparc_set_id(env, 0); + + qemu_register_reset(main_cpu_reset, env); + cpu_irqs = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS); + env->prom_addr = hwdef->slavio_base; + + /* allocate RAM */ + if ((uint64_t)RAM_size > hwdef->max_mem) { + fprintf(stderr, + "qemu: Too much memory for this machine: %d, maximum %d\n", + (unsigned int)(RAM_size / (1024 * 1024)), + (unsigned int)(hwdef->max_mem / (1024 * 1024))); + exit(1); + } + ram_offset = qemu_ram_alloc(RAM_size); + cpu_register_physical_memory(0, RAM_size, ram_offset); + + /* load boot prom */ + prom_offset = qemu_ram_alloc(PROM_SIZE_MAX); + cpu_register_physical_memory(hwdef->slavio_base, + (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & + TARGET_PAGE_MASK, + prom_offset | IO_MEM_ROM); + + if (bios_name == NULL) + bios_name = PROM_FILENAME; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); + ret = load_elf(buf, hwdef->slavio_base - PROM_VADDR, NULL, NULL, NULL); + if (ret < 0 || ret > PROM_SIZE_MAX) + ret = load_image_targphys(buf, hwdef->slavio_base, PROM_SIZE_MAX); + if (ret < 0 || ret > PROM_SIZE_MAX) { + fprintf(stderr, "qemu: could not load prom '%s'\n", + buf); + exit(1); + } + + /* set up devices */ + slavio_intctl = sun4c_intctl_init(hwdef->intctl_base, + &slavio_irq, cpu_irqs); + + iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version, + slavio_irq[hwdef->me_irq]); + + espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq], + iommu, &espdma_irq, &esp_reset); + + ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, + slavio_irq[hwdef->le_irq], iommu, &ledma_irq, + &le_reset); + + if (graphic_depth != 8 && graphic_depth != 24) { + fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth); + exit (1); + } + tcx_offset = qemu_ram_alloc(hwdef->vram_size); + tcx_init(ds, hwdef->tcx_base, phys_ram_base + tcx_offset, tcx_offset, + hwdef->vram_size, graphic_width, graphic_height, graphic_depth); + + if (nd_table[0].model == NULL + || strcmp(nd_table[0].model, "lance") == 0) { + lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset); + } else if (strcmp(nd_table[0].model, "?") == 0) { + fprintf(stderr, "qemu: Supported NICs: lance\n"); + exit (1); + } else { + fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); + exit (1); + } + + nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, + hwdef->nvram_size, 2); + + slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq], + nographic); + // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device + // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device + slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq], + serial_hds[1], serial_hds[0]); + + slavio_misc = slavio_misc_init(0, -1, hwdef->aux1_base, -1, + slavio_irq[hwdef->me_irq], NULL, &fdc_tc); + + if (hwdef->fd_base != (target_phys_addr_t)-1) { + /* there is zero or one floppy drive */ + fd[1] = fd[0] = NULL; + drive_index = drive_get_index(IF_FLOPPY, 0, 0); + if (drive_index != -1) + fd[0] = drives_table[drive_index].bdrv; + + sun4m_fdctrl_init(slavio_irq[hwdef->fd_irq], hwdef->fd_base, fd, + fdc_tc); + } + + if (drive_get_max_bus(IF_SCSI) > 0) { + fprintf(stderr, "qemu: too many SCSI bus\n"); + exit(1); + } + + main_esp = esp_init(hwdef->esp_base, 2, + espdma_memory_read, espdma_memory_write, + espdma, *espdma_irq, esp_reset); + + for (i = 0; i < ESP_MAX_DEVS; i++) { + drive_index = drive_get_index(IF_SCSI, 0, i); + if (drive_index == -1) + continue; + esp_scsi_attach(main_esp, drives_table[drive_index].bdrv, i); + } + + kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename, + RAM_size); + + nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, + boot_device, RAM_size, kernel_size, graphic_width, + graphic_height, graphic_depth, hwdef->nvram_machine_id, + "Sun4c"); + + fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); + fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); +} + +/* SPARCstation 2 hardware initialisation */ +static void ss2_init(ram_addr_t RAM_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + sun4c_hw_init(&sun4c_hwdefs[0], RAM_size, boot_device, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +QEMUMachine ss2_machine = { + .name = "SS-2", + .desc = "Sun4c platform, SPARCstation 2", + .init = ss2_init, + .ram_require = PROM_SIZE_MAX + TCX_SIZE, + .nodisk_ok = 1, + .use_scsi = 1, }; + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/sun4m.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/sun4m.h --- qemu-0.9.1/hw/sun4m.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/sun4m.h 2008-11-02 10:51:05.000000000 +0000 @@ -41,6 +41,8 @@ /* sun4c_intctl.c */ void *sun4c_intctl_init(target_phys_addr_t addr, qemu_irq **irq, qemu_irq *parent_irq); +void sun4c_pic_info(void *opaque); +void sun4c_irq_info(void *opaque); /* slavio_timer.c */ void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq, @@ -54,33 +56,22 @@ /* slavio_misc.c */ void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, - qemu_irq irq); + target_phys_addr_t aux1_base, + target_phys_addr_t aux2_base, qemu_irq irq, + qemu_irq cpu_halt, qemu_irq **fdc_tc); void slavio_set_power_fail(void *opaque, int power_failing); -/* esp.c */ -#define ESP_MAX_DEVS 7 -void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id); -void *esp_init(target_phys_addr_t espaddr, - void *dma_opaque, qemu_irq irq, qemu_irq *reset); - /* cs4231.c */ void cs_init(target_phys_addr_t base, int irq, void *intctl); /* sparc32_dma.c */ -void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq parent_irq, - void *iommu, qemu_irq **dev_irq, qemu_irq **reset); -void ledma_memory_read(void *opaque, target_phys_addr_t addr, - uint8_t *buf, int len, int do_bswap); -void ledma_memory_write(void *opaque, target_phys_addr_t addr, - uint8_t *buf, int len, int do_bswap); -void espdma_memory_read(void *opaque, uint8_t *buf, int len); -void espdma_memory_write(void *opaque, uint8_t *buf, int len); +#include "sparc32_dma.h" /* pcnet.c */ void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, qemu_irq irq, qemu_irq *reset); /* eccmemctl.c */ -void *ecc_init(target_phys_addr_t base, uint32_t version); +void *ecc_init(target_phys_addr_t base, qemu_irq irq, uint32_t version); #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/sun4u.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/sun4u.c --- qemu-0.9.1/hw/sun4u.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/sun4u.c 2008-11-05 19:25:39.000000000 +0000 @@ -1,5 +1,5 @@ /* - * QEMU Sun4u System Emulator + * QEMU Sun4u/Sun4v System Emulator * * Copyright (c) 2005 Fabrice Bellard * @@ -31,12 +31,21 @@ #include "sysemu.h" #include "boards.h" #include "firmware_abi.h" +#include "fw_cfg.h" + +//#define DEBUG_IRQ + +#ifdef DEBUG_IRQ +#define DPRINTF(fmt, args...) \ + do { printf("CPUIRQ: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) +#endif #define KERNEL_LOAD_ADDR 0x00404000 #define CMDLINE_ADDR 0x003ff000 #define INITRD_LOAD_ADDR 0x00300000 -#define PROM_SIZE_MAX (512 * 1024) -#define PROM_ADDR 0x1fff0000000ULL +#define PROM_SIZE_MAX (4 * 1024 * 1024) #define PROM_VADDR 0x000ffd00000ULL #define APB_SPECIAL_BASE 0x1fe00000000ULL #define APB_MEM_BASE 0x1ff00000000ULL @@ -44,13 +53,16 @@ #define PROM_FILENAME "openbios-sparc64" #define NVRAM_SIZE 0x2000 #define MAX_IDE_BUS 2 +#define BIOS_CFG_IOPORT 0x510 -/* TSC handling */ +#define MAX_PILS 16 -uint64_t cpu_get_tsc() -{ - return qemu_get_clock(vm_clock); -} +struct hwdef { + const char * const default_cpu_model; + uint16_t machine_id; + uint64_t prom_addr; + uint64_t console_serial_base; +}; int DMA_get_channel_mode (int nchan) { @@ -67,7 +79,6 @@ void DMA_hold_DREQ (int nchan) {} void DMA_release_DREQ (int nchan) {} void DMA_schedule(int nchan) {} -void DMA_run (void) {} void DMA_init (int high_page_enable) {} void DMA_register_channel (int nchan, DMA_transfer_handler transfer_handler, @@ -75,16 +86,37 @@ { } -extern int nographic; +static int nvram_boot_set(void *opaque, const char *boot_device) +{ + unsigned int i; + uint8_t image[sizeof(ohwcfg_v3_t)]; + ohwcfg_v3_t *header = (ohwcfg_v3_t *)ℑ + m48t59_t *nvram = (m48t59_t *)opaque; + + for (i = 0; i < sizeof(image); i++) + image[i] = m48t59_read(nvram, i) & 0xff; + + pstrcpy((char *)header->boot_devices, sizeof(header->boot_devices), + boot_device); + header->nboot_devices = strlen(boot_device) & 0xff; + header->crc = cpu_to_be16(OHW_compute_crc(header, 0x00, 0xF8)); + + for (i = 0; i < sizeof(image); i++) + m48t59_write(nvram, i, image[i]); + + return 0; +} static int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, - const unsigned char *arch, - uint32_t RAM_size, const char *boot_devices, + const char *arch, + ram_addr_t RAM_size, + const char *boot_devices, uint32_t kernel_image, uint32_t kernel_size, const char *cmdline, uint32_t initrd_image, uint32_t initrd_size, uint32_t NVRAM_image, - int width, int height, int depth) + int width, int height, int depth, + const uint8_t *macaddr) { unsigned int i; uint32_t start, end; @@ -96,22 +128,24 @@ memset(image, '\0', sizeof(image)); // Try to match PPC NVRAM - strcpy(header->struct_ident, "QEMU_BIOS"); + pstrcpy((char *)header->struct_ident, sizeof(header->struct_ident), + "QEMU_BIOS"); header->struct_version = cpu_to_be32(3); /* structure v3 */ header->nvram_size = cpu_to_be16(NVRAM_size); header->nvram_arch_ptr = cpu_to_be16(sizeof(ohwcfg_v3_t)); header->nvram_arch_size = cpu_to_be16(sizeof(struct sparc_arch_cfg)); - strcpy(header->arch, arch); + pstrcpy((char *)header->arch, sizeof(header->arch), arch); header->nb_cpus = smp_cpus & 0xff; header->RAM0_base = 0; header->RAM0_size = cpu_to_be64((uint64_t)RAM_size); - strcpy(header->boot_devices, boot_devices); + pstrcpy((char *)header->boot_devices, sizeof(header->boot_devices), + boot_devices); header->nboot_devices = strlen(boot_devices) & 0xff; header->kernel_image = cpu_to_be64((uint64_t)kernel_image); header->kernel_size = cpu_to_be64((uint64_t)kernel_size); if (cmdline) { - strcpy(phys_ram_base + CMDLINE_ADDR, cmdline); + pstrcpy_targphys(CMDLINE_ADDR, TARGET_PAGE_SIZE, cmdline); header->cmdline = cpu_to_be64((uint64_t)CMDLINE_ADDR); header->cmdline_size = cpu_to_be64((uint64_t)strlen(cmdline)); } @@ -137,7 +171,7 @@ // Variable partition part_header = (struct OpenBIOS_nvpart_v1 *)&image[start]; part_header->signature = OPENBIOS_PART_SYSTEM; - strcpy(part_header->name, "system"); + pstrcpy(part_header->name, sizeof(part_header->name), "system"); end = start + sizeof(struct OpenBIOS_nvpart_v1); for (i = 0; i < nb_prom_envs; i++) @@ -153,32 +187,86 @@ start = end; part_header = (struct OpenBIOS_nvpart_v1 *)&image[start]; part_header->signature = OPENBIOS_PART_FREE; - strcpy(part_header->name, "free"); + pstrcpy(part_header->name, sizeof(part_header->name), "free"); end = 0x1fd0; OpenBIOS_finish_partition(part_header, end - start); + Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr, 0x80); + for (i = 0; i < sizeof(image); i++) m48t59_write(nvram, i, image[i]); + qemu_register_boot_set(nvram_boot_set, nvram); + return 0; } -void pic_info() +void pic_info(void) { } -void irq_info() +void irq_info(void) { } +void cpu_check_irqs(CPUState *env) +{ + uint32_t pil = env->pil_in | (env->softint & ~SOFTINT_TIMER) | + ((env->softint & SOFTINT_TIMER) << 14); + + if (pil && (env->interrupt_index == 0 || + (env->interrupt_index & ~15) == TT_EXTINT)) { + unsigned int i; + + for (i = 15; i > 0; i--) { + if (pil & (1 << i)) { + int old_interrupt = env->interrupt_index; + + env->interrupt_index = TT_EXTINT | i; + if (old_interrupt != env->interrupt_index) { + DPRINTF("Set CPU IRQ %d\n", i); + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } + break; + } + } + } else if (!pil && (env->interrupt_index & ~15) == TT_EXTINT) { + DPRINTF("Reset CPU IRQ %d\n", env->interrupt_index & 15); + env->interrupt_index = 0; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } +} + +static void cpu_set_irq(void *opaque, int irq, int level) +{ + CPUState *env = opaque; + + if (level) { + DPRINTF("Raise CPU IRQ %d\n", irq); + env->halted = 0; + env->pil_in |= 1 << irq; + cpu_check_irqs(env); + } else { + DPRINTF("Lower CPU IRQ %d\n", irq); + env->pil_in &= ~(1 << irq); + cpu_check_irqs(env); + } +} + void qemu_system_powerdown(void) { } +typedef struct ResetData { + CPUState *env; + uint64_t reset_addr; +} ResetData; + static void main_cpu_reset(void *opaque) { - CPUState *env = opaque; + ResetData *s = (ResetData *)opaque; + CPUState *env = s->env; cpu_reset(env); ptimer_set_limit(env->tick, 0x7fffffffffffffffULL, 1); @@ -187,31 +275,50 @@ ptimer_run(env->stick, 0); ptimer_set_limit(env->hstick, 0x7fffffffffffffffULL, 1); ptimer_run(env->hstick, 0); + env->gregs[1] = 0; // Memory start + env->gregs[2] = ram_size; // Memory size + env->gregs[3] = 0; // Machine description XXX + env->pc = s->reset_addr; + env->npc = env->pc + 4; } -void tick_irq(void *opaque) +static void tick_irq(void *opaque) { CPUState *env = opaque; + env->softint |= SOFTINT_TIMER; cpu_interrupt(env, CPU_INTERRUPT_TIMER); } -void stick_irq(void *opaque) +static void stick_irq(void *opaque) { CPUState *env = opaque; + env->softint |= SOFTINT_TIMER; cpu_interrupt(env, CPU_INTERRUPT_TIMER); } -void hstick_irq(void *opaque) +static void hstick_irq(void *opaque) { CPUState *env = opaque; + env->softint |= SOFTINT_TIMER; cpu_interrupt(env, CPU_INTERRUPT_TIMER); } -static void dummy_cpu_set_irq(void *opaque, int irq, int level) +void cpu_tick_set_count(void *opaque, uint64_t count) { + ptimer_set_count(opaque, -count); +} + +uint64_t cpu_tick_get_count(void *opaque) +{ + return -ptimer_get_count(opaque); +} + +void cpu_tick_set_limit(void *opaque, uint64_t limit) +{ + ptimer_set_limit(opaque, -limit, 0); } static const int ide_iobase[2] = { 0x1f0, 0x170 }; @@ -226,30 +333,34 @@ static fdctrl_t *floppy_controller; -/* Sun4u hardware initialisation */ -static void sun4u_init(int ram_size, int vga_ram_size, - const char *boot_devices, DisplayState *ds, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void sun4uv_init(ram_addr_t RAM_size, int vga_ram_size, + const char *boot_devices, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model, + const struct hwdef *hwdef) { CPUState *env; char buf[1024]; m48t59_t *nvram; int ret, linux_boot; unsigned int i; - long prom_offset, initrd_size, kernel_size; + ram_addr_t ram_offset, prom_offset, vga_ram_offset; + long initrd_size, kernel_size; PCIBus *pci_bus; QEMUBH *bh; qemu_irq *irq; - int index; + int drive_index; BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; BlockDriverState *fd[MAX_FD]; + void *fw_cfg; + ResetData *reset_info; linux_boot = (kernel_filename != NULL); /* init CPUs */ - if (cpu_model == NULL) - cpu_model = "TI UltraSparc II"; + if (!cpu_model) + cpu_model = hwdef->default_cpu_model; + env = cpu_init(cpu_model); if (!env) { fprintf(stderr, "Unable to find Sparc CPU definition\n"); @@ -266,26 +377,39 @@ bh = qemu_bh_new(hstick_irq, env); env->hstick = ptimer_init(bh); ptimer_set_period(env->hstick, 1ULL); - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); - qemu_register_reset(main_cpu_reset, env); - main_cpu_reset(env); + + reset_info = qemu_mallocz(sizeof(ResetData)); + reset_info->env = env; + reset_info->reset_addr = hwdef->prom_addr + 0x40ULL; + qemu_register_reset(main_cpu_reset, reset_info); + main_cpu_reset(reset_info); + // Override warm reset address with cold start address + env->pc = hwdef->prom_addr + 0x20ULL; + env->npc = env->pc + 4; /* allocate RAM */ - cpu_register_physical_memory(0, ram_size, 0); + ram_offset = qemu_ram_alloc(RAM_size); + cpu_register_physical_memory(0, RAM_size, ram_offset); - prom_offset = ram_size + vga_ram_size; - cpu_register_physical_memory(PROM_ADDR, - (PROM_SIZE_MAX + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, + prom_offset = qemu_ram_alloc(PROM_SIZE_MAX); + cpu_register_physical_memory(hwdef->prom_addr, + (PROM_SIZE_MAX + TARGET_PAGE_SIZE) & + TARGET_PAGE_MASK, prom_offset | IO_MEM_ROM); if (bios_name == NULL) bios_name = PROM_FILENAME; snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); - ret = load_elf(buf, PROM_ADDR - PROM_VADDR, NULL, NULL, NULL); + ret = load_elf(buf, hwdef->prom_addr - PROM_VADDR, NULL, NULL, NULL); if (ret < 0) { - fprintf(stderr, "qemu: could not load prom '%s'\n", - buf); - exit(1); + ret = load_image_targphys(buf, hwdef->prom_addr, + (PROM_SIZE_MAX + TARGET_PAGE_SIZE) & + TARGET_PAGE_MASK); + if (ret < 0) { + fprintf(stderr, "qemu: could not load prom '%s'\n", + buf); + exit(1); + } } kernel_size = 0; @@ -294,9 +418,12 @@ /* XXX: put correct offset */ kernel_size = load_elf(kernel_filename, 0, NULL, NULL, NULL); if (kernel_size < 0) - kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR, + ram_size - KERNEL_LOAD_ADDR); if (kernel_size < 0) - kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + kernel_size = load_image_targphys(kernel_filename, + KERNEL_LOAD_ADDR, + ram_size - KERNEL_LOAD_ADDR); if (kernel_size < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); @@ -305,7 +432,9 @@ /* load initrd */ if (initrd_filename) { - initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); + initrd_size = load_image_targphys(initrd_filename, + INITRD_LOAD_ADDR, + ram_size - INITRD_LOAD_ADDR); if (initrd_size < 0) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); @@ -314,10 +443,9 @@ } if (initrd_size > 0) { for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { - if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i) - == 0x48647253) { // HdrS - stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR); - stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size); + if (ldl_phys(KERNEL_LOAD_ADDR + i) == 0x48647253) { // HdrS + stl_phys(KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR); + stl_phys(KERNEL_LOAD_ADDR + i + 20, initrd_size); break; } } @@ -325,17 +453,27 @@ } pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, NULL); isa_mem_base = VGA_BASE; - pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size); - - for(i = 0; i < MAX_SERIAL_PORTS; i++) { + vga_ram_offset = qemu_ram_alloc(vga_ram_size); + pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + vga_ram_offset, + vga_ram_offset, vga_ram_size); + + i = 0; + if (hwdef->console_serial_base) { + serial_mm_init(hwdef->console_serial_base, 0, NULL, 115200, + serial_hds[i], 1); + i++; + } + for(; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { - serial_init(serial_io[i], NULL/*serial_irq[i]*/, serial_hds[i]); + serial_init(serial_io[i], NULL/*serial_irq[i]*/, 115200, + serial_hds[i]); } } for(i = 0; i < MAX_PARALLEL_PORTS; i++) { if (parallel_hds[i]) { - parallel_init(parallel_io[i], NULL/*parallel_irq[i]*/, parallel_hds[i]); + parallel_init(parallel_io[i], NULL/*parallel_irq[i]*/, + parallel_hds[i]); } } @@ -345,15 +483,16 @@ pci_nic_init(pci_bus, &nd_table[i], -1); } - irq = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, 32); + irq = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS); if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { fprintf(stderr, "qemu: too many IDE bus\n"); exit(1); } for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) { - index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); - if (index != -1) - hd[i] = drives_table[index].bdrv; + drive_index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, + i % MAX_IDE_DEVS); + if (drive_index != -1) + hd[i] = drives_table[drive_index].bdrv; else hd[i] = NULL; } @@ -363,26 +502,112 @@ /* FIXME: wire up interrupts. */ i8042_init(NULL/*1*/, NULL/*12*/, 0x60); for(i = 0; i < MAX_FD; i++) { - index = drive_get_index(IF_FLOPPY, 0, i); - if (index != -1) - fd[i] = drives_table[index].bdrv; + drive_index = drive_get_index(IF_FLOPPY, 0, i); + if (drive_index != -1) + fd[i] = drives_table[drive_index].bdrv; else fd[i] = NULL; } floppy_controller = fdctrl_init(NULL/*6*/, 2, 0, 0x3f0, fd); nvram = m48t59_init(NULL/*8*/, 0, 0x0074, NVRAM_SIZE, 59); - sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_devices, - KERNEL_LOAD_ADDR, kernel_size, - kernel_cmdline, - INITRD_LOAD_ADDR, initrd_size, - /* XXX: need an option to load a NVRAM image */ - 0, - graphic_width, graphic_height, graphic_depth); + sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", RAM_size, boot_devices, + KERNEL_LOAD_ADDR, kernel_size, + kernel_cmdline, + INITRD_LOAD_ADDR, initrd_size, + /* XXX: need an option to load a NVRAM image */ + 0, + graphic_width, graphic_height, graphic_depth, + (uint8_t *)&nd_table[0].macaddr); + + fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); + fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); + fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); +} + +enum { + sun4u_id = 0, + sun4v_id = 64, + niagara_id, +}; + +static const struct hwdef hwdefs[] = { + /* Sun4u generic PC-like machine */ + { + .default_cpu_model = "TI UltraSparc II", + .machine_id = sun4u_id, + .prom_addr = 0x1fff0000000ULL, + .console_serial_base = 0, + }, + /* Sun4v generic PC-like machine */ + { + .default_cpu_model = "Sun UltraSparc T1", + .machine_id = sun4v_id, + .prom_addr = 0x1fff0000000ULL, + .console_serial_base = 0, + }, + /* Sun4v generic Niagara machine */ + { + .default_cpu_model = "Sun UltraSparc T1", + .machine_id = niagara_id, + .prom_addr = 0xfff0000000ULL, + .console_serial_base = 0xfff0c2c000ULL, + }, +}; +/* Sun4u hardware initialisation */ +static void sun4u_init(ram_addr_t RAM_size, int vga_ram_size, + const char *boot_devices, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + sun4uv_init(RAM_size, vga_ram_size, boot_devices, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model, &hwdefs[0]); +} + +/* Sun4v hardware initialisation */ +static void sun4v_init(ram_addr_t RAM_size, int vga_ram_size, + const char *boot_devices, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + sun4uv_init(RAM_size, vga_ram_size, boot_devices, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model, &hwdefs[1]); +} + +/* Niagara hardware initialisation */ +static void niagara_init(ram_addr_t RAM_size, int vga_ram_size, + const char *boot_devices, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + sun4uv_init(RAM_size, vga_ram_size, boot_devices, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model, &hwdefs[2]); } QEMUMachine sun4u_machine = { - "sun4u", - "Sun4u platform", - sun4u_init, + .name = "sun4u", + .desc = "Sun4u platform", + .init = sun4u_init, + .ram_require = PROM_SIZE_MAX + VGA_RAM_SIZE, + .nodisk_ok = 1, + .max_cpus = 1, // XXX for now +}; + +QEMUMachine sun4v_machine = { + .name = "sun4v", + .desc = "Sun4v platform", + .init = sun4v_init, + .ram_require = PROM_SIZE_MAX + VGA_RAM_SIZE, + .nodisk_ok = 1, + .max_cpus = 1, // XXX for now +}; + +QEMUMachine niagara_machine = { + .name = "Niagara", + .desc = "Sun4v platform, Niagara", + .init = niagara_init, + .ram_require = PROM_SIZE_MAX + VGA_RAM_SIZE, + .nodisk_ok = 1, + .max_cpus = 1, // XXX for now }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/tc58128.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/tc58128.c --- qemu-0.9.1/hw/tc58128.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/tc58128.c 2008-10-26 13:43:07.000000000 +0000 @@ -26,7 +26,7 @@ #define FLASH_SIZE (16*1024*1024) -void init_dev(tc58128_dev * dev, char *filename) +static void init_dev(tc58128_dev * dev, const char *filename) { int ret, blocks; @@ -58,7 +58,7 @@ } } -void handle_command(tc58128_dev * dev, uint8_t command) +static void handle_command(tc58128_dev * dev, uint8_t command) { switch (command) { case 0xff: @@ -86,7 +86,7 @@ } } -void handle_address(tc58128_dev * dev, uint8_t data) +static void handle_address(tc58128_dev * dev, uint8_t data) { switch (dev->state) { case READ1: @@ -119,7 +119,7 @@ } } -uint8_t handle_read(tc58128_dev * dev) +static uint8_t handle_read(tc58128_dev * dev) { #if 0 if (dev->address % 0x100000 == 0) @@ -131,9 +131,9 @@ /* We never mark the device as busy, so interrupts cannot be triggered XXXXX */ -int tc58128_cb(uint16_t porta, uint16_t portb, - uint16_t * periph_pdtra, uint16_t * periph_portadir, - uint16_t * periph_pdtrb, uint16_t * periph_portbdir) +static int tc58128_cb(uint16_t porta, uint16_t portb, + uint16_t * periph_pdtra, uint16_t * periph_portadir, + uint16_t * periph_pdtrb, uint16_t * periph_portbdir) { int dev; @@ -175,7 +175,7 @@ tc58128_cb /* Callback */ }; -int tc58128_init(struct SH7750State *s, char *zone1, char *zone2) +int tc58128_init(struct SH7750State *s, const char *zone1, const char *zone2) { init_dev(&tc58128_devs[0], zone1); init_dev(&tc58128_devs[1], zone2); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/tc6393xb.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/tc6393xb.c --- qemu-0.9.1/hw/tc6393xb.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/tc6393xb.c 2008-11-04 09:04:41.000000000 +0000 @@ -0,0 +1,615 @@ +/* + * Toshiba TC6393XB I/O Controller. + * Found in Sharp Zaurus SL-6000 (tosa) or some + * Toshiba e-Series PDAs. + * + * Most features are currently unsupported!!! + * + * This code is licensed under the GNU GPL v2. + */ +#include "hw.h" +#include "pxa.h" +#include "devices.h" +#include "flash.h" +#include "console.h" +#include "pixel_ops.h" + +#define IRQ_TC6393_NAND 0 +#define IRQ_TC6393_MMC 1 +#define IRQ_TC6393_OHCI 2 +#define IRQ_TC6393_SERIAL 3 +#define IRQ_TC6393_FB 4 + +#define TC6393XB_NR_IRQS 8 + +#define TC6393XB_GPIOS 16 + +#define SCR_REVID 0x08 /* b Revision ID */ +#define SCR_ISR 0x50 /* b Interrupt Status */ +#define SCR_IMR 0x52 /* b Interrupt Mask */ +#define SCR_IRR 0x54 /* b Interrupt Routing */ +#define SCR_GPER 0x60 /* w GP Enable */ +#define SCR_GPI_SR(i) (0x64 + (i)) /* b3 GPI Status */ +#define SCR_GPI_IMR(i) (0x68 + (i)) /* b3 GPI INT Mask */ +#define SCR_GPI_EDER(i) (0x6c + (i)) /* b3 GPI Edge Detect Enable */ +#define SCR_GPI_LIR(i) (0x70 + (i)) /* b3 GPI Level Invert */ +#define SCR_GPO_DSR(i) (0x78 + (i)) /* b3 GPO Data Set */ +#define SCR_GPO_DOECR(i) (0x7c + (i)) /* b3 GPO Data OE Control */ +#define SCR_GP_IARCR(i) (0x80 + (i)) /* b3 GP Internal Active Register Control */ +#define SCR_GP_IARLCR(i) (0x84 + (i)) /* b3 GP INTERNAL Active Register Level Control */ +#define SCR_GPI_BCR(i) (0x88 + (i)) /* b3 GPI Buffer Control */ +#define SCR_GPA_IARCR 0x8c /* w GPa Internal Active Register Control */ +#define SCR_GPA_IARLCR 0x90 /* w GPa Internal Active Register Level Control */ +#define SCR_GPA_BCR 0x94 /* w GPa Buffer Control */ +#define SCR_CCR 0x98 /* w Clock Control */ +#define SCR_PLL2CR 0x9a /* w PLL2 Control */ +#define SCR_PLL1CR 0x9c /* l PLL1 Control */ +#define SCR_DIARCR 0xa0 /* b Device Internal Active Register Control */ +#define SCR_DBOCR 0xa1 /* b Device Buffer Off Control */ +#define SCR_FER 0xe0 /* b Function Enable */ +#define SCR_MCR 0xe4 /* w Mode Control */ +#define SCR_CONFIG 0xfc /* b Configuration Control */ +#define SCR_DEBUG 0xff /* b Debug */ + +#define NAND_CFG_COMMAND 0x04 /* w Command */ +#define NAND_CFG_BASE 0x10 /* l Control Base Address */ +#define NAND_CFG_INTP 0x3d /* b Interrupt Pin */ +#define NAND_CFG_INTE 0x48 /* b Int Enable */ +#define NAND_CFG_EC 0x4a /* b Event Control */ +#define NAND_CFG_ICC 0x4c /* b Internal Clock Control */ +#define NAND_CFG_ECCC 0x5b /* b ECC Control */ +#define NAND_CFG_NFTC 0x60 /* b NAND Flash Transaction Control */ +#define NAND_CFG_NFM 0x61 /* b NAND Flash Monitor */ +#define NAND_CFG_NFPSC 0x62 /* b NAND Flash Power Supply Control */ +#define NAND_CFG_NFDC 0x63 /* b NAND Flash Detect Control */ + +#define NAND_DATA 0x00 /* l Data */ +#define NAND_MODE 0x04 /* b Mode */ +#define NAND_STATUS 0x05 /* b Status */ +#define NAND_ISR 0x06 /* b Interrupt Status */ +#define NAND_IMR 0x07 /* b Interrupt Mask */ + +#define NAND_MODE_WP 0x80 +#define NAND_MODE_CE 0x10 +#define NAND_MODE_ALE 0x02 +#define NAND_MODE_CLE 0x01 +#define NAND_MODE_ECC_MASK 0x60 +#define NAND_MODE_ECC_EN 0x20 +#define NAND_MODE_ECC_READ 0x40 +#define NAND_MODE_ECC_RST 0x60 + +struct tc6393xb_s { + target_phys_addr_t target_base; + qemu_irq irq; + qemu_irq *sub_irqs; + struct { + uint8_t ISR; + uint8_t IMR; + uint8_t IRR; + uint16_t GPER; + uint8_t GPI_SR[3]; + uint8_t GPI_IMR[3]; + uint8_t GPI_EDER[3]; + uint8_t GPI_LIR[3]; + uint8_t GP_IARCR[3]; + uint8_t GP_IARLCR[3]; + uint8_t GPI_BCR[3]; + uint16_t GPA_IARCR; + uint16_t GPA_IARLCR; + uint16_t CCR; + uint16_t PLL2CR; + uint32_t PLL1CR; + uint8_t DIARCR; + uint8_t DBOCR; + uint8_t FER; + uint16_t MCR; + uint8_t CONFIG; + uint8_t DEBUG; + } scr; + uint32_t gpio_dir; + uint32_t gpio_level; + uint32_t prev_level; + qemu_irq handler[TC6393XB_GPIOS]; + qemu_irq *gpio_in; + + struct { + uint8_t mode; + uint8_t isr; + uint8_t imr; + } nand; + int nand_enable; + uint32_t nand_phys; + struct nand_flash_s *flash; + struct ecc_state_s ecc; + + DisplayState *ds; + QEMUConsole *console; + ram_addr_t vram_addr; + uint32_t scr_width, scr_height; /* in pixels */ + qemu_irq l3v; + unsigned blank : 1, + blanked : 1; +}; + +qemu_irq *tc6393xb_gpio_in_get(struct tc6393xb_s *s) +{ + return s->gpio_in; +} + +static void tc6393xb_gpio_set(void *opaque, int line, int level) +{ +// struct tc6393xb_s *s = opaque; + + if (line > TC6393XB_GPIOS) { + printf("%s: No GPIO pin %i\n", __FUNCTION__, line); + return; + } + + // FIXME: how does the chip reflect the GPIO input level change? +} + +void tc6393xb_gpio_out_set(struct tc6393xb_s *s, int line, + qemu_irq handler) +{ + if (line >= TC6393XB_GPIOS) { + fprintf(stderr, "TC6393xb: no GPIO pin %d\n", line); + return; + } + + s->handler[line] = handler; +} + +static void tc6393xb_gpio_handler_update(struct tc6393xb_s *s) +{ + uint32_t level, diff; + int bit; + + level = s->gpio_level & s->gpio_dir; + + for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { + bit = ffs(diff) - 1; + qemu_set_irq(s->handler[bit], (level >> bit) & 1); + } + + s->prev_level = level; +} + +qemu_irq tc6393xb_l3v_get(struct tc6393xb_s *s) +{ + return s->l3v; +} + +static void tc6393xb_l3v(void *opaque, int line, int level) +{ + struct tc6393xb_s *s = opaque; + s->blank = !level; + fprintf(stderr, "L3V: %d\n", level); +} + +static void tc6393xb_sub_irq(void *opaque, int line, int level) { + struct tc6393xb_s *s = opaque; + uint8_t isr = s->scr.ISR; + if (level) + isr |= 1 << line; + else + isr &= ~(1 << line); + s->scr.ISR = isr; + qemu_set_irq(s->irq, isr & s->scr.IMR); +} + +#define SCR_REG_B(N) \ + case SCR_ ##N: return s->scr.N +#define SCR_REG_W(N) \ + case SCR_ ##N: return s->scr.N; \ + case SCR_ ##N + 1: return s->scr.N >> 8; +#define SCR_REG_L(N) \ + case SCR_ ##N: return s->scr.N; \ + case SCR_ ##N + 1: return s->scr.N >> 8; \ + case SCR_ ##N + 2: return s->scr.N >> 16; \ + case SCR_ ##N + 3: return s->scr.N >> 24; +#define SCR_REG_A(N) \ + case SCR_ ##N(0): return s->scr.N[0]; \ + case SCR_ ##N(1): return s->scr.N[1]; \ + case SCR_ ##N(2): return s->scr.N[2] + +static uint32_t tc6393xb_scr_readb(struct tc6393xb_s *s, target_phys_addr_t addr) +{ + switch (addr) { + case SCR_REVID: + return 3; + case SCR_REVID+1: + return 0; + SCR_REG_B(ISR); + SCR_REG_B(IMR); + SCR_REG_B(IRR); + SCR_REG_W(GPER); + SCR_REG_A(GPI_SR); + SCR_REG_A(GPI_IMR); + SCR_REG_A(GPI_EDER); + SCR_REG_A(GPI_LIR); + case SCR_GPO_DSR(0): + case SCR_GPO_DSR(1): + case SCR_GPO_DSR(2): + return (s->gpio_level >> ((addr - SCR_GPO_DSR(0)) * 8)) & 0xff; + case SCR_GPO_DOECR(0): + case SCR_GPO_DOECR(1): + case SCR_GPO_DOECR(2): + return (s->gpio_dir >> ((addr - SCR_GPO_DOECR(0)) * 8)) & 0xff; + SCR_REG_A(GP_IARCR); + SCR_REG_A(GP_IARLCR); + SCR_REG_A(GPI_BCR); + SCR_REG_W(GPA_IARCR); + SCR_REG_W(GPA_IARLCR); + SCR_REG_W(CCR); + SCR_REG_W(PLL2CR); + SCR_REG_L(PLL1CR); + SCR_REG_B(DIARCR); + SCR_REG_B(DBOCR); + SCR_REG_B(FER); + SCR_REG_W(MCR); + SCR_REG_B(CONFIG); + SCR_REG_B(DEBUG); + } + fprintf(stderr, "tc6393xb_scr: unhandled read at %08x\n", (uint32_t) addr); + return 0; +} +#undef SCR_REG_B +#undef SCR_REG_W +#undef SCR_REG_L +#undef SCR_REG_A + +#define SCR_REG_B(N) \ + case SCR_ ##N: s->scr.N = value; return; +#define SCR_REG_W(N) \ + case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return; \ + case SCR_ ##N + 1: s->scr.N = (s->scr.N & 0xff) | (value << 8); return +#define SCR_REG_L(N) \ + case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return; \ + case SCR_ ##N + 1: s->scr.N = (s->scr.N & ~(0xff << 8)) | (value & (0xff << 8)); return; \ + case SCR_ ##N + 2: s->scr.N = (s->scr.N & ~(0xff << 16)) | (value & (0xff << 16)); return; \ + case SCR_ ##N + 3: s->scr.N = (s->scr.N & ~(0xff << 24)) | (value & (0xff << 24)); return; +#define SCR_REG_A(N) \ + case SCR_ ##N(0): s->scr.N[0] = value; return; \ + case SCR_ ##N(1): s->scr.N[1] = value; return; \ + case SCR_ ##N(2): s->scr.N[2] = value; return + +static void tc6393xb_scr_writeb(struct tc6393xb_s *s, target_phys_addr_t addr, uint32_t value) +{ + switch (addr) { + SCR_REG_B(ISR); + SCR_REG_B(IMR); + SCR_REG_B(IRR); + SCR_REG_W(GPER); + SCR_REG_A(GPI_SR); + SCR_REG_A(GPI_IMR); + SCR_REG_A(GPI_EDER); + SCR_REG_A(GPI_LIR); + case SCR_GPO_DSR(0): + case SCR_GPO_DSR(1): + case SCR_GPO_DSR(2): + s->gpio_level = (s->gpio_level & ~(0xff << ((addr - SCR_GPO_DSR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DSR(0))*8)); + tc6393xb_gpio_handler_update(s); + return; + case SCR_GPO_DOECR(0): + case SCR_GPO_DOECR(1): + case SCR_GPO_DOECR(2): + s->gpio_dir = (s->gpio_dir & ~(0xff << ((addr - SCR_GPO_DOECR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DOECR(0))*8)); + tc6393xb_gpio_handler_update(s); + return; + SCR_REG_A(GP_IARCR); + SCR_REG_A(GP_IARLCR); + SCR_REG_A(GPI_BCR); + SCR_REG_W(GPA_IARCR); + SCR_REG_W(GPA_IARLCR); + SCR_REG_W(CCR); + SCR_REG_W(PLL2CR); + SCR_REG_L(PLL1CR); + SCR_REG_B(DIARCR); + SCR_REG_B(DBOCR); + SCR_REG_B(FER); + SCR_REG_W(MCR); + SCR_REG_B(CONFIG); + SCR_REG_B(DEBUG); + } + fprintf(stderr, "tc6393xb_scr: unhandled write at %08x: %02x\n", + (uint32_t) addr, value & 0xff); +} +#undef SCR_REG_B +#undef SCR_REG_W +#undef SCR_REG_L +#undef SCR_REG_A + +static void tc6393xb_nand_irq(struct tc6393xb_s *s) { + qemu_set_irq(s->sub_irqs[IRQ_TC6393_NAND], + (s->nand.imr & 0x80) && (s->nand.imr & s->nand.isr)); +} + +static uint32_t tc6393xb_nand_cfg_readb(struct tc6393xb_s *s, target_phys_addr_t addr) { + switch (addr) { + case NAND_CFG_COMMAND: + return s->nand_enable ? 2 : 0; + case NAND_CFG_BASE: + case NAND_CFG_BASE + 1: + case NAND_CFG_BASE + 2: + case NAND_CFG_BASE + 3: + return s->nand_phys >> (addr - NAND_CFG_BASE); + } + fprintf(stderr, "tc6393xb_nand_cfg: unhandled read at %08x\n", (uint32_t) addr); + return 0; +} +static void tc6393xb_nand_cfg_writeb(struct tc6393xb_s *s, target_phys_addr_t addr, uint32_t value) { + switch (addr) { + case NAND_CFG_COMMAND: + s->nand_enable = (value & 0x2); + return; + case NAND_CFG_BASE: + case NAND_CFG_BASE + 1: + case NAND_CFG_BASE + 2: + case NAND_CFG_BASE + 3: + s->nand_phys &= ~(0xff << ((addr - NAND_CFG_BASE) * 8)); + s->nand_phys |= (value & 0xff) << ((addr - NAND_CFG_BASE) * 8); + return; + } + fprintf(stderr, "tc6393xb_nand_cfg: unhandled write at %08x: %02x\n", + (uint32_t) addr, value & 0xff); +} + +static uint32_t tc6393xb_nand_readb(struct tc6393xb_s *s, target_phys_addr_t addr) { + switch (addr) { + case NAND_DATA + 0: + case NAND_DATA + 1: + case NAND_DATA + 2: + case NAND_DATA + 3: + return nand_getio(s->flash); + case NAND_MODE: + return s->nand.mode; + case NAND_STATUS: + return 0x14; + case NAND_ISR: + return s->nand.isr; + case NAND_IMR: + return s->nand.imr; + } + fprintf(stderr, "tc6393xb_nand: unhandled read at %08x\n", (uint32_t) addr); + return 0; +} +static void tc6393xb_nand_writeb(struct tc6393xb_s *s, target_phys_addr_t addr, uint32_t value) { +// fprintf(stderr, "tc6393xb_nand: write at %08x: %02x\n", +// (uint32_t) addr, value & 0xff); + switch (addr) { + case NAND_DATA + 0: + case NAND_DATA + 1: + case NAND_DATA + 2: + case NAND_DATA + 3: + nand_setio(s->flash, value); + s->nand.isr &= 1; + tc6393xb_nand_irq(s); + return; + case NAND_MODE: + s->nand.mode = value; + nand_setpins(s->flash, + value & NAND_MODE_CLE, + value & NAND_MODE_ALE, + !(value & NAND_MODE_CE), + value & NAND_MODE_WP, + 0); // FIXME: gnd + switch (value & NAND_MODE_ECC_MASK) { + case NAND_MODE_ECC_RST: + ecc_reset(&s->ecc); + break; + case NAND_MODE_ECC_READ: + // FIXME + break; + case NAND_MODE_ECC_EN: + ecc_reset(&s->ecc); + } + return; + case NAND_ISR: + s->nand.isr = value; + tc6393xb_nand_irq(s); + return; + case NAND_IMR: + s->nand.imr = value; + tc6393xb_nand_irq(s); + return; + } + fprintf(stderr, "tc6393xb_nand: unhandled write at %08x: %02x\n", + (uint32_t) addr, value & 0xff); +} + +#define BITS 8 +#include "tc6393xb_template.h" +#define BITS 15 +#include "tc6393xb_template.h" +#define BITS 16 +#include "tc6393xb_template.h" +#define BITS 24 +#include "tc6393xb_template.h" +#define BITS 32 +#include "tc6393xb_template.h" + +static void tc6393xb_draw_graphic(struct tc6393xb_s *s, int full_update) +{ + switch (s->ds->depth) { + case 8: + tc6393xb_draw_graphic8(s); + break; + case 15: + tc6393xb_draw_graphic15(s); + break; + case 16: + tc6393xb_draw_graphic16(s); + break; + case 24: + tc6393xb_draw_graphic24(s); + break; + case 32: + tc6393xb_draw_graphic32(s); + break; + default: + printf("tc6393xb: unknown depth %d\n", s->ds->depth); + return; + } + + dpy_update(s->ds, 0, 0, s->scr_width, s->scr_height); +} + +static void tc6393xb_draw_blank(struct tc6393xb_s *s, int full_update) +{ + int i, w; + uint8_t *d; + + if (!full_update) + return; + + w = s->scr_width * ((s->ds->depth + 7) >> 3); + d = s->ds->data; + for(i = 0; i < s->scr_height; i++) { + memset(d, 0, w); + d += s->ds->linesize; + } + + dpy_update(s->ds, 0, 0, s->scr_width, s->scr_height); +} + +static void tc6393xb_update_display(void *opaque) +{ + struct tc6393xb_s *s = opaque; + int full_update; + + if (s->scr_width == 0 || s->scr_height == 0) + return; + + full_update = 0; + if (s->blanked != s->blank) { + s->blanked = s->blank; + full_update = 1; + } + if (s->scr_width != s->ds->width || s->scr_height != s->ds->height) { + qemu_console_resize(s->console, s->scr_width, s->scr_height); + full_update = 1; + } + if (s->blanked) + tc6393xb_draw_blank(s, full_update); + else + tc6393xb_draw_graphic(s, full_update); +} + + +static uint32_t tc6393xb_readb(void *opaque, target_phys_addr_t addr) { + struct tc6393xb_s *s = opaque; + addr -= s->target_base; + + switch (addr >> 8) { + case 0: + return tc6393xb_scr_readb(s, addr & 0xff); + case 1: + return tc6393xb_nand_cfg_readb(s, addr & 0xff); + }; + + if ((addr &~0xff) == s->nand_phys && s->nand_enable) { +// return tc6393xb_nand_readb(s, addr & 0xff); + uint8_t d = tc6393xb_nand_readb(s, addr & 0xff); +// fprintf(stderr, "tc6393xb_nand: read at %08x: %02hhx\n", (uint32_t) addr, d); + return d; + } + +// fprintf(stderr, "tc6393xb: unhandled read at %08x\n", (uint32_t) addr); + return 0; +} + +static void tc6393xb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) { + struct tc6393xb_s *s = opaque; + addr -= s->target_base; + + switch (addr >> 8) { + case 0: + tc6393xb_scr_writeb(s, addr & 0xff, value); + return; + case 1: + tc6393xb_nand_cfg_writeb(s, addr & 0xff, value); + return; + }; + + if ((addr &~0xff) == s->nand_phys && s->nand_enable) + tc6393xb_nand_writeb(s, addr & 0xff, value); + else + fprintf(stderr, "tc6393xb: unhandled write at %08x: %02x\n", + (uint32_t) addr, value & 0xff); +} + +static uint32_t tc6393xb_readw(void *opaque, target_phys_addr_t addr) +{ + return (tc6393xb_readb(opaque, addr) & 0xff) | + (tc6393xb_readb(opaque, addr + 1) << 8); +} + +static uint32_t tc6393xb_readl(void *opaque, target_phys_addr_t addr) +{ + return (tc6393xb_readb(opaque, addr) & 0xff) | + ((tc6393xb_readb(opaque, addr + 1) & 0xff) << 8) | + ((tc6393xb_readb(opaque, addr + 2) & 0xff) << 16) | + ((tc6393xb_readb(opaque, addr + 3) & 0xff) << 24); +} + +static void tc6393xb_writew(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + tc6393xb_writeb(opaque, addr, value); + tc6393xb_writeb(opaque, addr + 1, value >> 8); +} + +static void tc6393xb_writel(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + tc6393xb_writeb(opaque, addr, value); + tc6393xb_writeb(opaque, addr + 1, value >> 8); + tc6393xb_writeb(opaque, addr + 2, value >> 16); + tc6393xb_writeb(opaque, addr + 3, value >> 24); +} + +struct tc6393xb_s *tc6393xb_init(uint32_t base, qemu_irq irq, DisplayState *ds) +{ + int iomemtype; + struct tc6393xb_s *s; + CPUReadMemoryFunc *tc6393xb_readfn[] = { + tc6393xb_readb, + tc6393xb_readw, + tc6393xb_readl, + }; + CPUWriteMemoryFunc *tc6393xb_writefn[] = { + tc6393xb_writeb, + tc6393xb_writew, + tc6393xb_writel, + }; + + s = (struct tc6393xb_s *) qemu_mallocz(sizeof(struct tc6393xb_s)); + s->target_base = base; + s->irq = irq; + s->gpio_in = qemu_allocate_irqs(tc6393xb_gpio_set, s, TC6393XB_GPIOS); + + s->l3v = *qemu_allocate_irqs(tc6393xb_l3v, s, 1); + s->blanked = 1; + + s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS); + + s->flash = nand_init(NAND_MFR_TOSHIBA, 0x76); + + iomemtype = cpu_register_io_memory(0, tc6393xb_readfn, + tc6393xb_writefn, s); + cpu_register_physical_memory(s->target_base, 0x10000, iomemtype); + + if (ds) { + s->ds = ds; + s->vram_addr = qemu_ram_alloc(0x100000); + cpu_register_physical_memory(s->target_base + 0x100000, 0x100000, s->vram_addr); + s->scr_width = 480; + s->scr_height = 640; + s->console = graphic_console_init(ds, + tc6393xb_update_display, + NULL, /* invalidate */ + NULL, /* screen_dump */ + NULL, /* text_update */ + s); + } + + return s; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/tc6393xb_template.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/tc6393xb_template.h --- qemu-0.9.1/hw/tc6393xb_template.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/tc6393xb_template.h 2008-11-04 09:04:41.000000000 +0000 @@ -0,0 +1,72 @@ +/* + * Toshiba TC6393XB I/O Controller. + * Found in Sharp Zaurus SL-6000 (tosa) or some + * Toshiba e-Series PDAs. + * + * FB support code. Based on G364 fb emulator + * + * Copyright (c) 2007 Hervé Poussineau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#if BITS == 8 +# define SET_PIXEL(addr, color) *(uint8_t*)addr = color; +#elif BITS == 15 || BITS == 16 +# define SET_PIXEL(addr, color) *(uint16_t*)addr = color; +#elif BITS == 24 +# define SET_PIXEL(addr, color) \ + addr[0] = color; addr[1] = (color) >> 8; addr[2] = (color) >> 16; +#elif BITS == 32 +# define SET_PIXEL(addr, color) *(uint32_t*)addr = color; +#else +# error unknown bit depth +#endif + + +static void glue(tc6393xb_draw_graphic, BITS)(struct tc6393xb_s *s) +{ + int i; + int w_display; + uint16_t *data_buffer; + uint8_t *data_display; + + data_buffer = (uint16_t*)(phys_ram_base + s->vram_addr); + w_display = s->scr_width * BITS / 8; + data_display = s->ds->data; + for(i = 0; i < s->scr_height; i++) { +#if (BITS == 16) + memcpy(data_display, data_buffer, s->scr_width * 2); + data_buffer += s->scr_width; + data_display += s->ds->linesize; +#else + int j; + for (j = 0; j < s->scr_width; j++, data_display += BITS / 8, data_buffer++) { + uint16_t color = *data_buffer; + uint32_t dest_color = glue(rgb_to_pixel, BITS)( + ((color & 0xf800) * 0x108) >> 11, + ((color & 0x7e0) * 0x41) >> 9, + ((color & 0x1f) * 0x21) >> 2 + ); + SET_PIXEL(data_display, dest_color); + } +#endif + } +} + +#undef BITS +#undef SET_PIXEL + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/tcx.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/tcx.c --- qemu-0.9.1/hw/tcx.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/tcx.c 2008-10-02 20:14:17.000000000 +0100 @@ -36,6 +36,7 @@ typedef struct TCXState { target_phys_addr_t addr; DisplayState *ds; + QEMUConsole *console; uint8_t *vram; uint32_t *vram24, *cplane; ram_addr_t vram_offset, vram24_offset, cplane_offset; @@ -123,19 +124,34 @@ } } +/* + XXX Could be much more optimal: + * detect if line/page/whole screen is in 24 bit mode + * if destination is also BGR, use memcpy + */ static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d, const uint8_t *s, int width, const uint32_t *cplane, const uint32_t *s24) { - int x; - uint8_t val; + int x, bgr, r, g, b; + uint8_t val, *p8; uint32_t *p = (uint32_t *)d; uint32_t dval; + bgr = s1->ds->bgr; for(x = 0; x < width; x++, s++, s24++) { - if ((bswap32(*cplane++) & 0xff000000) == 0x03000000) { // 24-bit direct - dval = bswap32(*s24) & 0x00ffffff; + if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) { + // 24-bit direct, BGR order + p8 = (uint8_t *)s24; + p8++; + b = *p8++; + g = *p8++; + r = *p8++; + if (bgr) + dval = rgb_to_pixel32bgr(r, g, b); + else + dval = rgb_to_pixel32(r, g, b); } else { val = *s; dval = s1->palette[val]; @@ -144,7 +160,7 @@ } } -static inline int check_dirty(TCXState *ts, ram_addr_t page, ram_addr_t page24, +static inline int check_dirty(ram_addr_t page, ram_addr_t page24, ram_addr_t cpage) { int ret; @@ -279,7 +295,7 @@ for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE, page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) { - if (check_dirty(ts, page, page24, cpage)) { + if (check_dirty(page, page24, cpage)) { if (y_start < 0) y_start = y; if (page < page_min) @@ -356,9 +372,9 @@ { TCXState *s = opaque; - qemu_put_be16s(f, (uint16_t *)&s->height); - qemu_put_be16s(f, (uint16_t *)&s->width); - qemu_put_be16s(f, (uint16_t *)&s->depth); + qemu_put_be16s(f, &s->height); + qemu_put_be16s(f, &s->width); + qemu_put_be16s(f, &s->depth); qemu_put_buffer(f, s->r, 256); qemu_put_buffer(f, s->g, 256); qemu_put_buffer(f, s->b, 256); @@ -375,13 +391,13 @@ return -EINVAL; if (version_id == 3) { - qemu_get_be32s(f, (uint32_t *)&dummy); - qemu_get_be32s(f, (uint32_t *)&dummy); - qemu_get_be32s(f, (uint32_t *)&dummy); - } - qemu_get_be16s(f, (uint16_t *)&s->height); - qemu_get_be16s(f, (uint16_t *)&s->width); - qemu_get_be16s(f, (uint16_t *)&s->depth); + qemu_get_be32s(f, &dummy); + qemu_get_be32s(f, &dummy); + qemu_get_be32s(f, &dummy); + } + qemu_get_be16s(f, &s->height); + qemu_get_be16s(f, &s->width); + qemu_get_be16s(f, &s->depth); qemu_get_buffer(f, s->r, 256); qemu_get_buffer(f, s->g, 256); qemu_get_buffer(f, s->b, 256); @@ -516,7 +532,8 @@ vram_base += size; io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s); - cpu_register_physical_memory(addr + 0x00200000ULL, TCX_DAC_NREGS, io_memory); + cpu_register_physical_memory(addr + 0x00200000ULL, TCX_DAC_NREGS, + io_memory); dummy_memory = cpu_register_io_memory(0, tcx_dummy_read, tcx_dummy_write, s); @@ -536,13 +553,15 @@ s->cplane = (uint32_t *)vram_base; s->cplane_offset = vram_offset; cpu_register_physical_memory(addr + 0x0a000000ULL, size, vram_offset); - graphic_console_init(s->ds, tcx24_update_display, - tcx24_invalidate_display, tcx24_screen_dump, s); + s->console = graphic_console_init(s->ds, tcx24_update_display, + tcx24_invalidate_display, + tcx24_screen_dump, NULL, s); } else { cpu_register_physical_memory(addr + 0x00300000ULL, TCX_THC_NREGS_8, dummy_memory); - graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display, - tcx_screen_dump, s); + s->console = graphic_console_init(s->ds, tcx_update_display, + tcx_invalidate_display, + tcx_screen_dump, NULL, s); } // NetBSD writes here even with 8-bit display cpu_register_physical_memory(addr + 0x00301000ULL, TCX_THC_NREGS_24, @@ -551,7 +570,7 @@ register_savevm("tcx", addr, 4, tcx_save, tcx_load, s); qemu_register_reset(tcx_reset, s); tcx_reset(s); - dpy_resize(s->ds, width, height); + qemu_console_resize(s->console, width, height); } static void tcx_screen_dump(void *opaque, const char *filename) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/tmp105.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/tmp105.c --- qemu-0.9.1/hw/tmp105.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/tmp105.c 2008-10-02 20:14:17.000000000 +0100 @@ -0,0 +1,246 @@ +/* + * Texas Instruments TMP105 temperature sensor. + * + * Copyright (C) 2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "hw.h" +#include "i2c.h" + +struct tmp105_s { + i2c_slave i2c; + int len; + uint8_t buf[2]; + qemu_irq pin; + + uint8_t pointer; + uint8_t config; + int16_t temperature; + int16_t limit[2]; + int faults; + int alarm; +}; + +static void tmp105_interrupt_update(struct tmp105_s *s) +{ + qemu_set_irq(s->pin, s->alarm ^ ((~s->config >> 2) & 1)); /* POL */ +} + +static void tmp105_alarm_update(struct tmp105_s *s) +{ + if ((s->config >> 0) & 1) { /* SD */ + if ((s->config >> 7) & 1) /* OS */ + s->config &= ~(1 << 7); /* OS */ + else + return; + } + + if ((s->config >> 1) & 1) { /* TM */ + if (s->temperature >= s->limit[1]) + s->alarm = 1; + else if (s->temperature < s->limit[0]) + s->alarm = 1; + } else { + if (s->temperature >= s->limit[1]) + s->alarm = 1; + else if (s->temperature < s->limit[0]) + s->alarm = 0; + } + + tmp105_interrupt_update(s); +} + +/* Units are 0.001 centigrades relative to 0 C. */ +void tmp105_set(i2c_slave *i2c, int temp) +{ + struct tmp105_s *s = (struct tmp105_s *) i2c; + + if (temp >= 128000 || temp < -128000) { + fprintf(stderr, "%s: values is out of range (%i.%03i C)\n", + __FUNCTION__, temp / 1000, temp % 1000); + exit(-1); + } + + s->temperature = ((int16_t) (temp * 0x800 / 128000)) << 4; + + tmp105_alarm_update(s); +} + +static const int tmp105_faultq[4] = { 1, 2, 4, 6 }; + +static void tmp105_read(struct tmp105_s *s) +{ + s->len = 0; + + if ((s->config >> 1) & 1) { /* TM */ + s->alarm = 0; + tmp105_interrupt_update(s); + } + + switch (s->pointer & 3) { + case 0: /* Temperature */ + s->buf[s->len ++] = (((uint16_t) s->temperature) >> 8); + s->buf[s->len ++] = (((uint16_t) s->temperature) >> 0) & + (0xf0 << ((~s->config >> 5) & 3)); /* R */ + break; + + case 1: /* Configuration */ + s->buf[s->len ++] = s->config; + break; + + case 2: /* T_LOW */ + s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 8; + s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 0; + break; + + case 3: /* T_HIGH */ + s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 8; + s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 0; + break; + } +} + +static void tmp105_write(struct tmp105_s *s) +{ + switch (s->pointer & 3) { + case 0: /* Temperature */ + break; + + case 1: /* Configuration */ + if (s->buf[0] & ~s->config & (1 << 0)) /* SD */ + printf("%s: TMP105 shutdown\n", __FUNCTION__); + s->config = s->buf[0]; + s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */ + tmp105_alarm_update(s); + break; + + case 2: /* T_LOW */ + case 3: /* T_HIGH */ + if (s->len >= 3) + s->limit[s->pointer & 1] = (int16_t) + ((((uint16_t) s->buf[0]) << 8) | s->buf[1]); + tmp105_alarm_update(s); + break; + } +} + +static int tmp105_rx(i2c_slave *i2c) +{ + struct tmp105_s *s = (struct tmp105_s *) i2c; + + if (s->len < 2) + return s->buf[s->len ++]; + else + return 0xff; +} + +static int tmp105_tx(i2c_slave *i2c, uint8_t data) +{ + struct tmp105_s *s = (struct tmp105_s *) i2c; + + if (!s->len ++) + s->pointer = data; + else { + if (s->len <= 2) + s->buf[s->len - 1] = data; + tmp105_write(s); + } + + return 0; +} + +static void tmp105_event(i2c_slave *i2c, enum i2c_event event) +{ + struct tmp105_s *s = (struct tmp105_s *) i2c; + + if (event == I2C_START_RECV) + tmp105_read(s); + + s->len = 0; +} + +static void tmp105_save(QEMUFile *f, void *opaque) +{ + struct tmp105_s *s = (struct tmp105_s *) opaque; + + qemu_put_byte(f, s->len); + qemu_put_8s(f, &s->buf[0]); + qemu_put_8s(f, &s->buf[1]); + + qemu_put_8s(f, &s->pointer); + qemu_put_8s(f, &s->config); + qemu_put_sbe16s(f, &s->temperature); + qemu_put_sbe16s(f, &s->limit[0]); + qemu_put_sbe16s(f, &s->limit[1]); + qemu_put_byte(f, s->alarm); + s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */ + + i2c_slave_save(f, &s->i2c); +} + +static int tmp105_load(QEMUFile *f, void *opaque, int version_id) +{ + struct tmp105_s *s = (struct tmp105_s *) opaque; + + s->len = qemu_get_byte(f); + qemu_get_8s(f, &s->buf[0]); + qemu_get_8s(f, &s->buf[1]); + + qemu_get_8s(f, &s->pointer); + qemu_get_8s(f, &s->config); + qemu_get_sbe16s(f, &s->temperature); + qemu_get_sbe16s(f, &s->limit[0]); + qemu_get_sbe16s(f, &s->limit[1]); + s->alarm = qemu_get_byte(f); + + tmp105_interrupt_update(s); + + i2c_slave_load(f, &s->i2c); + return 0; +} + +void tmp105_reset(i2c_slave *i2c) +{ + struct tmp105_s *s = (struct tmp105_s *) i2c; + + s->temperature = 0; + s->pointer = 0; + s->config = 0; + s->faults = tmp105_faultq[(s->config >> 3) & 3]; + s->alarm = 0; + + tmp105_interrupt_update(s); +} + +struct i2c_slave *tmp105_init(i2c_bus *bus, qemu_irq alarm) +{ + struct tmp105_s *s = (struct tmp105_s *) + i2c_slave_init(bus, 0, sizeof(struct tmp105_s)); + + s->i2c.event = tmp105_event; + s->i2c.recv = tmp105_rx; + s->i2c.send = tmp105_tx; + s->pin = alarm; + + tmp105_reset(&s->i2c); + + register_savevm("TMP105", -1, 0, tmp105_save, tmp105_load, s); + + return &s->i2c; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/tosa.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/tosa.c --- qemu-0.9.1/hw/tosa.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/tosa.c 2008-11-04 09:04:41.000000000 +0000 @@ -0,0 +1,251 @@ +/* vim:set shiftwidth=4 ts=4 et: */ +/* + * PXA255 Sharp Zaurus SL-6000 PDA platform + * + * Copyright (c) 2008 Dmitry Baryshkov + * + * Code based on spitz platform by Andrzej Zaborowski + * This code is licensed under the GNU GPL v2. + */ + +#include "hw.h" +#include "pxa.h" +#include "arm-misc.h" +#include "sysemu.h" +#include "devices.h" +#include "sharpsl.h" +#include "pcmcia.h" +#include "block.h" +#include "boards.h" +#include "i2c.h" + +#define TOSA_RAM 0x04000000 +#define TOSA_ROM 0x00800000 + +#define TOSA_GPIO_nSD_DETECT (9) +#define TOSA_GPIO_ON_RESET (19) +#define TOSA_GPIO_CF_IRQ (21) /* CF slot0 Ready */ +#define TOSA_GPIO_CF_CD (13) +#define TOSA_GPIO_TC6393XB_INT (15) +#define TOSA_GPIO_JC_CF_IRQ (36) /* CF slot1 Ready */ + +#define TOSA_SCOOP_GPIO_BASE 1 +#define TOSA_GPIO_IR_POWERDWN (TOSA_SCOOP_GPIO_BASE + 2) +#define TOSA_GPIO_SD_WP (TOSA_SCOOP_GPIO_BASE + 3) +#define TOSA_GPIO_PWR_ON (TOSA_SCOOP_GPIO_BASE + 4) + +#define TOSA_SCOOP_JC_GPIO_BASE 1 +#define TOSA_GPIO_BT_LED (TOSA_SCOOP_JC_GPIO_BASE + 0) +#define TOSA_GPIO_NOTE_LED (TOSA_SCOOP_JC_GPIO_BASE + 1) +#define TOSA_GPIO_CHRG_ERR_LED (TOSA_SCOOP_JC_GPIO_BASE + 2) +#define TOSA_GPIO_TC6393XB_L3V_ON (TOSA_SCOOP_JC_GPIO_BASE + 5) +#define TOSA_GPIO_WLAN_LED (TOSA_SCOOP_JC_GPIO_BASE + 7) + +#define DAC_BASE 0x4e +#define DAC_CH1 0 +#define DAC_CH2 1 + +static void tosa_microdrive_attach(struct pxa2xx_state_s *cpu) +{ + struct pcmcia_card_s *md; + int index; + BlockDriverState *bs; + + index = drive_get_index(IF_IDE, 0, 0); + if (index == -1) + return; + bs = drives_table[index].bdrv; + if (bdrv_is_inserted(bs) && !bdrv_is_removable(bs)) { + md = dscm1xxxx_init(bs); + pxa2xx_pcmcia_attach(cpu->pcmcia[0], md); + } +} + +static void tosa_out_switch(void *opaque, int line, int level) +{ + switch (line) { + case 0: + fprintf(stderr, "blue LED %s.\n", level ? "on" : "off"); + break; + case 1: + fprintf(stderr, "green LED %s.\n", level ? "on" : "off"); + break; + case 2: + fprintf(stderr, "amber LED %s.\n", level ? "on" : "off"); + break; + case 3: + fprintf(stderr, "wlan LED %s.\n", level ? "on" : "off"); + break; + default: + fprintf(stderr, "Uhandled out event: %d = %d\n", line, level); + break; + } +} + + +static void tosa_gpio_setup(struct pxa2xx_state_s *cpu, + struct scoop_info_s *scp0, + struct scoop_info_s *scp1, + struct tc6393xb_s *tmio) +{ + qemu_irq *outsignals = qemu_allocate_irqs(tosa_out_switch, cpu, 4); + /* MMC/SD host */ + pxa2xx_mmci_handlers(cpu->mmc, + scoop_gpio_in_get(scp0)[TOSA_GPIO_SD_WP], + qemu_irq_invert(pxa2xx_gpio_in_get(cpu->gpio)[TOSA_GPIO_nSD_DETECT])); + + /* Handle reset */ + pxa2xx_gpio_out_set(cpu->gpio, TOSA_GPIO_ON_RESET, cpu->reset); + + /* PCMCIA signals: card's IRQ and Card-Detect */ + pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0], + pxa2xx_gpio_in_get(cpu->gpio)[TOSA_GPIO_CF_IRQ], + pxa2xx_gpio_in_get(cpu->gpio)[TOSA_GPIO_CF_CD]); + + pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1], + pxa2xx_gpio_in_get(cpu->gpio)[TOSA_GPIO_JC_CF_IRQ], + NULL); + + scoop_gpio_out_set(scp1, TOSA_GPIO_BT_LED, outsignals[0]); + scoop_gpio_out_set(scp1, TOSA_GPIO_NOTE_LED, outsignals[1]); + scoop_gpio_out_set(scp1, TOSA_GPIO_CHRG_ERR_LED, outsignals[2]); + scoop_gpio_out_set(scp1, TOSA_GPIO_WLAN_LED, outsignals[3]); + + scoop_gpio_out_set(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio)); +} + +static uint32_t tosa_ssp_read(void *opaque) +{ + return 0; +} + +static void tosa_ssp_write(void *opaque, uint32_t value) +{ + fprintf(stderr, "TG: %d %02x\n", value >> 5, value & 0x1f); +} + +struct tosa_dac_i2c { + i2c_slave i2c; + int len; + char buf[3]; +}; + +static int tosa_dac_send(i2c_slave *i2c, uint8_t data) +{ + struct tosa_dac_i2c *s = (struct tosa_dac_i2c *)i2c; + s->buf[s->len] = data; + if (s->len ++ > 2) { +#ifdef VERBOSE + fprintf(stderr, "%s: message too long (%i bytes)\n", __FUNCTION__, s->len); +#endif + return 1; + } + + if (s->len == 2) { + fprintf(stderr, "dac: channel %d value 0x%02x\n", + s->buf[0], s->buf[1]); + } + + return 0; +} + +static void tosa_dac_event(i2c_slave *i2c, enum i2c_event event) +{ + struct tosa_dac_i2c *s = (struct tosa_dac_i2c *)i2c; + s->len = 0; + switch (event) { + case I2C_START_SEND: + break; + case I2C_START_RECV: + printf("%s: recv not supported!!!\n", __FUNCTION__); + break; + case I2C_FINISH: +#ifdef VERBOSE + if (s->len < 2) + printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len); + if (s->len > 2) + printf("%s: message too long\n", __FUNCTION__); +#endif + break; + default: + break; + } +} + +int tosa_dac_recv(i2c_slave *s) +{ + printf("%s: recv not supported!!!\n", __FUNCTION__); + return -1; +} + +static void tosa_tg_init(struct pxa2xx_state_s *cpu) +{ + struct i2c_bus *bus = pxa2xx_i2c_bus(cpu->i2c[0]); + struct i2c_slave *dac = i2c_slave_init(bus, 0, sizeof(struct tosa_dac_i2c)); + dac->send = tosa_dac_send; + dac->event = tosa_dac_event; + dac->recv = tosa_dac_recv; + i2c_set_slave_address(dac, DAC_BASE); + pxa2xx_ssp_attach(cpu->ssp[1], tosa_ssp_read, + tosa_ssp_write, cpu); +} + + +static struct arm_boot_info tosa_binfo = { + .loader_start = PXA2XX_SDRAM_BASE, + .ram_size = 0x04000000, +}; + +static void tosa_init(ram_addr_t ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + struct pxa2xx_state_s *cpu; + struct tc6393xb_s *tmio; + struct scoop_info_s *scp0, *scp1; + + if (ram_size < (TOSA_RAM + TOSA_ROM + PXA2XX_INTERNAL_SIZE + TC6393XB_RAM)) { + fprintf(stderr, "This platform requires %i bytes of memory\n", + TOSA_RAM + TOSA_ROM + PXA2XX_INTERNAL_SIZE); + exit(1); + } + + if (!cpu_model) + cpu_model = "pxa255"; + + cpu = pxa255_init(tosa_binfo.ram_size, NULL); + + cpu_register_physical_memory(0, TOSA_ROM, + qemu_ram_alloc(TOSA_ROM) | IO_MEM_ROM); + + tmio = tc6393xb_init(0x10000000, + pxa2xx_gpio_in_get(cpu->gpio)[TOSA_GPIO_TC6393XB_INT], + ds); + + scp0 = scoop_init(cpu, 0, 0x08800000); + scp1 = scoop_init(cpu, 1, 0x14800040); + + tosa_gpio_setup(cpu, scp0, scp1, tmio); + + tosa_microdrive_attach(cpu); + + tosa_tg_init(cpu); + + /* Setup initial (reset) machine state */ + cpu->env->regs[15] = tosa_binfo.loader_start; + + tosa_binfo.kernel_filename = kernel_filename; + tosa_binfo.kernel_cmdline = kernel_cmdline; + tosa_binfo.initrd_filename = initrd_filename; + tosa_binfo.board_id = 0x208; + arm_load_kernel(cpu->env, &tosa_binfo); + sl_bootparam_write(SL_PXA_PARAM_BASE - PXA2XX_SDRAM_BASE); +} + +QEMUMachine tosapda_machine = { + .name = "tosa", + .desc = "Tosa PDA (PXA255)", + .init = tosa_init, + .ram_require = TOSA_RAM + TOSA_ROM + PXA2XX_INTERNAL_SIZE + RAMSIZE_FIXED + TC6393XB_RAM, +}; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/tsc2005.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/tsc2005.c --- qemu-0.9.1/hw/tsc2005.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/tsc2005.c 2008-10-26 13:43:07.000000000 +0000 @@ -0,0 +1,595 @@ +/* + * TI TSC2005 emulator. + * + * Copyright (c) 2006 Andrzej Zaborowski + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "hw.h" +#include "qemu-timer.h" +#include "console.h" +#include "devices.h" + +#define TSC_CUT_RESOLUTION(value, p) ((value) >> (16 - (p ? 12 : 10))) + +struct tsc2005_state_s { + qemu_irq pint; /* Combination of the nPENIRQ and DAV signals */ + QEMUTimer *timer; + uint16_t model; + + int x, y; + int pressure; + + int state, reg, irq, command; + uint16_t data, dav; + + int busy; + int enabled; + int host_mode; + int function; + int nextfunction; + int precision; + int nextprecision; + int filter; + int pin_func; + int timing[2]; + int noise; + int reset; + int pdst; + int pnd0; + uint16_t temp_thr[2]; + uint16_t aux_thr[2]; + + int tr[8]; +}; + +enum { + TSC_MODE_XYZ_SCAN = 0x0, + TSC_MODE_XY_SCAN, + TSC_MODE_X, + TSC_MODE_Y, + TSC_MODE_Z, + TSC_MODE_AUX, + TSC_MODE_TEMP1, + TSC_MODE_TEMP2, + TSC_MODE_AUX_SCAN, + TSC_MODE_X_TEST, + TSC_MODE_Y_TEST, + TSC_MODE_TS_TEST, + TSC_MODE_RESERVED, + TSC_MODE_XX_DRV, + TSC_MODE_YY_DRV, + TSC_MODE_YX_DRV, +}; + +static const uint16_t mode_regs[16] = { + 0xf000, /* X, Y, Z scan */ + 0xc000, /* X, Y scan */ + 0x8000, /* X */ + 0x4000, /* Y */ + 0x3000, /* Z */ + 0x0800, /* AUX */ + 0x0400, /* TEMP1 */ + 0x0200, /* TEMP2 */ + 0x0800, /* AUX scan */ + 0x0040, /* X test */ + 0x0020, /* Y test */ + 0x0080, /* Short-circuit test */ + 0x0000, /* Reserved */ + 0x0000, /* X+, X- drivers */ + 0x0000, /* Y+, Y- drivers */ + 0x0000, /* Y+, X- drivers */ +}; + +#define X_TRANSFORM(s) \ + ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3]) +#define Y_TRANSFORM(s) \ + ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7]) +#define Z1_TRANSFORM(s) \ + ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4) +#define Z2_TRANSFORM(s) \ + ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4) + +#define AUX_VAL (700 << 4) /* +/- 3 at 12-bit */ +#define TEMP1_VAL (1264 << 4) /* +/- 5 at 12-bit */ +#define TEMP2_VAL (1531 << 4) /* +/- 5 at 12-bit */ + +static uint16_t tsc2005_read(struct tsc2005_state_s *s, int reg) +{ + uint16_t ret; + + switch (reg) { + case 0x0: /* X */ + s->dav &= ~mode_regs[TSC_MODE_X]; + return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) + + (s->noise & 3); + case 0x1: /* Y */ + s->dav &= ~mode_regs[TSC_MODE_Y]; + s->noise ++; + return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^ + (s->noise & 3); + case 0x2: /* Z1 */ + s->dav &= 0xdfff; + return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) - + (s->noise & 3); + case 0x3: /* Z2 */ + s->dav &= 0xefff; + return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) | + (s->noise & 3); + + case 0x4: /* AUX */ + s->dav &= ~mode_regs[TSC_MODE_AUX]; + return TSC_CUT_RESOLUTION(AUX_VAL, s->precision); + + case 0x5: /* TEMP1 */ + s->dav &= ~mode_regs[TSC_MODE_TEMP1]; + return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) - + (s->noise & 5); + case 0x6: /* TEMP2 */ + s->dav &= 0xdfff; + s->dav &= ~mode_regs[TSC_MODE_TEMP2]; + return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^ + (s->noise & 3); + + case 0x7: /* Status */ + ret = s->dav | (s->reset << 7) | (s->pdst << 2) | 0x0; + s->dav &= ~(mode_regs[TSC_MODE_X_TEST] | mode_regs[TSC_MODE_Y_TEST] | + mode_regs[TSC_MODE_TS_TEST]); + s->reset = 1; + return ret; + + case 0x8: /* AUX high treshold */ + return s->aux_thr[1]; + case 0x9: /* AUX low treshold */ + return s->aux_thr[0]; + + case 0xa: /* TEMP high treshold */ + return s->temp_thr[1]; + case 0xb: /* TEMP low treshold */ + return s->temp_thr[0]; + + case 0xc: /* CFR0 */ + return (s->pressure << 15) | ((!s->busy) << 14) | + (s->nextprecision << 13) | s->timing[0]; + case 0xd: /* CFR1 */ + return s->timing[1]; + case 0xe: /* CFR2 */ + return (s->pin_func << 14) | s->filter; + + case 0xf: /* Function select status */ + return s->function >= 0 ? 1 << s->function : 0; + } + + /* Never gets here */ + return 0xffff; +} + +static void tsc2005_write(struct tsc2005_state_s *s, int reg, uint16_t data) +{ + switch (reg) { + case 0x8: /* AUX high treshold */ + s->aux_thr[1] = data; + break; + case 0x9: /* AUX low treshold */ + s->aux_thr[0] = data; + break; + + case 0xa: /* TEMP high treshold */ + s->temp_thr[1] = data; + break; + case 0xb: /* TEMP low treshold */ + s->temp_thr[0] = data; + break; + + case 0xc: /* CFR0 */ + s->host_mode = data >> 15; + if (s->enabled != !(data & 0x4000)) { + s->enabled = !(data & 0x4000); + fprintf(stderr, "%s: touchscreen sense %sabled\n", + __FUNCTION__, s->enabled ? "en" : "dis"); + if (s->busy && !s->enabled) + qemu_del_timer(s->timer); + s->busy &= s->enabled; + } + s->nextprecision = (data >> 13) & 1; + s->timing[0] = data & 0x1fff; + if ((s->timing[0] >> 11) == 3) + fprintf(stderr, "%s: illegal conversion clock setting\n", + __FUNCTION__); + break; + case 0xd: /* CFR1 */ + s->timing[1] = data & 0xf07; + break; + case 0xe: /* CFR2 */ + s->pin_func = (data >> 14) & 3; + s->filter = data & 0x3fff; + break; + + default: + fprintf(stderr, "%s: write into read-only register %x\n", + __FUNCTION__, reg); + } +} + +/* This handles most of the chip's logic. */ +static void tsc2005_pin_update(struct tsc2005_state_s *s) +{ + int64_t expires; + int pin_state; + + switch (s->pin_func) { + case 0: + pin_state = !s->pressure && !!s->dav; + break; + case 1: + case 3: + default: + pin_state = !s->dav; + break; + case 2: + pin_state = !s->pressure; + } + + if (pin_state != s->irq) { + s->irq = pin_state; + qemu_set_irq(s->pint, s->irq); + } + + switch (s->nextfunction) { + case TSC_MODE_XYZ_SCAN: + case TSC_MODE_XY_SCAN: + if (!s->host_mode && s->dav) + s->enabled = 0; + if (!s->pressure) + return; + /* Fall through */ + case TSC_MODE_AUX_SCAN: + break; + + case TSC_MODE_X: + case TSC_MODE_Y: + case TSC_MODE_Z: + if (!s->pressure) + return; + /* Fall through */ + case TSC_MODE_AUX: + case TSC_MODE_TEMP1: + case TSC_MODE_TEMP2: + case TSC_MODE_X_TEST: + case TSC_MODE_Y_TEST: + case TSC_MODE_TS_TEST: + if (s->dav) + s->enabled = 0; + break; + + case TSC_MODE_RESERVED: + case TSC_MODE_XX_DRV: + case TSC_MODE_YY_DRV: + case TSC_MODE_YX_DRV: + default: + return; + } + + if (!s->enabled || s->busy) + return; + + s->busy = 1; + s->precision = s->nextprecision; + s->function = s->nextfunction; + s->pdst = !s->pnd0; /* Synchronised on internal clock */ + expires = qemu_get_clock(vm_clock) + (ticks_per_sec >> 7); + qemu_mod_timer(s->timer, expires); +} + +static void tsc2005_reset(struct tsc2005_state_s *s) +{ + s->state = 0; + s->pin_func = 0; + s->enabled = 0; + s->busy = 0; + s->nextprecision = 0; + s->nextfunction = 0; + s->timing[0] = 0; + s->timing[1] = 0; + s->irq = 0; + s->dav = 0; + s->reset = 0; + s->pdst = 1; + s->pnd0 = 0; + s->function = -1; + s->temp_thr[0] = 0x000; + s->temp_thr[1] = 0xfff; + s->aux_thr[0] = 0x000; + s->aux_thr[1] = 0xfff; + + tsc2005_pin_update(s); +} + +static uint8_t tsc2005_txrx_word(void *opaque, uint8_t value) +{ + struct tsc2005_state_s *s = opaque; + uint32_t ret = 0; + + switch (s->state ++) { + case 0: + if (value & 0x80) { + /* Command */ + if (value & (1 << 1)) + tsc2005_reset(s); + else { + s->nextfunction = (value >> 3) & 0xf; + s->nextprecision = (value >> 2) & 1; + if (s->enabled != !(value & 1)) { + s->enabled = !(value & 1); + fprintf(stderr, "%s: touchscreen sense %sabled\n", + __FUNCTION__, s->enabled ? "en" : "dis"); + if (s->busy && !s->enabled) + qemu_del_timer(s->timer); + s->busy &= s->enabled; + } + tsc2005_pin_update(s); + } + + s->state = 0; + } else if (value) { + /* Data transfer */ + s->reg = (value >> 3) & 0xf; + s->pnd0 = (value >> 1) & 1; + s->command = value & 1; + + if (s->command) { + /* Read */ + s->data = tsc2005_read(s, s->reg); + tsc2005_pin_update(s); + } else + s->data = 0; + } else + s->state = 0; + break; + + case 1: + if (s->command) + ret = (s->data >> 8) & 0xff; + else + s->data |= value << 8; + break; + + case 2: + if (s->command) + ret = s->data & 0xff; + else { + s->data |= value; + tsc2005_write(s, s->reg, s->data); + tsc2005_pin_update(s); + } + + s->state = 0; + break; + } + + return ret; +} + +uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len) +{ + uint32_t ret = 0; + + len &= ~7; + while (len > 0) { + len -= 8; + ret |= tsc2005_txrx_word(opaque, (value >> len) & 0xff) << len; + } + + return ret; +} + +static void tsc2005_timer_tick(void *opaque) +{ + struct tsc2005_state_s *s = opaque; + + /* Timer ticked -- a set of conversions has been finished. */ + + if (!s->busy) + return; + + s->busy = 0; + s->dav |= mode_regs[s->function]; + s->function = -1; + tsc2005_pin_update(s); +} + +static void tsc2005_touchscreen_event(void *opaque, + int x, int y, int z, int buttons_state) +{ + struct tsc2005_state_s *s = opaque; + int p = s->pressure; + + if (buttons_state) { + s->x = x; + s->y = y; + } + s->pressure = !!buttons_state; + + /* + * Note: We would get better responsiveness in the guest by + * signaling TS events immediately, but for now we simulate + * the first conversion delay for sake of correctness. + */ + if (p != s->pressure) + tsc2005_pin_update(s); +} + +static void tsc2005_save(QEMUFile *f, void *opaque) +{ + struct tsc2005_state_s *s = (struct tsc2005_state_s *) opaque; + int i; + + qemu_put_be16(f, s->x); + qemu_put_be16(f, s->y); + qemu_put_byte(f, s->pressure); + + qemu_put_byte(f, s->state); + qemu_put_byte(f, s->reg); + qemu_put_byte(f, s->command); + + qemu_put_byte(f, s->irq); + qemu_put_be16s(f, &s->dav); + qemu_put_be16s(f, &s->data); + + qemu_put_timer(f, s->timer); + qemu_put_byte(f, s->enabled); + qemu_put_byte(f, s->host_mode); + qemu_put_byte(f, s->function); + qemu_put_byte(f, s->nextfunction); + qemu_put_byte(f, s->precision); + qemu_put_byte(f, s->nextprecision); + qemu_put_be16(f, s->filter); + qemu_put_byte(f, s->pin_func); + qemu_put_be16(f, s->timing[0]); + qemu_put_be16(f, s->timing[1]); + qemu_put_be16s(f, &s->temp_thr[0]); + qemu_put_be16s(f, &s->temp_thr[1]); + qemu_put_be16s(f, &s->aux_thr[0]); + qemu_put_be16s(f, &s->aux_thr[1]); + qemu_put_be32(f, s->noise); + qemu_put_byte(f, s->reset); + qemu_put_byte(f, s->pdst); + qemu_put_byte(f, s->pnd0); + + for (i = 0; i < 8; i ++) + qemu_put_be32(f, s->tr[i]); +} + +static int tsc2005_load(QEMUFile *f, void *opaque, int version_id) +{ + struct tsc2005_state_s *s = (struct tsc2005_state_s *) opaque; + int i; + + s->x = qemu_get_be16(f); + s->y = qemu_get_be16(f); + s->pressure = qemu_get_byte(f); + + s->state = qemu_get_byte(f); + s->reg = qemu_get_byte(f); + s->command = qemu_get_byte(f); + + s->irq = qemu_get_byte(f); + qemu_get_be16s(f, &s->dav); + qemu_get_be16s(f, &s->data); + + qemu_get_timer(f, s->timer); + s->enabled = qemu_get_byte(f); + s->host_mode = qemu_get_byte(f); + s->function = qemu_get_byte(f); + s->nextfunction = qemu_get_byte(f); + s->precision = qemu_get_byte(f); + s->nextprecision = qemu_get_byte(f); + s->filter = qemu_get_be16(f); + s->pin_func = qemu_get_byte(f); + s->timing[0] = qemu_get_be16(f); + s->timing[1] = qemu_get_be16(f); + qemu_get_be16s(f, &s->temp_thr[0]); + qemu_get_be16s(f, &s->temp_thr[1]); + qemu_get_be16s(f, &s->aux_thr[0]); + qemu_get_be16s(f, &s->aux_thr[1]); + s->noise = qemu_get_be32(f); + s->reset = qemu_get_byte(f); + s->pdst = qemu_get_byte(f); + s->pnd0 = qemu_get_byte(f); + + for (i = 0; i < 8; i ++) + s->tr[i] = qemu_get_be32(f); + + s->busy = qemu_timer_pending(s->timer); + tsc2005_pin_update(s); + + return 0; +} + +void *tsc2005_init(qemu_irq pintdav) +{ + struct tsc2005_state_s *s; + + s = (struct tsc2005_state_s *) + qemu_mallocz(sizeof(struct tsc2005_state_s)); + s->x = 400; + s->y = 240; + s->pressure = 0; + s->precision = s->nextprecision = 0; + s->timer = qemu_new_timer(vm_clock, tsc2005_timer_tick, s); + s->pint = pintdav; + s->model = 0x2005; + + s->tr[0] = 0; + s->tr[1] = 1; + s->tr[2] = 1; + s->tr[3] = 0; + s->tr[4] = 1; + s->tr[5] = 0; + s->tr[6] = 1; + s->tr[7] = 0; + + tsc2005_reset(s); + + qemu_add_mouse_event_handler(tsc2005_touchscreen_event, s, 1, + "QEMU TSC2005-driven Touchscreen"); + + qemu_register_reset((void *) tsc2005_reset, s); + register_savevm("tsc2005", -1, 0, tsc2005_save, tsc2005_load, s); + + return s; +} + +/* + * Use tslib generated calibration data to generate ADC input values + * from the touchscreen. Assuming 12-bit precision was used during + * tslib calibration. + */ +void tsc2005_set_transform(void *opaque, struct mouse_transform_info_s *info) +{ + struct tsc2005_state_s *s = (struct tsc2005_state_s *) opaque; + + /* This version assumes touchscreen X & Y axis are parallel or + * perpendicular to LCD's X & Y axis in some way. */ + if (abs(info->a[0]) > abs(info->a[1])) { + s->tr[0] = 0; + s->tr[1] = -info->a[6] * info->x; + s->tr[2] = info->a[0]; + s->tr[3] = -info->a[2] / info->a[0]; + s->tr[4] = info->a[6] * info->y; + s->tr[5] = 0; + s->tr[6] = info->a[4]; + s->tr[7] = -info->a[5] / info->a[4]; + } else { + s->tr[0] = info->a[6] * info->y; + s->tr[1] = 0; + s->tr[2] = info->a[1]; + s->tr[3] = -info->a[2] / info->a[1]; + s->tr[4] = 0; + s->tr[5] = -info->a[6] * info->x; + s->tr[6] = info->a[3]; + s->tr[7] = -info->a[5] / info->a[3]; + } + + s->tr[0] >>= 11; + s->tr[1] >>= 11; + s->tr[3] <<= 4; + s->tr[4] >>= 11; + s->tr[5] >>= 11; + s->tr[7] <<= 4; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/tsc210x.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/tsc210x.c --- qemu-0.9.1/hw/tsc210x.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/tsc210x.c 2008-10-26 13:43:07.000000000 +0000 @@ -1,12 +1,14 @@ /* * TI TSC2102 (touchscreen/sensors/audio controller) emulator. + * TI TSC2301 (touchscreen/sensors/keypad). * * Copyright (c) 2006 Andrzej Zaborowski + * Copyright (C) 2008 Nokia Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -23,7 +25,8 @@ #include "audio/audio.h" #include "qemu-timer.h" #include "console.h" -#include "omap.h" +#include "omap.h" /* For struct i2s_codec_s and struct uwire_slave_s */ +#include "devices.h" #define TSC_DATA_REGISTERS_PAGE 0x0 #define TSC_CONTROL_REGISTERS_PAGE 0x1 @@ -35,12 +38,15 @@ struct tsc210x_state_s { qemu_irq pint; + qemu_irq kbint; + qemu_irq davint; QEMUTimer *timer; QEMUSoundCard card; struct uwire_slave_s chip; struct i2s_codec_s codec; uint8_t in_fifo[16384]; uint8_t out_fifo[16384]; + uint16_t model; int x, y; int pressure; @@ -64,7 +70,7 @@ uint16_t audio_ctrl1; uint16_t audio_ctrl2; uint16_t audio_ctrl3; - uint16_t pll[2]; + uint16_t pll[3]; uint16_t volume; int64_t volume_change; int softstep; @@ -78,6 +84,17 @@ int i2s_rx_rate; int i2s_tx_rate; AudioState *audio; + + int tr[8]; + + struct { + uint16_t down; + uint16_t mask; + int scan; + int debounce; + int mode; + int intr; + } kb; }; static const int resolution[4] = { 12, 8, 10, 12 }; @@ -118,17 +135,10 @@ 0x0000, /* Y+, X- drivers */ }; -/* - * Convert screen coordinates to arbitrary values that the - * touchscreen in my Palm Tungsten E device returns. - * This shouldn't really matter (because the guest system - * should calibrate the touchscreen anyway), but let's - * imitate some real hardware. - */ -#define X_TRANSFORM(value) \ - ((3850 - ((int) (value) * (3850 - 250) / 32768)) << 4) -#define Y_TRANSFORM(value) \ - ((150 + ((int) (value) * (3037 - 150) / 32768)) << 4) +#define X_TRANSFORM(s) \ + ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3]) +#define Y_TRANSFORM(s) \ + ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7]) #define Z1_TRANSFORM(s) \ ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4) #define Z2_TRANSFORM(s) \ @@ -161,6 +171,7 @@ s->audio_ctrl3 = 0x0000; s->pll[0] = 0x1004; s->pll[1] = 0x0000; + s->pll[2] = 0x1fff; s->volume = 0xffff; s->dac_power = 0x8540; s->softstep = 1; @@ -190,7 +201,15 @@ s->i2s_tx_rate = 0; s->i2s_rx_rate = 0; + s->kb.scan = 1; + s->kb.debounce = 0; + s->kb.mask = 0x0000; + s->kb.mode = 3; + s->kb.intr = 0; + qemu_set_irq(s->pint, !s->irq); + qemu_set_irq(s->davint, !s->dav); + qemu_irq_raise(s->kbint); } struct tsc210x_rate_info_s { @@ -344,13 +363,13 @@ switch (reg) { case 0x00: /* X */ s->dav &= 0xfbff; - return TSC_CUT_RESOLUTION(X_TRANSFORM(s->x), s->precision) + + return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) + (s->noise & 3); case 0x01: /* Y */ s->noise ++; s->dav &= 0xfdff; - return TSC_CUT_RESOLUTION(Y_TRANSFORM(s->y), s->precision) ^ + return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^ (s->noise & 3); case 0x02: /* Z1 */ @@ -364,6 +383,14 @@ (s->noise & 3); case 0x04: /* KPData */ + if ((s->model & 0xff00) == 0x2300) { + if (s->kb.intr && (s->kb.mode & 2)) { + s->kb.intr = 0; + qemu_irq_raise(s->kbint); + } + return s->kb.down; + } + return 0xffff; case 0x05: /* BAT1 */ @@ -414,9 +441,19 @@ return (s->pressure << 15) | ((!s->busy) << 14) | (s->nextfunction << 10) | (s->nextprecision << 8) | s->filter; - case 0x01: /* Status */ - return (s->pin_func << 14) | ((!s->enabled) << 13) | - (s->host_mode << 12) | ((!!s->dav) << 11) | s->dav; + case 0x01: /* Status / Keypad Control */ + if ((s->model & 0xff00) == 0x2100) + return (s->pin_func << 14) | ((!s->enabled) << 13) | + (s->host_mode << 12) | ((!!s->dav) << 11) | s->dav; + else + return (s->kb.intr << 15) | ((s->kb.scan || !s->kb.down) << 14) | + (s->kb.debounce << 11); + + case 0x02: /* DAC Control */ + if ((s->model & 0xff00) == 0x2300) + return s->dac_power & 0x8000; + else + goto bad_reg; case 0x03: /* Reference */ return s->ref; @@ -427,7 +464,18 @@ case 0x05: /* Configuration */ return s->timing; + case 0x06: /* Secondary configuration */ + if ((s->model & 0xff00) == 0x2100) + goto bad_reg; + return ((!s->dav) << 15) | ((s->kb.mode & 1) << 14) | s->pll[2]; + + case 0x10: /* Keypad Mask */ + if ((s->model & 0xff00) == 0x2100) + goto bad_reg; + return s->kb.mask; + default: + bad_reg: #ifdef TSC_VERBOSE fprintf(stderr, "tsc2102_control_register_read: " "no such register: 0x%02x\n", reg); @@ -556,10 +604,27 @@ s->filter = value & 0xff; return; - case 0x01: /* Status */ - s->pin_func = value >> 14; + case 0x01: /* Status / Keypad Control */ + if ((s->model & 0xff00) == 0x2100) + s->pin_func = value >> 14; + else { + s->kb.scan = (value >> 14) & 1; + s->kb.debounce = (value >> 11) & 7; + if (s->kb.intr && s->kb.scan) { + s->kb.intr = 0; + qemu_irq_raise(s->kbint); + } + } return; + case 0x02: /* DAC Control */ + if ((s->model & 0xff00) == 0x2300) { + s->dac_power &= 0x7fff; + s->dac_power |= 0x8000 & value; + } else + goto bad_reg; + break; + case 0x03: /* Reference */ s->ref = value & 0x1f; return; @@ -586,7 +651,21 @@ #endif return; + case 0x06: /* Secondary configuration */ + if ((s->model & 0xff00) == 0x2100) + goto bad_reg; + s->kb.mode = value >> 14; + s->pll[2] = value & 0x3ffff; + return; + + case 0x10: /* Keypad Mask */ + if ((s->model & 0xff00) == 0x2100) + goto bad_reg; + s->kb.mask = value; + return; + default: + bad_reg: #ifdef TSC_VERBOSE fprintf(stderr, "tsc2102_control_register_write: " "no such register: 0x%02x\n", reg); @@ -785,7 +864,7 @@ return; } - if (!s->enabled || s->busy) + if (!s->enabled || s->busy || s->dav) return; s->busy = 1; @@ -805,6 +884,8 @@ switch (s->page) { case TSC_DATA_REGISTERS_PAGE: ret = tsc2102_data_register_read(s, s->offset); + if (!s->dav) + qemu_irq_raise(s->davint); break; case TSC_CONTROL_REGISTERS_PAGE: ret = tsc2102_control_register_read(s, s->offset); @@ -859,6 +940,26 @@ } } +uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len) +{ + struct tsc210x_state_s *s = opaque; + uint32_t ret = 0; + + if (len != 16) + cpu_abort(cpu_single_env, "%s: FIXME: bad SPI word width %i\n", + __FUNCTION__, len); + + /* TODO: sequential reads etc - how do we make sure the host doesn't + * unintentionally read out a conversion result from a register while + * transmitting the command word of the next command? */ + if (!value || (s->state && s->command)) + ret = tsc210x_read(s); + if (value || (s->state && !s->command)) + tsc210x_write(s, value); + + return ret; +} + static void tsc210x_timer_tick(void *opaque) { struct tsc210x_state_s *s = opaque; @@ -871,6 +972,7 @@ s->busy = 0; s->dav |= mode_regs[s->function]; tsc210x_pin_update(s); + qemu_irq_lower(s->davint); } static void tsc210x_touchscreen_event(void *opaque, @@ -945,8 +1047,8 @@ qemu_put_be16s(f, &s->pll[0]); qemu_put_be16s(f, &s->pll[1]); qemu_put_be16s(f, &s->volume); - qemu_put_be64(f, (uint64_t) (s->volume_change - now)); - qemu_put_be64(f, (uint64_t) (s->powerdown - now)); + qemu_put_sbe64(f, (s->volume_change - now)); + qemu_put_sbe64(f, (s->powerdown - now)); qemu_put_byte(f, s->softstep); qemu_put_be16s(f, &s->dac_power); @@ -991,8 +1093,8 @@ qemu_get_be16s(f, &s->pll[0]); qemu_get_be16s(f, &s->pll[1]); qemu_get_be16s(f, &s->volume); - s->volume_change = (int64_t) qemu_get_be64(f) + now; - s->powerdown = (int64_t) qemu_get_be64(f) + now; + s->volume_change = qemu_get_sbe64(f) + now; + s->powerdown = qemu_get_sbe64(f) + now; s->softstep = qemu_get_byte(f); qemu_get_be16s(f, &s->dac_power); @@ -1001,12 +1103,11 @@ s->busy = qemu_timer_pending(s->timer); qemu_set_irq(s->pint, !s->irq); + qemu_set_irq(s->davint, !s->dav); return 0; } -static int tsc2102_iid = 0; - struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio) { struct tsc210x_state_s *s; @@ -1020,9 +1121,19 @@ s->precision = s->nextprecision = 0; s->timer = qemu_new_timer(vm_clock, tsc210x_timer_tick, s); s->pint = pint; + s->model = 0x2102; s->name = "tsc2102"; s->audio = audio; + s->tr[0] = 0; + s->tr[1] = 1; + s->tr[2] = 1; + s->tr[3] = 0; + s->tr[4] = 1; + s->tr[5] = 0; + s->tr[6] = 1; + s->tr[7] = 0; + s->chip.opaque = s; s->chip.send = (void *) tsc210x_write; s->chip.receive = (void *) tsc210x_read; @@ -1042,15 +1153,154 @@ AUD_register_card(s->audio, s->name, &s->card); qemu_register_reset((void *) tsc210x_reset, s); - register_savevm(s->name, tsc2102_iid ++, 0, + register_savevm(s->name, -1, 0, tsc210x_save, tsc210x_load, s); return &s->chip; } +struct uwire_slave_s *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, + qemu_irq dav, AudioState *audio) +{ + struct tsc210x_state_s *s; + + s = (struct tsc210x_state_s *) + qemu_mallocz(sizeof(struct tsc210x_state_s)); + memset(s, 0, sizeof(struct tsc210x_state_s)); + s->x = 400; + s->y = 240; + s->pressure = 0; + s->precision = s->nextprecision = 0; + s->timer = qemu_new_timer(vm_clock, tsc210x_timer_tick, s); + s->pint = penirq; + s->kbint = kbirq; + s->davint = dav; + s->model = 0x2301; + s->name = "tsc2301"; + s->audio = audio; + + s->tr[0] = 0; + s->tr[1] = 1; + s->tr[2] = 1; + s->tr[3] = 0; + s->tr[4] = 1; + s->tr[5] = 0; + s->tr[6] = 1; + s->tr[7] = 0; + + s->chip.opaque = s; + s->chip.send = (void *) tsc210x_write; + s->chip.receive = (void *) tsc210x_read; + + s->codec.opaque = s; + s->codec.tx_swallow = (void *) tsc210x_i2s_swallow; + s->codec.set_rate = (void *) tsc210x_i2s_set_rate; + s->codec.in.fifo = s->in_fifo; + s->codec.out.fifo = s->out_fifo; + + tsc210x_reset(s); + + qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1, + "QEMU TSC2301-driven Touchscreen"); + + if (s->audio) + AUD_register_card(s->audio, s->name, &s->card); + + qemu_register_reset((void *) tsc210x_reset, s); + register_savevm(s->name, -1, 0, tsc210x_save, tsc210x_load, s); + + return &s->chip; +} + struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip) { struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque; return &s->codec; } + +/* + * Use tslib generated calibration data to generate ADC input values + * from the touchscreen. Assuming 12-bit precision was used during + * tslib calibration. + */ +void tsc210x_set_transform(struct uwire_slave_s *chip, + struct mouse_transform_info_s *info) +{ + struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque; +#if 0 + int64_t ltr[8]; + + ltr[0] = (int64_t) info->a[1] * info->y; + ltr[1] = (int64_t) info->a[4] * info->x; + ltr[2] = (int64_t) info->a[1] * info->a[3] - + (int64_t) info->a[4] * info->a[0]; + ltr[3] = (int64_t) info->a[2] * info->a[4] - + (int64_t) info->a[5] * info->a[1]; + ltr[4] = (int64_t) info->a[0] * info->y; + ltr[5] = (int64_t) info->a[3] * info->x; + ltr[6] = (int64_t) info->a[4] * info->a[0] - + (int64_t) info->a[1] * info->a[3]; + ltr[7] = (int64_t) info->a[2] * info->a[3] - + (int64_t) info->a[5] * info->a[0]; + + /* Avoid integer overflow */ + s->tr[0] = ltr[0] >> 11; + s->tr[1] = ltr[1] >> 11; + s->tr[2] = muldiv64(ltr[2], 1, info->a[6]); + s->tr[3] = muldiv64(ltr[3], 1 << 4, ltr[2]); + s->tr[4] = ltr[4] >> 11; + s->tr[5] = ltr[5] >> 11; + s->tr[6] = muldiv64(ltr[6], 1, info->a[6]); + s->tr[7] = muldiv64(ltr[7], 1 << 4, ltr[6]); +#else + + /* This version assumes touchscreen X & Y axis are parallel or + * perpendicular to LCD's X & Y axis in some way. */ + if (abs(info->a[0]) > abs(info->a[1])) { + s->tr[0] = 0; + s->tr[1] = -info->a[6] * info->x; + s->tr[2] = info->a[0]; + s->tr[3] = -info->a[2] / info->a[0]; + s->tr[4] = info->a[6] * info->y; + s->tr[5] = 0; + s->tr[6] = info->a[4]; + s->tr[7] = -info->a[5] / info->a[4]; + } else { + s->tr[0] = info->a[6] * info->y; + s->tr[1] = 0; + s->tr[2] = info->a[1]; + s->tr[3] = -info->a[2] / info->a[1]; + s->tr[4] = 0; + s->tr[5] = -info->a[6] * info->x; + s->tr[6] = info->a[3]; + s->tr[7] = -info->a[5] / info->a[3]; + } + + s->tr[0] >>= 11; + s->tr[1] >>= 11; + s->tr[3] <<= 4; + s->tr[4] >>= 11; + s->tr[5] >>= 11; + s->tr[7] <<= 4; +#endif +} + +void tsc210x_key_event(struct uwire_slave_s *chip, int key, int down) +{ + struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque; + + if (down) + s->kb.down |= 1 << key; + else + s->kb.down &= ~(1 << key); + + if (down && (s->kb.down & ~s->kb.mask) && !s->kb.intr) { + s->kb.intr = 1; + qemu_irq_lower(s->kbint); + } else if (s->kb.intr && !(s->kb.down & ~s->kb.mask) && + !(s->kb.mode & 1)) { + s->kb.intr = 0; + qemu_irq_raise(s->kbint); + } +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/tusb6010.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/tusb6010.c --- qemu-0.9.1/hw/tusb6010.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/tusb6010.c 2008-10-26 13:43:07.000000000 +0000 @@ -0,0 +1,771 @@ +/* + * Texas Instruments TUSB6010 emulation. + * Based on reverse-engineering of a linux driver. + * + * Copyright (C) 2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include "qemu-common.h" +#include "qemu-timer.h" +#include "usb.h" +#include "omap.h" +#include "irq.h" +#include "devices.h" + +struct tusb_s { + int iomemtype[2]; + qemu_irq irq; + struct musb_s *musb; + QEMUTimer *otg_timer; + QEMUTimer *pwr_timer; + + int power; + uint32_t scratch; + uint16_t test_reset; + uint32_t prcm_config; + uint32_t prcm_mngmt; + uint16_t otg_status; + uint32_t dev_config; + int host_mode; + uint32_t intr; + uint32_t intr_ok; + uint32_t mask; + uint32_t usbip_intr; + uint32_t usbip_mask; + uint32_t gpio_intr; + uint32_t gpio_mask; + uint32_t gpio_config; + uint32_t dma_intr; + uint32_t dma_mask; + uint32_t dma_map; + uint32_t dma_config; + uint32_t ep0_config; + uint32_t rx_config[15]; + uint32_t tx_config[15]; + uint32_t wkup_mask; + uint32_t pullup[2]; + uint32_t control_config; + uint32_t otg_timer_val; +}; + +#define TUSB_DEVCLOCK 60000000 /* 60 MHz */ + +#define TUSB_VLYNQ_CTRL 0x004 + +/* Mentor Graphics OTG core registers. */ +#define TUSB_BASE_OFFSET 0x400 + +/* FIFO registers, 32-bit. */ +#define TUSB_FIFO_BASE 0x600 + +/* Device System & Control registers, 32-bit. */ +#define TUSB_SYS_REG_BASE 0x800 + +#define TUSB_DEV_CONF (TUSB_SYS_REG_BASE + 0x000) +#define TUSB_DEV_CONF_USB_HOST_MODE (1 << 16) +#define TUSB_DEV_CONF_PROD_TEST_MODE (1 << 15) +#define TUSB_DEV_CONF_SOFT_ID (1 << 1) +#define TUSB_DEV_CONF_ID_SEL (1 << 0) + +#define TUSB_PHY_OTG_CTRL_ENABLE (TUSB_SYS_REG_BASE + 0x004) +#define TUSB_PHY_OTG_CTRL (TUSB_SYS_REG_BASE + 0x008) +#define TUSB_PHY_OTG_CTRL_WRPROTECT (0xa5 << 24) +#define TUSB_PHY_OTG_CTRL_O_ID_PULLUP (1 << 23) +#define TUSB_PHY_OTG_CTRL_O_VBUS_DET_EN (1 << 19) +#define TUSB_PHY_OTG_CTRL_O_SESS_END_EN (1 << 18) +#define TUSB_PHY_OTG_CTRL_TESTM2 (1 << 17) +#define TUSB_PHY_OTG_CTRL_TESTM1 (1 << 16) +#define TUSB_PHY_OTG_CTRL_TESTM0 (1 << 15) +#define TUSB_PHY_OTG_CTRL_TX_DATA2 (1 << 14) +#define TUSB_PHY_OTG_CTRL_TX_GZ2 (1 << 13) +#define TUSB_PHY_OTG_CTRL_TX_ENABLE2 (1 << 12) +#define TUSB_PHY_OTG_CTRL_DM_PULLDOWN (1 << 11) +#define TUSB_PHY_OTG_CTRL_DP_PULLDOWN (1 << 10) +#define TUSB_PHY_OTG_CTRL_OSC_EN (1 << 9) +#define TUSB_PHY_OTG_CTRL_PHYREF_CLK(v) (((v) & 3) << 7) +#define TUSB_PHY_OTG_CTRL_PD (1 << 6) +#define TUSB_PHY_OTG_CTRL_PLL_ON (1 << 5) +#define TUSB_PHY_OTG_CTRL_EXT_RPU (1 << 4) +#define TUSB_PHY_OTG_CTRL_PWR_GOOD (1 << 3) +#define TUSB_PHY_OTG_CTRL_RESET (1 << 2) +#define TUSB_PHY_OTG_CTRL_SUSPENDM (1 << 1) +#define TUSB_PHY_OTG_CTRL_CLK_MODE (1 << 0) + +/* OTG status register */ +#define TUSB_DEV_OTG_STAT (TUSB_SYS_REG_BASE + 0x00c) +#define TUSB_DEV_OTG_STAT_PWR_CLK_GOOD (1 << 8) +#define TUSB_DEV_OTG_STAT_SESS_END (1 << 7) +#define TUSB_DEV_OTG_STAT_SESS_VALID (1 << 6) +#define TUSB_DEV_OTG_STAT_VBUS_VALID (1 << 5) +#define TUSB_DEV_OTG_STAT_VBUS_SENSE (1 << 4) +#define TUSB_DEV_OTG_STAT_ID_STATUS (1 << 3) +#define TUSB_DEV_OTG_STAT_HOST_DISCON (1 << 2) +#define TUSB_DEV_OTG_STAT_LINE_STATE (3 << 0) +#define TUSB_DEV_OTG_STAT_DP_ENABLE (1 << 1) +#define TUSB_DEV_OTG_STAT_DM_ENABLE (1 << 0) + +#define TUSB_DEV_OTG_TIMER (TUSB_SYS_REG_BASE + 0x010) +#define TUSB_DEV_OTG_TIMER_ENABLE (1 << 31) +#define TUSB_DEV_OTG_TIMER_VAL(v) ((v) & 0x07ffffff) +#define TUSB_PRCM_REV (TUSB_SYS_REG_BASE + 0x014) + +/* PRCM configuration register */ +#define TUSB_PRCM_CONF (TUSB_SYS_REG_BASE + 0x018) +#define TUSB_PRCM_CONF_SFW_CPEN (1 << 24) +#define TUSB_PRCM_CONF_SYS_CLKSEL(v) (((v) & 3) << 16) + +/* PRCM management register */ +#define TUSB_PRCM_MNGMT (TUSB_SYS_REG_BASE + 0x01c) +#define TUSB_PRCM_MNGMT_SRP_FIX_TMR(v) (((v) & 0xf) << 25) +#define TUSB_PRCM_MNGMT_SRP_FIX_EN (1 << 24) +#define TUSB_PRCM_MNGMT_VBUS_VAL_TMR(v) (((v) & 0xf) << 20) +#define TUSB_PRCM_MNGMT_VBUS_VAL_FLT_EN (1 << 19) +#define TUSB_PRCM_MNGMT_DFT_CLK_DIS (1 << 18) +#define TUSB_PRCM_MNGMT_VLYNQ_CLK_DIS (1 << 17) +#define TUSB_PRCM_MNGMT_OTG_SESS_END_EN (1 << 10) +#define TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN (1 << 9) +#define TUSB_PRCM_MNGMT_OTG_ID_PULLUP (1 << 8) +#define TUSB_PRCM_MNGMT_15_SW_EN (1 << 4) +#define TUSB_PRCM_MNGMT_33_SW_EN (1 << 3) +#define TUSB_PRCM_MNGMT_5V_CPEN (1 << 2) +#define TUSB_PRCM_MNGMT_PM_IDLE (1 << 1) +#define TUSB_PRCM_MNGMT_DEV_IDLE (1 << 0) + +/* Wake-up source clear and mask registers */ +#define TUSB_PRCM_WAKEUP_SOURCE (TUSB_SYS_REG_BASE + 0x020) +#define TUSB_PRCM_WAKEUP_CLEAR (TUSB_SYS_REG_BASE + 0x028) +#define TUSB_PRCM_WAKEUP_MASK (TUSB_SYS_REG_BASE + 0x02c) +#define TUSB_PRCM_WAKEUP_RESERVED_BITS (0xffffe << 13) +#define TUSB_PRCM_WGPIO_7 (1 << 12) +#define TUSB_PRCM_WGPIO_6 (1 << 11) +#define TUSB_PRCM_WGPIO_5 (1 << 10) +#define TUSB_PRCM_WGPIO_4 (1 << 9) +#define TUSB_PRCM_WGPIO_3 (1 << 8) +#define TUSB_PRCM_WGPIO_2 (1 << 7) +#define TUSB_PRCM_WGPIO_1 (1 << 6) +#define TUSB_PRCM_WGPIO_0 (1 << 5) +#define TUSB_PRCM_WHOSTDISCON (1 << 4) /* Host disconnect */ +#define TUSB_PRCM_WBUS (1 << 3) /* USB bus resume */ +#define TUSB_PRCM_WNORCS (1 << 2) /* NOR chip select */ +#define TUSB_PRCM_WVBUS (1 << 1) /* OTG PHY VBUS */ +#define TUSB_PRCM_WID (1 << 0) /* OTG PHY ID detect */ + +#define TUSB_PULLUP_1_CTRL (TUSB_SYS_REG_BASE + 0x030) +#define TUSB_PULLUP_2_CTRL (TUSB_SYS_REG_BASE + 0x034) +#define TUSB_INT_CTRL_REV (TUSB_SYS_REG_BASE + 0x038) +#define TUSB_INT_CTRL_CONF (TUSB_SYS_REG_BASE + 0x03c) +#define TUSB_USBIP_INT_SRC (TUSB_SYS_REG_BASE + 0x040) +#define TUSB_USBIP_INT_SET (TUSB_SYS_REG_BASE + 0x044) +#define TUSB_USBIP_INT_CLEAR (TUSB_SYS_REG_BASE + 0x048) +#define TUSB_USBIP_INT_MASK (TUSB_SYS_REG_BASE + 0x04c) +#define TUSB_DMA_INT_SRC (TUSB_SYS_REG_BASE + 0x050) +#define TUSB_DMA_INT_SET (TUSB_SYS_REG_BASE + 0x054) +#define TUSB_DMA_INT_CLEAR (TUSB_SYS_REG_BASE + 0x058) +#define TUSB_DMA_INT_MASK (TUSB_SYS_REG_BASE + 0x05c) +#define TUSB_GPIO_INT_SRC (TUSB_SYS_REG_BASE + 0x060) +#define TUSB_GPIO_INT_SET (TUSB_SYS_REG_BASE + 0x064) +#define TUSB_GPIO_INT_CLEAR (TUSB_SYS_REG_BASE + 0x068) +#define TUSB_GPIO_INT_MASK (TUSB_SYS_REG_BASE + 0x06c) + +/* NOR flash interrupt source registers */ +#define TUSB_INT_SRC (TUSB_SYS_REG_BASE + 0x070) +#define TUSB_INT_SRC_SET (TUSB_SYS_REG_BASE + 0x074) +#define TUSB_INT_SRC_CLEAR (TUSB_SYS_REG_BASE + 0x078) +#define TUSB_INT_MASK (TUSB_SYS_REG_BASE + 0x07c) +#define TUSB_INT_SRC_TXRX_DMA_DONE (1 << 24) +#define TUSB_INT_SRC_USB_IP_CORE (1 << 17) +#define TUSB_INT_SRC_OTG_TIMEOUT (1 << 16) +#define TUSB_INT_SRC_VBUS_SENSE_CHNG (1 << 15) +#define TUSB_INT_SRC_ID_STATUS_CHNG (1 << 14) +#define TUSB_INT_SRC_DEV_WAKEUP (1 << 13) +#define TUSB_INT_SRC_DEV_READY (1 << 12) +#define TUSB_INT_SRC_USB_IP_TX (1 << 9) +#define TUSB_INT_SRC_USB_IP_RX (1 << 8) +#define TUSB_INT_SRC_USB_IP_VBUS_ERR (1 << 7) +#define TUSB_INT_SRC_USB_IP_VBUS_REQ (1 << 6) +#define TUSB_INT_SRC_USB_IP_DISCON (1 << 5) +#define TUSB_INT_SRC_USB_IP_CONN (1 << 4) +#define TUSB_INT_SRC_USB_IP_SOF (1 << 3) +#define TUSB_INT_SRC_USB_IP_RST_BABBLE (1 << 2) +#define TUSB_INT_SRC_USB_IP_RESUME (1 << 1) +#define TUSB_INT_SRC_USB_IP_SUSPEND (1 << 0) + +#define TUSB_GPIO_REV (TUSB_SYS_REG_BASE + 0x080) +#define TUSB_GPIO_CONF (TUSB_SYS_REG_BASE + 0x084) +#define TUSB_DMA_CTRL_REV (TUSB_SYS_REG_BASE + 0x100) +#define TUSB_DMA_REQ_CONF (TUSB_SYS_REG_BASE + 0x104) +#define TUSB_EP0_CONF (TUSB_SYS_REG_BASE + 0x108) +#define TUSB_EP_IN_SIZE (TUSB_SYS_REG_BASE + 0x10c) +#define TUSB_DMA_EP_MAP (TUSB_SYS_REG_BASE + 0x148) +#define TUSB_EP_OUT_SIZE (TUSB_SYS_REG_BASE + 0x14c) +#define TUSB_EP_MAX_PACKET_SIZE_OFFSET (TUSB_SYS_REG_BASE + 0x188) +#define TUSB_SCRATCH_PAD (TUSB_SYS_REG_BASE + 0x1c4) +#define TUSB_WAIT_COUNT (TUSB_SYS_REG_BASE + 0x1c8) +#define TUSB_PROD_TEST_RESET (TUSB_SYS_REG_BASE + 0x1d8) + +#define TUSB_DIDR1_LO (TUSB_SYS_REG_BASE + 0x1f8) +#define TUSB_DIDR1_HI (TUSB_SYS_REG_BASE + 0x1fc) + +/* Device System & Control register bitfields */ +#define TUSB_INT_CTRL_CONF_INT_RLCYC(v) (((v) & 0x7) << 18) +#define TUSB_INT_CTRL_CONF_INT_POLARITY (1 << 17) +#define TUSB_INT_CTRL_CONF_INT_MODE (1 << 16) +#define TUSB_GPIO_CONF_DMAREQ(v) (((v) & 0x3f) << 24) +#define TUSB_DMA_REQ_CONF_BURST_SIZE(v) (((v) & 3) << 26) +#define TUSB_DMA_REQ_CONF_DMA_RQ_EN(v) (((v) & 0x3f) << 20) +#define TUSB_DMA_REQ_CONF_DMA_RQ_ASR(v) (((v) & 0xf) << 16) +#define TUSB_EP0_CONFIG_SW_EN (1 << 8) +#define TUSB_EP0_CONFIG_DIR_TX (1 << 7) +#define TUSB_EP0_CONFIG_XFR_SIZE(v) ((v) & 0x7f) +#define TUSB_EP_CONFIG_SW_EN (1 << 31) +#define TUSB_EP_CONFIG_XFR_SIZE(v) ((v) & 0x7fffffff) +#define TUSB_PROD_TEST_RESET_VAL 0xa596 + +int tusb6010_sync_io(struct tusb_s *s) +{ + return s->iomemtype[0]; +} + +int tusb6010_async_io(struct tusb_s *s) +{ + return s->iomemtype[1]; +} + +static void tusb_intr_update(struct tusb_s *s) +{ + if (s->control_config & TUSB_INT_CTRL_CONF_INT_POLARITY) + qemu_set_irq(s->irq, s->intr & ~s->mask & s->intr_ok); + else + qemu_set_irq(s->irq, (!(s->intr & ~s->mask)) & s->intr_ok); +} + +static void tusb_usbip_intr_update(struct tusb_s *s) +{ + /* TX interrupt in the MUSB */ + if (s->usbip_intr & 0x0000ffff & ~s->usbip_mask) + s->intr |= TUSB_INT_SRC_USB_IP_TX; + else + s->intr &= ~TUSB_INT_SRC_USB_IP_TX; + + /* RX interrupt in the MUSB */ + if (s->usbip_intr & 0xffff0000 & ~s->usbip_mask) + s->intr |= TUSB_INT_SRC_USB_IP_RX; + else + s->intr &= ~TUSB_INT_SRC_USB_IP_RX; + + /* XXX: What about TUSB_INT_SRC_USB_IP_CORE? */ + + tusb_intr_update(s); +} + +static void tusb_dma_intr_update(struct tusb_s *s) +{ + if (s->dma_intr & ~s->dma_mask) + s->intr |= TUSB_INT_SRC_TXRX_DMA_DONE; + else + s->intr &= ~TUSB_INT_SRC_TXRX_DMA_DONE; + + tusb_intr_update(s); +} + +static void tusb_gpio_intr_update(struct tusb_s *s) +{ + /* TODO: How is this signalled? */ +} + +extern CPUReadMemoryFunc *musb_read[]; +extern CPUWriteMemoryFunc *musb_write[]; + +static uint32_t tusb_async_readb(void *opaque, target_phys_addr_t addr) +{ + struct tusb_s *s = (struct tusb_s *) opaque; + + switch (addr & 0xfff) { + case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff): + return musb_read[0](s->musb, addr & 0x1ff); + + case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff): + return musb_read[0](s->musb, 0x20 + ((addr >> 3) & 0x3c)); + } + + printf("%s: unknown register at %03x\n", + __FUNCTION__, (int) (addr & 0xfff)); + return 0; +} + +static uint32_t tusb_async_readh(void *opaque, target_phys_addr_t addr) +{ + struct tusb_s *s = (struct tusb_s *) opaque; + + switch (addr & 0xfff) { + case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff): + return musb_read[1](s->musb, addr & 0x1ff); + + case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff): + return musb_read[1](s->musb, 0x20 + ((addr >> 3) & 0x3c)); + } + + printf("%s: unknown register at %03x\n", + __FUNCTION__, (int) (addr & 0xfff)); + return 0; +} + +static uint32_t tusb_async_readw(void *opaque, target_phys_addr_t addr) +{ + struct tusb_s *s = (struct tusb_s *) opaque; + int offset = addr & 0xfff; + int epnum; + uint32_t ret; + + switch (offset) { + case TUSB_DEV_CONF: + return s->dev_config; + + case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff): + return musb_read[2](s->musb, offset & 0x1ff); + + case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff): + return musb_read[2](s->musb, 0x20 + ((addr >> 3) & 0x3c)); + + case TUSB_PHY_OTG_CTRL_ENABLE: + case TUSB_PHY_OTG_CTRL: + return 0x00; /* TODO */ + + case TUSB_DEV_OTG_STAT: + ret = s->otg_status; +#if 0 + if (!(s->prcm_mngmt & TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN)) + ret &= ~TUSB_DEV_OTG_STAT_VBUS_VALID; +#endif + return ret; + case TUSB_DEV_OTG_TIMER: + return s->otg_timer_val; + + case TUSB_PRCM_REV: + return 0x20; + case TUSB_PRCM_CONF: + return s->prcm_config; + case TUSB_PRCM_MNGMT: + return s->prcm_mngmt; + case TUSB_PRCM_WAKEUP_SOURCE: + case TUSB_PRCM_WAKEUP_CLEAR: /* TODO: What does this one return? */ + return 0x00000000; + case TUSB_PRCM_WAKEUP_MASK: + return s->wkup_mask; + + case TUSB_PULLUP_1_CTRL: + return s->pullup[0]; + case TUSB_PULLUP_2_CTRL: + return s->pullup[1]; + + case TUSB_INT_CTRL_REV: + return 0x20; + case TUSB_INT_CTRL_CONF: + return s->control_config; + + case TUSB_USBIP_INT_SRC: + case TUSB_USBIP_INT_SET: /* TODO: What do these two return? */ + case TUSB_USBIP_INT_CLEAR: + return s->usbip_intr; + case TUSB_USBIP_INT_MASK: + return s->usbip_mask; + + case TUSB_DMA_INT_SRC: + case TUSB_DMA_INT_SET: /* TODO: What do these two return? */ + case TUSB_DMA_INT_CLEAR: + return s->dma_intr; + case TUSB_DMA_INT_MASK: + return s->dma_mask; + + case TUSB_GPIO_INT_SRC: /* TODO: What do these two return? */ + case TUSB_GPIO_INT_SET: + case TUSB_GPIO_INT_CLEAR: + return s->gpio_intr; + case TUSB_GPIO_INT_MASK: + return s->gpio_mask; + + case TUSB_INT_SRC: + case TUSB_INT_SRC_SET: /* TODO: What do these two return? */ + case TUSB_INT_SRC_CLEAR: + return s->intr; + case TUSB_INT_MASK: + return s->mask; + + case TUSB_GPIO_REV: + return 0x30; + case TUSB_GPIO_CONF: + return s->gpio_config; + + case TUSB_DMA_CTRL_REV: + return 0x30; + case TUSB_DMA_REQ_CONF: + return s->dma_config; + case TUSB_EP0_CONF: + return s->ep0_config; + case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b): + epnum = (offset - TUSB_EP_IN_SIZE) >> 2; + return s->tx_config[epnum]; + case TUSB_DMA_EP_MAP: + return s->dma_map; + case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b): + epnum = (offset - TUSB_EP_OUT_SIZE) >> 2; + return s->rx_config[epnum]; + case TUSB_EP_MAX_PACKET_SIZE_OFFSET ... + (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b): + epnum = (offset - TUSB_EP_MAX_PACKET_SIZE_OFFSET) >> 2; + return 0x00000000; /* TODO */ + case TUSB_WAIT_COUNT: + return 0x00; /* TODO */ + + case TUSB_SCRATCH_PAD: + return s->scratch; + + case TUSB_PROD_TEST_RESET: + return s->test_reset; + + /* DIE IDs */ + case TUSB_DIDR1_LO: + return 0xa9453c59; + case TUSB_DIDR1_HI: + return 0x54059adf; + } + + printf("%s: unknown register at %03x\n", __FUNCTION__, offset); + return 0; +} + +static void tusb_async_writeb(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct tusb_s *s = (struct tusb_s *) opaque; + + switch (addr & 0xfff) { + case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff): + musb_write[0](s->musb, addr & 0x1ff, value); + break; + + case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff): + musb_write[0](s->musb, 0x20 + ((addr >> 3) & 0x3c), value); + break; + + default: + printf("%s: unknown register at %03x\n", + __FUNCTION__, (int) (addr & 0xfff)); + return; + } +} + +static void tusb_async_writeh(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct tusb_s *s = (struct tusb_s *) opaque; + + switch (addr & 0xfff) { + case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff): + musb_write[1](s->musb, addr & 0x1ff, value); + break; + + case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff): + musb_write[1](s->musb, 0x20 + ((addr >> 3) & 0x3c), value); + break; + + default: + printf("%s: unknown register at %03x\n", + __FUNCTION__, (int) (addr & 0xfff)); + return; + } +} + +static void tusb_async_writew(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct tusb_s *s = (struct tusb_s *) opaque; + int offset = addr & 0xfff; + int epnum; + + switch (offset) { + case TUSB_VLYNQ_CTRL: + break; + + case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff): + musb_write[2](s->musb, offset & 0x1ff, value); + break; + + case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff): + musb_write[2](s->musb, 0x20 + ((addr >> 3) & 0x3c), value); + break; + + case TUSB_DEV_CONF: + s->dev_config = value; + s->host_mode = (value & TUSB_DEV_CONF_USB_HOST_MODE); + if (value & TUSB_DEV_CONF_PROD_TEST_MODE) + cpu_abort(cpu_single_env, "%s: Product Test mode not allowed\n", + __FUNCTION__); + break; + + case TUSB_PHY_OTG_CTRL_ENABLE: + case TUSB_PHY_OTG_CTRL: + return; /* TODO */ + case TUSB_DEV_OTG_TIMER: + s->otg_timer_val = value; + if (value & TUSB_DEV_OTG_TIMER_ENABLE) + qemu_mod_timer(s->otg_timer, qemu_get_clock(vm_clock) + + muldiv64(TUSB_DEV_OTG_TIMER_VAL(value), + ticks_per_sec, TUSB_DEVCLOCK)); + else + qemu_del_timer(s->otg_timer); + break; + + case TUSB_PRCM_CONF: + s->prcm_config = value; + break; + case TUSB_PRCM_MNGMT: + s->prcm_mngmt = value; + break; + case TUSB_PRCM_WAKEUP_CLEAR: + break; + case TUSB_PRCM_WAKEUP_MASK: + s->wkup_mask = value; + break; + + case TUSB_PULLUP_1_CTRL: + s->pullup[0] = value; + break; + case TUSB_PULLUP_2_CTRL: + s->pullup[1] = value; + break; + case TUSB_INT_CTRL_CONF: + s->control_config = value; + tusb_intr_update(s); + break; + + case TUSB_USBIP_INT_SET: + s->usbip_intr |= value; + tusb_usbip_intr_update(s); + break; + case TUSB_USBIP_INT_CLEAR: + s->usbip_intr &= ~value; + tusb_usbip_intr_update(s); + musb_core_intr_clear(s->musb, ~value); + break; + case TUSB_USBIP_INT_MASK: + s->usbip_mask = value; + tusb_usbip_intr_update(s); + break; + + case TUSB_DMA_INT_SET: + s->dma_intr |= value; + tusb_dma_intr_update(s); + break; + case TUSB_DMA_INT_CLEAR: + s->dma_intr &= ~value; + tusb_dma_intr_update(s); + break; + case TUSB_DMA_INT_MASK: + s->dma_mask = value; + tusb_dma_intr_update(s); + break; + + case TUSB_GPIO_INT_SET: + s->gpio_intr |= value; + tusb_gpio_intr_update(s); + break; + case TUSB_GPIO_INT_CLEAR: + s->gpio_intr &= ~value; + tusb_gpio_intr_update(s); + break; + case TUSB_GPIO_INT_MASK: + s->gpio_mask = value; + tusb_gpio_intr_update(s); + break; + + case TUSB_INT_SRC_SET: + s->intr |= value; + tusb_intr_update(s); + break; + case TUSB_INT_SRC_CLEAR: + s->intr &= ~value; + tusb_intr_update(s); + break; + case TUSB_INT_MASK: + s->mask = value; + tusb_intr_update(s); + break; + + case TUSB_GPIO_CONF: + s->gpio_config = value; + break; + case TUSB_DMA_REQ_CONF: + s->dma_config = value; + break; + case TUSB_EP0_CONF: + s->ep0_config = value & 0x1ff; + musb_set_size(s->musb, 0, TUSB_EP0_CONFIG_XFR_SIZE(value), + value & TUSB_EP0_CONFIG_DIR_TX); + break; + case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b): + epnum = (offset - TUSB_EP_IN_SIZE) >> 2; + s->tx_config[epnum] = value; + musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 1); + break; + case TUSB_DMA_EP_MAP: + s->dma_map = value; + break; + case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b): + epnum = (offset - TUSB_EP_OUT_SIZE) >> 2; + s->rx_config[epnum] = value; + musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 0); + break; + case TUSB_EP_MAX_PACKET_SIZE_OFFSET ... + (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b): + epnum = (offset - TUSB_EP_MAX_PACKET_SIZE_OFFSET) >> 2; + return; /* TODO */ + case TUSB_WAIT_COUNT: + return; /* TODO */ + + case TUSB_SCRATCH_PAD: + s->scratch = value; + break; + + case TUSB_PROD_TEST_RESET: + s->test_reset = value; + break; + + default: + printf("%s: unknown register at %03x\n", __FUNCTION__, offset); + return; + } +} + +static CPUReadMemoryFunc *tusb_async_readfn[] = { + tusb_async_readb, + tusb_async_readh, + tusb_async_readw, +}; + +static CPUWriteMemoryFunc *tusb_async_writefn[] = { + tusb_async_writeb, + tusb_async_writeh, + tusb_async_writew, +}; + +static void tusb_otg_tick(void *opaque) +{ + struct tusb_s *s = (struct tusb_s *) opaque; + + s->otg_timer_val = 0; + s->intr |= TUSB_INT_SRC_OTG_TIMEOUT; + tusb_intr_update(s); +} + +static void tusb_power_tick(void *opaque) +{ + struct tusb_s *s = (struct tusb_s *) opaque; + + if (s->power) { + s->intr_ok = ~0; + tusb_intr_update(s); + } +} + +static void tusb_musb_core_intr(void *opaque, int source, int level) +{ + struct tusb_s *s = (struct tusb_s *) opaque; + uint16_t otg_status = s->otg_status; + + switch (source) { + case musb_set_vbus: + if (level) + otg_status |= TUSB_DEV_OTG_STAT_VBUS_VALID; + else + otg_status &= ~TUSB_DEV_OTG_STAT_VBUS_VALID; + + /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_VBUS_DET_EN set? */ + /* XXX: only if TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN set? */ + if (s->otg_status != otg_status) { + s->otg_status = otg_status; + s->intr |= TUSB_INT_SRC_VBUS_SENSE_CHNG; + tusb_intr_update(s); + } + break; + + case musb_set_session: + /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_SESS_END_EN set? */ + /* XXX: only if TUSB_PRCM_MNGMT_OTG_SESS_END_EN set? */ + if (level) { + s->otg_status |= TUSB_DEV_OTG_STAT_SESS_VALID; + s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_END; + } else { + s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_VALID; + s->otg_status |= TUSB_DEV_OTG_STAT_SESS_END; + } + + /* XXX: some IRQ or anything? */ + break; + + case musb_irq_tx: + case musb_irq_rx: + s->usbip_intr = musb_core_intr_get(s->musb); + /* Fall through. */ + default: + if (level) + s->intr |= 1 << source; + else + s->intr &= ~(1 << source); + tusb_intr_update(s); + break; + } +} + +struct tusb_s *tusb6010_init(qemu_irq intr) +{ + struct tusb_s *s = qemu_mallocz(sizeof(*s)); + + s->test_reset = TUSB_PROD_TEST_RESET_VAL; + s->host_mode = 0; + s->dev_config = 0; + s->otg_status = 0; /* !TUSB_DEV_OTG_STAT_ID_STATUS means host mode */ + s->power = 0; + s->mask = 0xffffffff; + s->intr = 0x00000000; + s->otg_timer_val = 0; + s->iomemtype[1] = cpu_register_io_memory(0, tusb_async_readfn, + tusb_async_writefn, s); + s->irq = intr; + s->otg_timer = qemu_new_timer(vm_clock, tusb_otg_tick, s); + s->pwr_timer = qemu_new_timer(vm_clock, tusb_power_tick, s); + s->musb = musb_init(qemu_allocate_irqs(tusb_musb_core_intr, s, + __musb_irq_max)); + + return s; +} + +void tusb6010_power(struct tusb_s *s, int on) +{ + if (!on) + s->power = 0; + else if (!s->power && on) { + s->power = 1; + + /* Pull the interrupt down after TUSB6010 comes up. */ + s->intr_ok = 0; + tusb_intr_update(s); + qemu_mod_timer(s->pwr_timer, + qemu_get_clock(vm_clock) + ticks_per_sec / 2); + } +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/twl92230.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/twl92230.c --- qemu-0.9.1/hw/twl92230.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/twl92230.c 2008-08-17 21:26:25.000000000 +0100 @@ -0,0 +1,916 @@ +/* + * TI TWL92230C energy-management companion device for the OMAP24xx. + * Aka. Menelaus (N4200 MENELAUS1_V2.2) + * + * Copyright (C) 2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "hw.h" +#include "qemu-timer.h" +#include "i2c.h" +#include "sysemu.h" +#include "console.h" + +#define VERBOSE 1 + +struct menelaus_s { + i2c_slave i2c; + qemu_irq irq; + + int firstbyte; + uint8_t reg; + + uint8_t vcore[5]; + uint8_t dcdc[3]; + uint8_t ldo[8]; + uint8_t sleep[2]; + uint8_t osc; + uint8_t detect; + uint16_t mask; + uint16_t status; + uint8_t dir; + uint8_t inputs; + uint8_t outputs; + uint8_t bbsms; + uint8_t pull[4]; + uint8_t mmc_ctrl[3]; + uint8_t mmc_debounce; + struct { + uint8_t ctrl; + uint16_t comp; + QEMUTimer *hz; + int64_t next; + struct tm tm; + struct tm new; + struct tm alm; + int sec_offset; + int alm_sec; + int next_comp; + } rtc; + qemu_irq handler[3]; + qemu_irq *in; + int pwrbtn_state; + qemu_irq pwrbtn; +}; + +static inline void menelaus_update(struct menelaus_s *s) +{ + qemu_set_irq(s->irq, s->status & ~s->mask); +} + +static inline void menelaus_rtc_start(struct menelaus_s *s) +{ + s->rtc.next =+ qemu_get_clock(rt_clock); + qemu_mod_timer(s->rtc.hz, s->rtc.next); +} + +static inline void menelaus_rtc_stop(struct menelaus_s *s) +{ + qemu_del_timer(s->rtc.hz); + s->rtc.next =- qemu_get_clock(rt_clock); + if (s->rtc.next < 1) + s->rtc.next = 1; +} + +static void menelaus_rtc_update(struct menelaus_s *s) +{ + qemu_get_timedate(&s->rtc.tm, s->rtc.sec_offset); +} + +static void menelaus_alm_update(struct menelaus_s *s) +{ + if ((s->rtc.ctrl & 3) == 3) + s->rtc.alm_sec = qemu_timedate_diff(&s->rtc.alm) - s->rtc.sec_offset; +} + +static void menelaus_rtc_hz(void *opaque) +{ + struct menelaus_s *s = (struct menelaus_s *) opaque; + + s->rtc.next_comp --; + s->rtc.alm_sec --; + s->rtc.next += 1000; + qemu_mod_timer(s->rtc.hz, s->rtc.next); + if ((s->rtc.ctrl >> 3) & 3) { /* EVERY */ + menelaus_rtc_update(s); + if (((s->rtc.ctrl >> 3) & 3) == 1 && !s->rtc.tm.tm_sec) + s->status |= 1 << 8; /* RTCTMR */ + else if (((s->rtc.ctrl >> 3) & 3) == 2 && !s->rtc.tm.tm_min) + s->status |= 1 << 8; /* RTCTMR */ + else if (!s->rtc.tm.tm_hour) + s->status |= 1 << 8; /* RTCTMR */ + } else + s->status |= 1 << 8; /* RTCTMR */ + if ((s->rtc.ctrl >> 1) & 1) { /* RTC_AL_EN */ + if (s->rtc.alm_sec == 0) + s->status |= 1 << 9; /* RTCALM */ + /* TODO: wake-up */ + } + if (s->rtc.next_comp <= 0) { + s->rtc.next -= muldiv64((int16_t) s->rtc.comp, 1000, 0x8000); + s->rtc.next_comp = 3600; + } + menelaus_update(s); +} + +static void menelaus_reset(i2c_slave *i2c) +{ + struct menelaus_s *s = (struct menelaus_s *) i2c; + s->reg = 0x00; + + s->vcore[0] = 0x0c; /* XXX: X-loader needs 0x8c? check! */ + s->vcore[1] = 0x05; + s->vcore[2] = 0x02; + s->vcore[3] = 0x0c; + s->vcore[4] = 0x03; + s->dcdc[0] = 0x33; /* Depends on wiring */ + s->dcdc[1] = 0x03; + s->dcdc[2] = 0x00; + s->ldo[0] = 0x95; + s->ldo[1] = 0x7e; + s->ldo[2] = 0x00; + s->ldo[3] = 0x00; /* Depends on wiring */ + s->ldo[4] = 0x03; /* Depends on wiring */ + s->ldo[5] = 0x00; + s->ldo[6] = 0x00; + s->ldo[7] = 0x00; + s->sleep[0] = 0x00; + s->sleep[1] = 0x00; + s->osc = 0x01; + s->detect = 0x09; + s->mask = 0x0fff; + s->status = 0; + s->dir = 0x07; + s->outputs = 0x00; + s->bbsms = 0x00; + s->pull[0] = 0x00; + s->pull[1] = 0x00; + s->pull[2] = 0x00; + s->pull[3] = 0x00; + s->mmc_ctrl[0] = 0x03; + s->mmc_ctrl[1] = 0xc0; + s->mmc_ctrl[2] = 0x00; + s->mmc_debounce = 0x05; + + if (s->rtc.ctrl & 1) + menelaus_rtc_stop(s); + s->rtc.ctrl = 0x00; + s->rtc.comp = 0x0000; + s->rtc.next = 1000; + s->rtc.sec_offset = 0; + s->rtc.next_comp = 1800; + s->rtc.alm_sec = 1800; + s->rtc.alm.tm_sec = 0x00; + s->rtc.alm.tm_min = 0x00; + s->rtc.alm.tm_hour = 0x00; + s->rtc.alm.tm_mday = 0x01; + s->rtc.alm.tm_mon = 0x00; + s->rtc.alm.tm_year = 2004; + menelaus_update(s); +} + +static inline uint8_t to_bcd(int val) +{ + return ((val / 10) << 4) | (val % 10); +} + +static inline int from_bcd(uint8_t val) +{ + return ((val >> 4) * 10) + (val & 0x0f); +} + +static void menelaus_gpio_set(void *opaque, int line, int level) +{ + struct menelaus_s *s = (struct menelaus_s *) opaque; + + /* No interrupt generated */ + s->inputs &= ~(1 << line); + s->inputs |= level << line; +} + +static void menelaus_pwrbtn_set(void *opaque, int line, int level) +{ + struct menelaus_s *s = (struct menelaus_s *) opaque; + + if (!s->pwrbtn_state && level) { + s->status |= 1 << 11; /* PSHBTN */ + menelaus_update(s); + } + s->pwrbtn_state = level; +} + +#define MENELAUS_REV 0x01 +#define MENELAUS_VCORE_CTRL1 0x02 +#define MENELAUS_VCORE_CTRL2 0x03 +#define MENELAUS_VCORE_CTRL3 0x04 +#define MENELAUS_VCORE_CTRL4 0x05 +#define MENELAUS_VCORE_CTRL5 0x06 +#define MENELAUS_DCDC_CTRL1 0x07 +#define MENELAUS_DCDC_CTRL2 0x08 +#define MENELAUS_DCDC_CTRL3 0x09 +#define MENELAUS_LDO_CTRL1 0x0a +#define MENELAUS_LDO_CTRL2 0x0b +#define MENELAUS_LDO_CTRL3 0x0c +#define MENELAUS_LDO_CTRL4 0x0d +#define MENELAUS_LDO_CTRL5 0x0e +#define MENELAUS_LDO_CTRL6 0x0f +#define MENELAUS_LDO_CTRL7 0x10 +#define MENELAUS_LDO_CTRL8 0x11 +#define MENELAUS_SLEEP_CTRL1 0x12 +#define MENELAUS_SLEEP_CTRL2 0x13 +#define MENELAUS_DEVICE_OFF 0x14 +#define MENELAUS_OSC_CTRL 0x15 +#define MENELAUS_DETECT_CTRL 0x16 +#define MENELAUS_INT_MASK1 0x17 +#define MENELAUS_INT_MASK2 0x18 +#define MENELAUS_INT_STATUS1 0x19 +#define MENELAUS_INT_STATUS2 0x1a +#define MENELAUS_INT_ACK1 0x1b +#define MENELAUS_INT_ACK2 0x1c +#define MENELAUS_GPIO_CTRL 0x1d +#define MENELAUS_GPIO_IN 0x1e +#define MENELAUS_GPIO_OUT 0x1f +#define MENELAUS_BBSMS 0x20 +#define MENELAUS_RTC_CTRL 0x21 +#define MENELAUS_RTC_UPDATE 0x22 +#define MENELAUS_RTC_SEC 0x23 +#define MENELAUS_RTC_MIN 0x24 +#define MENELAUS_RTC_HR 0x25 +#define MENELAUS_RTC_DAY 0x26 +#define MENELAUS_RTC_MON 0x27 +#define MENELAUS_RTC_YR 0x28 +#define MENELAUS_RTC_WKDAY 0x29 +#define MENELAUS_RTC_AL_SEC 0x2a +#define MENELAUS_RTC_AL_MIN 0x2b +#define MENELAUS_RTC_AL_HR 0x2c +#define MENELAUS_RTC_AL_DAY 0x2d +#define MENELAUS_RTC_AL_MON 0x2e +#define MENELAUS_RTC_AL_YR 0x2f +#define MENELAUS_RTC_COMP_MSB 0x30 +#define MENELAUS_RTC_COMP_LSB 0x31 +#define MENELAUS_S1_PULL_EN 0x32 +#define MENELAUS_S1_PULL_DIR 0x33 +#define MENELAUS_S2_PULL_EN 0x34 +#define MENELAUS_S2_PULL_DIR 0x35 +#define MENELAUS_MCT_CTRL1 0x36 +#define MENELAUS_MCT_CTRL2 0x37 +#define MENELAUS_MCT_CTRL3 0x38 +#define MENELAUS_MCT_PIN_ST 0x39 +#define MENELAUS_DEBOUNCE1 0x3a + +static uint8_t menelaus_read(void *opaque, uint8_t addr) +{ + struct menelaus_s *s = (struct menelaus_s *) opaque; + int reg = 0; + + switch (addr) { + case MENELAUS_REV: + return 0x22; + + case MENELAUS_VCORE_CTRL5: reg ++; + case MENELAUS_VCORE_CTRL4: reg ++; + case MENELAUS_VCORE_CTRL3: reg ++; + case MENELAUS_VCORE_CTRL2: reg ++; + case MENELAUS_VCORE_CTRL1: + return s->vcore[reg]; + + case MENELAUS_DCDC_CTRL3: reg ++; + case MENELAUS_DCDC_CTRL2: reg ++; + case MENELAUS_DCDC_CTRL1: + return s->dcdc[reg]; + + case MENELAUS_LDO_CTRL8: reg ++; + case MENELAUS_LDO_CTRL7: reg ++; + case MENELAUS_LDO_CTRL6: reg ++; + case MENELAUS_LDO_CTRL5: reg ++; + case MENELAUS_LDO_CTRL4: reg ++; + case MENELAUS_LDO_CTRL3: reg ++; + case MENELAUS_LDO_CTRL2: reg ++; + case MENELAUS_LDO_CTRL1: + return s->ldo[reg]; + + case MENELAUS_SLEEP_CTRL2: reg ++; + case MENELAUS_SLEEP_CTRL1: + return s->sleep[reg]; + + case MENELAUS_DEVICE_OFF: + return 0; + + case MENELAUS_OSC_CTRL: + return s->osc | (1 << 7); /* CLK32K_GOOD */ + + case MENELAUS_DETECT_CTRL: + return s->detect; + + case MENELAUS_INT_MASK1: + return (s->mask >> 0) & 0xff; + case MENELAUS_INT_MASK2: + return (s->mask >> 8) & 0xff; + + case MENELAUS_INT_STATUS1: + return (s->status >> 0) & 0xff; + case MENELAUS_INT_STATUS2: + return (s->status >> 8) & 0xff; + + case MENELAUS_INT_ACK1: + case MENELAUS_INT_ACK2: + return 0; + + case MENELAUS_GPIO_CTRL: + return s->dir; + case MENELAUS_GPIO_IN: + return s->inputs | (~s->dir & s->outputs); + case MENELAUS_GPIO_OUT: + return s->outputs; + + case MENELAUS_BBSMS: + return s->bbsms; + + case MENELAUS_RTC_CTRL: + return s->rtc.ctrl; + case MENELAUS_RTC_UPDATE: + return 0x00; + case MENELAUS_RTC_SEC: + menelaus_rtc_update(s); + return to_bcd(s->rtc.tm.tm_sec); + case MENELAUS_RTC_MIN: + menelaus_rtc_update(s); + return to_bcd(s->rtc.tm.tm_min); + case MENELAUS_RTC_HR: + menelaus_rtc_update(s); + if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */ + return to_bcd((s->rtc.tm.tm_hour % 12) + 1) | + (!!(s->rtc.tm.tm_hour >= 12) << 7); /* PM_nAM */ + else + return to_bcd(s->rtc.tm.tm_hour); + case MENELAUS_RTC_DAY: + menelaus_rtc_update(s); + return to_bcd(s->rtc.tm.tm_mday); + case MENELAUS_RTC_MON: + menelaus_rtc_update(s); + return to_bcd(s->rtc.tm.tm_mon + 1); + case MENELAUS_RTC_YR: + menelaus_rtc_update(s); + return to_bcd(s->rtc.tm.tm_year - 2000); + case MENELAUS_RTC_WKDAY: + menelaus_rtc_update(s); + return to_bcd(s->rtc.tm.tm_wday); + case MENELAUS_RTC_AL_SEC: + return to_bcd(s->rtc.alm.tm_sec); + case MENELAUS_RTC_AL_MIN: + return to_bcd(s->rtc.alm.tm_min); + case MENELAUS_RTC_AL_HR: + if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */ + return to_bcd((s->rtc.alm.tm_hour % 12) + 1) | + (!!(s->rtc.alm.tm_hour >= 12) << 7);/* AL_PM_nAM */ + else + return to_bcd(s->rtc.alm.tm_hour); + case MENELAUS_RTC_AL_DAY: + return to_bcd(s->rtc.alm.tm_mday); + case MENELAUS_RTC_AL_MON: + return to_bcd(s->rtc.alm.tm_mon + 1); + case MENELAUS_RTC_AL_YR: + return to_bcd(s->rtc.alm.tm_year - 2000); + case MENELAUS_RTC_COMP_MSB: + return (s->rtc.comp >> 8) & 0xff; + case MENELAUS_RTC_COMP_LSB: + return (s->rtc.comp >> 0) & 0xff; + + case MENELAUS_S1_PULL_EN: + return s->pull[0]; + case MENELAUS_S1_PULL_DIR: + return s->pull[1]; + case MENELAUS_S2_PULL_EN: + return s->pull[2]; + case MENELAUS_S2_PULL_DIR: + return s->pull[3]; + + case MENELAUS_MCT_CTRL3: reg ++; + case MENELAUS_MCT_CTRL2: reg ++; + case MENELAUS_MCT_CTRL1: + return s->mmc_ctrl[reg]; + case MENELAUS_MCT_PIN_ST: + /* TODO: return the real Card Detect */ + return 0; + case MENELAUS_DEBOUNCE1: + return s->mmc_debounce; + + default: +#ifdef VERBOSE + printf("%s: unknown register %02x\n", __FUNCTION__, addr); +#endif + break; + } + return 0; +} + +static void menelaus_write(void *opaque, uint8_t addr, uint8_t value) +{ + struct menelaus_s *s = (struct menelaus_s *) opaque; + int line; + int reg = 0; + struct tm tm; + + switch (addr) { + case MENELAUS_VCORE_CTRL1: + s->vcore[0] = (value & 0xe) | MIN(value & 0x1f, 0x12); + break; + case MENELAUS_VCORE_CTRL2: + s->vcore[1] = value; + break; + case MENELAUS_VCORE_CTRL3: + s->vcore[2] = MIN(value & 0x1f, 0x12); + break; + case MENELAUS_VCORE_CTRL4: + s->vcore[3] = MIN(value & 0x1f, 0x12); + break; + case MENELAUS_VCORE_CTRL5: + s->vcore[4] = value & 3; + /* XXX + * auto set to 3 on M_Active, nRESWARM + * auto set to 0 on M_WaitOn, M_Backup + */ + break; + + case MENELAUS_DCDC_CTRL1: + s->dcdc[0] = value & 0x3f; + break; + case MENELAUS_DCDC_CTRL2: + s->dcdc[1] = value & 0x07; + /* XXX + * auto set to 3 on M_Active, nRESWARM + * auto set to 0 on M_WaitOn, M_Backup + */ + break; + case MENELAUS_DCDC_CTRL3: + s->dcdc[2] = value & 0x07; + break; + + case MENELAUS_LDO_CTRL1: + s->ldo[0] = value; + break; + case MENELAUS_LDO_CTRL2: + s->ldo[1] = value & 0x7f; + /* XXX + * auto set to 0x7e on M_WaitOn, M_Backup + */ + break; + case MENELAUS_LDO_CTRL3: + s->ldo[2] = value & 3; + /* XXX + * auto set to 3 on M_Active, nRESWARM + * auto set to 0 on M_WaitOn, M_Backup + */ + break; + case MENELAUS_LDO_CTRL4: + s->ldo[3] = value & 3; + /* XXX + * auto set to 3 on M_Active, nRESWARM + * auto set to 0 on M_WaitOn, M_Backup + */ + break; + case MENELAUS_LDO_CTRL5: + s->ldo[4] = value & 3; + /* XXX + * auto set to 3 on M_Active, nRESWARM + * auto set to 0 on M_WaitOn, M_Backup + */ + break; + case MENELAUS_LDO_CTRL6: + s->ldo[5] = value & 3; + break; + case MENELAUS_LDO_CTRL7: + s->ldo[6] = value & 3; + break; + case MENELAUS_LDO_CTRL8: + s->ldo[7] = value & 3; + break; + + case MENELAUS_SLEEP_CTRL2: reg ++; + case MENELAUS_SLEEP_CTRL1: + s->sleep[reg] = value; + break; + + case MENELAUS_DEVICE_OFF: + if (value & 1) + menelaus_reset(&s->i2c); + break; + + case MENELAUS_OSC_CTRL: + s->osc = value & 7; + break; + + case MENELAUS_DETECT_CTRL: + s->detect = value & 0x7f; + break; + + case MENELAUS_INT_MASK1: + s->mask &= 0xf00; + s->mask |= value << 0; + menelaus_update(s); + break; + case MENELAUS_INT_MASK2: + s->mask &= 0x0ff; + s->mask |= value << 8; + menelaus_update(s); + break; + + case MENELAUS_INT_ACK1: + s->status &= ~(((uint16_t) value) << 0); + menelaus_update(s); + break; + case MENELAUS_INT_ACK2: + s->status &= ~(((uint16_t) value) << 8); + menelaus_update(s); + break; + + case MENELAUS_GPIO_CTRL: + for (line = 0; line < 3; line ++) + if (((s->dir ^ value) >> line) & 1) + if (s->handler[line]) + qemu_set_irq(s->handler[line], + ((s->outputs & ~s->dir) >> line) & 1); + s->dir = value & 0x67; + break; + case MENELAUS_GPIO_OUT: + for (line = 0; line < 3; line ++) + if ((((s->outputs ^ value) & ~s->dir) >> line) & 1) + if (s->handler[line]) + qemu_set_irq(s->handler[line], (s->outputs >> line) & 1); + s->outputs = value & 0x07; + break; + + case MENELAUS_BBSMS: + s->bbsms = 0x0d; + break; + + case MENELAUS_RTC_CTRL: + if ((s->rtc.ctrl ^ value) & 1) { /* RTC_EN */ + if (value & 1) + menelaus_rtc_start(s); + else + menelaus_rtc_stop(s); + } + s->rtc.ctrl = value & 0x1f; + menelaus_alm_update(s); + break; + case MENELAUS_RTC_UPDATE: + menelaus_rtc_update(s); + memcpy(&tm, &s->rtc.tm, sizeof(tm)); + switch (value & 0xf) { + case 0: + break; + case 1: + tm.tm_sec = s->rtc.new.tm_sec; + break; + case 2: + tm.tm_min = s->rtc.new.tm_min; + break; + case 3: + if (s->rtc.new.tm_hour > 23) + goto rtc_badness; + tm.tm_hour = s->rtc.new.tm_hour; + break; + case 4: + if (s->rtc.new.tm_mday < 1) + goto rtc_badness; + /* TODO check range */ + tm.tm_mday = s->rtc.new.tm_mday; + break; + case 5: + if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11) + goto rtc_badness; + tm.tm_mon = s->rtc.new.tm_mon; + break; + case 6: + tm.tm_year = s->rtc.new.tm_year; + break; + case 7: + /* TODO set .tm_mday instead */ + tm.tm_wday = s->rtc.new.tm_wday; + break; + case 8: + if (s->rtc.new.tm_hour > 23) + goto rtc_badness; + if (s->rtc.new.tm_mday < 1) + goto rtc_badness; + if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11) + goto rtc_badness; + tm.tm_sec = s->rtc.new.tm_sec; + tm.tm_min = s->rtc.new.tm_min; + tm.tm_hour = s->rtc.new.tm_hour; + tm.tm_mday = s->rtc.new.tm_mday; + tm.tm_mon = s->rtc.new.tm_mon; + tm.tm_year = s->rtc.new.tm_year; + break; + rtc_badness: + default: + fprintf(stderr, "%s: bad RTC_UPDATE value %02x\n", + __FUNCTION__, value); + s->status |= 1 << 10; /* RTCERR */ + menelaus_update(s); + } + s->rtc.sec_offset = qemu_timedate_diff(&tm); + break; + case MENELAUS_RTC_SEC: + s->rtc.tm.tm_sec = from_bcd(value & 0x7f); + break; + case MENELAUS_RTC_MIN: + s->rtc.tm.tm_min = from_bcd(value & 0x7f); + break; + case MENELAUS_RTC_HR: + s->rtc.tm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */ + MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) : + from_bcd(value & 0x3f); + break; + case MENELAUS_RTC_DAY: + s->rtc.tm.tm_mday = from_bcd(value); + break; + case MENELAUS_RTC_MON: + s->rtc.tm.tm_mon = MAX(1, from_bcd(value)) - 1; + break; + case MENELAUS_RTC_YR: + s->rtc.tm.tm_year = 2000 + from_bcd(value); + break; + case MENELAUS_RTC_WKDAY: + s->rtc.tm.tm_mday = from_bcd(value); + break; + case MENELAUS_RTC_AL_SEC: + s->rtc.alm.tm_sec = from_bcd(value & 0x7f); + menelaus_alm_update(s); + break; + case MENELAUS_RTC_AL_MIN: + s->rtc.alm.tm_min = from_bcd(value & 0x7f); + menelaus_alm_update(s); + break; + case MENELAUS_RTC_AL_HR: + s->rtc.alm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */ + MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) : + from_bcd(value & 0x3f); + menelaus_alm_update(s); + break; + case MENELAUS_RTC_AL_DAY: + s->rtc.alm.tm_mday = from_bcd(value); + menelaus_alm_update(s); + break; + case MENELAUS_RTC_AL_MON: + s->rtc.alm.tm_mon = MAX(1, from_bcd(value)) - 1; + menelaus_alm_update(s); + break; + case MENELAUS_RTC_AL_YR: + s->rtc.alm.tm_year = 2000 + from_bcd(value); + menelaus_alm_update(s); + break; + case MENELAUS_RTC_COMP_MSB: + s->rtc.comp &= 0xff; + s->rtc.comp |= value << 8; + break; + case MENELAUS_RTC_COMP_LSB: + s->rtc.comp &= 0xff << 8; + s->rtc.comp |= value; + break; + + case MENELAUS_S1_PULL_EN: + s->pull[0] = value; + break; + case MENELAUS_S1_PULL_DIR: + s->pull[1] = value & 0x1f; + break; + case MENELAUS_S2_PULL_EN: + s->pull[2] = value; + break; + case MENELAUS_S2_PULL_DIR: + s->pull[3] = value & 0x1f; + break; + + case MENELAUS_MCT_CTRL1: + s->mmc_ctrl[0] = value & 0x7f; + break; + case MENELAUS_MCT_CTRL2: + s->mmc_ctrl[1] = value; + /* TODO update Card Detect interrupts */ + break; + case MENELAUS_MCT_CTRL3: + s->mmc_ctrl[2] = value & 0xf; + break; + case MENELAUS_DEBOUNCE1: + s->mmc_debounce = value & 0x3f; + break; + + default: +#ifdef VERBOSE + printf("%s: unknown register %02x\n", __FUNCTION__, addr); +#endif + } +} + +static void menelaus_event(i2c_slave *i2c, enum i2c_event event) +{ + struct menelaus_s *s = (struct menelaus_s *) i2c; + + if (event == I2C_START_SEND) + s->firstbyte = 1; +} + +static int menelaus_tx(i2c_slave *i2c, uint8_t data) +{ + struct menelaus_s *s = (struct menelaus_s *) i2c; + /* Interpret register address byte */ + if (s->firstbyte) { + s->reg = data; + s->firstbyte = 0; + } else + menelaus_write(s, s->reg ++, data); + + return 0; +} + +static int menelaus_rx(i2c_slave *i2c) +{ + struct menelaus_s *s = (struct menelaus_s *) i2c; + + return menelaus_read(s, s->reg ++); +} + +static void tm_put(QEMUFile *f, struct tm *tm) { + qemu_put_be16(f, tm->tm_sec); + qemu_put_be16(f, tm->tm_min); + qemu_put_be16(f, tm->tm_hour); + qemu_put_be16(f, tm->tm_mday); + qemu_put_be16(f, tm->tm_min); + qemu_put_be16(f, tm->tm_year); +} + +static void tm_get(QEMUFile *f, struct tm *tm) { + tm->tm_sec = qemu_get_be16(f); + tm->tm_min = qemu_get_be16(f); + tm->tm_hour = qemu_get_be16(f); + tm->tm_mday = qemu_get_be16(f); + tm->tm_min = qemu_get_be16(f); + tm->tm_year = qemu_get_be16(f); +} + +static void menelaus_save(QEMUFile *f, void *opaque) +{ + struct menelaus_s *s = (struct menelaus_s *) opaque; + + qemu_put_be32(f, s->firstbyte); + qemu_put_8s(f, &s->reg); + + qemu_put_8s(f, &s->vcore[0]); + qemu_put_8s(f, &s->vcore[1]); + qemu_put_8s(f, &s->vcore[2]); + qemu_put_8s(f, &s->vcore[3]); + qemu_put_8s(f, &s->vcore[4]); + qemu_put_8s(f, &s->dcdc[3]); + qemu_put_8s(f, &s->dcdc[3]); + qemu_put_8s(f, &s->dcdc[3]); + qemu_put_8s(f, &s->ldo[0]); + qemu_put_8s(f, &s->ldo[1]); + qemu_put_8s(f, &s->ldo[2]); + qemu_put_8s(f, &s->ldo[3]); + qemu_put_8s(f, &s->ldo[4]); + qemu_put_8s(f, &s->ldo[5]); + qemu_put_8s(f, &s->ldo[6]); + qemu_put_8s(f, &s->ldo[7]); + qemu_put_8s(f, &s->sleep[0]); + qemu_put_8s(f, &s->sleep[1]); + qemu_put_8s(f, &s->osc); + qemu_put_8s(f, &s->detect); + qemu_put_be16s(f, &s->mask); + qemu_put_be16s(f, &s->status); + qemu_put_8s(f, &s->dir); + qemu_put_8s(f, &s->inputs); + qemu_put_8s(f, &s->outputs); + qemu_put_8s(f, &s->bbsms); + qemu_put_8s(f, &s->pull[0]); + qemu_put_8s(f, &s->pull[1]); + qemu_put_8s(f, &s->pull[2]); + qemu_put_8s(f, &s->pull[3]); + qemu_put_8s(f, &s->mmc_ctrl[0]); + qemu_put_8s(f, &s->mmc_ctrl[1]); + qemu_put_8s(f, &s->mmc_ctrl[2]); + qemu_put_8s(f, &s->mmc_debounce); + qemu_put_8s(f, &s->rtc.ctrl); + qemu_put_be16s(f, &s->rtc.comp); + /* Should be <= 1000 */ + qemu_put_be16(f, s->rtc.next - qemu_get_clock(rt_clock)); + tm_put(f, &s->rtc.new); + tm_put(f, &s->rtc.alm); + qemu_put_byte(f, s->pwrbtn_state); + + i2c_slave_save(f, &s->i2c); +} + +static int menelaus_load(QEMUFile *f, void *opaque, int version_id) +{ + struct menelaus_s *s = (struct menelaus_s *) opaque; + + s->firstbyte = qemu_get_be32(f); + qemu_get_8s(f, &s->reg); + + if (s->rtc.ctrl & 1) /* RTC_EN */ + menelaus_rtc_stop(s); + qemu_get_8s(f, &s->vcore[0]); + qemu_get_8s(f, &s->vcore[1]); + qemu_get_8s(f, &s->vcore[2]); + qemu_get_8s(f, &s->vcore[3]); + qemu_get_8s(f, &s->vcore[4]); + qemu_get_8s(f, &s->dcdc[3]); + qemu_get_8s(f, &s->dcdc[3]); + qemu_get_8s(f, &s->dcdc[3]); + qemu_get_8s(f, &s->ldo[0]); + qemu_get_8s(f, &s->ldo[1]); + qemu_get_8s(f, &s->ldo[2]); + qemu_get_8s(f, &s->ldo[3]); + qemu_get_8s(f, &s->ldo[4]); + qemu_get_8s(f, &s->ldo[5]); + qemu_get_8s(f, &s->ldo[6]); + qemu_get_8s(f, &s->ldo[7]); + qemu_get_8s(f, &s->sleep[0]); + qemu_get_8s(f, &s->sleep[1]); + qemu_get_8s(f, &s->osc); + qemu_get_8s(f, &s->detect); + qemu_get_be16s(f, &s->mask); + qemu_get_be16s(f, &s->status); + qemu_get_8s(f, &s->dir); + qemu_get_8s(f, &s->inputs); + qemu_get_8s(f, &s->outputs); + qemu_get_8s(f, &s->bbsms); + qemu_get_8s(f, &s->pull[0]); + qemu_get_8s(f, &s->pull[1]); + qemu_get_8s(f, &s->pull[2]); + qemu_get_8s(f, &s->pull[3]); + qemu_get_8s(f, &s->mmc_ctrl[0]); + qemu_get_8s(f, &s->mmc_ctrl[1]); + qemu_get_8s(f, &s->mmc_ctrl[2]); + qemu_get_8s(f, &s->mmc_debounce); + qemu_get_8s(f, &s->rtc.ctrl); + qemu_get_be16s(f, &s->rtc.comp); + s->rtc.next = qemu_get_be16(f); + tm_get(f, &s->rtc.new); + tm_get(f, &s->rtc.alm); + s->pwrbtn_state = qemu_get_byte(f); + menelaus_alm_update(s); + menelaus_update(s); + if (s->rtc.ctrl & 1) /* RTC_EN */ + menelaus_rtc_start(s); + + i2c_slave_load(f, &s->i2c); + return 0; +} + +i2c_slave *twl92230_init(i2c_bus *bus, qemu_irq irq) +{ + struct menelaus_s *s = (struct menelaus_s *) + i2c_slave_init(bus, 0, sizeof(struct menelaus_s)); + + s->i2c.event = menelaus_event; + s->i2c.recv = menelaus_rx; + s->i2c.send = menelaus_tx; + + s->irq = irq; + s->rtc.hz = qemu_new_timer(rt_clock, menelaus_rtc_hz, s); + s->in = qemu_allocate_irqs(menelaus_gpio_set, s, 3); + s->pwrbtn = qemu_allocate_irqs(menelaus_pwrbtn_set, s, 1)[0]; + + menelaus_reset(&s->i2c); + + register_savevm("menelaus", -1, 0, menelaus_save, menelaus_load, s); + + return &s->i2c; +} + +qemu_irq *twl92230_gpio_in_get(i2c_slave *i2c) +{ + struct menelaus_s *s = (struct menelaus_s *) i2c; + + return s->in; +} + +void twl92230_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler) +{ + struct menelaus_s *s = (struct menelaus_s *) i2c; + + if (line >= 3 || line < 0) { + fprintf(stderr, "%s: No GPO line %i\n", __FUNCTION__, line); + exit(-1); + } + s->handler[line] = handler; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/usb-bt.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/usb-bt.c --- qemu-0.9.1/hw/usb-bt.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/usb-bt.c 2008-11-09 02:24:54.000000000 +0000 @@ -0,0 +1,649 @@ +/* + * QEMU Bluetooth HCI USB Transport Layer v1.0 + * + * Copyright (C) 2007 OpenMoko, Inc. + * Copyright (C) 2008 Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "qemu-common.h" +#include "usb.h" +#include "net.h" +#include "bt.h" + +struct USBBtState { + USBDevice dev; + struct HCIInfo *hci; + + int altsetting; + int config; + +#define CFIFO_LEN_MASK 255 +#define DFIFO_LEN_MASK 4095 + struct usb_hci_in_fifo_s { + uint8_t data[(DFIFO_LEN_MASK + 1) * 2]; + struct { + uint8_t *data; + int len; + } fifo[CFIFO_LEN_MASK + 1]; + int dstart, dlen, dsize, start, len; + } evt, acl, sco; + + struct usb_hci_out_fifo_s { + uint8_t data[4096]; + int len; + } outcmd, outacl, outsco; +}; + +#define USB_EVT_EP 1 +#define USB_ACL_EP 2 +#define USB_SCO_EP 3 + +static const uint8_t qemu_bt_dev_descriptor[] = { + 0x12, /* u8 bLength; */ + USB_DT_DEVICE, /* u8 bDescriptorType; Device */ + 0x10, 0x01, /* u16 bcdUSB; v1.10 */ + + 0xe0, /* u8 bDeviceClass; Wireless */ + 0x01, /* u8 bDeviceSubClass; Radio Frequency */ + 0x01, /* u8 bDeviceProtocol; Bluetooth */ + 0x40, /* u8 bMaxPacketSize0; 64 Bytes */ + + 0x12, 0x0a, /* u16 idVendor; */ + 0x01, 0x00, /* u16 idProduct; Bluetooth Dongle (HCI mode) */ + 0x58, 0x19, /* u16 bcdDevice; (some devices have 0x48, 0x02) */ + + 0x00, /* u8 iManufacturer; */ + 0x00, /* u8 iProduct; */ + 0x00, /* u8 iSerialNumber; */ + 0x01, /* u8 bNumConfigurations; */ +}; + +static const uint8_t qemu_bt_config_descriptor[] = { + /* one configuration */ + 0x09, /* u8 bLength; */ + USB_DT_CONFIG, /* u8 bDescriptorType; */ + 0xb1, 0x00, /* u16 wTotalLength; */ + 0x02, /* u8 bNumInterfaces; (2) */ + 0x01, /* u8 bConfigurationValue; */ + 0x00, /* u8 iConfiguration; */ + 0xc0, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 0x00, /* u8 MaxPower; */ + + /* USB 1.1: + * USB 2.0, single TT organization (mandatory): + * one interface, protocol 0 + * + * USB 2.0, multiple TT organization (optional): + * two interfaces, protocols 1 (like single TT) + * and 2 (multiple TT mode) ... config is + * sometimes settable + * NOT IMPLEMENTED + */ + + /* interface one */ + 0x09, /* u8 if_bLength; */ + USB_DT_INTERFACE, /* u8 if_bDescriptorType; */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x03, /* u8 if_bNumEndpoints; */ + 0xe0, /* u8 if_bInterfaceClass; Wireless */ + 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */ + 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */ + 0x00, /* u8 if_iInterface; */ + + /* endpoint one */ + 0x07, /* u8 ep_bLength; */ + USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ + USB_DIR_IN | USB_EVT_EP, /* u8 ep_bEndpointAddress; */ + 0x03, /* u8 ep_bmAttributes; Interrupt */ + 0x10, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x02, /* u8 ep_bInterval; */ + + /* endpoint two */ + 0x07, /* u8 ep_bLength; */ + USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ + USB_DIR_OUT | USB_ACL_EP, /* u8 ep_bEndpointAddress; */ + 0x02, /* u8 ep_bmAttributes; Bulk */ + 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + + /* endpoint three */ + 0x07, /* u8 ep_bLength; */ + USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ + USB_DIR_IN | USB_ACL_EP, /* u8 ep_bEndpointAddress; */ + 0x02, /* u8 ep_bmAttributes; Bulk */ + 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + + /* interface two setting one */ + 0x09, /* u8 if_bLength; */ + USB_DT_INTERFACE, /* u8 if_bDescriptorType; */ + 0x01, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x02, /* u8 if_bNumEndpoints; */ + 0xe0, /* u8 if_bInterfaceClass; Wireless */ + 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */ + 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */ + 0x00, /* u8 if_iInterface; */ + + /* endpoint one */ + 0x07, /* u8 ep_bLength; */ + USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ + USB_DIR_OUT | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ + 0x01, /* u8 ep_bmAttributes; Isochronous */ + 0x00, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + + /* endpoint two */ + 0x07, /* u8 ep_bLength; */ + USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ + USB_DIR_IN | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ + 0x01, /* u8 ep_bmAttributes; Isochronous */ + 0x00, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + + /* interface two setting two */ + 0x09, /* u8 if_bLength; */ + USB_DT_INTERFACE, /* u8 if_bDescriptorType; */ + 0x01, /* u8 if_bInterfaceNumber; */ + 0x01, /* u8 if_bAlternateSetting; */ + 0x02, /* u8 if_bNumEndpoints; */ + 0xe0, /* u8 if_bInterfaceClass; Wireless */ + 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */ + 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */ + 0x00, /* u8 if_iInterface; */ + + /* endpoint one */ + 0x07, /* u8 ep_bLength; */ + USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ + USB_DIR_OUT | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ + 0x01, /* u8 ep_bmAttributes; Isochronous */ + 0x09, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + + /* endpoint two */ + 0x07, /* u8 ep_bLength; */ + USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ + USB_DIR_IN | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ + 0x01, /* u8 ep_bmAttributes; Isochronous */ + 0x09, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + + /* interface two setting three */ + 0x09, /* u8 if_bLength; */ + USB_DT_INTERFACE, /* u8 if_bDescriptorType; */ + 0x01, /* u8 if_bInterfaceNumber; */ + 0x02, /* u8 if_bAlternateSetting; */ + 0x02, /* u8 if_bNumEndpoints; */ + 0xe0, /* u8 if_bInterfaceClass; Wireless */ + 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */ + 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */ + 0x00, /* u8 if_iInterface; */ + + /* endpoint one */ + 0x07, /* u8 ep_bLength; */ + USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ + USB_DIR_OUT | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ + 0x01, /* u8 ep_bmAttributes; Isochronous */ + 0x11, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + + /* endpoint two */ + 0x07, /* u8 ep_bLength; */ + USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ + USB_DIR_IN | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ + 0x01, /* u8 ep_bmAttributes; Isochronous */ + 0x11, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + + /* interface two setting four */ + 0x09, /* u8 if_bLength; */ + USB_DT_INTERFACE, /* u8 if_bDescriptorType; */ + 0x01, /* u8 if_bInterfaceNumber; */ + 0x03, /* u8 if_bAlternateSetting; */ + 0x02, /* u8 if_bNumEndpoints; */ + 0xe0, /* u8 if_bInterfaceClass; Wireless */ + 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */ + 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */ + 0x00, /* u8 if_iInterface; */ + + /* endpoint one */ + 0x07, /* u8 ep_bLength; */ + USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ + USB_DIR_OUT | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ + 0x01, /* u8 ep_bmAttributes; Isochronous */ + 0x19, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + + /* endpoint two */ + 0x07, /* u8 ep_bLength; */ + USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ + USB_DIR_IN | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ + 0x01, /* u8 ep_bmAttributes; Isochronous */ + 0x19, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + + /* interface two setting five */ + 0x09, /* u8 if_bLength; */ + USB_DT_INTERFACE, /* u8 if_bDescriptorType; */ + 0x01, /* u8 if_bInterfaceNumber; */ + 0x04, /* u8 if_bAlternateSetting; */ + 0x02, /* u8 if_bNumEndpoints; */ + 0xe0, /* u8 if_bInterfaceClass; Wireless */ + 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */ + 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */ + 0x00, /* u8 if_iInterface; */ + + /* endpoint one */ + 0x07, /* u8 ep_bLength; */ + USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ + USB_DIR_OUT | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ + 0x01, /* u8 ep_bmAttributes; Isochronous */ + 0x21, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + + /* endpoint two */ + 0x07, /* u8 ep_bLength; */ + USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ + USB_DIR_IN | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ + 0x01, /* u8 ep_bmAttributes; Isochronous */ + 0x21, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + + /* interface two setting six */ + 0x09, /* u8 if_bLength; */ + USB_DT_INTERFACE, /* u8 if_bDescriptorType; */ + 0x01, /* u8 if_bInterfaceNumber; */ + 0x05, /* u8 if_bAlternateSetting; */ + 0x02, /* u8 if_bNumEndpoints; */ + 0xe0, /* u8 if_bInterfaceClass; Wireless */ + 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */ + 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */ + 0x00, /* u8 if_iInterface; */ + + /* endpoint one */ + 0x07, /* u8 ep_bLength; */ + USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ + USB_DIR_OUT | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ + 0x01, /* u8 ep_bmAttributes; Isochronous */ + 0x31, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + + /* endpoint two */ + 0x07, /* u8 ep_bLength; */ + USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */ + USB_DIR_IN | USB_SCO_EP, /* u8 ep_bEndpointAddress; */ + 0x01, /* u8 ep_bmAttributes; Isochronous */ + 0x31, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + + /* If implemented, the DFU interface descriptor goes here with no + * endpoints or alternative settings. */ +}; + +static void usb_bt_fifo_reset(struct usb_hci_in_fifo_s *fifo) +{ + fifo->dstart = 0; + fifo->dlen = 0; + fifo->dsize = DFIFO_LEN_MASK + 1; + fifo->start = 0; + fifo->len = 0; +} + +static void usb_bt_fifo_enqueue(struct usb_hci_in_fifo_s *fifo, + const uint8_t *data, int len) +{ + int off = fifo->dstart + fifo->dlen; + uint8_t *buf; + + fifo->dlen += len; + if (off <= DFIFO_LEN_MASK) { + if (off + len > DFIFO_LEN_MASK + 1 && + (fifo->dsize = off + len) > (DFIFO_LEN_MASK + 1) * 2) { + fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len); + exit(-1); + } + buf = fifo->data + off; + } else { + if (fifo->dlen > fifo->dsize) { + fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len); + exit(-1); + } + buf = fifo->data + off - fifo->dsize; + } + + off = (fifo->start + fifo->len ++) & CFIFO_LEN_MASK; + fifo->fifo[off].data = memcpy(buf, data, len); + fifo->fifo[off].len = len; +} + +static inline int usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo, + USBPacket *p) +{ + int len; + + if (likely(!fifo->len)) + return USB_RET_STALL; + + len = MIN(p->len, fifo->fifo[fifo->start].len); + memcpy(p->data, fifo->fifo[fifo->start].data, len); + if (len == p->len) { + fifo->fifo[fifo->start].len -= len; + fifo->fifo[fifo->start].data += len; + } else { + fifo->start ++; + fifo->start &= CFIFO_LEN_MASK; + fifo->len --; + } + + fifo->dstart += len; + fifo->dlen -= len; + if (fifo->dstart >= fifo->dsize) { + fifo->dstart = 0; + fifo->dsize = DFIFO_LEN_MASK + 1; + } + + return len; +} + +static void inline usb_bt_fifo_out_enqueue(struct USBBtState *s, + struct usb_hci_out_fifo_s *fifo, + void (*send)(struct HCIInfo *, const uint8_t *, int), + int (*complete)(const uint8_t *, int), + const uint8_t *data, int len) +{ + if (fifo->len) { + memcpy(fifo->data + fifo->len, data, len); + fifo->len += len; + if (complete(fifo->data, fifo->len)) { + send(s->hci, fifo->data, fifo->len); + fifo->len = 0; + } + } else if (complete(data, len)) + send(s->hci, data, len); + else { + memcpy(fifo->data, data, len); + fifo->len = len; + } + + /* TODO: do we need to loop? */ +} + +static int usb_bt_hci_cmd_complete(const uint8_t *data, int len) +{ + len -= HCI_COMMAND_HDR_SIZE; + return len >= 0 && + len >= ((struct hci_command_hdr *) data)->plen; +} + +static int usb_bt_hci_acl_complete(const uint8_t *data, int len) +{ + len -= HCI_ACL_HDR_SIZE; + return len >= 0 && + len >= le16_to_cpu(((struct hci_acl_hdr *) data)->dlen); +} + +static int usb_bt_hci_sco_complete(const uint8_t *data, int len) +{ + len -= HCI_SCO_HDR_SIZE; + return len >= 0 && + len >= ((struct hci_sco_hdr *) data)->dlen; +} + +static void usb_bt_handle_reset(USBDevice *dev) +{ + struct USBBtState *s = (struct USBBtState *) dev->opaque; + + usb_bt_fifo_reset(&s->evt); + usb_bt_fifo_reset(&s->acl); + usb_bt_fifo_reset(&s->sco); + s->outcmd.len = 0; + s->outacl.len = 0; + s->outsco.len = 0; + s->altsetting = 0; +} + +static int usb_bt_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + struct USBBtState *s = (struct USBBtState *) dev->opaque; + int ret = 0; + + switch (request) { + case DeviceRequest | USB_REQ_GET_STATUS: + case InterfaceRequest | USB_REQ_GET_STATUS: + case EndpointRequest | USB_REQ_GET_STATUS: + data[0] = (1 << USB_DEVICE_SELF_POWERED) | + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[1] = 0x00; + ret = 2; + break; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + case InterfaceOutRequest | USB_REQ_CLEAR_FEATURE: + case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + case InterfaceOutRequest | USB_REQ_SET_FEATURE: + case EndpointOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch (value >> 8) { + case USB_DT_DEVICE: + ret = sizeof(qemu_bt_dev_descriptor); + memcpy(data, qemu_bt_dev_descriptor, ret); + break; + case USB_DT_CONFIG: + ret = sizeof(qemu_bt_config_descriptor); + memcpy(data, qemu_bt_config_descriptor, ret); + break; + case USB_DT_STRING: + switch(value & 0xff) { + case 0: + /* language ids */ + data[0] = 4; + data[1] = 3; + data[2] = 0x09; + data[3] = 0x04; + ret = 4; + break; + default: + goto fail; + } + break; + default: + goto fail; + } + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = qemu_bt_config_descriptor[0x5]; + ret = 1; + s->config = 0; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + ret = 0; + if (value != qemu_bt_config_descriptor[0x5] && value != 0) { + printf("%s: Wrong SET_CONFIGURATION request (%i)\n", + __FUNCTION__, value); + goto fail; + } + s->config = 1; + usb_bt_fifo_reset(&s->evt); + usb_bt_fifo_reset(&s->acl); + usb_bt_fifo_reset(&s->sco); + break; + case InterfaceRequest | USB_REQ_GET_INTERFACE: + if (value != 0 || (index & ~1) || length != 1) + goto fail; + if (index == 1) + data[0] = s->altsetting; + else + data[0] = 0; + ret = 1; + break; + case InterfaceOutRequest | USB_REQ_SET_INTERFACE: + if ((index & ~1) || length != 0 || + (index == 1 && (value < 0 || value > 4)) || + (index == 0 && value != 0)) { + printf("%s: Wrong SET_INTERFACE request (%i, %i)\n", + __FUNCTION__, index, value); + goto fail; + } + s->altsetting = value; + ret = 0; + break; + case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8): + if (s->config) + usb_bt_fifo_out_enqueue(s, &s->outcmd, s->hci->cmd_send, + usb_bt_hci_cmd_complete, data, length); + break; + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +static int usb_bt_handle_data(USBDevice *dev, USBPacket *p) +{ + struct USBBtState *s = (struct USBBtState *) dev->opaque; + int ret = 0; + + if (!s->config) + goto fail; + + switch (p->pid) { + case USB_TOKEN_IN: + switch (p->devep & 0xf) { + case USB_EVT_EP: + ret = usb_bt_fifo_dequeue(&s->evt, p); + break; + + case USB_ACL_EP: + ret = usb_bt_fifo_dequeue(&s->acl, p); + break; + + case USB_SCO_EP: + ret = usb_bt_fifo_dequeue(&s->sco, p); + break; + + default: + goto fail; + } + break; + + case USB_TOKEN_OUT: + switch (p->devep & 0xf) { + case USB_ACL_EP: + usb_bt_fifo_out_enqueue(s, &s->outacl, s->hci->acl_send, + usb_bt_hci_acl_complete, p->data, p->len); + break; + + case USB_SCO_EP: + usb_bt_fifo_out_enqueue(s, &s->outsco, s->hci->sco_send, + usb_bt_hci_sco_complete, p->data, p->len); + break; + + default: + goto fail; + } + break; + + default: + fail: + ret = USB_RET_STALL; + break; + } + + return ret; +} + +static void usb_bt_out_hci_packet_event(void *opaque, + const uint8_t *data, int len) +{ + struct USBBtState *s = (struct USBBtState *) opaque; + + usb_bt_fifo_enqueue(&s->evt, data, len); +} + +static void usb_bt_out_hci_packet_acl(void *opaque, + const uint8_t *data, int len) +{ + struct USBBtState *s = (struct USBBtState *) opaque; + + usb_bt_fifo_enqueue(&s->acl, data, len); +} + +static void usb_bt_handle_destroy(USBDevice *dev) +{ + struct USBBtState *s = (struct USBBtState *) dev->opaque; + + s->hci->opaque = 0; + s->hci->evt_recv = 0; + s->hci->acl_recv = 0; + qemu_free(s); +} + +USBDevice *usb_bt_init(HCIInfo *hci) +{ + struct USBBtState *s; + + if (!hci) + return NULL; + s = qemu_mallocz(sizeof(struct USBBtState)); + if (!s) + return NULL; + s->dev.opaque = s; + s->dev.speed = USB_SPEED_HIGH; + s->dev.handle_packet = usb_generic_handle_packet; + pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU BT dongle"); + + s->dev.handle_reset = usb_bt_handle_reset; + s->dev.handle_control = usb_bt_handle_control; + s->dev.handle_data = usb_bt_handle_data; + s->dev.handle_destroy = usb_bt_handle_destroy; + + s->hci = hci; + s->hci->opaque = s; + s->hci->evt_recv = usb_bt_out_hci_packet_event; + s->hci->acl_recv = usb_bt_out_hci_packet_acl; + + usb_bt_handle_reset(&s->dev); + + return &s->dev; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/usb.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/usb.c --- qemu-0.9.1/hw/usb.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/usb.c 2008-08-21 20:29:38.000000000 +0100 @@ -3,6 +3,8 @@ * * Copyright (c) 2005 Fabrice Bellard * + * 2008 Generic packet handler rewrite by Max Krasnyansky + * * 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 @@ -30,6 +32,7 @@ } /**********************/ + /* generic USB device helpers (you are not forced to use them when writing your USB device driver, but they help handling the protocol) @@ -39,141 +42,164 @@ #define SETUP_STATE_DATA 1 #define SETUP_STATE_ACK 2 -int usb_generic_handle_packet(USBDevice *s, USBPacket *p) +static int do_token_setup(USBDevice *s, USBPacket *p) +{ + int request, value, index; + int ret = 0; + + if (p->len != 8) + return USB_RET_STALL; + + memcpy(s->setup_buf, p->data, 8); + s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6]; + s->setup_index = 0; + + request = (s->setup_buf[0] << 8) | s->setup_buf[1]; + value = (s->setup_buf[3] << 8) | s->setup_buf[2]; + index = (s->setup_buf[5] << 8) | s->setup_buf[4]; + + if (s->setup_buf[0] & USB_DIR_IN) { + ret = s->handle_control(s, request, value, index, + s->setup_len, s->data_buf); + if (ret < 0) + return ret; + + if (ret < s->setup_len) + s->setup_len = ret; + s->setup_state = SETUP_STATE_DATA; + } else { + if (s->setup_len == 0) + s->setup_state = SETUP_STATE_ACK; + else + s->setup_state = SETUP_STATE_DATA; + } + + return ret; +} + +static int do_token_in(USBDevice *s, USBPacket *p) +{ + int request, value, index; + int ret = 0; + + if (p->devep != 0) + return s->handle_data(s, p); + + request = (s->setup_buf[0] << 8) | s->setup_buf[1]; + value = (s->setup_buf[3] << 8) | s->setup_buf[2]; + index = (s->setup_buf[5] << 8) | s->setup_buf[4]; + + switch(s->setup_state) { + case SETUP_STATE_ACK: + if (!(s->setup_buf[0] & USB_DIR_IN)) { + s->setup_state = SETUP_STATE_IDLE; + ret = s->handle_control(s, request, value, index, + s->setup_len, s->data_buf); + if (ret > 0) + return 0; + return ret; + } + + /* return 0 byte */ + return 0; + + case SETUP_STATE_DATA: + if (s->setup_buf[0] & USB_DIR_IN) { + int len = s->setup_len - s->setup_index; + if (len > p->len) + len = p->len; + memcpy(p->data, s->data_buf + s->setup_index, len); + s->setup_index += len; + if (s->setup_index >= s->setup_len) + s->setup_state = SETUP_STATE_ACK; + return len; + } + + s->setup_state = SETUP_STATE_IDLE; + return USB_RET_STALL; + + default: + return USB_RET_STALL; + } +} + +static int do_token_out(USBDevice *s, USBPacket *p) { - int l, ret = 0; - int len = p->len; - uint8_t *data = p->data; + if (p->devep != 0) + return s->handle_data(s, p); + + switch(s->setup_state) { + case SETUP_STATE_ACK: + if (s->setup_buf[0] & USB_DIR_IN) { + s->setup_state = SETUP_STATE_IDLE; + /* transfer OK */ + } else { + /* ignore additional output */ + } + return 0; + case SETUP_STATE_DATA: + if (!(s->setup_buf[0] & USB_DIR_IN)) { + int len = s->setup_len - s->setup_index; + if (len > p->len) + len = p->len; + memcpy(s->data_buf + s->setup_index, p->data, len); + s->setup_index += len; + if (s->setup_index >= s->setup_len) + s->setup_state = SETUP_STATE_ACK; + return len; + } + + s->setup_state = SETUP_STATE_IDLE; + return USB_RET_STALL; + + default: + return USB_RET_STALL; + } +} + +/* + * Generic packet handler. + * Called by the HC (host controller). + * + * Returns length of the transaction or one of the USB_RET_XXX codes. + */ +int usb_generic_handle_packet(USBDevice *s, USBPacket *p) +{ switch(p->pid) { case USB_MSG_ATTACH: s->state = USB_STATE_ATTACHED; - break; + return 0; + case USB_MSG_DETACH: s->state = USB_STATE_NOTATTACHED; - break; + return 0; + case USB_MSG_RESET: s->remote_wakeup = 0; s->addr = 0; s->state = USB_STATE_DEFAULT; s->handle_reset(s); - break; + return 0; + } + + /* Rest of the PIDs must match our address */ + if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr) + return USB_RET_NODEV; + + switch (p->pid) { case USB_TOKEN_SETUP: - if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr) - return USB_RET_NODEV; - if (len != 8) - goto fail; - memcpy(s->setup_buf, data, 8); - s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6]; - s->setup_index = 0; - if (s->setup_buf[0] & USB_DIR_IN) { - ret = s->handle_control(s, - (s->setup_buf[0] << 8) | s->setup_buf[1], - (s->setup_buf[3] << 8) | s->setup_buf[2], - (s->setup_buf[5] << 8) | s->setup_buf[4], - s->setup_len, - s->data_buf); - if (ret < 0) - return ret; - if (ret < s->setup_len) - s->setup_len = ret; - s->setup_state = SETUP_STATE_DATA; - } else { - if (s->setup_len == 0) - s->setup_state = SETUP_STATE_ACK; - else - s->setup_state = SETUP_STATE_DATA; - } - break; + return do_token_setup(s, p); + case USB_TOKEN_IN: - if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr) - return USB_RET_NODEV; - switch(p->devep) { - case 0: - switch(s->setup_state) { - case SETUP_STATE_ACK: - if (!(s->setup_buf[0] & USB_DIR_IN)) { - s->setup_state = SETUP_STATE_IDLE; - ret = s->handle_control(s, - (s->setup_buf[0] << 8) | s->setup_buf[1], - (s->setup_buf[3] << 8) | s->setup_buf[2], - (s->setup_buf[5] << 8) | s->setup_buf[4], - s->setup_len, - s->data_buf); - if (ret > 0) - ret = 0; - } else { - /* return 0 byte */ - } - break; - case SETUP_STATE_DATA: - if (s->setup_buf[0] & USB_DIR_IN) { - l = s->setup_len - s->setup_index; - if (l > len) - l = len; - memcpy(data, s->data_buf + s->setup_index, l); - s->setup_index += l; - if (s->setup_index >= s->setup_len) - s->setup_state = SETUP_STATE_ACK; - ret = l; - } else { - s->setup_state = SETUP_STATE_IDLE; - goto fail; - } - break; - default: - goto fail; - } - break; - default: - ret = s->handle_data(s, p); - break; - } - break; + return do_token_in(s, p); + case USB_TOKEN_OUT: - if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr) - return USB_RET_NODEV; - switch(p->devep) { - case 0: - switch(s->setup_state) { - case SETUP_STATE_ACK: - if (s->setup_buf[0] & USB_DIR_IN) { - s->setup_state = SETUP_STATE_IDLE; - /* transfer OK */ - } else { - /* ignore additional output */ - } - break; - case SETUP_STATE_DATA: - if (!(s->setup_buf[0] & USB_DIR_IN)) { - l = s->setup_len - s->setup_index; - if (l > len) - l = len; - memcpy(s->data_buf + s->setup_index, data, l); - s->setup_index += l; - if (s->setup_index >= s->setup_len) - s->setup_state = SETUP_STATE_ACK; - ret = l; - } else { - s->setup_state = SETUP_STATE_IDLE; - goto fail; - } - break; - default: - goto fail; - } - break; - default: - ret = s->handle_data(s, p); - break; - } - break; + return do_token_out(s, p); + default: - fail: - ret = USB_RET_STALL; - break; + return USB_RET_STALL; } - return ret; } /* XXX: fix overflow */ @@ -200,5 +226,6 @@ memset(&p, 0, sizeof(p)); p.pid = msg; dev->handle_packet(dev, &p); -} + /* This _must_ be synchronous */ +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/usb.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/usb.h --- qemu-0.9.1/hw/usb.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/usb.h 2008-09-29 01:40:44.000000000 +0100 @@ -108,6 +108,11 @@ #define USB_DT_INTERFACE 0x04 #define USB_DT_ENDPOINT 0x05 +#define USB_ENDPOINT_XFER_CONTROL 0 +#define USB_ENDPOINT_XFER_ISOC 1 +#define USB_ENDPOINT_XFER_BULK 2 +#define USB_ENDPOINT_XFER_INT 3 + typedef struct USBPort USBPort; typedef struct USBDevice USBDevice; typedef struct USBPacket USBPacket; @@ -115,18 +120,49 @@ /* definition of a USB device */ struct USBDevice { void *opaque; + + /* + * Process USB packet. + * Called by the HC (Host Controller). + * + * Returns length of the transaction + * or one of the USB_RET_XXX codes. + */ int (*handle_packet)(USBDevice *dev, USBPacket *p); + + /* + * Called when device is destroyed. + */ void (*handle_destroy)(USBDevice *dev); int speed; /* The following fields are used by the generic USB device - layer. They are here just to avoid creating a new structure for - them. */ + layer. They are here just to avoid creating a new structure + for them. */ + + /* + * Reset the device + */ void (*handle_reset)(USBDevice *dev); + + /* + * Process control request. + * Called from handle_packet(). + * + * Returns length or one of the USB_RET_ codes. + */ int (*handle_control)(USBDevice *dev, int request, int value, int index, int length, uint8_t *data); + + /* + * Process data transfers (both BULK and ISOC). + * Called from handle_packet(). + * + * Returns length or one of the USB_RET_ codes. + */ int (*handle_data)(USBDevice *dev, USBPacket *p); + uint8_t addr; char devname[32]; @@ -192,31 +228,42 @@ p->cancel_cb(p, p->cancel_opaque); } +int usb_device_add_dev(USBDevice *dev); +int usb_device_del_addr(int bus_num, int addr); void usb_attach(USBPort *port, USBDevice *dev); int usb_generic_handle_packet(USBDevice *s, USBPacket *p); int set_usb_string(uint8_t *buf, const char *str); void usb_send_msg(USBDevice *dev, int msg); -void usb_packet_complete(USBPacket *p); - /* usb hub */ USBDevice *usb_hub_init(int nb_ports); /* usb-linux.c */ USBDevice *usb_host_device_open(const char *devname); +int usb_host_device_close(const char *devname); void usb_host_info(void); /* usb-hid.c */ USBDevice *usb_mouse_init(void); USBDevice *usb_tablet_init(void); USBDevice *usb_keyboard_init(void); +void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *)); /* usb-msd.c */ USBDevice *usb_msd_init(const char *filename); +/* usb-net.c */ +USBDevice *usb_net_init(NICInfo *nd); + +/* usb-bt.c */ +USBDevice *usb_bt_init(HCIInfo *hci); + /* usb-wacom.c */ USBDevice *usb_wacom_init(void); +/* usb-serial.c */ +USBDevice *usb_serial_init(const char *filename); + /* usb ports of the VM */ void qemu_register_usb_port(USBPort *port, void *opaque, int index, @@ -224,3 +271,25 @@ #define VM_USB_HUB_SIZE 8 +/* usb-musb.c */ +enum musb_irq_source_e { + musb_irq_suspend = 0, + musb_irq_resume, + musb_irq_rst_babble, + musb_irq_sof, + musb_irq_connect, + musb_irq_disconnect, + musb_irq_vbus_request, + musb_irq_vbus_error, + musb_irq_rx, + musb_irq_tx, + musb_set_vbus, + musb_set_session, + __musb_irq_max, +}; + +struct musb_s; +struct musb_s *musb_init(qemu_irq *irqs); +uint32_t musb_core_intr_get(struct musb_s *s); +void musb_core_intr_clear(struct musb_s *s, uint32_t mask); +void musb_set_size(struct musb_s *s, int epnum, int size, int is_tx); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/usb-hid.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/usb-hid.c --- qemu-0.9.1/hw/usb-hid.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/usb-hid.c 2008-09-29 01:25:17.000000000 +0100 @@ -67,6 +67,8 @@ int protocol; int idle; int changed; + void *datain_opaque; + void (*datain)(void *); } USBHIDState; /* mostly the same values as the Bochs USB Mouse device */ @@ -134,14 +136,14 @@ 0x00, /* u8 country_code */ 0x01, /* u8 num_descriptors */ 0x22, /* u8 type; Report */ - 50, 0, /* u16 len */ + 52, 0, /* u16 len */ /* one endpoint (status change endpoint) */ 0x07, /* u8 ep_bLength; */ 0x05, /* u8 ep_bDescriptorType; Endpoint */ 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x03, /* u8 ep_bmAttributes; Interrupt */ - 0x03, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x04, 0x00, /* u16 ep_wMaxPacketSize; */ 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ }; @@ -256,53 +258,73 @@ }; static const uint8_t qemu_mouse_hid_report_descriptor[] = { - 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, - 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, - 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, - 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01, - 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81, - 0x25, 0x7F, 0x75, 0x08, 0x95, 0x02, 0x81, 0x06, - 0xC0, 0xC0, + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x02, /* Usage (Mouse) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x09, 0x01, /* Usage (Pointer) */ + 0xa1, 0x00, /* Collection (Physical) */ + 0x05, 0x09, /* Usage Page (Button) */ + 0x19, 0x01, /* Usage Minimum (1) */ + 0x29, 0x03, /* Usage Maximum (3) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x95, 0x03, /* Report Count (3) */ + 0x75, 0x01, /* Report Size (1) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x05, /* Report Size (5) */ + 0x81, 0x01, /* Input (Constant) */ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x30, /* Usage (X) */ + 0x09, 0x31, /* Usage (Y) */ + 0x09, 0x38, /* Usage (Wheel) */ + 0x15, 0x81, /* Logical Minimum (-0x7f) */ + 0x25, 0x7f, /* Logical Maximum (0x7f) */ + 0x75, 0x08, /* Report Size (8) */ + 0x95, 0x03, /* Report Count (3) */ + 0x81, 0x06, /* Input (Data, Variable, Relative) */ + 0xc0, /* End Collection */ + 0xc0, /* End Collection */ }; static const uint8_t qemu_tablet_hid_report_descriptor[] = { - 0x05, 0x01, /* Usage Page Generic Desktop */ - 0x09, 0x01, /* Usage Mouse */ - 0xA1, 0x01, /* Collection Application */ - 0x09, 0x01, /* Usage Pointer */ - 0xA1, 0x00, /* Collection Physical */ - 0x05, 0x09, /* Usage Page Button */ - 0x19, 0x01, /* Usage Minimum Button 1 */ - 0x29, 0x03, /* Usage Maximum Button 3 */ - 0x15, 0x00, /* Logical Minimum 0 */ - 0x25, 0x01, /* Logical Maximum 1 */ - 0x95, 0x03, /* Report Count 3 */ - 0x75, 0x01, /* Report Size 1 */ - 0x81, 0x02, /* Input (Data, Var, Abs) */ - 0x95, 0x01, /* Report Count 1 */ - 0x75, 0x05, /* Report Size 5 */ - 0x81, 0x01, /* Input (Cnst, Var, Abs) */ - 0x05, 0x01, /* Usage Page Generic Desktop */ - 0x09, 0x30, /* Usage X */ - 0x09, 0x31, /* Usage Y */ - 0x15, 0x00, /* Logical Minimum 0 */ - 0x26, 0xFF, 0x7F, /* Logical Maximum 0x7fff */ - 0x35, 0x00, /* Physical Minimum 0 */ - 0x46, 0xFE, 0x7F, /* Physical Maximum 0x7fff */ - 0x75, 0x10, /* Report Size 16 */ - 0x95, 0x02, /* Report Count 2 */ - 0x81, 0x02, /* Input (Data, Var, Abs) */ - 0x05, 0x01, /* Usage Page Generic Desktop */ - 0x09, 0x38, /* Usage Wheel */ - 0x15, 0x81, /* Logical Minimum -127 */ - 0x25, 0x7F, /* Logical Maximum 127 */ - 0x35, 0x00, /* Physical Minimum 0 (same as logical) */ - 0x45, 0x00, /* Physical Maximum 0 (same as logical) */ - 0x75, 0x08, /* Report Size 8 */ - 0x95, 0x01, /* Report Count 1 */ - 0x81, 0x02, /* Input (Data, Var, Rel) */ - 0xC0, /* End Collection */ - 0xC0, /* End Collection */ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x01, /* Usage (Pointer) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x09, 0x01, /* Usage (Pointer) */ + 0xa1, 0x00, /* Collection (Physical) */ + 0x05, 0x09, /* Usage Page (Button) */ + 0x19, 0x01, /* Usage Minimum (1) */ + 0x29, 0x03, /* Usage Maximum (3) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x95, 0x03, /* Report Count (3) */ + 0x75, 0x01, /* Report Size (1) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x05, /* Report Size (5) */ + 0x81, 0x01, /* Input (Constant) */ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x30, /* Usage (X) */ + 0x09, 0x31, /* Usage (Y) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x26, 0xff, 0x7f, /* Logical Maximum (0x7fff) */ + 0x35, 0x00, /* Physical Minimum (0) */ + 0x46, 0xff, 0x7f, /* Physical Maximum (0x7fff) */ + 0x75, 0x10, /* Report Size (16) */ + 0x95, 0x02, /* Report Count (2) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x38, /* Usage (Wheel) */ + 0x15, 0x81, /* Logical Minimum (-0x7f) */ + 0x25, 0x7f, /* Logical Maximum (0x7f) */ + 0x35, 0x00, /* Physical Minimum (same as logical) */ + 0x45, 0x00, /* Physical Maximum (same as logical) */ + 0x75, 0x08, /* Report Size (8) */ + 0x95, 0x01, /* Report Count (1) */ + 0x81, 0x06, /* Input (Data, Variable, Relative) */ + 0xc0, /* End Collection */ + 0xc0, /* End Collection */ }; static const uint8_t qemu_keyboard_hid_report_descriptor[] = { @@ -382,6 +404,14 @@ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +static void usb_hid_changed(USBHIDState *hs) +{ + hs->changed = 1; + + if (hs->datain) + hs->datain(hs->datain_opaque); +} + static void usb_mouse_event(void *opaque, int dx1, int dy1, int dz1, int buttons_state) { @@ -392,7 +422,8 @@ s->dy += dy1; s->dz += dz1; s->buttons_state = buttons_state; - hs->changed = 1; + + usb_hid_changed(hs); } static void usb_tablet_event(void *opaque, @@ -405,7 +436,8 @@ s->y = y; s->dz += dz; s->buttons_state = buttons_state; - hs->changed = 1; + + usb_hid_changed(hs); } static void usb_keyboard_event(void *opaque, int keycode) @@ -419,8 +451,6 @@ hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))]; s->modifiers &= ~(1 << 8); - hs->changed = 1; - switch (hid_code) { case 0x00: return; @@ -445,15 +475,23 @@ if (s->key[i] == hid_code) { s->key[i] = s->key[-- s->keys]; s->key[s->keys] = 0x00; - return; + usb_hid_changed(hs); + break; } + if (i < 0) + return; } else { for (i = s->keys - 1; i >= 0; i --) if (s->key[i] == hid_code) - return; - if (s->keys < sizeof(s->key)) - s->key[s->keys ++] = hid_code; + break; + if (i < 0) { + if (s->keys < sizeof(s->key)) + s->key[s->keys ++] = hid_code; + } else + return; } + + usb_hid_changed(hs); } static inline int int_clamp(int val, int vmin, int vmax) @@ -477,14 +515,17 @@ s->mouse_grabbed = 1; } - dx = int_clamp(s->dx, -128, 127); - dy = int_clamp(s->dy, -128, 127); - dz = int_clamp(s->dz, -128, 127); + dx = int_clamp(s->dx, -127, 127); + dy = int_clamp(s->dy, -127, 127); + dz = int_clamp(s->dz, -127, 127); s->dx -= dx; s->dy -= dy; s->dz -= dz; + /* Appears we have to invert the wheel direction */ + dz = 0 - dz; + b = 0; if (s->buttons_state & MOUSE_EVENT_LBUTTON) b |= 0x01; @@ -493,14 +534,15 @@ if (s->buttons_state & MOUSE_EVENT_MBUTTON) b |= 0x04; - buf[0] = b; - buf[1] = dx; - buf[2] = dy; - l = 3; - if (len >= 4) { - buf[3] = dz; - l = 4; - } + l = 0; + if (len > l) + buf[l ++] = b; + if (len > l) + buf[l ++] = dx; + if (len > l) + buf[l ++] = dy; + if (len > l) + buf[l ++] = dz; return l; } @@ -515,7 +557,7 @@ s->mouse_grabbed = 1; } - dz = int_clamp(s->dz, -128, 127); + dz = int_clamp(s->dz, -127, 127); s->dz -= dz; /* Appears we have to invert the wheel direction */ @@ -870,3 +912,11 @@ return (USBDevice *) s; } + +void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *)) +{ + USBHIDState *s = (USBHIDState *)dev; + + s->datain_opaque = opaque; + s->datain = datain; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/usb-msd.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/usb-msd.c --- qemu-0.9.1/hw/usb-msd.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/usb-msd.c 2008-08-21 23:24:32.000000000 +0100 @@ -517,13 +517,42 @@ { MSDState *s; BlockDriverState *bdrv; + BlockDriver *drv = NULL; + const char *p1; + char fmt[32]; + + p1 = strchr(filename, ':'); + if (p1++) { + const char *p2; + + if (strstart(filename, "format=", &p2)) { + int len = MIN(p1 - p2, sizeof(fmt)); + pstrcpy(fmt, len, p2); + + drv = bdrv_find_format(fmt); + if (!drv) { + printf("invalid format %s\n", fmt); + return NULL; + } + } else if (*filename != ':') { + printf("unrecognized USB mass-storage option %s\n", filename); + return NULL; + } + + filename = p1; + } + + if (!*filename) { + printf("block device specification needed\n"); + return NULL; + } s = qemu_mallocz(sizeof(MSDState)); if (!s) return NULL; bdrv = bdrv_new("usb"); - if (bdrv_open(bdrv, filename, 0) < 0) + if (bdrv_open2(bdrv, filename, 0, drv) < 0) goto fail; if (qemu_key_check(bdrv, filename)) goto fail; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/usb-musb.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/usb-musb.c --- qemu-0.9.1/hw/usb-musb.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/usb-musb.c 2008-04-22 04:15:10.000000000 +0100 @@ -0,0 +1,1449 @@ +/* + * "Inventra" High-speed Dual-Role Controller (MUSB-HDRC), Mentor Graphics, + * USB2.0 OTG compliant core used in various chips. + * + * Copyright (C) 2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Only host-mode and non-DMA accesses are currently supported. + */ +#include "qemu-common.h" +#include "qemu-timer.h" +#include "usb.h" +#include "irq.h" + +/* Common USB registers */ +#define MUSB_HDRC_FADDR 0x00 /* 8-bit */ +#define MUSB_HDRC_POWER 0x01 /* 8-bit */ + +#define MUSB_HDRC_INTRTX 0x02 /* 16-bit */ +#define MUSB_HDRC_INTRRX 0x04 +#define MUSB_HDRC_INTRTXE 0x06 +#define MUSB_HDRC_INTRRXE 0x08 +#define MUSB_HDRC_INTRUSB 0x0a /* 8 bit */ +#define MUSB_HDRC_INTRUSBE 0x0b /* 8 bit */ +#define MUSB_HDRC_FRAME 0x0c /* 16-bit */ +#define MUSB_HDRC_INDEX 0x0e /* 8 bit */ +#define MUSB_HDRC_TESTMODE 0x0f /* 8 bit */ + +/* Per-EP registers in indexed mode */ +#define MUSB_HDRC_EP_IDX 0x10 /* 8-bit */ + +/* EP FIFOs */ +#define MUSB_HDRC_FIFO 0x20 + +/* Additional Control Registers */ +#define MUSB_HDRC_DEVCTL 0x60 /* 8 bit */ + +/* These are indexed */ +#define MUSB_HDRC_TXFIFOSZ 0x62 /* 8 bit (see masks) */ +#define MUSB_HDRC_RXFIFOSZ 0x63 /* 8 bit (see masks) */ +#define MUSB_HDRC_TXFIFOADDR 0x64 /* 16 bit offset shifted right 3 */ +#define MUSB_HDRC_RXFIFOADDR 0x66 /* 16 bit offset shifted right 3 */ + +/* Some more registers */ +#define MUSB_HDRC_VCTRL 0x68 /* 8 bit */ +#define MUSB_HDRC_HWVERS 0x6c /* 8 bit */ + +/* Added in HDRC 1.9(?) & MHDRC 1.4 */ +/* ULPI pass-through */ +#define MUSB_HDRC_ULPI_VBUSCTL 0x70 +#define MUSB_HDRC_ULPI_REGDATA 0x74 +#define MUSB_HDRC_ULPI_REGADDR 0x75 +#define MUSB_HDRC_ULPI_REGCTL 0x76 + +/* Extended config & PHY control */ +#define MUSB_HDRC_ENDCOUNT 0x78 /* 8 bit */ +#define MUSB_HDRC_DMARAMCFG 0x79 /* 8 bit */ +#define MUSB_HDRC_PHYWAIT 0x7a /* 8 bit */ +#define MUSB_HDRC_PHYVPLEN 0x7b /* 8 bit */ +#define MUSB_HDRC_HS_EOF1 0x7c /* 8 bit, units of 546.1 us */ +#define MUSB_HDRC_FS_EOF1 0x7d /* 8 bit, units of 533.3 ns */ +#define MUSB_HDRC_LS_EOF1 0x7e /* 8 bit, units of 1.067 us */ + +/* Per-EP BUSCTL registers */ +#define MUSB_HDRC_BUSCTL 0x80 + +/* Per-EP registers in flat mode */ +#define MUSB_HDRC_EP 0x100 + +/* offsets to registers in flat model */ +#define MUSB_HDRC_TXMAXP 0x00 /* 16 bit apparently */ +#define MUSB_HDRC_TXCSR 0x02 /* 16 bit apparently */ +#define MUSB_HDRC_CSR0 MUSB_HDRC_TXCSR /* re-used for EP0 */ +#define MUSB_HDRC_RXMAXP 0x04 /* 16 bit apparently */ +#define MUSB_HDRC_RXCSR 0x06 /* 16 bit apparently */ +#define MUSB_HDRC_RXCOUNT 0x08 /* 16 bit apparently */ +#define MUSB_HDRC_COUNT0 MUSB_HDRC_RXCOUNT /* re-used for EP0 */ +#define MUSB_HDRC_TXTYPE 0x0a /* 8 bit apparently */ +#define MUSB_HDRC_TYPE0 MUSB_HDRC_TXTYPE /* re-used for EP0 */ +#define MUSB_HDRC_TXINTERVAL 0x0b /* 8 bit apparently */ +#define MUSB_HDRC_NAKLIMIT0 MUSB_HDRC_TXINTERVAL /* re-used for EP0 */ +#define MUSB_HDRC_RXTYPE 0x0c /* 8 bit apparently */ +#define MUSB_HDRC_RXINTERVAL 0x0d /* 8 bit apparently */ +#define MUSB_HDRC_FIFOSIZE 0x0f /* 8 bit apparently */ +#define MUSB_HDRC_CONFIGDATA MGC_O_HDRC_FIFOSIZE /* re-used for EP0 */ + +/* "Bus control" registers */ +#define MUSB_HDRC_TXFUNCADDR 0x00 +#define MUSB_HDRC_TXHUBADDR 0x02 +#define MUSB_HDRC_TXHUBPORT 0x03 + +#define MUSB_HDRC_RXFUNCADDR 0x04 +#define MUSB_HDRC_RXHUBADDR 0x06 +#define MUSB_HDRC_RXHUBPORT 0x07 + +/* + * MUSBHDRC Register bit masks + */ + +/* POWER */ +#define MGC_M_POWER_ISOUPDATE 0x80 +#define MGC_M_POWER_SOFTCONN 0x40 +#define MGC_M_POWER_HSENAB 0x20 +#define MGC_M_POWER_HSMODE 0x10 +#define MGC_M_POWER_RESET 0x08 +#define MGC_M_POWER_RESUME 0x04 +#define MGC_M_POWER_SUSPENDM 0x02 +#define MGC_M_POWER_ENSUSPEND 0x01 + +/* INTRUSB */ +#define MGC_M_INTR_SUSPEND 0x01 +#define MGC_M_INTR_RESUME 0x02 +#define MGC_M_INTR_RESET 0x04 +#define MGC_M_INTR_BABBLE 0x04 +#define MGC_M_INTR_SOF 0x08 +#define MGC_M_INTR_CONNECT 0x10 +#define MGC_M_INTR_DISCONNECT 0x20 +#define MGC_M_INTR_SESSREQ 0x40 +#define MGC_M_INTR_VBUSERROR 0x80 /* FOR SESSION END */ +#define MGC_M_INTR_EP0 0x01 /* FOR EP0 INTERRUPT */ + +/* DEVCTL */ +#define MGC_M_DEVCTL_BDEVICE 0x80 +#define MGC_M_DEVCTL_FSDEV 0x40 +#define MGC_M_DEVCTL_LSDEV 0x20 +#define MGC_M_DEVCTL_VBUS 0x18 +#define MGC_S_DEVCTL_VBUS 3 +#define MGC_M_DEVCTL_HM 0x04 +#define MGC_M_DEVCTL_HR 0x02 +#define MGC_M_DEVCTL_SESSION 0x01 + +/* TESTMODE */ +#define MGC_M_TEST_FORCE_HOST 0x80 +#define MGC_M_TEST_FIFO_ACCESS 0x40 +#define MGC_M_TEST_FORCE_FS 0x20 +#define MGC_M_TEST_FORCE_HS 0x10 +#define MGC_M_TEST_PACKET 0x08 +#define MGC_M_TEST_K 0x04 +#define MGC_M_TEST_J 0x02 +#define MGC_M_TEST_SE0_NAK 0x01 + +/* CSR0 */ +#define MGC_M_CSR0_FLUSHFIFO 0x0100 +#define MGC_M_CSR0_TXPKTRDY 0x0002 +#define MGC_M_CSR0_RXPKTRDY 0x0001 + +/* CSR0 in Peripheral mode */ +#define MGC_M_CSR0_P_SVDSETUPEND 0x0080 +#define MGC_M_CSR0_P_SVDRXPKTRDY 0x0040 +#define MGC_M_CSR0_P_SENDSTALL 0x0020 +#define MGC_M_CSR0_P_SETUPEND 0x0010 +#define MGC_M_CSR0_P_DATAEND 0x0008 +#define MGC_M_CSR0_P_SENTSTALL 0x0004 + +/* CSR0 in Host mode */ +#define MGC_M_CSR0_H_NO_PING 0x0800 +#define MGC_M_CSR0_H_WR_DATATOGGLE 0x0400 /* set to allow setting: */ +#define MGC_M_CSR0_H_DATATOGGLE 0x0200 /* data toggle control */ +#define MGC_M_CSR0_H_NAKTIMEOUT 0x0080 +#define MGC_M_CSR0_H_STATUSPKT 0x0040 +#define MGC_M_CSR0_H_REQPKT 0x0020 +#define MGC_M_CSR0_H_ERROR 0x0010 +#define MGC_M_CSR0_H_SETUPPKT 0x0008 +#define MGC_M_CSR0_H_RXSTALL 0x0004 + +/* CONFIGDATA */ +#define MGC_M_CONFIGDATA_MPRXE 0x80 /* auto bulk pkt combining */ +#define MGC_M_CONFIGDATA_MPTXE 0x40 /* auto bulk pkt splitting */ +#define MGC_M_CONFIGDATA_BIGENDIAN 0x20 +#define MGC_M_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */ +#define MGC_M_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */ +#define MGC_M_CONFIGDATA_DYNFIFO 0x04 /* dynamic FIFO sizing */ +#define MGC_M_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */ +#define MGC_M_CONFIGDATA_UTMIDW 0x01 /* Width, 0 => 8b, 1 => 16b */ + +/* TXCSR in Peripheral and Host mode */ +#define MGC_M_TXCSR_AUTOSET 0x8000 +#define MGC_M_TXCSR_ISO 0x4000 +#define MGC_M_TXCSR_MODE 0x2000 +#define MGC_M_TXCSR_DMAENAB 0x1000 +#define MGC_M_TXCSR_FRCDATATOG 0x0800 +#define MGC_M_TXCSR_DMAMODE 0x0400 +#define MGC_M_TXCSR_CLRDATATOG 0x0040 +#define MGC_M_TXCSR_FLUSHFIFO 0x0008 +#define MGC_M_TXCSR_FIFONOTEMPTY 0x0002 +#define MGC_M_TXCSR_TXPKTRDY 0x0001 + +/* TXCSR in Peripheral mode */ +#define MGC_M_TXCSR_P_INCOMPTX 0x0080 +#define MGC_M_TXCSR_P_SENTSTALL 0x0020 +#define MGC_M_TXCSR_P_SENDSTALL 0x0010 +#define MGC_M_TXCSR_P_UNDERRUN 0x0004 + +/* TXCSR in Host mode */ +#define MGC_M_TXCSR_H_WR_DATATOGGLE 0x0200 +#define MGC_M_TXCSR_H_DATATOGGLE 0x0100 +#define MGC_M_TXCSR_H_NAKTIMEOUT 0x0080 +#define MGC_M_TXCSR_H_RXSTALL 0x0020 +#define MGC_M_TXCSR_H_ERROR 0x0004 + +/* RXCSR in Peripheral and Host mode */ +#define MGC_M_RXCSR_AUTOCLEAR 0x8000 +#define MGC_M_RXCSR_DMAENAB 0x2000 +#define MGC_M_RXCSR_DISNYET 0x1000 +#define MGC_M_RXCSR_DMAMODE 0x0800 +#define MGC_M_RXCSR_INCOMPRX 0x0100 +#define MGC_M_RXCSR_CLRDATATOG 0x0080 +#define MGC_M_RXCSR_FLUSHFIFO 0x0010 +#define MGC_M_RXCSR_DATAERROR 0x0008 +#define MGC_M_RXCSR_FIFOFULL 0x0002 +#define MGC_M_RXCSR_RXPKTRDY 0x0001 + +/* RXCSR in Peripheral mode */ +#define MGC_M_RXCSR_P_ISO 0x4000 +#define MGC_M_RXCSR_P_SENTSTALL 0x0040 +#define MGC_M_RXCSR_P_SENDSTALL 0x0020 +#define MGC_M_RXCSR_P_OVERRUN 0x0004 + +/* RXCSR in Host mode */ +#define MGC_M_RXCSR_H_AUTOREQ 0x4000 +#define MGC_M_RXCSR_H_WR_DATATOGGLE 0x0400 +#define MGC_M_RXCSR_H_DATATOGGLE 0x0200 +#define MGC_M_RXCSR_H_RXSTALL 0x0040 +#define MGC_M_RXCSR_H_REQPKT 0x0020 +#define MGC_M_RXCSR_H_ERROR 0x0004 + +/* HUBADDR */ +#define MGC_M_HUBADDR_MULTI_TT 0x80 + +/* ULPI: Added in HDRC 1.9(?) & MHDRC 1.4 */ +#define MGC_M_ULPI_VBCTL_USEEXTVBUSIND 0x02 +#define MGC_M_ULPI_VBCTL_USEEXTVBUS 0x01 +#define MGC_M_ULPI_REGCTL_INT_ENABLE 0x08 +#define MGC_M_ULPI_REGCTL_READNOTWRITE 0x04 +#define MGC_M_ULPI_REGCTL_COMPLETE 0x02 +#define MGC_M_ULPI_REGCTL_REG 0x01 + +static void musb_attach(USBPort *port, USBDevice *dev); + +struct musb_s { + qemu_irq *irqs; + USBPort port; + + int idx; + uint8_t devctl; + uint8_t power; + uint8_t faddr; + + uint8_t intr; + uint8_t mask; + uint16_t tx_intr; + uint16_t tx_mask; + uint16_t rx_intr; + uint16_t rx_mask; + + int setup_len; + int session; + + uint32_t buf[0x2000]; + + struct musb_ep_s { + uint16_t faddr[2]; + uint8_t haddr[2]; + uint8_t hport[2]; + uint16_t csr[2]; + uint16_t maxp[2]; + uint16_t rxcount; + uint8_t type[2]; + uint8_t interval[2]; + uint8_t config; + uint8_t fifosize; + int timeout[2]; /* Always in microframes */ + + uint32_t *buf[2]; + int fifolen[2]; + int fifostart[2]; + int fifoaddr[2]; + USBPacket packey[2]; + int status[2]; + int ext_size[2]; + + /* For callbacks' use */ + int epnum; + int interrupt[2]; + struct musb_s *musb; + USBCallback *delayed_cb[2]; + QEMUTimer *intv_timer[2]; + /* Duplicating the world since 2008!... probably we should have 32 + * logical, single endpoints instead. */ + } ep[16]; +} *musb_init(qemu_irq *irqs) +{ + struct musb_s *s = qemu_mallocz(sizeof(*s)); + int i; + + s->irqs = irqs; + + s->faddr = 0x00; + s->power = MGC_M_POWER_HSENAB; + s->tx_intr = 0x0000; + s->rx_intr = 0x0000; + s->tx_mask = 0xffff; + s->rx_mask = 0xffff; + s->intr = 0x00; + s->mask = 0x06; + s->idx = 0; + + /* TODO: _DW */ + s->ep[0].config = MGC_M_CONFIGDATA_SOFTCONE | MGC_M_CONFIGDATA_DYNFIFO; + for (i = 0; i < 16; i ++) { + s->ep[i].fifosize = 64; + s->ep[i].maxp[0] = 0x40; + s->ep[i].maxp[1] = 0x40; + s->ep[i].musb = s; + s->ep[i].epnum = i; + } + + qemu_register_usb_port(&s->port, s, 0, musb_attach); + + return s; +} + +static void musb_vbus_set(struct musb_s *s, int level) +{ + if (level) + s->devctl |= 3 << MGC_S_DEVCTL_VBUS; + else + s->devctl &= ~MGC_M_DEVCTL_VBUS; + + qemu_set_irq(s->irqs[musb_set_vbus], level); +} + +static void musb_intr_set(struct musb_s *s, int line, int level) +{ + if (!level) { + s->intr &= ~(1 << line); + qemu_irq_lower(s->irqs[line]); + } else if (s->mask & (1 << line)) { + s->intr |= 1 << line; + qemu_irq_raise(s->irqs[line]); + } +} + +static void musb_tx_intr_set(struct musb_s *s, int line, int level) +{ + if (!level) { + s->tx_intr &= ~(1 << line); + if (!s->tx_intr) + qemu_irq_lower(s->irqs[musb_irq_tx]); + } else if (s->tx_mask & (1 << line)) { + s->tx_intr |= 1 << line; + qemu_irq_raise(s->irqs[musb_irq_tx]); + } +} + +static void musb_rx_intr_set(struct musb_s *s, int line, int level) +{ + if (line) { + if (!level) { + s->rx_intr &= ~(1 << line); + if (!s->rx_intr) + qemu_irq_lower(s->irqs[musb_irq_rx]); + } else if (s->rx_mask & (1 << line)) { + s->rx_intr |= 1 << line; + qemu_irq_raise(s->irqs[musb_irq_rx]); + } + } else + musb_tx_intr_set(s, line, level); +} + +uint32_t musb_core_intr_get(struct musb_s *s) +{ + return (s->rx_intr << 15) | s->tx_intr; +} + +void musb_core_intr_clear(struct musb_s *s, uint32_t mask) +{ + if (s->rx_intr) { + s->rx_intr &= mask >> 15; + if (!s->rx_intr) + qemu_irq_lower(s->irqs[musb_irq_rx]); + } + + if (s->tx_intr) { + s->tx_intr &= mask & 0xffff; + if (!s->tx_intr) + qemu_irq_lower(s->irqs[musb_irq_tx]); + } +} + +void musb_set_size(struct musb_s *s, int epnum, int size, int is_tx) +{ + s->ep[epnum].ext_size[!is_tx] = size; + s->ep[epnum].fifostart[0] = 0; + s->ep[epnum].fifostart[1] = 0; + s->ep[epnum].fifolen[0] = 0; + s->ep[epnum].fifolen[1] = 0; +} + +static void musb_session_update(struct musb_s *s, int prev_dev, int prev_sess) +{ + int detect_prev = prev_dev && prev_sess; + int detect = !!s->port.dev && s->session; + + if (detect && !detect_prev) { + /* Let's skip the ID pin sense and VBUS sense formalities and + * and signal a successful SRP directly. This should work at least + * for the Linux driver stack. */ + musb_intr_set(s, musb_irq_connect, 1); + + if (s->port.dev->speed == USB_SPEED_LOW) { + s->devctl &= ~MGC_M_DEVCTL_FSDEV; + s->devctl |= MGC_M_DEVCTL_LSDEV; + } else { + s->devctl |= MGC_M_DEVCTL_FSDEV; + s->devctl &= ~MGC_M_DEVCTL_LSDEV; + } + + /* A-mode? */ + s->devctl &= ~MGC_M_DEVCTL_BDEVICE; + + /* Host-mode bit? */ + s->devctl |= MGC_M_DEVCTL_HM; +#if 1 + musb_vbus_set(s, 1); +#endif + } else if (!detect && detect_prev) { +#if 1 + musb_vbus_set(s, 0); +#endif + } +} + +/* Attach or detach a device on our only port. */ +static void musb_attach(USBPort *port, USBDevice *dev) +{ + struct musb_s *s = (struct musb_s *) port->opaque; + USBDevice *curr; + + port = &s->port; + curr = port->dev; + + if (dev) { + if (curr) { + usb_attach(port, NULL); + /* TODO: signal some interrupts */ + } + + musb_intr_set(s, musb_irq_vbus_request, 1); + + /* Send the attach message to device */ + usb_send_msg(dev, USB_MSG_ATTACH); + } else if (curr) { + /* Send the detach message */ + usb_send_msg(curr, USB_MSG_DETACH); + + musb_intr_set(s, musb_irq_disconnect, 1); + } + + port->dev = dev; + + musb_session_update(s, !!curr, s->session); +} + +static inline void musb_cb_tick0(void *opaque) +{ + struct musb_ep_s *ep = (struct musb_ep_s *) opaque; + + ep->delayed_cb[0](&ep->packey[0], opaque); +} + +static inline void musb_cb_tick1(void *opaque) +{ + struct musb_ep_s *ep = (struct musb_ep_s *) opaque; + + ep->delayed_cb[1](&ep->packey[1], opaque); +} + +#define musb_cb_tick (dir ? musb_cb_tick1 : musb_cb_tick0) + +static inline void musb_schedule_cb(USBPacket *packey, void *opaque, int dir) +{ + struct musb_ep_s *ep = (struct musb_ep_s *) opaque; + int timeout = 0; + + if (ep->status[dir] == USB_RET_NAK) + timeout = ep->timeout[dir]; + else if (ep->interrupt[dir]) + timeout = 8; + else + return musb_cb_tick(opaque); + + if (!ep->intv_timer[dir]) + ep->intv_timer[dir] = qemu_new_timer(vm_clock, musb_cb_tick, opaque); + + qemu_mod_timer(ep->intv_timer[dir], qemu_get_clock(vm_clock) + + muldiv64(timeout, ticks_per_sec, 8000)); +} + +static void musb_schedule0_cb(USBPacket *packey, void *opaque) +{ + return musb_schedule_cb(packey, opaque, 0); +} + +static void musb_schedule1_cb(USBPacket *packey, void *opaque) +{ + return musb_schedule_cb(packey, opaque, 1); +} + +static int musb_timeout(int ttype, int speed, int val) +{ +#if 1 + return val << 3; +#endif + + switch (ttype) { + case USB_ENDPOINT_XFER_CONTROL: + if (val < 2) + return 0; + else if (speed == USB_SPEED_HIGH) + return 1 << (val - 1); + else + return 8 << (val - 1); + + case USB_ENDPOINT_XFER_INT: + if (speed == USB_SPEED_HIGH) + if (val < 2) + return 0; + else + return 1 << (val - 1); + else + return val << 3; + + case USB_ENDPOINT_XFER_BULK: + case USB_ENDPOINT_XFER_ISOC: + if (val < 2) + return 0; + else if (speed == USB_SPEED_HIGH) + return 1 << (val - 1); + else + return 8 << (val - 1); + /* TODO: what with low-speed Bulk and Isochronous? */ + } + + cpu_abort(cpu_single_env, "bad interval\n"); +} + +static inline void musb_packet(struct musb_s *s, struct musb_ep_s *ep, + int epnum, int pid, int len, USBCallback cb, int dir) +{ + int ret; + int idx = epnum && dir; + int ttype; + + /* ep->type[0,1] contains: + * in bits 7:6 the speed (0 - invalid, 1 - high, 2 - full, 3 - slow) + * in bits 5:4 the transfer type (BULK / INT) + * in bits 3:0 the EP num + */ + ttype = epnum ? (ep->type[idx] >> 4) & 3 : 0; + + ep->timeout[dir] = musb_timeout(ttype, + ep->type[idx] >> 6, ep->interval[idx]); + ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT; + ep->delayed_cb[dir] = cb; + cb = dir ? musb_schedule1_cb : musb_schedule0_cb; + + ep->packey[dir].pid = pid; + /* A wild guess on the FADDR semantics... */ + ep->packey[dir].devaddr = ep->faddr[idx]; + ep->packey[dir].devep = ep->type[idx] & 0xf; + ep->packey[dir].data = (void *) ep->buf[idx]; + ep->packey[dir].len = len; + ep->packey[dir].complete_cb = cb; + ep->packey[dir].complete_opaque = ep; + + if (s->port.dev) + ret = s->port.dev->handle_packet(s->port.dev, &ep->packey[dir]); + else + ret = USB_RET_NODEV; + + if (ret == USB_RET_ASYNC) { + ep->status[dir] = len; + return; + } + + ep->status[dir] = ret; + usb_packet_complete(&ep->packey[dir]); +} + +static void musb_tx_packet_complete(USBPacket *packey, void *opaque) +{ + /* Unfortunately we can't use packey->devep because that's the remote + * endpoint number and may be different than our local. */ + struct musb_ep_s *ep = (struct musb_ep_s *) opaque; + int epnum = ep->epnum; + struct musb_s *s = ep->musb; + + ep->fifostart[0] = 0; + ep->fifolen[0] = 0; +#ifdef CLEAR_NAK + if (ep->status[0] != USB_RET_NAK) { +#endif + if (epnum) + ep->csr[0] &= ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY); + else + ep->csr[0] &= ~MGC_M_CSR0_TXPKTRDY; +#ifdef CLEAR_NAK + } +#endif + + /* Clear all of the error bits first */ + if (epnum) + ep->csr[0] &= ~(MGC_M_TXCSR_H_ERROR | MGC_M_TXCSR_H_RXSTALL | + MGC_M_TXCSR_H_NAKTIMEOUT); + else + ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL | + MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING); + + if (ep->status[0] == USB_RET_STALL) { + /* Command not supported by target! */ + ep->status[0] = 0; + + if (epnum) + ep->csr[0] |= MGC_M_TXCSR_H_RXSTALL; + else + ep->csr[0] |= MGC_M_CSR0_H_RXSTALL; + } + + if (ep->status[0] == USB_RET_NAK) { + ep->status[0] = 0; + + /* NAK timeouts are only generated in Bulk transfers and + * Data-errors in Isochronous. */ + if (ep->interrupt[0]) { + return; + } + + if (epnum) + ep->csr[0] |= MGC_M_TXCSR_H_NAKTIMEOUT; + else + ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT; + } + + if (ep->status[0] < 0) { + if (ep->status[0] == USB_RET_BABBLE) + musb_intr_set(s, musb_irq_rst_babble, 1); + + /* Pretend we've tried three times already and failed (in + * case of USB_TOKEN_SETUP). */ + if (epnum) + ep->csr[0] |= MGC_M_TXCSR_H_ERROR; + else + ep->csr[0] |= MGC_M_CSR0_H_ERROR; + + musb_tx_intr_set(s, epnum, 1); + return; + } + /* TODO: check len for over/underruns of an OUT packet? */ + +#ifdef SETUPLEN_HACK + if (!epnum && ep->packey[0].pid == USB_TOKEN_SETUP) + s->setup_len = ep->packey[0].data[6]; +#endif + + /* In DMA mode: if no error, assert DMA request for this EP, + * and skip the interrupt. */ + musb_tx_intr_set(s, epnum, 1); +} + +static void musb_rx_packet_complete(USBPacket *packey, void *opaque) +{ + /* Unfortunately we can't use packey->devep because that's the remote + * endpoint number and may be different than our local. */ + struct musb_ep_s *ep = (struct musb_ep_s *) opaque; + int epnum = ep->epnum; + struct musb_s *s = ep->musb; + + ep->fifostart[1] = 0; + ep->fifolen[1] = 0; + +#ifdef CLEAR_NAK + if (ep->status[1] != USB_RET_NAK) { +#endif + ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT; + if (!epnum) + ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT; +#ifdef CLEAR_NAK + } +#endif + + /* Clear all of the imaginable error bits first */ + ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL | + MGC_M_RXCSR_DATAERROR); + if (!epnum) + ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL | + MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING); + + if (ep->status[1] == USB_RET_STALL) { + ep->status[1] = 0; + packey->len = 0; + + ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL; + if (!epnum) + ep->csr[0] |= MGC_M_CSR0_H_RXSTALL; + } + + if (ep->status[1] == USB_RET_NAK) { + ep->status[1] = 0; + + /* NAK timeouts are only generated in Bulk transfers and + * Data-errors in Isochronous. */ + if (ep->interrupt[1]) + return musb_packet(s, ep, epnum, USB_TOKEN_IN, + packey->len, musb_rx_packet_complete, 1); + + ep->csr[1] |= MGC_M_RXCSR_DATAERROR; + if (!epnum) + ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT; + } + + if (ep->status[1] < 0) { + if (ep->status[1] == USB_RET_BABBLE) { + musb_intr_set(s, musb_irq_rst_babble, 1); + return; + } + + /* Pretend we've tried three times already and failed (in + * case of a control transfer). */ + ep->csr[1] |= MGC_M_RXCSR_H_ERROR; + if (!epnum) + ep->csr[0] |= MGC_M_CSR0_H_ERROR; + + musb_rx_intr_set(s, epnum, 1); + return; + } + /* TODO: check len for over/underruns of an OUT packet? */ + /* TODO: perhaps make use of e->ext_size[1] here. */ + + packey->len = ep->status[1]; + + if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) { + ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY; + if (!epnum) + ep->csr[0] |= MGC_M_CSR0_RXPKTRDY; + + ep->rxcount = packey->len; /* XXX: MIN(packey->len, ep->maxp[1]); */ + /* In DMA mode: assert DMA request for this EP */ + } + + /* Only if DMA has not been asserted */ + musb_rx_intr_set(s, epnum, 1); +} + +static void musb_tx_rdy(struct musb_s *s, int epnum) +{ + struct musb_ep_s *ep = s->ep + epnum; + int pid; + int total, valid = 0; + + ep->fifostart[0] += ep->fifolen[0]; + ep->fifolen[0] = 0; + + /* XXX: how's the total size of the packet retrieved exactly in + * the generic case? */ + total = ep->maxp[0] & 0x3ff; + + if (ep->ext_size[0]) { + total = ep->ext_size[0]; + ep->ext_size[0] = 0; + valid = 1; + } + + /* If the packet is not fully ready yet, wait for a next segment. */ + if (epnum && (ep->fifostart[0] << 2) < total) + return; + + if (!valid) + total = ep->fifostart[0] << 2; + + pid = USB_TOKEN_OUT; + if (!epnum && (ep->csr[0] & MGC_M_CSR0_H_SETUPPKT)) { + pid = USB_TOKEN_SETUP; + if (total != 8) + printf("%s: illegal SETUPPKT length of %i bytes\n", + __FUNCTION__, total); + /* Controller should retry SETUP packets three times on errors + * but it doesn't make sense for us to do that. */ + } + + return musb_packet(s, ep, epnum, pid, + total, musb_tx_packet_complete, 0); +} + +static void musb_rx_req(struct musb_s *s, int epnum) +{ + struct musb_ep_s *ep = s->ep + epnum; + int total; + + /* If we already have a packet, which didn't fit into the + * 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */ + if (ep->packey[1].pid == USB_TOKEN_IN && ep->status[1] >= 0 && + (ep->fifostart[1] << 2) + ep->rxcount < + ep->packey[1].len) { + ep->fifostart[1] += ep->rxcount >> 2; + ep->fifolen[1] = 0; + + ep->rxcount = MIN(ep->packey[0].len - (ep->fifostart[1] << 2), + ep->maxp[1]); + + ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT; + if (!epnum) + ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT; + + /* Clear all of the error bits first */ + ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL | + MGC_M_RXCSR_DATAERROR); + if (!epnum) + ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL | + MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING); + + ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY; + if (!epnum) + ep->csr[0] |= MGC_M_CSR0_RXPKTRDY; + musb_rx_intr_set(s, epnum, 1); + return; + } + + /* The driver sets maxp[1] to 64 or less because it knows the hardware + * FIFO is this deep. Bigger packets get split in + * usb_generic_handle_packet but we can also do the splitting locally + * for performance. It turns out we can also have a bigger FIFO and + * ignore the limit set in ep->maxp[1]. The Linux MUSB driver deals + * OK with single packets of even 32KB and we avoid splitting, however + * usb_msd.c sometimes sends a packet bigger than what Linux expects + * (e.g. 8192 bytes instead of 4096) and we get an OVERRUN. Splitting + * hides this overrun from Linux. Up to 4096 everything is fine + * though. Currently this is disabled. + * + * XXX: mind ep->fifosize. */ + total = MIN(ep->maxp[1] & 0x3ff, sizeof(s->buf)); + +#ifdef SETUPLEN_HACK + /* Why should *we* do that instead of Linux? */ + if (!epnum) { + if (ep->packey[0].devaddr == 2) + total = MIN(s->setup_len, 8); + else + total = MIN(s->setup_len, 64); + s->setup_len -= total; + } +#endif + + return musb_packet(s, ep, epnum, USB_TOKEN_IN, + total, musb_rx_packet_complete, 1); +} + +static void musb_ep_frame_cancel(struct musb_ep_s *ep, int dir) +{ + if (ep->intv_timer[dir]) + qemu_del_timer(ep->intv_timer[dir]); +} + +/* Bus control */ +static uint8_t musb_busctl_readb(void *opaque, int ep, int addr) +{ + struct musb_s *s = (struct musb_s *) opaque; + + switch (addr) { + /* For USB2.0 HS hubs only */ + case MUSB_HDRC_TXHUBADDR: + return s->ep[ep].haddr[0]; + case MUSB_HDRC_TXHUBPORT: + return s->ep[ep].hport[0]; + case MUSB_HDRC_RXHUBADDR: + return s->ep[ep].haddr[1]; + case MUSB_HDRC_RXHUBPORT: + return s->ep[ep].hport[1]; + + default: + printf("%s: unknown register at %02x\n", __FUNCTION__, addr); + return 0x00; + }; +} + +static void musb_busctl_writeb(void *opaque, int ep, int addr, uint8_t value) +{ + struct musb_s *s = (struct musb_s *) opaque; + + switch (addr) { + case MUSB_HDRC_TXHUBADDR: + s->ep[ep].haddr[0] = value; + break; + case MUSB_HDRC_TXHUBPORT: + s->ep[ep].hport[0] = value; + break; + case MUSB_HDRC_RXHUBADDR: + s->ep[ep].haddr[1] = value; + break; + case MUSB_HDRC_RXHUBPORT: + s->ep[ep].hport[1] = value; + break; + + default: + printf("%s: unknown register at %02x\n", __FUNCTION__, addr); + }; +} + +static uint16_t musb_busctl_readh(void *opaque, int ep, int addr) +{ + struct musb_s *s = (struct musb_s *) opaque; + + switch (addr) { + case MUSB_HDRC_TXFUNCADDR: + return s->ep[ep].faddr[0]; + case MUSB_HDRC_RXFUNCADDR: + return s->ep[ep].faddr[1]; + + default: + return musb_busctl_readb(s, ep, addr) | + (musb_busctl_readb(s, ep, addr | 1) << 8); + }; +} + +static void musb_busctl_writeh(void *opaque, int ep, int addr, uint16_t value) +{ + struct musb_s *s = (struct musb_s *) opaque; + + switch (addr) { + case MUSB_HDRC_TXFUNCADDR: + s->ep[ep].faddr[0] = value; + break; + case MUSB_HDRC_RXFUNCADDR: + s->ep[ep].faddr[1] = value; + break; + + default: + musb_busctl_writeb(s, ep, addr, value & 0xff); + musb_busctl_writeb(s, ep, addr | 1, value >> 8); + }; +} + +/* Endpoint control */ +static uint8_t musb_ep_readb(void *opaque, int ep, int addr) +{ + struct musb_s *s = (struct musb_s *) opaque; + + switch (addr) { + case MUSB_HDRC_TXTYPE: + return s->ep[ep].type[0]; + case MUSB_HDRC_TXINTERVAL: + return s->ep[ep].interval[0]; + case MUSB_HDRC_RXTYPE: + return s->ep[ep].type[1]; + case MUSB_HDRC_RXINTERVAL: + return s->ep[ep].interval[1]; + case (MUSB_HDRC_FIFOSIZE & ~1): + return 0x00; + case MUSB_HDRC_FIFOSIZE: + return ep ? s->ep[ep].fifosize : s->ep[ep].config; + + default: + printf("%s: unknown register at %02x\n", __FUNCTION__, addr); + return 0x00; + }; +} + +static void musb_ep_writeb(void *opaque, int ep, int addr, uint8_t value) +{ + struct musb_s *s = (struct musb_s *) opaque; + + switch (addr) { + case MUSB_HDRC_TXTYPE: + s->ep[ep].type[0] = value; + break; + case MUSB_HDRC_TXINTERVAL: + s->ep[ep].interval[0] = value; + musb_ep_frame_cancel(&s->ep[ep], 0); + break; + case MUSB_HDRC_RXTYPE: + s->ep[ep].type[1] = value; + break; + case MUSB_HDRC_RXINTERVAL: + s->ep[ep].interval[1] = value; + musb_ep_frame_cancel(&s->ep[ep], 1); + break; + case (MUSB_HDRC_FIFOSIZE & ~1): + break; + case MUSB_HDRC_FIFOSIZE: + printf("%s: somebody messes with fifosize (now %i bytes)\n", + __FUNCTION__, value); + s->ep[ep].fifosize = value; + break; + + default: + printf("%s: unknown register at %02x\n", __FUNCTION__, addr); + }; +} + +static uint16_t musb_ep_readh(void *opaque, int ep, int addr) +{ + struct musb_s *s = (struct musb_s *) opaque; + uint16_t ret; + + switch (addr) { + case MUSB_HDRC_TXMAXP: + return s->ep[ep].maxp[0]; + case MUSB_HDRC_TXCSR: + return s->ep[ep].csr[0]; + case MUSB_HDRC_RXMAXP: + return s->ep[ep].maxp[1]; + case MUSB_HDRC_RXCSR: + ret = s->ep[ep].csr[1]; + + /* TODO: This and other bits probably depend on + * ep->csr[1] & MGC_M_RXCSR_AUTOCLEAR. */ + if (s->ep[ep].csr[1] & MGC_M_RXCSR_AUTOCLEAR) + s->ep[ep].csr[1] &= ~MGC_M_RXCSR_RXPKTRDY; + + return ret; + case MUSB_HDRC_RXCOUNT: + return s->ep[ep].rxcount; + + default: + return musb_ep_readb(s, ep, addr) | + (musb_ep_readb(s, ep, addr | 1) << 8); + }; +} + +static void musb_ep_writeh(void *opaque, int ep, int addr, uint16_t value) +{ + struct musb_s *s = (struct musb_s *) opaque; + + switch (addr) { + case MUSB_HDRC_TXMAXP: + s->ep[ep].maxp[0] = value; + break; + case MUSB_HDRC_TXCSR: + if (ep) { + s->ep[ep].csr[0] &= value & 0xa6; + s->ep[ep].csr[0] |= value & 0xff59; + } else { + s->ep[ep].csr[0] &= value & 0x85; + s->ep[ep].csr[0] |= value & 0xf7a; + } + + musb_ep_frame_cancel(&s->ep[ep], 0); + + if ((ep && (value & MGC_M_TXCSR_FLUSHFIFO)) || + (!ep && (value & MGC_M_CSR0_FLUSHFIFO))) { + s->ep[ep].fifolen[0] = 0; + s->ep[ep].fifostart[0] = 0; + if (ep) + s->ep[ep].csr[0] &= + ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY); + else + s->ep[ep].csr[0] &= + ~(MGC_M_CSR0_TXPKTRDY | MGC_M_CSR0_RXPKTRDY); + } + if ( + (ep && +#ifdef CLEAR_NAK + (value & MGC_M_TXCSR_TXPKTRDY) && + !(value & MGC_M_TXCSR_H_NAKTIMEOUT)) || +#else + (value & MGC_M_TXCSR_TXPKTRDY)) || +#endif + (!ep && +#ifdef CLEAR_NAK + (value & MGC_M_CSR0_TXPKTRDY) && + !(value & MGC_M_CSR0_H_NAKTIMEOUT))) +#else + (value & MGC_M_CSR0_TXPKTRDY))) +#endif + musb_tx_rdy(s, ep); + if (!ep && + (value & MGC_M_CSR0_H_REQPKT) && +#ifdef CLEAR_NAK + !(value & (MGC_M_CSR0_H_NAKTIMEOUT | + MGC_M_CSR0_RXPKTRDY))) +#else + !(value & MGC_M_CSR0_RXPKTRDY)) +#endif + musb_rx_req(s, ep); + break; + + case MUSB_HDRC_RXMAXP: + s->ep[ep].maxp[1] = value; + break; + case MUSB_HDRC_RXCSR: + /* (DMA mode only) */ + if ( + (value & MGC_M_RXCSR_H_AUTOREQ) && + !(value & MGC_M_RXCSR_RXPKTRDY) && + (s->ep[ep].csr[1] & MGC_M_RXCSR_RXPKTRDY)) + value |= MGC_M_RXCSR_H_REQPKT; + + s->ep[ep].csr[1] &= 0x102 | (value & 0x4d); + s->ep[ep].csr[1] |= value & 0xfeb0; + + musb_ep_frame_cancel(&s->ep[ep], 1); + + if (value & MGC_M_RXCSR_FLUSHFIFO) { + s->ep[ep].fifolen[1] = 0; + s->ep[ep].fifostart[1] = 0; + s->ep[ep].csr[1] &= ~(MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY); + /* If double buffering and we have two packets ready, flush + * only the first one and set up the fifo at the second packet. */ + } +#ifdef CLEAR_NAK + if ((value & MGC_M_RXCSR_H_REQPKT) && !(value & MGC_M_RXCSR_DATAERROR)) +#else + if (value & MGC_M_RXCSR_H_REQPKT) +#endif + musb_rx_req(s, ep); + break; + case MUSB_HDRC_RXCOUNT: + s->ep[ep].rxcount = value; + break; + + default: + musb_ep_writeb(s, ep, addr, value & 0xff); + musb_ep_writeb(s, ep, addr | 1, value >> 8); + }; +} + +/* Generic control */ +static uint32_t musb_readb(void *opaque, target_phys_addr_t addr) +{ + struct musb_s *s = (struct musb_s *) opaque; + int ep, i; + uint8_t ret; + + switch (addr) { + case MUSB_HDRC_FADDR: + return s->faddr; + case MUSB_HDRC_POWER: + return s->power; + case MUSB_HDRC_INTRUSB: + ret = s->intr; + for (i = 0; i < sizeof(ret) * 8; i ++) + if (ret & (1 << i)) + musb_intr_set(s, i, 0); + return ret; + case MUSB_HDRC_INTRUSBE: + return s->mask; + case MUSB_HDRC_INDEX: + return s->idx; + case MUSB_HDRC_TESTMODE: + return 0x00; + + case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf): + return musb_ep_readb(s, s->idx, addr & 0xf); + + case MUSB_HDRC_DEVCTL: + return s->devctl; + + case MUSB_HDRC_TXFIFOSZ: + case MUSB_HDRC_RXFIFOSZ: + case MUSB_HDRC_VCTRL: + /* TODO */ + return 0x00; + + case MUSB_HDRC_HWVERS: + return (1 << 10) | 400; + + case (MUSB_HDRC_VCTRL | 1): + case (MUSB_HDRC_HWVERS | 1): + case (MUSB_HDRC_DEVCTL | 1): + return 0x00; + + case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f): + ep = (addr >> 3) & 0xf; + return musb_busctl_readb(s, ep, addr & 0x7); + + case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff): + ep = (addr >> 4) & 0xf; + return musb_ep_readb(s, ep, addr & 0xf); + + default: + printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr); + return 0x00; + }; +} + +static void musb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + struct musb_s *s = (struct musb_s *) opaque; + int ep; + + switch (addr) { + case MUSB_HDRC_FADDR: + s->faddr = value & 0x7f; + break; + case MUSB_HDRC_POWER: + s->power = (value & 0xef) | (s->power & 0x10); + /* MGC_M_POWER_RESET is also read-only in Peripheral Mode */ + if ((value & MGC_M_POWER_RESET) && s->port.dev) { + usb_send_msg(s->port.dev, USB_MSG_RESET); + /* Negotiate high-speed operation if MGC_M_POWER_HSENAB is set. */ + if ((value & MGC_M_POWER_HSENAB) && + s->port.dev->speed == USB_SPEED_HIGH) + s->power |= MGC_M_POWER_HSMODE; /* Success */ + /* Restart frame counting. */ + } + if (value & MGC_M_POWER_SUSPENDM) { + /* When all transfers finish, suspend and if MGC_M_POWER_ENSUSPEND + * is set, also go into low power mode. Frame counting stops. */ + /* XXX: Cleared when the interrupt register is read */ + } + if (value & MGC_M_POWER_RESUME) { + /* Wait 20ms and signal resuming on the bus. Frame counting + * restarts. */ + } + break; + case MUSB_HDRC_INTRUSB: + break; + case MUSB_HDRC_INTRUSBE: + s->mask = value & 0xff; + break; + case MUSB_HDRC_INDEX: + s->idx = value & 0xf; + break; + case MUSB_HDRC_TESTMODE: + break; + + case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf): + musb_ep_writeb(s, s->idx, addr & 0xf, value); + break; + + case MUSB_HDRC_DEVCTL: + s->session = !!(value & MGC_M_DEVCTL_SESSION); + musb_session_update(s, + !!s->port.dev, + !!(s->devctl & MGC_M_DEVCTL_SESSION)); + + /* It seems this is the only R/W bit in this register? */ + s->devctl &= ~MGC_M_DEVCTL_SESSION; + s->devctl |= value & MGC_M_DEVCTL_SESSION; + break; + + case MUSB_HDRC_TXFIFOSZ: + case MUSB_HDRC_RXFIFOSZ: + case MUSB_HDRC_VCTRL: + /* TODO */ + break; + + case (MUSB_HDRC_VCTRL | 1): + case (MUSB_HDRC_DEVCTL | 1): + break; + + case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f): + ep = (addr >> 3) & 0xf; + musb_busctl_writeb(s, ep, addr & 0x7, value); + break; + + case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff): + ep = (addr >> 4) & 0xf; + musb_ep_writeb(s, ep, addr & 0xf, value); + break; + + default: + printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr); + }; +} + +static uint32_t musb_readh(void *opaque, target_phys_addr_t addr) +{ + struct musb_s *s = (struct musb_s *) opaque; + int ep, i; + uint16_t ret; + + switch (addr) { + case MUSB_HDRC_INTRTX: + ret = s->tx_intr; + /* Auto clear */ + for (i = 0; i < sizeof(ret) * 8; i ++) + if (ret & (1 << i)) + musb_tx_intr_set(s, i, 0); + return ret; + case MUSB_HDRC_INTRRX: + ret = s->rx_intr; + /* Auto clear */ + for (i = 0; i < sizeof(ret) * 8; i ++) + if (ret & (1 << i)) + musb_rx_intr_set(s, i, 0); + return ret; + case MUSB_HDRC_INTRTXE: + return s->tx_mask; + case MUSB_HDRC_INTRRXE: + return s->rx_mask; + + case MUSB_HDRC_FRAME: + /* TODO */ + return 0x0000; + case MUSB_HDRC_TXFIFOADDR: + return s->ep[s->idx].fifoaddr[0]; + case MUSB_HDRC_RXFIFOADDR: + return s->ep[s->idx].fifoaddr[1]; + + case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf): + return musb_ep_readh(s, s->idx, addr & 0xf); + + case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f): + ep = (addr >> 3) & 0xf; + return musb_busctl_readh(s, ep, addr & 0x7); + + case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff): + ep = (addr >> 4) & 0xf; + return musb_ep_readh(s, ep, addr & 0xf); + + default: + return musb_readb(s, addr) | (musb_readb(s, addr | 1) << 8); + }; +} + +static void musb_writeh(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + struct musb_s *s = (struct musb_s *) opaque; + int ep; + + switch (addr) { + case MUSB_HDRC_INTRTXE: + s->tx_mask = value; + /* XXX: the masks seem to apply on the raising edge like with + * edge-triggered interrupts, thus no need to update. I may be + * wrong though. */ + break; + case MUSB_HDRC_INTRRXE: + s->rx_mask = value; + break; + + case MUSB_HDRC_FRAME: + /* TODO */ + break; + case MUSB_HDRC_TXFIFOADDR: + s->ep[s->idx].fifoaddr[0] = value; + s->ep[s->idx].buf[0] = + s->buf + ((value << 1) & (sizeof(s->buf) / 4 - 1)); + break; + case MUSB_HDRC_RXFIFOADDR: + s->ep[s->idx].fifoaddr[1] = value; + s->ep[s->idx].buf[1] = + s->buf + ((value << 1) & (sizeof(s->buf) / 4 - 1)); + break; + + case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf): + musb_ep_writeh(s, s->idx, addr & 0xf, value); + break; + + case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f): + ep = (addr >> 3) & 0xf; + musb_busctl_writeh(s, ep, addr & 0x7, value); + break; + + case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff): + ep = (addr >> 4) & 0xf; + musb_ep_writeh(s, ep, addr & 0xf, value); + break; + + default: + musb_writeb(s, addr, value & 0xff); + musb_writeb(s, addr | 1, value >> 8); + }; +} + +static uint32_t musb_readw(void *opaque, target_phys_addr_t addr) +{ + struct musb_s *s = (struct musb_s *) opaque; + struct musb_ep_s *ep; + int epnum; + + switch (addr) { + case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): + epnum = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; + ep = s->ep + epnum; + + if (ep->fifolen[1] >= 16) { + /* We have a FIFO underrun */ + printf("%s: EP%i FIFO is now empty, stop reading\n", + __FUNCTION__, epnum); + return 0x00000000; + } + /* In DMA mode clear RXPKTRDY and set REQPKT automatically + * (if AUTOREQ is set) */ + + ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL; + return ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++]; + + default: + printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr); + return 0x00000000; + }; +} + +static void musb_writew(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + struct musb_s *s = (struct musb_s *) opaque; + struct musb_ep_s *ep; + int epnum; + + switch (addr) { + case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): + epnum = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; + ep = s->ep + epnum; + + if (ep->fifolen[0] >= 16) { + /* We have a FIFO overrun */ + printf("%s: EP%i FIFO exceeded 64 bytes, stop feeding data\n", + __FUNCTION__, epnum); + break; + } + + ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value; + if (epnum) + ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY; + break; + + default: + printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr); + }; +} + +CPUReadMemoryFunc *musb_read[] = { + musb_readb, + musb_readh, + musb_readw, +}; + +CPUWriteMemoryFunc *musb_write[] = { + musb_writeb, + musb_writeh, + musb_writew, +}; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/usb-net.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/usb-net.c --- qemu-0.9.1/hw/usb-net.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/usb-net.c 2008-09-20 09:07:15.000000000 +0100 @@ -0,0 +1,1473 @@ +/* + * QEMU USB Net devices + * + * Copyright (c) 2006 Thomas Sailer + * Copyright (c) 2008 Andrzej Zaborowski + * + * 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 "qemu-common.h" +#include "usb.h" +#include "net.h" +#include "sys-queue.h" + +/*#define TRAFFIC_DEBUG*/ +/* Thanks to NetChip Technologies for donating this product ID. + * It's for devices with only CDC Ethernet configurations. + */ +#define CDC_VENDOR_NUM 0x0525 /* NetChip */ +#define CDC_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */ +/* For hardware that can talk RNDIS and either of the above protocols, + * use this ID ... the windows INF files will know it. + */ +#define RNDIS_VENDOR_NUM 0x0525 /* NetChip */ +#define RNDIS_PRODUCT_NUM 0xa4a2 /* Ethernet/RNDIS Gadget */ + +enum usbstring_idx { + STRING_MANUFACTURER = 1, + STRING_PRODUCT, + STRING_ETHADDR, + STRING_DATA, + STRING_CONTROL, + STRING_RNDIS_CONTROL, + STRING_CDC, + STRING_SUBSET, + STRING_RNDIS, + STRING_SERIALNUMBER, +}; + +#define DEV_CONFIG_VALUE 1 /* CDC or a subset */ +#define DEV_RNDIS_CONFIG_VALUE 2 /* RNDIS; optional */ + +#define USB_CDC_SUBCLASS_ACM 0x02 +#define USB_CDC_SUBCLASS_ETHERNET 0x06 + +#define USB_CDC_PROTO_NONE 0 +#define USB_CDC_ACM_PROTO_VENDOR 0xff + +#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */ +#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */ +#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */ +#define USB_CDC_UNION_TYPE 0x06 /* union_desc */ +#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */ + +#define USB_DT_CS_INTERFACE 0x24 +#define USB_DT_CS_ENDPOINT 0x25 + +#define ClassInterfaceRequest \ + ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) +#define ClassInterfaceOutRequest \ + ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) + +#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00 +#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01 +#define USB_CDC_REQ_SET_LINE_CODING 0x20 +#define USB_CDC_REQ_GET_LINE_CODING 0x21 +#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22 +#define USB_CDC_REQ_SEND_BREAK 0x23 +#define USB_CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40 +#define USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER 0x41 +#define USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER 0x42 +#define USB_CDC_SET_ETHERNET_PACKET_FILTER 0x43 +#define USB_CDC_GET_ETHERNET_STATISTIC 0x44 + +#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ +#define STATUS_BYTECOUNT 16 /* 8 byte header + data */ + +#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ + +/* + * mostly the same descriptor as the linux gadget rndis driver + */ +static const uint8_t qemu_net_dev_descriptor[] = { + 0x12, /* u8 bLength; */ + USB_DT_DEVICE, /* u8 bDescriptorType; Device */ + 0x00, 0x02, /* u16 bcdUSB; v2.0 */ + USB_CLASS_COMM, /* u8 bDeviceClass; */ + 0x00, /* u8 bDeviceSubClass; */ + 0x00, /* u8 bDeviceProtocol; [ low/full only ] */ + 0x40, /* u8 bMaxPacketSize0 */ + RNDIS_VENDOR_NUM & 0xff, RNDIS_VENDOR_NUM >> 8, /* u16 idVendor; */ + RNDIS_PRODUCT_NUM & 0xff, RNDIS_PRODUCT_NUM >> 8, /* u16 idProduct; */ + 0x00, 0x00, /* u16 bcdDevice */ + STRING_MANUFACTURER, /* u8 iManufacturer; */ + STRING_PRODUCT, /* u8 iProduct; */ + STRING_SERIALNUMBER, /* u8 iSerialNumber; */ + 0x02, /* u8 bNumConfigurations; */ +}; + +static const uint8_t qemu_net_rndis_config_descriptor[] = { + /* Configuration Descriptor */ + 0x09, /* u8 bLength */ + USB_DT_CONFIG, /* u8 bDescriptorType */ + 0x43, 0x00, /* le16 wTotalLength */ + 0x02, /* u8 bNumInterfaces */ + DEV_RNDIS_CONFIG_VALUE, /* u8 bConfigurationValue */ + STRING_RNDIS, /* u8 iConfiguration */ + 0xc0, /* u8 bmAttributes */ + 0x32, /* u8 bMaxPower */ + /* RNDIS Control Interface */ + 0x09, /* u8 bLength */ + USB_DT_INTERFACE, /* u8 bDescriptorType */ + 0x00, /* u8 bInterfaceNumber */ + 0x00, /* u8 bAlternateSetting */ + 0x01, /* u8 bNumEndpoints */ + USB_CLASS_COMM, /* u8 bInterfaceClass */ + USB_CDC_SUBCLASS_ACM, /* u8 bInterfaceSubClass */ + USB_CDC_ACM_PROTO_VENDOR, /* u8 bInterfaceProtocol */ + STRING_RNDIS_CONTROL, /* u8 iInterface */ + /* Header Descriptor */ + 0x05, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */ + 0x10, 0x01, /* le16 bcdCDC */ + /* Call Management Descriptor */ + 0x05, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + USB_CDC_CALL_MANAGEMENT_TYPE, /* u8 bDescriptorSubType */ + 0x00, /* u8 bmCapabilities */ + 0x01, /* u8 bDataInterface */ + /* ACM Descriptor */ + 0x04, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + USB_CDC_ACM_TYPE, /* u8 bDescriptorSubType */ + 0x00, /* u8 bmCapabilities */ + /* Union Descriptor */ + 0x05, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */ + 0x00, /* u8 bMasterInterface0 */ + 0x01, /* u8 bSlaveInterface0 */ + /* Status Descriptor */ + 0x07, /* u8 bLength */ + USB_DT_ENDPOINT, /* u8 bDescriptorType */ + USB_DIR_IN | 1, /* u8 bEndpointAddress */ + USB_ENDPOINT_XFER_INT, /* u8 bmAttributes */ + STATUS_BYTECOUNT & 0xff, STATUS_BYTECOUNT >> 8, /* le16 wMaxPacketSize */ + 1 << LOG2_STATUS_INTERVAL_MSEC, /* u8 bInterval */ + /* RNDIS Data Interface */ + 0x09, /* u8 bLength */ + USB_DT_INTERFACE, /* u8 bDescriptorType */ + 0x01, /* u8 bInterfaceNumber */ + 0x00, /* u8 bAlternateSetting */ + 0x02, /* u8 bNumEndpoints */ + USB_CLASS_CDC_DATA, /* u8 bInterfaceClass */ + 0x00, /* u8 bInterfaceSubClass */ + 0x00, /* u8 bInterfaceProtocol */ + STRING_DATA, /* u8 iInterface */ + /* Source Endpoint */ + 0x07, /* u8 bLength */ + USB_DT_ENDPOINT, /* u8 bDescriptorType */ + USB_DIR_IN | 2, /* u8 bEndpointAddress */ + USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */ + 0x40, 0x00, /* le16 wMaxPacketSize */ + 0x00, /* u8 bInterval */ + /* Sink Endpoint */ + 0x07, /* u8 bLength */ + USB_DT_ENDPOINT, /* u8 bDescriptorType */ + USB_DIR_OUT | 2, /* u8 bEndpointAddress */ + USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */ + 0x40, 0x00, /* le16 wMaxPacketSize */ + 0x00 /* u8 bInterval */ +}; + +static const uint8_t qemu_net_cdc_config_descriptor[] = { + /* Configuration Descriptor */ + 0x09, /* u8 bLength */ + USB_DT_CONFIG, /* u8 bDescriptorType */ + 0x50, 0x00, /* le16 wTotalLength */ + 0x02, /* u8 bNumInterfaces */ + DEV_CONFIG_VALUE, /* u8 bConfigurationValue */ + STRING_CDC, /* u8 iConfiguration */ + 0xc0, /* u8 bmAttributes */ + 0x32, /* u8 bMaxPower */ + /* CDC Control Interface */ + 0x09, /* u8 bLength */ + USB_DT_INTERFACE, /* u8 bDescriptorType */ + 0x00, /* u8 bInterfaceNumber */ + 0x00, /* u8 bAlternateSetting */ + 0x01, /* u8 bNumEndpoints */ + USB_CLASS_COMM, /* u8 bInterfaceClass */ + USB_CDC_SUBCLASS_ETHERNET, /* u8 bInterfaceSubClass */ + USB_CDC_PROTO_NONE, /* u8 bInterfaceProtocol */ + STRING_CONTROL, /* u8 iInterface */ + /* Header Descriptor */ + 0x05, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */ + 0x10, 0x01, /* le16 bcdCDC */ + /* Union Descriptor */ + 0x05, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */ + 0x00, /* u8 bMasterInterface0 */ + 0x01, /* u8 bSlaveInterface0 */ + /* Ethernet Descriptor */ + 0x0d, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + USB_CDC_ETHERNET_TYPE, /* u8 bDescriptorSubType */ + STRING_ETHADDR, /* u8 iMACAddress */ + 0x00, 0x00, 0x00, 0x00, /* le32 bmEthernetStatistics */ + ETH_FRAME_LEN & 0xff, ETH_FRAME_LEN >> 8, /* le16 wMaxSegmentSize */ + 0x00, 0x00, /* le16 wNumberMCFilters */ + 0x00, /* u8 bNumberPowerFilters */ + /* Status Descriptor */ + 0x07, /* u8 bLength */ + USB_DT_ENDPOINT, /* u8 bDescriptorType */ + USB_DIR_IN | 1, /* u8 bEndpointAddress */ + USB_ENDPOINT_XFER_INT, /* u8 bmAttributes */ + STATUS_BYTECOUNT & 0xff, STATUS_BYTECOUNT >> 8, /* le16 wMaxPacketSize */ + 1 << LOG2_STATUS_INTERVAL_MSEC, /* u8 bInterval */ + /* CDC Data (nop) Interface */ + 0x09, /* u8 bLength */ + USB_DT_INTERFACE, /* u8 bDescriptorType */ + 0x01, /* u8 bInterfaceNumber */ + 0x00, /* u8 bAlternateSetting */ + 0x00, /* u8 bNumEndpoints */ + USB_CLASS_CDC_DATA, /* u8 bInterfaceClass */ + 0x00, /* u8 bInterfaceSubClass */ + 0x00, /* u8 bInterfaceProtocol */ + 0x00, /* u8 iInterface */ + /* CDC Data Interface */ + 0x09, /* u8 bLength */ + USB_DT_INTERFACE, /* u8 bDescriptorType */ + 0x01, /* u8 bInterfaceNumber */ + 0x01, /* u8 bAlternateSetting */ + 0x02, /* u8 bNumEndpoints */ + USB_CLASS_CDC_DATA, /* u8 bInterfaceClass */ + 0x00, /* u8 bInterfaceSubClass */ + 0x00, /* u8 bInterfaceProtocol */ + STRING_DATA, /* u8 iInterface */ + /* Source Endpoint */ + 0x07, /* u8 bLength */ + USB_DT_ENDPOINT, /* u8 bDescriptorType */ + USB_DIR_IN | 2, /* u8 bEndpointAddress */ + USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */ + 0x40, 0x00, /* le16 wMaxPacketSize */ + 0x00, /* u8 bInterval */ + /* Sink Endpoint */ + 0x07, /* u8 bLength */ + USB_DT_ENDPOINT, /* u8 bDescriptorType */ + USB_DIR_OUT | 2, /* u8 bEndpointAddress */ + USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */ + 0x40, 0x00, /* le16 wMaxPacketSize */ + 0x00 /* u8 bInterval */ +}; + +/* + * RNDIS Definitions - in theory not specific to USB. + */ +#define RNDIS_MAXIMUM_FRAME_SIZE 1518 +#define RNDIS_MAX_TOTAL_SIZE 1558 + +/* Remote NDIS Versions */ +#define RNDIS_MAJOR_VERSION 1 +#define RNDIS_MINOR_VERSION 0 + +/* Status Values */ +#define RNDIS_STATUS_SUCCESS 0x00000000U /* Success */ +#define RNDIS_STATUS_FAILURE 0xc0000001U /* Unspecified error */ +#define RNDIS_STATUS_INVALID_DATA 0xc0010015U /* Invalid data */ +#define RNDIS_STATUS_NOT_SUPPORTED 0xc00000bbU /* Unsupported request */ +#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000bU /* Device connected */ +#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000cU /* Device disconnected */ + +/* Message Set for Connectionless (802.3) Devices */ +enum { + RNDIS_PACKET_MSG = 1, + RNDIS_INITIALIZE_MSG = 2, /* Initialize device */ + RNDIS_HALT_MSG = 3, + RNDIS_QUERY_MSG = 4, + RNDIS_SET_MSG = 5, + RNDIS_RESET_MSG = 6, + RNDIS_INDICATE_STATUS_MSG = 7, + RNDIS_KEEPALIVE_MSG = 8, +}; + +/* Message completion */ +enum { + RNDIS_INITIALIZE_CMPLT = 0x80000002U, + RNDIS_QUERY_CMPLT = 0x80000004U, + RNDIS_SET_CMPLT = 0x80000005U, + RNDIS_RESET_CMPLT = 0x80000006U, + RNDIS_KEEPALIVE_CMPLT = 0x80000008U, +}; + +/* Device Flags */ +enum { + RNDIS_DF_CONNECTIONLESS = 1, + RNDIS_DF_CONNECTIONORIENTED = 2, +}; + +#define RNDIS_MEDIUM_802_3 0x00000000U + +/* from drivers/net/sk98lin/h/skgepnmi.h */ +#define OID_PNP_CAPABILITIES 0xfd010100 +#define OID_PNP_SET_POWER 0xfd010101 +#define OID_PNP_QUERY_POWER 0xfd010102 +#define OID_PNP_ADD_WAKE_UP_PATTERN 0xfd010103 +#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xfd010104 +#define OID_PNP_ENABLE_WAKE_UP 0xfd010106 + +typedef uint32_t le32; + +typedef struct rndis_init_msg_type { + le32 MessageType; + le32 MessageLength; + le32 RequestID; + le32 MajorVersion; + le32 MinorVersion; + le32 MaxTransferSize; +} rndis_init_msg_type; + +typedef struct rndis_init_cmplt_type { + le32 MessageType; + le32 MessageLength; + le32 RequestID; + le32 Status; + le32 MajorVersion; + le32 MinorVersion; + le32 DeviceFlags; + le32 Medium; + le32 MaxPacketsPerTransfer; + le32 MaxTransferSize; + le32 PacketAlignmentFactor; + le32 AFListOffset; + le32 AFListSize; +} rndis_init_cmplt_type; + +typedef struct rndis_halt_msg_type { + le32 MessageType; + le32 MessageLength; + le32 RequestID; +} rndis_halt_msg_type; + +typedef struct rndis_query_msg_type { + le32 MessageType; + le32 MessageLength; + le32 RequestID; + le32 OID; + le32 InformationBufferLength; + le32 InformationBufferOffset; + le32 DeviceVcHandle; +} rndis_query_msg_type; + +typedef struct rndis_query_cmplt_type { + le32 MessageType; + le32 MessageLength; + le32 RequestID; + le32 Status; + le32 InformationBufferLength; + le32 InformationBufferOffset; +} rndis_query_cmplt_type; + +typedef struct rndis_set_msg_type { + le32 MessageType; + le32 MessageLength; + le32 RequestID; + le32 OID; + le32 InformationBufferLength; + le32 InformationBufferOffset; + le32 DeviceVcHandle; +} rndis_set_msg_type; + +typedef struct rndis_set_cmplt_type { + le32 MessageType; + le32 MessageLength; + le32 RequestID; + le32 Status; +} rndis_set_cmplt_type; + +typedef struct rndis_reset_msg_type { + le32 MessageType; + le32 MessageLength; + le32 Reserved; +} rndis_reset_msg_type; + +typedef struct rndis_reset_cmplt_type { + le32 MessageType; + le32 MessageLength; + le32 Status; + le32 AddressingReset; +} rndis_reset_cmplt_type; + +typedef struct rndis_indicate_status_msg_type { + le32 MessageType; + le32 MessageLength; + le32 Status; + le32 StatusBufferLength; + le32 StatusBufferOffset; +} rndis_indicate_status_msg_type; + +typedef struct rndis_keepalive_msg_type { + le32 MessageType; + le32 MessageLength; + le32 RequestID; +} rndis_keepalive_msg_type; + +typedef struct rndis_keepalive_cmplt_type { + le32 MessageType; + le32 MessageLength; + le32 RequestID; + le32 Status; +} rndis_keepalive_cmplt_type; + +struct rndis_packet_msg_type { + le32 MessageType; + le32 MessageLength; + le32 DataOffset; + le32 DataLength; + le32 OOBDataOffset; + le32 OOBDataLength; + le32 NumOOBDataElements; + le32 PerPacketInfoOffset; + le32 PerPacketInfoLength; + le32 VcHandle; + le32 Reserved; +}; + +struct rndis_config_parameter { + le32 ParameterNameOffset; + le32 ParameterNameLength; + le32 ParameterType; + le32 ParameterValueOffset; + le32 ParameterValueLength; +}; + +/* implementation specific */ +enum rndis_state +{ + RNDIS_UNINITIALIZED, + RNDIS_INITIALIZED, + RNDIS_DATA_INITIALIZED, +}; + +/* from ndis.h */ +enum ndis_oid { + /* Required Object IDs (OIDs) */ + OID_GEN_SUPPORTED_LIST = 0x00010101, + OID_GEN_HARDWARE_STATUS = 0x00010102, + OID_GEN_MEDIA_SUPPORTED = 0x00010103, + OID_GEN_MEDIA_IN_USE = 0x00010104, + OID_GEN_MAXIMUM_LOOKAHEAD = 0x00010105, + OID_GEN_MAXIMUM_FRAME_SIZE = 0x00010106, + OID_GEN_LINK_SPEED = 0x00010107, + OID_GEN_TRANSMIT_BUFFER_SPACE = 0x00010108, + OID_GEN_RECEIVE_BUFFER_SPACE = 0x00010109, + OID_GEN_TRANSMIT_BLOCK_SIZE = 0x0001010a, + OID_GEN_RECEIVE_BLOCK_SIZE = 0x0001010b, + OID_GEN_VENDOR_ID = 0x0001010c, + OID_GEN_VENDOR_DESCRIPTION = 0x0001010d, + OID_GEN_CURRENT_PACKET_FILTER = 0x0001010e, + OID_GEN_CURRENT_LOOKAHEAD = 0x0001010f, + OID_GEN_DRIVER_VERSION = 0x00010110, + OID_GEN_MAXIMUM_TOTAL_SIZE = 0x00010111, + OID_GEN_PROTOCOL_OPTIONS = 0x00010112, + OID_GEN_MAC_OPTIONS = 0x00010113, + OID_GEN_MEDIA_CONNECT_STATUS = 0x00010114, + OID_GEN_MAXIMUM_SEND_PACKETS = 0x00010115, + OID_GEN_VENDOR_DRIVER_VERSION = 0x00010116, + OID_GEN_SUPPORTED_GUIDS = 0x00010117, + OID_GEN_NETWORK_LAYER_ADDRESSES = 0x00010118, + OID_GEN_TRANSPORT_HEADER_OFFSET = 0x00010119, + OID_GEN_MACHINE_NAME = 0x0001021a, + OID_GEN_RNDIS_CONFIG_PARAMETER = 0x0001021b, + OID_GEN_VLAN_ID = 0x0001021c, + + /* Optional OIDs */ + OID_GEN_MEDIA_CAPABILITIES = 0x00010201, + OID_GEN_PHYSICAL_MEDIUM = 0x00010202, + + /* Required statistics OIDs */ + OID_GEN_XMIT_OK = 0x00020101, + OID_GEN_RCV_OK = 0x00020102, + OID_GEN_XMIT_ERROR = 0x00020103, + OID_GEN_RCV_ERROR = 0x00020104, + OID_GEN_RCV_NO_BUFFER = 0x00020105, + + /* Optional statistics OIDs */ + OID_GEN_DIRECTED_BYTES_XMIT = 0x00020201, + OID_GEN_DIRECTED_FRAMES_XMIT = 0x00020202, + OID_GEN_MULTICAST_BYTES_XMIT = 0x00020203, + OID_GEN_MULTICAST_FRAMES_XMIT = 0x00020204, + OID_GEN_BROADCAST_BYTES_XMIT = 0x00020205, + OID_GEN_BROADCAST_FRAMES_XMIT = 0x00020206, + OID_GEN_DIRECTED_BYTES_RCV = 0x00020207, + OID_GEN_DIRECTED_FRAMES_RCV = 0x00020208, + OID_GEN_MULTICAST_BYTES_RCV = 0x00020209, + OID_GEN_MULTICAST_FRAMES_RCV = 0x0002020a, + OID_GEN_BROADCAST_BYTES_RCV = 0x0002020b, + OID_GEN_BROADCAST_FRAMES_RCV = 0x0002020c, + OID_GEN_RCV_CRC_ERROR = 0x0002020d, + OID_GEN_TRANSMIT_QUEUE_LENGTH = 0x0002020e, + OID_GEN_GET_TIME_CAPS = 0x0002020f, + OID_GEN_GET_NETCARD_TIME = 0x00020210, + OID_GEN_NETCARD_LOAD = 0x00020211, + OID_GEN_DEVICE_PROFILE = 0x00020212, + OID_GEN_INIT_TIME_MS = 0x00020213, + OID_GEN_RESET_COUNTS = 0x00020214, + OID_GEN_MEDIA_SENSE_COUNTS = 0x00020215, + OID_GEN_FRIENDLY_NAME = 0x00020216, + OID_GEN_MINIPORT_INFO = 0x00020217, + OID_GEN_RESET_VERIFY_PARAMETERS = 0x00020218, + + /* IEEE 802.3 (Ethernet) OIDs */ + OID_802_3_PERMANENT_ADDRESS = 0x01010101, + OID_802_3_CURRENT_ADDRESS = 0x01010102, + OID_802_3_MULTICAST_LIST = 0x01010103, + OID_802_3_MAXIMUM_LIST_SIZE = 0x01010104, + OID_802_3_MAC_OPTIONS = 0x01010105, + OID_802_3_RCV_ERROR_ALIGNMENT = 0x01020101, + OID_802_3_XMIT_ONE_COLLISION = 0x01020102, + OID_802_3_XMIT_MORE_COLLISIONS = 0x01020103, + OID_802_3_XMIT_DEFERRED = 0x01020201, + OID_802_3_XMIT_MAX_COLLISIONS = 0x01020202, + OID_802_3_RCV_OVERRUN = 0x01020203, + OID_802_3_XMIT_UNDERRUN = 0x01020204, + OID_802_3_XMIT_HEARTBEAT_FAILURE = 0x01020205, + OID_802_3_XMIT_TIMES_CRS_LOST = 0x01020206, + OID_802_3_XMIT_LATE_COLLISIONS = 0x01020207, +}; + +static const uint32_t oid_supported_list[] = +{ + /* the general stuff */ + OID_GEN_SUPPORTED_LIST, + OID_GEN_HARDWARE_STATUS, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_FRAME_SIZE, + OID_GEN_LINK_SPEED, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_VENDOR_DRIVER_VERSION, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_MEDIA_CONNECT_STATUS, + OID_GEN_PHYSICAL_MEDIUM, + + /* the statistical stuff */ + OID_GEN_XMIT_OK, + OID_GEN_RCV_OK, + OID_GEN_XMIT_ERROR, + OID_GEN_RCV_ERROR, + OID_GEN_RCV_NO_BUFFER, + + /* IEEE 802.3 */ + /* the general stuff */ + OID_802_3_PERMANENT_ADDRESS, + OID_802_3_CURRENT_ADDRESS, + OID_802_3_MULTICAST_LIST, + OID_802_3_MAC_OPTIONS, + OID_802_3_MAXIMUM_LIST_SIZE, + + /* the statistical stuff */ + OID_802_3_RCV_ERROR_ALIGNMENT, + OID_802_3_XMIT_ONE_COLLISION, + OID_802_3_XMIT_MORE_COLLISIONS, +}; + +#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA (1 << 0) +#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED (1 << 1) +#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND (1 << 2) +#define NDIS_MAC_OPTION_NO_LOOPBACK (1 << 3) +#define NDIS_MAC_OPTION_FULL_DUPLEX (1 << 4) +#define NDIS_MAC_OPTION_EOTX_INDICATION (1 << 5) +#define NDIS_MAC_OPTION_8021P_PRIORITY (1 << 6) + +struct rndis_response { + TAILQ_ENTRY(rndis_response) entries; + uint32_t length; + uint8_t buf[0]; +}; + +typedef struct USBNetState { + USBDevice dev; + + unsigned int rndis; + enum rndis_state rndis_state; + uint32_t medium; + uint32_t speed; + uint32_t media_state; + uint16_t filter; + uint32_t vendorid; + uint8_t mac[6]; + + unsigned int out_ptr; + uint8_t out_buf[2048]; + + USBPacket *inpkt; + unsigned int in_ptr, in_len; + uint8_t in_buf[2048]; + + char usbstring_mac[13]; + VLANClientState *vc; + TAILQ_HEAD(rndis_resp_head, rndis_response) rndis_resp; +} USBNetState; + +static int ndis_query(USBNetState *s, uint32_t oid, + uint8_t *inbuf, unsigned int inlen, uint8_t *outbuf, + size_t outlen) +{ + unsigned int i, count; + + switch (oid) { + /* general oids (table 4-1) */ + /* mandatory */ + case OID_GEN_SUPPORTED_LIST: + count = sizeof(oid_supported_list) / sizeof(uint32_t); + for (i = 0; i < count; i++) + ((le32 *) outbuf)[i] = cpu_to_le32(oid_supported_list[i]); + return sizeof(oid_supported_list); + + /* mandatory */ + case OID_GEN_HARDWARE_STATUS: + *((le32 *) outbuf) = cpu_to_le32(0); + return sizeof(le32); + + /* mandatory */ + case OID_GEN_MEDIA_SUPPORTED: + *((le32 *) outbuf) = cpu_to_le32(s->medium); + return sizeof(le32); + + /* mandatory */ + case OID_GEN_MEDIA_IN_USE: + *((le32 *) outbuf) = cpu_to_le32(s->medium); + return sizeof(le32); + + /* mandatory */ + case OID_GEN_MAXIMUM_FRAME_SIZE: + *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN); + return sizeof(le32); + + /* mandatory */ + case OID_GEN_LINK_SPEED: + *((le32 *) outbuf) = cpu_to_le32(s->speed); + return sizeof(le32); + + /* mandatory */ + case OID_GEN_TRANSMIT_BLOCK_SIZE: + *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN); + return sizeof(le32); + + /* mandatory */ + case OID_GEN_RECEIVE_BLOCK_SIZE: + *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN); + return sizeof(le32); + + /* mandatory */ + case OID_GEN_VENDOR_ID: + *((le32 *) outbuf) = cpu_to_le32(s->vendorid); + return sizeof(le32); + + /* mandatory */ + case OID_GEN_VENDOR_DESCRIPTION: + pstrcpy((char *)outbuf, outlen, "QEMU USB RNDIS Net"); + return strlen((char *)outbuf) + 1; + + case OID_GEN_VENDOR_DRIVER_VERSION: + *((le32 *) outbuf) = cpu_to_le32(1); + return sizeof(le32); + + /* mandatory */ + case OID_GEN_CURRENT_PACKET_FILTER: + *((le32 *) outbuf) = cpu_to_le32(s->filter); + return sizeof(le32); + + /* mandatory */ + case OID_GEN_MAXIMUM_TOTAL_SIZE: + *((le32 *) outbuf) = cpu_to_le32(RNDIS_MAX_TOTAL_SIZE); + return sizeof(le32); + + /* mandatory */ + case OID_GEN_MEDIA_CONNECT_STATUS: + *((le32 *) outbuf) = cpu_to_le32(s->media_state); + return sizeof(le32); + + case OID_GEN_PHYSICAL_MEDIUM: + *((le32 *) outbuf) = cpu_to_le32(0); + return sizeof(le32); + + case OID_GEN_MAC_OPTIONS: + *((le32 *) outbuf) = cpu_to_le32( + NDIS_MAC_OPTION_RECEIVE_SERIALIZED | + NDIS_MAC_OPTION_FULL_DUPLEX); + return sizeof(le32); + + /* statistics OIDs (table 4-2) */ + /* mandatory */ + case OID_GEN_XMIT_OK: + *((le32 *) outbuf) = cpu_to_le32(0); + return sizeof(le32); + + /* mandatory */ + case OID_GEN_RCV_OK: + *((le32 *) outbuf) = cpu_to_le32(0); + return sizeof(le32); + + /* mandatory */ + case OID_GEN_XMIT_ERROR: + *((le32 *) outbuf) = cpu_to_le32(0); + return sizeof(le32); + + /* mandatory */ + case OID_GEN_RCV_ERROR: + *((le32 *) outbuf) = cpu_to_le32(0); + return sizeof(le32); + + /* mandatory */ + case OID_GEN_RCV_NO_BUFFER: + *((le32 *) outbuf) = cpu_to_le32(0); + return sizeof(le32); + + /* ieee802.3 OIDs (table 4-3) */ + /* mandatory */ + case OID_802_3_PERMANENT_ADDRESS: + memcpy(outbuf, s->mac, 6); + return 6; + + /* mandatory */ + case OID_802_3_CURRENT_ADDRESS: + memcpy(outbuf, s->mac, 6); + return 6; + + /* mandatory */ + case OID_802_3_MULTICAST_LIST: + *((le32 *) outbuf) = cpu_to_le32(0xe0000000); + return sizeof(le32); + + /* mandatory */ + case OID_802_3_MAXIMUM_LIST_SIZE: + *((le32 *) outbuf) = cpu_to_le32(1); + return sizeof(le32); + + case OID_802_3_MAC_OPTIONS: + return 0; + + /* ieee802.3 statistics OIDs (table 4-4) */ + /* mandatory */ + case OID_802_3_RCV_ERROR_ALIGNMENT: + *((le32 *) outbuf) = cpu_to_le32(0); + return sizeof(le32); + + /* mandatory */ + case OID_802_3_XMIT_ONE_COLLISION: + *((le32 *) outbuf) = cpu_to_le32(0); + return sizeof(le32); + + /* mandatory */ + case OID_802_3_XMIT_MORE_COLLISIONS: + *((le32 *) outbuf) = cpu_to_le32(0); + return sizeof(le32); + + default: + fprintf(stderr, "usbnet: unknown OID 0x%08x\n", oid); + return 0; + } + return -1; +} + +static int ndis_set(USBNetState *s, uint32_t oid, + uint8_t *inbuf, unsigned int inlen) +{ + switch (oid) { + case OID_GEN_CURRENT_PACKET_FILTER: + s->filter = le32_to_cpup((le32 *) inbuf); + if (s->filter) { + s->rndis_state = RNDIS_DATA_INITIALIZED; + } else { + s->rndis_state = RNDIS_INITIALIZED; + } + return 0; + + case OID_802_3_MULTICAST_LIST: + return 0; + } + return -1; +} + +static int rndis_get_response(USBNetState *s, uint8_t *buf) +{ + int ret = 0; + struct rndis_response *r = s->rndis_resp.tqh_first; + + if (!r) + return ret; + + TAILQ_REMOVE(&s->rndis_resp, r, entries); + ret = r->length; + memcpy(buf, r->buf, r->length); + qemu_free(r); + + return ret; +} + +static void *rndis_queue_response(USBNetState *s, unsigned int length) +{ + struct rndis_response *r = + qemu_mallocz(sizeof(struct rndis_response) + length); + + TAILQ_INSERT_TAIL(&s->rndis_resp, r, entries); + r->length = length; + + return &r->buf[0]; +} + +static void rndis_clear_responsequeue(USBNetState *s) +{ + struct rndis_response *r; + + while ((r = s->rndis_resp.tqh_first)) { + TAILQ_REMOVE(&s->rndis_resp, r, entries); + qemu_free(r); + } +} + +static int rndis_init_response(USBNetState *s, rndis_init_msg_type *buf) +{ + rndis_init_cmplt_type *resp = + rndis_queue_response(s, sizeof(rndis_init_cmplt_type)); + + if (!resp) + return USB_RET_STALL; + + resp->MessageType = cpu_to_le32(RNDIS_INITIALIZE_CMPLT); + resp->MessageLength = cpu_to_le32(sizeof(rndis_init_cmplt_type)); + resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ + resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); + resp->MajorVersion = cpu_to_le32(RNDIS_MAJOR_VERSION); + resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION); + resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS); + resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3); + resp->MaxPacketsPerTransfer = cpu_to_le32(1); + resp->MaxTransferSize = cpu_to_le32(ETH_FRAME_LEN + + sizeof(struct rndis_packet_msg_type) + 22); + resp->PacketAlignmentFactor = cpu_to_le32(0); + resp->AFListOffset = cpu_to_le32(0); + resp->AFListSize = cpu_to_le32(0); + return 0; +} + +static int rndis_query_response(USBNetState *s, + rndis_query_msg_type *buf, unsigned int length) +{ + rndis_query_cmplt_type *resp; + /* oid_supported_list is the largest data reply */ + uint8_t infobuf[sizeof(oid_supported_list)]; + uint32_t bufoffs, buflen; + int infobuflen; + unsigned int resplen; + + bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8; + buflen = le32_to_cpu(buf->InformationBufferLength); + if (bufoffs + buflen > length) + return USB_RET_STALL; + + infobuflen = ndis_query(s, le32_to_cpu(buf->OID), + bufoffs + (uint8_t *) buf, buflen, infobuf, + sizeof(infobuf)); + resplen = sizeof(rndis_query_cmplt_type) + + ((infobuflen < 0) ? 0 : infobuflen); + resp = rndis_queue_response(s, resplen); + if (!resp) + return USB_RET_STALL; + + resp->MessageType = cpu_to_le32(RNDIS_QUERY_CMPLT); + resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ + resp->MessageLength = cpu_to_le32(resplen); + + if (infobuflen < 0) { + /* OID not supported */ + resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED); + resp->InformationBufferLength = cpu_to_le32(0); + resp->InformationBufferOffset = cpu_to_le32(0); + return 0; + } + + resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); + resp->InformationBufferOffset = + cpu_to_le32(infobuflen ? sizeof(rndis_query_cmplt_type) - 8 : 0); + resp->InformationBufferLength = cpu_to_le32(infobuflen); + memcpy(resp + 1, infobuf, infobuflen); + + return 0; +} + +static int rndis_set_response(USBNetState *s, + rndis_set_msg_type *buf, unsigned int length) +{ + rndis_set_cmplt_type *resp = + rndis_queue_response(s, sizeof(rndis_set_cmplt_type)); + uint32_t bufoffs, buflen; + int ret; + + if (!resp) + return USB_RET_STALL; + + bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8; + buflen = le32_to_cpu(buf->InformationBufferLength); + if (bufoffs + buflen > length) + return USB_RET_STALL; + + ret = ndis_set(s, le32_to_cpu(buf->OID), + bufoffs + (uint8_t *) buf, buflen); + resp->MessageType = cpu_to_le32(RNDIS_SET_CMPLT); + resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ + resp->MessageLength = cpu_to_le32(sizeof(rndis_set_cmplt_type)); + if (ret < 0) { + /* OID not supported */ + resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED); + return 0; + } + resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); + + return 0; +} + +static int rndis_reset_response(USBNetState *s, rndis_reset_msg_type *buf) +{ + rndis_reset_cmplt_type *resp = + rndis_queue_response(s, sizeof(rndis_reset_cmplt_type)); + + if (!resp) + return USB_RET_STALL; + + resp->MessageType = cpu_to_le32(RNDIS_RESET_CMPLT); + resp->MessageLength = cpu_to_le32(sizeof(rndis_reset_cmplt_type)); + resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); + resp->AddressingReset = cpu_to_le32(1); /* reset information */ + + return 0; +} + +static int rndis_keepalive_response(USBNetState *s, + rndis_keepalive_msg_type *buf) +{ + rndis_keepalive_cmplt_type *resp = + rndis_queue_response(s, sizeof(rndis_keepalive_cmplt_type)); + + if (!resp) + return USB_RET_STALL; + + resp->MessageType = cpu_to_le32(RNDIS_KEEPALIVE_CMPLT); + resp->MessageLength = cpu_to_le32(sizeof(rndis_keepalive_cmplt_type)); + resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ + resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); + + return 0; +} + +static int rndis_parse(USBNetState *s, uint8_t *data, int length) +{ + uint32_t msg_type, msg_length; + le32 *tmp = (le32 *) data; + + msg_type = le32_to_cpup(tmp++); + msg_length = le32_to_cpup(tmp++); + + switch (msg_type) { + case RNDIS_INITIALIZE_MSG: + s->rndis_state = RNDIS_INITIALIZED; + return rndis_init_response(s, (rndis_init_msg_type *) data); + + case RNDIS_HALT_MSG: + s->rndis_state = RNDIS_UNINITIALIZED; + return 0; + + case RNDIS_QUERY_MSG: + return rndis_query_response(s, (rndis_query_msg_type *) data, length); + + case RNDIS_SET_MSG: + return rndis_set_response(s, (rndis_set_msg_type *) data, length); + + case RNDIS_RESET_MSG: + rndis_clear_responsequeue(s); + s->out_ptr = s->in_ptr = s->in_len = 0; + return rndis_reset_response(s, (rndis_reset_msg_type *) data); + + case RNDIS_KEEPALIVE_MSG: + /* For USB: host does this every 5 seconds */ + return rndis_keepalive_response(s, (rndis_keepalive_msg_type *) data); + } + + return USB_RET_STALL; +} + +static void usb_net_handle_reset(USBDevice *dev) +{ +} + +static const char * const usb_net_stringtable[] = { + [STRING_MANUFACTURER] = "QEMU", + [STRING_PRODUCT] = "RNDIS/QEMU USB Network Device", + [STRING_ETHADDR] = "400102030405", + [STRING_DATA] = "QEMU USB Net Data Interface", + [STRING_CONTROL] = "QEMU USB Net Control Interface", + [STRING_RNDIS_CONTROL] = "QEMU USB Net RNDIS Control Interface", + [STRING_CDC] = "QEMU USB Net CDC", + [STRING_SUBSET] = "QEMU USB Net Subset", + [STRING_RNDIS] = "QEMU USB Net RNDIS", + [STRING_SERIALNUMBER] = "1", +}; + +static int usb_net_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + USBNetState *s = (USBNetState *) dev; + int ret = 0; + + switch(request) { + case DeviceRequest | USB_REQ_GET_STATUS: + data[0] = (1 << USB_DEVICE_SELF_POWERED) | + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[1] = 0x00; + ret = 2; + break; + + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + } else { + goto fail; + } + ret = 0; + break; + + case DeviceOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + } else { + goto fail; + } + ret = 0; + break; + + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + ret = 0; + break; + + case ClassInterfaceOutRequest | USB_CDC_SEND_ENCAPSULATED_COMMAND: + if (!s->rndis || value || index != 0) + goto fail; +#ifdef TRAFFIC_DEBUG + { + unsigned int i; + fprintf(stderr, "SEND_ENCAPSULATED_COMMAND:"); + for (i = 0; i < length; i++) { + if (!(i & 15)) + fprintf(stderr, "\n%04x:", i); + fprintf(stderr, " %02x", data[i]); + } + fprintf(stderr, "\n\n"); + } +#endif + ret = rndis_parse(s, data, length); + break; + + case ClassInterfaceRequest | USB_CDC_GET_ENCAPSULATED_RESPONSE: + if (!s->rndis || value || index != 0) + goto fail; + ret = rndis_get_response(s, data); + if (!ret) { + data[0] = 0; + ret = 1; + } +#ifdef TRAFFIC_DEBUG + { + unsigned int i; + fprintf(stderr, "GET_ENCAPSULATED_RESPONSE:"); + for (i = 0; i < ret; i++) { + if (!(i & 15)) + fprintf(stderr, "\n%04x:", i); + fprintf(stderr, " %02x", data[i]); + } + fprintf(stderr, "\n\n"); + } +#endif + break; + + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case USB_DT_DEVICE: + ret = sizeof(qemu_net_dev_descriptor); + memcpy(data, qemu_net_dev_descriptor, ret); + break; + + case USB_DT_CONFIG: + switch (value & 0xff) { + case 0: + ret = sizeof(qemu_net_rndis_config_descriptor); + memcpy(data, qemu_net_rndis_config_descriptor, ret); + break; + + case 1: + ret = sizeof(qemu_net_cdc_config_descriptor); + memcpy(data, qemu_net_cdc_config_descriptor, ret); + break; + + default: + goto fail; + } + + data[2] = ret & 0xff; + data[3] = ret >> 8; + break; + + case USB_DT_STRING: + switch (value & 0xff) { + case 0: + /* language ids */ + data[0] = 4; + data[1] = 3; + data[2] = 0x09; + data[3] = 0x04; + ret = 4; + break; + + case STRING_ETHADDR: + ret = set_usb_string(data, s->usbstring_mac); + break; + + default: + if (usb_net_stringtable[value & 0xff]) { + ret = set_usb_string(data, + usb_net_stringtable[value & 0xff]); + break; + } + + goto fail; + } + break; + + default: + goto fail; + } + break; + + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = s->rndis ? DEV_RNDIS_CONFIG_VALUE : DEV_CONFIG_VALUE; + ret = 1; + break; + + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + switch (value & 0xff) { + case DEV_CONFIG_VALUE: + s->rndis = 0; + break; + + case DEV_RNDIS_CONFIG_VALUE: + s->rndis = 1; + break; + + default: + goto fail; + } + ret = 0; + break; + + case DeviceRequest | USB_REQ_GET_INTERFACE: + case InterfaceRequest | USB_REQ_GET_INTERFACE: + data[0] = 0; + ret = 1; + break; + + case DeviceOutRequest | USB_REQ_SET_INTERFACE: + case InterfaceOutRequest | USB_REQ_SET_INTERFACE: + ret = 0; + break; + + default: + fail: + fprintf(stderr, "usbnet: failed control transaction: " + "request 0x%x value 0x%x index 0x%x length 0x%x\n", + request, value, index, length); + ret = USB_RET_STALL; + break; + } + return ret; +} + +static int usb_net_handle_statusin(USBNetState *s, USBPacket *p) +{ + int ret = 8; + + if (p->len < 8) + return USB_RET_STALL; + + ((le32 *) p->data)[0] = cpu_to_le32(1); + ((le32 *) p->data)[1] = cpu_to_le32(0); + if (!s->rndis_resp.tqh_first) + ret = USB_RET_NAK; + +#ifdef TRAFFIC_DEBUG + fprintf(stderr, "usbnet: interrupt poll len %u return %d", p->len, ret); + { + int i; + fprintf(stderr, ":"); + for (i = 0; i < ret; i++) { + if (!(i & 15)) + fprintf(stderr, "\n%04x:", i); + fprintf(stderr, " %02x", p->data[i]); + } + fprintf(stderr, "\n\n"); + } +#endif + + return ret; +} + +static int usb_net_handle_datain(USBNetState *s, USBPacket *p) +{ + int ret = USB_RET_NAK; + + if (s->in_ptr > s->in_len) { + s->in_ptr = s->in_len = 0; + ret = USB_RET_NAK; + return ret; + } + if (!s->in_len) { + ret = USB_RET_NAK; + return ret; + } + ret = s->in_len - s->in_ptr; + if (ret > p->len) + ret = p->len; + memcpy(p->data, &s->in_buf[s->in_ptr], ret); + s->in_ptr += ret; + if (s->in_ptr >= s->in_len && + (s->rndis || (s->in_len & (64 - 1)) || !ret)) { + /* no short packet necessary */ + s->in_ptr = s->in_len = 0; + } + +#ifdef TRAFFIC_DEBUG + fprintf(stderr, "usbnet: data in len %u return %d", p->len, ret); + { + int i; + fprintf(stderr, ":"); + for (i = 0; i < ret; i++) { + if (!(i & 15)) + fprintf(stderr, "\n%04x:", i); + fprintf(stderr, " %02x", p->data[i]); + } + fprintf(stderr, "\n\n"); + } +#endif + + return ret; +} + +static int usb_net_handle_dataout(USBNetState *s, USBPacket *p) +{ + int ret = p->len; + int sz = sizeof(s->out_buf) - s->out_ptr; + struct rndis_packet_msg_type *msg = + (struct rndis_packet_msg_type *) s->out_buf; + uint32_t len; + +#ifdef TRAFFIC_DEBUG + fprintf(stderr, "usbnet: data out len %u\n", p->len); + { + int i; + fprintf(stderr, ":"); + for (i = 0; i < p->len; i++) { + if (!(i & 15)) + fprintf(stderr, "\n%04x:", i); + fprintf(stderr, " %02x", p->data[i]); + } + fprintf(stderr, "\n\n"); + } +#endif + + if (sz > ret) + sz = ret; + memcpy(&s->out_buf[s->out_ptr], p->data, sz); + s->out_ptr += sz; + + if (!s->rndis) { + if (ret < 64) { + qemu_send_packet(s->vc, s->out_buf, s->out_ptr); + s->out_ptr = 0; + } + return ret; + } + len = le32_to_cpu(msg->MessageLength); + if (s->out_ptr < 8 || s->out_ptr < len) + return ret; + if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) { + uint32_t offs = 8 + le32_to_cpu(msg->DataOffset); + uint32_t size = le32_to_cpu(msg->DataLength); + if (offs + size <= len) + qemu_send_packet(s->vc, s->out_buf + offs, size); + } + s->out_ptr -= len; + memmove(s->out_buf, &s->out_buf[len], s->out_ptr); + + return ret; +} + +static int usb_net_handle_data(USBDevice *dev, USBPacket *p) +{ + USBNetState *s = (USBNetState *) dev; + int ret = 0; + + switch(p->pid) { + case USB_TOKEN_IN: + switch (p->devep) { + case 1: + ret = usb_net_handle_statusin(s, p); + break; + + case 2: + ret = usb_net_handle_datain(s, p); + break; + + default: + goto fail; + } + break; + + case USB_TOKEN_OUT: + switch (p->devep) { + case 2: + ret = usb_net_handle_dataout(s, p); + break; + + default: + goto fail; + } + break; + + default: + fail: + ret = USB_RET_STALL; + break; + } + if (ret == USB_RET_STALL) + fprintf(stderr, "usbnet: failed data transaction: " + "pid 0x%x ep 0x%x len 0x%x\n", + p->pid, p->devep, p->len); + return ret; +} + +static void usbnet_receive(void *opaque, const uint8_t *buf, int size) +{ + USBNetState *s = opaque; + struct rndis_packet_msg_type *msg; + + if (s->rndis) { + msg = (struct rndis_packet_msg_type *) s->in_buf; + if (!s->rndis_state == RNDIS_DATA_INITIALIZED) + return; + if (size + sizeof(struct rndis_packet_msg_type) > sizeof(s->in_buf)) + return; + + memset(msg, 0, sizeof(struct rndis_packet_msg_type)); + msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG); + msg->MessageLength = cpu_to_le32(size + sizeof(struct rndis_packet_msg_type)); + msg->DataOffset = cpu_to_le32(sizeof(struct rndis_packet_msg_type) - 8); + msg->DataLength = cpu_to_le32(size); + /* msg->OOBDataOffset; + * msg->OOBDataLength; + * msg->NumOOBDataElements; + * msg->PerPacketInfoOffset; + * msg->PerPacketInfoLength; + * msg->VcHandle; + * msg->Reserved; + */ + memcpy(msg + 1, buf, size); + s->in_len = size + sizeof(struct rndis_packet_msg_type); + } else { + if (size > sizeof(s->in_buf)) + return; + memcpy(s->in_buf, buf, size); + s->in_len = size; + } + s->in_ptr = 0; +} + +static int usbnet_can_receive(void *opaque) +{ + USBNetState *s = opaque; + + if (s->rndis && !s->rndis_state == RNDIS_DATA_INITIALIZED) + return 1; + + return !s->in_len; +} + +static void usb_net_handle_destroy(USBDevice *dev) +{ + USBNetState *s = (USBNetState *) dev; + + /* TODO: remove the nd_table[] entry */ + qemu_del_vlan_client(s->vc); + rndis_clear_responsequeue(s); + qemu_free(s); +} + +USBDevice *usb_net_init(NICInfo *nd) +{ + USBNetState *s; + + s = qemu_mallocz(sizeof(USBNetState)); + if (!s) + return NULL; + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = usb_generic_handle_packet; + + s->dev.handle_reset = usb_net_handle_reset; + s->dev.handle_control = usb_net_handle_control; + s->dev.handle_data = usb_net_handle_data; + s->dev.handle_destroy = usb_net_handle_destroy; + + s->rndis = 1; + s->rndis_state = RNDIS_UNINITIALIZED; + s->medium = 0; /* NDIS_MEDIUM_802_3 */ + s->speed = 1000000; /* 100MBps, in 100Bps units */ + s->media_state = 0; /* NDIS_MEDIA_STATE_CONNECTED */; + s->filter = 0; + s->vendorid = 0x1234; + + memcpy(s->mac, nd->macaddr, 6); + TAILQ_INIT(&s->rndis_resp); + + pstrcpy(s->dev.devname, sizeof(s->dev.devname), + "QEMU USB Network Interface"); + s->vc = qemu_new_vlan_client(nd->vlan, + usbnet_receive, usbnet_can_receive, s); + + snprintf(s->usbstring_mac, sizeof(s->usbstring_mac), + "%02x%02x%02x%02x%02x%02x", + 0x40, s->mac[1], s->mac[2], + s->mac[3], s->mac[4], s->mac[5]); + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "usbnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + s->mac[0], s->mac[1], s->mac[2], + s->mac[3], s->mac[4], s->mac[5]); + fprintf(stderr, "usbnet: initialized mac %02x:%02x:%02x:%02x:%02x:%02x\n", + s->mac[0], s->mac[1], s->mac[2], + s->mac[3], s->mac[4], s->mac[5]); + + return (USBDevice *) s; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/usb-ohci.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/usb-ohci.c --- qemu-0.9.1/hw/usb-ohci.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/usb-ohci.c 2008-09-14 07:45:34.000000000 +0100 @@ -565,7 +565,7 @@ { int dir; size_t len = 0; - char *str = NULL; + const char *str = NULL; int pid; int ret; int i; @@ -800,7 +800,7 @@ { int dir; size_t len = 0; - char *str = NULL; + const char *str = NULL; int pid; int ret; int i; @@ -1598,7 +1598,7 @@ int i; if (usb_frame_time == 0) { -#if OHCI_TIME_WARP +#ifdef OHCI_TIME_WARP usb_frame_time = ticks_per_sec; usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ/1000); #else diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/usb-serial.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/usb-serial.c --- qemu-0.9.1/hw/usb-serial.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/usb-serial.c 2008-10-31 17:31:29.000000000 +0000 @@ -0,0 +1,586 @@ +/* + * FTDI FT232BM Device emulation + * + * Copyright (c) 2006 CodeSourcery. + * Copyright (c) 2008 Samuel Thibault + * Written by Paul Brook, reused for FTDI by Samuel Thibault + * + * This code is licenced under the LGPL. + */ + +#include "qemu-common.h" +#include "usb.h" +#include "qemu-char.h" + +//#define DEBUG_Serial + +#ifdef DEBUG_Serial +#define DPRINTF(fmt, args...) \ +do { printf("usb-serial: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#endif + +#define RECV_BUF 384 + +/* Commands */ +#define FTDI_RESET 0 +#define FTDI_SET_MDM_CTRL 1 +#define FTDI_SET_FLOW_CTRL 2 +#define FTDI_SET_BAUD 3 +#define FTDI_SET_DATA 4 +#define FTDI_GET_MDM_ST 5 +#define FTDI_SET_EVENT_CHR 6 +#define FTDI_SET_ERROR_CHR 7 +#define FTDI_SET_LATENCY 9 +#define FTDI_GET_LATENCY 10 + +#define DeviceOutVendor ((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8) +#define DeviceInVendor ((USB_DIR_IN |USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8) + +/* RESET */ + +#define FTDI_RESET_SIO 0 +#define FTDI_RESET_RX 1 +#define FTDI_RESET_TX 2 + +/* SET_MDM_CTRL */ + +#define FTDI_DTR 1 +#define FTDI_SET_DTR (FTDI_DTR << 8) +#define FTDI_RTS 2 +#define FTDI_SET_RTS (FTDI_RTS << 8) + +/* SET_FLOW_CTRL */ + +#define FTDI_RTS_CTS_HS 1 +#define FTDI_DTR_DSR_HS 2 +#define FTDI_XON_XOFF_HS 4 + +/* SET_DATA */ + +#define FTDI_PARITY (0x7 << 8) +#define FTDI_ODD (0x1 << 8) +#define FTDI_EVEN (0x2 << 8) +#define FTDI_MARK (0x3 << 8) +#define FTDI_SPACE (0x4 << 8) + +#define FTDI_STOP (0x3 << 11) +#define FTDI_STOP1 (0x0 << 11) +#define FTDI_STOP15 (0x1 << 11) +#define FTDI_STOP2 (0x2 << 11) + +/* GET_MDM_ST */ +/* TODO: should be sent every 40ms */ +#define FTDI_CTS (1<<4) // CTS line status +#define FTDI_DSR (1<<5) // DSR line status +#define FTDI_RI (1<<6) // RI line status +#define FTDI_RLSD (1<<7) // Receive Line Signal Detect + +/* Status */ + +#define FTDI_DR (1<<0) // Data Ready +#define FTDI_OE (1<<1) // Overrun Err +#define FTDI_PE (1<<2) // Parity Err +#define FTDI_FE (1<<3) // Framing Err +#define FTDI_BI (1<<4) // Break Interrupt +#define FTDI_THRE (1<<5) // Transmitter Holding Register +#define FTDI_TEMT (1<<6) // Transmitter Empty +#define FTDI_FIFO (1<<7) // Error in FIFO + +typedef struct { + USBDevice dev; + uint16_t vendorid; + uint16_t productid; + uint8_t recv_buf[RECV_BUF]; + uint16_t recv_ptr; + uint16_t recv_used; + uint8_t event_chr; + uint8_t error_chr; + uint8_t event_trigger; + QEMUSerialSetParams params; + int latency; /* ms */ + CharDriverState *cs; +} USBSerialState; + +static const uint8_t qemu_serial_dev_descriptor[] = { + 0x12, /* u8 bLength; */ + 0x01, /* u8 bDescriptorType; Device */ + 0x00, 0x02, /* u16 bcdUSB; v2.0 */ + + 0x00, /* u8 bDeviceClass; */ + 0x00, /* u8 bDeviceSubClass; */ + 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ + 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ + + /* Vendor and product id are arbitrary. */ + 0x03, 0x04, /* u16 idVendor; */ + 0x00, 0xFF, /* u16 idProduct; */ + 0x00, 0x04, /* u16 bcdDevice */ + + 0x01, /* u8 iManufacturer; */ + 0x02, /* u8 iProduct; */ + 0x03, /* u8 iSerialNumber; */ + 0x01 /* u8 bNumConfigurations; */ +}; + +static const uint8_t qemu_serial_config_descriptor[] = { + + /* one configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ + 0x20, 0x00, /* u16 wTotalLength; */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x00, /* u8 iConfiguration; */ + 0x80, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 100/2, /* u8 MaxPower; */ + + /* one interface */ + 0x09, /* u8 if_bLength; */ + 0x04, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x02, /* u8 if_bNumEndpoints; */ + 0xff, /* u8 if_bInterfaceClass; Vendor Specific */ + 0xff, /* u8 if_bInterfaceSubClass; Vendor Specific */ + 0xff, /* u8 if_bInterfaceProtocol; Vendor Specific */ + 0x02, /* u8 if_iInterface; */ + + /* Bulk-In endpoint */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x02, /* u8 ep_bmAttributes; Bulk */ + 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x00, /* u8 ep_bInterval; */ + + /* Bulk-Out endpoint */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x02, /* u8 ep_bEndpointAddress; OUT Endpoint 2 */ + 0x02, /* u8 ep_bmAttributes; Bulk */ + 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x00 /* u8 ep_bInterval; */ +}; + +static void usb_serial_reset(USBSerialState *s) +{ + /* TODO: Set flow control to none */ + s->event_chr = 0x0d; + s->event_trigger = 0; + s->recv_ptr = 0; + s->recv_used = 0; + /* TODO: purge in char driver */ +} + +static void usb_serial_handle_reset(USBDevice *dev) +{ + USBSerialState *s = (USBSerialState *)dev; + + DPRINTF("Reset\n"); + + usb_serial_reset(s); + /* TODO: Reset char device, send BREAK? */ +} + +static uint8_t usb_get_modem_lines(USBSerialState *s) +{ + int flags; + uint8_t ret; + + if (qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) + return FTDI_CTS|FTDI_DSR|FTDI_RLSD; + + ret = 0; + if (flags & CHR_TIOCM_CTS) + ret |= FTDI_CTS; + if (flags & CHR_TIOCM_DSR) + ret |= FTDI_DSR; + if (flags & CHR_TIOCM_RI) + ret |= FTDI_RI; + if (flags & CHR_TIOCM_CAR) + ret |= FTDI_RLSD; + + return ret; +} + +static int usb_serial_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + USBSerialState *s = (USBSerialState *)dev; + int ret = 0; + + //DPRINTF("got control %x, value %x\n",request, value); + switch (request) { + case DeviceRequest | USB_REQ_GET_STATUS: + data[0] = (0 << USB_DEVICE_SELF_POWERED) | + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[1] = 0x00; + ret = 2; + break; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case USB_DT_DEVICE: + memcpy(data, qemu_serial_dev_descriptor, + sizeof(qemu_serial_dev_descriptor)); + data[8] = s->vendorid & 0xff; + data[9] = ((s->vendorid) >> 8) & 0xff; + data[10] = s->productid & 0xff; + data[11] = ((s->productid) >> 8) & 0xff; + ret = sizeof(qemu_serial_dev_descriptor); + break; + case USB_DT_CONFIG: + memcpy(data, qemu_serial_config_descriptor, + sizeof(qemu_serial_config_descriptor)); + ret = sizeof(qemu_serial_config_descriptor); + break; + case USB_DT_STRING: + switch(value & 0xff) { + case 0: + /* language ids */ + data[0] = 4; + data[1] = 3; + data[2] = 0x09; + data[3] = 0x04; + ret = 4; + break; + case 1: + /* vendor description */ + ret = set_usb_string(data, "QEMU " QEMU_VERSION); + break; + case 2: + /* product description */ + ret = set_usb_string(data, "QEMU USB SERIAL"); + break; + case 3: + /* serial number */ + ret = set_usb_string(data, "1"); + break; + default: + goto fail; + } + break; + default: + goto fail; + } + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = 1; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + data[0] = 0; + ret = 1; + break; + case InterfaceOutRequest | USB_REQ_SET_INTERFACE: + ret = 0; + break; + case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: + ret = 0; + break; + + /* Class specific requests. */ + case DeviceOutVendor | FTDI_RESET: + switch (value) { + case FTDI_RESET_SIO: + usb_serial_reset(s); + break; + case FTDI_RESET_RX: + s->recv_ptr = 0; + s->recv_used = 0; + /* TODO: purge from char device */ + break; + case FTDI_RESET_TX: + /* TODO: purge from char device */ + break; + } + break; + case DeviceOutVendor | FTDI_SET_MDM_CTRL: + { + static int flags; + qemu_chr_ioctl(s->cs,CHR_IOCTL_SERIAL_GET_TIOCM, &flags); + if (value & FTDI_SET_RTS) { + if (value & FTDI_RTS) + flags |= CHR_TIOCM_RTS; + else + flags &= ~CHR_TIOCM_RTS; + } + if (value & FTDI_SET_DTR) { + if (value & FTDI_DTR) + flags |= CHR_TIOCM_DTR; + else + flags &= ~CHR_TIOCM_DTR; + } + qemu_chr_ioctl(s->cs,CHR_IOCTL_SERIAL_SET_TIOCM, &flags); + break; + } + case DeviceOutVendor | FTDI_SET_FLOW_CTRL: + /* TODO: ioctl */ + break; + case DeviceOutVendor | FTDI_SET_BAUD: { + static const int subdivisors8[8] = { 0, 4, 2, 1, 3, 5, 6, 7 }; + int subdivisor8 = subdivisors8[((value & 0xc000) >> 14) + | ((index & 1) << 2)]; + int divisor = value & 0x3fff; + + /* chip special cases */ + if (divisor == 1 && subdivisor8 == 0) + subdivisor8 = 4; + if (divisor == 0 && subdivisor8 == 0) + divisor = 1; + + s->params.speed = (48000000 / 2) / (8 * divisor + subdivisor8); + qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params); + break; + } + case DeviceOutVendor | FTDI_SET_DATA: + switch (value & FTDI_PARITY) { + case 0: + s->params.parity = 'N'; + break; + case FTDI_ODD: + s->params.parity = 'O'; + break; + case FTDI_EVEN: + s->params.parity = 'E'; + break; + default: + DPRINTF("unsupported parity %d\n", value & FTDI_PARITY); + goto fail; + } + switch (value & FTDI_STOP) { + case FTDI_STOP1: + s->params.stop_bits = 1; + break; + case FTDI_STOP2: + s->params.stop_bits = 2; + break; + default: + DPRINTF("unsupported stop bits %d\n", value & FTDI_STOP); + goto fail; + } + qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params); + /* TODO: TX ON/OFF */ + break; + case DeviceInVendor | FTDI_GET_MDM_ST: + data[0] = usb_get_modem_lines(s) | 1; + data[1] = 0; + ret = 2; + break; + case DeviceOutVendor | FTDI_SET_EVENT_CHR: + /* TODO: handle it */ + s->event_chr = value; + break; + case DeviceOutVendor | FTDI_SET_ERROR_CHR: + /* TODO: handle it */ + s->error_chr = value; + break; + case DeviceOutVendor | FTDI_SET_LATENCY: + s->latency = value; + break; + case DeviceInVendor | FTDI_GET_LATENCY: + data[0] = s->latency; + ret = 1; + break; + default: + fail: + DPRINTF("got unsupported/bogus control %x, value %x\n", request, value); + ret = USB_RET_STALL; + break; + } + return ret; +} + +static int usb_serial_handle_data(USBDevice *dev, USBPacket *p) +{ + USBSerialState *s = (USBSerialState *)dev; + int ret = 0; + uint8_t devep = p->devep; + uint8_t *data = p->data; + int len = p->len; + int first_len; + + switch (p->pid) { + case USB_TOKEN_OUT: + if (devep != 2) + goto fail; + qemu_chr_write(s->cs, data, len); + break; + + case USB_TOKEN_IN: + if (devep != 1) + goto fail; + first_len = RECV_BUF - s->recv_ptr; + if (len <= 2) { + ret = USB_RET_NAK; + break; + } + *data++ = usb_get_modem_lines(s) | 1; + /* We do not have the uart details */ + *data++ = 0; + len -= 2; + if (len > s->recv_used) + len = s->recv_used; + if (!len) { + ret = USB_RET_NAK; + break; + } + if (first_len > len) + first_len = len; + memcpy(data, s->recv_buf + s->recv_ptr, first_len); + if (len > first_len) + memcpy(data + first_len, s->recv_buf, len - first_len); + s->recv_used -= len; + s->recv_ptr = (s->recv_ptr + len) % RECV_BUF; + ret = len + 2; + break; + + default: + DPRINTF("Bad token\n"); + fail: + ret = USB_RET_STALL; + break; + } + + return ret; +} + +static void usb_serial_handle_destroy(USBDevice *dev) +{ + USBSerialState *s = (USBSerialState *)dev; + + qemu_chr_close(s->cs); + qemu_free(s); +} + +static int usb_serial_can_read(void *opaque) +{ + USBSerialState *s = opaque; + return RECV_BUF - s->recv_used; +} + +static void usb_serial_read(void *opaque, const uint8_t *buf, int size) +{ + USBSerialState *s = opaque; + int first_size = RECV_BUF - s->recv_ptr; + if (first_size > size) + first_size = size; + memcpy(s->recv_buf + s->recv_ptr + s->recv_used, buf, first_size); + if (size > first_size) + memcpy(s->recv_buf, buf + first_size, size - first_size); + s->recv_used += size; +} + +static void usb_serial_event(void *opaque, int event) +{ + USBSerialState *s = opaque; + + switch (event) { + case CHR_EVENT_BREAK: + /* TODO: Send Break to USB */ + break; + case CHR_EVENT_FOCUS: + break; + case CHR_EVENT_RESET: + usb_serial_reset(s); + /* TODO: Reset USB port */ + break; + } +} + +USBDevice *usb_serial_init(const char *filename) +{ + USBSerialState *s; + CharDriverState *cdrv; + unsigned short vendorid = 0x0403, productid = 0x6001; + char label[32]; + static int index; + + while (*filename && *filename != ':') { + const char *p; + char *e; + if (strstart(filename, "vendorid=", &p)) { + vendorid = strtol(p, &e, 16); + if (e == p || (*e && *e != ',' && *e != ':')) { + printf("bogus vendor ID %s\n", p); + return NULL; + } + filename = e; + } else if (strstart(filename, "productid=", &p)) { + productid = strtol(p, &e, 16); + if (e == p || (*e && *e != ',' && *e != ':')) { + printf("bogus product ID %s\n", p); + return NULL; + } + filename = e; + } else { + printf("unrecognized serial USB option %s\n", filename); + return NULL; + } + while(*filename == ',') + filename++; + } + if (!*filename) { + printf("character device specification needed\n"); + return NULL; + } + filename++; + s = qemu_mallocz(sizeof(USBSerialState)); + if (!s) + return NULL; + + snprintf(label, sizeof(label), "usbserial%d", index++); + cdrv = qemu_chr_open(label, filename); + if (!cdrv) + goto fail; + s->cs = cdrv; + qemu_chr_add_handlers(cdrv, usb_serial_can_read, usb_serial_read, usb_serial_event, s); + + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = usb_generic_handle_packet; + + s->dev.handle_reset = usb_serial_handle_reset; + s->dev.handle_control = usb_serial_handle_control; + s->dev.handle_data = usb_serial_handle_data; + s->dev.handle_destroy = usb_serial_handle_destroy; + + s->vendorid = vendorid; + s->productid = productid; + + snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Serial(%.16s)", + filename); + + usb_serial_handle_reset((USBDevice *)s); + return (USBDevice *)s; + fail: + qemu_free(s); + return NULL; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/usb-uhci.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/usb-uhci.c --- qemu-0.9.1/hw/usb-uhci.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/usb-uhci.c 2008-09-11 20:42:00.000000000 +0100 @@ -3,6 +3,10 @@ * * Copyright (c) 2005 Fabrice Bellard * + * Copyright (c) 2008 Max Krasnyansky + * Magor rewrite of the UHCI data structures parser and frame processor + * Support for fully async operation and multiple outstanding transactions + * * 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 @@ -27,8 +31,7 @@ #include "qemu-timer.h" //#define DEBUG -//#define DEBUG_PACKET -//#define DEBUG_ISOCH +//#define DEBUG_DUMP_DATA #define UHCI_CMD_FGR (1 << 4) #define UHCI_CMD_EGSM (1 << 3) @@ -66,6 +69,52 @@ #define NB_PORTS 2 +#ifdef DEBUG +#define dprintf printf + +const char *pid2str(int pid) +{ + switch (pid) { + case USB_TOKEN_SETUP: return "SETUP"; + case USB_TOKEN_IN: return "IN"; + case USB_TOKEN_OUT: return "OUT"; + } + return "?"; +} + +#else +#define dprintf(...) +#endif + +#ifdef DEBUG_DUMP_DATA +static void dump_data(const uint8_t *data, int len) +{ + int i; + + printf("uhci: data: "); + for(i = 0; i < len; i++) + printf(" %02x", data[i]); + printf("\n"); +} +#else +static void dump_data(const uint8_t *data, int len) {} +#endif + +/* + * Pending async transaction. + * 'packet' must be the first field because completion + * handler does "(UHCIAsync *) pkt" cast. + */ +typedef struct UHCIAsync { + USBPacket packet; + struct UHCIAsync *next; + uint32_t td; + uint32_t token; + int8_t valid; + uint8_t done; + uint8_t buffer[2048]; +} UHCIAsync; + typedef struct UHCIPort { USBPort port; uint16_t ctrl; @@ -85,16 +134,10 @@ /* Interrupts that should be raised at the end of the current frame. */ uint32_t pending_int_mask; - /* For simplicity of implementation we only allow a single pending USB - request. This means all usb traffic on this controller is effectively - suspended until that transfer completes. When the transfer completes - the next transfer from that queue will be processed. However - other queues will not be processed until the next frame. The solution - is to allow multiple pending requests. */ - uint32_t async_qh; - uint32_t async_frame_addr; - USBPacket usb_packet; - uint8_t usb_buf[2048]; + + /* Active packets */ + UHCIAsync *async_pending; + UHCIAsync *async_pool; } UHCIState; typedef struct UHCI_TD { @@ -109,6 +152,156 @@ uint32_t el_link; } UHCI_QH; +static UHCIAsync *uhci_async_alloc(UHCIState *s) +{ + UHCIAsync *async = qemu_malloc(sizeof(UHCIAsync)); + if (async) { + memset(&async->packet, 0, sizeof(async->packet)); + async->valid = 0; + async->td = 0; + async->token = 0; + async->done = 0; + async->next = NULL; + } + + return async; +} + +static void uhci_async_free(UHCIState *s, UHCIAsync *async) +{ + qemu_free(async); +} + +static void uhci_async_link(UHCIState *s, UHCIAsync *async) +{ + async->next = s->async_pending; + s->async_pending = async; +} + +static void uhci_async_unlink(UHCIState *s, UHCIAsync *async) +{ + UHCIAsync *curr = s->async_pending; + UHCIAsync **prev = &s->async_pending; + + while (curr) { + if (curr == async) { + *prev = curr->next; + return; + } + + prev = &curr->next; + curr = curr->next; + } +} + +static void uhci_async_cancel(UHCIState *s, UHCIAsync *async) +{ + dprintf("uhci: cancel td 0x%x token 0x%x done %u\n", + async->td, async->token, async->done); + + if (!async->done) + usb_cancel_packet(&async->packet); + uhci_async_free(s, async); +} + +/* + * Mark all outstanding async packets as invalid. + * This is used for canceling them when TDs are removed by the HCD. + */ +static UHCIAsync *uhci_async_validate_begin(UHCIState *s) +{ + UHCIAsync *async = s->async_pending; + + while (async) { + async->valid--; + async = async->next; + } + return NULL; +} + +/* + * Cancel async packets that are no longer valid + */ +static void uhci_async_validate_end(UHCIState *s) +{ + UHCIAsync *curr = s->async_pending; + UHCIAsync **prev = &s->async_pending; + UHCIAsync *next; + + while (curr) { + if (curr->valid > 0) { + prev = &curr->next; + curr = curr->next; + continue; + } + + next = curr->next; + + /* Unlink */ + *prev = next; + + uhci_async_cancel(s, curr); + + curr = next; + } +} + +static void uhci_async_cancel_all(UHCIState *s) +{ + UHCIAsync *curr = s->async_pending; + UHCIAsync *next; + + while (curr) { + next = curr->next; + + uhci_async_cancel(s, curr); + + curr = next; + } + + s->async_pending = NULL; +} + +static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, uint32_t token) +{ + UHCIAsync *async = s->async_pending; + UHCIAsync *match = NULL; + int count = 0; + + /* + * We're looking for the best match here. ie both td addr and token. + * Otherwise we return last good match. ie just token. + * It's ok to match just token because it identifies the transaction + * rather well, token includes: device addr, endpoint, size, etc. + * + * Also since we queue async transactions in reverse order by returning + * last good match we restores the order. + * + * It's expected that we wont have a ton of outstanding transactions. + * If we ever do we'd want to optimize this algorithm. + */ + + while (async) { + if (async->token == token) { + /* Good match */ + match = async; + + if (async->td == addr) { + /* Best match */ + break; + } + } + + async = async->next; + count++; + } + + if (count > 64) + fprintf(stderr, "uhci: warning lots of async transactions\n"); + + return match; +} + static void uhci_attach(USBPort *port1, USBDevice *dev); static void uhci_update_irq(UHCIState *s) @@ -133,6 +326,8 @@ int i; UHCIPort *port; + dprintf("uhci: full reset\n"); + pci_conf = s->dev.config; pci_conf[0x6a] = 0x01; /* usb clock */ @@ -143,21 +338,25 @@ s->intr = 0; s->fl_base_addr = 0; s->sof_timing = 64; + for(i = 0; i < NB_PORTS; i++) { port = &s->ports[i]; port->ctrl = 0x0080; if (port->port.dev) uhci_attach(&port->port, port->port.dev); } + + uhci_async_cancel_all(s); } -#if 0 static void uhci_save(QEMUFile *f, void *opaque) { UHCIState *s = opaque; uint8_t num_ports = NB_PORTS; int i; + uhci_async_cancel_all(s); + pci_device_save(&s->dev, f); qemu_put_8s(f, &num_ports); @@ -203,7 +402,6 @@ return 0; } -#endif static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) { @@ -239,9 +437,8 @@ UHCIState *s = opaque; addr &= 0x1f; -#ifdef DEBUG - printf("uhci writew port=0x%04x val=0x%04x\n", addr, val); -#endif + dprintf("uhci: writew port=0x%04x val=0x%04x\n", addr, val); + switch(addr) { case 0x00: if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) { @@ -350,9 +547,9 @@ val = 0xff7f; /* disabled port */ break; } -#ifdef DEBUG - printf("uhci readw port=0x%04x val=0x%04x\n", addr, val); -#endif + + dprintf("uhci: readw port=0x%04x val=0x%04x\n", addr, val); + return val; } @@ -361,9 +558,8 @@ UHCIState *s = opaque; addr &= 0x1f; -#ifdef DEBUG - printf("uhci writel port=0x%04x val=0x%08x\n", addr, val); -#endif + dprintf("uhci: writel port=0x%04x val=0x%08x\n", addr, val); + switch(addr) { case 0x08: s->fl_base_addr = val & ~0xfff; @@ -451,417 +647,409 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p) { - UHCIPort *port; - USBDevice *dev; int i, ret; -#ifdef DEBUG_PACKET - { - const char *pidstr; - switch(p->pid) { - case USB_TOKEN_SETUP: pidstr = "SETUP"; break; - case USB_TOKEN_IN: pidstr = "IN"; break; - case USB_TOKEN_OUT: pidstr = "OUT"; break; - default: pidstr = "?"; break; - } - printf("frame %d: pid=%s addr=0x%02x ep=%d len=%d\n", - s->frnum, pidstr, p->devaddr, p->devep, p->len); - if (p->pid != USB_TOKEN_IN) { - printf(" data_out="); - for(i = 0; i < p->len; i++) { - printf(" %02x", p->data[i]); - } - printf("\n"); - } - } -#endif - for(i = 0; i < NB_PORTS; i++) { - port = &s->ports[i]; - dev = port->port.dev; - if (dev && (port->ctrl & UHCI_PORT_EN)) { + dprintf("uhci: packet enter. pid %s addr 0x%02x ep %d len %d\n", + pid2str(p->pid), p->devaddr, p->devep, p->len); + if (p->pid == USB_TOKEN_OUT || p->pid == USB_TOKEN_SETUP) + dump_data(p->data, p->len); + + ret = USB_RET_NODEV; + for (i = 0; i < NB_PORTS && ret == USB_RET_NODEV; i++) { + UHCIPort *port = &s->ports[i]; + USBDevice *dev = port->port.dev; + + if (dev && (port->ctrl & UHCI_PORT_EN)) ret = dev->handle_packet(dev, p); - if (ret != USB_RET_NODEV) { -#ifdef DEBUG_PACKET - if (ret == USB_RET_ASYNC) { - printf("usb-uhci: Async packet\n"); - } else { - printf(" ret=%d ", ret); - if (p->pid == USB_TOKEN_IN && ret > 0) { - printf("data_in="); - for(i = 0; i < ret; i++) { - printf(" %02x", p->data[i]); - } - } - printf("\n"); - } -#endif - return ret; - } - } } - return USB_RET_NODEV; + + dprintf("uhci: packet exit. ret %d len %d\n", ret, p->len); + if (p->pid == USB_TOKEN_IN && ret > 0) + dump_data(p->data, ret); + + return ret; } -static void uhci_async_complete_packet(USBPacket * packet, void *opaque); +static void uhci_async_complete(USBPacket * packet, void *opaque); +static void uhci_process_frame(UHCIState *s); /* return -1 if fatal error (frame must be stopped) 0 if TD successful 1 if TD unsuccessful or inactive */ -static int uhci_handle_td(UHCIState *s, UHCI_TD *td, uint32_t *int_mask, - int completion) +static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_t *int_mask) { + int len = 0, max_len, err, ret; uint8_t pid; - int len = 0, max_len, err, ret = 0; - /* ??? This is wrong for async completion. */ - if (td->ctrl & TD_CTRL_IOC) { + max_len = ((td->token >> 21) + 1) & 0x7ff; + pid = td->token & 0xff; + + ret = async->packet.len; + + if (td->ctrl & TD_CTRL_IOC) *int_mask |= 0x01; - } - if (!(td->ctrl & TD_CTRL_ACTIVE)) - return 1; + if (td->ctrl & TD_CTRL_IOS) + td->ctrl &= ~TD_CTRL_ACTIVE; - /* TD is active */ - max_len = ((td->token >> 21) + 1) & 0x7ff; - pid = td->token & 0xff; + if (ret < 0) + goto out; - if (completion && (s->async_qh || s->async_frame_addr)) { - ret = s->usb_packet.len; - if (ret >= 0) { - len = ret; - if (len > max_len) { - len = max_len; - ret = USB_RET_BABBLE; - } - if (len > 0) { - /* write the data back */ - cpu_physical_memory_write(td->buffer, s->usb_buf, len); - } - } else { - len = 0; - } - s->async_qh = 0; - s->async_frame_addr = 0; - } else if (!completion) { - s->usb_packet.pid = pid; - s->usb_packet.devaddr = (td->token >> 8) & 0x7f; - s->usb_packet.devep = (td->token >> 15) & 0xf; - s->usb_packet.data = s->usb_buf; - s->usb_packet.len = max_len; - s->usb_packet.complete_cb = uhci_async_complete_packet; - s->usb_packet.complete_opaque = s; - switch(pid) { - case USB_TOKEN_OUT: - case USB_TOKEN_SETUP: - cpu_physical_memory_read(td->buffer, s->usb_buf, max_len); - ret = uhci_broadcast_packet(s, &s->usb_packet); + len = async->packet.len; + td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff); + + /* The NAK bit may have been set by a previous frame, so clear it + here. The docs are somewhat unclear, but win2k relies on this + behavior. */ + td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK); + + if (pid == USB_TOKEN_IN) { + if (len > max_len) { len = max_len; - break; - case USB_TOKEN_IN: - ret = uhci_broadcast_packet(s, &s->usb_packet); - if (ret >= 0) { - len = ret; - if (len > max_len) { - len = max_len; - ret = USB_RET_BABBLE; - } - if (len > 0) { - /* write the data back */ - cpu_physical_memory_write(td->buffer, s->usb_buf, len); - } - } else { - len = 0; - } - break; - default: - /* invalid pid : frame interrupted */ - s->status |= UHCI_STS_HCPERR; - uhci_update_irq(s); - return -1; + ret = USB_RET_BABBLE; + goto out; } - } - if (ret == USB_RET_ASYNC) { - return 2; - } - if (td->ctrl & TD_CTRL_IOS) - td->ctrl &= ~TD_CTRL_ACTIVE; - if (ret >= 0) { - td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff); - /* The NAK bit may have been set by a previous frame, so clear it - here. The docs are somewhat unclear, but win2k relies on this - behavior. */ - td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK); - if (pid == USB_TOKEN_IN && - (td->ctrl & TD_CTRL_SPD) && - len < max_len) { + if (len > 0) { + /* write the data back */ + cpu_physical_memory_write(td->buffer, async->buffer, len); + } + + if ((td->ctrl & TD_CTRL_SPD) && len < max_len) { *int_mask |= 0x02; /* short packet: do not update QH */ + dprintf("uhci: short packet. td 0x%x token 0x%x\n", async->td, async->token); return 1; - } else { - /* success */ - return 0; } - } else { - switch(ret) { - default: - case USB_RET_NODEV: - do_timeout: - td->ctrl |= TD_CTRL_TIMEOUT; - err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3; - if (err != 0) { - err--; - if (err == 0) { - td->ctrl &= ~TD_CTRL_ACTIVE; - s->status |= UHCI_STS_USBERR; - uhci_update_irq(s); - } - } - td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) | - (err << TD_CTRL_ERROR_SHIFT); - return 1; - case USB_RET_NAK: - td->ctrl |= TD_CTRL_NAK; - if (pid == USB_TOKEN_SETUP) - goto do_timeout; - return 1; - case USB_RET_STALL: - td->ctrl |= TD_CTRL_STALL; - td->ctrl &= ~TD_CTRL_ACTIVE; - return 1; - case USB_RET_BABBLE: - td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL; + } + + /* success */ + return 0; + +out: + switch(ret) { + case USB_RET_STALL: + td->ctrl |= TD_CTRL_STALL; + td->ctrl &= ~TD_CTRL_ACTIVE; + return 1; + + case USB_RET_BABBLE: + td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL; + td->ctrl &= ~TD_CTRL_ACTIVE; + /* frame interrupted */ + return -1; + + case USB_RET_NAK: + td->ctrl |= TD_CTRL_NAK; + if (pid == USB_TOKEN_SETUP) + break; + return 1; + + case USB_RET_NODEV: + default: + break; + } + + /* Retry the TD if error count is not zero */ + + td->ctrl |= TD_CTRL_TIMEOUT; + err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3; + if (err != 0) { + err--; + if (err == 0) { td->ctrl &= ~TD_CTRL_ACTIVE; - /* frame interrupted */ - return -1; + s->status |= UHCI_STS_USBERR; + uhci_update_irq(s); } } + td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) | + (err << TD_CTRL_ERROR_SHIFT); + return 1; } -static void uhci_async_complete_packet(USBPacket * packet, void *opaque) +static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *int_mask) +{ + UHCIAsync *async; + int len = 0, max_len; + uint8_t pid; + + /* Is active ? */ + if (!(td->ctrl & TD_CTRL_ACTIVE)) + return 1; + + async = uhci_async_find_td(s, addr, td->token); + if (async) { + /* Already submitted */ + async->valid = 32; + + if (!async->done) + return 1; + + uhci_async_unlink(s, async); + goto done; + } + + /* Allocate new packet */ + async = uhci_async_alloc(s); + if (!async) + return 1; + + async->valid = 10; + async->td = addr; + async->token = td->token; + + max_len = ((td->token >> 21) + 1) & 0x7ff; + pid = td->token & 0xff; + + async->packet.pid = pid; + async->packet.devaddr = (td->token >> 8) & 0x7f; + async->packet.devep = (td->token >> 15) & 0xf; + async->packet.data = async->buffer; + async->packet.len = max_len; + async->packet.complete_cb = uhci_async_complete; + async->packet.complete_opaque = s; + + switch(pid) { + case USB_TOKEN_OUT: + case USB_TOKEN_SETUP: + cpu_physical_memory_read(td->buffer, async->buffer, max_len); + len = uhci_broadcast_packet(s, &async->packet); + if (len >= 0) + len = max_len; + break; + + case USB_TOKEN_IN: + len = uhci_broadcast_packet(s, &async->packet); + break; + + default: + /* invalid pid : frame interrupted */ + uhci_async_free(s, async); + s->status |= UHCI_STS_HCPERR; + uhci_update_irq(s); + return -1; + } + + if (len == USB_RET_ASYNC) { + uhci_async_link(s, async); + return 2; + } + + async->packet.len = len; + +done: + len = uhci_complete_td(s, td, async, int_mask); + uhci_async_free(s, async); + return len; +} + +static void uhci_async_complete(USBPacket *packet, void *opaque) { UHCIState *s = opaque; - UHCI_QH qh; + UHCIAsync *async = (UHCIAsync *) packet; + + dprintf("uhci: async complete. td 0x%x token 0x%x\n", async->td, async->token); + + async->done = 1; + + uhci_process_frame(s); +} + +static int is_valid(uint32_t link) +{ + return (link & 1) == 0; +} + +static int is_qh(uint32_t link) +{ + return (link & 2) != 0; +} + +static int depth_first(uint32_t link) +{ + return (link & 4) != 0; +} + +/* QH DB used for detecting QH loops */ +#define UHCI_MAX_QUEUES 128 +typedef struct { + uint32_t addr[UHCI_MAX_QUEUES]; + int count; +} QhDb; + +static void qhdb_reset(QhDb *db) +{ + db->count = 0; +} + +/* Add QH to DB. Returns 1 if already present or DB is full. */ +static int qhdb_insert(QhDb *db, uint32_t addr) +{ + int i; + for (i = 0; i < db->count; i++) + if (db->addr[i] == addr) + return 1; + + if (db->count >= UHCI_MAX_QUEUES) + return 1; + + db->addr[db->count++] = addr; + return 0; +} + +static void uhci_process_frame(UHCIState *s) +{ + uint32_t frame_addr, link, old_td_ctrl, val, int_mask; + uint32_t curr_qh; + int cnt, ret; UHCI_TD td; - uint32_t link; - uint32_t old_td_ctrl; - uint32_t val; - uint32_t frame_addr; - int ret; + UHCI_QH qh; + QhDb qhdb; + + frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2); + + dprintf("uhci: processing frame %d addr 0x%x\n" , s->frnum, frame_addr); + + cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4); + le32_to_cpus(&link); + + int_mask = 0; + curr_qh = 0; + + qhdb_reset(&qhdb); + + for (cnt = FRAME_MAX_LOOPS; is_valid(link) && cnt; cnt--) { + if (is_qh(link)) { + /* QH */ + + if (qhdb_insert(&qhdb, link)) { + /* + * We're going in circles. Which is not a bug because + * HCD is allowed to do that as part of the BW management. + * In our case though it makes no sense to spin here. Sync transations + * are already done, and async completion handler will re-process + * the frame when something is ready. + */ + dprintf("uhci: detected loop. qh 0x%x\n", link); + break; + } + + cpu_physical_memory_read(link & ~0xf, (uint8_t *) &qh, sizeof(qh)); + le32_to_cpus(&qh.link); + le32_to_cpus(&qh.el_link); + + dprintf("uhci: QH 0x%x load. link 0x%x elink 0x%x\n", + link, qh.link, qh.el_link); - /* Handle async isochronous packet completion */ - frame_addr = s->async_frame_addr; - if (frame_addr) { - cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4); - le32_to_cpus(&link); + if (!is_valid(qh.el_link)) { + /* QH w/o elements */ + curr_qh = 0; + link = qh.link; + } else { + /* QH with elements */ + curr_qh = link; + link = qh.el_link; + } + continue; + } - cpu_physical_memory_read(link & ~0xf, (uint8_t *)&td, sizeof(td)); + /* TD */ + cpu_physical_memory_read(link & ~0xf, (uint8_t *) &td, sizeof(td)); le32_to_cpus(&td.link); le32_to_cpus(&td.ctrl); le32_to_cpus(&td.token); le32_to_cpus(&td.buffer); - old_td_ctrl = td.ctrl; - ret = uhci_handle_td(s, &td, &s->pending_int_mask, 1); - /* update the status bits of the TD */ + dprintf("uhci: TD 0x%x load. link 0x%x ctrl 0x%x token 0x%x qh 0x%x\n", + link, td.link, td.ctrl, td.token, curr_qh); + + old_td_ctrl = td.ctrl; + ret = uhci_handle_td(s, link, &td, &int_mask); if (old_td_ctrl != td.ctrl) { + /* update the status bits of the TD */ val = cpu_to_le32(td.ctrl); cpu_physical_memory_write((link & ~0xf) + 4, - (const uint8_t *)&val, - sizeof(val)); + (const uint8_t *)&val, sizeof(val)); } - if (ret == 2) { - s->async_frame_addr = frame_addr; - } else if (ret == 0) { - /* update qh element link */ - val = cpu_to_le32(td.link); - cpu_physical_memory_write(frame_addr, - (const uint8_t *)&val, - sizeof(val)); + + if (ret < 0) { + /* interrupted frame */ + break; } - return; - } - link = s->async_qh; - if (!link) { - /* This should never happen. It means a TD somehow got removed - without cancelling the associated async IO request. */ - return; - } - cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh)); - le32_to_cpus(&qh.link); - le32_to_cpus(&qh.el_link); - /* Re-process the queue containing the async packet. */ - while (1) { - cpu_physical_memory_read(qh.el_link & ~0xf, - (uint8_t *)&td, sizeof(td)); - le32_to_cpus(&td.link); - le32_to_cpus(&td.ctrl); - le32_to_cpus(&td.token); - le32_to_cpus(&td.buffer); - old_td_ctrl = td.ctrl; - ret = uhci_handle_td(s, &td, &s->pending_int_mask, 1); + if (ret == 2 || ret == 1) { + dprintf("uhci: TD 0x%x %s. link 0x%x ctrl 0x%x token 0x%x qh 0x%x\n", + link, ret == 2 ? "pend" : "skip", + td.link, td.ctrl, td.token, curr_qh); - /* update the status bits of the TD */ - if (old_td_ctrl != td.ctrl) { - val = cpu_to_le32(td.ctrl); - cpu_physical_memory_write((qh.el_link & ~0xf) + 4, - (const uint8_t *)&val, - sizeof(val)); - } - if (ret < 0) - break; /* interrupted frame */ - if (ret == 2) { - s->async_qh = link; - break; - } else if (ret == 0) { - /* update qh element link */ - qh.el_link = td.link; + link = curr_qh ? qh.link : td.link; + continue; + } + + /* completed TD */ + + dprintf("uhci: TD 0x%x done. link 0x%x ctrl 0x%x token 0x%x qh 0x%x\n", + link, td.link, td.ctrl, td.token, curr_qh); + + link = td.link; + + if (curr_qh) { + /* update QH element link */ + qh.el_link = link; val = cpu_to_le32(qh.el_link); - cpu_physical_memory_write((link & ~0xf) + 4, - (const uint8_t *)&val, - sizeof(val)); - if (!(qh.el_link & 4)) - break; + cpu_physical_memory_write((curr_qh & ~0xf) + 4, + (const uint8_t *)&val, sizeof(val)); + + if (!depth_first(link)) { + /* done with this QH */ + + dprintf("uhci: QH 0x%x done. link 0x%x elink 0x%x\n", + curr_qh, qh.link, qh.el_link); + + curr_qh = 0; + link = qh.link; + } } - break; + + /* go to the next entry */ } + + s->pending_int_mask = int_mask; } static void uhci_frame_timer(void *opaque) { UHCIState *s = opaque; int64_t expire_time; - uint32_t frame_addr, link, old_td_ctrl, val, int_mask; - int cnt, ret; - UHCI_TD td; - UHCI_QH qh; - uint32_t old_async_qh; if (!(s->cmd & UHCI_CMD_RS)) { + /* Full stop */ qemu_del_timer(s->frame_timer); /* set hchalted bit in status - UHCI11D 2.1.2 */ s->status |= UHCI_STS_HCHALTED; + + dprintf("uhci: halted\n"); return; } - /* Complete the previous frame. */ - s->frnum = (s->frnum + 1) & 0x7ff; + + /* Complete the previous frame */ if (s->pending_int_mask) { s->status2 |= s->pending_int_mask; - s->status |= UHCI_STS_USBINT; + s->status |= UHCI_STS_USBINT; uhci_update_irq(s); } - old_async_qh = s->async_qh; - frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2); - cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4); - le32_to_cpus(&link); - int_mask = 0; - cnt = FRAME_MAX_LOOPS; - while ((link & 1) == 0) { - if (--cnt == 0) - break; - /* valid frame */ - if (link & 2) { - /* QH */ - if (link == s->async_qh) { - /* We've found a previously issues packet. - Nothing else to do. */ - old_async_qh = 0; - break; - } - cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh)); - le32_to_cpus(&qh.link); - le32_to_cpus(&qh.el_link); - depth_first: - if (qh.el_link & 1) { - /* no element : go to next entry */ - link = qh.link; - } else if (qh.el_link & 2) { - /* QH */ - link = qh.el_link; - } else if (s->async_qh) { - /* We can only cope with one pending packet. Keep looking - for the previously issued packet. */ - link = qh.link; - } else { - /* TD */ - if (--cnt == 0) - break; - cpu_physical_memory_read(qh.el_link & ~0xf, - (uint8_t *)&td, sizeof(td)); - le32_to_cpus(&td.link); - le32_to_cpus(&td.ctrl); - le32_to_cpus(&td.token); - le32_to_cpus(&td.buffer); - old_td_ctrl = td.ctrl; - ret = uhci_handle_td(s, &td, &int_mask, 0); - - /* update the status bits of the TD */ - if (old_td_ctrl != td.ctrl) { - val = cpu_to_le32(td.ctrl); - cpu_physical_memory_write((qh.el_link & ~0xf) + 4, - (const uint8_t *)&val, - sizeof(val)); - } - if (ret < 0) - break; /* interrupted frame */ - if (ret == 2) { - s->async_qh = link; - } else if (ret == 0) { - /* update qh element link */ - qh.el_link = td.link; - val = cpu_to_le32(qh.el_link); - cpu_physical_memory_write((link & ~0xf) + 4, - (const uint8_t *)&val, - sizeof(val)); - if (qh.el_link & 4) { - /* depth first */ - goto depth_first; - } - } - /* go to next entry */ - link = qh.link; - } - } else { - /* TD */ - cpu_physical_memory_read(link & ~0xf, (uint8_t *)&td, sizeof(td)); - le32_to_cpus(&td.link); - le32_to_cpus(&td.ctrl); - le32_to_cpus(&td.token); - le32_to_cpus(&td.buffer); - - /* Handle isochonous transfer. */ - /* FIXME: might be more than one isoc in frame */ - old_td_ctrl = td.ctrl; - ret = uhci_handle_td(s, &td, &int_mask, 0); - /* update the status bits of the TD */ - if (old_td_ctrl != td.ctrl) { - val = cpu_to_le32(td.ctrl); - cpu_physical_memory_write((link & ~0xf) + 4, - (const uint8_t *)&val, - sizeof(val)); - } - if (ret < 0) - break; /* interrupted frame */ - if (ret == 2) { - s->async_frame_addr = frame_addr; - } - link = td.link; - } - } - s->pending_int_mask = int_mask; - if (old_async_qh) { - /* A previously started transfer has disappeared from the transfer - list. There's nothing useful we can do with it now, so just - discard the packet and hope it wasn't too important. */ -#ifdef DEBUG - printf("Discarding USB packet\n"); -#endif - usb_cancel_packet(&s->usb_packet); - s->async_qh = 0; - } + /* Start new frame */ + s->frnum = (s->frnum + 1) & 0x7ff; + + dprintf("uhci: new frame #%u\n" , s->frnum); + + uhci_async_validate_begin(s); + + uhci_process_frame(s); + + uhci_async_validate_end(s); /* prepare the timer for the next frame */ expire_time = qemu_get_clock(vm_clock) + @@ -915,6 +1103,8 @@ to rely on this. */ pci_register_io_region(&s->dev, 4, 0x20, PCI_ADDRESS_SPACE_IO, uhci_map); + + register_savevm("uhci", 0, 1, uhci_save, uhci_load, s); } void usb_uhci_piix4_init(PCIBus *bus, int devfn) @@ -950,4 +1140,6 @@ to rely on this. */ pci_register_io_region(&s->dev, 4, 0x20, PCI_ADDRESS_SPACE_IO, uhci_map); + + register_savevm("uhci", 0, 1, uhci_save, uhci_load, s); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/versatilepb.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/versatilepb.c --- qemu-0.9.1/hw/versatilepb.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/versatilepb.c 2008-10-28 10:59:59.000000000 +0000 @@ -157,7 +157,9 @@ peripherans and expansion busses. For now we emulate a subset of the PB peripherals and just change the board ID. */ -static void versatile_init(int ram_size, int vga_ram_size, +static struct arm_boot_info versatile_binfo; + +static void versatile_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model, @@ -180,7 +182,7 @@ fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - /* ??? RAM shoud repeat to fill physical memory space. */ + /* ??? RAM should repeat to fill physical memory space. */ /* SDRAM at address zero. */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); @@ -283,11 +285,15 @@ /* 0x101f3000 UART2. */ /* 0x101f4000 SSPI. */ - arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline, - initrd_filename, board_id, 0x0); + versatile_binfo.ram_size = ram_size; + versatile_binfo.kernel_filename = kernel_filename; + versatile_binfo.kernel_cmdline = kernel_cmdline; + versatile_binfo.initrd_filename = initrd_filename; + versatile_binfo.board_id = board_id; + arm_load_kernel(env, &versatile_binfo); } -static void vpb_init(int ram_size, int vga_ram_size, +static void vpb_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -298,7 +304,7 @@ initrd_filename, cpu_model, 0x183); } -static void vab_init(int ram_size, int vga_ram_size, +static void vab_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -310,13 +316,15 @@ } QEMUMachine versatilepb_machine = { - "versatilepb", - "ARM Versatile/PB (ARM926EJ-S)", - vpb_init, + .name = "versatilepb", + .desc = "ARM Versatile/PB (ARM926EJ-S)", + .init = vpb_init, + .use_scsi = 1, }; QEMUMachine versatileab_machine = { - "versatileab", - "ARM Versatile/AB (ARM926EJ-S)", - vab_init, + .name = "versatileab", + .desc = "ARM Versatile/AB (ARM926EJ-S)", + .init = vab_init, + .use_scsi = 1, }; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/vga.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/vga.c --- qemu-0.9.1/hw/vga.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/vga.c 2008-10-11 18:37:25.000000000 +0100 @@ -27,6 +27,7 @@ #include "pci.h" #include "vga_int.h" #include "pixel_ops.h" +#include "qemu-timer.h" //#define DEBUG_VGA //#define DEBUG_VGA_MEM @@ -149,6 +150,136 @@ static void vga_screen_dump(void *opaque, const char *filename); +static void vga_dumb_update_retrace_info(VGAState *s) +{ + (void) s; +} + +static void vga_precise_update_retrace_info(VGAState *s) +{ + int htotal_chars; + int hretr_start_char; + int hretr_skew_chars; + int hretr_end_char; + + int vtotal_lines; + int vretr_start_line; + int vretr_end_line; + + int div2, sldiv2, dots; + int clocking_mode; + int clock_sel; + const int hz[] = {25175000, 28322000, 25175000, 25175000}; + int64_t chars_per_sec; + struct vga_precise_retrace *r = &s->retrace_info.precise; + + htotal_chars = s->cr[0x00] + 5; + hretr_start_char = s->cr[0x04]; + hretr_skew_chars = (s->cr[0x05] >> 5) & 3; + hretr_end_char = s->cr[0x05] & 0x1f; + + vtotal_lines = (s->cr[0x06] + | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2 + ; + vretr_start_line = s->cr[0x10] + | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8) + ; + vretr_end_line = s->cr[0x11] & 0xf; + + + div2 = (s->cr[0x17] >> 2) & 1; + sldiv2 = (s->cr[0x17] >> 3) & 1; + + clocking_mode = (s->sr[0x01] >> 3) & 1; + clock_sel = (s->msr >> 2) & 3; + dots = (s->msr & 1) ? 8 : 9; + + chars_per_sec = hz[clock_sel] / dots; + + htotal_chars <<= clocking_mode; + + r->total_chars = vtotal_lines * htotal_chars; + if (r->freq) { + r->ticks_per_char = ticks_per_sec / (r->total_chars * r->freq); + } else { + r->ticks_per_char = ticks_per_sec / chars_per_sec; + } + + r->vstart = vretr_start_line; + r->vend = r->vstart + vretr_end_line + 1; + + r->hstart = hretr_start_char + hretr_skew_chars; + r->hend = r->hstart + hretr_end_char + 1; + r->htotal = htotal_chars; + +#if 0 + printf ( + "hz=%f\n" + "htotal = %d\n" + "hretr_start = %d\n" + "hretr_skew = %d\n" + "hretr_end = %d\n" + "vtotal = %d\n" + "vretr_start = %d\n" + "vretr_end = %d\n" + "div2 = %d sldiv2 = %d\n" + "clocking_mode = %d\n" + "clock_sel = %d %d\n" + "dots = %d\n" + "ticks/char = %lld\n" + "\n", + (double) ticks_per_sec / (r->ticks_per_char * r->total_chars), + htotal_chars, + hretr_start_char, + hretr_skew_chars, + hretr_end_char, + vtotal_lines, + vretr_start_line, + vretr_end_line, + div2, sldiv2, + clocking_mode, + clock_sel, + hz[clock_sel], + dots, + r->ticks_per_char + ); +#endif +} + +static uint8_t vga_precise_retrace(VGAState *s) +{ + struct vga_precise_retrace *r = &s->retrace_info.precise; + uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE); + + if (r->total_chars) { + int cur_line, cur_line_char, cur_char; + int64_t cur_tick; + + cur_tick = qemu_get_clock(vm_clock); + + cur_char = (cur_tick / r->ticks_per_char) % r->total_chars; + cur_line = cur_char / r->htotal; + + if (cur_line >= r->vstart && cur_line <= r->vend) { + val |= ST01_V_RETRACE | ST01_DISP_ENABLE; + } else { + cur_line_char = cur_char % r->htotal; + if (cur_line_char >= r->hstart && cur_line_char <= r->hend) { + val |= ST01_DISP_ENABLE; + } + } + + return val; + } else { + return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE); + } +} + +static uint8_t vga_dumb_retrace(VGAState *s) +{ + return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE); +} + static uint32_t vga_ioport_read(void *opaque, uint32_t addr) { VGAState *s = opaque; @@ -228,8 +359,7 @@ case 0x3ba: case 0x3da: /* just toggle to fool polling */ - s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE; - val = s->st01; + val = s->st01 = s->retrace(s); s->ar_flip_flop = 0; break; default: @@ -291,6 +421,7 @@ break; case 0x3c2: s->msr = val & ~0x10; + s->update_retrace_info(s); break; case 0x3c4: s->sr_index = val & 7; @@ -300,6 +431,7 @@ printf("vga: write SR%x = 0x%02x\n", s->sr_index, val); #endif s->sr[s->sr_index] = val & sr_mask[s->sr_index]; + if (s->sr_index == 1) s->update_retrace_info(s); break; case 0x3c7: s->dac_read_index = val; @@ -357,6 +489,18 @@ s->cr[s->cr_index] = val; break; } + + switch(s->cr_index) { + case 0x00: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x11: + case 0x17: + s->update_retrace_info(s); + break; + } break; case 0x3ba: case 0x3da: @@ -1155,7 +1299,7 @@ cw != s->last_cw || cheight != s->last_ch) { s->last_scr_width = width * cw; s->last_scr_height = height * cheight; - dpy_resize(s->ds, s->last_scr_width, s->last_scr_height); + qemu_console_resize(s->console, s->last_scr_width, s->last_scr_height); s->last_width = width; s->last_height = height; s->last_ch = cheight; @@ -1418,7 +1562,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) { int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask; - int width, height, shift_control, line_offset, page0, page1, bwidth; + int width, height, shift_control, line_offset, page0, page1, bwidth, bits; int disp_width, multi_scan, multi_run; uint8_t *d; uint32_t v, addr1, addr; @@ -1454,6 +1598,7 @@ } else { v = VGA_DRAW_LINE4; } + bits = 4; } else if (shift_control == 1) { full_update |= update_palette16(s); if (s->sr[0x01] & 8) { @@ -1462,28 +1607,35 @@ } else { v = VGA_DRAW_LINE2; } + bits = 4; } else { switch(s->get_bpp(s)) { default: case 0: full_update |= update_palette256(s); v = VGA_DRAW_LINE8D2; + bits = 4; break; case 8: full_update |= update_palette256(s); v = VGA_DRAW_LINE8; + bits = 8; break; case 15: v = VGA_DRAW_LINE15; + bits = 16; break; case 16: v = VGA_DRAW_LINE16; + bits = 16; break; case 24: v = VGA_DRAW_LINE24; + bits = 24; break; case 32: v = VGA_DRAW_LINE32; + bits = 32; break; } } @@ -1491,7 +1643,7 @@ if (disp_width != s->last_width || height != s->last_height) { - dpy_resize(s->ds, disp_width, height); + qemu_console_resize(s->console, disp_width, height); s->last_scr_width = disp_width; s->last_scr_height = height; s->last_width = disp_width; @@ -1507,7 +1659,7 @@ width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]); #endif addr1 = (s->start_addr * 4); - bwidth = width * 4; + bwidth = (width * bits + 7) / 8; y_start = -1; page_min = 0x7fffffff; page_max = -1; @@ -1660,6 +1812,168 @@ s->graphic_mode = -1; /* force full update */ } +#define TEXTMODE_X(x) ((x) % width) +#define TEXTMODE_Y(x) ((x) / width) +#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \ + ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1)) +/* relay text rendering to the display driver + * instead of doing a full vga_update_display() */ +static void vga_update_text(void *opaque, console_ch_t *chardata) +{ + VGAState *s = (VGAState *) opaque; + int graphic_mode, i, cursor_offset, cursor_visible; + int cw, cheight, width, height, size, c_min, c_max; + uint32_t *src; + console_ch_t *dst, val; + char msg_buffer[80]; + int full_update = 0; + + if (!(s->ar_index & 0x20)) { + graphic_mode = GMODE_BLANK; + } else { + graphic_mode = s->gr[6] & 1; + } + if (graphic_mode != s->graphic_mode) { + s->graphic_mode = graphic_mode; + full_update = 1; + } + if (s->last_width == -1) { + s->last_width = 0; + full_update = 1; + } + + switch (graphic_mode) { + case GMODE_TEXT: + /* TODO: update palette */ + full_update |= update_basic_params(s); + + /* total width & height */ + cheight = (s->cr[9] & 0x1f) + 1; + cw = 8; + if (!(s->sr[1] & 0x01)) + cw = 9; + if (s->sr[1] & 0x08) + cw = 16; /* NOTE: no 18 pixel wide */ + width = (s->cr[0x01] + 1); + if (s->cr[0x06] == 100) { + /* ugly hack for CGA 160x100x16 - explain me the logic */ + height = 100; + } else { + height = s->cr[0x12] | + ((s->cr[0x07] & 0x02) << 7) | + ((s->cr[0x07] & 0x40) << 3); + height = (height + 1) / cheight; + } + + size = (height * width); + if (size > CH_ATTR_SIZE) { + if (!full_update) + return; + + snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode", + width, height); + break; + } + + if (width != s->last_width || height != s->last_height || + cw != s->last_cw || cheight != s->last_ch) { + s->last_scr_width = width * cw; + s->last_scr_height = height * cheight; + qemu_console_resize(s->console, width, height); + s->last_width = width; + s->last_height = height; + s->last_ch = cheight; + s->last_cw = cw; + full_update = 1; + } + + /* Update "hardware" cursor */ + cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr; + if (cursor_offset != s->cursor_offset || + s->cr[0xa] != s->cursor_start || + s->cr[0xb] != s->cursor_end || full_update) { + cursor_visible = !(s->cr[0xa] & 0x20); + if (cursor_visible && cursor_offset < size && cursor_offset >= 0) + dpy_cursor(s->ds, + TEXTMODE_X(cursor_offset), + TEXTMODE_Y(cursor_offset)); + else + dpy_cursor(s->ds, -1, -1); + s->cursor_offset = cursor_offset; + s->cursor_start = s->cr[0xa]; + s->cursor_end = s->cr[0xb]; + } + + src = (uint32_t *) s->vram_ptr + s->start_addr; + dst = chardata; + + if (full_update) { + for (i = 0; i < size; src ++, dst ++, i ++) + console_write_ch(dst, VMEM2CHTYPE(*src)); + + dpy_update(s->ds, 0, 0, width, height); + } else { + c_max = 0; + + for (i = 0; i < size; src ++, dst ++, i ++) { + console_write_ch(&val, VMEM2CHTYPE(*src)); + if (*dst != val) { + *dst = val; + c_max = i; + break; + } + } + c_min = i; + for (; i < size; src ++, dst ++, i ++) { + console_write_ch(&val, VMEM2CHTYPE(*src)); + if (*dst != val) { + *dst = val; + c_max = i; + } + } + + if (c_min <= c_max) { + i = TEXTMODE_Y(c_min); + dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1); + } + } + + return; + case GMODE_GRAPH: + if (!full_update) + return; + + s->get_resolution(s, &width, &height); + snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode", + width, height); + break; + case GMODE_BLANK: + default: + if (!full_update) + return; + + snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode"); + break; + } + + /* Display a message */ + s->last_width = 60; + s->last_height = height = 3; + dpy_cursor(s->ds, -1, -1); + qemu_console_resize(s->console, s->last_width, height); + + for (dst = chardata, i = 0; i < s->last_width * height; i ++) + console_write_ch(dst ++, ' '); + + size = strlen(msg_buffer); + width = (s->last_width - size) / 2; + dst = chardata + s->last_width + width; + for (i = 0; i < size; i ++) + console_write_ch(dst ++, 0x00200100 | msg_buffer[i]); + + dpy_update(s->ds, 0, 0, s->last_width, height); +} + static CPUReadMemoryFunc *vga_mem_read[3] = { vga_mem_readb, vga_mem_readw, @@ -1830,6 +2144,19 @@ s->update = vga_update_display; s->invalidate = vga_invalidate_display; s->screen_dump = vga_screen_dump; + s->text_update = vga_update_text; + switch (vga_retrace_method) { + case VGA_RETRACE_DUMB: + s->retrace = vga_dumb_retrace; + s->update_retrace_info = vga_dumb_update_retrace_info; + break; + + case VGA_RETRACE_PRECISE: + s->retrace = vga_precise_retrace; + s->update_retrace_info = vga_precise_update_retrace_info; + memset(&s->retrace_info, 0, sizeof (s->retrace_info)); + break; + } } /* used by both ISA and PCI */ @@ -1971,7 +2298,8 @@ vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); vga_init(s); - graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); + s->console = graphic_console_init(s->ds, s->update, s->invalidate, + s->screen_dump, s->text_update, s); #ifdef CONFIG_BOCHS_VBE /* XXX: use optimized standard vga accesses */ @@ -1995,7 +2323,8 @@ vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); vga_mm_init(s, vram_base, ctrl_base, it_shift); - graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); + s->console = graphic_console_init(s->ds, s->update, s->invalidate, + s->screen_dump, s->text_update, s); #ifdef CONFIG_BOCHS_VBE /* XXX: use optimized standard vga accesses */ @@ -2023,7 +2352,8 @@ vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); vga_init(s); - graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); + s->console = graphic_console_init(s->ds, s->update, s->invalidate, + s->screen_dump, s->text_update, s); s->pci_dev = &d->dev; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/vga_int.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/vga_int.h --- qemu-0.9.1/hw/vga_int.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/vga_int.h 2008-09-28 01:42:12.000000000 +0100 @@ -79,6 +79,25 @@ #define CH_ATTR_SIZE (160 * 100) #define VGA_MAX_HEIGHT 2048 +struct vga_precise_retrace { + int64_t ticks_per_char; + int64_t total_chars; + int htotal; + int hstart; + int hend; + int vstart; + int vend; + int freq; +}; + +union vga_retrace { + struct vga_precise_retrace precise; +}; + +struct VGAState; +typedef uint8_t (* vga_retrace_fn)(struct VGAState *s); +typedef void (* vga_update_retrace_info_fn)(struct VGAState *s); + #define VGA_STATE_COMMON \ uint8_t *vram_ptr; \ unsigned long vram_offset; \ @@ -121,6 +140,7 @@ VGA_STATE_COMMON_BOCHS_VBE \ /* display refresh support */ \ DisplayState *ds; \ + QEMUConsole *console; \ uint32_t font_offsets[2]; \ int graphic_mode; \ uint8_t shift_control; \ @@ -139,13 +159,18 @@ vga_hw_update_ptr update; \ vga_hw_invalidate_ptr invalidate; \ vga_hw_screen_dump_ptr screen_dump; \ + vga_hw_text_update_ptr text_update; \ /* hardware mouse cursor support */ \ uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32]; \ void (*cursor_invalidate)(struct VGAState *s); \ void (*cursor_draw_line)(struct VGAState *s, uint8_t *d, int y); \ /* tell for each page if it has been updated since the last time */ \ uint32_t last_palette[256]; \ - uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */ + uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */ \ + /* retrace */ \ + vga_retrace_fn retrace; \ + vga_update_retrace_info_fn update_retrace_info; \ + union vga_retrace retrace_info; typedef struct VGAState { diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/vmport.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/vmport.c --- qemu-0.9.1/hw/vmport.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/vmport.c 2008-08-19 20:13:06.000000000 +0100 @@ -26,6 +26,8 @@ #include "pc.h" #include "sysemu.h" +//#define VMPORT_DEBUG + #define VMPORT_CMD_GETVERSION 0x0a #define VMPORT_CMD_GETRAMSIZE 0x14 @@ -34,7 +36,6 @@ typedef struct _VMPortState { - CPUState *env; IOPortReadFunc *func[VMPORT_ENTRIES]; void *opaque[VMPORT_ENTRIES]; } VMPortState; @@ -53,46 +54,55 @@ static uint32_t vmport_ioport_read(void *opaque, uint32_t addr) { VMPortState *s = opaque; + CPUState *env = cpu_single_env; unsigned char command; uint32_t eax; - eax = s->env->regs[R_EAX]; + eax = env->regs[R_EAX]; if (eax != VMPORT_MAGIC) return eax; - command = s->env->regs[R_ECX]; + command = env->regs[R_ECX]; if (command >= VMPORT_ENTRIES) return eax; if (!s->func[command]) { - printf("vmport: unknown command %x\n", command); +#ifdef VMPORT_DEBUG + fprintf(stderr, "vmport: unknown command %x\n", command); +#endif return eax; } return s->func[command](s->opaque[command], addr); } +static void vmport_ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + CPUState *env = cpu_single_env; + + env->regs[R_EAX] = vmport_ioport_read(opaque, addr); +} + static uint32_t vmport_cmd_get_version(void *opaque, uint32_t addr) { - CPUState *env = opaque; + CPUState *env = cpu_single_env; env->regs[R_EBX] = VMPORT_MAGIC; return 6; } static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr) { - CPUState *env = opaque; + CPUState *env = cpu_single_env; env->regs[R_EBX] = 0x1177; return ram_size; } -void vmport_init(CPUState *env) +void vmport_init(void) { - port_state.env = env; - register_ioport_read(0x5658, 1, 4, vmport_ioport_read, &port_state); + register_ioport_write(0x5658, 1, 4, vmport_ioport_write, &port_state); /* Register some generic port commands */ - vmport_register(VMPORT_CMD_GETVERSION, vmport_cmd_get_version, env); - vmport_register(VMPORT_CMD_GETRAMSIZE, vmport_cmd_ram_size, env); + vmport_register(VMPORT_CMD_GETVERSION, vmport_cmd_get_version, NULL); + vmport_register(VMPORT_CMD_GETRAMSIZE, vmport_cmd_ram_size, NULL); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/vmware_vga.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/vmware_vga.c --- qemu-0.9.1/hw/vmware_vga.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/vmware_vga.c 2008-09-24 03:21:24.000000000 +0100 @@ -57,9 +57,12 @@ #ifndef EMBED_STDVGA DisplayState *ds; + QEMUConsole *console; int vram_size; + ram_addr_t vram_offset; #endif uint8_t *vram; + target_phys_addr_t vram_base; int index; int scratch_size; @@ -290,12 +293,33 @@ int x, int y, int w, int h) { #ifndef DIRECT_VRAM - int line = h; - int bypl = s->bypp * s->width; - int width = s->bypp * w; - int start = s->bypp * x + bypl * y; - uint8_t *src = s->vram + start; - uint8_t *dst = s->ds->data + start; + int line; + int bypl; + int width; + int start; + uint8_t *src; + uint8_t *dst; + + if (x + w > s->width) { + fprintf(stderr, "%s: update width too large x: %d, w: %d\n", + __FUNCTION__, x, w); + x = MIN(x, s->width); + w = s->width - x; + } + + if (y + h > s->height) { + fprintf(stderr, "%s: update height too large y: %d, h: %d\n", + __FUNCTION__, y, h); + y = MIN(y, s->height); + h = s->height - y; + } + + line = h; + bypl = s->bypp * s->width; + width = s->bypp * w; + start = s->bypp * x + bypl * y; + src = s->vram + start; + dst = s->ds->data + start; for (; line > 0; line --, src += bypl, dst += bypl) memcpy(dst, src, width); @@ -360,7 +384,7 @@ # ifdef DIRECT_VRAM if (s->ds->dpy_copy) - s->ds->dpy_copy(s->ds, x0, y0, x1, y1, w, h); + qemu_console_copy(s->console, x0, y0, x1, y1, w, h); else # endif { @@ -459,6 +483,8 @@ } #endif +#define CMD(f) le32_to_cpu(s->cmd->f) + static inline int vmsvga_fifo_empty(struct vmsvga_state_s *s) { if (!s->config || !s->enable) @@ -466,15 +492,20 @@ return (s->cmd->next_cmd == s->cmd->stop); } -static inline uint32_t vmsvga_fifo_read(struct vmsvga_state_s *s) +static inline uint32_t vmsvga_fifo_read_raw(struct vmsvga_state_s *s) { - uint32_t cmd = s->fifo[s->cmd->stop >> 2]; - s->cmd->stop += 4; - if (s->cmd->stop >= s->cmd->max) + uint32_t cmd = s->fifo[CMD(stop) >> 2]; + s->cmd->stop = cpu_to_le32(CMD(stop) + 4); + if (CMD(stop) >= CMD(max)) s->cmd->stop = s->cmd->min; return cmd; } +static inline uint32_t vmsvga_fifo_read(struct vmsvga_state_s *s) +{ + return le32_to_cpu(vmsvga_fifo_read_raw(s)); +} + static void vmsvga_fifo_run(struct vmsvga_state_s *s) { uint32_t cmd, colour; @@ -528,9 +559,9 @@ vmsvga_fifo_read(s); cursor.bpp = vmsvga_fifo_read(s); for (args = 0; args < SVGA_BITMAP_SIZE(x, y); args ++) - cursor.mask[args] = vmsvga_fifo_read(s); + cursor.mask[args] = vmsvga_fifo_read_raw(s); for (args = 0; args < SVGA_PIXMAP_SIZE(x, y, cursor.bpp); args ++) - cursor.image[args] = vmsvga_fifo_read(s); + cursor.image[args] = vmsvga_fifo_read_raw(s); #ifdef HW_MOUSE_ACCEL vmsvga_cursor_define(s, &cursor); break; @@ -644,7 +675,7 @@ return ((s->depth + 7) >> 3) * s->new_width; case SVGA_REG_FB_START: - return SVGA_MEM_BASE; + return s->vram_base; case SVGA_REG_FB_OFFSET: return 0x0; @@ -671,7 +702,7 @@ return caps; case SVGA_REG_MEM_START: - return SVGA_MEM_BASE + s->vram_size - SVGA_FIFO_SIZE; + return s->vram_base + s->vram_size - SVGA_FIFO_SIZE; case SVGA_REG_MEM_SIZE: return SVGA_FIFO_SIZE; @@ -764,14 +795,14 @@ if (value) { s->fifo = (uint32_t *) &s->vram[s->vram_size - SVGA_FIFO_SIZE]; /* Check range and alignment. */ - if ((s->cmd->min | s->cmd->max | - s->cmd->next_cmd | s->cmd->stop) & 3) + if ((CMD(min) | CMD(max) | + CMD(next_cmd) | CMD(stop)) & 3) break; - if (s->cmd->min < (uint8_t *) s->cmd->fifo - (uint8_t *) s->fifo) + if (CMD(min) < (uint8_t *) s->cmd->fifo - (uint8_t *) s->fifo) break; - if (s->cmd->max > SVGA_FIFO_SIZE) + if (CMD(max) > SVGA_FIFO_SIZE) break; - if (s->cmd->max < s->cmd->min + 10 * 1024) + if (CMD(max) < CMD(min) + 10 * 1024) break; } s->config = !!value; @@ -846,7 +877,7 @@ if (s->new_width != s->width || s->new_height != s->height) { s->width = s->new_width; s->height = s->new_height; - dpy_resize(s->ds, s->width, s->height); + qemu_console_resize(s->console, s->width, s->height); s->invalidated = 1; } } @@ -949,11 +980,19 @@ } } +static void vmsvga_text_update(void *opaque, console_ch_t *chardata) +{ + struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; + + if (s->text_update) + s->text_update(opaque, chardata); +} + #ifdef DIRECT_VRAM static uint32_t vmsvga_vram_readb(void *opaque, target_phys_addr_t addr) { struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; - addr -= SVGA_MEM_BASE; + addr -= s->vram_base; if (addr < s->fb_size) return *(uint8_t *) (s->ds->data + addr); else @@ -963,7 +1002,7 @@ static uint32_t vmsvga_vram_readw(void *opaque, target_phys_addr_t addr) { struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; - addr -= SVGA_MEM_BASE; + addr -= s->vram_base; if (addr < s->fb_size) return *(uint16_t *) (s->ds->data + addr); else @@ -973,7 +1012,7 @@ static uint32_t vmsvga_vram_readl(void *opaque, target_phys_addr_t addr) { struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; - addr -= SVGA_MEM_BASE; + addr -= s->vram_base; if (addr < s->fb_size) return *(uint32_t *) (s->ds->data + addr); else @@ -984,7 +1023,7 @@ uint32_t value) { struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; - addr -= SVGA_MEM_BASE; + addr -= s->vram_base; if (addr < s->fb_size) *(uint8_t *) (s->ds->data + addr) = value; else @@ -995,7 +1034,7 @@ uint32_t value) { struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; - addr -= SVGA_MEM_BASE; + addr -= s->vram_base; if (addr < s->fb_size) *(uint16_t *) (s->ds->data + addr) = value; else @@ -1006,7 +1045,7 @@ uint32_t value) { struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; - addr -= SVGA_MEM_BASE; + addr -= s->vram_base; if (addr < s->fb_size) *(uint32_t *) (s->ds->data + addr) = value; else @@ -1081,46 +1120,32 @@ uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size) { - int iomemtype; s->ds = ds; s->vram = vga_ram_base; s->vram_size = vga_ram_size; + s->vram_offset = vga_ram_offset; s->scratch_size = SVGA_SCRATCH_SIZE; s->scratch = (uint32_t *) qemu_malloc(s->scratch_size * 4); vmsvga_reset(s); -#ifdef DIRECT_VRAM - iomemtype = cpu_register_io_memory(0, vmsvga_vram_read, - vmsvga_vram_write, s); -#else - iomemtype = vga_ram_offset | IO_MEM_RAM; -#endif - cpu_register_physical_memory(SVGA_MEM_BASE, vga_ram_size, - iomemtype); - - register_ioport_read(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_INDEX_PORT, - 1, 4, vmsvga_index_read, s); - register_ioport_write(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_INDEX_PORT, - 1, 4, vmsvga_index_write, s); - register_ioport_read(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_VALUE_PORT, - 1, 4, vmsvga_value_read, s); - register_ioport_write(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_VALUE_PORT, - 1, 4, vmsvga_value_write, s); - register_ioport_read(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_BIOS_PORT, - 1, 4, vmsvga_bios_read, s); - register_ioport_write(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_BIOS_PORT, - 1, 4, vmsvga_bios_write, s); - - graphic_console_init(ds, vmsvga_update_display, - vmsvga_invalidate_display, vmsvga_screen_dump, s); - #ifdef EMBED_STDVGA vga_common_init((VGAState *) s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); vga_init((VGAState *) s); #endif + + s->console = graphic_console_init(ds, vmsvga_update_display, + vmsvga_invalidate_display, + vmsvga_screen_dump, + vmsvga_text_update, s); + +#ifdef CONFIG_BOCHS_VBE + /* XXX: use optimized standard vga accesses */ + cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, + vga_ram_size, vga_ram_offset); +#endif } static void pci_vmsvga_save(QEMUFile *f, void *opaque) @@ -1146,6 +1171,44 @@ return 0; } +static void pci_vmsvga_map_ioport(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev; + struct vmsvga_state_s *s = &d->chip; + + register_ioport_read(addr + SVGA_IO_MUL * SVGA_INDEX_PORT, + 1, 4, vmsvga_index_read, s); + register_ioport_write(addr + SVGA_IO_MUL * SVGA_INDEX_PORT, + 1, 4, vmsvga_index_write, s); + register_ioport_read(addr + SVGA_IO_MUL * SVGA_VALUE_PORT, + 1, 4, vmsvga_value_read, s); + register_ioport_write(addr + SVGA_IO_MUL * SVGA_VALUE_PORT, + 1, 4, vmsvga_value_write, s); + register_ioport_read(addr + SVGA_IO_MUL * SVGA_BIOS_PORT, + 1, 4, vmsvga_bios_read, s); + register_ioport_write(addr + SVGA_IO_MUL * SVGA_BIOS_PORT, + 1, 4, vmsvga_bios_write, s); +} + +static void pci_vmsvga_map_mem(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev; + struct vmsvga_state_s *s = &d->chip; + ram_addr_t iomemtype; + + s->vram_base = addr; +#ifdef DIRECT_VRAM + iomemtype = cpu_register_io_memory(0, vmsvga_vram_read, + vmsvga_vram_write, s); +#else + iomemtype = s->vram_offset | IO_MEM_RAM; +#endif + cpu_register_physical_memory(s->vram_base, s->vram_size, + iomemtype); +} + #define PCI_VENDOR_ID_VMWARE 0x15ad #define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405 #define PCI_DEVICE_ID_VMWARE_SVGA 0x0710 @@ -1175,20 +1238,17 @@ s->card.config[0x0c] = 0x08; /* Cache line size */ s->card.config[0x0d] = 0x40; /* Latency timer */ s->card.config[0x0e] = PCI_CLASS_HEADERTYPE_00h; - s->card.config[0x10] = ((SVGA_IO_BASE >> 0) & 0xff) | 1; - s->card.config[0x11] = (SVGA_IO_BASE >> 8) & 0xff; - s->card.config[0x12] = (SVGA_IO_BASE >> 16) & 0xff; - s->card.config[0x13] = (SVGA_IO_BASE >> 24) & 0xff; - s->card.config[0x18] = (SVGA_MEM_BASE >> 0) & 0xff; - s->card.config[0x19] = (SVGA_MEM_BASE >> 8) & 0xff; - s->card.config[0x1a] = (SVGA_MEM_BASE >> 16) & 0xff; - s->card.config[0x1b] = (SVGA_MEM_BASE >> 24) & 0xff; s->card.config[0x2c] = PCI_VENDOR_ID_VMWARE & 0xff; s->card.config[0x2d] = PCI_VENDOR_ID_VMWARE >> 8; s->card.config[0x2e] = SVGA_PCI_DEVICE_ID & 0xff; s->card.config[0x2f] = SVGA_PCI_DEVICE_ID >> 8; s->card.config[0x3c] = 0xff; /* End */ + pci_register_io_region(&s->card, 0, 0x10, + PCI_ADDRESS_SPACE_IO, pci_vmsvga_map_ioport); + pci_register_io_region(&s->card, 1, vga_ram_size, + PCI_ADDRESS_SPACE_MEM_PREFETCH, pci_vmsvga_map_mem); + vmsvga_init(&s->chip, ds, vga_ram_base, vga_ram_offset, vga_ram_size); register_savevm("vmware_vga", 0, 0, pci_vmsvga_save, pci_vmsvga_load, s); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/wm8750.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/wm8750.c --- qemu-0.9.1/hw/wm8750.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/hw/wm8750.c 2008-07-01 22:31:54.000000000 +0100 @@ -39,10 +39,20 @@ uint8_t diff[2], pol, ds, monomix[2], alc, mute; uint8_t path[4], mpath[2], power, format; - uint32_t inmask, outmask; const struct wm_rate_s *rate; + int adc_hz, dac_hz, ext_adc_hz, ext_dac_hz, master; }; +/* pow(10.0, -i / 20.0) * 255, i = 0..42 */ +static const uint8_t wm8750_vol_db_table[] = { + 255, 227, 203, 181, 161, 143, 128, 114, 102, 90, 81, 72, 64, 57, 51, 45, + 40, 36, 32, 29, 26, 23, 20, 18, 16, 14, 13, 11, 10, 9, 8, 7, 6, 6, 5, 5, + 4, 4, 3, 3, 3, 2, 2 +}; + +#define WM8750_OUTVOL_TRANSFORM(x) wm8750_vol_db_table[(0x7f - x) / 3] +#define WM8750_INVOL_TRANSFORM(x) (x << 2) + static inline void wm8750_in_load(struct wm8750_s *s) { int acquired; @@ -55,10 +65,10 @@ static inline void wm8750_out_flush(struct wm8750_s *s) { - int sent; - if (!s->idx_out) - return; - sent = AUD_write(*s->out[0], s->data_out, s->idx_out); + int sent = 0; + while (sent < s->idx_out) + sent += AUD_write(*s->out[0], s->data_out + sent, s->idx_out - sent) + ?: s->idx_out; s->idx_out = 0; } @@ -67,19 +77,20 @@ struct wm8750_s *s = (struct wm8750_s *) opaque; s->req_in = avail_b; s->data_req(s->opaque, s->req_out >> 2, avail_b >> 2); - -#if 0 - wm8750_in_load(s); -#endif } static void wm8750_audio_out_cb(void *opaque, int free_b) { struct wm8750_s *s = (struct wm8750_s *) opaque; - wm8750_out_flush(s); - s->req_out = free_b; - s->data_req(s->opaque, free_b >> 2, s->req_in >> 2); + if (s->idx_out >= free_b) { + s->idx_out = free_b; + s->req_out = 0; + wm8750_out_flush(s); + } else + s->req_out = free_b - s->idx_out; + + s->data_req(s->opaque, s->req_out >> 2, s->req_in >> 2); } struct wm_rate_s { @@ -121,9 +132,41 @@ { 512, 24000, 512, 24000 }, /* SR: 11100 */ { 768, 24000, 768, 24000 }, /* SR: 11101 */ { 128, 88200, 128, 88200 }, /* SR: 11110 */ - { 192, 88200, 128, 88200 }, /* SR: 11111 */ + { 192, 88200, 192, 88200 }, /* SR: 11111 */ }; +static void wm8750_vol_update(struct wm8750_s *s) +{ + /* FIXME: multiply all volumes by s->invol[2], s->invol[3] */ + + AUD_set_volume_in(s->adc_voice[0], s->mute, + s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]), + s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1])); + AUD_set_volume_in(s->adc_voice[1], s->mute, + s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]), + s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1])); + AUD_set_volume_in(s->adc_voice[2], s->mute, + s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]), + s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1])); + + /* FIXME: multiply all volumes by s->outvol[0], s->outvol[1] */ + + /* Speaker: LOUT2VOL ROUT2VOL */ + AUD_set_volume_out(s->dac_voice[0], s->mute, + s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[4]), + s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[5])); + + /* Headphone: LOUT1VOL ROUT1VOL */ + AUD_set_volume_out(s->dac_voice[1], s->mute, + s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[2]), + s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[3])); + + /* MONOOUT: MONOVOL MONOVOL */ + AUD_set_volume_out(s->dac_voice[2], s->mute, + s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]), + s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6])); +} + static void wm8750_set_format(struct wm8750_s *s) { int i; @@ -155,7 +198,7 @@ /* Setup input */ in_fmt.endianness = 0; in_fmt.nchannels = 2; - in_fmt.freq = s->rate->adc_hz; + in_fmt.freq = s->adc_hz; in_fmt.fmt = AUD_FMT_S16; s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0], @@ -168,7 +211,7 @@ /* Setup output */ out_fmt.endianness = 0; out_fmt.nchannels = 2; - out_fmt.freq = s->rate->dac_hz; + out_fmt.freq = s->dac_hz; out_fmt.fmt = AUD_FMT_S16; monoout_fmt.endianness = 0; monoout_fmt.nchannels = 1; @@ -184,6 +227,8 @@ CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt); /* no sense emulating OUT3 which is a mix of other outputs */ + wm8750_vol_update(s); + /* We should connect the left and right channels to their * respective inputs/outputs but we have completely no need * for mixing or combining paths to different ports, so we @@ -194,27 +239,33 @@ AUD_set_active_out(*s->out[0], 1); } -static void inline wm8750_mask_update(struct wm8750_s *s) +static void wm8750_clk_update(struct wm8750_s *s, int ext) { -#define R_ONLY 0x0000ffff -#define L_ONLY 0xffff0000 -#define BOTH (R_ONLY | L_ONLY) -#define NONE (R_ONLY & L_ONLY) - s->inmask = - (s->inmute[0] ? R_ONLY : BOTH) & - (s->inmute[1] ? L_ONLY : BOTH) & - (s->mute ? NONE : BOTH); - s->outmask = - (s->outmute[0] ? R_ONLY : BOTH) & - (s->outmute[1] ? L_ONLY : BOTH) & - (s->mute ? NONE : BOTH); + if (s->master || !s->ext_dac_hz) + s->dac_hz = s->rate->dac_hz; + else + s->dac_hz = s->ext_dac_hz; + + if (s->master || !s->ext_adc_hz) + s->adc_hz = s->rate->adc_hz; + else + s->adc_hz = s->ext_adc_hz; + + if (s->master || (!s->ext_dac_hz && !s->ext_adc_hz)) { + if (!ext) + wm8750_set_format(s); + } else { + if (ext) + wm8750_set_format(s); + } } void wm8750_reset(i2c_slave *i2c) { struct wm8750_s *s = (struct wm8750_s *) i2c; + s->rate = &wm_rate_table[0]; s->enable = 0; - wm8750_set_format(s); + wm8750_clk_update(s, 1); s->diff[0] = 0; s->diff[1] = 0; s->ds = 0; @@ -231,6 +282,7 @@ s->outvol[3] = 0x79; s->outvol[4] = 0x79; s->outvol[5] = 0x79; + s->outvol[6] = 0x79; s->inmute[0] = 0; s->inmute[1] = 0; s->outmute[0] = 0; @@ -247,7 +299,7 @@ s->req_in = 0; s->idx_out = 0; s->req_out = 0; - wm8750_mask_update(s); + wm8750_vol_update(s); s->i2c_len = 0; } @@ -365,19 +417,19 @@ case WM8750_LINVOL: /* Left Channel PGA */ s->invol[0] = value & 0x3f; /* LINVOL */ s->inmute[0] = (value >> 7) & 1; /* LINMUTE */ - wm8750_mask_update(s); + wm8750_vol_update(s); break; case WM8750_RINVOL: /* Right Channel PGA */ s->invol[1] = value & 0x3f; /* RINVOL */ s->inmute[1] = (value >> 7) & 1; /* RINMUTE */ - wm8750_mask_update(s); + wm8750_vol_update(s); break; case WM8750_ADCDAC: /* ADC and DAC Control */ s->pol = (value >> 5) & 3; /* ADCPOL */ s->mute = (value >> 3) & 1; /* DACMU */ - wm8750_mask_update(s); + wm8750_vol_update(s); break; case WM8750_ADCTL3: /* Additional Control (3) */ @@ -385,10 +437,12 @@ case WM8750_LADC: /* Left ADC Digital Volume */ s->invol[2] = value & 0xff; /* LADCVOL */ + wm8750_vol_update(s); break; case WM8750_RADC: /* Right ADC Digital Volume */ s->invol[3] = value & 0xff; /* RADCVOL */ + wm8750_vol_update(s); break; case WM8750_ALC1: /* ALC Control (1) */ @@ -401,10 +455,12 @@ case WM8750_LDAC: /* Left Channel Digital Volume */ s->outvol[0] = value & 0xff; /* LDACVOL */ + wm8750_vol_update(s); break; case WM8750_RDAC: /* Right Channel Digital Volume */ s->outvol[1] = value & 0xff; /* RDACVOL */ + wm8750_vol_update(s); break; case WM8750_BASS: /* Bass Control */ @@ -412,46 +468,63 @@ case WM8750_LOUTM1: /* Left Mixer Control (1) */ s->path[0] = (value >> 8) & 1; /* LD2LO */ + /* TODO: mute/unmute respective paths */ + wm8750_vol_update(s); break; case WM8750_LOUTM2: /* Left Mixer Control (2) */ s->path[1] = (value >> 8) & 1; /* RD2LO */ + /* TODO: mute/unmute respective paths */ + wm8750_vol_update(s); break; case WM8750_ROUTM1: /* Right Mixer Control (1) */ s->path[2] = (value >> 8) & 1; /* LD2RO */ + /* TODO: mute/unmute respective paths */ + wm8750_vol_update(s); break; case WM8750_ROUTM2: /* Right Mixer Control (2) */ s->path[3] = (value >> 8) & 1; /* RD2RO */ + /* TODO: mute/unmute respective paths */ + wm8750_vol_update(s); break; case WM8750_MOUTM1: /* Mono Mixer Control (1) */ s->mpath[0] = (value >> 8) & 1; /* LD2MO */ + /* TODO: mute/unmute respective paths */ + wm8750_vol_update(s); break; case WM8750_MOUTM2: /* Mono Mixer Control (2) */ s->mpath[1] = (value >> 8) & 1; /* RD2MO */ + /* TODO: mute/unmute respective paths */ + wm8750_vol_update(s); break; case WM8750_LOUT1V: /* LOUT1 Volume */ - s->outvol[2] = value & 0x7f; /* LOUT2VOL */ + s->outvol[2] = value & 0x7f; /* LOUT1VOL */ + wm8750_vol_update(s); break; case WM8750_LOUT2V: /* LOUT2 Volume */ s->outvol[4] = value & 0x7f; /* LOUT2VOL */ + wm8750_vol_update(s); break; case WM8750_ROUT1V: /* ROUT1 Volume */ - s->outvol[3] = value & 0x7f; /* ROUT2VOL */ + s->outvol[3] = value & 0x7f; /* ROUT1VOL */ + wm8750_vol_update(s); break; case WM8750_ROUT2V: /* ROUT2 Volume */ s->outvol[5] = value & 0x7f; /* ROUT2VOL */ + wm8750_vol_update(s); break; case WM8750_MOUTV: /* MONOOUT Volume */ s->outvol[6] = value & 0x7f; /* MONOOUTVOL */ + wm8750_vol_update(s); break; case WM8750_ADCTL2: /* Additional Control (2) */ @@ -459,20 +532,19 @@ case WM8750_PWR2: /* Power Management (2) */ s->power = value & 0x7e; + /* TODO: mute/unmute respective paths */ + wm8750_vol_update(s); break; case WM8750_IFACE: /* Digital Audio Interface Format */ -#ifdef VERBOSE - if (value & 0x40) /* MS */ - printf("%s: attempt to enable Master Mode\n", __FUNCTION__); -#endif s->format = value; - wm8750_set_format(s); + s->master = (value >> 6) & 1; /* MS */ + wm8750_clk_update(s, s->master); break; case WM8750_SRATE: /* Clocking and Sample Rate Control */ s->rate = &wm_rate_table[(value >> 1) & 0x1f]; - wm8750_set_format(s); + wm8750_clk_update(s, 0); break; case WM8750_RESET: /* Reset */ @@ -529,8 +601,6 @@ qemu_put_8s(f, &s->mpath[i]); qemu_put_8s(f, &s->format); qemu_put_8s(f, &s->power); - qemu_put_be32s(f, &s->inmask); - qemu_put_be32s(f, &s->outmask); qemu_put_byte(f, (s->rate - wm_rate_table) / sizeof(*s->rate)); i2c_slave_save(f, &s->i2c); } @@ -571,15 +641,11 @@ qemu_get_8s(f, &s->mpath[i]); qemu_get_8s(f, &s->format); qemu_get_8s(f, &s->power); - qemu_get_be32s(f, &s->inmask); - qemu_get_be32s(f, &s->outmask); s->rate = &wm_rate_table[(uint8_t) qemu_get_byte(f) & 0x1f]; i2c_slave_load(f, &s->i2c); return 0; } -static int wm8750_iid = 0; - i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio) { struct wm8750_s *s = (struct wm8750_s *) @@ -591,11 +657,12 @@ AUD_register_card(audio, CODEC, &s->card); wm8750_reset(&s->i2c); - register_savevm(CODEC, wm8750_iid ++, 0, wm8750_save, wm8750_load, s); + register_savevm(CODEC, -1, 0, wm8750_save, wm8750_load, s); return &s->i2c; } +#if 0 static void wm8750_fini(i2c_slave *i2c) { struct wm8750_s *s = (struct wm8750_s *) i2c; @@ -603,6 +670,7 @@ AUD_remove_card(&s->card); qemu_free(s); } +#endif void wm8750_data_req_set(i2c_slave *i2c, void (*data_req)(void *, int, int), void *opaque) @@ -615,22 +683,51 @@ void wm8750_dac_dat(void *opaque, uint32_t sample) { struct wm8750_s *s = (struct wm8750_s *) opaque; - uint32_t *data = (uint32_t *) &s->data_out[s->idx_out]; - *data = sample & s->outmask; + + *(uint32_t *) &s->data_out[s->idx_out] = sample; s->req_out -= 4; s->idx_out += 4; if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0) wm8750_out_flush(s); } +void *wm8750_dac_buffer(void *opaque, int samples) +{ + struct wm8750_s *s = (struct wm8750_s *) opaque; + /* XXX: Should check if there are samples free samples available */ + void *ret = s->data_out + s->idx_out; + + s->idx_out += samples << 2; + s->req_out -= samples << 2; + return ret; +} + +void wm8750_dac_commit(void *opaque) +{ + struct wm8750_s *s = (struct wm8750_s *) opaque; + + return wm8750_out_flush(s); +} + uint32_t wm8750_adc_dat(void *opaque) { struct wm8750_s *s = (struct wm8750_s *) opaque; uint32_t *data; + if (s->idx_in >= sizeof(s->data_in)) wm8750_in_load(s); + data = (uint32_t *) &s->data_in[s->idx_in]; s->req_in -= 4; s->idx_in += 4; - return *data & s->inmask; + return *data; +} + +void wm8750_set_bclk_in(void *opaque, int hz) +{ + struct wm8750_s *s = (struct wm8750_s *) opaque; + + s->ext_adc_hz = hz; + s->ext_dac_hz = hz; + wm8750_clk_update(s, 1); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/hw/zaurus.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/hw/zaurus.c --- qemu-0.9.1/hw/zaurus.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/hw/zaurus.c 2008-11-04 08:49:17.000000000 +0000 @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2006-2008 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include "hw.h" +#include "pxa.h" +#include "sharpsl.h" + +#undef REG_FMT +#if TARGET_PHYS_ADDR_BITS == 32 +#define REG_FMT "0x%02x" +#else +#define REG_FMT "0x%02lx" +#endif + +/* SCOOP devices */ + +struct scoop_info_s { + target_phys_addr_t target_base; + qemu_irq handler[16]; + qemu_irq *in; + uint16_t status; + uint16_t power; + uint32_t gpio_level; + uint32_t gpio_dir; + uint32_t prev_level; + + uint16_t mcr; + uint16_t cdr; + uint16_t ccr; + uint16_t irr; + uint16_t imr; + uint16_t isr; +}; + +#define SCOOP_MCR 0x00 +#define SCOOP_CDR 0x04 +#define SCOOP_CSR 0x08 +#define SCOOP_CPR 0x0c +#define SCOOP_CCR 0x10 +#define SCOOP_IRR_IRM 0x14 +#define SCOOP_IMR 0x18 +#define SCOOP_ISR 0x1c +#define SCOOP_GPCR 0x20 +#define SCOOP_GPWR 0x24 +#define SCOOP_GPRR 0x28 + +static inline void scoop_gpio_handler_update(struct scoop_info_s *s) { + uint32_t level, diff; + int bit; + level = s->gpio_level & s->gpio_dir; + + for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { + bit = ffs(diff) - 1; + qemu_set_irq(s->handler[bit], (level >> bit) & 1); + } + + s->prev_level = level; +} + +static uint32_t scoop_readb(void *opaque, target_phys_addr_t addr) +{ + struct scoop_info_s *s = (struct scoop_info_s *) opaque; + addr -= s->target_base; + + switch (addr) { + case SCOOP_MCR: + return s->mcr; + case SCOOP_CDR: + return s->cdr; + case SCOOP_CSR: + return s->status; + case SCOOP_CPR: + return s->power; + case SCOOP_CCR: + return s->ccr; + case SCOOP_IRR_IRM: + return s->irr; + case SCOOP_IMR: + return s->imr; + case SCOOP_ISR: + return s->isr; + case SCOOP_GPCR: + return s->gpio_dir; + case SCOOP_GPWR: + case SCOOP_GPRR: + return s->gpio_level; + default: + zaurus_printf("Bad register offset " REG_FMT "\n", addr); + } + + return 0; +} + +static void scoop_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + struct scoop_info_s *s = (struct scoop_info_s *) opaque; + addr -= s->target_base; + value &= 0xffff; + + switch (addr) { + case SCOOP_MCR: + s->mcr = value; + break; + case SCOOP_CDR: + s->cdr = value; + break; + case SCOOP_CPR: + s->power = value; + if (value & 0x80) + s->power |= 0x8040; + break; + case SCOOP_CCR: + s->ccr = value; + break; + case SCOOP_IRR_IRM: + s->irr = value; + break; + case SCOOP_IMR: + s->imr = value; + break; + case SCOOP_ISR: + s->isr = value; + break; + case SCOOP_GPCR: + s->gpio_dir = value; + scoop_gpio_handler_update(s); + break; + case SCOOP_GPWR: + case SCOOP_GPRR: /* GPRR is probably R/O in real HW */ + s->gpio_level = value & s->gpio_dir; + scoop_gpio_handler_update(s); + break; + default: + zaurus_printf("Bad register offset " REG_FMT "\n", addr); + } +} + +static CPUReadMemoryFunc *scoop_readfn[] = { + scoop_readb, + scoop_readb, + scoop_readb, +}; +static CPUWriteMemoryFunc *scoop_writefn[] = { + scoop_writeb, + scoop_writeb, + scoop_writeb, +}; + +void scoop_gpio_set(void *opaque, int line, int level) +{ + struct scoop_info_s *s = (struct scoop_info_s *) s; + + if (level) + s->gpio_level |= (1 << line); + else + s->gpio_level &= ~(1 << line); +} + +qemu_irq *scoop_gpio_in_get(struct scoop_info_s *s) +{ + return s->in; +} + +void scoop_gpio_out_set(struct scoop_info_s *s, int line, + qemu_irq handler) { + if (line >= 16) { + fprintf(stderr, "No GPIO pin %i\n", line); + exit(-1); + } + + s->handler[line] = handler; +} + +static void scoop_save(QEMUFile *f, void *opaque) +{ + struct scoop_info_s *s = (struct scoop_info_s *) opaque; + qemu_put_be16s(f, &s->status); + qemu_put_be16s(f, &s->power); + qemu_put_be32s(f, &s->gpio_level); + qemu_put_be32s(f, &s->gpio_dir); + qemu_put_be32s(f, &s->prev_level); + qemu_put_be16s(f, &s->mcr); + qemu_put_be16s(f, &s->cdr); + qemu_put_be16s(f, &s->ccr); + qemu_put_be16s(f, &s->irr); + qemu_put_be16s(f, &s->imr); + qemu_put_be16s(f, &s->isr); +} + +static int scoop_load(QEMUFile *f, void *opaque, int version_id) +{ + uint16_t dummy; + struct scoop_info_s *s = (struct scoop_info_s *) opaque; + qemu_get_be16s(f, &s->status); + qemu_get_be16s(f, &s->power); + qemu_get_be32s(f, &s->gpio_level); + qemu_get_be32s(f, &s->gpio_dir); + qemu_get_be32s(f, &s->prev_level); + qemu_get_be16s(f, &s->mcr); + qemu_get_be16s(f, &s->cdr); + qemu_get_be16s(f, &s->ccr); + qemu_get_be16s(f, &s->irr); + qemu_get_be16s(f, &s->imr); + qemu_get_be16s(f, &s->isr); + if (version_id < 1) + qemu_get_be16s(f, &dummy); + + return 0; +} + +struct scoop_info_s *scoop_init(struct pxa2xx_state_s *cpu, + int instance, + target_phys_addr_t target_base) { + int iomemtype; + struct scoop_info_s *s; + + s = (struct scoop_info_s *) + qemu_mallocz(sizeof(struct scoop_info_s)); + memset(s, 0, sizeof(struct scoop_info_s)); + + s->target_base = target_base; + s->status = 0x02; + s->in = qemu_allocate_irqs(scoop_gpio_set, s, 16); + iomemtype = cpu_register_io_memory(0, scoop_readfn, + scoop_writefn, s); + cpu_register_physical_memory(s->target_base, 0x1000, iomemtype); + register_savevm("scoop", instance, 1, scoop_save, scoop_load, s); + + return s; +} + +/* Write the bootloader parameters memory area. */ + +#define MAGIC_CHG(a, b, c, d) ((d << 24) | (c << 16) | (b << 8) | a) + +static struct __attribute__ ((__packed__)) sl_param_info { + uint32_t comadj_keyword; + int32_t comadj; + + uint32_t uuid_keyword; + char uuid[16]; + + uint32_t touch_keyword; + int32_t touch_xp; + int32_t touch_yp; + int32_t touch_xd; + int32_t touch_yd; + + uint32_t adadj_keyword; + int32_t adadj; + + uint32_t phad_keyword; + int32_t phadadj; +} zaurus_bootparam = { + .comadj_keyword = MAGIC_CHG('C', 'M', 'A', 'D'), + .comadj = 125, + .uuid_keyword = MAGIC_CHG('U', 'U', 'I', 'D'), + .uuid = { -1 }, + .touch_keyword = MAGIC_CHG('T', 'U', 'C', 'H'), + .touch_xp = -1, + .adadj_keyword = MAGIC_CHG('B', 'V', 'A', 'D'), + .adadj = -1, + .phad_keyword = MAGIC_CHG('P', 'H', 'A', 'D'), + .phadadj = 0x01, +}; + +void sl_bootparam_write(uint32_t ptr) +{ + memcpy(phys_ram_base + ptr, &zaurus_bootparam, + sizeof(struct sl_param_info)); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/i386-dis.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/i386-dis.c --- qemu-0.9.1/i386-dis.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/i386-dis.c 2008-10-02 19:29:22.000000000 +0100 @@ -37,6 +37,7 @@ #include #include "dis-asm.h" +#include "qemu-common.h" #define MAXLEN 20 @@ -59,7 +60,8 @@ static void oappend PARAMS ((const char *)); static void append_seg PARAMS ((void)); static void OP_indirE PARAMS ((int, int)); -static void print_operand_value PARAMS ((char *, int, bfd_vma)); +static void print_operand_value (char *buf, size_t bufsize, int hex, + bfd_vma disp); static void OP_E PARAMS ((int, int)); static void OP_G PARAMS ((int, int)); static bfd_vma get64 PARAMS ((void)); @@ -1129,63 +1131,63 @@ need to update onebyte_has_modrm or twobyte_has_modrm. */ #define MODRM_CHECK if (!need_modrm) abort () -static const char **names64; -static const char **names32; -static const char **names16; -static const char **names8; -static const char **names8rex; -static const char **names_seg; -static const char **index16; +static const char * const *names64; +static const char * const *names32; +static const char * const *names16; +static const char * const *names8; +static const char * const *names8rex; +static const char * const *names_seg; +static const char * const *index16; -static const char *intel_names64[] = { +static const char * const intel_names64[] = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" }; -static const char *intel_names32[] = { +static const char * const intel_names32[] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" }; -static const char *intel_names16[] = { +static const char * const intel_names16[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" }; -static const char *intel_names8[] = { +static const char * const intel_names8[] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", }; -static const char *intel_names8rex[] = { +static const char * const intel_names8rex[] = { "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" }; -static const char *intel_names_seg[] = { +static const char * const intel_names_seg[] = { "es", "cs", "ss", "ds", "fs", "gs", "?", "?", }; -static const char *intel_index16[] = { +static const char * const intel_index16[] = { "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx" }; -static const char *att_names64[] = { +static const char * const att_names64[] = { "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" }; -static const char *att_names32[] = { +static const char * const att_names32[] = { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi", "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d" }; -static const char *att_names16[] = { +static const char * const att_names16[] = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di", "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w" }; -static const char *att_names8[] = { +static const char * const att_names8[] = { "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh", }; -static const char *att_names8rex[] = { +static const char * const att_names8rex[] = { "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil", "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b" }; -static const char *att_names_seg[] = { +static const char * const att_names_seg[] = { "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "%?", "%?", }; -static const char *att_index16[] = { +static const char * const att_index16[] = { "%bx,%si", "%bx,%di", "%bp,%si", "%bp,%di", "%si", "%di", "%bp", "%bx" }; @@ -2432,7 +2434,7 @@ }, }; -static char *fgrps[][8] = { +static const char *fgrps[][8] = { /* d9_2 0 */ { "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", @@ -2512,7 +2514,7 @@ /* Instruction fnstsw is only one with strange arg. */ if (floatop == 0xdf && codep[-1] == 0xe0) - strcpy (op1out, names16[0]); + pstrcpy (op1out, sizeof(op1out), names16[0]); } else { @@ -2540,7 +2542,7 @@ int bytemode; int sizeflag; { - sprintf (scratchbuf, "%%st(%d)", rm); + snprintf (scratchbuf, sizeof(scratchbuf), "%%st(%d)", rm); oappend (scratchbuf + intel_syntax); } @@ -2573,7 +2575,7 @@ if (*p == '}') { /* Alternative not valid. */ - strcpy (obuf, "(bad)"); + pstrcpy (obuf, sizeof(obuf), "(bad)"); obufp = obuf + 5; return 1; } @@ -2874,10 +2876,7 @@ } static void -print_operand_value (buf, hex, disp) - char *buf; - int hex; - bfd_vma disp; +print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma disp) { if (mode_64bit) { @@ -2887,9 +2886,9 @@ int i; buf[0] = '0'; buf[1] = 'x'; - sprintf_vma (tmp, disp); + snprintf_vma (tmp, sizeof(tmp), disp); for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++); - strcpy (buf + 2, tmp + i); + pstrcpy (buf + 2, bufsize - 2, tmp + i); } else { @@ -2903,13 +2902,13 @@ /* Check for possible overflow on 0x8000000000000000. */ if (v < 0) { - strcpy (buf, "9223372036854775808"); + pstrcpy (buf, bufsize, "9223372036854775808"); return; } } if (!v) { - strcpy (buf, "0"); + pstrcpy (buf, bufsize, "0"); return; } @@ -2921,15 +2920,15 @@ v /= 10; i++; } - strcpy (buf, tmp + 29 - i); + pstrcpy (buf, bufsize, tmp + 29 - i); } } else { if (hex) - sprintf (buf, "0x%x", (unsigned int) disp); + snprintf (buf, bufsize, "0x%x", (unsigned int) disp); else - sprintf (buf, "%d", (int) disp); + snprintf (buf, bufsize, "%d", (int) disp); } } @@ -3054,7 +3053,7 @@ if (!intel_syntax) if (mod != 0 || (base & 7) == 5) { - print_operand_value (scratchbuf, !riprel, disp); + print_operand_value (scratchbuf, sizeof(scratchbuf), !riprel, disp); oappend (scratchbuf); if (riprel) { @@ -3115,14 +3114,14 @@ *obufp++ = separator_char; *obufp = '\0'; } - sprintf (scratchbuf, "%s", - mode_64bit && (sizeflag & AFLAG) - ? names64[index] : names32[index]); + snprintf (scratchbuf, sizeof(scratchbuf), "%s", + mode_64bit && (sizeflag & AFLAG) + ? names64[index] : names32[index]); } else - sprintf (scratchbuf, ",%s", - mode_64bit && (sizeflag & AFLAG) - ? names64[index] : names32[index]); + snprintf (scratchbuf, sizeof(scratchbuf), ",%s", + mode_64bit && (sizeflag & AFLAG) + ? names64[index] : names32[index]); oappend (scratchbuf); } if (!intel_syntax @@ -3133,7 +3132,7 @@ { *obufp++ = scale_char; *obufp = '\0'; - sprintf (scratchbuf, "%d", 1 << scale); + snprintf (scratchbuf, sizeof(scratchbuf), "%d", 1 << scale); oappend (scratchbuf); } } @@ -3149,7 +3148,8 @@ *obufp = '\0'; } - print_operand_value (scratchbuf, 0, disp); + print_operand_value (scratchbuf, sizeof(scratchbuf), 0, + disp); oappend (scratchbuf); } } @@ -3169,7 +3169,7 @@ oappend (names_seg[ds_reg - es_reg]); oappend (":"); } - print_operand_value (scratchbuf, 1, disp); + print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp); oappend (scratchbuf); } } @@ -3202,7 +3202,7 @@ if (!intel_syntax) if (mod != 0 || (rm & 7) == 6) { - print_operand_value (scratchbuf, 0, disp); + print_operand_value (scratchbuf, sizeof(scratchbuf), 0, disp); oappend (scratchbuf); } @@ -3504,7 +3504,7 @@ op &= mask; scratchbuf[0] = '$'; - print_operand_value (scratchbuf + 1, 1, op); + print_operand_value (scratchbuf + 1, sizeof(scratchbuf) - 1, 1, op); oappend (scratchbuf + intel_syntax); scratchbuf[0] = '\0'; } @@ -3557,7 +3557,7 @@ op &= mask; scratchbuf[0] = '$'; - print_operand_value (scratchbuf + 1, 1, op); + print_operand_value (scratchbuf + 1, sizeof(scratchbuf) - 1, 1, op); oappend (scratchbuf + intel_syntax); scratchbuf[0] = '\0'; } @@ -3609,7 +3609,7 @@ } scratchbuf[0] = '$'; - print_operand_value (scratchbuf + 1, 1, op); + print_operand_value (scratchbuf + 1, sizeof(scratchbuf) - 1, 1, op); oappend (scratchbuf + intel_syntax); } @@ -3647,7 +3647,7 @@ } disp = (start_pc + codep - start_codep + disp) & mask; set_op (disp, 0); - print_operand_value (scratchbuf, 1, disp); + print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp); oappend (scratchbuf); } @@ -3678,9 +3678,9 @@ } used_prefixes |= (prefixes & PREFIX_DATA); if (intel_syntax) - sprintf (scratchbuf, "0x%x,0x%x", seg, offset); + snprintf (scratchbuf, sizeof(scratchbuf), "0x%x,0x%x", seg, offset); else - sprintf (scratchbuf, "$0x%x,$0x%x", seg, offset); + snprintf (scratchbuf, sizeof(scratchbuf), "$0x%x,$0x%x", seg, offset); oappend (scratchbuf); } @@ -3707,7 +3707,7 @@ oappend (":"); } } - print_operand_value (scratchbuf, 1, off); + print_operand_value (scratchbuf, sizeof(scratchbuf), 1, off); oappend (scratchbuf); } @@ -3737,7 +3737,7 @@ oappend (":"); } } - print_operand_value (scratchbuf, 1, off); + print_operand_value (scratchbuf, sizeof(scratchbuf), 1, off); oappend (scratchbuf); } @@ -3806,7 +3806,7 @@ USED_REX (REX_EXTX); if (rex & REX_EXTX) add = 8; - sprintf (scratchbuf, "%%cr%d", reg + add); + snprintf (scratchbuf, sizeof(scratchbuf), "%%cr%d", reg + add); oappend (scratchbuf + intel_syntax); } @@ -3820,9 +3820,9 @@ if (rex & REX_EXTX) add = 8; if (intel_syntax) - sprintf (scratchbuf, "db%d", reg + add); + snprintf (scratchbuf, sizeof(scratchbuf), "db%d", reg + add); else - sprintf (scratchbuf, "%%db%d", reg + add); + snprintf (scratchbuf, sizeof(scratchbuf), "%%db%d", reg + add); oappend (scratchbuf); } @@ -3831,7 +3831,7 @@ int dummy; int sizeflag; { - sprintf (scratchbuf, "%%tr%d", reg); + snprintf (scratchbuf, sizeof(scratchbuf), "%%tr%d", reg); oappend (scratchbuf + intel_syntax); } @@ -3857,9 +3857,9 @@ add = 8; used_prefixes |= (prefixes & PREFIX_DATA); if (prefixes & PREFIX_DATA) - sprintf (scratchbuf, "%%xmm%d", reg + add); + snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", reg + add); else - sprintf (scratchbuf, "%%mm%d", reg + add); + snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", reg + add); oappend (scratchbuf + intel_syntax); } @@ -3872,7 +3872,7 @@ USED_REX (REX_EXTX); if (rex & REX_EXTX) add = 8; - sprintf (scratchbuf, "%%xmm%d", reg + add); + snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", reg + add); oappend (scratchbuf + intel_syntax); } @@ -3896,9 +3896,9 @@ codep++; used_prefixes |= (prefixes & PREFIX_DATA); if (prefixes & PREFIX_DATA) - sprintf (scratchbuf, "%%xmm%d", rm + add); + snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", rm + add); else - sprintf (scratchbuf, "%%mm%d", rm + add); + snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", rm + add); oappend (scratchbuf + intel_syntax); } @@ -3920,7 +3920,7 @@ /* Skip mod/rm byte. */ MODRM_CHECK; codep++; - sprintf (scratchbuf, "%%xmm%d", rm + add); + snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", rm + add); oappend (scratchbuf + intel_syntax); } @@ -4079,8 +4079,8 @@ suffix1 = 's', suffix2 = 'd'; } } - sprintf (scratchbuf, "cmp%s%c%c", - simd_cmp_op[cmp_type], suffix1, suffix2); + snprintf (scratchbuf, sizeof(scratchbuf), "cmp%s%c%c", + simd_cmp_op[cmp_type], suffix1, suffix2); used_prefixes |= (prefixes & PREFIX_REPZ); oappend (scratchbuf); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/i386.ld /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/i386.ld --- qemu-0.9.1/i386.ld 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/i386.ld 2008-05-31 17:21:33.000000000 +0100 @@ -69,6 +69,8 @@ /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ . = ALIGN(0x100000) + (. & (0x100000 - 1)); + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } .data : { *(.data) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/i386-vl.ld /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/i386-vl.ld --- qemu-0.9.1/i386-vl.ld 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/i386-vl.ld 1970-01-01 01:00:00.000000000 +0100 @@ -1,140 +0,0 @@ -/* ld script to make i386 Linux kernel - * Written by Martin Mares ; - */ -OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") -OUTPUT_ARCH(i386) -SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib); -ENTRY(_start) -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = 0xa8000000 + SIZEOF_HEADERS; - .interp : { *(.interp) } - .hash : { *(.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - .rel.text : - { *(.rel.text) *(.rel.gnu.linkonce.t*) } - .rela.text : - { *(.rela.text) *(.rela.gnu.linkonce.t*) } - .rel.data : - { *(.rel.data) *(.rel.gnu.linkonce.d*) } - .rela.data : - { *(.rela.data) *(.rela.gnu.linkonce.d*) } - .rel.rodata : - { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } - .rela.rodata : - { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.init : { *(.rel.init) } - .rela.init : { *(.rela.init) } - .rel.fini : { *(.rel.fini) } - .rela.fini : { *(.rela.fini) } - .rel.bss : { *(.rel.bss) } - .rela.bss : { *(.rela.bss) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : { *(.init) } =0x47ff041f - .text : - { - *(.text) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - *(.gnu.linkonce.t*) - } =0x47ff041f - _etext = .; - PROVIDE (etext = .); - .fini : { *(.fini) } =0x47ff041f - .rodata : { *(.rodata) *(.gnu.linkonce.r*) } - .rodata1 : { *(.rodata1) } - .reginfo : { *(.reginfo) } - __preinit_array_start = .; - .preinit_array : { *(.preinit_array) } - __preinit_array_end = .; - __init_array_start = .; - .init_array : { *(.init_array) } - __init_array_end = .; - __fini_array_start = .; - .fini_array : { *(.fini_array) } - __fini_array_end = .; - - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. */ - . = ALIGN(0x100000) + (. & (0x100000 - 1)); - .data : - { - *(.data) - *(.gnu.linkonce.d*) - CONSTRUCTORS - } - .data1 : { *(.data1) } - .ctors : - { - *(.ctors) - } - .dtors : - { - *(.dtors) - } - .plt : { *(.plt) } - .got : { *(.got.plt) *(.got) } - .dynamic : { *(.dynamic) } - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : { *(.sdata) } - _edata = .; - PROVIDE (edata = .); - __bss_start = .; - .sbss : { *(.sbss) *(.scommon) } - .bss : - { - *(.dynbss) - *(.bss) - *(COMMON) - } - _end = . ; - PROVIDE (end = .); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - /* These must appear regardless of . */ -} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/keymaps/ja /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/keymaps/ja --- qemu-0.9.1/keymaps/ja 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/keymaps/ja 2008-07-07 20:29:49.000000000 +0100 @@ -101,6 +101,7 @@ bar 0x7d shift underscore 0x73 shift Henkan_Mode 0x79 +Katakana_Real 0x70 Katakana 0x70 Muhenkan 0x7b Henkan_Mode_Real 0x79 diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/keymaps/modifiers /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/keymaps/modifiers --- qemu-0.9.1/keymaps/modifiers 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/keymaps/modifiers 2008-09-22 20:45:36.000000000 +0100 @@ -10,8 +10,8 @@ # Translate Super to Windows keys. # This is hardcoded. See documentation for details. -Super_R 0xdb -Super_L 0xdc +Super_R 0xdc +Super_L 0xdb # Translate Menu to the Windows Application key. Menu 0xdd diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/keymaps.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/keymaps.c --- qemu-0.9.1/keymaps.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/keymaps.c 2008-10-02 19:26:42.000000000 +0100 @@ -24,7 +24,7 @@ static int get_keysym(const char *name) { - name2keysym_t *p; + const name2keysym_t *p; for(p = name2keysym; p->name != NULL; p++) { if (!strcmp(p->name, name)) return p->keysym; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/kqemu.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/kqemu.c --- qemu-0.9.1/kqemu.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/kqemu.c 2008-06-08 02:55:09.000000000 +0100 @@ -1,7 +1,7 @@ /* * KQEMU support * - * Copyright (c) 2005 Fabrice Bellard + * Copyright (c) 2005-2008 Fabrice Bellard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -40,6 +40,7 @@ #include "cpu.h" #include "exec-all.h" +#include "qemu-common.h" #ifdef USE_KQEMU @@ -50,24 +51,14 @@ #include #include "kqemu.h" -/* compatibility stuff */ -#ifndef KQEMU_RET_SYSCALL -#define KQEMU_RET_SYSCALL 0x0300 /* syscall insn */ -#endif -#ifndef KQEMU_MAX_RAM_PAGES_TO_UPDATE -#define KQEMU_MAX_RAM_PAGES_TO_UPDATE 512 -#define KQEMU_RAM_PAGES_UPDATE_ALL (KQEMU_MAX_RAM_PAGES_TO_UPDATE + 1) -#endif -#ifndef KQEMU_MAX_MODIFIED_RAM_PAGES -#define KQEMU_MAX_MODIFIED_RAM_PAGES 512 -#endif - #ifdef _WIN32 #define KQEMU_DEVICE "\\\\.\\kqemu" #else #define KQEMU_DEVICE "/dev/kqemu" #endif +static void qpi_init(void); + #ifdef _WIN32 #define KQEMU_INVALID_FD INVALID_HANDLE_VALUE HANDLE kqemu_fd = KQEMU_INVALID_FD; @@ -83,14 +74,15 @@ 2 = kernel kqemu */ int kqemu_allowed = 1; -unsigned long *pages_to_flush; +uint64_t *pages_to_flush; unsigned int nb_pages_to_flush; -unsigned long *ram_pages_to_update; +uint64_t *ram_pages_to_update; unsigned int nb_ram_pages_to_update; -unsigned long *modified_ram_pages; +uint64_t *modified_ram_pages; unsigned int nb_modified_ram_pages; uint8_t *modified_ram_pages_table; -extern uint32_t **l1_phys_map; +int qpi_io_memory; +uint32_t kqemu_comm_base; /* physical address of the QPI communication page */ #define cpuid(index, eax, ebx, ecx, edx) \ asm volatile ("cpuid" \ @@ -160,7 +152,7 @@ int kqemu_init(CPUState *env) { - struct kqemu_init init; + struct kqemu_init kinit; int ret, version; #ifdef _WIN32 DWORD temp; @@ -174,14 +166,19 @@ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (kqemu_fd == KQEMU_INVALID_FD) { + fprintf(stderr, "Could not open '%s' - QEMU acceleration layer not activated: %lu\n", + KQEMU_DEVICE, GetLastError()); + return -1; + } #else kqemu_fd = open(KQEMU_DEVICE, O_RDWR); -#endif if (kqemu_fd == KQEMU_INVALID_FD) { fprintf(stderr, "Could not open '%s' - QEMU acceleration layer not activated: %s\n", KQEMU_DEVICE, strerror(errno)); return -1; } +#endif version = 0; #ifdef _WIN32 DeviceIoControl(kqemu_fd, KQEMU_GET_VERSION, NULL, 0, @@ -196,39 +193,35 @@ } pages_to_flush = qemu_vmalloc(KQEMU_MAX_PAGES_TO_FLUSH * - sizeof(unsigned long)); + sizeof(uint64_t)); if (!pages_to_flush) goto fail; ram_pages_to_update = qemu_vmalloc(KQEMU_MAX_RAM_PAGES_TO_UPDATE * - sizeof(unsigned long)); + sizeof(uint64_t)); if (!ram_pages_to_update) goto fail; modified_ram_pages = qemu_vmalloc(KQEMU_MAX_MODIFIED_RAM_PAGES * - sizeof(unsigned long)); + sizeof(uint64_t)); if (!modified_ram_pages) goto fail; modified_ram_pages_table = qemu_mallocz(phys_ram_size >> TARGET_PAGE_BITS); if (!modified_ram_pages_table) goto fail; - init.ram_base = phys_ram_base; - init.ram_size = phys_ram_size; - init.ram_dirty = phys_ram_dirty; - init.phys_to_ram_map = l1_phys_map; - init.pages_to_flush = pages_to_flush; -#if KQEMU_VERSION >= 0x010200 - init.ram_pages_to_update = ram_pages_to_update; -#endif -#if KQEMU_VERSION >= 0x010300 - init.modified_ram_pages = modified_ram_pages; -#endif + memset(&kinit, 0, sizeof(kinit)); /* set the paddings to zero */ + kinit.ram_base = phys_ram_base; + kinit.ram_size = phys_ram_size; + kinit.ram_dirty = phys_ram_dirty; + kinit.pages_to_flush = pages_to_flush; + kinit.ram_pages_to_update = ram_pages_to_update; + kinit.modified_ram_pages = modified_ram_pages; #ifdef _WIN32 - ret = DeviceIoControl(kqemu_fd, KQEMU_INIT, &init, sizeof(init), + ret = DeviceIoControl(kqemu_fd, KQEMU_INIT, &kinit, sizeof(kinit), NULL, 0, &temp, NULL) == TRUE ? 0 : -1; #else - ret = ioctl(kqemu_fd, KQEMU_INIT, &init); + ret = ioctl(kqemu_fd, KQEMU_INIT, &kinit); #endif if (ret < 0) { fprintf(stderr, "Error %d while initializing QEMU acceleration layer - disabling it for now\n", ret); @@ -241,6 +234,8 @@ env->kqemu_enabled = kqemu_allowed; nb_pages_to_flush = 0; nb_ram_pages_to_update = 0; + + qpi_init(); return 0; } @@ -271,7 +266,8 @@ { #ifdef DEBUG if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "kqemu_set_notdirty: addr=%08lx\n", ram_addr); + fprintf(logfile, "kqemu_set_notdirty: addr=%08lx\n", + (unsigned long)ram_addr); } #endif /* we only track transitions to dirty state */ @@ -326,6 +322,51 @@ } } +void kqemu_set_phys_mem(uint64_t start_addr, ram_addr_t size, + ram_addr_t phys_offset) +{ + struct kqemu_phys_mem kphys_mem1, *kphys_mem = &kphys_mem1; + uint64_t end; + int ret, io_index; + + end = (start_addr + size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; + start_addr &= TARGET_PAGE_MASK; + kphys_mem->phys_addr = start_addr; + kphys_mem->size = end - start_addr; + kphys_mem->ram_addr = phys_offset & TARGET_PAGE_MASK; + io_index = phys_offset & ~TARGET_PAGE_MASK; + switch(io_index) { + case IO_MEM_RAM: + kphys_mem->io_index = KQEMU_IO_MEM_RAM; + break; + case IO_MEM_ROM: + kphys_mem->io_index = KQEMU_IO_MEM_ROM; + break; + default: + if (qpi_io_memory == io_index) { + kphys_mem->io_index = KQEMU_IO_MEM_COMM; + } else { + kphys_mem->io_index = KQEMU_IO_MEM_UNASSIGNED; + } + break; + } +#ifdef _WIN32 + { + DWORD temp; + ret = DeviceIoControl(kqemu_fd, KQEMU_SET_PHYS_MEM, + kphys_mem, sizeof(*kphys_mem), + NULL, 0, &temp, NULL) == TRUE ? 0 : -1; + } +#else + ret = ioctl(kqemu_fd, KQEMU_SET_PHYS_MEM, kphys_mem); +#endif + if (ret < 0) { + fprintf(stderr, "kqemu: KQEMU_SET_PHYS_PAGE error=%d: start_addr=0x%016" PRIx64 " size=0x%08lx phys_offset=0x%08lx\n", + ret, start_addr, + (unsigned long)size, (unsigned long)phys_offset); + } +} + struct fpstate { uint16_t fpuc; uint16_t dummy1; @@ -473,7 +514,7 @@ int selector; selector = (env->star >> 32) & 0xffff; -#ifdef __x86_64__ +#ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { int code64; @@ -630,6 +671,24 @@ } #endif +static inline void kqemu_load_seg(struct kqemu_segment_cache *ksc, + const SegmentCache *sc) +{ + ksc->selector = sc->selector; + ksc->flags = sc->flags; + ksc->limit = sc->limit; + ksc->base = sc->base; +} + +static inline void kqemu_save_seg(SegmentCache *sc, + const struct kqemu_segment_cache *ksc) +{ + sc->selector = ksc->selector; + sc->flags = ksc->flags; + sc->limit = ksc->limit; + sc->base = ksc->base; +} + int kqemu_cpu_exec(CPUState *env) { struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state; @@ -637,7 +696,6 @@ #ifdef CONFIG_PROFILER int64_t ti; #endif - #ifdef _WIN32 DWORD temp; #endif @@ -651,35 +709,33 @@ cpu_dump_state(env, logfile, fprintf, 0); } #endif - memcpy(kenv->regs, env->regs, sizeof(kenv->regs)); + for(i = 0; i < CPU_NB_REGS; i++) + kenv->regs[i] = env->regs[i]; kenv->eip = env->eip; kenv->eflags = env->eflags; - memcpy(&kenv->segs, &env->segs, sizeof(env->segs)); - memcpy(&kenv->ldt, &env->ldt, sizeof(env->ldt)); - memcpy(&kenv->tr, &env->tr, sizeof(env->tr)); - memcpy(&kenv->gdt, &env->gdt, sizeof(env->gdt)); - memcpy(&kenv->idt, &env->idt, sizeof(env->idt)); + for(i = 0; i < 6; i++) + kqemu_load_seg(&kenv->segs[i], &env->segs[i]); + kqemu_load_seg(&kenv->ldt, &env->ldt); + kqemu_load_seg(&kenv->tr, &env->tr); + kqemu_load_seg(&kenv->gdt, &env->gdt); + kqemu_load_seg(&kenv->idt, &env->idt); kenv->cr0 = env->cr[0]; kenv->cr2 = env->cr[2]; kenv->cr3 = env->cr[3]; kenv->cr4 = env->cr[4]; kenv->a20_mask = env->a20_mask; -#if KQEMU_VERSION >= 0x010100 kenv->efer = env->efer; -#endif -#if KQEMU_VERSION >= 0x010300 kenv->tsc_offset = 0; kenv->star = env->star; kenv->sysenter_cs = env->sysenter_cs; kenv->sysenter_esp = env->sysenter_esp; kenv->sysenter_eip = env->sysenter_eip; -#ifdef __x86_64__ +#ifdef TARGET_X86_64 kenv->lstar = env->lstar; kenv->cstar = env->cstar; kenv->fmask = env->fmask; kenv->kernelgsbase = env->kernelgsbase; #endif -#endif if (env->dr[7] & 0xff) { kenv->dr7 = env->dr[7]; kenv->dr0 = env->dr[0]; @@ -693,15 +749,11 @@ cpl = (env->hflags & HF_CPL_MASK); kenv->cpl = cpl; kenv->nb_pages_to_flush = nb_pages_to_flush; -#if KQEMU_VERSION >= 0x010200 kenv->user_only = (env->kqemu_enabled == 1); kenv->nb_ram_pages_to_update = nb_ram_pages_to_update; -#endif nb_ram_pages_to_update = 0; - -#if KQEMU_VERSION >= 0x010300 kenv->nb_modified_ram_pages = nb_modified_ram_pages; -#endif + kqemu_reset_modified_ram_pages(); if (env->cpuid_features & CPUID_FXSR) @@ -719,41 +771,30 @@ ret = -1; } #else -#if KQEMU_VERSION >= 0x010100 ioctl(kqemu_fd, KQEMU_EXEC, kenv); ret = kenv->retval; -#else - ret = ioctl(kqemu_fd, KQEMU_EXEC, kenv); -#endif #endif if (env->cpuid_features & CPUID_FXSR) save_native_fp_fxsave(env); else save_native_fp_fsave(env); - memcpy(env->regs, kenv->regs, sizeof(env->regs)); + for(i = 0; i < CPU_NB_REGS; i++) + env->regs[i] = kenv->regs[i]; env->eip = kenv->eip; env->eflags = kenv->eflags; - memcpy(env->segs, kenv->segs, sizeof(env->segs)); + for(i = 0; i < 6; i++) + kqemu_save_seg(&env->segs[i], &kenv->segs[i]); cpu_x86_set_cpl(env, kenv->cpl); - memcpy(&env->ldt, &kenv->ldt, sizeof(env->ldt)); -#if 0 - /* no need to restore that */ - memcpy(env->tr, kenv->tr, sizeof(env->tr)); - memcpy(env->gdt, kenv->gdt, sizeof(env->gdt)); - memcpy(env->idt, kenv->idt, sizeof(env->idt)); - env->a20_mask = kenv->a20_mask; -#endif + kqemu_save_seg(&env->ldt, &kenv->ldt); env->cr[0] = kenv->cr0; env->cr[4] = kenv->cr4; env->cr[3] = kenv->cr3; env->cr[2] = kenv->cr2; env->dr[6] = kenv->dr6; -#if KQEMU_VERSION >= 0x010300 -#ifdef __x86_64__ +#ifdef TARGET_X86_64 env->kernelgsbase = kenv->kernelgsbase; #endif -#endif /* flush pages as indicated by kqemu */ if (kenv->nb_pages_to_flush >= KQEMU_FLUSH_ALL) { @@ -770,13 +811,10 @@ kqemu_exec_count++; #endif -#if KQEMU_VERSION >= 0x010200 if (kenv->nb_ram_pages_to_update > 0) { cpu_tlb_update_dirty(env); } -#endif -#if KQEMU_VERSION >= 0x010300 if (kenv->nb_modified_ram_pages > 0) { for(i = 0; i < kenv->nb_modified_ram_pages; i++) { unsigned long addr; @@ -784,7 +822,6 @@ tb_invalidate_phys_page_range(addr, addr + TARGET_PAGE_SIZE, 0); } } -#endif /* restore the hidden flags */ { @@ -904,11 +941,85 @@ void kqemu_cpu_interrupt(CPUState *env) { -#if defined(_WIN32) && KQEMU_VERSION >= 0x010101 +#if defined(_WIN32) /* cancelling the I/O request causes KQEMU to finish executing the current block and successfully returning. */ CancelIo(kqemu_fd); #endif } +/* + QEMU paravirtualization interface. The current interface only + allows to modify the IF and IOPL flags when running in + kqemu. + + At this point it is not very satisfactory. I leave it for reference + as it adds little complexity. +*/ + +#define QPI_COMM_PAGE_PHYS_ADDR 0xff000000 + +static uint32_t qpi_mem_readb(void *opaque, target_phys_addr_t addr) +{ + return 0; +} + +static uint32_t qpi_mem_readw(void *opaque, target_phys_addr_t addr) +{ + return 0; +} + +static void qpi_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +} + +static void qpi_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +} + +static uint32_t qpi_mem_readl(void *opaque, target_phys_addr_t addr) +{ + CPUState *env; + + env = cpu_single_env; + if (!env) + return 0; + return env->eflags & (IF_MASK | IOPL_MASK); +} + +/* Note: after writing to this address, the guest code must make sure + it is exiting the current TB. pushf/popf can be used for that + purpose. */ +static void qpi_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + CPUState *env; + + env = cpu_single_env; + if (!env) + return; + env->eflags = (env->eflags & ~(IF_MASK | IOPL_MASK)) | + (val & (IF_MASK | IOPL_MASK)); +} + +static CPUReadMemoryFunc *qpi_mem_read[3] = { + qpi_mem_readb, + qpi_mem_readw, + qpi_mem_readl, +}; + +static CPUWriteMemoryFunc *qpi_mem_write[3] = { + qpi_mem_writeb, + qpi_mem_writew, + qpi_mem_writel, +}; + +static void qpi_init(void) +{ + kqemu_comm_base = 0xff000000 | 1; + qpi_io_memory = cpu_register_io_memory(0, + qpi_mem_read, + qpi_mem_write, NULL); + cpu_register_physical_memory(kqemu_comm_base & ~0xfff, + 0x1000, qpi_io_memory); +} #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/kqemu.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/kqemu.h --- qemu-0.9.1/kqemu.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/kqemu.h 2008-05-30 21:48:25.000000000 +0100 @@ -1,8 +1,8 @@ /* * KQEMU header - * - * Copyright (c) 2004-2006 Fabrice Bellard - * + * + * Copyright (c) 2004-2008 Fabrice Bellard + * * 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 @@ -24,25 +24,27 @@ #ifndef KQEMU_H #define KQEMU_H -#define KQEMU_VERSION 0x010300 +#if defined(__i386__) +#define KQEMU_PAD32(x) x +#else +#define KQEMU_PAD32(x) +#endif + +#define KQEMU_VERSION 0x010400 struct kqemu_segment_cache { - uint32_t selector; - unsigned long base; - uint32_t limit; + uint16_t selector; + uint16_t padding1; uint32_t flags; + uint64_t base; + uint32_t limit; + uint32_t padding2; }; struct kqemu_cpu_state { -#ifdef __x86_64__ - unsigned long regs[16]; -#else - unsigned long regs[8]; -#endif - unsigned long eip; - unsigned long eflags; - - uint32_t dummy0, dummy1, dumm2, dummy3, dummy4; + uint64_t regs[16]; + uint64_t eip; + uint64_t eflags; struct kqemu_segment_cache segs[6]; /* selector values */ struct kqemu_segment_cache ldt; @@ -50,63 +52,81 @@ struct kqemu_segment_cache gdt; /* only base and limit are used */ struct kqemu_segment_cache idt; /* only base and limit are used */ - unsigned long cr0; - unsigned long dummy5; - unsigned long cr2; - unsigned long cr3; - unsigned long cr4; - uint32_t a20_mask; + uint64_t cr0; + uint64_t cr2; + uint64_t cr3; + uint64_t cr4; + uint64_t a20_mask; /* sysenter registers */ - uint32_t sysenter_cs; - uint32_t sysenter_esp; - uint32_t sysenter_eip; - uint64_t efer __attribute__((aligned(8))); + uint64_t sysenter_cs; + uint64_t sysenter_esp; + uint64_t sysenter_eip; + uint64_t efer; uint64_t star; -#ifdef __x86_64__ - unsigned long lstar; - unsigned long cstar; - unsigned long fmask; - unsigned long kernelgsbase; -#endif + + uint64_t lstar; + uint64_t cstar; + uint64_t fmask; + uint64_t kernelgsbase; + uint64_t tsc_offset; - unsigned long dr0; - unsigned long dr1; - unsigned long dr2; - unsigned long dr3; - unsigned long dr6; - unsigned long dr7; + uint64_t dr0; + uint64_t dr1; + uint64_t dr2; + uint64_t dr3; + uint64_t dr6; + uint64_t dr7; uint8_t cpl; uint8_t user_only; + uint16_t padding1; uint32_t error_code; /* error_code when exiting with an exception */ - unsigned long next_eip; /* next eip value when exiting with an interrupt */ - unsigned int nb_pages_to_flush; /* number of pages to flush, + uint64_t next_eip; /* next eip value when exiting with an interrupt */ + uint32_t nb_pages_to_flush; /* number of pages to flush, KQEMU_FLUSH_ALL means full flush */ #define KQEMU_MAX_PAGES_TO_FLUSH 512 #define KQEMU_FLUSH_ALL (KQEMU_MAX_PAGES_TO_FLUSH + 1) - long retval; + int32_t retval; /* number of ram_dirty entries to update */ - unsigned int nb_ram_pages_to_update; + uint32_t nb_ram_pages_to_update; #define KQEMU_MAX_RAM_PAGES_TO_UPDATE 512 #define KQEMU_RAM_PAGES_UPDATE_ALL (KQEMU_MAX_RAM_PAGES_TO_UPDATE + 1) #define KQEMU_MAX_MODIFIED_RAM_PAGES 512 - unsigned int nb_modified_ram_pages; + uint32_t nb_modified_ram_pages; }; struct kqemu_init { uint8_t *ram_base; /* must be page aligned */ - unsigned long ram_size; /* must be multiple of 4 KB */ + KQEMU_PAD32(uint32_t padding1;) + uint64_t ram_size; /* must be multiple of 4 KB */ uint8_t *ram_dirty; /* must be page aligned */ - uint32_t **phys_to_ram_map; /* must be page aligned */ - unsigned long *pages_to_flush; /* must be page aligned */ - unsigned long *ram_pages_to_update; /* must be page aligned */ - unsigned long *modified_ram_pages; /* must be page aligned */ + KQEMU_PAD32(uint32_t padding2;) + uint64_t *pages_to_flush; /* must be page aligned */ + KQEMU_PAD32(uint32_t padding4;) + uint64_t *ram_pages_to_update; /* must be page aligned */ + KQEMU_PAD32(uint32_t padding5;) + uint64_t *modified_ram_pages; /* must be page aligned */ + KQEMU_PAD32(uint32_t padding6;) +}; + +#define KQEMU_IO_MEM_RAM 0 +#define KQEMU_IO_MEM_ROM 1 +#define KQEMU_IO_MEM_COMM 2 /* kqemu communication page */ +#define KQEMU_IO_MEM_UNASSIGNED 3 /* any device: return to application */ + +struct kqemu_phys_mem { + uint64_t phys_addr; /* physical address range: phys_addr, + phys_addr + size */ + uint64_t size; + uint64_t ram_addr; /* corresponding ram address */ + uint32_t io_index; /* memory type: see KQEMU_IO_MEM_xxx */ + uint32_t padding1; }; #define KQEMU_RET_ABORT (-1) @@ -122,11 +142,13 @@ #define KQEMU_INIT CTL_CODE(FILE_DEVICE_UNKNOWN, 2, METHOD_BUFFERED, FILE_WRITE_ACCESS) #define KQEMU_GET_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN, 3, METHOD_BUFFERED, FILE_READ_ACCESS) #define KQEMU_MODIFY_RAM_PAGES CTL_CODE(FILE_DEVICE_UNKNOWN, 4, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define KQEMU_SET_PHYS_MEM CTL_CODE(FILE_DEVICE_UNKNOWN, 5, METHOD_BUFFERED, FILE_WRITE_ACCESS) #else #define KQEMU_EXEC _IOWR('q', 1, struct kqemu_cpu_state) #define KQEMU_INIT _IOW('q', 2, struct kqemu_init) #define KQEMU_GET_VERSION _IOR('q', 3, int) #define KQEMU_MODIFY_RAM_PAGES _IOW('q', 4, int) +#define KQEMU_SET_PHYS_MEM _IOW('q', 5, struct kqemu_phys_mem) #endif #endif /* KQEMU_H */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/kvm-all.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/kvm-all.c --- qemu-0.9.1/kvm-all.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/kvm-all.c 2008-11-10 15:55:14.000000000 +0000 @@ -0,0 +1,379 @@ +/* + * QEMU KVM support + * + * Copyright IBM, Corp. 2008 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include +#include +#include + +#include + +#include "qemu-common.h" +#include "sysemu.h" +#include "kvm.h" + +//#define DEBUG_KVM + +#ifdef DEBUG_KVM +#define dprintf(fmt, ...) \ + do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) +#else +#define dprintf(fmt, ...) \ + do { } while (0) +#endif + +typedef struct kvm_userspace_memory_region KVMSlot; + +int kvm_allowed = 0; + +struct KVMState +{ + KVMSlot slots[32]; + int fd; + int vmfd; +}; + +static KVMState *kvm_state; + +static KVMSlot *kvm_alloc_slot(KVMState *s) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(s->slots); i++) { + if (s->slots[i].memory_size == 0) + return &s->slots[i]; + } + + return NULL; +} + +static KVMSlot *kvm_lookup_slot(KVMState *s, target_phys_addr_t start_addr) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(s->slots); i++) { + KVMSlot *mem = &s->slots[i]; + + if (start_addr >= mem->guest_phys_addr && + start_addr < (mem->guest_phys_addr + mem->memory_size)) + return mem; + } + + return NULL; +} + +int kvm_init_vcpu(CPUState *env) +{ + KVMState *s = kvm_state; + long mmap_size; + int ret; + + dprintf("kvm_init_vcpu\n"); + + ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, + (void *)(unsigned long)env->cpu_index); + if (ret < 0) { + dprintf("kvm_create_vcpu failed\n"); + goto err; + } + + env->kvm_fd = ret; + env->kvm_state = s; + + mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0); + if (mmap_size < 0) { + dprintf("KVM_GET_VCPU_MMAP_SIZE failed\n"); + goto err; + } + + env->kvm_run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, + env->kvm_fd, 0); + if (env->kvm_run == MAP_FAILED) { + ret = -errno; + dprintf("mmap'ing vcpu state failed\n"); + goto err; + } + + ret = kvm_arch_init_vcpu(env); + +err: + return ret; +} + +int kvm_init(int smp_cpus) +{ + KVMState *s; + int ret; + int i; + + if (smp_cpus > 1) + return -EINVAL; + + s = qemu_mallocz(sizeof(KVMState)); + if (s == NULL) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(s->slots); i++) + s->slots[i].slot = i; + + s->vmfd = -1; + s->fd = open("/dev/kvm", O_RDWR); + if (s->fd == -1) { + fprintf(stderr, "Could not access KVM kernel module: %m\n"); + ret = -errno; + goto err; + } + + ret = kvm_ioctl(s, KVM_GET_API_VERSION, 0); + if (ret < KVM_API_VERSION) { + if (ret > 0) + ret = -EINVAL; + fprintf(stderr, "kvm version too old\n"); + goto err; + } + + if (ret > KVM_API_VERSION) { + ret = -EINVAL; + fprintf(stderr, "kvm version not supported\n"); + goto err; + } + + s->vmfd = kvm_ioctl(s, KVM_CREATE_VM, 0); + if (s->vmfd < 0) + goto err; + + /* initially, KVM allocated its own memory and we had to jump through + * hooks to make phys_ram_base point to this. Modern versions of KVM + * just use a user allocated buffer so we can use phys_ram_base + * unmodified. Make sure we have a sufficiently modern version of KVM. + */ + ret = kvm_ioctl(s, KVM_CHECK_EXTENSION, (void *)KVM_CAP_USER_MEMORY); + if (ret <= 0) { + if (ret == 0) + ret = -EINVAL; + fprintf(stderr, "kvm does not support KVM_CAP_USER_MEMORY\n"); + goto err; + } + + ret = kvm_arch_init(s, smp_cpus); + if (ret < 0) + goto err; + + kvm_state = s; + + return 0; + +err: + if (s) { + if (s->vmfd != -1) + close(s->vmfd); + if (s->fd != -1) + close(s->fd); + } + qemu_free(s); + + return ret; +} + +static int kvm_handle_io(CPUState *env, uint16_t port, void *data, + int direction, int size, uint32_t count) +{ + int i; + uint8_t *ptr = data; + + for (i = 0; i < count; i++) { + if (direction == KVM_EXIT_IO_IN) { + switch (size) { + case 1: + stb_p(ptr, cpu_inb(env, port)); + break; + case 2: + stw_p(ptr, cpu_inw(env, port)); + break; + case 4: + stl_p(ptr, cpu_inl(env, port)); + break; + } + } else { + switch (size) { + case 1: + cpu_outb(env, port, ldub_p(ptr)); + break; + case 2: + cpu_outw(env, port, lduw_p(ptr)); + break; + case 4: + cpu_outl(env, port, ldl_p(ptr)); + break; + } + } + + ptr += size; + } + + return 1; +} + +int kvm_cpu_exec(CPUState *env) +{ + struct kvm_run *run = env->kvm_run; + int ret; + + dprintf("kvm_cpu_exec()\n"); + + do { + kvm_arch_pre_run(env, run); + + if ((env->interrupt_request & CPU_INTERRUPT_EXIT)) { + dprintf("interrupt exit requested\n"); + ret = 0; + break; + } + + ret = kvm_vcpu_ioctl(env, KVM_RUN, 0); + kvm_arch_post_run(env, run); + + if (ret == -EINTR || ret == -EAGAIN) { + dprintf("io window exit\n"); + ret = 0; + break; + } + + if (ret < 0) { + dprintf("kvm run failed %s\n", strerror(-ret)); + abort(); + } + + ret = 0; /* exit loop */ + switch (run->exit_reason) { + case KVM_EXIT_IO: + dprintf("handle_io\n"); + ret = kvm_handle_io(env, run->io.port, + (uint8_t *)run + run->io.data_offset, + run->io.direction, + run->io.size, + run->io.count); + break; + case KVM_EXIT_MMIO: + dprintf("handle_mmio\n"); + cpu_physical_memory_rw(run->mmio.phys_addr, + run->mmio.data, + run->mmio.len, + run->mmio.is_write); + ret = 1; + break; + case KVM_EXIT_IRQ_WINDOW_OPEN: + dprintf("irq_window_open\n"); + break; + case KVM_EXIT_SHUTDOWN: + dprintf("shutdown\n"); + qemu_system_reset_request(); + ret = 1; + break; + case KVM_EXIT_UNKNOWN: + dprintf("kvm_exit_unknown\n"); + break; + case KVM_EXIT_FAIL_ENTRY: + dprintf("kvm_exit_fail_entry\n"); + break; + case KVM_EXIT_EXCEPTION: + dprintf("kvm_exit_exception\n"); + break; + case KVM_EXIT_DEBUG: + dprintf("kvm_exit_debug\n"); + break; + default: + dprintf("kvm_arch_handle_exit\n"); + ret = kvm_arch_handle_exit(env, run); + break; + } + } while (ret > 0); + + if ((env->interrupt_request & CPU_INTERRUPT_EXIT)) { + env->interrupt_request &= ~CPU_INTERRUPT_EXIT; + env->exception_index = EXCP_INTERRUPT; + } + + return ret; +} + +void kvm_set_phys_mem(target_phys_addr_t start_addr, + ram_addr_t size, + ram_addr_t phys_offset) +{ + KVMState *s = kvm_state; + ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK; + KVMSlot *mem; + + /* KVM does not support read-only slots */ + phys_offset &= ~IO_MEM_ROM; + + mem = kvm_lookup_slot(s, start_addr); + if (mem) { + if (flags == IO_MEM_UNASSIGNED) { + mem->memory_size = 0; + mem->guest_phys_addr = start_addr; + mem->userspace_addr = 0; + mem->flags = 0; + + kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, mem); + } else if (start_addr >= mem->guest_phys_addr && + (start_addr + size) <= (mem->guest_phys_addr + mem->memory_size)) + return; + } + + /* KVM does not need to know about this memory */ + if (flags >= IO_MEM_UNASSIGNED) + return; + + mem = kvm_alloc_slot(s); + mem->memory_size = size; + mem->guest_phys_addr = start_addr; + mem->userspace_addr = (unsigned long)(phys_ram_base + phys_offset); + mem->flags = 0; + + kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, mem); + /* FIXME deal with errors */ +} + +int kvm_ioctl(KVMState *s, int type, void *data) +{ + int ret; + + ret = ioctl(s->fd, type, data); + if (ret == -1) + ret = -errno; + + return ret; +} + +int kvm_vm_ioctl(KVMState *s, int type, void *data) +{ + int ret; + + ret = ioctl(s->vmfd, type, data); + if (ret == -1) + ret = -errno; + + return ret; +} + +int kvm_vcpu_ioctl(CPUState *env, int type, void *data) +{ + int ret; + + ret = ioctl(env->kvm_fd, type, data); + if (ret == -1) + ret = -errno; + + return ret; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/kvm.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/kvm.h --- qemu-0.9.1/kvm.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/kvm.h 2008-11-05 16:29:27.000000000 +0000 @@ -0,0 +1,68 @@ +/* + * QEMU KVM support + * + * Copyright IBM, Corp. 2008 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_KVM_H +#define QEMU_KVM_H + +#include "config.h" + +#ifdef CONFIG_KVM +extern int kvm_allowed; + +#define kvm_enabled() (kvm_allowed) +#else +#define kvm_enabled() (0) +#endif + +struct kvm_run; + +/* external API */ + +int kvm_init(int smp_cpus); + +int kvm_init_vcpu(CPUState *env); + +int kvm_cpu_exec(CPUState *env); + +void kvm_set_phys_mem(target_phys_addr_t start_addr, + ram_addr_t size, + ram_addr_t phys_offset); + +/* internal API */ + +struct KVMState; +typedef struct KVMState KVMState; + +int kvm_ioctl(KVMState *s, int type, void *data); + +int kvm_vm_ioctl(KVMState *s, int type, void *data); + +int kvm_vcpu_ioctl(CPUState *env, int type, void *data); + +/* Arch specific hooks */ + +int kvm_arch_post_run(CPUState *env, struct kvm_run *run); + +int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run); + +int kvm_arch_pre_run(CPUState *env, struct kvm_run *run); + +int kvm_arch_get_registers(CPUState *env); + +int kvm_arch_put_registers(CPUState *env); + +int kvm_arch_init(KVMState *s, int smp_cpus); + +int kvm_arch_init_vcpu(CPUState *env); + +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/LICENSE /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/LICENSE --- qemu-0.9.1/LICENSE 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/LICENSE 2008-02-01 10:50:11.000000000 +0000 @@ -10,6 +10,9 @@ released under the GNU Lesser General Public License. Many hardware device emulation sources are released under the BSD license. -3) QEMU is a trademark of Fabrice Bellard. +3) The Tiny Code Generator (TCG) is released under the BSD license + (see license headers in files). + +4) QEMU is a trademark of Fabrice Bellard. Fabrice Bellard. \ No newline at end of file diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/alpha/termbits.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/alpha/termbits.h --- qemu-0.9.1/linux-user/alpha/termbits.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/alpha/termbits.h 2008-11-12 10:01:12.000000000 +0000 @@ -157,44 +157,44 @@ #define TARGET_PENDIN 0x20000000 #define TARGET_IEXTEN 0x00000400 -#define TARGET_FIOCLEX _IO('f', 1) -#define TARGET_FIONCLEX _IO('f', 2) -#define TARGET_FIOASYNC _IOW('f', 125, int) -#define TARGET_FIONBIO _IOW('f', 126, int) -#define TARGET_FIONREAD _IOR('f', 127, int) +#define TARGET_FIOCLEX TARGET_IO('f', 1) +#define TARGET_FIONCLEX TARGET_IO('f', 2) +#define TARGET_FIOASYNC TARGET_IOW('f', 125, int) +#define TARGET_FIONBIO TARGET_IOW('f', 126, int) +#define TARGET_FIONREAD TARGET_IOR('f', 127, int) #define TARGET_TIOCINQ FIONREAD -#define TARGET_FIOQSIZE _IOR('f', 128, loff_t) +#define TARGET_FIOQSIZE TARGET_IOR('f', 128, loff_t) -#define TARGET_TIOCGETP _IOR('t', 8, struct sgttyb) -#define TARGET_TIOCSETP _IOW('t', 9, struct sgttyb) -#define TARGET_TIOCSETN _IOW('t', 10, struct sgttyb) /* TIOCSETP wo flush */ - -#define TARGET_TIOCSETC _IOW('t', 17, struct tchars) -#define TARGET_TIOCGETC _IOR('t', 18, struct tchars) -#define TARGET_TCGETS _IOR('t', 19, struct termios) -#define TARGET_TCSETS _IOW('t', 20, struct termios) -#define TARGET_TCSETSW _IOW('t', 21, struct termios) -#define TARGET_TCSETSF _IOW('t', 22, struct termios) - -#define TARGET_TCGETA _IOR('t', 23, struct termio) -#define TARGET_TCSETA _IOW('t', 24, struct termio) -#define TARGET_TCSETAW _IOW('t', 25, struct termio) -#define TARGET_TCSETAF _IOW('t', 28, struct termio) - -#define TARGET_TCSBRK _IO('t', 29) -#define TARGET_TCXONC _IO('t', 30) -#define TARGET_TCFLSH _IO('t', 31) - -#define TARGET_TIOCSWINSZ _IOW('t', 103, struct winsize) -#define TARGET_TIOCGWINSZ _IOR('t', 104, struct winsize) -#define TARGET_TIOCSTART _IO('t', 110) /* start output, like ^Q */ -#define TARGET_TIOCSTOP _IO('t', 111) /* stop output, like ^S */ -#define TARGET_TIOCOUTQ _IOR('t', 115, int) /* output queue size */ - -#define TARGET_TIOCGLTC _IOR('t', 116, struct ltchars) -#define TARGET_TIOCSLTC _IOW('t', 117, struct ltchars) -#define TARGET_TIOCSPGRP _IOW('t', 118, int) -#define TARGET_TIOCGPGRP _IOR('t', 119, int) +#define TARGET_TIOCGETP TARGET_IOR('t', 8, struct target_sgttyb) +#define TARGET_TIOCSETP TARGET_IOW('t', 9, struct target_sgttyb) +#define TARGET_TIOCSETN TARGET_IOW('t', 10, struct target_sgttyb) /* TIOCSETP wo flush */ + +#define TARGET_TIOCSETC TARGET_IOW('t', 17, struct target_tchars) +#define TARGET_TIOCGETC TARGET_IOR('t', 18, struct target_tchars) +#define TARGET_TCGETS TARGET_IOR('t', 19, struct target_termios) +#define TARGET_TCSETS TARGET_IOW('t', 20, struct target_termios) +#define TARGET_TCSETSW TARGET_IOW('t', 21, struct target_termios) +#define TARGET_TCSETSF TARGET_IOW('t', 22, struct target_termios) + +#define TARGET_TCGETA TARGET_IOR('t', 23, struct target_termio) +#define TARGET_TCSETA TARGET_IOW('t', 24, struct target_termio) +#define TARGET_TCSETAW TARGET_IOW('t', 25, struct target_termio) +#define TARGET_TCSETAF TARGET_IOW('t', 28, struct target_termio) + +#define TARGET_TCSBRK TARGET_IO('t', 29) +#define TARGET_TCXONC TARGET_IO('t', 30) +#define TARGET_TCFLSH TARGET_IO('t', 31) + +#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct target_winsize) +#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct target_winsize) +#define TARGET_TIOCSTART TARGET_IO('t', 110) /* start output, like ^Q */ +#define TARGET_TIOCSTOP TARGET_IO('t', 111) /* stop output, like ^S */ +#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */ + +#define TARGET_TIOCGLTC TARGET_IOR('t', 116, struct target_ltchars) +#define TARGET_TIOCSLTC TARGET_IOW('t', 117, struct target_ltchars) +#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) +#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) #define TARGET_TIOCEXCL 0x540C #define TARGET_TIOCNXCL 0x540D @@ -243,8 +243,8 @@ #define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ #define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ #define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ -#define TARGET_TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ -#define TARGET_TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ #define TARGET_TIOCSERCONFIG 0x5453 #define TARGET_TIOCSERGWILD 0x5454 diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/arm/nwfpe/double_cpdo.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/double_cpdo.c --- qemu-0.9.1/linux-user/arm/nwfpe/double_cpdo.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/double_cpdo.c 2008-04-09 07:53:01.000000000 +0100 @@ -0,0 +1,296 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" +#include "softfloat.h" +#include "fpopcode.h" + +float64 float64_exp(float64 Fm); +float64 float64_ln(float64 Fm); +float64 float64_sin(float64 rFm); +float64 float64_cos(float64 rFm); +float64 float64_arcsin(float64 rFm); +float64 float64_arctan(float64 rFm); +float64 float64_log(float64 rFm); +float64 float64_tan(float64 rFm); +float64 float64_arccos(float64 rFm); +float64 float64_pow(float64 rFn,float64 rFm); +float64 float64_pol(float64 rFn,float64 rFm); + +unsigned int DoubleCPDO(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + float64 rFm, rFn = float64_zero; + unsigned int Fd, Fm, Fn, nRc = 1; + + //printk("DoubleCPDO(0x%08x)\n",opcode); + + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) + { + rFm = getDoubleConstant(Fm); + } + else + { + switch (fpa11->fType[Fm]) + { + case typeSingle: + rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status); + break; + + case typeDouble: + rFm = fpa11->fpreg[Fm].fDouble; + break; + + case typeExtended: + // !! patb + //printk("not implemented! why not?\n"); + //!! ScottB + // should never get here, if extended involved + // then other operand should be promoted then + // ExtendedCPDO called. + break; + + default: return 0; + } + } + + if (!MONADIC_INSTRUCTION(opcode)) + { + Fn = getFn(opcode); + switch (fpa11->fType[Fn]) + { + case typeSingle: + rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); + break; + + case typeDouble: + rFn = fpa11->fpreg[Fn].fDouble; + break; + + default: return 0; + } + } + + Fd = getFd(opcode); + /* !! this switch isn't optimized; better (opcode & MASK_ARITHMETIC_OPCODE)>>24, sort of */ + switch (opcode & MASK_ARITHMETIC_OPCODE) + { + /* dyadic opcodes */ + case ADF_CODE: + fpa11->fpreg[Fd].fDouble = float64_add(rFn,rFm, &fpa11->fp_status); + break; + + case MUF_CODE: + case FML_CODE: + fpa11->fpreg[Fd].fDouble = float64_mul(rFn,rFm, &fpa11->fp_status); + break; + + case SUF_CODE: + fpa11->fpreg[Fd].fDouble = float64_sub(rFn,rFm, &fpa11->fp_status); + break; + + case RSF_CODE: + fpa11->fpreg[Fd].fDouble = float64_sub(rFm,rFn, &fpa11->fp_status); + break; + + case DVF_CODE: + case FDV_CODE: + fpa11->fpreg[Fd].fDouble = float64_div(rFn,rFm, &fpa11->fp_status); + break; + + case RDF_CODE: + case FRD_CODE: + fpa11->fpreg[Fd].fDouble = float64_div(rFm,rFn, &fpa11->fp_status); + break; + +#if 0 + case POW_CODE: + fpa11->fpreg[Fd].fDouble = float64_pow(rFn,rFm); + break; + + case RPW_CODE: + fpa11->fpreg[Fd].fDouble = float64_pow(rFm,rFn); + break; +#endif + + case RMF_CODE: + fpa11->fpreg[Fd].fDouble = float64_rem(rFn,rFm, &fpa11->fp_status); + break; + +#if 0 + case POL_CODE: + fpa11->fpreg[Fd].fDouble = float64_pol(rFn,rFm); + break; +#endif + + /* monadic opcodes */ + case MVF_CODE: + fpa11->fpreg[Fd].fDouble = rFm; + break; + + case MNF_CODE: + { + unsigned int *p = (unsigned int*)&rFm; +#ifdef WORDS_BIGENDIAN + p[0] ^= 0x80000000; +#else + p[1] ^= 0x80000000; +#endif + fpa11->fpreg[Fd].fDouble = rFm; + } + break; + + case ABS_CODE: + { + unsigned int *p = (unsigned int*)&rFm; +#ifdef WORDS_BIGENDIAN + p[0] &= 0x7fffffff; +#else + p[1] &= 0x7fffffff; +#endif + fpa11->fpreg[Fd].fDouble = rFm; + } + break; + + case RND_CODE: + case URD_CODE: + fpa11->fpreg[Fd].fDouble = float64_round_to_int(rFm, &fpa11->fp_status); + break; + + case SQT_CODE: + fpa11->fpreg[Fd].fDouble = float64_sqrt(rFm, &fpa11->fp_status); + break; + +#if 0 + case LOG_CODE: + fpa11->fpreg[Fd].fDouble = float64_log(rFm); + break; + + case LGN_CODE: + fpa11->fpreg[Fd].fDouble = float64_ln(rFm); + break; + + case EXP_CODE: + fpa11->fpreg[Fd].fDouble = float64_exp(rFm); + break; + + case SIN_CODE: + fpa11->fpreg[Fd].fDouble = float64_sin(rFm); + break; + + case COS_CODE: + fpa11->fpreg[Fd].fDouble = float64_cos(rFm); + break; + + case TAN_CODE: + fpa11->fpreg[Fd].fDouble = float64_tan(rFm); + break; + + case ASN_CODE: + fpa11->fpreg[Fd].fDouble = float64_arcsin(rFm); + break; + + case ACS_CODE: + fpa11->fpreg[Fd].fDouble = float64_arccos(rFm); + break; + + case ATN_CODE: + fpa11->fpreg[Fd].fDouble = float64_arctan(rFm); + break; +#endif + + case NRM_CODE: + break; + + default: + { + nRc = 0; + } + } + + if (0 != nRc) fpa11->fType[Fd] = typeDouble; + return nRc; +} + +#if 0 +float64 float64_exp(float64 rFm) +{ + return rFm; +//series +} + +float64 float64_ln(float64 rFm) +{ + return rFm; +//series +} + +float64 float64_sin(float64 rFm) +{ + return rFm; +//series +} + +float64 float64_cos(float64 rFm) +{ + return rFm; + //series +} + +#if 0 +float64 float64_arcsin(float64 rFm) +{ +//series +} + +float64 float64_arctan(float64 rFm) +{ + //series +} +#endif + +float64 float64_log(float64 rFm) +{ + return float64_div(float64_ln(rFm),getDoubleConstant(7)); +} + +float64 float64_tan(float64 rFm) +{ + return float64_div(float64_sin(rFm),float64_cos(rFm)); +} + +float64 float64_arccos(float64 rFm) +{ +return rFm; + //return float64_sub(halfPi,float64_arcsin(rFm)); +} + +float64 float64_pow(float64 rFn,float64 rFm) +{ + return float64_exp(float64_mul(rFm,float64_ln(rFn))); +} + +float64 float64_pol(float64 rFn,float64 rFm) +{ + return float64_arctan(float64_div(rFn,rFm)); +} +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/arm/nwfpe/extended_cpdo.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/extended_cpdo.c --- qemu-0.9.1/linux-user/arm/nwfpe/extended_cpdo.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/extended_cpdo.c 2008-04-09 07:53:01.000000000 +0100 @@ -0,0 +1,273 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" +#include "softfloat.h" +#include "fpopcode.h" + +floatx80 floatx80_exp(floatx80 Fm); +floatx80 floatx80_ln(floatx80 Fm); +floatx80 floatx80_sin(floatx80 rFm); +floatx80 floatx80_cos(floatx80 rFm); +floatx80 floatx80_arcsin(floatx80 rFm); +floatx80 floatx80_arctan(floatx80 rFm); +floatx80 floatx80_log(floatx80 rFm); +floatx80 floatx80_tan(floatx80 rFm); +floatx80 floatx80_arccos(floatx80 rFm); +floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm); +floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm); + +unsigned int ExtendedCPDO(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + floatx80 rFm, rFn; + unsigned int Fd, Fm, Fn, nRc = 1; + + //printk("ExtendedCPDO(0x%08x)\n",opcode); + + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) + { + rFm = getExtendedConstant(Fm); + } + else + { + switch (fpa11->fType[Fm]) + { + case typeSingle: + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status); + break; + + case typeDouble: + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status); + break; + + case typeExtended: + rFm = fpa11->fpreg[Fm].fExtended; + break; + + default: return 0; + } + } + + if (!MONADIC_INSTRUCTION(opcode)) + { + Fn = getFn(opcode); + switch (fpa11->fType[Fn]) + { + case typeSingle: + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); + break; + + case typeDouble: + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); + break; + + case typeExtended: + rFn = fpa11->fpreg[Fn].fExtended; + break; + + default: return 0; + } + } + + Fd = getFd(opcode); + switch (opcode & MASK_ARITHMETIC_OPCODE) + { + /* dyadic opcodes */ + case ADF_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_add(rFn,rFm, &fpa11->fp_status); + break; + + case MUF_CODE: + case FML_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_mul(rFn,rFm, &fpa11->fp_status); + break; + + case SUF_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_sub(rFn,rFm, &fpa11->fp_status); + break; + + case RSF_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_sub(rFm,rFn, &fpa11->fp_status); + break; + + case DVF_CODE: + case FDV_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_div(rFn,rFm, &fpa11->fp_status); + break; + + case RDF_CODE: + case FRD_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_div(rFm,rFn, &fpa11->fp_status); + break; + +#if 0 + case POW_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_pow(rFn,rFm); + break; + + case RPW_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_pow(rFm,rFn); + break; +#endif + + case RMF_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_rem(rFn,rFm, &fpa11->fp_status); + break; + +#if 0 + case POL_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_pol(rFn,rFm); + break; +#endif + + /* monadic opcodes */ + case MVF_CODE: + fpa11->fpreg[Fd].fExtended = rFm; + break; + + case MNF_CODE: + rFm.high ^= 0x8000; + fpa11->fpreg[Fd].fExtended = rFm; + break; + + case ABS_CODE: + rFm.high &= 0x7fff; + fpa11->fpreg[Fd].fExtended = rFm; + break; + + case RND_CODE: + case URD_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_round_to_int(rFm, &fpa11->fp_status); + break; + + case SQT_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_sqrt(rFm, &fpa11->fp_status); + break; + +#if 0 + case LOG_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_log(rFm); + break; + + case LGN_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_ln(rFm); + break; + + case EXP_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_exp(rFm); + break; + + case SIN_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_sin(rFm); + break; + + case COS_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_cos(rFm); + break; + + case TAN_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_tan(rFm); + break; + + case ASN_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_arcsin(rFm); + break; + + case ACS_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_arccos(rFm); + break; + + case ATN_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_arctan(rFm); + break; +#endif + + case NRM_CODE: + break; + + default: + { + nRc = 0; + } + } + + if (0 != nRc) fpa11->fType[Fd] = typeExtended; + return nRc; +} + +#if 0 +floatx80 floatx80_exp(floatx80 Fm) +{ +//series +} + +floatx80 floatx80_ln(floatx80 Fm) +{ +//series +} + +floatx80 floatx80_sin(floatx80 rFm) +{ +//series +} + +floatx80 floatx80_cos(floatx80 rFm) +{ +//series +} + +floatx80 floatx80_arcsin(floatx80 rFm) +{ +//series +} + +floatx80 floatx80_arctan(floatx80 rFm) +{ + //series +} + +floatx80 floatx80_log(floatx80 rFm) +{ + return floatx80_div(floatx80_ln(rFm),getExtendedConstant(7)); +} + +floatx80 floatx80_tan(floatx80 rFm) +{ + return floatx80_div(floatx80_sin(rFm),floatx80_cos(rFm)); +} + +floatx80 floatx80_arccos(floatx80 rFm) +{ + //return floatx80_sub(halfPi,floatx80_arcsin(rFm)); +} + +floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm) +{ + return floatx80_exp(floatx80_mul(rFm,floatx80_ln(rFn))); +} + +floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm) +{ + return floatx80_arctan(floatx80_div(rFn,rFm)); +} +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/arm/nwfpe/fpa11.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/fpa11.c --- qemu-0.9.1/linux-user/arm/nwfpe/fpa11.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/fpa11.c 2008-09-06 18:47:39.000000000 +0100 @@ -0,0 +1,244 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" + +#include "fpopcode.h" + +//#include "fpmodule.h" +//#include "fpmodule.inl" + +//#include + +#include + +/* forward declarations */ +unsigned int EmulateCPDO(const unsigned int); +unsigned int EmulateCPDT(const unsigned int); +unsigned int EmulateCPRT(const unsigned int); + +FPA11* qemufpa=0; +CPUARMState* user_registers; + +/* Reset the FPA11 chip. Called to initialize and reset the emulator. */ +void resetFPA11(void) +{ + int i; + FPA11 *fpa11 = GET_FPA11(); + + /* initialize the register type array */ + for (i=0;i<=7;i++) + { + fpa11->fType[i] = typeNone; + } + + /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ + fpa11->fpsr = FP_EMULATOR | BIT_AC; + + /* FPCR: set SB, AB and DA bits, clear all others */ +#ifdef MAINTAIN_FPCR + fpa11->fpcr = MASK_RESET; +#endif +} + +void SetRoundingMode(const unsigned int opcode) +{ + int rounding_mode; + FPA11 *fpa11 = GET_FPA11(); + +#ifdef MAINTAIN_FPCR + fpa11->fpcr &= ~MASK_ROUNDING_MODE; +#endif + switch (opcode & MASK_ROUNDING_MODE) + { + default: + case ROUND_TO_NEAREST: + rounding_mode = float_round_nearest_even; +#ifdef MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_NEAREST; +#endif + break; + + case ROUND_TO_PLUS_INFINITY: + rounding_mode = float_round_up; +#ifdef MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_PLUS_INFINITY; +#endif + break; + + case ROUND_TO_MINUS_INFINITY: + rounding_mode = float_round_down; +#ifdef MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_MINUS_INFINITY; +#endif + break; + + case ROUND_TO_ZERO: + rounding_mode = float_round_to_zero; +#ifdef MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_ZERO; +#endif + break; + } + set_float_rounding_mode(rounding_mode, &fpa11->fp_status); +} + +void SetRoundingPrecision(const unsigned int opcode) +{ + int rounding_precision; + FPA11 *fpa11 = GET_FPA11(); +#ifdef MAINTAIN_FPCR + fpa11->fpcr &= ~MASK_ROUNDING_PRECISION; +#endif + switch (opcode & MASK_ROUNDING_PRECISION) + { + case ROUND_SINGLE: + rounding_precision = 32; +#ifdef MAINTAIN_FPCR + fpa11->fpcr |= ROUND_SINGLE; +#endif + break; + + case ROUND_DOUBLE: + rounding_precision = 64; +#ifdef MAINTAIN_FPCR + fpa11->fpcr |= ROUND_DOUBLE; +#endif + break; + + case ROUND_EXTENDED: + rounding_precision = 80; +#ifdef MAINTAIN_FPCR + fpa11->fpcr |= ROUND_EXTENDED; +#endif + break; + + default: rounding_precision = 80; + } + set_floatx80_rounding_precision(rounding_precision, &fpa11->fp_status); +} + +/* Emulate the instruction in the opcode. */ +/* ??? This is not thread safe. */ +unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) +{ + unsigned int nRc = 0; +// unsigned long flags; + FPA11 *fpa11; +// save_flags(flags); sti(); + + qemufpa=qfpa; + user_registers=qregs; + +#if 0 + fprintf(stderr,"emulating FP insn 0x%08x, PC=0x%08x\n", + opcode, qregs[REG_PC]); +#endif + fpa11 = GET_FPA11(); + + if (fpa11->initflag == 0) /* good place for __builtin_expect */ + { + resetFPA11(); + SetRoundingMode(ROUND_TO_NEAREST); + SetRoundingPrecision(ROUND_EXTENDED); + fpa11->initflag = 1; + } + + set_float_exception_flags(0, &fpa11->fp_status); + + if (TEST_OPCODE(opcode,MASK_CPRT)) + { + //fprintf(stderr,"emulating CPRT\n"); + /* Emulate conversion opcodes. */ + /* Emulate register transfer opcodes. */ + /* Emulate comparison opcodes. */ + nRc = EmulateCPRT(opcode); + } + else if (TEST_OPCODE(opcode,MASK_CPDO)) + { + //fprintf(stderr,"emulating CPDO\n"); + /* Emulate monadic arithmetic opcodes. */ + /* Emulate dyadic arithmetic opcodes. */ + nRc = EmulateCPDO(opcode); + } + else if (TEST_OPCODE(opcode,MASK_CPDT)) + { + //fprintf(stderr,"emulating CPDT\n"); + /* Emulate load/store opcodes. */ + /* Emulate load/store multiple opcodes. */ + nRc = EmulateCPDT(opcode); + } + else + { + /* Invalid instruction detected. Return FALSE. */ + nRc = 0; + } + +// restore_flags(flags); + if(nRc == 1 && get_float_exception_flags(&fpa11->fp_status)) + { + //printf("fef 0x%x\n",float_exception_flags); + nRc=-get_float_exception_flags(&fpa11->fp_status); + } + + //printf("returning %d\n",nRc); + return(nRc); +} + +#if 0 +unsigned int EmulateAll1(unsigned int opcode) +{ + switch ((opcode >> 24) & 0xf) + { + case 0xc: + case 0xd: + if ((opcode >> 20) & 0x1) + { + switch ((opcode >> 8) & 0xf) + { + case 0x1: return PerformLDF(opcode); break; + case 0x2: return PerformLFM(opcode); break; + default: return 0; + } + } + else + { + switch ((opcode >> 8) & 0xf) + { + case 0x1: return PerformSTF(opcode); break; + case 0x2: return PerformSFM(opcode); break; + default: return 0; + } + } + break; + + case 0xe: + if (opcode & 0x10) + return EmulateCPDO(opcode); + else + return EmulateCPRT(opcode); + break; + + default: return 0; + } +} +#endif + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/arm/nwfpe/fpa11_cpdo.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/fpa11_cpdo.c --- qemu-0.9.1/linux-user/arm/nwfpe/fpa11_cpdo.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/fpa11_cpdo.c 2008-04-09 07:53:01.000000000 +0100 @@ -0,0 +1,117 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" +#include "fpopcode.h" + +unsigned int SingleCPDO(const unsigned int opcode); +unsigned int DoubleCPDO(const unsigned int opcode); +unsigned int ExtendedCPDO(const unsigned int opcode); + +unsigned int EmulateCPDO(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + unsigned int Fd, nType, nDest, nRc = 1; + + //printk("EmulateCPDO(0x%08x)\n",opcode); + + /* Get the destination size. If not valid let Linux perform + an invalid instruction trap. */ + nDest = getDestinationSize(opcode); + if (typeNone == nDest) return 0; + + SetRoundingMode(opcode); + + /* Compare the size of the operands in Fn and Fm. + Choose the largest size and perform operations in that size, + in order to make use of all the precision of the operands. + If Fm is a constant, we just grab a constant of a size + matching the size of the operand in Fn. */ + if (MONADIC_INSTRUCTION(opcode)) + nType = nDest; + else + nType = fpa11->fType[getFn(opcode)]; + + if (!CONSTANT_FM(opcode)) + { + register unsigned int Fm = getFm(opcode); + if (nType < fpa11->fType[Fm]) + { + nType = fpa11->fType[Fm]; + } + } + + switch (nType) + { + case typeSingle : nRc = SingleCPDO(opcode); break; + case typeDouble : nRc = DoubleCPDO(opcode); break; + case typeExtended : nRc = ExtendedCPDO(opcode); break; + default : nRc = 0; + } + + /* If the operation succeeded, check to see if the result in the + destination register is the correct size. If not force it + to be. */ + Fd = getFd(opcode); + nType = fpa11->fType[Fd]; + if ((0 != nRc) && (nDest != nType)) + { + switch (nDest) + { + case typeSingle: + { + if (typeDouble == nType) + fpa11->fpreg[Fd].fSingle = + float64_to_float32(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status); + else + fpa11->fpreg[Fd].fSingle = + floatx80_to_float32(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status); + } + break; + + case typeDouble: + { + if (typeSingle == nType) + fpa11->fpreg[Fd].fDouble = + float32_to_float64(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status); + else + fpa11->fpreg[Fd].fDouble = + floatx80_to_float64(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status); + } + break; + + case typeExtended: + { + if (typeSingle == nType) + fpa11->fpreg[Fd].fExtended = + float32_to_floatx80(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status); + else + fpa11->fpreg[Fd].fExtended = + float64_to_floatx80(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status); + } + break; + } + + fpa11->fType[Fd] = nDest; + } + + return nRc; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/arm/nwfpe/fpa11_cpdt.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/fpa11_cpdt.c --- qemu-0.9.1/linux-user/arm/nwfpe/fpa11_cpdt.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/fpa11_cpdt.c 2008-04-09 07:53:01.000000000 +0100 @@ -0,0 +1,386 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.com, 1998-1999 + (c) Philip Blundell, 1998 + + Direct questions, comments to Scott Bambrough + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" +#include "softfloat.h" +#include "fpopcode.h" +//#include "fpmodule.h" +//#include "fpmodule.inl" + +//#include + +static inline +void loadSingle(const unsigned int Fn,const unsigned int *pMem) +{ + target_ulong addr = (target_ulong)(long)pMem; + FPA11 *fpa11 = GET_FPA11(); + fpa11->fType[Fn] = typeSingle; + /* FIXME - handle failure of get_user() */ + get_user_u32(fpa11->fpreg[Fn].fSingle, addr); +} + +static inline +void loadDouble(const unsigned int Fn,const unsigned int *pMem) +{ + target_ulong addr = (target_ulong)(long)pMem; + FPA11 *fpa11 = GET_FPA11(); + unsigned int *p; + p = (unsigned int*)&fpa11->fpreg[Fn].fDouble; + fpa11->fType[Fn] = typeDouble; +#ifdef WORDS_BIGENDIAN + /* FIXME - handle failure of get_user() */ + get_user_u32(p[0], addr); /* sign & exponent */ + get_user_u32(p[1], addr + 4); +#else + /* FIXME - handle failure of get_user() */ + get_user_u32(p[0], addr + 4); + get_user_u32(p[1], addr); /* sign & exponent */ +#endif +} + +static inline +void loadExtended(const unsigned int Fn,const unsigned int *pMem) +{ + target_ulong addr = (target_ulong)(long)pMem; + FPA11 *fpa11 = GET_FPA11(); + unsigned int *p; + p = (unsigned int*)&fpa11->fpreg[Fn].fExtended; + fpa11->fType[Fn] = typeExtended; + /* FIXME - handle failure of get_user() */ + get_user_u32(p[0], addr); /* sign & exponent */ + get_user_u32(p[1], addr + 8); /* ls bits */ + get_user_u32(p[2], addr + 4); /* ms bits */ +} + +static inline +void loadMultiple(const unsigned int Fn,const unsigned int *pMem) +{ + target_ulong addr = (target_ulong)(long)pMem; + FPA11 *fpa11 = GET_FPA11(); + register unsigned int *p; + unsigned long x; + + p = (unsigned int*)&(fpa11->fpreg[Fn]); + /* FIXME - handle failure of get_user() */ + get_user_u32(x, addr); + fpa11->fType[Fn] = (x >> 14) & 0x00000003; + + switch (fpa11->fType[Fn]) + { + case typeSingle: + case typeDouble: + { + /* FIXME - handle failure of get_user() */ + get_user_u32(p[0], addr + 8); /* Single */ + get_user_u32(p[1], addr + 4); /* double msw */ + p[2] = 0; /* empty */ + } + break; + + case typeExtended: + { + /* FIXME - handle failure of get_user() */ + get_user_u32(p[1], addr + 8); + get_user_u32(p[2], addr + 4); /* msw */ + p[0] = (x & 0x80003fff); + } + break; + } +} + +static inline +void storeSingle(const unsigned int Fn,unsigned int *pMem) +{ + target_ulong addr = (target_ulong)(long)pMem; + FPA11 *fpa11 = GET_FPA11(); + float32 val; + register unsigned int *p = (unsigned int*)&val; + + switch (fpa11->fType[Fn]) + { + case typeDouble: + val = float64_to_float32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); + break; + + case typeExtended: + val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status); + break; + + default: val = fpa11->fpreg[Fn].fSingle; + } + + /* FIXME - handle put_user() failures */ + put_user_u32(p[0], addr); +} + +static inline +void storeDouble(const unsigned int Fn,unsigned int *pMem) +{ + target_ulong addr = (target_ulong)(long)pMem; + FPA11 *fpa11 = GET_FPA11(); + float64 val; + register unsigned int *p = (unsigned int*)&val; + + switch (fpa11->fType[Fn]) + { + case typeSingle: + val = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); + break; + + case typeExtended: + val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status); + break; + + default: val = fpa11->fpreg[Fn].fDouble; + } + /* FIXME - handle put_user() failures */ +#ifdef WORDS_BIGENDIAN + put_user_u32(p[0], addr); /* msw */ + put_user_u32(p[1], addr + 4); /* lsw */ +#else + put_user_u32(p[1], addr); /* msw */ + put_user_u32(p[0], addr + 4); /* lsw */ +#endif +} + +static inline +void storeExtended(const unsigned int Fn,unsigned int *pMem) +{ + target_ulong addr = (target_ulong)(long)pMem; + FPA11 *fpa11 = GET_FPA11(); + floatx80 val; + register unsigned int *p = (unsigned int*)&val; + + switch (fpa11->fType[Fn]) + { + case typeSingle: + val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); + break; + + case typeDouble: + val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); + break; + + default: val = fpa11->fpreg[Fn].fExtended; + } + + /* FIXME - handle put_user() failures */ + put_user_u32(p[0], addr); /* sign & exp */ + put_user_u32(p[1], addr + 8); + put_user_u32(p[2], addr + 4); /* msw */ +} + +static inline +void storeMultiple(const unsigned int Fn,unsigned int *pMem) +{ + target_ulong addr = (target_ulong)(long)pMem; + FPA11 *fpa11 = GET_FPA11(); + register unsigned int nType, *p; + + p = (unsigned int*)&(fpa11->fpreg[Fn]); + nType = fpa11->fType[Fn]; + + switch (nType) + { + case typeSingle: + case typeDouble: + { + put_user_u32(p[0], addr + 8); /* single */ + put_user_u32(p[1], addr + 4); /* double msw */ + put_user_u32(nType << 14, addr); + } + break; + + case typeExtended: + { + put_user_u32(p[2], addr + 4); /* msw */ + put_user_u32(p[1], addr + 8); + put_user_u32((p[0] & 0x80003fff) | (nType << 14), addr); + } + break; + } +} + +unsigned int PerformLDF(const unsigned int opcode) +{ + unsigned int *pBase, *pAddress, *pFinal, nRc = 1, + write_back = WRITE_BACK(opcode); + + //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); + + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) + { + pBase += 2; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + switch (opcode & MASK_TRANSFER_LENGTH) + { + case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break; + case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break; + case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break; + default: nRc = 0; + } + + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); + return nRc; +} + +unsigned int PerformSTF(const unsigned int opcode) +{ + unsigned int *pBase, *pAddress, *pFinal, nRc = 1, + write_back = WRITE_BACK(opcode); + + //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); + SetRoundingMode(ROUND_TO_NEAREST); + + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) + { + pBase += 2; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + switch (opcode & MASK_TRANSFER_LENGTH) + { + case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break; + case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break; + case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break; + default: nRc = 0; + } + + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); + return nRc; +} + +unsigned int PerformLFM(const unsigned int opcode) +{ + unsigned int i, Fd, *pBase, *pAddress, *pFinal, + write_back = WRITE_BACK(opcode); + + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) + { + pBase += 2; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + Fd = getFd(opcode); + for (i=getRegisterCount(opcode);i>0;i--) + { + loadMultiple(Fd,pAddress); + pAddress += 3; Fd++; + if (Fd == 8) Fd = 0; + } + + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); + return 1; +} + +unsigned int PerformSFM(const unsigned int opcode) +{ + unsigned int i, Fd, *pBase, *pAddress, *pFinal, + write_back = WRITE_BACK(opcode); + + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) + { + pBase += 2; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + Fd = getFd(opcode); + for (i=getRegisterCount(opcode);i>0;i--) + { + storeMultiple(Fd,pAddress); + pAddress += 3; Fd++; + if (Fd == 8) Fd = 0; + } + + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); + return 1; +} + +#if 1 +unsigned int EmulateCPDT(const unsigned int opcode) +{ + unsigned int nRc = 0; + + //printk("EmulateCPDT(0x%08x)\n",opcode); + + if (LDF_OP(opcode)) + { + nRc = PerformLDF(opcode); + } + else if (LFM_OP(opcode)) + { + nRc = PerformLFM(opcode); + } + else if (STF_OP(opcode)) + { + nRc = PerformSTF(opcode); + } + else if (SFM_OP(opcode)) + { + nRc = PerformSFM(opcode); + } + else + { + nRc = 0; + } + + return nRc; +} +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/arm/nwfpe/fpa11_cprt.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/fpa11_cprt.c --- qemu-0.9.1/linux-user/arm/nwfpe/fpa11_cprt.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/fpa11_cprt.c 2008-08-30 10:51:20.000000000 +0100 @@ -0,0 +1,284 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + (c) Philip Blundell, 1999 + + Direct questions, comments to Scott Bambrough + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpa11.inl" +//#include "fpmodule.h" +//#include "fpmodule.inl" + +unsigned int PerformFLT(const unsigned int opcode); +unsigned int PerformFIX(const unsigned int opcode); + +static unsigned int +PerformComparison(const unsigned int opcode); + +unsigned int EmulateCPRT(const unsigned int opcode) +{ + unsigned int nRc = 1; + + //printk("EmulateCPRT(0x%08x)\n",opcode); + + if (opcode & 0x800000) + { + /* This is some variant of a comparison (PerformComparison will + sort out which one). Since most of the other CPRT + instructions are oddball cases of some sort or other it makes + sense to pull this out into a fast path. */ + return PerformComparison(opcode); + } + + /* Hint to GCC that we'd like a jump table rather than a load of CMPs */ + switch ((opcode & 0x700000) >> 20) + { + case FLT_CODE >> 20: nRc = PerformFLT(opcode); break; + case FIX_CODE >> 20: nRc = PerformFIX(opcode); break; + + case WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break; + case RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break; + +#if 0 /* We currently have no use for the FPCR, so there's no point + in emulating it. */ + case WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode))); + case RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break; +#endif + + default: nRc = 0; + } + + return nRc; +} + +unsigned int PerformFLT(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + + unsigned int nRc = 1; + SetRoundingMode(opcode); + + switch (opcode & MASK_ROUNDING_PRECISION) + { + case ROUND_SINGLE: + { + fpa11->fType[getFn(opcode)] = typeSingle; + fpa11->fpreg[getFn(opcode)].fSingle = + int32_to_float32(readRegister(getRd(opcode)), &fpa11->fp_status); + } + break; + + case ROUND_DOUBLE: + { + fpa11->fType[getFn(opcode)] = typeDouble; + fpa11->fpreg[getFn(opcode)].fDouble = + int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status); + } + break; + + case ROUND_EXTENDED: + { + fpa11->fType[getFn(opcode)] = typeExtended; + fpa11->fpreg[getFn(opcode)].fExtended = + int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status); + } + break; + + default: nRc = 0; + } + + return nRc; +} + +unsigned int PerformFIX(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + unsigned int nRc = 1; + unsigned int Fn = getFm(opcode); + + SetRoundingMode(opcode); + + switch (fpa11->fType[Fn]) + { + case typeSingle: + { + writeRegister(getRd(opcode), + float32_to_int32(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status)); + } + break; + + case typeDouble: + { + //printf("F%d is 0x%" PRIx64 "\n",Fn,fpa11->fpreg[Fn].fDouble); + writeRegister(getRd(opcode), + float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status)); + } + break; + + case typeExtended: + { + writeRegister(getRd(opcode), + floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status)); + } + break; + + default: nRc = 0; + } + + return nRc; +} + + +static unsigned int __inline__ +PerformComparisonOperation(floatx80 Fn, floatx80 Fm) +{ + FPA11 *fpa11 = GET_FPA11(); + unsigned int flags = 0; + + /* test for less than condition */ + if (floatx80_lt(Fn,Fm, &fpa11->fp_status)) + { + flags |= CC_NEGATIVE; + } + + /* test for equal condition */ + if (floatx80_eq(Fn,Fm, &fpa11->fp_status)) + { + flags |= CC_ZERO; + } + + /* test for greater than or equal condition */ + if (floatx80_lt(Fm,Fn, &fpa11->fp_status)) + { + flags |= CC_CARRY; + } + + writeConditionCodes(flags); + return 1; +} + +/* This instruction sets the flags N, Z, C, V in the FPSR. */ + +static unsigned int PerformComparison(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + unsigned int Fn, Fm; + floatx80 rFn, rFm; + int e_flag = opcode & 0x400000; /* 1 if CxFE */ + int n_flag = opcode & 0x200000; /* 1 if CNxx */ + unsigned int flags = 0; + + //printk("PerformComparison(0x%08x)\n",opcode); + + Fn = getFn(opcode); + Fm = getFm(opcode); + + /* Check for unordered condition and convert all operands to 80-bit + format. + ?? Might be some mileage in avoiding this conversion if possible. + Eg, if both operands are 32-bit, detect this and do a 32-bit + comparison (cheaper than an 80-bit one). */ + switch (fpa11->fType[Fn]) + { + case typeSingle: + //printk("single.\n"); + if (float32_is_nan(fpa11->fpreg[Fn].fSingle)) + goto unordered; + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); + break; + + case typeDouble: + //printk("double.\n"); + if (float64_is_nan(fpa11->fpreg[Fn].fDouble)) + goto unordered; + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); + break; + + case typeExtended: + //printk("extended.\n"); + if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended)) + goto unordered; + rFn = fpa11->fpreg[Fn].fExtended; + break; + + default: return 0; + } + + if (CONSTANT_FM(opcode)) + { + //printk("Fm is a constant: #%d.\n",Fm); + rFm = getExtendedConstant(Fm); + if (floatx80_is_nan(rFm)) + goto unordered; + } + else + { + //printk("Fm = r%d which contains a ",Fm); + switch (fpa11->fType[Fm]) + { + case typeSingle: + //printk("single.\n"); + if (float32_is_nan(fpa11->fpreg[Fm].fSingle)) + goto unordered; + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status); + break; + + case typeDouble: + //printk("double.\n"); + if (float64_is_nan(fpa11->fpreg[Fm].fDouble)) + goto unordered; + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status); + break; + + case typeExtended: + //printk("extended.\n"); + if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended)) + goto unordered; + rFm = fpa11->fpreg[Fm].fExtended; + break; + + default: return 0; + } + } + + if (n_flag) + { + rFm.high ^= 0x8000; + } + + return PerformComparisonOperation(rFn,rFm); + + unordered: + /* ?? The FPA data sheet is pretty vague about this, in particular + about whether the non-E comparisons can ever raise exceptions. + This implementation is based on a combination of what it says in + the data sheet, observation of how the Acorn emulator actually + behaves (and how programs expect it to) and guesswork. */ + flags |= CC_OVERFLOW; + flags &= ~(CC_ZERO | CC_NEGATIVE); + + if (BIT_AC & readFPSR()) flags |= CC_CARRY; + + if (e_flag) float_raise(float_flag_invalid, &fpa11->fp_status); + + writeConditionCodes(flags); + return 1; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/arm/nwfpe/fpa11.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/fpa11.h --- qemu-0.9.1/linux-user/arm/nwfpe/fpa11.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/fpa11.h 2008-04-09 07:53:01.000000000 +0100 @@ -0,0 +1,122 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.com, 1998-1999 + + Direct questions, comments to Scott Bambrough + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __FPA11_H__ +#define __FPA11_H__ + +#include +#include +#include + +#include + +#define GET_FPA11() (qemufpa) + +/* + * The processes registers are always at the very top of the 8K + * stack+task struct. Use the same method as 'current' uses to + * reach them. + */ +extern CPUARMState *user_registers; + +#define GET_USERREG() (user_registers) + +/* Need task_struct */ +//#include + +/* includes */ +#include "fpsr.h" /* FP control and status register definitions */ +#include "softfloat.h" + +#define typeNone 0x00 +#define typeSingle 0x01 +#define typeDouble 0x02 +#define typeExtended 0x03 + +/* + * This must be no more and no less than 12 bytes. + */ +typedef union tagFPREG { + floatx80 fExtended; + float64 fDouble; + float32 fSingle; +} FPREG; + +/* + * FPA11 device model. + * + * This structure is exported to user space. Do not re-order. + * Only add new stuff to the end, and do not change the size of + * any element. Elements of this structure are used by user + * space, and must match struct user_fp in include/asm-arm/user.h. + * We include the byte offsets below for documentation purposes. + * + * The size of this structure and FPREG are checked by fpmodule.c + * on initialisation. If the rules have been broken, NWFPE will + * not initialise. + */ +typedef struct tagFPA11 { +/* 0 */ FPREG fpreg[8]; /* 8 floating point registers */ +/* 96 */ FPSR fpsr; /* floating point status register */ +/* 100 */ FPCR fpcr; /* floating point control register */ +/* 104 */ unsigned char fType[8]; /* type of floating point value held in + floating point registers. One of none + single, double or extended. */ +/* 112 */ int initflag; /* this is special. The kernel guarantees + to set it to 0 when a thread is launched, + so we can use it to detect whether this + instance of the emulator needs to be + initialised. */ + float_status fp_status; /* QEMU float emulator status */ +} FPA11; + +extern FPA11* qemufpa; + +extern void resetFPA11(void); +extern void SetRoundingMode(const unsigned int); +extern void SetRoundingPrecision(const unsigned int); + +static inline unsigned int readRegister(unsigned int reg) +{ + return (user_registers->regs[(reg)]); +} + +static inline void writeRegister(unsigned int x, unsigned int y) +{ +#if 0 + printf("writing %d to r%d\n",y,x); +#endif + user_registers->regs[(x)]=(y); +} + +static inline void writeConditionCodes(unsigned int x) +{ + cpsr_write(user_registers,x,CPSR_NZCV); +} + +#define REG_PC 15 + +unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs); + +/* included only for get_user/put_user macros */ +#include "qemu.h" + +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/arm/nwfpe/fpa11.inl /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/fpa11.inl --- qemu-0.9.1/linux-user/arm/nwfpe/fpa11.inl 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/fpa11.inl 2008-04-09 07:53:01.000000000 +0100 @@ -0,0 +1,51 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" + +/* Read and write floating point status register */ +static inline unsigned int readFPSR(void) +{ + FPA11 *fpa11 = GET_FPA11(); + return(fpa11->fpsr); +} + +static inline void writeFPSR(FPSR reg) +{ + FPA11 *fpa11 = GET_FPA11(); + /* the sysid byte in the status register is readonly */ + fpa11->fpsr = (fpa11->fpsr & MASK_SYSID) | (reg & ~MASK_SYSID); +} + +/* Read and write floating point control register */ +static inline FPCR readFPCR(void) +{ + FPA11 *fpa11 = GET_FPA11(); + /* clear SB, AB and DA bits before returning FPCR */ + return(fpa11->fpcr & ~MASK_RFC); +} + +static inline void writeFPCR(FPCR reg) +{ + FPA11 *fpa11 = GET_FPA11(); + fpa11->fpcr &= ~MASK_WFC; /* clear SB, AB and DA bits */ + fpa11->fpcr |= (reg & MASK_WFC); /* write SB, AB and DA bits */ +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/arm/nwfpe/fpopcode.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/fpopcode.c --- qemu-0.9.1/linux-user/arm/nwfpe/fpopcode.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/fpopcode.c 2008-04-09 07:53:01.000000000 +0100 @@ -0,0 +1,148 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpsr.h" +//#include "fpmodule.h" +//#include "fpmodule.inl" + +const floatx80 floatx80Constant[] = { + { 0x0000000000000000ULL, 0x0000}, /* extended 0.0 */ + { 0x8000000000000000ULL, 0x3fff}, /* extended 1.0 */ + { 0x8000000000000000ULL, 0x4000}, /* extended 2.0 */ + { 0xc000000000000000ULL, 0x4000}, /* extended 3.0 */ + { 0x8000000000000000ULL, 0x4001}, /* extended 4.0 */ + { 0xa000000000000000ULL, 0x4001}, /* extended 5.0 */ + { 0x8000000000000000ULL, 0x3ffe}, /* extended 0.5 */ + { 0xa000000000000000ULL, 0x4002} /* extended 10.0 */ +}; + +const float64 float64Constant[] = { + 0x0000000000000000ULL, /* double 0.0 */ + 0x3ff0000000000000ULL, /* double 1.0 */ + 0x4000000000000000ULL, /* double 2.0 */ + 0x4008000000000000ULL, /* double 3.0 */ + 0x4010000000000000ULL, /* double 4.0 */ + 0x4014000000000000ULL, /* double 5.0 */ + 0x3fe0000000000000ULL, /* double 0.5 */ + 0x4024000000000000ULL /* double 10.0 */ +}; + +const float32 float32Constant[] = { + 0x00000000, /* single 0.0 */ + 0x3f800000, /* single 1.0 */ + 0x40000000, /* single 2.0 */ + 0x40400000, /* single 3.0 */ + 0x40800000, /* single 4.0 */ + 0x40a00000, /* single 5.0 */ + 0x3f000000, /* single 0.5 */ + 0x41200000 /* single 10.0 */ +}; + +unsigned int getTransferLength(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_TRANSFER_LENGTH) + { + case 0x00000000: nRc = 1; break; /* single precision */ + case 0x00008000: nRc = 2; break; /* double precision */ + case 0x00400000: nRc = 3; break; /* extended precision */ + default: nRc = 0; + } + + return(nRc); +} + +unsigned int getRegisterCount(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_REGISTER_COUNT) + { + case 0x00000000: nRc = 4; break; + case 0x00008000: nRc = 1; break; + case 0x00400000: nRc = 2; break; + case 0x00408000: nRc = 3; break; + default: nRc = 0; + } + + return(nRc); +} + +unsigned int getRoundingPrecision(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_ROUNDING_PRECISION) + { + case 0x00000000: nRc = 1; break; + case 0x00000080: nRc = 2; break; + case 0x00080000: nRc = 3; break; + default: nRc = 0; + } + + return(nRc); +} + +unsigned int getDestinationSize(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_DESTINATION_SIZE) + { + case 0x00000000: nRc = typeSingle; break; + case 0x00000080: nRc = typeDouble; break; + case 0x00080000: nRc = typeExtended; break; + default: nRc = typeNone; + } + + return(nRc); +} + +/* condition code lookup table + index into the table is test code: EQ, NE, ... LT, GT, AL, NV + bit position in short is condition code: NZCV */ +static const unsigned short aCC[16] = { + 0xF0F0, // EQ == Z set + 0x0F0F, // NE + 0xCCCC, // CS == C set + 0x3333, // CC + 0xFF00, // MI == N set + 0x00FF, // PL + 0xAAAA, // VS == V set + 0x5555, // VC + 0x0C0C, // HI == C set && Z clear + 0xF3F3, // LS == C clear || Z set + 0xAA55, // GE == (N==V) + 0x55AA, // LT == (N!=V) + 0x0A05, // GT == (!Z && (N==V)) + 0xF5FA, // LE == (Z || (N!=V)) + 0xFFFF, // AL always + 0 // NV +}; + +unsigned int checkCondition(const unsigned int opcode, const unsigned int ccodes) +{ + return (aCC[opcode>>28] >> (ccodes>>28)) & 1; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/arm/nwfpe/fpopcode.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/fpopcode.h --- qemu-0.9.1/linux-user/arm/nwfpe/fpopcode.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/fpopcode.h 2008-09-14 07:45:34.000000000 +0100 @@ -0,0 +1,390 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __FPOPCODE_H__ +#define __FPOPCODE_H__ + +/* +ARM Floating Point Instruction Classes +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +|c o n d|1 1 0 P|U|u|W|L| Rn |v| Fd |0|0|0|1| o f f s e t | CPDT +|c o n d|1 1 0 P|U|w|W|L| Rn |x| Fd |0|0|0|1| o f f s e t | CPDT +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +|c o n d|1 1 1 0|a|b|c|d|e| Fn |j| Fd |0|0|0|1|f|g|h|0|i| Fm | CPDO +|c o n d|1 1 1 0|a|b|c|L|e| Fn | Rd |0|0|0|1|f|g|h|1|i| Fm | CPRT +|c o n d|1 1 1 0|a|b|c|1|e| Fn |1|1|1|1|0|0|0|1|f|g|h|1|i| Fm | comparisons +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | + +CPDT data transfer instructions + LDF, STF, LFM, SFM + +CPDO dyadic arithmetic instructions + ADF, MUF, SUF, RSF, DVF, RDF, + POW, RPW, RMF, FML, FDV, FRD, POL + +CPDO monadic arithmetic instructions + MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP, + SIN, COS, TAN, ASN, ACS, ATN, URD, NRM + +CPRT joint arithmetic/data transfer instructions + FIX (arithmetic followed by load/store) + FLT (load/store followed by arithmetic) + CMF, CNF CMFE, CNFE (comparisons) + WFS, RFS (write/read floating point status register) + WFC, RFC (write/read floating point control register) + +cond condition codes +P pre/post index bit: 0 = postindex, 1 = preindex +U up/down bit: 0 = stack grows down, 1 = stack grows up +W write back bit: 1 = update base register (Rn) +L load/store bit: 0 = store, 1 = load +Rn base register +Rd destination/source register +Fd floating point destination register +Fn floating point source register +Fm floating point source register or floating point constant + +uv transfer length (TABLE 1) +wx register count (TABLE 2) +abcd arithmetic opcode (TABLES 3 & 4) +ef destination size (rounding precision) (TABLE 5) +gh rounding mode (TABLE 6) +j dyadic/monadic bit: 0 = dyadic, 1 = monadic +i constant bit: 1 = constant (TABLE 6) +*/ + +/* +TABLE 1 ++-------------------------+---+---+---------+---------+ +| Precision | u | v | FPSR.EP | length | ++-------------------------+---+---+---------+---------+ +| Single | 0 ü 0 | x | 1 words | +| Double | 1 ü 1 | x | 2 words | +| Extended | 1 ü 1 | x | 3 words | +| Packed decimal | 1 ü 1 | 0 | 3 words | +| Expanded packed decimal | 1 ü 1 | 1 | 4 words | ++-------------------------+---+---+---------+---------+ +Note: x = don't care +*/ + +/* +TABLE 2 ++---+---+---------------------------------+ +| w | x | Number of registers to transfer | ++---+---+---------------------------------+ +| 0 ü 1 | 1 | +| 1 ü 0 | 2 | +| 1 ü 1 | 3 | +| 0 ü 0 | 4 | ++---+---+---------------------------------+ +*/ + +/* +TABLE 3: Dyadic Floating Point Opcodes ++---+---+---+---+----------+-----------------------+-----------------------+ +| a | b | c | d | Mnemonic | Description | Operation | ++---+---+---+---+----------+-----------------------+-----------------------+ +| 0 | 0 | 0 | 0 | ADF | Add | Fd := Fn + Fm | +| 0 | 0 | 0 | 1 | MUF | Multiply | Fd := Fn * Fm | +| 0 | 0 | 1 | 0 | SUF | Subtract | Fd := Fn - Fm | +| 0 | 0 | 1 | 1 | RSF | Reverse subtract | Fd := Fm - Fn | +| 0 | 1 | 0 | 0 | DVF | Divide | Fd := Fn / Fm | +| 0 | 1 | 0 | 1 | RDF | Reverse divide | Fd := Fm / Fn | +| 0 | 1 | 1 | 0 | POW | Power | Fd := Fn ^ Fm | +| 0 | 1 | 1 | 1 | RPW | Reverse power | Fd := Fm ^ Fn | +| 1 | 0 | 0 | 0 | RMF | Remainder | Fd := IEEE rem(Fn/Fm) | +| 1 | 0 | 0 | 1 | FML | Fast Multiply | Fd := Fn * Fm | +| 1 | 0 | 1 | 0 | FDV | Fast Divide | Fd := Fn / Fm | +| 1 | 0 | 1 | 1 | FRD | Fast reverse divide | Fd := Fm / Fn | +| 1 | 1 | 0 | 0 | POL | Polar angle (ArcTan2) | Fd := arctan2(Fn,Fm) | +| 1 | 1 | 0 | 1 | | undefined instruction | trap | +| 1 | 1 | 1 | 0 | | undefined instruction | trap | +| 1 | 1 | 1 | 1 | | undefined instruction | trap | ++---+---+---+---+----------+-----------------------+-----------------------+ +Note: POW, RPW, POL are deprecated, and are available for backwards + compatibility only. +*/ + +/* +TABLE 4: Monadic Floating Point Opcodes ++---+---+---+---+----------+-----------------------+-----------------------+ +| a | b | c | d | Mnemonic | Description | Operation | ++---+---+---+---+----------+-----------------------+-----------------------+ +| 0 | 0 | 0 | 0 | MVF | Move | Fd := Fm | +| 0 | 0 | 0 | 1 | MNF | Move negated | Fd := - Fm | +| 0 | 0 | 1 | 0 | ABS | Absolute value | Fd := abs(Fm) | +| 0 | 0 | 1 | 1 | RND | Round to integer | Fd := int(Fm) | +| 0 | 1 | 0 | 0 | SQT | Square root | Fd := sqrt(Fm) | +| 0 | 1 | 0 | 1 | LOG | Log base 10 | Fd := log10(Fm) | +| 0 | 1 | 1 | 0 | LGN | Log base e | Fd := ln(Fm) | +| 0 | 1 | 1 | 1 | EXP | Exponent | Fd := e ^ Fm | +| 1 | 0 | 0 | 0 | SIN | Sine | Fd := sin(Fm) | +| 1 | 0 | 0 | 1 | COS | Cosine | Fd := cos(Fm) | +| 1 | 0 | 1 | 0 | TAN | Tangent | Fd := tan(Fm) | +| 1 | 0 | 1 | 1 | ASN | Arc Sine | Fd := arcsin(Fm) | +| 1 | 1 | 0 | 0 | ACS | Arc Cosine | Fd := arccos(Fm) | +| 1 | 1 | 0 | 1 | ATN | Arc Tangent | Fd := arctan(Fm) | +| 1 | 1 | 1 | 0 | URD | Unnormalized round | Fd := int(Fm) | +| 1 | 1 | 1 | 1 | NRM | Normalize | Fd := norm(Fm) | ++---+---+---+---+----------+-----------------------+-----------------------+ +Note: LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN are deprecated, and are + available for backwards compatibility only. +*/ + +/* +TABLE 5 ++-------------------------+---+---+ +| Rounding Precision | e | f | ++-------------------------+---+---+ +| IEEE Single precision | 0 ü 0 | +| IEEE Double precision | 0 ü 1 | +| IEEE Extended precision | 1 ü 0 | +| undefined (trap) | 1 ü 1 | ++-------------------------+---+---+ +*/ + +/* +TABLE 5 ++---------------------------------+---+---+ +| Rounding Mode | g | h | ++---------------------------------+---+---+ +| Round to nearest (default) | 0 ü 0 | +| Round toward plus infinity | 0 ü 1 | +| Round toward negative infinity | 1 ü 0 | +| Round toward zero | 1 ü 1 | ++---------------------------------+---+---+ +*/ + +/* +=== +=== Definitions for load and store instructions +=== +*/ + +/* bit masks */ +#define BIT_PREINDEX 0x01000000 +#define BIT_UP 0x00800000 +#define BIT_WRITE_BACK 0x00200000 +#define BIT_LOAD 0x00100000 + +/* masks for load/store */ +#define MASK_CPDT 0x0c000000 /* data processing opcode */ +#define MASK_OFFSET 0x000000ff +#define MASK_TRANSFER_LENGTH 0x00408000 +#define MASK_REGISTER_COUNT MASK_TRANSFER_LENGTH +#define MASK_COPROCESSOR 0x00000f00 + +/* Tests for transfer length */ +#define TRANSFER_SINGLE 0x00000000 +#define TRANSFER_DOUBLE 0x00008000 +#define TRANSFER_EXTENDED 0x00400000 +#define TRANSFER_PACKED MASK_TRANSFER_LENGTH + +/* Get the coprocessor number from the opcode. */ +#define getCoprocessorNumber(opcode) ((opcode & MASK_COPROCESSOR) >> 8) + +/* Get the offset from the opcode. */ +#define getOffset(opcode) (opcode & MASK_OFFSET) + +/* Tests for specific data transfer load/store opcodes. */ +#define TEST_OPCODE(opcode,mask) (((opcode) & (mask)) == (mask)) + +#define LOAD_OP(opcode) TEST_OPCODE((opcode),MASK_CPDT | BIT_LOAD) +#define STORE_OP(opcode) ((opcode & (MASK_CPDT | BIT_LOAD)) == MASK_CPDT) + +#define LDF_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 1)) +#define LFM_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 2)) +#define STF_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 1)) +#define SFM_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 2)) + +#define PREINDEXED(opcode) ((opcode & BIT_PREINDEX) != 0) +#define POSTINDEXED(opcode) ((opcode & BIT_PREINDEX) == 0) +#define BIT_UP_SET(opcode) ((opcode & BIT_UP) != 0) +#define BIT_UP_CLEAR(opcode) ((opcode & BIT_DOWN) == 0) +#define WRITE_BACK(opcode) ((opcode & BIT_WRITE_BACK) != 0) +#define LOAD(opcode) ((opcode & BIT_LOAD) != 0) +#define STORE(opcode) ((opcode & BIT_LOAD) == 0) + +/* +=== +=== Definitions for arithmetic instructions +=== +*/ +/* bit masks */ +#define BIT_MONADIC 0x00008000 +#define BIT_CONSTANT 0x00000008 + +#define CONSTANT_FM(opcode) ((opcode & BIT_CONSTANT) != 0) +#define MONADIC_INSTRUCTION(opcode) ((opcode & BIT_MONADIC) != 0) + +/* instruction identification masks */ +#define MASK_CPDO 0x0e000000 /* arithmetic opcode */ +#define MASK_ARITHMETIC_OPCODE 0x00f08000 +#define MASK_DESTINATION_SIZE 0x00080080 + +/* dyadic arithmetic opcodes. */ +#define ADF_CODE 0x00000000 +#define MUF_CODE 0x00100000 +#define SUF_CODE 0x00200000 +#define RSF_CODE 0x00300000 +#define DVF_CODE 0x00400000 +#define RDF_CODE 0x00500000 +#define POW_CODE 0x00600000 +#define RPW_CODE 0x00700000 +#define RMF_CODE 0x00800000 +#define FML_CODE 0x00900000 +#define FDV_CODE 0x00a00000 +#define FRD_CODE 0x00b00000 +#define POL_CODE 0x00c00000 +/* 0x00d00000 is an invalid dyadic arithmetic opcode */ +/* 0x00e00000 is an invalid dyadic arithmetic opcode */ +/* 0x00f00000 is an invalid dyadic arithmetic opcode */ + +/* monadic arithmetic opcodes. */ +#define MVF_CODE 0x00008000 +#define MNF_CODE 0x00108000 +#define ABS_CODE 0x00208000 +#define RND_CODE 0x00308000 +#define SQT_CODE 0x00408000 +#define LOG_CODE 0x00508000 +#define LGN_CODE 0x00608000 +#define EXP_CODE 0x00708000 +#define SIN_CODE 0x00808000 +#define COS_CODE 0x00908000 +#define TAN_CODE 0x00a08000 +#define ASN_CODE 0x00b08000 +#define ACS_CODE 0x00c08000 +#define ATN_CODE 0x00d08000 +#define URD_CODE 0x00e08000 +#define NRM_CODE 0x00f08000 + +/* +=== +=== Definitions for register transfer and comparison instructions +=== +*/ + +#define MASK_CPRT 0x0e000010 /* register transfer opcode */ +#define MASK_CPRT_CODE 0x00f00000 +#define FLT_CODE 0x00000000 +#define FIX_CODE 0x00100000 +#define WFS_CODE 0x00200000 +#define RFS_CODE 0x00300000 +#define WFC_CODE 0x00400000 +#define RFC_CODE 0x00500000 +#define CMF_CODE 0x00900000 +#define CNF_CODE 0x00b00000 +#define CMFE_CODE 0x00d00000 +#define CNFE_CODE 0x00f00000 + +/* +=== +=== Common definitions +=== +*/ + +/* register masks */ +#define MASK_Rd 0x0000f000 +#define MASK_Rn 0x000f0000 +#define MASK_Fd 0x00007000 +#define MASK_Fm 0x00000007 +#define MASK_Fn 0x00070000 + +/* condition code masks */ +#define CC_MASK 0xf0000000 +#define CC_NEGATIVE 0x80000000 +#define CC_ZERO 0x40000000 +#define CC_CARRY 0x20000000 +#define CC_OVERFLOW 0x10000000 +#define CC_EQ 0x00000000 +#define CC_NE 0x10000000 +#define CC_CS 0x20000000 +#define CC_HS CC_CS +#define CC_CC 0x30000000 +#define CC_LO CC_CC +#define CC_MI 0x40000000 +#define CC_PL 0x50000000 +#define CC_VS 0x60000000 +#define CC_VC 0x70000000 +#define CC_HI 0x80000000 +#define CC_LS 0x90000000 +#define CC_GE 0xa0000000 +#define CC_LT 0xb0000000 +#define CC_GT 0xc0000000 +#define CC_LE 0xd0000000 +#define CC_AL 0xe0000000 +#define CC_NV 0xf0000000 + +/* rounding masks/values */ +#define MASK_ROUNDING_MODE 0x00000060 +#define ROUND_TO_NEAREST 0x00000000 +#define ROUND_TO_PLUS_INFINITY 0x00000020 +#define ROUND_TO_MINUS_INFINITY 0x00000040 +#define ROUND_TO_ZERO 0x00000060 + +#define MASK_ROUNDING_PRECISION 0x00080080 +#define ROUND_SINGLE 0x00000000 +#define ROUND_DOUBLE 0x00000080 +#define ROUND_EXTENDED 0x00080000 + +/* Get the condition code from the opcode. */ +#define getCondition(opcode) (opcode >> 28) + +/* Get the source register from the opcode. */ +#define getRn(opcode) ((opcode & MASK_Rn) >> 16) + +/* Get the destination floating point register from the opcode. */ +#define getFd(opcode) ((opcode & MASK_Fd) >> 12) + +/* Get the first source floating point register from the opcode. */ +#define getFn(opcode) ((opcode & MASK_Fn) >> 16) + +/* Get the second source floating point register from the opcode. */ +#define getFm(opcode) (opcode & MASK_Fm) + +/* Get the destination register from the opcode. */ +#define getRd(opcode) ((opcode & MASK_Rd) >> 12) + +/* Get the rounding mode from the opcode. */ +#define getRoundingMode(opcode) ((opcode & MASK_ROUNDING_MODE) >> 5) + +static inline floatx80 getExtendedConstant(const unsigned int nIndex) +{ + extern const floatx80 floatx80Constant[]; + return floatx80Constant[nIndex]; +} + +static inline float64 getDoubleConstant(const unsigned int nIndex) +{ + extern const float64 float64Constant[]; + return float64Constant[nIndex]; +} + +static inline float32 getSingleConstant(const unsigned int nIndex) +{ + extern const float32 float32Constant[]; + return float32Constant[nIndex]; +} + +extern unsigned int getRegisterCount(const unsigned int opcode); +extern unsigned int getDestinationSize(const unsigned int opcode); + +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/arm/nwfpe/fpsr.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/fpsr.h --- qemu-0.9.1/linux-user/arm/nwfpe/fpsr.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/fpsr.h 2008-04-09 07:53:01.000000000 +0100 @@ -0,0 +1,108 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.com, 1998-1999 + + Direct questions, comments to Scott Bambrough + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __FPSR_H__ +#define __FPSR_H__ + +/* +The FPSR is a 32 bit register consisting of 4 parts, each exactly +one byte. + + SYSTEM ID + EXCEPTION TRAP ENABLE BYTE + SYSTEM CONTROL BYTE + CUMULATIVE EXCEPTION FLAGS BYTE + +The FPCR is a 32 bit register consisting of bit flags. +*/ + +/* SYSTEM ID +------------ +Note: the system id byte is read only */ + +typedef unsigned int FPSR; /* type for floating point status register */ +typedef unsigned int FPCR; /* type for floating point control register */ + +#define MASK_SYSID 0xff000000 +#define BIT_HARDWARE 0x80000000 +#define FP_EMULATOR 0x01000000 /* System ID for emulator */ +#define FP_ACCELERATOR 0x81000000 /* System ID for FPA11 */ + +/* EXCEPTION TRAP ENABLE BYTE +----------------------------- */ + +#define MASK_TRAP_ENABLE 0x00ff0000 +#define MASK_TRAP_ENABLE_STRICT 0x001f0000 +#define BIT_IXE 0x00100000 /* inexact exception enable */ +#define BIT_UFE 0x00080000 /* underflow exception enable */ +#define BIT_OFE 0x00040000 /* overflow exception enable */ +#define BIT_DZE 0x00020000 /* divide by zero exception enable */ +#define BIT_IOE 0x00010000 /* invalid operation exception enable */ + +/* SYSTEM CONTROL BYTE +---------------------- */ + +#define MASK_SYSTEM_CONTROL 0x0000ff00 +#define MASK_TRAP_STRICT 0x00001f00 + +#define BIT_AC 0x00001000 /* use alternative C-flag definition + for compares */ +#define BIT_EP 0x00000800 /* use expanded packed decimal format */ +#define BIT_SO 0x00000400 /* select synchronous operation of FPA */ +#define BIT_NE 0x00000200 /* NaN exception bit */ +#define BIT_ND 0x00000100 /* no denormalized numbers bit */ + +/* CUMULATIVE EXCEPTION FLAGS BYTE +---------------------------------- */ + +#define MASK_EXCEPTION_FLAGS 0x000000ff +#define MASK_EXCEPTION_FLAGS_STRICT 0x0000001f + +#define BIT_IXC 0x00000010 /* inexact exception flag */ +#define BIT_UFC 0x00000008 /* underflow exception flag */ +#define BIT_OFC 0x00000004 /* overfloat exception flag */ +#define BIT_DZC 0x00000002 /* divide by zero exception flag */ +#define BIT_IOC 0x00000001 /* invalid operation exception flag */ + +/* Floating Point Control Register +----------------------------------*/ + +#define BIT_RU 0x80000000 /* rounded up bit */ +#define BIT_IE 0x10000000 /* inexact bit */ +#define BIT_MO 0x08000000 /* mantissa overflow bit */ +#define BIT_EO 0x04000000 /* exponent overflow bit */ +#define BIT_SB 0x00000800 /* store bounce */ +#define BIT_AB 0x00000400 /* arithmetic bounce */ +#define BIT_RE 0x00000200 /* rounding exception */ +#define BIT_DA 0x00000100 /* disable FPA */ + +#define MASK_OP 0x00f08010 /* AU operation code */ +#define MASK_PR 0x00080080 /* AU precision */ +#define MASK_S1 0x00070000 /* AU source register 1 */ +#define MASK_S2 0x00000007 /* AU source register 2 */ +#define MASK_DS 0x00007000 /* AU destination register */ +#define MASK_RM 0x00000060 /* AU rounding mode */ +#define MASK_ALU 0x9cfff2ff /* only ALU can write these bits */ +#define MASK_RESET 0x00000d00 /* bits set on reset, all others cleared */ +#define MASK_WFC MASK_RESET +#define MASK_RFC ~MASK_RESET + +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/arm/nwfpe/single_cpdo.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/single_cpdo.c --- qemu-0.9.1/linux-user/arm/nwfpe/single_cpdo.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/linux-user/arm/nwfpe/single_cpdo.c 2008-04-09 07:53:01.000000000 +0100 @@ -0,0 +1,253 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" +#include "softfloat.h" +#include "fpopcode.h" + +float32 float32_exp(float32 Fm); +float32 float32_ln(float32 Fm); +float32 float32_sin(float32 rFm); +float32 float32_cos(float32 rFm); +float32 float32_arcsin(float32 rFm); +float32 float32_arctan(float32 rFm); +float32 float32_log(float32 rFm); +float32 float32_tan(float32 rFm); +float32 float32_arccos(float32 rFm); +float32 float32_pow(float32 rFn,float32 rFm); +float32 float32_pol(float32 rFn,float32 rFm); + +unsigned int SingleCPDO(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + float32 rFm, rFn = float32_zero; + unsigned int Fd, Fm, Fn, nRc = 1; + + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) + { + rFm = getSingleConstant(Fm); + } + else + { + switch (fpa11->fType[Fm]) + { + case typeSingle: + rFm = fpa11->fpreg[Fm].fSingle; + break; + + default: return 0; + } + } + + if (!MONADIC_INSTRUCTION(opcode)) + { + Fn = getFn(opcode); + switch (fpa11->fType[Fn]) + { + case typeSingle: + rFn = fpa11->fpreg[Fn].fSingle; + break; + + default: return 0; + } + } + + Fd = getFd(opcode); + switch (opcode & MASK_ARITHMETIC_OPCODE) + { + /* dyadic opcodes */ + case ADF_CODE: + fpa11->fpreg[Fd].fSingle = float32_add(rFn,rFm, &fpa11->fp_status); + break; + + case MUF_CODE: + case FML_CODE: + fpa11->fpreg[Fd].fSingle = float32_mul(rFn,rFm, &fpa11->fp_status); + break; + + case SUF_CODE: + fpa11->fpreg[Fd].fSingle = float32_sub(rFn,rFm, &fpa11->fp_status); + break; + + case RSF_CODE: + fpa11->fpreg[Fd].fSingle = float32_sub(rFm,rFn, &fpa11->fp_status); + break; + + case DVF_CODE: + case FDV_CODE: + fpa11->fpreg[Fd].fSingle = float32_div(rFn,rFm, &fpa11->fp_status); + break; + + case RDF_CODE: + case FRD_CODE: + fpa11->fpreg[Fd].fSingle = float32_div(rFm,rFn, &fpa11->fp_status); + break; + +#if 0 + case POW_CODE: + fpa11->fpreg[Fd].fSingle = float32_pow(rFn,rFm); + break; + + case RPW_CODE: + fpa11->fpreg[Fd].fSingle = float32_pow(rFm,rFn); + break; +#endif + + case RMF_CODE: + fpa11->fpreg[Fd].fSingle = float32_rem(rFn,rFm, &fpa11->fp_status); + break; + +#if 0 + case POL_CODE: + fpa11->fpreg[Fd].fSingle = float32_pol(rFn,rFm); + break; +#endif + + /* monadic opcodes */ + case MVF_CODE: + fpa11->fpreg[Fd].fSingle = rFm; + break; + + case MNF_CODE: + fpa11->fpreg[Fd].fSingle = float32_chs(rFm); + break; + + case ABS_CODE: + fpa11->fpreg[Fd].fSingle = float32_abs(rFm); + break; + + case RND_CODE: + case URD_CODE: + fpa11->fpreg[Fd].fSingle = float32_round_to_int(rFm, &fpa11->fp_status); + break; + + case SQT_CODE: + fpa11->fpreg[Fd].fSingle = float32_sqrt(rFm, &fpa11->fp_status); + break; + +#if 0 + case LOG_CODE: + fpa11->fpreg[Fd].fSingle = float32_log(rFm); + break; + + case LGN_CODE: + fpa11->fpreg[Fd].fSingle = float32_ln(rFm); + break; + + case EXP_CODE: + fpa11->fpreg[Fd].fSingle = float32_exp(rFm); + break; + + case SIN_CODE: + fpa11->fpreg[Fd].fSingle = float32_sin(rFm); + break; + + case COS_CODE: + fpa11->fpreg[Fd].fSingle = float32_cos(rFm); + break; + + case TAN_CODE: + fpa11->fpreg[Fd].fSingle = float32_tan(rFm); + break; + + case ASN_CODE: + fpa11->fpreg[Fd].fSingle = float32_arcsin(rFm); + break; + + case ACS_CODE: + fpa11->fpreg[Fd].fSingle = float32_arccos(rFm); + break; + + case ATN_CODE: + fpa11->fpreg[Fd].fSingle = float32_arctan(rFm); + break; +#endif + + case NRM_CODE: + break; + + default: + { + nRc = 0; + } + } + + if (0 != nRc) fpa11->fType[Fd] = typeSingle; + return nRc; +} + +#if 0 +float32 float32_exp(float32 Fm) +{ +//series +} + +float32 float32_ln(float32 Fm) +{ +//series +} + +float32 float32_sin(float32 rFm) +{ +//series +} + +float32 float32_cos(float32 rFm) +{ +//series +} + +float32 float32_arcsin(float32 rFm) +{ +//series +} + +float32 float32_arctan(float32 rFm) +{ + //series +} + +float32 float32_arccos(float32 rFm) +{ + //return float32_sub(halfPi,float32_arcsin(rFm)); +} + +float32 float32_log(float32 rFm) +{ + return float32_div(float32_ln(rFm),getSingleConstant(7)); +} + +float32 float32_tan(float32 rFm) +{ + return float32_div(float32_sin(rFm),float32_cos(rFm)); +} + +float32 float32_pow(float32 rFn,float32 rFm) +{ + return float32_exp(float32_mul(rFm,float32_ln(rFn))); +} + +float32 float32_pol(float32 rFn,float32 rFm) +{ + return float32_arctan(float32_div(rFn,rFm)); +} +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/arm/syscall.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/arm/syscall.h --- qemu-0.9.1/linux-user/arm/syscall.h 2008-01-06 19:38:43.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/arm/syscall.h 2008-08-30 10:51:20.000000000 +0100 @@ -28,7 +28,9 @@ #define ARM_SYSCALL_BASE 0x900000 #define ARM_THUMB_SYSCALL 0 -#define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2) +#define ARM_NR_BASE 0xf0000 +#define ARM_NR_cacheflush (ARM_NR_BASE + 2) +#define ARM_NR_set_tls (ARM_NR_BASE + 5) #define ARM_NR_semihosting 0x123456 #define ARM_NR_thumb_semihosting 0xAB @@ -38,5 +40,3 @@ #else #define UNAME_MACHINE "armv5tel" #endif - -uint32_t do_arm_semihosting(CPUState *); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/elfload.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/elfload.c --- qemu-0.9.1/linux-user/elfload.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/elfload.c 2008-10-22 16:11:31.000000000 +0100 @@ -12,6 +12,15 @@ #include "qemu.h" #include "disas.h" +#ifdef __powerpc64__ +#undef ARCH_DLINFO +#undef ELF_PLATFORM +#undef ELF_HWCAP +#undef ELF_CLASS +#undef ELF_DATA +#undef ELF_ARCH +#endif + /* from personality.h */ /* @@ -89,7 +98,7 @@ static const char *get_elf_platform(void) { static char elf_platform[] = "i386"; - int family = (global_env->cpuid_version >> 8) & 0xff; + int family = (thread_env->cpuid_version >> 8) & 0xff; if (family > 6) family = 6; if (family >= 3) @@ -101,7 +110,7 @@ static uint32_t get_elf_hwcap(void) { - return global_env->cpuid_features; + return thread_env->cpuid_features; } #ifdef TARGET_X86_64 @@ -536,8 +545,6 @@ memcpy(to, from, n); } -extern unsigned long x86_stack_size; - static int load_aout_interp(void * exptr, int interp_fd); #ifdef BSWAP_NEEDED @@ -805,6 +812,7 @@ NEW_AUX_ENT(AT_GID, (abi_ulong) getgid()); NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid()); NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP); + NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK)); if (k_platform) NEW_AUX_ENT(AT_PLATFORM, u_platform); #ifdef ARCH_DLINFO @@ -976,80 +984,134 @@ return ((abi_ulong) interp_elf_ex->e_entry) + load_addr; } +static int symfind(const void *s0, const void *s1) +{ + struct elf_sym *key = (struct elf_sym *)s0; + struct elf_sym *sym = (struct elf_sym *)s1; + int result = 0; + if (key->st_value < sym->st_value) { + result = -1; + } else if (key->st_value > sym->st_value + sym->st_size) { + result = 1; + } + return result; +} + +static const char *lookup_symbolxx(struct syminfo *s, target_ulong orig_addr) +{ +#if ELF_CLASS == ELFCLASS32 + struct elf_sym *syms = s->disas_symtab.elf32; +#else + struct elf_sym *syms = s->disas_symtab.elf64; +#endif + + // binary search + struct elf_sym key; + struct elf_sym *sym; + + key.st_value = orig_addr; + + sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), symfind); + if (sym != 0) { + return s->disas_strtab + sym->st_name; + } + + return ""; +} + +/* FIXME: This should use elf_ops.h */ +static int symcmp(const void *s0, const void *s1) +{ + struct elf_sym *sym0 = (struct elf_sym *)s0; + struct elf_sym *sym1 = (struct elf_sym *)s1; + return (sym0->st_value < sym1->st_value) + ? -1 + : ((sym0->st_value > sym1->st_value) ? 1 : 0); +} + /* Best attempt to load symbols from this ELF object. */ static void load_symbols(struct elfhdr *hdr, int fd) { - unsigned int i; + unsigned int i, nsyms; struct elf_shdr sechdr, symtab, strtab; char *strings; struct syminfo *s; -#if (ELF_CLASS == ELFCLASS64) - // Disas uses 32 bit symbols - struct elf32_sym *syms32 = NULL; - struct elf_sym *sym; -#endif + struct elf_sym *syms; lseek(fd, hdr->e_shoff, SEEK_SET); for (i = 0; i < hdr->e_shnum; i++) { - if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) - return; + if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) + return; #ifdef BSWAP_NEEDED - bswap_shdr(&sechdr); + bswap_shdr(&sechdr); #endif - if (sechdr.sh_type == SHT_SYMTAB) { - symtab = sechdr; - lseek(fd, hdr->e_shoff - + sizeof(sechdr) * sechdr.sh_link, SEEK_SET); - if (read(fd, &strtab, sizeof(strtab)) - != sizeof(strtab)) - return; + if (sechdr.sh_type == SHT_SYMTAB) { + symtab = sechdr; + lseek(fd, hdr->e_shoff + + sizeof(sechdr) * sechdr.sh_link, SEEK_SET); + if (read(fd, &strtab, sizeof(strtab)) + != sizeof(strtab)) + return; #ifdef BSWAP_NEEDED - bswap_shdr(&strtab); + bswap_shdr(&strtab); #endif - goto found; - } + goto found; + } } return; /* Shouldn't happen... */ found: /* Now know where the strtab and symtab are. Snarf them. */ s = malloc(sizeof(*s)); - s->disas_symtab = malloc(symtab.sh_size); -#if (ELF_CLASS == ELFCLASS64) - syms32 = malloc(symtab.sh_size / sizeof(struct elf_sym) - * sizeof(struct elf32_sym)); -#endif + syms = malloc(symtab.sh_size); + if (!syms) + return; s->disas_strtab = strings = malloc(strtab.sh_size); - if (!s->disas_symtab || !s->disas_strtab) - return; + if (!s->disas_strtab) + return; lseek(fd, symtab.sh_offset, SEEK_SET); - if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size) - return; + if (read(fd, syms, symtab.sh_size) != symtab.sh_size) + return; + + nsyms = symtab.sh_size / sizeof(struct elf_sym); - for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) { + i = 0; + while (i < nsyms) { #ifdef BSWAP_NEEDED - bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i); + bswap_sym(syms + i); #endif -#if (ELF_CLASS == ELFCLASS64) - sym = s->disas_symtab + sizeof(struct elf_sym)*i; - syms32[i].st_name = sym->st_name; - syms32[i].st_info = sym->st_info; - syms32[i].st_other = sym->st_other; - syms32[i].st_shndx = sym->st_shndx; - syms32[i].st_value = sym->st_value & 0xffffffff; - syms32[i].st_size = sym->st_size & 0xffffffff; + // Throw away entries which we do not need. + if (syms[i].st_shndx == SHN_UNDEF || + syms[i].st_shndx >= SHN_LORESERVE || + ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) { + nsyms--; + if (i < nsyms) { + syms[i] = syms[nsyms]; + } + continue; + } +#if defined(TARGET_ARM) || defined (TARGET_MIPS) + /* The bottom address bit marks a Thumb or MIPS16 symbol. */ + syms[i].st_value &= ~(target_ulong)1; #endif + i++; } + syms = realloc(syms, nsyms * sizeof(*syms)); + + qsort(syms, nsyms, sizeof(*syms), symcmp); -#if (ELF_CLASS == ELFCLASS64) - free(s->disas_symtab); - s->disas_symtab = syms32; -#endif lseek(fd, strtab.sh_offset, SEEK_SET); if (read(fd, strings, strtab.sh_size) != strtab.sh_size) - return; - s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); + return; + s->disas_num_syms = nsyms; +#if ELF_CLASS == ELFCLASS32 + s->disas_symtab.elf32 = syms; + s->lookup_symbol = lookup_symbolxx; +#else + s->disas_symtab.elf64 = syms; + s->lookup_symbol = lookup_symbolxx; +#endif s->next = syminfos; syminfos = s; } @@ -1138,6 +1200,7 @@ end_code = 0; start_data = 0; end_data = 0; + interp_ex.a_info = 0; for(i=0;i < elf_ex.e_phnum; i++) { if (elf_ppnt->p_type == PT_INTERP) { @@ -1230,7 +1293,7 @@ } if (interp_elf_ex.e_ident[0] != 0x7f || - strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) { + strncmp((char *)&interp_elf_ex.e_ident[1], "ELF",3) != 0) { interpreter_type &= ~INTERPRETER_ELF; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/flatload.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/flatload.c --- qemu-0.9.1/linux-user/flatload.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/flatload.c 2008-10-26 13:43:07.000000000 +0000 @@ -102,8 +102,8 @@ return p; } -int target_pread(int fd, abi_ulong ptr, abi_ulong len, - abi_ulong offset) +static int target_pread(int fd, abi_ulong ptr, abi_ulong len, + abi_ulong offset) { void *buf; int ret; @@ -336,7 +336,7 @@ /****************************************************************************/ /* ??? This does not handle endianness correctly. */ -void old_reloc(struct lib_info *libinfo, uint32_t rl) +static void old_reloc(struct lib_info *libinfo, uint32_t rl) { #ifdef DEBUG char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" }; @@ -349,9 +349,9 @@ reloc_type = rl >> 30; /* ??? How to handle this? */ #if defined(CONFIG_COLDFIRE) - ptr = (uint32_t *) (libinfo->start_code + offset); + ptr = (uint32_t *) ((unsigned long) libinfo->start_code + offset); #else - ptr = (uint32_t *) (libinfo->start_data + offset); + ptr = (uint32_t *) ((unsigned long) libinfo->start_data + offset); #endif #ifdef DEBUG @@ -670,7 +670,7 @@ } /* zero the BSS. */ - memset((void*)(datapos + data_len), 0, bss_len); + memset((void *)((unsigned long)datapos + data_len), 0, bss_len); return 0; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/ioctls.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/ioctls.h --- qemu-0.9.1/linux-user/ioctls.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/ioctls.h 2008-09-20 04:03:09.000000000 +0100 @@ -300,3 +300,17 @@ IOCTL(VFAT_IOCTL_READDIR_BOTH, IOC_R, MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_dirent), 2))) IOCTL(VFAT_IOCTL_READDIR_SHORT, IOC_R, MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_dirent), 2))) + + IOCTL(LOOP_SET_FD, 0, TYPE_INT) + IOCTL(LOOP_CLR_FD, 0, TYPE_INT) + IOCTL(LOOP_SET_STATUS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info))) + IOCTL(LOOP_GET_STATUS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info))) +#if 0 /* These have some problems - not fully tested */ + IOCTL(LOOP_SET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64))) + IOCTL(LOOP_GET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64))) +#endif + IOCTL(LOOP_CHANGE_FD, 0, TYPE_INT) + + IOCTL(MTIOCTOP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_mtop))) + IOCTL(MTIOCGET, IOC_R, MK_PTR(MK_STRUCT(STRUCT_mtget))) + IOCTL(MTIOCPOS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_mtpos))) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/linux_loop.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/linux_loop.h --- qemu-0.9.1/linux-user/linux_loop.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/linux-user/linux_loop.h 2008-05-23 17:06:43.000000000 +0100 @@ -0,0 +1,95 @@ +/* Copied from 2.6.25 kernel headers to avoid problems on older hosts. */ +#ifndef _LINUX_LOOP_H +#define _LINUX_LOOP_H + +/* + * include/linux/loop.h + * + * Written by Theodore Ts'o, 3/29/93. + * + * Copyright 1993 by Theodore Ts'o. Redistribution of this file is + * permitted under the GNU General Public License. + */ + +#define LO_NAME_SIZE 64 +#define LO_KEY_SIZE 32 + + +/* + * Loop flags + */ +enum { + LO_FLAGS_READ_ONLY = 1, + LO_FLAGS_USE_AOPS = 2, + LO_FLAGS_AUTOCLEAR = 4, +}; + +#include +#include /* for __kernel_old_dev_t */ +#include /* for __u64 */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) /* This is a guess. */ +#define __kernel_old_dev_t __kernel_dev_t +#endif + +/* Backwards compatibility version */ +struct loop_info { + int lo_number; /* ioctl r/o */ + __kernel_old_dev_t lo_device; /* ioctl r/o */ + unsigned long lo_inode; /* ioctl r/o */ + __kernel_old_dev_t lo_rdevice; /* ioctl r/o */ + int lo_offset; + int lo_encrypt_type; + int lo_encrypt_key_size; /* ioctl w/o */ + int lo_flags; /* ioctl r/o */ + char lo_name[LO_NAME_SIZE]; + unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ + unsigned long lo_init[2]; + char reserved[4]; +}; + +struct loop_info64 { + __u64 lo_device; /* ioctl r/o */ + __u64 lo_inode; /* ioctl r/o */ + __u64 lo_rdevice; /* ioctl r/o */ + __u64 lo_offset; + __u64 lo_sizelimit;/* bytes, 0 == max available */ + __u32 lo_number; /* ioctl r/o */ + __u32 lo_encrypt_type; + __u32 lo_encrypt_key_size; /* ioctl w/o */ + __u32 lo_flags; /* ioctl r/o */ + __u8 lo_file_name[LO_NAME_SIZE]; + __u8 lo_crypt_name[LO_NAME_SIZE]; + __u8 lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ + __u64 lo_init[2]; +}; + +/* + * Loop filter types + */ + +#define LO_CRYPT_NONE 0 +#define LO_CRYPT_XOR 1 +#define LO_CRYPT_DES 2 +#define LO_CRYPT_FISH2 3 /* Twofish encryption */ +#define LO_CRYPT_BLOW 4 +#define LO_CRYPT_CAST128 5 +#define LO_CRYPT_IDEA 6 +#define LO_CRYPT_DUMMY 9 +#define LO_CRYPT_SKIPJACK 10 +#define LO_CRYPT_CRYPTOAPI 18 +#define MAX_LO_CRYPT 20 + +/* + * IOCTL commands --- we will commandeer 0x4C ('L') + */ + +#define LOOP_SET_FD 0x4C00 +#define LOOP_CLR_FD 0x4C01 +#define LOOP_SET_STATUS 0x4C02 +#define LOOP_GET_STATUS 0x4C03 +#define LOOP_SET_STATUS64 0x4C04 +#define LOOP_GET_STATUS64 0x4C05 +#define LOOP_CHANGE_FD 0x4C06 + +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/m68k/syscall.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/m68k/syscall.h --- qemu-0.9.1/linux-user/m68k/syscall.h 2008-01-06 19:38:43.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/m68k/syscall.h 2008-08-30 10:51:20.000000000 +0100 @@ -18,5 +18,4 @@ #define UNAME_MACHINE "m68k" -void do_m68k_semihosting(CPUState *, int); void do_m68k_simcall(CPUState *, int); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/m68k-sim.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/m68k-sim.c --- qemu-0.9.1/linux-user/m68k-sim.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/m68k-sim.c 2008-07-16 13:13:52.000000000 +0100 @@ -101,19 +101,19 @@ { uint32_t *args; - args = (uint32_t *)(env->aregs[7] + 4); + args = (uint32_t *)(unsigned long)(env->aregs[7] + 4); switch (nr) { case SYS_EXIT: exit(ARG(0)); case SYS_READ: - check_err(env, read(ARG(0), (void *)ARG(1), ARG(2))); + check_err(env, read(ARG(0), (void *)(unsigned long)ARG(1), ARG(2))); break; case SYS_WRITE: - check_err(env, write(ARG(0), (void *)ARG(1), ARG(2))); + check_err(env, write(ARG(0), (void *)(unsigned long)ARG(1), ARG(2))); break; case SYS_OPEN: - check_err(env, open((char *)ARG(0), translate_openflags(ARG(1)), - ARG(2))); + check_err(env, open((char *)(unsigned long)ARG(0), + translate_openflags(ARG(1)), ARG(2))); break; case SYS_CLOSE: { @@ -142,7 +142,7 @@ struct m86k_sim_stat *p; rc = check_err(env, fstat(ARG(0), &s)); if (rc == 0) { - p = (struct m86k_sim_stat *)ARG(1); + p = (struct m86k_sim_stat *)(unsigned long)ARG(1); p->sim_st_dev = tswap16(s.st_dev); p->sim_st_ino = tswap16(s.st_ino); p->sim_st_mode = tswap32(s.st_mode); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/main.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/main.c --- qemu-0.9.1/linux-user/main.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/main.c 2008-11-10 02:55:33.000000000 +0000 @@ -23,8 +23,12 @@ #include #include #include +#include #include "qemu.h" +#include "qemu-common.h" +/* For tb_lock */ +#include "exec-all.h" #define DEBUG_LOGFILE "/tmp/qemu.log" @@ -53,7 +57,8 @@ "__init_array_end:\n" "__fini_array_start:\n" "__fini_array_end:\n" - ".long 0\n"); + ".long 0\n" + ".previous\n"); #endif /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so @@ -103,10 +108,12 @@ return 0; } +#if defined(TARGET_I386) int cpu_get_pic_interrupt(CPUState *env) { return -1; } +#endif /* timers for rdtsc */ @@ -121,6 +128,135 @@ #endif +#if defined(USE_NPTL) +/***********************************************************/ +/* Helper routines for implementing atomic operations. */ + +/* To implement exclusive operations we force all cpus to syncronise. + We don't require a full sync, only that no cpus are executing guest code. + The alternative is to map target atomic ops onto host equivalents, + which requires quite a lot of per host/target work. */ +static pthread_mutex_t exclusive_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t exclusive_cond = PTHREAD_COND_INITIALIZER; +static pthread_cond_t exclusive_resume = PTHREAD_COND_INITIALIZER; +static int pending_cpus; + +/* Make sure everything is in a consistent state for calling fork(). */ +void fork_start(void) +{ + mmap_fork_start(); + pthread_mutex_lock(&tb_lock); + pthread_mutex_lock(&exclusive_lock); +} + +void fork_end(int child) +{ + if (child) { + /* Child processes created by fork() only have a single thread. + Discard information about the parent threads. */ + first_cpu = thread_env; + thread_env->next_cpu = NULL; + pending_cpus = 0; + pthread_mutex_init(&exclusive_lock, NULL); + pthread_cond_init(&exclusive_cond, NULL); + pthread_cond_init(&exclusive_resume, NULL); + pthread_mutex_init(&tb_lock, NULL); + } else { + pthread_mutex_unlock(&exclusive_lock); + pthread_mutex_unlock(&tb_lock); + } + mmap_fork_end(child); +} + +/* Wait for pending exclusive operations to complete. The exclusive lock + must be held. */ +static inline void exclusive_idle(void) +{ + while (pending_cpus) { + pthread_cond_wait(&exclusive_resume, &exclusive_lock); + } +} + +/* Start an exclusive operation. + Must only be called from outside cpu_arm_exec. */ +static inline void start_exclusive(void) +{ + CPUState *other; + pthread_mutex_lock(&exclusive_lock); + exclusive_idle(); + + pending_cpus = 1; + /* Make all other cpus stop executing. */ + for (other = first_cpu; other; other = other->next_cpu) { + if (other->running) { + pending_cpus++; + cpu_interrupt(other, CPU_INTERRUPT_EXIT); + } + } + if (pending_cpus > 1) { + pthread_cond_wait(&exclusive_cond, &exclusive_lock); + } +} + +/* Finish an exclusive operation. */ +static inline void end_exclusive(void) +{ + pending_cpus = 0; + pthread_cond_broadcast(&exclusive_resume); + pthread_mutex_unlock(&exclusive_lock); +} + +/* Wait for exclusive ops to finish, and begin cpu execution. */ +static inline void cpu_exec_start(CPUState *env) +{ + pthread_mutex_lock(&exclusive_lock); + exclusive_idle(); + env->running = 1; + pthread_mutex_unlock(&exclusive_lock); +} + +/* Mark cpu as not executing, and release pending exclusive ops. */ +static inline void cpu_exec_end(CPUState *env) +{ + pthread_mutex_lock(&exclusive_lock); + env->running = 0; + if (pending_cpus > 1) { + pending_cpus--; + if (pending_cpus == 1) { + pthread_cond_signal(&exclusive_cond); + } + } + exclusive_idle(); + pthread_mutex_unlock(&exclusive_lock); +} +#else /* if !USE_NPTL */ +/* These are no-ops because we are not threadsafe. */ +static inline void cpu_exec_start(CPUState *env) +{ +} + +static inline void cpu_exec_end(CPUState *env) +{ +} + +static inline void start_exclusive(void) +{ +} + +static inline void end_exclusive(void) +{ +} + +void fork_start(void) +{ +} + +void fork_end(int child) +{ +} +#endif + + #ifdef TARGET_I386 /***********************************************************/ /* CPUX86 core interface */ @@ -143,13 +279,12 @@ e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); e2 |= flags; p = ptr; - p[0] = tswapl(e1); - p[1] = tswapl(e2); + p[0] = tswap32(e1); + p[1] = tswap32(e2); } -#if TARGET_X86_64 -uint64_t idt_table[512]; - +static uint64_t *idt_table; +#ifdef TARGET_X86_64 static void set_gate64(void *ptr, unsigned int type, unsigned int dpl, uint64_t addr, unsigned int sel) { @@ -168,8 +303,6 @@ set_gate64(idt_table + n * 2, 0, dpl, 0, 0); } #else -uint64_t idt_table[256]; - static void set_gate(void *ptr, unsigned int type, unsigned int dpl, uint32_t addr, unsigned int sel) { @@ -228,7 +361,7 @@ info.si_errno = 0; info.si_code = TARGET_SI_KERNEL; info._sifields._sigfault._addr = 0; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); break; case EXCP0D_GPF: /* XXX: potential problem if ABI32 */ @@ -242,7 +375,7 @@ info.si_errno = 0; info.si_code = TARGET_SI_KERNEL; info._sifields._sigfault._addr = 0; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); } break; case EXCP0E_PAGE: @@ -253,7 +386,7 @@ else info.si_code = TARGET_SEGV_ACCERR; info._sifields._sigfault._addr = env->cr[2]; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); break; case EXCP00_DIVZ: #ifndef TARGET_X86_64 @@ -267,7 +400,7 @@ info.si_errno = 0; info.si_code = TARGET_FPE_INTDIV; info._sifields._sigfault._addr = env->eip; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); } break; case EXCP01_SSTP: @@ -287,7 +420,7 @@ info.si_code = TARGET_SI_KERNEL; info._sifields._sigfault._addr = 0; } - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); } break; case EXCP04_INTO: @@ -302,7 +435,7 @@ info.si_errno = 0; info.si_code = TARGET_SI_KERNEL; info._sifields._sigfault._addr = 0; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); } break; case EXCP06_ILLOP: @@ -310,7 +443,7 @@ info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPN; info._sifields._sigfault._addr = env->eip; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); break; case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ @@ -325,7 +458,7 @@ info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); } } break; @@ -342,9 +475,6 @@ #ifdef TARGET_ARM -/* XXX: find a better solution */ -extern void tb_invalidate_page_range(abi_ulong start, abi_ulong end); - static void arm_cache_flush(abi_ulong start, abi_ulong last) { abi_ulong addr, last1; @@ -363,6 +493,59 @@ } } +/* Handle a jump to the kernel code page. */ +static int +do_kernel_trap(CPUARMState *env) +{ + uint32_t addr; + uint32_t cpsr; + uint32_t val; + + switch (env->regs[15]) { + case 0xffff0fa0: /* __kernel_memory_barrier */ + /* ??? No-op. Will need to do better for SMP. */ + break; + case 0xffff0fc0: /* __kernel_cmpxchg */ + /* XXX: This only works between threads, not between processes. + It's probably possible to implement this with native host + operations. However things like ldrex/strex are much harder so + there's not much point trying. */ + start_exclusive(); + cpsr = cpsr_read(env); + addr = env->regs[2]; + /* FIXME: This should SEGV if the access fails. */ + if (get_user_u32(val, addr)) + val = ~env->regs[0]; + if (val == env->regs[0]) { + val = env->regs[1]; + /* FIXME: Check for segfaults. */ + put_user_u32(val, addr); + env->regs[0] = 0; + cpsr |= CPSR_C; + } else { + env->regs[0] = -1; + cpsr &= ~CPSR_C; + } + cpsr_write(env, cpsr, CPSR_C); + end_exclusive(); + break; + case 0xffff0fe0: /* __kernel_get_tls */ + env->regs[0] = env->cp15.c13_tls2; + break; + default: + return 1; + } + /* Jump back to the caller. */ + addr = env->regs[14]; + if (addr & 1) { + env->thumb = 1; + addr &= ~1; + } + env->regs[15] = addr; + + return 0; +} + void cpu_loop(CPUARMState *env) { int trapnr; @@ -371,25 +554,76 @@ uint32_t addr; for(;;) { + cpu_exec_start(env); trapnr = cpu_arm_exec(env); + cpu_exec_end(env); switch(trapnr) { case EXCP_UDEF: { TaskState *ts = env->opaque; uint32_t opcode; + int rc; /* we handle the FPU emulation here, as Linux */ /* we get the opcode */ /* FIXME - what to do if get_user() fails? */ get_user_u32(opcode, env->regs[15]); - if (EmulateAll(opcode, &ts->fpa, env) == 0) { + rc = EmulateAll(opcode, &ts->fpa, env); + if (rc == 0) { /* illegal instruction */ info.si_signo = SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPN; info._sifields._sigfault._addr = env->regs[15]; - queue_signal(info.si_signo, &info); - } else { + queue_signal(env, info.si_signo, &info); + } else if (rc < 0) { /* FP exception */ + int arm_fpe=0; + + /* translate softfloat flags to FPSR flags */ + if (-rc & float_flag_invalid) + arm_fpe |= BIT_IOC; + if (-rc & float_flag_divbyzero) + arm_fpe |= BIT_DZC; + if (-rc & float_flag_overflow) + arm_fpe |= BIT_OFC; + if (-rc & float_flag_underflow) + arm_fpe |= BIT_UFC; + if (-rc & float_flag_inexact) + arm_fpe |= BIT_IXC; + + FPSR fpsr = ts->fpa.fpsr; + //printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe); + + if (fpsr & (arm_fpe << 16)) { /* exception enabled? */ + info.si_signo = SIGFPE; + info.si_errno = 0; + + /* ordered by priority, least first */ + if (arm_fpe & BIT_IXC) info.si_code = TARGET_FPE_FLTRES; + if (arm_fpe & BIT_UFC) info.si_code = TARGET_FPE_FLTUND; + if (arm_fpe & BIT_OFC) info.si_code = TARGET_FPE_FLTOVF; + if (arm_fpe & BIT_DZC) info.si_code = TARGET_FPE_FLTDIV; + if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV; + + info._sifields._sigfault._addr = env->regs[15]; + queue_signal(env, info.si_signo, &info); + } else { + env->regs[15] += 4; + } + + /* accumulate unenabled exceptions */ + if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC)) + fpsr |= BIT_IXC; + if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC)) + fpsr |= BIT_UFC; + if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC)) + fpsr |= BIT_OFC; + if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC)) + fpsr |= BIT_DZC; + if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC)) + fpsr |= BIT_IOC; + ts->fpa.fpsr=fpsr; + } else { /* everything OK */ /* increment PC */ env->regs[15] += 4; } @@ -438,14 +672,31 @@ n -= ARM_SYSCALL_BASE; env->eabi = 0; } - env->regs[0] = do_syscall(env, - n, - env->regs[0], - env->regs[1], - env->regs[2], - env->regs[3], - env->regs[4], - env->regs[5]); + if ( n > ARM_NR_BASE) { + switch (n) { + case ARM_NR_cacheflush: + arm_cache_flush(env->regs[0], env->regs[1]); + break; + case ARM_NR_set_tls: + cpu_set_tls(env, env->regs[0]); + env->regs[0] = 0; + break; + default: + gemu_log("qemu: Unsupported ARM syscall: 0x%x\n", + n); + env->regs[0] = -TARGET_ENOSYS; + break; + } + } else { + env->regs[0] = do_syscall(env, + n, + env->regs[0], + env->regs[1], + env->regs[2], + env->regs[3], + env->regs[4], + env->regs[5]); + } } else { goto error; } @@ -455,10 +706,10 @@ /* just indicate that signals should be handled asap */ break; case EXCP_PREFETCH_ABORT: - addr = env->cp15.c6_data; + addr = env->cp15.c6_insn; goto do_segv; case EXCP_DATA_ABORT: - addr = env->cp15.c6_insn; + addr = env->cp15.c6_data; goto do_segv; do_segv: { @@ -467,7 +718,7 @@ /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = addr; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); } break; case EXCP_DEBUG: @@ -480,10 +731,14 @@ info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); } } break; + case EXCP_KERNEL_TRAP: + if (do_kernel_trap(env)) + goto error; + break; default: error: fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", @@ -498,6 +753,7 @@ #endif #ifdef TARGET_SPARC +#define SPARC64_STACK_BIAS 2047 //#define DEBUG_WIN @@ -505,11 +761,11 @@ can be found at http://www.sics.se/~psm/sparcstack.html */ static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) { - index = (index + cwp * 16) & (16 * NWINDOWS - 1); + index = (index + cwp * 16) % (16 * env->nwindows); /* wrap handling : if cwp is on the last window, then we use the registers 'after' the end */ - if (index < 8 && env->cwp == (NWINDOWS - 1)) - index += (16 * NWINDOWS); + if (index < 8 && env->cwp == env->nwindows - 1) + index += 16 * env->nwindows; return index; } @@ -520,9 +776,13 @@ abi_ulong sp_ptr; sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; +#ifdef TARGET_SPARC64 + if (sp_ptr & 3) + sp_ptr += SPARC64_STACK_BIAS; +#endif #if defined(DEBUG_WIN) - printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n", - (int)sp_ptr, cwp1); + printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n", + sp_ptr, cwp1); #endif for(i = 0; i < 16; i++) { /* FIXME - what to do if put_user() fails? */ @@ -535,12 +795,12 @@ { #ifndef TARGET_SPARC64 unsigned int new_wim; - new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) & - ((1LL << NWINDOWS) - 1); - save_window_offset(env, (env->cwp - 2) & (NWINDOWS - 1)); + new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) & + ((1LL << env->nwindows) - 1); + save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2)); env->wim = new_wim; #else - save_window_offset(env, (env->cwp - 2) & (NWINDOWS - 1)); + save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2)); env->cansave++; env->canrestore--; #endif @@ -548,30 +808,40 @@ static void restore_window(CPUSPARCState *env) { - unsigned int new_wim, i, cwp1; +#ifndef TARGET_SPARC64 + unsigned int new_wim; +#endif + unsigned int i, cwp1; abi_ulong sp_ptr; - new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) & - ((1LL << NWINDOWS) - 1); +#ifndef TARGET_SPARC64 + new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) & + ((1LL << env->nwindows) - 1); +#endif /* restore the invalid window */ - cwp1 = (env->cwp + 1) & (NWINDOWS - 1); + cwp1 = cpu_cwp_inc(env, env->cwp + 1); sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; +#ifdef TARGET_SPARC64 + if (sp_ptr & 3) + sp_ptr += SPARC64_STACK_BIAS; +#endif #if defined(DEBUG_WIN) - printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n", - (int)sp_ptr, cwp1); + printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n", + sp_ptr, cwp1); #endif for(i = 0; i < 16; i++) { /* FIXME - what to do if get_user() fails? */ get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); sp_ptr += sizeof(abi_ulong); } - env->wim = new_wim; #ifdef TARGET_SPARC64 env->canrestore++; - if (env->cleanwin < NWINDOWS - 1) - env->cleanwin++; + if (env->cleanwin < env->nwindows - 1) + env->cleanwin++; env->cansave--; +#else + env->wim = new_wim; #endif } @@ -582,15 +852,24 @@ offset = 1; for(;;) { /* if restore would invoke restore_window(), then we can stop */ - cwp1 = (env->cwp + offset) & (NWINDOWS - 1); + cwp1 = cpu_cwp_inc(env, env->cwp + offset); +#ifndef TARGET_SPARC64 if (env->wim & (1 << cwp1)) break; +#else + if (env->canrestore == 0) + break; + env->cansave++; + env->canrestore--; +#endif save_window_offset(env, cwp1); offset++; } + cwp1 = cpu_cwp_inc(env, env->cwp + 1); +#ifndef TARGET_SPARC64 /* set wim so that restore will reload the registers */ - cwp1 = (env->cwp + 1) & (NWINDOWS - 1); env->wim = 1 << cwp1; +#endif #if defined(DEBUG_WIN) printf("flush_windows: nb=%d\n", offset - 1); #endif @@ -659,7 +938,7 @@ /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->mmuregs[4]; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); } break; #else @@ -679,8 +958,8 @@ if (trapnr == TT_DFAULT) info._sifields._sigfault._addr = env->dmmuregs[4]; else - info._sifields._sigfault._addr = env->tpc[env->tl]; - queue_signal(info.si_signo, &info); + info._sifields._sigfault._addr = env->tsptr->tpc; + queue_signal(env, info.si_signo, &info); } break; #ifndef TARGET_ABI32 @@ -707,7 +986,7 @@ info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); } } break; @@ -828,7 +1107,7 @@ break; } info._sifields._sigfault._addr = env->nip; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); break; case POWERPC_EXCP_ISI: /* Instruction storage exception */ EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" ADDRX "\n", @@ -856,7 +1135,7 @@ break; } info._sifields._sigfault._addr = env->nip - 4; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); break; case POWERPC_EXCP_EXTERNAL: /* External input */ cpu_abort(env, "External interrupt while in user mode. " @@ -869,7 +1148,7 @@ info.si_errno = 0; info.si_code = TARGET_BUS_ADRALN; info._sifields._sigfault._addr = env->nip - 4; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); break; case POWERPC_EXCP_PROGRAM: /* Program exception */ /* XXX: check this */ @@ -962,7 +1241,7 @@ break; } info._sifields._sigfault._addr = env->nip - 4; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); break; case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ EXCP_DUMP(env, "No floating point allowed\n"); @@ -970,7 +1249,7 @@ info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; info._sifields._sigfault._addr = env->nip - 4; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); break; case POWERPC_EXCP_SYSCALL: /* System call exception */ cpu_abort(env, "Syscall exception while in user mode. " @@ -982,7 +1261,7 @@ info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; info._sifields._sigfault._addr = env->nip - 4; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); break; case POWERPC_EXCP_DECR: /* Decrementer exception */ cpu_abort(env, "Decrementer interrupt while in user mode. " @@ -1014,7 +1293,7 @@ info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); } } break; @@ -1024,7 +1303,7 @@ info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; info._sifields._sigfault._addr = env->nip - 4; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); break; case POWERPC_EXCP_EFPDI: /* Embedded floating-point data IRQ */ cpu_abort(env, "Embedded floating-point data IRQ not handled\n"); @@ -1088,7 +1367,7 @@ info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; info._sifields._sigfault._addr = env->nip - 4; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); break; case POWERPC_EXCP_PIT: /* Programmable interval timer IRQ */ cpu_abort(env, "Programable interval timer interrupt " @@ -1521,8 +1800,8 @@ trapnr = cpu_mips_exec(env); switch(trapnr) { case EXCP_SYSCALL: - syscall_num = env->gpr[2][env->current_tc] - 4000; - env->PC[env->current_tc] += 4; + syscall_num = env->active_tc.gpr[2] - 4000; + env->active_tc.PC += 4; if (syscall_num >= sizeof(mips_syscall_args)) { ret = -ENOSYS; } else { @@ -1531,7 +1810,7 @@ abi_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0; nb_args = mips_syscall_args[syscall_num]; - sp_reg = env->gpr[29][env->current_tc]; + sp_reg = env->active_tc.gpr[29]; switch (nb_args) { /* these arguments are taken from the stack */ /* FIXME - what to do if get_user() fails? */ @@ -1542,20 +1821,20 @@ default: break; } - ret = do_syscall(env, env->gpr[2][env->current_tc], - env->gpr[4][env->current_tc], - env->gpr[5][env->current_tc], - env->gpr[6][env->current_tc], - env->gpr[7][env->current_tc], + ret = do_syscall(env, env->active_tc.gpr[2], + env->active_tc.gpr[4], + env->active_tc.gpr[5], + env->active_tc.gpr[6], + env->active_tc.gpr[7], arg5, arg6/*, arg7, arg8*/); } if ((unsigned int)ret >= (unsigned int)(-1133)) { - env->gpr[7][env->current_tc] = 1; /* error flag */ + env->active_tc.gpr[7] = 1; /* error flag */ ret = -ret; } else { - env->gpr[7][env->current_tc] = 0; /* error flag */ + env->active_tc.gpr[7] = 0; /* error flag */ } - env->gpr[2][env->current_tc] = ret; + env->active_tc.gpr[2] = ret; break; case EXCP_TLBL: case EXCP_TLBS: @@ -1564,7 +1843,7 @@ info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = 0; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); break; case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ @@ -1579,7 +1858,7 @@ info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); } } break; @@ -1606,6 +1885,7 @@ switch (trapnr) { case 0x160: + env->pc += 2; ret = do_syscall(env, env->gregs[3], env->gregs[4], @@ -1615,7 +1895,6 @@ env->gregs[0], env->gregs[1]); env->gregs[0] = ret; - env->pc += 2; break; case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ @@ -1630,7 +1909,7 @@ info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); } } break; @@ -1640,7 +1919,7 @@ info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->tea; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); break; default: @@ -1668,10 +1947,13 @@ info.si_errno = 0; /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; - info._sifields._sigfault._addr = env->debug1; - queue_signal(info.si_signo, &info); + info._sifields._sigfault._addr = env->pregs[PR_EDA]; + queue_signal(env, info.si_signo, &info); } break; + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; case EXCP_BREAK: ret = do_syscall(env, env->regs[9], @@ -1682,7 +1964,6 @@ env->pregs[7], env->pregs[11]); env->regs[10] = ret; - env->pc += 2; break; case EXCP_DEBUG: { @@ -1694,7 +1975,7 @@ info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); } } break; @@ -1745,7 +2026,7 @@ info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPN; info._sifields._sigfault._addr = env->pc; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); break; case EXCP_TRAP0: { @@ -1759,7 +2040,7 @@ env->dregs[3], env->dregs[4], env->dregs[5], - env->dregs[6]); + env->aregs[0]); } break; case EXCP_INTERRUPT: @@ -1772,7 +2053,7 @@ /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->mmu.ar; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); } break; case EXCP_DEBUG: @@ -1785,7 +2066,7 @@ info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); } } break; @@ -1859,7 +2140,6 @@ exit(1); break; case EXCP_CALL_PAL ... (EXCP_CALL_PALP - 1): - fprintf(stderr, "Call to PALcode\n"); call_pal(env, (trapnr >> 6) | 0x80); break; case EXCP_CALL_PALP ... (EXCP_CALL_PALE - 1): @@ -1876,7 +2156,7 @@ info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(info.si_signo, &info); + queue_signal(env, info.si_signo, &info); } } break; @@ -1890,7 +2170,7 @@ } #endif /* TARGET_ALPHA */ -void usage(void) +static void usage(void) { printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n" "usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n" @@ -1920,12 +2200,21 @@ _exit(1); } -/* XXX: currently only used for async signals (see signal.c) */ -CPUState *global_env; - -/* used to free thread contexts */ -TaskState *first_task_state; +THREAD CPUState *thread_env; +/* Assumes contents are already zeroed. */ +void init_task_state(TaskState *ts) +{ + int i; + + ts->used = 1; + ts->first_free = ts->sigqueue_table; + for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) { + ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1]; + } + ts->sigqueue_table[i].next = NULL; +} + int main(int argc, char **argv) { const char *filename; @@ -1960,7 +2249,7 @@ break; } else if (!strcmp(r, "d")) { int mask; - CPULogItem *item; + const CPULogItem *item; if (optind >= argc) break; @@ -2061,6 +2350,7 @@ cpu_model = "any"; #endif } + cpu_exec_init_all(0); /* NOTE: we need to init the CPU at this stage to get qemu_host_page_size */ env = cpu_init(cpu_model); @@ -2068,7 +2358,7 @@ fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - global_env = env; + thread_env = env; if (getenv("QEMU_STRACE")) { do_strace = 1; @@ -2121,9 +2411,9 @@ /* build Task State */ memset(ts, 0, sizeof(TaskState)); - env->opaque = ts; - ts->used = 1; + init_task_state(ts); ts->info = info; + env->opaque = ts; env->user_mode_only = 1; #if defined(TARGET_I386) @@ -2173,14 +2463,21 @@ #endif /* linux interrupt setup */ - env->idt.base = h2g(idt_table); - env->idt.limit = sizeof(idt_table) - 1; +#ifndef TARGET_ABI32 + env->idt.limit = 511; +#else + env->idt.limit = 255; +#endif + env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1), + PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + idt_table = g2h(env->idt.base); set_idt(0, 0); set_idt(1, 0); set_idt(2, 0); set_idt(3, 3); set_idt(4, 3); - set_idt(5, 3); + set_idt(5, 0); set_idt(6, 0); set_idt(7, 0); set_idt(8, 0); @@ -2200,9 +2497,11 @@ /* linux segment setup */ { uint64_t *gdt_table; - gdt_table = qemu_mallocz(sizeof(uint64_t) * TARGET_GDT_ENTRIES); - env->gdt.base = h2g((unsigned long)gdt_table); + env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES, + PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1; + gdt_table = g2h(env->gdt.base); #ifdef TARGET_ABI32 write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | @@ -2295,9 +2594,9 @@ int i; for(i = 0; i < 32; i++) { - env->gpr[i][env->current_tc] = regs->regs[i]; + env->active_tc.gpr[i] = regs->regs[i]; } - env->PC[env->current_tc] = regs->cp0_epc; + env->active_tc.PC = regs->cp0_epc; } #elif defined(TARGET_SH4) { diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/mips/target_signal.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/mips/target_signal.h --- qemu-0.9.1/linux-user/mips/target_signal.h 2008-01-06 19:38:43.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/mips/target_signal.h 2008-06-27 11:02:35.000000000 +0100 @@ -23,7 +23,7 @@ static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state) { - return state->gpr[29][state->current_tc]; + return state->active_tc.gpr[29]; } #endif /* TARGET_SIGNAL_H */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/mips64/target_signal.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/mips64/target_signal.h --- qemu-0.9.1/linux-user/mips64/target_signal.h 2008-01-06 19:38:43.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/mips64/target_signal.h 2008-06-27 11:02:35.000000000 +0100 @@ -23,7 +23,7 @@ static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state) { - return state->gpr[29][state->current_tc]; + return state->active_tc.gpr[29]; } #endif /* TARGET_SIGNAL_H */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/mipsn32/target_signal.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/mipsn32/target_signal.h --- qemu-0.9.1/linux-user/mipsn32/target_signal.h 2008-01-06 19:38:43.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/mipsn32/target_signal.h 2008-06-27 11:02:35.000000000 +0100 @@ -23,7 +23,7 @@ static inline target_ulong get_sp_from_cpustate(CPUMIPSState *state) { - return state->gpr[29][state->current_tc]; + return state->active_tc.gpr[29]; } #endif /* TARGET_SIGNAL_H */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/mmap.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/mmap.c --- qemu-0.9.1/linux-user/mmap.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/mmap.c 2008-10-02 20:55:50.000000000 +0100 @@ -26,9 +26,100 @@ #include #include "qemu.h" +#include "qemu-common.h" //#define DEBUG_MMAP +#if defined(USE_NPTL) +pthread_mutex_t mmap_mutex; +static int __thread mmap_lock_count; + +void mmap_lock(void) +{ + if (mmap_lock_count++ == 0) { + pthread_mutex_lock(&mmap_mutex); + } +} + +void mmap_unlock(void) +{ + if (--mmap_lock_count == 0) { + pthread_mutex_unlock(&mmap_mutex); + } +} + +/* Grab lock to make sure things are in a consistent state after fork(). */ +void mmap_fork_start(void) +{ + if (mmap_lock_count) + abort(); + pthread_mutex_lock(&mmap_mutex); +} + +void mmap_fork_end(int child) +{ + if (child) + pthread_mutex_init(&mmap_mutex, NULL); + else + pthread_mutex_unlock(&mmap_mutex); +} +#else +/* We aren't threadsafe to start with, so no need to worry about locking. */ +void mmap_lock(void) +{ +} + +void mmap_unlock(void) +{ +} +#endif + +void *qemu_vmalloc(size_t size) +{ + void *p; + unsigned long addr; + mmap_lock(); + /* Use map and mark the pages as used. */ + p = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + addr = (unsigned long)p; + if (addr == (target_ulong) addr) { + /* Allocated region overlaps guest address space. + This may recurse. */ + page_set_flags(addr & TARGET_PAGE_MASK, TARGET_PAGE_ALIGN(addr + size), + PAGE_RESERVED); + } + + mmap_unlock(); + return p; +} + +void *qemu_malloc(size_t size) +{ + char * p; + size += 16; + p = qemu_vmalloc(size); + *(size_t *)p = size; + return p + 16; +} + +/* We use map, which is always zero initialized. */ +void * qemu_mallocz(size_t size) +{ + return qemu_malloc(size); +} + +void qemu_free(void *ptr) +{ + /* FIXME: We should unmark the reserved pages here. However this gets + complicated when one target page spans multiple host pages, so we + don't bother. */ + size_t *p; + p = (size_t *)((char *)ptr - 16); + munmap(p, *p); +} + /* NOTE: all the constants are the HOST ones, but addresses are target. */ int target_mprotect(abi_ulong start, abi_ulong len, int prot) { @@ -49,11 +140,11 @@ end = start + len; if (end < start) return -EINVAL; - if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) - return -EINVAL; + prot &= PROT_READ | PROT_WRITE | PROT_EXEC; if (len == 0) return 0; + mmap_lock(); host_start = start & qemu_host_page_mask; host_end = HOST_PAGE_ALIGN(end); if (start > host_start) { @@ -70,7 +161,7 @@ } ret = mprotect(g2h(host_start), qemu_host_page_size, prot1 & PAGE_BITS); if (ret != 0) - return ret; + goto error; host_start += qemu_host_page_size; } if (end < host_end) { @@ -81,7 +172,7 @@ ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size, prot1 & PAGE_BITS); if (ret != 0) - return ret; + goto error; host_end -= qemu_host_page_size; } @@ -89,10 +180,14 @@ if (host_start < host_end) { ret = mprotect(g2h(host_start), host_end - host_start, prot); if (ret != 0) - return ret; + goto error; } page_set_flags(start, start + len, prot | PAGE_VALID); + mmap_unlock(); return 0; +error: + mmap_unlock(); + return ret; } /* map an incomplete host page */ @@ -158,6 +253,8 @@ static abi_ulong mmap_next_start = 0x40000000; #endif +unsigned long last_brk; + /* find a free memory area of size 'size'. The search starts at 'start'. If 'start' == 0, then a default start address is used. Return -1 if error. @@ -168,6 +265,20 @@ { abi_ulong addr, addr1, addr_start; int prot; + unsigned long new_brk; + + new_brk = (unsigned long)sbrk(0); + if (last_brk && last_brk < new_brk && last_brk == (target_ulong)last_brk) { + /* This is a hack to catch the host allocating memory with brk(). + If it uses mmap then we loose. + FIXME: We really want to avoid the host allocating memory in + the first place, and maybe leave some slack to avoid switching + to mmap. */ + page_set_flags(last_brk & TARGET_PAGE_MASK, + TARGET_PAGE_ALIGN(new_brk), + PAGE_RESERVED); + } + last_brk = new_brk; size = HOST_PAGE_ALIGN(size); start = start & qemu_host_page_mask; @@ -199,6 +310,7 @@ abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; unsigned long host_start; + mmap_lock(); #ifdef DEBUG_MMAP { printf("mmap: start=0x" TARGET_FMT_lx @@ -228,12 +340,12 @@ if (offset & ~TARGET_PAGE_MASK) { errno = EINVAL; - return -1; + goto fail; } len = TARGET_PAGE_ALIGN(len); if (len == 0) - return start; + goto the_end; real_start = start & qemu_host_page_mask; if (!(flags & MAP_FIXED)) { @@ -245,7 +357,7 @@ mmap_start = mmap_find_vma(real_start, host_len); if (mmap_start == (abi_ulong)-1) { errno = ENOMEM; - return -1; + goto fail; } /* Note: we prefer to control the mapping address. It is especially important if qemu_host_page_size > @@ -253,20 +365,31 @@ p = mmap(g2h(mmap_start), host_len, prot, flags | MAP_FIXED, fd, host_offset); if (p == MAP_FAILED) - return -1; + goto fail; /* update start so that it points to the file position at 'offset' */ host_start = (unsigned long)p; if (!(flags & MAP_ANONYMOUS)) host_start += offset - host_offset; start = h2g(host_start); } else { + int flg; + target_ulong addr; + if (start & ~TARGET_PAGE_MASK) { errno = EINVAL; - return -1; + goto fail; } end = start + len; real_end = HOST_PAGE_ALIGN(end); - + + for(addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) { + flg = page_get_flags(addr); + if (flg & PAGE_RESERVED) { + errno = ENXIO; + goto fail; + } + } + /* worst case: we cannot map the file because the offset is not aligned, so we read it */ if (!(flags & MAP_ANONYMOUS) && @@ -276,18 +399,20 @@ if ((flags & MAP_TYPE) == MAP_SHARED && (prot & PROT_WRITE)) { errno = EINVAL; - return -1; + goto fail; } retaddr = target_mmap(start, len, prot | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (retaddr == -1) - return -1; + goto fail; pread(fd, g2h(start), len, offset); if (!(prot & PROT_WRITE)) { ret = target_mprotect(start, len, prot); - if (ret != 0) - return ret; + if (ret != 0) { + start = ret; + goto the_end; + } } goto the_end; } @@ -299,13 +424,13 @@ ret = mmap_frag(real_start, start, end, prot, flags, fd, offset); if (ret == -1) - return ret; + goto fail; goto the_end1; } ret = mmap_frag(real_start, start, real_start + qemu_host_page_size, prot, flags, fd, offset); if (ret == -1) - return ret; + goto fail; real_start += qemu_host_page_size; } /* handle the end of the mapping */ @@ -315,7 +440,7 @@ prot, flags, fd, offset + real_end - qemu_host_page_size - start); if (ret == -1) - return -1; + goto fail; real_end -= qemu_host_page_size; } @@ -330,18 +455,22 @@ p = mmap(g2h(real_start), real_end - real_start, prot, flags, fd, offset1); if (p == MAP_FAILED) - return -1; + goto fail; } } the_end1: page_set_flags(start, start + len, prot | PAGE_VALID); the_end: #ifdef DEBUG_MMAP - printf("ret=0x%llx\n", start); + printf("ret=0x" TARGET_FMT_lx "\n", start); page_dump(stdout); printf("\n"); #endif + mmap_unlock(); return start; +fail: + mmap_unlock(); + return -1; } int target_munmap(abi_ulong start, abi_ulong len) @@ -357,6 +486,7 @@ len = TARGET_PAGE_ALIGN(len); if (len == 0) return -EINVAL; + mmap_lock(); end = start + len; real_start = start & qemu_host_page_mask; real_end = HOST_PAGE_ALIGN(end); @@ -385,15 +515,16 @@ real_end -= qemu_host_page_size; } + ret = 0; /* unmap what we can */ if (real_start < real_end) { ret = munmap(g2h(real_start), real_end - real_start); - if (ret != 0) - return ret; } - page_set_flags(start, start + len, 0); - return 0; + if (ret == 0) + page_set_flags(start, start + len, 0); + mmap_unlock(); + return ret; } /* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED @@ -405,14 +536,18 @@ int prot; unsigned long host_addr; + mmap_lock(); /* XXX: use 5 args syscall */ host_addr = (long)mremap(g2h(old_addr), old_size, new_size, flags); - if (host_addr == -1) - return -1; - new_addr = h2g(host_addr); - prot = page_get_flags(old_addr); - page_set_flags(old_addr, old_addr + old_size, 0); - page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); + if (host_addr == -1) { + new_addr = -1; + } else { + new_addr = h2g(host_addr); + prot = page_get_flags(old_addr); + page_set_flags(old_addr, old_addr + old_size, 0); + page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); + } + mmap_unlock(); return new_addr; } @@ -432,4 +567,3 @@ start &= qemu_host_page_mask; return msync(g2h(start), end - start, flags); } - diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/path.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/path.c --- qemu-0.9.1/linux-user/path.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/path.c 2008-06-03 20:51:57.000000000 +0100 @@ -82,7 +82,7 @@ return root; } -/* This needs to be done after tree is stabalized (ie. no more reallocs!). */ +/* This needs to be done after tree is stabilized (ie. no more reallocs!). */ static void set_parents(struct pathelem *child, struct pathelem *parent) { unsigned int i; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/qemu.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/qemu.h --- qemu-0.9.1/linux-user/qemu.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/qemu.h 2008-10-05 12:05:14.000000000 +0100 @@ -37,6 +37,12 @@ #include "target_signal.h" #include "gdbstub.h" +#if defined(USE_NPTL) +#define THREAD __thread +#else +#define THREAD +#endif + /* This struct is used to hold certain information about the image. * Basically, it replicates in user space what would be certain * task_struct fields in the kernel @@ -82,6 +88,20 @@ #include "nwfpe/fpa11.h" #endif +#define MAX_SIGQUEUE_SIZE 1024 + +struct sigqueue { + struct sigqueue *next; + target_siginfo_t info; +}; + +struct emulated_sigtable { + int pending; /* true if signal is pending */ + struct sigqueue *first; + struct sigqueue info; /* in order to always have memory for the + first signal, we put it here */ +}; + /* NOTE: we force a big alignment so that the stack stored after is aligned too */ typedef struct TaskState { @@ -109,10 +129,16 @@ #endif int used; /* non zero if used */ struct image_info *info; + + struct emulated_sigtable sigtab[TARGET_NSIG]; + struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ + struct sigqueue *first_free; /* first free siginfo queue entry */ + int signal_pending; /* non zero if a signal may be pending */ + uint8_t stack[0]; } __attribute__((aligned(16))) TaskState; -extern TaskState *first_task_state; +void init_task_state(TaskState *ts); extern const char *qemu_uname_release; /* ??? See if we can avoid exposing so much of the loader internals. */ @@ -164,14 +190,16 @@ abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6); void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); -extern CPUState *global_env; +extern THREAD CPUState *thread_env; void cpu_loop(CPUState *env); void init_paths(const char *prefix); const char *path(const char *pathname); char *target_strerror(int err); +int get_osversion(void); +void fork_start(void); +void fork_end(int child); -extern int loglevel; -extern FILE *logfile; +#include "qemu-log.h" /* strace.c */ void print_syscall(int num, @@ -181,11 +209,12 @@ extern int do_strace; /* signal.c */ -void process_pending_signals(void *cpu_env); +void process_pending_signals(CPUState *cpu_env); void signal_init(void); -int queue_signal(int sig, target_siginfo_t *info); +int queue_signal(CPUState *env, int sig, target_siginfo_t *info); void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); +int target_to_host_signal(int sig); long do_sigreturn(CPUState *env); long do_rt_sigreturn(CPUState *env); abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp); @@ -210,6 +239,16 @@ abi_ulong new_size, unsigned long flags, abi_ulong new_addr); int target_msync(abi_ulong start, abi_ulong len, int flags); +extern unsigned long last_brk; +void mmap_lock(void); +void mmap_unlock(void); +#if defined(USE_NPTL) +void mmap_fork_start(void); +void mmap_fork_end(int child); +#endif + +/* main.c */ +extern unsigned long x86_stack_size; /* user access */ @@ -363,7 +402,7 @@ } /* Unlock an area of guest memory. The first LEN bytes must be - flushed back to guest memory. host_ptr = NULL is explicitely + flushed back to guest memory. host_ptr = NULL is explicitly allowed and does nothing. */ static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, long len) @@ -400,4 +439,8 @@ #define unlock_user_struct(host_ptr, guest_addr, copy) \ unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0) +#if defined(USE_NPTL) +#include +#endif + #endif /* QEMU_H */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/signal.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/signal.c --- qemu-0.9.1/linux-user/signal.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/signal.c 2008-10-08 15:39:08.000000000 +0100 @@ -31,31 +31,13 @@ //#define DEBUG_SIGNAL -#define MAX_SIGQUEUE_SIZE 1024 - -struct sigqueue { - struct sigqueue *next; - target_siginfo_t info; -}; - -struct emulated_sigaction { - struct target_sigaction sa; - int pending; /* true if signal is pending */ - struct sigqueue *first; - struct sigqueue info; /* in order to always have memory for the - first signal, we put it here */ -}; - -struct target_sigaltstack target_sigaltstack_used = { +static struct target_sigaltstack target_sigaltstack_used = { .ss_sp = 0, .ss_size = 0, .ss_flags = TARGET_SS_DISABLE, }; -static struct emulated_sigaction sigact_table[TARGET_NSIG]; -static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ -static struct sigqueue *first_free; /* first free siginfo queue entry */ -static int signal_pending; /* non zero if a signal may be pending */ +static struct target_sigaction sigact_table[TARGET_NSIG]; static void host_signal_handler(int host_signum, siginfo_t *info, void *puc); @@ -96,6 +78,12 @@ [SIGPWR] = TARGET_SIGPWR, [SIGSYS] = TARGET_SIGSYS, /* next signals stay the same */ + /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with + host libpthread signals. This assumes noone actually uses SIGRTMAX :-/ + To fix this properly we need to do manual signal delivery multiplexed + over a single host signal. */ + [__SIGRTMIN] = __SIGRTMAX, + [__SIGRTMAX] = __SIGRTMIN, }; static uint8_t target_to_host_signal_table[65]; @@ -113,38 +101,47 @@ static inline int host_to_target_signal(int sig) { + if (sig > 64) + return sig; return host_to_target_signal_table[sig]; } -static inline int target_to_host_signal(int sig) +int target_to_host_signal(int sig) { + if (sig > 64) + return sig; return target_to_host_signal_table[sig]; } +static inline void target_sigemptyset(target_sigset_t *set) +{ + memset(set, 0, sizeof(*set)); +} + +static inline void target_sigaddset(target_sigset_t *set, int signum) +{ + signum--; + abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW); + set->sig[signum / TARGET_NSIG_BPW] |= mask; +} + +static inline int target_sigismember(const target_sigset_t *set, int signum) +{ + signum--; + abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW); + return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0); +} + static void host_to_target_sigset_internal(target_sigset_t *d, const sigset_t *s) { int i; - unsigned long sigmask; - uint32_t target_sigmask; - - sigmask = ((unsigned long *)s)[0]; - target_sigmask = 0; - for(i = 0; i < 32; i++) { - if (sigmask & (1 << i)) - target_sigmask |= 1 << (host_to_target_signal(i + 1) - 1); - } -#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 32 - d->sig[0] = target_sigmask; - for(i = 1;i < TARGET_NSIG_WORDS; i++) { - d->sig[i] = ((unsigned long *)s)[i]; - } -#elif TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2 - d->sig[0] = target_sigmask; - d->sig[1] = sigmask >> 32; -#else - /* XXX: do it */ -#endif + target_sigemptyset(d); + for (i = 1; i <= TARGET_NSIG; i++) { + if (sigismember(s, i)) { + target_sigaddset(d, host_to_target_signal(i)); + } + } } void host_to_target_sigset(target_sigset_t *d, const sigset_t *s) @@ -157,28 +154,16 @@ d->sig[i] = tswapl(d1.sig[i]); } -void target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s) +static void target_to_host_sigset_internal(sigset_t *d, + const target_sigset_t *s) { int i; - unsigned long sigmask; - abi_ulong target_sigmask; - - target_sigmask = s->sig[0]; - sigmask = 0; - for(i = 0; i < 32; i++) { - if (target_sigmask & (1 << i)) - sigmask |= 1 << (target_to_host_signal(i + 1) - 1); - } -#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 32 - ((unsigned long *)d)[0] = sigmask; - for(i = 1;i < TARGET_NSIG_WORDS; i++) { - ((unsigned long *)d)[i] = s->sig[i]; - } -#elif TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2 - ((unsigned long *)d)[0] = sigmask | ((unsigned long)(s->sig[1]) << 32); -#else - /* XXX: do it */ -#endif /* TARGET_ABI_BITS */ + sigemptyset(d); + for (i = 1; i <= TARGET_NSIG; i++) { + if (target_sigismember(s, i)) { + sigaddset(d, target_to_host_signal(i)); + } + } } void target_to_host_sigset(sigset_t *d, const target_sigset_t *s) @@ -220,7 +205,7 @@ sig = host_to_target_signal(info->si_signo); tinfo->si_signo = sig; tinfo->si_errno = 0; - tinfo->si_code = 0; + tinfo->si_code = info->si_code; if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS || sig == SIGTRAP) { /* should never come here, but who knows. The information for @@ -282,7 +267,9 @@ void signal_init(void) { struct sigaction act; + struct sigaction oact; int i, j; + int host_sig; /* generate signal conversion tables */ for(i = 1; i <= 64; i++) { @@ -296,40 +283,49 @@ /* set all host signal handlers. ALL signals are blocked during the handlers to serialize them. */ + memset(sigact_table, 0, sizeof(sigact_table)); + sigfillset(&act.sa_mask); act.sa_flags = SA_SIGINFO; act.sa_sigaction = host_signal_handler; - for(i = 1; i < NSIG; i++) { - sigaction(i, &act, NULL); + for(i = 1; i <= TARGET_NSIG; i++) { + host_sig = target_to_host_signal(i); + sigaction(host_sig, NULL, &oact); + if (oact.sa_sigaction == (void *)SIG_IGN) { + sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN; + } else if (oact.sa_sigaction == (void *)SIG_DFL) { + sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL; + } + /* If there's already a handler installed then something has + gone horribly wrong, so don't even try to handle that case. */ + /* Install some handlers for our own use. */ + if (host_sig == SIGSEGV || host_sig == SIGBUS) { + sigaction(host_sig, &act, NULL); + } } - - memset(sigact_table, 0, sizeof(sigact_table)); - - first_free = &sigqueue_table[0]; - for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) - sigqueue_table[i].next = &sigqueue_table[i + 1]; - sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL; } /* signal queue handling */ -static inline struct sigqueue *alloc_sigqueue(void) +static inline struct sigqueue *alloc_sigqueue(CPUState *env) { - struct sigqueue *q = first_free; + TaskState *ts = env->opaque; + struct sigqueue *q = ts->first_free; if (!q) return NULL; - first_free = q->next; + ts->first_free = q->next; return q; } -static inline void free_sigqueue(struct sigqueue *q) +static inline void free_sigqueue(CPUState *env, struct sigqueue *q) { - q->next = first_free; - first_free = q; + TaskState *ts = env->opaque; + q->next = ts->first_free; + ts->first_free = q; } /* abort execution with signal */ -void __attribute((noreturn)) force_sig(int sig) +static void __attribute((noreturn)) force_sig(int sig) { int host_sig; host_sig = target_to_host_signal(sig); @@ -351,9 +347,10 @@ /* queue a signal so that it will be send to the virtual CPU as soon as possible */ -int queue_signal(int sig, target_siginfo_t *info) +int queue_signal(CPUState *env, int sig, target_siginfo_t *info) { - struct emulated_sigaction *k; + TaskState *ts = env->opaque; + struct emulated_sigtable *k; struct sigqueue *q, **pq; abi_ulong handler; @@ -361,8 +358,8 @@ fprintf(stderr, "queue_signal: sig=%d\n", sig); #endif - k = &sigact_table[sig - 1]; - handler = k->sa._sa_handler; + k = &ts->sigtab[sig - 1]; + handler = sigact_table[sig - 1]._sa_handler; if (handler == TARGET_SIG_DFL) { /* default handler : ignore some signal. The other are fatal */ if (sig != TARGET_SIGCHLD && @@ -390,7 +387,7 @@ /* first signal */ q = &k->info; } else { - q = alloc_sigqueue(); + q = alloc_sigqueue(env); if (!q) return -EAGAIN; while (*pq != NULL) @@ -402,7 +399,7 @@ q->next = NULL; k->pending = 1; /* signal that a new signal is pending */ - signal_pending = 1; + ts->signal_pending = 1; return 1; /* indicates that the signal was queued */ } } @@ -428,9 +425,9 @@ fprintf(stderr, "qemu: got signal %d\n", sig); #endif host_to_target_siginfo_noswap(&tinfo, info); - if (queue_signal(sig, &tinfo) == 1) { + if (queue_signal(thread_env, sig, &tinfo) == 1) { /* interrupt the virtual CPU as soon as possible */ - cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); + cpu_interrupt(thread_env, CPU_INTERRUPT_EXIT); } } @@ -500,7 +497,7 @@ int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction *oact) { - struct emulated_sigaction *k; + struct target_sigaction *k; struct sigaction act1; int host_sig; int ret = 0; @@ -513,34 +510,35 @@ sig, (int)act, (int)oact); #endif if (oact) { - oact->_sa_handler = tswapl(k->sa._sa_handler); - oact->sa_flags = tswapl(k->sa.sa_flags); + oact->_sa_handler = tswapl(k->_sa_handler); + oact->sa_flags = tswapl(k->sa_flags); #if !defined(TARGET_MIPS) - oact->sa_restorer = tswapl(k->sa.sa_restorer); + oact->sa_restorer = tswapl(k->sa_restorer); #endif - oact->sa_mask = k->sa.sa_mask; + oact->sa_mask = k->sa_mask; } if (act) { - k->sa._sa_handler = tswapl(act->_sa_handler); - k->sa.sa_flags = tswapl(act->sa_flags); + /* FIXME: This is not threadsafe. */ + k->_sa_handler = tswapl(act->_sa_handler); + k->sa_flags = tswapl(act->sa_flags); #if !defined(TARGET_MIPS) - k->sa.sa_restorer = tswapl(act->sa_restorer); + k->sa_restorer = tswapl(act->sa_restorer); #endif - k->sa.sa_mask = act->sa_mask; + k->sa_mask = act->sa_mask; /* we update the host linux signal state */ host_sig = target_to_host_signal(sig); if (host_sig != SIGSEGV && host_sig != SIGBUS) { sigfillset(&act1.sa_mask); act1.sa_flags = SA_SIGINFO; - if (k->sa.sa_flags & TARGET_SA_RESTART) + if (k->sa_flags & TARGET_SA_RESTART) act1.sa_flags |= SA_RESTART; /* NOTE: it is important to update the host kernel signal ignore state to avoid getting unexpected interrupted syscalls */ - if (k->sa._sa_handler == TARGET_SIG_IGN) { + if (k->_sa_handler == TARGET_SIG_IGN) { act1.sa_sigaction = (void *)SIG_IGN; - } else if (k->sa._sa_handler == TARGET_SIG_DFL) { + } else if (k->_sa_handler == TARGET_SIG_DFL) { act1.sa_sigaction = (void *)SIG_DFL; } else { act1.sa_sigaction = host_signal_handler; @@ -551,10 +549,6 @@ return ret; } -#ifndef offsetof -#define offsetof(type, field) ((size_t) &((type *)0)->field) -#endif - static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, const target_siginfo_t *info) { @@ -716,14 +710,14 @@ */ static inline abi_ulong -get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size) +get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size) { unsigned long esp; /* Default to using normal stack */ esp = env->regs[R_ESP]; /* This is the X/Open sanctioned signal stack switching. */ - if (ka->sa.sa_flags & TARGET_SA_ONSTACK) { + if (ka->sa_flags & TARGET_SA_ONSTACK) { if (sas_ss_flags(esp) == 0) esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; } @@ -731,15 +725,15 @@ /* This is the legacy signal stack switching. */ else if ((env->segs[R_SS].selector & 0xffff) != __USER_DS && - !(ka->sa.sa_flags & TARGET_SA_RESTORER) && - ka->sa.sa_restorer) { - esp = (unsigned long) ka->sa.sa_restorer; + !(ka->sa_flags & TARGET_SA_RESTORER) && + ka->sa_restorer) { + esp = (unsigned long) ka->sa_restorer; } return (esp - frame_size) & -8ul; } /* compare linux/arch/i386/kernel/signal.c:setup_frame() */ -static void setup_frame(int sig, struct emulated_sigaction *ka, +static void setup_frame(int sig, struct target_sigaction *ka, target_sigset_t *set, CPUX86State *env) { abi_ulong frame_addr; @@ -768,8 +762,8 @@ /* Set up to return from userspace. If provided, use a stub already in userspace. */ - if (ka->sa.sa_flags & TARGET_SA_RESTORER) { - err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); + if (ka->sa_flags & TARGET_SA_RESTORER) { + err |= __put_user(ka->sa_restorer, &frame->pretcode); } else { uint16_t val16; abi_ulong retcode_addr; @@ -788,7 +782,7 @@ /* Set up registers for signal handler */ env->regs[R_ESP] = frame_addr; - env->eip = ka->sa._sa_handler; + env->eip = ka->_sa_handler; cpu_x86_load_seg(env, R_DS, __USER_DS); cpu_x86_load_seg(env, R_ES, __USER_DS); @@ -803,12 +797,12 @@ give_sigsegv: unlock_user_struct(frame, frame_addr, 1); if (sig == TARGET_SIGSEGV) - ka->sa._sa_handler = TARGET_SIG_DFL; + ka->_sa_handler = TARGET_SIG_DFL; force_sig(TARGET_SIGSEGV /* , current */); } /* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */ -static void setup_rt_frame(int sig, struct emulated_sigaction *ka, +static void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUX86State *env) { @@ -850,8 +844,8 @@ /* Set up to return from userspace. If provided, use a stub already in userspace. */ - if (ka->sa.sa_flags & TARGET_SA_RESTORER) { - err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); + if (ka->sa_flags & TARGET_SA_RESTORER) { + err |= __put_user(ka->sa_restorer, &frame->pretcode); } else { uint16_t val16; addr = frame_addr + offsetof(struct rt_sigframe, retcode); @@ -868,7 +862,7 @@ /* Set up registers for signal handler */ env->regs[R_ESP] = frame_addr; - env->eip = ka->sa._sa_handler; + env->eip = ka->_sa_handler; cpu_x86_load_seg(env, R_DS, __USER_DS); cpu_x86_load_seg(env, R_ES, __USER_DS); @@ -883,7 +877,7 @@ give_sigsegv: unlock_user_struct(frame, frame_addr, 1); if (sig == TARGET_SIGSEGV) - ka->sa._sa_handler = TARGET_SIG_DFL; + ka->_sa_handler = TARGET_SIG_DFL; force_sig(TARGET_SIGSEGV /* , current */); } @@ -1020,7 +1014,7 @@ abi_ulong fault_address; }; -struct target_ucontext { +struct target_ucontext_v1 { abi_ulong tuc_flags; abi_ulong tuc_link; target_stack_t tuc_stack; @@ -1028,19 +1022,42 @@ target_sigset_t tuc_sigmask; /* mask last for extensibility */ }; -struct sigframe +struct target_ucontext_v2 { + abi_ulong tuc_flags; + abi_ulong tuc_link; + target_stack_t tuc_stack; + struct target_sigcontext tuc_mcontext; + target_sigset_t tuc_sigmask; /* mask last for extensibility */ + char __unused[128 - sizeof(sigset_t)]; + abi_ulong tuc_regspace[128] __attribute__((__aligned__(8))); +}; + +struct sigframe_v1 { struct target_sigcontext sc; abi_ulong extramask[TARGET_NSIG_WORDS-1]; abi_ulong retcode; }; -struct rt_sigframe +struct sigframe_v2 +{ + struct target_ucontext_v2 uc; + abi_ulong retcode; +}; + +struct rt_sigframe_v1 { abi_ulong pinfo; abi_ulong puc; struct target_siginfo info; - struct target_ucontext uc; + struct target_ucontext_v1 uc; + abi_ulong retcode; +}; + +struct rt_sigframe_v2 +{ + struct target_siginfo info; + struct target_ucontext_v2 uc; abi_ulong retcode; }; @@ -1065,7 +1082,6 @@ }; -#define __put_user_error(x,p,e) __put_user(x, p) #define __get_user_error(x,p,e) __get_user(x, p) static inline int valid_user_regs(CPUState *regs) @@ -1073,49 +1089,45 @@ return 1; } -static int +static void setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ CPUState *env, abi_ulong mask) { - int err = 0; - - __put_user_error(env->regs[0], &sc->arm_r0, err); - __put_user_error(env->regs[1], &sc->arm_r1, err); - __put_user_error(env->regs[2], &sc->arm_r2, err); - __put_user_error(env->regs[3], &sc->arm_r3, err); - __put_user_error(env->regs[4], &sc->arm_r4, err); - __put_user_error(env->regs[5], &sc->arm_r5, err); - __put_user_error(env->regs[6], &sc->arm_r6, err); - __put_user_error(env->regs[7], &sc->arm_r7, err); - __put_user_error(env->regs[8], &sc->arm_r8, err); - __put_user_error(env->regs[9], &sc->arm_r9, err); - __put_user_error(env->regs[10], &sc->arm_r10, err); - __put_user_error(env->regs[11], &sc->arm_fp, err); - __put_user_error(env->regs[12], &sc->arm_ip, err); - __put_user_error(env->regs[13], &sc->arm_sp, err); - __put_user_error(env->regs[14], &sc->arm_lr, err); - __put_user_error(env->regs[15], &sc->arm_pc, err); + __put_user(env->regs[0], &sc->arm_r0); + __put_user(env->regs[1], &sc->arm_r1); + __put_user(env->regs[2], &sc->arm_r2); + __put_user(env->regs[3], &sc->arm_r3); + __put_user(env->regs[4], &sc->arm_r4); + __put_user(env->regs[5], &sc->arm_r5); + __put_user(env->regs[6], &sc->arm_r6); + __put_user(env->regs[7], &sc->arm_r7); + __put_user(env->regs[8], &sc->arm_r8); + __put_user(env->regs[9], &sc->arm_r9); + __put_user(env->regs[10], &sc->arm_r10); + __put_user(env->regs[11], &sc->arm_fp); + __put_user(env->regs[12], &sc->arm_ip); + __put_user(env->regs[13], &sc->arm_sp); + __put_user(env->regs[14], &sc->arm_lr); + __put_user(env->regs[15], &sc->arm_pc); #ifdef TARGET_CONFIG_CPU_32 - __put_user_error(cpsr_read(env), &sc->arm_cpsr, err); + __put_user(cpsr_read(env), &sc->arm_cpsr); #endif - __put_user_error(/* current->thread.trap_no */ 0, &sc->trap_no, err); - __put_user_error(/* current->thread.error_code */ 0, &sc->error_code, err); - __put_user_error(/* current->thread.address */ 0, &sc->fault_address, err); - __put_user_error(mask, &sc->oldmask, err); - - return err; + __put_user(/* current->thread.trap_no */ 0, &sc->trap_no); + __put_user(/* current->thread.error_code */ 0, &sc->error_code); + __put_user(/* current->thread.address */ 0, &sc->fault_address); + __put_user(mask, &sc->oldmask); } static inline abi_ulong -get_sigframe(struct emulated_sigaction *ka, CPUState *regs, int framesize) +get_sigframe(struct target_sigaction *ka, CPUState *regs, int framesize) { unsigned long sp = regs->regs[13]; /* * This is the X/Open sanctioned signal stack switching. */ - if ((ka->sa.sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) + if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; /* * ATPCS B01 mandates 8-byte alignment @@ -1124,45 +1136,19 @@ } static int -setup_return(CPUState *env, struct emulated_sigaction *ka, +setup_return(CPUState *env, struct target_sigaction *ka, abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr) { - abi_ulong handler = ka->sa._sa_handler; + abi_ulong handler = ka->_sa_handler; abi_ulong retcode; - int thumb = 0; -#if defined(TARGET_CONFIG_CPU_32) -#if 0 - abi_ulong cpsr = env->cpsr; - - /* - * Maybe we need to deliver a 32-bit signal to a 26-bit task. - */ - if (ka->sa.sa_flags & SA_THIRTYTWO) - cpsr = (cpsr & ~MODE_MASK) | USR_MODE; - -#ifdef CONFIG_ARM_THUMB - if (elf_hwcap & HWCAP_THUMB) { - /* - * The LSB of the handler determines if we're going to - * be using THUMB or ARM mode for this signal handler. - */ - thumb = handler & 1; - - if (thumb) - cpsr |= T_BIT; - else - cpsr &= ~T_BIT; - } -#endif /* CONFIG_ARM_THUMB */ -#endif /* 0 */ -#endif /* TARGET_CONFIG_CPU_32 */ + int thumb = handler & 1; - if (ka->sa.sa_flags & TARGET_SA_RESTORER) { - retcode = ka->sa.sa_restorer; + if (ka->sa_flags & TARGET_SA_RESTORER) { + retcode = ka->sa_restorer; } else { unsigned int idx = thumb; - if (ka->sa.sa_flags & TARGET_SA_SIGINFO) + if (ka->sa_flags & TARGET_SA_SIGINFO) idx += 2; if (__put_user(retcodes[idx], rc)) @@ -1178,6 +1164,7 @@ env->regs[13] = frame_addr; env->regs[14] = retcode; env->regs[15] = handler & (thumb ? ~1 : ~3); + env->thumb = thumb; #if 0 #ifdef TARGET_CONFIG_CPU_32 @@ -1188,55 +1175,102 @@ return 0; } +static void setup_sigframe_v2(struct target_ucontext_v2 *uc, + target_sigset_t *set, CPUState *env) +{ + struct target_sigaltstack stack; + int i; + + /* Clear all the bits of the ucontext we don't use. */ + memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext)); + + memset(&stack, 0, sizeof(stack)); + __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp); + __put_user(target_sigaltstack_used.ss_size, &stack.ss_size); + __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags); + memcpy(&uc->tuc_stack, &stack, sizeof(stack)); + + setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]); + /* FIXME: Save coprocessor signal frame. */ + for(i = 0; i < TARGET_NSIG_WORDS; i++) { + __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]); + } +} + /* compare linux/arch/arm/kernel/signal.c:setup_frame() */ -static void setup_frame(int usig, struct emulated_sigaction *ka, - target_sigset_t *set, CPUState *regs) +static void setup_frame_v1(int usig, struct target_sigaction *ka, + target_sigset_t *set, CPUState *regs) { - struct sigframe *frame; + struct sigframe_v1 *frame; abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame)); - int i, err = 0; + int i; if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) return; - err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]); + setup_sigcontext(&frame->sc, regs, set->sig[0]); for(i = 1; i < TARGET_NSIG_WORDS; i++) { if (__put_user(set->sig[i], &frame->extramask[i - 1])) goto end; } - if (err == 0) - err = setup_return(regs, ka, &frame->retcode, frame_addr, usig, - frame_addr + offsetof(struct sigframe, retcode)); + setup_return(regs, ka, &frame->retcode, frame_addr, usig, + frame_addr + offsetof(struct sigframe_v1, retcode)); end: unlock_user_struct(frame, frame_addr, 1); - // return err; +} + +static void setup_frame_v2(int usig, struct target_sigaction *ka, + target_sigset_t *set, CPUState *regs) +{ + struct sigframe_v2 *frame; + abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame)); + + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) + return; + + setup_sigframe_v2(&frame->uc, set, regs); + + setup_return(regs, ka, &frame->retcode, frame_addr, usig, + frame_addr + offsetof(struct sigframe_v2, retcode)); + + unlock_user_struct(frame, frame_addr, 1); +} + +static void setup_frame(int usig, struct target_sigaction *ka, + target_sigset_t *set, CPUState *regs) +{ + if (get_osversion() >= 0x020612) { + setup_frame_v2(usig, ka, set, regs); + } else { + setup_frame_v1(usig, ka, set, regs); + } } /* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */ -static void setup_rt_frame(int usig, struct emulated_sigaction *ka, - target_siginfo_t *info, - target_sigset_t *set, CPUState *env) +static void setup_rt_frame_v1(int usig, struct target_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) { - struct rt_sigframe *frame; + struct rt_sigframe_v1 *frame; abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame)); struct target_sigaltstack stack; - int i, err = 0; + int i; abi_ulong info_addr, uc_addr; if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) return /* 1 */; - info_addr = frame_addr + offsetof(struct rt_sigframe, info); - __put_user_error(info_addr, &frame->pinfo, err); - uc_addr = frame_addr + offsetof(struct rt_sigframe, uc); - __put_user_error(uc_addr, &frame->puc, err); - err |= copy_siginfo_to_user(&frame->info, info); + info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info); + __put_user(info_addr, &frame->pinfo); + uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc); + __put_user(uc_addr, &frame->puc); + copy_siginfo_to_user(&frame->info, info); /* Clear all the bits of the ucontext we don't use. */ - memset(&frame->uc, 0, offsetof(struct target_ucontext, tuc_mcontext)); + memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext)); memset(&stack, 0, sizeof(stack)); __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp); @@ -1244,31 +1278,57 @@ __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags); memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack)); - err |= setup_sigcontext(&frame->uc.tuc_mcontext, /*&frame->fpstate,*/ - env, set->sig[0]); + setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]); for(i = 0; i < TARGET_NSIG_WORDS; i++) { if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i])) goto end; } - if (err == 0) - err = setup_return(env, ka, &frame->retcode, frame_addr, usig, - frame_addr + offsetof(struct rt_sigframe, retcode)); - - if (err == 0) { - /* - * For realtime signals we must also set the second and third - * arguments for the signal handler. - * -- Peter Maydell 2000-12-06 - */ - env->regs[1] = info_addr; - env->regs[2] = uc_addr; - } + setup_return(env, ka, &frame->retcode, frame_addr, usig, + frame_addr + offsetof(struct rt_sigframe_v1, retcode)); + + env->regs[1] = info_addr; + env->regs[2] = uc_addr; end: unlock_user_struct(frame, frame_addr, 1); +} + +static void setup_rt_frame_v2(int usig, struct target_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ + struct rt_sigframe_v2 *frame; + abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame)); + abi_ulong info_addr, uc_addr; + + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) + return /* 1 */; + + info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info); + uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc); + copy_siginfo_to_user(&frame->info, info); + + setup_sigframe_v2(&frame->uc, set, env); + + setup_return(env, ka, &frame->retcode, frame_addr, usig, + frame_addr + offsetof(struct rt_sigframe_v2, retcode)); + + env->regs[1] = info_addr; + env->regs[2] = uc_addr; + + unlock_user_struct(frame, frame_addr, 1); +} - // return err; +static void setup_rt_frame(int usig, struct target_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ + if (get_osversion() >= 0x020612) { + setup_rt_frame_v2(usig, ka, info, set, env); + } else { + setup_rt_frame_v1(usig, ka, info, set, env); + } } static int @@ -1295,7 +1355,7 @@ __get_user_error(env->regs[15], &sc->arm_pc, err); #ifdef TARGET_CONFIG_CPU_32 __get_user_error(cpsr, &sc->arm_cpsr, err); - cpsr_write(env, cpsr, 0xffffffff); + cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC); #endif err |= !valid_user_regs(env); @@ -1303,10 +1363,10 @@ return err; } -long do_sigreturn(CPUState *env) +long do_sigreturn_v1(CPUState *env) { abi_ulong frame_addr; - struct sigframe *frame; + struct sigframe_v1 *frame; target_sigset_t set; sigset_t host_set; int i; @@ -1350,10 +1410,71 @@ return 0; } -long do_rt_sigreturn(CPUState *env) +static int do_sigframe_return_v2(CPUState *env, target_ulong frame_addr, + struct target_ucontext_v2 *uc) +{ + sigset_t host_set; + + target_to_host_sigset(&host_set, &uc->tuc_sigmask); + sigprocmask(SIG_SETMASK, &host_set, NULL); + + if (restore_sigcontext(env, &uc->tuc_mcontext)) + return 1; + + if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) + return 1; + +#if 0 + /* Send SIGTRAP if we're single-stepping */ + if (ptrace_cancel_bpt(current)) + send_sig(SIGTRAP, current, 1); +#endif + + return 0; +} + +long do_sigreturn_v2(CPUState *env) { abi_ulong frame_addr; - struct rt_sigframe *frame; + struct sigframe_v2 *frame; + + /* + * Since we stacked the signal on a 64-bit boundary, + * then 'sp' should be word aligned here. If it's + * not, then the user is trying to mess with us. + */ + if (env->regs[13] & 7) + goto badframe; + + frame_addr = env->regs[13]; + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) + goto badframe; + + if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) + goto badframe; + + unlock_user_struct(frame, frame_addr, 0); + return env->regs[0]; + +badframe: + unlock_user_struct(frame, frame_addr, 0); + force_sig(SIGSEGV /* , current */); + return 0; +} + +long do_sigreturn(CPUState *env) +{ + if (get_osversion() >= 0x020612) { + return do_sigreturn_v2(env); + } else { + return do_sigreturn_v1(env); + } +} + +long do_rt_sigreturn_v1(CPUState *env) +{ + abi_ulong frame_addr; + struct rt_sigframe_v1 *frame; sigset_t host_set; /* @@ -1374,7 +1495,7 @@ if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) goto badframe; - if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) + if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) goto badframe; #if 0 @@ -1391,6 +1512,44 @@ return 0; } +long do_rt_sigreturn_v2(CPUState *env) +{ + abi_ulong frame_addr; + struct rt_sigframe_v2 *frame; + + /* + * Since we stacked the signal on a 64-bit boundary, + * then 'sp' should be word aligned here. If it's + * not, then the user is trying to mess with us. + */ + if (env->regs[13] & 7) + goto badframe; + + frame_addr = env->regs[13]; + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) + goto badframe; + + if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) + goto badframe; + + unlock_user_struct(frame, frame_addr, 0); + return env->regs[0]; + +badframe: + unlock_user_struct(frame, frame_addr, 0); + force_sig(SIGSEGV /* , current */); + return 0; +} + +long do_rt_sigreturn(CPUState *env) +{ + if (get_osversion() >= 0x020612) { + return do_rt_sigreturn_v2(env); + } else { + return do_rt_sigreturn_v1(env); + } +} + #elif defined(TARGET_SPARC) #define __SUNOS_MAXWIN 31 @@ -1489,7 +1648,7 @@ #define UREG_FP UREG_I6 #define UREG_SP UREG_O6 -static inline abi_ulong get_sigframe(struct emulated_sigaction *sa, +static inline abi_ulong get_sigframe(struct target_sigaction *sa, CPUState *env, unsigned long framesize) { abi_ulong sp; @@ -1497,7 +1656,7 @@ sp = env->regwptr[UREG_FP]; /* This is the X/Open sanctioned signal stack switching. */ - if (sa->sa.sa_flags & TARGET_SA_ONSTACK) { + if (sa->sa_flags & TARGET_SA_ONSTACK) { if (!on_sig_stack(sp) && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7)) sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; @@ -1544,7 +1703,7 @@ #endif #define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7))) -static void setup_frame(int sig, struct emulated_sigaction *ka, +static void setup_frame(int sig, struct target_sigaction *ka, target_sigset_t *set, CPUState *env) { abi_ulong sf_addr; @@ -1597,11 +1756,11 @@ offsetof(struct target_signal_frame, info); /* 4. signal handler */ - env->pc = ka->sa._sa_handler; + env->pc = ka->_sa_handler; env->npc = (env->pc + 4); /* 5. return to kernel instructions */ - if (ka->sa.sa_restorer) - env->regwptr[UREG_I7] = ka->sa.sa_restorer; + if (ka->sa_restorer) + env->regwptr[UREG_I7] = ka->sa_restorer; else { uint32_t val32; @@ -1673,7 +1832,7 @@ } -static void setup_rt_frame(int sig, struct emulated_sigaction *ka, +static void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUState *env) { @@ -2021,13 +2180,13 @@ # warning signal handling not implemented -static void setup_frame(int sig, struct emulated_sigaction *ka, +static void setup_frame(int sig, struct target_sigaction *ka, target_sigset_t *set, CPUState *env) { fprintf(stderr, "setup_frame: not implemented\n"); } -static void setup_rt_frame(int sig, struct emulated_sigaction *ka, +static void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUState *env) { @@ -2050,13 +2209,13 @@ # warning signal handling not implemented -static void setup_frame(int sig, struct emulated_sigaction *ka, +static void setup_frame(int sig, struct target_sigaction *ka, target_sigset_t *set, CPUState *env) { fprintf(stderr, "setup_frame: not implemented\n"); } -static void setup_rt_frame(int sig, struct emulated_sigaction *ka, +static void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUState *env) { @@ -2128,10 +2287,10 @@ { int err = 0; - err |= __put_user(regs->PC[regs->current_tc], &sc->sc_pc); + err |= __put_user(regs->active_tc.PC, &sc->sc_pc); -#define save_gp_reg(i) do { \ - err |= __put_user(regs->gpr[i][regs->current_tc], &sc->sc_regs[i]); \ +#define save_gp_reg(i) do { \ + err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \ } while(0) __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); @@ -2144,8 +2303,8 @@ save_gp_reg(31); #undef save_gp_reg - err |= __put_user(regs->HI[0][regs->current_tc], &sc->sc_mdhi); - err |= __put_user(regs->LO[0][regs->current_tc], &sc->sc_mdlo); + err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi); + err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo); /* Not used yet, but might be useful if we ever have DSP suppport */ #if 0 @@ -2205,11 +2364,11 @@ err |= __get_user(regs->CP0_EPC, &sc->sc_pc); - err |= __get_user(regs->HI[0][regs->current_tc], &sc->sc_mdhi); - err |= __get_user(regs->LO[0][regs->current_tc], &sc->sc_mdlo); + err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi); + err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo); #define restore_gp_reg(i) do { \ - err |= __get_user(regs->gpr[i][regs->current_tc], &sc->sc_regs[i]); \ + err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \ } while(0) restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); @@ -2270,12 +2429,12 @@ * Determine which stack to use.. */ static inline abi_ulong -get_sigframe(struct emulated_sigaction *ka, CPUState *regs, size_t frame_size) +get_sigframe(struct target_sigaction *ka, CPUState *regs, size_t frame_size) { unsigned long sp; /* Default to using normal stack */ - sp = regs->gpr[29][regs->current_tc]; + sp = regs->active_tc.gpr[29]; /* * FPU emulator may have it's own trampoline active just @@ -2285,7 +2444,7 @@ sp -= 32; /* This is the X/Open sanctioned signal stack switching. */ - if ((ka->sa.sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) { + if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) { sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; } @@ -2293,7 +2452,7 @@ } /* compare linux/arch/mips/kernel/signal.c:setup_frame() */ -static void setup_frame(int sig, struct emulated_sigaction * ka, +static void setup_frame(int sig, struct target_sigaction * ka, target_sigset_t *set, CPUState *regs) { struct sigframe *frame; @@ -2324,15 +2483,15 @@ * $25 and PC point to the signal handler, $29 points to the * struct sigframe. */ - regs->gpr[ 4][regs->current_tc] = sig; - regs->gpr[ 5][regs->current_tc] = 0; - regs->gpr[ 6][regs->current_tc] = frame_addr + offsetof(struct sigframe, sf_sc); - regs->gpr[29][regs->current_tc] = frame_addr; - regs->gpr[31][regs->current_tc] = frame_addr + offsetof(struct sigframe, sf_code); + regs->active_tc.gpr[ 4] = sig; + regs->active_tc.gpr[ 5] = 0; + regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc); + regs->active_tc.gpr[29] = frame_addr; + regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code); /* The original kernel code sets CP0_EPC to the handler * since it returns to userland using eret * we cannot do this here, and we must set PC directly */ - regs->PC[regs->current_tc] = regs->gpr[25][regs->current_tc] = ka->sa._sa_handler; + regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler; unlock_user_struct(frame, frame_addr, 1); return; @@ -2353,7 +2512,7 @@ #if defined(DEBUG_SIGNAL) fprintf(stderr, "do_sigreturn\n"); #endif - frame_addr = regs->gpr[29][regs->current_tc]; + frame_addr = regs->active_tc.gpr[29]; if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) goto badframe; @@ -2380,7 +2539,7 @@ /* Unreached */ #endif - regs->PC[regs->current_tc] = regs->CP0_EPC; + regs->active_tc.PC = regs->CP0_EPC; /* I am not sure this is right, but it seems to work * maybe a problem with nested signals ? */ regs->CP0_EPC = 0; @@ -2391,7 +2550,7 @@ return 0; } -static void setup_rt_frame(int sig, struct emulated_sigaction *ka, +static void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUState *env) { @@ -2459,10 +2618,10 @@ #define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */ #define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */ -static abi_ulong get_sigframe(struct emulated_sigaction *ka, +static abi_ulong get_sigframe(struct target_sigaction *ka, unsigned long sp, size_t frame_size) { - if ((ka->sa.sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) { + if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) { sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; } @@ -2521,7 +2680,7 @@ return err; } -static void setup_frame(int sig, struct emulated_sigaction *ka, +static void setup_frame(int sig, struct target_sigaction *ka, target_sigset_t *set, CPUState *regs) { struct target_sigframe *frame; @@ -2544,8 +2703,8 @@ /* Set up to return from userspace. If provided, use a stub already in userspace. */ - if (ka->sa.sa_flags & TARGET_SA_RESTORER) { - regs->pr = (unsigned long) ka->sa.sa_restorer; + if (ka->sa_flags & TARGET_SA_RESTORER) { + regs->pr = (unsigned long) ka->sa_restorer; } else { /* Generate return code (system call to sigreturn) */ err |= __put_user(MOVW(2), &frame->retcode[0]); @@ -2562,7 +2721,7 @@ regs->gregs[4] = signal; /* Arg for signal handler */ regs->gregs[5] = 0; regs->gregs[6] = (unsigned long) &frame->sc; - regs->pc = (unsigned long) ka->sa._sa_handler; + regs->pc = (unsigned long) ka->_sa_handler; unlock_user_struct(frame, frame_addr, 1); return; @@ -2572,7 +2731,7 @@ force_sig(SIGSEGV); } -static void setup_rt_frame(int sig, struct emulated_sigaction *ka, +static void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUState *regs) { @@ -2593,7 +2752,7 @@ /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, (unsigned long *)&frame->uc.uc_link); - err |= __put_user((void *)target_sigaltstack_used.ss_sp, + err |= __put_user((unsigned long)target_sigaltstack_used.ss_sp, &frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(regs->gregs[15]), &frame->uc.uc_stack.ss_flags); @@ -2607,8 +2766,8 @@ /* Set up to return from userspace. If provided, use a stub already in userspace. */ - if (ka->sa.sa_flags & TARGET_SA_RESTORER) { - regs->pr = (unsigned long) ka->sa.sa_restorer; + if (ka->sa_flags & TARGET_SA_RESTORER) { + regs->pr = (unsigned long) ka->sa_restorer; } else { /* Generate return code (system call to sigreturn) */ err |= __put_user(MOVW(2), &frame->retcode[0]); @@ -2625,7 +2784,7 @@ regs->gregs[4] = signal; /* Arg for signal handler */ regs->gregs[5] = (unsigned long) &frame->info; regs->gregs[6] = (unsigned long) &frame->uc; - regs->pc = (unsigned long) ka->sa._sa_handler; + regs->pc = (unsigned long) ka->_sa_handler; unlock_user_struct(frame, frame_addr, 1); return; @@ -2706,16 +2865,186 @@ force_sig(TARGET_SIGSEGV); return 0; } +#elif defined(TARGET_CRIS) + +struct target_sigcontext { + struct target_pt_regs regs; /* needs to be first */ + uint32_t oldmask; + uint32_t usp; /* usp before stacking this gunk on it */ +}; + +/* Signal frames. */ +struct target_signal_frame { + struct target_sigcontext sc; + uint32_t extramask[TARGET_NSIG_WORDS - 1]; + uint8_t retcode[8]; /* Trampoline code. */ +}; + +struct rt_signal_frame { + struct siginfo *pinfo; + void *puc; + struct siginfo info; + struct ucontext uc; + uint8_t retcode[8]; /* Trampoline code. */ +}; + +static void setup_sigcontext(struct target_sigcontext *sc, CPUState *env) +{ + __put_user(env->regs[0], &sc->regs.r0); + __put_user(env->regs[1], &sc->regs.r1); + __put_user(env->regs[2], &sc->regs.r2); + __put_user(env->regs[3], &sc->regs.r3); + __put_user(env->regs[4], &sc->regs.r4); + __put_user(env->regs[5], &sc->regs.r5); + __put_user(env->regs[6], &sc->regs.r6); + __put_user(env->regs[7], &sc->regs.r7); + __put_user(env->regs[8], &sc->regs.r8); + __put_user(env->regs[9], &sc->regs.r9); + __put_user(env->regs[10], &sc->regs.r10); + __put_user(env->regs[11], &sc->regs.r11); + __put_user(env->regs[12], &sc->regs.r12); + __put_user(env->regs[13], &sc->regs.r13); + __put_user(env->regs[14], &sc->usp); + __put_user(env->regs[15], &sc->regs.acr); + __put_user(env->pregs[PR_MOF], &sc->regs.mof); + __put_user(env->pregs[PR_SRP], &sc->regs.srp); + __put_user(env->pc, &sc->regs.erp); +} + +static void restore_sigcontext(struct target_sigcontext *sc, CPUState *env) +{ + __get_user(env->regs[0], &sc->regs.r0); + __get_user(env->regs[1], &sc->regs.r1); + __get_user(env->regs[2], &sc->regs.r2); + __get_user(env->regs[3], &sc->regs.r3); + __get_user(env->regs[4], &sc->regs.r4); + __get_user(env->regs[5], &sc->regs.r5); + __get_user(env->regs[6], &sc->regs.r6); + __get_user(env->regs[7], &sc->regs.r7); + __get_user(env->regs[8], &sc->regs.r8); + __get_user(env->regs[9], &sc->regs.r9); + __get_user(env->regs[10], &sc->regs.r10); + __get_user(env->regs[11], &sc->regs.r11); + __get_user(env->regs[12], &sc->regs.r12); + __get_user(env->regs[13], &sc->regs.r13); + __get_user(env->regs[14], &sc->usp); + __get_user(env->regs[15], &sc->regs.acr); + __get_user(env->pregs[PR_MOF], &sc->regs.mof); + __get_user(env->pregs[PR_SRP], &sc->regs.srp); + __get_user(env->pc, &sc->regs.erp); +} + +static abi_ulong get_sigframe(CPUState *env, int framesize) +{ + abi_ulong sp; + /* Align the stack downwards to 4. */ + sp = (env->regs[R_SP] & ~3); + return sp - framesize; +} + +static void setup_frame(int sig, struct target_sigaction *ka, + target_sigset_t *set, CPUState *env) +{ + struct target_signal_frame *frame; + abi_ulong frame_addr; + int err = 0; + int i; + + frame_addr = get_sigframe(env, sizeof *frame); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) + goto badframe; + + /* + * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't + * use this trampoline anymore but it sets it up for GDB. + * In QEMU, using the trampoline simplifies things a bit so we use it. + * + * This is movu.w __NR_sigreturn, r9; break 13; + */ + err |= __put_user(0x9c5f, frame->retcode+0); + err |= __put_user(TARGET_NR_sigreturn, + frame->retcode+2); + err |= __put_user(0xe93d, frame->retcode+4); + + /* Save the mask. */ + err |= __put_user(set->sig[0], &frame->sc.oldmask); + if (err) + goto badframe; + + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + if (__put_user(set->sig[i], &frame->extramask[i - 1])) + goto badframe; + } + + setup_sigcontext(&frame->sc, env); + + /* Move the stack and setup the arguments for the handler. */ + env->regs[R_SP] = (uint32_t) (unsigned long) frame; + env->regs[10] = sig; + env->pc = (unsigned long) ka->_sa_handler; + /* Link SRP so the guest returns through the trampoline. */ + env->pregs[PR_SRP] = (uint32_t) (unsigned long) &frame->retcode[0]; + + unlock_user_struct(frame, frame_addr, 1); + return; + badframe: + unlock_user_struct(frame, frame_addr, 1); + force_sig(TARGET_SIGSEGV); +} + +static void setup_rt_frame(int sig, struct target_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ + fprintf(stderr, "CRIS setup_rt_frame: not implemented\n"); +} + +long do_sigreturn(CPUState *env) +{ + struct target_signal_frame *frame; + abi_ulong frame_addr; + target_sigset_t target_set; + sigset_t set; + int i; + + frame_addr = env->regs[R_SP]; + /* Make sure the guest isn't playing games. */ + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) + goto badframe; + + /* Restore blocked signals */ + if (__get_user(target_set.sig[0], &frame->sc.oldmask)) + goto badframe; + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + if (__get_user(target_set.sig[i], &frame->extramask[i - 1])) + goto badframe; + } + target_to_host_sigset_internal(&set, &target_set); + sigprocmask(SIG_SETMASK, &set, NULL); + + restore_sigcontext(&frame->sc, env); + unlock_user_struct(frame, frame_addr, 0); + return env->regs[10]; + badframe: + unlock_user_struct(frame, frame_addr, 0); + force_sig(TARGET_SIGSEGV); +} + +long do_rt_sigreturn(CPUState *env) +{ + fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n"); + return -TARGET_ENOSYS; +} #else -static void setup_frame(int sig, struct emulated_sigaction *ka, +static void setup_frame(int sig, struct target_sigaction *ka, target_sigset_t *set, CPUState *env) { fprintf(stderr, "setup_frame: not implemented\n"); } -static void setup_rt_frame(int sig, struct emulated_sigaction *ka, +static void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUState *env) { @@ -2736,26 +3065,29 @@ #endif -void process_pending_signals(void *cpu_env) +void process_pending_signals(CPUState *cpu_env) { int sig; abi_ulong handler; sigset_t set, old_set; target_sigset_t target_old_set; - struct emulated_sigaction *k; + struct emulated_sigtable *k; + struct target_sigaction *sa; struct sigqueue *q; + TaskState *ts = cpu_env->opaque; - if (!signal_pending) + if (!ts->signal_pending) return; - k = sigact_table; + /* FIXME: This is not threadsafe. */ + k = ts->sigtab; for(sig = 1; sig <= TARGET_NSIG; sig++) { if (k->pending) goto handle_signal; k++; } /* if no signal is pending, just return */ - signal_pending = 0; + ts->signal_pending = 0; return; handle_signal: @@ -2774,7 +3106,8 @@ abort(); } - handler = k->sa._sa_handler; + sa = &sigact_table[sig - 1]; + handler = sa->_sa_handler; if (handler == TARGET_SIG_DFL) { /* default handler : ignore some signal. The other are fatal */ if (sig != TARGET_SIGCHLD && @@ -2788,10 +3121,10 @@ force_sig(sig); } else { /* compute the blocked signals during the handler execution */ - target_to_host_sigset(&set, &k->sa.sa_mask); + target_to_host_sigset(&set, &sa->sa_mask); /* SA_NODEFER indicates that the current signal should not be blocked during the handler */ - if (!(k->sa.sa_flags & TARGET_SA_NODEFER)) + if (!(sa->sa_flags & TARGET_SA_NODEFER)) sigaddset(&set, target_to_host_signal(sig)); /* block signals in the handler using Linux */ @@ -2809,13 +3142,13 @@ } #endif /* prepare the stack frame of the virtual CPU */ - if (k->sa.sa_flags & TARGET_SA_SIGINFO) - setup_rt_frame(sig, k, &q->info, &target_old_set, cpu_env); + if (sa->sa_flags & TARGET_SA_SIGINFO) + setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env); else - setup_frame(sig, k, &target_old_set, cpu_env); - if (k->sa.sa_flags & TARGET_SA_RESETHAND) - k->sa._sa_handler = TARGET_SIG_DFL; + setup_frame(sig, sa, &target_old_set, cpu_env); + if (sa->sa_flags & TARGET_SA_RESETHAND) + sa->_sa_handler = TARGET_SIG_DFL; } if (q != &k->info) - free_sigqueue(q); + free_sigqueue(cpu_env, q); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/strace.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/strace.c --- qemu-0.9.1/linux-user/strace.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/strace.c 2008-10-03 20:01:41.000000000 +0100 @@ -13,12 +13,12 @@ struct syscallname { int nr; - char *name; - char *format; - void (*call)(struct syscallname *, + const char *name; + const char *format; + void (*call)(const struct syscallname *, abi_long, abi_long, abi_long, abi_long, abi_long, abi_long); - void (*result)(struct syscallname *, abi_long); + void (*result)(const struct syscallname *, abi_long); }; /* @@ -131,7 +131,7 @@ static long newselect_arg5 = 0; static void -print_newselect(struct syscallname *name, +print_newselect(const struct syscallname *name, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { @@ -154,8 +154,9 @@ } #endif +#ifdef TARGET_NR_semctl static void -print_semctl(struct syscallname *name, +print_semctl(const struct syscallname *name, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { @@ -163,9 +164,10 @@ print_ipc_cmd(arg3); gemu_log(",0x" TARGET_ABI_FMT_lx ")", arg4); } +#endif static void -print_execve(struct syscallname *name, +print_execve(const struct syscallname *name, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { @@ -178,7 +180,7 @@ unlock_user(s, arg1, 0); for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) { - abi_ulong *arg_ptr, arg_addr, s_addr; + abi_ulong *arg_ptr, arg_addr; arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1); if (!arg_ptr) @@ -189,7 +191,7 @@ break; if ((s = lock_user_string(arg_addr))) { gemu_log("\"%s\",", s); - unlock_user(s, s_addr, 0); + unlock_user(s, arg_addr, 0); } } @@ -198,14 +200,15 @@ #ifdef TARGET_NR_ipc static void -print_ipc(struct syscallname *name, +print_ipc(const struct syscallname *name, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { switch(arg1) { case IPCOP_semctl: - name->name = "semctl"; - print_semctl(name,arg2,arg3,arg4,arg5,arg6,0); + gemu_log("semctl(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ",", arg1, arg2); + print_ipc_cmd(arg3); + gemu_log(",0x" TARGET_ABI_FMT_lx ")", arg4); break; default: gemu_log("%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ")", @@ -219,7 +222,7 @@ */ static void -print_syscall_ret_addr(struct syscallname *name, abi_long ret) +print_syscall_ret_addr(const struct syscallname *name, abi_long ret) { if( ret == -1 ) { gemu_log(" = -1 errno=%d (%s)\n", errno, target_strerror(errno)); @@ -238,7 +241,7 @@ #ifdef TARGET_NR__newselect static void -print_syscall_ret_newselect(struct syscallname *name, abi_long ret) +print_syscall_ret_newselect(const struct syscallname *name, abi_long ret) { gemu_log(" = 0x" TARGET_ABI_FMT_lx " (", ret); print_fdset(newselect_arg1,newselect_arg2); @@ -256,7 +259,7 @@ * An array of all of the syscalls we know about */ -static struct syscallname scnames[] = { +static const struct syscallname scnames[] = { #include "strace.list" }; @@ -271,7 +274,7 @@ abi_long arg4, abi_long arg5, abi_long arg6) { int i; - char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ")"; + const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ")"; gemu_log("%d ", getpid() ); @@ -286,8 +289,9 @@ format = scnames[i].format; gemu_log(format,scnames[i].name, arg1,arg2,arg3,arg4,arg5,arg6); } - break; + return; } + gemu_log("Unknown syscall %d\n", num); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/strace.list /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/strace.list --- qemu-0.9.1/linux-user/strace.list 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/strace.list 2008-10-28 10:39:39.000000000 +0000 @@ -1250,7 +1250,7 @@ { TARGET_NR_sgetmask, "sgetmask" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_shmat -{ TARGET_NR_shmat, "shmat" , NULL, NULL, NULL }, +{ TARGET_NR_shmat, "shmat" , NULL, NULL, print_syscall_ret_addr }, #endif #ifdef TARGET_NR_shmctl { TARGET_NR_shmctl, "shmctl" , NULL, NULL, NULL }, diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/syscall.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/syscall.c --- qemu-0.9.1/linux-user/syscall.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/syscall.c 2008-11-10 02:55:33.000000000 +0000 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,10 @@ //#include #include #include +#include +#ifdef HAVE_GPROF +#include +#endif #define termios host_termios #define winsize host_winsize @@ -66,10 +71,21 @@ #include #include #include -#include #include +#include +#include "linux_loop.h" #include "qemu.h" +#include "qemu-common.h" + +#if defined(USE_NPTL) +#include +#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \ + CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID) +#else +/* XXX: Hardcode the above values. */ +#define CLONE_NPTL_FLAGS2 0 +#endif //#define DEBUG @@ -80,8 +96,8 @@ #endif //#include -#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2]) -#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2]) +#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2]) +#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2]) #undef _syscall0 @@ -93,38 +109,38 @@ #undef _syscall6 #define _syscall0(type,name) \ -type name (void) \ +static type name (void) \ { \ return syscall(__NR_##name); \ } #define _syscall1(type,name,type1,arg1) \ -type name (type1 arg1) \ +static type name (type1 arg1) \ { \ return syscall(__NR_##name, arg1); \ } #define _syscall2(type,name,type1,arg1,type2,arg2) \ -type name (type1 arg1,type2 arg2) \ +static type name (type1 arg1,type2 arg2) \ { \ return syscall(__NR_##name, arg1, arg2); \ } #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ -type name (type1 arg1,type2 arg2,type3 arg3) \ +static type name (type1 arg1,type2 arg2,type3 arg3) \ { \ return syscall(__NR_##name, arg1, arg2, arg3); \ } #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ -type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \ +static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \ { \ return syscall(__NR_##name, arg1, arg2, arg3, arg4); \ } #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ type5,arg5) \ -type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ +static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ { \ return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \ } @@ -132,16 +148,20 @@ #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ type5,arg5,type6,arg6) \ -type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ +static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \ + type6 arg6) \ { \ return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \ } +#define __NR_sys_exit __NR_exit #define __NR_sys_uname __NR_uname #define __NR_sys_faccessat __NR_faccessat #define __NR_sys_fchmodat __NR_fchmodat #define __NR_sys_fchownat __NR_fchownat +#define __NR_sys_fstatat64 __NR_fstatat64 +#define __NR_sys_futimesat __NR_futimesat #define __NR_sys_getcwd1 __NR_getcwd #define __NR_sys_getdents __NR_getdents #define __NR_sys_getdents64 __NR_getdents64 @@ -159,6 +179,10 @@ #define __NR_sys_tkill __NR_tkill #define __NR_sys_unlinkat __NR_unlinkat #define __NR_sys_utimensat __NR_utimensat +#define __NR_sys_futex __NR_futex +#define __NR_sys_inotify_init __NR_inotify_init +#define __NR_sys_inotify_add_watch __NR_inotify_add_watch +#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) #define __NR__llseek __NR_lseek @@ -173,6 +197,7 @@ return -ENOSYS; } #endif +_syscall1(int,sys_exit,int,status) _syscall1(int,sys_uname,struct new_utsname *,buf) #if defined(TARGET_NR_faccessat) && defined(__NR_faccessat) _syscall4(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode,int,flags) @@ -181,18 +206,30 @@ _syscall4(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode,int,flags) #endif -#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) +#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) && defined(USE_UID16) _syscall5(int,sys_fchownat,int,dirfd,const char *,pathname, uid_t,owner,gid_t,group,int,flags) #endif +#if defined(TARGET_NR_fstatat64) && defined(__NR_fstatat64) +_syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname, + struct stat *,buf,int,flags) +#endif +#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat) +_syscall3(int,sys_futimesat,int,dirfd,const char *,pathname, + const struct timeval *,times) +#endif _syscall2(int,sys_getcwd1,char *,buf,size_t,size) -_syscall3(int, sys_getdents, uint, fd, struct dirent *, dirp, uint, count); +#if TARGET_ABI_BITS == 32 +_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count); +#endif #if defined(TARGET_NR_getdents64) && defined(__NR_getdents64) -_syscall3(int, sys_getdents64, uint, fd, struct dirent64 *, dirp, uint, count); +_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count); #endif _syscall2(int, sys_getpriority, int, which, int, who); +#if !defined (__x86_64__) _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); +#endif #if defined(TARGET_NR_linkat) && defined(__NR_linkat) _syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath, int,newdirfd,const char *,newpath,int,flags) @@ -240,15 +277,26 @@ _syscall4(int,sys_utimensat,int,dirfd,const char *,pathname, const struct timespec *,tsp,int,flags) #endif +#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init) +_syscall0(int,sys_inotify_init) +#endif +#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch) +_syscall3(int,sys_inotify_add_watch,int,fd,const char *,pathname,uint32_t,mask) +#endif +#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch) +_syscall2(int,sys_inotify_rm_watch,int,fd,uint32_t,wd) +#endif +#if defined(USE_NPTL) +#if defined(TARGET_NR_futex) && defined(__NR_futex) +_syscall6(int,sys_futex,int *,uaddr,int,op,int,val, + const struct timespec *,timeout,int *,uaddr2,int,val3) +#endif +#endif extern int personality(int); extern int flock(int, int); extern int setfsuid(int); extern int setfsgid(int); -extern int setresuid(uid_t, uid_t, uid_t); -extern int getresuid(uid_t *, uid_t *, uid_t *); -extern int setresgid(gid_t, gid_t, gid_t); -extern int getresgid(gid_t *, gid_t *, gid_t *); extern int setgroups(int, gid_t *); #define ERRNO_TABLE_SIZE 1200 @@ -420,7 +468,7 @@ if (!new_brk) return target_brk; if (new_brk < target_original_brk) - return -TARGET_ENOMEM; + return target_brk; brk_page = HOST_PAGE_ALIGN(target_brk); @@ -435,12 +483,11 @@ mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0)); - if (is_error(mapped_addr)) { - return mapped_addr; - } else { + + if (!is_error(mapped_addr)) target_brk = new_brk; - return target_brk; - } + + return target_brk; } static inline abi_long copy_from_user_fdset(fd_set *fds, @@ -916,7 +963,8 @@ abi_ulong optval_addr, abi_ulong optlen) { abi_long ret; - int len, lv, val; + int len, val; + socklen_t lv; switch(level) { case TARGET_SOL_SOCKET: @@ -1019,7 +1067,7 @@ { struct target_iovec *target_vec; abi_ulong base; - int i, j; + int i; target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); if (!target_vec) @@ -1027,20 +1075,17 @@ for(i = 0;i < count; i++) { base = tswapl(target_vec[i].iov_base); vec[i].iov_len = tswapl(target_vec[i].iov_len); - vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy); - if (!vec[i].iov_base) - goto fail; + if (vec[i].iov_len != 0) { + vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy); + /* Don't check lock_user return value. We must call writev even + if a element has invalid base address. */ + } else { + /* zero length pointer is ignored */ + vec[i].iov_base = NULL; + } } unlock_user (target_vec, target_addr, 0); return 0; - fail: - /* failure - unwind locks */ - for (j = 0; j < i; j++) { - base = tswapl(target_vec[j].iov_base); - unlock_user(vec[j].iov_base, base, 0); - } - unlock_user (target_vec, target_addr, 0); - return -TARGET_EFAULT; } static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr, @@ -1054,8 +1099,10 @@ if (!target_vec) return -TARGET_EFAULT; for(i = 0;i < count; i++) { - base = tswapl(target_vec[i].iov_base); - unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0); + if (target_vec[i].iov_base) { + base = tswapl(target_vec[i].iov_base); + unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0); + } } unlock_user (target_vec, target_addr, 0); @@ -1116,7 +1163,7 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, int flags, int send) { - abi_long ret; + abi_long ret, len; struct target_msghdr *msgp; struct msghdr msg; int count; @@ -1155,8 +1202,12 @@ ret = get_errno(sendmsg(fd, &msg, flags)); } else { ret = get_errno(recvmsg(fd, &msg, flags)); - if (!is_error(ret)) + if (!is_error(ret)) { + len = ret; ret = host_to_target_cmsg(msgp, &msg); + if (!is_error(ret)) + ret = len; + } } unlock_iovec(vec, target_vec, count, !send); unlock_user_struct(msgp, target_msg, send ? 0 : 1); @@ -1563,7 +1614,6 @@ } #endif -#ifdef TARGET_NR_ipc #define N_SHM_REGIONS 32 static struct shm_region { @@ -1797,20 +1847,26 @@ struct target_msqid_ds { - struct target_ipc_perm msg_perm; - abi_ulong msg_stime; - abi_ulong __unused1; - abi_ulong msg_rtime; - abi_ulong __unused2; - abi_ulong msg_ctime; - abi_ulong __unused3; - abi_ulong __msg_cbytes; - abi_ulong msg_qnum; - abi_ulong msg_qbytes; - abi_ulong msg_lspid; - abi_ulong msg_lrpid; - abi_ulong __unused4; - abi_ulong __unused5; + struct target_ipc_perm msg_perm; + abi_ulong msg_stime; +#if TARGET_ABI_BITS == 32 + abi_ulong __unused1; +#endif + abi_ulong msg_rtime; +#if TARGET_ABI_BITS == 32 + abi_ulong __unused2; +#endif + abi_ulong msg_ctime; +#if TARGET_ABI_BITS == 32 + abi_ulong __unused3; +#endif + abi_ulong __msg_cbytes; + abi_ulong msg_qnum; + abi_ulong msg_qbytes; + abi_ulong msg_lspid; + abi_ulong msg_lrpid; + abi_ulong __unused4; + abi_ulong __unused5; }; static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md, @@ -1820,7 +1876,8 @@ if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1)) return -TARGET_EFAULT; - target_to_host_ipc_perm(&(host_md->msg_perm),target_addr); + if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr)) + return -TARGET_EFAULT; host_md->msg_stime = tswapl(target_md->msg_stime); host_md->msg_rtime = tswapl(target_md->msg_rtime); host_md->msg_ctime = tswapl(target_md->msg_ctime); @@ -1840,7 +1897,8 @@ if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0)) return -TARGET_EFAULT; - host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)); + if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm))) + return -TARGET_EFAULT; target_md->msg_stime = tswapl(host_md->msg_stime); target_md->msg_rtime = tswapl(host_md->msg_rtime); target_md->msg_ctime = tswapl(host_md->msg_ctime); @@ -1853,26 +1911,70 @@ return 0; } -static inline abi_long do_msgctl(int first, int second, abi_long ptr) +struct target_msginfo { + int msgpool; + int msgmap; + int msgmax; + int msgmnb; + int msgmni; + int msgssz; + int msgtql; + unsigned short int msgseg; +}; + +static inline abi_long host_to_target_msginfo(abi_ulong target_addr, + struct msginfo *host_msginfo) +{ + struct target_msginfo *target_msginfo; + if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0)) + return -TARGET_EFAULT; + __put_user(host_msginfo->msgpool, &target_msginfo->msgpool); + __put_user(host_msginfo->msgmap, &target_msginfo->msgmap); + __put_user(host_msginfo->msgmax, &target_msginfo->msgmax); + __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb); + __put_user(host_msginfo->msgmni, &target_msginfo->msgmni); + __put_user(host_msginfo->msgssz, &target_msginfo->msgssz); + __put_user(host_msginfo->msgtql, &target_msginfo->msgtql); + __put_user(host_msginfo->msgseg, &target_msginfo->msgseg); + unlock_user_struct(target_msginfo, target_addr, 1); + return 0; +} + +static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr) { struct msqid_ds dsarg; - int cmd = second&0xff; - abi_long ret = 0; - switch( cmd ) { + struct msginfo msginfo; + abi_long ret = -TARGET_EINVAL; + + cmd &= 0xff; + + switch (cmd) { case IPC_STAT: case IPC_SET: - target_to_host_msqid_ds(&dsarg,ptr); - ret = get_errno(msgctl(first, cmd, &dsarg)); - host_to_target_msqid_ds(ptr,&dsarg); - default: - ret = get_errno(msgctl(first, cmd, &dsarg)); + case MSG_STAT: + if (target_to_host_msqid_ds(&dsarg,ptr)) + return -TARGET_EFAULT; + ret = get_errno(msgctl(msgid, cmd, &dsarg)); + if (host_to_target_msqid_ds(ptr,&dsarg)) + return -TARGET_EFAULT; + break; + case IPC_RMID: + ret = get_errno(msgctl(msgid, cmd, NULL)); + break; + case IPC_INFO: + case MSG_INFO: + ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo)); + if (host_to_target_msginfo(ptr, &msginfo)) + return -TARGET_EFAULT; + break; } + return ret; } struct target_msgbuf { - abi_ulong mtype; - char mtext[1]; + abi_long mtype; + char mtext[1]; }; static inline abi_long do_msgsnd(int msqid, abi_long msgp, @@ -1885,8 +1987,8 @@ if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0)) return -TARGET_EFAULT; host_mb = malloc(msgsz+sizeof(long)); - host_mb->mtype = tswapl(target_mb->mtype); - memcpy(host_mb->mtext,target_mb->mtext,msgsz); + host_mb->mtype = (abi_long) tswapl(target_mb->mtype); + memcpy(host_mb->mtext, target_mb->mtext, msgsz); ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg)); free(host_mb); unlock_user_struct(target_mb, msgp, 0); @@ -1895,7 +1997,7 @@ } static inline abi_long do_msgrcv(int msqid, abi_long msgp, - unsigned int msgsz, int msgtype, + unsigned int msgsz, abi_long msgtyp, int msgflg) { struct target_msgbuf *target_mb; @@ -1905,8 +2007,10 @@ if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0)) return -TARGET_EFAULT; + host_mb = malloc(msgsz+sizeof(long)); - ret = get_errno(msgrcv(msqid, host_mb, msgsz, 1, msgflg)); + ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapl(msgtyp), msgflg)); + if (ret > 0) { abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong); target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0); @@ -1914,9 +2018,10 @@ ret = -TARGET_EFAULT; goto end; } - memcpy(target_mb->mtext, host_mb->mtext, ret); + memcpy(target_mb->mtext, host_mb->mtext, ret); unlock_user(target_mtext, target_mtext_addr, ret); } + target_mb->mtype = tswapl(host_mb->mtype); free(host_mb); @@ -1926,6 +2031,7 @@ return ret; } +#ifdef TARGET_NR_ipc /* ??? This only works with linear mappings. */ /* do_ipc() must return target values and target errnos. */ static abi_long do_ipc(unsigned int call, int first, @@ -1958,34 +2064,41 @@ ret = -TARGET_ENOSYS; break; - case IPCOP_msgget: - ret = get_errno(msgget(first, second)); - break; + case IPCOP_msgget: + ret = get_errno(msgget(first, second)); + break; - case IPCOP_msgsnd: - ret = do_msgsnd(first, ptr, second, third); - break; + case IPCOP_msgsnd: + ret = do_msgsnd(first, ptr, second, third); + break; - case IPCOP_msgctl: - ret = do_msgctl(first, second, ptr); - break; + case IPCOP_msgctl: + ret = do_msgctl(first, second, ptr); + break; - case IPCOP_msgrcv: - { - /* XXX: this code is not correct */ - struct ipc_kludge - { - void *__unbounded msgp; - long int msgtyp; - }; + case IPCOP_msgrcv: + switch (version) { + case 0: + { + struct target_ipc_kludge { + abi_long msgp; + abi_long msgtyp; + } *tmp; - struct ipc_kludge *foo = (struct ipc_kludge *)g2h(ptr); - struct msgbuf *msgp = (struct msgbuf *) foo->msgp; + if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) { + ret = -TARGET_EFAULT; + break; + } - ret = do_msgrcv(first, (long)msgp, second, 0, third); + ret = do_msgrcv(first, tmp->msgp, second, tmp->msgtyp, third); - } - break; + unlock_user_struct(tmp, ptr, 0); + break; + } + default: + ret = do_msgrcv(first, ptr, second, fifth, third); + } + break; case IPCOP_shmat: { @@ -2070,7 +2183,7 @@ #undef STRUCT #undef STRUCT_SPECIAL -#define STRUCT(name, list...) const argtype struct_ ## name ## _def[] = { list, TYPE_NULL }; +#define STRUCT(name, list...) static const argtype struct_ ## name ## _def[] = { list, TYPE_NULL }; #define STRUCT_SPECIAL(name) #include "syscall_types.h" #undef STRUCT @@ -2090,7 +2203,7 @@ #define MAX_STRUCT_SIZE 4096 -IOCTLEntry ioctl_entries[] = { +static IOCTLEntry ioctl_entries[] = { #define IOCTL(cmd, access, types...) \ { TARGET_ ## cmd, cmd, #cmd, access, { types } }, #include "ioctls.h" @@ -2181,7 +2294,7 @@ return ret; } -bitmask_transtbl iflag_tbl[] = { +static const bitmask_transtbl iflag_tbl[] = { { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK }, { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT }, { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR }, @@ -2199,7 +2312,7 @@ { 0, 0, 0, 0 } }; -bitmask_transtbl oflag_tbl[] = { +static const bitmask_transtbl oflag_tbl[] = { { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST }, { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC }, { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR }, @@ -2227,7 +2340,7 @@ { 0, 0, 0, 0 } }; -bitmask_transtbl cflag_tbl[] = { +static const bitmask_transtbl cflag_tbl[] = { { TARGET_CBAUD, TARGET_B0, CBAUD, B0 }, { TARGET_CBAUD, TARGET_B50, CBAUD, B50 }, { TARGET_CBAUD, TARGET_B75, CBAUD, B75 }, @@ -2262,7 +2375,7 @@ { 0, 0, 0, 0 } }; -bitmask_transtbl lflag_tbl[] = { +static const bitmask_transtbl lflag_tbl[] = { { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG }, { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON }, { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE }, @@ -2349,7 +2462,7 @@ target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2]; } -StructEntry struct_termios_def = { +static const StructEntry struct_termios_def = { .convert = { host_to_target_termios, target_to_host_termios }, .size = { sizeof(struct target_termios), sizeof(struct host_termios) }, .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) }, @@ -2390,7 +2503,7 @@ #if defined(TARGET_I386) /* NOTE: there is really one LDT for all the threads */ -uint8_t *ldt_table; +static uint8_t *ldt_table; static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount) { @@ -2452,12 +2565,16 @@ } /* allocate the LDT */ if (!ldt_table) { - ldt_table = malloc(TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE); - if (!ldt_table) + env->ldt.base = target_mmap(0, + TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE, + PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + if (env->ldt.base == -1) return -TARGET_ENOMEM; - memset(ldt_table, 0, TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE); - env->ldt.base = h2g((unsigned long)ldt_table); + memset(g2h(env->ldt.base), 0, + TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE); env->ldt.limit = 0xffff; + ldt_table = g2h(env->ldt.base); } /* NOTE: same code as Linux kernel */ @@ -2500,8 +2617,8 @@ } /* specific and weird i386 syscalls */ -abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr, - unsigned long bytecount) +static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr, + unsigned long bytecount) { abi_long ret; @@ -2522,7 +2639,8 @@ return ret; } -abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr) +#if defined(TARGET_I386) && defined(TARGET_ABI32) +static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr) { uint64_t *gdt_table = g2h(env->gdt.base); struct target_modify_ldt_ldt_s ldt_info; @@ -2607,7 +2725,7 @@ return 0; } -abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr) +static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr) { struct target_modify_ldt_ldt_s *target_ldt_info; uint64_t *gdt_table = g2h(env->gdt.base); @@ -2653,9 +2771,10 @@ unlock_user_struct(target_ldt_info, ptr, 1); return 0; } +#endif /* TARGET_I386 && TARGET_ABI32 */ #ifndef TARGET_ABI32 -abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr) +static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr) { abi_long ret; abi_ulong val; @@ -2691,6 +2810,48 @@ #endif /* defined(TARGET_I386) */ +#if defined(USE_NPTL) + +#define NEW_STACK_SIZE PTHREAD_STACK_MIN + +static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER; +typedef struct { + CPUState *env; + pthread_mutex_t mutex; + pthread_cond_t cond; + pthread_t thread; + uint32_t tid; + abi_ulong child_tidptr; + abi_ulong parent_tidptr; + sigset_t sigmask; +} new_thread_info; + +static void *clone_func(void *arg) +{ + new_thread_info *info = arg; + CPUState *env; + + env = info->env; + thread_env = env; + info->tid = gettid(); + if (info->child_tidptr) + put_user_u32(info->tid, info->child_tidptr); + if (info->parent_tidptr) + put_user_u32(info->tid, info->parent_tidptr); + /* Enable signals. */ + sigprocmask(SIG_SETMASK, &info->sigmask, NULL); + /* Signal to the parent that we're ready. */ + pthread_mutex_lock(&info->mutex); + pthread_cond_broadcast(&info->cond); + pthread_mutex_unlock(&info->mutex); + /* Wait until the parent has finshed initializing the tls state. */ + pthread_mutex_lock(&clone_lock); + pthread_mutex_unlock(&clone_lock); + cpu_loop(env); + /* never exits */ + return NULL; +} +#else /* this stack is the equivalent of the kernel stack associated with a thread/process */ #define NEW_STACK_SIZE 8192 @@ -2702,95 +2863,128 @@ /* never exits */ return 0; } +#endif /* do_fork() Must return host values and target errnos (unlike most do_*() functions). */ -int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp) +static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp, + abi_ulong parent_tidptr, target_ulong newtls, + abi_ulong child_tidptr) { int ret; TaskState *ts; uint8_t *new_stack; CPUState *new_env; +#if defined(USE_NPTL) + unsigned int nptl_flags; + sigset_t sigmask; +#endif + + /* Emulate vfork() with fork() */ + if (flags & CLONE_VFORK) + flags &= ~(CLONE_VFORK | CLONE_VM); if (flags & CLONE_VM) { - ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE); - memset(ts, 0, sizeof(TaskState)); +#if defined(USE_NPTL) + new_thread_info info; + pthread_attr_t attr; +#endif + ts = qemu_mallocz(sizeof(TaskState) + NEW_STACK_SIZE); + init_task_state(ts); new_stack = ts->stack; - ts->used = 1; - /* add in task state list */ - ts->next = first_task_state; - first_task_state = ts; /* we create a new CPU instance. */ new_env = cpu_copy(env); -#if defined(TARGET_I386) - if (!newsp) - newsp = env->regs[R_ESP]; - new_env->regs[R_ESP] = newsp; - new_env->regs[R_EAX] = 0; -#elif defined(TARGET_ARM) - if (!newsp) - newsp = env->regs[13]; - new_env->regs[13] = newsp; - new_env->regs[0] = 0; -#elif defined(TARGET_SPARC) - if (!newsp) - newsp = env->regwptr[22]; - new_env->regwptr[22] = newsp; - new_env->regwptr[0] = 0; - /* XXXXX */ - printf ("HELPME: %s:%d\n", __FILE__, __LINE__); -#elif defined(TARGET_M68K) - if (!newsp) - newsp = env->aregs[7]; - new_env->aregs[7] = newsp; - new_env->dregs[0] = 0; - /* ??? is this sufficient? */ -#elif defined(TARGET_MIPS) - if (!newsp) - newsp = env->gpr[29][env->current_tc]; - new_env->gpr[29][env->current_tc] = newsp; -#elif defined(TARGET_PPC) - if (!newsp) - newsp = env->gpr[1]; - new_env->gpr[1] = newsp; - { - int i; - for (i = 7; i < 32; i++) - new_env->gpr[i] = 0; - } -#elif defined(TARGET_SH4) - if (!newsp) - newsp = env->gregs[15]; - new_env->gregs[15] = newsp; - /* XXXXX */ -#elif defined(TARGET_ALPHA) - if (!newsp) - newsp = env->ir[30]; - new_env->ir[30] = newsp; - /* ? */ - { - int i; - for (i = 7; i < 30; i++) - new_env->ir[i] = 0; + /* Init regs that differ from the parent. */ + cpu_clone_regs(new_env, newsp); + new_env->opaque = ts; +#if defined(USE_NPTL) + nptl_flags = flags; + flags &= ~CLONE_NPTL_FLAGS2; + + /* TODO: Implement CLONE_CHILD_CLEARTID. */ + if (nptl_flags & CLONE_SETTLS) + cpu_set_tls (new_env, newtls); + + /* Grab a mutex so that thread setup appears atomic. */ + pthread_mutex_lock(&clone_lock); + + memset(&info, 0, sizeof(info)); + pthread_mutex_init(&info.mutex, NULL); + pthread_mutex_lock(&info.mutex); + pthread_cond_init(&info.cond, NULL); + info.env = new_env; + if (nptl_flags & CLONE_CHILD_SETTID) + info.child_tidptr = child_tidptr; + if (nptl_flags & CLONE_PARENT_SETTID) + info.parent_tidptr = parent_tidptr; + + ret = pthread_attr_init(&attr); + ret = pthread_attr_setstack(&attr, new_stack, NEW_STACK_SIZE); + /* It is not safe to deliver signals until the child has finished + initializing, so temporarily block all signals. */ + sigfillset(&sigmask); + sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask); + + ret = pthread_create(&info.thread, &attr, clone_func, &info); + + sigprocmask(SIG_SETMASK, &info.sigmask, NULL); + pthread_attr_destroy(&attr); + if (ret == 0) { + /* Wait for the child to initialize. */ + pthread_cond_wait(&info.cond, &info.mutex); + ret = info.tid; + if (flags & CLONE_PARENT_SETTID) + put_user_u32(ret, parent_tidptr); + } else { + ret = -1; } -#elif defined(TARGET_CRIS) - if (!newsp) - newsp = env->regs[14]; - new_env->regs[14] = newsp; + pthread_mutex_unlock(&info.mutex); + pthread_cond_destroy(&info.cond); + pthread_mutex_destroy(&info.mutex); + pthread_mutex_unlock(&clone_lock); #else -#error unsupported target CPU -#endif - new_env->opaque = ts; + if (flags & CLONE_NPTL_FLAGS2) + return -EINVAL; + /* This is probably going to die very quickly, but do it anyway. */ #ifdef __ia64__ ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); #else ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); #endif +#endif } else { /* if no CLONE_VM, we consider it is a fork */ - if ((flags & ~CSIGNAL) != 0) + if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) return -EINVAL; + fork_start(); ret = fork(); +#if defined(USE_NPTL) + /* There is a race condition here. The parent process could + theoretically read the TID in the child process before the child + tid is set. This would require using either ptrace + (not implemented) or having *_tidptr to point at a shared memory + mapping. We can't repeat the spinlock hack used above because + the child process gets its own copy of the lock. */ + if (ret == 0) { + cpu_clone_regs(env, newsp); + fork_end(1); + /* Child Process. */ + if (flags & CLONE_CHILD_SETTID) + put_user_u32(gettid(), child_tidptr); + if (flags & CLONE_PARENT_SETTID) + put_user_u32(gettid(), parent_tidptr); + ts = (TaskState *)env->opaque; + if (flags & CLONE_SETTLS) + cpu_set_tls (env, newtls); + /* TODO: Implement CLONE_CHILD_CLEARTID. */ + } else { + fork_end(0); + } +#else + if (ret == 0) { + cpu_clone_regs(env, newsp); + } +#endif } return ret; } @@ -2965,10 +3159,11 @@ target_to_host_errno_table[host_to_target_errno_table[i]] = i; /* automatic consistency check if same arch */ -#if defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32) - if (ie->target_cmd != ie->host_cmd) { - fprintf(stderr, "ERROR: ioctl: target=0x%x host=0x%x\n", - ie->target_cmd, ie->host_cmd); +#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \ + (defined(__x86_64__) && defined(TARGET_X86_64)) + if (unlikely(ie->target_cmd != ie->host_cmd)) { + fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n", + ie->name, ie->target_cmd, ie->host_cmd); } #endif ie++; @@ -2978,7 +3173,7 @@ #if TARGET_ABI_BITS == 32 static inline uint64_t target_offset64(uint32_t word0, uint32_t word1) { -#ifdef TARGET_WORDS_BIG_ENDIAN +#ifdef TARGET_WORDS_BIGENDIAN return ((uint64_t)word0 << 32) | word1; #else return ((uint64_t)word1 << 32) | word0; @@ -3035,6 +3230,7 @@ host_ts->tv_sec = tswapl(target_ts->tv_sec); host_ts->tv_nsec = tswapl(target_ts->tv_nsec); unlock_user_struct(target_ts, target_addr, 0); + return 0; } static inline abi_long host_to_target_timespec(abi_ulong target_addr, @@ -3047,6 +3243,138 @@ target_ts->tv_sec = tswapl(host_ts->tv_sec); target_ts->tv_nsec = tswapl(host_ts->tv_nsec); unlock_user_struct(target_ts, target_addr, 1); + return 0; +} + +#ifdef TARGET_NR_stat64 +static inline abi_long host_to_target_stat64(void *cpu_env, + abi_ulong target_addr, + struct stat *host_st) +{ +#ifdef TARGET_ARM + if (((CPUARMState *)cpu_env)->eabi) { + struct target_eabi_stat64 *target_st; + + if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) + return -TARGET_EFAULT; + memset(target_st, 0, sizeof(struct target_eabi_stat64)); + __put_user(host_st->st_dev, &target_st->st_dev); + __put_user(host_st->st_ino, &target_st->st_ino); +#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO + __put_user(host_st->st_ino, &target_st->__st_ino); +#endif + __put_user(host_st->st_mode, &target_st->st_mode); + __put_user(host_st->st_nlink, &target_st->st_nlink); + __put_user(host_st->st_uid, &target_st->st_uid); + __put_user(host_st->st_gid, &target_st->st_gid); + __put_user(host_st->st_rdev, &target_st->st_rdev); + __put_user(host_st->st_size, &target_st->st_size); + __put_user(host_st->st_blksize, &target_st->st_blksize); + __put_user(host_st->st_blocks, &target_st->st_blocks); + __put_user(host_st->st_atime, &target_st->target_st_atime); + __put_user(host_st->st_mtime, &target_st->target_st_mtime); + __put_user(host_st->st_ctime, &target_st->target_st_ctime); + unlock_user_struct(target_st, target_addr, 1); + } else +#endif + { + struct target_stat64 *target_st; + + if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) + return -TARGET_EFAULT; + memset(target_st, 0, sizeof(struct target_stat64)); + __put_user(host_st->st_dev, &target_st->st_dev); + __put_user(host_st->st_ino, &target_st->st_ino); +#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO + __put_user(host_st->st_ino, &target_st->__st_ino); +#endif + __put_user(host_st->st_mode, &target_st->st_mode); + __put_user(host_st->st_nlink, &target_st->st_nlink); + __put_user(host_st->st_uid, &target_st->st_uid); + __put_user(host_st->st_gid, &target_st->st_gid); + __put_user(host_st->st_rdev, &target_st->st_rdev); + /* XXX: better use of kernel struct */ + __put_user(host_st->st_size, &target_st->st_size); + __put_user(host_st->st_blksize, &target_st->st_blksize); + __put_user(host_st->st_blocks, &target_st->st_blocks); + __put_user(host_st->st_atime, &target_st->target_st_atime); + __put_user(host_st->st_mtime, &target_st->target_st_mtime); + __put_user(host_st->st_ctime, &target_st->target_st_ctime); + unlock_user_struct(target_st, target_addr, 1); + } + + return 0; +} +#endif + +#if defined(USE_NPTL) +/* ??? Using host futex calls even when target atomic operations + are not really atomic probably breaks things. However implementing + futexes locally would make futexes shared between multiple processes + tricky. However they're probably useless because guest atomic + operations won't work either. */ +static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout, + target_ulong uaddr2, int val3) +{ + struct timespec ts, *pts; + + /* ??? We assume FUTEX_* constants are the same on both host + and target. */ + switch (op) { + case FUTEX_WAIT: + if (timeout) { + pts = &ts; + target_to_host_timespec(pts, timeout); + } else { + pts = NULL; + } + return get_errno(sys_futex(g2h(uaddr), FUTEX_WAIT, tswap32(val), + pts, NULL, 0)); + case FUTEX_WAKE: + return get_errno(sys_futex(g2h(uaddr), FUTEX_WAKE, val, NULL, NULL, 0)); + case FUTEX_FD: + return get_errno(sys_futex(g2h(uaddr), FUTEX_FD, val, NULL, NULL, 0)); + case FUTEX_REQUEUE: + return get_errno(sys_futex(g2h(uaddr), FUTEX_REQUEUE, val, + NULL, g2h(uaddr2), 0)); + case FUTEX_CMP_REQUEUE: + return get_errno(sys_futex(g2h(uaddr), FUTEX_CMP_REQUEUE, val, + NULL, g2h(uaddr2), tswap32(val3))); + default: + return -TARGET_ENOSYS; + } +} +#endif + +int get_osversion(void) +{ + static int osversion; + struct new_utsname buf; + const char *s; + int i, n, tmp; + if (osversion) + return osversion; + if (qemu_uname_release && *qemu_uname_release) { + s = qemu_uname_release; + } else { + if (sys_uname(&buf)) + return 0; + s = buf.release; + } + tmp = 0; + for (i = 0; i < 3; i++) { + n = 0; + while (*s >= '0' && *s <= '9') { + n *= 10; + n += *s - '0'; + s++; + } + tmp = (tmp << 8) + n; + if (*s == '.') + s++; + } + osversion = tmp; + return osversion; } /* do_syscall() should always have a single exit point at the end so @@ -3074,7 +3402,7 @@ #endif gdb_exit(cpu_env, arg1); /* XXX: should free thread stack and CPU env */ - _exit(arg1); + sys_exit(arg1); ret = 0; /* avoid warning */ break; case TARGET_NR_read: @@ -3115,7 +3443,7 @@ ret = do_brk(arg1); break; case TARGET_NR_fork: - ret = get_errno(do_fork(cpu_env, SIGCHLD, 0)); + ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0)); break; #ifdef TARGET_NR_waitpid case TARGET_NR_waitpid: @@ -3128,6 +3456,21 @@ } break; #endif +#ifdef TARGET_NR_waitid + case TARGET_NR_waitid: + { + siginfo_t info; + info.si_pid = 0; + ret = get_errno(waitid(arg1, arg2, &info, arg4)); + if (!is_error(ret) && arg3 && info.si_pid != 0) { + if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0))) + goto efault; + host_to_target_siginfo(p, &info); + unlock_user(p, arg3, sizeof(target_siginfo_t)); + } + } + break; +#endif #ifdef TARGET_NR_creat /* not on alpha */ case TARGET_NR_creat: if (!(p = lock_user_string(arg1))) @@ -3192,7 +3535,7 @@ argc = 0; guest_argp = arg2; - for (gp = guest_argp; ; gp += sizeof(abi_ulong)) { + for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) { if (get_user_ual(addr, gp)) goto efault; if (!addr) @@ -3201,7 +3544,7 @@ } envc = 0; guest_envp = arg3; - for (gp = guest_envp; ; gp += sizeof(abi_ulong)) { + for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) { if (get_user_ual(addr, gp)) goto efault; if (!addr) @@ -3212,7 +3555,7 @@ argp = alloca((argc + 1) * sizeof(void *)); envp = alloca((envc + 1) * sizeof(void *)); - for (gp = guest_argp, q = argp; ; + for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) { if (get_user_ual(addr, gp)) goto execve_efault; @@ -3223,7 +3566,7 @@ } *q = NULL; - for (gp = guest_envp, q = envp; ; + for (gp = guest_envp, q = envp; gp; gp += sizeof(abi_ulong), q++) { if (get_user_ual(addr, gp)) goto execve_efault; @@ -3411,6 +3754,26 @@ unlock_user(p, arg1, 0); } break; +#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat) + case TARGET_NR_futimesat: + { + struct timeval *tvp, tv[2]; + if (arg3) { + if (copy_from_user_timeval(&tv[0], arg3) + || copy_from_user_timeval(&tv[1], + arg3 + sizeof(struct target_timeval))) + goto efault; + tvp = tv; + } else { + tvp = NULL; + } + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_futimesat(arg1, path(p), tvp)); + unlock_user(p, arg2, 0); + } + break; +#endif #ifdef TARGET_NR_stty case TARGET_NR_stty: goto unimplemented; @@ -3447,7 +3810,7 @@ ret = 0; break; case TARGET_NR_kill: - ret = get_errno(kill(arg1, arg2)); + ret = get_errno(kill(arg1, target_to_host_signal(arg2))); break; case TARGET_NR_rename: { @@ -3507,7 +3870,10 @@ if (!is_error(ret)) { #if defined(TARGET_MIPS) CPUMIPSState *env = (CPUMIPSState*)cpu_env; - env->gpr[3][env->current_tc] = host_pipe[1]; + env->active_tc.gpr[3] = host_pipe[1]; + ret = host_pipe[0]; +#elif defined(TARGET_SH4) + ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1]; ret = host_pipe[0]; #else if (put_user_s32(host_pipe[0], arg1) @@ -3861,10 +4227,10 @@ } ret = get_errno(sigtimedwait(&set, &uinfo, puts)); if (!is_error(ret) && arg2) { - if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_sigset_t), 0))) + if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0))) goto efault; host_to_target_siginfo(p, &uinfo); - unlock_user(p, arg2, sizeof(target_sigset_t)); + unlock_user(p, arg2, sizeof(target_siginfo_t)); } } break; @@ -4078,10 +4444,8 @@ #endif #ifdef TARGET_NR_mmap2 case TARGET_NR_mmap2: -#if defined(TARGET_SPARC) || defined(TARGET_MIPS) +#ifndef MMAP_SHIFT #define MMAP_SHIFT 12 -#else -#define MMAP_SHIFT TARGET_PAGE_BITS #endif ret = get_errno(target_mmap(arg1, arg2, arg3, target_to_host_bitmask(arg4, mmap_flags_tbl), @@ -4473,15 +4837,43 @@ ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6); break; #endif + +#ifdef TARGET_NR_msgctl + case TARGET_NR_msgctl: + ret = do_msgctl(arg1, arg2, arg3); + break; +#endif +#ifdef TARGET_NR_msgget + case TARGET_NR_msgget: + ret = get_errno(msgget(arg1, arg2)); + break; +#endif +#ifdef TARGET_NR_msgrcv + case TARGET_NR_msgrcv: + ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5); + break; +#endif +#ifdef TARGET_NR_msgsnd + case TARGET_NR_msgsnd: + ret = do_msgsnd(arg1, arg2, arg3, arg4); + break; +#endif case TARGET_NR_fsync: ret = get_errno(fsync(arg1)); break; case TARGET_NR_clone: - ret = get_errno(do_fork(cpu_env, arg1, arg2)); +#if defined(TARGET_SH4) + ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4)); +#else + ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5)); +#endif break; #ifdef __NR_exit_group /* new thread calls */ case TARGET_NR_exit_group: +#ifdef HAVE_GPROF + _mcleanup(); +#endif gdb_exit(cpu_env, arg1); ret = get_errno(exit_group(arg1)); break; @@ -4579,7 +4971,7 @@ #elif TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64 { struct target_dirent *target_dirp; - struct dirent *dirp; + struct linux_dirent *dirp; abi_long count = arg3; dirp = malloc(count); @@ -4590,7 +4982,7 @@ ret = get_errno(sys_getdents(arg1, dirp, count)); if (!is_error(ret)) { - struct dirent *de; + struct linux_dirent *de; struct target_dirent *tde; int len = ret; int reclen, treclen; @@ -4611,8 +5003,8 @@ if (tnamelen > 256) tnamelen = 256; /* XXX: may not be correct */ - strncpy(tde->d_name, de->d_name, tnamelen); - de = (struct dirent *)((char *)de + reclen); + pstrcpy(tde->d_name, tnamelen, de->d_name); + de = (struct linux_dirent *)((char *)de + reclen); len -= reclen; tde = (struct target_dirent *)((char *)tde + treclen); count1 += treclen; @@ -4624,14 +5016,14 @@ } #else { - struct dirent *dirp; + struct linux_dirent *dirp; abi_long count = arg3; if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) goto efault; ret = get_errno(sys_getdents(arg1, dirp, count)); if (!is_error(ret)) { - struct dirent *de; + struct linux_dirent *de; int len = ret; int reclen; de = dirp; @@ -4642,7 +5034,7 @@ de->d_reclen = tswap16(reclen); tswapls(&de->d_ino); tswapls(&de->d_off); - de = (struct dirent *)((char *)de + reclen); + de = (struct linux_dirent *)((char *)de + reclen); len -= reclen; } } @@ -4653,13 +5045,13 @@ #if defined(TARGET_NR_getdents64) && defined(__NR_getdents64) case TARGET_NR_getdents64: { - struct dirent64 *dirp; + struct linux_dirent64 *dirp; abi_long count = arg3; if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) goto efault; ret = get_errno(sys_getdents64(arg1, dirp, count)); if (!is_error(ret)) { - struct dirent64 *de; + struct linux_dirent64 *de; int len = ret; int reclen; de = dirp; @@ -4670,7 +5062,7 @@ de->d_reclen = tswap16(reclen); tswap64s((uint64_t *)&de->d_ino); tswap64s((uint64_t *)&de->d_off); - de = (struct dirent64 *)((char *)de + reclen); + de = (struct linux_dirent64 *)((char *)de + reclen); len -= reclen; } } @@ -4723,7 +5115,8 @@ struct iovec *vec; vec = alloca(count * sizeof(struct iovec)); - lock_iovec(VERIFY_WRITE, vec, arg2, count, 0); + if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0) + goto efault; ret = get_errno(readv(arg1, vec, count)); unlock_iovec(vec, arg2, count, 1); } @@ -4734,7 +5127,8 @@ struct iovec *vec; vec = alloca(count * sizeof(struct iovec)); - lock_iovec(VERIFY_READ, vec, arg2, count, 1); + if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0) + goto efault; ret = get_errno(writev(arg1, vec, count)); unlock_iovec(vec, arg2, count, 0); } @@ -4855,18 +5249,40 @@ #endif #ifdef TARGET_NR_pread case TARGET_NR_pread: +#ifdef TARGET_ARM + if (((CPUARMState *)cpu_env)->eabi) + arg4 = arg5; +#endif if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) goto efault; ret = get_errno(pread(arg1, p, arg3, arg4)); unlock_user(p, arg2, ret); break; case TARGET_NR_pwrite: +#ifdef TARGET_ARM + if (((CPUARMState *)cpu_env)->eabi) + arg4 = arg5; +#endif if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) goto efault; ret = get_errno(pwrite(arg1, p, arg3, arg4)); unlock_user(p, arg2, 0); break; #endif +#ifdef TARGET_NR_pread64 + case TARGET_NR_pread64: + if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) + goto efault; + ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5))); + unlock_user(p, arg2, ret); + break; + case TARGET_NR_pwrite64: + if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) + goto efault; + ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5))); + unlock_user(p, arg2, 0); + break; +#endif case TARGET_NR_getcwd: if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0))) goto efault; @@ -4897,7 +5313,8 @@ #endif #ifdef TARGET_NR_vfork case TARGET_NR_vfork: - ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0)); + ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, + 0, 0, 0, 0)); break; #endif #ifdef TARGET_NR_ugetrlimit @@ -4935,7 +5352,9 @@ goto efault; ret = get_errno(stat(path(p), &st)); unlock_user(p, arg1, 0); - goto do_stat64; + if (!is_error(ret)) + ret = host_to_target_stat64(cpu_env, arg2, &st); + break; #endif #ifdef TARGET_NR_lstat64 case TARGET_NR_lstat64: @@ -4943,67 +5362,24 @@ goto efault; ret = get_errno(lstat(path(p), &st)); unlock_user(p, arg1, 0); - goto do_stat64; + if (!is_error(ret)) + ret = host_to_target_stat64(cpu_env, arg2, &st); + break; #endif #ifdef TARGET_NR_fstat64 case TARGET_NR_fstat64: - { - ret = get_errno(fstat(arg1, &st)); - do_stat64: - if (!is_error(ret)) { -#ifdef TARGET_ARM - if (((CPUARMState *)cpu_env)->eabi) { - struct target_eabi_stat64 *target_st; - - if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0)) - goto efault; - memset(target_st, 0, sizeof(struct target_eabi_stat64)); - __put_user(st.st_dev, &target_st->st_dev); - __put_user(st.st_ino, &target_st->st_ino); -#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO - __put_user(st.st_ino, &target_st->__st_ino); -#endif - __put_user(st.st_mode, &target_st->st_mode); - __put_user(st.st_nlink, &target_st->st_nlink); - __put_user(st.st_uid, &target_st->st_uid); - __put_user(st.st_gid, &target_st->st_gid); - __put_user(st.st_rdev, &target_st->st_rdev); - __put_user(st.st_size, &target_st->st_size); - __put_user(st.st_blksize, &target_st->st_blksize); - __put_user(st.st_blocks, &target_st->st_blocks); - __put_user(st.st_atime, &target_st->target_st_atime); - __put_user(st.st_mtime, &target_st->target_st_mtime); - __put_user(st.st_ctime, &target_st->target_st_ctime); - unlock_user_struct(target_st, arg2, 1); - } else -#endif - { - struct target_stat64 *target_st; - - if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0)) - goto efault; - memset(target_st, 0, sizeof(struct target_stat64)); - __put_user(st.st_dev, &target_st->st_dev); - __put_user(st.st_ino, &target_st->st_ino); -#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO - __put_user(st.st_ino, &target_st->__st_ino); + ret = get_errno(fstat(arg1, &st)); + if (!is_error(ret)) + ret = host_to_target_stat64(cpu_env, arg2, &st); + break; #endif - __put_user(st.st_mode, &target_st->st_mode); - __put_user(st.st_nlink, &target_st->st_nlink); - __put_user(st.st_uid, &target_st->st_uid); - __put_user(st.st_gid, &target_st->st_gid); - __put_user(st.st_rdev, &target_st->st_rdev); - /* XXX: better use of kernel struct */ - __put_user(st.st_size, &target_st->st_size); - __put_user(st.st_blksize, &target_st->st_blksize); - __put_user(st.st_blocks, &target_st->st_blocks); - __put_user(st.st_atime, &target_st->target_st_atime); - __put_user(st.st_mtime, &target_st->target_st_mtime); - __put_user(st.st_ctime, &target_st->target_st_ctime); - unlock_user_struct(target_st, arg2, 1); - } - } - } +#if defined(TARGET_NR_fstatat64) && defined(__NR_fstatat64) + case TARGET_NR_fstatat64: + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4)); + if (!is_error(ret)) + ret = host_to_target_stat64(cpu_env, arg3, &st); break; #endif #ifdef USE_UID16 @@ -5040,11 +5416,13 @@ grouplist = alloca(gidsetsize * sizeof(gid_t)); ret = get_errno(getgroups(gidsetsize, grouplist)); + if (gidsetsize == 0) + break; if (!is_error(ret)) { target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0); if (!target_grouplist) goto efault; - for(i = 0;i < gidsetsize; i++) + for(i = 0;i < ret; i++) target_grouplist[i] = tswap16(grouplist[i]); unlock_user(target_grouplist, arg2, gidsetsize * 2); } @@ -5190,13 +5568,15 @@ grouplist = alloca(gidsetsize * sizeof(gid_t)); ret = get_errno(getgroups(gidsetsize, grouplist)); + if (gidsetsize == 0) + break; if (!is_error(ret)) { target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0); if (!target_grouplist) { ret = -TARGET_EFAULT; goto fail; } - for(i = 0;i < gidsetsize; i++) + for(i = 0;i < ret; i++) target_grouplist[i] = tswap32(grouplist[i]); unlock_user(target_grouplist, arg2, gidsetsize * 4); } @@ -5300,7 +5680,40 @@ goto unimplemented; #ifdef TARGET_NR_mincore case TARGET_NR_mincore: - goto unimplemented; + { + void *a; + ret = -TARGET_EFAULT; + if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0))) + goto efault; + if (!(p = lock_user_string(arg3))) + goto mincore_fail; + ret = get_errno(mincore(a, arg2, p)); + unlock_user(p, arg3, ret); + mincore_fail: + unlock_user(a, arg1, 0); + } + break; +#endif +#ifdef TARGET_NR_arm_fadvise64_64 + case TARGET_NR_arm_fadvise64_64: + { + /* + * arm_fadvise64_64 looks like fadvise64_64 but + * with different argument order + */ + abi_long temp; + temp = arg3; + arg3 = arg4; + arg4 = temp; + } +#endif +#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) +#ifdef TARGET_NR_fadvise64_64 + case TARGET_NR_fadvise64_64: +#endif + /* This is a hint, so ignoring and returning success is ok. */ + ret = get_errno(0); + break; #endif #ifdef TARGET_NR_madvise case TARGET_NR_madvise: @@ -5440,7 +5853,20 @@ break; #ifdef TARGET_NR_readahead case TARGET_NR_readahead: - goto unimplemented; +#if TARGET_ABI_BITS == 32 +#ifdef TARGET_ARM + if (((CPUARMState *)cpu_env)->eabi) + { + arg2 = arg3; + arg3 = arg4; + arg4 = arg5; + } +#endif + ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4)); +#else + ret = get_errno(readahead(arg1, arg2, arg3)); +#endif + break; #endif #ifdef TARGET_NR_setxattr case TARGET_NR_setxattr: @@ -5505,6 +5931,17 @@ break; } #endif +#ifdef TARGET_NR_clock_nanosleep + case TARGET_NR_clock_nanosleep: + { + struct timespec ts; + target_to_host_timespec(&ts, arg3); + ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL)); + if (arg4) + host_to_target_timespec(arg4, &ts); + break; + } +#endif #if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address) case TARGET_NR_set_tid_address: @@ -5514,13 +5951,14 @@ #if defined(TARGET_NR_tkill) && defined(__NR_tkill) case TARGET_NR_tkill: - ret = get_errno(sys_tkill((int)arg1, (int)arg2)); + ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2))); break; #endif #if defined(TARGET_NR_tgkill) && defined(__NR_tgkill) case TARGET_NR_tgkill: - ret = get_errno(sys_tgkill((int)arg1, (int)arg2, (int)arg3)); + ret = get_errno(sys_tgkill((int)arg1, (int)arg2, + target_to_host_signal(arg3))); break; #endif @@ -5548,6 +5986,28 @@ } break; #endif +#if defined(USE_NPTL) + case TARGET_NR_futex: + ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_inotify_init + case TARGET_NR_inotify_init: + ret = get_errno(sys_inotify_init()); + break; +#endif +#ifdef TARGET_NR_inotify_add_watch + case TARGET_NR_inotify_add_watch: + p = lock_user_string(arg2); + ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3)); + unlock_user(p, arg2, 0); + break; +#endif +#ifdef TARGET_NR_inotify_rm_watch + case TARGET_NR_inotify_rm_watch: + ret = get_errno(sys_inotify_rm_watch(arg1, arg2)); + break; +#endif default: unimplemented: diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/syscall_defs.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/syscall_defs.h --- qemu-0.9.1/linux-user/syscall_defs.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/syscall_defs.h 2008-11-12 10:01:12.000000000 +0000 @@ -49,7 +49,7 @@ #define TARGET_IOC_TYPEBITS 8 #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) \ - || defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) + || defined(TARGET_M68K) || defined(TARGET_CRIS) #define TARGET_IOC_SIZEBITS 14 #define TARGET_IOC_DIRBITS 2 @@ -830,6 +830,14 @@ #define TARGET_HDIO_SET_DMA 0x0326 /* change use-dma flag */ #define TARGET_HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */ +/* loop ioctls */ +#define TARGET_LOOP_SET_FD 0x4C00 +#define TARGET_LOOP_CLR_FD 0x4C01 +#define TARGET_LOOP_SET_STATUS 0x4C02 +#define TARGET_LOOP_GET_STATUS 0x4C03 +#define TARGET_LOOP_SET_STATUS64 0x4C04 +#define TARGET_LOOP_GET_STATUS64 0x4C05 +#define TARGET_LOOP_CHANGE_FD 0x4C06 /* from asm/termbits.h */ @@ -852,11 +860,14 @@ #include "termbits.h" +/* Common */ #define TARGET_MAP_SHARED 0x01 /* Share changes */ #define TARGET_MAP_PRIVATE 0x02 /* Changes are private */ -#define TARGET_MAP_TYPE 0x0f /* Mask for type of mapping */ -#define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */ +#define TARGET_MAP_TYPE 0x0f /* Mask for type of mapping */ + +/* Target specific */ #if defined(TARGET_MIPS) +#define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */ #define TARGET_MAP_ANONYMOUS 0x0800 /* don't use a file */ #define TARGET_MAP_GROWSDOWN 0x1000 /* stack-like segment */ #define TARGET_MAP_DENYWRITE 0x2000 /* ETXTBSY */ @@ -865,18 +876,34 @@ #define TARGET_MAP_NORESERVE 0x0400 /* don't check for reservations */ #define TARGET_MAP_POPULATE 0x10000 /* populate (prefault) pagetables */ #define TARGET_MAP_NONBLOCK 0x20000 /* do not block on IO */ -#else +#elif defined(TARGET_PPC) +#define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */ #define TARGET_MAP_ANONYMOUS 0x20 /* don't use a file */ #define TARGET_MAP_GROWSDOWN 0x0100 /* stack-like segment */ #define TARGET_MAP_DENYWRITE 0x0800 /* ETXTBSY */ #define TARGET_MAP_EXECUTABLE 0x1000 /* mark it as an executable */ -#if defined(TARGET_PPC) #define TARGET_MAP_LOCKED 0x0080 /* pages are locked */ #define TARGET_MAP_NORESERVE 0x0040 /* don't check for reservations */ +#define TARGET_MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ +#define TARGET_MAP_NONBLOCK 0x10000 /* do not block on IO */ +#elif defined(TARGET_ALPHA) +#define TARGET_MAP_ANONYMOUS 0x10 /* don't use a file */ +#define TARGET_MAP_FIXED 0x100 /* Interpret addr exactly */ +#define TARGET_MAP_GROWSDOWN 0x01000 /* stack-like segment */ +#define TARGET_MAP_DENYWRITE 0x02000 /* ETXTBSY */ +#define TARGET_MAP_EXECUTABLE 0x04000 /* mark it as an executable */ +#define TARGET_MAP_LOCKED 0x08000 /* lock the mapping */ +#define TARGET_MAP_NORESERVE 0x10000 /* no check for reservations */ +#define TARGET_MAP_POPULATE 0x20000 /* pop (prefault) pagetables */ +#define TARGET_MAP_NONBLOCK 0x40000 /* do not block on IO */ #else +#define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */ +#define TARGET_MAP_ANONYMOUS 0x20 /* don't use a file */ +#define TARGET_MAP_GROWSDOWN 0x0100 /* stack-like segment */ +#define TARGET_MAP_DENYWRITE 0x0800 /* ETXTBSY */ +#define TARGET_MAP_EXECUTABLE 0x1000 /* mark it as an executable */ #define TARGET_MAP_LOCKED 0x2000 /* pages are locked */ #define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */ -#endif #define TARGET_MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ #define TARGET_MAP_NONBLOCK 0x10000 /* do not block on IO */ #endif @@ -1562,7 +1589,8 @@ uint32_t f_namelen; uint32_t f_spare[6]; }; -#elif defined(TARGET_PPC64) && !defined(TARGET_ABI32) +#elif (defined(TARGET_PPC64) || defined(TARGET_X86_64) || \ + defined(TARGET_SPARC64)) && !defined(TARGET_ABI32) struct target_statfs { abi_long f_type; abi_long f_bsize; @@ -1721,6 +1749,25 @@ #define TARGET_O_NOFOLLOW 0x20000 /* don't follow links */ #define TARGET_O_NOATIME 0x40000 #define TARGET_O_NDELAY TARGET_O_NONBLOCK +#elif defined(TARGET_ALPHA) +#define TARGET_O_ACCMODE 0x0003 +#define TARGET_O_RDONLY 0x0000 +#define TARGET_O_WRONLY 0x0001 +#define TARGET_O_RDWR 0x0002 +#define TARGET_O_APPEND 0x0008 +#define TARGET_O_SYNC 0x4000 +#define TARGET_O_NONBLOCK 0x0004 +#define TARGET_O_CREAT 0x0200 /* not fcntl */ +#define TARGET_O_TRUNC 0x0400 /* not fcntl */ +#define TARGET_O_EXCL 0x0800 /* not fcntl */ +#define TARGET_O_NOCTTY 0x1000 /* not fcntl */ +#define TARGET_FASYNC 0x2000 /* fcntl, for BSD compatibility */ +#define TARGET_O_LARGEFILE 0x0000 /* not necessary, always 64-bit */ +#define TARGET_O_DIRECT 0x80000 /* direct disk access hint */ +#define TARGET_O_DIRECTORY 0x8000 /* must be a directory */ +#define TARGET_O_NOFOLLOW 0x10000 /* don't follow links */ +#define TARGET_O_NOATIME 0x100000 +#define TARGET_O_NDELAY TARGET_O_NONBLOCK #else #define TARGET_O_ACCMODE 0003 #define TARGET_O_RDONLY 00 @@ -1752,6 +1799,9 @@ struct target_flock64 { short l_type; short l_whence; +#if defined(TARGET_PPC) || defined(TARGET_X86_64) || defined(TARGET_MIPS) || defined(TARGET_SPARC) || defined(TARGET_HPPA) + int __pad; +#endif unsigned long long l_start; unsigned long long l_len; int l_pid; @@ -1911,6 +1961,10 @@ #define TARGET_VFAT_IOCTL_READDIR_BOTH TARGET_IORU('r', 1) #define TARGET_VFAT_IOCTL_READDIR_SHORT TARGET_IORU('r', 2) +#define TARGET_MTIOCTOP TARGET_IOW('m', 1, struct mtop) +#define TARGET_MTIOCGET TARGET_IOR('m', 2, struct mtget) +#define TARGET_MTIOCPOS TARGET_IOR('m', 3, struct mtpos) + struct target_sysinfo { abi_long uptime; /* Seconds since boot */ abi_ulong loads[3]; /* 1, 5, and 15 minute load averages */ @@ -1928,6 +1982,21 @@ char _f[20-2*sizeof(abi_long)-sizeof(int)]; /* Padding: libc5 uses this.. */ }; +struct linux_dirent { + long d_ino; + unsigned long d_off; + unsigned short d_reclen; + char d_name[256]; /* We must not include limits.h! */ +}; + +struct linux_dirent64 { + uint64_t d_ino; + int64_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[256]; +}; + #include "socket.h" #include "errno_defs.h" diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/syscall_types.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/syscall_types.h --- qemu-0.9.1/linux-user/syscall_types.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/syscall_types.h 2008-09-20 04:03:09.000000000 +0100 @@ -79,3 +79,38 @@ STRUCT(mixer_info, MK_ARRAY(TYPE_CHAR, 16), MK_ARRAY(TYPE_CHAR, 32), TYPE_INT, MK_ARRAY(TYPE_INT, 10)) + +/* loop device ioctls */ +STRUCT(loop_info, + TYPE_INT, /* lo_number */ + TYPE_SHORT, /* lo_device */ + TYPE_ULONG, /* lo_inode */ + TYPE_SHORT, /* lo_rdevice */ + TYPE_INT, /* lo_offset */ + TYPE_INT, /* lo_encrypt_type */ + TYPE_INT, /* lo_encrypt_key_size */ + TYPE_INT, /* lo_flags */ + MK_ARRAY(TYPE_CHAR, 64), /* lo_name */ + MK_ARRAY(TYPE_CHAR, 32), /* lo_encrypt_key */ + MK_ARRAY(TYPE_ULONG, 2), /* lo_init */ + MK_ARRAY(TYPE_CHAR, 4)) /* reserved */ + +STRUCT(loop_info64, + TYPE_ULONGLONG, /* lo_device */ + TYPE_ULONGLONG, /* lo_inode */ + TYPE_ULONGLONG, /* lo_rdevice */ + TYPE_ULONGLONG, /* lo_offset */ + TYPE_ULONG, /* lo_number */ + TYPE_ULONG, /* lo_encrypt_type */ + TYPE_ULONG, /* lo_encrypt_key_size */ + TYPE_ULONG, /* lo_flags */ + MK_ARRAY(TYPE_CHAR, 64), /* lo_name */ + MK_ARRAY(TYPE_CHAR, 64), /* lo_crypt_name */ + MK_ARRAY(TYPE_CHAR, 32), /* lo_encrypt_key */ + MK_ARRAY(TYPE_ULONGLONG, 2)) /* lo_init */ + +/* mag tape ioctls */ +STRUCT(mtop, TYPE_SHORT, TYPE_INT) +STRUCT(mtget, TYPE_LONG, TYPE_LONG, TYPE_LONG, TYPE_LONG, TYPE_LONG, + TYPE_INT, TYPE_INT) +STRUCT(mtpos, TYPE_LONG) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/linux-user/uaccess.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/linux-user/uaccess.c --- qemu-0.9.1/linux-user/uaccess.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/linux-user/uaccess.c 2008-09-20 09:07:15.000000000 +0100 @@ -62,7 +62,7 @@ ptr = lock_user(VERIFY_READ, guest_addr, max_len, 1); if (!ptr) return -TARGET_EFAULT; - len = qemu_strnlen(ptr, max_len); + len = qemu_strnlen((const char *)ptr, max_len); unlock_user(ptr, guest_addr, 0); guest_addr += len; /* we don't allow wrapping or integer overflow */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/loader.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/loader.c --- qemu-0.9.1/loader.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/loader.c 2008-10-22 19:20:20.000000000 +0100 @@ -39,6 +39,7 @@ } /* return the size or -1 if error */ +/* deprecated, because caller does not specify buffer size! */ int load_image(const char *filename, uint8_t *addr) { int fd, size; @@ -55,6 +56,84 @@ return size; } +/* return the amount read, just like fread. 0 may mean error or eof */ +int fread_targphys(target_phys_addr_t dst_addr, size_t nbytes, FILE *f) +{ + uint8_t buf[4096]; + target_phys_addr_t dst_begin = dst_addr; + size_t want, did; + + while (nbytes) { + want = nbytes > sizeof(buf) ? sizeof(buf) : nbytes; + did = fread(buf, 1, want, f); + if (did != want) break; + + cpu_physical_memory_write_rom(dst_addr, buf, did); + dst_addr += did; + nbytes -= did; + } + return dst_addr - dst_begin; +} + +/* returns 0 on error, 1 if ok */ +int fread_targphys_ok(target_phys_addr_t dst_addr, size_t nbytes, FILE *f) +{ + return fread_targphys(dst_addr, nbytes, f) == nbytes; +} + +/* read()-like version */ +int read_targphys(int fd, target_phys_addr_t dst_addr, size_t nbytes) +{ + uint8_t buf[4096]; + target_phys_addr_t dst_begin = dst_addr; + size_t want, did; + + while (nbytes) { + want = nbytes > sizeof(buf) ? sizeof(buf) : nbytes; + did = read(fd, buf, want); + if (did != want) break; + + cpu_physical_memory_write_rom(dst_addr, buf, did); + dst_addr += did; + nbytes -= did; + } + return dst_addr - dst_begin; +} + +/* return the size or -1 if error */ +int load_image_targphys(const char *filename, + target_phys_addr_t addr, int max_sz) +{ + FILE *f; + size_t got; + + f = fopen(filename, "rb"); + if (!f) return -1; + + got = fread_targphys(addr, max_sz, f); + if (ferror(f)) { fclose(f); return -1; } + fclose(f); + + return got; +} + +void pstrcpy_targphys(target_phys_addr_t dest, int buf_size, + const char *source) +{ + static const uint8_t nul_byte = 0; + const char *nulp; + + if (buf_size <= 0) return; + nulp = memchr(source, 0, buf_size); + if (nulp) { + cpu_physical_memory_write_rom(dest, (uint8_t *)source, + (nulp - source) + 1); + } else { + cpu_physical_memory_write_rom(dest, (uint8_t *)source, buf_size - 1); + cpu_physical_memory_write_rom(dest, &nul_byte, 1); + } +} + /* A.OUT loader */ struct exec @@ -105,7 +184,7 @@ : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) -int load_aout(const char *filename, uint8_t *addr) +int load_aout(const char *filename, target_phys_addr_t addr, int max_sz) { int fd, size, ret; struct exec e; @@ -126,17 +205,21 @@ case ZMAGIC: case QMAGIC: case OMAGIC: + if (e.a_text + e.a_data > max_sz) + goto fail; lseek(fd, N_TXTOFF(e), SEEK_SET); - size = read(fd, addr, e.a_text + e.a_data); + size = read_targphys(fd, addr, e.a_text + e.a_data); if (size < 0) goto fail; break; case NMAGIC: + if (N_DATADDR(e) + e.a_data > max_sz) + goto fail; lseek(fd, N_TXTOFF(e), SEEK_SET); - size = read(fd, addr, e.a_text); + size = read_targphys(fd, addr, e.a_text); if (size < 0) goto fail; - ret = read(fd, addr + N_DATADDR(e), e.a_data); + ret = read_targphys(fd, addr + N_DATADDR(e), e.a_data); if (ret < 0) goto fail; size += ret; @@ -199,7 +282,7 @@ #include "elf_ops.h" /* return < 0 if error, otherwise the number of bytes loaded in memory */ -int load_elf(const char *filename, int64_t virt_to_phys_addend, +int load_elf(const char *filename, int64_t address_offset, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr) { int fd, data_order, host_data_order, must_swab, ret; @@ -234,10 +317,10 @@ lseek(fd, 0, SEEK_SET); if (e_ident[EI_CLASS] == ELFCLASS64) { - ret = load_elf64(fd, virt_to_phys_addend, must_swab, pentry, + ret = load_elf64(fd, address_offset, must_swab, pentry, lowaddr, highaddr); } else { - ret = load_elf32(fd, virt_to_phys_addend, must_swab, pentry, + ret = load_elf32(fd, address_offset, must_swab, pentry, lowaddr, highaddr); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/m68k-dis.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/m68k-dis.c --- qemu-0.9.1/m68k-dis.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/m68k-dis.c 2008-09-14 07:45:34.000000000 +0100 @@ -546,13 +546,13 @@ /* Local function prototypes. */ -const char * const fpcr_names[] = +static const char * const fpcr_names[] = { "", "%fpiar", "%fpsr", "%fpiar/%fpsr", "%fpcr", "%fpiar/%fpcr", "%fpsr/%fpcr", "%fpiar/%fpsr/%fpcr" }; -static char *const reg_names[] = +static const char *const reg_names[] = { "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp", @@ -561,7 +561,7 @@ /* Name of register halves for MAC/EMAC. Separate from reg_names since 'spu', 'fpl' look weird. */ -static char *const reg_half_names[] = +static const char *const reg_half_names[] = { "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7", @@ -991,7 +991,7 @@ disassemble_info *info) { int word; - static char *const scales[] = { "", ":2", ":4", ":8" }; + static const char *const scales[] = { "", ":2", ":4", ":8" }; bfd_vma base_disp; bfd_vma outer_disp; char buf[40]; @@ -1106,7 +1106,7 @@ { case 'c': /* Cache identifier. */ { - static char *const cacheFieldName[] = { "nc", "dc", "ic", "bc" }; + static const char *const cacheFieldName[] = { "nc", "dc", "ic", "bc" }; val = fetch_arg (buffer, place, 2, info); (*info->fprintf_func) (info->stream, cacheFieldName[val]); break; @@ -1157,7 +1157,7 @@ /* FIXME: There's a problem here, different m68k processors call the same address different names. This table can't get it right because it doesn't know which processor it's disassembling for. */ - static const struct { char *name; int value; } names[] + static const struct { const char *name; int value; } names[] = {{"%sfc", 0x000}, {"%dfc", 0x001}, {"%cacr", 0x002}, {"%tc", 0x003}, {"%itt0",0x004}, {"%itt1", 0x005}, {"%dtt0",0x006}, {"%dtt1",0x007}, {"%buscr",0x008}, @@ -1201,7 +1201,7 @@ case 'M': if (place == 'h') { - static char *const scalefactor_name[] = { "<<", ">>" }; + static const char *const scalefactor_name[] = { "<<", ">>" }; val = fetch_arg (buffer, place, 1, info); (*info->fprintf_func) (info->stream, scalefactor_name[val]); } @@ -1633,7 +1633,7 @@ case '3': { int val = fetch_arg (buffer, place, 5, info); - char *name = 0; + const char *name = 0; switch (val) { diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/MAINTAINERS /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/MAINTAINERS --- qemu-0.9.1/MAINTAINERS 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/MAINTAINERS 2008-08-25 23:26:03.000000000 +0100 @@ -0,0 +1,82 @@ +QEMU Maintainers +================ + +Project leaders: +---------------- + +Fabrice Bellard +Paul Brook + +CPU cores: +---------- + +x86 Fabrice Bellard +ARM Paul Brook +SPARC Blue Swirl +MIPS Thiemo Seufer +PowerPC ? +M68K Paul Brook +SH4 ? +CRIS Edgar E. Iglesias +Alpha ? + +Machines (sorted by CPU): +------------------------- + +x86 + pc.c Fabrice Bellard (new maintainer needed) +ARM + integratorcp.c Paul Brook + versatilepb.c Paul Brook + Real View Paul Brook + spitz.c Andrzej Zaborowski + palm.c Andrzej Zaborowski + nseries.c Andrzej Zaborowski + stellaris.c Paul Brook + gumstix.c Thorsten Zitterell + mainstone.c Armin Kuster + musicpal.c Jan Kiszka +SPARC + sun4u.c Blue Swirl + sun4m.c Blue Swirl +MIPS + mips_r4k.c Aurelien Jarno + mips_malta.c Aurelien Jarno + mips_jazz.c Hervé Poussineau + mips_mipssim.c Thiemo Seufer +PowerPC + ppc_prep.c ? + ppc_oldworld.c Fabrice Bellard + ppc_chrp.c Fabrice Bellard + ppc405_boards.c ? +M86K + mcf5208.c Paul Brook + an5206.c Paul Brook + dummy_m68k.c Paul Brook +SH4 + shix.c ? + r2d.c Magnus Damm +CRIS + etraxfs.c Edgar E. Iglesias +Alpha + +Generic Subsystems: +------------------- + +Dynamic translator Fabrice Bellard +Main loop Fabrice Bellard (new maintainer needed) +TCG Fabrice Bellard +kqemu interface Fabrice Bellard +IDE device ? +SCSI device Paul Brook +PCI layer ? +USB layer ? +Block layer ? +Graphic layer ? +Audio device layer Vassili Karpov (malc) +Character device layer ? +Network device layer ? +GDB stub ? +Linux user ? +Darwin user ? +SLIRP ? diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/Makefile /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/Makefile --- qemu-0.9.1/Makefile 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/Makefile 2008-11-11 21:33:36.000000000 +0000 @@ -2,66 +2,94 @@ include config-host.mak -.PHONY: all clean distclean dvi info install install-doc tar tarbin \ - speed test html dvi info +.PHONY: all clean cscope distclean dvi html info install install-doc \ + recurse-all speed tar tarbin test VPATH=$(SRC_PATH):$(SRC_PATH)/hw -BASE_CFLAGS= -BASE_LDFLAGS= +CFLAGS += $(OS_CFLAGS) $(ARCH_CFLAGS) +LDFLAGS += $(OS_LDFLAGS) $(ARCH_LDFLAGS) -BASE_CFLAGS += $(OS_CFLAGS) $(ARCH_CFLAGS) -BASE_LDFLAGS += $(OS_LDFLAGS) $(ARCH_LDFLAGS) - -CPPFLAGS += -I. -I$(SRC_PATH) -MMD -MP +CPPFLAGS += -I. -I$(SRC_PATH) -MMD -MP -MT $@ CPPFLAGS += -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE LIBS= ifdef CONFIG_STATIC -BASE_LDFLAGS += -static +LDFLAGS += -static endif ifdef BUILD_DOCS -DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 +DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 else DOCS= endif LIBS+=$(AIOLIBS) -all: $(TOOLS) $(DOCS) recurse-all +ifdef CONFIG_SOLARIS +LIBS+=-lsocket -lnsl -lresolv +endif + +ifdef CONFIG_WIN32 +LIBS+=-lwinmm -lws2_32 -liphlpapi +endif -subdir-%: dyngen$(EXESUF) libqemu_common.a +all: $(TOOLS) $(DOCS) recurse-all + +SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS)) + +subdir-%: dyngen$(EXESUF) $(MAKE) -C $(subst subdir-,,$@) all -recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS)) +$(filter %-softmmu,$(SUBDIR_RULES)): libqemu_common.a +$(filter %-user,$(SUBDIR_RULES)): libqemu_user.a + +recurse-all: $(SUBDIR_RULES) ####################################################################### # BLOCK_OBJS is code used by both qemu system emulation and qemu-img -BLOCK_OBJS=cutils.o +BLOCK_OBJS=cutils.o qemu-malloc.o BLOCK_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o BLOCK_OBJS+=block-dmg.o block-bochs.o block-vpc.o block-vvfat.o -BLOCK_OBJS+=block-qcow2.o block-parallels.o +BLOCK_OBJS+=block-qcow2.o block-parallels.o block-nbd.o +BLOCK_OBJS+=nbd.o block.o aio.o + +ifdef CONFIG_WIN32 +BLOCK_OBJS += block-raw-win32.o +else +BLOCK_OBJS += block-raw-posix.o +endif ###################################################################### -# libqemu_common.a: Target indepedent part of system emulation. The +# libqemu_common.a: Target independent part of system emulation. The # long term path is to suppress *all* target specific code in case of # system emulation, i.e. a single QEMU executable should support all # CPUs and machines. OBJS=$(BLOCK_OBJS) OBJS+=readline.o console.o -OBJS+=block.o OBJS+=irq.o OBJS+=i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o -OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o +OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o twl92230.o +OBJS+=tmp105.o lm832x.o OBJS+=scsi-disk.o cdrom.o OBJS+=scsi-generic.o OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o +OBJS+=usb-serial.o usb-net.o OBJS+=sd.o ssi-sd.o +OBJS+=bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o +OBJS+=buffered_file.o migration.o migration-tcp.o net.o qemu-sockets.o +OBJS+=qemu-char.o aio.o net-checksum.o savevm.o + +ifdef CONFIG_BRLAPI +OBJS+= baum.o +LIBS+=-lbrlapi +endif ifdef CONFIG_WIN32 OBJS+=tap-win32.o +else +OBJS+=migration-exec.o endif AUDIO_OBJS = audio.o noaudio.o wavaudio.o mixeng.o @@ -73,6 +101,7 @@ endif ifdef CONFIG_COREAUDIO AUDIO_OBJS += coreaudio.o +AUDIO_PT = yes endif ifdef CONFIG_ALSA AUDIO_OBJS += alsaaudio.o @@ -84,12 +113,31 @@ AUDIO_OBJS += fmodaudio.o audio/audio.o audio/fmodaudio.o: CPPFLAGS := -I$(CONFIG_FMOD_INC) $(CPPFLAGS) endif +ifdef CONFIG_ESD +AUDIO_PT = yes +AUDIO_PT_INT = yes +AUDIO_OBJS += esdaudio.o +endif +ifdef CONFIG_PA +AUDIO_PT = yes +AUDIO_PT_INT = yes +AUDIO_OBJS += paaudio.o +endif +ifdef AUDIO_PT +LDFLAGS += -pthread +endif +ifdef AUDIO_PT_INT +AUDIO_OBJS += audio_pt_int.o +endif AUDIO_OBJS+= wavcapture.o OBJS+=$(addprefix audio/, $(AUDIO_OBJS)) ifdef CONFIG_SDL OBJS+=sdl.o x_keymap.o endif +ifdef CONFIG_CURSES +OBJS+=curses.o +endif OBJS+=vnc.o d3des.o ifdef CONFIG_COCOA @@ -104,48 +152,58 @@ OBJS+=$(addprefix slirp/, $(SLIRP_OBJS)) endif +LIBS+=$(VDE_LIBS) + cocoa.o: cocoa.m - $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< sdl.o: sdl.c keymaps.c sdl_keysym.h - $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) -c -o $@ $< vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h d3des.c d3des.h - $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $(CONFIG_VNC_TLS_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS) $(CPPFLAGS) $(CONFIG_VNC_TLS_CFLAGS) -c -o $@ $< + +curses.o: curses.c keymaps.c curses_keys.h + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< + +bt-host.o: bt-host.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(CONFIG_BLUEZ_CFLAGS) -c -o $@ $< audio/sdlaudio.o: audio/sdlaudio.c - $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) -c -o $@ $< libqemu_common.a: $(OBJS) rm -f $@ $(AR) rcs $@ $(OBJS) -QEMU_IMG_BLOCK_OBJS = $(BLOCK_OBJS) -ifdef CONFIG_WIN32 -QEMU_IMG_BLOCK_OBJS += qemu-img-block-raw-win32.o -else -QEMU_IMG_BLOCK_OBJS += qemu-img-block-raw-posix.o -endif +####################################################################### +# USER_OBJS is code used by qemu userspace emulation +USER_OBJS=cutils.o -###################################################################### +libqemu_user.a: $(USER_OBJS) + rm -f $@ + $(AR) rcs $@ $(USER_OBJS) -qemu-img$(EXESUF): qemu-img.o qemu-img-block.o $(QEMU_IMG_BLOCK_OBJS) - $(CC) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^ -lz $(LIBS) +###################################################################### -qemu-img-%.o: %.c - $(CC) $(CFLAGS) $(CPPFLAGS) -DQEMU_IMG $(BASE_CFLAGS) -c -o $@ $< +qemu-img$(EXESUF): qemu-img.o qemu-tool.o osdep.o $(BLOCK_OBJS) + $(CC) $(LDFLAGS) -o $@ $^ -lz $(LIBS) %.o: %.c - $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< + +qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o osdep.o $(BLOCK_OBJS) + $(CC) $(LDFLAGS) -o $@ $^ -lz $(LIBS) # dyngen host tool dyngen$(EXESUF): dyngen.c - $(HOST_CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -o $@ $^ + $(HOST_CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^ clean: # avoid old build problems by removing potentially incorrect old files rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h rm -f *.o *.d *.a $(TOOLS) dyngen$(EXESUF) TAGS cscope.* *.pod *~ */*~ + rm -rf dyngen.dSYM rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d $(MAKE) -C tests clean for d in $(TARGET_DIRS); do \ @@ -169,6 +227,8 @@ ifndef CONFIG_WIN32 mkdir -p "$(DESTDIR)$(mandir)/man1" $(INSTALL) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1" + mkdir -p "$(DESTDIR)$(mandir)/man8" + $(INSTALL) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8" endif install: all $(if $(BUILD_DOCS),install-doc) @@ -177,14 +237,14 @@ $(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)" endif mkdir -p "$(DESTDIR)$(datadir)" - for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \ - video.x openbios-sparc32 pxe-ne2k_pci.bin \ - pxe-rtl8139.bin pxe-pcnet.bin; do \ + set -e; for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \ + video.x openbios-sparc32 openbios-sparc64 pxe-ne2k_pci.bin \ + pxe-rtl8139.bin pxe-pcnet.bin pxe-e1000.bin; do \ $(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \ done ifndef CONFIG_WIN32 mkdir -p "$(DESTDIR)$(datadir)/keymaps" - for x in $(KEYMAPS); do \ + set -e; for x in $(KEYMAPS); do \ $(INSTALL) -m 644 $(SRC_PATH)/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \ done endif @@ -201,7 +261,7 @@ cscope: rm -f ./cscope.* - find . -name "*.[ch]" -print > ./cscope.files + find . -name "*.[ch]" -print | sed 's,^\./,,' > ./cscope.files cscope -b # documentation @@ -222,12 +282,18 @@ $(SRC_PATH)/texi2pod.pl $< qemu-img.pod pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@ +qemu-nbd.8: qemu-nbd.texi + $(SRC_PATH)/texi2pod.pl $< qemu-nbd.pod + pod2man --section=8 --center=" " --release=" " qemu-nbd.pod > $@ + info: qemu-doc.info qemu-tech.info dvi: qemu-doc.dvi qemu-tech.dvi html: qemu-doc.html qemu-tech.html +qemu-doc.dvi qemu-doc.html qemu-doc.info: qemu-img.texi qemu-nbd.texi + VERSION ?= $(shell cat VERSION) FILE = qemu-$(VERSION) @@ -235,12 +301,12 @@ tar: rm -rf /tmp/$(FILE) cp -r . /tmp/$(FILE) - ( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS ) + cd /tmp && tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS --exclude .git --exclude .svn rm -rf /tmp/$(FILE) # generate a binary distribution tarbin: - ( cd / ; tar zcvf ~/qemu-$(VERSION)-$(ARCH).tar.gz \ + cd / && tar zcvf ~/qemu-$(VERSION)-$(ARCH).tar.gz \ $(bindir)/qemu \ $(bindir)/qemu-system-ppc \ $(bindir)/qemu-system-ppc64 \ @@ -274,22 +340,22 @@ $(bindir)/qemu-sh4eb \ $(bindir)/qemu-cris \ $(bindir)/qemu-img \ + $(bindir)/qemu-nbd \ $(datadir)/bios.bin \ $(datadir)/vgabios.bin \ $(datadir)/vgabios-cirrus.bin \ $(datadir)/ppc_rom.bin \ $(datadir)/video.x \ $(datadir)/openbios-sparc32 \ + $(datadir)/openbios-sparc64 \ $(datadir)/pxe-ne2k_pci.bin \ $(datadir)/pxe-rtl8139.bin \ $(datadir)/pxe-pcnet.bin \ + $(datadir)/pxe-e1000.bin \ $(docdir)/qemu-doc.html \ $(docdir)/qemu-tech.html \ - $(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 ) - -ifneq ($(wildcard .depend),) -include .depend -endif + $(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 + $(mandir)/man8/qemu-nbd.8 # Include automatically generated dependency files -include $(wildcard *.d audio/*.d slirp/*.d) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/Makefile.target /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/Makefile.target --- qemu-0.9.1/Makefile.target 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/Makefile.target 2008-11-11 21:20:14.000000000 +0000 @@ -24,23 +24,9 @@ endif TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH) VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw -CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) -MMD -MP -DNEED_CPU_H -ifdef CONFIG_DARWIN_USER -VPATH+=:$(SRC_PATH)/darwin-user -CPPFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH) -endif -ifdef CONFIG_LINUX_USER -VPATH+=:$(SRC_PATH)/linux-user -ifndef TARGET_ABI_DIR - TARGET_ABI_DIR=$(TARGET_ARCH) -endif -CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) -endif -BASE_CFLAGS= -BASE_LDFLAGS= +CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) -MMD -MT $@ -MP -DNEED_CPU_H #CFLAGS+=-Werror LIBS= -HELPER_CFLAGS=$(CFLAGS) DYNGEN=../dyngen$(EXESUF) # user emulator name ifndef TARGET_ARCH2 @@ -71,33 +57,24 @@ TARGET_ARCH2=mips64el endif endif -QEMU_USER=qemu-$(TARGET_ARCH2) + +ifdef CONFIG_USER_ONLY +# user emulator name +QEMU_PROG=qemu-$(TARGET_ARCH2) +else # system emulator name -ifdef CONFIG_SOFTMMU ifeq ($(TARGET_ARCH), i386) -QEMU_SYSTEM=qemu$(EXESUF) +QEMU_PROG=qemu$(EXESUF) else -QEMU_SYSTEM=qemu-system-$(TARGET_ARCH2)$(EXESUF) +QEMU_PROG=qemu-system-$(TARGET_ARCH2)$(EXESUF) endif -else -QEMU_SYSTEM=qemu-fast endif -ifdef CONFIG_USER_ONLY -PROGS=$(QEMU_USER) -else -PROGS+=$(QEMU_SYSTEM) -ifndef CONFIG_SOFTMMU -CONFIG_STATIC=y -endif -endif # !CONFIG_USER_ONLY - -ifdef CONFIG_STATIC -BASE_LDFLAGS+=-static -endif +PROGS=$(QEMU_PROG) # We require -O2 to avoid the stack setup prologue in EXIT_TB -OP_CFLAGS := -Wall -O2 -g -fno-strict-aliasing +OP_CFLAGS := -O2 -g -fno-strict-aliasing +OP_CFLAGS += -Wall -Wundef -Wendif-labels -Wwrite-strings # cc-option # Usage: OP_CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0) @@ -115,61 +92,42 @@ OP_CFLAGS+=$(call cc-option, -fno-align-functions, $(call cc-option, -malign-functions=0, "")) OP_CFLAGS+=$(call cc-option, -fno-section-anchors, "") +HELPER_CFLAGS= + ifeq ($(ARCH),i386) HELPER_CFLAGS+=-fomit-frame-pointer OP_CFLAGS+=-mpreferred-stack-boundary=2 -fomit-frame-pointer -ifdef TARGET_GPROF -USE_I386_LD=y -endif -ifdef CONFIG_STATIC -USE_I386_LD=y -endif -ifdef USE_I386_LD -BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -else -ifdef CONFIG_LINUX_USER -# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object -# that the kernel ELF loader considers as an executable. I think this -# is the simplest way to make it self virtualizable! -BASE_LDFLAGS+=-Wl,-shared -endif +# op.c and helper.c need this on 32-bit x86 system to avoid +# a compiler spill error. This can probably go away +# once the SSE ops have been converted to TCG +ifeq ($(HAVE_GT_GCC_3_3), true) +I386_CFLAGS=-march=i586 -mtune=i686 endif endif -ifeq ($(ARCH),x86_64) - ifneq ($(CONFIG_SOLARIS),yes) - BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld - endif -endif - ifeq ($(ARCH),ppc) CPPFLAGS+= -D__powerpc__ -BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -endif - -ifeq ($(ARCH),s390) -BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +OP_CFLAGS+= -mlongcall endif ifeq ($(ARCH),sparc) - BASE_CFLAGS+=-ffixed-g2 -ffixed-g3 + CFLAGS+=-ffixed-g2 -ffixed-g3 OP_CFLAGS+=-fno-delayed-branch -ffixed-i0 ifeq ($(CONFIG_SOLARIS),yes) OP_CFLAGS+=-fno-omit-frame-pointer else - BASE_CFLAGS+=-ffixed-g1 -ffixed-g6 - HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 - # -static is used to avoid g1/g3 usage by the dynamic linker - BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static + CFLAGS+=-ffixed-g1 -ffixed-g6 + HELPER_CFLAGS+=-ffixed-i0 endif endif ifeq ($(ARCH),sparc64) - BASE_CFLAGS+=-ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7 OP_CFLAGS+=-mcpu=ultrasparc -m64 -fno-delayed-branch -ffixed-i0 ifneq ($(CONFIG_SOLARIS),yes) - BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld - OP_CFLAGS+=-ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7 + CFLAGS+=-ffixed-g5 -ffixed-g6 -ffixed-g7 + OP_CFLAGS+=-ffixed-g5 -ffixed-g6 -ffixed-g7 + else + CFLAGS+=-ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7 endif endif @@ -177,65 +135,41 @@ # -msmall-data is not used for OP_CFLAGS because we want two-instruction # relocations for the constant constructions # Ensure there's only a single GP -BASE_CFLAGS+=-msmall-data +CFLAGS+=-msmall-data +endif + +ifeq ($(ARCH),hppa) +OP_CFLAGS=-O1 -fno-delayed-branch BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld endif ifeq ($(ARCH),ia64) -BASE_CFLAGS+=-mno-sdata +CFLAGS+=-mno-sdata OP_CFLAGS+=-mno-sdata -BASE_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/$(ARCH).ld endif ifeq ($(ARCH),arm) OP_CFLAGS+=-mno-sched-prolog -fno-omit-frame-pointer -BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld endif ifeq ($(ARCH),m68k) OP_CFLAGS+=-fomit-frame-pointer -BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld endif ifeq ($(ARCH),mips) OP_CFLAGS+=-mabi=32 -G0 -fno-PIC -mno-abicalls -fomit-frame-pointer -fno-delayed-branch -Wa,-O0 -ifeq ($(WORDS_BIGENDIAN),yes) -BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -else -BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld -endif endif ifeq ($(ARCH),mips64) OP_CFLAGS+=-mabi=n32 -G0 -fno-PIC -mno-abicalls -fomit-frame-pointer -fno-delayed-branch -Wa,-O0 -ifeq ($(WORDS_BIGENDIAN),yes) -BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -else -BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld -endif -endif - -ifeq ($(CONFIG_DARWIN),yes) -LIBS+=-lmx endif -ifdef CONFIG_DARWIN_USER -# Leave some space for the regular program loading zone -BASE_LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000 -endif - -BASE_CFLAGS+=$(OS_CFLAGS) $(ARCH_CFLAGS) -BASE_LDFLAGS+=$(OS_LDFLAGS) $(ARCH_LDFLAGS) +CFLAGS+=$(OS_CFLAGS) $(ARCH_CFLAGS) +LDFLAGS+=$(OS_LDFLAGS) $(ARCH_LDFLAGS) OP_CFLAGS+=$(OS_CFLAGS) $(ARCH_CFLAGS) -OP_LDFLAGS+=$(OS_LDFLAGS) $(ARCH_LDFLAGS) - -######################################################### CPPFLAGS+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE LIBS+=-lm -ifndef CONFIG_USER_ONLY -LIBS+=-lz -endif ifdef CONFIG_WIN32 LIBS+=-lwinmm -lws2_32 -liphlpapi endif @@ -245,96 +179,46 @@ LIBS+=-lsunmath LDFLAGS+=-L/opt/SUNWspro/prod/lib -R/opt/SUNWspro/prod/lib OP_CFLAGS+=-I/opt/SUNWspro/prod/include/cc -BASE_CFLAGS+=-I/opt/SUNWspro/prod/include/cc -endif -endif - -# profiling code -ifdef TARGET_GPROF -BASE_LDFLAGS+=-p -main.o: BASE_CFLAGS+=-p -endif - -ifdef CONFIG_LINUX_USER -OBJS= main.o syscall.o strace.o mmap.o signal.o path.o osdep.o thunk.o \ - elfload.o linuxload.o uaccess.o -LIBS+= $(AIOLIBS) -ifdef TARGET_HAS_BFLT -OBJS+= flatload.o +CFLAGS+=-I/opt/SUNWspro/prod/include/cc endif -ifdef TARGET_HAS_ELFLOAD32 -OBJS+= elfload32.o -elfload32.o: elfload.c endif -ifeq ($(TARGET_ARCH), i386) -OBJS+= vm86.o -endif -ifeq ($(TARGET_ARCH), arm) -OBJS+=nwfpe/fpa11.o nwfpe/fpa11_cpdo.o \ -nwfpe/fpa11_cpdt.o nwfpe/fpa11_cprt.o nwfpe/fpopcode.o nwfpe/single_cpdo.o \ - nwfpe/double_cpdo.o nwfpe/extended_cpdo.o arm-semi.o -endif -ifeq ($(TARGET_ARCH), m68k) -OBJS+= m68k-sim.o m68k-semi.o -endif -endif #CONFIG_LINUX_USER - -ifdef CONFIG_DARWIN_USER -OBJS= main.o commpage.o machload.o mmap.o osdep.o signal.o syscall.o thunk.o -endif +kvm.o: CFLAGS+=$(KVM_CFLAGS) +kvm-all.o: CFLAGS+=$(KVM_CFLAGS) -SRCS:= $(OBJS:.o=.c) -OBJS+= libqemu.a +all: $(PROGS) +######################################################### # cpu emulator library -LIBOBJS=exec.o kqemu.o translate-op.o translate-all.o cpu-exec.o\ - translate.o op.o host-utils.o +LIBOBJS=exec.o kqemu.o translate-all.o cpu-exec.o\ + translate.o host-utils.o +ifdef CONFIG_DYNGEN_OP +exec.o: dyngen-opc.h +LIBOBJS+=op.o +endif +# TCG code generator +LIBOBJS+= tcg/tcg.o tcg/tcg-dyngen.o tcg/tcg-runtime.o +CPPFLAGS+=-I$(SRC_PATH)/tcg -I$(SRC_PATH)/tcg/$(ARCH) +ifeq ($(ARCH),sparc64) +CPPFLAGS+=-I$(SRC_PATH)/tcg/sparc +endif ifdef CONFIG_SOFTFLOAT LIBOBJS+=fpu/softfloat.o else LIBOBJS+=fpu/softfloat-native.o endif CPPFLAGS+=-I$(SRC_PATH)/fpu - -ifeq ($(TARGET_ARCH), i386) -LIBOBJS+=helper.o helper2.o -endif - -ifeq ($(TARGET_ARCH), x86_64) -LIBOBJS+=helper.o helper2.o -endif - -ifeq ($(TARGET_BASE_ARCH), ppc) -LIBOBJS+= op_helper.o helper.o -endif - -ifeq ($(TARGET_BASE_ARCH), mips) LIBOBJS+= op_helper.o helper.o -endif - -ifeq ($(TARGET_BASE_ARCH), sparc) -LIBOBJS+= op_helper.o helper.o -endif ifeq ($(TARGET_BASE_ARCH), arm) -LIBOBJS+= op_helper.o helper.o -endif - -ifeq ($(TARGET_BASE_ARCH), sh4) -LIBOBJS+= op_helper.o helper.o -endif - -ifeq ($(TARGET_BASE_ARCH), m68k) -LIBOBJS+= op_helper.o helper.o +LIBOBJS+= neon_helper.o iwmmxt_helper.o endif ifeq ($(TARGET_BASE_ARCH), alpha) -LIBOBJS+= op_helper.o helper.o alpha_palcode.o +LIBOBJS+= alpha_palcode.o endif ifeq ($(TARGET_BASE_ARCH), cris) -LIBOBJS+= op_helper.o helper.o LIBOBJS+= cris-dis.o ifndef CONFIG_USER_ONLY @@ -374,146 +258,492 @@ ifeq ($(findstring sh4, $(TARGET_ARCH) $(ARCH)),sh4) LIBOBJS+=sh4-dis.o endif +ifeq ($(findstring hppa, $(TARGET_BASE_ARCH) $(ARCH)),hppa) +LIBOBJS+=hppa-dis.o +endif ifeq ($(findstring s390, $(TARGET_ARCH) $(ARCH)),s390) LIBOBJS+=s390-dis.o endif +# libqemu + +ifdef CONFIG_DYNGEN_OP +OPC_H = gen-op.h dyngen-opc.h op.h +endif + +libqemu.a: $(LIBOBJS) + rm -f $@ + $(AR) rcs $@ $(LIBOBJS) + +translate.o: translate.c cpu.h $(OPC_H) + +translate-all.o: translate-all.c cpu.h $(OPC_H) + +tcg/tcg.o: cpu.h $(OPC_H) + +tcg/tcg-dyngen.o: $(OPC_H) + +tcg/tcg-runtime.o: $(OPC_H) + +op.h: op.o $(DYNGEN) + $(DYNGEN) -o $@ $< + +dyngen-opc.h: op.o $(DYNGEN) + $(DYNGEN) -c -o $@ $< + +gen-op.h: op.o $(DYNGEN) + $(DYNGEN) -g -o $@ $< + +op.o: op.c + $(CC) $(OP_CFLAGS) $(CPPFLAGS) $(I386_CFLAGS) -c -o $@ $< + +machine.o: machine.c + $(CC) $(OP_CFLAGS) $(CPPFLAGS) -c -o $@ $< + +# HELPER_CFLAGS is used for all the code compiled with static register +# variables +op_helper.o: op_helper.c + $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(CFLAGS) $(I386_CFLAGS) -c -o $@ $< + +cpu-exec.o: cpu-exec.c $(OPC_H) + $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< + +######################################################### +# Linux user emulator target + +ifdef CONFIG_LINUX_USER + +ifndef TARGET_ABI_DIR + TARGET_ABI_DIR=$(TARGET_ARCH) +endif +VPATH+=:$(SRC_PATH)/linux-user:$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) +CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) + +ifdef CONFIG_STATIC +LDFLAGS+=-static +endif + +ifeq ($(ARCH),i386) +ifdef TARGET_GPROF +USE_I386_LD=y +endif +ifdef CONFIG_STATIC +USE_I386_LD=y +endif +ifdef USE_I386_LD +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +else +# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object +# that the kernel ELF loader considers as an executable. I think this +# is the simplest way to make it self virtualizable! +LDFLAGS+=-Wl,-shared +endif +endif + +ifeq ($(ARCH),x86_64) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +endif + +ifeq ($(ARCH),ppc) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +endif + +ifeq ($(ARCH),ppc64) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +endif + +ifeq ($(ARCH),s390) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +endif + +ifeq ($(ARCH),sparc) +# -static is used to avoid g1/g3 usage by the dynamic linker +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static +endif + +ifeq ($(ARCH),sparc64) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +endif + +ifeq ($(ARCH),alpha) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +endif + +ifeq ($(ARCH),ia64) +LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/$(ARCH).ld +endif + +ifeq ($(ARCH),arm) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +endif + +ifeq ($(ARCH),m68k) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +endif + +ifeq ($(ARCH),mips) +ifeq ($(WORDS_BIGENDIAN),yes) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +else +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld +endif +endif + +ifeq ($(ARCH),mips64) +ifeq ($(WORDS_BIGENDIAN),yes) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +else +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld +endif +endif + +# profiling code +ifdef TARGET_GPROF +LDFLAGS+=-p +CFLAGS+=-p +endif + +OBJS= main.o syscall.o strace.o mmap.o signal.o path.o thunk.o \ + elfload.o linuxload.o uaccess.o +LIBS+= $(AIOLIBS) +ifdef TARGET_HAS_BFLT +OBJS+= flatload.o +endif +ifdef TARGET_HAS_ELFLOAD32 +OBJS+= elfload32.o +elfload32.o: elfload.c +endif + +ifeq ($(TARGET_ARCH), i386) +OBJS+= vm86.o +endif +ifeq ($(TARGET_ARCH), arm) +OBJS+=nwfpe/fpa11.o nwfpe/fpa11_cpdo.o \ +nwfpe/fpa11_cpdt.o nwfpe/fpa11_cprt.o nwfpe/fpopcode.o nwfpe/single_cpdo.o \ + nwfpe/double_cpdo.o nwfpe/extended_cpdo.o arm-semi.o +endif +ifeq ($(TARGET_ARCH), m68k) +OBJS+= m68k-sim.o m68k-semi.o +endif + ifdef CONFIG_GDBSTUB -OBJS+=gdbstub.o +OBJS+=gdbstub.o gdbstub-xml.o endif -all: $(PROGS) +OBJS+= libqemu.a -$(QEMU_USER): $(OBJS) - $(CC) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^ $(LIBS) +# Note: this is a workaround. The real fix is to avoid compiling +# cpu_signal_handler() in cpu-exec.c. +signal.o: signal.c + $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< + +$(QEMU_PROG): $(OBJS) ../libqemu_user.a + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) ifeq ($(ARCH),alpha) # Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of # the address space (31 bit so sign extending doesn't matter) echo -ne '\001\000\000\000' | dd of=qemu bs=1 seek=48 count=4 conv=notrunc endif -# must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o -# XXX: suppress QEMU_TOOL tests +endif #CONFIG_LINUX_USER + +######################################################### +# Darwin user emulator target + +ifdef CONFIG_DARWIN_USER + +VPATH+=:$(SRC_PATH)/darwin-user +CPPFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH) + +# Leave some space for the regular program loading zone +LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000 + +LIBS+=-lmx + +OBJS= main.o commpage.o machload.o mmap.o signal.o syscall.o thunk.o + +OBJS+= libqemu.a + +ifdef CONFIG_GDBSTUB +OBJS+=gdbstub.o gdbstub-xml.o +endif + +# Note: this is a workaround. The real fix is to avoid compiling +# cpu_signal_handler() in cpu-exec.c. +signal.o: signal.c + $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< + +$(QEMU_PROG): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +endif #CONFIG_DARWIN_USER + +######################################################### +# BSD user emulator target + +ifdef CONFIG_BSD_USER + +VPATH+=:$(SRC_PATH)/bsd-user +CPPFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH) + +ifdef CONFIG_STATIC +LDFLAGS+=-static +endif + +ifeq ($(ARCH),i386) +ifdef TARGET_GPROF +USE_I386_LD=y +endif +ifdef CONFIG_STATIC +USE_I386_LD=y +endif +ifdef USE_I386_LD +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +else +# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object +# that the kernel ELF loader considers as an executable. I think this +# is the simplest way to make it self virtualizable! +LDFLAGS+=-Wl,-shared +endif +endif + +ifeq ($(ARCH),x86_64) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +endif + +ifeq ($(ARCH),ppc) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +endif + +ifeq ($(ARCH),ppc64) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +endif + +ifeq ($(ARCH),s390) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +endif + +ifeq ($(ARCH),sparc) +# -static is used to avoid g1/g3 usage by the dynamic linker +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static +endif + +ifeq ($(ARCH),sparc64) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +endif + +ifeq ($(ARCH),alpha) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +endif + +ifeq ($(ARCH),ia64) +LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/$(ARCH).ld +endif + +ifeq ($(ARCH),arm) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +endif + +ifeq ($(ARCH),m68k) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +endif + +ifeq ($(ARCH),mips) +ifeq ($(WORDS_BIGENDIAN),yes) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +else +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld +endif +endif + +ifeq ($(ARCH),mips64) +ifeq ($(WORDS_BIGENDIAN),yes) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +else +LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld +endif +endif + +OBJS= main.o bsdload.o elfload.o mmap.o path.o signal.o strace.o syscall.o +OBJS+= uaccess.o + +OBJS+= libqemu.a + +ifdef CONFIG_GDBSTUB +OBJS+=gdbstub.o +endif + +# Note: this is a workaround. The real fix is to avoid compiling +# cpu_signal_handler() in cpu-exec.c. +signal.o: signal.c + $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< + +$(QEMU_PROG): $(OBJS) ../libqemu_user.a + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +endif #CONFIG_BSD_USER + +######################################################### +# System emulator target +ifndef CONFIG_USER_ONLY + +OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o +OBJS+=fw_cfg.o +ifdef CONFIG_KVM +OBJS+=kvm.o kvm-all.o +endif ifdef CONFIG_WIN32 -VL_OBJS+=block-raw-win32.o +OBJS+=block-raw-win32.o else -VL_OBJS+=block-raw-posix.o +OBJS+=block-raw-posix.o endif +LIBS+=-lz ifdef CONFIG_ALSA LIBS += -lasound endif +ifdef CONFIG_ESD +LIBS += -lesd +endif +ifdef CONFIG_PA +LIBS += -lpulse-simple +endif ifdef CONFIG_DSOUND LIBS += -lole32 -ldxguid endif ifdef CONFIG_FMOD LIBS += $(CONFIG_FMOD_LIB) endif +ifdef CONFIG_OSS +LIBS += $(CONFIG_OSS_LIB) +endif SOUND_HW = sb16.o es1370.o +ifdef CONFIG_AC97 +SOUND_HW += ac97.o +endif ifdef CONFIG_ADLIB SOUND_HW += fmopl.o adlib.o endif +ifdef CONFIG_GUS +SOUND_HW += gus.o gusemu_hal.o gusemu_mixer.o +endif +ifdef CONFIG_CS4231A +SOUND_HW += cs4231a.o +endif ifdef CONFIG_VNC_TLS CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS) LIBS += $(CONFIG_VNC_TLS_LIBS) endif +ifdef CONFIG_BLUEZ +LIBS += $(CONFIG_BLUEZ_LIBS) +endif + # SCSI layer -VL_OBJS+= lsi53c895a.o +OBJS+= lsi53c895a.o esp.o # USB layer -VL_OBJS+= usb-ohci.o +OBJS+= usb-ohci.o # EEPROM emulation -VL_OBJS += eeprom93xx.o +OBJS += eeprom93xx.o # PCI network cards -VL_OBJS += eepro100.o -VL_OBJS += ne2000.o -VL_OBJS += pcnet.o -VL_OBJS += rtl8139.o +OBJS += eepro100.o +OBJS += ne2000.o +OBJS += pcnet.o +OBJS += rtl8139.o +OBJS += e1000.o ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support -VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o -VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o -VL_OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o -VL_OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o +OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o +OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o +OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o +OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE endif ifeq ($(TARGET_BASE_ARCH), ppc) CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE # shared objects -VL_OBJS+= ppc.o ide.o vga.o $(SOUND_HW) dma.o openpic.o +OBJS+= ppc.o ide.o vga.o $(SOUND_HW) dma.o openpic.o # PREP target -VL_OBJS+= pckbd.o ps2.o serial.o i8259.o i8254.o fdc.o m48t59.o mc146818rtc.o -VL_OBJS+= prep_pci.o ppc_prep.o +OBJS+= pckbd.o ps2.o serial.o i8259.o i8254.o fdc.o m48t59.o mc146818rtc.o +OBJS+= prep_pci.o ppc_prep.o # Mac shared devices -VL_OBJS+= macio.o cuda.o adb.o mac_nvram.o mac_dbdma.o +OBJS+= macio.o cuda.o adb.o mac_nvram.o mac_dbdma.o # OldWorld PowerMac -VL_OBJS+= heathrow_pic.o grackle_pci.o ppc_oldworld.o +OBJS+= heathrow_pic.o grackle_pci.o ppc_oldworld.o # NewWorld PowerMac -VL_OBJS+= unin_pci.o ppc_chrp.o +OBJS+= unin_pci.o ppc_chrp.o # PowerPC 4xx boards -VL_OBJS+= pflash_cfi02.o ppc4xx_devs.o ppc405_uc.o ppc405_boards.o +OBJS+= pflash_cfi02.o ppc4xx_devs.o ppc405_uc.o ppc405_boards.o endif ifeq ($(TARGET_BASE_ARCH), mips) -VL_OBJS+= mips_r4k.o mips_malta.o mips_pica61.o mips_mipssim.o -VL_OBJS+= mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o -VL_OBJS+= jazz_led.o -VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o -VL_OBJS+= piix_pci.o parallel.o cirrus_vga.o $(SOUND_HW) -VL_OBJS+= mipsnet.o -VL_OBJS+= pflash_cfi01.o -CPPFLAGS += -DHAS_AUDIO +OBJS+= mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o +OBJS+= mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o rc4030.o +OBJS+= g364fb.o jazz_led.o +OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o +OBJS+= piix_pci.o parallel.o cirrus_vga.o pcspk.o $(SOUND_HW) +OBJS+= mipsnet.o +OBJS+= pflash_cfi01.o +CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE endif ifeq ($(TARGET_BASE_ARCH), cris) -VL_OBJS+= etraxfs.o -VL_OBJS+= ptimer.o -VL_OBJS+= etraxfs_timer.o -VL_OBJS+= etraxfs_ser.o +OBJS+= etraxfs.o +OBJS+= etraxfs_dma.o +OBJS+= etraxfs_pic.o +OBJS+= etraxfs_eth.o +OBJS+= etraxfs_timer.o +OBJS+= etraxfs_ser.o + +OBJS+= ptimer.o +OBJS+= pflash_cfi02.o endif ifeq ($(TARGET_BASE_ARCH), sparc) ifeq ($(TARGET_ARCH), sparc64) -VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o apb_pci.o -VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o -VL_OBJS+= cirrus_vga.o parallel.o ptimer.o -else -VL_OBJS+= sun4m.o tcx.o pcnet.o iommu.o m48t59.o slavio_intctl.o -VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o sparc32_dma.o -VL_OBJS+= cs4231.o ptimer.o eccmemctl.o sbi.o sun4c_intctl.o +OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o apb_pci.o +OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o +OBJS+= cirrus_vga.o parallel.o ptimer.o +else +OBJS+= sun4m.o tcx.o pcnet.o iommu.o m48t59.o slavio_intctl.o +OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o sparc32_dma.o +OBJS+= cs4231.o ptimer.o eccmemctl.o sbi.o sun4c_intctl.o endif endif ifeq ($(TARGET_BASE_ARCH), arm) -VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o -VL_OBJS+= arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o -VL_OBJS+= versatile_pci.o ptimer.o -VL_OBJS+= realview_gic.o realview.o arm_sysctl.o mpcore.o -VL_OBJS+= armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o -VL_OBJS+= pl061.o -VL_OBJS+= arm-semi.o -VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o -VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o -VL_OBJS+= pflash_cfi01.o gumstix.o -VL_OBJS+= spitz.o ide.o serial.o nand.o ecc.o -VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o omap_i2c.o -VL_OBJS+= palm.o tsc210x.o -VL_OBJS+= mst_fpga.o mainstone.o +OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o +OBJS+= arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o +OBJS+= versatile_pci.o ptimer.o +OBJS+= realview_gic.o realview.o arm_sysctl.o mpcore.o +OBJS+= armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o +OBJS+= pl061.o +OBJS+= arm-semi.o +OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o +OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o +OBJS+= pflash_cfi01.o gumstix.o +OBJS+= zaurus.o ide.o serial.o nand.o ecc.o spitz.o tosa.o tc6393xb.o +OBJS+= omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o +OBJS+= omap2.o omap_dss.o soc_dma.o +OBJS+= palm.o tsc210x.o +OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o +OBJS+= tsc2005.o bt-hci-csr.o +OBJS+= mst_fpga.o mainstone.o +OBJS+= musicpal.o pflash_cfi02.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), sh4) -VL_OBJS+= shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o -VL_OBJS+= sh_timer.o ptimer.o sh_serial.o sh_intc.o +OBJS+= shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o +OBJS+= sh_timer.o ptimer.o sh_serial.o sh_intc.o sm501.o serial.o endif ifeq ($(TARGET_BASE_ARCH), m68k) -VL_OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o -VL_OBJS+= m68k-semi.o dummy_m68k.o +OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o +OBJS+= m68k-semi.o dummy_m68k.o endif ifdef CONFIG_GDBSTUB -VL_OBJS+=gdbstub.o +OBJS+=gdbstub.o gdbstub-xml.o endif ifdef CONFIG_COCOA COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit @@ -525,125 +755,64 @@ CPPFLAGS+=-I$(SRC_PATH)/slirp endif -VL_LDFLAGS=$(VL_OS_LDFLAGS) -VL_LIBS=$(AIOLIBS) +LIBS+=$(AIOLIBS) # specific flags are needed for non soft mmu emulator ifdef CONFIG_STATIC -VL_LDFLAGS+=-static -endif -ifndef CONFIG_SOFTMMU -VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld +LDFLAGS+=-static endif ifndef CONFIG_DARWIN ifndef CONFIG_WIN32 ifndef CONFIG_SOLARIS -VL_LIBS+=-lutil +LIBS+=-lutil endif endif endif ifdef TARGET_GPROF -vl.o: BASE_CFLAGS+=-p -VL_LDFLAGS+=-p +vl.o: CFLAGS+=-p +LDFLAGS+=-p endif ifeq ($(ARCH),ia64) -VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld -endif - -ifeq ($(ARCH),sparc64) - VL_LDFLAGS+=-m64 - ifneq ($(CONFIG_SOLARIS),yes) - VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld - endif -endif - -ifeq ($(ARCH),x86_64) - VL_LDFLAGS+=-m64 - ifneq ($(CONFIG_SOLARIS),yes) - VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld - endif +LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld endif ifdef CONFIG_WIN32 SDL_LIBS := $(filter-out -mwindows, $(SDL_LIBS)) -mconsole endif -$(QEMU_SYSTEM): $(VL_OBJS) ../libqemu_common.a libqemu.a - $(CC) $(VL_LDFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS) - -depend: $(SRCS) - $(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend +# profiling code +ifdef TARGET_GPROF +LDFLAGS+=-p +main.o: CFLAGS+=-p +endif -vldepend: $(VL_OBJS:.o=.c) - $(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend +$(QEMU_PROG): $(OBJS) ../libqemu_common.a libqemu.a + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(CURSES_LIBS) $(BRLAPI_LIBS) $(VDE_LIBS) -# libqemu +endif # !CONFIG_USER_ONLY -libqemu.a: $(LIBOBJS) +gdbstub-xml.c: $(TARGET_XML_FILES) feature_to_c.sh rm -f $@ - $(AR) rcs $@ $(LIBOBJS) - -translate.o: translate.c gen-op.h opc.h cpu.h - -translate-all.o: translate-all.c opc.h cpu.h - -translate-op.o: translate-all.c op.h opc.h cpu.h - -op.h: op.o $(DYNGEN) - $(DYNGEN) -o $@ $< - -opc.h: op.o $(DYNGEN) - $(DYNGEN) -c -o $@ $< - -gen-op.h: op.o $(DYNGEN) - $(DYNGEN) -g -o $@ $< - -op.o: op.c - $(CC) $(OP_CFLAGS) $(CPPFLAGS) -c -o $@ $< - -# HELPER_CFLAGS is used for all the code compiled with static register -# variables -ifeq ($(TARGET_BASE_ARCH), i386) -# XXX: rename helper.c to op_helper.c -helper.o: helper.c - $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< +ifeq ($(TARGET_XML_FILES),) + echo > $@ else -op_helper.o: op_helper.c - $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< + $(SHELL) $(SRC_PATH)/feature_to_c.sh $@ $(TARGET_XML_FILES) endif -cpu-exec.o: cpu-exec.c - $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< - -# Note: this is a workaround. The real fix is to avoid compiling -# cpu_signal_handler() in cpu-exec.c. -signal.o: signal.c - $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< - %.o: %.c - $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< + $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< %.o: %.S $(CC) $(CPPFLAGS) -c -o $@ $< clean: - rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o fpu/*.o - rm -f *.d */*.d + rm -f *.o *.a *~ $(PROGS) gen-op.h dyngen-opc.h op.h nwfpe/*.o fpu/*.o + rm -f *.d */*.d tcg/*.o install: all ifneq ($(PROGS),) $(INSTALL) -m 755 -s $(PROGS) "$(DESTDIR)$(bindir)" endif -ifneq ($(wildcard .depend),) -include .depend -endif - -ifeq (1, 0) -audio.o sdlaudio.o dsoundaudio.o ossaudio.o wavaudio.o noaudio.o \ -fmodaudio.o alsaaudio.o mixeng.o sb16.o es1370.o gus.o adlib.o: \ -CFLAGS := $(CFLAGS) -Wall -Werror -W -Wsign-compare -endif - # Include automatically generated dependency files -include $(wildcard *.d */*.d) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/migration.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/migration.c --- qemu-0.9.1/migration.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/migration.c 2008-11-11 16:46:33.000000000 +0000 @@ -0,0 +1,281 @@ +/* + * QEMU live migration + * + * Copyright IBM, Corp. 2008 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "qemu-common.h" +#include "migration.h" +#include "console.h" +#include "buffered_file.h" +#include "sysemu.h" +#include "block.h" +#include "qemu_socket.h" + +//#define DEBUG_MIGRATION + +#ifdef DEBUG_MIGRATION +#define dprintf(fmt, ...) \ + do { printf("migration: " fmt, ## __VA_ARGS__); } while (0) +#else +#define dprintf(fmt, ...) \ + do { } while (0) +#endif + +/* Migration speed throttling */ +static uint32_t max_throttle = (32 << 20); + +static MigrationState *current_migration; + +void qemu_start_incoming_migration(const char *uri) +{ + const char *p; + + if (strstart(uri, "tcp:", &p)) + tcp_start_incoming_migration(p); +#if !defined(WIN32) + else if (strstart(uri, "exec:", &p)) + exec_start_incoming_migration(p); +#endif + else + fprintf(stderr, "unknown migration protocol: %s\n", uri); +} + +void do_migrate(int detach, const char *uri) +{ + MigrationState *s = NULL; + const char *p; + + if (strstart(uri, "tcp:", &p)) + s = tcp_start_outgoing_migration(p, max_throttle, detach); +#if !defined(WIN32) + else if (strstart(uri, "exec:", &p)) + s = exec_start_outgoing_migration(p, max_throttle, detach); +#endif + else + term_printf("unknown migration protocol: %s\n", uri); + + if (s == NULL) + term_printf("migration failed\n"); + else { + if (current_migration) + current_migration->release(current_migration); + + current_migration = s; + } +} + +void do_migrate_cancel(void) +{ + MigrationState *s = current_migration; + + if (s) + s->cancel(s); +} + +void do_migrate_set_speed(const char *value) +{ + double d; + char *ptr; + + d = strtod(value, &ptr); + switch (*ptr) { + case 'G': case 'g': + d *= 1024; + case 'M': case 'm': + d *= 1024; + case 'K': case 'k': + d *= 1024; + default: + break; + } + + max_throttle = (uint32_t)d; +} + +void do_info_migrate(void) +{ + MigrationState *s = current_migration; + + if (s) { + term_printf("Migration status: "); + switch (s->get_status(s)) { + case MIG_STATE_ACTIVE: + term_printf("active\n"); + break; + case MIG_STATE_COMPLETED: + term_printf("completed\n"); + break; + case MIG_STATE_ERROR: + term_printf("failed\n"); + break; + case MIG_STATE_CANCELLED: + term_printf("cancelled\n"); + break; + } + } +} + +/* shared migration helpers */ + +void migrate_fd_error(FdMigrationState *s) +{ + dprintf("setting error state\n"); + s->state = MIG_STATE_ERROR; + migrate_fd_cleanup(s); +} + +void migrate_fd_cleanup(FdMigrationState *s) +{ + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); + + if (s->file) { + dprintf("closing file\n"); + qemu_fclose(s->file); + } + + if (s->fd != -1) + close(s->fd); + + /* Don't resume monitor until we've flushed all of the buffers */ + if (s->detach == 2) { + monitor_resume(); + s->detach = 0; + } + + s->fd = -1; +} + +void migrate_fd_put_notify(void *opaque) +{ + FdMigrationState *s = opaque; + + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); + qemu_file_put_notify(s->file); +} + +ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size) +{ + FdMigrationState *s = opaque; + ssize_t ret; + + do { + ret = s->write(s, data, size); + } while (ret == -1 && ((s->get_error(s)) == EINTR || (s->get_error(s)) == EWOULDBLOCK)); + + if (ret == -1) + ret = -(s->get_error(s)); + + if (ret == -EAGAIN) + qemu_set_fd_handler2(s->fd, NULL, NULL, migrate_fd_put_notify, s); + + return ret; +} + +void migrate_fd_connect(FdMigrationState *s) +{ + int ret; + + s->file = qemu_fopen_ops_buffered(s, + s->bandwidth_limit, + migrate_fd_put_buffer, + migrate_fd_put_ready, + migrate_fd_wait_for_unfreeze, + migrate_fd_close); + + dprintf("beginning savevm\n"); + ret = qemu_savevm_state_begin(s->file); + if (ret < 0) { + dprintf("failed, %d\n", ret); + migrate_fd_error(s); + return; + } + + migrate_fd_put_ready(s); +} + +void migrate_fd_put_ready(void *opaque) +{ + FdMigrationState *s = opaque; + + if (s->state != MIG_STATE_ACTIVE) { + dprintf("put_ready returning because of non-active state\n"); + return; + } + + dprintf("iterate\n"); + if (qemu_savevm_state_iterate(s->file) == 1) { + dprintf("done iterating\n"); + vm_stop(0); + + bdrv_flush_all(); + qemu_savevm_state_complete(s->file); + s->state = MIG_STATE_COMPLETED; + migrate_fd_cleanup(s); + } +} + +int migrate_fd_get_status(MigrationState *mig_state) +{ + FdMigrationState *s = migrate_to_fms(mig_state); + return s->state; +} + +void migrate_fd_cancel(MigrationState *mig_state) +{ + FdMigrationState *s = migrate_to_fms(mig_state); + + if (s->state != MIG_STATE_ACTIVE) + return; + + dprintf("cancelling migration\n"); + + s->state = MIG_STATE_CANCELLED; + + migrate_fd_cleanup(s); +} + +void migrate_fd_release(MigrationState *mig_state) +{ + FdMigrationState *s = migrate_to_fms(mig_state); + + dprintf("releasing state\n"); + + if (s->state == MIG_STATE_ACTIVE) { + s->state = MIG_STATE_CANCELLED; + migrate_fd_cleanup(s); + } + free(s); +} + +void migrate_fd_wait_for_unfreeze(void *opaque) +{ + FdMigrationState *s = opaque; + int ret; + + dprintf("wait for unfreeze\n"); + if (s->state != MIG_STATE_ACTIVE) + return; + + do { + fd_set wfds; + + FD_ZERO(&wfds); + FD_SET(s->fd, &wfds); + + ret = select(s->fd + 1, NULL, &wfds, NULL, NULL); + } while (ret == -1 && (s->get_error(s)) == EINTR); +} + +int migrate_fd_close(void *opaque) +{ + FdMigrationState *s = opaque; + return s->close(s); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/migration-exec.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/migration-exec.c --- qemu-0.9.1/migration-exec.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/migration-exec.c 2008-11-11 16:46:33.000000000 +0000 @@ -0,0 +1,141 @@ +/* + * QEMU live migration + * + * Copyright IBM, Corp. 2008 + * Copyright Dell MessageOne 2008 + * + * Authors: + * Anthony Liguori + * Charles Duffy + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "qemu-common.h" +#include "qemu_socket.h" +#include "migration.h" +#include "qemu-char.h" +#include "sysemu.h" +#include "console.h" +#include "buffered_file.h" +#include "block.h" + +//#define DEBUG_MIGRATION_EXEC + +#ifdef DEBUG_MIGRATION_EXEC +#define dprintf(fmt, ...) \ + do { printf("migration-exec: " fmt, ## __VA_ARGS__); } while (0) +#else +#define dprintf(fmt, ...) \ + do { } while (0) +#endif + +static int file_errno(FdMigrationState *s) +{ + return errno; +} + +static int file_write(FdMigrationState *s, const void * buf, size_t size) +{ + return write(s->fd, buf, size); +} + +static int exec_close(FdMigrationState *s) +{ + dprintf("exec_close\n"); + if (s->opaque) { + qemu_fclose(s->opaque); + s->opaque = NULL; + s->fd = -1; + } + return 0; +} + +MigrationState *exec_start_outgoing_migration(const char *command, + int64_t bandwidth_limit, + int async) +{ + FdMigrationState *s; + FILE *f; + + s = qemu_mallocz(sizeof(*s)); + if (s == NULL) { + dprintf("Unable to allocate FdMigrationState\n"); + goto err; + } + + f = popen(command, "w"); + if (f == NULL) { + dprintf("Unable to popen exec target\n"); + goto err_after_alloc; + } + + s->fd = fileno(f); + if (s->fd == -1) { + dprintf("Unable to retrieve file descriptor for popen'd handle\n"); + goto err_after_open; + } + + if (fcntl(s->fd, F_SETFD, O_NONBLOCK) == -1) { + dprintf("Unable to set nonblocking mode on file descriptor\n"); + goto err_after_open; + } + + s->opaque = qemu_popen(f, "w"); + + s->get_error = file_errno; + s->write = file_write; + s->mig_state.cancel = migrate_fd_cancel; + s->mig_state.get_status = migrate_fd_get_status; + s->mig_state.release = migrate_fd_release; + + s->state = MIG_STATE_ACTIVE; + s->detach = !async; + s->bandwidth_limit = bandwidth_limit; + + if (s->detach == 1) { + dprintf("detaching from monitor\n"); + monitor_suspend(); + s->detach = 2; + } + + migrate_fd_connect(s); + return &s->mig_state; + +err_after_open: + pclose(f); +err_after_alloc: + qemu_free(s); +err: + return NULL; +} + +int exec_start_incoming_migration(const char *command) +{ + int ret; + QEMUFile *f; + + dprintf("Attempting to start an incoming migration\n"); + f = qemu_popen_cmd(command, "r"); + if(f == NULL) { + dprintf("Unable to apply qemu wrapper to popen file\n"); + return -errno; + } + vm_stop(0); /* just in case */ + ret = qemu_loadvm_state(f); + if (ret < 0) { + fprintf(stderr, "load of migration failed\n"); + goto err; + } + qemu_announce_self(); + dprintf("successfully loaded vm state\n"); + vm_start(); + qemu_fclose(f); + return 0; + +err: + qemu_fclose(f); + return -errno; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/migration.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/migration.h --- qemu-0.9.1/migration.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/migration.h 2008-11-11 16:46:33.000000000 +0000 @@ -0,0 +1,98 @@ +/* + * QEMU live migration + * + * Copyright IBM, Corp. 2008 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_MIGRATION_H +#define QEMU_MIGRATION_H + +#define MIG_STATE_ERROR -1 +#define MIG_STATE_COMPLETED 0 +#define MIG_STATE_CANCELLED 1 +#define MIG_STATE_ACTIVE 2 + +typedef struct MigrationState MigrationState; + +struct MigrationState +{ + /* FIXME: add more accessors to print migration info */ + void (*cancel)(MigrationState *s); + int (*get_status)(MigrationState *s); + void (*release)(MigrationState *s); +}; + +typedef struct FdMigrationState FdMigrationState; + +struct FdMigrationState +{ + MigrationState mig_state; + int64_t bandwidth_limit; + QEMUFile *file; + int fd; + int detach; + int state; + int (*get_error)(struct FdMigrationState*); + int (*close)(struct FdMigrationState*); + int (*write)(struct FdMigrationState*, const void *, size_t); + void *opaque; +}; + +void qemu_start_incoming_migration(const char *uri); + +void do_migrate(int detach, const char *uri); + +void do_migrate_cancel(void); + +void do_migrate_set_speed(const char *value); + +void do_info_migrate(void); + +int exec_start_incoming_migration(const char *host_port); + +MigrationState *exec_start_outgoing_migration(const char *host_port, + int64_t bandwidth_limit, + int detach); + +int tcp_start_incoming_migration(const char *host_port); + +MigrationState *tcp_start_outgoing_migration(const char *host_port, + int64_t bandwidth_limit, + int detach); + +void migrate_fd_error(FdMigrationState *s); + +void migrate_fd_cleanup(FdMigrationState *s); + +void migrate_fd_put_notify(void *opaque); + +ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size); + +void migrate_fd_connect(FdMigrationState *s); + +void migrate_fd_put_ready(void *opaque); + +int migrate_fd_get_status(MigrationState *mig_state); + +void migrate_fd_cancel(MigrationState *mig_state); + +void migrate_fd_release(MigrationState *mig_state); + +void migrate_fd_wait_for_unfreeze(void *opaque); + +int migrate_fd_close(void *opaque); + +static inline FdMigrationState *migrate_to_fms(MigrationState *mig_state) +{ + return container_of(mig_state, FdMigrationState, mig_state); +} + +#endif + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/migration-tcp.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/migration-tcp.c --- qemu-0.9.1/migration-tcp.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/migration-tcp.c 2008-11-11 16:46:33.000000000 +0000 @@ -0,0 +1,217 @@ +/* + * QEMU live migration + * + * Copyright IBM, Corp. 2008 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "qemu-common.h" +#include "qemu_socket.h" +#include "migration.h" +#include "qemu-char.h" +#include "sysemu.h" +#include "console.h" +#include "buffered_file.h" +#include "block.h" + +//#define DEBUG_MIGRATION_TCP + +#ifdef DEBUG_MIGRATION_TCP +#define dprintf(fmt, ...) \ + do { printf("migration-tcp: " fmt, ## __VA_ARGS__); } while (0) +#else +#define dprintf(fmt, ...) \ + do { } while (0) +#endif + +static int socket_errno(FdMigrationState *s) +{ + return (s->get_error(s)); +} + +static int socket_write(FdMigrationState *s, const void * buf, size_t size) +{ + return send(s->fd, buf, size, 0); +} + +static int tcp_close(FdMigrationState *s) +{ + dprintf("tcp_close\n"); + if (s->fd != -1) { + close(s->fd); + s->fd = -1; + } + return 0; +} + + +static void tcp_wait_for_connect(void *opaque) +{ + FdMigrationState *s = opaque; + int val, ret; + socklen_t valsize = sizeof(val); + + dprintf("connect completed\n"); + do { + ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &val, &valsize); + } while (ret == -1 && (s->get_error(s)) == EINTR); + + if (ret < 0) { + migrate_fd_error(s); + return; + } + + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); + + if (val == 0) + migrate_fd_connect(s); + else { + dprintf("error connecting %d\n", val); + migrate_fd_error(s); + } +} + +MigrationState *tcp_start_outgoing_migration(const char *host_port, + int64_t bandwidth_limit, + int async) +{ + struct sockaddr_in addr; + FdMigrationState *s; + int ret; + + if (parse_host_port(&addr, host_port) < 0) + return NULL; + + s = qemu_mallocz(sizeof(*s)); + if (s == NULL) + return NULL; + + s->get_error = socket_errno; + s->write = socket_write; + s->close = tcp_close; + s->mig_state.cancel = migrate_fd_cancel; + s->mig_state.get_status = migrate_fd_get_status; + s->mig_state.release = migrate_fd_release; + + s->state = MIG_STATE_ACTIVE; + s->detach = !async; + s->bandwidth_limit = bandwidth_limit; + s->fd = socket(PF_INET, SOCK_STREAM, 0); + if (s->fd == -1) { + qemu_free(s); + return NULL; + } + + socket_set_nonblock(s->fd); + + if (s->detach == 1) { + dprintf("detaching from monitor\n"); + monitor_suspend(); + s->detach = 2; + } + + do { + ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr)); + if (ret == -1) + ret = -(s->get_error(s)); + + if (ret == -EINPROGRESS || ret == -EWOULDBLOCK) + qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s); + } while (ret == -EINTR); + + if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) { + dprintf("connect failed\n"); + close(s->fd); + qemu_free(s); + return NULL; + } else if (ret >= 0) + migrate_fd_connect(s); + + return &s->mig_state; +} + +static void tcp_accept_incoming_migration(void *opaque) +{ + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + int s = (unsigned long)opaque; + QEMUFile *f; + int c, ret; + + do { + c = accept(s, (struct sockaddr *)&addr, &addrlen); + } while (c == -1 && socket_error() == EINTR); + + dprintf("accepted migration\n"); + + if (c == -1) { + fprintf(stderr, "could not accept migration connection\n"); + return; + } + + f = qemu_fopen_socket(c); + if (f == NULL) { + fprintf(stderr, "could not qemu_fopen socket\n"); + goto out; + } + + vm_stop(0); /* just in case */ + ret = qemu_loadvm_state(f); + if (ret < 0) { + fprintf(stderr, "load of migration failed\n"); + goto out_fopen; + } + qemu_announce_self(); + dprintf("successfully loaded vm state\n"); + + /* we've successfully migrated, close the server socket */ + qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL); + close(s); + + vm_start(); + +out_fopen: + qemu_fclose(f); +out: + close(c); +} + +int tcp_start_incoming_migration(const char *host_port) +{ + struct sockaddr_in addr; + int val; + int s; + + if (parse_host_port(&addr, host_port) < 0) { + fprintf(stderr, "invalid host/port combination: %s\n", host_port); + return -EINVAL; + } + + s = socket(PF_INET, SOCK_STREAM, 0); + if (s == -1) + return -socket_error(); + + val = 1; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); + + if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) + goto err; + + if (listen(s, 1) == -1) + goto err; + + qemu_set_fd_handler2(s, NULL, tcp_accept_incoming_migration, NULL, + (void *)(unsigned long)s); + + return 0; + +err: + close(s); + return -socket_error(); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/mips-dis.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/mips-dis.c --- qemu-0.9.1/mips-dis.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/mips-dis.c 2008-09-06 18:47:39.000000000 +0100 @@ -3302,7 +3302,7 @@ #endif /* Set ISA, architecture, and cp0 register names as best we can. */ -#if ! SYMTAB_AVAILABLE && 0 +#if !defined(SYMTAB_AVAILABLE) && 0 /* This is running out on a target machine, not in a host tool. FIXME: Where does mips_target_info come from? */ target_processor = mips_target_info.processor; @@ -3322,9 +3322,7 @@ } void -parse_mips_dis_option (option, len) - const char *option; - unsigned int len; +parse_mips_dis_option (const char *option, unsigned int len) { unsigned int i, optionlen, vallen; const char *val; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/monitor.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/monitor.c --- qemu-0.9.1/monitor.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/monitor.c 2008-11-05 16:04:33.000000000 +0000 @@ -35,18 +35,13 @@ #include "audio/audio.h" #include "disas.h" #include - -#ifdef CONFIG_PROFILER -#include "qemu-timer.h" /* for ticks_per_sec */ -#endif +#include "qemu-timer.h" +#include "migration.h" +#include "kvm.h" //#define DEBUG //#define DEBUG_COMPLETION -#ifndef offsetof -#define offsetof(type, field) ((size_t) &((type *)0)->field) -#endif - /* * Supported types: * @@ -64,7 +59,7 @@ typedef struct term_cmd_t { const char *name; const char *args_type; - void (*handler)(); + void *handler; const char *params; const char *help; } term_cmd_t; @@ -73,15 +68,15 @@ static CharDriverState *monitor_hd[MAX_MON]; static int hide_banner; -static term_cmd_t term_cmds[]; -static term_cmd_t info_cmds[]; +static const term_cmd_t term_cmds[]; +static const term_cmd_t info_cmds[]; static uint8_t term_outbuf[1024]; static int term_outbuf_index; static void monitor_start_input(void); -CPUState *mon_cpu = NULL; +static CPUState *mon_cpu = NULL; void term_flush(void) { @@ -182,9 +177,9 @@ return 0; } -static void help_cmd1(term_cmd_t *cmds, const char *prefix, const char *name) +static void help_cmd1(const term_cmd_t *cmds, const char *prefix, const char *name) { - term_cmd_t *cmd; + const term_cmd_t *cmd; for(cmd = cmds; cmd->name != NULL; cmd++) { if (!name || !strcmp(name, cmd->name)) @@ -199,7 +194,7 @@ } else { help_cmd1(term_cmds, "", name); if (name && !strcmp(name, "log")) { - CPULogItem *item; + const CPULogItem *item; term_printf("Log items (comma separated):\n"); term_printf("%-10s %s\n", "none", "remove all logs"); for(item = cpu_log_items; item->mask != 0; item++) { @@ -228,7 +223,8 @@ static void do_info(const char *item) { - term_cmd_t *cmd; + const term_cmd_t *cmd; + void (*handler)(void); if (!item) goto help; @@ -240,7 +236,8 @@ help_cmd("info"); return; found: - cmd->handler(); + handler = cmd->handler; + handler(); } static void do_info_version(void) @@ -254,6 +251,15 @@ term_printf("%s\n", qemu_name); } +static void do_info_uuid(void) +{ + term_printf(UUID_FMT "\n", qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], + qemu_uuid[3], qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], + qemu_uuid[7], qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], + qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], + qemu_uuid[15]); +} + static void do_info_block(void) { bdrv_info(); @@ -314,21 +320,15 @@ env->cpu_index); #if defined(TARGET_I386) term_printf(" pc=0x" TARGET_FMT_lx, env->eip + env->segs[R_CS].base); - if (env->hflags & HF_HALTED_MASK) - term_printf(" (halted)"); #elif defined(TARGET_PPC) term_printf(" nip=0x" TARGET_FMT_lx, env->nip); - if (env->halted) - term_printf(" (halted)"); #elif defined(TARGET_SPARC) term_printf(" pc=0x" TARGET_FMT_lx " npc=0x" TARGET_FMT_lx, env->pc, env->npc); - if (env->halted) - term_printf(" (halted)"); #elif defined(TARGET_MIPS) - term_printf(" PC=0x" TARGET_FMT_lx, env->PC[env->current_tc]); + term_printf(" PC=0x" TARGET_FMT_lx, env->active_tc.PC); +#endif if (env->halted) term_printf(" (halted)"); -#endif term_printf("\n"); } } @@ -405,18 +405,26 @@ eject_device(bs, force); } -static void do_change_block(const char *device, const char *filename) +static void do_change_block(const char *device, const char *filename, const char *fmt) { BlockDriverState *bs; + BlockDriver *drv = NULL; bs = bdrv_find(device); if (!bs) { term_printf("device not found\n"); return; } + if (fmt) { + drv = bdrv_find_format(fmt); + if (!drv) { + term_printf("invalid format %s\n", fmt); + return; + } + } if (eject_device(bs, 0) < 0) return; - bdrv_open(bs, filename, 0); + bdrv_open2(bs, filename, 0, drv); qemu_key_check(bs, filename); } @@ -435,12 +443,12 @@ } } -static void do_change(const char *device, const char *target) +static void do_change(const char *device, const char *target, const char *fmt) { if (strcmp(device, "vnc") == 0) { do_change_vnc(target); } else { - do_change_block(device, target); + do_change_block(device, target, fmt); } } @@ -597,7 +605,10 @@ env = mon_get_cpu(); if (!env) break; - cpu_memory_rw_debug(env, addr, buf, l, 0); + if (cpu_memory_rw_debug(env, addr, buf, l, 0) < 0) { + term_printf(" Cannot access memory\n"); + break; + } } i = 0; while (i < l) { @@ -744,6 +755,32 @@ fclose(f); } +static void do_physical_memory_save(unsigned int valh, unsigned int vall, + uint32_t size, const char *filename) +{ + FILE *f; + uint32_t l; + uint8_t buf[1024]; + target_phys_addr_t addr = GET_TPHYSADDR(valh, vall); + + f = fopen(filename, "wb"); + if (!f) { + term_printf("could not open '%s'\n", filename); + return; + } + while (size != 0) { + l = sizeof(buf); + if (l > size) + l = size; + cpu_physical_memory_rw(addr, buf, l, 0); + fwrite(buf, 1, l, f); + fflush(f); + addr += l; + size -= l; + } + fclose(f); +} + static void do_sum(uint32_t start, uint32_t size) { uint32_t addr; @@ -771,6 +808,8 @@ { 0x38, "alt" }, { 0xb8, "alt_r" }, + { 0x64, "altgr" }, + { 0xe4, "altgr_r" }, { 0x1d, "ctrl" }, { 0x9d, "ctrl_r" }, @@ -823,6 +862,11 @@ { 0x30, "b" }, { 0x31, "n" }, { 0x32, "m" }, + { 0x33, "comma" }, + { 0x34, "dot" }, + { 0x35, "slash" }, + + { 0x37, "asterisk" }, { 0x39, "spc" }, { 0x3a, "caps_lock" }, @@ -845,6 +889,7 @@ { 0x4e, "kp_add" }, { 0x9c, "kp_enter" }, { 0x53, "kp_decimal" }, + { 0x54, "sysrq" }, { 0x52, "kp_0" }, { 0x4f, "kp_1" }, @@ -876,6 +921,23 @@ { 0xd2, "insert" }, { 0xd3, "delete" }, +#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64) + { 0xf0, "stop" }, + { 0xf1, "again" }, + { 0xf2, "props" }, + { 0xf3, "undo" }, + { 0xf4, "front" }, + { 0xf5, "copy" }, + { 0xf6, "open" }, + { 0xf7, "paste" }, + { 0xf8, "find" }, + { 0xf9, "cut" }, + { 0xfa, "lf" }, + { 0xfb, "help" }, + { 0xfc, "meta_l" }, + { 0xfd, "meta_r" }, + { 0xfe, "compose" }, +#endif { 0, NULL }, }; @@ -897,48 +959,73 @@ return -1; } -static void do_send_key(const char *string) +#define MAX_KEYCODES 16 +static uint8_t keycodes[MAX_KEYCODES]; +static int nb_pending_keycodes; +static QEMUTimer *key_timer; + +static void release_keys(void *opaque) { - char keybuf[16], *q; - uint8_t keycodes[16]; - const char *p; - int nb_keycodes, keycode, i; + int keycode; - nb_keycodes = 0; - p = string; - while (*p != '\0') { - q = keybuf; - while (*p != '\0' && *p != '-') { - if ((q - keybuf) < sizeof(keybuf) - 1) { - *q++ = *p; + while (nb_pending_keycodes > 0) { + nb_pending_keycodes--; + keycode = keycodes[nb_pending_keycodes]; + if (keycode & 0x80) + kbd_put_keycode(0xe0); + kbd_put_keycode(keycode | 0x80); + } +} + +static void do_sendkey(const char *string, int has_hold_time, int hold_time) +{ + char keyname_buf[16]; + char *separator; + int keyname_len, keycode, i; + + if (nb_pending_keycodes > 0) { + qemu_del_timer(key_timer); + release_keys(NULL); + } + if (!has_hold_time) + hold_time = 100; + i = 0; + while (1) { + separator = strchr(string, '-'); + keyname_len = separator ? separator - string : strlen(string); + if (keyname_len > 0) { + pstrcpy(keyname_buf, sizeof(keyname_buf), string); + if (keyname_len > sizeof(keyname_buf) - 1) { + term_printf("invalid key: '%s...'\n", keyname_buf); + return; } - p++; - } - *q = '\0'; - keycode = get_keycode(keybuf); - if (keycode < 0) { - term_printf("unknown key: '%s'\n", keybuf); - return; + if (i == MAX_KEYCODES) { + term_printf("too many keys\n"); + return; + } + keyname_buf[keyname_len] = 0; + keycode = get_keycode(keyname_buf); + if (keycode < 0) { + term_printf("unknown key: '%s'\n", keyname_buf); + return; + } + keycodes[i++] = keycode; } - keycodes[nb_keycodes++] = keycode; - if (*p == '\0') + if (!separator) break; - p++; + string = separator + 1; } + nb_pending_keycodes = i; /* key down events */ - for(i = 0; i < nb_keycodes; i++) { + for (i = 0; i < nb_pending_keycodes; i++) { keycode = keycodes[i]; if (keycode & 0x80) kbd_put_keycode(0xe0); kbd_put_keycode(keycode & 0x7f); } - /* key up events */ - for(i = nb_keycodes - 1; i >= 0; i--) { - keycode = keycodes[i]; - if (keycode & 0x80) - kbd_put_keycode(0xe0); - kbd_put_keycode(keycode | 0x80); - } + /* delayed key up events */ + qemu_mod_timer(key_timer, qemu_get_clock(vm_clock) + + muldiv64(ticks_per_sec, hold_time, 1000)); } static int mouse_button_state; @@ -991,6 +1078,31 @@ suffix, addr, size * 2, val); } +/* boot_set handler */ +static QEMUBootSetHandler *qemu_boot_set_handler = NULL; +static void *boot_opaque; + +void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque) +{ + qemu_boot_set_handler = func; + boot_opaque = opaque; +} + +static void do_boot_set(const char *bootdevice) +{ + int res; + + if (qemu_boot_set_handler) { + res = qemu_boot_set_handler(boot_opaque, bootdevice); + if (res == 0) + term_printf("boot device list now set to %s\n", bootdevice); + else + term_printf("setting boot device list failed with error %i\n", res); + } else { + term_printf("no function defined to set boot device list for this architecture\n"); + } +} + static void do_system_reset(void) { qemu_system_reset_request(); @@ -1152,6 +1264,19 @@ #endif } +static void do_info_kvm(void) +{ +#ifdef CONFIG_KVM + term_printf("kvm support: "); + if (kvm_enabled()) + term_printf("enabled\n"); + else + term_printf("disabled\n"); +#else + term_printf("kvm support: not compiled\n"); +#endif +} + #ifdef CONFIG_PROFILER int64_t kqemu_time; @@ -1227,9 +1352,6 @@ } #ifdef HAS_AUDIO -int wav_start_capture (CaptureState *s, const char *path, int freq, - int bits, int nchannels); - static void do_wav_capture (const char *path, int has_freq, int freq, int has_bits, int bits, @@ -1255,7 +1377,20 @@ } #endif -static term_cmd_t term_cmds[] = { +#if defined(TARGET_I386) +static void do_inject_nmi(int cpu_index) +{ + CPUState *env; + + for (env = first_cpu; env != NULL; env = env->next_cpu) + if (env->cpu_index == cpu_index) { + cpu_interrupt(env, CPU_INTERRUPT_NMI); + break; + } +} +#endif + +static const term_cmd_t term_cmds[] = { { "help|?", "s?", do_help, "[cmd]", "show the help" }, { "commit", "s", do_commit, @@ -1266,11 +1401,11 @@ "", "quit the emulator" }, { "eject", "-fB", do_eject, "[-f] device", "eject a removable medium (use -f to force it)" }, - { "change", "BF", do_change, - "device filename", "change a removable medium" }, + { "change", "BFs?", do_change, + "device filename [format]", "change a removable medium, optional format" }, { "screendump", "F", do_screen_dump, "filename", "save screen into PPM image 'filename'" }, - { "logfile", "s", do_logfile, + { "logfile", "F", do_logfile, "filename", "output logs to 'filename'" }, { "log", "s", do_log, "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" }, @@ -1297,8 +1432,8 @@ { "i", "/ii.", do_ioport_read, "/fmt addr", "I/O port read" }, - { "sendkey", "s", do_send_key, - "keys", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1')" }, + { "sendkey", "si?", do_sendkey, + "keys [hold_ms]", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)" }, { "system_reset", "", do_system_reset, "", "reset the system" }, { "system_powerdown", "", do_system_powerdown, @@ -1326,14 +1461,30 @@ "capture index", "stop capture" }, { "memsave", "lis", do_memory_save, "addr size file", "save to disk virtual memory dump starting at 'addr' of size 'size'", }, + { "pmemsave", "lis", do_physical_memory_save, + "addr size file", "save to disk physical memory dump starting at 'addr' of size 'size'", }, + { "boot_set", "s", do_boot_set, + "bootdevice", "define new values for the boot device list" }, +#if defined(TARGET_I386) + { "nmi", "i", do_inject_nmi, + "cpu", "inject an NMI on the given CPU", }, +#endif + { "migrate", "-ds", do_migrate, + "[-d] uri", "migrate to URI (using -d to not wait for completion)" }, + { "migrate_cancel", "", do_migrate_cancel, + "", "cancel the current VM migration" }, + { "migrate_set_speed", "s", do_migrate_set_speed, + "value", "set maximum speed (in bytes) for migrations" }, { NULL, NULL, }, }; -static term_cmd_t info_cmds[] = { +static const term_cmd_t info_cmds[] = { { "version", "", do_info_version, "", "show the version of qemu" }, { "network", "", do_info_network, "", "show the network state" }, + { "chardev", "", qemu_chr_info, + "", "show the character devices" }, { "block", "", do_info_block, "", "show the block devices" }, { "blockstats", "", do_info_blockstats, @@ -1360,6 +1511,8 @@ "", "show dynamic compiler info", }, { "kqemu", "", do_info_kqemu, "", "show kqemu information", }, + { "kvm", "", do_info_kvm, + "", "show kvm information", }, { "usb", "", usb_info, "", "show guest USB devices", }, { "usbhost", "", usb_host_info, @@ -1378,6 +1531,8 @@ "", "show the vnc server status"}, { "name", "", do_info_name, "", "show the current VM name" }, + { "uuid", "", do_info_uuid, + "", "show the current VM UUID" }, #if defined(TARGET_PPC) { "cpustats", "", do_info_cpu_stats, "", "show CPU statistics", }, @@ -1386,6 +1541,7 @@ { "slirp", "", do_info_slirp, "", "show SLIRP statistics", }, #endif + { "migrate", "", do_info_migrate, "", "show migration status" }, { NULL, NULL, }, }; @@ -1400,12 +1556,12 @@ typedef struct MonitorDef { const char *name; int offset; - target_long (*get_value)(struct MonitorDef *md, int val); + target_long (*get_value)(const struct MonitorDef *md, int val); int type; } MonitorDef; #if defined(TARGET_I386) -static target_long monitor_get_pc (struct MonitorDef *md, int val) +static target_long monitor_get_pc (const struct MonitorDef *md, int val) { CPUState *env = mon_get_cpu(); if (!env) @@ -1415,7 +1571,7 @@ #endif #if defined(TARGET_PPC) -static target_long monitor_get_ccr (struct MonitorDef *md, int val) +static target_long monitor_get_ccr (const struct MonitorDef *md, int val) { CPUState *env = mon_get_cpu(); unsigned int u; @@ -1431,7 +1587,7 @@ return u; } -static target_long monitor_get_msr (struct MonitorDef *md, int val) +static target_long monitor_get_msr (const struct MonitorDef *md, int val) { CPUState *env = mon_get_cpu(); if (!env) @@ -1439,15 +1595,15 @@ return env->msr; } -static target_long monitor_get_xer (struct MonitorDef *md, int val) +static target_long monitor_get_xer (const struct MonitorDef *md, int val) { CPUState *env = mon_get_cpu(); if (!env) return 0; - return ppc_load_xer(env); + return env->xer; } -static target_long monitor_get_decr (struct MonitorDef *md, int val) +static target_long monitor_get_decr (const struct MonitorDef *md, int val) { CPUState *env = mon_get_cpu(); if (!env) @@ -1455,7 +1611,7 @@ return cpu_ppc_load_decr(env); } -static target_long monitor_get_tbu (struct MonitorDef *md, int val) +static target_long monitor_get_tbu (const struct MonitorDef *md, int val) { CPUState *env = mon_get_cpu(); if (!env) @@ -1463,7 +1619,7 @@ return cpu_ppc_load_tbu(env); } -static target_long monitor_get_tbl (struct MonitorDef *md, int val) +static target_long monitor_get_tbl (const struct MonitorDef *md, int val) { CPUState *env = mon_get_cpu(); if (!env) @@ -1474,7 +1630,7 @@ #if defined(TARGET_SPARC) #ifndef TARGET_SPARC64 -static target_long monitor_get_psr (struct MonitorDef *md, int val) +static target_long monitor_get_psr (const struct MonitorDef *md, int val) { CPUState *env = mon_get_cpu(); if (!env) @@ -1483,7 +1639,7 @@ } #endif -static target_long monitor_get_reg(struct MonitorDef *md, int val) +static target_long monitor_get_reg(const struct MonitorDef *md, int val) { CPUState *env = mon_get_cpu(); if (!env) @@ -1492,7 +1648,7 @@ } #endif -static MonitorDef monitor_defs[] = { +static const MonitorDef monitor_defs[] = { #ifdef TARGET_I386 #define SEG(name, seg) \ @@ -1743,7 +1899,7 @@ /* return 0 if OK, -1 if not found, -2 if no CPU defined */ static int get_monitor_def(target_long *pval, const char *name) { - MonitorDef *md; + const MonitorDef *md; void *ptr; for(md = monitor_defs; md->name != NULL; md++) { @@ -2037,11 +2193,22 @@ const char *p, *pstart, *typestr; char *q; int c, nb_args, len, i, has_arg; - term_cmd_t *cmd; + const term_cmd_t *cmd; char cmdname[256]; char buf[1024]; void *str_allocated[MAX_ARGS]; void *args[MAX_ARGS]; + void (*handler_0)(void); + void (*handler_1)(void *arg0); + void (*handler_2)(void *arg0, void *arg1); + void (*handler_3)(void *arg0, void *arg1, void *arg2); + void (*handler_4)(void *arg0, void *arg1, void *arg2, void *arg3); + void (*handler_5)(void *arg0, void *arg1, void *arg2, void *arg3, + void *arg4); + void (*handler_6)(void *arg0, void *arg1, void *arg2, void *arg3, + void *arg4, void *arg5); + void (*handler_7)(void *arg0, void *arg1, void *arg2, void *arg3, + void *arg4, void *arg5, void *arg6); #ifdef DEBUG term_printf("command='%s'\n", cmdline); @@ -2117,7 +2284,7 @@ goto fail; } str = qemu_malloc(strlen(buf) + 1); - strcpy(str, buf); + pstrcpy(str, sizeof(buf), buf); str_allocated[nb_args] = str; add_str: if (nb_args >= MAX_ARGS) { @@ -2189,8 +2356,8 @@ /* for 'i', not specifying a size gives -1 as size */ if (size < 0) size = default_fmt_size; + default_fmt_size = size; } - default_fmt_size = size; default_fmt_format = format; } else { count = 1; @@ -2304,28 +2471,36 @@ switch(nb_args) { case 0: - cmd->handler(); + handler_0 = cmd->handler; + handler_0(); break; case 1: - cmd->handler(args[0]); + handler_1 = cmd->handler; + handler_1(args[0]); break; case 2: - cmd->handler(args[0], args[1]); + handler_2 = cmd->handler; + handler_2(args[0], args[1]); break; case 3: - cmd->handler(args[0], args[1], args[2]); + handler_3 = cmd->handler; + handler_3(args[0], args[1], args[2]); break; case 4: - cmd->handler(args[0], args[1], args[2], args[3]); + handler_4 = cmd->handler; + handler_4(args[0], args[1], args[2], args[3]); break; case 5: - cmd->handler(args[0], args[1], args[2], args[3], args[4]); + handler_5 = cmd->handler; + handler_5(args[0], args[1], args[2], args[3], args[4]); break; case 6: - cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5]); + handler_6 = cmd->handler; + handler_6(args[0], args[1], args[2], args[3], args[4], args[5]); break; case 7: - cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + handler_7 = cmd->handler; + handler_7(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); break; default: term_printf("unsupported number of arguments: %d\n", nb_args); @@ -2376,7 +2551,7 @@ if (!p) { input_path_len = 0; pstrcpy(file_prefix, sizeof(file_prefix), input); - strcpy(path, "."); + pstrcpy(path, sizeof(path), "."); } else { input_path_len = p - input + 1; memcpy(path, input, input_path_len); @@ -2398,13 +2573,15 @@ break; if (strstart(d->d_name, file_prefix, NULL)) { memcpy(file, input, input_path_len); - strcpy(file + input_path_len, d->d_name); + if (input_path_len < sizeof(file)) + pstrcpy(file + input_path_len, sizeof(file) - input_path_len, + d->d_name); /* stat the file to find out if it's a directory. * In that case add a slash to speed up typing long paths */ stat(file, &sb); if(S_ISDIR(sb.st_mode)) - strcat(file, "/"); + pstrcat(file, sizeof(file), "/"); add_completion(file); } } @@ -2453,7 +2630,7 @@ char *args[MAX_ARGS]; int nb_args, i, len; const char *ptype, *str; - term_cmd_t *cmd; + const term_cmd_t *cmd; const KeyDef *key; parse_cmdline(cmdline, &nb_args, args); @@ -2543,12 +2720,27 @@ readline_handle_byte(buf[i]); } -static void monitor_start_input(void); +static int monitor_suspended; static void monitor_handle_command1(void *opaque, const char *cmdline) { monitor_handle_command(cmdline); - monitor_start_input(); + if (!monitor_suspended) + monitor_start_input(); + else + monitor_suspended = 2; +} + +void monitor_suspend(void) +{ + monitor_suspended = 1; +} + +void monitor_resume(void) +{ + if (monitor_suspended == 2) + monitor_start_input(); + monitor_suspended = 0; } static void monitor_start_input(void) @@ -2574,6 +2766,9 @@ int i; if (is_first_init) { + key_timer = qemu_new_timer(vm_clock, release_keys, NULL); + if (!key_timer) + return; for (i = 0; i < MAX_MON; i++) { monitor_hd[i] = NULL; } @@ -2609,12 +2804,19 @@ char *buf, int buf_size) { int i; + int old_focus[MAX_MON]; if (is_password) { - for (i = 0; i < MAX_MON; i++) - if (monitor_hd[i] && monitor_hd[i]->focus == 0) + for (i = 0; i < MAX_MON; i++) { + old_focus[i] = 0; + if (monitor_hd[i]) { + old_focus[i] = monitor_hd[i]->focus; + monitor_hd[i]->focus = 0; qemu_chr_send_event(monitor_hd[i], CHR_EVENT_FOCUS); + } + } } + readline_start(prompt, is_password, monitor_readline_cb, NULL); monitor_readline_buf = buf; monitor_readline_buf_size = buf_size; @@ -2622,4 +2824,10 @@ while (monitor_readline_started) { main_loop_wait(10); } + /* restore original focus */ + if (is_password) { + for (i = 0; i < MAX_MON; i++) + if (old_focus[i]) + monitor_hd[i]->focus = old_focus[i]; + } } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/nbd.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/nbd.c --- qemu-0.9.1/nbd.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/nbd.c 2008-09-15 16:51:35.000000000 +0100 @@ -0,0 +1,661 @@ +/* + * Copyright (C) 2005 Anthony Liguori + * + * Network Block Device + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "nbd.h" + +#include +#include +#ifndef _WIN32 +#include +#endif +#ifdef __sun__ +#include +#endif +#include +#include + +#include "qemu_socket.h" + +//#define DEBUG_NBD + +#ifdef DEBUG_NBD +#define TRACE(msg, ...) do { \ + LOG(msg, ## __VA_ARGS__); \ +} while(0) +#else +#define TRACE(msg, ...) \ + do { } while (0) +#endif + +#define LOG(msg, ...) do { \ + fprintf(stderr, "%s:%s():L%d: " msg "\n", \ + __FILE__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \ +} while(0) + +/* This is all part of the "official" NBD API */ + +#define NBD_REQUEST_MAGIC 0x25609513 +#define NBD_REPLY_MAGIC 0x67446698 + +#define NBD_SET_SOCK _IO(0xab, 0) +#define NBD_SET_BLKSIZE _IO(0xab, 1) +#define NBD_SET_SIZE _IO(0xab, 2) +#define NBD_DO_IT _IO(0xab, 3) +#define NBD_CLEAR_SOCK _IO(0xab, 4) +#define NBD_CLEAR_QUE _IO(0xab, 5) +#define NBD_PRINT_DEBUG _IO(0xab, 6) +#define NBD_SET_SIZE_BLOCKS _IO(0xab, 7) +#define NBD_DISCONNECT _IO(0xab, 8) + +/* That's all folks */ + +#define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true) +#define write_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, false) + +size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read) +{ + size_t offset = 0; + + while (offset < size) { + ssize_t len; + + if (do_read) { + len = recv(fd, buffer + offset, size - offset, 0); + } else { + len = send(fd, buffer + offset, size - offset, 0); + } + + if (len == -1) + errno = socket_error(); + + /* recoverable error */ + if (len == -1 && (errno == EAGAIN || errno == EINTR)) { + continue; + } + + /* eof */ + if (len == 0) { + break; + } + + /* unrecoverable error */ + if (len == -1) { + return 0; + } + + offset += len; + } + + return offset; +} + +int tcp_socket_outgoing(const char *address, uint16_t port) +{ + int s; + struct in_addr in; + struct sockaddr_in addr; + + s = socket(PF_INET, SOCK_STREAM, 0); + if (s == -1) { + return -1; + } + + if (inet_aton(address, &in) == 0) { + struct hostent *ent; + + ent = gethostbyname(address); + if (ent == NULL) { + goto error; + } + + memcpy(&in, ent->h_addr, sizeof(in)); + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + memcpy(&addr.sin_addr.s_addr, &in, sizeof(in)); + + if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + goto error; + } + + return s; +error: + closesocket(s); + return -1; +} + +int tcp_socket_incoming(const char *address, uint16_t port) +{ + int s; + struct in_addr in; + struct sockaddr_in addr; + int opt; + + s = socket(PF_INET, SOCK_STREAM, 0); + if (s == -1) { + return -1; + } + + if (inet_aton(address, &in) == 0) { + struct hostent *ent; + + ent = gethostbyname(address); + if (ent == NULL) { + goto error; + } + + memcpy(&in, ent->h_addr, sizeof(in)); + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + memcpy(&addr.sin_addr.s_addr, &in, sizeof(in)); + + opt = 1; + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) { + goto error; + } + + if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + goto error; + } + + if (listen(s, 128) == -1) { + goto error; + } + + return s; +error: + closesocket(s); + return -1; +} + +#ifndef _WIN32 +int unix_socket_incoming(const char *path) +{ + int s; + struct sockaddr_un addr; + + s = socket(PF_UNIX, SOCK_STREAM, 0); + if (s == -1) { + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + pstrcpy(addr.sun_path, sizeof(addr.sun_path), path); + + if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + goto error; + } + + if (listen(s, 128) == -1) { + goto error; + } + + return s; +error: + closesocket(s); + return -1; +} + +int unix_socket_outgoing(const char *path) +{ + int s; + struct sockaddr_un addr; + + s = socket(PF_UNIX, SOCK_STREAM, 0); + if (s == -1) { + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + pstrcpy(addr.sun_path, sizeof(addr.sun_path), path); + + if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + goto error; + } + + return s; +error: + closesocket(s); + return -1; +} +#else +int unix_socket_incoming(const char *path) +{ + errno = ENOTSUP; + return -1; +} + +int unix_socket_outgoing(const char *path) +{ + errno = ENOTSUP; + return -1; +} +#endif + + +/* Basic flow + + Server Client + + Negotiate + Request + Response + Request + Response + ... + ... + Request (type == 2) +*/ + +int nbd_negotiate(int csock, off_t size) +{ + char buf[8 + 8 + 8 + 128]; + + /* Negotiate + [ 0 .. 7] passwd ("NBDMAGIC") + [ 8 .. 15] magic (0x00420281861253) + [16 .. 23] size + [24 .. 151] reserved (0) + */ + + TRACE("Beginning negotiation."); + memcpy(buf, "NBDMAGIC", 8); + cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL); + cpu_to_be64w((uint64_t*)(buf + 16), size); + memset(buf + 24, 0, 128); + + if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { + LOG("write failed"); + errno = EINVAL; + return -1; + } + + TRACE("Negotation succeeded."); + + return 0; +} + +int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize) +{ + char buf[8 + 8 + 8 + 128]; + uint64_t magic; + + TRACE("Receiving negotation."); + + if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { + LOG("read failed"); + errno = EINVAL; + return -1; + } + + magic = be64_to_cpup((uint64_t*)(buf + 8)); + *size = be64_to_cpup((uint64_t*)(buf + 16)); + *blocksize = 1024; + + TRACE("Magic is %c%c%c%c%c%c%c%c", + isprint(buf[0]) ? buf[0] : '.', + isprint(buf[1]) ? buf[1] : '.', + isprint(buf[2]) ? buf[2] : '.', + isprint(buf[3]) ? buf[3] : '.', + isprint(buf[4]) ? buf[4] : '.', + isprint(buf[5]) ? buf[5] : '.', + isprint(buf[6]) ? buf[6] : '.', + isprint(buf[7]) ? buf[7] : '.'); + TRACE("Magic is 0x%" PRIx64, magic); + TRACE("Size is %" PRIu64, *size); + + if (memcmp(buf, "NBDMAGIC", 8) != 0) { + LOG("Invalid magic received"); + errno = EINVAL; + return -1; + } + + TRACE("Checking magic"); + + if (magic != 0x00420281861253LL) { + LOG("Bad magic received"); + errno = EINVAL; + return -1; + } + return 0; +} + +#ifndef _WIN32 +int nbd_init(int fd, int csock, off_t size, size_t blocksize) +{ + TRACE("Setting block size to %lu", (unsigned long)blocksize); + + if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) { + int serrno = errno; + LOG("Failed setting NBD block size"); + errno = serrno; + return -1; + } + + TRACE("Setting size to %llu block(s)", + (unsigned long long)(size / blocksize)); + + if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) == -1) { + int serrno = errno; + LOG("Failed setting size (in blocks)"); + errno = serrno; + return -1; + } + + TRACE("Clearing NBD socket"); + + if (ioctl(fd, NBD_CLEAR_SOCK) == -1) { + int serrno = errno; + LOG("Failed clearing NBD socket"); + errno = serrno; + return -1; + } + + TRACE("Setting NBD socket"); + + if (ioctl(fd, NBD_SET_SOCK, csock) == -1) { + int serrno = errno; + LOG("Failed to set NBD socket"); + errno = serrno; + return -1; + } + + TRACE("Negotiation ended"); + + return 0; +} + +int nbd_disconnect(int fd) +{ + ioctl(fd, NBD_CLEAR_QUE); + ioctl(fd, NBD_DISCONNECT); + ioctl(fd, NBD_CLEAR_SOCK); + return 0; +} + +int nbd_client(int fd, int csock) +{ + int ret; + int serrno; + + TRACE("Doing NBD loop"); + + ret = ioctl(fd, NBD_DO_IT); + serrno = errno; + + TRACE("NBD loop returned %d: %s", ret, strerror(serrno)); + + TRACE("Clearing NBD queue"); + ioctl(fd, NBD_CLEAR_QUE); + + TRACE("Clearing NBD socket"); + ioctl(fd, NBD_CLEAR_SOCK); + + errno = serrno; + return ret; +} +#else +int nbd_init(int fd, int csock, off_t size, size_t blocksize) +{ + errno = ENOTSUP; + return -1; +} + +int nbd_disconnect(int fd) +{ + errno = ENOTSUP; + return -1; +} + +int nbd_client(int fd, int csock) +{ + errno = ENOTSUP; + return -1; +} +#endif + +int nbd_send_request(int csock, struct nbd_request *request) +{ + uint8_t buf[4 + 4 + 8 + 8 + 4]; + + cpu_to_be32w((uint32_t*)buf, NBD_REQUEST_MAGIC); + cpu_to_be32w((uint32_t*)(buf + 4), request->type); + cpu_to_be64w((uint64_t*)(buf + 8), request->handle); + cpu_to_be64w((uint64_t*)(buf + 16), request->from); + cpu_to_be32w((uint32_t*)(buf + 24), request->len); + + TRACE("Sending request to client"); + + if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { + LOG("writing to socket failed"); + errno = EINVAL; + return -1; + } + return 0; +} + + +static int nbd_receive_request(int csock, struct nbd_request *request) +{ + uint8_t buf[4 + 4 + 8 + 8 + 4]; + uint32_t magic; + + if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { + LOG("read failed"); + errno = EINVAL; + return -1; + } + + /* Request + [ 0 .. 3] magic (NBD_REQUEST_MAGIC) + [ 4 .. 7] type (0 == READ, 1 == WRITE) + [ 8 .. 15] handle + [16 .. 23] from + [24 .. 27] len + */ + + magic = be32_to_cpup((uint32_t*)buf); + request->type = be32_to_cpup((uint32_t*)(buf + 4)); + request->handle = be64_to_cpup((uint64_t*)(buf + 8)); + request->from = be64_to_cpup((uint64_t*)(buf + 16)); + request->len = be32_to_cpup((uint32_t*)(buf + 24)); + + TRACE("Got request: " + "{ magic = 0x%x, .type = %d, from = %" PRIu64" , len = %u }", + magic, request->type, request->from, request->len); + + if (magic != NBD_REQUEST_MAGIC) { + LOG("invalid magic (got 0x%x)", magic); + errno = EINVAL; + return -1; + } + return 0; +} + +int nbd_receive_reply(int csock, struct nbd_reply *reply) +{ + uint8_t buf[4 + 4 + 8]; + uint32_t magic; + + memset(buf, 0xAA, sizeof(buf)); + + if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { + LOG("read failed"); + errno = EINVAL; + return -1; + } + + /* Reply + [ 0 .. 3] magic (NBD_REPLY_MAGIC) + [ 4 .. 7] error (0 == no error) + [ 7 .. 15] handle + */ + + magic = be32_to_cpup((uint32_t*)buf); + reply->error = be32_to_cpup((uint32_t*)(buf + 4)); + reply->handle = be64_to_cpup((uint64_t*)(buf + 8)); + + TRACE("Got reply: " + "{ magic = 0x%x, .error = %d, handle = %" PRIu64" }", + magic, reply->error, reply->handle); + + if (magic != NBD_REPLY_MAGIC) { + LOG("invalid magic (got 0x%x)", magic); + errno = EINVAL; + return -1; + } + return 0; +} + +static int nbd_send_reply(int csock, struct nbd_reply *reply) +{ + uint8_t buf[4 + 4 + 8]; + + /* Reply + [ 0 .. 3] magic (NBD_REPLY_MAGIC) + [ 4 .. 7] error (0 == no error) + [ 7 .. 15] handle + */ + cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC); + cpu_to_be32w((uint32_t*)(buf + 4), reply->error); + cpu_to_be64w((uint64_t*)(buf + 8), reply->handle); + + TRACE("Sending response to client"); + + if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { + LOG("writing to socket failed"); + errno = EINVAL; + return -1; + } + return 0; +} + +int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, + off_t *offset, bool readonly, uint8_t *data, int data_size) +{ + struct nbd_request request; + struct nbd_reply reply; + + TRACE("Reading request."); + + if (nbd_receive_request(csock, &request) == -1) + return -1; + + if (request.len > data_size) { + LOG("len (%u) is larger than max len (%u)", + request.len, data_size); + errno = EINVAL; + return -1; + } + + if ((request.from + request.len) < request.from) { + LOG("integer overflow detected! " + "you're probably being attacked"); + errno = EINVAL; + return -1; + } + + if ((request.from + request.len) > size) { + LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64 + ", Offset: %" PRIu64 "\n", + request.from, request.len, size, dev_offset); + LOG("requested operation past EOF--bad client?"); + errno = EINVAL; + return -1; + } + + TRACE("Decoding type"); + + reply.handle = request.handle; + reply.error = 0; + + switch (request.type) { + case NBD_CMD_READ: + TRACE("Request type is READ"); + + if (bdrv_read(bs, (request.from + dev_offset) / 512, data, + request.len / 512) == -1) { + LOG("reading from file failed"); + errno = EINVAL; + return -1; + } + *offset += request.len; + + TRACE("Read %u byte(s)", request.len); + + if (nbd_send_reply(csock, &reply) == -1) + return -1; + + TRACE("Sending data to client"); + + if (write_sync(csock, data, request.len) != request.len) { + LOG("writing to socket failed"); + errno = EINVAL; + return -1; + } + break; + case NBD_CMD_WRITE: + TRACE("Request type is WRITE"); + + TRACE("Reading %u byte(s)", request.len); + + if (read_sync(csock, data, request.len) != request.len) { + LOG("reading from socket failed"); + errno = EINVAL; + return -1; + } + + if (readonly) { + TRACE("Server is read-only, return error"); + reply.error = 1; + } else { + TRACE("Writing to device"); + + if (bdrv_write(bs, (request.from + dev_offset) / 512, + data, request.len / 512) == -1) { + LOG("writing to file failed"); + errno = EINVAL; + return -1; + } + + *offset += request.len; + } + + if (nbd_send_reply(csock, &reply) == -1) + return -1; + break; + case NBD_CMD_DISC: + TRACE("Request type is DISCONNECT"); + errno = 0; + return 1; + default: + LOG("invalid request type (%u) received", request.type); + errno = EINVAL; + return -1; + } + + TRACE("Request/Reply complete"); + + return 0; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/nbd.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/nbd.h --- qemu-0.9.1/nbd.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/nbd.h 2008-09-10 16:23:19.000000000 +0100 @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2005 Anthony Liguori + * + * Network Block Device + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NBD_H +#define NBD_H + +#include +#include + +#include +#include "block_int.h" + +struct nbd_request { + uint32_t type; + uint64_t handle; + uint64_t from; + uint32_t len; +}; + +struct nbd_reply { + uint32_t error; + uint64_t handle; +}; + +enum { + NBD_CMD_READ = 0, + NBD_CMD_WRITE = 1, + NBD_CMD_DISC = 2 +}; + +size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read); +int tcp_socket_outgoing(const char *address, uint16_t port); +int tcp_socket_incoming(const char *address, uint16_t port); +int unix_socket_outgoing(const char *path); +int unix_socket_incoming(const char *path); + +int nbd_negotiate(int csock, off_t size); +int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize); +int nbd_init(int fd, int csock, off_t size, size_t blocksize); +int nbd_send_request(int csock, struct nbd_request *request); +int nbd_receive_reply(int csock, struct nbd_reply *reply); +int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, + off_t *offset, bool readonly, uint8_t *data, int data_size); +int nbd_client(int fd, int csock); +int nbd_disconnect(int fd); + +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/net.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/net.c --- qemu-0.9.1/net.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/net.c 2008-11-11 21:20:14.000000000 +0000 @@ -0,0 +1,1599 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * 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 "qemu-common.h" +#include "net.h" +#include "console.h" +#include "sysemu.h" +#include "qemu-timer.h" +#include "qemu-char.h" +#include "audio/audio.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __NetBSD__ +#include +#endif +#ifdef __linux__ +#include +#endif +#include +#include +#include +#include +#ifdef _BSD +#include +#ifdef __FreeBSD__ +#include +#else +#include +#endif +#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__) +#include +#else +#ifdef __linux__ +#include +#include +#include + +/* For the benefit of older linux systems which don't supply it, + we use a local copy of hpet.h. */ +/* #include */ +#include "hpet.h" + +#include +#include +#endif +#ifdef __sun__ +#include +#include +#include +#include +#include +#include +#include +#include // must come after ip.h +#include +#include +#include +#include +#include +#endif +#endif +#endif + +#include "qemu_socket.h" + +#if defined(CONFIG_SLIRP) +#include "libslirp.h" +#endif + +#if defined(__OpenBSD__) +#include +#endif + +#if defined(CONFIG_VDE) +#include +#endif + +#ifdef _WIN32 +#include +#include +#include +#define getopt_long_only getopt_long +#define memalign(align, size) malloc(size) +#endif + +#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" +#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown" +#ifdef __sun__ +#define SMBD_COMMAND "/usr/sfw/sbin/smbd" +#else +#define SMBD_COMMAND "/usr/sbin/smbd" +#endif + +static VLANState *first_vlan; + +/***********************************************************/ +/* network device redirectors */ + +#if defined(DEBUG_NET) || defined(DEBUG_SLIRP) +static void hex_dump(FILE *f, const uint8_t *buf, int size) +{ + int len, i, j, c; + + for(i=0;i 16) + len = 16; + fprintf(f, "%08x ", i); + for(j=0;j<16;j++) { + if (j < len) + fprintf(f, " %02x", buf[i+j]); + else + fprintf(f, " "); + } + fprintf(f, " "); + for(j=0;j '~') + c = '.'; + fprintf(f, "%c", c); + } + fprintf(f, "\n"); + } +} +#endif + +static int parse_macaddr(uint8_t *macaddr, const char *p) +{ + int i; + char *last_char; + long int offset; + + errno = 0; + offset = strtol(p, &last_char, 0); + if (0 == errno && '\0' == *last_char && + offset >= 0 && offset <= 0xFFFFFF) { + macaddr[3] = (offset & 0xFF0000) >> 16; + macaddr[4] = (offset & 0xFF00) >> 8; + macaddr[5] = offset & 0xFF; + return 0; + } else { + for(i = 0; i < 6; i++) { + macaddr[i] = strtol(p, (char **)&p, 16); + if (i == 5) { + if (*p != '\0') + return -1; + } else { + if (*p != ':' && *p != '-') + return -1; + p++; + } + } + return 0; + } + + return -1; +} + +static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) +{ + const char *p, *p1; + int len; + p = *pp; + p1 = strchr(p, sep); + if (!p1) + return -1; + len = p1 - p; + p1++; + if (buf_size > 0) { + if (len > buf_size - 1) + len = buf_size - 1; + memcpy(buf, p, len); + buf[len] = '\0'; + } + *pp = p1; + return 0; +} + +int parse_host_src_port(struct sockaddr_in *haddr, + struct sockaddr_in *saddr, + const char *input_str) +{ + char *str = strdup(input_str); + char *host_str = str; + char *src_str; + const char *src_str2; + char *ptr; + + /* + * Chop off any extra arguments at the end of the string which + * would start with a comma, then fill in the src port information + * if it was provided else use the "any address" and "any port". + */ + if ((ptr = strchr(str,','))) + *ptr = '\0'; + + if ((src_str = strchr(input_str,'@'))) { + *src_str = '\0'; + src_str++; + } + + if (parse_host_port(haddr, host_str) < 0) + goto fail; + + src_str2 = src_str; + if (!src_str || *src_str == '\0') + src_str2 = ":0"; + + if (parse_host_port(saddr, src_str2) < 0) + goto fail; + + free(str); + return(0); + +fail: + free(str); + return -1; +} + +int parse_host_port(struct sockaddr_in *saddr, const char *str) +{ + char buf[512]; + struct hostent *he; + const char *p, *r; + int port; + + p = str; + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) + return -1; + saddr->sin_family = AF_INET; + if (buf[0] == '\0') { + saddr->sin_addr.s_addr = 0; + } else { + if (isdigit(buf[0])) { + if (!inet_aton(buf, &saddr->sin_addr)) + return -1; + } else { + if ((he = gethostbyname(buf)) == NULL) + return - 1; + saddr->sin_addr = *(struct in_addr *)he->h_addr; + } + } + port = strtol(p, (char **)&r, 0); + if (r == p) + return -1; + saddr->sin_port = htons(port); + return 0; +} + +#ifndef _WIN32 +int parse_unix_path(struct sockaddr_un *uaddr, const char *str) +{ + const char *p; + int len; + + len = MIN(108, strlen(str)); + p = strchr(str, ','); + if (p) + len = MIN(len, p - str); + + memset(uaddr, 0, sizeof(*uaddr)); + + uaddr->sun_family = AF_UNIX; + memcpy(uaddr->sun_path, str, len); + + return 0; +} +#endif + +VLANClientState *qemu_new_vlan_client(VLANState *vlan, + IOReadHandler *fd_read, + IOCanRWHandler *fd_can_read, + void *opaque) +{ + VLANClientState *vc, **pvc; + vc = qemu_mallocz(sizeof(VLANClientState)); + if (!vc) + return NULL; + vc->fd_read = fd_read; + vc->fd_can_read = fd_can_read; + vc->opaque = opaque; + vc->vlan = vlan; + + vc->next = NULL; + pvc = &vlan->first_client; + while (*pvc != NULL) + pvc = &(*pvc)->next; + *pvc = vc; + return vc; +} + +void qemu_del_vlan_client(VLANClientState *vc) +{ + VLANClientState **pvc = &vc->vlan->first_client; + + while (*pvc != NULL) + if (*pvc == vc) { + *pvc = vc->next; + free(vc); + break; + } else + pvc = &(*pvc)->next; +} + +int qemu_can_send_packet(VLANClientState *vc1) +{ + VLANState *vlan = vc1->vlan; + VLANClientState *vc; + + for(vc = vlan->first_client; vc != NULL; vc = vc->next) { + if (vc != vc1) { + if (vc->fd_can_read && vc->fd_can_read(vc->opaque)) + return 1; + } + } + return 0; +} + +void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size) +{ + VLANState *vlan = vc1->vlan; + VLANClientState *vc; + +#ifdef DEBUG_NET + printf("vlan %d send:\n", vlan->id); + hex_dump(stdout, buf, size); +#endif + for(vc = vlan->first_client; vc != NULL; vc = vc->next) { + if (vc != vc1) { + vc->fd_read(vc->opaque, buf, size); + } + } +} + +#if defined(CONFIG_SLIRP) + +/* slirp network adapter */ + +static int slirp_inited; +static VLANClientState *slirp_vc; + +int slirp_can_output(void) +{ + return !slirp_vc || qemu_can_send_packet(slirp_vc); +} + +void slirp_output(const uint8_t *pkt, int pkt_len) +{ +#ifdef DEBUG_SLIRP + printf("slirp output:\n"); + hex_dump(stdout, pkt, pkt_len); +#endif + if (!slirp_vc) + return; + qemu_send_packet(slirp_vc, pkt, pkt_len); +} + +int slirp_is_inited(void) +{ + return slirp_inited; +} + +static void slirp_receive(void *opaque, const uint8_t *buf, int size) +{ +#ifdef DEBUG_SLIRP + printf("slirp input:\n"); + hex_dump(stdout, buf, size); +#endif + slirp_input(buf, size); +} + +static int net_slirp_init(VLANState *vlan) +{ + if (!slirp_inited) { + slirp_inited = 1; + slirp_init(); + } + slirp_vc = qemu_new_vlan_client(vlan, + slirp_receive, NULL, NULL); + snprintf(slirp_vc->info_str, sizeof(slirp_vc->info_str), "user redirector"); + return 0; +} + +void net_slirp_redir(const char *redir_str) +{ + int is_udp; + char buf[256], *r; + const char *p; + struct in_addr guest_addr; + int host_port, guest_port; + + if (!slirp_inited) { + slirp_inited = 1; + slirp_init(); + } + + p = redir_str; + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) + goto fail; + if (!strcmp(buf, "tcp")) { + is_udp = 0; + } else if (!strcmp(buf, "udp")) { + is_udp = 1; + } else { + goto fail; + } + + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) + goto fail; + host_port = strtol(buf, &r, 0); + if (r == buf) + goto fail; + + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) + goto fail; + if (buf[0] == '\0') { + pstrcpy(buf, sizeof(buf), "10.0.2.15"); + } + if (!inet_aton(buf, &guest_addr)) + goto fail; + + guest_port = strtol(p, &r, 0); + if (r == p) + goto fail; + + if (slirp_redir(is_udp, host_port, guest_addr, guest_port) < 0) { + fprintf(stderr, "qemu: could not set up redirection\n"); + exit(1); + } + return; + fail: + fprintf(stderr, "qemu: syntax: -redir [tcp|udp]:host-port:[guest-host]:guest-port\n"); + exit(1); +} + +#ifndef _WIN32 + +static char smb_dir[1024]; + +static void erase_dir(char *dir_name) +{ + DIR *d; + struct dirent *de; + char filename[1024]; + + /* erase all the files in the directory */ + if ((d = opendir(dir_name)) != 0) { + for(;;) { + de = readdir(d); + if (!de) + break; + if (strcmp(de->d_name, ".") != 0 && + strcmp(de->d_name, "..") != 0) { + snprintf(filename, sizeof(filename), "%s/%s", + smb_dir, de->d_name); + if (unlink(filename) != 0) /* is it a directory? */ + erase_dir(filename); + } + } + closedir(d); + rmdir(dir_name); + } +} + +/* automatic user mode samba server configuration */ +static void smb_exit(void) +{ + erase_dir(smb_dir); +} + +/* automatic user mode samba server configuration */ +void net_slirp_smb(const char *exported_dir) +{ + char smb_conf[1024]; + char smb_cmdline[1024]; + FILE *f; + + if (!slirp_inited) { + slirp_inited = 1; + slirp_init(); + } + + /* XXX: better tmp dir construction */ + snprintf(smb_dir, sizeof(smb_dir), "/tmp/qemu-smb.%d", getpid()); + if (mkdir(smb_dir, 0700) < 0) { + fprintf(stderr, "qemu: could not create samba server dir '%s'\n", smb_dir); + exit(1); + } + snprintf(smb_conf, sizeof(smb_conf), "%s/%s", smb_dir, "smb.conf"); + + f = fopen(smb_conf, "w"); + if (!f) { + fprintf(stderr, "qemu: could not create samba server configuration file '%s'\n", smb_conf); + exit(1); + } + fprintf(f, + "[global]\n" + "private dir=%s\n" + "smb ports=0\n" + "socket address=127.0.0.1\n" + "pid directory=%s\n" + "lock directory=%s\n" + "log file=%s/log.smbd\n" + "smb passwd file=%s/smbpasswd\n" + "security = share\n" + "[qemu]\n" + "path=%s\n" + "read only=no\n" + "guest ok=yes\n", + smb_dir, + smb_dir, + smb_dir, + smb_dir, + smb_dir, + exported_dir + ); + fclose(f); + atexit(smb_exit); + + snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s", + SMBD_COMMAND, smb_conf); + + slirp_add_exec(0, smb_cmdline, 4, 139); +} + +#endif /* !defined(_WIN32) */ +void do_info_slirp(void) +{ + slirp_stats(); +} + +#endif /* CONFIG_SLIRP */ + +#if !defined(_WIN32) + +typedef struct TAPState { + VLANClientState *vc; + int fd; + char down_script[1024]; +} TAPState; + +static void tap_receive(void *opaque, const uint8_t *buf, int size) +{ + TAPState *s = opaque; + int ret; + for(;;) { + ret = write(s->fd, buf, size); + if (ret < 0 && (errno == EINTR || errno == EAGAIN)) { + } else { + break; + } + } +} + +static void tap_send(void *opaque) +{ + TAPState *s = opaque; + uint8_t buf[4096]; + int size; + +#ifdef __sun__ + struct strbuf sbuf; + int f = 0; + sbuf.maxlen = sizeof(buf); + sbuf.buf = buf; + size = getmsg(s->fd, NULL, &sbuf, &f) >=0 ? sbuf.len : -1; +#else + size = read(s->fd, buf, sizeof(buf)); +#endif + if (size > 0) { + qemu_send_packet(s->vc, buf, size); + } +} + +/* fd support */ + +static TAPState *net_tap_fd_init(VLANState *vlan, int fd) +{ + TAPState *s; + + s = qemu_mallocz(sizeof(TAPState)); + if (!s) + return NULL; + s->fd = fd; + s->vc = qemu_new_vlan_client(vlan, tap_receive, NULL, s); + qemu_set_fd_handler(s->fd, tap_send, NULL, s); + snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: fd=%d", fd); + return s; +} + +#if defined (_BSD) || defined (__FreeBSD_kernel__) +static int tap_open(char *ifname, int ifname_size) +{ + int fd; + char *dev; + struct stat s; + + TFR(fd = open("/dev/tap", O_RDWR)); + if (fd < 0) { + fprintf(stderr, "warning: could not open /dev/tap: no virtual network emulation\n"); + return -1; + } + + fstat(fd, &s); + dev = devname(s.st_rdev, S_IFCHR); + pstrcpy(ifname, ifname_size, dev); + + fcntl(fd, F_SETFL, O_NONBLOCK); + return fd; +} +#elif defined(__sun__) +#define TUNNEWPPA (('T'<<16) | 0x0001) +/* + * Allocate TAP device, returns opened fd. + * Stores dev name in the first arg(must be large enough). + */ +int tap_alloc(char *dev, size_t dev_size) +{ + int tap_fd, if_fd, ppa = -1; + static int ip_fd = 0; + char *ptr; + + static int arp_fd = 0; + int ip_muxid, arp_muxid; + struct strioctl strioc_if, strioc_ppa; + int link_type = I_PLINK;; + struct lifreq ifr; + char actual_name[32] = ""; + + memset(&ifr, 0x0, sizeof(ifr)); + + if( *dev ){ + ptr = dev; + while( *ptr && !isdigit((int)*ptr) ) ptr++; + ppa = atoi(ptr); + } + + /* Check if IP device was opened */ + if( ip_fd ) + close(ip_fd); + + TFR(ip_fd = open("/dev/udp", O_RDWR, 0)); + if (ip_fd < 0) { + syslog(LOG_ERR, "Can't open /dev/ip (actually /dev/udp)"); + return -1; + } + + TFR(tap_fd = open("/dev/tap", O_RDWR, 0)); + if (tap_fd < 0) { + syslog(LOG_ERR, "Can't open /dev/tap"); + return -1; + } + + /* Assign a new PPA and get its unit number. */ + strioc_ppa.ic_cmd = TUNNEWPPA; + strioc_ppa.ic_timout = 0; + strioc_ppa.ic_len = sizeof(ppa); + strioc_ppa.ic_dp = (char *)&ppa; + if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0) + syslog (LOG_ERR, "Can't assign new interface"); + + TFR(if_fd = open("/dev/tap", O_RDWR, 0)); + if (if_fd < 0) { + syslog(LOG_ERR, "Can't open /dev/tap (2)"); + return -1; + } + if(ioctl(if_fd, I_PUSH, "ip") < 0){ + syslog(LOG_ERR, "Can't push IP module"); + return -1; + } + + if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) + syslog(LOG_ERR, "Can't get flags\n"); + + snprintf (actual_name, 32, "tap%d", ppa); + pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name); + + ifr.lifr_ppa = ppa; + /* Assign ppa according to the unit number returned by tun device */ + + if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0) + syslog (LOG_ERR, "Can't set PPA %d", ppa); + if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0) + syslog (LOG_ERR, "Can't get flags\n"); + /* Push arp module to if_fd */ + if (ioctl (if_fd, I_PUSH, "arp") < 0) + syslog (LOG_ERR, "Can't push ARP module (2)"); + + /* Push arp module to ip_fd */ + if (ioctl (ip_fd, I_POP, NULL) < 0) + syslog (LOG_ERR, "I_POP failed\n"); + if (ioctl (ip_fd, I_PUSH, "arp") < 0) + syslog (LOG_ERR, "Can't push ARP module (3)\n"); + /* Open arp_fd */ + TFR(arp_fd = open ("/dev/tap", O_RDWR, 0)); + if (arp_fd < 0) + syslog (LOG_ERR, "Can't open %s\n", "/dev/tap"); + + /* Set ifname to arp */ + strioc_if.ic_cmd = SIOCSLIFNAME; + strioc_if.ic_timout = 0; + strioc_if.ic_len = sizeof(ifr); + strioc_if.ic_dp = (char *)𝔦 + if (ioctl(arp_fd, I_STR, &strioc_if) < 0){ + syslog (LOG_ERR, "Can't set ifname to arp\n"); + } + + if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){ + syslog(LOG_ERR, "Can't link TAP device to IP"); + return -1; + } + + if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0) + syslog (LOG_ERR, "Can't link TAP device to ARP"); + + close (if_fd); + + memset(&ifr, 0x0, sizeof(ifr)); + pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name); + ifr.lifr_ip_muxid = ip_muxid; + ifr.lifr_arp_muxid = arp_muxid; + + if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0) + { + ioctl (ip_fd, I_PUNLINK , arp_muxid); + ioctl (ip_fd, I_PUNLINK, ip_muxid); + syslog (LOG_ERR, "Can't set multiplexor id"); + } + + snprintf(dev, dev_size, "tap%d", ppa); + return tap_fd; +} + +static int tap_open(char *ifname, int ifname_size) +{ + char dev[10]=""; + int fd; + if( (fd = tap_alloc(dev, sizeof(dev))) < 0 ){ + fprintf(stderr, "Cannot allocate TAP device\n"); + return -1; + } + pstrcpy(ifname, ifname_size, dev); + fcntl(fd, F_SETFL, O_NONBLOCK); + return fd; +} +#else +static int tap_open(char *ifname, int ifname_size) +{ + struct ifreq ifr; + int fd, ret; + + TFR(fd = open("/dev/net/tun", O_RDWR)); + if (fd < 0) { + fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n"); + return -1; + } + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + if (ifname[0] != '\0') + pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname); + else + pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d"); + ret = ioctl(fd, TUNSETIFF, (void *) &ifr); + if (ret != 0) { + fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n"); + close(fd); + return -1; + } + pstrcpy(ifname, ifname_size, ifr.ifr_name); + fcntl(fd, F_SETFL, O_NONBLOCK); + return fd; +} +#endif + +static int launch_script(const char *setup_script, const char *ifname, int fd) +{ + int pid, status; + char *args[3]; + char **parg; + + /* try to launch network script */ + pid = fork(); + if (pid >= 0) { + if (pid == 0) { + int open_max = sysconf (_SC_OPEN_MAX), i; + for (i = 0; i < open_max; i++) + if (i != STDIN_FILENO && + i != STDOUT_FILENO && + i != STDERR_FILENO && + i != fd) + close(i); + + parg = args; + *parg++ = (char *)setup_script; + *parg++ = (char *)ifname; + *parg++ = NULL; + execv(setup_script, args); + _exit(1); + } + while (waitpid(pid, &status, 0) != pid); + if (!WIFEXITED(status) || + WEXITSTATUS(status) != 0) { + fprintf(stderr, "%s: could not launch network script\n", + setup_script); + return -1; + } + } + return 0; +} + +static int net_tap_init(VLANState *vlan, const char *ifname1, + const char *setup_script, const char *down_script) +{ + TAPState *s; + int fd; + char ifname[128]; + + if (ifname1 != NULL) + pstrcpy(ifname, sizeof(ifname), ifname1); + else + ifname[0] = '\0'; + TFR(fd = tap_open(ifname, sizeof(ifname))); + if (fd < 0) + return -1; + + if (!setup_script || !strcmp(setup_script, "no")) + setup_script = ""; + if (setup_script[0] != '\0') { + if (launch_script(setup_script, ifname, fd)) + return -1; + } + s = net_tap_fd_init(vlan, fd); + if (!s) + return -1; + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "tap: ifname=%s setup_script=%s", ifname, setup_script); + if (down_script && strcmp(down_script, "no")) + snprintf(s->down_script, sizeof(s->down_script), "%s", down_script); + return 0; +} + +#endif /* !_WIN32 */ + +#if defined(CONFIG_VDE) +typedef struct VDEState { + VLANClientState *vc; + VDECONN *vde; +} VDEState; + +static void vde_to_qemu(void *opaque) +{ + VDEState *s = opaque; + uint8_t buf[4096]; + int size; + + size = vde_recv(s->vde, buf, sizeof(buf), 0); + if (size > 0) { + qemu_send_packet(s->vc, buf, size); + } +} + +static void vde_from_qemu(void *opaque, const uint8_t *buf, int size) +{ + VDEState *s = opaque; + int ret; + for(;;) { + ret = vde_send(s->vde, buf, size, 0); + if (ret < 0 && errno == EINTR) { + } else { + break; + } + } +} + +static int net_vde_init(VLANState *vlan, const char *sock, int port, + const char *group, int mode) +{ + VDEState *s; + char *init_group = strlen(group) ? (char *)group : NULL; + char *init_sock = strlen(sock) ? (char *)sock : NULL; + + struct vde_open_args args = { + .port = port, + .group = init_group, + .mode = mode, + }; + + s = qemu_mallocz(sizeof(VDEState)); + if (!s) + return -1; + s->vde = vde_open(init_sock, "QEMU", &args); + if (!s->vde){ + free(s); + return -1; + } + s->vc = qemu_new_vlan_client(vlan, vde_from_qemu, NULL, s); + qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s); + snprintf(s->vc->info_str, sizeof(s->vc->info_str), "vde: sock=%s fd=%d", + sock, vde_datafd(s->vde)); + return 0; +} +#endif + +/* network connection */ +typedef struct NetSocketState { + VLANClientState *vc; + int fd; + int state; /* 0 = getting length, 1 = getting data */ + int index; + int packet_len; + uint8_t buf[4096]; + struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */ +} NetSocketState; + +typedef struct NetSocketListenState { + VLANState *vlan; + int fd; +} NetSocketListenState; + +/* XXX: we consider we can send the whole packet without blocking */ +static void net_socket_receive(void *opaque, const uint8_t *buf, int size) +{ + NetSocketState *s = opaque; + uint32_t len; + len = htonl(size); + + send_all(s->fd, (const uint8_t *)&len, sizeof(len)); + send_all(s->fd, buf, size); +} + +static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size) +{ + NetSocketState *s = opaque; + sendto(s->fd, buf, size, 0, + (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst)); +} + +static void net_socket_send(void *opaque) +{ + NetSocketState *s = opaque; + int l, size, err; + uint8_t buf1[4096]; + const uint8_t *buf; + + size = recv(s->fd, buf1, sizeof(buf1), 0); + if (size < 0) { + err = socket_error(); + if (err != EWOULDBLOCK) + goto eoc; + } else if (size == 0) { + /* end of connection */ + eoc: + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + closesocket(s->fd); + return; + } + buf = buf1; + while (size > 0) { + /* reassemble a packet from the network */ + switch(s->state) { + case 0: + l = 4 - s->index; + if (l > size) + l = size; + memcpy(s->buf + s->index, buf, l); + buf += l; + size -= l; + s->index += l; + if (s->index == 4) { + /* got length */ + s->packet_len = ntohl(*(uint32_t *)s->buf); + s->index = 0; + s->state = 1; + } + break; + case 1: + l = s->packet_len - s->index; + if (l > size) + l = size; + memcpy(s->buf + s->index, buf, l); + s->index += l; + buf += l; + size -= l; + if (s->index >= s->packet_len) { + qemu_send_packet(s->vc, s->buf, s->packet_len); + s->index = 0; + s->state = 0; + } + break; + } + } +} + +static void net_socket_send_dgram(void *opaque) +{ + NetSocketState *s = opaque; + int size; + + size = recv(s->fd, s->buf, sizeof(s->buf), 0); + if (size < 0) + return; + if (size == 0) { + /* end of connection */ + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + return; + } + qemu_send_packet(s->vc, s->buf, size); +} + +static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) +{ + struct ip_mreq imr; + int fd; + int val, ret; + if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) { + fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n", + inet_ntoa(mcastaddr->sin_addr), + (int)ntohl(mcastaddr->sin_addr.s_addr)); + return -1; + + } + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + perror("socket(PF_INET, SOCK_DGRAM)"); + return -1; + } + + val = 1; + ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + (const char *)&val, sizeof(val)); + if (ret < 0) { + perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); + goto fail; + } + + ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr)); + if (ret < 0) { + perror("bind"); + goto fail; + } + + /* Add host to multicast group */ + imr.imr_multiaddr = mcastaddr->sin_addr; + imr.imr_interface.s_addr = htonl(INADDR_ANY); + + ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (const char *)&imr, sizeof(struct ip_mreq)); + if (ret < 0) { + perror("setsockopt(IP_ADD_MEMBERSHIP)"); + goto fail; + } + + /* Force mcast msgs to loopback (eg. several QEMUs in same host */ + val = 1; + ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, + (const char *)&val, sizeof(val)); + if (ret < 0) { + perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)"); + goto fail; + } + + socket_set_nonblock(fd); + return fd; +fail: + if (fd >= 0) + closesocket(fd); + return -1; +} + +static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd, + int is_connected) +{ + struct sockaddr_in saddr; + int newfd; + socklen_t saddr_len; + NetSocketState *s; + + /* fd passed: multicast: "learn" dgram_dst address from bound address and save it + * Because this may be "shared" socket from a "master" process, datagrams would be recv() + * by ONLY ONE process: we must "clone" this dgram socket --jjo + */ + + if (is_connected) { + if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) { + /* must be bound */ + if (saddr.sin_addr.s_addr==0) { + fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n", + fd); + return NULL; + } + /* clone dgram socket */ + newfd = net_socket_mcast_create(&saddr); + if (newfd < 0) { + /* error already reported by net_socket_mcast_create() */ + close(fd); + return NULL; + } + /* clone newfd to fd, close newfd */ + dup2(newfd, fd); + close(newfd); + + } else { + fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n", + fd, strerror(errno)); + return NULL; + } + } + + s = qemu_mallocz(sizeof(NetSocketState)); + if (!s) + return NULL; + s->fd = fd; + + s->vc = qemu_new_vlan_client(vlan, net_socket_receive_dgram, NULL, s); + qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s); + + /* mcast: save bound address as dst */ + if (is_connected) s->dgram_dst=saddr; + + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "socket: fd=%d (%s mcast=%s:%d)", + fd, is_connected? "cloned" : "", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + return s; +} + +static void net_socket_connect(void *opaque) +{ + NetSocketState *s = opaque; + qemu_set_fd_handler(s->fd, net_socket_send, NULL, s); +} + +static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd, + int is_connected) +{ + NetSocketState *s; + s = qemu_mallocz(sizeof(NetSocketState)); + if (!s) + return NULL; + s->fd = fd; + s->vc = qemu_new_vlan_client(vlan, + net_socket_receive, NULL, s); + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "socket: fd=%d", fd); + if (is_connected) { + net_socket_connect(s); + } else { + qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s); + } + return s; +} + +static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd, + int is_connected) +{ + int so_type=-1, optlen=sizeof(so_type); + + if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, + (socklen_t *)&optlen)< 0) { + fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd); + return NULL; + } + switch(so_type) { + case SOCK_DGRAM: + return net_socket_fd_init_dgram(vlan, fd, is_connected); + case SOCK_STREAM: + return net_socket_fd_init_stream(vlan, fd, is_connected); + default: + /* who knows ... this could be a eg. a pty, do warn and continue as stream */ + fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd); + return net_socket_fd_init_stream(vlan, fd, is_connected); + } + return NULL; +} + +static void net_socket_accept(void *opaque) +{ + NetSocketListenState *s = opaque; + NetSocketState *s1; + struct sockaddr_in saddr; + socklen_t len; + int fd; + + for(;;) { + len = sizeof(saddr); + fd = accept(s->fd, (struct sockaddr *)&saddr, &len); + if (fd < 0 && errno != EINTR) { + return; + } else if (fd >= 0) { + break; + } + } + s1 = net_socket_fd_init(s->vlan, fd, 1); + if (!s1) { + closesocket(fd); + } else { + snprintf(s1->vc->info_str, sizeof(s1->vc->info_str), + "socket: connection from %s:%d", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + } +} + +static int net_socket_listen_init(VLANState *vlan, const char *host_str) +{ + NetSocketListenState *s; + int fd, val, ret; + struct sockaddr_in saddr; + + if (parse_host_port(&saddr, host_str) < 0) + return -1; + + s = qemu_mallocz(sizeof(NetSocketListenState)); + if (!s) + return -1; + + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { + perror("socket"); + return -1; + } + socket_set_nonblock(fd); + + /* allow fast reuse */ + val = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); + + ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); + if (ret < 0) { + perror("bind"); + return -1; + } + ret = listen(fd, 0); + if (ret < 0) { + perror("listen"); + return -1; + } + s->vlan = vlan; + s->fd = fd; + qemu_set_fd_handler(fd, net_socket_accept, NULL, s); + return 0; +} + +static int net_socket_connect_init(VLANState *vlan, const char *host_str) +{ + NetSocketState *s; + int fd, connected, ret, err; + struct sockaddr_in saddr; + + if (parse_host_port(&saddr, host_str) < 0) + return -1; + + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { + perror("socket"); + return -1; + } + socket_set_nonblock(fd); + + connected = 0; + for(;;) { + ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); + if (ret < 0) { + err = socket_error(); + if (err == EINTR || err == EWOULDBLOCK) { + } else if (err == EINPROGRESS) { + break; +#ifdef _WIN32 + } else if (err == WSAEALREADY) { + break; +#endif + } else { + perror("connect"); + closesocket(fd); + return -1; + } + } else { + connected = 1; + break; + } + } + s = net_socket_fd_init(vlan, fd, connected); + if (!s) + return -1; + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "socket: connect to %s:%d", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + return 0; +} + +static int net_socket_mcast_init(VLANState *vlan, const char *host_str) +{ + NetSocketState *s; + int fd; + struct sockaddr_in saddr; + + if (parse_host_port(&saddr, host_str) < 0) + return -1; + + + fd = net_socket_mcast_create(&saddr); + if (fd < 0) + return -1; + + s = net_socket_fd_init(vlan, fd, 0); + if (!s) + return -1; + + s->dgram_dst = saddr; + + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "socket: mcast=%s:%d", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + return 0; + +} + +/* find or alloc a new VLAN */ +VLANState *qemu_find_vlan(int id) +{ + VLANState **pvlan, *vlan; + for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { + if (vlan->id == id) + return vlan; + } + vlan = qemu_mallocz(sizeof(VLANState)); + if (!vlan) + return NULL; + vlan->id = id; + vlan->next = NULL; + pvlan = &first_vlan; + while (*pvlan != NULL) + pvlan = &(*pvlan)->next; + *pvlan = vlan; + return vlan; +} + +int net_client_init(const char *device, const char *p) +{ + char buf[1024]; + int vlan_id, ret; + VLANState *vlan; + + vlan_id = 0; + if (get_param_value(buf, sizeof(buf), "vlan", p)) { + vlan_id = strtol(buf, NULL, 0); + } + vlan = qemu_find_vlan(vlan_id); + if (!vlan) { + fprintf(stderr, "Could not create vlan %d\n", vlan_id); + return -1; + } + if (!strcmp(device, "nic")) { + NICInfo *nd; + uint8_t *macaddr; + + if (nb_nics >= MAX_NICS) { + fprintf(stderr, "Too Many NICs\n"); + return -1; + } + nd = &nd_table[nb_nics]; + macaddr = nd->macaddr; + macaddr[0] = 0x52; + macaddr[1] = 0x54; + macaddr[2] = 0x00; + macaddr[3] = 0x12; + macaddr[4] = 0x34; + macaddr[5] = 0x56 + nb_nics; + + if (get_param_value(buf, sizeof(buf), "macaddr", p)) { + if (parse_macaddr(macaddr, buf) < 0) { + fprintf(stderr, "invalid syntax for ethernet address\n"); + return -1; + } + } + if (get_param_value(buf, sizeof(buf), "model", p)) { + nd->model = strdup(buf); + } + nd->vlan = vlan; + nb_nics++; + vlan->nb_guest_devs++; + ret = 0; + } else + if (!strcmp(device, "none")) { + /* does nothing. It is needed to signal that no network cards + are wanted */ + ret = 0; + } else +#ifdef CONFIG_SLIRP + if (!strcmp(device, "user")) { + if (get_param_value(buf, sizeof(buf), "hostname", p)) { + pstrcpy(slirp_hostname, sizeof(slirp_hostname), buf); + } + vlan->nb_host_devs++; + ret = net_slirp_init(vlan); + } else +#endif +#ifdef _WIN32 + if (!strcmp(device, "tap")) { + char ifname[64]; + if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) { + fprintf(stderr, "tap: no interface name\n"); + return -1; + } + vlan->nb_host_devs++; + ret = tap_win32_init(vlan, ifname); + } else +#else + if (!strcmp(device, "tap")) { + char ifname[64]; + char setup_script[1024], down_script[1024]; + int fd; + vlan->nb_host_devs++; + if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { + fd = strtol(buf, NULL, 0); + fcntl(fd, F_SETFL, O_NONBLOCK); + ret = -1; + if (net_tap_fd_init(vlan, fd)) + ret = 0; + } else { + if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) { + ifname[0] = '\0'; + } + if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) { + pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT); + } + if (get_param_value(down_script, sizeof(down_script), "downscript", p) == 0) { + pstrcpy(down_script, sizeof(down_script), DEFAULT_NETWORK_DOWN_SCRIPT); + } + ret = net_tap_init(vlan, ifname, setup_script, down_script); + } + } else +#endif + if (!strcmp(device, "socket")) { + if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { + int fd; + fd = strtol(buf, NULL, 0); + ret = -1; + if (net_socket_fd_init(vlan, fd, 1)) + ret = 0; + } else if (get_param_value(buf, sizeof(buf), "listen", p) > 0) { + ret = net_socket_listen_init(vlan, buf); + } else if (get_param_value(buf, sizeof(buf), "connect", p) > 0) { + ret = net_socket_connect_init(vlan, buf); + } else if (get_param_value(buf, sizeof(buf), "mcast", p) > 0) { + ret = net_socket_mcast_init(vlan, buf); + } else { + fprintf(stderr, "Unknown socket options: %s\n", p); + return -1; + } + vlan->nb_host_devs++; + } else +#ifdef CONFIG_VDE + if (!strcmp(device, "vde")) { + char vde_sock[1024], vde_group[512]; + int vde_port, vde_mode; + vlan->nb_host_devs++; + if (get_param_value(vde_sock, sizeof(vde_sock), "sock", p) <= 0) { + vde_sock[0] = '\0'; + } + if (get_param_value(buf, sizeof(buf), "port", p) > 0) { + vde_port = strtol(buf, NULL, 10); + } else { + vde_port = 0; + } + if (get_param_value(vde_group, sizeof(vde_group), "group", p) <= 0) { + vde_group[0] = '\0'; + } + if (get_param_value(buf, sizeof(buf), "mode", p) > 0) { + vde_mode = strtol(buf, NULL, 8); + } else { + vde_mode = 0700; + } + ret = net_vde_init(vlan, vde_sock, vde_port, vde_group, vde_mode); + } else +#endif + { + fprintf(stderr, "Unknown network device: %s\n", device); + return -1; + } + if (ret < 0) { + fprintf(stderr, "Could not initialize device '%s'\n", device); + } + + return ret; +} + +int net_client_parse(const char *str) +{ + const char *p; + char *q; + char device[64]; + + p = str; + q = device; + while (*p != '\0' && *p != ',') { + if ((q - device) < sizeof(device) - 1) + *q++ = *p; + p++; + } + *q = '\0'; + if (*p == ',') + p++; + + return net_client_init(device, p); +} + +void do_info_network(void) +{ + VLANState *vlan; + VLANClientState *vc; + + for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { + term_printf("VLAN %d devices:\n", vlan->id); + for(vc = vlan->first_client; vc != NULL; vc = vc->next) + term_printf(" %s\n", vc->info_str); + } +} + +void net_cleanup(void) +{ + VLANState *vlan; + +#if !defined(_WIN32) + /* close network clients */ + for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { + VLANClientState *vc; + + for(vc = vlan->first_client; vc != NULL; vc = vc->next) { + if (vc->fd_read == tap_receive) { + char ifname[64]; + TAPState *s = vc->opaque; + + if (sscanf(vc->info_str, "tap: ifname=%63s ", ifname) == 1 && + s->down_script[0]) + launch_script(s->down_script, ifname, s->fd); + } +#if defined(CONFIG_VDE) + if (vc->fd_read == vde_from_qemu) { + VDEState *s = vc->opaque; + vde_close(s->vde); + } +#endif + } + } +#endif +} + +void net_client_check(void) +{ + VLANState *vlan; + + for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { + if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0) + continue; + if (vlan->nb_guest_devs == 0) + fprintf(stderr, "Warning: vlan %d with no nics\n", vlan->id); + if (vlan->nb_host_devs == 0) + fprintf(stderr, + "Warning: vlan %d is not connected to host network\n", + vlan->id); + } +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/net-checksum.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/net-checksum.c --- qemu-0.9.1/net-checksum.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/net-checksum.c 2008-07-29 20:40:04.000000000 +0100 @@ -0,0 +1,87 @@ +/* + * IP checksumming functions. + * (c) 2008 Gerd Hoffmann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "hw/hw.h" +#include "net.h" + +#define PROTO_TCP 6 +#define PROTO_UDP 17 + +uint32_t net_checksum_add(int len, uint8_t *buf) +{ + uint32_t sum = 0; + int i; + + for (i = 0; i < len; i++) { + if (i & 1) + sum += (uint32_t)buf[i]; + else + sum += (uint32_t)buf[i] << 8; + } + return sum; +} + +uint16_t net_checksum_finish(uint32_t sum) +{ + while (sum>>16) + sum = (sum & 0xFFFF)+(sum >> 16); + return ~sum; +} + +uint16_t net_checksum_tcpudp(uint16_t length, uint16_t proto, + uint8_t *addrs, uint8_t *buf) +{ + uint32_t sum = 0; + + sum += net_checksum_add(length, buf); // payload + sum += net_checksum_add(8, addrs); // src + dst address + sum += proto + length; // protocol & length + return net_checksum_finish(sum); +} + +void net_checksum_calculate(uint8_t *data, int length) +{ + int hlen, plen, proto, csum_offset; + uint16_t csum; + + if ((data[14] & 0xf0) != 0x40) + return; /* not IPv4 */ + hlen = (data[14] & 0x0f) * 4; + plen = (data[16] << 8 | data[17]) - hlen; + proto = data[23]; + + switch (proto) { + case PROTO_TCP: + csum_offset = 16; + break; + case PROTO_UDP: + csum_offset = 6; + break; + default: + return; + } + + if (plen < csum_offset+2) + return; + + data[14+hlen+csum_offset] = 0; + data[14+hlen+csum_offset+1] = 0; + csum = net_checksum_tcpudp(plen, proto, data+14+12, data+14+hlen); + data[14+hlen+csum_offset] = csum >> 8; + data[14+hlen+csum_offset+1] = csum & 0xff; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/net.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/net.h --- qemu-0.9.1/net.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/net.h 2008-10-31 19:10:00.000000000 +0000 @@ -28,6 +28,7 @@ IOReadHandler *fd_read, IOCanRWHandler *fd_can_read, void *opaque); +void qemu_del_vlan_client(VLANClientState *vc); int qemu_can_send_packet(VLANClientState *vc); void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size); void qemu_handler_true(void *opaque); @@ -47,4 +48,34 @@ extern int nb_nics; extern NICInfo nd_table[MAX_NICS]; +/* BT HCI info */ + +struct HCIInfo { + int (*bdaddr_set)(struct HCIInfo *hci, const uint8_t *bd_addr); + void (*cmd_send)(struct HCIInfo *hci, const uint8_t *data, int len); + void (*sco_send)(struct HCIInfo *hci, const uint8_t *data, int len); + void (*acl_send)(struct HCIInfo *hci, const uint8_t *data, int len); + void *opaque; + void (*evt_recv)(void *opaque, const uint8_t *data, int len); + void (*acl_recv)(void *opaque, const uint8_t *data, int len); +}; + +struct HCIInfo *qemu_next_hci(void); + +/* checksumming functions (net-checksum.c) */ +uint32_t net_checksum_add(int len, uint8_t *buf); +uint16_t net_checksum_finish(uint32_t sum); +uint16_t net_checksum_tcpudp(uint16_t length, uint16_t proto, + uint8_t *addrs, uint8_t *buf); +void net_checksum_calculate(uint8_t *data, int length); + +/* from net.c */ +int net_client_init(const char *device, const char *p); +int net_client_parse(const char *str); +void net_slirp_smb(const char *exported_dir); +void net_slirp_redir(const char *redir_str); +void net_cleanup(void); +int slirp_is_inited(void); +void net_client_check(void); + #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/osdep.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/osdep.c --- qemu-0.9.1/osdep.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/osdep.c 2008-11-11 22:06:42.000000000 +0000 @@ -45,20 +45,7 @@ #include #endif -void *get_mmap_addr(unsigned long size) -{ - return NULL; -} - -void qemu_free(void *ptr) -{ - free(ptr); -} - -void *qemu_malloc(size_t size) -{ - return malloc(size); -} +#include "qemu_socket.h" #if defined(_WIN32) void *qemu_memalign(size_t alignment, size_t size) @@ -83,7 +70,14 @@ #if defined(USE_KQEMU) +#ifdef __OpenBSD__ +#include +#include +#include +#else #include +#endif + #include #include @@ -91,9 +85,14 @@ { static int phys_ram_fd = -1; static int phys_ram_size = 0; + void *ptr; + +#ifdef __OpenBSD__ /* no need (?) for a dummy file on OpenBSD */ + int map_anon = MAP_ANON; +#else + int map_anon = 0; const char *tmpdir; char phys_ram_file[1024]; - void *ptr; #ifdef HOST_SOLARIS struct statvfs stfs; #else @@ -113,7 +112,6 @@ int64_t free_space; int ram_mb; - extern int ram_size; free_space = (int64_t)stfs.f_bavail * stfs.f_bsize; if ((ram_size + 8192 * 1024) >= free_space) { ram_mb = (ram_size / (1024 * 1024)); @@ -122,8 +120,7 @@ tmpdir, ram_mb); if (strcmp(tmpdir, "/dev/shm") == 0) { fprintf(stderr, "To have more space available provided you have enough RAM and swap, do as root:\n" - "umount /dev/shm\n" - "mount -t tmpfs -o size=%dm none /dev/shm\n", + "mount -o remount,size=%dm /dev/shm\n", ram_mb + 16); } else { fprintf(stderr, @@ -157,9 +154,10 @@ } size = (size + 4095) & ~4095; ftruncate(phys_ram_fd, phys_ram_size + size); +#endif /* !__OpenBSD__ */ ptr = mmap(NULL, size, - PROT_WRITE | PROT_READ, MAP_SHARED, + PROT_WRITE | PROT_READ, map_anon | MAP_SHARED, phys_ram_fd, phys_ram_size); if (ptr == MAP_FAILED) { fprintf(stderr, "Could not map physical memory\n"); @@ -202,7 +200,7 @@ #ifdef _BSD return valloc(size); #else - return memalign(4096, size); + return memalign(getpagesize(), size); #endif } @@ -217,26 +215,6 @@ #endif -void *qemu_mallocz(size_t size) -{ - void *ptr; - ptr = qemu_malloc(size); - if (!ptr) - return NULL; - memset(ptr, 0, size); - return ptr; -} - -char *qemu_strdup(const char *str) -{ - char *ptr; - ptr = qemu_malloc(strlen(str) + 1); - if (!ptr) - return NULL; - strcpy(ptr, str); - return ptr; -} - int qemu_create_pidfile(const char *filename) { char buffer[128]; @@ -307,3 +285,28 @@ return 0; } #endif /* _WIN32 */ + + +#ifdef _WIN32 +void socket_set_nonblock(int fd) +{ + unsigned long opt = 1; + ioctlsocket(fd, FIONBIO, &opt); +} + +int inet_aton(const char *cp, struct in_addr *ia) +{ + uint32_t addr = inet_addr(cp); + if (addr == 0xffffffff) + return 0; + ia->s_addr = addr; + return 1; +} +#else +void socket_set_nonblock(int fd) +{ + int f; + f = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, f | O_NONBLOCK); +} +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/osdep.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/osdep.h --- qemu-0.9.1/osdep.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/osdep.h 2008-11-11 22:06:42.000000000 +0000 @@ -2,6 +2,10 @@ #define QEMU_OSDEP_H #include +#ifdef __OpenBSD__ +#include +#include +#endif #ifndef glue #define xglue(x, y) x ## y @@ -19,6 +23,15 @@ #define unlikely(x) __builtin_expect(!!(x), 0) #endif +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *) 0)->MEMBER) +#endif +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + const typeof(((type *) 0)->member) *__mptr = (ptr); \ + (type *) ((char *) __mptr - offsetof(type, member));}) +#endif + #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif @@ -26,34 +39,40 @@ #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + #ifndef always_inline #if (__GNUC__ < 3) || defined(__APPLE__) #define always_inline inline #else #define always_inline __attribute__ (( always_inline )) __inline__ +#define inline always_inline #endif -#endif +#else #define inline always_inline +#endif #ifdef __i386__ -#define REGPARM(n) __attribute((regparm(n))) +#define REGPARM __attribute((regparm(3))) #else -#define REGPARM(n) +#define REGPARM #endif #define qemu_printf printf -void *qemu_malloc(size_t size); -void *qemu_mallocz(size_t size); -void qemu_free(void *ptr); -char *qemu_strdup(const char *str); +#if defined (__GNUC__) && defined (__GNUC_MINOR_) +# define QEMU_GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +# define QEMU_GNUC_PREREQ(maj, min) 0 +#endif void *qemu_memalign(size_t alignment, size_t size); void *qemu_vmalloc(size_t size); void qemu_vfree(void *ptr); -void *get_mmap_addr(unsigned long size); - int qemu_create_pidfile(const char *filename); #ifdef _WIN32 Binary files /tmp/5T7tsf7Gxy/qemu-0.9.1/pc-bios/bios.bin and /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/pc-bios/bios.bin differ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/pc-bios/bios.diff /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/pc-bios/bios.diff --- qemu-0.9.1/pc-bios/bios.diff 2008-01-06 19:38:43.000000000 +0000 +++ qemu-0.9.1+svn20081112/pc-bios/bios.diff 2008-08-21 04:14:29.000000000 +0100 @@ -1,32 +1,5 @@ -Index: rombios.c -=================================================================== -RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v -retrieving revision 1.174 -diff -u -w -r1.174 rombios.c ---- rombios.c 17 Oct 2006 16:48:05 -0000 1.174 -+++ rombios.c 8 Feb 2007 21:57:48 -0000 -@@ -9472,6 +9472,14 @@ - mov eax, #0x00040000 - call eax - -+ ;; reset the memory (some boot loaders such as syslinux suppose -+ ;; that the memory is set to zero) -+ mov edi, #0x00040000 -+ mov ecx, #0x40000 / 4 -+ xor eax, eax -+ rep -+ stosd -+ - ;; return to 16 bit protected mode first - db 0xea - dd rombios32_10 -Index: rombios.h -=================================================================== -RCS file: /cvsroot/bochs/bochs/bios/rombios.h,v -retrieving revision 1.3 -diff -u -w -r1.3 rombios.h ---- rombios.h 3 Oct 2006 20:27:30 -0000 1.3 -+++ rombios.h 8 Feb 2007 21:57:48 -0000 +--- bochs-2.3.7.orig/bios/rombios.h ++++ bochs-2.3.7/bios/rombios.h @@ -19,7 +19,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA @@ -36,22 +9,137 @@ #ifndef LEGACY # define BX_ROMBIOS32 1 -Index: rombios32.c -=================================================================== -RCS file: /cvsroot/bochs/bochs/bios/rombios32.c,v -retrieving revision 1.8 -diff -u -w -r1.8 rombios32.c ---- rombios32.c 3 Oct 2006 20:27:30 -0000 1.8 -+++ rombios32.c 8 Feb 2007 21:57:48 -0000 -@@ -852,6 +852,11 @@ - int ioapic_id, i, len; - int mp_config_table_size; - -+#ifdef BX_QEMU -+ if (smp_cpus <= 1) -+ return; -+#endif +--- bochs-2.3.7.orig/bios/rombios.c ++++ bochs-2.3.7/bios/rombios.c +@@ -4404,22 +4404,25 @@ + #endif // BX_USE_PS2_MOUSE + + +-void set_e820_range(ES, DI, start, end, type) ++void set_e820_range(ES, DI, start, end, extra_start, extra_end, type) + Bit16u ES; + Bit16u DI; + Bit32u start; + Bit32u end; ++ Bit8u extra_start; ++ Bit8u extra_end; + Bit16u type; + { + write_word(ES, DI, start); + write_word(ES, DI+2, start >> 16); +- write_word(ES, DI+4, 0x00); ++ write_word(ES, DI+4, extra_start); + write_word(ES, DI+6, 0x00); + + end -= start; ++ extra_end -= extra_start; + write_word(ES, DI+8, end); + write_word(ES, DI+10, end >> 16); +- write_word(ES, DI+12, 0x0000); ++ write_word(ES, DI+12, extra_end); + write_word(ES, DI+14, 0x0000); + + write_word(ES, DI+16, type); +@@ -4432,7 +4435,9 @@ + Bit16u ES, DS, FLAGS; + { + Bit32u extended_memory_size=0; // 64bits long ++ Bit32u extra_lowbits_memory_size=0; + Bit16u CX,DX; ++ Bit8u extra_highbits_memory_size=0; + + BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax); + +@@ -4506,11 +4511,18 @@ + extended_memory_size += (1L * 1024 * 1024); + } + ++ extra_lowbits_memory_size = inb_cmos(0x5c); ++ extra_lowbits_memory_size <<= 8; ++ extra_lowbits_memory_size |= inb_cmos(0x5b); ++ extra_lowbits_memory_size *= 64; ++ extra_lowbits_memory_size *= 1024; ++ extra_highbits_memory_size = inb_cmos(0x5d); + - #ifdef BX_USE_EBDA_TABLES - mp_config_table = (uint8_t *)(ram_size - ACPI_DATA_SIZE - MPTABLE_MAX_SIZE); + switch(regs.u.r16.bx) + { + case 0: + set_e820_range(ES, regs.u.r16.di, +- 0x0000000L, 0x0009fc00L, 1); ++ 0x0000000L, 0x0009fc00L, 0, 0, 1); + regs.u.r32.ebx = 1; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; +@@ -4519,7 +4531,7 @@ + break; + case 1: + set_e820_range(ES, regs.u.r16.di, +- 0x0009fc00L, 0x000a0000L, 2); ++ 0x0009fc00L, 0x000a0000L, 0, 0, 2); + regs.u.r32.ebx = 2; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; +@@ -4528,7 +4540,7 @@ + break; + case 2: + set_e820_range(ES, regs.u.r16.di, +- 0x000e8000L, 0x00100000L, 2); ++ 0x000e8000L, 0x00100000L, 0, 0, 2); + regs.u.r32.ebx = 3; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; +@@ -4539,7 +4551,7 @@ + #if BX_ROMBIOS32 + set_e820_range(ES, regs.u.r16.di, + 0x00100000L, +- extended_memory_size - ACPI_DATA_SIZE, 1); ++ extended_memory_size - ACPI_DATA_SIZE ,0, 0, 1); + regs.u.r32.ebx = 4; #else + set_e820_range(ES, regs.u.r16.di, +@@ -4555,7 +4567,7 @@ + case 4: + set_e820_range(ES, regs.u.r16.di, + extended_memory_size - ACPI_DATA_SIZE, +- extended_memory_size, 3); // ACPI RAM ++ extended_memory_size ,0, 0, 3); // ACPI RAM + regs.u.r32.ebx = 5; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; +@@ -4565,7 +4577,20 @@ + case 5: + /* 256KB BIOS area at the end of 4 GB */ + set_e820_range(ES, regs.u.r16.di, +- 0xfffc0000L, 0x00000000L, 2); ++ 0xfffc0000L, 0x00000000L ,0, 0, 2); ++ if (extra_highbits_memory_size || extra_lowbits_memory_size) ++ regs.u.r32.ebx = 6; ++ else ++ regs.u.r32.ebx = 0; ++ regs.u.r32.eax = 0x534D4150; ++ regs.u.r32.ecx = 0x14; ++ CLEAR_CF(); ++ return; ++ case 6: ++ /* Maping of memory above 4 GB */ ++ set_e820_range(ES, regs.u.r16.di, 0x00000000L, ++ extra_lowbits_memory_size, 1, extra_highbits_memory_size ++ + 1, 1); + regs.u.r32.ebx = 0; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; +--- bochs-2.3.7.orig/bios/rombios32.c ++++ bochs-2.3.7/bios/rombios32.c +@@ -479,7 +479,12 @@ + sipi_vector = AP_BOOT_ADDR >> 12; + writel(APIC_BASE + APIC_ICR_LOW, 0x000C4600 | sipi_vector); + ++#ifndef BX_QEMU + delay_ms(10); ++#else ++ while (cmos_readb(0x5f) + 1 != readw((void *)CPU_COUNT_ADDR)) ++ ; ++#endif + + smp_cpus = readw((void *)CPU_COUNT_ADDR); + } Binary files /tmp/5T7tsf7Gxy/qemu-0.9.1/pc-bios/openbios-sparc32 and /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/pc-bios/openbios-sparc32 differ Binary files /tmp/5T7tsf7Gxy/qemu-0.9.1/pc-bios/openbios-sparc64 and /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/pc-bios/openbios-sparc64 differ Binary files /tmp/5T7tsf7Gxy/qemu-0.9.1/pc-bios/ppc_rom.bin and /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/pc-bios/ppc_rom.bin differ Binary files /tmp/5T7tsf7Gxy/qemu-0.9.1/pc-bios/pxe-e1000.bin and /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/pc-bios/pxe-e1000.bin differ Binary files /tmp/5T7tsf7Gxy/qemu-0.9.1/pc-bios/pxe-ne2k_pci.bin and /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/pc-bios/pxe-ne2k_pci.bin differ Binary files /tmp/5T7tsf7Gxy/qemu-0.9.1/pc-bios/pxe-pcnet.bin and /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/pc-bios/pxe-pcnet.bin differ Binary files /tmp/5T7tsf7Gxy/qemu-0.9.1/pc-bios/pxe-rtl8139.bin and /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/pc-bios/pxe-rtl8139.bin differ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/pc-bios/README /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/pc-bios/README --- qemu-0.9.1/pc-bios/README 2008-01-06 19:38:43.000000000 +0000 +++ qemu-0.9.1+svn20081112/pc-bios/README 2008-09-18 20:41:28.000000000 +0100 @@ -14,8 +14,7 @@ - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. - The included Sparc32 image is built from SVN revision 183 - and Sparc64 from SVN revision 181. + The included Sparc32 and Sparc64 images are built from SVN revision 237. - The PXE roms come from Rom-o-Matic etherboot 5.4.2. pcnet32:pcnet32 -- [0x1022,0x2000] Binary files /tmp/5T7tsf7Gxy/qemu-0.9.1/pc-bios/vgabios.bin and /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/pc-bios/vgabios.bin differ Binary files /tmp/5T7tsf7Gxy/qemu-0.9.1/pc-bios/vgabios-cirrus.bin and /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/pc-bios/vgabios-cirrus.bin differ Binary files /tmp/5T7tsf7Gxy/qemu-0.9.1/pc-bios/video.x and /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/pc-bios/video.x differ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/ppc64.ld /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/ppc64.ld --- qemu-0.9.1/ppc64.ld 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/ppc64.ld 2008-08-20 23:39:24.000000000 +0100 @@ -0,0 +1,226 @@ +/* Script for -z combreloc: combine and sort reloc sections */ +OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", + "elf64-powerpc") +OUTPUT_ARCH(powerpc:common64) +ENTRY(_start) +SEARCH_DIR("/usr/powerpc64-unknown-linux-gnu/lib64"); +SEARCH_DIR("/usr/lib/binutils/powerpc64-unknown-linux-gnu/2.16.164"); +SEARCH_DIR("/usr/local/lib64"); SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64"); +SEARCH_DIR("/usr/powerpc64-unknown-linux-gnu/lib"); +SEARCH_DIR("/usr/lib/binutils/powerpc64-unknown-linux-gnu/2.16.1"); +SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib"); /* Do we +need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data.rel.ro*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) + *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) + *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) + *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.toc) + *(.rela.opd) + *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) + *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) + *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) + *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .rela.tocbss : { *(.rela.tocbss) } + .init : + { + KEEP (*(.init)) + } =0x60000000 + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.sfpr .glink) + } =0x60000000 + .fini : + { + KEEP (*(.fini)) + } =0x60000000 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { KEEP (*(.gcc_except_table)) +*(.gcc_except_table.*) } /* Adjust the address for the data segment. We want to +adjust up to + the same address within the page on the next page up. */ + . = ALIGN (0x10000) - ((0x10000 - .) & (0x10000 - 1)); . = DATA_SEGMENT_ALIGN +(0x10000, 0x1000); /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { KEEP (*(.gcc_except_table)) +*(.gcc_except_table.*) } /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(64 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { KEEP (*(.preinit_array)) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { KEEP (*(.init_array)) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { KEEP (*(.fini_array)) } + PROVIDE (__fini_array_end = .); + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin*.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) } + .dynamic : { *(.dynamic) } + . = DATA_SEGMENT_RELRO_END (0, .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .toc1 ALIGN(8) : { *(.toc1) } + .opd ALIGN(8) : { KEEP (*(.opd)) } + .got ALIGN(8) : { *(.got .toc) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .tocbss ALIGN(8) : { *(.tocbss)} + .sbss : + { + PROVIDE (__sbss_start = .); + PROVIDE (___sbss_start = .); + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + PROVIDE (__sbss_end = .); + PROVIDE (___sbss_end = .); + } + .plt : { *(.plt) } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(64 / 8); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/qemu-aio.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/qemu-aio.h --- qemu-0.9.1/qemu-aio.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/qemu-aio.h 2008-09-22 20:17:18.000000000 +0100 @@ -0,0 +1,45 @@ +/* + * QEMU aio implementation + * + * Copyright IBM, Corp. 2008 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_AIO_H +#define QEMU_AIO_H + +#include "qemu-common.h" +#include "qemu-char.h" + +/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */ +typedef int (AioFlushHandler)(void *opaque); + +/* Flush any pending AIO operation. This function will block until all + * outstanding AIO operations have been completed or cancelled. */ +void qemu_aio_flush(void); + +/* Wait for a single AIO completion to occur. This function will until a + * single AIO opeartion has completed. It is intended to be used as a looping + * primative when simulating synchronous IO based on asynchronous IO. */ +void qemu_aio_wait(void); + +/* Register a file descriptor and associated callbacks. Behaves very similarly + * to qemu_set_fd_handler2. Unlike qemu_set_fd_handler2, these callbacks will + * be invoked when using either qemu_aio_wait() or qemu_aio_flush(). + * + * Code that invokes AIO completion functions should rely on this function + * instead of qemu_set_fd_handler[2]. + */ +int qemu_aio_set_fd_handler(int fd, + IOHandler *io_read, + IOHandler *io_write, + AioFlushHandler *io_flush, + void *opaque); + +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/qemu-char.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/qemu-char.c --- qemu-0.9.1/qemu-char.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/qemu-char.c 2008-11-11 20:54:09.000000000 +0000 @@ -0,0 +1,2168 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * 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 "qemu-common.h" +#include "net.h" +#include "console.h" +#include "sysemu.h" +#include "qemu-timer.h" +#include "qemu-char.h" +#include "block.h" +#include "hw/usb.h" +#include "hw/baum.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __NetBSD__ +#include +#endif +#ifdef __linux__ +#include +#endif +#include +#include +#include +#include +#ifdef _BSD +#include +#ifdef __FreeBSD__ +#include +#else +#include +#endif +#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__) +#include +#else +#ifdef __linux__ +#include + +#include +#include +#endif +#ifdef __sun__ +#include +#include +#include +#include +#include +#include +#include +#include // must come after ip.h +#include +#include +#include +#include +#include +#endif +#endif +#endif + +#include "qemu_socket.h" + +/***********************************************************/ +/* character device */ + +static void qemu_chr_event(CharDriverState *s, int event) +{ + if (!s->chr_event) + return; + s->chr_event(s->handler_opaque, event); +} + +static void qemu_chr_reset_bh(void *opaque) +{ + CharDriverState *s = opaque; + qemu_chr_event(s, CHR_EVENT_RESET); + qemu_bh_delete(s->bh); + s->bh = NULL; +} + +void qemu_chr_reset(CharDriverState *s) +{ + if (s->bh == NULL) { + s->bh = qemu_bh_new(qemu_chr_reset_bh, s); + qemu_bh_schedule(s->bh); + } +} + +int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len) +{ + return s->chr_write(s, buf, len); +} + +int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg) +{ + if (!s->chr_ioctl) + return -ENOTSUP; + return s->chr_ioctl(s, cmd, arg); +} + +int qemu_chr_can_read(CharDriverState *s) +{ + if (!s->chr_can_read) + return 0; + return s->chr_can_read(s->handler_opaque); +} + +void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len) +{ + s->chr_read(s->handler_opaque, buf, len); +} + +void qemu_chr_accept_input(CharDriverState *s) +{ + if (s->chr_accept_input) + s->chr_accept_input(s); +} + +void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) +{ + char buf[4096]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + qemu_chr_write(s, (uint8_t *)buf, strlen(buf)); + va_end(ap); +} + +void qemu_chr_send_event(CharDriverState *s, int event) +{ + if (s->chr_send_event) + s->chr_send_event(s, event); +} + +void qemu_chr_add_handlers(CharDriverState *s, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, + IOEventHandler *fd_event, + void *opaque) +{ + s->chr_can_read = fd_can_read; + s->chr_read = fd_read; + s->chr_event = fd_event; + s->handler_opaque = opaque; + if (s->chr_update_read_handler) + s->chr_update_read_handler(s); +} + +static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + return len; +} + +static CharDriverState *qemu_chr_open_null(void) +{ + CharDriverState *chr; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + return NULL; + chr->chr_write = null_chr_write; + return chr; +} + +/* MUX driver for serial I/O splitting */ +static int term_timestamps; +static int64_t term_timestamps_start; +#define MAX_MUX 4 +#define MUX_BUFFER_SIZE 32 /* Must be a power of 2. */ +#define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1) +typedef struct { + IOCanRWHandler *chr_can_read[MAX_MUX]; + IOReadHandler *chr_read[MAX_MUX]; + IOEventHandler *chr_event[MAX_MUX]; + void *ext_opaque[MAX_MUX]; + CharDriverState *drv; + unsigned char buffer[MUX_BUFFER_SIZE]; + int prod; + int cons; + int mux_cnt; + int term_got_escape; + int max_size; +} MuxDriver; + + +static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + MuxDriver *d = chr->opaque; + int ret; + if (!term_timestamps) { + ret = d->drv->chr_write(d->drv, buf, len); + } else { + int i; + + ret = 0; + for(i = 0; i < len; i++) { + ret += d->drv->chr_write(d->drv, buf+i, 1); + if (buf[i] == '\n') { + char buf1[64]; + int64_t ti; + int secs; + + ti = qemu_get_clock(rt_clock); + if (term_timestamps_start == -1) + term_timestamps_start = ti; + ti -= term_timestamps_start; + secs = ti / 1000000000; + snprintf(buf1, sizeof(buf1), + "[%02d:%02d:%02d.%03d] ", + secs / 3600, + (secs / 60) % 60, + secs % 60, + (int)((ti / 1000000) % 1000)); + d->drv->chr_write(d->drv, (uint8_t *)buf1, strlen(buf1)); + } + } + } + return ret; +} + +static const char * const mux_help[] = { + "% h print this help\n\r", + "% x exit emulator\n\r", + "% s save disk data back to file (if -snapshot)\n\r", + "% t toggle console timestamps\n\r" + "% b send break (magic sysrq)\n\r", + "% c switch between console and monitor\n\r", + "% % sends %\n\r", + NULL +}; + +int term_escape_char = 0x01; /* ctrl-a is used for escape */ +static void mux_print_help(CharDriverState *chr) +{ + int i, j; + char ebuf[15] = "Escape-Char"; + char cbuf[50] = "\n\r"; + + if (term_escape_char > 0 && term_escape_char < 26) { + snprintf(cbuf, sizeof(cbuf), "\n\r"); + snprintf(ebuf, sizeof(ebuf), "C-%c", term_escape_char - 1 + 'a'); + } else { + snprintf(cbuf, sizeof(cbuf), + "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r", + term_escape_char); + } + chr->chr_write(chr, (uint8_t *)cbuf, strlen(cbuf)); + for (i = 0; mux_help[i] != NULL; i++) { + for (j=0; mux_help[i][j] != '\0'; j++) { + if (mux_help[i][j] == '%') + chr->chr_write(chr, (uint8_t *)ebuf, strlen(ebuf)); + else + chr->chr_write(chr, (uint8_t *)&mux_help[i][j], 1); + } + } +} + +static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) +{ + if (d->term_got_escape) { + d->term_got_escape = 0; + if (ch == term_escape_char) + goto send_char; + switch(ch) { + case '?': + case 'h': + mux_print_help(chr); + break; + case 'x': + { + const char *term = "QEMU: Terminated\n\r"; + chr->chr_write(chr,(uint8_t *)term,strlen(term)); + exit(0); + break; + } + case 's': + { + int i; + for (i = 0; i < nb_drives; i++) { + bdrv_commit(drives_table[i].bdrv); + } + } + break; + case 'b': + qemu_chr_event(chr, CHR_EVENT_BREAK); + break; + case 'c': + /* Switch to the next registered device */ + chr->focus++; + if (chr->focus >= d->mux_cnt) + chr->focus = 0; + break; + case 't': + term_timestamps = !term_timestamps; + term_timestamps_start = -1; + break; + } + } else if (ch == term_escape_char) { + d->term_got_escape = 1; + } else { + send_char: + return 1; + } + return 0; +} + +static void mux_chr_accept_input(CharDriverState *chr) +{ + int m = chr->focus; + MuxDriver *d = chr->opaque; + + while (d->prod != d->cons && + d->chr_can_read[m] && + d->chr_can_read[m](d->ext_opaque[m])) { + d->chr_read[m](d->ext_opaque[m], + &d->buffer[d->cons++ & MUX_BUFFER_MASK], 1); + } +} + +static int mux_chr_can_read(void *opaque) +{ + CharDriverState *chr = opaque; + MuxDriver *d = chr->opaque; + + if ((d->prod - d->cons) < MUX_BUFFER_SIZE) + return 1; + if (d->chr_can_read[chr->focus]) + return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]); + return 0; +} + +static void mux_chr_read(void *opaque, const uint8_t *buf, int size) +{ + CharDriverState *chr = opaque; + MuxDriver *d = chr->opaque; + int m = chr->focus; + int i; + + mux_chr_accept_input (opaque); + + for(i = 0; i < size; i++) + if (mux_proc_byte(chr, d, buf[i])) { + if (d->prod == d->cons && + d->chr_can_read[m] && + d->chr_can_read[m](d->ext_opaque[m])) + d->chr_read[m](d->ext_opaque[m], &buf[i], 1); + else + d->buffer[d->prod++ & MUX_BUFFER_MASK] = buf[i]; + } +} + +static void mux_chr_event(void *opaque, int event) +{ + CharDriverState *chr = opaque; + MuxDriver *d = chr->opaque; + int i; + + /* Send the event to all registered listeners */ + for (i = 0; i < d->mux_cnt; i++) + if (d->chr_event[i]) + d->chr_event[i](d->ext_opaque[i], event); +} + +static void mux_chr_update_read_handler(CharDriverState *chr) +{ + MuxDriver *d = chr->opaque; + + if (d->mux_cnt >= MAX_MUX) { + fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n"); + return; + } + d->ext_opaque[d->mux_cnt] = chr->handler_opaque; + d->chr_can_read[d->mux_cnt] = chr->chr_can_read; + d->chr_read[d->mux_cnt] = chr->chr_read; + d->chr_event[d->mux_cnt] = chr->chr_event; + /* Fix up the real driver with mux routines */ + if (d->mux_cnt == 0) { + qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read, + mux_chr_event, chr); + } + chr->focus = d->mux_cnt; + d->mux_cnt++; +} + +static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) +{ + CharDriverState *chr; + MuxDriver *d; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + return NULL; + d = qemu_mallocz(sizeof(MuxDriver)); + if (!d) { + free(chr); + return NULL; + } + + chr->opaque = d; + d->drv = drv; + chr->focus = -1; + chr->chr_write = mux_chr_write; + chr->chr_update_read_handler = mux_chr_update_read_handler; + chr->chr_accept_input = mux_chr_accept_input; + return chr; +} + + +#ifdef _WIN32 +int send_all(int fd, const void *buf, int len1) +{ + int ret, len; + + len = len1; + while (len > 0) { + ret = send(fd, buf, len, 0); + if (ret < 0) { + int errno; + errno = WSAGetLastError(); + if (errno != WSAEWOULDBLOCK) { + return -1; + } + } else if (ret == 0) { + break; + } else { + buf += ret; + len -= ret; + } + } + return len1 - len; +} + +#else + +static int unix_write(int fd, const uint8_t *buf, int len1) +{ + int ret, len; + + len = len1; + while (len > 0) { + ret = write(fd, buf, len); + if (ret < 0) { + if (errno != EINTR && errno != EAGAIN) + return -1; + } else if (ret == 0) { + break; + } else { + buf += ret; + len -= ret; + } + } + return len1 - len; +} + +int send_all(int fd, const void *buf, int len1) +{ + return unix_write(fd, buf, len1); +} +#endif /* !_WIN32 */ + +#ifndef _WIN32 + +typedef struct { + int fd_in, fd_out; + int max_size; +} FDCharDriver; + +#define STDIO_MAX_CLIENTS 1 +static int stdio_nb_clients = 0; + +static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + FDCharDriver *s = chr->opaque; + return send_all(s->fd_out, buf, len); +} + +static int fd_chr_read_poll(void *opaque) +{ + CharDriverState *chr = opaque; + FDCharDriver *s = chr->opaque; + + s->max_size = qemu_chr_can_read(chr); + return s->max_size; +} + +static void fd_chr_read(void *opaque) +{ + CharDriverState *chr = opaque; + FDCharDriver *s = chr->opaque; + int size, len; + uint8_t buf[1024]; + + len = sizeof(buf); + if (len > s->max_size) + len = s->max_size; + if (len == 0) + return; + size = read(s->fd_in, buf, len); + if (size == 0) { + /* FD has been closed. Remove it from the active list. */ + qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL); + return; + } + if (size > 0) { + qemu_chr_read(chr, buf, size); + } +} + +static void fd_chr_update_read_handler(CharDriverState *chr) +{ + FDCharDriver *s = chr->opaque; + + if (s->fd_in >= 0) { + if (nographic && s->fd_in == 0) { + } else { + qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll, + fd_chr_read, NULL, chr); + } + } +} + +static void fd_chr_close(struct CharDriverState *chr) +{ + FDCharDriver *s = chr->opaque; + + if (s->fd_in >= 0) { + if (nographic && s->fd_in == 0) { + } else { + qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL); + } + } + + qemu_free(s); +} + +/* open a character device to a unix fd */ +static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) +{ + CharDriverState *chr; + FDCharDriver *s; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + return NULL; + s = qemu_mallocz(sizeof(FDCharDriver)); + if (!s) { + free(chr); + return NULL; + } + s->fd_in = fd_in; + s->fd_out = fd_out; + chr->opaque = s; + chr->chr_write = fd_chr_write; + chr->chr_update_read_handler = fd_chr_update_read_handler; + chr->chr_close = fd_chr_close; + + qemu_chr_reset(chr); + + return chr; +} + +static CharDriverState *qemu_chr_open_file_out(const char *file_out) +{ + int fd_out; + + TFR(fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666)); + if (fd_out < 0) + return NULL; + return qemu_chr_open_fd(-1, fd_out); +} + +static CharDriverState *qemu_chr_open_pipe(const char *filename) +{ + int fd_in, fd_out; + char filename_in[256], filename_out[256]; + + snprintf(filename_in, 256, "%s.in", filename); + snprintf(filename_out, 256, "%s.out", filename); + TFR(fd_in = open(filename_in, O_RDWR | O_BINARY)); + TFR(fd_out = open(filename_out, O_RDWR | O_BINARY)); + if (fd_in < 0 || fd_out < 0) { + if (fd_in >= 0) + close(fd_in); + if (fd_out >= 0) + close(fd_out); + TFR(fd_in = fd_out = open(filename, O_RDWR | O_BINARY)); + if (fd_in < 0) + return NULL; + } + return qemu_chr_open_fd(fd_in, fd_out); +} + + +/* for STDIO, we handle the case where several clients use it + (nographic mode) */ + +#define TERM_FIFO_MAX_SIZE 1 + +static uint8_t term_fifo[TERM_FIFO_MAX_SIZE]; +static int term_fifo_size; + +static int stdio_read_poll(void *opaque) +{ + CharDriverState *chr = opaque; + + /* try to flush the queue if needed */ + if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) { + qemu_chr_read(chr, term_fifo, 1); + term_fifo_size = 0; + } + /* see if we can absorb more chars */ + if (term_fifo_size == 0) + return 1; + else + return 0; +} + +static void stdio_read(void *opaque) +{ + int size; + uint8_t buf[1]; + CharDriverState *chr = opaque; + + size = read(0, buf, 1); + if (size == 0) { + /* stdin has been closed. Remove it from the active list. */ + qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL); + return; + } + if (size > 0) { + if (qemu_chr_can_read(chr) > 0) { + qemu_chr_read(chr, buf, 1); + } else if (term_fifo_size == 0) { + term_fifo[term_fifo_size++] = buf[0]; + } + } +} + +/* init terminal so that we can grab keys */ +static struct termios oldtty; +static int old_fd0_flags; +static int term_atexit_done; + +static void term_exit(void) +{ + tcsetattr (0, TCSANOW, &oldtty); + fcntl(0, F_SETFL, old_fd0_flags); +} + +static void term_init(void) +{ + struct termios tty; + + tcgetattr (0, &tty); + oldtty = tty; + old_fd0_flags = fcntl(0, F_GETFL); + + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP + |INLCR|IGNCR|ICRNL|IXON); + tty.c_oflag |= OPOST; + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); + /* if graphical mode, we allow Ctrl-C handling */ + if (nographic) + tty.c_lflag &= ~ISIG; + tty.c_cflag &= ~(CSIZE|PARENB); + tty.c_cflag |= CS8; + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 0; + + tcsetattr (0, TCSANOW, &tty); + + if (!term_atexit_done++) + atexit(term_exit); + + fcntl(0, F_SETFL, O_NONBLOCK); +} + +static void qemu_chr_close_stdio(struct CharDriverState *chr) +{ + term_exit(); + stdio_nb_clients--; + qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL); + fd_chr_close(chr); +} + +static CharDriverState *qemu_chr_open_stdio(void) +{ + CharDriverState *chr; + + if (stdio_nb_clients >= STDIO_MAX_CLIENTS) + return NULL; + chr = qemu_chr_open_fd(0, 1); + chr->chr_close = qemu_chr_close_stdio; + qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr); + stdio_nb_clients++; + term_init(); + + return chr; +} + +#ifdef __sun__ +/* Once Solaris has openpty(), this is going to be removed. */ +int openpty(int *amaster, int *aslave, char *name, + struct termios *termp, struct winsize *winp) +{ + const char *slave; + int mfd = -1, sfd = -1; + + *amaster = *aslave = -1; + + mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY); + if (mfd < 0) + goto err; + + if (grantpt(mfd) == -1 || unlockpt(mfd) == -1) + goto err; + + if ((slave = ptsname(mfd)) == NULL) + goto err; + + if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1) + goto err; + + if (ioctl(sfd, I_PUSH, "ptem") == -1 || + (termp != NULL && tcgetattr(sfd, termp) < 0)) + goto err; + + if (amaster) + *amaster = mfd; + if (aslave) + *aslave = sfd; + if (winp) + ioctl(sfd, TIOCSWINSZ, winp); + + return 0; + +err: + if (sfd != -1) + close(sfd); + close(mfd); + return -1; +} + +void cfmakeraw (struct termios *termios_p) +{ + termios_p->c_iflag &= + ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); + termios_p->c_oflag &= ~OPOST; + termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); + termios_p->c_cflag &= ~(CSIZE|PARENB); + termios_p->c_cflag |= CS8; + + termios_p->c_cc[VMIN] = 0; + termios_p->c_cc[VTIME] = 0; +} +#endif + +#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ + || defined(__NetBSD__) || defined(__OpenBSD__) + +typedef struct { + int fd; + int connected; + int polling; + int read_bytes; + QEMUTimer *timer; +} PtyCharDriver; + +static void pty_chr_update_read_handler(CharDriverState *chr); +static void pty_chr_state(CharDriverState *chr, int connected); + +static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + PtyCharDriver *s = chr->opaque; + + if (!s->connected) { + /* guest sends data, check for (re-)connect */ + pty_chr_update_read_handler(chr); + return 0; + } + return send_all(s->fd, buf, len); +} + +static int pty_chr_read_poll(void *opaque) +{ + CharDriverState *chr = opaque; + PtyCharDriver *s = chr->opaque; + + s->read_bytes = qemu_chr_can_read(chr); + return s->read_bytes; +} + +static void pty_chr_read(void *opaque) +{ + CharDriverState *chr = opaque; + PtyCharDriver *s = chr->opaque; + int size, len; + uint8_t buf[1024]; + + len = sizeof(buf); + if (len > s->read_bytes) + len = s->read_bytes; + if (len == 0) + return; + size = read(s->fd, buf, len); + if ((size == -1 && errno == EIO) || + (size == 0)) { + pty_chr_state(chr, 0); + return; + } + if (size > 0) { + pty_chr_state(chr, 1); + qemu_chr_read(chr, buf, size); + } +} + +static void pty_chr_update_read_handler(CharDriverState *chr) +{ + PtyCharDriver *s = chr->opaque; + + qemu_set_fd_handler2(s->fd, pty_chr_read_poll, + pty_chr_read, NULL, chr); + s->polling = 1; + /* + * Short timeout here: just need wait long enougth that qemu makes + * it through the poll loop once. When reconnected we want a + * short timeout so we notice it almost instantly. Otherwise + * read() gives us -EIO instantly, making pty_chr_state() reset the + * timeout to the normal (much longer) poll interval before the + * timer triggers. + */ + qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 10); +} + +static void pty_chr_state(CharDriverState *chr, int connected) +{ + PtyCharDriver *s = chr->opaque; + + if (!connected) { + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); + s->connected = 0; + s->polling = 0; + /* (re-)connect poll interval for idle guests: once per second. + * We check more frequently in case the guests sends data to + * the virtual device linked to our pty. */ + qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000); + } else { + if (!s->connected) + qemu_chr_reset(chr); + s->connected = 1; + } +} + +static void pty_chr_timer(void *opaque) +{ + struct CharDriverState *chr = opaque; + PtyCharDriver *s = chr->opaque; + + if (s->connected) + return; + if (s->polling) { + /* If we arrive here without polling being cleared due + * read returning -EIO, then we are (re-)connected */ + pty_chr_state(chr, 1); + return; + } + + /* Next poll ... */ + pty_chr_update_read_handler(chr); +} + +static void pty_chr_close(struct CharDriverState *chr) +{ + PtyCharDriver *s = chr->opaque; + + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); + close(s->fd); + qemu_free(s); +} + +static CharDriverState *qemu_chr_open_pty(void) +{ + CharDriverState *chr; + PtyCharDriver *s; + struct termios tty; + int slave_fd, len; +#if defined(__OpenBSD__) + char pty_name[PATH_MAX]; +#define q_ptsname(x) pty_name +#else + char *pty_name = NULL; +#define q_ptsname(x) ptsname(x) +#endif + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + return NULL; + s = qemu_mallocz(sizeof(PtyCharDriver)); + if (!s) { + qemu_free(chr); + return NULL; + } + + if (openpty(&s->fd, &slave_fd, pty_name, NULL, NULL) < 0) { + return NULL; + } + + /* Set raw attributes on the pty. */ + cfmakeraw(&tty); + tcsetattr(slave_fd, TCSAFLUSH, &tty); + close(slave_fd); + + len = strlen(q_ptsname(s->fd)) + 5; + chr->filename = qemu_malloc(len); + snprintf(chr->filename, len, "pty:%s", q_ptsname(s->fd)); + fprintf(stderr, "char device redirected to %s\n", q_ptsname(s->fd)); + + chr->opaque = s; + chr->chr_write = pty_chr_write; + chr->chr_update_read_handler = pty_chr_update_read_handler; + chr->chr_close = pty_chr_close; + + s->timer = qemu_new_timer(rt_clock, pty_chr_timer, chr); + + return chr; +} + +static void tty_serial_init(int fd, int speed, + int parity, int data_bits, int stop_bits) +{ + struct termios tty; + speed_t spd; + +#if 0 + printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n", + speed, parity, data_bits, stop_bits); +#endif + tcgetattr (fd, &tty); + +#define MARGIN 1.1 + if (speed <= 50 * MARGIN) + spd = B50; + else if (speed <= 75 * MARGIN) + spd = B75; + else if (speed <= 300 * MARGIN) + spd = B300; + else if (speed <= 600 * MARGIN) + spd = B600; + else if (speed <= 1200 * MARGIN) + spd = B1200; + else if (speed <= 2400 * MARGIN) + spd = B2400; + else if (speed <= 4800 * MARGIN) + spd = B4800; + else if (speed <= 9600 * MARGIN) + spd = B9600; + else if (speed <= 19200 * MARGIN) + spd = B19200; + else if (speed <= 38400 * MARGIN) + spd = B38400; + else if (speed <= 57600 * MARGIN) + spd = B57600; + else if (speed <= 115200 * MARGIN) + spd = B115200; + else + spd = B115200; + + cfsetispeed(&tty, spd); + cfsetospeed(&tty, spd); + + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP + |INLCR|IGNCR|ICRNL|IXON); + tty.c_oflag |= OPOST; + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG); + tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS|CSTOPB); + switch(data_bits) { + default: + case 8: + tty.c_cflag |= CS8; + break; + case 7: + tty.c_cflag |= CS7; + break; + case 6: + tty.c_cflag |= CS6; + break; + case 5: + tty.c_cflag |= CS5; + break; + } + switch(parity) { + default: + case 'N': + break; + case 'E': + tty.c_cflag |= PARENB; + break; + case 'O': + tty.c_cflag |= PARENB | PARODD; + break; + } + if (stop_bits == 2) + tty.c_cflag |= CSTOPB; + + tcsetattr (fd, TCSANOW, &tty); +} + +static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg) +{ + FDCharDriver *s = chr->opaque; + + switch(cmd) { + case CHR_IOCTL_SERIAL_SET_PARAMS: + { + QEMUSerialSetParams *ssp = arg; + tty_serial_init(s->fd_in, ssp->speed, ssp->parity, + ssp->data_bits, ssp->stop_bits); + } + break; + case CHR_IOCTL_SERIAL_SET_BREAK: + { + int enable = *(int *)arg; + if (enable) + tcsendbreak(s->fd_in, 1); + } + break; + case CHR_IOCTL_SERIAL_GET_TIOCM: + { + int sarg = 0; + int *targ = (int *)arg; + ioctl(s->fd_in, TIOCMGET, &sarg); + *targ = 0; + if (sarg | TIOCM_CTS) + *targ |= CHR_TIOCM_CTS; + if (sarg | TIOCM_CAR) + *targ |= CHR_TIOCM_CAR; + if (sarg | TIOCM_DSR) + *targ |= CHR_TIOCM_DSR; + if (sarg | TIOCM_RI) + *targ |= CHR_TIOCM_RI; + if (sarg | TIOCM_DTR) + *targ |= CHR_TIOCM_DTR; + if (sarg | TIOCM_RTS) + *targ |= CHR_TIOCM_RTS; + } + break; + case CHR_IOCTL_SERIAL_SET_TIOCM: + { + int sarg = *(int *)arg; + int targ = 0; + if (sarg | CHR_TIOCM_DTR) + targ |= TIOCM_DTR; + if (sarg | CHR_TIOCM_RTS) + targ |= TIOCM_RTS; + ioctl(s->fd_in, TIOCMSET, &targ); + } + break; + default: + return -ENOTSUP; + } + return 0; +} + +static CharDriverState *qemu_chr_open_tty(const char *filename) +{ + CharDriverState *chr; + int fd; + + TFR(fd = open(filename, O_RDWR | O_NONBLOCK)); + tty_serial_init(fd, 115200, 'N', 8, 1); + chr = qemu_chr_open_fd(fd, fd); + if (!chr) { + close(fd); + return NULL; + } + chr->chr_ioctl = tty_serial_ioctl; + qemu_chr_reset(chr); + return chr; +} +#else /* ! __linux__ && ! __sun__ */ +static CharDriverState *qemu_chr_open_pty(void) +{ + return NULL; +} +#endif /* __linux__ || __sun__ */ + +#if defined(__linux__) +typedef struct { + int fd; + int mode; +} ParallelCharDriver; + +static int pp_hw_mode(ParallelCharDriver *s, uint16_t mode) +{ + if (s->mode != mode) { + int m = mode; + if (ioctl(s->fd, PPSETMODE, &m) < 0) + return 0; + s->mode = mode; + } + return 1; +} + +static int pp_ioctl(CharDriverState *chr, int cmd, void *arg) +{ + ParallelCharDriver *drv = chr->opaque; + int fd = drv->fd; + uint8_t b; + + switch(cmd) { + case CHR_IOCTL_PP_READ_DATA: + if (ioctl(fd, PPRDATA, &b) < 0) + return -ENOTSUP; + *(uint8_t *)arg = b; + break; + case CHR_IOCTL_PP_WRITE_DATA: + b = *(uint8_t *)arg; + if (ioctl(fd, PPWDATA, &b) < 0) + return -ENOTSUP; + break; + case CHR_IOCTL_PP_READ_CONTROL: + if (ioctl(fd, PPRCONTROL, &b) < 0) + return -ENOTSUP; + /* Linux gives only the lowest bits, and no way to know data + direction! For better compatibility set the fixed upper + bits. */ + *(uint8_t *)arg = b | 0xc0; + break; + case CHR_IOCTL_PP_WRITE_CONTROL: + b = *(uint8_t *)arg; + if (ioctl(fd, PPWCONTROL, &b) < 0) + return -ENOTSUP; + break; + case CHR_IOCTL_PP_READ_STATUS: + if (ioctl(fd, PPRSTATUS, &b) < 0) + return -ENOTSUP; + *(uint8_t *)arg = b; + break; + case CHR_IOCTL_PP_DATA_DIR: + if (ioctl(fd, PPDATADIR, (int *)arg) < 0) + return -ENOTSUP; + break; + case CHR_IOCTL_PP_EPP_READ_ADDR: + if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) { + struct ParallelIOArg *parg = arg; + int n = read(fd, parg->buffer, parg->count); + if (n != parg->count) { + return -EIO; + } + } + break; + case CHR_IOCTL_PP_EPP_READ: + if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) { + struct ParallelIOArg *parg = arg; + int n = read(fd, parg->buffer, parg->count); + if (n != parg->count) { + return -EIO; + } + } + break; + case CHR_IOCTL_PP_EPP_WRITE_ADDR: + if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) { + struct ParallelIOArg *parg = arg; + int n = write(fd, parg->buffer, parg->count); + if (n != parg->count) { + return -EIO; + } + } + break; + case CHR_IOCTL_PP_EPP_WRITE: + if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) { + struct ParallelIOArg *parg = arg; + int n = write(fd, parg->buffer, parg->count); + if (n != parg->count) { + return -EIO; + } + } + break; + default: + return -ENOTSUP; + } + return 0; +} + +static void pp_close(CharDriverState *chr) +{ + ParallelCharDriver *drv = chr->opaque; + int fd = drv->fd; + + pp_hw_mode(drv, IEEE1284_MODE_COMPAT); + ioctl(fd, PPRELEASE); + close(fd); + qemu_free(drv); +} + +static CharDriverState *qemu_chr_open_pp(const char *filename) +{ + CharDriverState *chr; + ParallelCharDriver *drv; + int fd; + + TFR(fd = open(filename, O_RDWR)); + if (fd < 0) + return NULL; + + if (ioctl(fd, PPCLAIM) < 0) { + close(fd); + return NULL; + } + + drv = qemu_mallocz(sizeof(ParallelCharDriver)); + if (!drv) { + close(fd); + return NULL; + } + drv->fd = fd; + drv->mode = IEEE1284_MODE_COMPAT; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) { + qemu_free(drv); + close(fd); + return NULL; + } + chr->chr_write = null_chr_write; + chr->chr_ioctl = pp_ioctl; + chr->chr_close = pp_close; + chr->opaque = drv; + + qemu_chr_reset(chr); + + return chr; +} +#endif /* __linux__ */ + +#else /* _WIN32 */ + +typedef struct { + int max_size; + HANDLE hcom, hrecv, hsend; + OVERLAPPED orecv, osend; + BOOL fpipe; + DWORD len; +} WinCharState; + +#define NSENDBUF 2048 +#define NRECVBUF 2048 +#define MAXCONNECT 1 +#define NTIMEOUT 5000 + +static int win_chr_poll(void *opaque); +static int win_chr_pipe_poll(void *opaque); + +static void win_chr_close(CharDriverState *chr) +{ + WinCharState *s = chr->opaque; + + if (s->hsend) { + CloseHandle(s->hsend); + s->hsend = NULL; + } + if (s->hrecv) { + CloseHandle(s->hrecv); + s->hrecv = NULL; + } + if (s->hcom) { + CloseHandle(s->hcom); + s->hcom = NULL; + } + if (s->fpipe) + qemu_del_polling_cb(win_chr_pipe_poll, chr); + else + qemu_del_polling_cb(win_chr_poll, chr); +} + +static int win_chr_init(CharDriverState *chr, const char *filename) +{ + WinCharState *s = chr->opaque; + COMMCONFIG comcfg; + COMMTIMEOUTS cto = { 0, 0, 0, 0, 0}; + COMSTAT comstat; + DWORD size; + DWORD err; + + s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!s->hsend) { + fprintf(stderr, "Failed CreateEvent\n"); + goto fail; + } + s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!s->hrecv) { + fprintf(stderr, "Failed CreateEvent\n"); + goto fail; + } + + s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + if (s->hcom == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Failed CreateFile (%lu)\n", GetLastError()); + s->hcom = NULL; + goto fail; + } + + if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) { + fprintf(stderr, "Failed SetupComm\n"); + goto fail; + } + + ZeroMemory(&comcfg, sizeof(COMMCONFIG)); + size = sizeof(COMMCONFIG); + GetDefaultCommConfig(filename, &comcfg, &size); + comcfg.dcb.DCBlength = sizeof(DCB); + CommConfigDialog(filename, NULL, &comcfg); + + if (!SetCommState(s->hcom, &comcfg.dcb)) { + fprintf(stderr, "Failed SetCommState\n"); + goto fail; + } + + if (!SetCommMask(s->hcom, EV_ERR)) { + fprintf(stderr, "Failed SetCommMask\n"); + goto fail; + } + + cto.ReadIntervalTimeout = MAXDWORD; + if (!SetCommTimeouts(s->hcom, &cto)) { + fprintf(stderr, "Failed SetCommTimeouts\n"); + goto fail; + } + + if (!ClearCommError(s->hcom, &err, &comstat)) { + fprintf(stderr, "Failed ClearCommError\n"); + goto fail; + } + qemu_add_polling_cb(win_chr_poll, chr); + return 0; + + fail: + win_chr_close(chr); + return -1; +} + +static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1) +{ + WinCharState *s = chr->opaque; + DWORD len, ret, size, err; + + len = len1; + ZeroMemory(&s->osend, sizeof(s->osend)); + s->osend.hEvent = s->hsend; + while (len > 0) { + if (s->hsend) + ret = WriteFile(s->hcom, buf, len, &size, &s->osend); + else + ret = WriteFile(s->hcom, buf, len, &size, NULL); + if (!ret) { + err = GetLastError(); + if (err == ERROR_IO_PENDING) { + ret = GetOverlappedResult(s->hcom, &s->osend, &size, TRUE); + if (ret) { + buf += size; + len -= size; + } else { + break; + } + } else { + break; + } + } else { + buf += size; + len -= size; + } + } + return len1 - len; +} + +static int win_chr_read_poll(CharDriverState *chr) +{ + WinCharState *s = chr->opaque; + + s->max_size = qemu_chr_can_read(chr); + return s->max_size; +} + +static void win_chr_readfile(CharDriverState *chr) +{ + WinCharState *s = chr->opaque; + int ret, err; + uint8_t buf[1024]; + DWORD size; + + ZeroMemory(&s->orecv, sizeof(s->orecv)); + s->orecv.hEvent = s->hrecv; + ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv); + if (!ret) { + err = GetLastError(); + if (err == ERROR_IO_PENDING) { + ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE); + } + } + + if (size > 0) { + qemu_chr_read(chr, buf, size); + } +} + +static void win_chr_read(CharDriverState *chr) +{ + WinCharState *s = chr->opaque; + + if (s->len > s->max_size) + s->len = s->max_size; + if (s->len == 0) + return; + + win_chr_readfile(chr); +} + +static int win_chr_poll(void *opaque) +{ + CharDriverState *chr = opaque; + WinCharState *s = chr->opaque; + COMSTAT status; + DWORD comerr; + + ClearCommError(s->hcom, &comerr, &status); + if (status.cbInQue > 0) { + s->len = status.cbInQue; + win_chr_read_poll(chr); + win_chr_read(chr); + return 1; + } + return 0; +} + +static CharDriverState *qemu_chr_open_win(const char *filename) +{ + CharDriverState *chr; + WinCharState *s; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + return NULL; + s = qemu_mallocz(sizeof(WinCharState)); + if (!s) { + free(chr); + return NULL; + } + chr->opaque = s; + chr->chr_write = win_chr_write; + chr->chr_close = win_chr_close; + + if (win_chr_init(chr, filename) < 0) { + free(s); + free(chr); + return NULL; + } + qemu_chr_reset(chr); + return chr; +} + +static int win_chr_pipe_poll(void *opaque) +{ + CharDriverState *chr = opaque; + WinCharState *s = chr->opaque; + DWORD size; + + PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL); + if (size > 0) { + s->len = size; + win_chr_read_poll(chr); + win_chr_read(chr); + return 1; + } + return 0; +} + +static int win_chr_pipe_init(CharDriverState *chr, const char *filename) +{ + WinCharState *s = chr->opaque; + OVERLAPPED ov; + int ret; + DWORD size; + char openname[256]; + + s->fpipe = TRUE; + + s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!s->hsend) { + fprintf(stderr, "Failed CreateEvent\n"); + goto fail; + } + s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!s->hrecv) { + fprintf(stderr, "Failed CreateEvent\n"); + goto fail; + } + + snprintf(openname, sizeof(openname), "\\\\.\\pipe\\%s", filename); + s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | + PIPE_WAIT, + MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL); + if (s->hcom == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Failed CreateNamedPipe (%lu)\n", GetLastError()); + s->hcom = NULL; + goto fail; + } + + ZeroMemory(&ov, sizeof(ov)); + ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + ret = ConnectNamedPipe(s->hcom, &ov); + if (ret) { + fprintf(stderr, "Failed ConnectNamedPipe\n"); + goto fail; + } + + ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE); + if (!ret) { + fprintf(stderr, "Failed GetOverlappedResult\n"); + if (ov.hEvent) { + CloseHandle(ov.hEvent); + ov.hEvent = NULL; + } + goto fail; + } + + if (ov.hEvent) { + CloseHandle(ov.hEvent); + ov.hEvent = NULL; + } + qemu_add_polling_cb(win_chr_pipe_poll, chr); + return 0; + + fail: + win_chr_close(chr); + return -1; +} + + +static CharDriverState *qemu_chr_open_win_pipe(const char *filename) +{ + CharDriverState *chr; + WinCharState *s; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + return NULL; + s = qemu_mallocz(sizeof(WinCharState)); + if (!s) { + free(chr); + return NULL; + } + chr->opaque = s; + chr->chr_write = win_chr_write; + chr->chr_close = win_chr_close; + + if (win_chr_pipe_init(chr, filename) < 0) { + free(s); + free(chr); + return NULL; + } + qemu_chr_reset(chr); + return chr; +} + +static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) +{ + CharDriverState *chr; + WinCharState *s; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + return NULL; + s = qemu_mallocz(sizeof(WinCharState)); + if (!s) { + free(chr); + return NULL; + } + s->hcom = fd_out; + chr->opaque = s; + chr->chr_write = win_chr_write; + qemu_chr_reset(chr); + return chr; +} + +static CharDriverState *qemu_chr_open_win_con(const char *filename) +{ + return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE)); +} + +static CharDriverState *qemu_chr_open_win_file_out(const char *file_out) +{ + HANDLE fd_out; + + fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (fd_out == INVALID_HANDLE_VALUE) + return NULL; + + return qemu_chr_open_win_file(fd_out); +} +#endif /* !_WIN32 */ + +/***********************************************************/ +/* UDP Net console */ + +typedef struct { + int fd; + struct sockaddr_in daddr; + uint8_t buf[1024]; + int bufcnt; + int bufptr; + int max_size; +} NetCharDriver; + +static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + NetCharDriver *s = chr->opaque; + + return sendto(s->fd, buf, len, 0, + (struct sockaddr *)&s->daddr, sizeof(struct sockaddr_in)); +} + +static int udp_chr_read_poll(void *opaque) +{ + CharDriverState *chr = opaque; + NetCharDriver *s = chr->opaque; + + s->max_size = qemu_chr_can_read(chr); + + /* If there were any stray characters in the queue process them + * first + */ + while (s->max_size > 0 && s->bufptr < s->bufcnt) { + qemu_chr_read(chr, &s->buf[s->bufptr], 1); + s->bufptr++; + s->max_size = qemu_chr_can_read(chr); + } + return s->max_size; +} + +static void udp_chr_read(void *opaque) +{ + CharDriverState *chr = opaque; + NetCharDriver *s = chr->opaque; + + if (s->max_size == 0) + return; + s->bufcnt = recv(s->fd, s->buf, sizeof(s->buf), 0); + s->bufptr = s->bufcnt; + if (s->bufcnt <= 0) + return; + + s->bufptr = 0; + while (s->max_size > 0 && s->bufptr < s->bufcnt) { + qemu_chr_read(chr, &s->buf[s->bufptr], 1); + s->bufptr++; + s->max_size = qemu_chr_can_read(chr); + } +} + +static void udp_chr_update_read_handler(CharDriverState *chr) +{ + NetCharDriver *s = chr->opaque; + + if (s->fd >= 0) { + qemu_set_fd_handler2(s->fd, udp_chr_read_poll, + udp_chr_read, NULL, chr); + } +} + +static CharDriverState *qemu_chr_open_udp(const char *def) +{ + CharDriverState *chr = NULL; + NetCharDriver *s = NULL; + int fd = -1; + struct sockaddr_in saddr; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + goto return_err; + s = qemu_mallocz(sizeof(NetCharDriver)); + if (!s) + goto return_err; + + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + perror("socket(PF_INET, SOCK_DGRAM)"); + goto return_err; + } + + if (parse_host_src_port(&s->daddr, &saddr, def) < 0) { + printf("Could not parse: %s\n", def); + goto return_err; + } + + if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) + { + perror("bind"); + goto return_err; + } + + s->fd = fd; + s->bufcnt = 0; + s->bufptr = 0; + chr->opaque = s; + chr->chr_write = udp_chr_write; + chr->chr_update_read_handler = udp_chr_update_read_handler; + return chr; + +return_err: + if (chr) + free(chr); + if (s) + free(s); + if (fd >= 0) + closesocket(fd); + return NULL; +} + +/***********************************************************/ +/* TCP Net console */ + +typedef struct { + int fd, listen_fd; + int connected; + int max_size; + int do_telnetopt; + int do_nodelay; + int is_unix; +} TCPCharDriver; + +static void tcp_chr_accept(void *opaque); + +static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + TCPCharDriver *s = chr->opaque; + if (s->connected) { + return send_all(s->fd, buf, len); + } else { + /* XXX: indicate an error ? */ + return len; + } +} + +static int tcp_chr_read_poll(void *opaque) +{ + CharDriverState *chr = opaque; + TCPCharDriver *s = chr->opaque; + if (!s->connected) + return 0; + s->max_size = qemu_chr_can_read(chr); + return s->max_size; +} + +#define IAC 255 +#define IAC_BREAK 243 +static void tcp_chr_process_IAC_bytes(CharDriverState *chr, + TCPCharDriver *s, + uint8_t *buf, int *size) +{ + /* Handle any telnet client's basic IAC options to satisfy char by + * char mode with no echo. All IAC options will be removed from + * the buf and the do_telnetopt variable will be used to track the + * state of the width of the IAC information. + * + * IAC commands come in sets of 3 bytes with the exception of the + * "IAC BREAK" command and the double IAC. + */ + + int i; + int j = 0; + + for (i = 0; i < *size; i++) { + if (s->do_telnetopt > 1) { + if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) { + /* Double IAC means send an IAC */ + if (j != i) + buf[j] = buf[i]; + j++; + s->do_telnetopt = 1; + } else { + if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) { + /* Handle IAC break commands by sending a serial break */ + qemu_chr_event(chr, CHR_EVENT_BREAK); + s->do_telnetopt++; + } + s->do_telnetopt++; + } + if (s->do_telnetopt >= 4) { + s->do_telnetopt = 1; + } + } else { + if ((unsigned char)buf[i] == IAC) { + s->do_telnetopt = 2; + } else { + if (j != i) + buf[j] = buf[i]; + j++; + } + } + } + *size = j; +} + +static void tcp_chr_read(void *opaque) +{ + CharDriverState *chr = opaque; + TCPCharDriver *s = chr->opaque; + uint8_t buf[1024]; + int len, size; + + if (!s->connected || s->max_size <= 0) + return; + len = sizeof(buf); + if (len > s->max_size) + len = s->max_size; + size = recv(s->fd, buf, len, 0); + if (size == 0) { + /* connection closed */ + s->connected = 0; + if (s->listen_fd >= 0) { + qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); + } + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + closesocket(s->fd); + s->fd = -1; + } else if (size > 0) { + if (s->do_telnetopt) + tcp_chr_process_IAC_bytes(chr, s, buf, &size); + if (size > 0) + qemu_chr_read(chr, buf, size); + } +} + +static void tcp_chr_connect(void *opaque) +{ + CharDriverState *chr = opaque; + TCPCharDriver *s = chr->opaque; + + s->connected = 1; + qemu_set_fd_handler2(s->fd, tcp_chr_read_poll, + tcp_chr_read, NULL, chr); + qemu_chr_reset(chr); +} + +#define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c; +static void tcp_chr_telnet_init(int fd) +{ + char buf[3]; + /* Send the telnet negotion to put telnet in binary, no echo, single char mode */ + IACSET(buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */ + send(fd, (char *)buf, 3, 0); + IACSET(buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */ + send(fd, (char *)buf, 3, 0); + IACSET(buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */ + send(fd, (char *)buf, 3, 0); + IACSET(buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */ + send(fd, (char *)buf, 3, 0); +} + +static void socket_set_nodelay(int fd) +{ + int val = 1; + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); +} + +static void tcp_chr_accept(void *opaque) +{ + CharDriverState *chr = opaque; + TCPCharDriver *s = chr->opaque; + struct sockaddr_in saddr; +#ifndef _WIN32 + struct sockaddr_un uaddr; +#endif + struct sockaddr *addr; + socklen_t len; + int fd; + + for(;;) { +#ifndef _WIN32 + if (s->is_unix) { + len = sizeof(uaddr); + addr = (struct sockaddr *)&uaddr; + } else +#endif + { + len = sizeof(saddr); + addr = (struct sockaddr *)&saddr; + } + fd = accept(s->listen_fd, addr, &len); + if (fd < 0 && errno != EINTR) { + return; + } else if (fd >= 0) { + if (s->do_telnetopt) + tcp_chr_telnet_init(fd); + break; + } + } + socket_set_nonblock(fd); + if (s->do_nodelay) + socket_set_nodelay(fd); + s->fd = fd; + qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); + tcp_chr_connect(chr); +} + +static void tcp_chr_close(CharDriverState *chr) +{ + TCPCharDriver *s = chr->opaque; + if (s->fd >= 0) + closesocket(s->fd); + if (s->listen_fd >= 0) + closesocket(s->listen_fd); + qemu_free(s); +} + +static CharDriverState *qemu_chr_open_tcp(const char *host_str, + int is_telnet, + int is_unix) +{ + CharDriverState *chr = NULL; + TCPCharDriver *s = NULL; + int fd = -1, offset = 0; + int is_listen = 0; + int is_waitconnect = 1; + int do_nodelay = 0; + const char *ptr; + + ptr = host_str; + while((ptr = strchr(ptr,','))) { + ptr++; + if (!strncmp(ptr,"server",6)) { + is_listen = 1; + } else if (!strncmp(ptr,"nowait",6)) { + is_waitconnect = 0; + } else if (!strncmp(ptr,"nodelay",6)) { + do_nodelay = 1; + } else if (!strncmp(ptr,"to=",3)) { + /* nothing, inet_listen() parses this one */; + } else { + printf("Unknown option: %s\n", ptr); + goto fail; + } + } + if (!is_listen) + is_waitconnect = 0; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + goto fail; + s = qemu_mallocz(sizeof(TCPCharDriver)); + if (!s) + goto fail; + + if (is_listen) { + chr->filename = qemu_malloc(256); + if (is_unix) { + strcpy(chr->filename, "unix:"); + } else if (is_telnet) { + strcpy(chr->filename, "telnet:"); + } else { + strcpy(chr->filename, "tcp:"); + } + offset = strlen(chr->filename); + } + if (is_unix) { + if (is_listen) { + fd = unix_listen(host_str, chr->filename + offset, 256 - offset); + } else { + fd = unix_connect(host_str); + } + } else { + if (is_listen) { + fd = inet_listen(host_str, chr->filename + offset, 256 - offset, + SOCK_STREAM, 0); + } else { + fd = inet_connect(host_str, SOCK_STREAM); + } + } + if (fd < 0) + goto fail; + + if (!is_waitconnect) + socket_set_nonblock(fd); + + s->connected = 0; + s->fd = -1; + s->listen_fd = -1; + s->is_unix = is_unix; + s->do_nodelay = do_nodelay && !is_unix; + + chr->opaque = s; + chr->chr_write = tcp_chr_write; + chr->chr_close = tcp_chr_close; + + if (is_listen) { + s->listen_fd = fd; + qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); + if (is_telnet) + s->do_telnetopt = 1; + } else { + s->connected = 1; + s->fd = fd; + socket_set_nodelay(fd); + tcp_chr_connect(chr); + } + + if (is_listen && is_waitconnect) { + printf("QEMU waiting for connection on: %s\n", + chr->filename ? chr->filename : host_str); + tcp_chr_accept(chr); + socket_set_nonblock(s->listen_fd); + } + + return chr; + fail: + if (fd >= 0) + closesocket(fd); + qemu_free(s); + qemu_free(chr); + return NULL; +} + +static TAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs += TAILQ_HEAD_INITIALIZER(chardevs); + +CharDriverState *qemu_chr_open(const char *label, const char *filename) +{ + const char *p; + CharDriverState *chr; + + if (!strcmp(filename, "vc")) { + chr = text_console_init(&display_state, 0); + } else + if (strstart(filename, "vc:", &p)) { + chr = text_console_init(&display_state, p); + } else + if (!strcmp(filename, "null")) { + chr = qemu_chr_open_null(); + } else + if (strstart(filename, "tcp:", &p)) { + chr = qemu_chr_open_tcp(p, 0, 0); + } else + if (strstart(filename, "telnet:", &p)) { + chr = qemu_chr_open_tcp(p, 1, 0); + } else + if (strstart(filename, "udp:", &p)) { + chr = qemu_chr_open_udp(p); + } else + if (strstart(filename, "mon:", &p)) { + chr = qemu_chr_open(label, p); + if (chr) { + chr = qemu_chr_open_mux(chr); + monitor_init(chr, !nographic); + } else { + printf("Unable to open driver: %s\n", p); + } + } else +#ifndef _WIN32 + if (strstart(filename, "unix:", &p)) { + chr = qemu_chr_open_tcp(p, 0, 1); + } else if (strstart(filename, "file:", &p)) { + chr = qemu_chr_open_file_out(p); + } else if (strstart(filename, "pipe:", &p)) { + chr = qemu_chr_open_pipe(p); + } else if (!strcmp(filename, "pty")) { + chr = qemu_chr_open_pty(); + } else if (!strcmp(filename, "stdio")) { + chr = qemu_chr_open_stdio(); + } else +#if defined(__linux__) + if (strstart(filename, "/dev/parport", NULL)) { + chr = qemu_chr_open_pp(filename); + } else +#endif +#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ + || defined(__NetBSD__) || defined(__OpenBSD__) + if (strstart(filename, "/dev/", NULL)) { + chr = qemu_chr_open_tty(filename); + } else +#endif +#else /* !_WIN32 */ + if (strstart(filename, "COM", NULL)) { + chr = qemu_chr_open_win(filename); + } else + if (strstart(filename, "pipe:", &p)) { + chr = qemu_chr_open_win_pipe(p); + } else + if (strstart(filename, "con:", NULL)) { + chr = qemu_chr_open_win_con(filename); + } else + if (strstart(filename, "file:", &p)) { + chr = qemu_chr_open_win_file_out(p); + } else +#endif +#ifdef CONFIG_BRLAPI + if (!strcmp(filename, "braille")) { + chr = chr_baum_init(); + } else +#endif + { + chr = NULL; + } + + if (chr) { + if (!chr->filename) + chr->filename = qemu_strdup(filename); + chr->label = qemu_strdup(label); + TAILQ_INSERT_TAIL(&chardevs, chr, next); + } + return chr; +} + +void qemu_chr_close(CharDriverState *chr) +{ + TAILQ_REMOVE(&chardevs, chr, next); + if (chr->chr_close) + chr->chr_close(chr); + qemu_free(chr->filename); + qemu_free(chr->label); + qemu_free(chr); +} + +void qemu_chr_info(void) +{ + CharDriverState *chr; + + TAILQ_FOREACH(chr, &chardevs, next) { + term_printf("%s: filename=%s\n", chr->label, chr->filename); + } +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/qemu-char.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/qemu-char.h --- qemu-0.9.1/qemu-char.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/qemu-char.h 2008-10-31 18:44:40.000000000 +0000 @@ -1,6 +1,7 @@ #ifndef QEMU_CHAR_H #define QEMU_CHAR_H +#include "sys-queue.h" /* character device */ #define CHR_EVENT_BREAK 0 /* serial break char */ @@ -27,6 +28,17 @@ #define CHR_IOCTL_PP_EPP_READ 9 #define CHR_IOCTL_PP_EPP_WRITE_ADDR 10 #define CHR_IOCTL_PP_EPP_WRITE 11 +#define CHR_IOCTL_PP_DATA_DIR 12 + +#define CHR_IOCTL_SERIAL_SET_TIOCM 13 +#define CHR_IOCTL_SERIAL_GET_TIOCM 14 + +#define CHR_TIOCM_CTS 0x020 +#define CHR_TIOCM_CAR 0x040 +#define CHR_TIOCM_DSR 0x100 +#define CHR_TIOCM_RI 0x080 +#define CHR_TIOCM_DTR 0x002 +#define CHR_TIOCM_RTS 0x004 typedef void IOEventHandler(void *opaque, int event); @@ -44,9 +56,12 @@ void *opaque; int focus; QEMUBH *bh; + char *label; + char *filename; + TAILQ_ENTRY(CharDriverState) next; }; -CharDriverState *qemu_chr_open(const char *filename); +CharDriverState *qemu_chr_open(const char *label, const char *filename); void qemu_chr_close(CharDriverState *chr); void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); @@ -61,6 +76,9 @@ int qemu_chr_can_read(CharDriverState *s); void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len); void qemu_chr_accept_input(CharDriverState *s); +void qemu_chr_info(void); + +extern int term_escape_char; /* async I/O support */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/qemu-common.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/qemu-common.h --- qemu-0.9.1/qemu-common.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/qemu-common.h 2008-11-11 20:46:40.000000000 +0000 @@ -29,6 +29,7 @@ #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN +#define WINVER 0x0501 /* needed for ipv6 bits */ #include #define fsync _commit #define lseek _lseeki64 @@ -70,12 +71,22 @@ QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque); void qemu_bh_schedule(QEMUBH *bh); +/* Bottom halfs that are scheduled from a bottom half handler are instantly + * invoked. This can create an infinite loop if a bottom half handler + * schedules itself. qemu_bh_schedule_idle() avoids this infinite loop by + * ensuring that the bottom half isn't executed until the next main loop + * iteration. + */ +void qemu_bh_schedule_idle(QEMUBH *bh); void qemu_bh_cancel(QEMUBH *bh); void qemu_bh_delete(QEMUBH *bh); int qemu_bh_poll(void); uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); +void qemu_get_timedate(struct tm *tm, int offset); +int qemu_timedate_diff(struct tm *tm); + /* cutils.c */ void pstrcpy(char *buf, int buf_size, const char *str); char *pstrcat(char *buf, int buf_size, const char *s); @@ -83,6 +94,16 @@ int stristart(const char *str, const char *val, const char **ptr); time_t mktimegm(struct tm *tm); +void *qemu_malloc(size_t size); +void *qemu_realloc(void *ptr, size_t size); +void *qemu_mallocz(size_t size); +void qemu_free(void *ptr); +char *qemu_strdup(const char *str); +char *qemu_strndup(const char *str, size_t size); + +void *get_mmap_addr(unsigned long size); + + /* Error handling. */ void hw_error(const char *fmt, ...) @@ -104,10 +125,12 @@ /* A load of opaque types so that device init declarations don't have to pull in all the real definitions. */ typedef struct NICInfo NICInfo; +typedef struct HCIInfo HCIInfo; typedef struct AudioState AudioState; typedef struct BlockDriverState BlockDriverState; typedef struct DisplayState DisplayState; typedef struct TextConsole TextConsole; +typedef TextConsole QEMUConsole; typedef struct CharDriverState CharDriverState; typedef struct VLANState VLANState; typedef struct QEMUFile QEMUFile; @@ -121,4 +144,11 @@ typedef struct IRQState *qemu_irq; struct pcmcia_card_s; +/* CPU save/load. */ +void cpu_save(QEMUFile *f, void *opaque); +int cpu_load(QEMUFile *f, void *opaque, int version_id); + +/* Force QEMU to stop what it's doing and service IO */ +void qemu_service_io(void); + #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/qemu-doc.texi /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/qemu-doc.texi --- qemu-0.9.1/qemu-doc.texi 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/qemu-doc.texi 2008-11-09 02:24:54.000000000 +0000 @@ -75,8 +75,9 @@ @item G3 BW PowerMac (PowerPC processor) @item Mac99 PowerMac (PowerPC processor, in progress) @item Sun4m/Sun4c/Sun4d (32-bit Sparc processor) -@item Sun4u (64-bit Sparc processor, in progress) +@item Sun4u/Sun4v (64-bit Sparc processor, in progress) @item Malta board (32-bit and 64-bit MIPS processors) +@item MIPS Magnum (64-bit MIPS processor) @item ARM Integrator/CP (ARM) @item ARM Versatile baseboard (ARM) @item ARM RealView Emulation baseboard (ARM) @@ -86,6 +87,8 @@ @item Freescale MCF5208EVB (ColdFire V2). @item Arnewsh MCF5206 evaluation board (ColdFire V2). @item Palm Tungsten|E PDA (OMAP310 processor) +@item N800 and N810 tablets (OMAP2420 processor) +@item MusicPal (MV88W8618 ARM processor) @end itemize For user emulation, x86, PowerPC, ARM, 32-bit MIPS, Sparc32/64 and ColdFire(m68k) CPUs are supported. @@ -166,21 +169,33 @@ @item ENSONIQ AudioPCI ES1370 sound card @item +Intel 82801AA AC97 Audio compatible sound card +@item Adlib(OPL2) - Yamaha YM3812 compatible chip @item +Gravis Ultrasound GF1 sound card +@item +CS4231A compatible sound card +@item PCI UHCI USB controller and a virtual USB hub. @end itemize SMP is supported with up to 255 CPUs. -Note that adlib is only available when QEMU was configured with --enable-adlib +Note that adlib, ac97, gus and cs4231a are only available when QEMU +was configured with --audio-card-list option containing the name(s) of +required card(s). QEMU uses the PC BIOS from the Bochs project and the Plex86/Bochs LGPL VGA BIOS. QEMU uses YM3812 emulation by Tatsuyuki Satoh. +QEMU uses GUS emulation(GUSEMU32 @url{http://www.deinmeister.de/gusemu/}) +by Tibor "TS" Schütz. + +CS4231A is the chip used in Windows Sound System and GUSMAX products + @c man end @node pcsys_quickstart @@ -234,7 +249,8 @@ @table @code @item file=@var{file} This option defines which disk image (@pxref{disk_images}) to use with -this drive. +this drive. If the filename contains comma, you must double it +(for instance, "file=my,,file" to use file "my,file"). @item if=@var{interface} This option defines on which type on interface the drive is connected. Available types are: ide, scsi, sd, mtd, floppy, pflash. @@ -251,8 +267,27 @@ @item snapshot=@var{snapshot} @var{snapshot} is "on" or "off" and allows to enable snapshot for given drive (see @option{-snapshot}). @item cache=@var{cache} -@var{cache} is "on" or "off" and allows to disable host cache to access data. -@end table +@var{cache} is "none", "writeback", or "writethrough" and controls how the host cache is used to access block data. +@item format=@var{format} +Specify which disk @var{format} will be used rather than detecting +the format. Can be used to specifiy format=raw to avoid interpreting +an untrusted format header. +@end table + +By default, writethrough caching is used for all block device. This means that +the host page cache will be used to read and write data but write notification +will be sent to the guest only when the data has been reported as written by +the storage subsystem. + +Writeback caching will report data writes as completed as soon as the data is +present in the host page cache. This is safe as long as you trust your host. +If your host crashes or loses power, then the guest may experience data +corruption. When using the @option{-snapshot} option, writeback caching is +used by default. + +The host page can be avoided entirely with @option{cache=none}. This will +attempt to do disk IO directly to the guests memory. QEMU may still perform +an internal copy of the data. Instead of @option{-cdrom} you can use: @example @@ -313,7 +348,12 @@ be needed to boot from old floppy disks. @item -m @var{megs} -Set virtual RAM size to @var{megs} megabytes. Default is 128 MiB. +Set virtual RAM size to @var{megs} megabytes. Default is 128 MiB. Optionally, +a suffix of ``M'' or ``G'' can be used to signify a value in megabytes or +gigabytes respectively. + +@item -cpu @var{model} +Select CPU model (-cpu ? for list and additional feature selection) @item -smp @var{n} Simulate an SMP system with @var{n} CPUs. On the PC target, up to 255 @@ -333,10 +373,18 @@ @example qemu -soundhw sb16,adlib hda qemu -soundhw es1370 hda +qemu -soundhw ac97 hda qemu -soundhw all hda qemu -soundhw ? @end example +Note that Linux's i810_audio OSS kernel (for AC97) module might +require manually specifying clocking. + +@example +modprobe i810_audio clocking=48000 +@end example + @item -localtime Set the real time clock to local time (the default is to UTC time). This option is needed to have correct date in MS-DOS or @@ -384,12 +432,22 @@ the console. Therefore, you can still use QEMU to debug a Linux kernel with a serial console. +@item -curses + +Normally, QEMU uses SDL to display the VGA output. With this option, +QEMU can display the VGA output when in text mode using a +curses/ncurses interface. Nothing is displayed in graphical mode. + @item -no-frame Do not use decorations for SDL windows and start them using the whole available screen space. This makes the using QEMU in a dedicated desktop workspace more convenient. +@item -no-quit + +Disable SDL window close capability. + @item -full-screen Start in full screen. @@ -405,21 +463,21 @@ @table @code -@item @var{interface}:@var{d} +@item @var{host}:@var{d} -TCP connections will only be allowed from @var{interface} on display @var{d}. -By convention the TCP port is 5900+@var{d}. Optionally, @var{interface} can -be omitted in which case the server will bind to all interfaces. +TCP connections will only be allowed from @var{host} on display @var{d}. +By convention the TCP port is 5900+@var{d}. Optionally, @var{host} can +be omitted in which case the server will accept connections from any host. -@item @var{unix}:@var{path} +@item @code{unix}:@var{path} Connections will be allowed over UNIX domain sockets where @var{path} is the location of a unix socket to listen for connections on. @item none -VNC is initialized by not started. The monitor @code{change} command can be used -to later start the VNC server. +VNC is initialized but not started. The monitor @code{change} command +can be used to later start the VNC server. @end table @@ -428,6 +486,13 @@ @table @code +@item reverse + +Connect to a listening VNC client via a ``reverse'' connection. The +client is specified by the @var{display}. For reverse network +connections (@var{host}:@var{d},@code{reverse}), the @var{d} argument +is a TCP port number, not a display number. + @item password Require that password based authentication is used for client connections. @@ -492,6 +557,41 @@ @item -usbdevice @var{devname} Add the USB device @var{devname}. @xref{usb_devices}. + +@table @code + +@item mouse +Virtual Mouse. This will override the PS/2 mouse emulation when activated. + +@item tablet +Pointer device that uses absolute coordinates (like a touchscreen). This +means qemu is able to report the mouse position without having to grab the +mouse. Also overrides the PS/2 mouse emulation when activated. + +@item disk:[format=@var{format}]:file +Mass storage device based on file. The optional @var{format} argument +will be used rather than detecting the format. Can be used to specifiy +format=raw to avoid interpreting an untrusted format header. + +@item host:bus.addr +Pass through the host device identified by bus.addr (Linux only). + +@item host:vendor_id:product_id +Pass through the host device identified by vendor_id:product_id (Linux only). + +@item serial:[vendorid=@var{vendor_id}][,productid=@var{product_id}]:@var{dev} +Serial converter to host character device @var{dev}, see @code{-serial} for the +available devices. + +@item braille +Braille device. This will use BrlAPI to display the braille output on a real +or fake device. + +@item net:options +Network adapter that supports CDC ethernet and RNDIS protocols. + +@end table + @end table Network options: @@ -507,7 +607,7 @@ Valid values for @var{type} are @code{i82551}, @code{i82557b}, @code{i82559er}, @code{ne2k_pci}, @code{ne2k_isa}, @code{pcnet}, @code{rtl8139}, -@code{smc91c111}, @code{lance} and @code{mcf_fec}. +@code{e1000}, @code{smc91c111}, @code{lance} and @code{mcf_fec}. Not all devices are supported on all targets. Use -net nic,model=? for a list of available devices for your target. @@ -595,6 +695,21 @@ /path/to/linux ubd0=/path/to/root_fs eth0=mcast @end example +@item -net vde[,vlan=@var{n}][,sock=@var{socketpath}][,port=@var{n}][,group=@var{groupname}][,mode=@var{octalmode}] +Connect VLAN @var{n} to PORT @var{n} of a vde switch running on host and +listening for incoming connections on @var{socketpath}. Use GROUP @var{groupname} +and MODE @var{octalmode} to change default ownership and permissions for +communication port. This option is available only if QEMU has been compiled +with vde support enabled. + +Example: +@example +# launch vde switch +vde_switch -F -sock /tmp/myswitch +# launch QEMU instance +qemu linux.img -net nic -net vde,sock=/tmp/myswitch +@end example + @item -net none Indicate that no network devices should be configured. It is used to override the default configuration (@option{-net nic -net user}) which @@ -667,6 +782,62 @@ @end table +Bluetooth(R) options: +@table @option + +@item -bt hci[...] +Defines the function of the corresponding Bluetooth HCI. -bt options +are matched with the HCIs present in the chosen machine type. For +example when emulating a machine with only one HCI built into it, only +the first @code{-bt hci[...]} option is valid and defines the HCI's +logic. The Transport Layer is decided by the machine type. Currently +the machines @code{n800} and @code{n810} have one HCI and all other +machines have none. + +@anchor{bt-hcis} +The following three types are recognized: + +@table @code +@item -bt hci,null +(default) The corresponding Bluetooth HCI assumes no internal logic +and will not respond to any HCI commands or emit events. + +@item -bt hci,host[:@var{id}] +(@code{bluez} only) The corresponding HCI passes commands / events +to / from the physical HCI identified by the name @var{id} (default: +@code{hci0}) on the computer running QEMU. Only available on @code{bluez} +capable systems like Linux. + +@item -bt hci[,vlan=@var{n}] +Add a virtual, standard HCI that will participate in the Bluetooth +scatternet @var{n} (default @code{0}). Similarly to @option{-net} +VLANs, devices inside a bluetooth network @var{n} can only communicate +with other devices in the same network (scatternet). +@end table + +@item -bt vhci[,vlan=@var{n}] +(Linux-host only) Create a HCI in scatternet @var{n} (default 0) attached +to the host bluetooth stack instead of to the emulated target. This +allows the host and target machines to participate in a common scatternet +and communicate. Requires the Linux @code{vhci} driver installed. Can +be used as following: + +@example +qemu [...OPTIONS...] -bt hci,vlan=5 -bt vhci,vlan=5 +@end example + +@item -bt device:@var{dev}[,vlan=@var{n}] +Emulate a bluetooth device @var{dev} and place it in network @var{n} +(default @code{0}). QEMU can only emulate one type of bluetooth devices +currently: + +@table @code +@item keyboard +Virtual wireless keyboard implementing the HIDP bluetooth profile. +@end table + +@end table + Linux boot specific: When using these options, you can use a given Linux kernel without installing it in the disk image. It can be useful for easier testing of various kernels. @@ -803,6 +974,10 @@ @item -serial mon:telnet::4444,server,nowait @end table +@item braille +Braille device. This will use BrlAPI to display the braille output on a real +or fake device. + @end table @item -parallel @var{dev} @@ -854,11 +1029,24 @@ @item -L path Set the directory for the BIOS, VGA BIOS and keymaps. -@item -std-vga -Simulate a standard VGA card with Bochs VBE extensions (default is -Cirrus Logic GD5446 PCI VGA). If your guest OS supports the VESA 2.0 -VBE extensions (e.g. Windows XP) and if you want to use high -resolution modes (>= 1280x1024x16) then you should use this option. +@item -vga @var{type} +Select type of VGA card to emulate. Valid values for @var{type} are +@table @code +@item cirrus +Cirrus Logic GD5446 Video card. All Windows versions starting from +Windows 95 should recognize and use this graphic card. For optimal +performances, use 16 bit color depth in the guest and the host OS. +(This one is the default) +@item std +Standard VGA card with Bochs VBE extensions. If your guest OS +supports the VESA 2.0 VBE extensions (e.g. Windows XP) and if you want +to use high resolution modes (>= 1280x1024x16) then you should use +this option. +@item vmware +VMWare SVGA-II compatible adapter. Use it if you have sufficiently +recent XFree86/XOrg server or Windows guest with a driver for this +card. +@end table @item -no-acpi Disable ACPI (Advanced Configuration and Power Interface) support. Use @@ -868,6 +1056,11 @@ @item -no-reboot Exit instead of rebooting. +@item -no-shutdown +Don't exit QEMU on guest shutdown, but instead only stop the emulation. +This allows for instance switching to monitor to commit changes to the +disk image. + @item -loadvm file Start right away with a saved state (@code{loadvm} in monitor) @@ -879,6 +1072,17 @@ Note that this allows guest direct access to the host filesystem, so should only be used with trusted guest OS. + +@item -icount [N|auto] +Enable virtual instruction counter. The virtual cpu will execute one +instruction every 2^N ns of virtual time. If @code{auto} is specified +then the virtual cpu speed will be automatically adjusted to keep virtual +time within a few seconds of real time. + +Note that while this option can give deterministic behavior, it does not +provide cycle accurate emulation. Modern CPUs contain superscalar out of +order cores with complex cache hierarchies. The number of instructions +executed often has little or no correlation with actual performance. @end table @c man end @@ -1018,7 +1222,7 @@ Change the medium for a removable disk device to point to @var{filename}. eg @example -(qemu) change cdrom /path/to/some.iso +(qemu) change ide1-cd0 /path/to/some.iso @end example @item change vnc @var{display},@var{options} @@ -1167,8 +1371,9 @@ @item sendkey @var{keys} -Send @var{keys} to the emulator. Use @code{-} to press several keys -simultaneously. Example: +Send @var{keys} to the emulator. @var{keys} could be the name of the +key or @code{#} followed by the raw value in either decimal or hexadecimal +format. Use @code{-} to press several keys simultaneously. Example: @example sendkey ctrl-alt-f1 @end example @@ -1180,6 +1385,14 @@ Reset the system. +@item boot_set @var{bootdevicelist} + +Define new values for the boot device list. Those values will override +the values specified on the command line through the @code{-boot} option. + +The values that can be specified here depend on the machine type, but are +the same that can be specified in the @code{-boot} command line option. + @item usb_add @var{devname} Add the USB device @var{devname}. For details of available devices see @@ -1213,8 +1426,10 @@ * disk_images_snapshot_mode:: Snapshot mode * vm_snapshots:: VM snapshots * qemu_img_invocation:: qemu-img Invocation +* qemu_nbd_invocation:: qemu-nbd Invocation * host_drives:: Using host drives * disk_images_fat_images:: Virtual FAT disk images +* disk_images_nbd:: NBD access @end menu @node disk_images_quickstart @@ -1295,6 +1510,11 @@ @include qemu-img.texi +@node qemu_nbd_invocation +@subsection @code{qemu-nbd} Invocation + +@include qemu-nbd.texi + @node host_drives @subsection Using host drives @@ -1392,6 +1612,40 @@ @item write to the FAT directory on the host system while accessing it with the guest system. @end itemize +@node disk_images_nbd +@subsection NBD access + +QEMU can access directly to block device exported using the Network Block Device +protocol. + +@example +qemu linux.img -hdb nbd:my_nbd_server.mydomain.org:1024 +@end example + +If the NBD server is located on the same host, you can use an unix socket instead +of an inet socket: + +@example +qemu linux.img -hdb nbd:unix:/tmp/my_socket +@end example + +In this case, the block device must be exported using qemu-nbd: + +@example +qemu-nbd --socket=/tmp/my_socket my_disk.qcow2 +@end example + +The use of qemu-nbd allows to share a disk between several guests: +@example +qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2 +@end example + +and then you can use it with two guests: +@example +qemu linux1.img -hdb nbd:unix:/tmp/my_socket +qemu linux2.img -hdb nbd:unix:/tmp/my_socket +@end example + @node pcsys_network @section Network emulation @@ -1527,27 +1781,57 @@ USB devices can be connected with the @option{-usbdevice} commandline option or the @code{usb_add} monitor command. Available devices are: -@table @var -@item @code{mouse} +@table @code +@item mouse Virtual Mouse. This will override the PS/2 mouse emulation when activated. -@item @code{tablet} +@item tablet Pointer device that uses absolute coordinates (like a touchscreen). This means qemu is able to report the mouse position without having to grab the mouse. Also overrides the PS/2 mouse emulation when activated. -@item @code{disk:@var{file}} +@item disk:@var{file} Mass storage device based on @var{file} (@pxref{disk_images}) -@item @code{host:@var{bus.addr}} +@item host:@var{bus.addr} Pass through the host device identified by @var{bus.addr} (Linux only) -@item @code{host:@var{vendor_id:product_id}} +@item host:@var{vendor_id:product_id} Pass through the host device identified by @var{vendor_id:product_id} (Linux only) -@item @code{wacom-tablet} +@item wacom-tablet Virtual Wacom PenPartner tablet. This device is similar to the @code{tablet} above but it can be used with the tslib library because in addition to touch coordinates it reports touch pressure. -@item @code{keyboard} +@item keyboard Standard USB keyboard. Will override the PS/2 keyboard (if present). +@item serial:[vendorid=@var{vendor_id}][,product_id=@var{product_id}]:@var{dev} +Serial converter. This emulates an FTDI FT232BM chip connected to host character +device @var{dev}. The available character devices are the same as for the +@code{-serial} option. The @code{vendorid} and @code{productid} options can be +used to override the default 0403:6001. For instance, +@example +usb_add serial:productid=FA00:tcp:192.168.0.2:4444 +@end example +will connect to tcp port 4444 of ip 192.168.0.2, and plug that to the virtual +serial converter, faking a Matrix Orbital LCD Display (USB ID 0403:FA00). +@item braille +Braille device. This will use BrlAPI to display the braille output on a real +or fake device. +@item net:@var{options} +Network adapter that supports CDC ethernet and RNDIS protocols. @var{options} +specifies NIC options as with @code{-net nic,}@var{options} (see description). +For instance, user-mode networking can be used with +@example +qemu [...OPTIONS...] -net user,vlan=0 -usbdevice net:vlan=0 +@end example +Currently this cannot be used in machines that support PCI NICs. +@item bt[:@var{hci-type}] +Bluetooth dongle whose type is specified in the same format as with +the @option{-bt hci} option, @pxref{bt-hcis,,allowed HCI types}. If +no type is given, the HCI logic corresponds to @code{-bt hci,vlan=0}. +This USB device implements the USB Transport Layer of HCI. Example +usage: +@example +qemu [...OPTIONS...] -usbdevice bt:hci,vlan=3 -bt device:keyboard,vlan=3 +@end example @end table @node host_usb_devices @@ -1637,7 +1921,7 @@ to provide high security. The password can be fairly easily brute-forced by a client making repeat connections. For this reason, a VNC server using password authentication should be restricted to only listen on the loopback interface -or UNIX domain sockets. Password ayuthentication is requested with the @code{password} +or UNIX domain sockets. Password authentication is requested with the @code{password} option, and then once QEMU is running the password is set with the monitor. Until the monitor is used to set the password all clients will be rejected. @@ -1847,6 +2131,36 @@ @code{x/10i $cs*16+$eip} to dump the code at the PC position. @end enumerate +Advanced debugging options: + +The default single stepping behavior is step with the IRQs and timer service routines off. It is set this way because when gdb executes a single step it expects to advance beyond the current instruction. With the IRQs and and timer service routines on, a single step might jump into the one of the interrupt or exception vectors instead of executing the current instruction. This means you may hit the same breakpoint a number of times before executing the instruction gdb wants to have executed. Because there are rare circumstances where you want to single step into an interrupt vector the behavior can be controlled from GDB. There are three commands you can query and set the single step behavior: +@table @code +@item maintenance packet qqemu.sstepbits + +This will display the MASK bits used to control the single stepping IE: +@example +(gdb) maintenance packet qqemu.sstepbits +sending: "qqemu.sstepbits" +received: "ENABLE=1,NOIRQ=2,NOTIMER=4" +@end example +@item maintenance packet qqemu.sstep + +This will display the current value of the mask used when single stepping IE: +@example +(gdb) maintenance packet qqemu.sstep +sending: "qqemu.sstep" +received: "0x7" +@end example +@item maintenance packet Qqemu.sstep=HEX_VALUE + +This will change the single step mask, so if wanted to enable IRQs on the single step, but not timers, you would use: +@example +(gdb) maintenance packet Qqemu.sstep=0x5 +sending: "qemu.sstep=0x5" +received: "OK" +@end example +@end table + @node pcsys_os_specific @section Target OS specific information @@ -2025,14 +2339,37 @@ @node Sparc32 System emulator @section Sparc32 System emulator -Use the executable @file{qemu-system-sparc} to simulate a SPARCstation -5, SPARCstation 10, SPARCstation 20, SPARCserver 600MP (sun4m -architecture), SPARCstation 2 (sun4c architecture), SPARCserver 1000, -or SPARCcenter 2000 (sun4d architecture). The emulation is somewhat -complete. SMP up to 16 CPUs is supported, but Linux limits the number -of usable CPUs to 4. +Use the executable @file{qemu-system-sparc} to simulate the following +Sun4m architecture machines: +@itemize @minus +@item +SPARCstation 4 +@item +SPARCstation 5 +@item +SPARCstation 10 +@item +SPARCstation 20 +@item +SPARCserver 600MP +@item +SPARCstation LX +@item +SPARCstation Voyager +@item +SPARCclassic +@item +SPARCbook +@end itemize + +The emulation is somewhat complete. SMP up to 16 CPUs is supported, +but Linux limits the number of usable CPUs to 4. + +It's also possible to simulate a SPARCstation 2 (sun4c architecture), +SPARCserver 1000, or SPARCcenter 2000 (sun4d architecture), but these +emulators are not usable yet. -QEMU emulates the following sun4m/sun4d peripherals: +QEMU emulates the following sun4m/sun4c/sun4d peripherals: @itemize @minus @item @@ -2042,7 +2379,7 @@ @item Lance (Am7990) Ethernet @item -Non Volatile RAM M48T08 +Non Volatile RAM M48T02/M48T08 @item Slave I/O: timers, interrupt controllers, Zilog serial ports, keyboard and power/reset logic @@ -2064,8 +2401,10 @@ 1275-1994 (referred to as Open Firmware) compliant firmware. A sample Linux 2.6 series kernel and ram disk image are available on -the QEMU web site. Please note that currently NetBSD, OpenBSD or -Solaris kernels don't work. +the QEMU web site. There are still issues with NetBSD and OpenBSD, but +some kernel versions work. Please note that currently Solaris kernels +don't work probably due to interface issues between OpenBIOS and +Solaris. @c man begin OPTIONS @@ -2087,7 +2426,7 @@ -prom-env 'boot-device=sd(0,2,0):d' -prom-env 'boot-args=linux single' @end example -@item -M [SS-5|SS-10|SS-20|SS-600MP|SS-2|SS-1000|SS-2000] +@item -M [SS-4|SS-5|SS-10|SS-20|SS-600MP|LX|Voyager|SPARCClassic|SPARCbook|SS-2|SS-1000|SS-2000] Set the emulated machine type. Default is SS-5. @@ -2098,10 +2437,12 @@ @node Sparc64 System emulator @section Sparc64 System emulator -Use the executable @file{qemu-system-sparc64} to simulate a Sun4u machine. -The emulator is not usable for anything yet. +Use the executable @file{qemu-system-sparc64} to simulate a Sun4u +(UltraSPARC PC-like machine), Sun4v (T1 PC-like machine), or generic +Niagara (T1) machine. The emulator is not usable for anything yet, but +it can launch some kernels. -QEMU emulates the following sun4u peripherals: +QEMU emulates the following peripherals: @itemize @minus @item @@ -2109,18 +2450,46 @@ @item PCI VGA compatible card with VESA Bochs Extensions @item +PS/2 mouse and keyboard +@item Non Volatile RAM M48T59 @item PC-compatible serial ports +@item +2 PCI IDE interfaces with hard disk and CD-ROM support +@item +Floppy disk @end itemize +@c man begin OPTIONS + +The following options are specific to the Sparc64 emulation: + +@table @option + +@item -prom-env string + +Set OpenBIOS variables in NVRAM, for example: + +@example +qemu-system-sparc64 -prom-env 'auto-boot?=false' +@end example + +@item -M [sun4u|sun4v|Niagara] + +Set the emulated machine type. The default is sun4u. + +@end table + +@c man end + @node MIPS System emulator @section MIPS System emulator Four executables cover simulation of 32 and 64-bit MIPS systems in both endian options, @file{qemu-system-mips}, @file{qemu-system-mipsel} @file{qemu-system-mips64} and @file{qemu-system-mips64el}. -Four different machine types are emulated: +Five different machine types are emulated: @itemize @minus @item @@ -2131,6 +2500,8 @@ An ACER Pica "pica61". This machine needs the 64-bit emulator. @item MIPS emulator pseudo board "mipssim" +@item +A MIPS Magnum R4000 machine "magnum". This machine needs the 64-bit emulator. @end itemize The generic emulation is supported by Debian 'Etch' and is able to @@ -2191,6 +2562,22 @@ MIPSnet network emulation @end itemize +The MIPS Magnum R4000 emulation supports: + +@itemize @minus +@item +MIPS R4000 CPU +@item +PC-style IRQ controller +@item +PC Keyboard +@item +SCSI controller +@item +G364 framebuffer +@end itemize + + @node ARM System emulator @section ARM System emulator @@ -2320,6 +2707,41 @@ Three on-chip UARTs @end itemize +Nokia N800 and N810 internet tablets (known also as RX-34 and RX-44 / 48) +emulation supports the following elements: + +@itemize @minus +@item +Texas Instruments OMAP2420 System-on-chip (ARM 1136 core) +@item +RAM and non-volatile OneNAND Flash memories +@item +Display connected to EPSON remote framebuffer chip and OMAP on-chip +display controller and a LS041y3 MIPI DBI-C controller +@item +TI TSC2301 (in N800) and TI TSC2005 (in N810) touchscreen controllers +driven through SPI bus +@item +National Semiconductor LM8323-controlled qwerty keyboard driven +through I@math{^2}C bus +@item +Secure Digital card connected to OMAP MMC/SD host +@item +Three OMAP on-chip UARTs and on-chip STI debugging console +@item +A Bluetooth(R) transciever and HCI connected to an UART +@item +Mentor Graphics "Inventra" dual-role USB controller embedded in a TI +TUSB6010 chip - only USB host mode is supported +@item +TI TMP105 temperature sensor driven through I@math{^2}C bus +@item +TI TWL92230C power management companion with an RTC on I@math{^2}C bus +@item +Nokia RETU and TAHVO multi-purpose chips with an RTC, connected +through CBUS +@end itemize + The Luminary Micro Stellaris LM3S811EVB emulation includes the following devices: @@ -2348,6 +2770,26 @@ OSRAM Pictiva 128x64 OLED with SSD0323 controller connected via SSI. @end itemize +The Freecom MusicPal internet radio emulation includes the following +elements: + +@itemize @minus +@item +Marvell MV88W8618 ARM core. +@item +32 MB RAM, 256 KB SRAM, 8 MB flash. +@item +Up to 2 16550 UARTs +@item +MV88W8xx8 Ethernet controller +@item +MV88W8618 audio controller, WM8750 CODEC and mixer +@item +128×64 display with brightness control +@item +2 buttons, 2 navigation wheels with button function +@end itemize + A Linux 2.6 test image is available on the QEMU web site. More information is available in the QEMU mailing-list archive. @@ -2384,6 +2826,7 @@ * Supported Operating Systems :: * Linux User space emulator:: * Mac OS X/Darwin User space emulator :: +* BSD User space emulator :: @end menu @node Supported Operating Systems @@ -2396,6 +2839,8 @@ Linux (referred as qemu-linux-user) @item Mac OS X/Darwin (referred as qemu-darwin-user) +@item +BSD (referred as qemu-bsd-user) @end itemize @node Linux User space emulator @@ -2492,7 +2937,7 @@ @subsection Command line options @example -usage: qemu-i386 [-h] [-d] [-L path] [-s size] program [arguments...] +usage: qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g port] program [arguments...] @end example @table @option @@ -2502,6 +2947,8 @@ Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386) @item -s size Set the x86 stack size in bytes (default=524288) +@item -cpu model +Select CPU model (-cpu ? for list and additional feature selection) @end table Debug options: @@ -2511,6 +2958,8 @@ Activate log (logfile=/tmp/qemu.log) @item -p pagesize Act as if the host page size was 'pagesize' bytes +@item -g port +Wait gdb connection to port @end table Environment variables: @@ -2538,6 +2987,8 @@ The binary format is detected automatically. +@command{qemu-sparc} can execute Sparc32 binaries (Sparc32 CPU, 32 bit ABI). + @command{qemu-sparc32plus} can execute Sparc32 and SPARC32PLUS binaries (Sparc64 CPU, 32 bit ABI). @@ -2629,6 +3080,68 @@ Act as if the host page size was 'pagesize' bytes @end table +@node BSD User space emulator +@section BSD User space emulator + +@menu +* BSD Status:: +* BSD Quick Start:: +* BSD Command line options:: +@end menu + +@node BSD Status +@subsection BSD Status + +@itemize @minus +@item +target Sparc64 on Sparc64: Some trivial programs work. +@end itemize + +@node BSD Quick Start +@subsection Quick Start + +In order to launch a BSD process, QEMU needs the process executable +itself and all the target dynamic libraries used by it. + +@itemize + +@item On Sparc64, you can just try to launch any process by using the native +libraries: + +@example +qemu-sparc64 /bin/ls +@end example + +@end itemize + +@node BSD Command line options +@subsection Command line options + +@example +usage: qemu-sparc64 [-h] [-d] [-L path] [-s size] [-bsd type] program [arguments...] +@end example + +@table @option +@item -h +Print the help +@item -L path +Set the library root path (default=/) +@item -s size +Set the stack size in bytes (default=524288) +@item -bsd type +Set the type of the emulated BSD Operating system. Valid values are +FreeBSD, NetBSD and OpenBSD (default). +@end table + +Debug options: + +@table @option +@item -d +Activate log (logfile=/tmp/qemu.log) +@item -p pagesize +Act as if the host page size was 'pagesize' bytes +@end table + @node compilation @chapter Compilation from the sources diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/qemu-img.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/qemu-img.c --- qemu-0.9.1/qemu-img.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/qemu-img.c 2008-08-24 11:30:33.000000000 +0100 @@ -30,41 +30,6 @@ #include #endif -void *get_mmap_addr(unsigned long size) -{ - return NULL; -} - -void qemu_free(void *ptr) -{ - free(ptr); -} - -void *qemu_malloc(size_t size) -{ - return malloc(size); -} - -void *qemu_mallocz(size_t size) -{ - void *ptr; - ptr = qemu_malloc(size); - if (!ptr) - return NULL; - memset(ptr, 0, size); - return ptr; -} - -char *qemu_strdup(const char *str) -{ - char *ptr; - ptr = qemu_malloc(strlen(str) + 1); - if (!ptr) - return NULL; - strcpy(ptr, str); - return ptr; -} - static void __attribute__((noreturn)) error(const char *fmt, ...) { va_list ap; @@ -90,13 +55,17 @@ "Command syntax:\n" " create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n" " commit [-f fmt] filename\n" - " convert [-c] [-e] [-6] [-f fmt] filename [filename2 [...]] [-O output_fmt] output_filename\n" + " convert [-c] [-e] [-6] [-f fmt] [-O output_fmt] [-B output_base_image] filename [filename2 [...]] output_filename\n" " info [-f fmt] filename\n" "\n" "Command parameters:\n" " 'filename' is a disk image filename\n" " 'base_image' is the read-only disk image which is used as base for a copy on\n" " write image; the copy on write image only stores the modified data\n" + " 'output_base_image' forces the output image to be created as a copy on write\n" + " image of the specified base image; 'output_base_image' should have the same\n" + " content as the input's base image, however the path, image format, etc may\n" + " differ\n" " 'fmt' is the disk image format. It is guessed automatically in most cases\n" " 'size' is the disk image size in kilobytes. Optional suffixes 'M' (megabyte)\n" " and 'G' (gigabyte) are supported\n" @@ -385,6 +354,13 @@ return 0; } +/* + * Returns true iff the first sector pointed to by 'buf' contains at least + * a non-NUL byte. + * + * 'pnum' is set to the number of sectors (including and immediately following + * the first one) that are known to be in the same allocated/unallocated state. + */ static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum) { int v, i; @@ -408,7 +384,7 @@ static int img_convert(int argc, char **argv) { int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors; - const char *fmt, *out_fmt, *out_filename; + const char *fmt, *out_fmt, *out_baseimg, *out_filename; BlockDriver *drv; BlockDriverState **bs, *out_bs; int64_t total_sectors, nb_sectors, sector_num, bs_offset; @@ -419,9 +395,10 @@ fmt = NULL; out_fmt = "raw"; + out_baseimg = NULL; flags = 0; for(;;) { - c = getopt(argc, argv, "f:O:hce6"); + c = getopt(argc, argv, "f:O:B:hce6"); if (c == -1) break; switch(c) { @@ -434,6 +411,9 @@ case 'O': out_fmt = optarg; break; + case 'B': + out_baseimg = optarg; + break; case 'c': flags |= BLOCK_FLAG_COMPRESS; break; @@ -450,6 +430,9 @@ if (bs_n < 1) help(); out_filename = argv[argc - 1]; + + if (bs_n > 1 && out_baseimg) + error("-B makes no sense when concatenating multiple input images"); bs = calloc(bs_n, sizeof(BlockDriverState *)); if (!bs) @@ -476,7 +459,7 @@ if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS) error("Compression and encryption not supported at the same time"); - ret = bdrv_create(drv, out_filename, total_sectors, NULL, flags); + ret = bdrv_create(drv, out_filename, total_sectors, out_baseimg, flags); if (ret < 0) { if (ret == -ENOTSUP) { error("Formatting not supported for file format '%s'", fmt); @@ -555,7 +538,7 @@ /* signal EOF to align */ bdrv_write_compressed(out_bs, 0, NULL, 0); } else { - sector_num = 0; + sector_num = 0; // total number of sectors converted so far for(;;) { nb_sectors = total_sectors - sector_num; if (nb_sectors <= 0) @@ -578,6 +561,20 @@ if (n > bs_offset + bs_sectors - sector_num) n = bs_offset + bs_sectors - sector_num; + /* If the output image is being created as a copy on write image, + assume that sectors which are unallocated in the input image + are present in both the output's and input's base images (no + need to copy them). */ + if (out_baseimg) { + if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset, n, &n1)) { + sector_num += n1; + continue; + } + /* The next 'n1' sectors are allocated in the input image. Copy + only those as they may be followed by unallocated sectors. */ + n = n1; + } + if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0) error("error while reading"); /* NOTE: at the same time we convert, we do not write zero @@ -585,7 +582,10 @@ should add a specific call to have the info to go faster */ buf1 = buf; while (n > 0) { - if (is_allocated_sectors(buf1, n, &n1)) { + /* If the output image is being created as a copy on write image, + copy all sectors even the ones containing only NUL bytes, + because they may differ from the sectors in the base image. */ + if (out_baseimg || is_allocated_sectors(buf1, n, &n1)) { if (bdrv_write(out_bs, sector_num, buf1, n1) < 0) error("error while writing"); } @@ -699,7 +699,7 @@ get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512); allocated_size = get_allocated_file_size(filename); if (allocated_size < 0) - sprintf(dsize_buf, "unavailable"); + snprintf(dsize_buf, sizeof(dsize_buf), "unavailable"); else get_human_readable_size(dsize_buf, sizeof(dsize_buf), allocated_size); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/qemu-img.texi /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/qemu-img.texi --- qemu-0.9.1/qemu-img.texi 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/qemu-img.texi 2008-06-05 22:53:49.000000000 +0100 @@ -10,7 +10,7 @@ @table @option @item create [-e] [-6] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}] @item commit [-f @var{fmt}] @var{filename} -@item convert [-c] [-e] [-6] [-f @var{fmt}] @var{filename} [-O @var{output_fmt}] @var{output_filename} +@item convert [-c] [-e] [-6] [-f @var{fmt}] [-O @var{output_fmt}] [-B @var{output_base_image}] @var{filename} [@var{filename2} [...]] @var{output_filename} @item info [-f @var{fmt}] @var{filename} @end table @@ -21,7 +21,11 @@ @item base_image is the read-only disk image which is used as base for a copy on write image; the copy on write image only stores the modified data - +@item output_base_image +forces the output image to be created as a copy on write +image of the specified base image; @code{output_base_image} should have the same +content as the input's base image, however the path, image format, etc may +differ @item fmt is the disk image format. It is guessed automatically in most cases. The following formats are supported: diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/qemu-lock.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/qemu-lock.h --- qemu-0.9.1/qemu-lock.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/qemu-lock.h 2008-06-07 21:50:51.000000000 +0100 @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2003 Fabrice Bellard + * + * 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 + */ + +/* Locking primitives. Most of this code should be redundant - + system emulation doesn't need/use locking, NPTL userspace uses + pthread mutexes, and non-NPTL userspace isn't threadsafe anyway. + In either case a spinlock is probably the wrong kind of lock. + Spinlocks are only good if you know annother CPU has the lock and is + likely to release it soon. In environments where you have more threads + than physical CPUs (the extreme case being a single CPU host) a spinlock + simply wastes CPU until the OS decides to preempt it. */ +#if defined(USE_NPTL) + +#include +#define spin_lock pthread_mutex_lock +#define spin_unlock pthread_mutex_unlock +#define spinlock_t pthread_mutex_t +#define SPIN_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER + +#else + +#if defined(__hppa__) + +typedef int spinlock_t[4]; + +#define SPIN_LOCK_UNLOCKED { 1, 1, 1, 1 } + +static inline void resetlock (spinlock_t *p) +{ + (*p)[0] = (*p)[1] = (*p)[2] = (*p)[3] = 1; +} + +#else + +typedef int spinlock_t; + +#define SPIN_LOCK_UNLOCKED 0 + +static inline void resetlock (spinlock_t *p) +{ + *p = SPIN_LOCK_UNLOCKED; +} + +#endif + +#if defined(__powerpc__) +static inline int testandset (int *p) +{ + int ret; + __asm__ __volatile__ ( + "0: lwarx %0,0,%1\n" + " xor. %0,%3,%0\n" + " bne 1f\n" + " stwcx. %2,0,%1\n" + " bne- 0b\n" + "1: " + : "=&r" (ret) + : "r" (p), "r" (1), "r" (0) + : "cr0", "memory"); + return ret; +} +#elif defined(__i386__) +static inline int testandset (int *p) +{ + long int readval = 0; + + __asm__ __volatile__ ("lock; cmpxchgl %2, %0" + : "+m" (*p), "+a" (readval) + : "r" (1) + : "cc"); + return readval; +} +#elif defined(__x86_64__) +static inline int testandset (int *p) +{ + long int readval = 0; + + __asm__ __volatile__ ("lock; cmpxchgl %2, %0" + : "+m" (*p), "+a" (readval) + : "r" (1) + : "cc"); + return readval; +} +#elif defined(__s390__) +static inline int testandset (int *p) +{ + int ret; + + __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n" + " jl 0b" + : "=&d" (ret) + : "r" (1), "a" (p), "0" (*p) + : "cc", "memory" ); + return ret; +} +#elif defined(__alpha__) +static inline int testandset (int *p) +{ + int ret; + unsigned long one; + + __asm__ __volatile__ ("0: mov 1,%2\n" + " ldl_l %0,%1\n" + " stl_c %2,%1\n" + " beq %2,1f\n" + ".subsection 2\n" + "1: br 0b\n" + ".previous" + : "=r" (ret), "=m" (*p), "=r" (one) + : "m" (*p)); + return ret; +} +#elif defined(__sparc__) +static inline int testandset (int *p) +{ + int ret; + + __asm__ __volatile__("ldstub [%1], %0" + : "=r" (ret) + : "r" (p) + : "memory"); + + return (ret ? 1 : 0); +} +#elif defined(__arm__) +static inline int testandset (int *spinlock) +{ + register unsigned int ret; + __asm__ __volatile__("swp %0, %1, [%2]" + : "=r"(ret) + : "0"(1), "r"(spinlock)); + + return ret; +} +#elif defined(__mc68000) +static inline int testandset (int *p) +{ + char ret; + __asm__ __volatile__("tas %1; sne %0" + : "=r" (ret) + : "m" (p) + : "cc","memory"); + return ret; +} +#elif defined(__hppa__) + +/* Because malloc only guarantees 8-byte alignment for malloc'd data, + and GCC only guarantees 8-byte alignment for stack locals, we can't + be assured of 16-byte alignment for atomic lock data even if we + specify "__attribute ((aligned(16)))" in the type declaration. So, + we use a struct containing an array of four ints for the atomic lock + type and dynamically select the 16-byte aligned int from the array + for the semaphore. */ +#define __PA_LDCW_ALIGNMENT 16 +static inline void *ldcw_align (void *p) { + unsigned long a = (unsigned long)p; + a = (a + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1); + return (void *)a; +} + +static inline int testandset (spinlock_t *p) +{ + unsigned int ret; + p = ldcw_align(p); + __asm__ __volatile__("ldcw 0(%1),%0" + : "=r" (ret) + : "r" (p) + : "memory" ); + return !ret; +} + +#elif defined(__ia64) + +#include + +static inline int testandset (int *p) +{ + return __sync_lock_test_and_set (p, 1); +} +#elif defined(__mips__) +static inline int testandset (int *p) +{ + int ret; + + __asm__ __volatile__ ( + " .set push \n" + " .set noat \n" + " .set mips2 \n" + "1: li $1, 1 \n" + " ll %0, %1 \n" + " sc $1, %1 \n" + " beqz $1, 1b \n" + " .set pop " + : "=r" (ret), "+R" (*p) + : + : "memory"); + + return ret; +} +#else +#error unimplemented CPU support +#endif + +#if defined(CONFIG_USER_ONLY) +static inline void spin_lock(spinlock_t *lock) +{ + while (testandset(lock)); +} + +static inline void spin_unlock(spinlock_t *lock) +{ + resetlock(lock); +} + +static inline int spin_trylock(spinlock_t *lock) +{ + return !testandset(lock); +} +#else +static inline void spin_lock(spinlock_t *lock) +{ +} + +static inline void spin_unlock(spinlock_t *lock) +{ +} + +static inline int spin_trylock(spinlock_t *lock) +{ + return 1; +} +#endif + +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/qemu-log.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/qemu-log.h --- qemu-0.9.1/qemu-log.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/qemu-log.h 2008-08-30 10:51:20.000000000 +0100 @@ -0,0 +1,7 @@ +#ifndef QEMU_LOG_H +#define QEMU_LOG_H + +extern FILE *logfile; +extern int loglevel; + +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/qemu-malloc.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/qemu-malloc.c --- qemu-0.9.1/qemu-malloc.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/qemu-malloc.c 2008-11-09 00:28:40.000000000 +0000 @@ -0,0 +1,79 @@ +/* + * malloc-like functions for system emulation. + * + * Copyright (c) 2006 Fabrice Bellard + * + * 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 "qemu-common.h" + +void *get_mmap_addr(unsigned long size) +{ + return NULL; +} + +void qemu_free(void *ptr) +{ + free(ptr); +} + +void *qemu_malloc(size_t size) +{ + return malloc(size); +} + +void *qemu_realloc(void *ptr, size_t size) +{ + return realloc(ptr, size); +} + +void *qemu_mallocz(size_t size) +{ + void *ptr; + ptr = qemu_malloc(size); + if (!ptr) + return NULL; + memset(ptr, 0, size); + return ptr; +} + +char *qemu_strdup(const char *str) +{ + char *ptr; + size_t len = strlen(str); + ptr = qemu_malloc(len + 1); + if (!ptr) + return NULL; + memcpy(ptr, str, len + 1); + return ptr; +} + +char *qemu_strndup(const char *str, size_t size) +{ + const char *end = memchr(str, 0, size); + char *new; + + if (end) + size = end - str; + + new = qemu_malloc(size + 1); + new[size] = 0; + + return memcpy(new, str, size); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/qemu-nbd.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/qemu-nbd.c --- qemu-0.9.1/qemu-nbd.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/qemu-nbd.c 2008-10-26 13:43:07.000000000 +0000 @@ -0,0 +1,478 @@ +/* + * Copyright (C) 2005 Anthony Liguori + * + * Network Block Device + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "block_int.h" +#include "nbd.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SOCKET_PATH "/var/lock/qemu-nbd-%s" + +#define NBD_BUFFER_SIZE (1024*1024) + +static int verbose; + +static void usage(const char *name) +{ + printf( +"Usage: %s [OPTIONS] FILE\n" +"QEMU Disk Network Block Device Server\n" +"\n" +" -p, --port=PORT port to listen on (default `1024')\n" +" -o, --offset=OFFSET offset into the image\n" +" -b, --bind=IFACE interface to bind to (default `0.0.0.0')\n" +" -k, --socket=PATH path to the unix socket\n" +" (default '"SOCKET_PATH"')\n" +" -r, --read-only export read-only\n" +" -P, --partition=NUM only expose partition NUM\n" +" -s, --snapshot use snapshot file\n" +" -n, --nocache disable host cache\n" +" -c, --connect=DEV connect FILE to the local NBD device DEV\n" +" -d, --disconnect disconnect the specified device\n" +" -e, --shared=NUM device can be shared by NUM clients (default '1')\n" +" -t, --persistent don't exit on the last connection\n" +" -v, --verbose display extra debugging information\n" +" -h, --help display this help and exit\n" +" -V, --version output version information and exit\n" +"\n" +"Report bugs to \n" + , name, "DEVICE"); +} + +static void version(const char *name) +{ + printf( +"%s version 0.0.1\n" +"Written by Anthony Liguori.\n" +"\n" +"Copyright (C) 2006 Anthony Liguori .\n" +"This is free software; see the source for copying conditions. There is NO\n" +"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" + , name); +} + +struct partition_record +{ + uint8_t bootable; + uint8_t start_head; + uint32_t start_cylinder; + uint8_t start_sector; + uint8_t system; + uint8_t end_head; + uint8_t end_cylinder; + uint8_t end_sector; + uint32_t start_sector_abs; + uint32_t nb_sectors_abs; +}; + +static void read_partition(uint8_t *p, struct partition_record *r) +{ + r->bootable = p[0]; + r->start_head = p[1]; + r->start_cylinder = p[3] | ((p[2] << 2) & 0x0300); + r->start_sector = p[2] & 0x3f; + r->system = p[4]; + r->end_head = p[5]; + r->end_cylinder = p[7] | ((p[6] << 2) & 0x300); + r->end_sector = p[6] & 0x3f; + r->start_sector_abs = p[8] | p[9] << 8 | p[10] << 16 | p[11] << 24; + r->nb_sectors_abs = p[12] | p[13] << 8 | p[14] << 16 | p[15] << 24; +} + +static int find_partition(BlockDriverState *bs, int partition, + off_t *offset, off_t *size) +{ + struct partition_record mbr[4]; + uint8_t data[512]; + int i; + int ext_partnum = 4; + + if (bdrv_read(bs, 0, data, 1)) + errx(EINVAL, "error while reading"); + + if (data[510] != 0x55 || data[511] != 0xaa) { + errno = -EINVAL; + return -1; + } + + for (i = 0; i < 4; i++) { + read_partition(&data[446 + 16 * i], &mbr[i]); + + if (!mbr[i].nb_sectors_abs) + continue; + + if (mbr[i].system == 0xF || mbr[i].system == 0x5) { + struct partition_record ext[4]; + uint8_t data1[512]; + int j; + + if (bdrv_read(bs, mbr[i].start_sector_abs, data1, 1)) + errx(EINVAL, "error while reading"); + + for (j = 0; j < 4; j++) { + read_partition(&data1[446 + 16 * j], &ext[j]); + if (!ext[j].nb_sectors_abs) + continue; + + if ((ext_partnum + j + 1) == partition) { + *offset = (uint64_t)ext[j].start_sector_abs << 9; + *size = (uint64_t)ext[j].nb_sectors_abs << 9; + return 0; + } + } + ext_partnum += 4; + } else if ((i + 1) == partition) { + *offset = (uint64_t)mbr[i].start_sector_abs << 9; + *size = (uint64_t)mbr[i].nb_sectors_abs << 9; + return 0; + } + } + + errno = -ENOENT; + return -1; +} + +static void show_parts(const char *device) +{ + if (fork() == 0) { + int nbd; + + /* linux just needs an open() to trigger + * the partition table update + * but remember to load the module with max_part != 0 : + * modprobe nbd max_part=63 + */ + nbd = open(device, O_RDWR); + if (nbd != -1) + close(nbd); + exit(0); + } +} + +int main(int argc, char **argv) +{ + BlockDriverState *bs; + off_t dev_offset = 0; + off_t offset = 0; + bool readonly = false; + bool disconnect = false; + const char *bindto = "0.0.0.0"; + int port = 1024; + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + off_t fd_size; + char *device = NULL; + char *socket = NULL; + char sockpath[128]; + const char *sopt = "hVbo:p:rsnP:c:dvk:e:t"; + struct option lopt[] = { + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'V' }, + { "bind", 1, 0, 'b' }, + { "port", 1, 0, 'p' }, + { "socket", 1, 0, 'k' }, + { "offset", 1, 0, 'o' }, + { "read-only", 0, 0, 'r' }, + { "partition", 1, 0, 'P' }, + { "connect", 1, 0, 'c' }, + { "disconnect", 0, 0, 'd' }, + { "snapshot", 0, 0, 's' }, + { "nocache", 0, 0, 'n' }, + { "shared", 1, 0, 'e' }, + { "persistent", 0, 0, 't' }, + { "verbose", 0, 0, 'v' }, + { NULL, 0, 0, 0 } + }; + int ch; + int opt_ind = 0; + int li; + char *end; + int flags = 0; + int partition = -1; + int ret; + int shared = 1; + uint8_t *data; + fd_set fds; + int *sharing_fds; + int fd; + int i; + int nb_fds = 0; + int max_fd; + int persistent = 0; + + while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { + switch (ch) { + case 's': + flags |= BDRV_O_SNAPSHOT; + break; + case 'n': + flags |= BDRV_O_NOCACHE; + break; + case 'b': + bindto = optarg; + break; + case 'p': + li = strtol(optarg, &end, 0); + if (*end) { + errx(EINVAL, "Invalid port `%s'", optarg); + } + if (li < 1 || li > 65535) { + errx(EINVAL, "Port out of range `%s'", optarg); + } + port = (uint16_t)li; + break; + case 'o': + dev_offset = strtoll (optarg, &end, 0); + if (*end) { + errx(EINVAL, "Invalid offset `%s'", optarg); + } + if (dev_offset < 0) { + errx(EINVAL, "Offset must be positive `%s'", optarg); + } + break; + case 'r': + readonly = true; + break; + case 'P': + partition = strtol(optarg, &end, 0); + if (*end) + errx(EINVAL, "Invalid partition `%s'", optarg); + if (partition < 1 || partition > 8) + errx(EINVAL, "Invalid partition %d", partition); + break; + case 'k': + socket = optarg; + if (socket[0] != '/') + errx(EINVAL, "socket path must be absolute\n"); + break; + case 'd': + disconnect = true; + break; + case 'c': + device = optarg; + break; + case 'e': + shared = strtol(optarg, &end, 0); + if (*end) { + errx(EINVAL, "Invalid shared device number '%s'", optarg); + } + if (shared < 1) { + errx(EINVAL, "Shared device number must be greater than 0\n"); + } + break; + case 't': + persistent = 1; + break; + case 'v': + verbose = 1; + break; + case 'V': + version(argv[0]); + exit(0); + break; + case 'h': + usage(argv[0]); + exit(0); + break; + case '?': + errx(EINVAL, "Try `%s --help' for more information.", + argv[0]); + } + } + + if ((argc - optind) != 1) { + errx(EINVAL, "Invalid number of argument.\n" + "Try `%s --help' for more information.", + argv[0]); + } + + if (disconnect) { + fd = open(argv[optind], O_RDWR); + if (fd == -1) + errx(errno, "Cannot open %s", argv[optind]); + + nbd_disconnect(fd); + + close(fd); + + printf("%s disconnected\n", argv[optind]); + + return 0; + } + + bdrv_init(); + + bs = bdrv_new("hda"); + if (bs == NULL) + return 1; + + if (bdrv_open(bs, argv[optind], flags) == -1) + return 1; + + fd_size = bs->total_sectors * 512; + + if (partition != -1 && + find_partition(bs, partition, &dev_offset, &fd_size)) + errx(errno, "Could not find partition %d", partition); + + if (device) { + pid_t pid; + int sock; + + if (!verbose) + daemon(0, 0); /* detach client and server */ + + if (socket == NULL) { + sprintf(sockpath, SOCKET_PATH, basename(device)); + socket = sockpath; + } + + pid = fork(); + if (pid < 0) + return 1; + if (pid != 0) { + off_t size; + size_t blocksize; + + ret = 0; + bdrv_close(bs); + + do { + sock = unix_socket_outgoing(socket); + if (sock == -1) { + if (errno != ENOENT && errno != ECONNREFUSED) + goto out; + sleep(1); /* wait children */ + } + } while (sock == -1); + + fd = open(device, O_RDWR); + if (fd == -1) { + ret = 1; + goto out; + } + + ret = nbd_receive_negotiate(sock, &size, &blocksize); + if (ret == -1) { + ret = 1; + goto out; + } + + ret = nbd_init(fd, sock, size, blocksize); + if (ret == -1) { + ret = 1; + goto out; + } + + printf("NBD device %s is now connected to file %s\n", + device, argv[optind]); + + /* update partition table */ + + show_parts(device); + + nbd_client(fd, sock); + close(fd); + out: + kill(pid, SIGTERM); + unlink(socket); + + return ret; + } + /* children */ + } + + sharing_fds = qemu_malloc((shared + 1) * sizeof(int)); + if (sharing_fds == NULL) + errx(ENOMEM, "Cannot allocate sharing fds"); + + if (socket) { + sharing_fds[0] = unix_socket_incoming(socket); + } else { + sharing_fds[0] = tcp_socket_incoming(bindto, port); + } + + if (sharing_fds[0] == -1) + return 1; + max_fd = sharing_fds[0]; + nb_fds++; + + data = qemu_memalign(512, NBD_BUFFER_SIZE); + if (data == NULL) + errx(ENOMEM, "Cannot allocate data buffer"); + + do { + + FD_ZERO(&fds); + for (i = 0; i < nb_fds; i++) + FD_SET(sharing_fds[i], &fds); + + ret = select(max_fd + 1, &fds, NULL, NULL, NULL); + if (ret == -1) + break; + + if (FD_ISSET(sharing_fds[0], &fds)) + ret--; + for (i = 1; i < nb_fds && ret; i++) { + if (FD_ISSET(sharing_fds[i], &fds)) { + if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset, + &offset, readonly, data, NBD_BUFFER_SIZE) != 0) { + close(sharing_fds[i]); + nb_fds--; + sharing_fds[i] = sharing_fds[nb_fds]; + i--; + } + ret--; + } + } + /* new connection ? */ + if (FD_ISSET(sharing_fds[0], &fds)) { + if (nb_fds < shared + 1) { + sharing_fds[nb_fds] = accept(sharing_fds[0], + (struct sockaddr *)&addr, + &addr_len); + if (sharing_fds[nb_fds] != -1 && + nbd_negotiate(sharing_fds[nb_fds], fd_size) != -1) { + if (sharing_fds[nb_fds] > max_fd) + max_fd = sharing_fds[nb_fds]; + nb_fds++; + } + } + } + } while (persistent || nb_fds > 1); + qemu_free(data); + + close(sharing_fds[0]); + bdrv_close(bs); + qemu_free(sharing_fds); + if (socket) + unlink(socket); + + return 0; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/qemu-nbd.texi /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/qemu-nbd.texi --- qemu-0.9.1/qemu-nbd.texi 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/qemu-nbd.texi 2008-09-22 21:41:57.000000000 +0100 @@ -0,0 +1,66 @@ +@example +@c man begin SYNOPSIS +usage: qemu-nbd [OPTION]... @var{filename} +@c man end +@end example + +@c man begin DESCRIPTION + +Export Qemu disk image using NBD protocol. + +@c man end + +@c man begin OPTIONS +@table @option +@item @var{filename} + is a disk image filename +@item -p, --port=@var{port} + port to listen on (default @samp{1024}) +@item -o, --offset=@var{offset} + offset into the image +@item -b, --bind=@var{iface} + interface to bind to (default @samp{0.0.0.0}) +@item -k, --socket=@var{path} + Use a unix socket with path @var{path} +@item -r, --read-only + export read-only +@item -P, --partition=@var{num} + only expose partition @var{num} +@item -s, --snapshot + use snapshot file +@item -n, --nocache + disable host cache +@item -c, --connect + connect FILE to NBD device DEV +@item -d, --disconnect + disconnect the specified device +@item -e, --shared=@var{num} + device can be shared by @var{num} clients (default @samp{1}) +@item -t, --persistent + don't exit on the last connection +@item -v, --verbose + display extra debugging information +@item -h, --help + display this help and exit +@item -V, --version + output version information and exit +@end table + +@c man end + +@ignore + +@setfilename qemu-nbd +@settitle QEMU Disk Network Block Device Server + +@c man begin AUTHOR +Copyright (C) 2006 Anthony Liguori . +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +@c man end + +@c man begin SEEALSO +qemu-img(1) +@c man end + +@end ignore diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/qemu_socket.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/qemu_socket.h --- qemu-0.9.1/qemu_socket.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/qemu_socket.h 2008-11-11 20:46:40.000000000 +0000 @@ -4,6 +4,7 @@ #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN +#define WINVER 0x0501 /* needed for ipv6 bits */ #include #include #include @@ -14,11 +15,15 @@ #define EINTR WSAEINTR #define EINPROGRESS WSAEINPROGRESS +int inet_aton(const char *cp, struct in_addr *ia); + #else #include #include #include +#include +#include #include #define socket_error() errno @@ -26,6 +31,22 @@ #endif /* !_WIN32 */ +/* misc helpers */ void socket_set_nonblock(int fd); +int send_all(int fd, const void *buf, int len1); + +/* New, ipv6-ready socket helper functions, see qemu-sockets.c */ +int inet_listen(const char *str, char *ostr, int olen, + int socktype, int port_offset); +int inet_connect(const char *str, int socktype); + +int unix_listen(const char *path, char *ostr, int olen); +int unix_connect(const char *path); + +/* Old, ipv4 only bits. Don't use for new code. */ +int parse_host_port(struct sockaddr_in *saddr, const char *str); +int parse_host_src_port(struct sockaddr_in *haddr, + struct sockaddr_in *saddr, + const char *str); #endif /* QEMU_SOCKET_H */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/qemu-sockets.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/qemu-sockets.c --- qemu-0.9.1/qemu-sockets.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/qemu-sockets.c 2008-11-11 20:46:40.000000000 +0000 @@ -0,0 +1,400 @@ +#include +#include +#include +#include +#include +#include + +#include "qemu_socket.h" + +#ifndef AI_ADDRCONFIG +# define AI_ADDRCONFIG 0 +#endif + +static int sockets_debug = 0; +static const int on=1, off=0; + +static int inet_getport(struct addrinfo *e) +{ + struct sockaddr_in *i4; + struct sockaddr_in6 *i6; + + switch (e->ai_family) { + case PF_INET6: + i6 = (void*)e->ai_addr; + return ntohs(i6->sin6_port); + case PF_INET: + i4 = (void*)e->ai_addr; + return ntohs(i4->sin_port); + default: + return 0; + } +} + +static void inet_setport(struct addrinfo *e, int port) +{ + struct sockaddr_in *i4; + struct sockaddr_in6 *i6; + + switch (e->ai_family) { + case PF_INET6: + i6 = (void*)e->ai_addr; + i6->sin6_port = htons(port); + break; + case PF_INET: + i4 = (void*)e->ai_addr; + i4->sin_port = htons(port); + break; + } +} + +static const char *inet_strfamily(int family) +{ + switch (family) { + case PF_INET6: return "ipv6"; + case PF_INET: return "ipv4"; + case PF_UNIX: return "unix"; + } + return "????"; +} + +static void inet_print_addrinfo(const char *tag, struct addrinfo *res) +{ + struct addrinfo *e; + char uaddr[INET6_ADDRSTRLEN+1]; + char uport[33]; + + for (e = res; e != NULL; e = e->ai_next) { + getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, + uaddr,INET6_ADDRSTRLEN,uport,32, + NI_NUMERICHOST | NI_NUMERICSERV); + fprintf(stderr,"%s: getaddrinfo: family %s, host %s, port %s\n", + tag, inet_strfamily(e->ai_family), uaddr, uport); + } +} + +int inet_listen(const char *str, char *ostr, int olen, + int socktype, int port_offset) +{ + struct addrinfo ai,*res,*e; + char addr[64]; + char port[33]; + char uaddr[INET6_ADDRSTRLEN+1]; + char uport[33]; + const char *opts, *h; + int slisten,rc,pos,to,try_next; + + memset(&ai,0, sizeof(ai)); + ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + ai.ai_family = PF_UNSPEC; + ai.ai_socktype = socktype; + + /* parse address */ + if (str[0] == ':') { + /* no host given */ + strcpy(addr,""); + if (1 != sscanf(str,":%32[^,]%n",port,&pos)) { + fprintf(stderr, "%s: portonly parse error (%s)\n", + __FUNCTION__, str); + return -1; + } + } else if (str[0] == '[') { + /* IPv6 addr */ + if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) { + fprintf(stderr, "%s: ipv6 parse error (%s)\n", + __FUNCTION__, str); + return -1; + } + ai.ai_family = PF_INET6; + } else if (isdigit(str[0])) { + /* IPv4 addr */ + if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) { + fprintf(stderr, "%s: ipv4 parse error (%s)\n", + __FUNCTION__, str); + return -1; + } + ai.ai_family = PF_INET; + } else { + /* hostname */ + if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) { + fprintf(stderr, "%s: hostname parse error (%s)\n", + __FUNCTION__, str); + return -1; + } + } + + /* parse options */ + opts = str + pos; + h = strstr(opts, ",to="); + to = h ? atoi(h+4) : 0; + if (strstr(opts, ",ipv4")) + ai.ai_family = PF_INET; + if (strstr(opts, ",ipv6")) + ai.ai_family = PF_INET6; + + /* lookup */ + if (port_offset) + snprintf(port, sizeof(port), "%d", atoi(port) + port_offset); + rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res); + if (rc != 0) { + fprintf(stderr,"%s: getaddrinfo(%s,%s): %s\n", __FUNCTION__, + addr, port, gai_strerror(rc)); + return -1; + } + if (sockets_debug) + inet_print_addrinfo(__FUNCTION__, res); + + /* create socket + bind */ + for (e = res; e != NULL; e = e->ai_next) { + getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, + uaddr,INET6_ADDRSTRLEN,uport,32, + NI_NUMERICHOST | NI_NUMERICSERV); + slisten = socket(e->ai_family, e->ai_socktype, e->ai_protocol); + if (slisten < 0) { + fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, + inet_strfamily(e->ai_family), strerror(errno)); + continue; + } + + setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); +#ifdef IPV6_V6ONLY + if (e->ai_family == PF_INET6) { + /* listen on both ipv4 and ipv6 */ + setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off,sizeof(off)); + } +#endif + + for (;;) { + if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) { + if (sockets_debug) + fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, + inet_strfamily(e->ai_family), uaddr, inet_getport(e)); + goto listen; + } + try_next = to && (inet_getport(e) <= to + port_offset); + if (!try_next || sockets_debug) + fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__, + inet_strfamily(e->ai_family), uaddr, inet_getport(e), + strerror(errno)); + if (try_next) { + inet_setport(e, inet_getport(e) + 1); + continue; + } + break; + } + closesocket(slisten); + } + fprintf(stderr, "%s: FAILED\n", __FUNCTION__); + freeaddrinfo(res); + return -1; + +listen: + if (listen(slisten,1) != 0) { + perror("listen"); + closesocket(slisten); + return -1; + } + if (ostr) { + if (e->ai_family == PF_INET6) { + snprintf(ostr, olen, "[%s]:%d%s", uaddr, + inet_getport(e) - port_offset, opts); + } else { + snprintf(ostr, olen, "%s:%d%s", uaddr, + inet_getport(e) - port_offset, opts); + } + } + freeaddrinfo(res); + return slisten; +} + +int inet_connect(const char *str, int socktype) +{ + struct addrinfo ai,*res,*e; + char addr[64]; + char port[33]; + char uaddr[INET6_ADDRSTRLEN+1]; + char uport[33]; + int sock,rc; + + memset(&ai,0, sizeof(ai)); + ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; + ai.ai_family = PF_UNSPEC; + ai.ai_socktype = socktype; + + /* parse address */ + if (str[0] == '[') { + /* IPv6 addr */ + if (2 != sscanf(str,"[%64[^]]]:%32[^,]",addr,port)) { + fprintf(stderr, "%s: ipv6 parse error (%s)\n", + __FUNCTION__, str); + return -1; + } + ai.ai_family = PF_INET6; + } else if (isdigit(str[0])) { + /* IPv4 addr */ + if (2 != sscanf(str,"%64[0-9.]:%32[^,]",addr,port)) { + fprintf(stderr, "%s: ipv4 parse error (%s)\n", + __FUNCTION__, str); + return -1; + } + ai.ai_family = PF_INET; + } else { + /* hostname */ + if (2 != sscanf(str,"%64[^:]:%32[^,]",addr,port)) { + fprintf(stderr, "%s: hostname parse error (%s)\n", + __FUNCTION__, str); + return -1; + } + } + + /* parse options */ + if (strstr(str, ",ipv4")) + ai.ai_family = PF_INET; + if (strstr(str, ",ipv6")) + ai.ai_family = PF_INET6; + + /* lookup */ + if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) { + fprintf(stderr,"getaddrinfo(%s,%s): %s\n", gai_strerror(rc), + addr, port); + return -1; + } + if (sockets_debug) + inet_print_addrinfo(__FUNCTION__, res); + + for (e = res; e != NULL; e = e->ai_next) { + if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, + uaddr,INET6_ADDRSTRLEN,uport,32, + NI_NUMERICHOST | NI_NUMERICSERV) != 0) { + fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__); + continue; + } + sock = socket(e->ai_family, e->ai_socktype, e->ai_protocol); + if (sock < 0) { + fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, + inet_strfamily(e->ai_family), strerror(errno)); + continue; + } + setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); + + /* connect to peer */ + if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) { + if (sockets_debug || NULL == e->ai_next) + fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, + inet_strfamily(e->ai_family), + e->ai_canonname, uaddr, uport, strerror(errno)); + closesocket(sock); + continue; + } + if (sockets_debug) + fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__, + inet_strfamily(e->ai_family), + e->ai_canonname, uaddr, uport); + freeaddrinfo(res); + return sock; + } + freeaddrinfo(res); + return -1; +} + +#ifndef _WIN32 + +int unix_listen(const char *str, char *ostr, int olen) +{ + struct sockaddr_un un; + char *path, *opts; + int sock, fd, len; + + sock = socket(PF_UNIX, SOCK_STREAM, 0); + if (sock < 0) { + perror("socket(unix)"); + return -1; + } + + opts = strchr(str, ','); + if (opts) { + len = opts - str; + path = malloc(len+1); + snprintf(path, len+1, "%.*s", len, str); + } else + path = strdup(str); + + memset(&un, 0, sizeof(un)); + un.sun_family = AF_UNIX; + if (path && strlen(path)) { + snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); + } else { + char *tmpdir = getenv("TMPDIR"); + snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX", + tmpdir ? tmpdir : "/tmp"); + /* + * This dummy fd usage silences the mktemp() unsecure warning. + * Using mkstemp() doesn't make things more secure here + * though. bind() complains about existing files, so we have + * to unlink first and thus re-open the race window. The + * worst case possible is bind() failing, i.e. a DoS attack. + */ + fd = mkstemp(un.sun_path); close(fd); + } + snprintf(ostr, olen, "%s%s", un.sun_path, opts ? opts : ""); + + unlink(un.sun_path); + if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { + fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno)); + goto err; + } + if (listen(sock, 1) < 0) { + fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno)); + goto err; + } + + if (sockets_debug) + fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path); + free(path); + return sock; + +err: + free(path); + closesocket(sock); + return -1; +} + +int unix_connect(const char *path) +{ + struct sockaddr_un un; + int sock; + + sock = socket(PF_UNIX, SOCK_STREAM, 0); + if (sock < 0) { + perror("socket(unix)"); + return -1; + } + + memset(&un, 0, sizeof(un)); + un.sun_family = AF_UNIX; + snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); + if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { + fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno)); + return -1; + } + + if (sockets_debug) + fprintf(stderr, "connect(unix:%s): OK\n", path); + return sock; +} + +#else + +int unix_listen(const char *path, char *ostr, int olen) +{ + fprintf(stderr, "unix sockets are not available on windows\n"); + return -1; +} + +int unix_connect(const char *path) +{ + fprintf(stderr, "unix sockets are not available on windows\n"); + return -1; +} + +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/qemu-tech.texi /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/qemu-tech.texi --- qemu-0.9.1/qemu-tech.texi 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/qemu-tech.texi 2008-10-09 19:52:04.000000000 +0100 @@ -33,11 +33,12 @@ @menu * intro_features:: Features -* intro_x86_emulation:: x86 emulation +* intro_x86_emulation:: x86 and x86-64 emulation * intro_arm_emulation:: ARM emulation * intro_mips_emulation:: MIPS emulation * intro_ppc_emulation:: PowerPC emulation -* intro_sparc_emulation:: SPARC emulation +* intro_sparc_emulation:: Sparc32 and Sparc64 emulation +* intro_other_emulation:: Other CPU emulation @end menu @node intro_features @@ -51,17 +52,17 @@ @itemize @minus @item -Full system emulation. In this mode, QEMU emulates a full system -(usually a PC), including a processor and various peripherals. It can -be used to launch an different Operating System without rebooting the -PC or to debug system code. +Full system emulation. In this mode (full platform virtualization), +QEMU emulates a full system (usually a PC), including a processor and +various peripherals. It can be used to launch several different +Operating Systems at once without rebooting the host machine or to +debug system code. @item -User mode emulation (Linux host only). In this mode, QEMU can launch -Linux processes compiled for one CPU on another CPU. It can be used to -launch the Wine Windows API emulator (@url{http://www.winehq.org}) or -to ease cross-compilation and cross-debugging. - +User mode emulation. In this mode (application level virtualization), +QEMU can launch processes compiled for one CPU on another CPU, however +the Operating Systems must match. This can be used for example to ease +cross-compilation and cross-debugging. @end itemize As QEMU requires no host kernel driver to run, it is very safe and @@ -75,7 +76,10 @@ @item Using dynamic translation to native code for reasonable speed. -@item Working on x86 and PowerPC hosts. Being tested on ARM, Sparc32, Alpha and S390. +@item +Working on x86, x86_64 and PowerPC32/64 hosts. Being tested on ARM, +HPPA, Sparc32 and Sparc64. Previous versions had some support for +Alpha and S390 hosts, but TCG (see below) doesn't support those yet. @item Self-modifying code support. @@ -85,6 +89,10 @@ in other projects (look at @file{qemu/tests/qruncom.c} to have an example of user mode @code{libqemu} usage). +@item +Floating point library supporting both full software emulation and +native host FPU instructions. + @end itemize QEMU user mode emulation features: @@ -96,20 +104,47 @@ @item Accurate signal handling by remapping host signals to target signals. @end itemize +Linux user emulator (Linux host only) can be used to launch the Wine +Windows API emulator (@url{http://www.winehq.org}). A Darwin user +emulator (Darwin hosts only) exists and a BSD user emulator for BSD +hosts is under development. It would also be possible to develop a +similar user emulator for Solaris. + QEMU full system emulation features: @itemize -@item QEMU can either use a full software MMU for maximum portability or use the host system call mmap() to simulate the target MMU. +@item +QEMU uses a full software MMU for maximum portability. + +@item +QEMU can optionally use an in-kernel accelerator, like kqemu and +kvm. The accelerators execute some of the guest code natively, while +continuing to emulate the rest of the machine. + +@item +Various hardware devices can be emulated and in some cases, host +devices (e.g. serial and parallel ports, USB, drives) can be used +transparently by the guest Operating System. Host device passthrough +can be used for talking to external physical peripherals (e.g. a +webcam, modem or tape drive). + +@item +Symmetric multiprocessing (SMP) even on a host with a single CPU. On a +SMP host system, QEMU can use only one CPU fully due to difficulty in +implementing atomic memory accesses efficiently. + @end itemize @node intro_x86_emulation -@section x86 emulation +@section x86 and x86-64 emulation QEMU x86 target features: @itemize @item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation. -LDT/GDT and IDT are emulated. VM86 mode is also supported to run DOSEMU. +LDT/GDT and IDT are emulated. VM86 mode is also supported to run +DOSEMU. There is some support for MMX/3DNow!, SSE, SSE2, SSE3, SSSE3, +and SSE4 as well as x86-64 SVM. @item Support of host page sizes bigger than 4KB in user mode emulation. @@ -124,9 +159,7 @@ @itemize -@item No SSE/MMX support (yet). - -@item No x86-64 support. +@item Limited x86-64 support. @item IPC syscalls are missing. @@ -134,10 +167,6 @@ memory access (yet). Hopefully, very few OSes seem to rely on that for normal use. -@item On non x86 host CPUs, @code{double}s are used instead of the non standard -10 byte @code{long double}s of x86 for floating point emulation to get -maximum performances. - @end itemize @node intro_arm_emulation @@ -193,7 +222,7 @@ @end itemize @node intro_sparc_emulation -@section SPARC emulation +@section Sparc32 and Sparc64 emulation @itemize @@ -216,17 +245,34 @@ @item Atomic instructions are not correctly implemented. -@item Sparc64 emulators are not usable for anything yet. +@item There are still some problems with Sparc64 emulators. @end itemize +@node intro_other_emulation +@section Other CPU emulation + +In addition to the above, QEMU supports emulation of other CPUs with +varying levels of success. These are: + +@itemize + +@item +Alpha +@item +CRIS +@item +M68k +@item +SH4 +@end itemize + @node QEMU Internals @chapter QEMU Internals @menu * QEMU compared to other emulators:: * Portable dynamic translation:: -* Register allocation:: * Condition code optimisations:: * CPU state optimisations:: * Translation cache:: @@ -234,6 +280,7 @@ * Self-modifying code and translated code invalidation:: * Exception support:: * MMU emulation:: +* Device emulation:: * Hardware interrupts:: * User emulation specific details:: * Bibliography:: @@ -273,19 +320,23 @@ QEMU accepts unpatched Linux kernels. The price to pay is that QEMU is slower. -The new Plex86 [8] PC virtualizer is done in the same spirit as the -qemu-fast system emulator. It requires a patched Linux kernel to work -(you cannot launch the same kernel on your PC), but the patches are -really small. As it is a PC virtualizer (no emulation is done except -for some priveledged instructions), it has the potential of being -faster than QEMU. The downside is that a complicated (and potentially -unsafe) host kernel patch is needed. +The Plex86 [8] PC virtualizer is done in the same spirit as the now +obsolete qemu-fast system emulator. It requires a patched Linux kernel +to work (you cannot launch the same kernel on your PC), but the +patches are really small. As it is a PC virtualizer (no emulation is +done except for some privileged instructions), it has the potential of +being faster than QEMU. The downside is that a complicated (and +potentially unsafe) host kernel patch is needed. The commercial PC Virtualizers (VMWare [9], VirtualPC [10], TwoOStwo [11]) are faster than QEMU, but they all need specific, proprietary and potentially unsafe host drivers. Moreover, they are unable to provide cycle exact simulation as an emulator can. +VirtualBox [12], Xen [13] and KVM [14] are based on QEMU. QEMU-SystemC +[15] uses QEMU to simulate a system where some hardware devices are +developed in SystemC. + @node Portable dynamic translation @section Portable dynamic translation @@ -295,63 +346,51 @@ which make it relatively easily portable and simple while achieving good performances. -The basic idea is to split every x86 instruction into fewer simpler -instructions. Each simple instruction is implemented by a piece of C -code (see @file{target-i386/op.c}). Then a compile time tool -(@file{dyngen}) takes the corresponding object file (@file{op.o}) -to generate a dynamic code generator which concatenates the simple -instructions to build a function (see @file{op.h:dyngen_code()}). - -In essence, the process is similar to [1], but more work is done at -compile time. - -A key idea to get optimal performances is that constant parameters can -be passed to the simple operations. For that purpose, dummy ELF -relocations are generated with gcc for each constant parameter. Then, -the tool (@file{dyngen}) can locate the relocations and generate the -appriopriate C code to resolve them when building the dynamic code. - -That way, QEMU is no more difficult to port than a dynamic linker. - -To go even faster, GCC static register variables are used to keep the -state of the virtual CPU. - -@node Register allocation -@section Register allocation - -Since QEMU uses fixed simple instructions, no efficient register -allocation can be done. However, because RISC CPUs have a lot of -register, most of the virtual CPU state can be put in registers without -doing complicated register allocation. +After the release of version 0.9.1, QEMU switched to a new method of +generating code, Tiny Code Generator or TCG. TCG relaxes the +dependency on the exact version of the compiler used. The basic idea +is to split every target instruction into a couple of RISC-like TCG +ops (see @code{target-i386/translate.c}). Some optimizations can be +performed at this stage, including liveness analysis and trivial +constant expression evaluation. TCG ops are then implemented in the +host CPU back end, also known as TCG target (see +@code{tcg/i386/tcg-target.c}). For more information, please take a +look at @code{tcg/README}. @node Condition code optimisations @section Condition code optimisations -Good CPU condition codes emulation (@code{EFLAGS} register on x86) is a -critical point to get good performances. QEMU uses lazy condition code -evaluation: instead of computing the condition codes after each x86 -instruction, it just stores one operand (called @code{CC_SRC}), the -result (called @code{CC_DST}) and the type of operation (called -@code{CC_OP}). +Lazy evaluation of CPU condition codes (@code{EFLAGS} register on x86) +is important for CPUs where every instruction sets the condition +codes. It tends to be less important on conventional RISC systems +where condition codes are only updated when explicitly requested. + +Instead of computing the condition codes after each x86 instruction, +QEMU just stores one operand (called @code{CC_SRC}), the result +(called @code{CC_DST}) and the type of operation (called +@code{CC_OP}). When the condition codes are needed, the condition +codes can be calculated using this information. In addition, an +optimized calculation can be performed for some instruction types like +conditional branches. -@code{CC_OP} is almost never explicitely set in the generated code +@code{CC_OP} is almost never explicitly set in the generated code because it is known at translation time. -In order to increase performances, a backward pass is performed on the -generated simple instructions (see -@code{target-i386/translate.c:optimize_flags()}). When it can be proved that -the condition codes are not needed by the next instructions, no -condition codes are computed at all. +The lazy condition code evaluation is used on x86, m68k and cris. ARM +uses a simplified variant for the N and Z flags. @node CPU state optimisations @section CPU state optimisations -The x86 CPU has many internal states which change the way it evaluates -instructions. In order to achieve a good speed, the translation phase -considers that some state information of the virtual x86 CPU cannot -change in it. For example, if the SS, DS and ES segments have a zero -base, then the translator does not even generate an addition for the -segment base. +The target CPUs have many internal states which change the way it +evaluates instructions. In order to achieve a good speed, the +translation phase considers that some state information of the virtual +CPU cannot change in it. The state is recorded in the Translation +Block (TB). If the state changes (e.g. privilege level), a new TB will +be generated and the previous TB won't be used anymore until the state +matches the state recorded in the previous TB. For example, if the SS, +DS and ES segments have a zero base, then the translator does not even +generate an addition for the segment base. [The FPU stack pointer register is not handled that way yet]. @@ -388,28 +427,20 @@ is modified. When translated code is generated for a basic block, the corresponding -host page is write protected if it is not already read-only (with the -system call @code{mprotect()}). Then, if a write access is done to the -page, Linux raises a SEGV signal. QEMU then invalidates all the -translated code in the page and enables write accesses to the page. +host page is write protected if it is not already read-only. Then, if +a write access is done to the page, Linux raises a SEGV signal. QEMU +then invalidates all the translated code in the page and enables write +accesses to the page. Correct translated code invalidation is done efficiently by maintaining a linked list of every translated block contained in a given page. Other linked lists are also maintained to undo direct block chaining. -Although the overhead of doing @code{mprotect()} calls is important, -most MSDOS programs can be emulated at reasonnable speed with QEMU and -DOSEMU. - -Note that QEMU also invalidates pages of translated code when it detects -that memory mappings are modified with @code{mmap()} or @code{munmap()}. - -When using a software MMU, the code invalidation is more efficient: if -a given code page is invalidated too often because of write accesses, -then a bitmap representing all the code inside the page is -built. Every store into that page checks the bitmap to see if the code -really needs to be invalidated. It avoids invalidating the code when -only data is modified in the page. +On RISC targets, correctly written software uses memory barriers and +cache flushes, so some of the protection above would not be +necessary. However, QEMU still requires that the generated code always +matches the target instructions in memory in order to handle +exceptions correctly. @node Exception support @section Exception support @@ -418,10 +449,9 @@ encountered. The host SIGSEGV and SIGBUS signal handlers are used to get invalid -memory accesses. The exact CPU state can be retrieved because all the -x86 registers are stored in fixed host registers. The simulated program -counter is found by retranslating the corresponding basic block and by -looking where the host program counter was at the exception point. +memory accesses. The simulated program counter is found by +retranslating the corresponding basic block and by looking where the +host program counter was at the exception point. The virtual CPU cannot retrieve the exact @code{EFLAGS} register because in some cases it is not computed because of condition code @@ -431,15 +461,10 @@ @node MMU emulation @section MMU emulation -For system emulation, QEMU uses the mmap() system call to emulate the -target CPU MMU. It works as long the emulated OS does not use an area -reserved by the host OS (such as the area above 0xc0000000 on x86 -Linux). - -In order to be able to launch any OS, QEMU also supports a soft -MMU. In that mode, the MMU virtual to physical address translation is -done at every memory access. QEMU uses an address translation cache to -speed up the translation. +For system emulation QEMU supports a soft MMU. In that mode, the MMU +virtual to physical address translation is done at every memory +access. QEMU uses an address translation cache to speed up the +translation. In order to avoid flushing the translated code each time the MMU mappings change, QEMU uses a physically indexed translation cache. It @@ -448,6 +473,33 @@ When MMU mappings change, only the chaining of the basic blocks is reset (i.e. a basic block can no longer jump directly to another one). +@node Device emulation +@section Device emulation + +Systems emulated by QEMU are organized by boards. At initialization +phase, each board instantiates a number of CPUs, devices, RAM and +ROM. Each device in turn can assign I/O ports or memory areas (for +MMIO) to its handlers. When the emulation starts, an access to the +ports or MMIO memory areas assigned to the device causes the +corresponding handler to be called. + +RAM and ROM are handled more optimally, only the offset to the host +memory needs to be added to the guest address. + +The video RAM of VGA and other display cards is special: it can be +read or written directly like RAM, but write accesses cause the memory +to be marked with VGA_DIRTY flag as well. + +QEMU supports some device classes like serial and parallel ports, USB, +drives and network devices, by providing APIs for easier connection to +the generic, higher level implementations. The API hides the +implementation details from the devices, like native device use or +advanced block device formats like QCOW. + +Usually the devices implement a reset method and register support for +saving and loading of the device state. The devices can also use +timers, especially together with the use of bottom halves (BHs). + @node Hardware interrupts @section Hardware interrupts @@ -513,9 +565,9 @@ emulator. Achieving self-virtualization is not easy because there may be address -space conflicts. QEMU solves this problem by being an executable ELF -shared object as the ld-linux.so ELF interpreter. That way, it can be -relocated at load time. +space conflicts. QEMU user emulators solve this problem by being an +executable ELF shared object as the ld-linux.so ELF interpreter. That +way, it can be relocated at load time. @node Bibliography @section Bibliography @@ -568,6 +620,22 @@ @url{http://www.twoostwo.org/}, The TwoOStwo PC virtualizer. +@item [12] +@url{http://virtualbox.org/}, +The VirtualBox PC virtualizer. + +@item [13] +@url{http://www.xen.org/}, +The Xen hypervisor. + +@item [14] +@url{http://kvm.qumranet.com/kvmwiki/Front_Page}, +Kernel Based Virtual Machine (KVM). + +@item [15] +@url{http://www.greensocs.com/projects/QEMUSystemC}, +QEMU-SystemC, a hardware co-simulator. + @end table @node Regression Tests diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/qemu-tool.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/qemu-tool.c --- qemu-0.9.1/qemu-tool.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/qemu-tool.c 2008-10-29 14:37:18.000000000 +0000 @@ -0,0 +1,87 @@ +/* + * Compatibility for qemu-img/qemu-nbd + * + * Copyright IBM, Corp. 2008 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "qemu-common.h" +#include "console.h" +#include "sysemu.h" +#include "qemu-timer.h" + +#include + +QEMUClock *rt_clock; + +struct QEMUBH +{ + QEMUBHFunc *cb; + void *opaque; +}; + +void qemu_service_io(void) +{ +} + +void term_printf(const char *fmt, ...) +{ +} + +void term_print_filename(const char *filename) +{ +} + +QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque) +{ + QEMUBH *bh; + + bh = qemu_malloc(sizeof(*bh)); + if (bh) { + bh->cb = cb; + bh->opaque = opaque; + } + + return bh; +} + +int qemu_bh_poll(void) +{ + return 0; +} + +void qemu_bh_schedule(QEMUBH *bh) +{ + bh->cb(bh->opaque); +} + +void qemu_bh_cancel(QEMUBH *bh) +{ +} + +void qemu_bh_delete(QEMUBH *bh) +{ + qemu_free(bh); +} + +int qemu_set_fd_handler2(int fd, + IOCanRWHandler *fd_read_poll, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque) +{ + return 0; +} + +int64_t qemu_get_clock(QEMUClock *clock) +{ + struct timeval tv; + qemu_gettimeofday(&tv); + return (tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000)) / 1000000; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/s390-dis.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/s390-dis.c --- qemu-0.9.1/s390-dis.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/s390-dis.c 2008-01-17 13:56:59.000000000 +0000 @@ -1,23 +1,23 @@ /* s390-dis.c -- Disassemble S390 instructions - Copyright 2000, 2001, 2002, 2003, 2005, 2007 Free Software Foundation, Inc. + Copyright 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc. Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). - This file is part of the GNU opcodes library. + This file is part of GDB, GAS and the GNU binutils. - This library is free software; you can redistribute it and/or modify + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your option) - any later version. + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. - It 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 General Public - License for more details. + This program 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 General Public License for more details. You should have received a copy of the GNU General Public License - along with this file; see the file COPYING. If not, write to the - Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ #include #include "dis-asm.h" @@ -397,25 +397,25 @@ } } /* s390-opc.c -- S390 opcode list - Copyright 2000, 2001, 2003, 2007 Free Software Foundation, Inc. + Copyright 2000, 2001, 2003 Free Software Foundation, Inc. Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). - This file is part of the GNU opcodes library. + This file is part of GDB, GAS, and the GNU binutils. - This library is free software; you can redistribute it and/or modify + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your option) - any later version. + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. - It 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 General Public - License for more details. + This program 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 General Public License for more details. You should have received a copy of the GNU General Public License - along with this file; see the file COPYING. If not, write to the - Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ #include diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/savevm.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/savevm.c --- qemu-0.9.1/savevm.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/savevm.c 2008-11-11 21:33:36.000000000 +0000 @@ -0,0 +1,1245 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * 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 "qemu-common.h" +#include "hw/hw.h" +#include "net.h" +#include "console.h" +#include "sysemu.h" +#include "qemu-timer.h" +#include "qemu-char.h" +#include "block.h" +#include "audio/audio.h" +#include "migration.h" +#include "qemu_socket.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(__NetBSD__) +#include +#endif +#ifdef __linux__ +#include +#endif +#include +#include +#include +#include +#ifdef _BSD +#include +#ifdef __FreeBSD__ +#include +#else +#include +#endif +#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__) +#include +#else +#ifdef __linux__ +#include +#include +#include +#endif +#endif +#endif + +#ifdef _WIN32 +#include +#include +#include +#define getopt_long_only getopt_long +#define memalign(align, size) malloc(size) +#endif + +/* point to the block driver where the snapshots are managed */ +static BlockDriverState *bs_snapshots; + +#define SELF_ANNOUNCE_ROUNDS 5 +#define ETH_P_EXPERIMENTAL 0x01F1 /* just a number */ +//#define ETH_P_EXPERIMENTAL 0x0012 /* make it the size of the packet */ +#define EXPERIMENTAL_MAGIC 0xf1f23f4f + +static int announce_self_create(uint8_t *buf, + uint8_t *mac_addr) +{ + uint32_t magic = EXPERIMENTAL_MAGIC; + uint16_t proto = htons(ETH_P_EXPERIMENTAL); + + /* FIXME: should we send a different packet (arp/rarp/ping)? */ + + memset(buf, 0xff, 6); /* h_dst */ + memcpy(buf + 6, mac_addr, 6); /* h_src */ + memcpy(buf + 12, &proto, 2); /* h_proto */ + memcpy(buf + 14, &magic, 4); /* magic */ + + return 18; /* len */ +} + +void qemu_announce_self(void) +{ + int i, j, len; + VLANState *vlan; + VLANClientState *vc; + uint8_t buf[256]; + + for (i = 0; i < nb_nics; i++) { + len = announce_self_create(buf, nd_table[i].macaddr); + vlan = nd_table[i].vlan; + for(vc = vlan->first_client; vc != NULL; vc = vc->next) { + for (j=0; j < SELF_ANNOUNCE_ROUNDS; j++) + vc->fd_read(vc->opaque, buf, len); + } + } +} + +/***********************************************************/ +/* savevm/loadvm support */ + +#define IO_BUF_SIZE 32768 + +struct QEMUFile { + QEMUFilePutBufferFunc *put_buffer; + QEMUFileGetBufferFunc *get_buffer; + QEMUFileCloseFunc *close; + QEMUFileRateLimit *rate_limit; + void *opaque; + int is_write; + + int64_t buf_offset; /* start of buffer when writing, end of buffer + when reading */ + int buf_index; + int buf_size; /* 0 when writing */ + uint8_t buf[IO_BUF_SIZE]; + + int has_error; +}; + +typedef struct QEMUFilePopen +{ + FILE *popen_file; + QEMUFile *file; +} QEMUFilePopen; + +typedef struct QEMUFileSocket +{ + int fd; + QEMUFile *file; +} QEMUFileSocket; + +static int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) +{ + QEMUFileSocket *s = opaque; + ssize_t len; + + do { + len = recv(s->fd, buf, size, 0); + } while (len == -1 && socket_error() == EINTR); + + if (len == -1) + len = -socket_error(); + + return len; +} + +static int socket_close(void *opaque) +{ + QEMUFileSocket *s = opaque; + qemu_free(s); + return 0; +} + +static int popen_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) +{ + QEMUFilePopen *s = opaque; + return fwrite(buf, 1, size, s->popen_file); +} + +static int popen_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) +{ + QEMUFilePopen *s = opaque; + return fread(buf, 1, size, s->popen_file); +} + +static int popen_close(void *opaque) +{ + QEMUFilePopen *s = opaque; + pclose(s->popen_file); + qemu_free(s); + return 0; +} + +QEMUFile *qemu_popen(FILE *popen_file, const char *mode) +{ + QEMUFilePopen *s; + + if (popen_file == NULL || mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) { + fprintf(stderr, "qemu_popen: Argument validity check failed\n"); + return NULL; + } + + s = qemu_mallocz(sizeof(QEMUFilePopen)); + if (!s) { + fprintf(stderr, "qemu_popen: malloc failed\n"); + return NULL; + } + + s->popen_file = popen_file; + + if(mode[0] == 'r') { + s->file = qemu_fopen_ops(s, NULL, popen_get_buffer, popen_close, NULL); + } else { + s->file = qemu_fopen_ops(s, popen_put_buffer, NULL, popen_close, NULL); + } + fprintf(stderr, "qemu_popen: returning result of qemu_fopen_ops\n"); + return s->file; +} + +QEMUFile *qemu_popen_cmd(const char *command, const char *mode) +{ + FILE *popen_file; + + popen_file = popen(command, mode); + if(popen_file == NULL) { + return NULL; + } + + return qemu_popen(popen_file, mode); +} + +QEMUFile *qemu_fopen_socket(int fd) +{ + QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket)); + + if (s == NULL) + return NULL; + + s->fd = fd; + s->file = qemu_fopen_ops(s, NULL, socket_get_buffer, socket_close, NULL); + return s->file; +} + +typedef struct QEMUFileStdio +{ + FILE *outfile; +} QEMUFileStdio; + +static int file_put_buffer(void *opaque, const uint8_t *buf, + int64_t pos, int size) +{ + QEMUFileStdio *s = opaque; + fseek(s->outfile, pos, SEEK_SET); + fwrite(buf, 1, size, s->outfile); + return size; +} + +static int file_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) +{ + QEMUFileStdio *s = opaque; + fseek(s->outfile, pos, SEEK_SET); + return fread(buf, 1, size, s->outfile); +} + +static int file_close(void *opaque) +{ + QEMUFileStdio *s = opaque; + fclose(s->outfile); + qemu_free(s); + return 0; +} + +QEMUFile *qemu_fopen(const char *filename, const char *mode) +{ + QEMUFileStdio *s; + + s = qemu_mallocz(sizeof(QEMUFileStdio)); + if (!s) + return NULL; + + s->outfile = fopen(filename, mode); + if (!s->outfile) + goto fail; + + if (!strcmp(mode, "wb")) + return qemu_fopen_ops(s, file_put_buffer, NULL, file_close, NULL); + else if (!strcmp(mode, "rb")) + return qemu_fopen_ops(s, NULL, file_get_buffer, file_close, NULL); + +fail: + if (s->outfile) + fclose(s->outfile); + qemu_free(s); + return NULL; +} + +typedef struct QEMUFileBdrv +{ + BlockDriverState *bs; + int64_t base_offset; +} QEMUFileBdrv; + +static int bdrv_put_buffer(void *opaque, const uint8_t *buf, + int64_t pos, int size) +{ + QEMUFileBdrv *s = opaque; + bdrv_pwrite(s->bs, s->base_offset + pos, buf, size); + return size; +} + +static int bdrv_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) +{ + QEMUFileBdrv *s = opaque; + return bdrv_pread(s->bs, s->base_offset + pos, buf, size); +} + +static int bdrv_fclose(void *opaque) +{ + QEMUFileBdrv *s = opaque; + qemu_free(s); + return 0; +} + +static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable) +{ + QEMUFileBdrv *s; + + s = qemu_mallocz(sizeof(QEMUFileBdrv)); + if (!s) + return NULL; + + s->bs = bs; + s->base_offset = offset; + + if (is_writable) + return qemu_fopen_ops(s, bdrv_put_buffer, NULL, bdrv_fclose, NULL); + + return qemu_fopen_ops(s, NULL, bdrv_get_buffer, bdrv_fclose, NULL); +} + +QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer, + QEMUFileGetBufferFunc *get_buffer, + QEMUFileCloseFunc *close, + QEMUFileRateLimit *rate_limit) +{ + QEMUFile *f; + + f = qemu_mallocz(sizeof(QEMUFile)); + if (!f) + return NULL; + + f->opaque = opaque; + f->put_buffer = put_buffer; + f->get_buffer = get_buffer; + f->close = close; + f->rate_limit = rate_limit; + f->is_write = 0; + + return f; +} + +int qemu_file_has_error(QEMUFile *f) +{ + return f->has_error; +} + +void qemu_fflush(QEMUFile *f) +{ + if (!f->put_buffer) + return; + + if (f->is_write && f->buf_index > 0) { + int len; + + len = f->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index); + if (len > 0) + f->buf_offset += f->buf_index; + else + f->has_error = 1; + f->buf_index = 0; + } +} + +static void qemu_fill_buffer(QEMUFile *f) +{ + int len; + + if (!f->get_buffer) + return; + + if (f->is_write) + abort(); + + len = f->get_buffer(f->opaque, f->buf, f->buf_offset, IO_BUF_SIZE); + if (len > 0) { + f->buf_index = 0; + f->buf_size = len; + f->buf_offset += len; + } else if (len != -EAGAIN) + f->has_error = 1; +} + +int qemu_fclose(QEMUFile *f) +{ + int ret = 0; + qemu_fflush(f); + if (f->close) + ret = f->close(f->opaque); + qemu_free(f); + return ret; +} + +void qemu_file_put_notify(QEMUFile *f) +{ + f->put_buffer(f->opaque, NULL, 0, 0); +} + +void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) +{ + int l; + + if (!f->has_error && f->is_write == 0 && f->buf_index > 0) { + fprintf(stderr, + "Attempted to write to buffer while read buffer is not empty\n"); + abort(); + } + + while (!f->has_error && size > 0) { + l = IO_BUF_SIZE - f->buf_index; + if (l > size) + l = size; + memcpy(f->buf + f->buf_index, buf, l); + f->is_write = 1; + f->buf_index += l; + buf += l; + size -= l; + if (f->buf_index >= IO_BUF_SIZE) + qemu_fflush(f); + } +} + +void qemu_put_byte(QEMUFile *f, int v) +{ + if (!f->has_error && f->is_write == 0 && f->buf_index > 0) { + fprintf(stderr, + "Attempted to write to buffer while read buffer is not empty\n"); + abort(); + } + + f->buf[f->buf_index++] = v; + f->is_write = 1; + if (f->buf_index >= IO_BUF_SIZE) + qemu_fflush(f); +} + +int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1) +{ + int size, l; + + if (f->is_write) + abort(); + + size = size1; + while (size > 0) { + l = f->buf_size - f->buf_index; + if (l == 0) { + qemu_fill_buffer(f); + l = f->buf_size - f->buf_index; + if (l == 0) + break; + } + if (l > size) + l = size; + memcpy(buf, f->buf + f->buf_index, l); + f->buf_index += l; + buf += l; + size -= l; + } + return size1 - size; +} + +int qemu_get_byte(QEMUFile *f) +{ + if (f->is_write) + abort(); + + if (f->buf_index >= f->buf_size) { + qemu_fill_buffer(f); + if (f->buf_index >= f->buf_size) + return 0; + } + return f->buf[f->buf_index++]; +} + +int64_t qemu_ftell(QEMUFile *f) +{ + return f->buf_offset - f->buf_size + f->buf_index; +} + +int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence) +{ + if (whence == SEEK_SET) { + /* nothing to do */ + } else if (whence == SEEK_CUR) { + pos += qemu_ftell(f); + } else { + /* SEEK_END not supported */ + return -1; + } + if (f->put_buffer) { + qemu_fflush(f); + f->buf_offset = pos; + } else { + f->buf_offset = pos; + f->buf_index = 0; + f->buf_size = 0; + } + return pos; +} + +int qemu_file_rate_limit(QEMUFile *f) +{ + if (f->rate_limit) + return f->rate_limit(f->opaque); + + return 0; +} + +void qemu_put_be16(QEMUFile *f, unsigned int v) +{ + qemu_put_byte(f, v >> 8); + qemu_put_byte(f, v); +} + +void qemu_put_be32(QEMUFile *f, unsigned int v) +{ + qemu_put_byte(f, v >> 24); + qemu_put_byte(f, v >> 16); + qemu_put_byte(f, v >> 8); + qemu_put_byte(f, v); +} + +void qemu_put_be64(QEMUFile *f, uint64_t v) +{ + qemu_put_be32(f, v >> 32); + qemu_put_be32(f, v); +} + +unsigned int qemu_get_be16(QEMUFile *f) +{ + unsigned int v; + v = qemu_get_byte(f) << 8; + v |= qemu_get_byte(f); + return v; +} + +unsigned int qemu_get_be32(QEMUFile *f) +{ + unsigned int v; + v = qemu_get_byte(f) << 24; + v |= qemu_get_byte(f) << 16; + v |= qemu_get_byte(f) << 8; + v |= qemu_get_byte(f); + return v; +} + +uint64_t qemu_get_be64(QEMUFile *f) +{ + uint64_t v; + v = (uint64_t)qemu_get_be32(f) << 32; + v |= qemu_get_be32(f); + return v; +} + +typedef struct SaveStateEntry { + char idstr[256]; + int instance_id; + int version_id; + int section_id; + SaveLiveStateHandler *save_live_state; + SaveStateHandler *save_state; + LoadStateHandler *load_state; + void *opaque; + struct SaveStateEntry *next; +} SaveStateEntry; + +static SaveStateEntry *first_se; + +/* TODO: Individual devices generally have very little idea about the rest + of the system, so instance_id should be removed/replaced. + Meanwhile pass -1 as instance_id if you do not already have a clearly + distinguishing id for all instances of your device class. */ +int register_savevm_live(const char *idstr, + int instance_id, + int version_id, + SaveLiveStateHandler *save_live_state, + SaveStateHandler *save_state, + LoadStateHandler *load_state, + void *opaque) +{ + SaveStateEntry *se, **pse; + static int global_section_id; + + se = qemu_malloc(sizeof(SaveStateEntry)); + if (!se) + return -1; + pstrcpy(se->idstr, sizeof(se->idstr), idstr); + se->instance_id = (instance_id == -1) ? 0 : instance_id; + se->version_id = version_id; + se->section_id = global_section_id++; + se->save_live_state = save_live_state; + se->save_state = save_state; + se->load_state = load_state; + se->opaque = opaque; + se->next = NULL; + + /* add at the end of list */ + pse = &first_se; + while (*pse != NULL) { + if (instance_id == -1 + && strcmp(se->idstr, (*pse)->idstr) == 0 + && se->instance_id <= (*pse)->instance_id) + se->instance_id = (*pse)->instance_id + 1; + pse = &(*pse)->next; + } + *pse = se; + return 0; +} + +int register_savevm(const char *idstr, + int instance_id, + int version_id, + SaveStateHandler *save_state, + LoadStateHandler *load_state, + void *opaque) +{ + return register_savevm_live(idstr, instance_id, version_id, + NULL, save_state, load_state, opaque); +} + +#define QEMU_VM_FILE_MAGIC 0x5145564d +#define QEMU_VM_FILE_VERSION_COMPAT 0x00000002 +#define QEMU_VM_FILE_VERSION 0x00000003 + +#define QEMU_VM_EOF 0x00 +#define QEMU_VM_SECTION_START 0x01 +#define QEMU_VM_SECTION_PART 0x02 +#define QEMU_VM_SECTION_END 0x03 +#define QEMU_VM_SECTION_FULL 0x04 + +int qemu_savevm_state_begin(QEMUFile *f) +{ + SaveStateEntry *se; + + qemu_put_be32(f, QEMU_VM_FILE_MAGIC); + qemu_put_be32(f, QEMU_VM_FILE_VERSION); + + for (se = first_se; se != NULL; se = se->next) { + int len; + + if (se->save_live_state == NULL) + continue; + + /* Section type */ + qemu_put_byte(f, QEMU_VM_SECTION_START); + qemu_put_be32(f, se->section_id); + + /* ID string */ + len = strlen(se->idstr); + qemu_put_byte(f, len); + qemu_put_buffer(f, (uint8_t *)se->idstr, len); + + qemu_put_be32(f, se->instance_id); + qemu_put_be32(f, se->version_id); + + se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque); + } + + if (qemu_file_has_error(f)) + return -EIO; + + return 0; +} + +int qemu_savevm_state_iterate(QEMUFile *f) +{ + SaveStateEntry *se; + int ret = 1; + + for (se = first_se; se != NULL; se = se->next) { + if (se->save_live_state == NULL) + continue; + + /* Section type */ + qemu_put_byte(f, QEMU_VM_SECTION_PART); + qemu_put_be32(f, se->section_id); + + ret &= !!se->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque); + } + + if (ret) + return 1; + + if (qemu_file_has_error(f)) + return -EIO; + + return 0; +} + +int qemu_savevm_state_complete(QEMUFile *f) +{ + SaveStateEntry *se; + + for (se = first_se; se != NULL; se = se->next) { + if (se->save_live_state == NULL) + continue; + + /* Section type */ + qemu_put_byte(f, QEMU_VM_SECTION_END); + qemu_put_be32(f, se->section_id); + + se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque); + } + + for(se = first_se; se != NULL; se = se->next) { + int len; + + if (se->save_state == NULL) + continue; + + /* Section type */ + qemu_put_byte(f, QEMU_VM_SECTION_FULL); + qemu_put_be32(f, se->section_id); + + /* ID string */ + len = strlen(se->idstr); + qemu_put_byte(f, len); + qemu_put_buffer(f, (uint8_t *)se->idstr, len); + + qemu_put_be32(f, se->instance_id); + qemu_put_be32(f, se->version_id); + + se->save_state(f, se->opaque); + } + + qemu_put_byte(f, QEMU_VM_EOF); + + if (qemu_file_has_error(f)) + return -EIO; + + return 0; +} + +int qemu_savevm_state(QEMUFile *f) +{ + int saved_vm_running; + int ret; + + saved_vm_running = vm_running; + vm_stop(0); + + bdrv_flush_all(); + + ret = qemu_savevm_state_begin(f); + if (ret < 0) + goto out; + + do { + ret = qemu_savevm_state_iterate(f); + if (ret < 0) + goto out; + } while (ret == 0); + + ret = qemu_savevm_state_complete(f); + +out: + if (qemu_file_has_error(f)) + ret = -EIO; + + if (!ret && saved_vm_running) + vm_start(); + + return ret; +} + +static SaveStateEntry *find_se(const char *idstr, int instance_id) +{ + SaveStateEntry *se; + + for(se = first_se; se != NULL; se = se->next) { + if (!strcmp(se->idstr, idstr) && + instance_id == se->instance_id) + return se; + } + return NULL; +} + +typedef struct LoadStateEntry { + SaveStateEntry *se; + int section_id; + int version_id; + struct LoadStateEntry *next; +} LoadStateEntry; + +static int qemu_loadvm_state_v2(QEMUFile *f) +{ + SaveStateEntry *se; + int len, ret, instance_id, record_len, version_id; + int64_t total_len, end_pos, cur_pos; + char idstr[256]; + + total_len = qemu_get_be64(f); + end_pos = total_len + qemu_ftell(f); + for(;;) { + if (qemu_ftell(f) >= end_pos) + break; + len = qemu_get_byte(f); + qemu_get_buffer(f, (uint8_t *)idstr, len); + idstr[len] = '\0'; + instance_id = qemu_get_be32(f); + version_id = qemu_get_be32(f); + record_len = qemu_get_be32(f); + cur_pos = qemu_ftell(f); + se = find_se(idstr, instance_id); + if (!se) { + fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n", + instance_id, idstr); + } else { + ret = se->load_state(f, se->opaque, version_id); + if (ret < 0) { + fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n", + instance_id, idstr); + } + } + /* always seek to exact end of record */ + qemu_fseek(f, cur_pos + record_len, SEEK_SET); + } + + if (qemu_file_has_error(f)) + return -EIO; + + return 0; +} + +int qemu_loadvm_state(QEMUFile *f) +{ + LoadStateEntry *first_le = NULL; + uint8_t section_type; + unsigned int v; + int ret; + + v = qemu_get_be32(f); + if (v != QEMU_VM_FILE_MAGIC) + return -EINVAL; + + v = qemu_get_be32(f); + if (v == QEMU_VM_FILE_VERSION_COMPAT) + return qemu_loadvm_state_v2(f); + if (v != QEMU_VM_FILE_VERSION) + return -ENOTSUP; + + while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) { + uint32_t instance_id, version_id, section_id; + LoadStateEntry *le; + SaveStateEntry *se; + char idstr[257]; + int len; + + switch (section_type) { + case QEMU_VM_SECTION_START: + case QEMU_VM_SECTION_FULL: + /* Read section start */ + section_id = qemu_get_be32(f); + len = qemu_get_byte(f); + qemu_get_buffer(f, (uint8_t *)idstr, len); + idstr[len] = 0; + instance_id = qemu_get_be32(f); + version_id = qemu_get_be32(f); + + /* Find savevm section */ + se = find_se(idstr, instance_id); + if (se == NULL) { + fprintf(stderr, "Unknown savevm section or instance '%s' %d\n", idstr, instance_id); + ret = -EINVAL; + goto out; + } + + /* Validate version */ + if (version_id > se->version_id) { + fprintf(stderr, "savevm: unsupported version %d for '%s' v%d\n", + version_id, idstr, se->version_id); + ret = -EINVAL; + goto out; + } + + /* Add entry */ + le = qemu_mallocz(sizeof(*le)); + if (le == NULL) { + ret = -ENOMEM; + goto out; + } + + le->se = se; + le->section_id = section_id; + le->version_id = version_id; + le->next = first_le; + first_le = le; + + le->se->load_state(f, le->se->opaque, le->version_id); + break; + case QEMU_VM_SECTION_PART: + case QEMU_VM_SECTION_END: + section_id = qemu_get_be32(f); + + for (le = first_le; le && le->section_id != section_id; le = le->next); + if (le == NULL) { + fprintf(stderr, "Unknown savevm section %d\n", section_id); + ret = -EINVAL; + goto out; + } + + le->se->load_state(f, le->se->opaque, le->version_id); + break; + default: + fprintf(stderr, "Unknown savevm section type %d\n", section_type); + ret = -EINVAL; + goto out; + } + } + + ret = 0; + +out: + while (first_le) { + LoadStateEntry *le = first_le; + first_le = first_le->next; + qemu_free(le); + } + + if (qemu_file_has_error(f)) + ret = -EIO; + + return ret; +} + +/* device can contain snapshots */ +static int bdrv_can_snapshot(BlockDriverState *bs) +{ + return (bs && + !bdrv_is_removable(bs) && + !bdrv_is_read_only(bs)); +} + +/* device must be snapshots in order to have a reliable snapshot */ +static int bdrv_has_snapshot(BlockDriverState *bs) +{ + return (bs && + !bdrv_is_removable(bs) && + !bdrv_is_read_only(bs)); +} + +static BlockDriverState *get_bs_snapshots(void) +{ + BlockDriverState *bs; + int i; + + if (bs_snapshots) + return bs_snapshots; + for(i = 0; i <= nb_drives; i++) { + bs = drives_table[i].bdrv; + if (bdrv_can_snapshot(bs)) + goto ok; + } + return NULL; + ok: + bs_snapshots = bs; + return bs; +} + +static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, + const char *name) +{ + QEMUSnapshotInfo *sn_tab, *sn; + int nb_sns, i, ret; + + ret = -ENOENT; + nb_sns = bdrv_snapshot_list(bs, &sn_tab); + if (nb_sns < 0) + return ret; + for(i = 0; i < nb_sns; i++) { + sn = &sn_tab[i]; + if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) { + *sn_info = *sn; + ret = 0; + break; + } + } + qemu_free(sn_tab); + return ret; +} + +void do_savevm(const char *name) +{ + BlockDriverState *bs, *bs1; + QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1; + int must_delete, ret, i; + BlockDriverInfo bdi1, *bdi = &bdi1; + QEMUFile *f; + int saved_vm_running; +#ifdef _WIN32 + struct _timeb tb; +#else + struct timeval tv; +#endif + + bs = get_bs_snapshots(); + if (!bs) { + term_printf("No block device can accept snapshots\n"); + return; + } + + /* ??? Should this occur after vm_stop? */ + qemu_aio_flush(); + + saved_vm_running = vm_running; + vm_stop(0); + + must_delete = 0; + if (name) { + ret = bdrv_snapshot_find(bs, old_sn, name); + if (ret >= 0) { + must_delete = 1; + } + } + memset(sn, 0, sizeof(*sn)); + if (must_delete) { + pstrcpy(sn->name, sizeof(sn->name), old_sn->name); + pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str); + } else { + if (name) + pstrcpy(sn->name, sizeof(sn->name), name); + } + + /* fill auxiliary fields */ +#ifdef _WIN32 + _ftime(&tb); + sn->date_sec = tb.time; + sn->date_nsec = tb.millitm * 1000000; +#else + gettimeofday(&tv, NULL); + sn->date_sec = tv.tv_sec; + sn->date_nsec = tv.tv_usec * 1000; +#endif + sn->vm_clock_nsec = qemu_get_clock(vm_clock); + + if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) { + term_printf("Device %s does not support VM state snapshots\n", + bdrv_get_device_name(bs)); + goto the_end; + } + + /* save the VM state */ + f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 1); + if (!f) { + term_printf("Could not open VM state file\n"); + goto the_end; + } + ret = qemu_savevm_state(f); + sn->vm_state_size = qemu_ftell(f); + qemu_fclose(f); + if (ret < 0) { + term_printf("Error %d while writing VM\n", ret); + goto the_end; + } + + /* create the snapshots */ + + for(i = 0; i < nb_drives; i++) { + bs1 = drives_table[i].bdrv; + if (bdrv_has_snapshot(bs1)) { + if (must_delete) { + ret = bdrv_snapshot_delete(bs1, old_sn->id_str); + if (ret < 0) { + term_printf("Error while deleting snapshot on '%s'\n", + bdrv_get_device_name(bs1)); + } + } + ret = bdrv_snapshot_create(bs1, sn); + if (ret < 0) { + term_printf("Error while creating snapshot on '%s'\n", + bdrv_get_device_name(bs1)); + } + } + } + + the_end: + if (saved_vm_running) + vm_start(); +} + +void do_loadvm(const char *name) +{ + BlockDriverState *bs, *bs1; + BlockDriverInfo bdi1, *bdi = &bdi1; + QEMUFile *f; + int i, ret; + int saved_vm_running; + + bs = get_bs_snapshots(); + if (!bs) { + term_printf("No block device supports snapshots\n"); + return; + } + + /* Flush all IO requests so they don't interfere with the new state. */ + qemu_aio_flush(); + + saved_vm_running = vm_running; + vm_stop(0); + + for(i = 0; i <= nb_drives; i++) { + bs1 = drives_table[i].bdrv; + if (bdrv_has_snapshot(bs1)) { + ret = bdrv_snapshot_goto(bs1, name); + if (ret < 0) { + if (bs != bs1) + term_printf("Warning: "); + switch(ret) { + case -ENOTSUP: + term_printf("Snapshots not supported on device '%s'\n", + bdrv_get_device_name(bs1)); + break; + case -ENOENT: + term_printf("Could not find snapshot '%s' on device '%s'\n", + name, bdrv_get_device_name(bs1)); + break; + default: + term_printf("Error %d while activating snapshot on '%s'\n", + ret, bdrv_get_device_name(bs1)); + break; + } + /* fatal on snapshot block device */ + if (bs == bs1) + goto the_end; + } + } + } + + if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) { + term_printf("Device %s does not support VM state snapshots\n", + bdrv_get_device_name(bs)); + return; + } + + /* restore the VM state */ + f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 0); + if (!f) { + term_printf("Could not open VM state file\n"); + goto the_end; + } + ret = qemu_loadvm_state(f); + qemu_fclose(f); + if (ret < 0) { + term_printf("Error %d while loading VM state\n", ret); + } + the_end: + if (saved_vm_running) + vm_start(); +} + +void do_delvm(const char *name) +{ + BlockDriverState *bs, *bs1; + int i, ret; + + bs = get_bs_snapshots(); + if (!bs) { + term_printf("No block device supports snapshots\n"); + return; + } + + for(i = 0; i <= nb_drives; i++) { + bs1 = drives_table[i].bdrv; + if (bdrv_has_snapshot(bs1)) { + ret = bdrv_snapshot_delete(bs1, name); + if (ret < 0) { + if (ret == -ENOTSUP) + term_printf("Snapshots not supported on device '%s'\n", + bdrv_get_device_name(bs1)); + else + term_printf("Error %d while deleting snapshot on '%s'\n", + ret, bdrv_get_device_name(bs1)); + } + } + } +} + +void do_info_snapshots(void) +{ + BlockDriverState *bs, *bs1; + QEMUSnapshotInfo *sn_tab, *sn; + int nb_sns, i; + char buf[256]; + + bs = get_bs_snapshots(); + if (!bs) { + term_printf("No available block device supports snapshots\n"); + return; + } + term_printf("Snapshot devices:"); + for(i = 0; i <= nb_drives; i++) { + bs1 = drives_table[i].bdrv; + if (bdrv_has_snapshot(bs1)) { + if (bs == bs1) + term_printf(" %s", bdrv_get_device_name(bs1)); + } + } + term_printf("\n"); + + nb_sns = bdrv_snapshot_list(bs, &sn_tab); + if (nb_sns < 0) { + term_printf("bdrv_snapshot_list: error %d\n", nb_sns); + return; + } + term_printf("Snapshot list (from %s):\n", bdrv_get_device_name(bs)); + term_printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL)); + for(i = 0; i < nb_sns; i++) { + sn = &sn_tab[i]; + term_printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn)); + } + qemu_free(sn_tab); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/sdl.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/sdl.c --- qemu-0.9.1/sdl.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/sdl.c 2008-08-21 21:08:55.000000000 +0100 @@ -89,7 +89,18 @@ ds->data = screen->pixels; ds->linesize = screen->pitch; ds->depth = screen->format->BitsPerPixel; - if (screen->format->Bshift > screen->format->Rshift) { + /* SDL BitsPerPixel never indicates any values other than + multiples of 8, so we need to check for strange depths. */ + if (ds->depth == 16) { + uint32_t mask; + + mask = screen->format->Rmask; + mask |= screen->format->Gmask; + mask |= screen->format->Bmask; + if ((mask & 0x8000) == 0) + ds->depth = 15; + } + if (ds->depth == 32 && screen->format->Rshift == 0) { ds->bgr = 1; } else { ds->bgr = 0; @@ -276,8 +287,6 @@ } else sdl_hide_cursor(); SDL_WM_GrabInput(SDL_GRAB_ON); - /* dummy read to avoid moving the mouse */ - SDL_GetRelativeMouseState(NULL, NULL); gui_grab = 1; sdl_update_caption(); } @@ -290,10 +299,9 @@ sdl_update_caption(); } -static void sdl_send_mouse_event(int dz) +static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state) { - int dx, dy, state, buttons; - state = SDL_GetRelativeMouseState(&dx, &dy); + int buttons; buttons = 0; if (state & SDL_BUTTON(SDL_BUTTON_LEFT)) buttons |= MOUSE_EVENT_LBUTTON; @@ -311,18 +319,18 @@ absolute_enabled = 1; } - SDL_GetMouseState(&dx, &dy); - dx = dx * 0x7FFF / width; - dy = dy * 0x7FFF / height; + dx = x * 0x7FFF / (width - 1); + dy = y * 0x7FFF / (height - 1); } else if (absolute_enabled) { sdl_show_cursor(); absolute_enabled = 0; } else if (guest_cursor) { - SDL_GetMouseState(&dx, &dy); - dx -= guest_x; - dy -= guest_y; - guest_x += dx; - guest_y += dy; + x -= guest_x; + y -= guest_y; + guest_x += x; + guest_y += y; + dx = x; + dy = y; } kbd_mouse_event(dx, dy, dz, buttons); @@ -347,6 +355,7 @@ { SDL_Event ev1, *ev = &ev1; int mod_state; + int buttonstate = SDL_GetMouseState(NULL, NULL); if (last_vm_running != vm_running) { last_vm_running = vm_running; @@ -354,6 +363,7 @@ } vga_hw_update(); + SDL_EnableUNICODE(!is_graphic_console()); while (SDL_PollEvent(ev)) { switch (ev->type) { @@ -466,15 +476,14 @@ sdl_process_key(&ev->key); break; case SDL_QUIT: - if (!no_quit) { + if (!no_quit) qemu_system_shutdown_request(); - vm_start(); /* In case we're paused */ - } break; case SDL_MOUSEMOTION: if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) { - sdl_send_mouse_event(0); + sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0, + ev->motion.x, ev->motion.y, ev->motion.state); } break; case SDL_MOUSEBUTTONDOWN: @@ -483,13 +492,18 @@ SDL_MouseButtonEvent *bev = &ev->button; if (!gui_grab && !kbd_mouse_is_absolute()) { if (ev->type == SDL_MOUSEBUTTONDOWN && - (bev->state & SDL_BUTTON_LMASK)) { + (bev->button == SDL_BUTTON_LEFT)) { /* start grabbing all events */ sdl_grab_start(); } } else { int dz; dz = 0; + if (ev->type == SDL_MOUSEBUTTONDOWN) { + buttonstate |= SDL_BUTTON(bev->button); + } else { + buttonstate &= ~SDL_BUTTON(bev->button); + } #ifdef SDL_BUTTON_WHEELUP if (bev->button == SDL_BUTTON_WHEELUP && ev->type == SDL_MOUSEBUTTONDOWN) { dz = -1; @@ -497,7 +511,7 @@ dz = 1; } #endif - sdl_send_mouse_event(dz); + sdl_send_mouse_event(0, 0, dz, bev->x, bev->y, buttonstate); } } break; @@ -506,6 +520,17 @@ !ev->active.gain && !gui_fullscreen_initial_grab) { sdl_grab_end(); } + if (ev->active.state & SDL_APPACTIVE) { + if (ev->active.gain) { + /* Back to default interval */ + ds->gui_timer_interval = 0; + ds->idle = 0; + } else { + /* Sleeping interval */ + ds->gui_timer_interval = 500; + ds->idle = 1; + } + } break; default: break; @@ -611,11 +636,6 @@ fprintf(stderr, "Could not initialize SDL - exiting\n"); exit(1); } -#ifndef _WIN32 - /* NOTE: we still want Ctrl-C to work, so we undo the SDL redirections */ - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); -#endif ds->dpy_update = sdl_update; ds->dpy_resize = sdl_resize; @@ -627,7 +647,6 @@ sdl_resize(ds, 640, 400); sdl_update_caption(); SDL_EnableKeyRepeat(250, 50); - SDL_EnableUNICODE(1); gui_grab = 0; sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/sdl_keysym.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/sdl_keysym.h --- qemu-0.9.1/sdl_keysym.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/sdl_keysym.h 2008-10-02 19:26:42.000000000 +0100 @@ -2,7 +2,7 @@ const char* name; int keysym; } name2keysym_t; -static name2keysym_t name2keysym[]={ +static const name2keysym_t name2keysym[]={ /* ascii */ { "space", 0x020}, { "exclam", 0x021}, diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/sh4-dis.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/sh4-dis.c --- qemu-0.9.1/sh4-dis.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/sh4-dis.c 2008-09-14 07:45:34.000000000 +0100 @@ -325,7 +325,7 @@ typedef struct { - char *name; + const char *name; sh_arg_type arg[4]; sh_nibble_type nibbles[9]; unsigned int arch; @@ -1386,13 +1386,13 @@ int field_b; struct disassemble_info *info; { - static char *sx_tab[] = { "x0", "x1", "a0", "a1" }; - static char *sy_tab[] = { "y0", "y1", "m0", "m1" }; + static const char *sx_tab[] = { "x0", "x1", "a0", "a1" }; + static const char *sy_tab[] = { "y0", "y1", "m0", "m1" }; fprintf_ftype fprintf_fn = info->fprintf_func; void *stream = info->stream; unsigned int nib1, nib2, nib3; unsigned int altnib1, nib4; - char *dc = NULL; + const char *dc = NULL; const sh_opcode_info *op; if ((field_b & 0xe800) == 0) @@ -1405,10 +1405,10 @@ } if ((field_b & 0xc000) == 0x4000 && (field_b & 0x3000) != 0x1000) { - static char *du_tab[] = { "x0", "y0", "a0", "a1" }; - static char *se_tab[] = { "x0", "x1", "y0", "a1" }; - static char *sf_tab[] = { "y0", "y1", "x0", "a1" }; - static char *sg_tab[] = { "m0", "m1", "a0", "a1" }; + static const char *du_tab[] = { "x0", "y0", "a0", "a1" }; + static const char *se_tab[] = { "x0", "x1", "y0", "a1" }; + static const char *sf_tab[] = { "y0", "y1", "x0", "a1" }; + static const char *sg_tab[] = { "m0", "m1", "a0", "a1" }; if (field_b & 0x2000) { diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/slirp/bootp.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/slirp/bootp.c --- qemu-0.9.1/slirp/bootp.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/slirp/bootp.c 2008-10-01 20:06:48.000000000 +0100 @@ -36,7 +36,7 @@ uint8_t macaddr[6]; } BOOTPClient; -BOOTPClient bootp_clients[NB_ADDR]; +static BOOTPClient bootp_clients[NB_ADDR]; const char *bootp_filename; @@ -172,7 +172,8 @@ } if (bootp_filename) - snprintf(rbp->bp_file, sizeof(rbp->bp_file), "%s", bootp_filename); + snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s", + bootp_filename); dprintf("offered addr=%08x\n", ntohl(daddr.sin_addr.s_addr)); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/slirp/.cvsignore /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/slirp/.cvsignore --- qemu-0.9.1/slirp/.cvsignore 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/slirp/.cvsignore 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -*.d diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/slirp/debug.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/slirp/debug.c --- qemu-0.9.1/slirp/debug.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/slirp/debug.c 2008-08-30 10:51:20.000000000 +0100 @@ -16,8 +16,6 @@ #endif int slirp_debug = 0; -extern char *strerror _P((int)); - /* Carry over one item from main.c so that the tty's restored. * Only done when the tty being used is /dev/tty --RedWolf */ #ifndef CONFIG_QEMU diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/slirp/if.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/slirp/if.c --- qemu-0.9.1/slirp/if.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/slirp/if.c 2008-09-30 19:18:27.000000000 +0100 @@ -15,9 +15,8 @@ #define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm)) -void -ifs_insque(ifm, ifmhead) - struct mbuf *ifm, *ifmhead; +static void +ifs_insque(struct mbuf *ifm, struct mbuf *ifmhead) { ifm->ifs_next = ifmhead->ifs_next; ifmhead->ifs_next = ifm; @@ -25,9 +24,8 @@ ifm->ifs_next->ifs_prev = ifm; } -void -ifs_remque(ifm) - struct mbuf *ifm; +static void +ifs_remque(struct mbuf *ifm) { ifm->ifs_prev->ifs_next = ifm->ifs_next; ifm->ifs_next->ifs_prev = ifm->ifs_prev; @@ -291,7 +289,7 @@ } /* Encapsulate the packet for sending */ - if_encap(ifm->m_data, ifm->m_len); + if_encap((uint8_t *)ifm->m_data, ifm->m_len); m_free(ifm); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/slirp/ip_icmp.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/slirp/ip_icmp.c --- qemu-0.9.1/slirp/ip_icmp.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/slirp/ip_icmp.c 2008-10-01 20:06:48.000000000 +0100 @@ -43,7 +43,7 @@ /* The message sent when emulating PING */ /* Be nice and tell them it's just a pseudo-ping packet */ -const char icmp_ping_msg[] = "This is a pseudo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n"; +static const char icmp_ping_msg[] = "This is a pseudo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n"; /* list of actions for icmp_error() on RX of an icmp message */ static const int icmp_flush[19] = { @@ -207,12 +207,8 @@ #define ICMP_MAXDATALEN (IP_MSS-28) void -icmp_error(msrc, type, code, minsize, message) - struct mbuf *msrc; - u_char type; - u_char code; - int minsize; - char *message; +icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize, + const char *message) { unsigned hlen, shlen, s_ip_len; register struct ip *ip; @@ -228,7 +224,7 @@ /* check msrc */ if(!msrc) goto end_error; ip = mtod(msrc, struct ip *); -#if DEBUG +#ifdef DEBUG { char bufa[20], bufb[20]; strcpy(bufa, inet_ntoa(ip->ip_src)); strcpy(bufb, inet_ntoa(ip->ip_dst)); @@ -285,7 +281,7 @@ HTONS(icp->icmp_ip.ip_id); HTONS(icp->icmp_ip.ip_off); -#if DEBUG +#ifdef DEBUG if(message) { /* DEBUG : append message to ICMP packet */ int message_len; char *cpnt; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/slirp/ip_icmp.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/slirp/ip_icmp.h --- qemu-0.9.1/slirp/ip_icmp.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/slirp/ip_icmp.h 2008-09-14 07:45:34.000000000 +0100 @@ -158,7 +158,8 @@ (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) void icmp_input _P((struct mbuf *, int)); -void icmp_error _P((struct mbuf *, u_char, u_char, int, char *)); +void icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize, + const char *message); void icmp_reflect _P((struct mbuf *)); #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/slirp/mbuf.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/slirp/mbuf.c --- qemu-0.9.1/slirp/mbuf.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/slirp/mbuf.c 2008-10-01 19:08:41.000000000 +0100 @@ -17,8 +17,6 @@ #include -struct mbuf *mbutl; -char *mclrefcnt; int mbuf_alloced = 0; struct mbuf m_freelist, m_usedlist; #define MBUF_THRESH 30 @@ -28,7 +26,7 @@ * Find a nice value for msize * XXX if_maxlinkhdr already in mtu */ -#define MSIZE (IF_MTU + IF_MAXLINKHDR + sizeof(struct m_hdr ) + 6) +#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + sizeof(struct m_hdr ) + 6) void m_init() @@ -54,7 +52,7 @@ DEBUG_CALL("m_get"); if (m_freelist.m_next == &m_freelist) { - m = (struct mbuf *)malloc(MSIZE); + m = (struct mbuf *)malloc(SLIRP_MSIZE); if (m == NULL) goto end_error; mbuf_alloced++; if (mbuf_alloced > MBUF_THRESH) @@ -71,7 +69,7 @@ m->m_flags = (flags | M_USEDLIST); /* Initialise it */ - m->m_size = MSIZE - sizeof(struct m_hdr); + m->m_size = SLIRP_MSIZE - sizeof(struct m_hdr); m->m_data = m->m_dat; m->m_len = 0; m->m_nextpkt = 0; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/slirp/misc.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/slirp/misc.c --- qemu-0.9.1/slirp/misc.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/slirp/misc.c 2008-09-15 16:51:35.000000000 +0100 @@ -66,20 +66,6 @@ } #endif -#ifndef HAVE_INET_ATON -int -inet_aton(cp, ia) - const char *cp; - struct in_addr *ia; -{ - u_int32_t addr = inet_addr(cp); - if (addr == 0xffffffff) - return 0; - ia->s_addr = addr; - return 1; -} -#endif - /* * Get our IP address and put it in our_addr */ @@ -304,10 +290,10 @@ { int s; struct sockaddr_in addr; - int addrlen = sizeof(addr); + socklen_t addrlen = sizeof(addr); int opt; int master = -1; - char *argv[256]; + const char *argv[256]; #if 0 char buff[256]; #endif @@ -411,14 +397,15 @@ } while (c); argv[i] = 0; - execvp(argv[0], argv); + execvp(argv[0], (char **)argv); /* Ooops, failed, let's tell the user why */ { char buff[256]; - sprintf(buff, "Error: execvp of %s failed: %s\n", - argv[0], strerror(errno)); + snprintf(buff, sizeof(buff), + "Error: execvp of %s failed: %s\n", + argv[0], strerror(errno)); write(2, buff, strlen(buff)+1); } close(0); close(1); close(2); /* XXX */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/slirp/misc.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/slirp/misc.h --- qemu-0.9.1/slirp/misc.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/slirp/misc.h 2008-10-26 15:26:09.000000000 +0000 @@ -17,7 +17,7 @@ }; extern struct ex_list *exec_list; -extern u_int curtime, time_fasttimo, last_slowtimo; +extern u_int time_fasttimo, last_slowtimo; extern int (*lprint_print) _P((void *, const char *, va_list)); extern char *lprint_ptr, *lprint_ptr2, **lprint_arg; @@ -72,8 +72,8 @@ int show_x _P((char *, struct socket *)); void redir_x _P((u_int32_t, int, int, int)); void getouraddr _P((void)); -inline void slirp_insque _P((void *, void *)); -inline void slirp_remque _P((void *)); +void slirp_insque _P((void *, void *)); +void slirp_remque _P((void *)); int add_exec _P((struct ex_list **, int, char *, int, int)); int slirp_openpty _P((int *, int *)); int fork_exec(struct socket *so, const char *ex, int do_pty); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/slirp/slirp.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/slirp/slirp.c --- qemu-0.9.1/slirp/slirp.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/slirp/slirp.c 2008-10-17 18:31:57.000000000 +0100 @@ -1,3 +1,26 @@ +/* + * libslirp glue + * + * Copyright (c) 2004-2008 Fabrice Bellard + * + * 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 "slirp.h" /* host address */ @@ -16,7 +39,11 @@ 0x52, 0x54, 0x00, 0x12, 0x35, 0x00 }; +/* ARP cache for the guest IP addresses (XXX: allow many entries) */ uint8_t client_ethaddr[6]; +static struct in_addr client_ipaddr; + +static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 }; int do_slowtimo; int link_up; @@ -84,7 +111,7 @@ static int get_dns_addr(struct in_addr *pdns_addr) { char buff[512]; - char buff2[256]; + char buff2[257]; FILE *f; int found = 0; struct in_addr tmp_addr; @@ -554,7 +581,7 @@ unsigned char ar_tip[4]; /* target IP address */ }; -void arp_input(const uint8_t *pkt, int pkt_len) +static void arp_input(const uint8_t *pkt, int pkt_len) { struct ethhdr *eh = (struct ethhdr *)pkt; struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN); @@ -597,6 +624,13 @@ slirp_output(arp_reply, sizeof(arp_reply)); } break; + case ARPOP_REPLY: + /* reply to request of client mac address ? */ + if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN) && + !memcmp(ah->ar_sip, &client_ipaddr.s_addr, 4)) { + memcpy(client_ethaddr, ah->ar_sha, ETH_ALEN); + } + break; default: break; } @@ -641,14 +675,47 @@ if (ip_data_len + ETH_HLEN > sizeof(buf)) return; - - memcpy(eh->h_dest, client_ethaddr, ETH_ALEN); - memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1); - /* XXX: not correct */ - eh->h_source[5] = CTL_ALIAS; - eh->h_proto = htons(ETH_P_IP); - memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len); - slirp_output(buf, ip_data_len + ETH_HLEN); + + if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN)) { + uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)]; + struct ethhdr *reh = (struct ethhdr *)arp_req; + struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN); + const struct ip *iph = (const struct ip *)ip_data; + + /* If the client addr is not known, there is no point in + sending the packet to it. Normally the sender should have + done an ARP request to get its MAC address. Here we do it + in place of sending the packet and we hope that the sender + will retry sending its packet. */ + memset(reh->h_dest, 0xff, ETH_ALEN); + memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1); + reh->h_source[5] = CTL_ALIAS; + reh->h_proto = htons(ETH_P_ARP); + rah->ar_hrd = htons(1); + rah->ar_pro = htons(ETH_P_IP); + rah->ar_hln = ETH_ALEN; + rah->ar_pln = 4; + rah->ar_op = htons(ARPOP_REQUEST); + /* source hw addr */ + memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 1); + rah->ar_sha[5] = CTL_ALIAS; + /* source IP */ + memcpy(rah->ar_sip, &alias_addr, 4); + /* target hw addr (none) */ + memset(rah->ar_tha, 0, ETH_ALEN); + /* target IP */ + memcpy(rah->ar_tip, &iph->ip_dst, 4); + client_ipaddr = iph->ip_dst; + slirp_output(arp_req, sizeof(arp_req)); + } else { + memcpy(eh->h_dest, client_ethaddr, ETH_ALEN); + memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1); + /* XXX: not correct */ + eh->h_source[5] = CTL_ALIAS; + eh->h_proto = htons(ETH_P_IP); + memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len); + slirp_output(buf, ip_data_len + ETH_HLEN); + } } int slirp_redir(int is_udp, int host_port, diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/slirp/slirp_config.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/slirp/slirp_config.h --- qemu-0.9.1/slirp/slirp_config.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/slirp/slirp_config.h 2008-08-30 10:51:20.000000000 +0100 @@ -128,10 +128,10 @@ #undef HAVE_SYS_STROPTS_H /* Define to whatever your compiler thinks inline should be */ -#define inline inline +//#define inline inline /* Define to whatever your compiler thinks const should be */ -#define const const +//#define const const /* Define if your compiler doesn't like prototypes */ #undef NO_PROTOTYPES @@ -170,7 +170,7 @@ #undef HAVE_SETENV /* Define if you have index() */ -#undef HAVE_INDEX +#define HAVE_INDEX /* Define if you have bcmp() */ #undef HAVE_BCMP @@ -182,7 +182,7 @@ #define HAVE_MEMMOVE /* Define if you have gethostid */ -#undef HAVE_GETHOSTID +#define HAVE_GETHOSTID /* Define if you DON'T have unix-domain sockets */ #undef NO_UNIX_SOCKETS diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/slirp/slirp.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/slirp/slirp.h --- qemu-0.9.1/slirp/slirp.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/slirp/slirp.h 2008-10-26 15:26:09.000000000 +0000 @@ -32,6 +32,7 @@ #define WIN32_LEAN_AND_MEAN # include # include +# include # include # include @@ -102,7 +103,7 @@ # include # include #else -# if HAVE_SYS_TIME_H +# ifdef HAVE_SYS_TIME_H # include # else # include @@ -269,8 +270,8 @@ # define insque_32 insque # define remque_32 remque #else - inline void insque_32 _P((void *, void *)); - inline void remque_32 _P((void *)); + void insque_32 _P((void *, void *)); + void remque_32 _P((void *)); #endif #ifndef _WIN32 diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/slirp/socket.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/slirp/socket.c --- qemu-0.9.1/slirp/socket.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/slirp/socket.c 2008-10-01 20:39:40.000000000 +0100 @@ -8,7 +8,6 @@ #define WANT_SYS_IOCTL_H #include #include "ip_icmp.h" -#include "main.h" #ifdef __sun__ #include #endif @@ -117,6 +116,8 @@ len = sb->sb_datalen - sb->sb_cc; iov[0].iov_base = sb->sb_wptr; + iov[1].iov_base = NULL; + iov[1].iov_len = 0; if (sb->sb_wptr < sb->sb_rptr) { iov[0].iov_len = sb->sb_rptr - sb->sb_wptr; /* Should never succeed, but... */ @@ -320,6 +321,8 @@ len = sb->sb_cc; iov[0].iov_base = sb->sb_rptr; + iov[1].iov_base = NULL; + iov[1].iov_len = 0; if (sb->sb_rptr < sb->sb_wptr) { iov[0].iov_len = sb->sb_wptr - sb->sb_rptr; /* Should never succeed, but... */ @@ -392,7 +395,7 @@ struct socket *so; { struct sockaddr_in addr; - int addrlen = sizeof(struct sockaddr_in); + socklen_t addrlen = sizeof(struct sockaddr_in); DEBUG_CALL("sorecvfrom"); DEBUG_ARG("so = %lx", (long)so); @@ -545,7 +548,8 @@ { struct sockaddr_in addr; struct socket *so; - int s, addrlen = sizeof(addr), opt = 1; + int s, opt = 1; + socklen_t addrlen = sizeof(addr); DEBUG_CALL("solisten"); DEBUG_ARG("port = %d", port); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/slirp/tcp_subr.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/slirp/tcp_subr.c --- qemu-0.9.1/slirp/tcp_subr.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/slirp/tcp_subr.c 2008-09-20 09:07:15.000000000 +0100 @@ -447,7 +447,7 @@ { struct socket *so; struct sockaddr_in addr; - int addrlen = sizeof(struct sockaddr_in); + socklen_t addrlen = sizeof(struct sockaddr_in); struct tcpcb *tp; int s, opt; @@ -629,7 +629,7 @@ struct mbuf *m; { u_int n1, n2, n3, n4, n5, n6; - char buff[256]; + char buff[257]; u_int32_t laddr; u_int lport; char *bptr; @@ -649,7 +649,7 @@ { struct socket *tmpso; struct sockaddr_in addr; - int addrlen = sizeof(struct sockaddr_in); + socklen_t addrlen = sizeof(struct sockaddr_in); struct sbuf *so_rcv = &so->so_rcv; memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); @@ -673,7 +673,9 @@ } } } - so_rcv->sb_cc = sprintf(so_rcv->sb_data, "%d,%d\r\n", n1, n2); + so_rcv->sb_cc = snprintf(so_rcv->sb_data, + so_rcv->sb_datalen, + "%d,%d\r\n", n1, n2); so_rcv->sb_rptr = so_rcv->sb_data; so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc; } @@ -1007,8 +1009,9 @@ n4 = (laddr & 0xff); m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s", - n1, n2, n3, n4, n5, n6, x==7?buff:""); + m->m_len += snprintf(bptr, m->m_hdr.mh_size - m->m_len, + "ORT %d,%d,%d,%d,%d,%d\r\n%s", + n1, n2, n3, n4, n5, n6, x==7?buff:""); return 1; } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) { /* @@ -1038,8 +1041,9 @@ n4 = (laddr & 0xff); m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += sprintf(bptr,"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", - n1, n2, n3, n4, n5, n6, x==7?buff:""); + m->m_len += snprintf(bptr, m->m_hdr.mh_size - m->m_len, + "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", + n1, n2, n3, n4, n5, n6, x==7?buff:""); return 1; } @@ -1062,7 +1066,8 @@ } if (m->m_data[m->m_len-1] == '\0' && lport != 0 && (so = solisten(0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL) - m->m_len = sprintf(m->m_data, "%d", ntohs(so->so_fport))+1; + m->m_len = snprintf(m->m_data, m->m_hdr.mh_size, "%d", + ntohs(so->so_fport)) + 1; return 1; case EMU_IRC: @@ -1079,25 +1084,28 @@ return 1; m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += sprintf(bptr, "DCC CHAT chat %lu %u%c\n", - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), 1); + m->m_len += snprintf(bptr, m->m_hdr.mh_size, + "DCC CHAT chat %lu %u%c\n", + (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), 1); } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) return 1; m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n", - buff, (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), n1, 1); + m->m_len += snprintf(bptr, m->m_hdr.mh_size, + "DCC SEND %s %lu %u %u%c\n", buff, + (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), n1, 1); } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) return 1; m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += sprintf(bptr, "DCC MOVE %s %lu %u %u%c\n", - buff, (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), n1, 1); + m->m_len += snprintf(bptr, m->m_hdr.mh_size, + "DCC MOVE %s %lu %u %u%c\n", buff, + (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), n1, 1); } return 1; @@ -1285,8 +1293,8 @@ /* FALLTHROUGH */ case CTL_ALIAS: - sb->sb_cc = sprintf(sb->sb_wptr, - "Error: No application configured.\r\n"); + sb->sb_cc = snprintf(sb->sb_wptr, sb->sb_datalen - (sb->sb_wptr - sb->sb_data), + "Error: No application configured.\r\n"); sb->sb_wptr += sb->sb_cc; return(0); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/slirp/tftp.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/slirp/tftp.c --- qemu-0.9.1/slirp/tftp.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/slirp/tftp.c 2008-09-20 09:07:15.000000000 +0100 @@ -23,6 +23,7 @@ */ #include +#include "qemu-common.h" // for pstrcpy struct tftp_session { int in_use; @@ -148,8 +149,10 @@ m->m_data += sizeof(struct udpiphdr); tp->tp_op = htons(TFTP_OACK); - n += sprintf(tp->x.tp_buf + n, "%s", key) + 1; - n += sprintf(tp->x.tp_buf + n, "%u", value) + 1; + n += snprintf((char *)tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s", + key) + 1; + n += snprintf((char *)tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u", + value) + 1; saddr.sin_addr = recv_tp->ip.ip_dst; saddr.sin_port = recv_tp->udp.uh_dport; @@ -189,7 +192,7 @@ tp->tp_op = htons(TFTP_ERROR); tp->x.tp_error.tp_error_code = htons(errorcode); - strcpy(tp->x.tp_error.tp_msg, msg); + pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg); saddr.sin_addr = recv_tp->ip.ip_dst; saddr.sin_port = recv_tp->udp.uh_dport; @@ -324,8 +327,8 @@ /* do sanity checks on the filename */ if ((spt->filename[0] != '/') - || (spt->filename[strlen(spt->filename) - 1] == '/') - || strstr(spt->filename, "/../")) { + || (spt->filename[strlen((char *)spt->filename) - 1] == '/') + || strstr((char *)spt->filename, "/../")) { tftp_send_error(spt, 2, "Access violation", tp); return; } @@ -352,7 +355,7 @@ while (k < n) { const char *key, *value; - key = src + k; + key = (char *)src + k; k += strlen(key) + 1; if (k >= n) { @@ -360,7 +363,7 @@ return; } - value = src + k; + value = (char *)src + k; k += strlen(value) + 1; if (strcmp(key, "tsize") == 0) { diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/slirp/udp.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/slirp/udp.c --- qemu-0.9.1/slirp/udp.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/slirp/udp.c 2008-10-25 12:21:28.000000000 +0100 @@ -319,9 +319,11 @@ saddr = *addr; if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { - saddr.sin_addr.s_addr = so->so_faddr.s_addr; if ((so->so_faddr.s_addr & htonl(0x000000ff)) == htonl(0xff)) saddr.sin_addr.s_addr = alias_addr.s_addr; + else if (addr->sin_addr.s_addr == loopback_addr.s_addr || + (ntohl(so->so_faddr.s_addr) & 0xff) != CTL_ALIAS) + saddr.sin_addr.s_addr = so->so_faddr.s_addr; } daddr.sin_addr = so->so_laddr; daddr.sin_port = so->so_lport; @@ -408,7 +410,7 @@ udp_emu(struct socket *so, struct mbuf *m) { struct sockaddr_in addr; - int addrlen = sizeof(addr); + socklen_t addrlen = sizeof(addr); #ifdef EMULATE_TALK CTL_MSG_OLD *omsg; CTL_MSG *nmsg; @@ -473,14 +475,14 @@ type = omsg->type; OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port; OTOSIN(omsg, ctl_addr)->sin_addr = our_addr; - strncpy(omsg->l_name, getlogin(), NAME_SIZE_OLD); + pstrcpy(omsg->l_name, NAME_SIZE_OLD, getlogin()); } else { /* new talk */ omsg = (CTL_MSG_OLD *) buff; nmsg = mtod(m, CTL_MSG *); type = nmsg->type; OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port; OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr; - strncpy(nmsg->l_name, getlogin(), NAME_SIZE_OLD); + pstrcpy(nmsg->l_name, NAME_SIZE_OLD, getlogin()); } if (type == LOOK_UP) @@ -639,7 +641,7 @@ { struct sockaddr_in addr; struct socket *so; - int addrlen = sizeof(struct sockaddr_in), opt = 1; + socklen_t addrlen = sizeof(struct sockaddr_in), opt = 1; if ((so = socreate()) == NULL) { free(so); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/softmmu_defs.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/softmmu_defs.h --- qemu-0.9.1/softmmu_defs.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/softmmu_defs.h 2008-08-30 10:51:20.000000000 +0100 @@ -0,0 +1,22 @@ +#ifndef SOFTMMU_DEFS_H +#define SOFTMMU_DEFS_H + +uint8_t REGPARM __ldb_mmu(target_ulong addr, int mmu_idx); +void REGPARM __stb_mmu(target_ulong addr, uint8_t val, int mmu_idx); +uint16_t REGPARM __ldw_mmu(target_ulong addr, int mmu_idx); +void REGPARM __stw_mmu(target_ulong addr, uint16_t val, int mmu_idx); +uint32_t REGPARM __ldl_mmu(target_ulong addr, int mmu_idx); +void REGPARM __stl_mmu(target_ulong addr, uint32_t val, int mmu_idx); +uint64_t REGPARM __ldq_mmu(target_ulong addr, int mmu_idx); +void REGPARM __stq_mmu(target_ulong addr, uint64_t val, int mmu_idx); + +uint8_t REGPARM __ldb_cmmu(target_ulong addr, int mmu_idx); +void REGPARM __stb_cmmu(target_ulong addr, uint8_t val, int mmu_idx); +uint16_t REGPARM __ldw_cmmu(target_ulong addr, int mmu_idx); +void REGPARM __stw_cmmu(target_ulong addr, uint16_t val, int mmu_idx); +uint32_t REGPARM __ldl_cmmu(target_ulong addr, int mmu_idx); +void REGPARM __stl_cmmu(target_ulong addr, uint32_t val, int mmu_idx); +uint64_t REGPARM __ldq_cmmu(target_ulong addr, int mmu_idx); +void REGPARM __stq_cmmu(target_ulong addr, uint64_t val, int mmu_idx); + +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/softmmu_exec.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/softmmu_exec.h --- qemu-0.9.1/softmmu_exec.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/softmmu_exec.h 2008-08-30 10:51:20.000000000 +0100 @@ -9,6 +9,8 @@ #define ldul_executive ldl_executive #define ldul_supervisor ldl_supervisor +#include "softmmu_defs.h" + #define ACCESS_TYPE 0 #define MEMSUFFIX MMU_MODE0_SUFFIX #define DATA_SIZE 1 diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/softmmu_header.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/softmmu_header.h --- qemu-0.9.1/softmmu_header.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/softmmu_header.h 2008-08-30 10:51:20.000000000 +0100 @@ -70,15 +70,9 @@ #define ADDR_READ addr_read #endif -DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, - int mmu_idx); -void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE v, int mmu_idx); - #if (DATA_SIZE <= 4) && (TARGET_LONG_BITS == 32) && defined(__i386__) && \ (ACCESS_TYPE < NB_MMU_MODES) && defined(ASM_SOFTMMU) -#define CPU_TLB_ENTRY_BITS 4 - static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) { int res; @@ -92,9 +86,8 @@ "cmpl (%%edx), %%eax\n" "movl %1, %%eax\n" "je 1f\n" - "pushl %6\n" + "movl %6, %%edx\n" "call %7\n" - "popl %%edx\n" "movl %%eax, %0\n" "jmp 2f\n" "1:\n" @@ -135,9 +128,8 @@ "cmpl (%%edx), %%eax\n" "movl %1, %%eax\n" "je 1f\n" - "pushl %6\n" + "movl %6, %%edx\n" "call %7\n" - "popl %%edx\n" #if DATA_SIZE == 1 "movsbl %%al, %0\n" #elif DATA_SIZE == 2 @@ -189,9 +181,8 @@ #else #error unsupported size #endif - "pushl %6\n" + "movl %6, %%ecx\n" "call %7\n" - "popl %%eax\n" "jmp 2f\n" "1:\n" "addl 8(%%edx), %%eax\n" @@ -207,9 +198,11 @@ "2:\n" : : "r" (ptr), -/* NOTE: 'q' would be needed as constraint, but we could not use it - with T1 ! */ +#if DATA_SIZE == 1 + "q" (v), +#else "r" (v), +#endif "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), @@ -225,20 +218,20 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) { - int index; + int page_index; RES_TYPE res; target_ulong addr; unsigned long physaddr; int mmu_idx; addr = ptr; - index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); mmu_idx = CPU_MMU_INDEX; - if (__builtin_expect(env->tlb_table[mmu_idx][index].ADDR_READ != - (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) { + if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ != + (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx); } else { - physaddr = addr + env->tlb_table[mmu_idx][index].addend; + physaddr = addr + env->tlb_table[mmu_idx][page_index].addend; res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr); } return res; @@ -247,19 +240,19 @@ #if DATA_SIZE <= 2 static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) { - int res, index; + int res, page_index; target_ulong addr; unsigned long physaddr; int mmu_idx; addr = ptr; - index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); mmu_idx = CPU_MMU_INDEX; - if (__builtin_expect(env->tlb_table[mmu_idx][index].ADDR_READ != - (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) { + if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ != + (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx); } else { - physaddr = addr + env->tlb_table[mmu_idx][index].addend; + physaddr = addr + env->tlb_table[mmu_idx][page_index].addend; res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr); } return res; @@ -272,19 +265,19 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v) { - int index; + int page_index; target_ulong addr; unsigned long physaddr; int mmu_idx; addr = ptr; - index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); mmu_idx = CPU_MMU_INDEX; - if (__builtin_expect(env->tlb_table[mmu_idx][index].addr_write != - (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) { + if (unlikely(env->tlb_table[mmu_idx][page_index].addr_write != + (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, mmu_idx); } else { - physaddr = addr + env->tlb_table[mmu_idx][index].addend; + physaddr = addr + env->tlb_table[mmu_idx][page_index].addend; glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v); } } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/softmmu-semi.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/softmmu-semi.h --- qemu-0.9.1/softmmu-semi.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/softmmu-semi.h 2008-09-20 09:07:15.000000000 +0100 @@ -37,7 +37,7 @@ static void *softmmu_lock_user(CPUState *env, uint32_t addr, uint32_t len, int copy) { - char *p; + uint8_t *p; /* TODO: Make this something that isn't fixed size. */ p = malloc(len); if (copy) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/softmmu_template.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/softmmu_template.h --- qemu-0.9.1/softmmu_template.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/softmmu_template.h 2008-06-29 02:03:05.000000000 +0100 @@ -51,12 +51,19 @@ int mmu_idx, void *retaddr); static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, - target_ulong tlb_addr) + target_ulong addr, + void *retaddr) { DATA_TYPE res; int index; + index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + physaddr = (physaddr & TARGET_PAGE_MASK) + addr; + env->mem_io_pc = (unsigned long)retaddr; + if (index > (IO_MEM_NOTDIRTY >> IO_MEM_SHIFT) + && !can_do_io(env)) { + cpu_io_recompile(env, retaddr); + } - index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); #if SHIFT <= 2 res = io_mem_read[index][SHIFT](io_mem_opaque[index], physaddr); #else @@ -75,13 +82,13 @@ } /* handle all cases except unaligned access which span two pages */ -DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, - int mmu_idx) +DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, + int mmu_idx) { DATA_TYPE res; int index; target_ulong tlb_addr; - target_phys_addr_t physaddr; + target_phys_addr_t addend; void *retaddr; /* test if there is match for unaligned or IO access */ @@ -90,12 +97,13 @@ redo: tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = addr + env->tlb_table[mmu_idx][index].addend; if (tlb_addr & ~TARGET_PAGE_MASK) { /* IO access */ if ((addr & (DATA_SIZE - 1)) != 0) goto do_unaligned_access; - res = glue(io_read, SUFFIX)(physaddr, tlb_addr); + retaddr = GETPC(); + addend = env->iotlb[mmu_idx][index]; + res = glue(io_read, SUFFIX)(addend, addr, retaddr); } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { /* slow unaligned access (it spans two pages or IO) */ do_unaligned_access: @@ -113,7 +121,8 @@ do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); } #endif - res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)physaddr); + addend = env->tlb_table[mmu_idx][index].addend; + res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend)); } } else { /* the page is not in the TLB : fill it */ @@ -135,19 +144,20 @@ { DATA_TYPE res, res1, res2; int index, shift; - target_phys_addr_t physaddr; + target_phys_addr_t addend; target_ulong tlb_addr, addr1, addr2; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = addr + env->tlb_table[mmu_idx][index].addend; if (tlb_addr & ~TARGET_PAGE_MASK) { /* IO access */ if ((addr & (DATA_SIZE - 1)) != 0) goto do_unaligned_access; - res = glue(io_read, SUFFIX)(physaddr, tlb_addr); + retaddr = GETPC(); + addend = env->iotlb[mmu_idx][index]; + res = glue(io_read, SUFFIX)(addend, addr, retaddr); } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { do_unaligned_access: /* slow unaligned access (it spans two pages) */ @@ -166,7 +176,8 @@ res = (DATA_TYPE)res; } else { /* unaligned/aligned access in the same page */ - res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)physaddr); + addend = env->tlb_table[mmu_idx][index].addend; + res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend)); } } else { /* the page is not in the TLB : fill it */ @@ -185,14 +196,19 @@ static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, DATA_TYPE val, - target_ulong tlb_addr, + target_ulong addr, void *retaddr) { int index; + index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + physaddr = (physaddr & TARGET_PAGE_MASK) + addr; + if (index > (IO_MEM_NOTDIRTY >> IO_MEM_SHIFT) + && !can_do_io(env)) { + cpu_io_recompile(env, retaddr); + } - index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); - env->mem_write_vaddr = tlb_addr; - env->mem_write_pc = (unsigned long)retaddr; + env->mem_io_vaddr = addr; + env->mem_io_pc = (unsigned long)retaddr; #if SHIFT <= 2 io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val); #else @@ -209,11 +225,11 @@ #endif } -void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, - DATA_TYPE val, - int mmu_idx) +void REGPARM glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, + DATA_TYPE val, + int mmu_idx) { - target_phys_addr_t physaddr; + target_phys_addr_t addend; target_ulong tlb_addr; void *retaddr; int index; @@ -222,13 +238,13 @@ redo: tlb_addr = env->tlb_table[mmu_idx][index].addr_write; if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = addr + env->tlb_table[mmu_idx][index].addend; if (tlb_addr & ~TARGET_PAGE_MASK) { /* IO access */ if ((addr & (DATA_SIZE - 1)) != 0) goto do_unaligned_access; retaddr = GETPC(); - glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr); + addend = env->iotlb[mmu_idx][index]; + glue(io_write, SUFFIX)(addend, val, addr, retaddr); } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { do_unaligned_access: retaddr = GETPC(); @@ -245,7 +261,8 @@ do_unaligned_access(addr, 1, mmu_idx, retaddr); } #endif - glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)physaddr, val); + addend = env->tlb_table[mmu_idx][index].addend; + glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val); } } else { /* the page is not in the TLB : fill it */ @@ -265,7 +282,7 @@ int mmu_idx, void *retaddr) { - target_phys_addr_t physaddr; + target_phys_addr_t addend; target_ulong tlb_addr; int index, i; @@ -273,12 +290,12 @@ redo: tlb_addr = env->tlb_table[mmu_idx][index].addr_write; if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = addr + env->tlb_table[mmu_idx][index].addend; if (tlb_addr & ~TARGET_PAGE_MASK) { /* IO access */ if ((addr & (DATA_SIZE - 1)) != 0) goto do_unaligned_access; - glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr); + addend = env->iotlb[mmu_idx][index]; + glue(io_write, SUFFIX)(addend, val, addr, retaddr); } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { do_unaligned_access: /* XXX: not efficient, but simple */ @@ -295,7 +312,8 @@ } } else { /* aligned/unaligned access in the same page */ - glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)physaddr, val); + addend = env->tlb_table[mmu_idx][index].addend; + glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val); } } else { /* the page is not in the TLB : fill it */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/sparc64.ld /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/sparc64.ld --- qemu-0.9.1/sparc64.ld 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/sparc64.ld 2008-07-26 16:05:57.000000000 +0100 @@ -69,6 +69,7 @@ . = ALIGN(0x100000) + (. & (0x100000 - 1)); .data : { + *(.gen_code) *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/sparc-dis.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/sparc-dis.c --- qemu-0.9.1/sparc-dis.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/sparc-dis.c 2008-10-26 19:13:20.000000000 +0000 @@ -1,20 +1,32 @@ -/* Print SPARC instructions. - Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2002 Free Software Foundation, Inc. +/* + * These files from binutils are concatenated: + * include/opcode/sparc.h, opcodes/sparc-opc.c, opcodes/sparc-dis.c + */ + +/* include/opcode/sparc.h */ + +/* Definitions for opcode table for the sparc. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000, 2002, + 2003, 2005 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler, GDB, the GNU debugger, and + the GNU Binutils. + + GAS/GDB is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS/GDB 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS or GDB; see the file COPYING. If not, write to + the Free Software Foundation, 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. */ -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "dis-asm.h" @@ -33,17 +45,18 @@ The values are indices into `sparc_opcode_archs' defined in sparc-opc.c. Don't change this without updating sparc-opc.c. */ -enum sparc_opcode_arch_val { +enum sparc_opcode_arch_val +{ SPARC_OPCODE_ARCH_V6 = 0, SPARC_OPCODE_ARCH_V7, SPARC_OPCODE_ARCH_V8, SPARC_OPCODE_ARCH_SPARCLET, SPARC_OPCODE_ARCH_SPARCLITE, - /* v9 variants must appear last */ + /* V9 variants must appear last. */ SPARC_OPCODE_ARCH_V9, - SPARC_OPCODE_ARCH_V9A, /* v9 with ultrasparc additions */ - SPARC_OPCODE_ARCH_V9B, /* v9 with ultrasparc and cheetah additions */ - SPARC_OPCODE_ARCH_BAD /* error return from sparc_opcode_lookup_arch */ + SPARC_OPCODE_ARCH_V9A, /* V9 with ultrasparc additions. */ + SPARC_OPCODE_ARCH_V9B, /* V9 with ultrasparc and cheetah additions. */ + SPARC_OPCODE_ARCH_BAD /* Error return from sparc_opcode_lookup_arch. */ }; /* The highest architecture in the table. */ @@ -58,20 +71,17 @@ /* Table of cpu variants. */ -struct sparc_opcode_arch { +typedef struct sparc_opcode_arch +{ const char *name; /* Mask of sparc_opcode_arch_val's supported. EG: For v7 this would be (SPARC_OPCODE_ARCH_MASK (..._V6) | SPARC_OPCODE_ARCH_MASK (..._V7)). These are short's because sparc_opcode.architecture is. */ short supported; -}; - -extern const struct sparc_opcode_arch sparc_opcode_archs[]; +} sparc_opcode_arch; -/* Given architecture name, look up it's sparc_opcode_arch_val value. */ -extern enum sparc_opcode_arch_val sparc_opcode_lookup_arch - PARAMS ((const char *)); +static const struct sparc_opcode_arch sparc_opcode_archs[]; /* Return the bitmask of supported architectures for ARCH. */ #define SPARC_OPCODE_SUPPORTED(ARCH) (sparc_opcode_archs[ARCH].supported) @@ -79,44 +89,43 @@ /* Non-zero if ARCH1 conflicts with ARCH2. IE: ARCH1 as a supported bit set that ARCH2 doesn't, and vice versa. */ #define SPARC_OPCODE_CONFLICT_P(ARCH1, ARCH2) \ -(((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \ - != SPARC_OPCODE_SUPPORTED (ARCH1)) \ - && ((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \ + (((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \ + != SPARC_OPCODE_SUPPORTED (ARCH1)) \ + && ((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \ != SPARC_OPCODE_SUPPORTED (ARCH2))) /* Structure of an opcode table entry. */ -struct sparc_opcode { +typedef struct sparc_opcode +{ const char *name; - unsigned long match; /* Bits that must be set. */ - unsigned long lose; /* Bits that must not be set. */ + unsigned long match; /* Bits that must be set. */ + unsigned long lose; /* Bits that must not be set. */ const char *args; - /* This was called "delayed" in versions before the flags. */ + /* This was called "delayed" in versions before the flags. */ char flags; short architecture; /* Bitmask of sparc_opcode_arch_val's. */ -}; +} sparc_opcode; -#define F_DELAYED 1 /* Delayed branch */ -#define F_ALIAS 2 /* Alias for a "real" instruction */ -#define F_UNBR 4 /* Unconditional branch */ -#define F_CONDBR 8 /* Conditional branch */ -#define F_JSR 16 /* Subroutine call */ -#define F_FLOAT 32 /* Floating point instruction (not a branch) */ -#define F_FBR 64 /* Floating point branch */ +#define F_DELAYED 1 /* Delayed branch. */ +#define F_ALIAS 2 /* Alias for a "real" instruction. */ +#define F_UNBR 4 /* Unconditional branch. */ +#define F_CONDBR 8 /* Conditional branch. */ +#define F_JSR 16 /* Subroutine call. */ +#define F_FLOAT 32 /* Floating point instruction (not a branch). */ +#define F_FBR 64 /* Floating point branch. */ /* FIXME: Add F_ANACHRONISTIC flag for v9. */ -/* - -All sparc opcodes are 32 bits, except for the `set' instruction (really a -macro), which is 64 bits. It is handled as a special case. +/* All sparc opcodes are 32 bits, except for the `set' instruction (really a + macro), which is 64 bits. It is handled as a special case. -The match component is a mask saying which bits must match a particular -opcode in order for an instruction to be an instance of that opcode. + The match component is a mask saying which bits must match a particular + opcode in order for an instruction to be an instance of that opcode. -The args component is a string containing one character for each operand of the -instruction. + The args component is a string containing one character for each operand of the + instruction. -Kinds of operands: + Kinds of operands: # Number used by optimizer. It is ignored. 1 rs1 register. 2 rs2 register. @@ -184,49 +193,77 @@ _ Ancillary state register in rd (v9a) / Ancillary state register in rs1 (v9a) -The following chars are unused: (note: ,[] are used as punctuation) -[45] + The following chars are unused: (note: ,[] are used as punctuation) + [45]. */ + +#define OP2(x) (((x) & 0x7) << 22) /* Op2 field of format2 insns. */ +#define OP3(x) (((x) & 0x3f) << 19) /* Op3 field of format3 insns. */ +#define OP(x) ((unsigned) ((x) & 0x3) << 30) /* Op field of all insns. */ +#define OPF(x) (((x) & 0x1ff) << 5) /* Opf field of float insns. */ +#define OPF_LOW5(x) OPF ((x) & 0x1f) /* V9. */ +#define F3F(x, y, z) (OP (x) | OP3 (y) | OPF (z)) /* Format3 float insns. */ +#define F3I(x) (((x) & 0x1) << 13) /* Immediate field of format 3 insns. */ +#define F2(x, y) (OP (x) | OP2(y)) /* Format 2 insns. */ +#define F3(x, y, z) (OP (x) | OP3(y) | F3I(z)) /* Format3 insns. */ +#define F1(x) (OP (x)) +#define DISP30(x) ((x) & 0x3fffffff) +#define ASI(x) (((x) & 0xff) << 5) /* Asi field of format3 insns. */ +#define RS2(x) ((x) & 0x1f) /* Rs2 field. */ +#define SIMM13(x) ((x) & 0x1fff) /* Simm13 field. */ +#define RD(x) (((x) & 0x1f) << 25) /* Destination register field. */ +#define RS1(x) (((x) & 0x1f) << 14) /* Rs1 field. */ +#define ASI_RS2(x) (SIMM13 (x)) +#define MEMBAR(x) ((x) & 0x7f) +#define SLCPOP(x) (((x) & 0x7f) << 6) /* Sparclet cpop. */ + +#define ANNUL (1 << 29) +#define BPRED (1 << 19) /* V9. */ +#define IMMED F3I (1) +#define RD_G0 RD (~0) +#define RS1_G0 RS1 (~0) +#define RS2_G0 RS2 (~0) + +static const struct sparc_opcode sparc_opcodes[]; +static const int sparc_num_opcodes; + +static const char *sparc_decode_asi_v8 (int); +static const char *sparc_decode_asi_v9 (int); +static const char *sparc_decode_membar (int); +static const char *sparc_decode_prefetch (int); +static const char *sparc_decode_sparclet_cpreg (int); + +/* Local Variables: + fill-column: 131 + comment-column: 0 + End: */ + +/* opcodes/sparc-opc.c */ + +/* Table of opcodes for the sparc. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2002, 2004, 2005 + Free Software Foundation, Inc. -*/ + This file is part of the BFD library. -#define OP2(x) (((x)&0x7) << 22) /* op2 field of format2 insns */ -#define OP3(x) (((x)&0x3f) << 19) /* op3 field of format3 insns */ -#define OP(x) ((unsigned)((x)&0x3) << 30) /* op field of all insns */ -#define OPF(x) (((x)&0x1ff) << 5) /* opf field of float insns */ -#define OPF_LOW5(x) OPF((x)&0x1f) /* v9 */ -#define F3F(x, y, z) (OP(x) | OP3(y) | OPF(z)) /* format3 float insns */ -#define F3I(x) (((x)&0x1) << 13) /* immediate field of format 3 insns */ -#define F2(x, y) (OP(x) | OP2(y)) /* format 2 insns */ -#define F3(x, y, z) (OP(x) | OP3(y) | F3I(z)) /* format3 insns */ -#define F1(x) (OP(x)) -#define DISP30(x) ((x)&0x3fffffff) -#define ASI(x) (((x)&0xff) << 5) /* asi field of format3 insns */ -#define RS2(x) ((x)&0x1f) /* rs2 field */ -#define SIMM13(x) ((x)&0x1fff) /* simm13 field */ -#define RD(x) (((x)&0x1f) << 25) /* destination register field */ -#define RS1(x) (((x)&0x1f) << 14) /* rs1 field */ -#define ASI_RS2(x) (SIMM13(x)) -#define MEMBAR(x) ((x)&0x7f) -#define SLCPOP(x) (((x)&0x7f) << 6) /* sparclet cpop */ - -#define ANNUL (1<<29) -#define BPRED (1<<19) /* v9 */ -#define IMMED F3I(1) -#define RD_G0 RD(~0) -#define RS1_G0 RS1(~0) -#define RS2_G0 RS2(~0) - -extern const struct sparc_opcode sparc_opcodes[]; -extern const int sparc_num_opcodes; - -extern int sparc_encode_asi PARAMS ((const char *)); -extern const char *sparc_decode_asi PARAMS ((int)); -extern int sparc_encode_membar PARAMS ((const char *)); -extern const char *sparc_decode_membar PARAMS ((int)); -extern int sparc_encode_prefetch PARAMS ((const char *)); -extern const char *sparc_decode_prefetch PARAMS ((int)); -extern int sparc_encode_sparclet_cpreg PARAMS ((const char *)); -extern const char *sparc_decode_sparclet_cpreg PARAMS ((int)); + BFD is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2, or (at your option) any later + version. + + BFD 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 General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with this software; see the file COPYING. If not, write to + the Free Software Foundation, 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* FIXME-someday: perhaps the ,a's and such should be embedded in the + instruction's name rather than the args. This would make gas faster, pinsn + slower, but would mess up some macros a bit. xoxorich. */ /* Some defines to make life easy. */ #define MASK_V6 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V6) @@ -242,7 +279,7 @@ #define v6 (MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET \ | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B) -/* v6 insns not supported on the sparclet */ +/* v6 insns not supported on the sparclet. */ #define v6notlet (MASK_V6 | MASK_V7 | MASK_V8 \ | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B) #define v7 (MASK_V7 | MASK_V8 | MASK_SPARCLET \ @@ -260,17 +297,18 @@ #define v9 (MASK_V9 | MASK_V9A | MASK_V9B) #define v9a (MASK_V9A | MASK_V9B) #define v9b (MASK_V9B) -/* v6 insns not supported by v9 */ +/* v6 insns not supported by v9. */ #define v6notv9 (MASK_V6 | MASK_V7 | MASK_V8 \ | MASK_SPARCLET | MASK_SPARCLITE) /* v9a instructions which would appear to be aliases to v9's impdep's - otherwise */ + otherwise. */ #define v9notv9a (MASK_V9) /* Table of opcode architectures. The order is defined in opcode/sparc.h. */ -const struct sparc_opcode_arch sparc_opcode_archs[] = { +static const struct sparc_opcode_arch sparc_opcode_archs[] = +{ { "v6", MASK_V6 }, { "v7", MASK_V6 | MASK_V7 }, { "v8", MASK_V6 | MASK_V7 | MASK_V8 }, @@ -285,87 +323,68 @@ { NULL, 0 } }; -/* Given NAME, return it's architecture entry. */ - -enum sparc_opcode_arch_val -sparc_opcode_lookup_arch (name) - const char *name; -{ - const struct sparc_opcode_arch *p; - - for (p = &sparc_opcode_archs[0]; p->name; ++p) - { - if (strcmp (name, p->name) == 0) - return (enum sparc_opcode_arch_val) (p - &sparc_opcode_archs[0]); - } - - return SPARC_OPCODE_ARCH_BAD; -} - /* Branch condition field. */ -#define COND(x) (((x)&0xf)<<25) +#define COND(x) (((x) & 0xf) << 25) /* v9: Move (MOVcc and FMOVcc) condition field. */ -#define MCOND(x,i_or_f) ((((i_or_f)&1)<<18)|(((x)>>11)&(0xf<<14))) /* v9 */ +#define MCOND(x,i_or_f) ((((i_or_f) & 1) << 18) | (((x) >> 11) & (0xf << 14))) /* v9 */ /* v9: Move register (MOVRcc and FMOVRcc) condition field. */ -#define RCOND(x) (((x)&0x7)<<10) /* v9 */ +#define RCOND(x) (((x) & 0x7) << 10) /* v9 */ -#define CONDA (COND(0x8)) -#define CONDCC (COND(0xd)) -#define CONDCS (COND(0x5)) -#define CONDE (COND(0x1)) -#define CONDG (COND(0xa)) -#define CONDGE (COND(0xb)) -#define CONDGU (COND(0xc)) -#define CONDL (COND(0x3)) -#define CONDLE (COND(0x2)) -#define CONDLEU (COND(0x4)) -#define CONDN (COND(0x0)) -#define CONDNE (COND(0x9)) -#define CONDNEG (COND(0x6)) -#define CONDPOS (COND(0xe)) -#define CONDVC (COND(0xf)) -#define CONDVS (COND(0x7)) +#define CONDA (COND (0x8)) +#define CONDCC (COND (0xd)) +#define CONDCS (COND (0x5)) +#define CONDE (COND (0x1)) +#define CONDG (COND (0xa)) +#define CONDGE (COND (0xb)) +#define CONDGU (COND (0xc)) +#define CONDL (COND (0x3)) +#define CONDLE (COND (0x2)) +#define CONDLEU (COND (0x4)) +#define CONDN (COND (0x0)) +#define CONDNE (COND (0x9)) +#define CONDNEG (COND (0x6)) +#define CONDPOS (COND (0xe)) +#define CONDVC (COND (0xf)) +#define CONDVS (COND (0x7)) #define CONDNZ CONDNE #define CONDZ CONDE #define CONDGEU CONDCC #define CONDLU CONDCS -#define FCONDA (COND(0x8)) -#define FCONDE (COND(0x9)) -#define FCONDG (COND(0x6)) -#define FCONDGE (COND(0xb)) -#define FCONDL (COND(0x4)) -#define FCONDLE (COND(0xd)) -#define FCONDLG (COND(0x2)) -#define FCONDN (COND(0x0)) -#define FCONDNE (COND(0x1)) -#define FCONDO (COND(0xf)) -#define FCONDU (COND(0x7)) -#define FCONDUE (COND(0xa)) -#define FCONDUG (COND(0x5)) -#define FCONDUGE (COND(0xc)) -#define FCONDUL (COND(0x3)) -#define FCONDULE (COND(0xe)) +#define FCONDA (COND (0x8)) +#define FCONDE (COND (0x9)) +#define FCONDG (COND (0x6)) +#define FCONDGE (COND (0xb)) +#define FCONDL (COND (0x4)) +#define FCONDLE (COND (0xd)) +#define FCONDLG (COND (0x2)) +#define FCONDN (COND (0x0)) +#define FCONDNE (COND (0x1)) +#define FCONDO (COND (0xf)) +#define FCONDU (COND (0x7)) +#define FCONDUE (COND (0xa)) +#define FCONDUG (COND (0x5)) +#define FCONDUGE (COND (0xc)) +#define FCONDUL (COND (0x3)) +#define FCONDULE (COND (0xe)) #define FCONDNZ FCONDNE #define FCONDZ FCONDE -#define ICC (0) /* v9 */ -#define XCC (1<<12) /* v9 */ -#define FCC(x) (((x)&0x3)<<11) /* v9 */ -#define FBFCC(x) (((x)&0x3)<<20) /* v9 */ +#define ICC (0) /* v9 */ +#define XCC (1 << 12) /* v9 */ +#define FCC(x) (((x) & 0x3) << 11) /* v9 */ +#define FBFCC(x) (((x) & 0x3) << 20) /* v9 */ /* The order of the opcodes in the table is significant: * The assembler requires that all instances of the same mnemonic must be consecutive. If they aren't, the assembler will bomb at runtime. - * The disassembler should not care about the order of the opcodes. - -*/ + * The disassembler should not care about the order of the opcodes. */ /* Entries for commutative arithmetic operations. */ /* ??? More entries can make use of this. */ @@ -374,7 +393,7 @@ { opcode, F3(2, op3, 1), F3(~2, ~op3, ~1), "1,i,d", 0, arch_mask }, \ { opcode, F3(2, op3, 1), F3(~2, ~op3, ~1), "i,1,d", 0, arch_mask } -const struct sparc_opcode sparc_opcodes[] = { +static const struct sparc_opcode sparc_opcodes[] = { { "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0), "[1+2],d", 0, v6 }, { "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0)|RS2_G0, "[1],d", 0, v6 }, /* ld [rs1+%g0],d */ @@ -896,6 +915,10 @@ { "retry", F3(2, 0x3e, 0)|RD(1), F3(~2, ~0x3e, ~0)|RD(~1)|RS1_G0|SIMM13(~0), "", 0, v9 }, { "saved", F3(2, 0x31, 0)|RD(0), F3(~2, ~0x31, ~0)|RD(~0)|RS1_G0|SIMM13(~0), "", 0, v9 }, { "restored", F3(2, 0x31, 0)|RD(1), F3(~2, ~0x31, ~0)|RD(~1)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "allclean", F3(2, 0x31, 0)|RD(2), F3(~2, ~0x31, ~0)|RD(~2)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "otherw", F3(2, 0x31, 0)|RD(3), F3(~2, ~0x31, ~0)|RD(~3)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "normalw", F3(2, 0x31, 0)|RD(4), F3(~2, ~0x31, ~0)|RD(~4)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "invalw", F3(2, 0x31, 0)|RD(5), F3(~2, ~0x31, ~0)|RD(~5)|RS1_G0|SIMM13(~0), "", 0, v9 }, { "sir", F3(2, 0x30, 1)|RD(0xf), F3(~2, ~0x30, ~1)|RD(~0xf)|RS1_G0, "i", 0, v9 }, { "flush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI(~0), "1+2", 0, v8 }, @@ -1082,6 +1105,13 @@ { "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1), "i,1,!", F_ALIAS, v9 }, /* wrpr i,r1,%priv */ { "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RS1(~0), "i,!", 0, v9 }, /* wrpr i,%priv */ +{ "rdhpr", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|SIMM13(~0), "$,d", 0, v9 }, /* rdhpr %hpriv,r */ +{ "wrhpr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0), "1,2,%", 0, v9 }, /* wrhpr r1,r2,%hpriv */ +{ "wrhpr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|SIMM13(~0), "1,%", 0, v9 }, /* wrhpr r1,%hpriv */ +{ "wrhpr", F3(2, 0x33, 1), F3(~2, ~0x33, ~1), "1,i,%", 0, v9 }, /* wrhpr r1,i,%hpriv */ +{ "wrhpr", F3(2, 0x33, 1), F3(~2, ~0x33, ~1), "i,1,%", F_ALIAS, v9 }, /* wrhpr i,r1,%hpriv */ +{ "wrhpr", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RS1(~0), "i,%", 0, v9 }, /* wrhpr i,%hpriv */ + /* ??? This group seems wrong. A three operand move? */ { "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI(~0), "1,2,m", F_ALIAS, v8 }, /* wr r,r,%asrX */ { "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "1,i,m", F_ALIAS, v8 }, /* wr r,i,%asrX */ @@ -1473,110 +1503,72 @@ #define FM_DF 2 /* v9 */ #define FM_QF 3 /* v9 */ -#define fmovicc(opcode, fpsize, cond, flags) /* v9 */ \ -{ opcode, F3F(2, 0x35, 0x100+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x100+fpsize))|MCOND(~cond,~0), "z,f,g", flags, v9 }, \ -{ opcode, F3F(2, 0x35, 0x180+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x180+fpsize))|MCOND(~cond,~0), "Z,f,g", flags, v9 } - -#define fmovfcc(opcode, fpsize, fcond, flags) /* v9 */ \ -{ opcode, F3F(2, 0x35, 0x000+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x000+fpsize))|MCOND(~fcond,~0), "6,f,g", flags, v9 }, \ -{ opcode, F3F(2, 0x35, 0x040+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x040+fpsize))|MCOND(~fcond,~0), "7,f,g", flags, v9 }, \ -{ opcode, F3F(2, 0x35, 0x080+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x080+fpsize))|MCOND(~fcond,~0), "8,f,g", flags, v9 }, \ -{ opcode, F3F(2, 0x35, 0x0c0+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x0c0+fpsize))|MCOND(~fcond,~0), "9,f,g", flags, v9 } +#define fmoviccx(opcode, fpsize, args, cond, flags) /* v9 */ \ +{ opcode, F3F(2, 0x35, 0x100+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x100+fpsize))|MCOND(~cond,~0), "z," args, flags, v9 }, \ +{ opcode, F3F(2, 0x35, 0x180+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x180+fpsize))|MCOND(~cond,~0), "Z," args, flags, v9 } + +#define fmovfccx(opcode, fpsize, args, fcond, flags) /* v9 */ \ +{ opcode, F3F(2, 0x35, 0x000+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x000+fpsize))|MCOND(~fcond,~0), "6," args, flags, v9 }, \ +{ opcode, F3F(2, 0x35, 0x040+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x040+fpsize))|MCOND(~fcond,~0), "7," args, flags, v9 }, \ +{ opcode, F3F(2, 0x35, 0x080+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x080+fpsize))|MCOND(~fcond,~0), "8," args, flags, v9 }, \ +{ opcode, F3F(2, 0x35, 0x0c0+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x0c0+fpsize))|MCOND(~fcond,~0), "9," args, flags, v9 } /* FIXME: use fmovicc/fmovfcc? */ /* v9 */ -#define fmovcc(opcode, fpsize, cond, fcond, flags) /* v9 */ \ -{ opcode, F3F(2, 0x35, 0x100+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x100+fpsize))|MCOND(~cond,~0), "z,f,g", flags | F_FLOAT, v9 }, \ -{ opcode, F3F(2, 0x35, 0x000+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x000+fpsize))|MCOND(~fcond,~0), "6,f,g", flags | F_FLOAT, v9 }, \ -{ opcode, F3F(2, 0x35, 0x180+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x180+fpsize))|MCOND(~cond,~0), "Z,f,g", flags | F_FLOAT, v9 }, \ -{ opcode, F3F(2, 0x35, 0x040+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x040+fpsize))|MCOND(~fcond,~0), "7,f,g", flags | F_FLOAT, v9 }, \ -{ opcode, F3F(2, 0x35, 0x080+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x080+fpsize))|MCOND(~fcond,~0), "8,f,g", flags | F_FLOAT, v9 }, \ -{ opcode, F3F(2, 0x35, 0x0c0+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x0c0+fpsize))|MCOND(~fcond,~0), "9,f,g", flags | F_FLOAT, v9 } - -/* v9 */ fmovcc ("fmovda", FM_DF, CONDA, FCONDA, 0), -/* v9 */ fmovcc ("fmovqa", FM_QF, CONDA, FCONDA, 0), -/* v9 */ fmovcc ("fmovsa", FM_SF, CONDA, FCONDA, 0), -/* v9 */ fmovicc ("fmovdcc", FM_DF, CONDCC, 0), -/* v9 */ fmovicc ("fmovqcc", FM_QF, CONDCC, 0), -/* v9 */ fmovicc ("fmovscc", FM_SF, CONDCC, 0), -/* v9 */ fmovicc ("fmovdcs", FM_DF, CONDCS, 0), -/* v9 */ fmovicc ("fmovqcs", FM_QF, CONDCS, 0), -/* v9 */ fmovicc ("fmovscs", FM_SF, CONDCS, 0), -/* v9 */ fmovcc ("fmovde", FM_DF, CONDE, FCONDE, 0), -/* v9 */ fmovcc ("fmovqe", FM_QF, CONDE, FCONDE, 0), -/* v9 */ fmovcc ("fmovse", FM_SF, CONDE, FCONDE, 0), -/* v9 */ fmovcc ("fmovdg", FM_DF, CONDG, FCONDG, 0), -/* v9 */ fmovcc ("fmovqg", FM_QF, CONDG, FCONDG, 0), -/* v9 */ fmovcc ("fmovsg", FM_SF, CONDG, FCONDG, 0), -/* v9 */ fmovcc ("fmovdge", FM_DF, CONDGE, FCONDGE, 0), -/* v9 */ fmovcc ("fmovqge", FM_QF, CONDGE, FCONDGE, 0), -/* v9 */ fmovcc ("fmovsge", FM_SF, CONDGE, FCONDGE, 0), -/* v9 */ fmovicc ("fmovdgeu", FM_DF, CONDGEU, F_ALIAS), -/* v9 */ fmovicc ("fmovqgeu", FM_QF, CONDGEU, F_ALIAS), -/* v9 */ fmovicc ("fmovsgeu", FM_SF, CONDGEU, F_ALIAS), -/* v9 */ fmovicc ("fmovdgu", FM_DF, CONDGU, 0), -/* v9 */ fmovicc ("fmovqgu", FM_QF, CONDGU, 0), -/* v9 */ fmovicc ("fmovsgu", FM_SF, CONDGU, 0), -/* v9 */ fmovcc ("fmovdl", FM_DF, CONDL, FCONDL, 0), -/* v9 */ fmovcc ("fmovql", FM_QF, CONDL, FCONDL, 0), -/* v9 */ fmovcc ("fmovsl", FM_SF, CONDL, FCONDL, 0), -/* v9 */ fmovcc ("fmovdle", FM_DF, CONDLE, FCONDLE, 0), -/* v9 */ fmovcc ("fmovqle", FM_QF, CONDLE, FCONDLE, 0), -/* v9 */ fmovcc ("fmovsle", FM_SF, CONDLE, FCONDLE, 0), -/* v9 */ fmovicc ("fmovdleu", FM_DF, CONDLEU, 0), -/* v9 */ fmovicc ("fmovqleu", FM_QF, CONDLEU, 0), -/* v9 */ fmovicc ("fmovsleu", FM_SF, CONDLEU, 0), -/* v9 */ fmovfcc ("fmovdlg", FM_DF, FCONDLG, 0), -/* v9 */ fmovfcc ("fmovqlg", FM_QF, FCONDLG, 0), -/* v9 */ fmovfcc ("fmovslg", FM_SF, FCONDLG, 0), -/* v9 */ fmovicc ("fmovdlu", FM_DF, CONDLU, F_ALIAS), -/* v9 */ fmovicc ("fmovqlu", FM_QF, CONDLU, F_ALIAS), -/* v9 */ fmovicc ("fmovslu", FM_SF, CONDLU, F_ALIAS), -/* v9 */ fmovcc ("fmovdn", FM_DF, CONDN, FCONDN, 0), -/* v9 */ fmovcc ("fmovqn", FM_QF, CONDN, FCONDN, 0), -/* v9 */ fmovcc ("fmovsn", FM_SF, CONDN, FCONDN, 0), -/* v9 */ fmovcc ("fmovdne", FM_DF, CONDNE, FCONDNE, 0), -/* v9 */ fmovcc ("fmovqne", FM_QF, CONDNE, FCONDNE, 0), -/* v9 */ fmovcc ("fmovsne", FM_SF, CONDNE, FCONDNE, 0), -/* v9 */ fmovicc ("fmovdneg", FM_DF, CONDNEG, 0), -/* v9 */ fmovicc ("fmovqneg", FM_QF, CONDNEG, 0), -/* v9 */ fmovicc ("fmovsneg", FM_SF, CONDNEG, 0), -/* v9 */ fmovcc ("fmovdnz", FM_DF, CONDNZ, FCONDNZ, F_ALIAS), -/* v9 */ fmovcc ("fmovqnz", FM_QF, CONDNZ, FCONDNZ, F_ALIAS), -/* v9 */ fmovcc ("fmovsnz", FM_SF, CONDNZ, FCONDNZ, F_ALIAS), -/* v9 */ fmovfcc ("fmovdo", FM_DF, FCONDO, 0), -/* v9 */ fmovfcc ("fmovqo", FM_QF, FCONDO, 0), -/* v9 */ fmovfcc ("fmovso", FM_SF, FCONDO, 0), -/* v9 */ fmovicc ("fmovdpos", FM_DF, CONDPOS, 0), -/* v9 */ fmovicc ("fmovqpos", FM_QF, CONDPOS, 0), -/* v9 */ fmovicc ("fmovspos", FM_SF, CONDPOS, 0), -/* v9 */ fmovfcc ("fmovdu", FM_DF, FCONDU, 0), -/* v9 */ fmovfcc ("fmovqu", FM_QF, FCONDU, 0), -/* v9 */ fmovfcc ("fmovsu", FM_SF, FCONDU, 0), -/* v9 */ fmovfcc ("fmovdue", FM_DF, FCONDUE, 0), -/* v9 */ fmovfcc ("fmovque", FM_QF, FCONDUE, 0), -/* v9 */ fmovfcc ("fmovsue", FM_SF, FCONDUE, 0), -/* v9 */ fmovfcc ("fmovdug", FM_DF, FCONDUG, 0), -/* v9 */ fmovfcc ("fmovqug", FM_QF, FCONDUG, 0), -/* v9 */ fmovfcc ("fmovsug", FM_SF, FCONDUG, 0), -/* v9 */ fmovfcc ("fmovduge", FM_DF, FCONDUGE, 0), -/* v9 */ fmovfcc ("fmovquge", FM_QF, FCONDUGE, 0), -/* v9 */ fmovfcc ("fmovsuge", FM_SF, FCONDUGE, 0), -/* v9 */ fmovfcc ("fmovdul", FM_DF, FCONDUL, 0), -/* v9 */ fmovfcc ("fmovqul", FM_QF, FCONDUL, 0), -/* v9 */ fmovfcc ("fmovsul", FM_SF, FCONDUL, 0), -/* v9 */ fmovfcc ("fmovdule", FM_DF, FCONDULE, 0), -/* v9 */ fmovfcc ("fmovqule", FM_QF, FCONDULE, 0), -/* v9 */ fmovfcc ("fmovsule", FM_SF, FCONDULE, 0), -/* v9 */ fmovicc ("fmovdvc", FM_DF, CONDVC, 0), -/* v9 */ fmovicc ("fmovqvc", FM_QF, CONDVC, 0), -/* v9 */ fmovicc ("fmovsvc", FM_SF, CONDVC, 0), -/* v9 */ fmovicc ("fmovdvs", FM_DF, CONDVS, 0), -/* v9 */ fmovicc ("fmovqvs", FM_QF, CONDVS, 0), -/* v9 */ fmovicc ("fmovsvs", FM_SF, CONDVS, 0), -/* v9 */ fmovcc ("fmovdz", FM_DF, CONDZ, FCONDZ, F_ALIAS), -/* v9 */ fmovcc ("fmovqz", FM_QF, CONDZ, FCONDZ, F_ALIAS), -/* v9 */ fmovcc ("fmovsz", FM_SF, CONDZ, FCONDZ, F_ALIAS), - +#define fmovccx(opcode, fpsize, args, cond, fcond, flags) /* v9 */ \ +{ opcode, F3F(2, 0x35, 0x100+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x100+fpsize))|MCOND(~cond,~0), "z," args, flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x000+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x000+fpsize))|MCOND(~fcond,~0), "6," args, flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x180+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x180+fpsize))|MCOND(~cond,~0), "Z," args, flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x040+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x040+fpsize))|MCOND(~fcond,~0), "7," args, flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x080+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x080+fpsize))|MCOND(~fcond,~0), "8," args, flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x0c0+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x0c0+fpsize))|MCOND(~fcond,~0), "9," args, flags | F_FLOAT, v9 } + +#define fmovicc(suffix, cond, flags) /* v9 */ \ +fmoviccx("fmovd" suffix, FM_DF, "B,H", cond, flags), \ +fmoviccx("fmovq" suffix, FM_QF, "R,J", cond, flags), \ +fmoviccx("fmovs" suffix, FM_SF, "f,g", cond, flags) + +#define fmovfcc(suffix, fcond, flags) /* v9 */ \ +fmovfccx("fmovd" suffix, FM_DF, "B,H", fcond, flags), \ +fmovfccx("fmovq" suffix, FM_QF, "R,J", fcond, flags), \ +fmovfccx("fmovs" suffix, FM_SF, "f,g", fcond, flags) + +#define fmovcc(suffix, cond, fcond, flags) /* v9 */ \ +fmovccx("fmovd" suffix, FM_DF, "B,H", cond, fcond, flags), \ +fmovccx("fmovq" suffix, FM_QF, "R,J", cond, fcond, flags), \ +fmovccx("fmovs" suffix, FM_SF, "f,g", cond, fcond, flags) + +/* v9 */ fmovcc ("a", CONDA, FCONDA, 0), +/* v9 */ fmovicc ("cc", CONDCC, 0), +/* v9 */ fmovicc ("cs", CONDCS, 0), +/* v9 */ fmovcc ("e", CONDE, FCONDE, 0), +/* v9 */ fmovcc ("g", CONDG, FCONDG, 0), +/* v9 */ fmovcc ("ge", CONDGE, FCONDGE, 0), +/* v9 */ fmovicc ("geu", CONDGEU, F_ALIAS), +/* v9 */ fmovicc ("gu", CONDGU, 0), +/* v9 */ fmovcc ("l", CONDL, FCONDL, 0), +/* v9 */ fmovcc ("le", CONDLE, FCONDLE, 0), +/* v9 */ fmovicc ("leu", CONDLEU, 0), +/* v9 */ fmovfcc ("lg", FCONDLG, 0), +/* v9 */ fmovicc ("lu", CONDLU, F_ALIAS), +/* v9 */ fmovcc ("n", CONDN, FCONDN, 0), +/* v9 */ fmovcc ("ne", CONDNE, FCONDNE, 0), +/* v9 */ fmovicc ("neg", CONDNEG, 0), +/* v9 */ fmovcc ("nz", CONDNZ, FCONDNZ, F_ALIAS), +/* v9 */ fmovfcc ("o", FCONDO, 0), +/* v9 */ fmovicc ("pos", CONDPOS, 0), +/* v9 */ fmovfcc ("u", FCONDU, 0), +/* v9 */ fmovfcc ("ue", FCONDUE, 0), +/* v9 */ fmovfcc ("ug", FCONDUG, 0), +/* v9 */ fmovfcc ("uge", FCONDUGE, 0), +/* v9 */ fmovfcc ("ul", FCONDUL, 0), +/* v9 */ fmovfcc ("ule", FCONDULE, 0), +/* v9 */ fmovicc ("vc", CONDVC, 0), +/* v9 */ fmovicc ("vs", CONDVS, 0), +/* v9 */ fmovcc ("z", CONDZ, FCONDZ, F_ALIAS), + +#undef fmoviccx /* v9 */ +#undef fmovfccx /* v9 */ +#undef fmovccx /* v9 */ #undef fmovicc /* v9 */ #undef fmovfcc /* v9 */ #undef fmovcc /* v9 */ @@ -1586,13 +1578,13 @@ /* Coprocessor branches. */ #define CBR(opcode, mask, lose, flags, arch) \ - { opcode, (mask), ANNUL|(lose), "l", flags|F_DELAYED, arch }, \ - { opcode, (mask)|ANNUL, (lose), ",a l", flags|F_DELAYED, arch } + { opcode, (mask), ANNUL | (lose), "l", flags | F_DELAYED, arch }, \ + { opcode, (mask) | ANNUL, (lose), ",a l", flags | F_DELAYED, arch } /* Floating point branches. */ #define FBR(opcode, mask, lose, flags) \ - { opcode, (mask), ANNUL|(lose), "l", flags|F_DELAYED|F_FBR, v6 }, \ - { opcode, (mask)|ANNUL, (lose), ",a l", flags|F_DELAYED|F_FBR, v6 } + { opcode, (mask), ANNUL | (lose), "l", flags | F_DELAYED | F_FBR, v6 }, \ + { opcode, (mask) | ANNUL, (lose), ",a l", flags | F_DELAYED | F_FBR, v6 } /* V9 extended floating point branches. */ #define FBRX(opcode, mask, lose, flags) /* v9 */ \ @@ -1725,17 +1717,17 @@ { "fstoi", F3F(2, 0x34, 0x0d1), F3F(~2, ~0x34, ~0x0d1)|RS1_G0, "f,g", F_FLOAT, v6 }, { "fqtoi", F3F(2, 0x34, 0x0d3), F3F(~2, ~0x34, ~0x0d3)|RS1_G0, "R,g", F_FLOAT, v8 }, -{ "fdtox", F3F(2, 0x34, 0x082), F3F(~2, ~0x34, ~0x082)|RS1_G0, "B,g", F_FLOAT, v9 }, -{ "fstox", F3F(2, 0x34, 0x081), F3F(~2, ~0x34, ~0x081)|RS1_G0, "f,g", F_FLOAT, v9 }, -{ "fqtox", F3F(2, 0x34, 0x083), F3F(~2, ~0x34, ~0x083)|RS1_G0, "R,g", F_FLOAT, v9 }, +{ "fdtox", F3F(2, 0x34, 0x082), F3F(~2, ~0x34, ~0x082)|RS1_G0, "B,H", F_FLOAT, v9 }, +{ "fstox", F3F(2, 0x34, 0x081), F3F(~2, ~0x34, ~0x081)|RS1_G0, "f,H", F_FLOAT, v9 }, +{ "fqtox", F3F(2, 0x34, 0x083), F3F(~2, ~0x34, ~0x083)|RS1_G0, "R,H", F_FLOAT, v9 }, { "fitod", F3F(2, 0x34, 0x0c8), F3F(~2, ~0x34, ~0x0c8)|RS1_G0, "f,H", F_FLOAT, v6 }, { "fitos", F3F(2, 0x34, 0x0c4), F3F(~2, ~0x34, ~0x0c4)|RS1_G0, "f,g", F_FLOAT, v6 }, { "fitoq", F3F(2, 0x34, 0x0cc), F3F(~2, ~0x34, ~0x0cc)|RS1_G0, "f,J", F_FLOAT, v8 }, -{ "fxtod", F3F(2, 0x34, 0x088), F3F(~2, ~0x34, ~0x088)|RS1_G0, "f,H", F_FLOAT, v9 }, -{ "fxtos", F3F(2, 0x34, 0x084), F3F(~2, ~0x34, ~0x084)|RS1_G0, "f,g", F_FLOAT, v9 }, -{ "fxtoq", F3F(2, 0x34, 0x08c), F3F(~2, ~0x34, ~0x08c)|RS1_G0, "f,J", F_FLOAT, v9 }, +{ "fxtod", F3F(2, 0x34, 0x088), F3F(~2, ~0x34, ~0x088)|RS1_G0, "B,H", F_FLOAT, v9 }, +{ "fxtos", F3F(2, 0x34, 0x084), F3F(~2, ~0x34, ~0x084)|RS1_G0, "B,g", F_FLOAT, v9 }, +{ "fxtoq", F3F(2, 0x34, 0x08c), F3F(~2, ~0x34, ~0x08c)|RS1_G0, "B,J", F_FLOAT, v9 }, { "fdtoq", F3F(2, 0x34, 0x0ce), F3F(~2, ~0x34, ~0x0ce)|RS1_G0, "B,J", F_FLOAT, v8 }, { "fdtos", F3F(2, 0x34, 0x0c6), F3F(~2, ~0x34, ~0x0c6)|RS1_G0, "B,g", F_FLOAT, v6 }, @@ -2055,7 +2047,7 @@ }; -const int sparc_num_opcodes = ((sizeof sparc_opcodes)/(sizeof sparc_opcodes[0])); +static const int sparc_num_opcodes = ((sizeof sparc_opcodes)/(sizeof sparc_opcodes[0])); /* Utilities for argument parsing. */ @@ -2065,31 +2057,10 @@ const char *name; } arg; -/* Look up NAME in TABLE. */ - -static int lookup_name PARAMS ((const arg *, const char *)); -static const char *lookup_value PARAMS ((const arg *, int)); - -static int -lookup_name (table, name) - const arg *table; - const char *name; -{ - const arg *p; - - for (p = table; p->name; ++p) - if (strcmp (name, p->name) == 0) - return p->value; - - return -1; -} - /* Look up VALUE in TABLE. */ static const char * -lookup_value (table, value) - const arg *table; - int value; +lookup_value (const arg *table, int value) { const arg *p; @@ -2097,7 +2068,7 @@ if (value == p->value) return p->name; - return (char *) 0; + return NULL; } /* Handle ASI's. */ @@ -2218,20 +2189,10 @@ { 0, 0 } }; -/* Return the value for membar arg NAME, or -1 if not found. */ - -int -sparc_encode_membar (name) - const char *name; -{ - return lookup_name (membar_table, name); -} - /* Return the name for membar value VALUE or NULL if not found. */ -const char * -sparc_decode_membar (value) - int value; +static const char * +sparc_decode_membar (int value) { return lookup_value (membar_table, value); } @@ -2249,20 +2210,10 @@ { 0, 0 } }; -/* Return the value for prefetch arg NAME, or -1 if not found. */ - -int -sparc_encode_prefetch (name) - const char *name; -{ - return lookup_name (prefetch_table, name); -} - /* Return the name for prefetch value VALUE or NULL if not found. */ -const char * -sparc_decode_prefetch (value) - int value; +static const char * +sparc_decode_prefetch (int value) { return lookup_value (prefetch_table, value); } @@ -2281,26 +2232,37 @@ { 0, 0 } }; -/* Return the value for sparclet cpreg arg NAME, or -1 if not found. */ - -int -sparc_encode_sparclet_cpreg (name) - const char *name; -{ - return lookup_name (sparclet_cpreg_table, name); -} - /* Return the name for sparclet cpreg value VALUE or NULL if not found. */ -const char * -sparc_decode_sparclet_cpreg (value) - int value; +static const char * +sparc_decode_sparclet_cpreg (int value) { return lookup_value (sparclet_cpreg_table, value); } #undef MASK_V9 +/* opcodes/sparc-dis.c */ + +/* Print SPARC instructions. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + /* Bitmask of v9 architectures. */ #define MASK_V9 ((1 << SPARC_OPCODE_ARCH_V9) \ | (1 << SPARC_OPCODE_ARCH_V9A) \ @@ -2311,7 +2273,7 @@ #define V9_P(insn) (((insn)->architecture & MASK_V9) != 0) /* The sorted opcode table. */ -static const struct sparc_opcode **sorted_opcodes; +static const sparc_opcode **sorted_opcodes; /* For faster lookup, after insns are sorted they are hashed. */ /* ??? I think there is room for even more improvement. */ @@ -2323,17 +2285,13 @@ static const int opcode_bits[4] = { 0x01c00000, 0x0, 0x01f80000, 0x01f80000 }; #define HASH_INSN(INSN) \ ((((INSN) >> 24) & 0xc0) | (((INSN) & opcode_bits[((INSN) >> 30) & 3]) >> 19)) -struct opcode_hash { - struct opcode_hash *next; - const struct sparc_opcode *opcode; -}; -static struct opcode_hash *opcode_hash_table[HASH_SIZE]; +typedef struct sparc_opcode_hash +{ + struct sparc_opcode_hash *next; + const sparc_opcode *opcode; +} sparc_opcode_hash; -static void build_hash_table - PARAMS ((const struct sparc_opcode **, struct opcode_hash **, int)); -static int is_delayed_branch PARAMS ((unsigned long)); -static int compare_opcodes PARAMS ((const void *, const void *)); -static int compute_arch_mask PARAMS ((unsigned long)); +static sparc_opcode_hash *opcode_hash_table[HASH_SIZE]; /* Sign-extend a value which is N bits long. */ #define SEX(value, bits) \ @@ -2365,11 +2323,22 @@ { "tpc", "tnpc", "tstate", "tt", "tick", "tba", "pstate", "tl", "pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin", - "wstate", "fq" + "wstate", "fq", "gl" /* "ver" - special cased */ }; /* These are ordered according to there register number in + rdhpr and wrhpr insns. */ +static const char * const v9_hpriv_reg_names[] = +{ + "hpstate", "htstate", "resv2", "hintp", "resv4", "htba", "hver", + "resv7", "resv8", "resv9", "resv10", "resv11", "resv12", "resv13", + "resv14", "resv15", "resv16", "resv17", "resv18", "resv19", "resv20", + "resv21", "resv22", "resv23", "resv24", "resv25", "resv26", "resv27", + "resv28", "resv29", "resv30", "hstick_cmpr" +}; + +/* These are ordered according to there register number in rd and wr insns (-16). */ static const char * const v9a_asr_reg_names[] = { @@ -2380,21 +2349,21 @@ /* Macros used to extract instruction fields. Not all fields have macros defined here, only those which are actually used. */ -#define X_RD(i) (((i) >> 25) & 0x1f) -#define X_RS1(i) (((i) >> 14) & 0x1f) -#define X_LDST_I(i) (((i) >> 13) & 1) -#define X_ASI(i) (((i) >> 5) & 0xff) -#define X_RS2(i) (((i) >> 0) & 0x1f) -#define X_IMM(i,n) (((i) >> 0) & ((1 << (n)) - 1)) -#define X_SIMM(i,n) SEX (X_IMM ((i), (n)), (n)) -#define X_DISP22(i) (((i) >> 0) & 0x3fffff) -#define X_IMM22(i) X_DISP22 (i) -#define X_DISP30(i) (((i) >> 0) & 0x3fffffff) +#define X_RD(i) (((i) >> 25) & 0x1f) +#define X_RS1(i) (((i) >> 14) & 0x1f) +#define X_LDST_I(i) (((i) >> 13) & 1) +#define X_ASI(i) (((i) >> 5) & 0xff) +#define X_RS2(i) (((i) >> 0) & 0x1f) +#define X_IMM(i,n) (((i) >> 0) & ((1 << (n)) - 1)) +#define X_SIMM(i,n) SEX (X_IMM ((i), (n)), (n)) +#define X_DISP22(i) (((i) >> 0) & 0x3fffff) +#define X_IMM22(i) X_DISP22 (i) +#define X_DISP30(i) (((i) >> 0) & 0x3fffffff) /* These are for v9. */ -#define X_DISP16(i) (((((i) >> 20) & 3) << 14) | (((i) >> 0) & 0x3fff)) -#define X_DISP19(i) (((i) >> 0) & 0x7ffff) -#define X_MEMBAR(i) ((i) & 0x7f) +#define X_DISP16(i) (((((i) >> 20) & 3) << 14) | (((i) >> 0) & 0x3fff)) +#define X_DISP19(i) (((i) >> 0) & 0x7ffff) +#define X_MEMBAR(i) ((i) & 0x7f) /* Here is the union which was used to extract instruction fields before the shift and mask macros were written. @@ -2452,23 +2421,22 @@ unsigned int adisp30:30; #define disp30 call.adisp30 } call; - }; - - */ + }; */ /* Nonzero if INSN is the opcode for a delayed branch. */ + static int -is_delayed_branch (insn) - unsigned long insn; +is_delayed_branch (unsigned long insn) { - struct opcode_hash *op; + sparc_opcode_hash *op; for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next) { - const struct sparc_opcode *opcode = op->opcode; + const sparc_opcode *opcode = op->opcode; + if ((opcode->match & insn) == opcode->match && (opcode->lose & insn) == 0) - return (opcode->flags & F_DELAYED); + return opcode->flags & F_DELAYED; } return 0; } @@ -2479,146 +2447,377 @@ to compare_opcodes. */ static unsigned int current_arch_mask; -/* Print one instruction from MEMADDR on INFO->STREAM. - - We suffix the instruction with a comment that gives the absolute - address involved, as well as its symbolic form, if the instruction - is preceded by a findable `sethi' and it either adds an immediate - displacement to that register, or it is an `add' or `or' instruction - on that register. */ +/* Given BFD mach number, return a mask of SPARC_OPCODE_ARCH_FOO values. */ -int -print_insn_sparc (memaddr, info) - bfd_vma memaddr; - disassemble_info *info; +static int +compute_arch_mask (unsigned long mach) { - FILE *stream = info->stream; - bfd_byte buffer[4]; - unsigned long insn; - register struct opcode_hash *op; - /* Nonzero of opcode table has been initialized. */ - static int opcodes_initialized = 0; - /* bfd mach number of last call. */ - static unsigned long current_mach = 0; - bfd_vma (*getword) PARAMS ((const unsigned char *)); - - if (!opcodes_initialized - || info->mach != current_mach) + switch (mach) { - int i; - - current_arch_mask = compute_arch_mask (info->mach); + case 0 : + case bfd_mach_sparc : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8); + case bfd_mach_sparc_sparclet : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET); + case bfd_mach_sparc_sparclite : + case bfd_mach_sparc_sparclite_le : + /* sparclites insns are recognized by default (because that's how + they've always been treated, for better or worse). Kludge this by + indicating generic v8 is also selected. */ + return (SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE) + | SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8)); + case bfd_mach_sparc_v8plus : + case bfd_mach_sparc_v9 : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9); + case bfd_mach_sparc_v8plusa : + case bfd_mach_sparc_v9a : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A); + case bfd_mach_sparc_v8plusb : + case bfd_mach_sparc_v9b : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9B); + } + abort (); +} - if (!opcodes_initialized) - sorted_opcodes = (const struct sparc_opcode **) - malloc (sparc_num_opcodes * sizeof (struct sparc_opcode *)); - /* Reset the sorted table so we can resort it. */ - for (i = 0; i < sparc_num_opcodes; ++i) - sorted_opcodes[i] = &sparc_opcodes[i]; - qsort ((char *) sorted_opcodes, sparc_num_opcodes, - sizeof (sorted_opcodes[0]), compare_opcodes); +/* Compare opcodes A and B. */ - build_hash_table (sorted_opcodes, opcode_hash_table, sparc_num_opcodes); - current_mach = info->mach; - opcodes_initialized = 1; - } +static int +compare_opcodes (const void * a, const void * b) +{ + sparc_opcode *op0 = * (sparc_opcode **) a; + sparc_opcode *op1 = * (sparc_opcode **) b; + unsigned long int match0 = op0->match, match1 = op1->match; + unsigned long int lose0 = op0->lose, lose1 = op1->lose; + register unsigned int i; - { - int status = - (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info); - if (status != 0) - { - (*info->memory_error_func) (status, memaddr, info); + /* If one (and only one) insn isn't supported by the current architecture, + prefer the one that is. If neither are supported, but they're both for + the same architecture, continue processing. Otherwise (both unsupported + and for different architectures), prefer lower numbered arch's (fudged + by comparing the bitmasks). */ + if (op0->architecture & current_arch_mask) + { + if (! (op1->architecture & current_arch_mask)) return -1; - } - } - - /* On SPARClite variants such as DANlite (sparc86x), instructions - are always big-endian even when the machine is in little-endian mode. */ - if (info->endian == BFD_ENDIAN_BIG || info->mach == bfd_mach_sparc_sparclite) - getword = bfd_getb32; + } else - getword = bfd_getl32; + { + if (op1->architecture & current_arch_mask) + return 1; + else if (op0->architecture != op1->architecture) + return op0->architecture - op1->architecture; + } - insn = getword (buffer); + /* If a bit is set in both match and lose, there is something + wrong with the opcode table. */ + if (match0 & lose0) + { + fprintf + (stderr, + /* xgettext:c-format */ + _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"), + op0->name, match0, lose0); + op0->lose &= ~op0->match; + lose0 = op0->lose; + } - info->insn_info_valid = 1; /* We do return this info */ - info->insn_type = dis_nonbranch; /* Assume non branch insn */ - info->branch_delay_insns = 0; /* Assume no delay */ - info->target = 0; /* Assume no target known */ + if (match1 & lose1) + { + fprintf + (stderr, + /* xgettext:c-format */ + _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"), + op1->name, match1, lose1); + op1->lose &= ~op1->match; + lose1 = op1->lose; + } - for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next) + /* Because the bits that are variable in one opcode are constant in + another, it is important to order the opcodes in the right order. */ + for (i = 0; i < 32; ++i) { - const struct sparc_opcode *opcode = op->opcode; + unsigned long int x = 1 << i; + int x0 = (match0 & x) != 0; + int x1 = (match1 & x) != 0; - /* If the insn isn't supported by the current architecture, skip it. */ - if (! (opcode->architecture & current_arch_mask)) - continue; + if (x0 != x1) + return x1 - x0; + } - if ((opcode->match & insn) == opcode->match - && (opcode->lose & insn) == 0) - { - /* Nonzero means that we have found an instruction which has - the effect of adding or or'ing the imm13 field to rs1. */ - int imm_added_to_rs1 = 0; - int imm_ored_to_rs1 = 0; + for (i = 0; i < 32; ++i) + { + unsigned long int x = 1 << i; + int x0 = (lose0 & x) != 0; + int x1 = (lose1 & x) != 0; - /* Nonzero means that we have found a plus sign in the args - field of the opcode table. */ - int found_plus = 0; + if (x0 != x1) + return x1 - x0; + } - /* Nonzero means we have an annulled branch. */ - int is_annulled = 0; + /* They are functionally equal. So as long as the opcode table is + valid, we can put whichever one first we want, on aesthetic grounds. */ - /* Do we have an `add' or `or' instruction combining an - immediate with rs1? */ - if (opcode->match == 0x80102000) /* or */ - imm_ored_to_rs1 = 1; - if (opcode->match == 0x80002000) /* add */ - imm_added_to_rs1 = 1; + /* Our first aesthetic ground is that aliases defer to real insns. */ + { + int alias_diff = (op0->flags & F_ALIAS) - (op1->flags & F_ALIAS); - if (X_RS1 (insn) != X_RD (insn) - && strchr (opcode->args, 'r') != 0) - /* Can't do simple format if source and dest are different. */ - continue; - if (X_RS2 (insn) != X_RD (insn) - && strchr (opcode->args, 'O') != 0) - /* Can't do simple format if source and dest are different. */ - continue; + if (alias_diff != 0) + /* Put the one that isn't an alias first. */ + return alias_diff; + } - (*info->fprintf_func) (stream, opcode->name); + /* Except for aliases, two "identical" instructions had + better have the same opcode. This is a sanity check on the table. */ + i = strcmp (op0->name, op1->name); + if (i) + { + if (op0->flags & F_ALIAS) /* If they're both aliases, be arbitrary. */ + return i; + else + fprintf (stderr, + /* xgettext:c-format */ + _("Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n"), + op0->name, op1->name); + } - { - register const char *s; + /* Fewer arguments are preferred. */ + { + int length_diff = strlen (op0->args) - strlen (op1->args); + + if (length_diff != 0) + /* Put the one with fewer arguments first. */ + return length_diff; + } + + /* Put 1+i before i+1. */ + { + char *p0 = (char *) strchr (op0->args, '+'); + char *p1 = (char *) strchr (op1->args, '+'); + + if (p0 && p1) + { + /* There is a plus in both operands. Note that a plus + sign cannot be the first character in args, + so the following [-1]'s are valid. */ + if (p0[-1] == 'i' && p1[1] == 'i') + /* op0 is i+1 and op1 is 1+i, so op1 goes first. */ + return 1; + if (p0[1] == 'i' && p1[-1] == 'i') + /* op0 is 1+i and op1 is i+1, so op0 goes first. */ + return -1; + } + } + + /* Put 1,i before i,1. */ + { + int i0 = strncmp (op0->args, "i,1", 3) == 0; + int i1 = strncmp (op1->args, "i,1", 3) == 0; + + if (i0 ^ i1) + return i0 - i1; + } + + /* They are, as far as we can tell, identical. + Since qsort may have rearranged the table partially, there is + no way to tell which one was first in the opcode table as + written, so just say there are equal. */ + /* ??? This is no longer true now that we sort a vector of pointers, + not the table itself. */ + return 0; +} + +/* Build a hash table from the opcode table. + OPCODE_TABLE is a sorted list of pointers into the opcode table. */ + +static void +build_hash_table (const sparc_opcode **opcode_table, + sparc_opcode_hash **hash_table, + int num_opcodes) +{ + int i; + int hash_count[HASH_SIZE]; + static sparc_opcode_hash *hash_buf = NULL; + + /* Start at the end of the table and work backwards so that each + chain is sorted. */ + + memset (hash_table, 0, HASH_SIZE * sizeof (hash_table[0])); + memset (hash_count, 0, HASH_SIZE * sizeof (hash_count[0])); + if (hash_buf != NULL) + free (hash_buf); + hash_buf = malloc (sizeof (* hash_buf) * num_opcodes); + for (i = num_opcodes - 1; i >= 0; --i) + { + int hash = HASH_INSN (opcode_table[i]->match); + sparc_opcode_hash *h = &hash_buf[i]; + + h->next = hash_table[hash]; + h->opcode = opcode_table[i]; + hash_table[hash] = h; + ++hash_count[hash]; + } + +#if 0 /* for debugging */ + { + int min_count = num_opcodes, max_count = 0; + int total; + + for (i = 0; i < HASH_SIZE; ++i) + { + if (hash_count[i] < min_count) + min_count = hash_count[i]; + if (hash_count[i] > max_count) + max_count = hash_count[i]; + total += hash_count[i]; + } + + printf ("Opcode hash table stats: min %d, max %d, ave %f\n", + min_count, max_count, (double) total / HASH_SIZE); + } +#endif +} + +/* Print one instruction from MEMADDR on INFO->STREAM. + + We suffix the instruction with a comment that gives the absolute + address involved, as well as its symbolic form, if the instruction + is preceded by a findable `sethi' and it either adds an immediate + displacement to that register, or it is an `add' or `or' instruction + on that register. */ + +int +print_insn_sparc (bfd_vma memaddr, disassemble_info *info) +{ + FILE *stream = info->stream; + bfd_byte buffer[4]; + unsigned long insn; + sparc_opcode_hash *op; + /* Nonzero of opcode table has been initialized. */ + static int opcodes_initialized = 0; + /* bfd mach number of last call. */ + static unsigned long current_mach = 0; + bfd_vma (*getword) (const unsigned char *); + + if (!opcodes_initialized + || info->mach != current_mach) + { + int i; + + current_arch_mask = compute_arch_mask (info->mach); + + if (!opcodes_initialized) + sorted_opcodes = + malloc (sparc_num_opcodes * sizeof (sparc_opcode *)); + /* Reset the sorted table so we can resort it. */ + for (i = 0; i < sparc_num_opcodes; ++i) + sorted_opcodes[i] = &sparc_opcodes[i]; + qsort ((char *) sorted_opcodes, sparc_num_opcodes, + sizeof (sorted_opcodes[0]), compare_opcodes); + + build_hash_table (sorted_opcodes, opcode_hash_table, sparc_num_opcodes); + current_mach = info->mach; + opcodes_initialized = 1; + } + + { + int status = + (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info); + + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + } + + /* On SPARClite variants such as DANlite (sparc86x), instructions + are always big-endian even when the machine is in little-endian mode. */ + if (info->endian == BFD_ENDIAN_BIG || info->mach == bfd_mach_sparc_sparclite) + getword = bfd_getb32; + else + getword = bfd_getl32; + + insn = getword (buffer); + + info->insn_info_valid = 1; /* We do return this info. */ + info->insn_type = dis_nonbranch; /* Assume non branch insn. */ + info->branch_delay_insns = 0; /* Assume no delay. */ + info->target = 0; /* Assume no target known. */ + + for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next) + { + const sparc_opcode *opcode = op->opcode; + + /* If the insn isn't supported by the current architecture, skip it. */ + if (! (opcode->architecture & current_arch_mask)) + continue; + + if ((opcode->match & insn) == opcode->match + && (opcode->lose & insn) == 0) + { + /* Nonzero means that we have found an instruction which has + the effect of adding or or'ing the imm13 field to rs1. */ + int imm_added_to_rs1 = 0; + int imm_ored_to_rs1 = 0; + + /* Nonzero means that we have found a plus sign in the args + field of the opcode table. */ + int found_plus = 0; + + /* Nonzero means we have an annulled branch. */ + int is_annulled = 0; + + /* Do we have an `add' or `or' instruction combining an + immediate with rs1? */ + if (opcode->match == 0x80102000) /* or */ + imm_ored_to_rs1 = 1; + if (opcode->match == 0x80002000) /* add */ + imm_added_to_rs1 = 1; + + if (X_RS1 (insn) != X_RD (insn) + && strchr (opcode->args, 'r') != 0) + /* Can't do simple format if source and dest are different. */ + continue; + if (X_RS2 (insn) != X_RD (insn) + && strchr (opcode->args, 'O') != 0) + /* Can't do simple format if source and dest are different. */ + continue; + + (*info->fprintf_func) (stream, opcode->name); + + { + const char *s; if (opcode->args[0] != ',') (*info->fprintf_func) (stream, " "); + for (s = opcode->args; *s != '\0'; ++s) { while (*s == ',') { (*info->fprintf_func) (stream, ","); ++s; - switch (*s) { - case 'a': - (*info->fprintf_func) (stream, "a"); - is_annulled = 1; - ++s; - continue; - case 'N': - (*info->fprintf_func) (stream, "pn"); - ++s; - continue; - - case 'T': - (*info->fprintf_func) (stream, "pt"); - ++s; - continue; - - default: - break; - } /* switch on arg */ - } /* while there are comma started args */ + switch (*s) + { + case 'a': + (*info->fprintf_func) (stream, "a"); + is_annulled = 1; + ++s; + continue; + case 'N': + (*info->fprintf_func) (stream, "pn"); + ++s; + continue; + + case 'T': + (*info->fprintf_func) (stream, "pt"); + ++s; + continue; + + default: + break; + } + } (*info->fprintf_func) (stream, " "); @@ -2626,8 +2825,8 @@ { case '+': found_plus = 1; + /* Fall through. */ - /* note fall-through */ default: (*info->fprintf_func) (stream, "%c", *s); break; @@ -2657,24 +2856,24 @@ case 'e': freg (X_RS1 (insn)); break; - case 'v': /* double/even */ - case 'V': /* quad/multiple of 4 */ + case 'v': /* Double/even. */ + case 'V': /* Quad/multiple of 4. */ fregx (X_RS1 (insn)); break; case 'f': freg (X_RS2 (insn)); break; - case 'B': /* double/even */ - case 'R': /* quad/multiple of 4 */ + case 'B': /* Double/even. */ + case 'R': /* Quad/multiple of 4. */ fregx (X_RS2 (insn)); break; case 'g': freg (X_RD (insn)); break; - case 'H': /* double/even */ - case 'J': /* quad/multiple of 4 */ + case 'H': /* Double/even. */ + case 'J': /* Quad/multiple of 4. */ fregx (X_RD (insn)); break; #undef freg @@ -2700,9 +2899,9 @@ & ((int) X_IMM22 (insn) << 10))); break; - case 'i': /* 13 bit immediate */ - case 'I': /* 11 bit immediate */ - case 'j': /* 10 bit immediate */ + case 'i': /* 13 bit immediate. */ + case 'I': /* 11 bit immediate. */ + case 'j': /* 10 bit immediate. */ { int imm; @@ -2730,8 +2929,8 @@ } break; - case 'X': /* 5 bit unsigned immediate */ - case 'Y': /* 6 bit unsigned immediate */ + case 'X': /* 5 bit unsigned immediate. */ + case 'Y': /* 6 bit unsigned immediate. */ { int imm = X_IMM (insn, *s == 'X' ? 5 : 6); @@ -2743,7 +2942,7 @@ break; case '3': - (info->fprintf_func) (stream, "%d", X_IMM (insn, 3)); + (info->fprintf_func) (stream, "%ld", X_IMM (insn, 3)); break; case 'K': @@ -2818,7 +3017,7 @@ case '?': if (X_RS1 (insn) == 31) (*info->fprintf_func) (stream, "%%ver"); - else if ((unsigned) X_RS1 (insn) < 16) + else if ((unsigned) X_RS1 (insn) < 17) (*info->fprintf_func) (stream, "%%%s", v9_priv_reg_names[X_RS1 (insn)]); else @@ -2826,13 +3025,29 @@ break; case '!': - if ((unsigned) X_RD (insn) < 15) + if ((unsigned) X_RD (insn) < 17) (*info->fprintf_func) (stream, "%%%s", v9_priv_reg_names[X_RD (insn)]); else (*info->fprintf_func) (stream, "%%reserved"); break; + case '$': + if ((unsigned) X_RS1 (insn) < 32) + (*info->fprintf_func) (stream, "%%%s", + v9_hpriv_reg_names[X_RS1 (insn)]); + else + (*info->fprintf_func) (stream, "%%reserved"); + break; + + case '%': + if ((unsigned) X_RD (insn) < 32) + (*info->fprintf_func) (stream, "%%%s", + v9_hpriv_reg_names[X_RD (insn)]); + else + (*info->fprintf_func) (stream, "%%reserved"); + break; + case '/': if (X_RS1 (insn) < 16 || X_RS1 (insn) > 25) (*info->fprintf_func) (stream, "%%reserved"); @@ -2856,16 +3071,16 @@ if (name) (*info->fprintf_func) (stream, "%s", name); else - (*info->fprintf_func) (stream, "%d", X_RD (insn)); + (*info->fprintf_func) (stream, "%ld", X_RD (insn)); break; } case 'M': - (*info->fprintf_func) (stream, "%%asr%d", X_RS1 (insn)); + (*info->fprintf_func) (stream, "%%asr%ld", X_RS1 (insn)); break; case 'm': - (*info->fprintf_func) (stream, "%%asr%d", X_RD (insn)); + (*info->fprintf_func) (stream, "%%asr%ld", X_RD (insn)); break; case 'L': @@ -2897,7 +3112,7 @@ if (name) (*info->fprintf_func) (stream, "%s", name); else - (*info->fprintf_func) (stream, "(%d)", X_ASI (insn)); + (*info->fprintf_func) (stream, "(%ld)", X_ASI (insn)); break; } @@ -2930,7 +3145,7 @@ break; case 'x': - (*info->fprintf_func) (stream, "%d", + (*info->fprintf_func) (stream, "%ld", ((X_LDST_I (insn) << 8) + X_ASI (insn))); break; @@ -2966,26 +3181,33 @@ unsigned long prev_insn; int errcode; - errcode = - (*info->read_memory_func) + if (memaddr >= 4) + errcode = + (*info->read_memory_func) (memaddr - 4, buffer, sizeof (buffer), info); + else + errcode = 1; + prev_insn = getword (buffer); if (errcode == 0) { /* If it is a delayed branch, we need to look at the instruction before the delayed branch. This handles - sequences such as + sequences such as: sethi %o1, %hi(_foo), %o1 call _printf - or %o1, %lo(_foo), %o1 - */ + or %o1, %lo(_foo), %o1 */ if (is_delayed_branch (prev_insn)) { - errcode = (*info->read_memory_func) - (memaddr - 8, buffer, sizeof (buffer), info); + if (memaddr >= 8) + errcode = (*info->read_memory_func) + (memaddr - 8, buffer, sizeof (buffer), info); + else + errcode = 1; + prev_insn = getword (buffer); } } @@ -3015,7 +3237,7 @@ if (opcode->flags & (F_UNBR|F_CONDBR|F_JSR)) { - /* FIXME -- check is_annulled flag */ + /* FIXME -- check is_annulled flag. */ if (opcode->flags & F_UNBR) info->insn_type = dis_branch; if (opcode->flags & F_CONDBR) @@ -3030,236 +3252,7 @@ } } - info->insn_type = dis_noninsn; /* Mark as non-valid instruction */ + info->insn_type = dis_noninsn; /* Mark as non-valid instruction. */ (*info->fprintf_func) (stream, _("unknown")); return sizeof (buffer); } - -/* Given BFD mach number, return a mask of SPARC_OPCODE_ARCH_FOO values. */ - -static int -compute_arch_mask (mach) - unsigned long mach; -{ - switch (mach) - { - case 0 : - case bfd_mach_sparc : - return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8); - case bfd_mach_sparc_sparclet : - return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET); - case bfd_mach_sparc_sparclite : - case bfd_mach_sparc_sparclite_le : - /* sparclites insns are recognized by default (because that's how - they've always been treated, for better or worse). Kludge this by - indicating generic v8 is also selected. */ - return (SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE) - | SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8)); - case bfd_mach_sparc_v8plus : - case bfd_mach_sparc_v9 : - return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9); - case bfd_mach_sparc_v8plusa : - case bfd_mach_sparc_v9a : - return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A); - case bfd_mach_sparc_v8plusb : - case bfd_mach_sparc_v9b : - return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9B); - } - abort (); -} - -/* Compare opcodes A and B. */ - -static int -compare_opcodes (const void *a, const void *b) -{ - struct sparc_opcode *op0 = * (struct sparc_opcode **) a; - struct sparc_opcode *op1 = * (struct sparc_opcode **) b; - unsigned long int match0 = op0->match, match1 = op1->match; - unsigned long int lose0 = op0->lose, lose1 = op1->lose; - register unsigned int i; - - /* If one (and only one) insn isn't supported by the current architecture, - prefer the one that is. If neither are supported, but they're both for - the same architecture, continue processing. Otherwise (both unsupported - and for different architectures), prefer lower numbered arch's (fudged - by comparing the bitmasks). */ - if (op0->architecture & current_arch_mask) - { - if (! (op1->architecture & current_arch_mask)) - return -1; - } - else - { - if (op1->architecture & current_arch_mask) - return 1; - else if (op0->architecture != op1->architecture) - return op0->architecture - op1->architecture; - } - - /* If a bit is set in both match and lose, there is something - wrong with the opcode table. */ - if (match0 & lose0) - { - fprintf - (stderr, - /* xgettext:c-format */ - _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"), - op0->name, match0, lose0); - op0->lose &= ~op0->match; - lose0 = op0->lose; - } - - if (match1 & lose1) - { - fprintf - (stderr, - /* xgettext:c-format */ - _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"), - op1->name, match1, lose1); - op1->lose &= ~op1->match; - lose1 = op1->lose; - } - - /* Because the bits that are variable in one opcode are constant in - another, it is important to order the opcodes in the right order. */ - for (i = 0; i < 32; ++i) - { - unsigned long int x = 1 << i; - int x0 = (match0 & x) != 0; - int x1 = (match1 & x) != 0; - - if (x0 != x1) - return x1 - x0; - } - - for (i = 0; i < 32; ++i) - { - unsigned long int x = 1 << i; - int x0 = (lose0 & x) != 0; - int x1 = (lose1 & x) != 0; - - if (x0 != x1) - return x1 - x0; - } - - /* They are functionally equal. So as long as the opcode table is - valid, we can put whichever one first we want, on aesthetic grounds. */ - - /* Our first aesthetic ground is that aliases defer to real insns. */ - { - int alias_diff = (op0->flags & F_ALIAS) - (op1->flags & F_ALIAS); - if (alias_diff != 0) - /* Put the one that isn't an alias first. */ - return alias_diff; - } - - /* Except for aliases, two "identical" instructions had - better have the same opcode. This is a sanity check on the table. */ - i = strcmp (op0->name, op1->name); - if (i) - { - if (op0->flags & F_ALIAS) /* If they're both aliases, be arbitrary. */ - return i; - else - fprintf (stderr, - /* xgettext:c-format */ - _("Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n"), - op0->name, op1->name); - } - - /* Fewer arguments are preferred. */ - { - int length_diff = strlen (op0->args) - strlen (op1->args); - if (length_diff != 0) - /* Put the one with fewer arguments first. */ - return length_diff; - } - - /* Put 1+i before i+1. */ - { - char *p0 = (char *) strchr (op0->args, '+'); - char *p1 = (char *) strchr (op1->args, '+'); - - if (p0 && p1) - { - /* There is a plus in both operands. Note that a plus - sign cannot be the first character in args, - so the following [-1]'s are valid. */ - if (p0[-1] == 'i' && p1[1] == 'i') - /* op0 is i+1 and op1 is 1+i, so op1 goes first. */ - return 1; - if (p0[1] == 'i' && p1[-1] == 'i') - /* op0 is 1+i and op1 is i+1, so op0 goes first. */ - return -1; - } - } - - /* Put 1,i before i,1. */ - { - int i0 = strncmp (op0->args, "i,1", 3) == 0; - int i1 = strncmp (op1->args, "i,1", 3) == 0; - - if (i0 ^ i1) - return i0 - i1; - } - - /* They are, as far as we can tell, identical. - Since qsort may have rearranged the table partially, there is - no way to tell which one was first in the opcode table as - written, so just say there are equal. */ - /* ??? This is no longer true now that we sort a vector of pointers, - not the table itself. */ - return 0; -} - -/* Build a hash table from the opcode table. - OPCODE_TABLE is a sorted list of pointers into the opcode table. */ - -static void -build_hash_table (opcode_table, hash_table, num_opcodes) - const struct sparc_opcode **opcode_table; - struct opcode_hash **hash_table; - int num_opcodes; -{ - register int i; - int hash_count[HASH_SIZE]; - static struct opcode_hash *hash_buf = NULL; - - /* Start at the end of the table and work backwards so that each - chain is sorted. */ - - memset (hash_table, 0, HASH_SIZE * sizeof (hash_table[0])); - memset (hash_count, 0, HASH_SIZE * sizeof (hash_count[0])); - if (hash_buf != NULL) - free (hash_buf); - hash_buf = (struct opcode_hash *) malloc (sizeof (struct opcode_hash) * num_opcodes); - for (i = num_opcodes - 1; i >= 0; --i) - { - register int hash = HASH_INSN (opcode_table[i]->match); - register struct opcode_hash *h = &hash_buf[i]; - h->next = hash_table[hash]; - h->opcode = opcode_table[i]; - hash_table[hash] = h; - ++hash_count[hash]; - } - -#if 0 /* for debugging */ - { - int min_count = num_opcodes, max_count = 0; - int total; - - for (i = 0; i < HASH_SIZE; ++i) - { - if (hash_count[i] < min_count) - min_count = hash_count[i]; - if (hash_count[i] > max_count) - max_count = hash_count[i]; - total += hash_count[i]; - } - - printf ("Opcode hash table stats: min %d, max %d, ave %f\n", - min_count, max_count, (double) total / HASH_SIZE); - } -#endif -} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/sysemu.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/sysemu.h --- qemu-0.9.1/sysemu.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/sysemu.h 2008-10-31 19:10:00.000000000 +0000 @@ -8,6 +8,8 @@ extern int vm_running; extern const char *qemu_name; +extern uint8_t qemu_uuid[]; +#define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" typedef struct vm_change_state_entry VMChangeStateEntry; typedef void VMChangeStateHandler(void *opaque, int running); @@ -30,23 +32,33 @@ void qemu_system_reset_request(void); void qemu_system_shutdown_request(void); void qemu_system_powerdown_request(void); -#if !defined(TARGET_SPARC) +int qemu_shutdown_requested(void); +int qemu_reset_requested(void); +int qemu_powerdown_requested(void); +#if !defined(TARGET_SPARC) && !defined(TARGET_I386) // Please implement a power failure function to signal the OS #define qemu_system_powerdown() do{}while(0) #else void qemu_system_powerdown(void); #endif - -void cpu_save(QEMUFile *f, void *opaque); -int cpu_load(QEMUFile *f, void *opaque, int version_id); +void qemu_system_reset(void); void do_savevm(const char *name); void do_loadvm(const char *name); void do_delvm(const char *name); void do_info_snapshots(void); +void qemu_announce_self(void); + void main_loop_wait(int timeout); +int qemu_savevm_state_begin(QEMUFile *f); +int qemu_savevm_state_iterate(QEMUFile *f); +int qemu_savevm_state_complete(QEMUFile *f); +int qemu_savevm_state(QEMUFile *f); +int qemu_loadvm_state(QEMUFile *f); + +#ifdef _WIN32 /* Polling handling */ /* return TRUE if no sleep should be done afterwards */ @@ -55,7 +67,6 @@ int qemu_add_polling_cb(PollingFunc *func, void *opaque); void qemu_del_polling_cb(PollingFunc *func, void *opaque); -#ifdef _WIN32 /* Wait objects handling */ typedef void WaitObjectFunc(void *opaque); @@ -69,15 +80,13 @@ /* SLIRP */ void do_info_slirp(void); -extern int ram_size; extern int bios_size; -extern int rtc_utc; -extern int rtc_start_date; extern int cirrus_vga_enabled; extern int vmsvga_enabled; extern int graphic_width; extern int graphic_height; extern int graphic_depth; +extern int nographic; extern const char *keyboard_layout; extern int win2k_install_hack; extern int alt_grab; @@ -87,10 +96,9 @@ extern int graphic_rotate; extern int no_quit; extern int semihosting_enabled; -extern int autostart; extern int old_param; extern const char *bootp_filename; - +extern DisplayState display_state; #ifdef USE_KQEMU extern int kqemu_allowed; @@ -106,8 +114,6 @@ extern unsigned int nb_prom_envs; #endif -/* XXX: make it dynamic */ -#define MAX_BIOS_SIZE (4 * 1024 * 1024) #if defined (TARGET_PPC) #define BIOS_SIZE (1024 * 1024) #elif defined (TARGET_SPARC64) @@ -131,8 +137,8 @@ #define MAX_SCSI_DEVS 7 #define MAX_DRIVES 32 -int nb_drives; -DriveInfo drives_table[MAX_DRIVES+1]; +extern int nb_drives; +extern DriveInfo drives_table[MAX_DRIVES+1]; extern int drive_get_index(BlockInterfaceType type, int bus, int unit); extern int drive_get_max_bus(BlockInterfaceType type); @@ -149,14 +155,23 @@ extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; +#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR) + #ifdef NEED_CPU_H /* loader.c */ int get_image_size(const char *filename); -int load_image(const char *filename, uint8_t *addr); -int load_elf(const char *filename, int64_t virt_to_phys_addend, +int load_image(const char *filename, uint8_t *addr); /* deprecated */ +int load_image_targphys(const char *filename, target_phys_addr_t, int max_sz); +int load_elf(const char *filename, int64_t address_offset, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr); -int load_aout(const char *filename, uint8_t *addr); +int load_aout(const char *filename, target_phys_addr_t addr, int max_sz); int load_uboot(const char *filename, target_ulong *ep, int *is_linux); + +int fread_targphys(target_phys_addr_t dst_addr, size_t nbytes, FILE *f); +int fread_targphys_ok(target_phys_addr_t dst_addr, size_t nbytes, FILE *f); +int read_targphys(int fd, target_phys_addr_t dst_addr, size_t nbytes); +void pstrcpy_targphys(target_phys_addr_t dest, int buf_size, + const char *source); #endif #ifdef HAS_AUDIO @@ -178,4 +193,11 @@ void do_usb_del(const char *devname); void usb_info(void); +const char *get_opt_name(char *buf, int buf_size, const char *p); +const char *get_opt_value(char *buf, int buf_size, const char *p); +int get_param_value(char *buf, int buf_size, + const char *tag, const char *str); +int check_params(char *buf, int buf_size, + const char * const *params, const char *str); + #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/sys-queue.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/sys-queue.h --- qemu-0.9.1/sys-queue.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/sys-queue.h 2008-07-29 21:08:37.000000000 +0100 @@ -0,0 +1,338 @@ +/* $NetBSD: queue.h,v 1.45.14.1 2007/07/18 20:13:24 liamjfoy Exp $ */ + +/* + * Qemu version: Copy from netbsd, removed debug code, removed some of + * the implementations. Left in lists, tail queues and circular queues. + */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines three types of data structures: + * lists, tail queues, and circular queues. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + (head)->lh_first = NULL; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (/*CONSTCOND*/0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = ((head)->lh_first); \ + (var); \ + (var) = ((var)->field.le_next)) + +/* + * List access methods. + */ +#define LIST_EMPTY(head) ((head)->lh_first == NULL) +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + + +/* + * Tail queue definitions. + */ +#define _TAILQ_HEAD(name, type, qual) \ +struct name { \ + qual type *tqh_first; /* first element */ \ + qual type *qual *tqh_last; /* addr of last next element */ \ +} +#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,) + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define _TAILQ_ENTRY(type, qual) \ +struct { \ + qual type *tqe_next; /* next element */ \ + qual type *qual *tqe_prev; /* address of previous next element */\ +} +#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->tqh_first); \ + (var); \ + (var) = ((var)->field.tqe_next)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \ + (var); \ + (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) + +/* + * Tail queue access methods. + */ +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { (void *)&head, (void *)&head } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = (void *)(head); \ + (head)->cqh_last = (void *)(head); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = (void *)(head); \ + if ((head)->cqh_last == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = (void *)(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->cqh_first); \ + (var) != (const void *)(head); \ + (var) = ((var)->field.cqe_next)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for ((var) = ((head)->cqh_last); \ + (var) != (const void *)(head); \ + (var) = ((var)->field.cqe_prev)) + +/* + * Circular queue access methods. + */ +#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) + +#define CIRCLEQ_LOOP_NEXT(head, elm, field) \ + (((elm)->field.cqe_next == (void *)(head)) \ + ? ((head)->cqh_first) \ + : (elm->field.cqe_next)) +#define CIRCLEQ_LOOP_PREV(head, elm, field) \ + (((elm)->field.cqe_prev == (void *)(head)) \ + ? ((head)->cqh_last) \ + : (elm->field.cqe_prev)) + +#endif /* !_SYS_QUEUE_H_ */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tap-win32.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tap-win32.c --- qemu-0.9.1/tap-win32.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/tap-win32.c 2008-11-06 09:38:51.000000000 +0000 @@ -77,7 +77,7 @@ // Compile time configuration //====================== -//#define DEBUG_TAP_WIN32 1 +//#define DEBUG_TAP_WIN32 #define TUN_ASYNCHRONOUS_WRITES 1 @@ -509,7 +509,7 @@ result = GetOverlappedResult( overlapped->handle, &overlapped->read_overlapped, &read_size, FALSE); if (!result) { -#if DEBUG_TAP_WIN32 +#ifdef DEBUG_TAP_WIN32 LPVOID lpBuffer; dwError = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, @@ -520,7 +520,7 @@ #endif } } else { -#if DEBUG_TAP_WIN32 +#ifdef DEBUG_TAP_WIN32 LPVOID lpBuffer; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-alpha/cpu.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-alpha/cpu.h --- qemu-0.9.1/target-alpha/cpu.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-alpha/cpu.h 2008-09-29 18:21:28.000000000 +0100 @@ -269,27 +269,21 @@ uint64_t ps; uint64_t unique; int saved_mode; /* Used for HW_LD / HW_ST */ + int intr_flag; /* For RC and RS */ #if TARGET_LONG_BITS > HOST_LONG_BITS /* temporary fixed-point registers * used to emulate 64 bits target on 32 bits hosts */ - target_ulong t0, t1, t2; + target_ulong t0, t1; #endif - /* */ - double ft0, ft1, ft2; /* Those resources are used only in Qemu core */ CPU_COMMON - jmp_buf jmp_env; - int user_mode_only; /* user mode only simulation */ uint32_t hflags; - int halted; - int exception_index; int error_code; - int interrupt_request; uint32_t features; uint32_t amask; @@ -314,6 +308,15 @@ return (env->ps >> 3) & 3; } +#if defined(CONFIG_USER_ONLY) +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) +{ + if (newsp) + env->ir[30] = newsp; + /* FIXME: Zero syscall return value. */ +} +#endif + #include "cpu-all.h" enum { @@ -407,6 +410,12 @@ int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp); void cpu_loop_exit (void); void pal_init (CPUState *env); +#if !defined (CONFIG_USER_ONLY) +void call_pal (CPUState *env); +#else void call_pal (CPUState *env, int palcode); +#endif + +#define CPU_PC_FROM_TB(env, tb) env->pc = tb->pc #endif /* !defined (__CPU_ALPHA_H__) */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-alpha/exec.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-alpha/exec.h --- qemu-0.9.1/target-alpha/exec.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-alpha/exec.h 2008-09-30 07:45:44.000000000 +0100 @@ -29,34 +29,10 @@ register struct CPUAlphaState *env asm(AREG0); -#if TARGET_LONG_BITS > HOST_LONG_BITS - -/* no registers can be used */ -#define T0 (env->t0) -#define T1 (env->t1) -#define T2 (env->t2) - -#else - -register uint64_t T0 asm(AREG1); -register uint64_t T1 asm(AREG2); -register uint64_t T2 asm(AREG3); - -#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ - #define PARAM(n) ((uint64_t)PARAM##n) #define SPARAM(n) ((int32_t)PARAM##n) -#define FT0 (env->ft0) -#define FT1 (env->ft1) -#define FT2 (env->ft2) #define FP_STATUS (env->fp_status) -#if defined (DEBUG_OP) -#define RETURN() __asm__ __volatile__("nop" : : : "memory"); -#else -#define RETURN() __asm__ __volatile__("" : : : "memory"); -#endif - #include "cpu.h" #include "exec-all.h" @@ -74,8 +50,6 @@ int cpu_alpha_handle_mmu_fault (CPUState *env, uint64_t address, int rw, int mmu_idx, int is_softmmu); -int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp); -int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp); void do_interrupt (CPUState *env); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-alpha/helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-alpha/helper.c --- qemu-0.9.1/target-alpha/helper.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-alpha/helper.c 2008-11-07 14:00:24.000000000 +0000 @@ -411,7 +411,7 @@ int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) { - static unsigned char *linux_reg_names[] = { + static const char *linux_reg_names[] = { "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ", "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ", "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ", @@ -434,21 +434,6 @@ if ((i % 3) == 2) cpu_fprintf(f, "\n"); } - cpu_fprintf(f, "FT " TARGET_FMT_lx " " TARGET_FMT_lx " " TARGET_FMT_lx, - *((uint64_t *)(&env->ft0)), *((uint64_t *)(&env->ft1)), - *((uint64_t *)(&env->ft2))); - cpu_fprintf(f, "\nMEM " TARGET_FMT_lx " %d %d\n", - ldq_raw(0x000000004007df60ULL), - (uint8_t *)(&env->ft0), (uint8_t *)(&env->fir[0])); + cpu_fprintf(f, "\nlock " TARGET_FMT_lx "\n", env->lock); } -void cpu_dump_EA (target_ulong EA) -{ - FILE *f; - - if (logfile) - f = logfile; - else - f = stdout; - fprintf(f, "Memory access at address " TARGET_FMT_lx "\n", EA); -} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-alpha/helper.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-alpha/helper.h --- qemu-0.9.1/target-alpha/helper.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-alpha/helper.h 2008-09-30 07:45:44.000000000 +0100 @@ -0,0 +1,133 @@ +#ifndef DEF_HELPER +#define DEF_HELPER(ret, name, params) ret name params; +#endif + +DEF_HELPER(void, helper_tb_flush, (void)) + +DEF_HELPER(void, helper_excp, (int, int)) +DEF_HELPER(uint64_t, helper_amask, (uint64_t)) +DEF_HELPER(uint64_t, helper_load_pcc, (void)) +DEF_HELPER(uint64_t, helper_load_implver, (void)) +DEF_HELPER(uint64_t, helper_rc, (void)) +DEF_HELPER(uint64_t, helper_rs, (void)) + +DEF_HELPER(uint64_t, helper_addqv, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_addlv, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_subqv, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_sublv, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_mullv, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_mulqv, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_umulh, (uint64_t, uint64_t)) + +DEF_HELPER(uint64_t, helper_ctpop, (uint64_t)) +DEF_HELPER(uint64_t, helper_ctlz, (uint64_t)) +DEF_HELPER(uint64_t, helper_cttz, (uint64_t)) + +DEF_HELPER(uint64_t, helper_mskbl, (int64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_insbl, (int64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_mskwl, (int64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_inswl, (int64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_mskll, (int64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_insll, (int64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_zap, (int64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_zapnot, (int64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_mskql, (int64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_insql, (int64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_mskwh, (int64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_inswh, (int64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_msklh, (int64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_inslh, (int64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_mskqh, (int64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_insqh, (int64_t, uint64_t)) + +DEF_HELPER(uint64_t, helper_cmpbge, (uint64_t, uint64_t)) + +DEF_HELPER(uint64_t, helper_load_fpcr, (void)) +DEF_HELPER(void, helper_store_fpcr, (uint64_t val)) + +DEF_HELPER(uint32_t, helper_f_to_memory, (uint64_t s)) +DEF_HELPER(uint64_t, helper_memory_to_f, (uint32_t s)) +DEF_HELPER(uint64_t, helper_addf, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_subf, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_mulf, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_divf, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_sqrtf, (uint64_t)) + +DEF_HELPER(uint64_t, helper_g_to_memory, (uint64_t s)) +DEF_HELPER(uint64_t, helper_memory_to_g, (uint64_t s)) +DEF_HELPER(uint64_t, helper_addg, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_subg, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_mulg, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_divg, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_sqrtg, (uint64_t)) + +DEF_HELPER(uint32_t, helper_s_to_memory, (uint64_t s)) +DEF_HELPER(uint64_t, helper_memory_to_s, (uint32_t s)) +DEF_HELPER(uint64_t, helper_adds, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_subs, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_muls, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_divs, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_sqrts, (uint64_t)) + +DEF_HELPER(uint64_t, helper_addt, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_subt, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_mult, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_divt, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_sqrtt, (uint64_t)) + +DEF_HELPER(uint64_t, helper_cmptun, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_cmpteq, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_cmptle, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_cmptlt, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_cmpgeq, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_cmpgle, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_cmpglt, (uint64_t, uint64_t)) + +DEF_HELPER(uint64_t, helper_cmpfeq, (uint64_t)) +DEF_HELPER(uint64_t, helper_cmpfne, (uint64_t)) +DEF_HELPER(uint64_t, helper_cmpflt, (uint64_t)) +DEF_HELPER(uint64_t, helper_cmpfle, (uint64_t)) +DEF_HELPER(uint64_t, helper_cmpfgt, (uint64_t)) +DEF_HELPER(uint64_t, helper_cmpfge, (uint64_t)) + +DEF_HELPER(uint64_t, helper_cpys, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_cpysn, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_cpyse, (uint64_t, uint64_t)) + +DEF_HELPER(uint64_t, helper_cvtts, (uint64_t)) +DEF_HELPER(uint64_t, helper_cvtst, (uint64_t)) +DEF_HELPER(uint64_t, helper_cvttq, (uint64_t)) +DEF_HELPER(uint32_t, helper_cvtqs, (uint64_t)) +DEF_HELPER(uint64_t, helper_cvtqt, (uint64_t)) +DEF_HELPER(uint64_t, helper_cvtqf, (uint64_t)) +DEF_HELPER(uint64_t, helper_cvtgf, (uint64_t)) +DEF_HELPER(uint64_t, helper_cvtgq, (uint64_t)) +DEF_HELPER(uint64_t, helper_cvtqg, (uint64_t)) +DEF_HELPER(uint64_t, helper_cvtlq, (uint64_t)) +DEF_HELPER(uint64_t, helper_cvtql, (uint64_t)) +DEF_HELPER(uint64_t, helper_cvtqlv, (uint64_t)) +DEF_HELPER(uint64_t, helper_cvtqlsv, (uint64_t)) + +#if !defined (CONFIG_USER_ONLY) +DEF_HELPER(void, helper_hw_rei, (void)) +DEF_HELPER(void, helper_hw_ret, (uint64_t)) +DEF_HELPER(uint64_t, helper_mfpr, (int, uint64_t)) +DEF_HELPER(void, helper_mtpr, (int, uint64_t)) +DEF_HELPER(void, helper_set_alt_mode, (void)) +DEF_HELPER(void, helper_restore_mode, (void)) + +DEF_HELPER(uint64_t, helper_ld_virt_to_phys, (uint64_t)) +DEF_HELPER(uint64_t, helper_st_virt_to_phys, (uint64_t)) +DEF_HELPER(void, helper_ldl_raw, (uint64_t, uint64_t)) +DEF_HELPER(void, helper_ldq_raw, (uint64_t, uint64_t)) +DEF_HELPER(void, helper_ldl_l_raw, (uint64_t, uint64_t)) +DEF_HELPER(void, helper_ldq_l_raw, (uint64_t, uint64_t)) +DEF_HELPER(void, helper_ldl_kernel, (uint64_t, uint64_t)) +DEF_HELPER(void, helper_ldq_kernel, (uint64_t, uint64_t)) +DEF_HELPER(void, helper_ldl_data, (uint64_t, uint64_t)) +DEF_HELPER(void, helper_ldq_data, (uint64_t, uint64_t)) +DEF_HELPER(void, helper_stl_raw, (uint64_t, uint64_t)) +DEF_HELPER(void, helper_stq_raw, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_stl_c_raw, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_stq_c_raw, (uint64_t, uint64_t)) +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-alpha/op.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-alpha/op.c --- qemu-0.9.1/target-alpha/op.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-alpha/op.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,1111 +0,0 @@ -/* - * Alpha emulation cpu micro-operations for qemu. - * - * Copyright (c) 2007 Jocelyn Mayer - * - * 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 - */ - -#define DEBUG_OP - -#include "config.h" -#include "exec.h" -#include "host-utils.h" - -#include "op_helper.h" - -#define REG 0 -#include "op_template.h" - -#define REG 1 -#include "op_template.h" - -#define REG 2 -#include "op_template.h" - -#define REG 3 -#include "op_template.h" - -#define REG 4 -#include "op_template.h" - -#define REG 5 -#include "op_template.h" - -#define REG 6 -#include "op_template.h" - -#define REG 7 -#include "op_template.h" - -#define REG 8 -#include "op_template.h" - -#define REG 9 -#include "op_template.h" - -#define REG 10 -#include "op_template.h" - -#define REG 11 -#include "op_template.h" - -#define REG 12 -#include "op_template.h" - -#define REG 13 -#include "op_template.h" - -#define REG 14 -#include "op_template.h" - -#define REG 15 -#include "op_template.h" - -#define REG 16 -#include "op_template.h" - -#define REG 17 -#include "op_template.h" - -#define REG 18 -#include "op_template.h" - -#define REG 19 -#include "op_template.h" - -#define REG 20 -#include "op_template.h" - -#define REG 21 -#include "op_template.h" - -#define REG 22 -#include "op_template.h" - -#define REG 23 -#include "op_template.h" - -#define REG 24 -#include "op_template.h" - -#define REG 25 -#include "op_template.h" - -#define REG 26 -#include "op_template.h" - -#define REG 27 -#include "op_template.h" - -#define REG 28 -#include "op_template.h" - -#define REG 29 -#include "op_template.h" - -#define REG 30 -#include "op_template.h" - -#define REG 31 -#include "op_template.h" - -/* Debug stuff */ -void OPPROTO op_no_op (void) -{ -#if !defined (DEBUG_OP) - __asm__ __volatile__("nop" : : : "memory"); -#endif - RETURN(); -} - -void OPPROTO op_tb_flush (void) -{ - helper_tb_flush(); - RETURN(); -} - -/* Load and stores */ -#define MEMSUFFIX _raw -#include "op_mem.h" -#if !defined(CONFIG_USER_ONLY) -#define MEMSUFFIX _kernel -#include "op_mem.h" -#define MEMSUFFIX _executive -#include "op_mem.h" -#define MEMSUFFIX _supervisor -#include "op_mem.h" -#define MEMSUFFIX _user -#include "op_mem.h" -/* This is used for pal modes */ -#define MEMSUFFIX _data -#include "op_mem.h" -#endif - -/* Special operation for load and store */ -void OPPROTO op_n7 (void) -{ - T0 &= ~(uint64_t)0x7; - RETURN(); -} - -/* Misc */ -void OPPROTO op_excp (void) -{ - helper_excp(PARAM(1), PARAM(2)); - RETURN(); -} - -void OPPROTO op_load_amask (void) -{ - helper_amask(); - RETURN(); -} - -void OPPROTO op_load_pcc (void) -{ - helper_load_pcc(); - RETURN(); -} - -void OPPROTO op_load_implver (void) -{ - helper_load_implver(); - RETURN(); -} - -void OPPROTO op_load_fpcr (void) -{ - helper_load_fpcr(); - RETURN(); -} - -void OPPROTO op_store_fpcr (void) -{ - helper_store_fpcr(); - RETURN(); -} - -void OPPROTO op_load_irf (void) -{ - helper_load_irf(); - RETURN(); -} - -void OPPROTO op_set_irf (void) -{ - helper_set_irf(); - RETURN(); -} - -void OPPROTO op_clear_irf (void) -{ - helper_clear_irf(); - RETURN(); -} - -void OPPROTO op_exit_tb (void) -{ - EXIT_TB(); -} - -/* Arithmetic */ -void OPPROTO op_addq (void) -{ - T0 += T1; - RETURN(); -} - -void OPPROTO op_addqv (void) -{ - helper_addqv(); - RETURN(); -} - -void OPPROTO op_addl (void) -{ - T0 = (int64_t)((int32_t)(T0 + T1)); - RETURN(); -} - -void OPPROTO op_addlv (void) -{ - helper_addlv(); - RETURN(); -} - -void OPPROTO op_subq (void) -{ - T0 -= T1; - RETURN(); -} - -void OPPROTO op_subqv (void) -{ - helper_subqv(); - RETURN(); -} - -void OPPROTO op_subl (void) -{ - T0 = (int64_t)((int32_t)(T0 - T1)); - RETURN(); -} - -void OPPROTO op_sublv (void) -{ - helper_sublv(); - RETURN(); -} - -void OPPROTO op_s4 (void) -{ - T0 <<= 2; - RETURN(); -} - -void OPPROTO op_s8 (void) -{ - T0 <<= 3; - RETURN(); -} - -void OPPROTO op_mull (void) -{ - T0 = (int64_t)((int32_t)T0 * (int32_t)T1); - RETURN(); -} - -void OPPROTO op_mullv (void) -{ - helper_mullv(); - RETURN(); -} - -void OPPROTO op_mulq (void) -{ - T0 = (int64_t)T0 * (int64_t)T1; - RETURN(); -} - -void OPPROTO op_mulqv (void) -{ - helper_mulqv(); - RETURN(); -} - -void OPPROTO op_umulh (void) -{ - uint64_t tl, th; - - mulu64(&tl, &th, T0, T1); - T0 = th; - RETURN(); -} - -/* Logical */ -void OPPROTO op_and (void) -{ - T0 &= T1; - RETURN(); -} - -void OPPROTO op_bic (void) -{ - T0 &= ~T1; - RETURN(); -} - -void OPPROTO op_bis (void) -{ - T0 |= T1; - RETURN(); -} - -void OPPROTO op_eqv (void) -{ - T0 ^= ~T1; - RETURN(); -} - -void OPPROTO op_ornot (void) -{ - T0 |= ~T1; - RETURN(); -} - -void OPPROTO op_xor (void) -{ - T0 ^= T1; - RETURN(); -} - -void OPPROTO op_sll (void) -{ - T0 <<= T1; - RETURN(); -} - -void OPPROTO op_srl (void) -{ - T0 >>= T1; - RETURN(); -} - -void OPPROTO op_sra (void) -{ - T0 = (int64_t)T0 >> T1; - RETURN(); -} - -void OPPROTO op_sextb (void) -{ - T0 = (int64_t)((int8_t)T0); - RETURN(); -} - -void OPPROTO op_sextw (void) -{ - T0 = (int64_t)((int16_t)T0); - RETURN(); - -} - -void OPPROTO op_ctpop (void) -{ - helper_ctpop(); - RETURN(); -} - -void OPPROTO op_ctlz (void) -{ - helper_ctlz(); - RETURN(); -} - -void OPPROTO op_cttz (void) -{ - helper_cttz(); - RETURN(); -} - -void OPPROTO op_mskbl (void) -{ - helper_mskbl(); - RETURN(); -} - -void OPPROTO op_extbl (void) -{ - helper_extbl(); - RETURN(); -} - -void OPPROTO op_insbl (void) -{ - helper_insbl(); - RETURN(); -} - -void OPPROTO op_mskwl (void) -{ - helper_mskwl(); - RETURN(); -} - -void OPPROTO op_extwl (void) -{ - helper_extwl(); - RETURN(); -} - -void OPPROTO op_inswl (void) -{ - helper_inswl(); - RETURN(); -} - -void OPPROTO op_mskll (void) -{ - helper_mskll(); - RETURN(); -} - -void OPPROTO op_extll (void) -{ - helper_extll(); - RETURN(); -} - -void OPPROTO op_insll (void) -{ - helper_insll(); - RETURN(); -} - -void OPPROTO op_zap (void) -{ - helper_zap(); - RETURN(); -} - -void OPPROTO op_zapnot (void) -{ - helper_zapnot(); - RETURN(); -} - -void OPPROTO op_mskql (void) -{ - helper_mskql(); - RETURN(); -} - -void OPPROTO op_extql (void) -{ - helper_extql(); - RETURN(); -} - -void OPPROTO op_insql (void) -{ - helper_insql(); - RETURN(); -} - -void OPPROTO op_mskwh (void) -{ - helper_mskwh(); - RETURN(); -} - -void OPPROTO op_inswh (void) -{ - helper_inswh(); - RETURN(); -} - -void OPPROTO op_extwh (void) -{ - helper_extwh(); - RETURN(); -} - -void OPPROTO op_msklh (void) -{ - helper_msklh(); - RETURN(); -} - -void OPPROTO op_inslh (void) -{ - helper_inslh(); - RETURN(); -} - -void OPPROTO op_extlh (void) -{ - helper_extlh(); - RETURN(); -} - -void OPPROTO op_mskqh (void) -{ - helper_mskqh(); - RETURN(); -} - -void OPPROTO op_insqh (void) -{ - helper_insqh(); - RETURN(); -} - -void OPPROTO op_extqh (void) -{ - helper_extqh(); - RETURN(); -} - -/* Tests */ -void OPPROTO op_cmpult (void) -{ - if (T0 < T1) - T0 = 1; - else - T0 = 0; - RETURN(); -} - -void OPPROTO op_cmpule (void) -{ - if (T0 <= T1) - T0 = 1; - else - T0 = 0; - RETURN(); -} - -void OPPROTO op_cmpeq (void) -{ - if (T0 == T1) - T0 = 1; - else - T0 = 0; - RETURN(); -} - -void OPPROTO op_cmplt (void) -{ - if ((int64_t)T0 < (int64_t)T1) - T0 = 1; - else - T0 = 0; - RETURN(); -} - -void OPPROTO op_cmple (void) -{ - if ((int64_t)T0 <= (int64_t)T1) - T0 = 1; - else - T0 = 0; - RETURN(); -} - -void OPPROTO op_cmpbge (void) -{ - helper_cmpbge(); - RETURN(); -} - -void OPPROTO op_cmpeqz (void) -{ - if (T0 == 0) - T0 = 1; - else - T0 = 0; - RETURN(); -} - -void OPPROTO op_cmpnez (void) -{ - if (T0 != 0) - T0 = 1; - else - T0 = 0; - RETURN(); -} - -void OPPROTO op_cmpltz (void) -{ - if ((int64_t)T0 < 0) - T0 = 1; - else - T0 = 0; - RETURN(); -} - -void OPPROTO op_cmplez (void) -{ - if ((int64_t)T0 <= 0) - T0 = 1; - else - T0 = 0; - RETURN(); -} - -void OPPROTO op_cmpgtz (void) -{ - if ((int64_t)T0 > 0) - T0 = 1; - else - T0 = 0; - RETURN(); -} - -void OPPROTO op_cmpgez (void) -{ - if ((int64_t)T0 >= 0) - T0 = 1; - else - T0 = 0; - RETURN(); -} - -void OPPROTO op_cmplbs (void) -{ - T0 &= 1; - RETURN(); -} - -void OPPROTO op_cmplbc (void) -{ - T0 = (~T0) & 1; - RETURN(); -} - -/* Branches */ -void OPPROTO op_branch (void) -{ - env->pc = T0 & ~3; - RETURN(); -} - -void OPPROTO op_addq1 (void) -{ - T1 += T0; - RETURN(); -} - -#if 0 // Qemu does not know how to do this... -void OPPROTO op_bcond (void) -{ - if (T0) - env->pc = T1 & ~3; - else - env->pc = PARAM(1); - RETURN(); -} -#else -void OPPROTO op_bcond (void) -{ - if (T0) - env->pc = T1 & ~3; - else - env->pc = ((uint64_t)PARAM(1) << 32) | (uint64_t)PARAM(2); - RETURN(); -} -#endif - -#if 0 // Qemu does not know how to do this... -void OPPROTO op_update_pc (void) -{ - env->pc = PARAM(1); - RETURN(); -} -#else -void OPPROTO op_update_pc (void) -{ - env->pc = ((uint64_t)PARAM(1) << 32) | (uint64_t)PARAM(2); - RETURN(); -} -#endif - -/* Optimization for 32 bits hosts architectures */ -void OPPROTO op_update_pc32 (void) -{ - env->pc = (uint64_t)PARAM(1); - RETURN(); -} - -/* IEEE floating point arithmetic */ -/* S floating (single) */ -void OPPROTO op_adds (void) -{ - FT0 = float32_add(FT0, FT1, &FP_STATUS); - RETURN(); -} - -void OPPROTO op_subs (void) -{ - FT0 = float32_sub(FT0, FT1, &FP_STATUS); - RETURN(); -} - -void OPPROTO op_muls (void) -{ - FT0 = float32_mul(FT0, FT1, &FP_STATUS); - RETURN(); -} - -void OPPROTO op_divs (void) -{ - FT0 = float32_div(FT0, FT1, &FP_STATUS); - RETURN(); -} - -void OPPROTO op_sqrts (void) -{ - helper_sqrts(); - RETURN(); -} - -void OPPROTO op_cpys (void) -{ - helper_cpys(); - RETURN(); -} - -void OPPROTO op_cpysn (void) -{ - helper_cpysn(); - RETURN(); -} - -void OPPROTO op_cpyse (void) -{ - helper_cpyse(); - RETURN(); -} - -void OPPROTO op_itofs (void) -{ - helper_itofs(); - RETURN(); -} - -void OPPROTO op_ftois (void) -{ - helper_ftois(); - RETURN(); -} - -/* T floating (double) */ -void OPPROTO op_addt (void) -{ - FT0 = float64_add(FT0, FT1, &FP_STATUS); - RETURN(); -} - -void OPPROTO op_subt (void) -{ - FT0 = float64_sub(FT0, FT1, &FP_STATUS); - RETURN(); -} - -void OPPROTO op_mult (void) -{ - FT0 = float64_mul(FT0, FT1, &FP_STATUS); - RETURN(); -} - -void OPPROTO op_divt (void) -{ - FT0 = float64_div(FT0, FT1, &FP_STATUS); - RETURN(); -} - -void OPPROTO op_sqrtt (void) -{ - helper_sqrtt(); - RETURN(); -} - -void OPPROTO op_cmptun (void) -{ - helper_cmptun(); - RETURN(); -} - -void OPPROTO op_cmpteq (void) -{ - helper_cmpteq(); - RETURN(); -} - -void OPPROTO op_cmptle (void) -{ - helper_cmptle(); - RETURN(); -} - -void OPPROTO op_cmptlt (void) -{ - helper_cmptlt(); - RETURN(); -} - -void OPPROTO op_itoft (void) -{ - helper_itoft(); - RETURN(); -} - -void OPPROTO op_ftoit (void) -{ - helper_ftoit(); - RETURN(); -} - -/* VAX floating point arithmetic */ -/* F floating */ -void OPPROTO op_addf (void) -{ - helper_addf(); - RETURN(); -} - -void OPPROTO op_subf (void) -{ - helper_subf(); - RETURN(); -} - -void OPPROTO op_mulf (void) -{ - helper_mulf(); - RETURN(); -} - -void OPPROTO op_divf (void) -{ - helper_divf(); - RETURN(); -} - -void OPPROTO op_sqrtf (void) -{ - helper_sqrtf(); - RETURN(); -} - -void OPPROTO op_cmpfeq (void) -{ - helper_cmpfeq(); - RETURN(); -} - -void OPPROTO op_cmpfne (void) -{ - helper_cmpfne(); - RETURN(); -} - -void OPPROTO op_cmpflt (void) -{ - helper_cmpflt(); - RETURN(); -} - -void OPPROTO op_cmpfle (void) -{ - helper_cmpfle(); - RETURN(); -} - -void OPPROTO op_cmpfgt (void) -{ - helper_cmpfgt(); - RETURN(); -} - -void OPPROTO op_cmpfge (void) -{ - helper_cmpfge(); - RETURN(); -} - -void OPPROTO op_itoff (void) -{ - helper_itoff(); - RETURN(); -} - -/* G floating */ -void OPPROTO op_addg (void) -{ - helper_addg(); - RETURN(); -} - -void OPPROTO op_subg (void) -{ - helper_subg(); - RETURN(); -} - -void OPPROTO op_mulg (void) -{ - helper_mulg(); - RETURN(); -} - -void OPPROTO op_divg (void) -{ - helper_divg(); - RETURN(); -} - -void OPPROTO op_sqrtg (void) -{ - helper_sqrtg(); - RETURN(); -} - -void OPPROTO op_cmpgeq (void) -{ - helper_cmpgeq(); - RETURN(); -} - -void OPPROTO op_cmpglt (void) -{ - helper_cmpglt(); - RETURN(); -} - -void OPPROTO op_cmpgle (void) -{ - helper_cmpgle(); - RETURN(); -} - -/* Floating point format conversion */ -void OPPROTO op_cvtst (void) -{ - FT0 = (float)FT0; - RETURN(); -} - -void OPPROTO op_cvtqs (void) -{ - helper_cvtqs(); - RETURN(); -} - -void OPPROTO op_cvtts (void) -{ - FT0 = (float)FT0; - RETURN(); -} - -void OPPROTO op_cvttq (void) -{ - helper_cvttq(); - RETURN(); -} - -void OPPROTO op_cvtqt (void) -{ - helper_cvtqt(); - RETURN(); -} - -void OPPROTO op_cvtqf (void) -{ - helper_cvtqf(); - RETURN(); -} - -void OPPROTO op_cvtgf (void) -{ - helper_cvtgf(); - RETURN(); -} - -void OPPROTO op_cvtgd (void) -{ - helper_cvtgd(); - RETURN(); -} - -void OPPROTO op_cvtgq (void) -{ - helper_cvtgq(); - RETURN(); -} - -void OPPROTO op_cvtqg (void) -{ - helper_cvtqg(); - RETURN(); -} - -void OPPROTO op_cvtdg (void) -{ - helper_cvtdg(); - RETURN(); -} - -void OPPROTO op_cvtlq (void) -{ - helper_cvtlq(); - RETURN(); -} - -void OPPROTO op_cvtql (void) -{ - helper_cvtql(); - RETURN(); -} - -void OPPROTO op_cvtqlv (void) -{ - helper_cvtqlv(); - RETURN(); -} - -void OPPROTO op_cvtqlsv (void) -{ - helper_cvtqlsv(); - RETURN(); -} - -/* PALcode support special instructions */ -#if !defined (CONFIG_USER_ONLY) -void OPPROTO op_hw_rei (void) -{ - env->pc = env->ipr[IPR_EXC_ADDR] & ~3; - env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1; - /* XXX: re-enable interrupts and memory mapping */ - RETURN(); -} - -void OPPROTO op_hw_ret (void) -{ - env->pc = T0 & ~3; - env->ipr[IPR_EXC_ADDR] = T0 & 1; - /* XXX: re-enable interrupts and memory mapping */ - RETURN(); -} - -void OPPROTO op_mfpr (void) -{ - helper_mfpr(PARAM(1)); - RETURN(); -} - -void OPPROTO op_mtpr (void) -{ - helper_mtpr(PARAM(1)); - RETURN(); -} - -void OPPROTO op_set_alt_mode (void) -{ - env->saved_mode = env->ps & 0xC; - env->ps = (env->ps & ~0xC) | (env->ipr[IPR_ALT_MODE] & 0xC); - RETURN(); -} - -void OPPROTO op_restore_mode (void) -{ - env->ps = (env->ps & ~0xC) | env->saved_mode; - RETURN(); -} - -void OPPROTO op_ld_phys_to_virt (void) -{ - helper_ld_phys_to_virt(); - RETURN(); -} - -void OPPROTO op_st_phys_to_virt (void) -{ - helper_st_phys_to_virt(); - RETURN(); -} -#endif /* !defined (CONFIG_USER_ONLY) */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-alpha/op_helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-alpha/op_helper.c --- qemu-0.9.1/target-alpha/op_helper.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-alpha/op_helper.c 2008-11-10 11:10:14.000000000 +0000 @@ -22,50 +22,21 @@ #include "host-utils.h" #include "softfloat.h" -#include "op_helper.h" - -#define MEMSUFFIX _raw -#include "op_helper_mem.h" - -#if !defined(CONFIG_USER_ONLY) -#define MEMSUFFIX _kernel -#include "op_helper_mem.h" - -#define MEMSUFFIX _executive -#include "op_helper_mem.h" - -#define MEMSUFFIX _supervisor -#include "op_helper_mem.h" - -#define MEMSUFFIX _user -#include "op_helper_mem.h" - -/* This is used for pal modes */ -#define MEMSUFFIX _data -#include "op_helper_mem.h" -#endif - void helper_tb_flush (void) { tlb_flush(env, 1); } -void cpu_dump_EA (target_ulong EA); -void helper_print_mem_EA (target_ulong EA) -{ - cpu_dump_EA(EA); -} - /*****************************************************************************/ /* Exceptions processing helpers */ -void helper_excp (uint32_t excp, uint32_t error) +void helper_excp (int excp, int error) { env->exception_index = excp; env->error_code = error; cpu_loop_exit(); } -void helper_amask (void) +uint64_t helper_amask (uint64_t arg) { switch (env->implver) { case IMPLVER_2106x: @@ -74,53 +45,55 @@ case IMPLVER_21164: case IMPLVER_21264: case IMPLVER_21364: - T0 &= ~env->amask; + arg &= ~env->amask; break; } + return arg; } -void helper_load_pcc (void) +uint64_t helper_load_pcc (void) { /* XXX: TODO */ - T0 = 0; + return 0; } -void helper_load_implver (void) +uint64_t helper_load_implver (void) { - T0 = env->implver; + return env->implver; } -void helper_load_fpcr (void) +uint64_t helper_load_fpcr (void) { - T0 = 0; + uint64_t ret = 0; #ifdef CONFIG_SOFTFLOAT - T0 |= env->fp_status.float_exception_flags << 52; + ret |= env->fp_status.float_exception_flags << 52; if (env->fp_status.float_exception_flags) - T0 |= 1ULL << 63; + ret |= 1ULL << 63; env->ipr[IPR_EXC_SUM] &= ~0x3E: env->ipr[IPR_EXC_SUM] |= env->fp_status.float_exception_flags << 1; #endif switch (env->fp_status.float_rounding_mode) { case float_round_nearest_even: - T0 |= 2ULL << 58; + ret |= 2ULL << 58; break; case float_round_down: - T0 |= 1ULL << 58; + ret |= 1ULL << 58; break; case float_round_up: - T0 |= 3ULL << 58; + ret |= 3ULL << 58; break; case float_round_to_zero: break; } + return ret; } -void helper_store_fpcr (void) +void helper_store_fpcr (uint64_t val) { #ifdef CONFIG_SOFTFLOAT - set_float_exception_flags((T0 >> 52) & 0x3F, &FP_STATUS); + set_float_exception_flags((val >> 52) & 0x3F, &FP_STATUS); #endif - switch ((T0 >> 58) & 3) { + switch ((val >> 58) & 3) { case 0: set_float_rounding_mode(float_round_to_zero, &FP_STATUS); break; @@ -136,93 +109,115 @@ } } -void helper_load_irf (void) -{ - /* XXX: TODO */ - T0 = 0; -} +spinlock_t intr_cpu_lock = SPIN_LOCK_UNLOCKED; -void helper_set_irf (void) +uint64_t helper_rs(void) { - /* XXX: TODO */ + uint64_t tmp; + + spin_lock(&intr_cpu_lock); + tmp = env->intr_flag; + env->intr_flag = 1; + spin_unlock(&intr_cpu_lock); + + return tmp; } -void helper_clear_irf (void) +uint64_t helper_rc(void) { - /* XXX: TODO */ + uint64_t tmp; + + spin_lock(&intr_cpu_lock); + tmp = env->intr_flag; + env->intr_flag = 0; + spin_unlock(&intr_cpu_lock); + + return tmp; } -void helper_addqv (void) +uint64_t helper_addqv (uint64_t op1, uint64_t op2) { - T2 = T0; - T0 += T1; - if (unlikely((T2 ^ T1 ^ (-1ULL)) & (T2 ^ T0) & (1ULL << 63))) { + uint64_t tmp = op1; + op1 += op2; + if (unlikely((tmp ^ op2 ^ (-1ULL)) & (tmp ^ op1) & (1ULL << 63))) { helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); } + return op1; } -void helper_addlv (void) +uint64_t helper_addlv (uint64_t op1, uint64_t op2) { - T2 = T0; - T0 = (uint32_t)(T0 + T1); - if (unlikely((T2 ^ T1 ^ (-1UL)) & (T2 ^ T0) & (1UL << 31))) { + uint64_t tmp = op1; + op1 = (uint32_t)(op1 + op2); + if (unlikely((tmp ^ op2 ^ (-1UL)) & (tmp ^ op1) & (1UL << 31))) { helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); } + return op1; } -void helper_subqv (void) +uint64_t helper_subqv (uint64_t op1, uint64_t op2) { - T2 = T0; - T0 -= T1; - if (unlikely(((~T2) ^ T0 ^ (-1ULL)) & ((~T2) ^ T1) & (1ULL << 63))) { + uint64_t tmp = op1; + op1 -= op2; + if (unlikely(((~tmp) ^ op1 ^ (-1ULL)) & ((~tmp) ^ op2) & (1ULL << 63))) { helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); } + return op1; } -void helper_sublv (void) +uint64_t helper_sublv (uint64_t op1, uint64_t op2) { - T2 = T0; - T0 = (uint32_t)(T0 - T1); - if (unlikely(((~T2) ^ T0 ^ (-1UL)) & ((~T2) ^ T1) & (1UL << 31))) { + uint64_t tmp = op1; + op1 = (uint32_t)(op1 - op2); + if (unlikely(((~tmp) ^ op1 ^ (-1UL)) & ((~tmp) ^ op2) & (1UL << 31))) { helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); } + return op1; } -void helper_mullv (void) +uint64_t helper_mullv (uint64_t op1, uint64_t op2) { - int64_t res = (int64_t)T0 * (int64_t)T1; + int64_t res = (int64_t)op1 * (int64_t)op2; if (unlikely((int32_t)res != res)) { helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); } - T0 = (int64_t)((int32_t)res); + return (int64_t)((int32_t)res); } -void helper_mulqv () +uint64_t helper_mulqv (uint64_t op1, uint64_t op2) { uint64_t tl, th; - muls64(&tl, &th, T0, T1); + muls64(&tl, &th, op1, op2); /* If th != 0 && th != -1, then we had an overflow */ if (unlikely((th + 1) > 1)) { helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); } - T0 = tl; + return tl; } -void helper_ctpop (void) +uint64_t helper_umulh (uint64_t op1, uint64_t op2) { - T0 = ctpop64(T0); + uint64_t tl, th; + + mulu64(&tl, &th, op1, op2); + return th; } -void helper_ctlz (void) +uint64_t helper_ctpop (uint64_t arg) { - T0 = clz64(T0); + return ctpop64(arg); } -void helper_cttz (void) +uint64_t helper_ctlz (uint64_t arg) { - T0 = ctz64(T0); + return clz64(arg); +} + +uint64_t helper_cttz (uint64_t arg) +{ + return ctz64(arg); } static always_inline uint64_t byte_zap (uint64_t op, uint8_t mskb) @@ -242,909 +237,927 @@ return op & ~mask; } -void helper_mskbl (void) +uint64_t helper_mskbl(uint64_t val, uint64_t mask) { - T0 = byte_zap(T0, 0x01 << (T1 & 7)); + return byte_zap(val, 0x01 << (mask & 7)); } -void helper_extbl (void) +uint64_t helper_insbl(uint64_t val, uint64_t mask) { - T0 >>= (T1 & 7) * 8; - T0 = byte_zap(T0, 0xFE); + val <<= (mask & 7) * 8; + return byte_zap(val, ~(0x01 << (mask & 7))); } -void helper_insbl (void) +uint64_t helper_mskwl(uint64_t val, uint64_t mask) { - T0 <<= (T1 & 7) * 8; - T0 = byte_zap(T0, ~(0x01 << (T1 & 7))); + return byte_zap(val, 0x03 << (mask & 7)); } -void helper_mskwl (void) +uint64_t helper_inswl(uint64_t val, uint64_t mask) { - T0 = byte_zap(T0, 0x03 << (T1 & 7)); + val <<= (mask & 7) * 8; + return byte_zap(val, ~(0x03 << (mask & 7))); } -void helper_extwl (void) +uint64_t helper_mskll(uint64_t val, uint64_t mask) { - T0 >>= (T1 & 7) * 8; - T0 = byte_zap(T0, 0xFC); + return byte_zap(val, 0x0F << (mask & 7)); } -void helper_inswl (void) +uint64_t helper_insll(uint64_t val, uint64_t mask) { - T0 <<= (T1 & 7) * 8; - T0 = byte_zap(T0, ~(0x03 << (T1 & 7))); + val <<= (mask & 7) * 8; + return byte_zap(val, ~(0x0F << (mask & 7))); } -void helper_mskll (void) +uint64_t helper_zap(uint64_t val, uint64_t mask) { - T0 = byte_zap(T0, 0x0F << (T1 & 7)); + return byte_zap(val, mask); } -void helper_extll (void) +uint64_t helper_zapnot(uint64_t val, uint64_t mask) { - T0 >>= (T1 & 7) * 8; - T0 = byte_zap(T0, 0xF0); + return byte_zap(val, ~mask); } -void helper_insll (void) +uint64_t helper_mskql(uint64_t val, uint64_t mask) { - T0 <<= (T1 & 7) * 8; - T0 = byte_zap(T0, ~(0x0F << (T1 & 7))); + return byte_zap(val, 0xFF << (mask & 7)); } -void helper_zap (void) +uint64_t helper_insql(uint64_t val, uint64_t mask) { - T0 = byte_zap(T0, T1); + val <<= (mask & 7) * 8; + return byte_zap(val, ~(0xFF << (mask & 7))); } -void helper_zapnot (void) +uint64_t helper_mskwh(uint64_t val, uint64_t mask) { - T0 = byte_zap(T0, ~T1); + return byte_zap(val, (0x03 << (mask & 7)) >> 8); } -void helper_mskql (void) +uint64_t helper_inswh(uint64_t val, uint64_t mask) { - T0 = byte_zap(T0, 0xFF << (T1 & 7)); + val >>= 64 - ((mask & 7) * 8); + return byte_zap(val, ~((0x03 << (mask & 7)) >> 8)); } -void helper_extql (void) +uint64_t helper_msklh(uint64_t val, uint64_t mask) { - T0 >>= (T1 & 7) * 8; - T0 = byte_zap(T0, 0x00); + return byte_zap(val, (0x0F << (mask & 7)) >> 8); } -void helper_insql (void) +uint64_t helper_inslh(uint64_t val, uint64_t mask) { - T0 <<= (T1 & 7) * 8; - T0 = byte_zap(T0, ~(0xFF << (T1 & 7))); + val >>= 64 - ((mask & 7) * 8); + return byte_zap(val, ~((0x0F << (mask & 7)) >> 8)); } -void helper_mskwh (void) +uint64_t helper_mskqh(uint64_t val, uint64_t mask) { - T0 = byte_zap(T0, (0x03 << (T1 & 7)) >> 8); + return byte_zap(val, (0xFF << (mask & 7)) >> 8); } -void helper_inswh (void) +uint64_t helper_insqh(uint64_t val, uint64_t mask) { - T0 >>= 64 - ((T1 & 7) * 8); - T0 = byte_zap(T0, ~((0x03 << (T1 & 7)) >> 8)); + val >>= 64 - ((mask & 7) * 8); + return byte_zap(val, ~((0xFF << (mask & 7)) >> 8)); } -void helper_extwh (void) +uint64_t helper_cmpbge (uint64_t op1, uint64_t op2) { - T0 <<= 64 - ((T1 & 7) * 8); - T0 = byte_zap(T0, ~0x07); -} + uint8_t opa, opb, res; + int i; -void helper_msklh (void) -{ - T0 = byte_zap(T0, (0x0F << (T1 & 7)) >> 8); + res = 0; + for (i = 0; i < 8; i++) { + opa = op1 >> (i * 8); + opb = op2 >> (i * 8); + if (opa >= opb) + res |= 1 << i; + } + return res; } -void helper_inslh (void) -{ - T0 >>= 64 - ((T1 & 7) * 8); - T0 = byte_zap(T0, ~((0x0F << (T1 & 7)) >> 8)); -} +/* Floating point helpers */ -void helper_extlh (void) +/* F floating (VAX) */ +static always_inline uint64_t float32_to_f (float32 fa) { - T0 <<= 64 - ((T1 & 7) * 8); - T0 = byte_zap(T0, ~0x0F); + uint32_t a; + uint64_t r, exp, mant, sig; + + a = *(uint32_t*)(&fa); + sig = ((uint64_t)a & 0x80000000) << 32; + exp = (a >> 23) & 0xff; + mant = ((uint64_t)a & 0x007fffff) << 29; + + if (exp == 255) { + /* NaN or infinity */ + r = 1; /* VAX dirty zero */ + } else if (exp == 0) { + if (mant == 0) { + /* Zero */ + r = 0; + } else { + /* Denormalized */ + r = sig | ((exp + 1) << 52) | mant; + } + } else { + if (exp >= 253) { + /* Overflow */ + r = 1; /* VAX dirty zero */ + } else { + r = sig | ((exp + 2) << 52); + } + } + + return r; } -void helper_mskqh (void) +static always_inline float32 f_to_float32 (uint64_t a) { - T0 = byte_zap(T0, (0xFF << (T1 & 7)) >> 8); + uint32_t r, exp, mant_sig; + + exp = ((a >> 55) & 0x80) | ((a >> 52) & 0x7f); + mant_sig = ((a >> 32) & 0x80000000) | ((a >> 29) & 0x007fffff); + + if (unlikely(!exp && mant_sig)) { + /* Reserved operands / Dirty zero */ + helper_excp(EXCP_OPCDEC, 0); + } + + if (exp < 3) { + /* Underflow */ + r = 0; + } else { + r = ((exp - 2) << 23) | mant_sig; + } + + return *(float32*)(&a); } -void helper_insqh (void) +uint32_t helper_f_to_memory (uint64_t a) { - T0 >>= 64 - ((T1 & 7) * 8); - T0 = byte_zap(T0, ~((0xFF << (T1 & 7)) >> 8)); + uint32_t r; + r = (a & 0x00001fffe0000000ull) >> 13; + r |= (a & 0x07ffe00000000000ull) >> 45; + r |= (a & 0xc000000000000000ull) >> 48; + return r; } -void helper_extqh (void) +uint64_t helper_memory_to_f (uint32_t a) { - T0 <<= 64 - ((T1 & 7) * 8); - T0 = byte_zap(T0, 0x00); + uint64_t r; + r = ((uint64_t)(a & 0x0000c000)) << 48; + r |= ((uint64_t)(a & 0x003fffff)) << 45; + r |= ((uint64_t)(a & 0xffff0000)) << 13; + if (!(a & 0x00004000)) + r |= 0x7ll << 59; + return r; } -void helper_cmpbge (void) +uint64_t helper_addf (uint64_t a, uint64_t b) { - uint8_t opa, opb, res; - int i; + float32 fa, fb, fr; - res = 0; - for (i = 0; i < 7; i++) { - opa = T0 >> (i * 8); - opb = T1 >> (i * 8); - if (opa >= opb) - res |= 1 << i; - } - T0 = res; + fa = f_to_float32(a); + fb = f_to_float32(b); + fr = float32_add(fa, fb, &FP_STATUS); + return float32_to_f(fr); } -void helper_cmov_fir (int freg) +uint64_t helper_subf (uint64_t a, uint64_t b) { - if (FT0 != 0) - env->fir[freg] = FT1; -} + float32 fa, fb, fr; -void helper_sqrts (void) -{ - FT0 = float32_sqrt(FT0, &FP_STATUS); + fa = f_to_float32(a); + fb = f_to_float32(b); + fr = float32_sub(fa, fb, &FP_STATUS); + return float32_to_f(fr); } -void helper_cpys (void) +uint64_t helper_mulf (uint64_t a, uint64_t b) { - union { - double d; - uint64_t i; - } p, q, r; + float32 fa, fb, fr; - p.d = FT0; - q.d = FT1; - r.i = p.i & 0x8000000000000000ULL; - r.i |= q.i & ~0x8000000000000000ULL; - FT0 = r.d; + fa = f_to_float32(a); + fb = f_to_float32(b); + fr = float32_mul(fa, fb, &FP_STATUS); + return float32_to_f(fr); } -void helper_cpysn (void) +uint64_t helper_divf (uint64_t a, uint64_t b) { - union { - double d; - uint64_t i; - } p, q, r; + float32 fa, fb, fr; - p.d = FT0; - q.d = FT1; - r.i = (~p.i) & 0x8000000000000000ULL; - r.i |= q.i & ~0x8000000000000000ULL; - FT0 = r.d; + fa = f_to_float32(a); + fb = f_to_float32(b); + fr = float32_div(fa, fb, &FP_STATUS); + return float32_to_f(fr); } -void helper_cpyse (void) +uint64_t helper_sqrtf (uint64_t t) { - union { - double d; - uint64_t i; - } p, q, r; + float32 ft, fr; - p.d = FT0; - q.d = FT1; - r.i = p.i & 0xFFF0000000000000ULL; - r.i |= q.i & ~0xFFF0000000000000ULL; - FT0 = r.d; + ft = f_to_float32(t); + fr = float32_sqrt(ft, &FP_STATUS); + return float32_to_f(fr); } -void helper_itofs (void) + +/* G floating (VAX) */ +static always_inline uint64_t float64_to_g (float64 fa) { - union { - double d; - uint64_t i; - } p; + uint64_t a, r, exp, mant, sig; + + a = *(uint64_t*)(&fa); + sig = a & 0x8000000000000000ull; + exp = (a >> 52) & 0x7ff; + mant = a & 0x000fffffffffffffull; + + if (exp == 2047) { + /* NaN or infinity */ + r = 1; /* VAX dirty zero */ + } else if (exp == 0) { + if (mant == 0) { + /* Zero */ + r = 0; + } else { + /* Denormalized */ + r = sig | ((exp + 1) << 52) | mant; + } + } else { + if (exp >= 2045) { + /* Overflow */ + r = 1; /* VAX dirty zero */ + } else { + r = sig | ((exp + 2) << 52); + } + } - p.d = FT0; - FT0 = int64_to_float32(p.i, &FP_STATUS); + return r; } -void helper_ftois (void) +static always_inline float64 g_to_float64 (uint64_t a) { - union { - double d; - uint64_t i; - } p; + uint64_t r, exp, mant_sig; + + exp = (a >> 52) & 0x7ff; + mant_sig = a & 0x800fffffffffffffull; + + if (!exp && mant_sig) { + /* Reserved operands / Dirty zero */ + helper_excp(EXCP_OPCDEC, 0); + } - p.i = float32_to_int64(FT0, &FP_STATUS); - FT0 = p.d; + if (exp < 3) { + /* Underflow */ + r = 0; + } else { + r = ((exp - 2) << 52) | mant_sig; + } + + return *(float64*)(&a); } -void helper_sqrtt (void) +uint64_t helper_g_to_memory (uint64_t a) { - FT0 = float64_sqrt(FT0, &FP_STATUS); + uint64_t r; + r = (a & 0x000000000000ffffull) << 48; + r |= (a & 0x00000000ffff0000ull) << 16; + r |= (a & 0x0000ffff00000000ull) >> 16; + r |= (a & 0xffff000000000000ull) >> 48; + return r; } -void helper_cmptun (void) +uint64_t helper_memory_to_g (uint64_t a) { - union { - double d; - uint64_t i; - } p; - - p.i = 0; - if (float64_is_nan(FT0) || float64_is_nan(FT1)) - p.i = 0x4000000000000000ULL; - FT0 = p.d; + uint64_t r; + r = (a & 0x000000000000ffffull) << 48; + r |= (a & 0x00000000ffff0000ull) << 16; + r |= (a & 0x0000ffff00000000ull) >> 16; + r |= (a & 0xffff000000000000ull) >> 48; + return r; } -void helper_cmpteq (void) +uint64_t helper_addg (uint64_t a, uint64_t b) { - union { - double d; - uint64_t i; - } p; + float64 fa, fb, fr; - p.i = 0; - if (float64_eq(FT0, FT1, &FP_STATUS)) - p.i = 0x4000000000000000ULL; - FT0 = p.d; + fa = g_to_float64(a); + fb = g_to_float64(b); + fr = float64_add(fa, fb, &FP_STATUS); + return float64_to_g(fr); } -void helper_cmptle (void) +uint64_t helper_subg (uint64_t a, uint64_t b) { - union { - double d; - uint64_t i; - } p; + float64 fa, fb, fr; - p.i = 0; - if (float64_le(FT0, FT1, &FP_STATUS)) - p.i = 0x4000000000000000ULL; - FT0 = p.d; + fa = g_to_float64(a); + fb = g_to_float64(b); + fr = float64_sub(fa, fb, &FP_STATUS); + return float64_to_g(fr); } -void helper_cmptlt (void) +uint64_t helper_mulg (uint64_t a, uint64_t b) { - union { - double d; - uint64_t i; - } p; + float64 fa, fb, fr; - p.i = 0; - if (float64_lt(FT0, FT1, &FP_STATUS)) - p.i = 0x4000000000000000ULL; - FT0 = p.d; + fa = g_to_float64(a); + fb = g_to_float64(b); + fr = float64_mul(fa, fb, &FP_STATUS); + return float64_to_g(fr); } -void helper_itoft (void) +uint64_t helper_divg (uint64_t a, uint64_t b) { - union { - double d; - uint64_t i; - } p; + float64 fa, fb, fr; - p.d = FT0; - FT0 = int64_to_float64(p.i, &FP_STATUS); + fa = g_to_float64(a); + fb = g_to_float64(b); + fr = float64_div(fa, fb, &FP_STATUS); + return float64_to_g(fr); } -void helper_ftoit (void) +uint64_t helper_sqrtg (uint64_t a) { - union { - double d; - uint64_t i; - } p; + float64 fa, fr; - p.i = float64_to_int64(FT0, &FP_STATUS); - FT0 = p.d; + fa = g_to_float64(a); + fr = float64_sqrt(fa, &FP_STATUS); + return float64_to_g(fr); } -static always_inline int vaxf_is_valid (float ff) + +/* S floating (single) */ +static always_inline uint64_t float32_to_s (float32 fa) { - union { - float f; - uint32_t i; - } p; - uint32_t exp, mant; + uint32_t a; + uint64_t r; - p.f = ff; - exp = (p.i >> 23) & 0xFF; - mant = p.i & 0x007FFFFF; - if (exp == 0 && ((p.i & 0x80000000) || mant != 0)) { - /* Reserved operands / Dirty zero */ - return 0; - } + a = *(uint32_t*)(&fa); - return 1; + r = (((uint64_t)(a & 0xc0000000)) << 32) | (((uint64_t)(a & 0x3fffffff)) << 29); + if (((a & 0x7f800000) != 0x7f800000) && (!(a & 0x40000000))) + r |= 0x7ll << 59; + return r; } -static always_inline float vaxf_to_ieee32 (float ff) +static always_inline float32 s_to_float32 (uint64_t a) { - union { - float f; - uint32_t i; - } p; - uint32_t exp; - - p.f = ff; - exp = (p.i >> 23) & 0xFF; - if (exp < 3) { - /* Underflow */ - p.f = 0.0; - } else { - p.f *= 0.25; - } + uint32_t r = ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff); + return *(float32*)(&r); +} - return p.f; +uint32_t helper_s_to_memory (uint64_t a) +{ + /* Memory format is the same as float32 */ + float32 fa = s_to_float32(a); + return *(uint32_t*)(&fa); } -static always_inline float ieee32_to_vaxf (float fi) +uint64_t helper_memory_to_s (uint32_t a) { - union { - float f; - uint32_t i; - } p; - uint32_t exp, mant; + /* Memory format is the same as float32 */ + return float32_to_s(*(float32*)(&a)); +} - p.f = fi; - exp = (p.i >> 23) & 0xFF; - mant = p.i & 0x007FFFFF; - if (exp == 255) { - /* NaN or infinity */ - p.i = 1; - } else if (exp == 0) { - if (mant == 0) { - /* Zero */ - p.i = 0; - } else { - /* Denormalized */ - p.f *= 2.0; - } - } else { - if (exp >= 253) { - /* Overflow */ - p.i = 1; - } else { - p.f *= 4.0; - } - } +uint64_t helper_adds (uint64_t a, uint64_t b) +{ + float32 fa, fb, fr; - return p.f; + fa = s_to_float32(a); + fb = s_to_float32(b); + fr = float32_add(fa, fb, &FP_STATUS); + return float32_to_s(fr); } -void helper_addf (void) +uint64_t helper_subs (uint64_t a, uint64_t b) { - float ft0, ft1, ft2; + float32 fa, fb, fr; - if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) { - /* XXX: TODO */ - } - ft0 = vaxf_to_ieee32(FT0); - ft1 = vaxf_to_ieee32(FT1); - ft2 = float32_add(ft0, ft1, &FP_STATUS); - FT0 = ieee32_to_vaxf(ft2); + fa = s_to_float32(a); + fb = s_to_float32(b); + fr = float32_sub(fa, fb, &FP_STATUS); + return float32_to_s(fr); } -void helper_subf (void) +uint64_t helper_muls (uint64_t a, uint64_t b) { - float ft0, ft1, ft2; + float32 fa, fb, fr; - if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) { - /* XXX: TODO */ - } - ft0 = vaxf_to_ieee32(FT0); - ft1 = vaxf_to_ieee32(FT1); - ft2 = float32_sub(ft0, ft1, &FP_STATUS); - FT0 = ieee32_to_vaxf(ft2); + fa = s_to_float32(a); + fb = s_to_float32(b); + fr = float32_mul(fa, fb, &FP_STATUS); + return float32_to_s(fr); } -void helper_mulf (void) +uint64_t helper_divs (uint64_t a, uint64_t b) { - float ft0, ft1, ft2; + float32 fa, fb, fr; - if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) { - /* XXX: TODO */ - } - ft0 = vaxf_to_ieee32(FT0); - ft1 = vaxf_to_ieee32(FT1); - ft2 = float32_mul(ft0, ft1, &FP_STATUS); - FT0 = ieee32_to_vaxf(ft2); + fa = s_to_float32(a); + fb = s_to_float32(b); + fr = float32_div(fa, fb, &FP_STATUS); + return float32_to_s(fr); } -void helper_divf (void) +uint64_t helper_sqrts (uint64_t a) { - float ft0, ft1, ft2; + float32 fa, fr; - if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) { - /* XXX: TODO */ - } - ft0 = vaxf_to_ieee32(FT0); - ft1 = vaxf_to_ieee32(FT1); - ft2 = float32_div(ft0, ft1, &FP_STATUS); - FT0 = ieee32_to_vaxf(ft2); + fa = s_to_float32(a); + fr = float32_sqrt(fa, &FP_STATUS); + return float32_to_s(fr); } -void helper_sqrtf (void) -{ - float ft0, ft1; - if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) { - /* XXX: TODO */ - } - ft0 = vaxf_to_ieee32(FT0); - ft1 = float32_sqrt(ft0, &FP_STATUS); - FT0 = ieee32_to_vaxf(ft1); +/* T floating (double) */ +static always_inline float64 t_to_float64 (uint64_t a) +{ + /* Memory format is the same as float64 */ + return *(float64*)(&a); } -void helper_itoff (void) +static always_inline uint64_t float64_to_t (float64 fa) { - /* XXX: TODO */ + /* Memory format is the same as float64 */ + return *(uint64*)(&fa); } -static always_inline int vaxg_is_valid (double ff) +uint64_t helper_addt (uint64_t a, uint64_t b) { - union { - double f; - uint64_t i; - } p; - uint64_t exp, mant; - - p.f = ff; - exp = (p.i >> 52) & 0x7FF; - mant = p.i & 0x000FFFFFFFFFFFFFULL; - if (exp == 0 && ((p.i & 0x8000000000000000ULL) || mant != 0)) { - /* Reserved operands / Dirty zero */ - return 0; - } + float64 fa, fb, fr; - return 1; + fa = t_to_float64(a); + fb = t_to_float64(b); + fr = float64_add(fa, fb, &FP_STATUS); + return float64_to_t(fr); } -static always_inline double vaxg_to_ieee64 (double fg) +uint64_t helper_subt (uint64_t a, uint64_t b) { - union { - double f; - uint64_t i; - } p; - uint32_t exp; - - p.f = fg; - exp = (p.i >> 52) & 0x7FF; - if (exp < 3) { - /* Underflow */ - p.f = 0.0; - } else { - p.f *= 0.25; - } + float64 fa, fb, fr; - return p.f; + fa = t_to_float64(a); + fb = t_to_float64(b); + fr = float64_sub(fa, fb, &FP_STATUS); + return float64_to_t(fr); } -static always_inline double ieee64_to_vaxg (double fi) +uint64_t helper_mult (uint64_t a, uint64_t b) { - union { - double f; - uint64_t i; - } p; - uint64_t mant; - uint32_t exp; - - p.f = fi; - exp = (p.i >> 52) & 0x7FF; - mant = p.i & 0x000FFFFFFFFFFFFFULL; - if (exp == 255) { - /* NaN or infinity */ - p.i = 1; /* VAX dirty zero */ - } else if (exp == 0) { - if (mant == 0) { - /* Zero */ - p.i = 0; - } else { - /* Denormalized */ - p.f *= 2.0; - } - } else { - if (exp >= 2045) { - /* Overflow */ - p.i = 1; /* VAX dirty zero */ - } else { - p.f *= 4.0; - } - } + float64 fa, fb, fr; - return p.f; + fa = t_to_float64(a); + fb = t_to_float64(b); + fr = float64_mul(fa, fb, &FP_STATUS); + return float64_to_t(fr); } -void helper_addg (void) +uint64_t helper_divt (uint64_t a, uint64_t b) { - double ft0, ft1, ft2; + float64 fa, fb, fr; - if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { - /* XXX: TODO */ - } - ft0 = vaxg_to_ieee64(FT0); - ft1 = vaxg_to_ieee64(FT1); - ft2 = float64_add(ft0, ft1, &FP_STATUS); - FT0 = ieee64_to_vaxg(ft2); + fa = t_to_float64(a); + fb = t_to_float64(b); + fr = float64_div(fa, fb, &FP_STATUS); + return float64_to_t(fr); } -void helper_subg (void) +uint64_t helper_sqrtt (uint64_t a) { - double ft0, ft1, ft2; + float64 fa, fr; - if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { - /* XXX: TODO */ - } - ft0 = vaxg_to_ieee64(FT0); - ft1 = vaxg_to_ieee64(FT1); - ft2 = float64_sub(ft0, ft1, &FP_STATUS); - FT0 = ieee64_to_vaxg(ft2); + fa = t_to_float64(a); + fr = float64_sqrt(fa, &FP_STATUS); + return float64_to_t(fr); } -void helper_mulg (void) -{ - double ft0, ft1, ft2; - if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { - /* XXX: TODO */ - } - ft0 = vaxg_to_ieee64(FT0); - ft1 = vaxg_to_ieee64(FT1); - ft2 = float64_mul(ft0, ft1, &FP_STATUS); - FT0 = ieee64_to_vaxg(ft2); +/* Sign copy */ +uint64_t helper_cpys(uint64_t a, uint64_t b) +{ + return (a & 0x8000000000000000ULL) | (b & ~0x8000000000000000ULL); } -void helper_divg (void) +uint64_t helper_cpysn(uint64_t a, uint64_t b) { - double ft0, ft1, ft2; + return ((~a) & 0x8000000000000000ULL) | (b & ~0x8000000000000000ULL); +} - if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { - /* XXX: TODO */ - } - ft0 = vaxg_to_ieee64(FT0); - ft1 = vaxg_to_ieee64(FT1); - ft2 = float64_div(ft0, ft1, &FP_STATUS); - FT0 = ieee64_to_vaxg(ft2); +uint64_t helper_cpyse(uint64_t a, uint64_t b) +{ + return (a & 0xFFF0000000000000ULL) | (b & ~0xFFF0000000000000ULL); } -void helper_sqrtg (void) + +/* Comparisons */ +uint64_t helper_cmptun (uint64_t a, uint64_t b) { - double ft0, ft1; + float64 fa, fb; - if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { - /* XXX: TODO */ - } - ft0 = vaxg_to_ieee64(FT0); - ft1 = float64_sqrt(ft0, &FP_STATUS); - FT0 = ieee64_to_vaxg(ft1); + fa = t_to_float64(a); + fb = t_to_float64(b); + + if (float64_is_nan(fa) || float64_is_nan(fb)) + return 0x4000000000000000ULL; + else + return 0; } -void helper_cmpgeq (void) +uint64_t helper_cmpteq(uint64_t a, uint64_t b) { - union { - double d; - uint64_t u; - } p; - double ft0, ft1; + float64 fa, fb; - if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { - /* XXX: TODO */ - } - ft0 = vaxg_to_ieee64(FT0); - ft1 = vaxg_to_ieee64(FT1); - p.u = 0; - if (float64_eq(ft0, ft1, &FP_STATUS)) - p.u = 0x4000000000000000ULL; - FT0 = p.d; + fa = t_to_float64(a); + fb = t_to_float64(b); + + if (float64_eq(fa, fb, &FP_STATUS)) + return 0x4000000000000000ULL; + else + return 0; } -void helper_cmpglt (void) +uint64_t helper_cmptle(uint64_t a, uint64_t b) { - union { - double d; - uint64_t u; - } p; - double ft0, ft1; + float64 fa, fb; - if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { - /* XXX: TODO */ - } - ft0 = vaxg_to_ieee64(FT0); - ft1 = vaxg_to_ieee64(FT1); - p.u = 0; - if (float64_lt(ft0, ft1, &FP_STATUS)) - p.u = 0x4000000000000000ULL; - FT0 = p.d; + fa = t_to_float64(a); + fb = t_to_float64(b); + + if (float64_le(fa, fb, &FP_STATUS)) + return 0x4000000000000000ULL; + else + return 0; } -void helper_cmpgle (void) +uint64_t helper_cmptlt(uint64_t a, uint64_t b) { - union { - double d; - uint64_t u; - } p; - double ft0, ft1; + float64 fa, fb; - if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { - /* XXX: TODO */ - } - ft0 = vaxg_to_ieee64(FT0); - ft1 = vaxg_to_ieee64(FT1); - p.u = 0; - if (float64_le(ft0, ft1, &FP_STATUS)) - p.u = 0x4000000000000000ULL; - FT0 = p.d; + fa = t_to_float64(a); + fb = t_to_float64(b); + + if (float64_lt(fa, fb, &FP_STATUS)) + return 0x4000000000000000ULL; + else + return 0; } -void helper_cvtqs (void) +uint64_t helper_cmpgeq(uint64_t a, uint64_t b) { - union { - double d; - uint64_t u; - } p; + float64 fa, fb; + + fa = g_to_float64(a); + fb = g_to_float64(b); - p.d = FT0; - FT0 = (float)p.u; + if (float64_eq(fa, fb, &FP_STATUS)) + return 0x4000000000000000ULL; + else + return 0; } -void helper_cvttq (void) +uint64_t helper_cmpgle(uint64_t a, uint64_t b) { - union { - double d; - uint64_t u; - } p; + float64 fa, fb; - p.u = FT0; - FT0 = p.d; + fa = g_to_float64(a); + fb = g_to_float64(b); + + if (float64_le(fa, fb, &FP_STATUS)) + return 0x4000000000000000ULL; + else + return 0; } -void helper_cvtqt (void) +uint64_t helper_cmpglt(uint64_t a, uint64_t b) { - union { - double d; - uint64_t u; - } p; + float64 fa, fb; + + fa = g_to_float64(a); + fb = g_to_float64(b); - p.d = FT0; - FT0 = p.u; + if (float64_lt(fa, fb, &FP_STATUS)) + return 0x4000000000000000ULL; + else + return 0; } -void helper_cvtqf (void) +uint64_t helper_cmpfeq (uint64_t a) { - union { - double d; - uint64_t u; - } p; + return !(a & 0x7FFFFFFFFFFFFFFFULL); +} - p.d = FT0; - FT0 = ieee32_to_vaxf(p.u); +uint64_t helper_cmpfne (uint64_t a) +{ + return (a & 0x7FFFFFFFFFFFFFFFULL); } -void helper_cvtgf (void) +uint64_t helper_cmpflt (uint64_t a) { - double ft0; + return (a & 0x8000000000000000ULL) && (a & 0x7FFFFFFFFFFFFFFFULL); +} - ft0 = vaxg_to_ieee64(FT0); - FT0 = ieee32_to_vaxf(ft0); +uint64_t helper_cmpfle (uint64_t a) +{ + return (a & 0x8000000000000000ULL) || !(a & 0x7FFFFFFFFFFFFFFFULL); } -void helper_cvtgd (void) +uint64_t helper_cmpfgt (uint64_t a) { - /* XXX: TODO */ + return !(a & 0x8000000000000000ULL) && (a & 0x7FFFFFFFFFFFFFFFULL); } -void helper_cvtgq (void) +uint64_t helper_cmpfge (uint64_t a) { - union { - double d; - uint64_t u; - } p; + return !(a & 0x8000000000000000ULL) || !(a & 0x7FFFFFFFFFFFFFFFULL); +} + - p.u = vaxg_to_ieee64(FT0); - FT0 = p.d; +/* Floating point format conversion */ +uint64_t helper_cvtts (uint64_t a) +{ + float64 fa; + float32 fr; + + fa = t_to_float64(a); + fr = float64_to_float32(fa, &FP_STATUS); + return float32_to_s(fr); } -void helper_cvtqg (void) +uint64_t helper_cvtst (uint64_t a) { - union { - double d; - uint64_t u; - } p; + float32 fa; + float64 fr; - p.d = FT0; - FT0 = ieee64_to_vaxg(p.u); + fa = s_to_float32(a); + fr = float32_to_float64(fa, &FP_STATUS); + return float64_to_t(fr); } -void helper_cvtdg (void) +uint64_t helper_cvtqs (uint64_t a) { - /* XXX: TODO */ + float32 fr = int64_to_float32(a, &FP_STATUS); + return float32_to_s(fr); } -void helper_cvtlq (void) +uint64_t helper_cvttq (uint64_t a) { - union { - double d; - uint64_t u; - } p, q; - - p.d = FT0; - q.u = (p.u >> 29) & 0x3FFFFFFF; - q.u |= (p.u >> 32); - q.u = (int64_t)((int32_t)q.u); - FT0 = q.d; -} - -static always_inline void __helper_cvtql (int s, int v) -{ - union { - double d; - uint64_t u; - } p, q; - - p.d = FT0; - q.u = ((uint64_t)(p.u & 0xC0000000)) << 32; - q.u |= ((uint64_t)(p.u & 0x7FFFFFFF)) << 29; - FT0 = q.d; - if (v && (int64_t)((int32_t)p.u) != (int64_t)p.u) { - helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); - } - if (s) { - /* TODO */ - } + float64 fa = t_to_float64(a); + return float64_to_int64_round_to_zero(fa, &FP_STATUS); } -void helper_cvtql (void) +uint64_t helper_cvtqt (uint64_t a) { - __helper_cvtql(0, 0); + float64 fr = int64_to_float64(a, &FP_STATUS); + return float64_to_t(fr); } -void helper_cvtqlv (void) +uint64_t helper_cvtqf (uint64_t a) { - __helper_cvtql(0, 1); + float32 fr = int64_to_float32(a, &FP_STATUS); + return float32_to_f(fr); } -void helper_cvtqlsv (void) +uint64_t helper_cvtgf (uint64_t a) { - __helper_cvtql(1, 1); + float64 fa; + float32 fr; + + fa = g_to_float64(a); + fr = float64_to_float32(fa, &FP_STATUS); + return float32_to_f(fr); } -void helper_cmpfeq (void) +uint64_t helper_cvtgq (uint64_t a) { - if (float64_eq(FT0, FT1, &FP_STATUS)) - T0 = 1; - else - T0 = 0; + float64 fa = g_to_float64(a); + return float64_to_int64_round_to_zero(fa, &FP_STATUS); } -void helper_cmpfne (void) +uint64_t helper_cvtqg (uint64_t a) { - if (float64_eq(FT0, FT1, &FP_STATUS)) - T0 = 0; - else - T0 = 1; + float64 fr; + fr = int64_to_float64(a, &FP_STATUS); + return float64_to_g(fr); } -void helper_cmpflt (void) +uint64_t helper_cvtlq (uint64_t a) { - if (float64_lt(FT0, FT1, &FP_STATUS)) - T0 = 1; - else - T0 = 0; + return (int64_t)((int32_t)((a >> 32) | ((a >> 29) & 0x3FFFFFFF))); } -void helper_cmpfle (void) +static always_inline uint64_t __helper_cvtql (uint64_t a, int s, int v) { - if (float64_lt(FT0, FT1, &FP_STATUS)) - T0 = 1; - else - T0 = 0; + uint64_t r; + + r = ((uint64_t)(a & 0xC0000000)) << 32; + r |= ((uint64_t)(a & 0x7FFFFFFF)) << 29; + + if (v && (int64_t)((int32_t)r) != (int64_t)r) { + helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); + } + if (s) { + /* TODO */ + } + return r; } -void helper_cmpfgt (void) +uint64_t helper_cvtql (uint64_t a) { - if (float64_le(FT0, FT1, &FP_STATUS)) - T0 = 0; - else - T0 = 1; + return __helper_cvtql(a, 0, 0); } -void helper_cmpfge (void) +uint64_t helper_cvtqlv (uint64_t a) { - if (float64_lt(FT0, FT1, &FP_STATUS)) - T0 = 0; - else - T0 = 1; + return __helper_cvtql(a, 0, 1); +} + +uint64_t helper_cvtqlsv (uint64_t a) +{ + return __helper_cvtql(a, 1, 1); } +/* PALcode support special instructions */ #if !defined (CONFIG_USER_ONLY) -void helper_mfpr (int iprn) +void helper_hw_rei (void) { - uint64_t val; + env->pc = env->ipr[IPR_EXC_ADDR] & ~3; + env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1; + /* XXX: re-enable interrupts and memory mapping */ +} - if (cpu_alpha_mfpr(env, iprn, &val) == 0) - T0 = val; +void helper_hw_ret (uint64_t a) +{ + env->pc = a & ~3; + env->ipr[IPR_EXC_ADDR] = a & 1; + /* XXX: re-enable interrupts and memory mapping */ } -void helper_mtpr (int iprn) +uint64_t helper_mfpr (int iprn, uint64_t val) { - cpu_alpha_mtpr(env, iprn, T0, NULL); + uint64_t tmp; + + if (cpu_alpha_mfpr(env, iprn, &tmp) == 0) + val = tmp; + + return val; } -#endif -#if defined(HOST_SPARC) || defined(HOST_SPARC64) -void helper_reset_FT0 (void) +void helper_mtpr (int iprn, uint64_t val) { - FT0 = 0; + cpu_alpha_mtpr(env, iprn, val, NULL); } -void helper_reset_FT1 (void) +void helper_set_alt_mode (void) { - FT1 = 0; + env->saved_mode = env->ps & 0xC; + env->ps = (env->ps & ~0xC) | (env->ipr[IPR_ALT_MODE] & 0xC); } -void helper_reset_FT2 (void) +void helper_restore_mode (void) { - FT2 = 0; + env->ps = (env->ps & ~0xC) | env->saved_mode; } + #endif /*****************************************************************************/ /* Softmmu support */ #if !defined (CONFIG_USER_ONLY) -#ifdef __s390__ -# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) -#else -# define GETPC() (__builtin_return_address(0)) -#endif - /* XXX: the two following helpers are pure hacks. * Hopefully, we emulate the PALcode, then we should never see * HW_LD / HW_ST instructions. */ -void helper_ld_phys_to_virt (void) +uint64_t helper_ld_virt_to_phys (uint64_t virtaddr) { uint64_t tlb_addr, physaddr; int index, mmu_idx; void *retaddr; mmu_idx = cpu_mmu_index(env); - index = (T0 >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + index = (virtaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: tlb_addr = env->tlb_table[mmu_idx][index].addr_read; - if ((T0 & TARGET_PAGE_MASK) == + if ((virtaddr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = T0 + env->tlb_table[mmu_idx][index].addend; + physaddr = virtaddr + env->tlb_table[mmu_idx][index].addend; } else { /* the page is not in the TLB : fill it */ retaddr = GETPC(); - tlb_fill(T0, 0, mmu_idx, retaddr); + tlb_fill(virtaddr, 0, mmu_idx, retaddr); goto redo; } - T0 = physaddr; + return physaddr; } -void helper_st_phys_to_virt (void) +uint64_t helper_st_virt_to_phys (uint64_t virtaddr) { uint64_t tlb_addr, physaddr; int index, mmu_idx; void *retaddr; mmu_idx = cpu_mmu_index(env); - index = (T0 >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + index = (virtaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: tlb_addr = env->tlb_table[mmu_idx][index].addr_write; - if ((T0 & TARGET_PAGE_MASK) == + if ((virtaddr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = T0 + env->tlb_table[mmu_idx][index].addend; + physaddr = virtaddr + env->tlb_table[mmu_idx][index].addend; } else { /* the page is not in the TLB : fill it */ retaddr = GETPC(); - tlb_fill(T0, 1, mmu_idx, retaddr); + tlb_fill(virtaddr, 1, mmu_idx, retaddr); goto redo; } - T0 = physaddr; + return physaddr; +} + +void helper_ldl_raw(uint64_t t0, uint64_t t1) +{ + ldl_raw(t1, t0); +} + +void helper_ldq_raw(uint64_t t0, uint64_t t1) +{ + ldq_raw(t1, t0); +} + +void helper_ldl_l_raw(uint64_t t0, uint64_t t1) +{ + env->lock = t1; + ldl_raw(t1, t0); +} + +void helper_ldq_l_raw(uint64_t t0, uint64_t t1) +{ + env->lock = t1; + ldl_raw(t1, t0); +} + +void helper_ldl_kernel(uint64_t t0, uint64_t t1) +{ + ldl_kernel(t1, t0); +} + +void helper_ldq_kernel(uint64_t t0, uint64_t t1) +{ + ldq_kernel(t1, t0); +} + +void helper_ldl_data(uint64_t t0, uint64_t t1) +{ + ldl_data(t1, t0); +} + +void helper_ldq_data(uint64_t t0, uint64_t t1) +{ + ldq_data(t1, t0); +} + +void helper_stl_raw(uint64_t t0, uint64_t t1) +{ + stl_raw(t1, t0); +} + +void helper_stq_raw(uint64_t t0, uint64_t t1) +{ + stq_raw(t1, t0); +} + +uint64_t helper_stl_c_raw(uint64_t t0, uint64_t t1) +{ + uint64_t ret; + + if (t1 == env->lock) { + stl_raw(t1, t0); + ret = 0; + } else + ret = 1; + + env->lock = 1; + + return ret; +} + +uint64_t helper_stq_c_raw(uint64_t t0, uint64_t t1) +{ + uint64_t ret; + + if (t1 == env->lock) { + stq_raw(t1, t0); + ret = 0; + } else + ret = 1; + + env->lock = 1; + + return ret; } #define MMUSUFFIX _mmu diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-alpha/op_helper.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-alpha/op_helper.h --- qemu-0.9.1/target-alpha/op_helper.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-alpha/op_helper.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,146 +0,0 @@ -/* - * Alpha emulation cpu micro-operations helpers definitions for qemu. - * - * Copyright (c) 2007 Jocelyn Mayer - * - * 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 - */ - -void helper_call_pal (uint32_t palcode); -void helper_excp (uint32_t excp, uint32_t error); -void helper_amask (void); -void helper_load_pcc (void); -void helper_load_implver (void); -void helper_load_fpcr (void); -void helper_store_fpcr (void); -void helper_load_irf (void); -void helper_set_irf (void); -void helper_clear_irf (void); -void helper_addqv (void); -void helper_addlv (void); -void helper_subqv (void); -void helper_sublv (void); -void helper_mullv (void); -void helper_mulqv (void); -void helper_ctpop (void); -void helper_ctlz (void); -void helper_cttz (void); -void helper_mskbl (void); -void helper_extbl (void); -void helper_insbl (void); -void helper_mskwl (void); -void helper_extwl (void); -void helper_inswl (void); -void helper_mskll (void); -void helper_extll (void); -void helper_insll (void); -void helper_zap (void); -void helper_zapnot (void); -void helper_mskql (void); -void helper_extql (void); -void helper_insql (void); -void helper_mskwh (void); -void helper_inswh (void); -void helper_extwh (void); -void helper_msklh (void); -void helper_inslh (void); -void helper_extlh (void); -void helper_mskqh (void); -void helper_insqh (void); -void helper_extqh (void); -void helper_cmpbge (void); -void helper_cmov_fir (int freg); - -double helper_ldff_raw (target_ulong ea); -void helper_stff_raw (target_ulong ea, double op); -double helper_ldfg_raw (target_ulong ea); -void helper_stfg_raw (target_ulong ea, double op); -#if !defined(CONFIG_USER_ONLY) -double helper_ldff_user (target_ulong ea); -void helper_stff_user (target_ulong ea, double op); -double helper_ldff_kernel (target_ulong ea); -void helper_stff_kernel (target_ulong ea, double op); -double helper_ldff_data (target_ulong ea); -void helper_stff_data (target_ulong ea, double op); -double helper_ldfg_user (target_ulong ea); -void helper_stfg_user (target_ulong ea, double op); -double helper_ldfg_kernel (target_ulong ea); -void helper_stfg_kernel (target_ulong ea, double op); -double helper_ldfg_data (target_ulong ea); -void helper_stfg_data (target_ulong ea, double op); -#endif - -void helper_sqrts (void); -void helper_cpys (void); -void helper_cpysn (void); -void helper_cpyse (void); -void helper_itofs (void); -void helper_ftois (void); - -void helper_sqrtt (void); -void helper_cmptun (void); -void helper_cmpteq (void); -void helper_cmptle (void); -void helper_cmptlt (void); -void helper_itoft (void); -void helper_ftoit (void); - -void helper_addf (void); -void helper_subf (void); -void helper_mulf (void); -void helper_divf (void); -void helper_sqrtf (void); -void helper_cmpfeq (void); -void helper_cmpfne (void); -void helper_cmpflt (void); -void helper_cmpfle (void); -void helper_cmpfgt (void); -void helper_cmpfge (void); -void helper_itoff (void); - -void helper_addg (void); -void helper_subg (void); -void helper_mulg (void); -void helper_divg (void); -void helper_sqrtg (void); -void helper_cmpgeq (void); -void helper_cmpglt (void); -void helper_cmpgle (void); - -void helper_cvtqs (void); -void helper_cvttq (void); -void helper_cvtqt (void); -void helper_cvtqf (void); -void helper_cvtgf (void); -void helper_cvtgd (void); -void helper_cvtgq (void); -void helper_cvtqg (void); -void helper_cvtdg (void); -void helper_cvtlq (void); -void helper_cvtql (void); -void helper_cvtqlv (void); -void helper_cvtqlsv (void); - -void helper_mfpr (int iprn); -void helper_mtpr (int iprn); -void helper_ld_phys_to_virt (void); -void helper_st_phys_to_virt (void); -void helper_tb_flush (void); - -#if defined(HOST_SPARC) || defined(HOST_SPARC64) -void helper_reset_FT0 (void); -void helper_reset_FT1 (void); -void helper_reset_FT2 (void); -#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-alpha/op_helper_mem.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-alpha/op_helper_mem.h --- qemu-0.9.1/target-alpha/op_helper_mem.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-alpha/op_helper_mem.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,40 +0,0 @@ -/* - * Alpha emulation cpu micro-operations helpers for memory accesses for qemu. - * - * Copyright (c) 2007 Jocelyn Mayer - * - * 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 - */ - -/* XXX: TODO */ -double glue(helper_ldff, MEMSUFFIX) (target_ulong ea) -{ - return 0; -} - -void glue(helper_stff, MEMSUFFIX) (target_ulong ea, double op) -{ -} - -double glue(helper_ldfg, MEMSUFFIX) (target_ulong ea) -{ - return 0; -} - -void glue(helper_stfg, MEMSUFFIX) (target_ulong ea, double op) -{ -} - -#undef MEMSUFFIX diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-alpha/op_mem.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-alpha/op_mem.h --- qemu-0.9.1/target-alpha/op_mem.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-alpha/op_mem.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,127 +0,0 @@ -/* - * Alpha emulation cpu micro-operations for memory accesses for qemu. - * - * Copyright (c) 2007 Jocelyn Mayer - * - * 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 - */ - -//#define DEBUG_MEM_ACCESSES -#if defined (DEBUG_MEM_ACCESSES) -void helper_print_mem_EA (target_ulong EA); -#define print_mem_EA(EA) do { helper_print_mem_EA(EA); } while (0) -#else -#define print_mem_EA(EA) do { } while (0) -#endif - -static always_inline uint32_t glue(ldl_l, MEMSUFFIX) (target_ulong EA) -{ - env->lock = EA; - - return glue(ldl, MEMSUFFIX)(EA); -} - -static always_inline uint32_t glue(ldq_l, MEMSUFFIX) (target_ulong EA) -{ - env->lock = EA; - - return glue(ldq, MEMSUFFIX)(EA); -} - -static always_inline void glue(stl_c, MEMSUFFIX) (target_ulong EA, - uint32_t data) -{ - if (EA == env->lock) { - glue(stl, MEMSUFFIX)(EA, data); - T0 = 0; - } else { - T0 = 1; - } - env->lock = -1; -} - -static always_inline void glue(stq_c, MEMSUFFIX) (target_ulong EA, - uint64_t data) -{ - if (EA == env->lock) { - glue(stq, MEMSUFFIX)(EA, data); - T0 = 0; - } else { - T0 = 1; - } - env->lock = -1; -} - -#define ALPHA_LD_OP(name, op) \ -void OPPROTO glue(glue(op_ld, name), MEMSUFFIX) (void) \ -{ \ - print_mem_EA(T0); \ - T1 = glue(op, MEMSUFFIX)(T0); \ - RETURN(); \ -} - -#define ALPHA_ST_OP(name, op) \ -void OPPROTO glue(glue(op_st, name), MEMSUFFIX) (void) \ -{ \ - print_mem_EA(T0); \ - glue(op, MEMSUFFIX)(T0, T1); \ - RETURN(); \ -} - -ALPHA_LD_OP(bu, ldub); -ALPHA_ST_OP(b, stb); -ALPHA_LD_OP(wu, lduw); -ALPHA_ST_OP(w, stw); -ALPHA_LD_OP(l, ldl); -ALPHA_ST_OP(l, stl); -ALPHA_LD_OP(q, ldq); -ALPHA_ST_OP(q, stq); - -ALPHA_LD_OP(q_u, ldq); -ALPHA_ST_OP(q_u, stq); - -ALPHA_LD_OP(l_l, ldl_l); -ALPHA_LD_OP(q_l, ldq_l); -ALPHA_ST_OP(l_c, stl_c); -ALPHA_ST_OP(q_c, stq_c); - -#define ALPHA_LDF_OP(name, op) \ -void OPPROTO glue(glue(op_ld, name), MEMSUFFIX) (void) \ -{ \ - print_mem_EA(T0); \ - FT1 = glue(op, MEMSUFFIX)(T0); \ - RETURN(); \ -} - -#define ALPHA_STF_OP(name, op) \ -void OPPROTO glue(glue(op_st, name), MEMSUFFIX) (void) \ -{ \ - print_mem_EA(T0); \ - glue(op, MEMSUFFIX)(T0, FT1); \ - RETURN(); \ -} - -ALPHA_LDF_OP(t, ldfq); -ALPHA_STF_OP(t, stfq); -ALPHA_LDF_OP(s, ldfl); -ALPHA_STF_OP(s, stfl); - -/* VAX floating point */ -ALPHA_LDF_OP(f, helper_ldff); -ALPHA_STF_OP(f, helper_stff); -ALPHA_LDF_OP(g, helper_ldfg); -ALPHA_STF_OP(g, helper_stfg); - -#undef MEMSUFFIX diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-alpha/op_template.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-alpha/op_template.h --- qemu-0.9.1/target-alpha/op_template.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-alpha/op_template.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,175 +0,0 @@ -/* - * Alpha emulation cpu micro-operations templates for qemu. - * - * Copyright (c) 2007 Jocelyn Mayer - * - * 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 - */ - -/* Optimized constant loads */ -#if REG < 3 -void OPPROTO glue(op_reset_T, REG) (void) -{ - glue(T, REG) = 0; - RETURN(); -} - -#if !defined(HOST_SPARC) && !defined(HOST_SPARC64) -void OPPROTO glue(op_reset_FT, REG) (void) -{ - glue(FT, REG) = 0; - RETURN(); -} -#else -void OPPROTO glue(op_reset_FT, REG) (void) -{ - glue(helper_reset_FT, REG)(); - RETURN(); -} -#endif - -/* XXX: This can be great on most RISC machines */ -#if !defined(__i386__) && !defined(__x86_64__) -void OPPROTO glue(op_set_s16_T, REG) (void) -{ - glue(T, REG) = (int16_t)PARAM(1); - RETURN(); -} - -void OPPROTO glue(op_set_u16_T, REG) (void) -{ - glue(T, REG) = (uint16_t)PARAM(1); - RETURN(); -} -#endif - -void OPPROTO glue(op_set_s32_T, REG) (void) -{ - glue(T, REG) = (int32_t)PARAM(1); - RETURN(); -} - -void OPPROTO glue(op_set_u32_T, REG) (void) -{ - glue(T, REG) = (uint32_t)PARAM(1); - RETURN(); -} - -#if 0 // Qemu does not know how to do this... -void OPPROTO glue(op_set_64_T, REG) (void) -{ - glue(T, REG) = (int64_t)PARAM(1); - RETURN(); -} -#else -void OPPROTO glue(op_set_64_T, REG) (void) -{ - glue(T, REG) = ((int64_t)PARAM(1) << 32) | (int64_t)PARAM(2); - RETURN(); -} -#endif - -#endif /* REG < 3 */ - -/* Fixed-point register moves */ -#if REG < 31 -void OPPROTO glue(op_load_T0_ir, REG) (void) -{ - T0 = env->ir[REG]; - RETURN(); -} - -void OPPROTO glue(op_load_T1_ir, REG) (void) -{ - T1 = env->ir[REG]; - RETURN(); -} - -void OPPROTO glue(op_load_T2_ir, REG) (void) -{ - T2 = env->ir[REG]; - RETURN(); -} - -void OPPROTO glue(op_store_T0_ir, REG) (void) -{ - env->ir[REG] = T0; - RETURN(); -} - -void OPPROTO glue(op_store_T1_ir, REG) (void) -{ - env->ir[REG] = T1; - RETURN(); -} - -void OPPROTO glue(op_store_T2_ir, REG) (void) -{ - env->ir[REG] = T2; - RETURN(); -} - -void OPPROTO glue(op_cmov_ir, REG) (void) -{ - if (T0) - env->ir[REG] = T1; - RETURN(); -} - -/* floating point registers moves */ -void OPPROTO glue(op_load_FT0_fir, REG) (void) -{ - FT0 = env->fir[REG]; - RETURN(); -} - -void OPPROTO glue(op_load_FT1_fir, REG) (void) -{ - FT1 = env->fir[REG]; - RETURN(); -} - -void OPPROTO glue(op_load_FT2_fir, REG) (void) -{ - FT2 = env->fir[REG]; - RETURN(); -} - -void OPPROTO glue(op_store_FT0_fir, REG) (void) -{ - env->fir[REG] = FT0; - RETURN(); -} - -void OPPROTO glue(op_store_FT1_fir, REG) (void) -{ - env->fir[REG] = FT1; - RETURN(); -} - -void OPPROTO glue(op_store_FT2_fir, REG) (void) -{ - env->fir[REG] = FT2; - RETURN(); -} - -void OPPROTO glue(op_cmov_fir, REG) (void) -{ - helper_cmov_fir(REG); - RETURN(); -} -#endif /* REG < 31 */ - -#undef REG diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-alpha/STATUS /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-alpha/STATUS --- qemu-0.9.1/target-alpha/STATUS 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-alpha/STATUS 2008-10-01 08:07:59.000000000 +0100 @@ -5,18 +5,13 @@ exec.h : CPU definitions used only for translated code execution helper.c : helpers that can be called either by the translated code or the Qemu core, including the exception handler. -op.c : Alpha dedicated micro-operations used by the code translator -op_helper.c : helpers that can be called only from micro-operations -op_helper.h : micro-operations helpers prototypes -op_helper_mem.h : micro-operations templates - for load and stores accesses helpers -op_mem.h : micro-operations templates for load and stores accesses -op_template.h : micro-operation templates for register moves +op_helper.c : helpers that can be called only from TCG +helper.h : TCG helpers prototypes translate.c : Alpha instructions to micro-operations translator Code translator status: The Alpha CPU instruction emulation should be quite complete with the -limitation that the VAX floating-point load and stores are not implemented. +limitation that the VAX floating-point load and stores are not tested. The 4 MMU modes are implemented. Linux user mode emulation status: diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-alpha/translate.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-alpha/translate.c --- qemu-0.9.1/target-alpha/translate.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-alpha/translate.c 2008-11-11 13:54:54.000000000 +0000 @@ -25,11 +25,14 @@ #include "cpu.h" #include "exec-all.h" #include "disas.h" +#include "host-utils.h" +#include "helper.h" +#include "tcg-op.h" +#include "qemu-common.h" -#define DO_SINGLE_STEP -#define GENERATE_NOP +/* #define DO_SINGLE_STEP */ #define ALPHA_DEBUG_DISAS -#define DO_TB_FLUSH +/* #define DO_TB_FLUSH */ typedef struct DisasContext DisasContext; struct DisasContext { @@ -41,590 +44,490 @@ uint32_t amask; }; -#ifdef USE_DIRECT_JUMP -#define TBPARAM(x) -#else -#define TBPARAM(x) (long)(x) -#endif +/* global register indexes */ +static TCGv cpu_env; +static TCGv cpu_ir[31]; +static TCGv cpu_fir[31]; +static TCGv cpu_pc; +static TCGv cpu_lock; -enum { -#define DEF(s, n, copy_size) INDEX_op_ ## s, -#include "opc.h" -#undef DEF - NB_OPS, -}; +/* register names */ +static char cpu_reg_names[10*4+21*5 + 10*5+21*6]; -static uint16_t *gen_opc_ptr; -static uint32_t *gen_opparam_ptr; +#include "gen-icount.h" -#include "gen-op.h" - -static always_inline void gen_op_nop (void) +static void alpha_translate_init(void) { -#if defined(GENERATE_NOP) - gen_op_no_op(); -#endif -} + int i; + char *p; + static int done_init = 0; -#define GEN32(func, NAME) \ -static GenOpFunc *NAME ## _table [32] = { \ -NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ -NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ -NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ -NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ -NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ -NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ -NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ -NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ -}; \ -static always_inline void func (int n) \ -{ \ - NAME ## _table[n](); \ -} - -/* IR moves */ -/* Special hacks for ir31 */ -#define gen_op_load_T0_ir31 gen_op_reset_T0 -#define gen_op_load_T1_ir31 gen_op_reset_T1 -#define gen_op_load_T2_ir31 gen_op_reset_T2 -#define gen_op_store_T0_ir31 gen_op_nop -#define gen_op_store_T1_ir31 gen_op_nop -#define gen_op_store_T2_ir31 gen_op_nop -#define gen_op_cmov_ir31 gen_op_nop -GEN32(gen_op_load_T0_ir, gen_op_load_T0_ir); -GEN32(gen_op_load_T1_ir, gen_op_load_T1_ir); -GEN32(gen_op_load_T2_ir, gen_op_load_T2_ir); -GEN32(gen_op_store_T0_ir, gen_op_store_T0_ir); -GEN32(gen_op_store_T1_ir, gen_op_store_T1_ir); -GEN32(gen_op_store_T2_ir, gen_op_store_T2_ir); -GEN32(gen_op_cmov_ir, gen_op_cmov_ir); - -static always_inline void gen_load_ir (DisasContext *ctx, int irn, int Tn) -{ - switch (Tn) { - case 0: - gen_op_load_T0_ir(irn); - break; - case 1: - gen_op_load_T1_ir(irn); - break; - case 2: - gen_op_load_T2_ir(irn); - break; - } -} + if (done_init) + return; -static always_inline void gen_store_ir (DisasContext *ctx, int irn, int Tn) -{ - switch (Tn) { - case 0: - gen_op_store_T0_ir(irn); - break; - case 1: - gen_op_store_T1_ir(irn); - break; - case 2: - gen_op_store_T2_ir(irn); - break; - } -} + cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env"); -/* FIR moves */ -/* Special hacks for fir31 */ -#define gen_op_load_FT0_fir31 gen_op_reset_FT0 -#define gen_op_load_FT1_fir31 gen_op_reset_FT1 -#define gen_op_load_FT2_fir31 gen_op_reset_FT2 -#define gen_op_store_FT0_fir31 gen_op_nop -#define gen_op_store_FT1_fir31 gen_op_nop -#define gen_op_store_FT2_fir31 gen_op_nop -#define gen_op_cmov_fir31 gen_op_nop -GEN32(gen_op_load_FT0_fir, gen_op_load_FT0_fir); -GEN32(gen_op_load_FT1_fir, gen_op_load_FT1_fir); -GEN32(gen_op_load_FT2_fir, gen_op_load_FT2_fir); -GEN32(gen_op_store_FT0_fir, gen_op_store_FT0_fir); -GEN32(gen_op_store_FT1_fir, gen_op_store_FT1_fir); -GEN32(gen_op_store_FT2_fir, gen_op_store_FT2_fir); -GEN32(gen_op_cmov_fir, gen_op_cmov_fir); - -static always_inline void gen_load_fir (DisasContext *ctx, int firn, int Tn) -{ - switch (Tn) { - case 0: - gen_op_load_FT0_fir(firn); - break; - case 1: - gen_op_load_FT1_fir(firn); - break; - case 2: - gen_op_load_FT2_fir(firn); - break; - } -} + p = cpu_reg_names; + for (i = 0; i < 31; i++) { + sprintf(p, "ir%d", i); + cpu_ir[i] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, + offsetof(CPUState, ir[i]), p); + p += (i < 10) ? 4 : 5; -static always_inline void gen_store_fir (DisasContext *ctx, int firn, int Tn) -{ - switch (Tn) { - case 0: - gen_op_store_FT0_fir(firn); - break; - case 1: - gen_op_store_FT1_fir(firn); - break; - case 2: - gen_op_store_FT2_fir(firn); - break; + sprintf(p, "fir%d", i); + cpu_fir[i] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, + offsetof(CPUState, fir[i]), p); + p += (i < 10) ? 5 : 6; } -} -/* Memory moves */ -#if defined(CONFIG_USER_ONLY) -#define OP_LD_TABLE(width) \ -static GenOpFunc *gen_op_ld##width[] = { \ - &gen_op_ld##width##_raw, \ -} -#define OP_ST_TABLE(width) \ -static GenOpFunc *gen_op_st##width[] = { \ - &gen_op_st##width##_raw, \ -} -#else -#define OP_LD_TABLE(width) \ -static GenOpFunc *gen_op_ld##width[] = { \ - &gen_op_ld##width##_kernel, \ - &gen_op_ld##width##_executive, \ - &gen_op_ld##width##_supervisor, \ - &gen_op_ld##width##_user, \ -} -#define OP_ST_TABLE(width) \ -static GenOpFunc *gen_op_st##width[] = { \ - &gen_op_st##width##_kernel, \ - &gen_op_st##width##_executive, \ - &gen_op_st##width##_supervisor, \ - &gen_op_st##width##_user, \ -} -#endif + cpu_pc = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, + offsetof(CPUState, pc), "pc"); -#define GEN_LD(width) \ -OP_LD_TABLE(width); \ -static always_inline void gen_ld##width (DisasContext *ctx) \ -{ \ - (*gen_op_ld##width[ctx->mem_idx])(); \ -} - -#define GEN_ST(width) \ -OP_ST_TABLE(width); \ -static always_inline void gen_st##width (DisasContext *ctx) \ -{ \ - (*gen_op_st##width[ctx->mem_idx])(); \ -} + cpu_lock = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, + offsetof(CPUState, lock), "lock"); -GEN_LD(bu); -GEN_ST(b); -GEN_LD(wu); -GEN_ST(w); -GEN_LD(l); -GEN_ST(l); -GEN_LD(q); -GEN_ST(q); -GEN_LD(q_u); -GEN_ST(q_u); -GEN_LD(l_l); -GEN_ST(l_c); -GEN_LD(q_l); -GEN_ST(q_c); + /* register helpers */ +#undef DEF_HELPER +#define DEF_HELPER(ret, name, params) tcg_register_helper(name, #name); +#include "helper.h" -#if 0 /* currently unused */ -GEN_LD(f); -GEN_ST(f); -GEN_LD(g); -GEN_ST(g); -#endif /* 0 */ -GEN_LD(s); -GEN_ST(s); -GEN_LD(t); -GEN_ST(t); + done_init = 1; +} -#if defined(__i386__) || defined(__x86_64__) -static always_inline void gen_op_set_s16_T0 (int16_t imm) +static always_inline void gen_excp (DisasContext *ctx, + int exception, int error_code) { - gen_op_set_s32_T0((int32_t)imm); + TCGv tmp1, tmp2; + + tcg_gen_movi_i64(cpu_pc, ctx->pc); + tmp1 = tcg_const_i32(exception); + tmp2 = tcg_const_i32(error_code); + tcg_gen_helper_0_2(helper_excp, tmp1, tmp2); + tcg_temp_free(tmp2); + tcg_temp_free(tmp1); } -static always_inline void gen_op_set_s16_T1 (int16_t imm) +static always_inline void gen_invalid (DisasContext *ctx) { - gen_op_set_s32_T1((int32_t)imm); + gen_excp(ctx, EXCP_OPCDEC, 0); } -static always_inline void gen_op_set_u16_T0 (uint16_t imm) +static always_inline void gen_qemu_ldf (TCGv t0, TCGv t1, int flags) { - gen_op_set_s32_T0((uint32_t)imm); + TCGv tmp = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_qemu_ld32u(tmp, t1, flags); + tcg_gen_helper_1_1(helper_memory_to_f, t0, tmp); + tcg_temp_free(tmp); } -static always_inline void gen_op_set_u16_T1 (uint16_t imm) +static always_inline void gen_qemu_ldg (TCGv t0, TCGv t1, int flags) { - gen_op_set_s32_T1((uint32_t)imm); + TCGv tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_qemu_ld64(tmp, t1, flags); + tcg_gen_helper_1_1(helper_memory_to_g, t0, tmp); + tcg_temp_free(tmp); } -#endif -static always_inline void gen_set_sT0 (DisasContext *ctx, int64_t imm) +static always_inline void gen_qemu_lds (TCGv t0, TCGv t1, int flags) { - int32_t imm32; - int16_t imm16; - - imm32 = imm; - if (imm32 == imm) { - imm16 = imm; - if (imm16 == imm) { - if (imm == 0) { - gen_op_reset_T0(); - } else { - gen_op_set_s16_T0(imm16); - } - } else { - gen_op_set_s32_T0(imm32); - } - } else { -#if 0 // Qemu does not know how to do this... - gen_op_set_64_T0(imm); -#else - gen_op_set_64_T0(imm >> 32, imm); -#endif - } + TCGv tmp = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_qemu_ld32u(tmp, t1, flags); + tcg_gen_helper_1_1(helper_memory_to_s, t0, tmp); + tcg_temp_free(tmp); } -static always_inline void gen_set_sT1 (DisasContext *ctx, int64_t imm) +static always_inline void gen_qemu_ldl_l (TCGv t0, TCGv t1, int flags) { - int32_t imm32; - int16_t imm16; - - imm32 = imm; - if (imm32 == imm) { - imm16 = imm; - if (imm16 == imm) { - if (imm == 0) { - gen_op_reset_T1(); - } else { - gen_op_set_s16_T1(imm16); - } - } else { - gen_op_set_s32_T1(imm32); - } - } else { -#if 0 // Qemu does not know how to do this... - gen_op_set_64_T1(imm); -#else - gen_op_set_64_T1(imm >> 32, imm); -#endif - } + tcg_gen_mov_i64(cpu_lock, t1); + tcg_gen_qemu_ld32s(t0, t1, flags); } -static always_inline void gen_set_uT0 (DisasContext *ctx, uint64_t imm) +static always_inline void gen_qemu_ldq_l (TCGv t0, TCGv t1, int flags) { - if (!(imm >> 32)) { - if ((!imm >> 16)) { - if (imm == 0) - gen_op_reset_T0(); - else - gen_op_set_u16_T0(imm); - } else { - gen_op_set_u32_T0(imm); - } - } else { -#if 0 // Qemu does not know how to do this... - gen_op_set_64_T0(imm); -#else - gen_op_set_64_T0(imm >> 32, imm); -#endif - } + tcg_gen_mov_i64(cpu_lock, t1); + tcg_gen_qemu_ld64(t0, t1, flags); } -static always_inline void gen_set_uT1 (DisasContext *ctx, uint64_t imm) +static always_inline void gen_load_mem (DisasContext *ctx, + void (*tcg_gen_qemu_load)(TCGv t0, TCGv t1, int flags), + int ra, int rb, int32_t disp16, + int fp, int clear) { - if (!(imm >> 32)) { - if ((!imm >> 16)) { - if (imm == 0) - gen_op_reset_T1(); - else - gen_op_set_u16_T1(imm); - } else { - gen_op_set_u32_T1(imm); - } + TCGv addr; + + if (unlikely(ra == 31)) + return; + + addr = tcg_temp_new(TCG_TYPE_I64); + if (rb != 31) { + tcg_gen_addi_i64(addr, cpu_ir[rb], disp16); + if (clear) + tcg_gen_andi_i64(addr, addr, ~0x7); } else { -#if 0 // Qemu does not know how to do this... - gen_op_set_64_T1(imm); -#else - gen_op_set_64_T1(imm >> 32, imm); -#endif + if (clear) + disp16 &= ~0x7; + tcg_gen_movi_i64(addr, disp16); } + if (fp) + tcg_gen_qemu_load(cpu_fir[ra], addr, ctx->mem_idx); + else + tcg_gen_qemu_load(cpu_ir[ra], addr, ctx->mem_idx); + tcg_temp_free(addr); } -static always_inline void gen_update_pc (DisasContext *ctx) +static always_inline void gen_qemu_stf (TCGv t0, TCGv t1, int flags) { - if (!(ctx->pc >> 32)) { - gen_op_update_pc32(ctx->pc); - } else { -#if 0 // Qemu does not know how to do this... - gen_op_update_pc(ctx->pc); -#else - gen_op_update_pc(ctx->pc >> 32, ctx->pc); -#endif - } + TCGv tmp = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_helper_1_1(helper_f_to_memory, tmp, t0); + tcg_gen_qemu_st32(tmp, t1, flags); + tcg_temp_free(tmp); } -static always_inline void _gen_op_bcond (DisasContext *ctx) +static always_inline void gen_qemu_stg (TCGv t0, TCGv t1, int flags) { -#if 0 // Qemu does not know how to do this... - gen_op_bcond(ctx->pc); -#else - gen_op_bcond(ctx->pc >> 32, ctx->pc); -#endif + TCGv tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_helper_1_1(helper_g_to_memory, tmp, t0); + tcg_gen_qemu_st64(tmp, t1, flags); + tcg_temp_free(tmp); } -static always_inline void gen_excp (DisasContext *ctx, - int exception, int error_code) +static always_inline void gen_qemu_sts (TCGv t0, TCGv t1, int flags) { - gen_update_pc(ctx); - gen_op_excp(exception, error_code); + TCGv tmp = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_helper_1_1(helper_s_to_memory, tmp, t0); + tcg_gen_qemu_st32(tmp, t1, flags); + tcg_temp_free(tmp); } -static always_inline void gen_invalid (DisasContext *ctx) +static always_inline void gen_qemu_stl_c (TCGv t0, TCGv t1, int flags) { - gen_excp(ctx, EXCP_OPCDEC, 0); + int l1, l2; + + l1 = gen_new_label(); + l2 = gen_new_label(); + tcg_gen_brcond_i64(TCG_COND_NE, cpu_lock, t1, l1); + tcg_gen_qemu_st32(t0, t1, flags); + tcg_gen_movi_i64(t0, 1); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i64(t0, 0); + gen_set_label(l2); + tcg_gen_movi_i64(cpu_lock, -1); } -static always_inline void gen_load_mem (DisasContext *ctx, - void (*gen_load_op)(DisasContext *ctx), - int ra, int rb, int32_t disp16, - int clear) +static always_inline void gen_qemu_stq_c (TCGv t0, TCGv t1, int flags) { - if (ra == 31 && disp16 == 0) { - /* UNOP */ - gen_op_nop(); - } else { - gen_load_ir(ctx, rb, 0); - if (disp16 != 0) { - gen_set_sT1(ctx, disp16); - gen_op_addq(); - } - if (clear) - gen_op_n7(); - (*gen_load_op)(ctx); - gen_store_ir(ctx, ra, 1); - } + int l1, l2; + + l1 = gen_new_label(); + l2 = gen_new_label(); + tcg_gen_brcond_i64(TCG_COND_NE, cpu_lock, t1, l1); + tcg_gen_qemu_st64(t0, t1, flags); + tcg_gen_movi_i64(t0, 1); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i64(t0, 0); + gen_set_label(l2); + tcg_gen_movi_i64(cpu_lock, -1); } static always_inline void gen_store_mem (DisasContext *ctx, - void (*gen_store_op)(DisasContext *ctx), + void (*tcg_gen_qemu_store)(TCGv t0, TCGv t1, int flags), int ra, int rb, int32_t disp16, - int clear) + int fp, int clear, int local) { - gen_load_ir(ctx, rb, 0); - if (disp16 != 0) { - gen_set_sT1(ctx, disp16); - gen_op_addq(); - } - if (clear) - gen_op_n7(); - gen_load_ir(ctx, ra, 1); - (*gen_store_op)(ctx); -} - -static always_inline void gen_load_fmem (DisasContext *ctx, - void (*gen_load_fop)(DisasContext *ctx), - int ra, int rb, int32_t disp16) -{ - gen_load_ir(ctx, rb, 0); - if (disp16 != 0) { - gen_set_sT1(ctx, disp16); - gen_op_addq(); + TCGv addr; + if (local) + addr = tcg_temp_local_new(TCG_TYPE_I64); + else + addr = tcg_temp_new(TCG_TYPE_I64); + if (rb != 31) { + tcg_gen_addi_i64(addr, cpu_ir[rb], disp16); + if (clear) + tcg_gen_andi_i64(addr, addr, ~0x7); + } else { + if (clear) + disp16 &= ~0x7; + tcg_gen_movi_i64(addr, disp16); } - (*gen_load_fop)(ctx); - gen_store_fir(ctx, ra, 1); -} - -static always_inline void gen_store_fmem (DisasContext *ctx, - void (*gen_store_fop)(DisasContext *ctx), - int ra, int rb, int32_t disp16) -{ - gen_load_ir(ctx, rb, 0); - if (disp16 != 0) { - gen_set_sT1(ctx, disp16); - gen_op_addq(); + if (ra != 31) { + if (fp) + tcg_gen_qemu_store(cpu_fir[ra], addr, ctx->mem_idx); + else + tcg_gen_qemu_store(cpu_ir[ra], addr, ctx->mem_idx); + } else { + TCGv zero; + if (local) + zero = tcg_const_local_i64(0); + else + zero = tcg_const_i64(0); + tcg_gen_qemu_store(zero, addr, ctx->mem_idx); + tcg_temp_free(zero); } - gen_load_fir(ctx, ra, 1); - (*gen_store_fop)(ctx); + tcg_temp_free(addr); } static always_inline void gen_bcond (DisasContext *ctx, - void (*gen_test_op)(void), - int ra, int32_t disp16) + TCGCond cond, + int ra, int32_t disp16, int mask) { - if (disp16 != 0) { - gen_set_uT0(ctx, ctx->pc); - gen_set_sT1(ctx, disp16 << 2); - gen_op_addq1(); + int l1, l2; + + l1 = gen_new_label(); + l2 = gen_new_label(); + if (likely(ra != 31)) { + if (mask) { + TCGv tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_andi_i64(tmp, cpu_ir[ra], 1); + tcg_gen_brcondi_i64(cond, tmp, 0, l1); + tcg_temp_free(tmp); + } else + tcg_gen_brcondi_i64(cond, cpu_ir[ra], 0, l1); } else { - gen_set_uT1(ctx, ctx->pc); - } - gen_load_ir(ctx, ra, 0); - (*gen_test_op)(); - _gen_op_bcond(ctx); + /* Very uncommon case - Do not bother to optimize. */ + TCGv tmp = tcg_const_i64(0); + tcg_gen_brcondi_i64(cond, tmp, 0, l1); + tcg_temp_free(tmp); + } + tcg_gen_movi_i64(cpu_pc, ctx->pc); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i64(cpu_pc, ctx->pc + (int64_t)(disp16 << 2)); + gen_set_label(l2); } static always_inline void gen_fbcond (DisasContext *ctx, - void (*gen_test_op)(void), + void* func, int ra, int32_t disp16) { - if (disp16 != 0) { - gen_set_uT0(ctx, ctx->pc); - gen_set_sT1(ctx, disp16 << 2); - gen_op_addq1(); - } else { - gen_set_uT1(ctx, ctx->pc); - } - gen_load_fir(ctx, ra, 0); - (*gen_test_op)(); - _gen_op_bcond(ctx); -} + int l1, l2; + TCGv tmp; -static always_inline void gen_arith2 (DisasContext *ctx, - void (*gen_arith_op)(void), - int rb, int rc, int islit, int8_t lit) -{ - if (islit) - gen_set_sT0(ctx, lit); - else - gen_load_ir(ctx, rb, 0); - (*gen_arith_op)(); - gen_store_ir(ctx, rc, 0); + l1 = gen_new_label(); + l2 = gen_new_label(); + if (ra != 31) { + tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_helper_1_1(func, tmp, cpu_fir[ra]); + } else { + tmp = tcg_const_i64(0); + tcg_gen_helper_1_1(func, tmp, tmp); + } + tcg_gen_brcondi_i64(TCG_COND_NE, tmp, 0, l1); + tcg_gen_movi_i64(cpu_pc, ctx->pc); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i64(cpu_pc, ctx->pc + (int64_t)(disp16 << 2)); + gen_set_label(l2); } -static always_inline void gen_arith3 (DisasContext *ctx, - void (*gen_arith_op)(void), - int ra, int rb, int rc, - int islit, int8_t lit) -{ - gen_load_ir(ctx, ra, 0); - if (islit) - gen_set_sT1(ctx, lit); - else - gen_load_ir(ctx, rb, 1); - (*gen_arith_op)(); - gen_store_ir(ctx, rc, 0); -} - -static always_inline void gen_cmov (DisasContext *ctx, - void (*gen_test_op)(void), +static always_inline void gen_cmov (TCGCond inv_cond, int ra, int rb, int rc, - int islit, int8_t lit) + int islit, uint8_t lit, int mask) { - gen_load_ir(ctx, ra, 1); + int l1; + + if (unlikely(rc == 31)) + return; + + l1 = gen_new_label(); + + if (ra != 31) { + if (mask) { + TCGv tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_andi_i64(tmp, cpu_ir[ra], 1); + tcg_gen_brcondi_i64(inv_cond, tmp, 0, l1); + tcg_temp_free(tmp); + } else + tcg_gen_brcondi_i64(inv_cond, cpu_ir[ra], 0, l1); + } else { + /* Very uncommon case - Do not bother to optimize. */ + TCGv tmp = tcg_const_i64(0); + tcg_gen_brcondi_i64(inv_cond, tmp, 0, l1); + tcg_temp_free(tmp); + } + if (islit) - gen_set_sT0(ctx, lit); + tcg_gen_movi_i64(cpu_ir[rc], lit); else - gen_load_ir(ctx, rb, 0); - (*gen_test_op)(); - gen_op_cmov_ir(rc); + tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]); + gen_set_label(l1); } -static always_inline void gen_farith2 (DisasContext *ctx, - void (*gen_arith_fop)(void), +static always_inline void gen_farith2 (void *helper, int rb, int rc) { - gen_load_fir(ctx, rb, 0); - (*gen_arith_fop)(); - gen_store_fir(ctx, rc, 0); + if (unlikely(rc == 31)) + return; + + if (rb != 31) + tcg_gen_helper_1_1(helper, cpu_fir[rc], cpu_fir[rb]); + else { + TCGv tmp = tcg_const_i64(0); + tcg_gen_helper_1_1(helper, cpu_fir[rc], tmp); + tcg_temp_free(tmp); + } } -static always_inline void gen_farith3 (DisasContext *ctx, - void (*gen_arith_fop)(void), +static always_inline void gen_farith3 (void *helper, int ra, int rb, int rc) { - gen_load_fir(ctx, ra, 0); - gen_load_fir(ctx, rb, 1); - (*gen_arith_fop)(); - gen_store_fir(ctx, rc, 0); -} + if (unlikely(rc == 31)) + return; -static always_inline void gen_fcmov (DisasContext *ctx, - void (*gen_test_fop)(void), - int ra, int rb, int rc) -{ - gen_load_fir(ctx, ra, 0); - gen_load_fir(ctx, rb, 1); - (*gen_test_fop)(); - gen_op_cmov_fir(rc); + if (ra != 31) { + if (rb != 31) + tcg_gen_helper_1_2(helper, cpu_fir[rc], cpu_fir[ra], cpu_fir[rb]); + else { + TCGv tmp = tcg_const_i64(0); + tcg_gen_helper_1_2(helper, cpu_fir[rc], cpu_fir[ra], tmp); + tcg_temp_free(tmp); + } + } else { + TCGv tmp = tcg_const_i64(0); + if (rb != 31) + tcg_gen_helper_1_2(helper, cpu_fir[rc], tmp, cpu_fir[rb]); + else + tcg_gen_helper_1_2(helper, cpu_fir[rc], tmp, tmp); + tcg_temp_free(tmp); + } } -static always_inline void gen_fti (DisasContext *ctx, - void (*gen_move_fop)(void), - int ra, int rc) +static always_inline void gen_fcmov (void *func, + int ra, int rb, int rc) { - gen_load_fir(ctx, rc, 0); - (*gen_move_fop)(); - gen_store_ir(ctx, ra, 0); -} + int l1; + TCGv tmp; -static always_inline void gen_itf (DisasContext *ctx, - void (*gen_move_fop)(void), - int ra, int rc) -{ - gen_load_ir(ctx, ra, 0); - (*gen_move_fop)(); - gen_store_fir(ctx, rc, 0); -} + if (unlikely(rc == 31)) + return; -static always_inline void gen_s4addl (void) -{ - gen_op_s4(); - gen_op_addl(); + l1 = gen_new_label(); + tmp = tcg_temp_new(TCG_TYPE_I64); + if (ra != 31) { + tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_helper_1_1(func, tmp, cpu_fir[ra]); + } else { + tmp = tcg_const_i64(0); + tcg_gen_helper_1_1(func, tmp, tmp); + } + tcg_gen_brcondi_i64(TCG_COND_EQ, tmp, 0, l1); + if (rb != 31) + tcg_gen_mov_i64(cpu_fir[rc], cpu_fir[ra]); + else + tcg_gen_movi_i64(cpu_fir[rc], 0); + gen_set_label(l1); } -static always_inline void gen_s4subl (void) +/* EXTWH, EXTWH, EXTLH, EXTQH */ +static always_inline void gen_ext_h(void (*tcg_gen_ext_i64)(TCGv t0, TCGv t1), + int ra, int rb, int rc, + int islit, uint8_t lit) { - gen_op_s4(); - gen_op_subl(); -} + if (unlikely(rc == 31)) + return; -static always_inline void gen_s8addl (void) -{ - gen_op_s8(); - gen_op_addl(); + if (ra != 31) { + if (islit) { + if (lit != 0) + tcg_gen_shli_i64(cpu_ir[rc], cpu_ir[ra], 64 - ((lit & 7) * 8)); + else + tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[ra]); + } else { + TCGv tmp1, tmp2; + tmp1 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_andi_i64(tmp1, cpu_ir[rb], 7); + tcg_gen_shli_i64(tmp1, tmp1, 3); + tmp2 = tcg_const_i64(64); + tcg_gen_sub_i64(tmp1, tmp2, tmp1); + tcg_temp_free(tmp2); + tcg_gen_shl_i64(cpu_ir[rc], cpu_ir[ra], tmp1); + tcg_temp_free(tmp1); + } + if (tcg_gen_ext_i64) + tcg_gen_ext_i64(cpu_ir[rc], cpu_ir[rc]); + } else + tcg_gen_movi_i64(cpu_ir[rc], 0); } -static always_inline void gen_s8subl (void) +/* EXTBL, EXTWL, EXTWL, EXTLL, EXTQL */ +static always_inline void gen_ext_l(void (*tcg_gen_ext_i64)(TCGv t0, TCGv t1), + int ra, int rb, int rc, + int islit, uint8_t lit) { - gen_op_s8(); - gen_op_subl(); -} + if (unlikely(rc == 31)) + return; -static always_inline void gen_s4addq (void) -{ - gen_op_s4(); - gen_op_addq(); + if (ra != 31) { + if (islit) { + tcg_gen_shri_i64(cpu_ir[rc], cpu_ir[ra], (lit & 7) * 8); + } else { + TCGv tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_andi_i64(tmp, cpu_ir[rb], 7); + tcg_gen_shli_i64(tmp, tmp, 3); + tcg_gen_shr_i64(cpu_ir[rc], cpu_ir[ra], tmp); + tcg_temp_free(tmp); + } + if (tcg_gen_ext_i64) + tcg_gen_ext_i64(cpu_ir[rc], cpu_ir[rc]); + } else + tcg_gen_movi_i64(cpu_ir[rc], 0); } -static always_inline void gen_s4subq (void) +/* Code to call arith3 helpers */ +static always_inline void gen_arith3 (void *helper, + int ra, int rb, int rc, + int islit, uint8_t lit) { - gen_op_s4(); - gen_op_subq(); -} + if (unlikely(rc == 31)) + return; -static always_inline void gen_s8addq (void) -{ - gen_op_s8(); - gen_op_addq(); + if (ra != 31) { + if (islit) { + TCGv tmp = tcg_const_i64(lit); + tcg_gen_helper_1_2(helper, cpu_ir[rc], cpu_ir[ra], tmp); + tcg_temp_free(tmp); + } else + tcg_gen_helper_1_2(helper, cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]); + } else { + TCGv tmp1 = tcg_const_i64(0); + if (islit) { + TCGv tmp2 = tcg_const_i64(lit); + tcg_gen_helper_1_2(helper, cpu_ir[rc], tmp1, tmp2); + tcg_temp_free(tmp2); + } else + tcg_gen_helper_1_2(helper, cpu_ir[rc], tmp1, cpu_ir[rb]); + tcg_temp_free(tmp1); + } } -static always_inline void gen_s8subq (void) -{ - gen_op_s8(); - gen_op_subq(); -} +static always_inline void gen_cmp(TCGCond cond, + int ra, int rb, int rc, + int islit, uint8_t lit) +{ + int l1, l2; + TCGv tmp; + + if (unlikely(rc == 31)) + return; + + l1 = gen_new_label(); + l2 = gen_new_label(); + + if (ra != 31) { + tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_mov_i64(tmp, cpu_ir[ra]); + } else + tmp = tcg_const_i64(0); + if (islit) + tcg_gen_brcondi_i64(cond, tmp, lit, l1); + else + tcg_gen_brcond_i64(cond, tmp, cpu_ir[rb], l1); -static always_inline void gen_amask (void) -{ - gen_op_load_amask(); - gen_op_bic(); + tcg_gen_movi_i64(cpu_ir[rc], 0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i64(cpu_ir[rc], 1); + gen_set_label(l2); } static always_inline int translate_one (DisasContext *ctx, uint32_t insn) @@ -633,7 +536,7 @@ int32_t disp21, disp16, disp12; uint16_t fn11, fn16; uint8_t opc, ra, rb, rc, sbz, fpfn, fn7, fn2, islit; - int8_t lit; + uint8_t lit; int ret; /* Decode all instruction fields */ @@ -643,7 +546,11 @@ rc = insn & 0x1F; sbz = (insn >> 13) & 0x07; islit = (insn >> 12) & 1; - lit = (insn >> 13) & 0xFF; + if (rb == 31 && !islit) { + islit = 1; + lit = 0; + } else + lit = (insn >> 13) & 0xFF; palcode = insn & 0x03FFFFFF; disp21 = ((int32_t)((insn & 0x001FFFFF) << 11)) >> 11; disp16 = (int16_t)(insn & 0x0000FFFF); @@ -703,139 +610,320 @@ goto invalid_opc; case 0x08: /* LDA */ - gen_load_ir(ctx, rb, 0); - gen_set_sT1(ctx, disp16); - gen_op_addq(); - gen_store_ir(ctx, ra, 0); + if (likely(ra != 31)) { + if (rb != 31) + tcg_gen_addi_i64(cpu_ir[ra], cpu_ir[rb], disp16); + else + tcg_gen_movi_i64(cpu_ir[ra], disp16); + } break; case 0x09: /* LDAH */ - gen_load_ir(ctx, rb, 0); - gen_set_sT1(ctx, disp16 << 16); - gen_op_addq(); - gen_store_ir(ctx, ra, 0); + if (likely(ra != 31)) { + if (rb != 31) + tcg_gen_addi_i64(cpu_ir[ra], cpu_ir[rb], disp16 << 16); + else + tcg_gen_movi_i64(cpu_ir[ra], disp16 << 16); + } break; case 0x0A: /* LDBU */ if (!(ctx->amask & AMASK_BWX)) goto invalid_opc; - gen_load_mem(ctx, &gen_ldbu, ra, rb, disp16, 0); + gen_load_mem(ctx, &tcg_gen_qemu_ld8u, ra, rb, disp16, 0, 0); break; case 0x0B: /* LDQ_U */ - gen_load_mem(ctx, &gen_ldq_u, ra, rb, disp16, 1); + gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 0, 1); break; case 0x0C: /* LDWU */ if (!(ctx->amask & AMASK_BWX)) goto invalid_opc; - gen_load_mem(ctx, &gen_ldwu, ra, rb, disp16, 0); + gen_load_mem(ctx, &tcg_gen_qemu_ld16u, ra, rb, disp16, 0, 1); break; case 0x0D: /* STW */ - if (!(ctx->amask & AMASK_BWX)) - goto invalid_opc; - gen_store_mem(ctx, &gen_stw, ra, rb, disp16, 0); + gen_store_mem(ctx, &tcg_gen_qemu_st16, ra, rb, disp16, 0, 0, 0); break; case 0x0E: /* STB */ - if (!(ctx->amask & AMASK_BWX)) - goto invalid_opc; - gen_store_mem(ctx, &gen_stb, ra, rb, disp16, 0); + gen_store_mem(ctx, &tcg_gen_qemu_st8, ra, rb, disp16, 0, 0, 0); break; case 0x0F: /* STQ_U */ - gen_store_mem(ctx, &gen_stq_u, ra, rb, disp16, 1); + gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 0, 1, 0); break; case 0x10: switch (fn7) { case 0x00: /* ADDL */ - gen_arith3(ctx, &gen_op_addl, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + if (islit) { + tcg_gen_addi_i64(cpu_ir[rc], cpu_ir[ra], lit); + tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]); + } else { + tcg_gen_add_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]); + tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]); + } + } else { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], lit); + else + tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rb]); + } + } break; case 0x02: /* S4ADDL */ - gen_arith3(ctx, &gen_s4addl, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + TCGv tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_shli_i64(tmp, cpu_ir[ra], 2); + if (islit) + tcg_gen_addi_i64(tmp, tmp, lit); + else + tcg_gen_add_i64(tmp, tmp, cpu_ir[rb]); + tcg_gen_ext32s_i64(cpu_ir[rc], tmp); + tcg_temp_free(tmp); + } else { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], lit); + else + tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rb]); + } + } break; case 0x09: /* SUBL */ - gen_arith3(ctx, &gen_op_subl, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + if (islit) + tcg_gen_subi_i64(cpu_ir[rc], cpu_ir[ra], lit); + else + tcg_gen_sub_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]); + tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]); + } else { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], -lit); + else { + tcg_gen_neg_i64(cpu_ir[rc], cpu_ir[rb]); + tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]); + } + } break; case 0x0B: /* S4SUBL */ - gen_arith3(ctx, &gen_s4subl, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + TCGv tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_shli_i64(tmp, cpu_ir[ra], 2); + if (islit) + tcg_gen_subi_i64(tmp, tmp, lit); + else + tcg_gen_sub_i64(tmp, tmp, cpu_ir[rb]); + tcg_gen_ext32s_i64(cpu_ir[rc], tmp); + tcg_temp_free(tmp); + } else { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], -lit); + else { + tcg_gen_neg_i64(cpu_ir[rc], cpu_ir[rb]); + tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]); + } + } + } break; case 0x0F: /* CMPBGE */ - gen_arith3(ctx, &gen_op_cmpbge, ra, rb, rc, islit, lit); + gen_arith3(helper_cmpbge, ra, rb, rc, islit, lit); break; case 0x12: /* S8ADDL */ - gen_arith3(ctx, &gen_s8addl, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + TCGv tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_shli_i64(tmp, cpu_ir[ra], 3); + if (islit) + tcg_gen_addi_i64(tmp, tmp, lit); + else + tcg_gen_add_i64(tmp, tmp, cpu_ir[rb]); + tcg_gen_ext32s_i64(cpu_ir[rc], tmp); + tcg_temp_free(tmp); + } else { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], lit); + else + tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rb]); + } + } break; case 0x1B: /* S8SUBL */ - gen_arith3(ctx, &gen_s8subl, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + TCGv tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_shli_i64(tmp, cpu_ir[ra], 3); + if (islit) + tcg_gen_subi_i64(tmp, tmp, lit); + else + tcg_gen_sub_i64(tmp, tmp, cpu_ir[rb]); + tcg_gen_ext32s_i64(cpu_ir[rc], tmp); + tcg_temp_free(tmp); + } else { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], -lit); + else + tcg_gen_neg_i64(cpu_ir[rc], cpu_ir[rb]); + tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]); + } + } + } break; case 0x1D: /* CMPULT */ - gen_arith3(ctx, &gen_op_cmpult, ra, rb, rc, islit, lit); + gen_cmp(TCG_COND_LTU, ra, rb, rc, islit, lit); break; case 0x20: /* ADDQ */ - gen_arith3(ctx, &gen_op_addq, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + if (islit) + tcg_gen_addi_i64(cpu_ir[rc], cpu_ir[ra], lit); + else + tcg_gen_add_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]); + } else { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], lit); + else + tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]); + } + } break; case 0x22: /* S4ADDQ */ - gen_arith3(ctx, &gen_s4addq, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + TCGv tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_shli_i64(tmp, cpu_ir[ra], 2); + if (islit) + tcg_gen_addi_i64(cpu_ir[rc], tmp, lit); + else + tcg_gen_add_i64(cpu_ir[rc], tmp, cpu_ir[rb]); + tcg_temp_free(tmp); + } else { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], lit); + else + tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]); + } + } break; case 0x29: /* SUBQ */ - gen_arith3(ctx, &gen_op_subq, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + if (islit) + tcg_gen_subi_i64(cpu_ir[rc], cpu_ir[ra], lit); + else + tcg_gen_sub_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]); + } else { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], -lit); + else + tcg_gen_neg_i64(cpu_ir[rc], cpu_ir[rb]); + } + } break; case 0x2B: /* S4SUBQ */ - gen_arith3(ctx, &gen_s4subq, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + TCGv tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_shli_i64(tmp, cpu_ir[ra], 2); + if (islit) + tcg_gen_subi_i64(cpu_ir[rc], tmp, lit); + else + tcg_gen_sub_i64(cpu_ir[rc], tmp, cpu_ir[rb]); + tcg_temp_free(tmp); + } else { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], -lit); + else + tcg_gen_neg_i64(cpu_ir[rc], cpu_ir[rb]); + } + } break; case 0x2D: /* CMPEQ */ - gen_arith3(ctx, &gen_op_cmpeq, ra, rb, rc, islit, lit); + gen_cmp(TCG_COND_EQ, ra, rb, rc, islit, lit); break; case 0x32: /* S8ADDQ */ - gen_arith3(ctx, &gen_s8addq, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + TCGv tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_shli_i64(tmp, cpu_ir[ra], 3); + if (islit) + tcg_gen_addi_i64(cpu_ir[rc], tmp, lit); + else + tcg_gen_add_i64(cpu_ir[rc], tmp, cpu_ir[rb]); + tcg_temp_free(tmp); + } else { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], lit); + else + tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]); + } + } break; case 0x3B: /* S8SUBQ */ - gen_arith3(ctx, &gen_s8subq, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + TCGv tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_shli_i64(tmp, cpu_ir[ra], 3); + if (islit) + tcg_gen_subi_i64(cpu_ir[rc], tmp, lit); + else + tcg_gen_sub_i64(cpu_ir[rc], tmp, cpu_ir[rb]); + tcg_temp_free(tmp); + } else { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], -lit); + else + tcg_gen_neg_i64(cpu_ir[rc], cpu_ir[rb]); + } + } break; case 0x3D: /* CMPULE */ - gen_arith3(ctx, &gen_op_cmpule, ra, rb, rc, islit, lit); + gen_cmp(TCG_COND_LEU, ra, rb, rc, islit, lit); break; case 0x40: /* ADDL/V */ - gen_arith3(ctx, &gen_op_addlv, ra, rb, rc, islit, lit); + gen_arith3(helper_addlv, ra, rb, rc, islit, lit); break; case 0x49: /* SUBL/V */ - gen_arith3(ctx, &gen_op_sublv, ra, rb, rc, islit, lit); + gen_arith3(helper_sublv, ra, rb, rc, islit, lit); break; case 0x4D: /* CMPLT */ - gen_arith3(ctx, &gen_op_cmplt, ra, rb, rc, islit, lit); + gen_cmp(TCG_COND_LT, ra, rb, rc, islit, lit); break; case 0x60: /* ADDQ/V */ - gen_arith3(ctx, &gen_op_addqv, ra, rb, rc, islit, lit); + gen_arith3(helper_addqv, ra, rb, rc, islit, lit); break; case 0x69: /* SUBQ/V */ - gen_arith3(ctx, &gen_op_subqv, ra, rb, rc, islit, lit); + gen_arith3(helper_subqv, ra, rb, rc, islit, lit); break; case 0x6D: /* CMPLE */ - gen_arith3(ctx, &gen_op_cmple, ra, rb, rc, islit, lit); + gen_cmp(TCG_COND_LE, ra, rb, rc, islit, lit); break; default: goto invalid_opc; @@ -845,79 +933,136 @@ switch (fn7) { case 0x00: /* AND */ - gen_arith3(ctx, &gen_op_and, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra == 31) + tcg_gen_movi_i64(cpu_ir[rc], 0); + else if (islit) + tcg_gen_andi_i64(cpu_ir[rc], cpu_ir[ra], lit); + else + tcg_gen_and_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]); + } break; case 0x08: /* BIC */ - gen_arith3(ctx, &gen_op_bic, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + if (islit) + tcg_gen_andi_i64(cpu_ir[rc], cpu_ir[ra], ~lit); + else + tcg_gen_andc_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]); + } else + tcg_gen_movi_i64(cpu_ir[rc], 0); + } break; case 0x14: /* CMOVLBS */ - gen_cmov(ctx, &gen_op_cmplbs, ra, rb, rc, islit, lit); + gen_cmov(TCG_COND_EQ, ra, rb, rc, islit, lit, 1); break; case 0x16: /* CMOVLBC */ - gen_cmov(ctx, &gen_op_cmplbc, ra, rb, rc, islit, lit); + gen_cmov(TCG_COND_NE, ra, rb, rc, islit, lit, 1); break; case 0x20: /* BIS */ - if (ra == rb || ra == 31 || rb == 31) { - if (ra == 31 && rc == 31) { - /* NOP */ - gen_op_nop(); + if (likely(rc != 31)) { + if (ra != 31) { + if (islit) + tcg_gen_ori_i64(cpu_ir[rc], cpu_ir[ra], lit); + else + tcg_gen_or_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]); } else { - /* MOV */ - gen_load_ir(ctx, rb, 0); - gen_store_ir(ctx, rc, 0); + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], lit); + else + tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]); } - } else { - gen_arith3(ctx, &gen_op_bis, ra, rb, rc, islit, lit); } break; case 0x24: /* CMOVEQ */ - gen_cmov(ctx, &gen_op_cmpeqz, ra, rb, rc, islit, lit); + gen_cmov(TCG_COND_NE, ra, rb, rc, islit, lit, 0); break; case 0x26: /* CMOVNE */ - gen_cmov(ctx, &gen_op_cmpnez, ra, rb, rc, islit, lit); + gen_cmov(TCG_COND_EQ, ra, rb, rc, islit, lit, 0); break; case 0x28: /* ORNOT */ - gen_arith3(ctx, &gen_op_ornot, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + if (islit) + tcg_gen_ori_i64(cpu_ir[rc], cpu_ir[ra], ~lit); + else + tcg_gen_orc_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]); + } else { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], ~lit); + else + tcg_gen_not_i64(cpu_ir[rc], cpu_ir[rb]); + } + } break; case 0x40: /* XOR */ - gen_arith3(ctx, &gen_op_xor, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + if (islit) + tcg_gen_xori_i64(cpu_ir[rc], cpu_ir[ra], lit); + else + tcg_gen_xor_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]); + } else { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], lit); + else + tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]); + } + } break; case 0x44: /* CMOVLT */ - gen_cmov(ctx, &gen_op_cmpltz, ra, rb, rc, islit, lit); + gen_cmov(TCG_COND_GE, ra, rb, rc, islit, lit, 0); break; case 0x46: /* CMOVGE */ - gen_cmov(ctx, &gen_op_cmpgez, ra, rb, rc, islit, lit); + gen_cmov(TCG_COND_LT, ra, rb, rc, islit, lit, 0); break; case 0x48: /* EQV */ - gen_arith3(ctx, &gen_op_eqv, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + if (islit) + tcg_gen_xori_i64(cpu_ir[rc], cpu_ir[ra], ~lit); + else + tcg_gen_eqv_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]); + } else { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], ~lit); + else + tcg_gen_not_i64(cpu_ir[rc], cpu_ir[rb]); + } + } break; case 0x61: /* AMASK */ - gen_arith2(ctx, &gen_amask, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], helper_amask(lit)); + else + tcg_gen_helper_1_1(helper_amask, cpu_ir[rc], cpu_ir[rb]); + } break; case 0x64: /* CMOVLE */ - gen_cmov(ctx, &gen_op_cmplez, ra, rb, rc, islit, lit); + gen_cmov(TCG_COND_GT, ra, rb, rc, islit, lit, 0); break; case 0x66: /* CMOVGT */ - gen_cmov(ctx, &gen_op_cmpgtz, ra, rb, rc, islit, lit); + gen_cmov(TCG_COND_LE, ra, rb, rc, islit, lit, 0); break; case 0x6C: /* IMPLVER */ - gen_op_load_implver(); - gen_store_ir(ctx, rc, 0); + if (rc != 31) + tcg_gen_helper_1_0(helper_load_implver, cpu_ir[rc]); break; default: goto invalid_opc; @@ -927,107 +1072,143 @@ switch (fn7) { case 0x02: /* MSKBL */ - gen_arith3(ctx, &gen_op_mskbl, ra, rb, rc, islit, lit); + gen_arith3(helper_mskbl, ra, rb, rc, islit, lit); break; case 0x06: /* EXTBL */ - gen_arith3(ctx, &gen_op_extbl, ra, rb, rc, islit, lit); + gen_ext_l(&tcg_gen_ext8u_i64, ra, rb, rc, islit, lit); break; case 0x0B: /* INSBL */ - gen_arith3(ctx, &gen_op_insbl, ra, rb, rc, islit, lit); + gen_arith3(helper_insbl, ra, rb, rc, islit, lit); break; case 0x12: /* MSKWL */ - gen_arith3(ctx, &gen_op_mskwl, ra, rb, rc, islit, lit); + gen_arith3(helper_mskwl, ra, rb, rc, islit, lit); break; case 0x16: /* EXTWL */ - gen_arith3(ctx, &gen_op_extwl, ra, rb, rc, islit, lit); + gen_ext_l(&tcg_gen_ext16u_i64, ra, rb, rc, islit, lit); break; case 0x1B: /* INSWL */ - gen_arith3(ctx, &gen_op_inswl, ra, rb, rc, islit, lit); + gen_arith3(helper_inswl, ra, rb, rc, islit, lit); break; case 0x22: /* MSKLL */ - gen_arith3(ctx, &gen_op_mskll, ra, rb, rc, islit, lit); + gen_arith3(helper_mskll, ra, rb, rc, islit, lit); break; case 0x26: /* EXTLL */ - gen_arith3(ctx, &gen_op_extll, ra, rb, rc, islit, lit); + gen_ext_l(&tcg_gen_ext32u_i64, ra, rb, rc, islit, lit); break; case 0x2B: /* INSLL */ - gen_arith3(ctx, &gen_op_insll, ra, rb, rc, islit, lit); + gen_arith3(helper_insll, ra, rb, rc, islit, lit); break; case 0x30: /* ZAP */ - gen_arith3(ctx, &gen_op_zap, ra, rb, rc, islit, lit); + gen_arith3(helper_zap, ra, rb, rc, islit, lit); break; case 0x31: /* ZAPNOT */ - gen_arith3(ctx, &gen_op_zapnot, ra, rb, rc, islit, lit); + gen_arith3(helper_zapnot, ra, rb, rc, islit, lit); break; case 0x32: /* MSKQL */ - gen_arith3(ctx, &gen_op_mskql, ra, rb, rc, islit, lit); + gen_arith3(helper_mskql, ra, rb, rc, islit, lit); break; case 0x34: /* SRL */ - gen_arith3(ctx, &gen_op_srl, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + if (islit) + tcg_gen_shri_i64(cpu_ir[rc], cpu_ir[ra], lit & 0x3f); + else { + TCGv shift = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_andi_i64(shift, cpu_ir[rb], 0x3f); + tcg_gen_shr_i64(cpu_ir[rc], cpu_ir[ra], shift); + tcg_temp_free(shift); + } + } else + tcg_gen_movi_i64(cpu_ir[rc], 0); + } break; case 0x36: /* EXTQL */ - gen_arith3(ctx, &gen_op_extql, ra, rb, rc, islit, lit); + gen_ext_l(NULL, ra, rb, rc, islit, lit); break; case 0x39: /* SLL */ - gen_arith3(ctx, &gen_op_sll, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + if (islit) + tcg_gen_shli_i64(cpu_ir[rc], cpu_ir[ra], lit & 0x3f); + else { + TCGv shift = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_andi_i64(shift, cpu_ir[rb], 0x3f); + tcg_gen_shl_i64(cpu_ir[rc], cpu_ir[ra], shift); + tcg_temp_free(shift); + } + } else + tcg_gen_movi_i64(cpu_ir[rc], 0); + } break; case 0x3B: /* INSQL */ - gen_arith3(ctx, &gen_op_insql, ra, rb, rc, islit, lit); + gen_arith3(helper_insql, ra, rb, rc, islit, lit); break; case 0x3C: /* SRA */ - gen_arith3(ctx, &gen_op_sra, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra != 31) { + if (islit) + tcg_gen_sari_i64(cpu_ir[rc], cpu_ir[ra], lit & 0x3f); + else { + TCGv shift = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_andi_i64(shift, cpu_ir[rb], 0x3f); + tcg_gen_sar_i64(cpu_ir[rc], cpu_ir[ra], shift); + tcg_temp_free(shift); + } + } else + tcg_gen_movi_i64(cpu_ir[rc], 0); + } break; case 0x52: /* MSKWH */ - gen_arith3(ctx, &gen_op_mskwh, ra, rb, rc, islit, lit); + gen_arith3(helper_mskwh, ra, rb, rc, islit, lit); break; case 0x57: /* INSWH */ - gen_arith3(ctx, &gen_op_inswh, ra, rb, rc, islit, lit); + gen_arith3(helper_inswh, ra, rb, rc, islit, lit); break; case 0x5A: /* EXTWH */ - gen_arith3(ctx, &gen_op_extwh, ra, rb, rc, islit, lit); + gen_ext_h(&tcg_gen_ext16u_i64, ra, rb, rc, islit, lit); break; case 0x62: /* MSKLH */ - gen_arith3(ctx, &gen_op_msklh, ra, rb, rc, islit, lit); + gen_arith3(helper_msklh, ra, rb, rc, islit, lit); break; case 0x67: /* INSLH */ - gen_arith3(ctx, &gen_op_inslh, ra, rb, rc, islit, lit); + gen_arith3(helper_inslh, ra, rb, rc, islit, lit); break; case 0x6A: /* EXTLH */ - gen_arith3(ctx, &gen_op_extlh, ra, rb, rc, islit, lit); + gen_ext_h(&tcg_gen_ext16u_i64, ra, rb, rc, islit, lit); break; case 0x72: /* MSKQH */ - gen_arith3(ctx, &gen_op_mskqh, ra, rb, rc, islit, lit); + gen_arith3(helper_mskqh, ra, rb, rc, islit, lit); break; case 0x77: /* INSQH */ - gen_arith3(ctx, &gen_op_insqh, ra, rb, rc, islit, lit); + gen_arith3(helper_insqh, ra, rb, rc, islit, lit); break; case 0x7A: /* EXTQH */ - gen_arith3(ctx, &gen_op_extqh, ra, rb, rc, islit, lit); + gen_ext_h(NULL, ra, rb, rc, islit, lit); break; default: goto invalid_opc; @@ -1037,23 +1218,40 @@ switch (fn7) { case 0x00: /* MULL */ - gen_arith3(ctx, &gen_op_mull, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra == 31) + tcg_gen_movi_i64(cpu_ir[rc], 0); + else { + if (islit) + tcg_gen_muli_i64(cpu_ir[rc], cpu_ir[ra], lit); + else + tcg_gen_mul_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]); + tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]); + } + } break; case 0x20: /* MULQ */ - gen_arith3(ctx, &gen_op_mulq, ra, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (ra == 31) + tcg_gen_movi_i64(cpu_ir[rc], 0); + else if (islit) + tcg_gen_muli_i64(cpu_ir[rc], cpu_ir[ra], lit); + else + tcg_gen_mul_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]); + } break; case 0x30: /* UMULH */ - gen_arith3(ctx, &gen_op_umulh, ra, rb, rc, islit, lit); + gen_arith3(helper_umulh, ra, rb, rc, islit, lit); break; case 0x40: /* MULL/V */ - gen_arith3(ctx, &gen_op_mullv, ra, rb, rc, islit, lit); + gen_arith3(helper_mullv, ra, rb, rc, islit, lit); break; case 0x60: /* MULQ/V */ - gen_arith3(ctx, &gen_op_mulqv, ra, rb, rc, islit, lit); + gen_arith3(helper_mulqv, ra, rb, rc, islit, lit); break; default: goto invalid_opc; @@ -1065,47 +1263,64 @@ /* ITOFS */ if (!(ctx->amask & AMASK_FIX)) goto invalid_opc; - gen_itf(ctx, &gen_op_itofs, ra, rc); + if (likely(rc != 31)) { + if (ra != 31) { + TCGv tmp = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_trunc_i64_i32(tmp, cpu_ir[ra]); + tcg_gen_helper_1_1(helper_memory_to_s, cpu_fir[rc], tmp); + tcg_temp_free(tmp); + } else + tcg_gen_movi_i64(cpu_fir[rc], 0); + } break; case 0x0A: /* SQRTF */ if (!(ctx->amask & AMASK_FIX)) goto invalid_opc; - gen_farith2(ctx, &gen_op_sqrtf, rb, rc); + gen_farith2(&helper_sqrtf, rb, rc); break; case 0x0B: /* SQRTS */ if (!(ctx->amask & AMASK_FIX)) goto invalid_opc; - gen_farith2(ctx, &gen_op_sqrts, rb, rc); + gen_farith2(&helper_sqrts, rb, rc); break; case 0x14: /* ITOFF */ if (!(ctx->amask & AMASK_FIX)) goto invalid_opc; -#if 0 // TODO - gen_itf(ctx, &gen_op_itoff, ra, rc); -#else - goto invalid_opc; -#endif + if (likely(rc != 31)) { + if (ra != 31) { + TCGv tmp = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_trunc_i64_i32(tmp, cpu_ir[ra]); + tcg_gen_helper_1_1(helper_memory_to_f, cpu_fir[rc], tmp); + tcg_temp_free(tmp); + } else + tcg_gen_movi_i64(cpu_fir[rc], 0); + } break; case 0x24: /* ITOFT */ if (!(ctx->amask & AMASK_FIX)) goto invalid_opc; - gen_itf(ctx, &gen_op_itoft, ra, rc); + if (likely(rc != 31)) { + if (ra != 31) + tcg_gen_mov_i64(cpu_fir[rc], cpu_ir[ra]); + else + tcg_gen_movi_i64(cpu_fir[rc], 0); + } break; case 0x2A: /* SQRTG */ if (!(ctx->amask & AMASK_FIX)) goto invalid_opc; - gen_farith2(ctx, &gen_op_sqrtg, rb, rc); + gen_farith2(&helper_sqrtg, rb, rc); break; case 0x02B: /* SQRTT */ if (!(ctx->amask & AMASK_FIX)) goto invalid_opc; - gen_farith2(ctx, &gen_op_sqrtt, rb, rc); + gen_farith2(&helper_sqrtt, rb, rc); break; default: goto invalid_opc; @@ -1117,79 +1332,79 @@ switch (fpfn) { /* f11 & 0x3F */ case 0x00: /* ADDF */ - gen_farith3(ctx, &gen_op_addf, ra, rb, rc); + gen_farith3(&helper_addf, ra, rb, rc); break; case 0x01: /* SUBF */ - gen_farith3(ctx, &gen_op_subf, ra, rb, rc); + gen_farith3(&helper_subf, ra, rb, rc); break; case 0x02: /* MULF */ - gen_farith3(ctx, &gen_op_mulf, ra, rb, rc); + gen_farith3(&helper_mulf, ra, rb, rc); break; case 0x03: /* DIVF */ - gen_farith3(ctx, &gen_op_divf, ra, rb, rc); + gen_farith3(&helper_divf, ra, rb, rc); break; case 0x1E: /* CVTDG */ #if 0 // TODO - gen_farith2(ctx, &gen_op_cvtdg, rb, rc); + gen_farith2(&helper_cvtdg, rb, rc); #else goto invalid_opc; #endif break; case 0x20: /* ADDG */ - gen_farith3(ctx, &gen_op_addg, ra, rb, rc); + gen_farith3(&helper_addg, ra, rb, rc); break; case 0x21: /* SUBG */ - gen_farith3(ctx, &gen_op_subg, ra, rb, rc); + gen_farith3(&helper_subg, ra, rb, rc); break; case 0x22: /* MULG */ - gen_farith3(ctx, &gen_op_mulg, ra, rb, rc); + gen_farith3(&helper_mulg, ra, rb, rc); break; case 0x23: /* DIVG */ - gen_farith3(ctx, &gen_op_divg, ra, rb, rc); + gen_farith3(&helper_divg, ra, rb, rc); break; case 0x25: /* CMPGEQ */ - gen_farith3(ctx, &gen_op_cmpgeq, ra, rb, rc); + gen_farith3(&helper_cmpgeq, ra, rb, rc); break; case 0x26: /* CMPGLT */ - gen_farith3(ctx, &gen_op_cmpglt, ra, rb, rc); + gen_farith3(&helper_cmpglt, ra, rb, rc); break; case 0x27: /* CMPGLE */ - gen_farith3(ctx, &gen_op_cmpgle, ra, rb, rc); + gen_farith3(&helper_cmpgle, ra, rb, rc); break; case 0x2C: /* CVTGF */ - gen_farith2(ctx, &gen_op_cvtgf, rb, rc); + gen_farith2(&helper_cvtgf, rb, rc); break; case 0x2D: /* CVTGD */ #if 0 // TODO - gen_farith2(ctx, &gen_op_cvtgd, rb, rc); + gen_farith2(ctx, &helper_cvtgd, rb, rc); #else goto invalid_opc; #endif break; case 0x2F: /* CVTGQ */ - gen_farith2(ctx, &gen_op_cvtgq, rb, rc); + gen_farith2(&helper_cvtgq, rb, rc); break; case 0x3C: /* CVTQF */ - gen_farith2(ctx, &gen_op_cvtqf, rb, rc); + gen_farith2(&helper_cvtqf, rb, rc); break; case 0x3E: /* CVTQG */ - gen_farith2(ctx, &gen_op_cvtqg, rb, rc); + gen_farith2(&helper_cvtqg, rb, rc); break; default: goto invalid_opc; @@ -1201,73 +1416,73 @@ switch (fpfn) { /* f11 & 0x3F */ case 0x00: /* ADDS */ - gen_farith3(ctx, &gen_op_adds, ra, rb, rc); + gen_farith3(&helper_adds, ra, rb, rc); break; case 0x01: /* SUBS */ - gen_farith3(ctx, &gen_op_subs, ra, rb, rc); + gen_farith3(&helper_subs, ra, rb, rc); break; case 0x02: /* MULS */ - gen_farith3(ctx, &gen_op_muls, ra, rb, rc); + gen_farith3(&helper_muls, ra, rb, rc); break; case 0x03: /* DIVS */ - gen_farith3(ctx, &gen_op_divs, ra, rb, rc); + gen_farith3(&helper_divs, ra, rb, rc); break; case 0x20: /* ADDT */ - gen_farith3(ctx, &gen_op_addt, ra, rb, rc); + gen_farith3(&helper_addt, ra, rb, rc); break; case 0x21: /* SUBT */ - gen_farith3(ctx, &gen_op_subt, ra, rb, rc); + gen_farith3(&helper_subt, ra, rb, rc); break; case 0x22: /* MULT */ - gen_farith3(ctx, &gen_op_mult, ra, rb, rc); + gen_farith3(&helper_mult, ra, rb, rc); break; case 0x23: /* DIVT */ - gen_farith3(ctx, &gen_op_divt, ra, rb, rc); + gen_farith3(&helper_divt, ra, rb, rc); break; case 0x24: /* CMPTUN */ - gen_farith3(ctx, &gen_op_cmptun, ra, rb, rc); + gen_farith3(&helper_cmptun, ra, rb, rc); break; case 0x25: /* CMPTEQ */ - gen_farith3(ctx, &gen_op_cmpteq, ra, rb, rc); + gen_farith3(&helper_cmpteq, ra, rb, rc); break; case 0x26: /* CMPTLT */ - gen_farith3(ctx, &gen_op_cmptlt, ra, rb, rc); + gen_farith3(&helper_cmptlt, ra, rb, rc); break; case 0x27: /* CMPTLE */ - gen_farith3(ctx, &gen_op_cmptle, ra, rb, rc); + gen_farith3(&helper_cmptle, ra, rb, rc); break; case 0x2C: /* XXX: incorrect */ - if (fn11 == 0x2AC) { + if (fn11 == 0x2AC || fn11 == 0x6AC) { /* CVTST */ - gen_farith2(ctx, &gen_op_cvtst, rb, rc); + gen_farith2(&helper_cvtst, rb, rc); } else { /* CVTTS */ - gen_farith2(ctx, &gen_op_cvtts, rb, rc); + gen_farith2(&helper_cvtts, rb, rc); } break; case 0x2F: /* CVTTQ */ - gen_farith2(ctx, &gen_op_cvttq, rb, rc); + gen_farith2(&helper_cvttq, rb, rc); break; case 0x3C: /* CVTQS */ - gen_farith2(ctx, &gen_op_cvtqs, rb, rc); + gen_farith2(&helper_cvtqs, rb, rc); break; case 0x3E: /* CVTQT */ - gen_farith2(ctx, &gen_op_cvtqt, rb, rc); + gen_farith2(&helper_cvtqt, rb, rc); break; default: goto invalid_opc; @@ -1277,76 +1492,76 @@ switch (fn11) { case 0x010: /* CVTLQ */ - gen_farith2(ctx, &gen_op_cvtlq, rb, rc); + gen_farith2(&helper_cvtlq, rb, rc); break; case 0x020: - /* CPYS */ - if (ra == rb) { - if (ra == 31 && rc == 31) { - /* FNOP */ - gen_op_nop(); - } else { + if (likely(rc != 31)) { + if (ra == rb) /* FMOV */ - gen_load_fir(ctx, rb, 0); - gen_store_fir(ctx, rc, 0); - } - } else { - gen_farith3(ctx, &gen_op_cpys, ra, rb, rc); + tcg_gen_mov_i64(cpu_fir[rc], cpu_fir[ra]); + else + /* CPYS */ + gen_farith3(&helper_cpys, ra, rb, rc); } break; case 0x021: /* CPYSN */ - gen_farith2(ctx, &gen_op_cpysn, rb, rc); + gen_farith3(&helper_cpysn, ra, rb, rc); break; case 0x022: /* CPYSE */ - gen_farith2(ctx, &gen_op_cpyse, rb, rc); + gen_farith3(&helper_cpyse, ra, rb, rc); break; case 0x024: /* MT_FPCR */ - gen_load_fir(ctx, ra, 0); - gen_op_store_fpcr(); + if (likely(ra != 31)) + tcg_gen_helper_0_1(helper_store_fpcr, cpu_fir[ra]); + else { + TCGv tmp = tcg_const_i64(0); + tcg_gen_helper_0_1(helper_store_fpcr, tmp); + tcg_temp_free(tmp); + } break; case 0x025: /* MF_FPCR */ - gen_op_load_fpcr(); - gen_store_fir(ctx, ra, 0); + if (likely(ra != 31)) + tcg_gen_helper_1_0(helper_load_fpcr, cpu_fir[ra]); break; case 0x02A: /* FCMOVEQ */ - gen_fcmov(ctx, &gen_op_cmpfeq, ra, rb, rc); + gen_fcmov(&helper_cmpfeq, ra, rb, rc); break; case 0x02B: /* FCMOVNE */ - gen_fcmov(ctx, &gen_op_cmpfne, ra, rb, rc); + gen_fcmov(&helper_cmpfne, ra, rb, rc); break; case 0x02C: /* FCMOVLT */ - gen_fcmov(ctx, &gen_op_cmpflt, ra, rb, rc); + gen_fcmov(&helper_cmpflt, ra, rb, rc); break; case 0x02D: /* FCMOVGE */ - gen_fcmov(ctx, &gen_op_cmpfge, ra, rb, rc); + gen_fcmov(&helper_cmpfge, ra, rb, rc); break; case 0x02E: /* FCMOVLE */ - gen_fcmov(ctx, &gen_op_cmpfle, ra, rb, rc); + gen_fcmov(&helper_cmpfle, ra, rb, rc); break; case 0x02F: /* FCMOVGT */ - gen_fcmov(ctx, &gen_op_cmpfgt, ra, rb, rc); + gen_fcmov(&helper_cmpfgt, ra, rb, rc); break; case 0x030: /* CVTQL */ - gen_farith2(ctx, &gen_op_cvtql, rb, rc); + gen_farith2(&helper_cvtql, rb, rc); break; case 0x130: /* CVTQL/V */ - gen_farith2(ctx, &gen_op_cvtqlv, rb, rc); + gen_farith2(&helper_cvtqlv, rb, rc); break; case 0x530: /* CVTQL/SV */ - gen_farith2(ctx, &gen_op_cvtqlsv, rb, rc); + gen_farith2(&helper_cvtqlsv, rb, rc); break; default: goto invalid_opc; @@ -1382,14 +1597,13 @@ break; case 0xC000: /* RPCC */ - gen_op_load_pcc(); - gen_store_ir(ctx, ra, 0); + if (ra != 31) + tcg_gen_helper_1_0(helper_load_pcc, cpu_ir[ra]); break; case 0xE000: /* RC */ - gen_op_load_irf(); - gen_store_ir(ctx, ra, 0); - gen_op_clear_irf(); + if (ra != 31) + tcg_gen_helper_1_0(helper_rc, cpu_ir[ra]); break; case 0xE800: /* ECB */ @@ -1402,9 +1616,8 @@ break; case 0xF000: /* RS */ - gen_op_load_irf(); - gen_store_ir(ctx, ra, 0); - gen_op_set_irf(); + if (ra != 31) + tcg_gen_helper_1_0(helper_rs, cpu_ir[ra]); break; case 0xF800: /* WH64 */ @@ -1421,17 +1634,20 @@ #else if (!ctx->pal_mode) goto invalid_opc; - gen_op_mfpr(insn & 0xFF); - gen_store_ir(ctx, ra, 0); + if (ra != 31) { + TCGv tmp = tcg_const_i32(insn & 0xFF); + tcg_gen_helper_1_2(helper_mfpr, cpu_ir[ra], tmp, cpu_ir[ra]); + tcg_temp_free(tmp); + } break; #endif case 0x1A: - gen_load_ir(ctx, rb, 0); - if (ra != 31) { - gen_set_uT1(ctx, ctx->pc); - gen_store_ir(ctx, ra, 1); - } - gen_op_branch(); + if (rb != 31) + tcg_gen_andi_i64(cpu_pc, cpu_ir[rb], ~3); + else + tcg_gen_movi_i64(cpu_pc, 0); + if (ra != 31) + tcg_gen_movi_i64(cpu_ir[ra], ctx->pc); /* Those four jumps only differ by the branch prediction hint */ switch (fn2) { case 0x0: @@ -1456,90 +1672,94 @@ #else if (!ctx->pal_mode) goto invalid_opc; - gen_load_ir(ctx, rb, 0); - gen_set_sT1(ctx, disp12); - gen_op_addq(); - switch ((insn >> 12) & 0xF) { - case 0x0: - /* Longword physical access */ - gen_op_ldl_raw(); - break; - case 0x1: - /* Quadword physical access */ - gen_op_ldq_raw(); - break; - case 0x2: - /* Longword physical access with lock */ - gen_op_ldl_l_raw(); - break; - case 0x3: - /* Quadword physical access with lock */ - gen_op_ldq_l_raw(); - break; - case 0x4: - /* Longword virtual PTE fetch */ - gen_op_ldl_kernel(); - break; - case 0x5: - /* Quadword virtual PTE fetch */ - gen_op_ldq_kernel(); - break; - case 0x6: - /* Invalid */ - goto invalid_opc; - case 0x7: - /* Invalid */ - goto invalid_opc; - case 0x8: - /* Longword virtual access */ - gen_op_ld_phys_to_virt(); - gen_op_ldl_raw(); - break; - case 0x9: - /* Quadword virtual access */ - gen_op_ld_phys_to_virt(); - gen_op_ldq_raw(); - break; - case 0xA: - /* Longword virtual access with protection check */ - gen_ldl(ctx); - break; - case 0xB: - /* Quadword virtual access with protection check */ - gen_ldq(ctx); - break; - case 0xC: - /* Longword virtual access with altenate access mode */ - gen_op_set_alt_mode(); - gen_op_ld_phys_to_virt(); - gen_op_ldl_raw(); - gen_op_restore_mode(); - break; - case 0xD: - /* Quadword virtual access with altenate access mode */ - gen_op_set_alt_mode(); - gen_op_ld_phys_to_virt(); - gen_op_ldq_raw(); - gen_op_restore_mode(); - break; - case 0xE: - /* Longword virtual access with alternate access mode and - * protection checks - */ - gen_op_set_alt_mode(); - gen_op_ldl_data(); - gen_op_restore_mode(); - break; - case 0xF: - /* Quadword virtual access with alternate access mode and - * protection checks - */ - gen_op_set_alt_mode(); - gen_op_ldq_data(); - gen_op_restore_mode(); - break; + if (ra != 31) { + TCGv addr = tcg_temp_new(TCG_TYPE_I64); + if (rb != 31) + tcg_gen_addi_i64(addr, cpu_ir[rb], disp12); + else + tcg_gen_movi_i64(addr, disp12); + switch ((insn >> 12) & 0xF) { + case 0x0: + /* Longword physical access */ + tcg_gen_helper_0_2(helper_ldl_raw, cpu_ir[ra], addr); + break; + case 0x1: + /* Quadword physical access */ + tcg_gen_helper_0_2(helper_ldq_raw, cpu_ir[ra], addr); + break; + case 0x2: + /* Longword physical access with lock */ + tcg_gen_helper_0_2(helper_ldl_l_raw, cpu_ir[ra], addr); + break; + case 0x3: + /* Quadword physical access with lock */ + tcg_gen_helper_0_2(helper_ldq_l_raw, cpu_ir[ra], addr); + break; + case 0x4: + /* Longword virtual PTE fetch */ + tcg_gen_helper_0_2(helper_ldl_kernel, cpu_ir[ra], addr); + break; + case 0x5: + /* Quadword virtual PTE fetch */ + tcg_gen_helper_0_2(helper_ldq_kernel, cpu_ir[ra], addr); + break; + case 0x6: + /* Incpu_ir[ra]id */ + goto incpu_ir[ra]id_opc; + case 0x7: + /* Incpu_ir[ra]id */ + goto incpu_ir[ra]id_opc; + case 0x8: + /* Longword virtual access */ + tcg_gen_helper_1_1(helper_st_virt_to_phys, addr, addr); + tcg_gen_helper_0_2(helper_ldl_raw, cpu_ir[ra], addr); + break; + case 0x9: + /* Quadword virtual access */ + tcg_gen_helper_1_1(helper_st_virt_to_phys, addr, addr); + tcg_gen_helper_0_2(helper_ldq_raw, cpu_ir[ra], addr); + break; + case 0xA: + /* Longword virtual access with protection check */ + tcg_gen_qemu_ld32s(cpu_ir[ra], addr, ctx->flags); + break; + case 0xB: + /* Quadword virtual access with protection check */ + tcg_gen_qemu_ld64(cpu_ir[ra], addr, ctx->flags); + break; + case 0xC: + /* Longword virtual access with altenate access mode */ + tcg_gen_helper_0_0(helper_set_alt_mode); + tcg_gen_helper_1_1(helper_st_virt_to_phys, addr, addr); + tcg_gen_helper_0_2(helper_ldl_raw, cpu_ir[ra], addr); + tcg_gen_helper_0_0(helper_restore_mode); + break; + case 0xD: + /* Quadword virtual access with altenate access mode */ + tcg_gen_helper_0_0(helper_set_alt_mode); + tcg_gen_helper_1_1(helper_st_virt_to_phys, addr, addr); + tcg_gen_helper_0_2(helper_ldq_raw, cpu_ir[ra], addr); + tcg_gen_helper_0_0(helper_restore_mode); + break; + case 0xE: + /* Longword virtual access with alternate access mode and + * protection checks + */ + tcg_gen_helper_0_0(helper_set_alt_mode); + tcg_gen_helper_0_2(helper_ldl_data, cpu_ir[ra], addr); + tcg_gen_helper_0_0(helper_restore_mode); + break; + case 0xF: + /* Quadword virtual access with alternate access mode and + * protection checks + */ + tcg_gen_helper_0_0(helper_set_alt_mode); + tcg_gen_helper_0_2(helper_ldq_data, cpu_ir[ra], addr); + tcg_gen_helper_0_0(helper_restore_mode); + break; + } + tcg_temp_free(addr); } - gen_store_ir(ctx, ra, 1); break; #endif case 0x1C: @@ -1548,19 +1768,34 @@ /* SEXTB */ if (!(ctx->amask & AMASK_BWX)) goto invalid_opc; - gen_arith2(ctx, &gen_op_sextb, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], (int64_t)((int8_t)lit)); + else + tcg_gen_ext8s_i64(cpu_ir[rc], cpu_ir[rb]); + } break; case 0x01: /* SEXTW */ if (!(ctx->amask & AMASK_BWX)) goto invalid_opc; - gen_arith2(ctx, &gen_op_sextw, rb, rc, islit, lit); + if (likely(rc != 31)) { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], (int64_t)((int16_t)lit)); + else + tcg_gen_ext16s_i64(cpu_ir[rc], cpu_ir[rb]); + } break; case 0x30: /* CTPOP */ if (!(ctx->amask & AMASK_CIX)) goto invalid_opc; - gen_arith2(ctx, &gen_op_ctpop, rb, rc, 0, 0); + if (likely(rc != 31)) { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], ctpop64(lit)); + else + tcg_gen_helper_1_1(helper_ctpop, cpu_ir[rc], cpu_ir[rb]); + } break; case 0x31: /* PERR */ @@ -1573,13 +1808,23 @@ /* CTLZ */ if (!(ctx->amask & AMASK_CIX)) goto invalid_opc; - gen_arith2(ctx, &gen_op_ctlz, rb, rc, 0, 0); + if (likely(rc != 31)) { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], clz64(lit)); + else + tcg_gen_helper_1_1(helper_ctlz, cpu_ir[rc], cpu_ir[rb]); + } break; case 0x33: /* CTTZ */ if (!(ctx->amask & AMASK_CIX)) goto invalid_opc; - gen_arith2(ctx, &gen_op_cttz, rb, rc, 0, 0); + if (likely(rc != 31)) { + if (islit) + tcg_gen_movi_i64(cpu_ir[rc], ctz64(lit)); + else + tcg_gen_helper_1_1(helper_cttz, cpu_ir[rc], cpu_ir[rb]); + } break; case 0x34: /* UNPKBW */ @@ -1669,13 +1914,29 @@ /* FTOIT */ if (!(ctx->amask & AMASK_FIX)) goto invalid_opc; - gen_fti(ctx, &gen_op_ftoit, ra, rb); + if (likely(rc != 31)) { + if (ra != 31) + tcg_gen_mov_i64(cpu_ir[rc], cpu_fir[ra]); + else + tcg_gen_movi_i64(cpu_ir[rc], 0); + } break; case 0x78: /* FTOIS */ if (!(ctx->amask & AMASK_FIX)) goto invalid_opc; - gen_fti(ctx, &gen_op_ftois, ra, rb); + if (rc != 31) { + TCGv tmp1 = tcg_temp_new(TCG_TYPE_I32); + if (ra != 31) + tcg_gen_helper_1_1(helper_s_to_memory, tmp1, cpu_fir[ra]); + else { + TCGv tmp2 = tcg_const_i64(0); + tcg_gen_helper_1_1(helper_s_to_memory, tmp1, tmp2); + tcg_temp_free(tmp2); + } + tcg_gen_ext_i32_i64(cpu_ir[rc], tmp1); + tcg_temp_free(tmp1); + } break; default: goto invalid_opc; @@ -1688,9 +1949,18 @@ #else if (!ctx->pal_mode) goto invalid_opc; - gen_load_ir(ctx, ra, 0); - gen_op_mtpr(insn & 0xFF); - ret = 2; + else { + TCGv tmp1 = tcg_const_i32(insn & 0xFF); + if (ra != 31) + tcg_gen_helper(helper_mtpr, tmp1, cpu_ir[ra]); + else { + TCGv tmp2 = tcg_const_i64(0); + tcg_gen_helper(helper_mtpr, tmp1, tmp2); + tcg_temp_free(tmp2); + } + tcg_temp_free(tmp1); + ret = 2; + } break; #endif case 0x1E: @@ -1702,12 +1972,17 @@ goto invalid_opc; if (rb == 31) { /* "Old" alpha */ - gen_op_hw_rei(); + tcg_gen_helper_0_0(helper_hw_rei); } else { - gen_load_ir(ctx, rb, 0); - gen_set_uT1(ctx, (((int64_t)insn << 51) >> 51)); - gen_op_addq(); - gen_op_hw_ret(); + TCGv tmp; + + if (ra != 31) { + tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_addi_i64(tmp, cpu_ir[rb], (((int64_t)insn << 51) >> 51)); + } else + tmp = tcg_const_i64(((int64_t)insn << 51) >> 51); + tcg_gen_helper_0_1(helper_hw_ret, tmp); + tcg_temp_free(tmp); } ret = 2; break; @@ -1719,249 +1994,238 @@ #else if (!ctx->pal_mode) goto invalid_opc; - gen_load_ir(ctx, rb, 0); - gen_set_sT1(ctx, disp12); - gen_op_addq(); - gen_load_ir(ctx, ra, 1); - switch ((insn >> 12) & 0xF) { - case 0x0: - /* Longword physical access */ - gen_op_stl_raw(); - break; - case 0x1: - /* Quadword physical access */ - gen_op_stq_raw(); - break; - case 0x2: - /* Longword physical access with lock */ - gen_op_stl_c_raw(); - break; - case 0x3: - /* Quadword physical access with lock */ - gen_op_stq_c_raw(); - break; - case 0x4: - /* Longword virtual access */ - gen_op_st_phys_to_virt(); - gen_op_stl_raw(); - break; - case 0x5: - /* Quadword virtual access */ - gen_op_st_phys_to_virt(); - gen_op_stq_raw(); - break; - case 0x6: - /* Invalid */ - goto invalid_opc; - case 0x7: - /* Invalid */ - goto invalid_opc; - case 0x8: - /* Invalid */ - goto invalid_opc; - case 0x9: - /* Invalid */ - goto invalid_opc; - case 0xA: - /* Invalid */ - goto invalid_opc; - case 0xB: - /* Invalid */ - goto invalid_opc; - case 0xC: - /* Longword virtual access with alternate access mode */ - gen_op_set_alt_mode(); - gen_op_st_phys_to_virt(); - gen_op_ldl_raw(); - gen_op_restore_mode(); - break; - case 0xD: - /* Quadword virtual access with alternate access mode */ - gen_op_set_alt_mode(); - gen_op_st_phys_to_virt(); - gen_op_ldq_raw(); - gen_op_restore_mode(); - break; - case 0xE: - /* Invalid */ - goto invalid_opc; - case 0xF: - /* Invalid */ - goto invalid_opc; + else { + TCGv addr, val; + addr = tcg_temp_new(TCG_TYPE_I64); + if (rb != 31) + tcg_gen_addi_i64(addr, cpu_ir[rb], disp12); + else + tcg_gen_movi_i64(addr, disp12); + if (ra != 31) + val = cpu_ir[ra]; + else { + val = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_movi_i64(val, 0); + } + switch ((insn >> 12) & 0xF) { + case 0x0: + /* Longword physical access */ + tcg_gen_helper_0_2(helper_stl_raw, val, addr); + break; + case 0x1: + /* Quadword physical access */ + tcg_gen_helper_0_2(helper_stq_raw, val, addr); + break; + case 0x2: + /* Longword physical access with lock */ + tcg_gen_helper_1_2(helper_stl_c_raw, val, val, addr); + break; + case 0x3: + /* Quadword physical access with lock */ + tcg_gen_helper_1_2(helper_stq_c_raw, val, val, addr); + break; + case 0x4: + /* Longword virtual access */ + tcg_gen_helper_1_1(helper_st_virt_to_phys, addr, addr); + tcg_gen_helper_0_2(helper_stl_raw, val, addr); + break; + case 0x5: + /* Quadword virtual access */ + tcg_gen_helper_1_1(helper_st_virt_to_phys, addr, addr); + tcg_gen_helper_0_2(helper_stq_raw, val, addr); + break; + case 0x6: + /* Invalid */ + goto invalid_opc; + case 0x7: + /* Invalid */ + goto invalid_opc; + case 0x8: + /* Invalid */ + goto invalid_opc; + case 0x9: + /* Invalid */ + goto invalid_opc; + case 0xA: + /* Invalid */ + goto invalid_opc; + case 0xB: + /* Invalid */ + goto invalid_opc; + case 0xC: + /* Longword virtual access with alternate access mode */ + tcg_gen_helper_0_0(helper_set_alt_mode); + tcg_gen_helper_1_1(helper_st_virt_to_phys, addr, addr); + tcg_gen_helper_0_2(helper_stl_raw, val, addr); + tcg_gen_helper_0_0(helper_restore_mode); + break; + case 0xD: + /* Quadword virtual access with alternate access mode */ + tcg_gen_helper_0_0(helper_set_alt_mode); + tcg_gen_helper_1_1(helper_st_virt_to_phys, addr, addr); + tcg_gen_helper_0_2(helper_stl_raw, val, addr); + tcg_gen_helper_0_0(helper_restore_mode); + break; + case 0xE: + /* Invalid */ + goto invalid_opc; + case 0xF: + /* Invalid */ + goto invalid_opc; + } + if (ra != 31) + tcg_temp_free(val); + tcg_temp_free(addr); } ret = 2; break; #endif case 0x20: /* LDF */ -#if 0 // TODO - gen_load_fmem(ctx, &gen_ldf, ra, rb, disp16); -#else - goto invalid_opc; -#endif + gen_load_mem(ctx, &gen_qemu_ldf, ra, rb, disp16, 1, 0); break; case 0x21: /* LDG */ -#if 0 // TODO - gen_load_fmem(ctx, &gen_ldg, ra, rb, disp16); -#else - goto invalid_opc; -#endif + gen_load_mem(ctx, &gen_qemu_ldg, ra, rb, disp16, 1, 0); break; case 0x22: /* LDS */ - gen_load_fmem(ctx, &gen_lds, ra, rb, disp16); + gen_load_mem(ctx, &gen_qemu_lds, ra, rb, disp16, 1, 0); break; case 0x23: /* LDT */ - gen_load_fmem(ctx, &gen_ldt, ra, rb, disp16); + gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 1, 0); break; case 0x24: /* STF */ -#if 0 // TODO - gen_store_fmem(ctx, &gen_stf, ra, rb, disp16); -#else - goto invalid_opc; -#endif + gen_store_mem(ctx, &gen_qemu_stf, ra, rb, disp16, 1, 0, 0); break; case 0x25: /* STG */ -#if 0 // TODO - gen_store_fmem(ctx, &gen_stg, ra, rb, disp16); -#else - goto invalid_opc; -#endif + gen_store_mem(ctx, &gen_qemu_stg, ra, rb, disp16, 1, 0, 0); break; case 0x26: /* STS */ - gen_store_fmem(ctx, &gen_sts, ra, rb, disp16); + gen_store_mem(ctx, &gen_qemu_sts, ra, rb, disp16, 1, 0, 0); break; case 0x27: /* STT */ - gen_store_fmem(ctx, &gen_stt, ra, rb, disp16); + gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 1, 0, 0); break; case 0x28: /* LDL */ - gen_load_mem(ctx, &gen_ldl, ra, rb, disp16, 0); + gen_load_mem(ctx, &tcg_gen_qemu_ld32s, ra, rb, disp16, 0, 0); break; case 0x29: /* LDQ */ - gen_load_mem(ctx, &gen_ldq, ra, rb, disp16, 0); + gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 0, 0); break; case 0x2A: /* LDL_L */ - gen_load_mem(ctx, &gen_ldl_l, ra, rb, disp16, 0); + gen_load_mem(ctx, &gen_qemu_ldl_l, ra, rb, disp16, 0, 0); break; case 0x2B: /* LDQ_L */ - gen_load_mem(ctx, &gen_ldq_l, ra, rb, disp16, 0); + gen_load_mem(ctx, &gen_qemu_ldq_l, ra, rb, disp16, 0, 0); break; case 0x2C: /* STL */ - gen_store_mem(ctx, &gen_stl, ra, rb, disp16, 0); + gen_store_mem(ctx, &tcg_gen_qemu_st32, ra, rb, disp16, 0, 0, 0); break; case 0x2D: /* STQ */ - gen_store_mem(ctx, &gen_stq, ra, rb, disp16, 0); + gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 0, 0, 0); break; case 0x2E: /* STL_C */ - gen_store_mem(ctx, &gen_stl_c, ra, rb, disp16, 0); + gen_store_mem(ctx, &gen_qemu_stl_c, ra, rb, disp16, 0, 0, 1); break; case 0x2F: /* STQ_C */ - gen_store_mem(ctx, &gen_stq_c, ra, rb, disp16, 0); + gen_store_mem(ctx, &gen_qemu_stq_c, ra, rb, disp16, 0, 0, 1); break; case 0x30: /* BR */ - gen_set_uT0(ctx, ctx->pc); - gen_store_ir(ctx, ra, 0); - if (disp21 != 0) { - gen_set_sT1(ctx, disp21 << 2); - gen_op_addq(); - } - gen_op_branch(); + if (ra != 31) + tcg_gen_movi_i64(cpu_ir[ra], ctx->pc); + tcg_gen_movi_i64(cpu_pc, ctx->pc + (int64_t)(disp21 << 2)); ret = 1; break; case 0x31: /* FBEQ */ - gen_fbcond(ctx, &gen_op_cmpfeq, ra, disp16); + gen_fbcond(ctx, &helper_cmpfeq, ra, disp16); ret = 1; break; case 0x32: /* FBLT */ - gen_fbcond(ctx, &gen_op_cmpflt, ra, disp16); + gen_fbcond(ctx, &helper_cmpflt, ra, disp16); ret = 1; break; case 0x33: /* FBLE */ - gen_fbcond(ctx, &gen_op_cmpfle, ra, disp16); + gen_fbcond(ctx, &helper_cmpfle, ra, disp16); ret = 1; break; case 0x34: /* BSR */ - gen_set_uT0(ctx, ctx->pc); - gen_store_ir(ctx, ra, 0); - if (disp21 != 0) { - gen_set_sT1(ctx, disp21 << 2); - gen_op_addq(); - } - gen_op_branch(); + if (ra != 31) + tcg_gen_movi_i64(cpu_ir[ra], ctx->pc); + tcg_gen_movi_i64(cpu_pc, ctx->pc + (int64_t)(disp21 << 2)); ret = 1; break; case 0x35: /* FBNE */ - gen_fbcond(ctx, &gen_op_cmpfne, ra, disp16); + gen_fbcond(ctx, &helper_cmpfne, ra, disp16); ret = 1; break; case 0x36: /* FBGE */ - gen_fbcond(ctx, &gen_op_cmpfge, ra, disp16); + gen_fbcond(ctx, &helper_cmpfge, ra, disp16); ret = 1; break; case 0x37: /* FBGT */ - gen_fbcond(ctx, &gen_op_cmpfgt, ra, disp16); + gen_fbcond(ctx, &helper_cmpfgt, ra, disp16); ret = 1; break; case 0x38: /* BLBC */ - gen_bcond(ctx, &gen_op_cmplbc, ra, disp16); + gen_bcond(ctx, TCG_COND_EQ, ra, disp16, 1); ret = 1; break; case 0x39: /* BEQ */ - gen_bcond(ctx, &gen_op_cmpeqz, ra, disp16); + gen_bcond(ctx, TCG_COND_EQ, ra, disp16, 0); ret = 1; break; case 0x3A: /* BLT */ - gen_bcond(ctx, &gen_op_cmpltz, ra, disp16); + gen_bcond(ctx, TCG_COND_LT, ra, disp16, 0); ret = 1; break; case 0x3B: /* BLE */ - gen_bcond(ctx, &gen_op_cmplez, ra, disp16); + gen_bcond(ctx, TCG_COND_LE, ra, disp16, 0); ret = 1; break; case 0x3C: /* BLBS */ - gen_bcond(ctx, &gen_op_cmplbs, ra, disp16); + gen_bcond(ctx, TCG_COND_NE, ra, disp16, 1); ret = 1; break; case 0x3D: /* BNE */ - gen_bcond(ctx, &gen_op_cmpnez, ra, disp16); + gen_bcond(ctx, TCG_COND_NE, ra, disp16, 0); ret = 1; break; case 0x3E: /* BGE */ - gen_bcond(ctx, &gen_op_cmpgez, ra, disp16); + gen_bcond(ctx, TCG_COND_GE, ra, disp16, 0); ret = 1; break; case 0x3F: /* BGT */ - gen_bcond(ctx, &gen_op_cmpgtz, ra, disp16); + gen_bcond(ctx, TCG_COND_GT, ra, disp16, 0); ret = 1; break; invalid_opc: @@ -1973,9 +2237,9 @@ return ret; } -static always_inline int gen_intermediate_code_internal (CPUState *env, - TranslationBlock *tb, - int search_pc) +static always_inline void gen_intermediate_code_internal (CPUState *env, + TranslationBlock *tb, + int search_pc) { #if defined ALPHA_DEBUG_DISAS static int insn_count; @@ -1986,12 +2250,11 @@ uint16_t *gen_opc_end; int j, lj = -1; int ret; + int num_insns; + int max_insns; pc_start = tb->pc; - gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; - gen_opparam_ptr = gen_opparam_buf; - nb_gen_labels = 0; ctx.pc = pc_start; ctx.amask = env->amask; #if defined (CONFIG_USER_ONLY) @@ -2000,6 +2263,12 @@ ctx.mem_idx = ((env->ps >> 3) & 3); ctx.pal_mode = env->ipr[IPR_EXC_ADDR] & 1; #endif + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + if (max_insns == 0) + max_insns = CF_COUNT_MASK; + + gen_icount_start(); for (ret = 0; ret == 0;) { if (env->nb_breakpoints > 0) { for(j = 0; j < env->nb_breakpoints; j++) { @@ -2017,8 +2286,11 @@ gen_opc_instr_start[lj++] = 0; gen_opc_pc[lj] = ctx.pc; gen_opc_instr_start[lj] = 1; + gen_opc_icount[lj] = num_insns; } } + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) + gen_io_start(); #if defined ALPHA_DEBUG_DISAS insn_count++; if (logfile != NULL) { @@ -2033,6 +2305,7 @@ fprintf(logfile, "opcode %08x %d\n", insn, insn_count); } #endif + num_insns++; ctx.pc += 4; ret = translate_one(ctxp, insn); if (ret != 0) @@ -2041,7 +2314,8 @@ * generation */ if (((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) || - (env->singlestep_enabled)) { + (env->singlestep_enabled) || + num_insns >= max_insns) { break; } #if defined (DO_SINGLE_STEP) @@ -2049,14 +2323,16 @@ #endif } if (ret != 1 && ret != 3) { - gen_update_pc(&ctx); + tcg_gen_movi_i64(cpu_pc, ctx.pc); } - gen_op_reset_T0(); #if defined (DO_TB_FLUSH) - gen_op_tb_flush(); + tcg_gen_helper_0_0(helper_tb_flush); #endif + if (tb->cflags & CF_LAST_IO) + gen_io_end(); /* Generate the return instruction */ - gen_op_exit_tb(); + tcg_gen_exit_tb(0); + gen_icount_end(tb, num_insns); *gen_opc_ptr = INDEX_op_end; if (search_pc) { j = gen_opc_ptr - gen_opc_buf; @@ -2065,6 +2341,7 @@ gen_opc_instr_start[lj++] = 0; } else { tb->size = ctx.pc - pc_start; + tb->icount = num_insns; } #if defined ALPHA_DEBUG_DISAS if (loglevel & CPU_LOG_TB_CPU) { @@ -2072,27 +2349,20 @@ } if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); - target_disas(logfile, pc_start, ctx.pc - pc_start, 1); - fprintf(logfile, "\n"); - } - if (loglevel & CPU_LOG_TB_OP) { - fprintf(logfile, "OP:\n"); - dump_ops(gen_opc_buf, gen_opparam_buf); + target_disas(logfile, pc_start, ctx.pc - pc_start, 1); fprintf(logfile, "\n"); } #endif - - return 0; } -int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) +void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) { - return gen_intermediate_code_internal(env, tb, 0); + gen_intermediate_code_internal(env, tb, 0); } -int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) +void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) { - return gen_intermediate_code_internal(env, tb, 1); + gen_intermediate_code_internal(env, tb, 1); } CPUAlphaState * cpu_alpha_init (const char *cpu_model) @@ -2104,6 +2374,7 @@ if (!env) return NULL; cpu_exec_init(env); + alpha_translate_init(); tlb_flush(env, 1); /* XXX: should not be hardcoded */ env->implver = IMPLVER_2106x; @@ -2134,3 +2405,8 @@ return env; } +void gen_pc_load(CPUState *env, TranslationBlock *tb, + unsigned long searched_pc, int pc_pos, void *puc) +{ + env->pc = gen_opc_pc[pc_pos]; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/cpu.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/cpu.h --- qemu-0.9.1/target-arm/cpu.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/cpu.h 2008-10-22 20:22:30.000000000 +0100 @@ -38,6 +38,7 @@ #define EXCP_FIQ 6 #define EXCP_BKPT 7 #define EXCP_EXCEPTION_EXIT 8 /* Return from v7M exception. */ +#define EXCP_KERNEL_TRAP 9 /* Jumped to kernel code page. */ #define ARMV7M_EXCP_RESET 1 #define ARMV7M_EXCP_NMI 2 @@ -55,6 +56,8 @@ typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info, int dstreg, int operand); +struct arm_boot_info; + #define NB_MMU_MODES 2 /* We currently assume float and double are IEEE single and double @@ -86,10 +89,11 @@ /* cpsr flag cache for faster execution */ uint32_t CF; /* 0 or 1 */ uint32_t VF; /* V is the bit 31. All other bits are undefined */ - uint32_t NZF; /* N is bit 31. Z is computed from NZF */ + uint32_t NF; /* N is bit 31. All other bits are undefined. */ + uint32_t ZF; /* Z set if zero. */ uint32_t QF; /* 0 or 1 */ uint32_t GE; /* cpsr[19:16] */ - int thumb; /* cprs[5]. 0 = arm mode, 1 = thumb mode. */ + uint32_t thumb; /* cpsr[5]. 0 = arm mode, 1 = thumb mode. */ uint32_t condexec_bits; /* IT bits. cpsr[15:10,26:25]. */ /* System control coprocessor (cp15) */ @@ -103,7 +107,9 @@ uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */ uint32_t c2_base0; /* MMU translation table base 0. */ uint32_t c2_base1; /* MMU translation table base 1. */ - uint32_t c2_mask; /* MMU translation table base mask. */ + uint32_t c2_control; /* MMU translation table base control. */ + uint32_t c2_mask; /* MMU translation table base selection mask. */ + uint32_t c2_base_mask; /* MMU translation table base 0 mask. */ uint32_t c2_data; /* MPU data cachable bits. */ uint32_t c2_insn; /* MPU instruction cachable bits. */ uint32_t c3; /* MMU domain access control register @@ -152,13 +158,6 @@ int (*get_irq_vector)(struct CPUARMState *); void *irq_opaque; - /* exception/interrupt handling */ - jmp_buf jmp_env; - int exception_index; - int interrupt_request; - int user_mode_only; - int halted; - /* VFP coprocessor state. */ struct { float64 regs[32]; @@ -168,9 +167,6 @@ int vec_len; int vec_stride; - /* Temporary variables if we don't have spare fp regs. */ - float32 tmp0s, tmp1s; - float64 tmp0d, tmp1d; /* scratch space when Tn are not sufficient. */ uint32_t scratch[8]; @@ -198,15 +194,11 @@ CPU_COMMON /* These fields after the common ones so they are preserved on reset. */ - int ram_size; - const char *kernel_filename; - const char *kernel_cmdline; - const char *initrd_filename; - int board_id; - target_phys_addr_t loader_start; + struct arm_boot_info *boot_info; } CPUARMState; CPUARMState *cpu_arm_init(const char *cpu_model); +void arm_translate_init(void); int cpu_arm_exec(CPUARMState *s); void cpu_arm_close(CPUARMState *s); void do_interrupt(CPUARMState *); @@ -221,6 +213,10 @@ void cpu_lock(void); void cpu_unlock(void); +static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls) +{ + env->cp15.c13_tls2 = newtls; +} #define CPSR_M (0x1f) #define CPSR_T (1 << 5) @@ -256,8 +252,8 @@ static inline uint32_t xpsr_read(CPUARMState *env) { int ZF; - ZF = (env->NZF == 0); - return (env->NZF & 0x80000000) | (ZF << 30) + ZF = (env->ZF == 0); + return (env->NF & 0x80000000) | (ZF << 30) | (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27) | (env->thumb << 24) | ((env->condexec_bits & 3) << 25) | ((env->condexec_bits & 0xfc) << 8) @@ -267,9 +263,9 @@ /* Set the xPSR. Note that some bits of mask must be all-set or all-clear. */ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) { - /* NOTE: N = 1 and Z = 1 cannot be stored currently */ if (mask & CPSR_NZCV) { - env->NZF = (val & 0xc0000000) ^ 0x40000000; + env->ZF = (~val) & CPSR_Z; + env->NF = val; env->CF = (val >> 29) & 1; env->VF = (val << 3) & 0x80000000; } @@ -377,6 +373,7 @@ #define ARM_CPUID_PXA270_C0 0x69054114 #define ARM_CPUID_PXA270_C5 0x69054117 #define ARM_CPUID_ARM1136 0x4117b363 +#define ARM_CPUID_ARM1136_R2 0x4107b362 #define ARM_CPUID_ARM11MPCORE 0x410fb022 #define ARM_CPUID_CORTEXA8 0x410fc080 #define ARM_CPUID_CORTEXM3 0x410fc231 @@ -398,7 +395,7 @@ #define cpu_signal_handler cpu_arm_signal_handler #define cpu_list arm_cpu_list -#define ARM_CPU_SAVE_VERSION 1 +#define CPU_SAVE_VERSION 1 /* MMU modes definitions */ #define MMU_MODE0_SUFFIX _kernel @@ -409,6 +406,17 @@ return (env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR ? 1 : 0; } +#if defined(CONFIG_USER_ONLY) +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) +{ + if (newsp) + env->regs[13] = newsp; + env->regs[0] = 0; +} +#endif + +#define CPU_PC_FROM_TB(env, tb) env->regs[15] = tb->pc + #include "cpu-all.h" #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/exec.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/exec.h --- qemu-0.9.1/target-arm/exec.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/exec.h 2008-08-30 10:51:20.000000000 +0100 @@ -23,14 +23,6 @@ register struct CPUARMState *env asm(AREG0); register uint32_t T0 asm(AREG1); register uint32_t T1 asm(AREG2); -register uint32_t T2 asm(AREG3); - -/* TODO: Put these in FP regs on targets that have such things. */ -/* It is ok for FT0s and FT0d to overlap. Likewise FT1s and FT1d. */ -#define FT0s env->vfp.tmp0s -#define FT1s env->vfp.tmp1s -#define FT0d env->vfp.tmp0d -#define FT1d env->vfp.tmp1d #define M0 env->iwmmxt.val @@ -66,42 +58,6 @@ #include "softmmu_exec.h" #endif -/* In op_helper.c */ - -void helper_set_cp(CPUState *, uint32_t, uint32_t); -uint32_t helper_get_cp(CPUState *, uint32_t); -void helper_set_cp15(CPUState *, uint32_t, uint32_t); -uint32_t helper_get_cp15(CPUState *, uint32_t); -void helper_set_r13_banked(CPUState *env, int mode, uint32_t val); -uint32_t helper_get_r13_banked(CPUState *env, int mode); -uint32_t helper_v7m_mrs(CPUState *env, int reg); -void helper_v7m_msr(CPUState *env, int reg, uint32_t val); - -void helper_mark_exclusive(CPUARMState *, uint32_t addr); -int helper_test_exclusive(CPUARMState *, uint32_t addr); -void helper_clrex(CPUARMState *env); - void cpu_loop_exit(void); void raise_exception(int); - -void do_vfp_abss(void); -void do_vfp_absd(void); -void do_vfp_negs(void); -void do_vfp_negd(void); -void do_vfp_sqrts(void); -void do_vfp_sqrtd(void); -void do_vfp_cmps(void); -void do_vfp_cmpd(void); -void do_vfp_cmpes(void); -void do_vfp_cmped(void); -void do_vfp_set_fpscr(void); -void do_vfp_get_fpscr(void); -float32 helper_recps_f32(float32, float32); -float32 helper_rsqrts_f32(float32, float32); -uint32_t helper_recpe_u32(uint32_t); -uint32_t helper_rsqrte_u32(uint32_t); -float32 helper_recpe_f32(float32); -float32 helper_rsqrte_f32(float32); -void helper_neon_tbl(int rn, int maxindex); -uint32_t helper_neon_mul_p8(uint32_t op1, uint32_t op2); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/helper.c --- qemu-0.9.1/target-arm/helper.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/helper.c 2008-10-22 20:22:30.000000000 +0100 @@ -5,6 +5,8 @@ #include "cpu.h" #include "exec-all.h" #include "gdbstub.h" +#include "helpers.h" +#include "qemu-common.h" static uint32_t cortexa8_cp15_c0_c1[8] = { 0x1031, 0x11, 0x400, 0, 0x31100003, 0x20000000, 0x01202000, 0x11 }; @@ -53,6 +55,7 @@ env->cp15.c0_cachetype = 0x1dd20d2; env->cp15.c1_sys = 0x00090078; break; + case ARM_CPUID_ARM1136_R2: case ARM_CPUID_ARM1136: set_feature(env, ARM_FEATURE_V6); set_feature(env, ARM_FEATURE_VFP); @@ -61,7 +64,7 @@ env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111; env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000; memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t)); - memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t)); + memcpy(env->cp15.c0_c2, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t)); env->cp15.c0_cachetype = 0x1dd20d2; break; case ARM_CPUID_ARM11MPCORE: @@ -73,7 +76,7 @@ env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111; env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000; memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c1, 8 * sizeof(uint32_t)); - memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c2, 8 * sizeof(uint32_t)); + memcpy(env->cp15.c0_c2, mpcore_cp15_c0_c2, 8 * sizeof(uint32_t)); env->cp15.c0_cachetype = 0x1dd20d2; break; case ARM_CPUID_CORTEXA8: @@ -89,7 +92,7 @@ env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222; env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100; memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t)); - memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c2, 8 * sizeof(uint32_t)); + memcpy(env->cp15.c0_c2, cortexa8_cp15_c0_c2, 8 * sizeof(uint32_t)); env->cp15.c0_cachetype = 0x1dd20d2; break; case ARM_CPUID_CORTEXM3: @@ -165,15 +168,69 @@ if (IS_M(env)) env->uncached_cpsr &= ~CPSR_I; env->vfp.xregs[ARM_VFP_FPEXC] = 0; + env->cp15.c2_base_mask = 0xffffc000u; #endif env->regs[15] = 0; tlb_flush(env, 1); } +static int vfp_gdb_get_reg(CPUState *env, uint8_t *buf, int reg) +{ + int nregs; + + /* VFP data registers are always little-endian. */ + nregs = arm_feature(env, ARM_FEATURE_VFP3) ? 32 : 16; + if (reg < nregs) { + stfq_le_p(buf, env->vfp.regs[reg]); + return 8; + } + if (arm_feature(env, ARM_FEATURE_NEON)) { + /* Aliases for Q regs. */ + nregs += 16; + if (reg < nregs) { + stfq_le_p(buf, env->vfp.regs[(reg - 32) * 2]); + stfq_le_p(buf + 8, env->vfp.regs[(reg - 32) * 2 + 1]); + return 16; + } + } + switch (reg - nregs) { + case 0: stl_p(buf, env->vfp.xregs[ARM_VFP_FPSID]); return 4; + case 1: stl_p(buf, env->vfp.xregs[ARM_VFP_FPSCR]); return 4; + case 2: stl_p(buf, env->vfp.xregs[ARM_VFP_FPEXC]); return 4; + } + return 0; +} + +static int vfp_gdb_set_reg(CPUState *env, uint8_t *buf, int reg) +{ + int nregs; + + nregs = arm_feature(env, ARM_FEATURE_VFP3) ? 32 : 16; + if (reg < nregs) { + env->vfp.regs[reg] = ldfq_le_p(buf); + return 8; + } + if (arm_feature(env, ARM_FEATURE_NEON)) { + nregs += 16; + if (reg < nregs) { + env->vfp.regs[(reg - 32) * 2] = ldfq_le_p(buf); + env->vfp.regs[(reg - 32) * 2 + 1] = ldfq_le_p(buf + 8); + return 16; + } + } + switch (reg - nregs) { + case 0: env->vfp.xregs[ARM_VFP_FPSID] = ldl_p(buf); return 4; + case 1: env->vfp.xregs[ARM_VFP_FPSCR] = ldl_p(buf); return 4; + case 2: env->vfp.xregs[ARM_VFP_FPEXC] = ldl_p(buf); return 4; + } + return 0; +} + CPUARMState *cpu_arm_init(const char *cpu_model) { CPUARMState *env; uint32_t id; + static int inited = 0; id = cpu_arm_find_by_name(cpu_model); if (id == 0) @@ -182,9 +239,24 @@ if (!env) return NULL; cpu_exec_init(env); + if (!inited) { + inited = 1; + arm_translate_init(); + } + env->cpu_model_str = cpu_model; env->cp15.c0_cpuid = id; cpu_reset(env); + if (arm_feature(env, ARM_FEATURE_NEON)) { + gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg, + 51, "arm-neon.xml", 0); + } else if (arm_feature(env, ARM_FEATURE_VFP3)) { + gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg, + 35, "arm-vfp3.xml", 0); + } else if (arm_feature(env, ARM_FEATURE_VFP)) { + gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg, + 19, "arm-vfp.xml", 0); + } return env; } @@ -198,6 +270,7 @@ { ARM_CPUID_ARM946, "arm946"}, { ARM_CPUID_ARM1026, "arm1026"}, { ARM_CPUID_ARM1136, "arm1136"}, + { ARM_CPUID_ARM1136_R2, "arm1136-r2"}, { ARM_CPUID_ARM11MPCORE, "arm11mpcore"}, { ARM_CPUID_CORTEXM3, "cortex-m3"}, { ARM_CPUID_CORTEXA8, "cortex-a8"}, @@ -249,35 +322,11 @@ free(env); } -/* Polynomial multiplication is like integer multiplcation except the - partial products are XORed, not added. */ -uint32_t helper_neon_mul_p8(uint32_t op1, uint32_t op2) -{ - uint32_t mask; - uint32_t result; - result = 0; - while (op1) { - mask = 0; - if (op1 & 1) - mask |= 0xff; - if (op1 & (1 << 8)) - mask |= (0xff << 8); - if (op1 & (1 << 16)) - mask |= (0xff << 16); - if (op1 & (1 << 24)) - mask |= (0xff << 24); - result ^= op2 & mask; - op1 = (op1 >> 1) & 0x7f7f7f7f; - op2 = (op2 << 1) & 0xfefefefe; - } - return result; -} - uint32_t cpsr_read(CPUARMState *env) { int ZF; - ZF = (env->NZF == 0); - return env->uncached_cpsr | (env->NZF & 0x80000000) | (ZF << 30) | + ZF = (env->ZF == 0); + return env->uncached_cpsr | (env->NF & 0x80000000) | (ZF << 30) | (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27) | (env->thumb << 5) | ((env->condexec_bits & 3) << 25) | ((env->condexec_bits & 0xfc) << 8) @@ -286,9 +335,9 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) { - /* NOTE: N = 1 and Z = 1 cannot be stored currently */ if (mask & CPSR_NZCV) { - env->NZF = (val & 0xc0000000) ^ 0x40000000; + env->ZF = (~val) & CPSR_Z; + env->NF = val; env->CF = (val >> 29) & 1; env->VF = (val << 3) & 0x80000000; } @@ -315,6 +364,65 @@ env->uncached_cpsr = (env->uncached_cpsr & ~mask) | (val & mask); } +/* Sign/zero extend */ +uint32_t HELPER(sxtb16)(uint32_t x) +{ + uint32_t res; + res = (uint16_t)(int8_t)x; + res |= (uint32_t)(int8_t)(x >> 16) << 16; + return res; +} + +uint32_t HELPER(uxtb16)(uint32_t x) +{ + uint32_t res; + res = (uint16_t)(uint8_t)x; + res |= (uint32_t)(uint8_t)(x >> 16) << 16; + return res; +} + +uint32_t HELPER(clz)(uint32_t x) +{ + int count; + for (count = 32; x; count--) + x >>= 1; + return count; +} + +int32_t HELPER(sdiv)(int32_t num, int32_t den) +{ + if (den == 0) + return 0; + return num / den; +} + +uint32_t HELPER(udiv)(uint32_t num, uint32_t den) +{ + if (den == 0) + return 0; + return num / den; +} + +uint32_t HELPER(rbit)(uint32_t x) +{ + x = ((x & 0xff000000) >> 24) + | ((x & 0x00ff0000) >> 8) + | ((x & 0x0000ff00) << 8) + | ((x & 0x000000ff) << 24); + x = ((x & 0xf0f0f0f0) >> 4) + | ((x & 0x0f0f0f0f) << 4); + x = ((x & 0x88888888) >> 3) + | ((x & 0x44444444) >> 1) + | ((x & 0x22222222) << 1) + | ((x & 0x11111111) << 3); + return x; +} + +uint32_t HELPER(abs)(uint32_t x) +{ + return ((int32_t)x < 0) ? -x : x; +} + #if defined(CONFIG_USER_ONLY) void do_interrupt (CPUState *env) @@ -371,7 +479,7 @@ } /* Mark an address for exclusive access. */ -void helper_mark_exclusive(CPUState *env, uint32_t addr) +void HELPER(mark_exclusive)(CPUState *env, uint32_t addr) { if (!env->mmon_entry) allocate_mmon_state(env); @@ -382,7 +490,7 @@ /* Test if an exclusive address is still exclusive. Returns zero if the address is still exclusive. */ -int helper_test_exclusive(CPUState *env, uint32_t addr) +uint32_t HELPER(test_exclusive)(CPUState *env, uint32_t addr) { int res; @@ -396,7 +504,7 @@ return res; } -void helper_clrex(CPUState *env) +void HELPER(clrex)(CPUState *env) { if (!(env->mmon_entry && env->mmon_entry->addr)) return; @@ -409,38 +517,38 @@ } /* These should probably raise undefined insn exceptions. */ -void helper_set_cp(CPUState *env, uint32_t insn, uint32_t val) +void HELPER(set_cp)(CPUState *env, uint32_t insn, uint32_t val) { int op1 = (insn >> 8) & 0xf; cpu_abort(env, "cp%i insn %08x\n", op1, insn); return; } -uint32_t helper_get_cp(CPUState *env, uint32_t insn) +uint32_t HELPER(get_cp)(CPUState *env, uint32_t insn) { int op1 = (insn >> 8) & 0xf; cpu_abort(env, "cp%i insn %08x\n", op1, insn); return 0; } -void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) +void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) { cpu_abort(env, "cp15 insn %08x\n", insn); } -uint32_t helper_get_cp15(CPUState *env, uint32_t insn) +uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) { cpu_abort(env, "cp15 insn %08x\n", insn); return 0; } /* These should probably raise undefined insn exceptions. */ -void helper_v7m_msr(CPUState *env, int reg, uint32_t val) +void HELPER(v7m_msr)(CPUState *env, uint32_t reg, uint32_t val) { cpu_abort(env, "v7m_mrs %d\n", reg); } -uint32_t helper_v7m_mrs(CPUState *env, int reg) +uint32_t HELPER(v7m_mrs)(CPUState *env, uint32_t reg) { cpu_abort(env, "v7m_mrs %d\n", reg); return 0; @@ -452,12 +560,12 @@ cpu_abort(env, "Tried to switch out of user mode\n"); } -void helper_set_r13_banked(CPUState *env, int mode, uint32_t val) +void HELPER(set_r13_banked)(CPUState *env, uint32_t mode, uint32_t val) { cpu_abort(env, "banked r13 write\n"); } -uint32_t helper_get_r13_banked(CPUState *env, int mode) +uint32_t HELPER(get_r13_banked)(CPUState *env, uint32_t mode) { cpu_abort(env, "banked r13 read\n"); return 0; @@ -629,10 +737,10 @@ /* ??? Should only do this if Configuration Control Register STACKALIGN bit is set. */ if (env->regs[13] & 4) { - env->regs[13] += 4; + env->regs[13] -= 4; xpsr |= 0x200; } - /* Switch to the hander mode. */ + /* Switch to the handler mode. */ v7m_push(env, xpsr); v7m_push(env, env->regs[15]); v7m_push(env, env->regs[14]); @@ -692,7 +800,7 @@ new_mode = ARM_CPU_MODE_SVC; addr = 0x08; mask = CPSR_I; - /* The PC already points to the next instructon. */ + /* The PC already points to the next instruction. */ offset = 0; break; case EXCP_BKPT: @@ -803,6 +911,19 @@ } } +static uint32_t get_level1_table_address(CPUState *env, uint32_t address) +{ + uint32_t table; + + if (address & env->cp15.c2_mask) + table = env->cp15.c2_base1 & 0xffffc000; + else + table = env->cp15.c2_base0 & env->cp15.c2_base_mask; + + table |= (address >> 18) & 0x3ffc; + return table; +} + static int get_phys_addr_v5(CPUState *env, uint32_t address, int access_type, int is_user, uint32_t *phys_ptr, int *prot) { @@ -816,16 +937,12 @@ /* Pagetable walk. */ /* Lookup l1 descriptor. */ - if (address & env->cp15.c2_mask) - table = env->cp15.c2_base1; - else - table = env->cp15.c2_base0; - table = (table & 0xffffc000) | ((address >> 18) & 0x3ffc); + table = get_level1_table_address(env, address); desc = ldl_phys(table); type = (desc & 3); domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3; if (type == 0) { - /* Secton translation fault. */ + /* Section translation fault. */ code = 5; goto do_fault; } @@ -908,15 +1025,11 @@ /* Pagetable walk. */ /* Lookup l1 descriptor. */ - if (address & env->cp15.c2_mask) - table = env->cp15.c2_base1; - else - table = env->cp15.c2_base0; - table = (table & 0xffffc000) | ((address >> 18) & 0x3ffc); + table = get_level1_table_address(env, address); desc = ldl_phys(table); type = (desc & 3); if (type == 0) { - /* Secton translation fault. */ + /* Section translation fault. */ code = 5; domain = 0; goto do_fault; @@ -1115,22 +1228,22 @@ /* Not really implemented. Need to figure out a sane way of doing this. Maybe add generic watchpoint support and use that. */ -void helper_mark_exclusive(CPUState *env, uint32_t addr) +void HELPER(mark_exclusive)(CPUState *env, uint32_t addr) { env->mmon_addr = addr; } -int helper_test_exclusive(CPUState *env, uint32_t addr) +uint32_t HELPER(test_exclusive)(CPUState *env, uint32_t addr) { return (env->mmon_addr != addr); } -void helper_clrex(CPUState *env) +void HELPER(clrex)(CPUState *env) { env->mmon_addr = -1; } -void helper_set_cp(CPUState *env, uint32_t insn, uint32_t val) +void HELPER(set_cp)(CPUState *env, uint32_t insn, uint32_t val) { int cp_num = (insn >> 8) & 0xf; int cp_info = (insn >> 5) & 7; @@ -1142,7 +1255,7 @@ cp_info, src, operand, val); } -uint32_t helper_get_cp(CPUState *env, uint32_t insn) +uint32_t HELPER(get_cp)(CPUState *env, uint32_t insn) { int cp_num = (insn >> 8) & 0xf; int cp_info = (insn >> 5) & 7; @@ -1185,7 +1298,7 @@ return ret; } -void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) +void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) { int op1; int op2; @@ -1227,9 +1340,11 @@ case 2: if (arm_feature(env, ARM_FEATURE_XSCALE)) goto bad_reg; - env->cp15.c1_coproc = val; - /* ??? Is this safe when called from within a TB? */ - tb_flush(env); + if (env->cp15.c1_coproc != val) { + env->cp15.c1_coproc = val; + /* ??? Is this safe when called from within a TB? */ + tb_flush(env); + } break; default: goto bad_reg; @@ -1256,7 +1371,10 @@ env->cp15.c2_base1 = val; break; case 2: + val &= 7; + env->cp15.c2_control = val; env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> val); + env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> val); break; default: goto bad_reg; @@ -1469,7 +1587,7 @@ (insn >> 16) & 0xf, crm, op1, op2); } -uint32_t helper_get_cp15(CPUState *env, uint32_t insn) +uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) { int op1; int op2; @@ -1539,6 +1657,7 @@ case ARM_CPUID_ARM1026: return 1; case ARM_CPUID_ARM1136: + case ARM_CPUID_ARM1136_R2: return 7; case ARM_CPUID_ARM11MPCORE: return 1; @@ -1573,17 +1692,7 @@ case 1: return env->cp15.c2_base1; case 2: - { - int n; - uint32_t mask; - n = 0; - mask = env->cp15.c2_mask; - while (mask) { - n++; - mask <<= 1; - } - return n; - } + return env->cp15.c2_control; default: goto bad_reg; } @@ -1648,10 +1757,8 @@ } } case 7: /* Cache control. */ - /* ??? This is for test, clean and invaidate operations that set the - Z flag. We can't represent N = Z = 1, so it also clears - the N flag. Oh well. */ - env->NZF = 0; + /* FIXME: Should only clear Z flag if destination is r15. */ + env->ZF = 0; return 0; case 8: /* MMU TLB control. */ goto bad_reg; @@ -1721,6 +1828,10 @@ case 8: /* TI925T_status */ return 0; } + /* TODO: Peripheral port remap register: + * On OMAP2 mcr p15, 0, rn, c15, c2, 4 sets up the interrupt + * controller base address at $rn & ~0xfff and map size of + * 0x200 << ($rn & 0xfff), when MMU is off. */ goto bad_reg; } return 0; @@ -1732,17 +1843,17 @@ return 0; } -void helper_set_r13_banked(CPUState *env, int mode, uint32_t val) +void HELPER(set_r13_banked)(CPUState *env, uint32_t mode, uint32_t val) { env->banked_r13[bank_number(mode)] = val; } -uint32_t helper_get_r13_banked(CPUState *env, int mode) +uint32_t HELPER(get_r13_banked)(CPUState *env, uint32_t mode) { return env->banked_r13[bank_number(mode)]; } -uint32_t helper_v7m_mrs(CPUState *env, int reg) +uint32_t HELPER(v7m_mrs)(CPUState *env, uint32_t reg) { switch (reg) { case 0: /* APSR */ @@ -1779,7 +1890,7 @@ } } -void helper_v7m_msr(CPUState *env, int reg, uint32_t val) +void HELPER(v7m_msr)(CPUState *env, uint32_t reg, uint32_t val) { switch (reg) { case 0: /* APSR */ @@ -1861,3 +1972,616 @@ } #endif + +/* Note that signed overflow is undefined in C. The following routines are + careful to use unsigned types where modulo arithmetic is required. + Failure to do so _will_ break on newer gcc. */ + +/* Signed saturating arithmetic. */ + +/* Perform 16-bit signed saturating addition. */ +static inline uint16_t add16_sat(uint16_t a, uint16_t b) +{ + uint16_t res; + + res = a + b; + if (((res ^ a) & 0x8000) && !((a ^ b) & 0x8000)) { + if (a & 0x8000) + res = 0x8000; + else + res = 0x7fff; + } + return res; +} + +/* Perform 8-bit signed saturating addition. */ +static inline uint8_t add8_sat(uint8_t a, uint8_t b) +{ + uint8_t res; + + res = a + b; + if (((res ^ a) & 0x80) && !((a ^ b) & 0x80)) { + if (a & 0x80) + res = 0x80; + else + res = 0x7f; + } + return res; +} + +/* Perform 16-bit signed saturating subtraction. */ +static inline uint16_t sub16_sat(uint16_t a, uint16_t b) +{ + uint16_t res; + + res = a - b; + if (((res ^ a) & 0x8000) && ((a ^ b) & 0x8000)) { + if (a & 0x8000) + res = 0x8000; + else + res = 0x7fff; + } + return res; +} + +/* Perform 8-bit signed saturating subtraction. */ +static inline uint8_t sub8_sat(uint8_t a, uint8_t b) +{ + uint8_t res; + + res = a - b; + if (((res ^ a) & 0x80) && ((a ^ b) & 0x80)) { + if (a & 0x80) + res = 0x80; + else + res = 0x7f; + } + return res; +} + +#define ADD16(a, b, n) RESULT(add16_sat(a, b), n, 16); +#define SUB16(a, b, n) RESULT(sub16_sat(a, b), n, 16); +#define ADD8(a, b, n) RESULT(add8_sat(a, b), n, 8); +#define SUB8(a, b, n) RESULT(sub8_sat(a, b), n, 8); +#define PFX q + +#include "op_addsub.h" + +/* Unsigned saturating arithmetic. */ +static inline uint16_t add16_usat(uint16_t a, uint16_t b) +{ + uint16_t res; + res = a + b; + if (res < a) + res = 0xffff; + return res; +} + +static inline uint16_t sub16_usat(uint16_t a, uint16_t b) +{ + if (a < b) + return a - b; + else + return 0; +} + +static inline uint8_t add8_usat(uint8_t a, uint8_t b) +{ + uint8_t res; + res = a + b; + if (res < a) + res = 0xff; + return res; +} + +static inline uint8_t sub8_usat(uint8_t a, uint8_t b) +{ + if (a < b) + return a - b; + else + return 0; +} + +#define ADD16(a, b, n) RESULT(add16_usat(a, b), n, 16); +#define SUB16(a, b, n) RESULT(sub16_usat(a, b), n, 16); +#define ADD8(a, b, n) RESULT(add8_usat(a, b), n, 8); +#define SUB8(a, b, n) RESULT(sub8_usat(a, b), n, 8); +#define PFX uq + +#include "op_addsub.h" + +/* Signed modulo arithmetic. */ +#define SARITH16(a, b, n, op) do { \ + int32_t sum; \ + sum = (int16_t)((uint16_t)(a) op (uint16_t)(b)); \ + RESULT(sum, n, 16); \ + if (sum >= 0) \ + ge |= 3 << (n * 2); \ + } while(0) + +#define SARITH8(a, b, n, op) do { \ + int32_t sum; \ + sum = (int8_t)((uint8_t)(a) op (uint8_t)(b)); \ + RESULT(sum, n, 8); \ + if (sum >= 0) \ + ge |= 1 << n; \ + } while(0) + + +#define ADD16(a, b, n) SARITH16(a, b, n, +) +#define SUB16(a, b, n) SARITH16(a, b, n, -) +#define ADD8(a, b, n) SARITH8(a, b, n, +) +#define SUB8(a, b, n) SARITH8(a, b, n, -) +#define PFX s +#define ARITH_GE + +#include "op_addsub.h" + +/* Unsigned modulo arithmetic. */ +#define ADD16(a, b, n) do { \ + uint32_t sum; \ + sum = (uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b); \ + RESULT(sum, n, 16); \ + if ((sum >> 16) == 1) \ + ge |= 3 << (n * 2); \ + } while(0) + +#define ADD8(a, b, n) do { \ + uint32_t sum; \ + sum = (uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b); \ + RESULT(sum, n, 8); \ + if ((sum >> 8) == 1) \ + ge |= 1 << n; \ + } while(0) + +#define SUB16(a, b, n) do { \ + uint32_t sum; \ + sum = (uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b); \ + RESULT(sum, n, 16); \ + if ((sum >> 16) == 0) \ + ge |= 3 << (n * 2); \ + } while(0) + +#define SUB8(a, b, n) do { \ + uint32_t sum; \ + sum = (uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b); \ + RESULT(sum, n, 8); \ + if ((sum >> 8) == 0) \ + ge |= 1 << n; \ + } while(0) + +#define PFX u +#define ARITH_GE + +#include "op_addsub.h" + +/* Halved signed arithmetic. */ +#define ADD16(a, b, n) \ + RESULT(((int32_t)(int16_t)(a) + (int32_t)(int16_t)(b)) >> 1, n, 16) +#define SUB16(a, b, n) \ + RESULT(((int32_t)(int16_t)(a) - (int32_t)(int16_t)(b)) >> 1, n, 16) +#define ADD8(a, b, n) \ + RESULT(((int32_t)(int8_t)(a) + (int32_t)(int8_t)(b)) >> 1, n, 8) +#define SUB8(a, b, n) \ + RESULT(((int32_t)(int8_t)(a) - (int32_t)(int8_t)(b)) >> 1, n, 8) +#define PFX sh + +#include "op_addsub.h" + +/* Halved unsigned arithmetic. */ +#define ADD16(a, b, n) \ + RESULT(((uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b)) >> 1, n, 16) +#define SUB16(a, b, n) \ + RESULT(((uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b)) >> 1, n, 16) +#define ADD8(a, b, n) \ + RESULT(((uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b)) >> 1, n, 8) +#define SUB8(a, b, n) \ + RESULT(((uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b)) >> 1, n, 8) +#define PFX uh + +#include "op_addsub.h" + +static inline uint8_t do_usad(uint8_t a, uint8_t b) +{ + if (a > b) + return a - b; + else + return b - a; +} + +/* Unsigned sum of absolute byte differences. */ +uint32_t HELPER(usad8)(uint32_t a, uint32_t b) +{ + uint32_t sum; + sum = do_usad(a, b); + sum += do_usad(a >> 8, b >> 8); + sum += do_usad(a >> 16, b >>16); + sum += do_usad(a >> 24, b >> 24); + return sum; +} + +/* For ARMv6 SEL instruction. */ +uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b) +{ + uint32_t mask; + + mask = 0; + if (flags & 1) + mask |= 0xff; + if (flags & 2) + mask |= 0xff00; + if (flags & 4) + mask |= 0xff0000; + if (flags & 8) + mask |= 0xff000000; + return (a & mask) | (b & ~mask); +} + +uint32_t HELPER(logicq_cc)(uint64_t val) +{ + return (val >> 32) | (val != 0); +} + +/* VFP support. We follow the convention used for VFP instrunctions: + Single precition routines have a "s" suffix, double precision a + "d" suffix. */ + +/* Convert host exception flags to vfp form. */ +static inline int vfp_exceptbits_from_host(int host_bits) +{ + int target_bits = 0; + + if (host_bits & float_flag_invalid) + target_bits |= 1; + if (host_bits & float_flag_divbyzero) + target_bits |= 2; + if (host_bits & float_flag_overflow) + target_bits |= 4; + if (host_bits & float_flag_underflow) + target_bits |= 8; + if (host_bits & float_flag_inexact) + target_bits |= 0x10; + return target_bits; +} + +uint32_t HELPER(vfp_get_fpscr)(CPUState *env) +{ + int i; + uint32_t fpscr; + + fpscr = (env->vfp.xregs[ARM_VFP_FPSCR] & 0xffc8ffff) + | (env->vfp.vec_len << 16) + | (env->vfp.vec_stride << 20); + i = get_float_exception_flags(&env->vfp.fp_status); + fpscr |= vfp_exceptbits_from_host(i); + return fpscr; +} + +/* Convert vfp exception flags to target form. */ +static inline int vfp_exceptbits_to_host(int target_bits) +{ + int host_bits = 0; + + if (target_bits & 1) + host_bits |= float_flag_invalid; + if (target_bits & 2) + host_bits |= float_flag_divbyzero; + if (target_bits & 4) + host_bits |= float_flag_overflow; + if (target_bits & 8) + host_bits |= float_flag_underflow; + if (target_bits & 0x10) + host_bits |= float_flag_inexact; + return host_bits; +} + +void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val) +{ + int i; + uint32_t changed; + + changed = env->vfp.xregs[ARM_VFP_FPSCR]; + env->vfp.xregs[ARM_VFP_FPSCR] = (val & 0xffc8ffff); + env->vfp.vec_len = (val >> 16) & 7; + env->vfp.vec_stride = (val >> 20) & 3; + + changed ^= val; + if (changed & (3 << 22)) { + i = (val >> 22) & 3; + switch (i) { + case 0: + i = float_round_nearest_even; + break; + case 1: + i = float_round_up; + break; + case 2: + i = float_round_down; + break; + case 3: + i = float_round_to_zero; + break; + } + set_float_rounding_mode(i, &env->vfp.fp_status); + } + + i = vfp_exceptbits_to_host((val >> 8) & 0x1f); + set_float_exception_flags(i, &env->vfp.fp_status); + /* XXX: FZ and DN are not implemented. */ +} + +#define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p)) + +#define VFP_BINOP(name) \ +float32 VFP_HELPER(name, s)(float32 a, float32 b, CPUState *env) \ +{ \ + return float32_ ## name (a, b, &env->vfp.fp_status); \ +} \ +float64 VFP_HELPER(name, d)(float64 a, float64 b, CPUState *env) \ +{ \ + return float64_ ## name (a, b, &env->vfp.fp_status); \ +} +VFP_BINOP(add) +VFP_BINOP(sub) +VFP_BINOP(mul) +VFP_BINOP(div) +#undef VFP_BINOP + +float32 VFP_HELPER(neg, s)(float32 a) +{ + return float32_chs(a); +} + +float64 VFP_HELPER(neg, d)(float64 a) +{ + return float64_chs(a); +} + +float32 VFP_HELPER(abs, s)(float32 a) +{ + return float32_abs(a); +} + +float64 VFP_HELPER(abs, d)(float64 a) +{ + return float64_abs(a); +} + +float32 VFP_HELPER(sqrt, s)(float32 a, CPUState *env) +{ + return float32_sqrt(a, &env->vfp.fp_status); +} + +float64 VFP_HELPER(sqrt, d)(float64 a, CPUState *env) +{ + return float64_sqrt(a, &env->vfp.fp_status); +} + +/* XXX: check quiet/signaling case */ +#define DO_VFP_cmp(p, type) \ +void VFP_HELPER(cmp, p)(type a, type b, CPUState *env) \ +{ \ + uint32_t flags; \ + switch(type ## _compare_quiet(a, b, &env->vfp.fp_status)) { \ + case 0: flags = 0x6; break; \ + case -1: flags = 0x8; break; \ + case 1: flags = 0x2; break; \ + default: case 2: flags = 0x3; break; \ + } \ + env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28) \ + | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ +} \ +void VFP_HELPER(cmpe, p)(type a, type b, CPUState *env) \ +{ \ + uint32_t flags; \ + switch(type ## _compare(a, b, &env->vfp.fp_status)) { \ + case 0: flags = 0x6; break; \ + case -1: flags = 0x8; break; \ + case 1: flags = 0x2; break; \ + default: case 2: flags = 0x3; break; \ + } \ + env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28) \ + | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ +} +DO_VFP_cmp(s, float32) +DO_VFP_cmp(d, float64) +#undef DO_VFP_cmp + +/* Helper routines to perform bitwise copies between float and int. */ +static inline float32 vfp_itos(uint32_t i) +{ + union { + uint32_t i; + float32 s; + } v; + + v.i = i; + return v.s; +} + +static inline uint32_t vfp_stoi(float32 s) +{ + union { + uint32_t i; + float32 s; + } v; + + v.s = s; + return v.i; +} + +static inline float64 vfp_itod(uint64_t i) +{ + union { + uint64_t i; + float64 d; + } v; + + v.i = i; + return v.d; +} + +static inline uint64_t vfp_dtoi(float64 d) +{ + union { + uint64_t i; + float64 d; + } v; + + v.d = d; + return v.i; +} + +/* Integer to float conversion. */ +float32 VFP_HELPER(uito, s)(float32 x, CPUState *env) +{ + return uint32_to_float32(vfp_stoi(x), &env->vfp.fp_status); +} + +float64 VFP_HELPER(uito, d)(float32 x, CPUState *env) +{ + return uint32_to_float64(vfp_stoi(x), &env->vfp.fp_status); +} + +float32 VFP_HELPER(sito, s)(float32 x, CPUState *env) +{ + return int32_to_float32(vfp_stoi(x), &env->vfp.fp_status); +} + +float64 VFP_HELPER(sito, d)(float32 x, CPUState *env) +{ + return int32_to_float64(vfp_stoi(x), &env->vfp.fp_status); +} + +/* Float to integer conversion. */ +float32 VFP_HELPER(toui, s)(float32 x, CPUState *env) +{ + return vfp_itos(float32_to_uint32(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(toui, d)(float64 x, CPUState *env) +{ + return vfp_itos(float64_to_uint32(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(tosi, s)(float32 x, CPUState *env) +{ + return vfp_itos(float32_to_int32(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(tosi, d)(float64 x, CPUState *env) +{ + return vfp_itos(float64_to_int32(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(touiz, s)(float32 x, CPUState *env) +{ + return vfp_itos(float32_to_uint32_round_to_zero(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(touiz, d)(float64 x, CPUState *env) +{ + return vfp_itos(float64_to_uint32_round_to_zero(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(tosiz, s)(float32 x, CPUState *env) +{ + return vfp_itos(float32_to_int32_round_to_zero(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(tosiz, d)(float64 x, CPUState *env) +{ + return vfp_itos(float64_to_int32_round_to_zero(x, &env->vfp.fp_status)); +} + +/* floating point conversion */ +float64 VFP_HELPER(fcvtd, s)(float32 x, CPUState *env) +{ + return float32_to_float64(x, &env->vfp.fp_status); +} + +float32 VFP_HELPER(fcvts, d)(float64 x, CPUState *env) +{ + return float64_to_float32(x, &env->vfp.fp_status); +} + +/* VFP3 fixed point conversion. */ +#define VFP_CONV_FIX(name, p, ftype, itype, sign) \ +ftype VFP_HELPER(name##to, p)(ftype x, uint32_t shift, CPUState *env) \ +{ \ + ftype tmp; \ + tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(x), \ + &env->vfp.fp_status); \ + return ftype##_scalbn(tmp, shift, &env->vfp.fp_status); \ +} \ +ftype VFP_HELPER(to##name, p)(ftype x, uint32_t shift, CPUState *env) \ +{ \ + ftype tmp; \ + tmp = ftype##_scalbn(x, shift, &env->vfp.fp_status); \ + return vfp_ito##p((itype)ftype##_to_##sign##int32_round_to_zero(tmp, \ + &env->vfp.fp_status)); \ +} + +VFP_CONV_FIX(sh, d, float64, int16, ) +VFP_CONV_FIX(sl, d, float64, int32, ) +VFP_CONV_FIX(uh, d, float64, uint16, u) +VFP_CONV_FIX(ul, d, float64, uint32, u) +VFP_CONV_FIX(sh, s, float32, int16, ) +VFP_CONV_FIX(sl, s, float32, int32, ) +VFP_CONV_FIX(uh, s, float32, uint16, u) +VFP_CONV_FIX(ul, s, float32, uint32, u) +#undef VFP_CONV_FIX + +float32 HELPER(recps_f32)(float32 a, float32 b, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 two = int32_to_float32(2, s); + return float32_sub(two, float32_mul(a, b, s), s); +} + +float32 HELPER(rsqrts_f32)(float32 a, float32 b, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 three = int32_to_float32(3, s); + return float32_sub(three, float32_mul(a, b, s), s); +} + +/* NEON helpers. */ + +/* TODO: The architecture specifies the value that the estimate functions + should return. We return the exact reciprocal/root instead. */ +float32 HELPER(recpe_f32)(float32 a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 one = int32_to_float32(1, s); + return float32_div(one, a, s); +} + +float32 HELPER(rsqrte_f32)(float32 a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 one = int32_to_float32(1, s); + return float32_div(one, float32_sqrt(a, s), s); +} + +uint32_t HELPER(recpe_u32)(uint32_t a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 tmp; + tmp = int32_to_float32(a, s); + tmp = float32_scalbn(tmp, -32, s); + tmp = helper_recpe_f32(tmp, env); + tmp = float32_scalbn(tmp, 31, s); + return float32_to_int32(tmp, s); +} + +uint32_t HELPER(rsqrte_u32)(uint32_t a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 tmp; + tmp = int32_to_float32(a, s); + tmp = float32_scalbn(tmp, -32, s); + tmp = helper_rsqrte_f32(tmp, env); + tmp = float32_scalbn(tmp, 31, s); + return float32_to_int32(tmp, s); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/helpers.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/helpers.h --- qemu-0.9.1/target-arm/helpers.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-arm/helpers.h 2008-03-31 04:49:05.000000000 +0100 @@ -0,0 +1,539 @@ +#define DEF_HELPER(name, ret, args) ret glue(helper_,name) args; + +#ifdef GEN_HELPER +#define DEF_HELPER_0_0(name, ret, args) \ +DEF_HELPER(name, ret, args) \ +static inline void gen_helper_##name(void) \ +{ \ + tcg_gen_helper_0_0(helper_##name); \ +} +#define DEF_HELPER_0_1(name, ret, args) \ +DEF_HELPER(name, ret, args) \ +static inline void gen_helper_##name(TCGv arg1) \ +{ \ + tcg_gen_helper_0_1(helper_##name, arg1); \ +} +#define DEF_HELPER_0_2(name, ret, args) \ +DEF_HELPER(name, ret, args) \ +static inline void gen_helper_##name(TCGv arg1, TCGv arg2) \ +{ \ + tcg_gen_helper_0_2(helper_##name, arg1, arg2); \ +} +#define DEF_HELPER_0_3(name, ret, args) \ +DEF_HELPER(name, ret, args) \ +static inline void gen_helper_##name( \ + TCGv arg1, TCGv arg2, TCGv arg3) \ +{ \ + tcg_gen_helper_0_3(helper_##name, arg1, arg2, arg3); \ +} +#define DEF_HELPER_1_0(name, ret, args) \ +DEF_HELPER(name, ret, args) \ +static inline void gen_helper_##name(TCGv ret) \ +{ \ + tcg_gen_helper_1_0(helper_##name, ret); \ +} +#define DEF_HELPER_1_1(name, ret, args) \ +DEF_HELPER(name, ret, args) \ +static inline void gen_helper_##name(TCGv ret, TCGv arg1) \ +{ \ + tcg_gen_helper_1_1(helper_##name, ret, arg1); \ +} +#define DEF_HELPER_1_2(name, ret, args) \ +DEF_HELPER(name, ret, args) \ +static inline void gen_helper_##name(TCGv ret, TCGv arg1, TCGv arg2) \ +{ \ + tcg_gen_helper_1_2(helper_##name, ret, arg1, arg2); \ +} +#define DEF_HELPER_1_3(name, ret, args) \ +DEF_HELPER(name, ret, args) \ +static inline void gen_helper_##name(TCGv ret, \ + TCGv arg1, TCGv arg2, TCGv arg3) \ +{ \ + tcg_gen_helper_1_3(helper_##name, ret, arg1, arg2, arg3); \ +} +#define DEF_HELPER_1_4(name, ret, args) \ +DEF_HELPER(name, ret, args) \ +static inline void gen_helper_##name(TCGv ret, \ + TCGv arg1, TCGv arg2, TCGv arg3, TCGv arg4) \ +{ \ + tcg_gen_helper_1_4(helper_##name, ret, arg1, arg2, arg3, arg4); \ +} +#else /* !GEN_HELPER */ +#define DEF_HELPER_0_0 DEF_HELPER +#define DEF_HELPER_0_1 DEF_HELPER +#define DEF_HELPER_0_2 DEF_HELPER +#define DEF_HELPER_0_3 DEF_HELPER +#define DEF_HELPER_1_0 DEF_HELPER +#define DEF_HELPER_1_1 DEF_HELPER +#define DEF_HELPER_1_2 DEF_HELPER +#define DEF_HELPER_1_3 DEF_HELPER +#define DEF_HELPER_1_4 DEF_HELPER +#define HELPER(x) glue(helper_,x) +#endif + +DEF_HELPER_1_1(clz, uint32_t, (uint32_t)) +DEF_HELPER_1_1(sxtb16, uint32_t, (uint32_t)) +DEF_HELPER_1_1(uxtb16, uint32_t, (uint32_t)) + +DEF_HELPER_1_2(add_setq, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(add_saturate, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(sub_saturate, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(add_usaturate, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(sub_usaturate, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_1(double_saturate, uint32_t, (int32_t)) +DEF_HELPER_1_2(sdiv, int32_t, (int32_t, int32_t)) +DEF_HELPER_1_2(udiv, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_1(rbit, uint32_t, (uint32_t)) +DEF_HELPER_1_1(abs, uint32_t, (uint32_t)) + +#define PAS_OP(pfx) \ + DEF_HELPER_1_3(pfx ## add8, uint32_t, (uint32_t, uint32_t, uint32_t *)) \ + DEF_HELPER_1_3(pfx ## sub8, uint32_t, (uint32_t, uint32_t, uint32_t *)) \ + DEF_HELPER_1_3(pfx ## sub16, uint32_t, (uint32_t, uint32_t, uint32_t *)) \ + DEF_HELPER_1_3(pfx ## add16, uint32_t, (uint32_t, uint32_t, uint32_t *)) \ + DEF_HELPER_1_3(pfx ## addsubx, uint32_t, (uint32_t, uint32_t, uint32_t *)) \ + DEF_HELPER_1_3(pfx ## subaddx, uint32_t, (uint32_t, uint32_t, uint32_t *)) + +PAS_OP(s) +PAS_OP(u) +#undef PAS_OP + +#define PAS_OP(pfx) \ + DEF_HELPER_1_2(pfx ## add8, uint32_t, (uint32_t, uint32_t)) \ + DEF_HELPER_1_2(pfx ## sub8, uint32_t, (uint32_t, uint32_t)) \ + DEF_HELPER_1_2(pfx ## sub16, uint32_t, (uint32_t, uint32_t)) \ + DEF_HELPER_1_2(pfx ## add16, uint32_t, (uint32_t, uint32_t)) \ + DEF_HELPER_1_2(pfx ## addsubx, uint32_t, (uint32_t, uint32_t)) \ + DEF_HELPER_1_2(pfx ## subaddx, uint32_t, (uint32_t, uint32_t)) +PAS_OP(q) +PAS_OP(sh) +PAS_OP(uq) +PAS_OP(uh) +#undef PAS_OP + +DEF_HELPER_1_2(ssat, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(usat, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(ssat16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(usat16, uint32_t, (uint32_t, uint32_t)) + +DEF_HELPER_1_2(usad8, uint32_t, (uint32_t, uint32_t)) + +DEF_HELPER_1_1(logicq_cc, uint32_t, (uint64_t)) + +DEF_HELPER_1_3(sel_flags, uint32_t, (uint32_t, uint32_t, uint32_t)) +DEF_HELPER_0_1(exception, void, (uint32_t)) +DEF_HELPER_0_0(wfi, void, (void)) + +DEF_HELPER_0_2(cpsr_write, void, (uint32_t, uint32_t)) +DEF_HELPER_1_0(cpsr_read, uint32_t, (void)) + +DEF_HELPER_0_3(v7m_msr, void, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_2(v7m_mrs, uint32_t, (CPUState *, uint32_t)) + +DEF_HELPER_0_3(set_cp15, void, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_2(get_cp15, uint32_t, (CPUState *, uint32_t)) + +DEF_HELPER_0_3(set_cp, void, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_2(get_cp, uint32_t, (CPUState *, uint32_t)) + +DEF_HELPER_1_2(get_r13_banked, uint32_t, (CPUState *, uint32_t)) +DEF_HELPER_0_3(set_r13_banked, void, (CPUState *, uint32_t, uint32_t)) + +DEF_HELPER_0_2(mark_exclusive, void, (CPUState *, uint32_t)) +DEF_HELPER_1_2(test_exclusive, uint32_t, (CPUState *, uint32_t)) +DEF_HELPER_0_1(clrex, void, (CPUState *)) + +DEF_HELPER_1_1(get_user_reg, uint32_t, (uint32_t)) +DEF_HELPER_0_2(set_user_reg, void, (uint32_t, uint32_t)) + +DEF_HELPER_1_1(vfp_get_fpscr, uint32_t, (CPUState *)) +DEF_HELPER_0_2(vfp_set_fpscr, void, (CPUState *, uint32_t)) + +DEF_HELPER_1_3(vfp_adds, float32, (float32, float32, CPUState *)) +DEF_HELPER_1_3(vfp_addd, float64, (float64, float64, CPUState *)) +DEF_HELPER_1_3(vfp_subs, float32, (float32, float32, CPUState *)) +DEF_HELPER_1_3(vfp_subd, float64, (float64, float64, CPUState *)) +DEF_HELPER_1_3(vfp_muls, float32, (float32, float32, CPUState *)) +DEF_HELPER_1_3(vfp_muld, float64, (float64, float64, CPUState *)) +DEF_HELPER_1_3(vfp_divs, float32, (float32, float32, CPUState *)) +DEF_HELPER_1_3(vfp_divd, float64, (float64, float64, CPUState *)) +DEF_HELPER_1_1(vfp_negs, float32, (float32)) +DEF_HELPER_1_1(vfp_negd, float64, (float64)) +DEF_HELPER_1_1(vfp_abss, float32, (float32)) +DEF_HELPER_1_1(vfp_absd, float64, (float64)) +DEF_HELPER_1_2(vfp_sqrts, float32, (float32, CPUState *)) +DEF_HELPER_1_2(vfp_sqrtd, float64, (float64, CPUState *)) +DEF_HELPER_0_3(vfp_cmps, void, (float32, float32, CPUState *)) +DEF_HELPER_0_3(vfp_cmpd, void, (float64, float64, CPUState *)) +DEF_HELPER_0_3(vfp_cmpes, void, (float32, float32, CPUState *)) +DEF_HELPER_0_3(vfp_cmped, void, (float64, float64, CPUState *)) + +DEF_HELPER_1_2(vfp_fcvtds, float64, (float32, CPUState *)) +DEF_HELPER_1_2(vfp_fcvtsd, float32, (float64, CPUState *)) + +DEF_HELPER_1_2(vfp_uitos, float32, (float32, CPUState *)) +DEF_HELPER_1_2(vfp_uitod, float64, (float32, CPUState *)) +DEF_HELPER_1_2(vfp_sitos, float32, (float32, CPUState *)) +DEF_HELPER_1_2(vfp_sitod, float64, (float32, CPUState *)) + +DEF_HELPER_1_2(vfp_touis, float32, (float32, CPUState *)) +DEF_HELPER_1_2(vfp_touid, float32, (float64, CPUState *)) +DEF_HELPER_1_2(vfp_touizs, float32, (float32, CPUState *)) +DEF_HELPER_1_2(vfp_touizd, float32, (float64, CPUState *)) +DEF_HELPER_1_2(vfp_tosis, float32, (float32, CPUState *)) +DEF_HELPER_1_2(vfp_tosid, float32, (float64, CPUState *)) +DEF_HELPER_1_2(vfp_tosizs, float32, (float32, CPUState *)) +DEF_HELPER_1_2(vfp_tosizd, float32, (float64, CPUState *)) + +DEF_HELPER_1_3(vfp_toshs, float32, (float32, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_tosls, float32, (float32, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_touhs, float32, (float32, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_touls, float32, (float32, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_toshd, float64, (float64, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_tosld, float64, (float64, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_touhd, float64, (float64, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_tould, float64, (float64, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_shtos, float32, (float32, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_sltos, float32, (float32, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_uhtos, float32, (float32, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_ultos, float32, (float32, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_shtod, float64, (float64, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_sltod, float64, (float64, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_uhtod, float64, (float64, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_ultod, float64, (float64, uint32_t, CPUState *)) + +DEF_HELPER_1_3(recps_f32, float32, (float32, float32, CPUState *)) +DEF_HELPER_1_3(rsqrts_f32, float32, (float32, float32, CPUState *)) +DEF_HELPER_1_2(recpe_f32, float32, (float32, CPUState *)) +DEF_HELPER_1_2(rsqrte_f32, float32, (float32, CPUState *)) +DEF_HELPER_1_2(recpe_u32, uint32_t, (uint32_t, CPUState *)) +DEF_HELPER_1_2(rsqrte_u32, uint32_t, (uint32_t, CPUState *)) +DEF_HELPER_1_4(neon_tbl, uint32_t, (uint32_t, uint32_t, uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_add_saturate_u64, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(neon_add_saturate_s64, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(neon_sub_saturate_u64, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(neon_sub_saturate_s64, uint64_t, (uint64_t, uint64_t)) + +DEF_HELPER_1_2(add_cc, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(adc_cc, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(sub_cc, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(sbc_cc, uint32_t, (uint32_t, uint32_t)) + +DEF_HELPER_1_2(shl, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(shr, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(sar, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(ror, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(shl_cc, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(shr_cc, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(sar_cc, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(ror_cc, uint32_t, (uint32_t, uint32_t)) + +/* neon_helper.c */ +DEF_HELPER_1_3(neon_qadd_u8, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qadd_s8, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qadd_u16, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qadd_s16, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qsub_u8, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qsub_s8, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qsub_u16, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qsub_s16, uint32_t, (CPUState *, uint32_t, uint32_t)) + +DEF_HELPER_1_2(neon_hadd_s8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_hadd_u8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_hadd_s16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_hadd_u16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_hadd_s32, int32_t, (int32_t, int32_t)) +DEF_HELPER_1_2(neon_hadd_u32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_rhadd_s8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_rhadd_u8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_rhadd_s16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_rhadd_u16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_rhadd_s32, int32_t, (int32_t, int32_t)) +DEF_HELPER_1_2(neon_rhadd_u32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_hsub_s8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_hsub_u8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_hsub_s16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_hsub_u16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_hsub_s32, int32_t, (int32_t, int32_t)) +DEF_HELPER_1_2(neon_hsub_u32, uint32_t, (uint32_t, uint32_t)) + +DEF_HELPER_1_2(neon_cgt_u8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_cgt_s8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_cgt_u16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_cgt_s16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_cgt_u32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_cgt_s32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_cge_u8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_cge_s8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_cge_u16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_cge_s16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_cge_u32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_cge_s32, uint32_t, (uint32_t, uint32_t)) + +DEF_HELPER_1_2(neon_min_u8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_min_s8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_min_u16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_min_s16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_min_u32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_min_s32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_max_u8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_max_s8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_max_u16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_max_s16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_max_u32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_max_s32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_pmin_u8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_pmin_s8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_pmin_u16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_pmin_s16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_pmin_u32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_pmin_s32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_pmax_u8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_pmax_s8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_pmax_u16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_pmax_s16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_pmax_u32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_pmax_s32, uint32_t, (uint32_t, uint32_t)) + +DEF_HELPER_1_2(neon_abd_u8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_abd_s8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_abd_u16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_abd_s16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_abd_u32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_abd_s32, uint32_t, (uint32_t, uint32_t)) + +DEF_HELPER_1_2(neon_shl_u8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_shl_s8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_shl_u16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_shl_s16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_shl_u32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_shl_s32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_shl_u64, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(neon_shl_s64, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(neon_rshl_u8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_rshl_s8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_rshl_u16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_rshl_s16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_rshl_u32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_rshl_s32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_rshl_u64, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(neon_rshl_s64, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_3(neon_qshl_u8, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qshl_s8, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qshl_u16, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qshl_s16, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qshl_u32, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qshl_s32, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qshl_u64, uint64_t, (CPUState *, uint64_t, uint64_t)) +DEF_HELPER_1_3(neon_qshl_s64, uint64_t, (CPUState *, uint64_t, uint64_t)) +DEF_HELPER_1_3(neon_qrshl_u8, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qrshl_s8, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qrshl_u16, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qrshl_s16, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qrshl_u32, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qrshl_s32, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qrshl_u64, uint64_t, (CPUState *, uint64_t, uint64_t)) +DEF_HELPER_1_3(neon_qrshl_s64, uint64_t, (CPUState *, uint64_t, uint64_t)) + +DEF_HELPER_1_2(neon_add_u8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_add_u16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_padd_u8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_padd_u16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_sub_u8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_sub_u16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_mul_u8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_mul_u16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_mul_p8, uint32_t, (uint32_t, uint32_t)) + +DEF_HELPER_1_2(neon_tst_u8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_tst_u16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_tst_u32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_ceq_u8, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_ceq_u16, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_ceq_u32, uint32_t, (uint32_t, uint32_t)) + +DEF_HELPER_1_1(neon_abs_s8, uint32_t, (uint32_t)) +DEF_HELPER_1_1(neon_abs_s16, uint32_t, (uint32_t)) +DEF_HELPER_1_1(neon_clz_u8, uint32_t, (uint32_t)) +DEF_HELPER_1_1(neon_clz_u16, uint32_t, (uint32_t)) +DEF_HELPER_1_1(neon_cls_s8, uint32_t, (uint32_t)) +DEF_HELPER_1_1(neon_cls_s16, uint32_t, (uint32_t)) +DEF_HELPER_1_1(neon_cls_s32, uint32_t, (uint32_t)) +DEF_HELPER_1_1(neon_cnt_u8, uint32_t, (uint32_t)) + +DEF_HELPER_1_3(neon_qdmulh_s16, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qrdmulh_s16, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qdmulh_s32, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(neon_qrdmulh_s32, uint32_t, (CPUState *, uint32_t, uint32_t)) + +DEF_HELPER_1_1(neon_narrow_u8, uint32_t, (uint64_t)) +DEF_HELPER_1_1(neon_narrow_u16, uint32_t, (uint64_t)) +DEF_HELPER_1_2(neon_narrow_sat_u8, uint32_t, (CPUState *, uint64_t)) +DEF_HELPER_1_2(neon_narrow_sat_s8, uint32_t, (CPUState *, uint64_t)) +DEF_HELPER_1_2(neon_narrow_sat_u16, uint32_t, (CPUState *, uint64_t)) +DEF_HELPER_1_2(neon_narrow_sat_s16, uint32_t, (CPUState *, uint64_t)) +DEF_HELPER_1_2(neon_narrow_sat_u32, uint32_t, (CPUState *, uint64_t)) +DEF_HELPER_1_2(neon_narrow_sat_s32, uint32_t, (CPUState *, uint64_t)) +DEF_HELPER_1_1(neon_narrow_high_u8, uint32_t, (uint64_t)) +DEF_HELPER_1_1(neon_narrow_high_u16, uint32_t, (uint64_t)) +DEF_HELPER_1_1(neon_narrow_round_high_u8, uint32_t, (uint64_t)) +DEF_HELPER_1_1(neon_narrow_round_high_u16, uint32_t, (uint64_t)) +DEF_HELPER_1_1(neon_widen_u8, uint64_t, (uint32_t)) +DEF_HELPER_1_1(neon_widen_s8, uint64_t, (uint32_t)) +DEF_HELPER_1_1(neon_widen_u16, uint64_t, (uint32_t)) +DEF_HELPER_1_1(neon_widen_s16, uint64_t, (uint32_t)) + +DEF_HELPER_1_2(neon_addl_u16, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(neon_addl_u32, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(neon_paddl_u16, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(neon_paddl_u32, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(neon_subl_u16, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(neon_subl_u32, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_3(neon_addl_saturate_s32, uint64_t, (CPUState *, uint64_t, uint64_t)) +DEF_HELPER_1_3(neon_addl_saturate_s64, uint64_t, (CPUState *, uint64_t, uint64_t)) +DEF_HELPER_1_2(neon_abdl_u16, uint64_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_abdl_s16, uint64_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_abdl_u32, uint64_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_abdl_s32, uint64_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_abdl_u64, uint64_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_abdl_s64, uint64_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_mull_u8, uint64_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_mull_s8, uint64_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_mull_u16, uint64_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_mull_s16, uint64_t, (uint32_t, uint32_t)) + +DEF_HELPER_1_1(neon_negl_u16, uint64_t, (uint64_t)) +DEF_HELPER_1_1(neon_negl_u32, uint64_t, (uint64_t)) +DEF_HELPER_1_1(neon_negl_u64, uint64_t, (uint64_t)) + +DEF_HELPER_1_2(neon_qabs_s8, uint32_t, (CPUState *, uint32_t)) +DEF_HELPER_1_2(neon_qabs_s16, uint32_t, (CPUState *, uint32_t)) +DEF_HELPER_1_2(neon_qabs_s32, uint32_t, (CPUState *, uint32_t)) +DEF_HELPER_1_2(neon_qneg_s8, uint32_t, (CPUState *, uint32_t)) +DEF_HELPER_1_2(neon_qneg_s16, uint32_t, (CPUState *, uint32_t)) +DEF_HELPER_1_2(neon_qneg_s32, uint32_t, (CPUState *, uint32_t)) + +DEF_HELPER_0_0(neon_trn_u8, void, (void)) +DEF_HELPER_0_0(neon_trn_u16, void, (void)) +DEF_HELPER_0_0(neon_unzip_u8, void, (void)) +DEF_HELPER_0_0(neon_zip_u8, void, (void)) +DEF_HELPER_0_0(neon_zip_u16, void, (void)) + +DEF_HELPER_1_2(neon_min_f32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_max_f32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_abd_f32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_add_f32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_sub_f32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_mul_f32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_ceq_f32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_cge_f32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_cgt_f32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_acge_f32, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_1_2(neon_acgt_f32, uint32_t, (uint32_t, uint32_t)) + +/* iwmmxt_helper.c */ +DEF_HELPER_1_2(iwmmxt_maddsq, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(iwmmxt_madduq, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(iwmmxt_sadb, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(iwmmxt_sadw, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(iwmmxt_mulslw, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(iwmmxt_mulshw, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(iwmmxt_mululw, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(iwmmxt_muluhw, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(iwmmxt_macsw, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_2(iwmmxt_macuw, uint64_t, (uint64_t, uint64_t)) +DEF_HELPER_1_1(iwmmxt_setpsr_nz, uint32_t, (uint64_t)) + +#define DEF_IWMMXT_HELPER_SIZE_ENV(name) \ +DEF_HELPER_1_3(iwmmxt_##name##b, uint64_t, (CPUState *, uint64_t, uint64_t)) \ +DEF_HELPER_1_3(iwmmxt_##name##w, uint64_t, (CPUState *, uint64_t, uint64_t)) \ +DEF_HELPER_1_3(iwmmxt_##name##l, uint64_t, (CPUState *, uint64_t, uint64_t)) \ + +DEF_IWMMXT_HELPER_SIZE_ENV(unpackl) +DEF_IWMMXT_HELPER_SIZE_ENV(unpackh) + +DEF_HELPER_1_2(iwmmxt_unpacklub, uint64_t, (CPUState *, uint64_t)) +DEF_HELPER_1_2(iwmmxt_unpackluw, uint64_t, (CPUState *, uint64_t)) +DEF_HELPER_1_2(iwmmxt_unpacklul, uint64_t, (CPUState *, uint64_t)) +DEF_HELPER_1_2(iwmmxt_unpackhub, uint64_t, (CPUState *, uint64_t)) +DEF_HELPER_1_2(iwmmxt_unpackhuw, uint64_t, (CPUState *, uint64_t)) +DEF_HELPER_1_2(iwmmxt_unpackhul, uint64_t, (CPUState *, uint64_t)) +DEF_HELPER_1_2(iwmmxt_unpacklsb, uint64_t, (CPUState *, uint64_t)) +DEF_HELPER_1_2(iwmmxt_unpacklsw, uint64_t, (CPUState *, uint64_t)) +DEF_HELPER_1_2(iwmmxt_unpacklsl, uint64_t, (CPUState *, uint64_t)) +DEF_HELPER_1_2(iwmmxt_unpackhsb, uint64_t, (CPUState *, uint64_t)) +DEF_HELPER_1_2(iwmmxt_unpackhsw, uint64_t, (CPUState *, uint64_t)) +DEF_HELPER_1_2(iwmmxt_unpackhsl, uint64_t, (CPUState *, uint64_t)) + +DEF_IWMMXT_HELPER_SIZE_ENV(cmpeq) +DEF_IWMMXT_HELPER_SIZE_ENV(cmpgtu) +DEF_IWMMXT_HELPER_SIZE_ENV(cmpgts) + +DEF_IWMMXT_HELPER_SIZE_ENV(mins) +DEF_IWMMXT_HELPER_SIZE_ENV(minu) +DEF_IWMMXT_HELPER_SIZE_ENV(maxs) +DEF_IWMMXT_HELPER_SIZE_ENV(maxu) + +DEF_IWMMXT_HELPER_SIZE_ENV(subn) +DEF_IWMMXT_HELPER_SIZE_ENV(addn) +DEF_IWMMXT_HELPER_SIZE_ENV(subu) +DEF_IWMMXT_HELPER_SIZE_ENV(addu) +DEF_IWMMXT_HELPER_SIZE_ENV(subs) +DEF_IWMMXT_HELPER_SIZE_ENV(adds) + +DEF_HELPER_1_3(iwmmxt_avgb0, uint64_t, (CPUState *, uint64_t, uint64_t)) +DEF_HELPER_1_3(iwmmxt_avgb1, uint64_t, (CPUState *, uint64_t, uint64_t)) +DEF_HELPER_1_3(iwmmxt_avgw0, uint64_t, (CPUState *, uint64_t, uint64_t)) +DEF_HELPER_1_3(iwmmxt_avgw1, uint64_t, (CPUState *, uint64_t, uint64_t)) + +DEF_HELPER_1_2(iwmmxt_msadb, uint64_t, (uint64_t, uint64_t)) + +DEF_HELPER_1_3(iwmmxt_align, uint64_t, (uint64_t, uint64_t, uint32_t)) +DEF_HELPER_1_4(iwmmxt_insr, uint64_t, (uint64_t, uint32_t, uint32_t, uint32_t)) + +DEF_HELPER_1_1(iwmmxt_bcstb, uint64_t, (uint32_t)) +DEF_HELPER_1_1(iwmmxt_bcstw, uint64_t, (uint32_t)) +DEF_HELPER_1_1(iwmmxt_bcstl, uint64_t, (uint32_t)) + +DEF_HELPER_1_1(iwmmxt_addcb, uint64_t, (uint64_t)) +DEF_HELPER_1_1(iwmmxt_addcw, uint64_t, (uint64_t)) +DEF_HELPER_1_1(iwmmxt_addcl, uint64_t, (uint64_t)) + +DEF_HELPER_1_1(iwmmxt_msbb, uint32_t, (uint64_t)) +DEF_HELPER_1_1(iwmmxt_msbw, uint32_t, (uint64_t)) +DEF_HELPER_1_1(iwmmxt_msbl, uint32_t, (uint64_t)) + +DEF_HELPER_1_3(iwmmxt_srlw, uint64_t, (CPUState *, uint64_t, uint32_t)) +DEF_HELPER_1_3(iwmmxt_srll, uint64_t, (CPUState *, uint64_t, uint32_t)) +DEF_HELPER_1_3(iwmmxt_srlq, uint64_t, (CPUState *, uint64_t, uint32_t)) +DEF_HELPER_1_3(iwmmxt_sllw, uint64_t, (CPUState *, uint64_t, uint32_t)) +DEF_HELPER_1_3(iwmmxt_slll, uint64_t, (CPUState *, uint64_t, uint32_t)) +DEF_HELPER_1_3(iwmmxt_sllq, uint64_t, (CPUState *, uint64_t, uint32_t)) +DEF_HELPER_1_3(iwmmxt_sraw, uint64_t, (CPUState *, uint64_t, uint32_t)) +DEF_HELPER_1_3(iwmmxt_sral, uint64_t, (CPUState *, uint64_t, uint32_t)) +DEF_HELPER_1_3(iwmmxt_sraq, uint64_t, (CPUState *, uint64_t, uint32_t)) +DEF_HELPER_1_3(iwmmxt_rorw, uint64_t, (CPUState *, uint64_t, uint32_t)) +DEF_HELPER_1_3(iwmmxt_rorl, uint64_t, (CPUState *, uint64_t, uint32_t)) +DEF_HELPER_1_3(iwmmxt_rorq, uint64_t, (CPUState *, uint64_t, uint32_t)) +DEF_HELPER_1_3(iwmmxt_shufh, uint64_t, (CPUState *, uint64_t, uint32_t)) + +DEF_HELPER_1_3(iwmmxt_packuw, uint64_t, (CPUState *, uint64_t, uint64_t)) +DEF_HELPER_1_3(iwmmxt_packul, uint64_t, (CPUState *, uint64_t, uint64_t)) +DEF_HELPER_1_3(iwmmxt_packuq, uint64_t, (CPUState *, uint64_t, uint64_t)) +DEF_HELPER_1_3(iwmmxt_packsw, uint64_t, (CPUState *, uint64_t, uint64_t)) +DEF_HELPER_1_3(iwmmxt_packsl, uint64_t, (CPUState *, uint64_t, uint64_t)) +DEF_HELPER_1_3(iwmmxt_packsq, uint64_t, (CPUState *, uint64_t, uint64_t)) + +DEF_HELPER_1_3(iwmmxt_muladdsl, uint64_t, (uint64_t, uint32_t, uint32_t)) +DEF_HELPER_1_3(iwmmxt_muladdsw, uint64_t, (uint64_t, uint32_t, uint32_t)) +DEF_HELPER_1_3(iwmmxt_muladdswl, uint64_t, (uint64_t, uint32_t, uint32_t)) + +#undef DEF_HELPER +#undef DEF_HELPER_0_0 +#undef DEF_HELPER_0_1 +#undef DEF_HELPER_0_2 +#undef DEF_HELPER_1_0 +#undef DEF_HELPER_1_1 +#undef DEF_HELPER_1_2 +#undef DEF_HELPER_1_3 +#undef GEN_HELPER diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/iwmmxt_helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/iwmmxt_helper.c --- qemu-0.9.1/target-arm/iwmmxt_helper.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-arm/iwmmxt_helper.c 2008-03-31 04:49:05.000000000 +0100 @@ -0,0 +1,682 @@ +/* + * iwMMXt micro operations for XScale. + * + * Copyright (c) 2007 OpenedHand, Ltd. + * Written by Andrzej Zaborowski + * Copyright (c) 2008 CodeSourcery + * + * 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 +#include + +#include "cpu.h" +#include "exec-all.h" +#include "helpers.h" + +/* iwMMXt macros extracted from GNU gdb. */ + +/* Set the SIMD wCASF flags for 8, 16, 32 or 64-bit operations. */ +#define SIMD8_SET( v, n, b) ((v != 0) << ((((b) + 1) * 4) + (n))) +#define SIMD16_SET(v, n, h) ((v != 0) << ((((h) + 1) * 8) + (n))) +#define SIMD32_SET(v, n, w) ((v != 0) << ((((w) + 1) * 16) + (n))) +#define SIMD64_SET(v, n) ((v != 0) << (32 + (n))) +/* Flags to pass as "n" above. */ +#define SIMD_NBIT -1 +#define SIMD_ZBIT -2 +#define SIMD_CBIT -3 +#define SIMD_VBIT -4 +/* Various status bit macros. */ +#define NBIT8(x) ((x) & 0x80) +#define NBIT16(x) ((x) & 0x8000) +#define NBIT32(x) ((x) & 0x80000000) +#define NBIT64(x) ((x) & 0x8000000000000000ULL) +#define ZBIT8(x) (((x) & 0xff) == 0) +#define ZBIT16(x) (((x) & 0xffff) == 0) +#define ZBIT32(x) (((x) & 0xffffffff) == 0) +#define ZBIT64(x) (x == 0) +/* Sign extension macros. */ +#define EXTEND8H(a) ((uint16_t) (int8_t) (a)) +#define EXTEND8(a) ((uint32_t) (int8_t) (a)) +#define EXTEND16(a) ((uint32_t) (int16_t) (a)) +#define EXTEND16S(a) ((int32_t) (int16_t) (a)) +#define EXTEND32(a) ((uint64_t) (int32_t) (a)) + +uint64_t HELPER(iwmmxt_maddsq)(uint64_t a, uint64_t b) +{ + a = (( + EXTEND16S((a >> 0) & 0xffff) * EXTEND16S((b >> 0) & 0xffff) + + EXTEND16S((a >> 16) & 0xffff) * EXTEND16S((b >> 16) & 0xffff) + ) & 0xffffffff) | ((uint64_t) ( + EXTEND16S((a >> 32) & 0xffff) * EXTEND16S((b >> 32) & 0xffff) + + EXTEND16S((a >> 48) & 0xffff) * EXTEND16S((b >> 48) & 0xffff) + ) << 32); + return a; +} + +uint64_t HELPER(iwmmxt_madduq)(uint64_t a, uint64_t b) +{ + a = (( + ((a >> 0) & 0xffff) * ((b >> 0) & 0xffff) + + ((a >> 16) & 0xffff) * ((b >> 16) & 0xffff) + ) & 0xffffffff) | (( + ((a >> 32) & 0xffff) * ((b >> 32) & 0xffff) + + ((a >> 48) & 0xffff) * ((b >> 48) & 0xffff) + ) << 32); + return a; +} + +uint64_t HELPER(iwmmxt_sadb)(uint64_t a, uint64_t b) +{ +#define abs(x) (((x) >= 0) ? x : -x) +#define SADB(SHR) abs((int) ((a >> SHR) & 0xff) - (int) ((b >> SHR) & 0xff)) + return + SADB(0) + SADB(8) + SADB(16) + SADB(24) + + SADB(32) + SADB(40) + SADB(48) + SADB(56); +#undef SADB +} + +uint64_t HELPER(iwmmxt_sadw)(uint64_t a, uint64_t b) +{ +#define SADW(SHR) \ + abs((int) ((a >> SHR) & 0xffff) - (int) ((b >> SHR) & 0xffff)) + return SADW(0) + SADW(16) + SADW(32) + SADW(48); +#undef SADW +} + +uint64_t HELPER(iwmmxt_mulslw)(uint64_t a, uint64_t b) +{ +#define MULS(SHR) ((uint64_t) ((( \ + EXTEND16S((a >> SHR) & 0xffff) * EXTEND16S((b >> SHR) & 0xffff) \ + ) >> 0) & 0xffff) << SHR) + return MULS(0) | MULS(16) | MULS(32) | MULS(48); +#undef MULS +} + +uint64_t HELPER(iwmmxt_mulshw)(uint64_t a, uint64_t b) +{ +#define MULS(SHR) ((uint64_t) ((( \ + EXTEND16S((a >> SHR) & 0xffff) * EXTEND16S((b >> SHR) & 0xffff) \ + ) >> 16) & 0xffff) << SHR) + return MULS(0) | MULS(16) | MULS(32) | MULS(48); +#undef MULS +} + +uint64_t HELPER(iwmmxt_mululw)(uint64_t a, uint64_t b) +{ +#define MULU(SHR) ((uint64_t) ((( \ + ((a >> SHR) & 0xffff) * ((b >> SHR) & 0xffff) \ + ) >> 0) & 0xffff) << SHR) + return MULU(0) | MULU(16) | MULU(32) | MULU(48); +#undef MULU +} + +uint64_t HELPER(iwmmxt_muluhw)(uint64_t a, uint64_t b) +{ +#define MULU(SHR) ((uint64_t) ((( \ + ((a >> SHR) & 0xffff) * ((b >> SHR) & 0xffff) \ + ) >> 16) & 0xffff) << SHR) + return MULU(0) | MULU(16) | MULU(32) | MULU(48); +#undef MULU +} + +uint64_t HELPER(iwmmxt_macsw)(uint64_t a, uint64_t b) +{ +#define MACS(SHR) ( \ + EXTEND16((a >> SHR) & 0xffff) * EXTEND16S((b >> SHR) & 0xffff)) + return (int64_t) (MACS(0) + MACS(16) + MACS(32) + MACS(48)); +#undef MACS +} + +uint64_t HELPER(iwmmxt_macuw)(uint64_t a, uint64_t b) +{ +#define MACU(SHR) ( \ + (uint32_t) ((a >> SHR) & 0xffff) * \ + (uint32_t) ((b >> SHR) & 0xffff)) + return MACU(0) + MACU(16) + MACU(32) + MACU(48); +#undef MACU +} + +#define NZBIT8(x, i) \ + SIMD8_SET(NBIT8((x) & 0xff), SIMD_NBIT, i) | \ + SIMD8_SET(ZBIT8((x) & 0xff), SIMD_ZBIT, i) +#define NZBIT16(x, i) \ + SIMD16_SET(NBIT16((x) & 0xffff), SIMD_NBIT, i) | \ + SIMD16_SET(ZBIT16((x) & 0xffff), SIMD_ZBIT, i) +#define NZBIT32(x, i) \ + SIMD32_SET(NBIT32((x) & 0xffffffff), SIMD_NBIT, i) | \ + SIMD32_SET(ZBIT32((x) & 0xffffffff), SIMD_ZBIT, i) +#define NZBIT64(x) \ + SIMD64_SET(NBIT64(x), SIMD_NBIT) | \ + SIMD64_SET(ZBIT64(x), SIMD_ZBIT) +#define IWMMXT_OP_UNPACK(S, SH0, SH1, SH2, SH3) \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, b)))(CPUState *env, \ + uint64_t a, uint64_t b) \ +{ \ + a = \ + (((a >> SH0) & 0xff) << 0) | (((b >> SH0) & 0xff) << 8) | \ + (((a >> SH1) & 0xff) << 16) | (((b >> SH1) & 0xff) << 24) | \ + (((a >> SH2) & 0xff) << 32) | (((b >> SH2) & 0xff) << 40) | \ + (((a >> SH3) & 0xff) << 48) | (((b >> SH3) & 0xff) << 56); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | \ + NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | \ + NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | \ + NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); \ + return a; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, w)))(CPUState *env, \ + uint64_t a, uint64_t b) \ +{ \ + a = \ + (((a >> SH0) & 0xffff) << 0) | \ + (((b >> SH0) & 0xffff) << 16) | \ + (((a >> SH2) & 0xffff) << 32) | \ + (((b >> SH2) & 0xffff) << 48); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT8(a >> 0, 0) | NZBIT8(a >> 16, 1) | \ + NZBIT8(a >> 32, 2) | NZBIT8(a >> 48, 3); \ + return a; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, l)))(CPUState *env, \ + uint64_t a, uint64_t b) \ +{ \ + a = \ + (((a >> SH0) & 0xffffffff) << 0) | \ + (((b >> SH0) & 0xffffffff) << 32); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); \ + return a; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ub)))(CPUState *env, \ + uint64_t x) \ +{ \ + x = \ + (((x >> SH0) & 0xff) << 0) | \ + (((x >> SH1) & 0xff) << 16) | \ + (((x >> SH2) & 0xff) << 32) | \ + (((x >> SH3) & 0xff) << 48); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | \ + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); \ + return x; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, uw)))(CPUState *env, \ + uint64_t x) \ +{ \ + x = \ + (((x >> SH0) & 0xffff) << 0) | \ + (((x >> SH2) & 0xffff) << 32); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); \ + return x; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ul)))(CPUState *env, \ + uint64_t x) \ +{ \ + x = (((x >> SH0) & 0xffffffff) << 0); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0); \ + return x; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sb)))(CPUState *env, \ + uint64_t x) \ +{ \ + x = \ + ((uint64_t) EXTEND8H((x >> SH0) & 0xff) << 0) | \ + ((uint64_t) EXTEND8H((x >> SH1) & 0xff) << 16) | \ + ((uint64_t) EXTEND8H((x >> SH2) & 0xff) << 32) | \ + ((uint64_t) EXTEND8H((x >> SH3) & 0xff) << 48); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | \ + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); \ + return x; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sw)))(CPUState *env, \ + uint64_t x) \ +{ \ + x = \ + ((uint64_t) EXTEND16((x >> SH0) & 0xffff) << 0) | \ + ((uint64_t) EXTEND16((x >> SH2) & 0xffff) << 32); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); \ + return x; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sl)))(CPUState *env, \ + uint64_t x) \ +{ \ + x = EXTEND32((x >> SH0) & 0xffffffff); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0); \ + return x; \ +} +IWMMXT_OP_UNPACK(l, 0, 8, 16, 24) +IWMMXT_OP_UNPACK(h, 32, 40, 48, 56) + +#define IWMMXT_OP_CMP(SUFF, Tb, Tw, Tl, O) \ +uint64_t HELPER(glue(iwmmxt_, glue(SUFF, b)))(CPUState *env, \ + uint64_t a, uint64_t b) \ +{ \ + a = \ + CMP(0, Tb, O, 0xff) | CMP(8, Tb, O, 0xff) | \ + CMP(16, Tb, O, 0xff) | CMP(24, Tb, O, 0xff) | \ + CMP(32, Tb, O, 0xff) | CMP(40, Tb, O, 0xff) | \ + CMP(48, Tb, O, 0xff) | CMP(56, Tb, O, 0xff); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | \ + NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | \ + NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | \ + NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); \ + return a; \ +} \ +uint64_t HELPER(glue(iwmmxt_, glue(SUFF, w)))(CPUState *env, \ + uint64_t a, uint64_t b) \ +{ \ + a = CMP(0, Tw, O, 0xffff) | CMP(16, Tw, O, 0xffff) | \ + CMP(32, Tw, O, 0xffff) | CMP(48, Tw, O, 0xffff); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) | \ + NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3); \ + return a; \ +} \ +uint64_t HELPER(glue(iwmmxt_, glue(SUFF, l)))(CPUState *env, \ + uint64_t a, uint64_t b) \ +{ \ + a = CMP(0, Tl, O, 0xffffffff) | \ + CMP(32, Tl, O, 0xffffffff); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); \ + return a; \ +} +#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((a >> SHR) & MASK) OPER \ + (TYPE) ((b >> SHR) & MASK)) ? (uint64_t) MASK : 0) << SHR) +IWMMXT_OP_CMP(cmpeq, uint8_t, uint16_t, uint32_t, ==) +IWMMXT_OP_CMP(cmpgts, int8_t, int16_t, int32_t, >) +IWMMXT_OP_CMP(cmpgtu, uint8_t, uint16_t, uint32_t, >) +#undef CMP +#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((a >> SHR) & MASK) OPER \ + (TYPE) ((b >> SHR) & MASK)) ? a : b) & ((uint64_t) MASK << SHR)) +IWMMXT_OP_CMP(mins, int8_t, int16_t, int32_t, <) +IWMMXT_OP_CMP(minu, uint8_t, uint16_t, uint32_t, <) +IWMMXT_OP_CMP(maxs, int8_t, int16_t, int32_t, >) +IWMMXT_OP_CMP(maxu, uint8_t, uint16_t, uint32_t, >) +#undef CMP +#define CMP(SHR, TYPE, OPER, MASK) ((uint64_t) (((TYPE) ((a >> SHR) & MASK) \ + OPER (TYPE) ((b >> SHR) & MASK)) & MASK) << SHR) +IWMMXT_OP_CMP(subn, uint8_t, uint16_t, uint32_t, -) +IWMMXT_OP_CMP(addn, uint8_t, uint16_t, uint32_t, +) +#undef CMP +/* TODO Signed- and Unsigned-Saturation */ +#define CMP(SHR, TYPE, OPER, MASK) ((uint64_t) (((TYPE) ((a >> SHR) & MASK) \ + OPER (TYPE) ((b >> SHR) & MASK)) & MASK) << SHR) +IWMMXT_OP_CMP(subu, uint8_t, uint16_t, uint32_t, -) +IWMMXT_OP_CMP(addu, uint8_t, uint16_t, uint32_t, +) +IWMMXT_OP_CMP(subs, int8_t, int16_t, int32_t, -) +IWMMXT_OP_CMP(adds, int8_t, int16_t, int32_t, +) +#undef CMP +#undef IWMMXT_OP_CMP + +#define AVGB(SHR) ((( \ + ((a >> SHR) & 0xff) + ((b >> SHR) & 0xff) + round) >> 1) << SHR) +#define IWMMXT_OP_AVGB(r) \ +uint64_t HELPER(iwmmxt_avgb##r)(CPUState *env, uint64_t a, uint64_t b) \ +{ \ + const int round = r; \ + a = AVGB(0) | AVGB(8) | AVGB(16) | AVGB(24) | \ + AVGB(32) | AVGB(40) | AVGB(48) | AVGB(56); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + SIMD8_SET(ZBIT8((a >> 0) & 0xff), SIMD_ZBIT, 0) | \ + SIMD8_SET(ZBIT8((a >> 8) & 0xff), SIMD_ZBIT, 1) | \ + SIMD8_SET(ZBIT8((a >> 16) & 0xff), SIMD_ZBIT, 2) | \ + SIMD8_SET(ZBIT8((a >> 24) & 0xff), SIMD_ZBIT, 3) | \ + SIMD8_SET(ZBIT8((a >> 32) & 0xff), SIMD_ZBIT, 4) | \ + SIMD8_SET(ZBIT8((a >> 40) & 0xff), SIMD_ZBIT, 5) | \ + SIMD8_SET(ZBIT8((a >> 48) & 0xff), SIMD_ZBIT, 6) | \ + SIMD8_SET(ZBIT8((a >> 56) & 0xff), SIMD_ZBIT, 7); \ + return a; \ +} +IWMMXT_OP_AVGB(0) +IWMMXT_OP_AVGB(1) +#undef IWMMXT_OP_AVGB +#undef AVGB + +#define AVGW(SHR) ((( \ + ((a >> SHR) & 0xffff) + ((b >> SHR) & 0xffff) + round) >> 1) << SHR) +#define IWMMXT_OP_AVGW(r) \ +uint64_t HELPER(iwmmxt_avgw##r)(CPUState *env, uint64_t a, uint64_t b) \ +{ \ + const int round = r; \ + a = AVGW(0) | AVGW(16) | AVGW(32) | AVGW(48); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + SIMD16_SET(ZBIT16((a >> 0) & 0xffff), SIMD_ZBIT, 0) | \ + SIMD16_SET(ZBIT16((a >> 16) & 0xffff), SIMD_ZBIT, 1) | \ + SIMD16_SET(ZBIT16((a >> 32) & 0xffff), SIMD_ZBIT, 2) | \ + SIMD16_SET(ZBIT16((a >> 48) & 0xffff), SIMD_ZBIT, 3); \ + return a; \ +} +IWMMXT_OP_AVGW(0) +IWMMXT_OP_AVGW(1) +#undef IWMMXT_OP_AVGW +#undef AVGW + +uint64_t HELPER(iwmmxt_msadb)(uint64_t a, uint64_t b) +{ + a = ((((a >> 0 ) & 0xffff) * ((b >> 0) & 0xffff) + + ((a >> 16) & 0xffff) * ((b >> 16) & 0xffff)) & 0xffffffff) | + ((((a >> 32) & 0xffff) * ((b >> 32) & 0xffff) + + ((a >> 48) & 0xffff) * ((b >> 48) & 0xffff)) << 32); + return a; +} + +uint64_t HELPER(iwmmxt_align)(uint64_t a, uint64_t b, uint32_t n) +{ + a >>= n << 3; + a |= b << (64 - (n << 3)); + return a; +} + +uint64_t HELPER(iwmmxt_insr)(uint64_t x, uint32_t a, uint32_t b, uint32_t n) +{ + x &= ~((uint64_t) b << n); + x |= (uint64_t) (a & b) << n; + return x; +} + +uint32_t HELPER(iwmmxt_setpsr_nz)(uint64_t x) +{ + return SIMD64_SET((x == 0), SIMD_ZBIT) | + SIMD64_SET((x & (1ULL << 63)), SIMD_NBIT); +} + +uint64_t HELPER(iwmmxt_bcstb)(uint32_t arg) +{ + arg &= 0xff; + return + ((uint64_t) arg << 0 ) | ((uint64_t) arg << 8 ) | + ((uint64_t) arg << 16) | ((uint64_t) arg << 24) | + ((uint64_t) arg << 32) | ((uint64_t) arg << 40) | + ((uint64_t) arg << 48) | ((uint64_t) arg << 56); +} + +uint64_t HELPER(iwmmxt_bcstw)(uint32_t arg) +{ + arg &= 0xffff; + return + ((uint64_t) arg << 0 ) | ((uint64_t) arg << 16) | + ((uint64_t) arg << 32) | ((uint64_t) arg << 48); +} + +uint64_t HELPER(iwmmxt_bcstl)(uint32_t arg) +{ + return arg | ((uint64_t) arg << 32); +} + +uint64_t HELPER(iwmmxt_addcb)(uint64_t x) +{ + return + ((x >> 0) & 0xff) + ((x >> 8) & 0xff) + + ((x >> 16) & 0xff) + ((x >> 24) & 0xff) + + ((x >> 32) & 0xff) + ((x >> 40) & 0xff) + + ((x >> 48) & 0xff) + ((x >> 56) & 0xff); +} + +uint64_t HELPER(iwmmxt_addcw)(uint64_t x) +{ + return + ((x >> 0) & 0xffff) + ((x >> 16) & 0xffff) + + ((x >> 32) & 0xffff) + ((x >> 48) & 0xffff); +} + +uint64_t HELPER(iwmmxt_addcl)(uint64_t x) +{ + return (x & 0xffffffff) + (x >> 32); +} + +uint32_t HELPER(iwmmxt_msbb)(uint64_t x) +{ + return + ((x >> 7) & 0x01) | ((x >> 14) & 0x02) | + ((x >> 21) & 0x04) | ((x >> 28) & 0x08) | + ((x >> 35) & 0x10) | ((x >> 42) & 0x20) | + ((x >> 49) & 0x40) | ((x >> 56) & 0x80); +} + +uint32_t HELPER(iwmmxt_msbw)(uint64_t x) +{ + return + ((x >> 15) & 0x01) | ((x >> 30) & 0x02) | + ((x >> 45) & 0x04) | ((x >> 52) & 0x08); +} + +uint32_t HELPER(iwmmxt_msbl)(uint64_t x) +{ + return ((x >> 31) & 0x01) | ((x >> 62) & 0x02); +} + +/* FIXME: Split wCASF setting into a separate op to avoid env use. */ +uint64_t HELPER(iwmmxt_srlw)(CPUState *env, uint64_t x, uint32_t n) +{ + x = (((x & (0xffffll << 0)) >> n) & (0xffffll << 0)) | + (((x & (0xffffll << 16)) >> n) & (0xffffll << 16)) | + (((x & (0xffffll << 32)) >> n) & (0xffffll << 32)) | + (((x & (0xffffll << 48)) >> n) & (0xffffll << 48)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); + return x; +} + +uint64_t HELPER(iwmmxt_srll)(CPUState *env, uint64_t x, uint32_t n) +{ + x = ((x & (0xffffffffll << 0)) >> n) | + ((x >> n) & (0xffffffffll << 32)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); + return x; +} + +uint64_t HELPER(iwmmxt_srlq)(CPUState *env, uint64_t x, uint32_t n) +{ + x >>= n; + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x); + return x; +} + +uint64_t HELPER(iwmmxt_sllw)(CPUState *env, uint64_t x, uint32_t n) +{ + x = (((x & (0xffffll << 0)) << n) & (0xffffll << 0)) | + (((x & (0xffffll << 16)) << n) & (0xffffll << 16)) | + (((x & (0xffffll << 32)) << n) & (0xffffll << 32)) | + (((x & (0xffffll << 48)) << n) & (0xffffll << 48)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); + return x; +} + +uint64_t HELPER(iwmmxt_slll)(CPUState *env, uint64_t x, uint32_t n) +{ + x = ((x << n) & (0xffffffffll << 0)) | + ((x & (0xffffffffll << 32)) << n); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); + return x; +} + +uint64_t HELPER(iwmmxt_sllq)(CPUState *env, uint64_t x, uint32_t n) +{ + x <<= n; + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x); + return x; +} + +uint64_t HELPER(iwmmxt_sraw)(CPUState *env, uint64_t x, uint32_t n) +{ + x = ((uint64_t) ((EXTEND16(x >> 0) >> n) & 0xffff) << 0) | + ((uint64_t) ((EXTEND16(x >> 16) >> n) & 0xffff) << 16) | + ((uint64_t) ((EXTEND16(x >> 32) >> n) & 0xffff) << 32) | + ((uint64_t) ((EXTEND16(x >> 48) >> n) & 0xffff) << 48); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); + return x; +} + +uint64_t HELPER(iwmmxt_sral)(CPUState *env, uint64_t x, uint32_t n) +{ + x = (((EXTEND32(x >> 0) >> n) & 0xffffffff) << 0) | + (((EXTEND32(x >> 32) >> n) & 0xffffffff) << 32); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); + return x; +} + +uint64_t HELPER(iwmmxt_sraq)(CPUState *env, uint64_t x, uint32_t n) +{ + x = (int64_t) x >> n; + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x); + return x; +} + +uint64_t HELPER(iwmmxt_rorw)(CPUState *env, uint64_t x, uint32_t n) +{ + x = ((((x & (0xffffll << 0)) >> n) | + ((x & (0xffffll << 0)) << (16 - n))) & (0xffffll << 0)) | + ((((x & (0xffffll << 16)) >> n) | + ((x & (0xffffll << 16)) << (16 - n))) & (0xffffll << 16)) | + ((((x & (0xffffll << 32)) >> n) | + ((x & (0xffffll << 32)) << (16 - n))) & (0xffffll << 32)) | + ((((x & (0xffffll << 48)) >> n) | + ((x & (0xffffll << 48)) << (16 - n))) & (0xffffll << 48)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); + return x; +} + +uint64_t HELPER(iwmmxt_rorl)(CPUState *env, uint64_t x, uint32_t n) +{ + x = ((x & (0xffffffffll << 0)) >> n) | + ((x >> n) & (0xffffffffll << 32)) | + ((x << (32 - n)) & (0xffffffffll << 0)) | + ((x & (0xffffffffll << 32)) << (32 - n)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); + return x; +} + +uint64_t HELPER(iwmmxt_rorq)(CPUState *env, uint64_t x, uint32_t n) +{ + x = (x >> n) | (x << (64 - n)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x); + return x; +} + +uint64_t HELPER(iwmmxt_shufh)(CPUState *env, uint64_t x, uint32_t n) +{ + x = (((x >> ((n << 4) & 0x30)) & 0xffff) << 0) | + (((x >> ((n << 2) & 0x30)) & 0xffff) << 16) | + (((x >> ((n << 0) & 0x30)) & 0xffff) << 32) | + (((x >> ((n >> 2) & 0x30)) & 0xffff) << 48); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); + return x; +} + +/* TODO: Unsigned-Saturation */ +uint64_t HELPER(iwmmxt_packuw)(CPUState *env, uint64_t a, uint64_t b) +{ + a = (((a >> 0) & 0xff) << 0) | (((a >> 16) & 0xff) << 8) | + (((a >> 32) & 0xff) << 16) | (((a >> 48) & 0xff) << 24) | + (((b >> 0) & 0xff) << 32) | (((b >> 16) & 0xff) << 40) | + (((b >> 32) & 0xff) << 48) | (((b >> 48) & 0xff) << 56); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | + NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | + NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | + NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); + return a; +} + +uint64_t HELPER(iwmmxt_packul)(CPUState *env, uint64_t a, uint64_t b) +{ + a = (((a >> 0) & 0xffff) << 0) | (((a >> 32) & 0xffff) << 16) | + (((b >> 0) & 0xffff) << 32) | (((b >> 32) & 0xffff) << 48); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) | + NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3); + return a; +} + +uint64_t HELPER(iwmmxt_packuq)(CPUState *env, uint64_t a, uint64_t b) +{ + a = (a & 0xffffffff) | ((b & 0xffffffff) << 32); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); + return a; +} + +/* TODO: Signed-Saturation */ +uint64_t HELPER(iwmmxt_packsw)(CPUState *env, uint64_t a, uint64_t b) +{ + a = (((a >> 0) & 0xff) << 0) | (((a >> 16) & 0xff) << 8) | + (((a >> 32) & 0xff) << 16) | (((a >> 48) & 0xff) << 24) | + (((b >> 0) & 0xff) << 32) | (((b >> 16) & 0xff) << 40) | + (((b >> 32) & 0xff) << 48) | (((b >> 48) & 0xff) << 56); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | + NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | + NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | + NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); + return a; +} + +uint64_t HELPER(iwmmxt_packsl)(CPUState *env, uint64_t a, uint64_t b) +{ + a = (((a >> 0) & 0xffff) << 0) | (((a >> 32) & 0xffff) << 16) | + (((b >> 0) & 0xffff) << 32) | (((b >> 32) & 0xffff) << 48); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) | + NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3); + return a; +} + +uint64_t HELPER(iwmmxt_packsq)(CPUState *env, uint64_t a, uint64_t b) +{ + a = (a & 0xffffffff) | ((b & 0xffffffff) << 32); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); + return a; +} + +uint64_t HELPER(iwmmxt_muladdsl)(uint64_t c, uint32_t a, uint32_t b) +{ + return c + ((int32_t) EXTEND32(a) * (int32_t) EXTEND32(b)); +} + +uint64_t HELPER(iwmmxt_muladdsw)(uint64_t c, uint32_t a, uint32_t b) +{ + c += EXTEND32(EXTEND16S((a >> 0) & 0xffff) * + EXTEND16S((b >> 0) & 0xffff)); + c += EXTEND32(EXTEND16S((a >> 16) & 0xffff) * + EXTEND16S((b >> 16) & 0xffff)); + return c; +} + +uint64_t HELPER(iwmmxt_muladdswl)(uint64_t c, uint32_t a, uint32_t b) +{ + return c + (EXTEND32(EXTEND16S(a & 0xffff) * + EXTEND16S(b & 0xffff))); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/machine.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/machine.c --- qemu-0.9.1/target-arm/machine.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-arm/machine.c 2008-06-30 17:31:04.000000000 +0100 @@ -0,0 +1,215 @@ +#include "hw/hw.h" +#include "hw/boards.h" + +void register_machines(void) +{ + qemu_register_machine(&integratorcp_machine); + qemu_register_machine(&versatilepb_machine); + qemu_register_machine(&versatileab_machine); + qemu_register_machine(&realview_machine); + qemu_register_machine(&akitapda_machine); + qemu_register_machine(&spitzpda_machine); + qemu_register_machine(&borzoipda_machine); + qemu_register_machine(&terrierpda_machine); + qemu_register_machine(&palmte_machine); + qemu_register_machine(&n800_machine); + qemu_register_machine(&n810_machine); + qemu_register_machine(&lm3s811evb_machine); + qemu_register_machine(&lm3s6965evb_machine); + qemu_register_machine(&connex_machine); + qemu_register_machine(&verdex_machine); + qemu_register_machine(&mainstone2_machine); + qemu_register_machine(&musicpal_machine); + qemu_register_machine(&tosapda_machine); +} + +void cpu_save(QEMUFile *f, void *opaque) +{ + int i; + CPUARMState *env = (CPUARMState *)opaque; + + for (i = 0; i < 16; i++) { + qemu_put_be32(f, env->regs[i]); + } + qemu_put_be32(f, cpsr_read(env)); + qemu_put_be32(f, env->spsr); + for (i = 0; i < 6; i++) { + qemu_put_be32(f, env->banked_spsr[i]); + qemu_put_be32(f, env->banked_r13[i]); + qemu_put_be32(f, env->banked_r14[i]); + } + for (i = 0; i < 5; i++) { + qemu_put_be32(f, env->usr_regs[i]); + qemu_put_be32(f, env->fiq_regs[i]); + } + qemu_put_be32(f, env->cp15.c0_cpuid); + qemu_put_be32(f, env->cp15.c0_cachetype); + qemu_put_be32(f, env->cp15.c1_sys); + qemu_put_be32(f, env->cp15.c1_coproc); + qemu_put_be32(f, env->cp15.c1_xscaleauxcr); + qemu_put_be32(f, env->cp15.c2_base0); + qemu_put_be32(f, env->cp15.c2_base1); + qemu_put_be32(f, env->cp15.c2_mask); + qemu_put_be32(f, env->cp15.c2_data); + qemu_put_be32(f, env->cp15.c2_insn); + qemu_put_be32(f, env->cp15.c3); + qemu_put_be32(f, env->cp15.c5_insn); + qemu_put_be32(f, env->cp15.c5_data); + for (i = 0; i < 8; i++) { + qemu_put_be32(f, env->cp15.c6_region[i]); + } + qemu_put_be32(f, env->cp15.c6_insn); + qemu_put_be32(f, env->cp15.c6_data); + qemu_put_be32(f, env->cp15.c9_insn); + qemu_put_be32(f, env->cp15.c9_data); + qemu_put_be32(f, env->cp15.c13_fcse); + qemu_put_be32(f, env->cp15.c13_context); + qemu_put_be32(f, env->cp15.c13_tls1); + qemu_put_be32(f, env->cp15.c13_tls2); + qemu_put_be32(f, env->cp15.c13_tls3); + qemu_put_be32(f, env->cp15.c15_cpar); + + qemu_put_be32(f, env->features); + + if (arm_feature(env, ARM_FEATURE_VFP)) { + for (i = 0; i < 16; i++) { + CPU_DoubleU u; + u.d = env->vfp.regs[i]; + qemu_put_be32(f, u.l.upper); + qemu_put_be32(f, u.l.lower); + } + for (i = 0; i < 16; i++) { + qemu_put_be32(f, env->vfp.xregs[i]); + } + + /* TODO: Should use proper FPSCR access functions. */ + qemu_put_be32(f, env->vfp.vec_len); + qemu_put_be32(f, env->vfp.vec_stride); + + if (arm_feature(env, ARM_FEATURE_VFP3)) { + for (i = 16; i < 32; i++) { + CPU_DoubleU u; + u.d = env->vfp.regs[i]; + qemu_put_be32(f, u.l.upper); + qemu_put_be32(f, u.l.lower); + } + } + } + + if (arm_feature(env, ARM_FEATURE_IWMMXT)) { + for (i = 0; i < 16; i++) { + qemu_put_be64(f, env->iwmmxt.regs[i]); + } + for (i = 0; i < 16; i++) { + qemu_put_be32(f, env->iwmmxt.cregs[i]); + } + } + + if (arm_feature(env, ARM_FEATURE_M)) { + qemu_put_be32(f, env->v7m.other_sp); + qemu_put_be32(f, env->v7m.vecbase); + qemu_put_be32(f, env->v7m.basepri); + qemu_put_be32(f, env->v7m.control); + qemu_put_be32(f, env->v7m.current_sp); + qemu_put_be32(f, env->v7m.exception); + } +} + +int cpu_load(QEMUFile *f, void *opaque, int version_id) +{ + CPUARMState *env = (CPUARMState *)opaque; + int i; + + if (version_id != CPU_SAVE_VERSION) + return -EINVAL; + + for (i = 0; i < 16; i++) { + env->regs[i] = qemu_get_be32(f); + } + cpsr_write(env, qemu_get_be32(f), 0xffffffff); + env->spsr = qemu_get_be32(f); + for (i = 0; i < 6; i++) { + env->banked_spsr[i] = qemu_get_be32(f); + env->banked_r13[i] = qemu_get_be32(f); + env->banked_r14[i] = qemu_get_be32(f); + } + for (i = 0; i < 5; i++) { + env->usr_regs[i] = qemu_get_be32(f); + env->fiq_regs[i] = qemu_get_be32(f); + } + env->cp15.c0_cpuid = qemu_get_be32(f); + env->cp15.c0_cachetype = qemu_get_be32(f); + env->cp15.c1_sys = qemu_get_be32(f); + env->cp15.c1_coproc = qemu_get_be32(f); + env->cp15.c1_xscaleauxcr = qemu_get_be32(f); + env->cp15.c2_base0 = qemu_get_be32(f); + env->cp15.c2_base1 = qemu_get_be32(f); + env->cp15.c2_mask = qemu_get_be32(f); + env->cp15.c2_data = qemu_get_be32(f); + env->cp15.c2_insn = qemu_get_be32(f); + env->cp15.c3 = qemu_get_be32(f); + env->cp15.c5_insn = qemu_get_be32(f); + env->cp15.c5_data = qemu_get_be32(f); + for (i = 0; i < 8; i++) { + env->cp15.c6_region[i] = qemu_get_be32(f); + } + env->cp15.c6_insn = qemu_get_be32(f); + env->cp15.c6_data = qemu_get_be32(f); + env->cp15.c9_insn = qemu_get_be32(f); + env->cp15.c9_data = qemu_get_be32(f); + env->cp15.c13_fcse = qemu_get_be32(f); + env->cp15.c13_context = qemu_get_be32(f); + env->cp15.c13_tls1 = qemu_get_be32(f); + env->cp15.c13_tls2 = qemu_get_be32(f); + env->cp15.c13_tls3 = qemu_get_be32(f); + env->cp15.c15_cpar = qemu_get_be32(f); + + env->features = qemu_get_be32(f); + + if (arm_feature(env, ARM_FEATURE_VFP)) { + for (i = 0; i < 16; i++) { + CPU_DoubleU u; + u.l.upper = qemu_get_be32(f); + u.l.lower = qemu_get_be32(f); + env->vfp.regs[i] = u.d; + } + for (i = 0; i < 16; i++) { + env->vfp.xregs[i] = qemu_get_be32(f); + } + + /* TODO: Should use proper FPSCR access functions. */ + env->vfp.vec_len = qemu_get_be32(f); + env->vfp.vec_stride = qemu_get_be32(f); + + if (arm_feature(env, ARM_FEATURE_VFP3)) { + for (i = 0; i < 16; i++) { + CPU_DoubleU u; + u.l.upper = qemu_get_be32(f); + u.l.lower = qemu_get_be32(f); + env->vfp.regs[i] = u.d; + } + } + } + + if (arm_feature(env, ARM_FEATURE_IWMMXT)) { + for (i = 0; i < 16; i++) { + env->iwmmxt.regs[i] = qemu_get_be64(f); + } + for (i = 0; i < 16; i++) { + env->iwmmxt.cregs[i] = qemu_get_be32(f); + } + } + + if (arm_feature(env, ARM_FEATURE_M)) { + env->v7m.other_sp = qemu_get_be32(f); + env->v7m.vecbase = qemu_get_be32(f); + env->v7m.basepri = qemu_get_be32(f); + env->v7m.control = qemu_get_be32(f); + env->v7m.current_sp = qemu_get_be32(f); + env->v7m.exception = qemu_get_be32(f); + } + + return 0; +} + + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/neon_helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/neon_helper.c --- qemu-0.9.1/target-arm/neon_helper.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-arm/neon_helper.c 2008-04-11 05:55:07.000000000 +0100 @@ -0,0 +1,1457 @@ +/* + * ARM NEON vector operations. + * + * Copyright (c) 2007, 2008 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GNU GPL v2. + */ +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "helpers.h" + +#define SIGNBIT (uint32_t)0x80000000 +#define SIGNBIT64 ((uint64_t)1 << 63) + +#define SET_QC() env->vfp.xregs[ARM_VFP_FPSCR] = CPSR_Q + +static float_status neon_float_status; +#define NFS &neon_float_status + +/* Helper routines to perform bitwise copies between float and int. */ +static inline float32 vfp_itos(uint32_t i) +{ + union { + uint32_t i; + float32 s; + } v; + + v.i = i; + return v.s; +} + +static inline uint32_t vfp_stoi(float32 s) +{ + union { + uint32_t i; + float32 s; + } v; + + v.s = s; + return v.i; +} + +#define NEON_TYPE1(name, type) \ +typedef struct \ +{ \ + type v1; \ +} neon_##name; +#ifdef WORDS_BIGENDIAN +#define NEON_TYPE2(name, type) \ +typedef struct \ +{ \ + type v2; \ + type v1; \ +} neon_##name; +#define NEON_TYPE4(name, type) \ +typedef struct \ +{ \ + type v4; \ + type v3; \ + type v2; \ + type v1; \ +} neon_##name; +#else +#define NEON_TYPE2(name, type) \ +typedef struct \ +{ \ + type v1; \ + type v2; \ +} neon_##name; +#define NEON_TYPE4(name, type) \ +typedef struct \ +{ \ + type v1; \ + type v2; \ + type v3; \ + type v4; \ +} neon_##name; +#endif + +NEON_TYPE4(s8, int8_t) +NEON_TYPE4(u8, uint8_t) +NEON_TYPE2(s16, int16_t) +NEON_TYPE2(u16, uint16_t) +NEON_TYPE1(s32, int32_t) +NEON_TYPE1(u32, uint32_t) +#undef NEON_TYPE4 +#undef NEON_TYPE2 +#undef NEON_TYPE1 + +/* Copy from a uint32_t to a vector structure type. */ +#define NEON_UNPACK(vtype, dest, val) do { \ + union { \ + vtype v; \ + uint32_t i; \ + } conv_u; \ + conv_u.i = (val); \ + dest = conv_u.v; \ + } while(0) + +/* Copy from a vector structure type to a uint32_t. */ +#define NEON_PACK(vtype, dest, val) do { \ + union { \ + vtype v; \ + uint32_t i; \ + } conv_u; \ + conv_u.v = (val); \ + dest = conv_u.i; \ + } while(0) + +#define NEON_DO1 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); +#define NEON_DO2 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); \ + NEON_FN(vdest.v2, vsrc1.v2, vsrc2.v2); +#define NEON_DO4 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); \ + NEON_FN(vdest.v2, vsrc1.v2, vsrc2.v2); \ + NEON_FN(vdest.v3, vsrc1.v3, vsrc2.v3); \ + NEON_FN(vdest.v4, vsrc1.v4, vsrc2.v4); + +#define NEON_VOP_BODY(vtype, n) \ +{ \ + uint32_t res; \ + vtype vsrc1; \ + vtype vsrc2; \ + vtype vdest; \ + NEON_UNPACK(vtype, vsrc1, arg1); \ + NEON_UNPACK(vtype, vsrc2, arg2); \ + NEON_DO##n; \ + NEON_PACK(vtype, res, vdest); \ + return res; \ +} + +#define NEON_VOP(name, vtype, n) \ +uint32_t HELPER(glue(neon_,name))(uint32_t arg1, uint32_t arg2) \ +NEON_VOP_BODY(vtype, n) + +#define NEON_VOP_ENV(name, vtype, n) \ +uint32_t HELPER(glue(neon_,name))(CPUState *env, uint32_t arg1, uint32_t arg2) \ +NEON_VOP_BODY(vtype, n) + +/* Pairwise operations. */ +/* For 32-bit elements each segment only contains a single element, so + the elementwise and pairwise operations are the same. */ +#define NEON_PDO2 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc1.v2); \ + NEON_FN(vdest.v2, vsrc2.v1, vsrc2.v2); +#define NEON_PDO4 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc1.v2); \ + NEON_FN(vdest.v2, vsrc1.v3, vsrc1.v4); \ + NEON_FN(vdest.v3, vsrc2.v1, vsrc2.v2); \ + NEON_FN(vdest.v4, vsrc2.v3, vsrc2.v4); \ + +#define NEON_POP(name, vtype, n) \ +uint32_t HELPER(glue(neon_,name))(uint32_t arg1, uint32_t arg2) \ +{ \ + uint32_t res; \ + vtype vsrc1; \ + vtype vsrc2; \ + vtype vdest; \ + NEON_UNPACK(vtype, vsrc1, arg1); \ + NEON_UNPACK(vtype, vsrc2, arg2); \ + NEON_PDO##n; \ + NEON_PACK(vtype, res, vdest); \ + return res; \ +} + +/* Unary operators. */ +#define NEON_VOP1(name, vtype, n) \ +uint32_t HELPER(glue(neon_,name))(uint32_t arg) \ +{ \ + vtype vsrc1; \ + vtype vdest; \ + NEON_UNPACK(vtype, vsrc1, arg); \ + NEON_DO##n; \ + NEON_PACK(vtype, arg, vdest); \ + return arg; \ +} + + +#define NEON_USAT(dest, src1, src2, type) do { \ + uint32_t tmp = (uint32_t)src1 + (uint32_t)src2; \ + if (tmp != (type)tmp) { \ + SET_QC(); \ + dest = ~0; \ + } else { \ + dest = tmp; \ + }} while(0) +#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint8_t) +NEON_VOP_ENV(qadd_u8, neon_u8, 4) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint16_t) +NEON_VOP_ENV(qadd_u16, neon_u16, 2) +#undef NEON_FN +#undef NEON_USAT + +#define NEON_SSAT(dest, src1, src2, type) do { \ + int32_t tmp = (uint32_t)src1 + (uint32_t)src2; \ + if (tmp != (type)tmp) { \ + SET_QC(); \ + if (src2 > 0) { \ + tmp = (1 << (sizeof(type) * 8 - 1)) - 1; \ + } else { \ + tmp = 1 << (sizeof(type) * 8 - 1); \ + } \ + } \ + dest = tmp; \ + } while(0) +#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int8_t) +NEON_VOP_ENV(qadd_s8, neon_s8, 4) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int16_t) +NEON_VOP_ENV(qadd_s16, neon_s16, 2) +#undef NEON_FN +#undef NEON_SSAT + +#define NEON_USAT(dest, src1, src2, type) do { \ + uint32_t tmp = (uint32_t)src1 - (uint32_t)src2; \ + if (tmp != (type)tmp) { \ + SET_QC(); \ + dest = 0; \ + } else { \ + dest = tmp; \ + }} while(0) +#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint8_t) +NEON_VOP_ENV(qsub_u8, neon_u8, 4) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint16_t) +NEON_VOP_ENV(qsub_u16, neon_u16, 2) +#undef NEON_FN +#undef NEON_USAT + +#define NEON_SSAT(dest, src1, src2, type) do { \ + int32_t tmp = (uint32_t)src1 - (uint32_t)src2; \ + if (tmp != (type)tmp) { \ + SET_QC(); \ + if (src2 < 0) { \ + tmp = (1 << (sizeof(type) * 8 - 1)) - 1; \ + } else { \ + tmp = 1 << (sizeof(type) * 8 - 1); \ + } \ + } \ + dest = tmp; \ + } while(0) +#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int8_t) +NEON_VOP_ENV(qsub_s8, neon_s8, 4) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int16_t) +NEON_VOP_ENV(qsub_s16, neon_s16, 2) +#undef NEON_FN +#undef NEON_SSAT + +#define NEON_FN(dest, src1, src2) dest = (src1 + src2) >> 1 +NEON_VOP(hadd_s8, neon_s8, 4) +NEON_VOP(hadd_u8, neon_u8, 4) +NEON_VOP(hadd_s16, neon_s16, 2) +NEON_VOP(hadd_u16, neon_u16, 2) +#undef NEON_FN + +int32_t HELPER(neon_hadd_s32)(int32_t src1, int32_t src2) +{ + int32_t dest; + + dest = (src1 >> 1) + (src2 >> 1); + if (src1 & src2 & 1) + dest++; + return dest; +} + +uint32_t HELPER(neon_hadd_u32)(uint32_t src1, uint32_t src2) +{ + uint32_t dest; + + dest = (src1 >> 1) + (src2 >> 1); + if (src1 & src2 & 1) + dest++; + return dest; +} + +#define NEON_FN(dest, src1, src2) dest = (src1 + src2 + 1) >> 1 +NEON_VOP(rhadd_s8, neon_s8, 4) +NEON_VOP(rhadd_u8, neon_u8, 4) +NEON_VOP(rhadd_s16, neon_s16, 2) +NEON_VOP(rhadd_u16, neon_u16, 2) +#undef NEON_FN + +int32_t HELPER(neon_rhadd_s32)(int32_t src1, int32_t src2) +{ + int32_t dest; + + dest = (src1 >> 1) + (src2 >> 1); + if ((src1 | src2) & 1) + dest++; + return dest; +} + +uint32_t HELPER(neon_rhadd_u32)(uint32_t src1, uint32_t src2) +{ + uint32_t dest; + + dest = (src1 >> 1) + (src2 >> 1); + if ((src1 | src2) & 1) + dest++; + return dest; +} + +#define NEON_FN(dest, src1, src2) dest = (src1 - src2) >> 1 +NEON_VOP(hsub_s8, neon_s8, 4) +NEON_VOP(hsub_u8, neon_u8, 4) +NEON_VOP(hsub_s16, neon_s16, 2) +NEON_VOP(hsub_u16, neon_u16, 2) +#undef NEON_FN + +int32_t HELPER(neon_hsub_s32)(int32_t src1, int32_t src2) +{ + int32_t dest; + + dest = (src1 >> 1) - (src2 >> 1); + if ((~src1) & src2 & 1) + dest--; + return dest; +} + +uint32_t HELPER(neon_hsub_u32)(uint32_t src1, uint32_t src2) +{ + uint32_t dest; + + dest = (src1 >> 1) - (src2 >> 1); + if ((~src1) & src2 & 1) + dest--; + return dest; +} + +#define NEON_FN(dest, src1, src2) dest = (src1 > src2) ? ~0 : 0 +NEON_VOP(cgt_s8, neon_s8, 4) +NEON_VOP(cgt_u8, neon_u8, 4) +NEON_VOP(cgt_s16, neon_s16, 2) +NEON_VOP(cgt_u16, neon_u16, 2) +NEON_VOP(cgt_s32, neon_s32, 1) +NEON_VOP(cgt_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = (src1 >= src2) ? ~0 : 0 +NEON_VOP(cge_s8, neon_s8, 4) +NEON_VOP(cge_u8, neon_u8, 4) +NEON_VOP(cge_s16, neon_s16, 2) +NEON_VOP(cge_u16, neon_u16, 2) +NEON_VOP(cge_s32, neon_s32, 1) +NEON_VOP(cge_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = (src1 < src2) ? src1 : src2 +NEON_VOP(min_s8, neon_s8, 4) +NEON_VOP(min_u8, neon_u8, 4) +NEON_VOP(min_s16, neon_s16, 2) +NEON_VOP(min_u16, neon_u16, 2) +NEON_VOP(min_s32, neon_s32, 1) +NEON_VOP(min_u32, neon_u32, 1) +NEON_POP(pmin_s8, neon_s8, 4) +NEON_POP(pmin_u8, neon_u8, 4) +NEON_POP(pmin_s16, neon_s16, 2) +NEON_POP(pmin_u16, neon_u16, 2) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = (src1 > src2) ? src1 : src2 +NEON_VOP(max_s8, neon_s8, 4) +NEON_VOP(max_u8, neon_u8, 4) +NEON_VOP(max_s16, neon_s16, 2) +NEON_VOP(max_u16, neon_u16, 2) +NEON_VOP(max_s32, neon_s32, 1) +NEON_VOP(max_u32, neon_u32, 1) +NEON_POP(pmax_s8, neon_s8, 4) +NEON_POP(pmax_u8, neon_u8, 4) +NEON_POP(pmax_s16, neon_s16, 2) +NEON_POP(pmax_u16, neon_u16, 2) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) \ + dest = (src1 > src2) ? (src1 - src2) : (src2 - src1) +NEON_VOP(abd_s8, neon_s8, 4) +NEON_VOP(abd_u8, neon_u8, 4) +NEON_VOP(abd_s16, neon_s16, 2) +NEON_VOP(abd_u16, neon_u16, 2) +NEON_VOP(abd_s32, neon_s32, 1) +NEON_VOP(abd_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp >= sizeof(src1) * 8 || tmp <= -sizeof(src1) * 8) { \ + dest = 0; \ + } else if (tmp < 0) { \ + dest = src1 >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + }} while (0) +NEON_VOP(shl_u8, neon_u8, 4) +NEON_VOP(shl_u16, neon_u16, 2) +NEON_VOP(shl_u32, neon_u32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_shl_u64)(uint64_t val, uint64_t shiftop) +{ + int8_t shift = (int8_t)shiftop; + if (shift >= 64 || shift <= -64) { + val = 0; + } else if (shift < 0) { + val >>= -shift; + } else { + val <<= shift; + } + return val; +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp >= sizeof(src1) * 8) { \ + dest = 0; \ + } else if (tmp <= -sizeof(src1) * 8) { \ + dest = src1 >> (sizeof(src1) * 8 - 1); \ + } else if (tmp < 0) { \ + dest = src1 >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + }} while (0) +NEON_VOP(shl_s8, neon_s8, 4) +NEON_VOP(shl_s16, neon_s16, 2) +NEON_VOP(shl_s32, neon_s32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_shl_s64)(uint64_t valop, uint64_t shiftop) +{ + int8_t shift = (int8_t)shiftop; + int64_t val = valop; + if (shift >= 64) { + val = 0; + } else if (shift <= -64) { + val >>= 63; + } else if (shift < 0) { + val >>= -shift; + } else { + val <<= shift; + } + return val; +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp >= sizeof(src1) * 8) { \ + dest = 0; \ + } else if (tmp < -sizeof(src1) * 8) { \ + dest >>= sizeof(src1) * 8 - 1; \ + } else if (tmp == -sizeof(src1) * 8) { \ + dest = src1 >> (tmp - 1); \ + dest++; \ + src2 >>= 1; \ + } else if (tmp < 0) { \ + dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + }} while (0) +NEON_VOP(rshl_s8, neon_s8, 4) +NEON_VOP(rshl_s16, neon_s16, 2) +NEON_VOP(rshl_s32, neon_s32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_rshl_s64)(uint64_t valop, uint64_t shiftop) +{ + int8_t shift = (int8_t)shiftop; + int64_t val = valop; + if (shift >= 64) { + val = 0; + } else if (shift < -64) { + val >>= 63; + } else if (shift == -63) { + val >>= 63; + val++; + val >>= 1; + } else if (shift < 0) { + val = (val + ((int64_t)1 << (-1 - shift))) >> -shift; + } else { + val <<= shift; + } + return val; +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp >= sizeof(src1) * 8 || tmp < -sizeof(src1) * 8) { \ + dest = 0; \ + } else if (tmp == -sizeof(src1) * 8) { \ + dest = src1 >> (tmp - 1); \ + } else if (tmp < 0) { \ + dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + }} while (0) +NEON_VOP(rshl_u8, neon_u8, 4) +NEON_VOP(rshl_u16, neon_u16, 2) +NEON_VOP(rshl_u32, neon_u32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_rshl_u64)(uint64_t val, uint64_t shiftop) +{ + int8_t shift = (uint8_t)shiftop; + if (shift >= 64 || shift < 64) { + val = 0; + } else if (shift == -64) { + /* Rounding a 1-bit result just preserves that bit. */ + val >>= 63; + } if (shift < 0) { + val = (val + ((uint64_t)1 << (-1 - shift))) >> -shift; + val >>= -shift; + } else { + val <<= shift; + } + return val; +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp >= sizeof(src1) * 8) { \ + if (src1) { \ + SET_QC(); \ + dest = ~0; \ + } else { \ + dest = 0; \ + } \ + } else if (tmp <= -sizeof(src1) * 8) { \ + dest = 0; \ + } else if (tmp < 0) { \ + dest = src1 >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + if ((dest >> tmp) != src1) { \ + SET_QC(); \ + dest = ~0; \ + } \ + }} while (0) +NEON_VOP_ENV(qshl_u8, neon_u8, 4) +NEON_VOP_ENV(qshl_u16, neon_u16, 2) +NEON_VOP_ENV(qshl_u32, neon_u32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop) +{ + int8_t shift = (int8_t)shiftop; + if (shift >= 64) { + if (val) { + val = ~(uint64_t)0; + SET_QC(); + } else { + val = 0; + } + } else if (shift <= -64) { + val = 0; + } else if (shift < 0) { + val >>= -shift; + } else { + uint64_t tmp = val; + val <<= shift; + if ((val >> shift) != tmp) { + SET_QC(); + val = ~(uint64_t)0; + } + } + return val; +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp >= sizeof(src1) * 8) { \ + if (src1) \ + SET_QC(); \ + dest = src1 >> 31; \ + } else if (tmp <= -sizeof(src1) * 8) { \ + dest = src1 >> 31; \ + } else if (tmp < 0) { \ + dest = src1 >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + if ((dest >> tmp) != src1) { \ + SET_QC(); \ + dest = src2 >> 31; \ + } \ + }} while (0) +NEON_VOP_ENV(qshl_s8, neon_s8, 4) +NEON_VOP_ENV(qshl_s16, neon_s16, 2) +NEON_VOP_ENV(qshl_s32, neon_s32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_qshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop) +{ + int8_t shift = (uint8_t)shiftop; + int64_t val = valop; + if (shift >= 64) { + if (val) { + SET_QC(); + val = (val >> 63) & ~SIGNBIT64; + } + } else if (shift <= 64) { + val >>= 63; + } else if (shift < 0) { + val >>= -shift; + } else { + int64_t tmp = val; + val <<= shift; + if ((val >> shift) != tmp) { + SET_QC(); + val = (tmp >> 63) ^ ~SIGNBIT64; + } + } + return val; +} + + +/* FIXME: This is wrong. */ +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp < 0) { \ + dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + if ((dest >> tmp) != src1) { \ + SET_QC(); \ + dest = ~0; \ + } \ + }} while (0) +NEON_VOP_ENV(qrshl_u8, neon_u8, 4) +NEON_VOP_ENV(qrshl_u16, neon_u16, 2) +NEON_VOP_ENV(qrshl_u32, neon_u32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_qrshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop) +{ + int8_t shift = (int8_t)shiftop; + if (shift < 0) { + val = (val + (1 << (-1 - shift))) >> -shift; + } else { \ + uint64_t tmp = val; + val <<= shift; + if ((val >> shift) != tmp) { + SET_QC(); + val = ~0; + } + } + return val; +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp < 0) { \ + dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + if ((dest >> tmp) != src1) { \ + SET_QC(); \ + dest = src1 >> 31; \ + } \ + }} while (0) +NEON_VOP_ENV(qrshl_s8, neon_s8, 4) +NEON_VOP_ENV(qrshl_s16, neon_s16, 2) +NEON_VOP_ENV(qrshl_s32, neon_s32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_qrshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop) +{ + int8_t shift = (uint8_t)shiftop; + int64_t val = valop; + + if (shift < 0) { + val = (val + (1 << (-1 - shift))) >> -shift; + } else { + int64_t tmp = val;; + val <<= shift; + if ((val >> shift) != tmp) { + SET_QC(); + val = tmp >> 31; + } + } + return val; +} + +uint32_t HELPER(neon_add_u8)(uint32_t a, uint32_t b) +{ + uint32_t mask; + mask = (a ^ b) & 0x80808080u; + a &= ~0x80808080u; + b &= ~0x80808080u; + return (a + b) ^ mask; +} + +uint32_t HELPER(neon_add_u16)(uint32_t a, uint32_t b) +{ + uint32_t mask; + mask = (a ^ b) & 0x80008000u; + a &= ~0x80008000u; + b &= ~0x80008000u; + return (a + b) ^ mask; +} + +#define NEON_FN(dest, src1, src2) dest = src1 + src2 +NEON_POP(padd_u8, neon_u8, 4) +NEON_POP(padd_u16, neon_u16, 2) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = src1 - src2 +NEON_VOP(sub_u8, neon_u8, 4) +NEON_VOP(sub_u16, neon_u16, 2) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = src1 * src2 +NEON_VOP(mul_u8, neon_u8, 4) +NEON_VOP(mul_u16, neon_u16, 2) +#undef NEON_FN + +/* Polynomial multiplication is like integer multiplication except the + partial products are XORed, not added. */ +uint32_t HELPER(neon_mul_p8)(uint32_t op1, uint32_t op2) +{ + uint32_t mask; + uint32_t result; + result = 0; + while (op1) { + mask = 0; + if (op1 & 1) + mask |= 0xff; + if (op1 & (1 << 8)) + mask |= (0xff << 8); + if (op1 & (1 << 16)) + mask |= (0xff << 16); + if (op1 & (1 << 24)) + mask |= (0xff << 24); + result ^= op2 & mask; + op1 = (op1 >> 1) & 0x7f7f7f7f; + op2 = (op2 << 1) & 0xfefefefe; + } + return result; +} + +#define NEON_FN(dest, src1, src2) dest = (src1 & src2) ? -1 : 0 +NEON_VOP(tst_u8, neon_u8, 4) +NEON_VOP(tst_u16, neon_u16, 2) +NEON_VOP(tst_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = (src1 == src2) ? -1 : 0 +NEON_VOP(ceq_u8, neon_u8, 4) +NEON_VOP(ceq_u16, neon_u16, 2) +NEON_VOP(ceq_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src, dummy) dest = (src < 0) ? -src : src +NEON_VOP1(abs_s8, neon_s8, 4) +NEON_VOP1(abs_s16, neon_s16, 2) +#undef NEON_FN + +/* Count Leading Sign/Zero Bits. */ +static inline int do_clz8(uint8_t x) +{ + int n; + for (n = 8; x; n--) + x >>= 1; + return n; +} + +static inline int do_clz16(uint16_t x) +{ + int n; + for (n = 16; x; n--) + x >>= 1; + return n; +} + +#define NEON_FN(dest, src, dummy) dest = do_clz8(src) +NEON_VOP1(clz_u8, neon_u8, 4) +#undef NEON_FN + +#define NEON_FN(dest, src, dummy) dest = do_clz16(src) +NEON_VOP1(clz_u16, neon_u16, 2) +#undef NEON_FN + +#define NEON_FN(dest, src, dummy) dest = do_clz8((src < 0) ? ~src : src) - 1 +NEON_VOP1(cls_s8, neon_s8, 4) +#undef NEON_FN + +#define NEON_FN(dest, src, dummy) dest = do_clz16((src < 0) ? ~src : src) - 1 +NEON_VOP1(cls_s16, neon_s16, 2) +#undef NEON_FN + +uint32_t HELPER(neon_cls_s32)(uint32_t x) +{ + int count; + if ((int32_t)x < 0) + x = ~x; + for (count = 32; x; count--) + x = x >> 1; + return count - 1; +} + +/* Bit count. */ +uint32_t HELPER(neon_cnt_u8)(uint32_t x) +{ + x = (x & 0x55555555) + ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x & 0x0f0f0f0f) + ((x >> 4) & 0x0f0f0f0f); + return x; +} + +#define NEON_QDMULH16(dest, src1, src2, round) do { \ + uint32_t tmp = (int32_t)(int16_t) src1 * (int16_t) src2; \ + if ((tmp ^ (tmp << 1)) & SIGNBIT) { \ + SET_QC(); \ + tmp = (tmp >> 31) ^ ~SIGNBIT; \ + } \ + tmp <<= 1; \ + if (round) { \ + int32_t old = tmp; \ + tmp += 1 << 15; \ + if ((int32_t)tmp < old) { \ + SET_QC(); \ + tmp = SIGNBIT - 1; \ + } \ + } \ + dest = tmp >> 16; \ + } while(0) +#define NEON_FN(dest, src1, src2) NEON_QDMULH16(dest, src1, src2, 0) +NEON_VOP_ENV(qdmulh_s16, neon_s16, 2) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_QDMULH16(dest, src1, src2, 1) +NEON_VOP_ENV(qrdmulh_s16, neon_s16, 2) +#undef NEON_FN +#undef NEON_QDMULH16 + +#define NEON_QDMULH32(dest, src1, src2, round) do { \ + uint64_t tmp = (int64_t)(int32_t) src1 * (int32_t) src2; \ + if ((tmp ^ (tmp << 1)) & SIGNBIT64) { \ + SET_QC(); \ + tmp = (tmp >> 63) ^ ~SIGNBIT64; \ + } else { \ + tmp <<= 1; \ + } \ + if (round) { \ + int64_t old = tmp; \ + tmp += (int64_t)1 << 31; \ + if ((int64_t)tmp < old) { \ + SET_QC(); \ + tmp = SIGNBIT64 - 1; \ + } \ + } \ + dest = tmp >> 32; \ + } while(0) +#define NEON_FN(dest, src1, src2) NEON_QDMULH32(dest, src1, src2, 0) +NEON_VOP_ENV(qdmulh_s32, neon_s32, 1) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_QDMULH32(dest, src1, src2, 1) +NEON_VOP_ENV(qrdmulh_s32, neon_s32, 1) +#undef NEON_FN +#undef NEON_QDMULH32 + +uint32_t HELPER(neon_narrow_u8)(uint64_t x) +{ + return (x & 0xffu) | ((x >> 8) & 0xff00u) | ((x >> 16) & 0xff0000u) + | ((x >> 24) & 0xff000000u); +} + +uint32_t HELPER(neon_narrow_u16)(uint64_t x) +{ + return (x & 0xffffu) | ((x >> 16) & 0xffff0000u); +} + +uint32_t HELPER(neon_narrow_high_u8)(uint64_t x) +{ + return ((x >> 8) & 0xff) | ((x >> 16) & 0xff00) + | ((x >> 24) & 0xff0000) | ((x >> 32) & 0xff000000); +} + +uint32_t HELPER(neon_narrow_high_u16)(uint64_t x) +{ + return ((x >> 16) & 0xffff) | ((x >> 32) & 0xffff0000); +} + +uint32_t HELPER(neon_narrow_round_high_u8)(uint64_t x) +{ + x &= 0xff80ff80ff80ff80ull; + x += 0x0080008000800080ull; + return ((x >> 8) & 0xff) | ((x >> 16) & 0xff00) + | ((x >> 24) & 0xff0000) | ((x >> 32) & 0xff000000); +} + +uint32_t HELPER(neon_narrow_round_high_u16)(uint64_t x) +{ + x &= 0xffff8000ffff8000ull; + x += 0x0000800000008000ull; + return ((x >> 16) & 0xffff) | ((x >> 32) & 0xffff0000); +} + +uint32_t HELPER(neon_narrow_sat_u8)(CPUState *env, uint64_t x) +{ + uint16_t s; + uint8_t d; + uint32_t res = 0; +#define SAT8(n) \ + s = x >> n; \ + if (s > 0xff) { \ + d = 0xff; \ + SET_QC(); \ + } else { \ + d = s; \ + } \ + res |= (uint32_t)d << (n / 2); + + SAT8(0); + SAT8(16); + SAT8(32); + SAT8(48); +#undef SAT8 + return res; +} + +uint32_t HELPER(neon_narrow_sat_s8)(CPUState *env, uint64_t x) +{ + int16_t s; + uint8_t d; + uint32_t res = 0; +#define SAT8(n) \ + s = x >> n; \ + if (s != (int8_t)s) { \ + d = (s >> 15) ^ 0x7f; \ + SET_QC(); \ + } else { \ + d = s; \ + } \ + res |= (uint32_t)d << (n / 2); + + SAT8(0); + SAT8(16); + SAT8(32); + SAT8(48); +#undef SAT8 + return res; +} + +uint32_t HELPER(neon_narrow_sat_u16)(CPUState *env, uint64_t x) +{ + uint32_t high; + uint32_t low; + low = x; + if (low > 0xffff) { + low = 0xffff; + SET_QC(); + } + high = x >> 32; + if (high > 0xffff) { + high = 0xffff; + SET_QC(); + } + return low | (high << 16); +} + +uint32_t HELPER(neon_narrow_sat_s16)(CPUState *env, uint64_t x) +{ + int32_t low; + int32_t high; + low = x; + if (low != (int16_t)low) { + low = (low >> 31) ^ 0x7fff; + SET_QC(); + } + high = x >> 32; + if (high != (int16_t)high) { + high = (high >> 31) ^ 0x7fff; + SET_QC(); + } + return (uint16_t)low | (high << 16); +} + +uint32_t HELPER(neon_narrow_sat_u32)(CPUState *env, uint64_t x) +{ + if (x > 0xffffffffu) { + SET_QC(); + return 0xffffffffu; + } + return x; +} + +uint32_t HELPER(neon_narrow_sat_s32)(CPUState *env, uint64_t x) +{ + if ((int64_t)x != (int32_t)x) { + SET_QC(); + return (x >> 63) ^ 0x7fffffff; + } + return x; +} + +uint64_t HELPER(neon_widen_u8)(uint32_t x) +{ + uint64_t tmp; + uint64_t ret; + ret = (uint8_t)x; + tmp = (uint8_t)(x >> 8); + ret |= tmp << 16; + tmp = (uint8_t)(x >> 16); + ret |= tmp << 32; + tmp = (uint8_t)(x >> 24); + ret |= tmp << 48; + return ret; +} + +uint64_t HELPER(neon_widen_s8)(uint32_t x) +{ + uint64_t tmp; + uint64_t ret; + ret = (uint16_t)(int8_t)x; + tmp = (uint16_t)(int8_t)(x >> 8); + ret |= tmp << 16; + tmp = (uint16_t)(int8_t)(x >> 16); + ret |= tmp << 32; + tmp = (uint16_t)(int8_t)(x >> 24); + ret |= tmp << 48; + return ret; +} + +uint64_t HELPER(neon_widen_u16)(uint32_t x) +{ + uint64_t high = (uint16_t)(x >> 16); + return ((uint16_t)x) | (high << 32); +} + +uint64_t HELPER(neon_widen_s16)(uint32_t x) +{ + uint64_t high = (int16_t)(x >> 16); + return ((uint32_t)(int16_t)x) | (high << 32); +} + +uint64_t HELPER(neon_addl_u16)(uint64_t a, uint64_t b) +{ + uint64_t mask; + mask = (a ^ b) & 0x8000800080008000ull; + a &= ~0x8000800080008000ull; + b &= ~0x8000800080008000ull; + return (a + b) ^ mask; +} + +uint64_t HELPER(neon_addl_u32)(uint64_t a, uint64_t b) +{ + uint64_t mask; + mask = (a ^ b) & 0x8000000080000000ull; + a &= ~0x8000000080000000ull; + b &= ~0x8000000080000000ull; + return (a + b) ^ mask; +} + +uint64_t HELPER(neon_paddl_u16)(uint64_t a, uint64_t b) +{ + uint64_t tmp; + uint64_t tmp2; + + tmp = a & 0x0000ffff0000ffffull; + tmp += (a >> 16) & 0x0000ffff0000ffffull; + tmp2 = b & 0xffff0000ffff0000ull; + tmp2 += (b << 16) & 0xffff0000ffff0000ull; + return ( tmp & 0xffff) + | ((tmp >> 16) & 0xffff0000ull) + | ((tmp2 << 16) & 0xffff00000000ull) + | ( tmp2 & 0xffff000000000000ull); +} + +uint64_t HELPER(neon_paddl_u32)(uint64_t a, uint64_t b) +{ + uint32_t low = a + (a >> 32); + uint32_t high = b + (b >> 32); + return low + ((uint64_t)high << 32); +} + +uint64_t HELPER(neon_subl_u16)(uint64_t a, uint64_t b) +{ + uint64_t mask; + mask = (a ^ ~b) & 0x8000800080008000ull; + a |= 0x8000800080008000ull; + b &= ~0x8000800080008000ull; + return (a - b) ^ mask; +} + +uint64_t HELPER(neon_subl_u32)(uint64_t a, uint64_t b) +{ + uint64_t mask; + mask = (a ^ ~b) & 0x8000000080000000ull; + a |= 0x8000000080000000ull; + b &= ~0x8000000080000000ull; + return (a - b) ^ mask; +} + +uint64_t HELPER(neon_addl_saturate_s32)(CPUState *env, uint64_t a, uint64_t b) +{ + uint32_t x, y; + uint32_t low, high; + + x = a; + y = b; + low = x + y; + if (((low ^ x) & SIGNBIT) && !((x ^ y) & SIGNBIT)) { + SET_QC(); + low = ((int32_t)x >> 31) ^ ~SIGNBIT; + } + x = a >> 32; + y = b >> 32; + high = x + y; + if (((high ^ x) & SIGNBIT) && !((x ^ y) & SIGNBIT)) { + SET_QC(); + high = ((int32_t)x >> 31) ^ ~SIGNBIT; + } + return low | ((uint64_t)high << 32); +} + +uint64_t HELPER(neon_addl_saturate_s64)(CPUState *env, uint64_t a, uint64_t b) +{ + uint64_t result; + + result = a + b; + if (((result ^ a) & SIGNBIT64) && !((a ^ b) & SIGNBIT64)) { + SET_QC(); + result = ((int64_t)a >> 63) ^ ~SIGNBIT64; + } + return result; +} + +#define DO_ABD(dest, x, y, type) do { \ + type tmp_x = x; \ + type tmp_y = y; \ + dest = ((tmp_x > tmp_y) ? tmp_x - tmp_y : tmp_y - tmp_x); \ + } while(0) + +uint64_t HELPER(neon_abdl_u16)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + DO_ABD(result, a, b, uint8_t); + DO_ABD(tmp, a >> 8, b >> 8, uint8_t); + result |= tmp << 16; + DO_ABD(tmp, a >> 16, b >> 16, uint8_t); + result |= tmp << 32; + DO_ABD(tmp, a >> 24, b >> 24, uint8_t); + result |= tmp << 48; + return result; +} + +uint64_t HELPER(neon_abdl_s16)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + DO_ABD(result, a, b, int8_t); + DO_ABD(tmp, a >> 8, b >> 8, int8_t); + result |= tmp << 16; + DO_ABD(tmp, a >> 16, b >> 16, int8_t); + result |= tmp << 32; + DO_ABD(tmp, a >> 24, b >> 24, int8_t); + result |= tmp << 48; + return result; +} + +uint64_t HELPER(neon_abdl_u32)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + DO_ABD(result, a, b, uint16_t); + DO_ABD(tmp, a >> 16, b >> 16, uint16_t); + return result | (tmp << 32); +} + +uint64_t HELPER(neon_abdl_s32)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + DO_ABD(result, a, b, int16_t); + DO_ABD(tmp, a >> 16, b >> 16, int16_t); + return result | (tmp << 32); +} + +uint64_t HELPER(neon_abdl_u64)(uint32_t a, uint32_t b) +{ + uint64_t result; + DO_ABD(result, a, b, uint32_t); + return result; +} + +uint64_t HELPER(neon_abdl_s64)(uint32_t a, uint32_t b) +{ + uint64_t result; + DO_ABD(result, a, b, int32_t); + return result; +} +#undef DO_ABD + +/* Widening multiply. Named type is the source type. */ +#define DO_MULL(dest, x, y, type1, type2) do { \ + type1 tmp_x = x; \ + type1 tmp_y = y; \ + dest = (type2)((type2)tmp_x * (type2)tmp_y); \ + } while(0) + +uint64_t HELPER(neon_mull_u8)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + + DO_MULL(result, a, b, uint8_t, uint16_t); + DO_MULL(tmp, a >> 8, b >> 8, uint8_t, uint16_t); + result |= tmp << 16; + DO_MULL(tmp, a >> 16, b >> 16, uint8_t, uint16_t); + result |= tmp << 32; + DO_MULL(tmp, a >> 24, b >> 24, uint8_t, uint16_t); + result |= tmp << 48; + return result; +} + +uint64_t HELPER(neon_mull_s8)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + + DO_MULL(result, a, b, int8_t, uint16_t); + DO_MULL(tmp, a >> 8, b >> 8, int8_t, uint16_t); + result |= tmp << 16; + DO_MULL(tmp, a >> 16, b >> 16, int8_t, uint16_t); + result |= tmp << 32; + DO_MULL(tmp, a >> 24, b >> 24, int8_t, uint16_t); + result |= tmp << 48; + return result; +} + +uint64_t HELPER(neon_mull_u16)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + + DO_MULL(result, a, b, uint16_t, uint32_t); + DO_MULL(tmp, a >> 16, b >> 16, uint16_t, uint32_t); + return result | (tmp << 32); +} + +uint64_t HELPER(neon_mull_s16)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + + DO_MULL(result, a, b, int16_t, uint32_t); + DO_MULL(tmp, a >> 16, b >> 16, int16_t, uint32_t); + return result | (tmp << 32); +} + +uint64_t HELPER(neon_negl_u16)(uint64_t x) +{ + uint16_t tmp; + uint64_t result; + result = (uint16_t)-x; + tmp = -(x >> 16); + result |= (uint64_t)tmp << 16; + tmp = -(x >> 32); + result |= (uint64_t)tmp << 32; + tmp = -(x >> 48); + result |= (uint64_t)tmp << 48; + return result; +} + +#include +uint64_t HELPER(neon_negl_u32)(uint64_t x) +{ + uint32_t low = -x; + uint32_t high = -(x >> 32); + return low | ((uint64_t)high << 32); +} + +/* FIXME: There should be a native op for this. */ +uint64_t HELPER(neon_negl_u64)(uint64_t x) +{ + return -x; +} + +/* Saturnating sign manuipulation. */ +/* ??? Make these use NEON_VOP1 */ +#define DO_QABS8(x) do { \ + if (x == (int8_t)0x80) { \ + x = 0x7f; \ + SET_QC(); \ + } else if (x < 0) { \ + x = -x; \ + }} while (0) +uint32_t HELPER(neon_qabs_s8)(CPUState *env, uint32_t x) +{ + neon_s8 vec; + NEON_UNPACK(neon_s8, vec, x); + DO_QABS8(vec.v1); + DO_QABS8(vec.v2); + DO_QABS8(vec.v3); + DO_QABS8(vec.v4); + NEON_PACK(neon_s8, x, vec); + return x; +} +#undef DO_QABS8 + +#define DO_QNEG8(x) do { \ + if (x == (int8_t)0x80) { \ + x = 0x7f; \ + SET_QC(); \ + } else { \ + x = -x; \ + }} while (0) +uint32_t HELPER(neon_qneg_s8)(CPUState *env, uint32_t x) +{ + neon_s8 vec; + NEON_UNPACK(neon_s8, vec, x); + DO_QNEG8(vec.v1); + DO_QNEG8(vec.v2); + DO_QNEG8(vec.v3); + DO_QNEG8(vec.v4); + NEON_PACK(neon_s8, x, vec); + return x; +} +#undef DO_QNEG8 + +#define DO_QABS16(x) do { \ + if (x == (int16_t)0x8000) { \ + x = 0x7fff; \ + SET_QC(); \ + } else if (x < 0) { \ + x = -x; \ + }} while (0) +uint32_t HELPER(neon_qabs_s16)(CPUState *env, uint32_t x) +{ + neon_s16 vec; + NEON_UNPACK(neon_s16, vec, x); + DO_QABS16(vec.v1); + DO_QABS16(vec.v2); + NEON_PACK(neon_s16, x, vec); + return x; +} +#undef DO_QABS16 + +#define DO_QNEG16(x) do { \ + if (x == (int16_t)0x8000) { \ + x = 0x7fff; \ + SET_QC(); \ + } else { \ + x = -x; \ + }} while (0) +uint32_t HELPER(neon_qneg_s16)(CPUState *env, uint32_t x) +{ + neon_s16 vec; + NEON_UNPACK(neon_s16, vec, x); + DO_QNEG16(vec.v1); + DO_QNEG16(vec.v2); + NEON_PACK(neon_s16, x, vec); + return x; +} +#undef DO_QNEG16 + +uint32_t HELPER(neon_qabs_s32)(CPUState *env, uint32_t x) +{ + if (x == SIGNBIT) { + SET_QC(); + x = ~SIGNBIT; + } else if ((int32_t)x < 0) { + x = -x; + } + return x; +} + +uint32_t HELPER(neon_qneg_s32)(CPUState *env, uint32_t x) +{ + if (x == SIGNBIT) { + SET_QC(); + x = ~SIGNBIT; + } else { + x = -x; + } + return x; +} + +/* NEON Float helpers. */ +uint32_t HELPER(neon_min_f32)(uint32_t a, uint32_t b) +{ + float32 f0 = vfp_itos(a); + float32 f1 = vfp_itos(b); + return (float32_compare_quiet(f0, f1, NFS) == -1) ? a : b; +} + +uint32_t HELPER(neon_max_f32)(uint32_t a, uint32_t b) +{ + float32 f0 = vfp_itos(a); + float32 f1 = vfp_itos(b); + return (float32_compare_quiet(f0, f1, NFS) == 1) ? a : b; +} + +uint32_t HELPER(neon_abd_f32)(uint32_t a, uint32_t b) +{ + float32 f0 = vfp_itos(a); + float32 f1 = vfp_itos(b); + return vfp_stoi((float32_compare_quiet(f0, f1, NFS) == 1) + ? float32_sub(f0, f1, NFS) + : float32_sub(f1, f0, NFS)); +} + +uint32_t HELPER(neon_add_f32)(uint32_t a, uint32_t b) +{ + return vfp_stoi(float32_add(vfp_itos(a), vfp_itos(b), NFS)); +} + +uint32_t HELPER(neon_sub_f32)(uint32_t a, uint32_t b) +{ + return vfp_stoi(float32_sub(vfp_itos(a), vfp_itos(b), NFS)); +} + +uint32_t HELPER(neon_mul_f32)(uint32_t a, uint32_t b) +{ + return vfp_stoi(float32_mul(vfp_itos(a), vfp_itos(b), NFS)); +} + +/* Floating point comparisons produce an integer result. */ +#define NEON_VOP_FCMP(name, cmp) \ +uint32_t HELPER(neon_##name)(uint32_t a, uint32_t b) \ +{ \ + if (float32_compare_quiet(vfp_itos(a), vfp_itos(b), NFS) cmp 0) \ + return ~0; \ + else \ + return 0; \ +} + +NEON_VOP_FCMP(ceq_f32, ==) +NEON_VOP_FCMP(cge_f32, >=) +NEON_VOP_FCMP(cgt_f32, >) + +uint32_t HELPER(neon_acge_f32)(uint32_t a, uint32_t b) +{ + float32 f0 = float32_abs(vfp_itos(a)); + float32 f1 = float32_abs(vfp_itos(b)); + return (float32_compare_quiet(f0, f1,NFS) >= 0) ? ~0 : 0; +} + +uint32_t HELPER(neon_acgt_f32)(uint32_t a, uint32_t b) +{ + float32 f0 = float32_abs(vfp_itos(a)); + float32 f1 = float32_abs(vfp_itos(b)); + return (float32_compare_quiet(f0, f1, NFS) > 0) ? ~0 : 0; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/nwfpe/double_cpdo.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/nwfpe/double_cpdo.c --- qemu-0.9.1/target-arm/nwfpe/double_cpdo.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/nwfpe/double_cpdo.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,296 +0,0 @@ -/* - NetWinder Floating Point Emulator - (c) Rebel.COM, 1998,1999 - - Direct questions, comments to Scott Bambrough - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "fpa11.h" -#include "softfloat.h" -#include "fpopcode.h" - -float64 float64_exp(float64 Fm); -float64 float64_ln(float64 Fm); -float64 float64_sin(float64 rFm); -float64 float64_cos(float64 rFm); -float64 float64_arcsin(float64 rFm); -float64 float64_arctan(float64 rFm); -float64 float64_log(float64 rFm); -float64 float64_tan(float64 rFm); -float64 float64_arccos(float64 rFm); -float64 float64_pow(float64 rFn,float64 rFm); -float64 float64_pol(float64 rFn,float64 rFm); - -unsigned int DoubleCPDO(const unsigned int opcode) -{ - FPA11 *fpa11 = GET_FPA11(); - float64 rFm, rFn = float64_zero; - unsigned int Fd, Fm, Fn, nRc = 1; - - //printk("DoubleCPDO(0x%08x)\n",opcode); - - Fm = getFm(opcode); - if (CONSTANT_FM(opcode)) - { - rFm = getDoubleConstant(Fm); - } - else - { - switch (fpa11->fType[Fm]) - { - case typeSingle: - rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status); - break; - - case typeDouble: - rFm = fpa11->fpreg[Fm].fDouble; - break; - - case typeExtended: - // !! patb - //printk("not implemented! why not?\n"); - //!! ScottB - // should never get here, if extended involved - // then other operand should be promoted then - // ExtendedCPDO called. - break; - - default: return 0; - } - } - - if (!MONADIC_INSTRUCTION(opcode)) - { - Fn = getFn(opcode); - switch (fpa11->fType[Fn]) - { - case typeSingle: - rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); - break; - - case typeDouble: - rFn = fpa11->fpreg[Fn].fDouble; - break; - - default: return 0; - } - } - - Fd = getFd(opcode); - /* !! this switch isn't optimized; better (opcode & MASK_ARITHMETIC_OPCODE)>>24, sort of */ - switch (opcode & MASK_ARITHMETIC_OPCODE) - { - /* dyadic opcodes */ - case ADF_CODE: - fpa11->fpreg[Fd].fDouble = float64_add(rFn,rFm, &fpa11->fp_status); - break; - - case MUF_CODE: - case FML_CODE: - fpa11->fpreg[Fd].fDouble = float64_mul(rFn,rFm, &fpa11->fp_status); - break; - - case SUF_CODE: - fpa11->fpreg[Fd].fDouble = float64_sub(rFn,rFm, &fpa11->fp_status); - break; - - case RSF_CODE: - fpa11->fpreg[Fd].fDouble = float64_sub(rFm,rFn, &fpa11->fp_status); - break; - - case DVF_CODE: - case FDV_CODE: - fpa11->fpreg[Fd].fDouble = float64_div(rFn,rFm, &fpa11->fp_status); - break; - - case RDF_CODE: - case FRD_CODE: - fpa11->fpreg[Fd].fDouble = float64_div(rFm,rFn, &fpa11->fp_status); - break; - -#if 0 - case POW_CODE: - fpa11->fpreg[Fd].fDouble = float64_pow(rFn,rFm); - break; - - case RPW_CODE: - fpa11->fpreg[Fd].fDouble = float64_pow(rFm,rFn); - break; -#endif - - case RMF_CODE: - fpa11->fpreg[Fd].fDouble = float64_rem(rFn,rFm, &fpa11->fp_status); - break; - -#if 0 - case POL_CODE: - fpa11->fpreg[Fd].fDouble = float64_pol(rFn,rFm); - break; -#endif - - /* monadic opcodes */ - case MVF_CODE: - fpa11->fpreg[Fd].fDouble = rFm; - break; - - case MNF_CODE: - { - unsigned int *p = (unsigned int*)&rFm; -#ifdef WORDS_BIGENDIAN - p[0] ^= 0x80000000; -#else - p[1] ^= 0x80000000; -#endif - fpa11->fpreg[Fd].fDouble = rFm; - } - break; - - case ABS_CODE: - { - unsigned int *p = (unsigned int*)&rFm; -#ifdef WORDS_BIGENDIAN - p[0] &= 0x7fffffff; -#else - p[1] &= 0x7fffffff; -#endif - fpa11->fpreg[Fd].fDouble = rFm; - } - break; - - case RND_CODE: - case URD_CODE: - fpa11->fpreg[Fd].fDouble = float64_round_to_int(rFm, &fpa11->fp_status); - break; - - case SQT_CODE: - fpa11->fpreg[Fd].fDouble = float64_sqrt(rFm, &fpa11->fp_status); - break; - -#if 0 - case LOG_CODE: - fpa11->fpreg[Fd].fDouble = float64_log(rFm); - break; - - case LGN_CODE: - fpa11->fpreg[Fd].fDouble = float64_ln(rFm); - break; - - case EXP_CODE: - fpa11->fpreg[Fd].fDouble = float64_exp(rFm); - break; - - case SIN_CODE: - fpa11->fpreg[Fd].fDouble = float64_sin(rFm); - break; - - case COS_CODE: - fpa11->fpreg[Fd].fDouble = float64_cos(rFm); - break; - - case TAN_CODE: - fpa11->fpreg[Fd].fDouble = float64_tan(rFm); - break; - - case ASN_CODE: - fpa11->fpreg[Fd].fDouble = float64_arcsin(rFm); - break; - - case ACS_CODE: - fpa11->fpreg[Fd].fDouble = float64_arccos(rFm); - break; - - case ATN_CODE: - fpa11->fpreg[Fd].fDouble = float64_arctan(rFm); - break; -#endif - - case NRM_CODE: - break; - - default: - { - nRc = 0; - } - } - - if (0 != nRc) fpa11->fType[Fd] = typeDouble; - return nRc; -} - -#if 0 -float64 float64_exp(float64 rFm) -{ - return rFm; -//series -} - -float64 float64_ln(float64 rFm) -{ - return rFm; -//series -} - -float64 float64_sin(float64 rFm) -{ - return rFm; -//series -} - -float64 float64_cos(float64 rFm) -{ - return rFm; - //series -} - -#if 0 -float64 float64_arcsin(float64 rFm) -{ -//series -} - -float64 float64_arctan(float64 rFm) -{ - //series -} -#endif - -float64 float64_log(float64 rFm) -{ - return float64_div(float64_ln(rFm),getDoubleConstant(7)); -} - -float64 float64_tan(float64 rFm) -{ - return float64_div(float64_sin(rFm),float64_cos(rFm)); -} - -float64 float64_arccos(float64 rFm) -{ -return rFm; - //return float64_sub(halfPi,float64_arcsin(rFm)); -} - -float64 float64_pow(float64 rFn,float64 rFm) -{ - return float64_exp(float64_mul(rFm,float64_ln(rFn))); -} - -float64 float64_pol(float64 rFn,float64 rFm) -{ - return float64_arctan(float64_div(rFn,rFm)); -} -#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/nwfpe/extended_cpdo.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/nwfpe/extended_cpdo.c --- qemu-0.9.1/target-arm/nwfpe/extended_cpdo.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/nwfpe/extended_cpdo.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,273 +0,0 @@ -/* - NetWinder Floating Point Emulator - (c) Rebel.COM, 1998,1999 - - Direct questions, comments to Scott Bambrough - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "fpa11.h" -#include "softfloat.h" -#include "fpopcode.h" - -floatx80 floatx80_exp(floatx80 Fm); -floatx80 floatx80_ln(floatx80 Fm); -floatx80 floatx80_sin(floatx80 rFm); -floatx80 floatx80_cos(floatx80 rFm); -floatx80 floatx80_arcsin(floatx80 rFm); -floatx80 floatx80_arctan(floatx80 rFm); -floatx80 floatx80_log(floatx80 rFm); -floatx80 floatx80_tan(floatx80 rFm); -floatx80 floatx80_arccos(floatx80 rFm); -floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm); -floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm); - -unsigned int ExtendedCPDO(const unsigned int opcode) -{ - FPA11 *fpa11 = GET_FPA11(); - floatx80 rFm, rFn; - unsigned int Fd, Fm, Fn, nRc = 1; - - //printk("ExtendedCPDO(0x%08x)\n",opcode); - - Fm = getFm(opcode); - if (CONSTANT_FM(opcode)) - { - rFm = getExtendedConstant(Fm); - } - else - { - switch (fpa11->fType[Fm]) - { - case typeSingle: - rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status); - break; - - case typeDouble: - rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status); - break; - - case typeExtended: - rFm = fpa11->fpreg[Fm].fExtended; - break; - - default: return 0; - } - } - - if (!MONADIC_INSTRUCTION(opcode)) - { - Fn = getFn(opcode); - switch (fpa11->fType[Fn]) - { - case typeSingle: - rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); - break; - - case typeDouble: - rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); - break; - - case typeExtended: - rFn = fpa11->fpreg[Fn].fExtended; - break; - - default: return 0; - } - } - - Fd = getFd(opcode); - switch (opcode & MASK_ARITHMETIC_OPCODE) - { - /* dyadic opcodes */ - case ADF_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_add(rFn,rFm, &fpa11->fp_status); - break; - - case MUF_CODE: - case FML_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_mul(rFn,rFm, &fpa11->fp_status); - break; - - case SUF_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_sub(rFn,rFm, &fpa11->fp_status); - break; - - case RSF_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_sub(rFm,rFn, &fpa11->fp_status); - break; - - case DVF_CODE: - case FDV_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_div(rFn,rFm, &fpa11->fp_status); - break; - - case RDF_CODE: - case FRD_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_div(rFm,rFn, &fpa11->fp_status); - break; - -#if 0 - case POW_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_pow(rFn,rFm); - break; - - case RPW_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_pow(rFm,rFn); - break; -#endif - - case RMF_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_rem(rFn,rFm, &fpa11->fp_status); - break; - -#if 0 - case POL_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_pol(rFn,rFm); - break; -#endif - - /* monadic opcodes */ - case MVF_CODE: - fpa11->fpreg[Fd].fExtended = rFm; - break; - - case MNF_CODE: - rFm.high ^= 0x8000; - fpa11->fpreg[Fd].fExtended = rFm; - break; - - case ABS_CODE: - rFm.high &= 0x7fff; - fpa11->fpreg[Fd].fExtended = rFm; - break; - - case RND_CODE: - case URD_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_round_to_int(rFm, &fpa11->fp_status); - break; - - case SQT_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_sqrt(rFm, &fpa11->fp_status); - break; - -#if 0 - case LOG_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_log(rFm); - break; - - case LGN_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_ln(rFm); - break; - - case EXP_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_exp(rFm); - break; - - case SIN_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_sin(rFm); - break; - - case COS_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_cos(rFm); - break; - - case TAN_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_tan(rFm); - break; - - case ASN_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_arcsin(rFm); - break; - - case ACS_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_arccos(rFm); - break; - - case ATN_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_arctan(rFm); - break; -#endif - - case NRM_CODE: - break; - - default: - { - nRc = 0; - } - } - - if (0 != nRc) fpa11->fType[Fd] = typeExtended; - return nRc; -} - -#if 0 -floatx80 floatx80_exp(floatx80 Fm) -{ -//series -} - -floatx80 floatx80_ln(floatx80 Fm) -{ -//series -} - -floatx80 floatx80_sin(floatx80 rFm) -{ -//series -} - -floatx80 floatx80_cos(floatx80 rFm) -{ -//series -} - -floatx80 floatx80_arcsin(floatx80 rFm) -{ -//series -} - -floatx80 floatx80_arctan(floatx80 rFm) -{ - //series -} - -floatx80 floatx80_log(floatx80 rFm) -{ - return floatx80_div(floatx80_ln(rFm),getExtendedConstant(7)); -} - -floatx80 floatx80_tan(floatx80 rFm) -{ - return floatx80_div(floatx80_sin(rFm),floatx80_cos(rFm)); -} - -floatx80 floatx80_arccos(floatx80 rFm) -{ - //return floatx80_sub(halfPi,floatx80_arcsin(rFm)); -} - -floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm) -{ - return floatx80_exp(floatx80_mul(rFm,floatx80_ln(rFn))); -} - -floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm) -{ - return floatx80_arctan(floatx80_div(rFn,rFm)); -} -#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/nwfpe/fpa11.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/nwfpe/fpa11.c --- qemu-0.9.1/target-arm/nwfpe/fpa11.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/nwfpe/fpa11.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,237 +0,0 @@ -/* - NetWinder Floating Point Emulator - (c) Rebel.COM, 1998,1999 - - Direct questions, comments to Scott Bambrough - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "fpa11.h" - -#include "fpopcode.h" - -//#include "fpmodule.h" -//#include "fpmodule.inl" - -//#include - -#include - -/* forward declarations */ -unsigned int EmulateCPDO(const unsigned int); -unsigned int EmulateCPDT(const unsigned int); -unsigned int EmulateCPRT(const unsigned int); - -FPA11* qemufpa=0; -CPUARMState* user_registers; - -/* Reset the FPA11 chip. Called to initialize and reset the emulator. */ -void resetFPA11(void) -{ - int i; - FPA11 *fpa11 = GET_FPA11(); - - /* initialize the register type array */ - for (i=0;i<=7;i++) - { - fpa11->fType[i] = typeNone; - } - - /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ - fpa11->fpsr = FP_EMULATOR | BIT_AC; - - /* FPCR: set SB, AB and DA bits, clear all others */ -#if MAINTAIN_FPCR - fpa11->fpcr = MASK_RESET; -#endif -} - -void SetRoundingMode(const unsigned int opcode) -{ - int rounding_mode; - FPA11 *fpa11 = GET_FPA11(); - -#if MAINTAIN_FPCR - fpa11->fpcr &= ~MASK_ROUNDING_MODE; -#endif - switch (opcode & MASK_ROUNDING_MODE) - { - default: - case ROUND_TO_NEAREST: - rounding_mode = float_round_nearest_even; -#if MAINTAIN_FPCR - fpa11->fpcr |= ROUND_TO_NEAREST; -#endif - break; - - case ROUND_TO_PLUS_INFINITY: - rounding_mode = float_round_up; -#if MAINTAIN_FPCR - fpa11->fpcr |= ROUND_TO_PLUS_INFINITY; -#endif - break; - - case ROUND_TO_MINUS_INFINITY: - rounding_mode = float_round_down; -#if MAINTAIN_FPCR - fpa11->fpcr |= ROUND_TO_MINUS_INFINITY; -#endif - break; - - case ROUND_TO_ZERO: - rounding_mode = float_round_to_zero; -#if MAINTAIN_FPCR - fpa11->fpcr |= ROUND_TO_ZERO; -#endif - break; - } - set_float_rounding_mode(rounding_mode, &fpa11->fp_status); -} - -void SetRoundingPrecision(const unsigned int opcode) -{ - int rounding_precision; - FPA11 *fpa11 = GET_FPA11(); -#if MAINTAIN_FPCR - fpa11->fpcr &= ~MASK_ROUNDING_PRECISION; -#endif - switch (opcode & MASK_ROUNDING_PRECISION) - { - case ROUND_SINGLE: - rounding_precision = 32; -#if MAINTAIN_FPCR - fpa11->fpcr |= ROUND_SINGLE; -#endif - break; - - case ROUND_DOUBLE: - rounding_precision = 64; -#if MAINTAIN_FPCR - fpa11->fpcr |= ROUND_DOUBLE; -#endif - break; - - case ROUND_EXTENDED: - rounding_precision = 80; -#if MAINTAIN_FPCR - fpa11->fpcr |= ROUND_EXTENDED; -#endif - break; - - default: rounding_precision = 80; - } - set_floatx80_rounding_precision(rounding_precision, &fpa11->fp_status); -} - -/* Emulate the instruction in the opcode. */ -/* ??? This is not thread safe. */ -unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) -{ - unsigned int nRc = 0; -// unsigned long flags; - FPA11 *fpa11; -// save_flags(flags); sti(); - - qemufpa=qfpa; - user_registers=qregs; - -#if 0 - fprintf(stderr,"emulating FP insn 0x%08x, PC=0x%08x\n", - opcode, qregs[REG_PC]); -#endif - fpa11 = GET_FPA11(); - - if (fpa11->initflag == 0) /* good place for __builtin_expect */ - { - resetFPA11(); - SetRoundingMode(ROUND_TO_NEAREST); - SetRoundingPrecision(ROUND_EXTENDED); - fpa11->initflag = 1; - } - - if (TEST_OPCODE(opcode,MASK_CPRT)) - { - //fprintf(stderr,"emulating CPRT\n"); - /* Emulate conversion opcodes. */ - /* Emulate register transfer opcodes. */ - /* Emulate comparison opcodes. */ - nRc = EmulateCPRT(opcode); - } - else if (TEST_OPCODE(opcode,MASK_CPDO)) - { - //fprintf(stderr,"emulating CPDO\n"); - /* Emulate monadic arithmetic opcodes. */ - /* Emulate dyadic arithmetic opcodes. */ - nRc = EmulateCPDO(opcode); - } - else if (TEST_OPCODE(opcode,MASK_CPDT)) - { - //fprintf(stderr,"emulating CPDT\n"); - /* Emulate load/store opcodes. */ - /* Emulate load/store multiple opcodes. */ - nRc = EmulateCPDT(opcode); - } - else - { - /* Invalid instruction detected. Return FALSE. */ - nRc = 0; - } - -// restore_flags(flags); - - //printf("returning %d\n",nRc); - return(nRc); -} - -#if 0 -unsigned int EmulateAll1(unsigned int opcode) -{ - switch ((opcode >> 24) & 0xf) - { - case 0xc: - case 0xd: - if ((opcode >> 20) & 0x1) - { - switch ((opcode >> 8) & 0xf) - { - case 0x1: return PerformLDF(opcode); break; - case 0x2: return PerformLFM(opcode); break; - default: return 0; - } - } - else - { - switch ((opcode >> 8) & 0xf) - { - case 0x1: return PerformSTF(opcode); break; - case 0x2: return PerformSFM(opcode); break; - default: return 0; - } - } - break; - - case 0xe: - if (opcode & 0x10) - return EmulateCPDO(opcode); - else - return EmulateCPRT(opcode); - break; - - default: return 0; - } -} -#endif - diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/nwfpe/fpa11_cpdo.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/nwfpe/fpa11_cpdo.c --- qemu-0.9.1/target-arm/nwfpe/fpa11_cpdo.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/nwfpe/fpa11_cpdo.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,117 +0,0 @@ -/* - NetWinder Floating Point Emulator - (c) Rebel.COM, 1998,1999 - - Direct questions, comments to Scott Bambrough - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "fpa11.h" -#include "fpopcode.h" - -unsigned int SingleCPDO(const unsigned int opcode); -unsigned int DoubleCPDO(const unsigned int opcode); -unsigned int ExtendedCPDO(const unsigned int opcode); - -unsigned int EmulateCPDO(const unsigned int opcode) -{ - FPA11 *fpa11 = GET_FPA11(); - unsigned int Fd, nType, nDest, nRc = 1; - - //printk("EmulateCPDO(0x%08x)\n",opcode); - - /* Get the destination size. If not valid let Linux perform - an invalid instruction trap. */ - nDest = getDestinationSize(opcode); - if (typeNone == nDest) return 0; - - SetRoundingMode(opcode); - - /* Compare the size of the operands in Fn and Fm. - Choose the largest size and perform operations in that size, - in order to make use of all the precision of the operands. - If Fm is a constant, we just grab a constant of a size - matching the size of the operand in Fn. */ - if (MONADIC_INSTRUCTION(opcode)) - nType = nDest; - else - nType = fpa11->fType[getFn(opcode)]; - - if (!CONSTANT_FM(opcode)) - { - register unsigned int Fm = getFm(opcode); - if (nType < fpa11->fType[Fm]) - { - nType = fpa11->fType[Fm]; - } - } - - switch (nType) - { - case typeSingle : nRc = SingleCPDO(opcode); break; - case typeDouble : nRc = DoubleCPDO(opcode); break; - case typeExtended : nRc = ExtendedCPDO(opcode); break; - default : nRc = 0; - } - - /* If the operation succeeded, check to see if the result in the - destination register is the correct size. If not force it - to be. */ - Fd = getFd(opcode); - nType = fpa11->fType[Fd]; - if ((0 != nRc) && (nDest != nType)) - { - switch (nDest) - { - case typeSingle: - { - if (typeDouble == nType) - fpa11->fpreg[Fd].fSingle = - float64_to_float32(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status); - else - fpa11->fpreg[Fd].fSingle = - floatx80_to_float32(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status); - } - break; - - case typeDouble: - { - if (typeSingle == nType) - fpa11->fpreg[Fd].fDouble = - float32_to_float64(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status); - else - fpa11->fpreg[Fd].fDouble = - floatx80_to_float64(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status); - } - break; - - case typeExtended: - { - if (typeSingle == nType) - fpa11->fpreg[Fd].fExtended = - float32_to_floatx80(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status); - else - fpa11->fpreg[Fd].fExtended = - float64_to_floatx80(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status); - } - break; - } - - fpa11->fType[Fd] = nDest; - } - - return nRc; -} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/nwfpe/fpa11_cpdt.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/nwfpe/fpa11_cpdt.c --- qemu-0.9.1/target-arm/nwfpe/fpa11_cpdt.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/nwfpe/fpa11_cpdt.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,386 +0,0 @@ -/* - NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 - (c) Philip Blundell, 1998 - - Direct questions, comments to Scott Bambrough - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "fpa11.h" -#include "softfloat.h" -#include "fpopcode.h" -//#include "fpmodule.h" -//#include "fpmodule.inl" - -//#include - -static inline -void loadSingle(const unsigned int Fn,const unsigned int *pMem) -{ - target_ulong addr = (target_ulong)(long)pMem; - FPA11 *fpa11 = GET_FPA11(); - fpa11->fType[Fn] = typeSingle; - /* FIXME - handle failure of get_user() */ - get_user_u32(fpa11->fpreg[Fn].fSingle, addr); -} - -static inline -void loadDouble(const unsigned int Fn,const unsigned int *pMem) -{ - target_ulong addr = (target_ulong)(long)pMem; - FPA11 *fpa11 = GET_FPA11(); - unsigned int *p; - p = (unsigned int*)&fpa11->fpreg[Fn].fDouble; - fpa11->fType[Fn] = typeDouble; -#ifdef WORDS_BIGENDIAN - /* FIXME - handle failure of get_user() */ - get_user_u32(p[0], addr); /* sign & exponent */ - get_user_u32(p[1], addr + 4); -#else - /* FIXME - handle failure of get_user() */ - get_user_u32(p[0], addr + 4); - get_user_u32(p[1], addr); /* sign & exponent */ -#endif -} - -static inline -void loadExtended(const unsigned int Fn,const unsigned int *pMem) -{ - target_ulong addr = (target_ulong)(long)pMem; - FPA11 *fpa11 = GET_FPA11(); - unsigned int *p; - p = (unsigned int*)&fpa11->fpreg[Fn].fExtended; - fpa11->fType[Fn] = typeExtended; - /* FIXME - handle failure of get_user() */ - get_user_u32(p[0], addr); /* sign & exponent */ - get_user_u32(p[1], addr + 8); /* ls bits */ - get_user_u32(p[2], addr + 4); /* ms bits */ -} - -static inline -void loadMultiple(const unsigned int Fn,const unsigned int *pMem) -{ - target_ulong addr = (target_ulong)(long)pMem; - FPA11 *fpa11 = GET_FPA11(); - register unsigned int *p; - unsigned long x; - - p = (unsigned int*)&(fpa11->fpreg[Fn]); - /* FIXME - handle failure of get_user() */ - get_user_u32(x, addr); - fpa11->fType[Fn] = (x >> 14) & 0x00000003; - - switch (fpa11->fType[Fn]) - { - case typeSingle: - case typeDouble: - { - /* FIXME - handle failure of get_user() */ - get_user_u32(p[0], addr + 8); /* Single */ - get_user_u32(p[1], addr + 4); /* double msw */ - p[2] = 0; /* empty */ - } - break; - - case typeExtended: - { - /* FIXME - handle failure of get_user() */ - get_user_u32(p[1], addr + 8); - get_user_u32(p[2], addr + 4); /* msw */ - p[0] = (x & 0x80003fff); - } - break; - } -} - -static inline -void storeSingle(const unsigned int Fn,unsigned int *pMem) -{ - target_ulong addr = (target_ulong)(long)pMem; - FPA11 *fpa11 = GET_FPA11(); - float32 val; - register unsigned int *p = (unsigned int*)&val; - - switch (fpa11->fType[Fn]) - { - case typeDouble: - val = float64_to_float32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); - break; - - case typeExtended: - val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status); - break; - - default: val = fpa11->fpreg[Fn].fSingle; - } - - /* FIXME - handle put_user() failures */ - put_user_u32(p[0], addr); -} - -static inline -void storeDouble(const unsigned int Fn,unsigned int *pMem) -{ - target_ulong addr = (target_ulong)(long)pMem; - FPA11 *fpa11 = GET_FPA11(); - float64 val; - register unsigned int *p = (unsigned int*)&val; - - switch (fpa11->fType[Fn]) - { - case typeSingle: - val = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); - break; - - case typeExtended: - val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status); - break; - - default: val = fpa11->fpreg[Fn].fDouble; - } - /* FIXME - handle put_user() failures */ -#ifdef WORDS_BIGENDIAN - put_user_u32(p[0], addr); /* msw */ - put_user_u32(p[1], addr + 4); /* lsw */ -#else - put_user_u32(p[1], addr); /* msw */ - put_user_u32(p[0], addr + 4); /* lsw */ -#endif -} - -static inline -void storeExtended(const unsigned int Fn,unsigned int *pMem) -{ - target_ulong addr = (target_ulong)(long)pMem; - FPA11 *fpa11 = GET_FPA11(); - floatx80 val; - register unsigned int *p = (unsigned int*)&val; - - switch (fpa11->fType[Fn]) - { - case typeSingle: - val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); - break; - - case typeDouble: - val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); - break; - - default: val = fpa11->fpreg[Fn].fExtended; - } - - /* FIXME - handle put_user() failures */ - put_user_u32(p[0], addr); /* sign & exp */ - put_user_u32(p[1], addr + 8); - put_user_u32(p[2], addr + 4); /* msw */ -} - -static inline -void storeMultiple(const unsigned int Fn,unsigned int *pMem) -{ - target_ulong addr = (target_ulong)(long)pMem; - FPA11 *fpa11 = GET_FPA11(); - register unsigned int nType, *p; - - p = (unsigned int*)&(fpa11->fpreg[Fn]); - nType = fpa11->fType[Fn]; - - switch (nType) - { - case typeSingle: - case typeDouble: - { - put_user_u32(p[0], addr + 8); /* single */ - put_user_u32(p[1], addr + 4); /* double msw */ - put_user_u32(nType << 14, addr); - } - break; - - case typeExtended: - { - put_user_u32(p[2], addr + 4); /* msw */ - put_user_u32(p[1], addr + 8); - put_user_u32((p[0] & 0x80003fff) | (nType << 14), addr); - } - break; - } -} - -unsigned int PerformLDF(const unsigned int opcode) -{ - unsigned int *pBase, *pAddress, *pFinal, nRc = 1, - write_back = WRITE_BACK(opcode); - - //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); - - pBase = (unsigned int*)readRegister(getRn(opcode)); - if (REG_PC == getRn(opcode)) - { - pBase += 2; - write_back = 0; - } - - pFinal = pBase; - if (BIT_UP_SET(opcode)) - pFinal += getOffset(opcode); - else - pFinal -= getOffset(opcode); - - if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; - - switch (opcode & MASK_TRANSFER_LENGTH) - { - case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break; - case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break; - case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break; - default: nRc = 0; - } - - if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); - return nRc; -} - -unsigned int PerformSTF(const unsigned int opcode) -{ - unsigned int *pBase, *pAddress, *pFinal, nRc = 1, - write_back = WRITE_BACK(opcode); - - //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); - SetRoundingMode(ROUND_TO_NEAREST); - - pBase = (unsigned int*)readRegister(getRn(opcode)); - if (REG_PC == getRn(opcode)) - { - pBase += 2; - write_back = 0; - } - - pFinal = pBase; - if (BIT_UP_SET(opcode)) - pFinal += getOffset(opcode); - else - pFinal -= getOffset(opcode); - - if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; - - switch (opcode & MASK_TRANSFER_LENGTH) - { - case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break; - case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break; - case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break; - default: nRc = 0; - } - - if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); - return nRc; -} - -unsigned int PerformLFM(const unsigned int opcode) -{ - unsigned int i, Fd, *pBase, *pAddress, *pFinal, - write_back = WRITE_BACK(opcode); - - pBase = (unsigned int*)readRegister(getRn(opcode)); - if (REG_PC == getRn(opcode)) - { - pBase += 2; - write_back = 0; - } - - pFinal = pBase; - if (BIT_UP_SET(opcode)) - pFinal += getOffset(opcode); - else - pFinal -= getOffset(opcode); - - if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; - - Fd = getFd(opcode); - for (i=getRegisterCount(opcode);i>0;i--) - { - loadMultiple(Fd,pAddress); - pAddress += 3; Fd++; - if (Fd == 8) Fd = 0; - } - - if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); - return 1; -} - -unsigned int PerformSFM(const unsigned int opcode) -{ - unsigned int i, Fd, *pBase, *pAddress, *pFinal, - write_back = WRITE_BACK(opcode); - - pBase = (unsigned int*)readRegister(getRn(opcode)); - if (REG_PC == getRn(opcode)) - { - pBase += 2; - write_back = 0; - } - - pFinal = pBase; - if (BIT_UP_SET(opcode)) - pFinal += getOffset(opcode); - else - pFinal -= getOffset(opcode); - - if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; - - Fd = getFd(opcode); - for (i=getRegisterCount(opcode);i>0;i--) - { - storeMultiple(Fd,pAddress); - pAddress += 3; Fd++; - if (Fd == 8) Fd = 0; - } - - if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); - return 1; -} - -#if 1 -unsigned int EmulateCPDT(const unsigned int opcode) -{ - unsigned int nRc = 0; - - //printk("EmulateCPDT(0x%08x)\n",opcode); - - if (LDF_OP(opcode)) - { - nRc = PerformLDF(opcode); - } - else if (LFM_OP(opcode)) - { - nRc = PerformLFM(opcode); - } - else if (STF_OP(opcode)) - { - nRc = PerformSTF(opcode); - } - else if (SFM_OP(opcode)) - { - nRc = PerformSFM(opcode); - } - else - { - nRc = 0; - } - - return nRc; -} -#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/nwfpe/fpa11_cprt.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/nwfpe/fpa11_cprt.c --- qemu-0.9.1/target-arm/nwfpe/fpa11_cprt.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/nwfpe/fpa11_cprt.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,286 +0,0 @@ -/* - NetWinder Floating Point Emulator - (c) Rebel.COM, 1998,1999 - (c) Philip Blundell, 1999 - - Direct questions, comments to Scott Bambrough - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "fpa11.h" -#include "softfloat.h" -#include "fpopcode.h" -#include "fpa11.inl" -//#include "fpmodule.h" -//#include "fpmodule.inl" - -void SetRoundingMode(const unsigned int opcode); - -unsigned int PerformFLT(const unsigned int opcode); -unsigned int PerformFIX(const unsigned int opcode); - -static unsigned int -PerformComparison(const unsigned int opcode); - -unsigned int EmulateCPRT(const unsigned int opcode) -{ - unsigned int nRc = 1; - - //printk("EmulateCPRT(0x%08x)\n",opcode); - - if (opcode & 0x800000) - { - /* This is some variant of a comparison (PerformComparison will - sort out which one). Since most of the other CPRT - instructions are oddball cases of some sort or other it makes - sense to pull this out into a fast path. */ - return PerformComparison(opcode); - } - - /* Hint to GCC that we'd like a jump table rather than a load of CMPs */ - switch ((opcode & 0x700000) >> 20) - { - case FLT_CODE >> 20: nRc = PerformFLT(opcode); break; - case FIX_CODE >> 20: nRc = PerformFIX(opcode); break; - - case WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break; - case RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break; - -#if 0 /* We currently have no use for the FPCR, so there's no point - in emulating it. */ - case WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode))); - case RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break; -#endif - - default: nRc = 0; - } - - return nRc; -} - -unsigned int PerformFLT(const unsigned int opcode) -{ - FPA11 *fpa11 = GET_FPA11(); - - unsigned int nRc = 1; - SetRoundingMode(opcode); - - switch (opcode & MASK_ROUNDING_PRECISION) - { - case ROUND_SINGLE: - { - fpa11->fType[getFn(opcode)] = typeSingle; - fpa11->fpreg[getFn(opcode)].fSingle = - int32_to_float32(readRegister(getRd(opcode)), &fpa11->fp_status); - } - break; - - case ROUND_DOUBLE: - { - fpa11->fType[getFn(opcode)] = typeDouble; - fpa11->fpreg[getFn(opcode)].fDouble = - int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status); - } - break; - - case ROUND_EXTENDED: - { - fpa11->fType[getFn(opcode)] = typeExtended; - fpa11->fpreg[getFn(opcode)].fExtended = - int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status); - } - break; - - default: nRc = 0; - } - - return nRc; -} - -unsigned int PerformFIX(const unsigned int opcode) -{ - FPA11 *fpa11 = GET_FPA11(); - unsigned int nRc = 1; - unsigned int Fn = getFm(opcode); - - SetRoundingMode(opcode); - - switch (fpa11->fType[Fn]) - { - case typeSingle: - { - writeRegister(getRd(opcode), - float32_to_int32(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status)); - } - break; - - case typeDouble: - { - //printf("F%d is 0x%" PRIx64 "\n",Fn,fpa11->fpreg[Fn].fDouble); - writeRegister(getRd(opcode), - float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status)); - } - break; - - case typeExtended: - { - writeRegister(getRd(opcode), - floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status)); - } - break; - - default: nRc = 0; - } - - return nRc; -} - - -static unsigned int __inline__ -PerformComparisonOperation(floatx80 Fn, floatx80 Fm) -{ - FPA11 *fpa11 = GET_FPA11(); - unsigned int flags = 0; - - /* test for less than condition */ - if (floatx80_lt(Fn,Fm, &fpa11->fp_status)) - { - flags |= CC_NEGATIVE; - } - - /* test for equal condition */ - if (floatx80_eq(Fn,Fm, &fpa11->fp_status)) - { - flags |= CC_ZERO; - } - - /* test for greater than or equal condition */ - if (floatx80_lt(Fm,Fn, &fpa11->fp_status)) - { - flags |= CC_CARRY; - } - - writeConditionCodes(flags); - return 1; -} - -/* This instruction sets the flags N, Z, C, V in the FPSR. */ - -static unsigned int PerformComparison(const unsigned int opcode) -{ - FPA11 *fpa11 = GET_FPA11(); - unsigned int Fn, Fm; - floatx80 rFn, rFm; - int e_flag = opcode & 0x400000; /* 1 if CxFE */ - int n_flag = opcode & 0x200000; /* 1 if CNxx */ - unsigned int flags = 0; - - //printk("PerformComparison(0x%08x)\n",opcode); - - Fn = getFn(opcode); - Fm = getFm(opcode); - - /* Check for unordered condition and convert all operands to 80-bit - format. - ?? Might be some mileage in avoiding this conversion if possible. - Eg, if both operands are 32-bit, detect this and do a 32-bit - comparison (cheaper than an 80-bit one). */ - switch (fpa11->fType[Fn]) - { - case typeSingle: - //printk("single.\n"); - if (float32_is_nan(fpa11->fpreg[Fn].fSingle)) - goto unordered; - rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); - break; - - case typeDouble: - //printk("double.\n"); - if (float64_is_nan(fpa11->fpreg[Fn].fDouble)) - goto unordered; - rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); - break; - - case typeExtended: - //printk("extended.\n"); - if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended)) - goto unordered; - rFn = fpa11->fpreg[Fn].fExtended; - break; - - default: return 0; - } - - if (CONSTANT_FM(opcode)) - { - //printk("Fm is a constant: #%d.\n",Fm); - rFm = getExtendedConstant(Fm); - if (floatx80_is_nan(rFm)) - goto unordered; - } - else - { - //printk("Fm = r%d which contains a ",Fm); - switch (fpa11->fType[Fm]) - { - case typeSingle: - //printk("single.\n"); - if (float32_is_nan(fpa11->fpreg[Fm].fSingle)) - goto unordered; - rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status); - break; - - case typeDouble: - //printk("double.\n"); - if (float64_is_nan(fpa11->fpreg[Fm].fDouble)) - goto unordered; - rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status); - break; - - case typeExtended: - //printk("extended.\n"); - if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended)) - goto unordered; - rFm = fpa11->fpreg[Fm].fExtended; - break; - - default: return 0; - } - } - - if (n_flag) - { - rFm.high ^= 0x8000; - } - - return PerformComparisonOperation(rFn,rFm); - - unordered: - /* ?? The FPA data sheet is pretty vague about this, in particular - about whether the non-E comparisons can ever raise exceptions. - This implementation is based on a combination of what it says in - the data sheet, observation of how the Acorn emulator actually - behaves (and how programs expect it to) and guesswork. */ - flags |= CC_OVERFLOW; - flags &= ~(CC_ZERO | CC_NEGATIVE); - - if (BIT_AC & readFPSR()) flags |= CC_CARRY; - - if (e_flag) float_raise(float_flag_invalid, &fpa11->fp_status); - - writeConditionCodes(flags); - return 1; -} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/nwfpe/fpa11.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/nwfpe/fpa11.h --- qemu-0.9.1/target-arm/nwfpe/fpa11.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/nwfpe/fpa11.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,122 +0,0 @@ -/* - NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 - - Direct questions, comments to Scott Bambrough - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __FPA11_H__ -#define __FPA11_H__ - -#include -#include -#include - -#include - -#define GET_FPA11() (qemufpa) - -/* - * The processes registers are always at the very top of the 8K - * stack+task struct. Use the same method as 'current' uses to - * reach them. - */ -extern CPUARMState *user_registers; - -#define GET_USERREG() (user_registers) - -/* Need task_struct */ -//#include - -/* includes */ -#include "fpsr.h" /* FP control and status register definitions */ -#include "softfloat.h" - -#define typeNone 0x00 -#define typeSingle 0x01 -#define typeDouble 0x02 -#define typeExtended 0x03 - -/* - * This must be no more and no less than 12 bytes. - */ -typedef union tagFPREG { - floatx80 fExtended; - float64 fDouble; - float32 fSingle; -} FPREG; - -/* - * FPA11 device model. - * - * This structure is exported to user space. Do not re-order. - * Only add new stuff to the end, and do not change the size of - * any element. Elements of this structure are used by user - * space, and must match struct user_fp in include/asm-arm/user.h. - * We include the byte offsets below for documentation purposes. - * - * The size of this structure and FPREG are checked by fpmodule.c - * on initialisation. If the rules have been broken, NWFPE will - * not initialise. - */ -typedef struct tagFPA11 { -/* 0 */ FPREG fpreg[8]; /* 8 floating point registers */ -/* 96 */ FPSR fpsr; /* floating point status register */ -/* 100 */ FPCR fpcr; /* floating point control register */ -/* 104 */ unsigned char fType[8]; /* type of floating point value held in - floating point registers. One of none - single, double or extended. */ -/* 112 */ int initflag; /* this is special. The kernel guarantees - to set it to 0 when a thread is launched, - so we can use it to detect whether this - instance of the emulator needs to be - initialised. */ - float_status fp_status; /* QEMU float emulator status */ -} FPA11; - -extern FPA11* qemufpa; - -extern void resetFPA11(void); -extern void SetRoundingMode(const unsigned int); -extern void SetRoundingPrecision(const unsigned int); - -static inline unsigned int readRegister(unsigned int reg) -{ - return (user_registers->regs[(reg)]); -} - -static inline void writeRegister(unsigned int x, unsigned int y) -{ -#if 0 - printf("writing %d to r%d\n",y,x); -#endif - user_registers->regs[(x)]=(y); -} - -static inline void writeConditionCodes(unsigned int x) -{ - cpsr_write(user_registers,x,CPSR_NZCV); -} - -#define REG_PC 15 - -unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs); - -/* included only for get_user/put_user macros */ -#include "qemu.h" - -#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/nwfpe/fpa11.inl /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/nwfpe/fpa11.inl --- qemu-0.9.1/target-arm/nwfpe/fpa11.inl 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/nwfpe/fpa11.inl 1970-01-01 01:00:00.000000000 +0100 @@ -1,51 +0,0 @@ -/* - NetWinder Floating Point Emulator - (c) Rebel.COM, 1998,1999 - - Direct questions, comments to Scott Bambrough - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "fpa11.h" - -/* Read and write floating point status register */ -static inline unsigned int readFPSR(void) -{ - FPA11 *fpa11 = GET_FPA11(); - return(fpa11->fpsr); -} - -static inline void writeFPSR(FPSR reg) -{ - FPA11 *fpa11 = GET_FPA11(); - /* the sysid byte in the status register is readonly */ - fpa11->fpsr = (fpa11->fpsr & MASK_SYSID) | (reg & ~MASK_SYSID); -} - -/* Read and write floating point control register */ -static inline FPCR readFPCR(void) -{ - FPA11 *fpa11 = GET_FPA11(); - /* clear SB, AB and DA bits before returning FPCR */ - return(fpa11->fpcr & ~MASK_RFC); -} - -static inline void writeFPCR(FPCR reg) -{ - FPA11 *fpa11 = GET_FPA11(); - fpa11->fpcr &= ~MASK_WFC; /* clear SB, AB and DA bits */ - fpa11->fpcr |= (reg & MASK_WFC); /* write SB, AB and DA bits */ -} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/nwfpe/fpopcode.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/nwfpe/fpopcode.c --- qemu-0.9.1/target-arm/nwfpe/fpopcode.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/nwfpe/fpopcode.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,148 +0,0 @@ -/* - NetWinder Floating Point Emulator - (c) Rebel.COM, 1998,1999 - - Direct questions, comments to Scott Bambrough - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "fpa11.h" -#include "softfloat.h" -#include "fpopcode.h" -#include "fpsr.h" -//#include "fpmodule.h" -//#include "fpmodule.inl" - -const floatx80 floatx80Constant[] = { - { 0x0000000000000000ULL, 0x0000}, /* extended 0.0 */ - { 0x8000000000000000ULL, 0x3fff}, /* extended 1.0 */ - { 0x8000000000000000ULL, 0x4000}, /* extended 2.0 */ - { 0xc000000000000000ULL, 0x4000}, /* extended 3.0 */ - { 0x8000000000000000ULL, 0x4001}, /* extended 4.0 */ - { 0xa000000000000000ULL, 0x4001}, /* extended 5.0 */ - { 0x8000000000000000ULL, 0x3ffe}, /* extended 0.5 */ - { 0xa000000000000000ULL, 0x4002} /* extended 10.0 */ -}; - -const float64 float64Constant[] = { - 0x0000000000000000ULL, /* double 0.0 */ - 0x3ff0000000000000ULL, /* double 1.0 */ - 0x4000000000000000ULL, /* double 2.0 */ - 0x4008000000000000ULL, /* double 3.0 */ - 0x4010000000000000ULL, /* double 4.0 */ - 0x4014000000000000ULL, /* double 5.0 */ - 0x3fe0000000000000ULL, /* double 0.5 */ - 0x4024000000000000ULL /* double 10.0 */ -}; - -const float32 float32Constant[] = { - 0x00000000, /* single 0.0 */ - 0x3f800000, /* single 1.0 */ - 0x40000000, /* single 2.0 */ - 0x40400000, /* single 3.0 */ - 0x40800000, /* single 4.0 */ - 0x40a00000, /* single 5.0 */ - 0x3f000000, /* single 0.5 */ - 0x41200000 /* single 10.0 */ -}; - -unsigned int getTransferLength(const unsigned int opcode) -{ - unsigned int nRc; - - switch (opcode & MASK_TRANSFER_LENGTH) - { - case 0x00000000: nRc = 1; break; /* single precision */ - case 0x00008000: nRc = 2; break; /* double precision */ - case 0x00400000: nRc = 3; break; /* extended precision */ - default: nRc = 0; - } - - return(nRc); -} - -unsigned int getRegisterCount(const unsigned int opcode) -{ - unsigned int nRc; - - switch (opcode & MASK_REGISTER_COUNT) - { - case 0x00000000: nRc = 4; break; - case 0x00008000: nRc = 1; break; - case 0x00400000: nRc = 2; break; - case 0x00408000: nRc = 3; break; - default: nRc = 0; - } - - return(nRc); -} - -unsigned int getRoundingPrecision(const unsigned int opcode) -{ - unsigned int nRc; - - switch (opcode & MASK_ROUNDING_PRECISION) - { - case 0x00000000: nRc = 1; break; - case 0x00000080: nRc = 2; break; - case 0x00080000: nRc = 3; break; - default: nRc = 0; - } - - return(nRc); -} - -unsigned int getDestinationSize(const unsigned int opcode) -{ - unsigned int nRc; - - switch (opcode & MASK_DESTINATION_SIZE) - { - case 0x00000000: nRc = typeSingle; break; - case 0x00000080: nRc = typeDouble; break; - case 0x00080000: nRc = typeExtended; break; - default: nRc = typeNone; - } - - return(nRc); -} - -/* condition code lookup table - index into the table is test code: EQ, NE, ... LT, GT, AL, NV - bit position in short is condition code: NZCV */ -static const unsigned short aCC[16] = { - 0xF0F0, // EQ == Z set - 0x0F0F, // NE - 0xCCCC, // CS == C set - 0x3333, // CC - 0xFF00, // MI == N set - 0x00FF, // PL - 0xAAAA, // VS == V set - 0x5555, // VC - 0x0C0C, // HI == C set && Z clear - 0xF3F3, // LS == C clear || Z set - 0xAA55, // GE == (N==V) - 0x55AA, // LT == (N!=V) - 0x0A05, // GT == (!Z && (N==V)) - 0xF5FA, // LE == (Z || (N!=V)) - 0xFFFF, // AL always - 0 // NV -}; - -unsigned int checkCondition(const unsigned int opcode, const unsigned int ccodes) -{ - return (aCC[opcode>>28] >> (ccodes>>28)) & 1; -} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/nwfpe/fpopcode.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/nwfpe/fpopcode.h --- qemu-0.9.1/target-arm/nwfpe/fpopcode.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/nwfpe/fpopcode.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,390 +0,0 @@ -/* - NetWinder Floating Point Emulator - (c) Rebel.COM, 1998,1999 - - Direct questions, comments to Scott Bambrough - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __FPOPCODE_H__ -#define __FPOPCODE_H__ - -/* -ARM Floating Point Instruction Classes -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | -|c o n d|1 1 0 P|U|u|W|L| Rn |v| Fd |0|0|0|1| o f f s e t | CPDT -|c o n d|1 1 0 P|U|w|W|L| Rn |x| Fd |0|0|0|1| o f f s e t | CPDT -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | -|c o n d|1 1 1 0|a|b|c|d|e| Fn |j| Fd |0|0|0|1|f|g|h|0|i| Fm | CPDO -|c o n d|1 1 1 0|a|b|c|L|e| Fn | Rd |0|0|0|1|f|g|h|1|i| Fm | CPRT -|c o n d|1 1 1 0|a|b|c|1|e| Fn |1|1|1|1|0|0|0|1|f|g|h|1|i| Fm | comparisons -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | - -CPDT data transfer instructions - LDF, STF, LFM, SFM - -CPDO dyadic arithmetic instructions - ADF, MUF, SUF, RSF, DVF, RDF, - POW, RPW, RMF, FML, FDV, FRD, POL - -CPDO monadic arithmetic instructions - MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP, - SIN, COS, TAN, ASN, ACS, ATN, URD, NRM - -CPRT joint arithmetic/data transfer instructions - FIX (arithmetic followed by load/store) - FLT (load/store followed by arithmetic) - CMF, CNF CMFE, CNFE (comparisons) - WFS, RFS (write/read floating point status register) - WFC, RFC (write/read floating point control register) - -cond condition codes -P pre/post index bit: 0 = postindex, 1 = preindex -U up/down bit: 0 = stack grows down, 1 = stack grows up -W write back bit: 1 = update base register (Rn) -L load/store bit: 0 = store, 1 = load -Rn base register -Rd destination/source register -Fd floating point destination register -Fn floating point source register -Fm floating point source register or floating point constant - -uv transfer length (TABLE 1) -wx register count (TABLE 2) -abcd arithmetic opcode (TABLES 3 & 4) -ef destination size (rounding precision) (TABLE 5) -gh rounding mode (TABLE 6) -j dyadic/monadic bit: 0 = dyadic, 1 = monadic -i constant bit: 1 = constant (TABLE 6) -*/ - -/* -TABLE 1 -+-------------------------+---+---+---------+---------+ -| Precision | u | v | FPSR.EP | length | -+-------------------------+---+---+---------+---------+ -| Single | 0 ü 0 | x | 1 words | -| Double | 1 ü 1 | x | 2 words | -| Extended | 1 ü 1 | x | 3 words | -| Packed decimal | 1 ü 1 | 0 | 3 words | -| Expanded packed decimal | 1 ü 1 | 1 | 4 words | -+-------------------------+---+---+---------+---------+ -Note: x = don't care -*/ - -/* -TABLE 2 -+---+---+---------------------------------+ -| w | x | Number of registers to transfer | -+---+---+---------------------------------+ -| 0 ü 1 | 1 | -| 1 ü 0 | 2 | -| 1 ü 1 | 3 | -| 0 ü 0 | 4 | -+---+---+---------------------------------+ -*/ - -/* -TABLE 3: Dyadic Floating Point Opcodes -+---+---+---+---+----------+-----------------------+-----------------------+ -| a | b | c | d | Mnemonic | Description | Operation | -+---+---+---+---+----------+-----------------------+-----------------------+ -| 0 | 0 | 0 | 0 | ADF | Add | Fd := Fn + Fm | -| 0 | 0 | 0 | 1 | MUF | Multiply | Fd := Fn * Fm | -| 0 | 0 | 1 | 0 | SUF | Subtract | Fd := Fn - Fm | -| 0 | 0 | 1 | 1 | RSF | Reverse subtract | Fd := Fm - Fn | -| 0 | 1 | 0 | 0 | DVF | Divide | Fd := Fn / Fm | -| 0 | 1 | 0 | 1 | RDF | Reverse divide | Fd := Fm / Fn | -| 0 | 1 | 1 | 0 | POW | Power | Fd := Fn ^ Fm | -| 0 | 1 | 1 | 1 | RPW | Reverse power | Fd := Fm ^ Fn | -| 1 | 0 | 0 | 0 | RMF | Remainder | Fd := IEEE rem(Fn/Fm) | -| 1 | 0 | 0 | 1 | FML | Fast Multiply | Fd := Fn * Fm | -| 1 | 0 | 1 | 0 | FDV | Fast Divide | Fd := Fn / Fm | -| 1 | 0 | 1 | 1 | FRD | Fast reverse divide | Fd := Fm / Fn | -| 1 | 1 | 0 | 0 | POL | Polar angle (ArcTan2) | Fd := arctan2(Fn,Fm) | -| 1 | 1 | 0 | 1 | | undefined instruction | trap | -| 1 | 1 | 1 | 0 | | undefined instruction | trap | -| 1 | 1 | 1 | 1 | | undefined instruction | trap | -+---+---+---+---+----------+-----------------------+-----------------------+ -Note: POW, RPW, POL are deprecated, and are available for backwards - compatibility only. -*/ - -/* -TABLE 4: Monadic Floating Point Opcodes -+---+---+---+---+----------+-----------------------+-----------------------+ -| a | b | c | d | Mnemonic | Description | Operation | -+---+---+---+---+----------+-----------------------+-----------------------+ -| 0 | 0 | 0 | 0 | MVF | Move | Fd := Fm | -| 0 | 0 | 0 | 1 | MNF | Move negated | Fd := - Fm | -| 0 | 0 | 1 | 0 | ABS | Absolute value | Fd := abs(Fm) | -| 0 | 0 | 1 | 1 | RND | Round to integer | Fd := int(Fm) | -| 0 | 1 | 0 | 0 | SQT | Square root | Fd := sqrt(Fm) | -| 0 | 1 | 0 | 1 | LOG | Log base 10 | Fd := log10(Fm) | -| 0 | 1 | 1 | 0 | LGN | Log base e | Fd := ln(Fm) | -| 0 | 1 | 1 | 1 | EXP | Exponent | Fd := e ^ Fm | -| 1 | 0 | 0 | 0 | SIN | Sine | Fd := sin(Fm) | -| 1 | 0 | 0 | 1 | COS | Cosine | Fd := cos(Fm) | -| 1 | 0 | 1 | 0 | TAN | Tangent | Fd := tan(Fm) | -| 1 | 0 | 1 | 1 | ASN | Arc Sine | Fd := arcsin(Fm) | -| 1 | 1 | 0 | 0 | ACS | Arc Cosine | Fd := arccos(Fm) | -| 1 | 1 | 0 | 1 | ATN | Arc Tangent | Fd := arctan(Fm) | -| 1 | 1 | 1 | 0 | URD | Unnormalized round | Fd := int(Fm) | -| 1 | 1 | 1 | 1 | NRM | Normalize | Fd := norm(Fm) | -+---+---+---+---+----------+-----------------------+-----------------------+ -Note: LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN are deprecated, and are - available for backwards compatibility only. -*/ - -/* -TABLE 5 -+-------------------------+---+---+ -| Rounding Precision | e | f | -+-------------------------+---+---+ -| IEEE Single precision | 0 ü 0 | -| IEEE Double precision | 0 ü 1 | -| IEEE Extended precision | 1 ü 0 | -| undefined (trap) | 1 ü 1 | -+-------------------------+---+---+ -*/ - -/* -TABLE 5 -+---------------------------------+---+---+ -| Rounding Mode | g | h | -+---------------------------------+---+---+ -| Round to nearest (default) | 0 ü 0 | -| Round toward plus infinity | 0 ü 1 | -| Round toward negative infinity | 1 ü 0 | -| Round toward zero | 1 ü 1 | -+---------------------------------+---+---+ -*/ - -/* -=== -=== Definitions for load and store instructions -=== -*/ - -/* bit masks */ -#define BIT_PREINDEX 0x01000000 -#define BIT_UP 0x00800000 -#define BIT_WRITE_BACK 0x00200000 -#define BIT_LOAD 0x00100000 - -/* masks for load/store */ -#define MASK_CPDT 0x0c000000 /* data processing opcode */ -#define MASK_OFFSET 0x000000ff -#define MASK_TRANSFER_LENGTH 0x00408000 -#define MASK_REGISTER_COUNT MASK_TRANSFER_LENGTH -#define MASK_COPROCESSOR 0x00000f00 - -/* Tests for transfer length */ -#define TRANSFER_SINGLE 0x00000000 -#define TRANSFER_DOUBLE 0x00008000 -#define TRANSFER_EXTENDED 0x00400000 -#define TRANSFER_PACKED MASK_TRANSFER_LENGTH - -/* Get the coprocessor number from the opcode. */ -#define getCoprocessorNumber(opcode) ((opcode & MASK_COPROCESSOR) >> 8) - -/* Get the offset from the opcode. */ -#define getOffset(opcode) (opcode & MASK_OFFSET) - -/* Tests for specific data transfer load/store opcodes. */ -#define TEST_OPCODE(opcode,mask) (((opcode) & (mask)) == (mask)) - -#define LOAD_OP(opcode) TEST_OPCODE((opcode),MASK_CPDT | BIT_LOAD) -#define STORE_OP(opcode) ((opcode & (MASK_CPDT | BIT_LOAD)) == MASK_CPDT) - -#define LDF_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 1)) -#define LFM_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 2)) -#define STF_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 1)) -#define SFM_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 2)) - -#define PREINDEXED(opcode) ((opcode & BIT_PREINDEX) != 0) -#define POSTINDEXED(opcode) ((opcode & BIT_PREINDEX) == 0) -#define BIT_UP_SET(opcode) ((opcode & BIT_UP) != 0) -#define BIT_UP_CLEAR(opcode) ((opcode & BIT_DOWN) == 0) -#define WRITE_BACK(opcode) ((opcode & BIT_WRITE_BACK) != 0) -#define LOAD(opcode) ((opcode & BIT_LOAD) != 0) -#define STORE(opcode) ((opcode & BIT_LOAD) == 0) - -/* -=== -=== Definitions for arithmetic instructions -=== -*/ -/* bit masks */ -#define BIT_MONADIC 0x00008000 -#define BIT_CONSTANT 0x00000008 - -#define CONSTANT_FM(opcode) ((opcode & BIT_CONSTANT) != 0) -#define MONADIC_INSTRUCTION(opcode) ((opcode & BIT_MONADIC) != 0) - -/* instruction identification masks */ -#define MASK_CPDO 0x0e000000 /* arithmetic opcode */ -#define MASK_ARITHMETIC_OPCODE 0x00f08000 -#define MASK_DESTINATION_SIZE 0x00080080 - -/* dyadic arithmetic opcodes. */ -#define ADF_CODE 0x00000000 -#define MUF_CODE 0x00100000 -#define SUF_CODE 0x00200000 -#define RSF_CODE 0x00300000 -#define DVF_CODE 0x00400000 -#define RDF_CODE 0x00500000 -#define POW_CODE 0x00600000 -#define RPW_CODE 0x00700000 -#define RMF_CODE 0x00800000 -#define FML_CODE 0x00900000 -#define FDV_CODE 0x00a00000 -#define FRD_CODE 0x00b00000 -#define POL_CODE 0x00c00000 -/* 0x00d00000 is an invalid dyadic arithmetic opcode */ -/* 0x00e00000 is an invalid dyadic arithmetic opcode */ -/* 0x00f00000 is an invalid dyadic arithmetic opcode */ - -/* monadic arithmetic opcodes. */ -#define MVF_CODE 0x00008000 -#define MNF_CODE 0x00108000 -#define ABS_CODE 0x00208000 -#define RND_CODE 0x00308000 -#define SQT_CODE 0x00408000 -#define LOG_CODE 0x00508000 -#define LGN_CODE 0x00608000 -#define EXP_CODE 0x00708000 -#define SIN_CODE 0x00808000 -#define COS_CODE 0x00908000 -#define TAN_CODE 0x00a08000 -#define ASN_CODE 0x00b08000 -#define ACS_CODE 0x00c08000 -#define ATN_CODE 0x00d08000 -#define URD_CODE 0x00e08000 -#define NRM_CODE 0x00f08000 - -/* -=== -=== Definitions for register transfer and comparison instructions -=== -*/ - -#define MASK_CPRT 0x0e000010 /* register transfer opcode */ -#define MASK_CPRT_CODE 0x00f00000 -#define FLT_CODE 0x00000000 -#define FIX_CODE 0x00100000 -#define WFS_CODE 0x00200000 -#define RFS_CODE 0x00300000 -#define WFC_CODE 0x00400000 -#define RFC_CODE 0x00500000 -#define CMF_CODE 0x00900000 -#define CNF_CODE 0x00b00000 -#define CMFE_CODE 0x00d00000 -#define CNFE_CODE 0x00f00000 - -/* -=== -=== Common definitions -=== -*/ - -/* register masks */ -#define MASK_Rd 0x0000f000 -#define MASK_Rn 0x000f0000 -#define MASK_Fd 0x00007000 -#define MASK_Fm 0x00000007 -#define MASK_Fn 0x00070000 - -/* condition code masks */ -#define CC_MASK 0xf0000000 -#define CC_NEGATIVE 0x80000000 -#define CC_ZERO 0x40000000 -#define CC_CARRY 0x20000000 -#define CC_OVERFLOW 0x10000000 -#define CC_EQ 0x00000000 -#define CC_NE 0x10000000 -#define CC_CS 0x20000000 -#define CC_HS CC_CS -#define CC_CC 0x30000000 -#define CC_LO CC_CC -#define CC_MI 0x40000000 -#define CC_PL 0x50000000 -#define CC_VS 0x60000000 -#define CC_VC 0x70000000 -#define CC_HI 0x80000000 -#define CC_LS 0x90000000 -#define CC_GE 0xa0000000 -#define CC_LT 0xb0000000 -#define CC_GT 0xc0000000 -#define CC_LE 0xd0000000 -#define CC_AL 0xe0000000 -#define CC_NV 0xf0000000 - -/* rounding masks/values */ -#define MASK_ROUNDING_MODE 0x00000060 -#define ROUND_TO_NEAREST 0x00000000 -#define ROUND_TO_PLUS_INFINITY 0x00000020 -#define ROUND_TO_MINUS_INFINITY 0x00000040 -#define ROUND_TO_ZERO 0x00000060 - -#define MASK_ROUNDING_PRECISION 0x00080080 -#define ROUND_SINGLE 0x00000000 -#define ROUND_DOUBLE 0x00000080 -#define ROUND_EXTENDED 0x00080000 - -/* Get the condition code from the opcode. */ -#define getCondition(opcode) (opcode >> 28) - -/* Get the source register from the opcode. */ -#define getRn(opcode) ((opcode & MASK_Rn) >> 16) - -/* Get the destination floating point register from the opcode. */ -#define getFd(opcode) ((opcode & MASK_Fd) >> 12) - -/* Get the first source floating point register from the opcode. */ -#define getFn(opcode) ((opcode & MASK_Fn) >> 16) - -/* Get the second source floating point register from the opcode. */ -#define getFm(opcode) (opcode & MASK_Fm) - -/* Get the destination register from the opcode. */ -#define getRd(opcode) ((opcode & MASK_Rd) >> 12) - -/* Get the rounding mode from the opcode. */ -#define getRoundingMode(opcode) ((opcode & MASK_ROUNDING_MODE) >> 5) - -static inline const floatx80 getExtendedConstant(const unsigned int nIndex) -{ - extern const floatx80 floatx80Constant[]; - return floatx80Constant[nIndex]; -} - -static inline const float64 getDoubleConstant(const unsigned int nIndex) -{ - extern const float64 float64Constant[]; - return float64Constant[nIndex]; -} - -static inline const float32 getSingleConstant(const unsigned int nIndex) -{ - extern const float32 float32Constant[]; - return float32Constant[nIndex]; -} - -extern unsigned int getRegisterCount(const unsigned int opcode); -extern unsigned int getDestinationSize(const unsigned int opcode); - -#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/nwfpe/fpsr.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/nwfpe/fpsr.h --- qemu-0.9.1/target-arm/nwfpe/fpsr.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/nwfpe/fpsr.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,108 +0,0 @@ -/* - NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 - - Direct questions, comments to Scott Bambrough - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __FPSR_H__ -#define __FPSR_H__ - -/* -The FPSR is a 32 bit register consisting of 4 parts, each exactly -one byte. - - SYSTEM ID - EXCEPTION TRAP ENABLE BYTE - SYSTEM CONTROL BYTE - CUMULATIVE EXCEPTION FLAGS BYTE - -The FPCR is a 32 bit register consisting of bit flags. -*/ - -/* SYSTEM ID ------------- -Note: the system id byte is read only */ - -typedef unsigned int FPSR; /* type for floating point status register */ -typedef unsigned int FPCR; /* type for floating point control register */ - -#define MASK_SYSID 0xff000000 -#define BIT_HARDWARE 0x80000000 -#define FP_EMULATOR 0x01000000 /* System ID for emulator */ -#define FP_ACCELERATOR 0x81000000 /* System ID for FPA11 */ - -/* EXCEPTION TRAP ENABLE BYTE ------------------------------ */ - -#define MASK_TRAP_ENABLE 0x00ff0000 -#define MASK_TRAP_ENABLE_STRICT 0x001f0000 -#define BIT_IXE 0x00100000 /* inexact exception enable */ -#define BIT_UFE 0x00080000 /* underflow exception enable */ -#define BIT_OFE 0x00040000 /* overflow exception enable */ -#define BIT_DZE 0x00020000 /* divide by zero exception enable */ -#define BIT_IOE 0x00010000 /* invalid operation exception enable */ - -/* SYSTEM CONTROL BYTE ----------------------- */ - -#define MASK_SYSTEM_CONTROL 0x0000ff00 -#define MASK_TRAP_STRICT 0x00001f00 - -#define BIT_AC 0x00001000 /* use alternative C-flag definition - for compares */ -#define BIT_EP 0x00000800 /* use expanded packed decimal format */ -#define BIT_SO 0x00000400 /* select synchronous operation of FPA */ -#define BIT_NE 0x00000200 /* NaN exception bit */ -#define BIT_ND 0x00000100 /* no denormalized numbers bit */ - -/* CUMULATIVE EXCEPTION FLAGS BYTE ----------------------------------- */ - -#define MASK_EXCEPTION_FLAGS 0x000000ff -#define MASK_EXCEPTION_FLAGS_STRICT 0x0000001f - -#define BIT_IXC 0x00000010 /* inexact exception flag */ -#define BIT_UFC 0x00000008 /* underflow exception flag */ -#define BIT_OFC 0x00000004 /* overfloat exception flag */ -#define BIT_DZC 0x00000002 /* divide by zero exception flag */ -#define BIT_IOC 0x00000001 /* invalid operation exception flag */ - -/* Floating Point Control Register -----------------------------------*/ - -#define BIT_RU 0x80000000 /* rounded up bit */ -#define BIT_IE 0x10000000 /* inexact bit */ -#define BIT_MO 0x08000000 /* mantissa overflow bit */ -#define BIT_EO 0x04000000 /* exponent overflow bit */ -#define BIT_SB 0x00000800 /* store bounce */ -#define BIT_AB 0x00000400 /* arithmetic bounce */ -#define BIT_RE 0x00000200 /* rounding exception */ -#define BIT_DA 0x00000100 /* disable FPA */ - -#define MASK_OP 0x00f08010 /* AU operation code */ -#define MASK_PR 0x00080080 /* AU precision */ -#define MASK_S1 0x00070000 /* AU source register 1 */ -#define MASK_S2 0x00000007 /* AU source register 2 */ -#define MASK_DS 0x00007000 /* AU destination register */ -#define MASK_RM 0x00000060 /* AU rounding mode */ -#define MASK_ALU 0x9cfff2ff /* only ALU can write these bits */ -#define MASK_RESET 0x00000d00 /* bits set on reset, all others cleared */ -#define MASK_WFC MASK_RESET -#define MASK_RFC ~MASK_RESET - -#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/nwfpe/single_cpdo.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/nwfpe/single_cpdo.c --- qemu-0.9.1/target-arm/nwfpe/single_cpdo.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/nwfpe/single_cpdo.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,253 +0,0 @@ -/* - NetWinder Floating Point Emulator - (c) Rebel.COM, 1998,1999 - - Direct questions, comments to Scott Bambrough - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "fpa11.h" -#include "softfloat.h" -#include "fpopcode.h" - -float32 float32_exp(float32 Fm); -float32 float32_ln(float32 Fm); -float32 float32_sin(float32 rFm); -float32 float32_cos(float32 rFm); -float32 float32_arcsin(float32 rFm); -float32 float32_arctan(float32 rFm); -float32 float32_log(float32 rFm); -float32 float32_tan(float32 rFm); -float32 float32_arccos(float32 rFm); -float32 float32_pow(float32 rFn,float32 rFm); -float32 float32_pol(float32 rFn,float32 rFm); - -unsigned int SingleCPDO(const unsigned int opcode) -{ - FPA11 *fpa11 = GET_FPA11(); - float32 rFm, rFn = float32_zero; - unsigned int Fd, Fm, Fn, nRc = 1; - - Fm = getFm(opcode); - if (CONSTANT_FM(opcode)) - { - rFm = getSingleConstant(Fm); - } - else - { - switch (fpa11->fType[Fm]) - { - case typeSingle: - rFm = fpa11->fpreg[Fm].fSingle; - break; - - default: return 0; - } - } - - if (!MONADIC_INSTRUCTION(opcode)) - { - Fn = getFn(opcode); - switch (fpa11->fType[Fn]) - { - case typeSingle: - rFn = fpa11->fpreg[Fn].fSingle; - break; - - default: return 0; - } - } - - Fd = getFd(opcode); - switch (opcode & MASK_ARITHMETIC_OPCODE) - { - /* dyadic opcodes */ - case ADF_CODE: - fpa11->fpreg[Fd].fSingle = float32_add(rFn,rFm, &fpa11->fp_status); - break; - - case MUF_CODE: - case FML_CODE: - fpa11->fpreg[Fd].fSingle = float32_mul(rFn,rFm, &fpa11->fp_status); - break; - - case SUF_CODE: - fpa11->fpreg[Fd].fSingle = float32_sub(rFn,rFm, &fpa11->fp_status); - break; - - case RSF_CODE: - fpa11->fpreg[Fd].fSingle = float32_sub(rFm,rFn, &fpa11->fp_status); - break; - - case DVF_CODE: - case FDV_CODE: - fpa11->fpreg[Fd].fSingle = float32_div(rFn,rFm, &fpa11->fp_status); - break; - - case RDF_CODE: - case FRD_CODE: - fpa11->fpreg[Fd].fSingle = float32_div(rFm,rFn, &fpa11->fp_status); - break; - -#if 0 - case POW_CODE: - fpa11->fpreg[Fd].fSingle = float32_pow(rFn,rFm); - break; - - case RPW_CODE: - fpa11->fpreg[Fd].fSingle = float32_pow(rFm,rFn); - break; -#endif - - case RMF_CODE: - fpa11->fpreg[Fd].fSingle = float32_rem(rFn,rFm, &fpa11->fp_status); - break; - -#if 0 - case POL_CODE: - fpa11->fpreg[Fd].fSingle = float32_pol(rFn,rFm); - break; -#endif - - /* monadic opcodes */ - case MVF_CODE: - fpa11->fpreg[Fd].fSingle = rFm; - break; - - case MNF_CODE: - fpa11->fpreg[Fd].fSingle = float32_chs(rFm); - break; - - case ABS_CODE: - fpa11->fpreg[Fd].fSingle = float32_abs(rFm); - break; - - case RND_CODE: - case URD_CODE: - fpa11->fpreg[Fd].fSingle = float32_round_to_int(rFm, &fpa11->fp_status); - break; - - case SQT_CODE: - fpa11->fpreg[Fd].fSingle = float32_sqrt(rFm, &fpa11->fp_status); - break; - -#if 0 - case LOG_CODE: - fpa11->fpreg[Fd].fSingle = float32_log(rFm); - break; - - case LGN_CODE: - fpa11->fpreg[Fd].fSingle = float32_ln(rFm); - break; - - case EXP_CODE: - fpa11->fpreg[Fd].fSingle = float32_exp(rFm); - break; - - case SIN_CODE: - fpa11->fpreg[Fd].fSingle = float32_sin(rFm); - break; - - case COS_CODE: - fpa11->fpreg[Fd].fSingle = float32_cos(rFm); - break; - - case TAN_CODE: - fpa11->fpreg[Fd].fSingle = float32_tan(rFm); - break; - - case ASN_CODE: - fpa11->fpreg[Fd].fSingle = float32_arcsin(rFm); - break; - - case ACS_CODE: - fpa11->fpreg[Fd].fSingle = float32_arccos(rFm); - break; - - case ATN_CODE: - fpa11->fpreg[Fd].fSingle = float32_arctan(rFm); - break; -#endif - - case NRM_CODE: - break; - - default: - { - nRc = 0; - } - } - - if (0 != nRc) fpa11->fType[Fd] = typeSingle; - return nRc; -} - -#if 0 -float32 float32_exp(float32 Fm) -{ -//series -} - -float32 float32_ln(float32 Fm) -{ -//series -} - -float32 float32_sin(float32 rFm) -{ -//series -} - -float32 float32_cos(float32 rFm) -{ -//series -} - -float32 float32_arcsin(float32 rFm) -{ -//series -} - -float32 float32_arctan(float32 rFm) -{ - //series -} - -float32 float32_arccos(float32 rFm) -{ - //return float32_sub(halfPi,float32_arcsin(rFm)); -} - -float32 float32_log(float32 rFm) -{ - return float32_div(float32_ln(rFm),getSingleConstant(7)); -} - -float32 float32_tan(float32 rFm) -{ - return float32_div(float32_sin(rFm),float32_cos(rFm)); -} - -float32 float32_pow(float32 rFn,float32 rFm) -{ - return float32_exp(float32_mul(rFm,float32_ln(rFn))); -} - -float32 float32_pol(float32 rFn,float32 rFm) -{ - return float32_arctan(float32_div(rFn,rFm)); -} -#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/op_addsub.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/op_addsub.h --- qemu-0.9.1/target-arm/op_addsub.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/op_addsub.h 2008-03-31 04:46:33.000000000 +0100 @@ -8,9 +8,11 @@ */ #ifdef ARITH_GE +#define GE_ARG , uint32_t *gep #define DECLARE_GE uint32_t ge = 0 -#define SET_GE env->GE = ge +#define SET_GE *gep = ge #else +#define GE_ARG #define DECLARE_GE do{}while(0) #define SET_GE do{}while(0) #endif @@ -18,82 +20,77 @@ #define RESULT(val, n, width) \ res |= ((uint32_t)(glue(glue(uint,width),_t))(val)) << (n * width) -void OPPROTO glue(glue(op_,PFX),add16_T0_T1)(void) +uint32_t HELPER(glue(PFX,add16))(uint32_t a, uint32_t b GE_ARG) { uint32_t res = 0; DECLARE_GE; - ADD16(T0, T1, 0); - ADD16(T0 >> 16, T1 >> 16, 1); + ADD16(a, b, 0); + ADD16(a >> 16, b >> 16, 1); SET_GE; - T0 = res; - FORCE_RET(); + return res; } -void OPPROTO glue(glue(op_,PFX),add8_T0_T1)(void) +uint32_t HELPER(glue(PFX,add8))(uint32_t a, uint32_t b GE_ARG) { uint32_t res = 0; DECLARE_GE; - ADD8(T0, T1, 0); - ADD8(T0 >> 8, T1 >> 8, 1); - ADD8(T0 >> 16, T1 >> 16, 2); - ADD8(T0 >> 24, T1 >> 24, 3); + ADD8(a, b, 0); + ADD8(a >> 8, b >> 8, 1); + ADD8(a >> 16, b >> 16, 2); + ADD8(a >> 24, b >> 24, 3); SET_GE; - T0 = res; - FORCE_RET(); + return res; } -void OPPROTO glue(glue(op_,PFX),sub16_T0_T1)(void) +uint32_t HELPER(glue(PFX,sub16))(uint32_t a, uint32_t b GE_ARG) { uint32_t res = 0; DECLARE_GE; - SUB16(T0, T1, 0); - SUB16(T0 >> 16, T1 >> 16, 1); + SUB16(a, b, 0); + SUB16(a >> 16, b >> 16, 1); SET_GE; - T0 = res; - FORCE_RET(); + return res; } -void OPPROTO glue(glue(op_,PFX),sub8_T0_T1)(void) +uint32_t HELPER(glue(PFX,sub8))(uint32_t a, uint32_t b GE_ARG) { uint32_t res = 0; DECLARE_GE; - SUB8(T0, T1, 0); - SUB8(T0 >> 8, T1 >> 8, 1); - SUB8(T0 >> 16, T1 >> 16, 2); - SUB8(T0 >> 24, T1 >> 24, 3); + SUB8(a, b, 0); + SUB8(a >> 8, b >> 8, 1); + SUB8(a >> 16, b >> 16, 2); + SUB8(a >> 24, b >> 24, 3); SET_GE; - T0 = res; - FORCE_RET(); + return res; } -void OPPROTO glue(glue(op_,PFX),subaddx_T0_T1)(void) +uint32_t HELPER(glue(PFX,subaddx))(uint32_t a, uint32_t b GE_ARG) { uint32_t res = 0; DECLARE_GE; - ADD16(T0, T1, 0); - SUB16(T0 >> 16, T1 >> 16, 1); + ADD16(a, b, 0); + SUB16(a >> 16, b >> 16, 1); SET_GE; - T0 = res; - FORCE_RET(); + return res; } -void OPPROTO glue(glue(op_,PFX),addsubx_T0_T1)(void) +uint32_t HELPER(glue(PFX,addsubx))(uint32_t a, uint32_t b GE_ARG) { uint32_t res = 0; DECLARE_GE; - SUB16(T0, T1, 0); - ADD16(T0 >> 16, T1 >> 16, 1); + SUB16(a, b, 0); + ADD16(a >> 16, b >> 16, 1); SET_GE; - T0 = res; - FORCE_RET(); + return res; } +#undef GE_ARG #undef DECLARE_GE #undef SET_GE #undef RESULT diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/op.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/op.c --- qemu-0.9.1/target-arm/op.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/op.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,1923 +0,0 @@ -/* - * ARM micro operations - * - * Copyright (c) 2003 Fabrice Bellard - * Copyright (c) 2005-2007 CodeSourcery, LLC - * - * 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 "exec.h" - -#define REGNAME r0 -#define REG (env->regs[0]) -#include "op_template.h" - -#define REGNAME r1 -#define REG (env->regs[1]) -#include "op_template.h" - -#define REGNAME r2 -#define REG (env->regs[2]) -#include "op_template.h" - -#define REGNAME r3 -#define REG (env->regs[3]) -#include "op_template.h" - -#define REGNAME r4 -#define REG (env->regs[4]) -#include "op_template.h" - -#define REGNAME r5 -#define REG (env->regs[5]) -#include "op_template.h" - -#define REGNAME r6 -#define REG (env->regs[6]) -#include "op_template.h" - -#define REGNAME r7 -#define REG (env->regs[7]) -#include "op_template.h" - -#define REGNAME r8 -#define REG (env->regs[8]) -#include "op_template.h" - -#define REGNAME r9 -#define REG (env->regs[9]) -#include "op_template.h" - -#define REGNAME r10 -#define REG (env->regs[10]) -#include "op_template.h" - -#define REGNAME r11 -#define REG (env->regs[11]) -#include "op_template.h" - -#define REGNAME r12 -#define REG (env->regs[12]) -#include "op_template.h" - -#define REGNAME r13 -#define REG (env->regs[13]) -#include "op_template.h" - -#define REGNAME r14 -#define REG (env->regs[14]) -#include "op_template.h" - -#define REGNAME r15 -#define REG (env->regs[15]) -#define SET_REG(x) REG = x & ~(uint32_t)1 -#include "op_template.h" - -void OPPROTO op_bx_T0(void) -{ - env->regs[15] = T0 & ~(uint32_t)1; - env->thumb = (T0 & 1) != 0; -} - -void OPPROTO op_movl_T0_0(void) -{ - T0 = 0; -} - -void OPPROTO op_movl_T0_im(void) -{ - T0 = PARAM1; -} - -void OPPROTO op_movl_T1_im(void) -{ - T1 = PARAM1; -} - -void OPPROTO op_mov_CF_T1(void) -{ - env->CF = ((uint32_t)T1) >> 31; -} - -void OPPROTO op_movl_T2_im(void) -{ - T2 = PARAM1; -} - -void OPPROTO op_addl_T1_im(void) -{ - T1 += PARAM1; -} - -void OPPROTO op_addl_T1_T2(void) -{ - T1 += T2; -} - -void OPPROTO op_subl_T1_T2(void) -{ - T1 -= T2; -} - -void OPPROTO op_addl_T0_T1(void) -{ - T0 += T1; -} - -void OPPROTO op_addl_T0_T1_cc(void) -{ - unsigned int src1; - src1 = T0; - T0 += T1; - env->NZF = T0; - env->CF = T0 < src1; - env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); -} - -void OPPROTO op_adcl_T0_T1(void) -{ - T0 += T1 + env->CF; -} - -void OPPROTO op_adcl_T0_T1_cc(void) -{ - unsigned int src1; - src1 = T0; - if (!env->CF) { - T0 += T1; - env->CF = T0 < src1; - } else { - T0 += T1 + 1; - env->CF = T0 <= src1; - } - env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); - env->NZF = T0; - FORCE_RET(); -} - -#define OPSUB(sub, sbc, res, T0, T1) \ - \ -void OPPROTO op_ ## sub ## l_T0_T1(void) \ -{ \ - res = T0 - T1; \ -} \ - \ -void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \ -{ \ - unsigned int src1; \ - src1 = T0; \ - T0 -= T1; \ - env->NZF = T0; \ - env->CF = src1 >= T1; \ - env->VF = (src1 ^ T1) & (src1 ^ T0); \ - res = T0; \ -} \ - \ -void OPPROTO op_ ## sbc ## l_T0_T1(void) \ -{ \ - res = T0 - T1 + env->CF - 1; \ -} \ - \ -void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \ -{ \ - unsigned int src1; \ - src1 = T0; \ - if (!env->CF) { \ - T0 = T0 - T1 - 1; \ - env->CF = src1 > T1; \ - } else { \ - T0 = T0 - T1; \ - env->CF = src1 >= T1; \ - } \ - env->VF = (src1 ^ T1) & (src1 ^ T0); \ - env->NZF = T0; \ - res = T0; \ - FORCE_RET(); \ -} - -OPSUB(sub, sbc, T0, T0, T1) - -OPSUB(rsb, rsc, T0, T1, T0) - -void OPPROTO op_andl_T0_T1(void) -{ - T0 &= T1; -} - -void OPPROTO op_xorl_T0_T1(void) -{ - T0 ^= T1; -} - -void OPPROTO op_orl_T0_T1(void) -{ - T0 |= T1; -} - -void OPPROTO op_bicl_T0_T1(void) -{ - T0 &= ~T1; -} - -void OPPROTO op_notl_T0(void) -{ - T0 = ~T0; -} - -void OPPROTO op_notl_T1(void) -{ - T1 = ~T1; -} - -void OPPROTO op_logic_T0_cc(void) -{ - env->NZF = T0; -} - -void OPPROTO op_logic_T1_cc(void) -{ - env->NZF = T1; -} - -#define EIP (env->regs[15]) - -void OPPROTO op_test_eq(void) -{ - if (env->NZF == 0) - GOTO_LABEL_PARAM(1);; - FORCE_RET(); -} - -void OPPROTO op_test_ne(void) -{ - if (env->NZF != 0) - GOTO_LABEL_PARAM(1);; - FORCE_RET(); -} - -void OPPROTO op_test_cs(void) -{ - if (env->CF != 0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO op_test_cc(void) -{ - if (env->CF == 0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO op_test_mi(void) -{ - if ((env->NZF & 0x80000000) != 0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO op_test_pl(void) -{ - if ((env->NZF & 0x80000000) == 0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO op_test_vs(void) -{ - if ((env->VF & 0x80000000) != 0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO op_test_vc(void) -{ - if ((env->VF & 0x80000000) == 0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO op_test_hi(void) -{ - if (env->CF != 0 && env->NZF != 0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO op_test_ls(void) -{ - if (env->CF == 0 || env->NZF == 0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO op_test_ge(void) -{ - if (((env->VF ^ env->NZF) & 0x80000000) == 0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO op_test_lt(void) -{ - if (((env->VF ^ env->NZF) & 0x80000000) != 0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO op_test_gt(void) -{ - if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO op_test_le(void) -{ - if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO op_test_T0(void) -{ - if (T0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} -void OPPROTO op_testn_T0(void) -{ - if (!T0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO op_goto_tb0(void) -{ - GOTO_TB(op_goto_tb0, PARAM1, 0); -} - -void OPPROTO op_goto_tb1(void) -{ - GOTO_TB(op_goto_tb1, PARAM1, 1); -} - -void OPPROTO op_exit_tb(void) -{ - EXIT_TB(); -} - -void OPPROTO op_movl_T0_cpsr(void) -{ - /* Execution state bits always read as zero. */ - T0 = cpsr_read(env) & ~CPSR_EXEC; - FORCE_RET(); -} - -void OPPROTO op_movl_T0_spsr(void) -{ - T0 = env->spsr; -} - -void OPPROTO op_movl_spsr_T0(void) -{ - uint32_t mask = PARAM1; - env->spsr = (env->spsr & ~mask) | (T0 & mask); -} - -void OPPROTO op_movl_cpsr_T0(void) -{ - cpsr_write(env, T0, PARAM1); - FORCE_RET(); -} - -void OPPROTO op_mul_T0_T1(void) -{ - T0 = T0 * T1; -} - -/* 64 bit unsigned mul */ -void OPPROTO op_mull_T0_T1(void) -{ - uint64_t res; - res = (uint64_t)T0 * (uint64_t)T1; - T1 = res >> 32; - T0 = res; -} - -/* 64 bit signed mul */ -void OPPROTO op_imull_T0_T1(void) -{ - uint64_t res; - res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1); - T1 = res >> 32; - T0 = res; -} - -/* 48 bit signed mul, top 32 bits */ -void OPPROTO op_imulw_T0_T1(void) -{ - uint64_t res; - res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1); - T0 = res >> 16; -} - -void OPPROTO op_addq_T0_T1(void) -{ - uint64_t res; - res = ((uint64_t)T1 << 32) | T0; - res += ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]); - T1 = res >> 32; - T0 = res; -} - -void OPPROTO op_addq_lo_T0_T1(void) -{ - uint64_t res; - res = ((uint64_t)T1 << 32) | T0; - res += (uint64_t)(env->regs[PARAM1]); - T1 = res >> 32; - T0 = res; -} - -/* Dual 16-bit accumulate. */ -void OPPROTO op_addq_T0_T1_dual(void) -{ - uint64_t res; - res = ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]); - res += (int32_t)T0; - res += (int32_t)T1; - env->regs[PARAM1] = (uint32_t)res; - env->regs[PARAM2] = res >> 32; -} - -/* Dual 16-bit subtract accumulate. */ -void OPPROTO op_subq_T0_T1_dual(void) -{ - uint64_t res; - res = ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]); - res += (int32_t)T0; - res -= (int32_t)T1; - env->regs[PARAM1] = (uint32_t)res; - env->regs[PARAM2] = res >> 32; -} - -void OPPROTO op_logicq_cc(void) -{ - env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0); -} - -/* memory access */ - -#define MEMSUFFIX _raw -#include "op_mem.h" - -#if !defined(CONFIG_USER_ONLY) -#define MEMSUFFIX _user -#include "op_mem.h" -#define MEMSUFFIX _kernel -#include "op_mem.h" -#endif - -void OPPROTO op_clrex(void) -{ - cpu_lock(); - helper_clrex(env); - cpu_unlock(); -} - -/* shifts */ - -/* Used by NEON. */ -void OPPROTO op_shll_T0_im(void) -{ - T1 = T1 << PARAM1; -} - -/* T1 based */ - -void OPPROTO op_shll_T1_im(void) -{ - T1 = T1 << PARAM1; -} - -void OPPROTO op_shrl_T1_im(void) -{ - T1 = (uint32_t)T1 >> PARAM1; -} - -void OPPROTO op_shrl_T1_0(void) -{ - T1 = 0; -} - -void OPPROTO op_sarl_T1_im(void) -{ - T1 = (int32_t)T1 >> PARAM1; -} - -void OPPROTO op_sarl_T1_0(void) -{ - T1 = (int32_t)T1 >> 31; -} - -void OPPROTO op_rorl_T1_im(void) -{ - int shift; - shift = PARAM1; - T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); -} - -void OPPROTO op_rrxl_T1(void) -{ - T1 = ((uint32_t)T1 >> 1) | ((uint32_t)env->CF << 31); -} - -/* T1 based, set C flag */ -void OPPROTO op_shll_T1_im_cc(void) -{ - env->CF = (T1 >> (32 - PARAM1)) & 1; - T1 = T1 << PARAM1; -} - -void OPPROTO op_shrl_T1_im_cc(void) -{ - env->CF = (T1 >> (PARAM1 - 1)) & 1; - T1 = (uint32_t)T1 >> PARAM1; -} - -void OPPROTO op_shrl_T1_0_cc(void) -{ - env->CF = (T1 >> 31) & 1; - T1 = 0; -} - -void OPPROTO op_sarl_T1_im_cc(void) -{ - env->CF = (T1 >> (PARAM1 - 1)) & 1; - T1 = (int32_t)T1 >> PARAM1; -} - -void OPPROTO op_sarl_T1_0_cc(void) -{ - env->CF = (T1 >> 31) & 1; - T1 = (int32_t)T1 >> 31; -} - -void OPPROTO op_rorl_T1_im_cc(void) -{ - int shift; - shift = PARAM1; - env->CF = (T1 >> (shift - 1)) & 1; - T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); -} - -void OPPROTO op_rrxl_T1_cc(void) -{ - uint32_t c; - c = T1 & 1; - T1 = ((uint32_t)T1 >> 1) | ((uint32_t)env->CF << 31); - env->CF = c; -} - -/* T2 based */ -void OPPROTO op_shll_T2_im(void) -{ - T2 = T2 << PARAM1; -} - -void OPPROTO op_shrl_T2_im(void) -{ - T2 = (uint32_t)T2 >> PARAM1; -} - -void OPPROTO op_shrl_T2_0(void) -{ - T2 = 0; -} - -void OPPROTO op_sarl_T2_im(void) -{ - T2 = (int32_t)T2 >> PARAM1; -} - -void OPPROTO op_sarl_T2_0(void) -{ - T2 = (int32_t)T2 >> 31; -} - -void OPPROTO op_rorl_T2_im(void) -{ - int shift; - shift = PARAM1; - T2 = ((uint32_t)T2 >> shift) | (T2 << (32 - shift)); -} - -void OPPROTO op_rrxl_T2(void) -{ - T2 = ((uint32_t)T2 >> 1) | ((uint32_t)env->CF << 31); -} - -/* T1 based, use T0 as shift count */ - -void OPPROTO op_shll_T1_T0(void) -{ - int shift; - shift = T0 & 0xff; - if (shift >= 32) - T1 = 0; - else - T1 = T1 << shift; - FORCE_RET(); -} - -void OPPROTO op_shrl_T1_T0(void) -{ - int shift; - shift = T0 & 0xff; - if (shift >= 32) - T1 = 0; - else - T1 = (uint32_t)T1 >> shift; - FORCE_RET(); -} - -void OPPROTO op_sarl_T1_T0(void) -{ - int shift; - shift = T0 & 0xff; - if (shift >= 32) - shift = 31; - T1 = (int32_t)T1 >> shift; -} - -void OPPROTO op_rorl_T1_T0(void) -{ - int shift; - shift = T0 & 0x1f; - if (shift) { - T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); - } - FORCE_RET(); -} - -/* T1 based, use T0 as shift count and compute CF */ - -void OPPROTO op_shll_T1_T0_cc(void) -{ - int shift; - shift = T0 & 0xff; - if (shift >= 32) { - if (shift == 32) - env->CF = T1 & 1; - else - env->CF = 0; - T1 = 0; - } else if (shift != 0) { - env->CF = (T1 >> (32 - shift)) & 1; - T1 = T1 << shift; - } - FORCE_RET(); -} - -void OPPROTO op_shrl_T1_T0_cc(void) -{ - int shift; - shift = T0 & 0xff; - if (shift >= 32) { - if (shift == 32) - env->CF = (T1 >> 31) & 1; - else - env->CF = 0; - T1 = 0; - } else if (shift != 0) { - env->CF = (T1 >> (shift - 1)) & 1; - T1 = (uint32_t)T1 >> shift; - } - FORCE_RET(); -} - -void OPPROTO op_sarl_T1_T0_cc(void) -{ - int shift; - shift = T0 & 0xff; - if (shift >= 32) { - env->CF = (T1 >> 31) & 1; - T1 = (int32_t)T1 >> 31; - } else if (shift != 0) { - env->CF = (T1 >> (shift - 1)) & 1; - T1 = (int32_t)T1 >> shift; - } - FORCE_RET(); -} - -void OPPROTO op_rorl_T1_T0_cc(void) -{ - int shift1, shift; - shift1 = T0 & 0xff; - shift = shift1 & 0x1f; - if (shift == 0) { - if (shift1 != 0) - env->CF = (T1 >> 31) & 1; - } else { - env->CF = (T1 >> (shift - 1)) & 1; - T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); - } - FORCE_RET(); -} - -/* misc */ -void OPPROTO op_clz_T0(void) -{ - int count; - for (count = 32; T0 > 0; count--) - T0 = T0 >> 1; - T0 = count; - FORCE_RET(); -} - -void OPPROTO op_sarl_T0_im(void) -{ - T0 = (int32_t)T0 >> PARAM1; -} - -/* Sign/zero extend */ -void OPPROTO op_sxth_T0(void) -{ - T0 = (int16_t)T0; -} - -void OPPROTO op_sxth_T1(void) -{ - T1 = (int16_t)T1; -} - -void OPPROTO op_sxtb_T1(void) -{ - T1 = (int8_t)T1; -} - -void OPPROTO op_uxtb_T1(void) -{ - T1 = (uint8_t)T1; -} - -void OPPROTO op_uxth_T1(void) -{ - T1 = (uint16_t)T1; -} - -void OPPROTO op_sxtb16_T1(void) -{ - uint32_t res; - res = (uint16_t)(int8_t)T1; - res |= (uint32_t)(int8_t)(T1 >> 16) << 16; - T1 = res; -} - -void OPPROTO op_uxtb16_T1(void) -{ - uint32_t res; - res = (uint16_t)(uint8_t)T1; - res |= (uint32_t)(uint8_t)(T1 >> 16) << 16; - T1 = res; -} - -#define SIGNBIT (uint32_t)0x80000000 -/* saturating arithmetic */ -void OPPROTO op_addl_T0_T1_setq(void) -{ - uint32_t res; - - res = T0 + T1; - if (((res ^ T0) & SIGNBIT) && !((T0 ^ T1) & SIGNBIT)) - env->QF = 1; - - T0 = res; - FORCE_RET(); -} - -void OPPROTO op_addl_T0_T1_saturate(void) -{ - uint32_t res; - - res = T0 + T1; - if (((res ^ T0) & SIGNBIT) && !((T0 ^ T1) & SIGNBIT)) { - env->QF = 1; - if (T0 & SIGNBIT) - T0 = 0x80000000; - else - T0 = 0x7fffffff; - } - else - T0 = res; - - FORCE_RET(); -} - -void OPPROTO op_subl_T0_T1_saturate(void) -{ - uint32_t res; - - res = T0 - T1; - if (((res ^ T0) & SIGNBIT) && ((T0 ^ T1) & SIGNBIT)) { - env->QF = 1; - if (T0 & SIGNBIT) - T0 = 0x80000000; - else - T0 = 0x7fffffff; - } - else - T0 = res; - - FORCE_RET(); -} - -void OPPROTO op_double_T1_saturate(void) -{ - int32_t val; - - val = T1; - if (val >= 0x40000000) { - T1 = 0x7fffffff; - env->QF = 1; - } else if (val <= (int32_t)0xc0000000) { - T1 = 0x80000000; - env->QF = 1; - } else { - T1 = val << 1; - } - FORCE_RET(); -} - -/* Unsigned saturating arithmetic for NEON. */ -void OPPROTO op_addl_T0_T1_usaturate(void) -{ - uint32_t res; - - res = T0 + T1; - if (res < T0) { - env->QF = 1; - T0 = 0xffffffff; - } else { - T0 = res; - } - - FORCE_RET(); -} - -void OPPROTO op_subl_T0_T1_usaturate(void) -{ - uint32_t res; - - res = T0 - T1; - if (res > T0) { - env->QF = 1; - T0 = 0; - } else { - T0 = res; - } - - FORCE_RET(); -} - -/* Thumb shift by immediate */ -void OPPROTO op_shll_T0_im_thumb_cc(void) -{ - int shift; - shift = PARAM1; - if (shift != 0) { - env->CF = (T0 >> (32 - shift)) & 1; - T0 = T0 << shift; - } - env->NZF = T0; - FORCE_RET(); -} - -void OPPROTO op_shll_T0_im_thumb(void) -{ - T0 = T0 << PARAM1; - FORCE_RET(); -} - -void OPPROTO op_shrl_T0_im_thumb_cc(void) -{ - int shift; - - shift = PARAM1; - if (shift == 0) { - env->CF = ((uint32_t)T0) >> 31; - T0 = 0; - } else { - env->CF = (T0 >> (shift - 1)) & 1; - T0 = T0 >> shift; - } - env->NZF = T0; - FORCE_RET(); -} - -void OPPROTO op_shrl_T0_im_thumb(void) -{ - int shift; - - shift = PARAM1; - if (shift == 0) { - T0 = 0; - } else { - T0 = T0 >> shift; - } - FORCE_RET(); -} - -void OPPROTO op_sarl_T0_im_thumb_cc(void) -{ - int shift; - - shift = PARAM1; - if (shift == 0) { - T0 = ((int32_t)T0) >> 31; - env->CF = T0 & 1; - } else { - env->CF = (T0 >> (shift - 1)) & 1; - T0 = ((int32_t)T0) >> shift; - } - env->NZF = T0; - FORCE_RET(); -} - -void OPPROTO op_sarl_T0_im_thumb(void) -{ - int shift; - - shift = PARAM1; - if (shift == 0) { - env->CF = T0 & 1; - } else { - T0 = ((int32_t)T0) >> shift; - } - FORCE_RET(); -} - -/* exceptions */ - -void OPPROTO op_swi(void) -{ - env->exception_index = EXCP_SWI; - cpu_loop_exit(); -} - -void OPPROTO op_undef_insn(void) -{ - env->exception_index = EXCP_UDEF; - cpu_loop_exit(); -} - -void OPPROTO op_debug(void) -{ - env->exception_index = EXCP_DEBUG; - cpu_loop_exit(); -} - -void OPPROTO op_wfi(void) -{ - env->exception_index = EXCP_HLT; - env->halted = 1; - cpu_loop_exit(); -} - -void OPPROTO op_bkpt(void) -{ - env->exception_index = EXCP_BKPT; - cpu_loop_exit(); -} - -void OPPROTO op_exception_exit(void) -{ - env->exception_index = EXCP_EXCEPTION_EXIT; - cpu_loop_exit(); -} - -/* VFP support. We follow the convention used for VFP instrunctions: - Single precition routines have a "s" suffix, double precision a - "d" suffix. */ - -#define VFP_OP(name, p) void OPPROTO op_vfp_##name##p(void) - -#define VFP_BINOP(name) \ -VFP_OP(name, s) \ -{ \ - FT0s = float32_ ## name (FT0s, FT1s, &env->vfp.fp_status); \ -} \ -VFP_OP(name, d) \ -{ \ - FT0d = float64_ ## name (FT0d, FT1d, &env->vfp.fp_status); \ -} -VFP_BINOP(add) -VFP_BINOP(sub) -VFP_BINOP(mul) -VFP_BINOP(div) -#undef VFP_BINOP - -#define VFP_HELPER(name) \ -VFP_OP(name, s) \ -{ \ - do_vfp_##name##s(); \ -} \ -VFP_OP(name, d) \ -{ \ - do_vfp_##name##d(); \ -} -VFP_HELPER(abs) -VFP_HELPER(sqrt) -VFP_HELPER(cmp) -VFP_HELPER(cmpe) -#undef VFP_HELPER - -/* XXX: Will this do the right thing for NANs. Should invert the signbit - without looking at the rest of the value. */ -VFP_OP(neg, s) -{ - FT0s = float32_chs(FT0s); -} - -VFP_OP(neg, d) -{ - FT0d = float64_chs(FT0d); -} - -VFP_OP(F1_ld0, s) -{ - union { - uint32_t i; - float32 s; - } v; - v.i = 0; - FT1s = v.s; -} - -VFP_OP(F1_ld0, d) -{ - union { - uint64_t i; - float64 d; - } v; - v.i = 0; - FT1d = v.d; -} - -/* Helper routines to perform bitwise copies between float and int. */ -static inline float32 vfp_itos(uint32_t i) -{ - union { - uint32_t i; - float32 s; - } v; - - v.i = i; - return v.s; -} - -static inline uint32_t vfp_stoi(float32 s) -{ - union { - uint32_t i; - float32 s; - } v; - - v.s = s; - return v.i; -} - -static inline float64 vfp_itod(uint64_t i) -{ - union { - uint64_t i; - float64 d; - } v; - - v.i = i; - return v.d; -} - -static inline uint64_t vfp_dtoi(float64 d) -{ - union { - uint64_t i; - float64 d; - } v; - - v.d = d; - return v.i; -} - -/* Integer to float conversion. */ -VFP_OP(uito, s) -{ - FT0s = uint32_to_float32(vfp_stoi(FT0s), &env->vfp.fp_status); -} - -VFP_OP(uito, d) -{ - FT0d = uint32_to_float64(vfp_stoi(FT0s), &env->vfp.fp_status); -} - -VFP_OP(sito, s) -{ - FT0s = int32_to_float32(vfp_stoi(FT0s), &env->vfp.fp_status); -} - -VFP_OP(sito, d) -{ - FT0d = int32_to_float64(vfp_stoi(FT0s), &env->vfp.fp_status); -} - -/* Float to integer conversion. */ -VFP_OP(toui, s) -{ - FT0s = vfp_itos(float32_to_uint32(FT0s, &env->vfp.fp_status)); -} - -VFP_OP(toui, d) -{ - FT0s = vfp_itos(float64_to_uint32(FT0d, &env->vfp.fp_status)); -} - -VFP_OP(tosi, s) -{ - FT0s = vfp_itos(float32_to_int32(FT0s, &env->vfp.fp_status)); -} - -VFP_OP(tosi, d) -{ - FT0s = vfp_itos(float64_to_int32(FT0d, &env->vfp.fp_status)); -} - -/* TODO: Set rounding mode properly. */ -VFP_OP(touiz, s) -{ - FT0s = vfp_itos(float32_to_uint32_round_to_zero(FT0s, &env->vfp.fp_status)); -} - -VFP_OP(touiz, d) -{ - FT0s = vfp_itos(float64_to_uint32_round_to_zero(FT0d, &env->vfp.fp_status)); -} - -VFP_OP(tosiz, s) -{ - FT0s = vfp_itos(float32_to_int32_round_to_zero(FT0s, &env->vfp.fp_status)); -} - -VFP_OP(tosiz, d) -{ - FT0s = vfp_itos(float64_to_int32_round_to_zero(FT0d, &env->vfp.fp_status)); -} - -/* floating point conversion */ -VFP_OP(fcvtd, s) -{ - FT0d = float32_to_float64(FT0s, &env->vfp.fp_status); -} - -VFP_OP(fcvts, d) -{ - FT0s = float64_to_float32(FT0d, &env->vfp.fp_status); -} - -/* VFP3 fixed point conversion. */ -#define VFP_CONV_FIX(name, p, ftype, itype, sign) \ -VFP_OP(name##to, p) \ -{ \ - ftype tmp; \ - tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(FT0##p), \ - &env->vfp.fp_status); \ - FT0##p = ftype##_scalbn(tmp, PARAM1, &env->vfp.fp_status); \ -} \ -VFP_OP(to##name, p) \ -{ \ - ftype tmp; \ - tmp = ftype##_scalbn(FT0##p, PARAM1, &env->vfp.fp_status); \ - FT0##p = vfp_ito##p((itype)ftype##_to_##sign##int32_round_to_zero(tmp, \ - &env->vfp.fp_status)); \ -} - -VFP_CONV_FIX(sh, d, float64, int16, ) -VFP_CONV_FIX(sl, d, float64, int32, ) -VFP_CONV_FIX(uh, d, float64, uint16, u) -VFP_CONV_FIX(ul, d, float64, uint32, u) -VFP_CONV_FIX(sh, s, float32, int16, ) -VFP_CONV_FIX(sl, s, float32, int32, ) -VFP_CONV_FIX(uh, s, float32, uint16, u) -VFP_CONV_FIX(ul, s, float32, uint32, u) - -/* Get and Put values from registers. */ -VFP_OP(getreg_F0, d) -{ - FT0d = *(float64 *)((char *) env + PARAM1); -} - -VFP_OP(getreg_F0, s) -{ - FT0s = *(float32 *)((char *) env + PARAM1); -} - -VFP_OP(getreg_F1, d) -{ - FT1d = *(float64 *)((char *) env + PARAM1); -} - -VFP_OP(getreg_F1, s) -{ - FT1s = *(float32 *)((char *) env + PARAM1); -} - -VFP_OP(setreg_F0, d) -{ - *(float64 *)((char *) env + PARAM1) = FT0d; -} - -VFP_OP(setreg_F0, s) -{ - *(float32 *)((char *) env + PARAM1) = FT0s; -} - -void OPPROTO op_vfp_movl_T0_fpscr(void) -{ - do_vfp_get_fpscr (); -} - -void OPPROTO op_vfp_movl_T0_fpscr_flags(void) -{ - T0 = env->vfp.xregs[ARM_VFP_FPSCR] & (0xf << 28); -} - -void OPPROTO op_vfp_movl_fpscr_T0(void) -{ - do_vfp_set_fpscr(); -} - -void OPPROTO op_vfp_movl_T0_xreg(void) -{ - T0 = env->vfp.xregs[PARAM1]; -} - -void OPPROTO op_vfp_movl_xreg_T0(void) -{ - env->vfp.xregs[PARAM1] = T0; -} - -/* Move between FT0s to T0 */ -void OPPROTO op_vfp_mrs(void) -{ - T0 = vfp_stoi(FT0s); -} - -void OPPROTO op_vfp_msr(void) -{ - FT0s = vfp_itos(T0); -} - -/* Move between FT0d and {T0,T1} */ -void OPPROTO op_vfp_mrrd(void) -{ - CPU_DoubleU u; - - u.d = FT0d; - T0 = u.l.lower; - T1 = u.l.upper; -} - -void OPPROTO op_vfp_mdrr(void) -{ - CPU_DoubleU u; - - u.l.lower = T0; - u.l.upper = T1; - FT0d = u.d; -} - -/* Load immediate. PARAM1 is the 32 most significant bits of the value. */ -void OPPROTO op_vfp_fconstd(void) -{ - CPU_DoubleU u; - u.l.upper = PARAM1; - u.l.lower = 0; - FT0d = u.d; -} - -void OPPROTO op_vfp_fconsts(void) -{ - FT0s = vfp_itos(PARAM1); -} - -/* Copy the most significant bit of T0 to all bits of T1. */ -void OPPROTO op_signbit_T1_T0(void) -{ - T1 = (int32_t)T0 >> 31; -} - -void OPPROTO op_movl_cp_T0(void) -{ - helper_set_cp(env, PARAM1, T0); - FORCE_RET(); -} - -void OPPROTO op_movl_T0_cp(void) -{ - T0 = helper_get_cp(env, PARAM1); - FORCE_RET(); -} - -void OPPROTO op_movl_cp15_T0(void) -{ - helper_set_cp15(env, PARAM1, T0); - FORCE_RET(); -} - -void OPPROTO op_movl_T0_cp15(void) -{ - T0 = helper_get_cp15(env, PARAM1); - FORCE_RET(); -} - -/* Access to user mode registers from privileged modes. */ -void OPPROTO op_movl_T0_user(void) -{ - int regno = PARAM1; - if (regno == 13) { - T0 = env->banked_r13[0]; - } else if (regno == 14) { - T0 = env->banked_r14[0]; - } else if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) { - T0 = env->usr_regs[regno - 8]; - } else { - T0 = env->regs[regno]; - } - FORCE_RET(); -} - - -void OPPROTO op_movl_user_T0(void) -{ - int regno = PARAM1; - if (regno == 13) { - env->banked_r13[0] = T0; - } else if (regno == 14) { - env->banked_r14[0] = T0; - } else if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) { - env->usr_regs[regno - 8] = T0; - } else { - env->regs[regno] = T0; - } - FORCE_RET(); -} - -void OPPROTO op_movl_T0_T1(void) -{ - T0 = T1; -} - -void OPPROTO op_movl_T0_T2(void) -{ - T0 = T2; -} - -void OPPROTO op_movl_T1_T0(void) -{ - T1 = T0; -} - -void OPPROTO op_movl_T1_T2(void) -{ - T1 = T2; -} - -void OPPROTO op_movl_T2_T0(void) -{ - T2 = T0; -} - -/* ARMv6 Media instructions. */ - -/* Note that signed overflow is undefined in C. The following routines are - careful to use unsigned types where modulo arithmetic is required. - Failure to do so _will_ break on newer gcc. */ - -/* Signed saturating arithmetic. */ - -/* Perform 16-bit signed satruating addition. */ -static inline uint16_t add16_sat(uint16_t a, uint16_t b) -{ - uint16_t res; - - res = a + b; - if (((res ^ a) & 0x8000) && !((a ^ b) & 0x8000)) { - if (a & 0x8000) - res = 0x8000; - else - res = 0x7fff; - } - return res; -} - -/* Perform 8-bit signed satruating addition. */ -static inline uint8_t add8_sat(uint8_t a, uint8_t b) -{ - uint8_t res; - - res = a + b; - if (((res ^ a) & 0x80) && !((a ^ b) & 0x80)) { - if (a & 0x80) - res = 0x80; - else - res = 0x7f; - } - return res; -} - -/* Perform 16-bit signed satruating subtraction. */ -static inline uint16_t sub16_sat(uint16_t a, uint16_t b) -{ - uint16_t res; - - res = a - b; - if (((res ^ a) & 0x8000) && ((a ^ b) & 0x8000)) { - if (a & 0x8000) - res = 0x8000; - else - res = 0x7fff; - } - return res; -} - -/* Perform 8-bit signed satruating subtraction. */ -static inline uint8_t sub8_sat(uint8_t a, uint8_t b) -{ - uint8_t res; - - res = a - b; - if (((res ^ a) & 0x80) && ((a ^ b) & 0x80)) { - if (a & 0x80) - res = 0x80; - else - res = 0x7f; - } - return res; -} - -#define ADD16(a, b, n) RESULT(add16_sat(a, b), n, 16); -#define SUB16(a, b, n) RESULT(sub16_sat(a, b), n, 16); -#define ADD8(a, b, n) RESULT(add8_sat(a, b), n, 8); -#define SUB8(a, b, n) RESULT(sub8_sat(a, b), n, 8); -#define PFX q - -#include "op_addsub.h" - -/* Unsigned saturating arithmetic. */ -static inline uint16_t add16_usat(uint16_t a, uint8_t b) -{ - uint16_t res; - res = a + b; - if (res < a) - res = 0xffff; - return res; -} - -static inline uint16_t sub16_usat(uint16_t a, uint8_t b) -{ - if (a < b) - return a - b; - else - return 0; -} - -static inline uint8_t add8_usat(uint8_t a, uint8_t b) -{ - uint8_t res; - res = a + b; - if (res < a) - res = 0xff; - return res; -} - -static inline uint8_t sub8_usat(uint8_t a, uint8_t b) -{ - if (a < b) - return a - b; - else - return 0; -} - -#define ADD16(a, b, n) RESULT(add16_usat(a, b), n, 16); -#define SUB16(a, b, n) RESULT(sub16_usat(a, b), n, 16); -#define ADD8(a, b, n) RESULT(add8_usat(a, b), n, 8); -#define SUB8(a, b, n) RESULT(sub8_usat(a, b), n, 8); -#define PFX uq - -#include "op_addsub.h" - -/* Signed modulo arithmetic. */ -#define SARITH16(a, b, n, op) do { \ - int32_t sum; \ - sum = (int16_t)((uint16_t)(a) op (uint16_t)(b)); \ - RESULT(sum, n, 16); \ - if (sum >= 0) \ - ge |= 3 << (n * 2); \ - } while(0) - -#define SARITH8(a, b, n, op) do { \ - int32_t sum; \ - sum = (int8_t)((uint8_t)(a) op (uint8_t)(b)); \ - RESULT(sum, n, 8); \ - if (sum >= 0) \ - ge |= 1 << n; \ - } while(0) - - -#define ADD16(a, b, n) SARITH16(a, b, n, +) -#define SUB16(a, b, n) SARITH16(a, b, n, -) -#define ADD8(a, b, n) SARITH8(a, b, n, +) -#define SUB8(a, b, n) SARITH8(a, b, n, -) -#define PFX s -#define ARITH_GE - -#include "op_addsub.h" - -/* Unsigned modulo arithmetic. */ -#define ADD16(a, b, n) do { \ - uint32_t sum; \ - sum = (uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b); \ - RESULT(sum, n, 16); \ - if ((sum >> 16) == 0) \ - ge |= 3 << (n * 2); \ - } while(0) - -#define ADD8(a, b, n) do { \ - uint32_t sum; \ - sum = (uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b); \ - RESULT(sum, n, 8); \ - if ((sum >> 8) == 0) \ - ge |= 3 << (n * 2); \ - } while(0) - -#define SUB16(a, b, n) do { \ - uint32_t sum; \ - sum = (uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b); \ - RESULT(sum, n, 16); \ - if ((sum >> 16) == 0) \ - ge |= 3 << (n * 2); \ - } while(0) - -#define SUB8(a, b, n) do { \ - uint32_t sum; \ - sum = (uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b); \ - RESULT(sum, n, 8); \ - if ((sum >> 8) == 0) \ - ge |= 3 << (n * 2); \ - } while(0) - -#define PFX u -#define ARITH_GE - -#include "op_addsub.h" - -/* Halved signed arithmetic. */ -#define ADD16(a, b, n) \ - RESULT(((int32_t)(int16_t)(a) + (int32_t)(int16_t)(b)) >> 1, n, 16) -#define SUB16(a, b, n) \ - RESULT(((int32_t)(int16_t)(a) - (int32_t)(int16_t)(b)) >> 1, n, 16) -#define ADD8(a, b, n) \ - RESULT(((int32_t)(int8_t)(a) + (int32_t)(int8_t)(b)) >> 1, n, 8) -#define SUB8(a, b, n) \ - RESULT(((int32_t)(int8_t)(a) - (int32_t)(int8_t)(b)) >> 1, n, 8) -#define PFX sh - -#include "op_addsub.h" - -/* Halved unsigned arithmetic. */ -#define ADD16(a, b, n) \ - RESULT(((uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b)) >> 1, n, 16) -#define SUB16(a, b, n) \ - RESULT(((uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b)) >> 1, n, 16) -#define ADD8(a, b, n) \ - RESULT(((uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b)) >> 1, n, 8) -#define SUB8(a, b, n) \ - RESULT(((uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b)) >> 1, n, 8) -#define PFX uh - -#include "op_addsub.h" - -void OPPROTO op_pkhtb_T0_T1(void) -{ - T0 = (T0 & 0xffff0000) | (T1 & 0xffff); -} - -void OPPROTO op_pkhbt_T0_T1(void) -{ - T0 = (T0 & 0xffff) | (T1 & 0xffff0000); -} -void OPPROTO op_rev_T0(void) -{ - T0 = ((T0 & 0xff000000) >> 24) - | ((T0 & 0x00ff0000) >> 8) - | ((T0 & 0x0000ff00) << 8) - | ((T0 & 0x000000ff) << 24); -} - -void OPPROTO op_revh_T0(void) -{ - T0 = (T0 >> 16) | (T0 << 16); -} - -void OPPROTO op_rev16_T0(void) -{ - T0 = ((T0 & 0xff000000) >> 8) - | ((T0 & 0x00ff0000) << 8) - | ((T0 & 0x0000ff00) >> 8) - | ((T0 & 0x000000ff) << 8); -} - -void OPPROTO op_revsh_T0(void) -{ - T0 = (int16_t)( ((T0 & 0x0000ff00) >> 8) - | ((T0 & 0x000000ff) << 8)); -} - -void OPPROTO op_rbit_T0(void) -{ - T0 = ((T0 & 0xff000000) >> 24) - | ((T0 & 0x00ff0000) >> 8) - | ((T0 & 0x0000ff00) << 8) - | ((T0 & 0x000000ff) << 24); - T0 = ((T0 & 0xf0f0f0f0) >> 4) - | ((T0 & 0x0f0f0f0f) << 4); - T0 = ((T0 & 0x88888888) >> 3) - | ((T0 & 0x44444444) >> 1) - | ((T0 & 0x22222222) << 1) - | ((T0 & 0x11111111) << 3); -} - -/* Swap low and high halfwords. */ -void OPPROTO op_swap_half_T1(void) -{ - T1 = (T1 >> 16) | (T1 << 16); - FORCE_RET(); -} - -/* Dual 16-bit signed multiply. */ -void OPPROTO op_mul_dual_T0_T1(void) -{ - int32_t low; - int32_t high; - low = (int32_t)(int16_t)T0 * (int32_t)(int16_t)T1; - high = (((int32_t)T0) >> 16) * (((int32_t)T1) >> 16); - T0 = low; - T1 = high; -} - -void OPPROTO op_sel_T0_T1(void) -{ - uint32_t mask; - uint32_t flags; - - flags = env->GE; - mask = 0; - if (flags & 1) - mask |= 0xff; - if (flags & 2) - mask |= 0xff00; - if (flags & 4) - mask |= 0xff0000; - if (flags & 8) - mask |= 0xff000000; - T0 = (T0 & mask) | (T1 & ~mask); - FORCE_RET(); -} - -void OPPROTO op_roundqd_T0_T1(void) -{ - T0 = T1 + ((uint32_t)T0 >> 31); -} - -/* Signed saturation. */ -static inline uint32_t do_ssat(int32_t val, int shift) -{ - int32_t top; - uint32_t mask; - - shift = PARAM1; - top = val >> shift; - mask = (1u << shift) - 1; - if (top > 0) { - env->QF = 1; - return mask; - } else if (top < -1) { - env->QF = 1; - return ~mask; - } - return val; -} - -/* Unsigned saturation. */ -static inline uint32_t do_usat(int32_t val, int shift) -{ - uint32_t max; - - shift = PARAM1; - max = (1u << shift) - 1; - if (val < 0) { - env->QF = 1; - return 0; - } else if (val > max) { - env->QF = 1; - return max; - } - return val; -} - -/* Signed saturate. */ -void OPPROTO op_ssat_T1(void) -{ - T0 = do_ssat(T0, PARAM1); - FORCE_RET(); -} - -/* Dual halfword signed saturate. */ -void OPPROTO op_ssat16_T1(void) -{ - uint32_t res; - - res = (uint16_t)do_ssat((int16_t)T0, PARAM1); - res |= do_ssat(((int32_t)T0) >> 16, PARAM1) << 16; - T0 = res; - FORCE_RET(); -} - -/* Unsigned saturate. */ -void OPPROTO op_usat_T1(void) -{ - T0 = do_usat(T0, PARAM1); - FORCE_RET(); -} - -/* Dual halfword unsigned saturate. */ -void OPPROTO op_usat16_T1(void) -{ - uint32_t res; - - res = (uint16_t)do_usat((int16_t)T0, PARAM1); - res |= do_usat(((int32_t)T0) >> 16, PARAM1) << 16; - T0 = res; - FORCE_RET(); -} - -/* Dual 16-bit add. */ -void OPPROTO op_add16_T1_T2(void) -{ - uint32_t mask; - mask = (T0 & T1) & 0x8000; - T0 ^= ~0x8000; - T1 ^= ~0x8000; - T0 = (T0 + T1) ^ mask; -} - -static inline uint8_t do_usad(uint8_t a, uint8_t b) -{ - if (a > b) - return a - b; - else - return b - a; -} - -/* Unsigned sum of absolute byte differences. */ -void OPPROTO op_usad8_T0_T1(void) -{ - uint32_t sum; - sum = do_usad(T0, T1); - sum += do_usad(T0 >> 8, T1 >> 8); - sum += do_usad(T0 >> 16, T1 >>16); - sum += do_usad(T0 >> 24, T1 >> 24); - T0 = sum; -} - -/* Thumb-2 instructions. */ - -/* Insert T1 into T0. Result goes in T1. */ -void OPPROTO op_bfi_T1_T0(void) -{ - int shift = PARAM1; - uint32_t mask = PARAM2; - uint32_t bits; - - bits = (T1 << shift) & mask; - T1 = (T0 & ~mask) | bits; -} - -/* Unsigned bitfield extract. */ -void OPPROTO op_ubfx_T1(void) -{ - uint32_t shift = PARAM1; - uint32_t mask = PARAM2; - - T1 >>= shift; - T1 &= mask; -} - -/* Signed bitfield extract. */ -void OPPROTO op_sbfx_T1(void) -{ - uint32_t shift = PARAM1; - uint32_t width = PARAM2; - int32_t val; - - val = T1 << (32 - (shift + width)); - T1 = val >> (32 - width); -} - -void OPPROTO op_movtop_T0_im(void) -{ - T0 = (T0 & 0xffff) | PARAM1; -} - -/* Used by table branch instructions. */ -void OPPROTO op_jmp_T0_im(void) -{ - env->regs[15] = PARAM1 + (T0 << 1); -} - -void OPPROTO op_set_condexec(void) -{ - env->condexec_bits = PARAM1; -} - -void OPPROTO op_sdivl_T0_T1(void) -{ - int32_t num; - int32_t den; - num = T0; - den = T1; - if (den == 0) - T0 = 0; - else - T0 = num / den; - FORCE_RET(); -} - -void OPPROTO op_udivl_T0_T1(void) -{ - uint32_t num; - uint32_t den; - num = T0; - den = T1; - if (den == 0) - T0 = 0; - else - T0 = num / den; - FORCE_RET(); -} - -void OPPROTO op_movl_T1_r13_banked(void) -{ - T1 = helper_get_r13_banked(env, PARAM1); -} - -void OPPROTO op_movl_r13_T1_banked(void) -{ - helper_set_r13_banked(env, PARAM1, T1); -} - -void OPPROTO op_v7m_mrs_T0(void) -{ - T0 = helper_v7m_mrs(env, PARAM1); -} - -void OPPROTO op_v7m_msr_T0(void) -{ - helper_v7m_msr(env, PARAM1, T0); -} - -void OPPROTO op_movl_T0_sp(void) -{ - if (PARAM1 == env->v7m.current_sp) - T0 = env->regs[13]; - else - T0 = env->v7m.other_sp; - FORCE_RET(); -} - -#include "op_neon.h" - -/* iwMMXt support */ -#include "op_iwmmxt.c" diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/op_helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/op_helper.c --- qemu-0.9.1/target-arm/op_helper.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/op_helper.c 2008-10-26 13:43:07.000000000 +0000 @@ -18,6 +18,10 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "exec.h" +#include "helpers.h" + +#define SIGNBIT (uint32_t)0x80000000 +#define SIGNBIT64 ((uint64_t)1 << 63) void raise_exception(int tt) { @@ -27,7 +31,7 @@ /* thread support */ -spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; void cpu_lock(void) { @@ -39,225 +43,31 @@ spin_unlock(&global_cpu_lock); } -/* VFP support. */ - -void do_vfp_abss(void) -{ - FT0s = float32_abs(FT0s); -} - -void do_vfp_absd(void) -{ - FT0d = float64_abs(FT0d); -} - -void do_vfp_sqrts(void) -{ - FT0s = float32_sqrt(FT0s, &env->vfp.fp_status); -} - -void do_vfp_sqrtd(void) -{ - FT0d = float64_sqrt(FT0d, &env->vfp.fp_status); -} - -/* XXX: check quiet/signaling case */ -#define DO_VFP_cmp(p, size) \ -void do_vfp_cmp##p(void) \ -{ \ - uint32_t flags; \ - switch(float ## size ## _compare_quiet(FT0##p, FT1##p, &env->vfp.fp_status)) {\ - case 0: flags = 0x6; break;\ - case -1: flags = 0x8; break;\ - case 1: flags = 0x2; break;\ - default: case 2: flags = 0x3; break;\ - }\ - env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28)\ - | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ - FORCE_RET(); \ -}\ -\ -void do_vfp_cmpe##p(void) \ -{ \ - uint32_t flags; \ - switch(float ## size ## _compare(FT0##p, FT1##p, &env->vfp.fp_status)) {\ - case 0: flags = 0x6; break;\ - case -1: flags = 0x8; break;\ - case 1: flags = 0x2; break;\ - default: case 2: flags = 0x3; break;\ - }\ - env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28)\ - | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ - FORCE_RET(); \ -} -DO_VFP_cmp(s, 32) -DO_VFP_cmp(d, 64) -#undef DO_VFP_cmp - -/* Convert host exception flags to vfp form. */ -static inline int vfp_exceptbits_from_host(int host_bits) -{ - int target_bits = 0; - - if (host_bits & float_flag_invalid) - target_bits |= 1; - if (host_bits & float_flag_divbyzero) - target_bits |= 2; - if (host_bits & float_flag_overflow) - target_bits |= 4; - if (host_bits & float_flag_underflow) - target_bits |= 8; - if (host_bits & float_flag_inexact) - target_bits |= 0x10; - return target_bits; -} - -/* Convert vfp exception flags to target form. */ -static inline int vfp_exceptbits_to_host(int target_bits) -{ - int host_bits = 0; - - if (target_bits & 1) - host_bits |= float_flag_invalid; - if (target_bits & 2) - host_bits |= float_flag_divbyzero; - if (target_bits & 4) - host_bits |= float_flag_overflow; - if (target_bits & 8) - host_bits |= float_flag_underflow; - if (target_bits & 0x10) - host_bits |= float_flag_inexact; - return host_bits; -} - -void do_vfp_set_fpscr(void) -{ - int i; - uint32_t changed; - - changed = env->vfp.xregs[ARM_VFP_FPSCR]; - env->vfp.xregs[ARM_VFP_FPSCR] = (T0 & 0xffc8ffff); - env->vfp.vec_len = (T0 >> 16) & 7; - env->vfp.vec_stride = (T0 >> 20) & 3; - - changed ^= T0; - if (changed & (3 << 22)) { - i = (T0 >> 22) & 3; - switch (i) { - case 0: - i = float_round_nearest_even; - break; - case 1: - i = float_round_up; - break; - case 2: - i = float_round_down; - break; - case 3: - i = float_round_to_zero; - break; - } - set_float_rounding_mode(i, &env->vfp.fp_status); - } - - i = vfp_exceptbits_to_host((T0 >> 8) & 0x1f); - set_float_exception_flags(i, &env->vfp.fp_status); - /* XXX: FZ and DN are not implemented. */ -} - -void do_vfp_get_fpscr(void) -{ - int i; - - T0 = (env->vfp.xregs[ARM_VFP_FPSCR] & 0xffc8ffff) | (env->vfp.vec_len << 16) - | (env->vfp.vec_stride << 20); - i = get_float_exception_flags(&env->vfp.fp_status); - T0 |= vfp_exceptbits_from_host(i); -} - -float32 helper_recps_f32(float32 a, float32 b) -{ - float_status *s = &env->vfp.fp_status; - float32 two = int32_to_float32(2, s); - return float32_sub(two, float32_mul(a, b, s), s); -} - -float32 helper_rsqrts_f32(float32 a, float32 b) -{ - float_status *s = &env->vfp.fp_status; - float32 three = int32_to_float32(3, s); - return float32_sub(three, float32_mul(a, b, s), s); -} - -/* TODO: The architecture specifies the value that the estimate functions - should return. We return the exact reciprocal/root instead. */ -float32 helper_recpe_f32(float32 a) -{ - float_status *s = &env->vfp.fp_status; - float32 one = int32_to_float32(1, s); - return float32_div(one, a, s); -} - -float32 helper_rsqrte_f32(float32 a) -{ - float_status *s = &env->vfp.fp_status; - float32 one = int32_to_float32(1, s); - return float32_div(one, float32_sqrt(a, s), s); -} - -uint32_t helper_recpe_u32(uint32_t a) -{ - float_status *s = &env->vfp.fp_status; - float32 tmp; - tmp = int32_to_float32(a, s); - tmp = float32_scalbn(tmp, -32, s); - tmp = helper_recpe_f32(tmp); - tmp = float32_scalbn(tmp, 31, s); - return float32_to_int32(tmp, s); -} - -uint32_t helper_rsqrte_u32(uint32_t a) -{ - float_status *s = &env->vfp.fp_status; - float32 tmp; - tmp = int32_to_float32(a, s); - tmp = float32_scalbn(tmp, -32, s); - tmp = helper_rsqrte_f32(tmp); - tmp = float32_scalbn(tmp, 31, s); - return float32_to_int32(tmp, s); -} - -void helper_neon_tbl(int rn, int maxindex) +uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def, + uint32_t rn, uint32_t maxindex) { uint32_t val; - uint32_t mask; uint32_t tmp; int index; int shift; uint64_t *table; table = (uint64_t *)&env->vfp.regs[rn]; val = 0; - mask = 0; for (shift = 0; shift < 32; shift += 8) { - index = (T1 >> shift) & 0xff; - if (index <= maxindex) { - tmp = (table[index >> 3] >> (index & 7)) & 0xff; + index = (ireg >> shift) & 0xff; + if (index < maxindex) { + tmp = (table[index >> 3] >> ((index & 7) << 3)) & 0xff; val |= tmp << shift; } else { - val |= T0 & (0xff << shift); + val |= def & (0xff << shift); } } - T0 = val; + return val; } #if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _mmu -#ifdef __s390__ -# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) -#else -# define GETPC() (__builtin_return_address(0)) -#endif #define SHIFT 0 #include "softmmu_template.h" @@ -287,7 +97,7 @@ saved_env = env; env = cpu_single_env; ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); - if (__builtin_expect(ret, 0)) { + if (unlikely(ret)) { if (retaddr) { /* now we have a real cpu fault */ pc = (unsigned long)retaddr; @@ -303,3 +113,449 @@ env = saved_env; } #endif + +/* FIXME: Pass an axplicit pointer to QF to CPUState, and move saturating + instructions into helper.c */ +uint32_t HELPER(add_setq)(uint32_t a, uint32_t b) +{ + uint32_t res = a + b; + if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) + env->QF = 1; + return res; +} + +uint32_t HELPER(add_saturate)(uint32_t a, uint32_t b) +{ + uint32_t res = a + b; + if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) { + env->QF = 1; + res = ~(((int32_t)a >> 31) ^ SIGNBIT); + } + return res; +} + +uint32_t HELPER(sub_saturate)(uint32_t a, uint32_t b) +{ + uint32_t res = a - b; + if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) { + env->QF = 1; + res = ~(((int32_t)a >> 31) ^ SIGNBIT); + } + return res; +} + +uint32_t HELPER(double_saturate)(int32_t val) +{ + uint32_t res; + if (val >= 0x40000000) { + res = ~SIGNBIT; + env->QF = 1; + } else if (val <= (int32_t)0xc0000000) { + res = SIGNBIT; + env->QF = 1; + } else { + res = val << 1; + } + return res; +} + +uint32_t HELPER(add_usaturate)(uint32_t a, uint32_t b) +{ + uint32_t res = a + b; + if (res < a) { + env->QF = 1; + res = ~0; + } + return res; +} + +uint32_t HELPER(sub_usaturate)(uint32_t a, uint32_t b) +{ + uint32_t res = a - b; + if (res > a) { + env->QF = 1; + res = 0; + } + return res; +} + +/* Signed saturation. */ +static inline uint32_t do_ssat(int32_t val, int shift) +{ + int32_t top; + uint32_t mask; + + top = val >> shift; + mask = (1u << shift) - 1; + if (top > 0) { + env->QF = 1; + return mask; + } else if (top < -1) { + env->QF = 1; + return ~mask; + } + return val; +} + +/* Unsigned saturation. */ +static inline uint32_t do_usat(int32_t val, int shift) +{ + uint32_t max; + + max = (1u << shift) - 1; + if (val < 0) { + env->QF = 1; + return 0; + } else if (val > max) { + env->QF = 1; + return max; + } + return val; +} + +/* Signed saturate. */ +uint32_t HELPER(ssat)(uint32_t x, uint32_t shift) +{ + return do_ssat(x, shift); +} + +/* Dual halfword signed saturate. */ +uint32_t HELPER(ssat16)(uint32_t x, uint32_t shift) +{ + uint32_t res; + + res = (uint16_t)do_ssat((int16_t)x, shift); + res |= do_ssat(((int32_t)x) >> 16, shift) << 16; + return res; +} + +/* Unsigned saturate. */ +uint32_t HELPER(usat)(uint32_t x, uint32_t shift) +{ + return do_usat(x, shift); +} + +/* Dual halfword unsigned saturate. */ +uint32_t HELPER(usat16)(uint32_t x, uint32_t shift) +{ + uint32_t res; + + res = (uint16_t)do_usat((int16_t)x, shift); + res |= do_usat(((int32_t)x) >> 16, shift) << 16; + return res; +} + +void HELPER(wfi)(void) +{ + env->exception_index = EXCP_HLT; + env->halted = 1; + cpu_loop_exit(); +} + +void HELPER(exception)(uint32_t excp) +{ + env->exception_index = excp; + cpu_loop_exit(); +} + +uint32_t HELPER(cpsr_read)(void) +{ + return cpsr_read(env) & ~CPSR_EXEC; +} + +void HELPER(cpsr_write)(uint32_t val, uint32_t mask) +{ + cpsr_write(env, val, mask); +} + +/* Access to user mode registers from privileged modes. */ +uint32_t HELPER(get_user_reg)(uint32_t regno) +{ + uint32_t val; + + if (regno == 13) { + val = env->banked_r13[0]; + } else if (regno == 14) { + val = env->banked_r14[0]; + } else if (regno >= 8 + && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) { + val = env->usr_regs[regno - 8]; + } else { + val = env->regs[regno]; + } + return val; +} + +void HELPER(set_user_reg)(uint32_t regno, uint32_t val) +{ + if (regno == 13) { + env->banked_r13[0] = val; + } else if (regno == 14) { + env->banked_r14[0] = val; + } else if (regno >= 8 + && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) { + env->usr_regs[regno - 8] = val; + } else { + env->regs[regno] = val; + } +} + +/* ??? Flag setting arithmetic is awkward because we need to do comparisons. + The only way to do that in TCG is a conditional branch, which clobbers + all our temporaries. For now implement these as helper functions. */ + +uint32_t HELPER (add_cc)(uint32_t a, uint32_t b) +{ + uint32_t result; + result = T0 + T1; + env->NF = env->ZF = result; + env->CF = result < a; + env->VF = (a ^ b ^ -1) & (a ^ result); + return result; +} + +uint32_t HELPER(adc_cc)(uint32_t a, uint32_t b) +{ + uint32_t result; + if (!env->CF) { + result = a + b; + env->CF = result < a; + } else { + result = a + b + 1; + env->CF = result <= a; + } + env->VF = (a ^ b ^ -1) & (a ^ result); + env->NF = env->ZF = result; + return result; +} + +uint32_t HELPER(sub_cc)(uint32_t a, uint32_t b) +{ + uint32_t result; + result = a - b; + env->NF = env->ZF = result; + env->CF = a >= b; + env->VF = (a ^ b) & (a ^ result); + return result; +} + +uint32_t HELPER(sbc_cc)(uint32_t a, uint32_t b) +{ + uint32_t result; + if (!env->CF) { + result = a - b - 1; + env->CF = a > b; + } else { + result = a - b; + env->CF = a >= b; + } + env->VF = (a ^ b) & (a ^ result); + env->NF = env->ZF = result; + return result; +} + +/* Similarly for variable shift instructions. */ + +uint32_t HELPER(shl)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) + return 0; + return x << shift; +} + +uint32_t HELPER(shr)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) + return 0; + return (uint32_t)x >> shift; +} + +uint32_t HELPER(sar)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) + shift = 31; + return (int32_t)x >> shift; +} + +uint32_t HELPER(ror)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift == 0) + return x; + return (x >> shift) | (x << (32 - shift)); +} + +uint32_t HELPER(shl_cc)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + if (shift == 32) + env->CF = x & 1; + else + env->CF = 0; + return 0; + } else if (shift != 0) { + env->CF = (x >> (32 - shift)) & 1; + return x << shift; + } + return x; +} + +uint32_t HELPER(shr_cc)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + if (shift == 32) + env->CF = (x >> 31) & 1; + else + env->CF = 0; + return 0; + } else if (shift != 0) { + env->CF = (x >> (shift - 1)) & 1; + return x >> shift; + } + return x; +} + +uint32_t HELPER(sar_cc)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + env->CF = (x >> 31) & 1; + return (int32_t)x >> 31; + } else if (shift != 0) { + env->CF = (x >> (shift - 1)) & 1; + return (int32_t)x >> shift; + } + return x; +} + +uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i) +{ + int shift1, shift; + shift1 = i & 0xff; + shift = shift1 & 0x1f; + if (shift == 0) { + if (shift1 != 0) + env->CF = (x >> 31) & 1; + return x; + } else { + env->CF = (x >> (shift - 1)) & 1; + return ((uint32_t)x >> shift) | (x << (32 - shift)); + } +} + +uint64_t HELPER(neon_add_saturate_s64)(uint64_t src1, uint64_t src2) +{ + uint64_t res; + + res = src1 + src2; + if (((res ^ src1) & SIGNBIT64) && !((src1 ^ src2) & SIGNBIT64)) { + env->QF = 1; + res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64; + } + return res; +} + +uint64_t HELPER(neon_add_saturate_u64)(uint64_t src1, uint64_t src2) +{ + uint64_t res; + + res = src1 + src2; + if (res < src1) { + env->QF = 1; + res = ~(uint64_t)0; + } + return res; +} + +uint64_t HELPER(neon_sub_saturate_s64)(uint64_t src1, uint64_t src2) +{ + uint64_t res; + + res = src1 - src2; + if (((res ^ src1) & SIGNBIT64) && ((src1 ^ src2) & SIGNBIT64)) { + env->QF = 1; + res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64; + } + return res; +} + +uint64_t HELPER(neon_sub_saturate_u64)(uint64_t src1, uint64_t src2) +{ + uint64_t res; + + if (src1 < src2) { + env->QF = 1; + res = 0; + } else { + res = src1 - src2; + } + return res; +} + +/* These need to return a pair of value, so still use T0/T1. */ +/* Transpose. Argument order is rather strange to avoid special casing + the tranlation code. + On input T0 = rm, T1 = rd. On output T0 = rd, T1 = rm */ +void HELPER(neon_trn_u8)(void) +{ + uint32_t rd; + uint32_t rm; + rd = ((T0 & 0x00ff00ff) << 8) | (T1 & 0x00ff00ff); + rm = ((T1 & 0xff00ff00) >> 8) | (T0 & 0xff00ff00); + T0 = rd; + T1 = rm; + FORCE_RET(); +} + +void HELPER(neon_trn_u16)(void) +{ + uint32_t rd; + uint32_t rm; + rd = (T0 << 16) | (T1 & 0xffff); + rm = (T1 >> 16) | (T0 & 0xffff0000); + T0 = rd; + T1 = rm; + FORCE_RET(); +} + +/* Worker routines for zip and unzip. */ +void HELPER(neon_unzip_u8)(void) +{ + uint32_t rd; + uint32_t rm; + rd = (T0 & 0xff) | ((T0 >> 8) & 0xff00) + | ((T1 << 16) & 0xff0000) | ((T1 << 8) & 0xff000000); + rm = ((T0 >> 8) & 0xff) | ((T0 >> 16) & 0xff00) + | ((T1 << 8) & 0xff0000) | (T1 & 0xff000000); + T0 = rd; + T1 = rm; + FORCE_RET(); +} + +void HELPER(neon_zip_u8)(void) +{ + uint32_t rd; + uint32_t rm; + rd = (T0 & 0xff) | ((T1 << 8) & 0xff00) + | ((T0 << 16) & 0xff0000) | ((T1 << 24) & 0xff000000); + rm = ((T0 >> 16) & 0xff) | ((T1 >> 8) & 0xff00) + | ((T0 >> 8) & 0xff0000) | (T1 & 0xff000000); + T0 = rd; + T1 = rm; + FORCE_RET(); +} + +void HELPER(neon_zip_u16)(void) +{ + uint32_t tmp; + + tmp = (T0 & 0xffff) | (T1 << 16); + T1 = (T1 & 0xffff0000) | (T0 >> 16); + T0 = tmp; + FORCE_RET(); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/op_iwmmxt.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/op_iwmmxt.c --- qemu-0.9.1/target-arm/op_iwmmxt.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/op_iwmmxt.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,707 +0,0 @@ -/* - * iwMMXt micro operations for XScale. - * - * Copyright (c) 2007 OpenedHand, Ltd. - * Written by Andrzej Zaborowski - * - * 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 - */ - -#define M1 env->iwmmxt.regs[PARAM1] - -/* iwMMXt macros extracted from GNU gdb. */ - -/* Set the SIMD wCASF flags for 8, 16, 32 or 64-bit operations. */ -#define SIMD8_SET( v, n, b) ((v != 0) << ((((b) + 1) * 4) + (n))) -#define SIMD16_SET(v, n, h) ((v != 0) << ((((h) + 1) * 8) + (n))) -#define SIMD32_SET(v, n, w) ((v != 0) << ((((w) + 1) * 16) + (n))) -#define SIMD64_SET(v, n) ((v != 0) << (32 + (n))) -/* Flags to pass as "n" above. */ -#define SIMD_NBIT -1 -#define SIMD_ZBIT -2 -#define SIMD_CBIT -3 -#define SIMD_VBIT -4 -/* Various status bit macros. */ -#define NBIT8(x) ((x) & 0x80) -#define NBIT16(x) ((x) & 0x8000) -#define NBIT32(x) ((x) & 0x80000000) -#define NBIT64(x) ((x) & 0x8000000000000000ULL) -#define ZBIT8(x) (((x) & 0xff) == 0) -#define ZBIT16(x) (((x) & 0xffff) == 0) -#define ZBIT32(x) (((x) & 0xffffffff) == 0) -#define ZBIT64(x) (x == 0) -/* Sign extension macros. */ -#define EXTEND8H(a) ((uint16_t) (int8_t) (a)) -#define EXTEND8(a) ((uint32_t) (int8_t) (a)) -#define EXTEND16(a) ((uint32_t) (int16_t) (a)) -#define EXTEND16S(a) ((int32_t) (int16_t) (a)) -#define EXTEND32(a) ((uint64_t) (int32_t) (a)) - -void OPPROTO op_iwmmxt_movl_T0_T1_wRn(void) -{ - T0 = M1 & ~(uint32_t) 0; - T1 = M1 >> 32; -} - -void OPPROTO op_iwmmxt_movl_wRn_T0_T1(void) -{ - M1 = ((uint64_t) T1 << 32) | T0; -} - -void OPPROTO op_iwmmxt_movq_M0_wRn(void) -{ - M0 = M1; -} - -void OPPROTO op_iwmmxt_orq_M0_wRn(void) -{ - M0 |= M1; -} - -void OPPROTO op_iwmmxt_andq_M0_wRn(void) -{ - M0 &= M1; -} - -void OPPROTO op_iwmmxt_xorq_M0_wRn(void) -{ - M0 ^= M1; -} - -void OPPROTO op_iwmmxt_maddsq_M0_wRn(void) -{ - M0 = (( - EXTEND16S((M0 >> 0) & 0xffff) * EXTEND16S((M1 >> 0) & 0xffff) + - EXTEND16S((M0 >> 16) & 0xffff) * EXTEND16S((M1 >> 16) & 0xffff) - ) & 0xffffffff) | ((uint64_t) ( - EXTEND16S((M0 >> 32) & 0xffff) * EXTEND16S((M1 >> 32) & 0xffff) + - EXTEND16S((M0 >> 48) & 0xffff) * EXTEND16S((M1 >> 48) & 0xffff) - ) << 32); -} - -void OPPROTO op_iwmmxt_madduq_M0_wRn(void) -{ - M0 = (( - ((M0 >> 0) & 0xffff) * ((M1 >> 0) & 0xffff) + - ((M0 >> 16) & 0xffff) * ((M1 >> 16) & 0xffff) - ) & 0xffffffff) | (( - ((M0 >> 32) & 0xffff) * ((M1 >> 32) & 0xffff) + - ((M0 >> 48) & 0xffff) * ((M1 >> 48) & 0xffff) - ) << 32); -} - -void OPPROTO op_iwmmxt_sadb_M0_wRn(void) -{ -#define abs(x) (((x) >= 0) ? x : -x) -#define SADB(SHR) abs((int) ((M0 >> SHR) & 0xff) - (int) ((M1 >> SHR) & 0xff)) - M0 = - SADB(0) + SADB(8) + SADB(16) + SADB(24) + - SADB(32) + SADB(40) + SADB(48) + SADB(56); -#undef SADB -} - -void OPPROTO op_iwmmxt_sadw_M0_wRn(void) -{ -#define SADW(SHR) \ - abs((int) ((M0 >> SHR) & 0xffff) - (int) ((M1 >> SHR) & 0xffff)) - M0 = SADW(0) + SADW(16) + SADW(32) + SADW(48); -#undef SADW -} - -void OPPROTO op_iwmmxt_addl_M0_wRn(void) -{ - M0 += env->iwmmxt.regs[PARAM1] & 0xffffffff; -} - -void OPPROTO op_iwmmxt_mulsw_M0_wRn(void) -{ -#define MULS(SHR) ((uint64_t) ((( \ - EXTEND16S((M0 >> SHR) & 0xffff) * EXTEND16S((M1 >> SHR) & 0xffff) \ - ) >> PARAM2) & 0xffff) << SHR) - M0 = MULS(0) | MULS(16) | MULS(32) | MULS(48); -#undef MULS -} - -void OPPROTO op_iwmmxt_muluw_M0_wRn(void) -{ -#define MULU(SHR) ((uint64_t) ((( \ - ((M0 >> SHR) & 0xffff) * ((M1 >> SHR) & 0xffff) \ - ) >> PARAM2) & 0xffff) << SHR) - M0 = MULU(0) | MULU(16) | MULU(32) | MULU(48); -#undef MULU -} - -void OPPROTO op_iwmmxt_macsw_M0_wRn(void) -{ -#define MACS(SHR) ( \ - EXTEND16((M0 >> SHR) & 0xffff) * EXTEND16S((M1 >> SHR) & 0xffff)) - M0 = (int64_t) (MACS(0) + MACS(16) + MACS(32) + MACS(48)); -#undef MACS -} - -void OPPROTO op_iwmmxt_macuw_M0_wRn(void) -{ -#define MACU(SHR) ( \ - (uint32_t) ((M0 >> SHR) & 0xffff) * \ - (uint32_t) ((M1 >> SHR) & 0xffff)) - M0 = MACU(0) + MACU(16) + MACU(32) + MACU(48); -#undef MACU -} - -void OPPROTO op_iwmmxt_addsq_M0_wRn(void) -{ - M0 = (int64_t) M0 + (int64_t) M1; -} - -void OPPROTO op_iwmmxt_adduq_M0_wRn(void) -{ - M0 += M1; -} - -void OPPROTO op_iwmmxt_movq_wRn_M0(void) -{ - M1 = M0; -} - -void OPPROTO op_iwmmxt_movl_wCx_T0(void) -{ - env->iwmmxt.cregs[PARAM1] = T0; -} - -void OPPROTO op_iwmmxt_movl_T0_wCx(void) -{ - T0 = env->iwmmxt.cregs[PARAM1]; -} - -void OPPROTO op_iwmmxt_movl_T1_wCx(void) -{ - T1 = env->iwmmxt.cregs[PARAM1]; -} - -void OPPROTO op_iwmmxt_set_mup(void) -{ - env->iwmmxt.cregs[ARM_IWMMXT_wCon] |= 2; -} - -void OPPROTO op_iwmmxt_set_cup(void) -{ - env->iwmmxt.cregs[ARM_IWMMXT_wCon] |= 1; -} - -void OPPROTO op_iwmmxt_setpsr_nz(void) -{ - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = - SIMD64_SET((M0 == 0), SIMD_ZBIT) | - SIMD64_SET((M0 & (1ULL << 63)), SIMD_NBIT); -} - -void OPPROTO op_iwmmxt_negq_M0(void) -{ - M0 = ~M0; -} - -#define NZBIT8(x, i) \ - SIMD8_SET(NBIT8((x) & 0xff), SIMD_NBIT, i) | \ - SIMD8_SET(ZBIT8((x) & 0xff), SIMD_ZBIT, i) -#define NZBIT16(x, i) \ - SIMD16_SET(NBIT16((x) & 0xffff), SIMD_NBIT, i) | \ - SIMD16_SET(ZBIT16((x) & 0xffff), SIMD_ZBIT, i) -#define NZBIT32(x, i) \ - SIMD32_SET(NBIT32((x) & 0xffffffff), SIMD_NBIT, i) | \ - SIMD32_SET(ZBIT32((x) & 0xffffffff), SIMD_ZBIT, i) -#define NZBIT64(x) \ - SIMD64_SET(NBIT64(x), SIMD_NBIT) | \ - SIMD64_SET(ZBIT64(x), SIMD_ZBIT) -#define IWMMXT_OP_UNPACK(S, SH0, SH1, SH2, SH3) \ -void OPPROTO glue(op_iwmmxt_unpack, glue(S, b_M0_wRn))(void) \ -{ \ - M0 = \ - (((M0 >> SH0) & 0xff) << 0) | (((M1 >> SH0) & 0xff) << 8) | \ - (((M0 >> SH1) & 0xff) << 16) | (((M1 >> SH1) & 0xff) << 24) | \ - (((M0 >> SH2) & 0xff) << 32) | (((M1 >> SH2) & 0xff) << 40) | \ - (((M0 >> SH3) & 0xff) << 48) | (((M1 >> SH3) & 0xff) << 56); \ - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ - NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) | \ - NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) | \ - NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) | \ - NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7); \ -} \ -void OPPROTO glue(op_iwmmxt_unpack, glue(S, w_M0_wRn))(void) \ -{ \ - M0 = \ - (((M0 >> SH0) & 0xffff) << 0) | \ - (((M1 >> SH0) & 0xffff) << 16) | \ - (((M0 >> SH2) & 0xffff) << 32) | \ - (((M1 >> SH2) & 0xffff) << 48); \ - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ - NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 16, 1) | \ - NZBIT8(M0 >> 32, 2) | NZBIT8(M0 >> 48, 3); \ -} \ -void OPPROTO glue(op_iwmmxt_unpack, glue(S, l_M0_wRn))(void) \ -{ \ - M0 = \ - (((M0 >> SH0) & 0xffffffff) << 0) | \ - (((M1 >> SH0) & 0xffffffff) << 32); \ - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ - NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); \ -} \ -void OPPROTO glue(op_iwmmxt_unpack, glue(S, ub_M0))(void) \ -{ \ - M0 = \ - (((M0 >> SH0) & 0xff) << 0) | \ - (((M0 >> SH1) & 0xff) << 16) | \ - (((M0 >> SH2) & 0xff) << 32) | \ - (((M0 >> SH3) & 0xff) << 48); \ - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ - NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | \ - NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); \ -} \ -void OPPROTO glue(op_iwmmxt_unpack, glue(S, uw_M0))(void) \ -{ \ - M0 = \ - (((M0 >> SH0) & 0xffff) << 0) | \ - (((M0 >> SH2) & 0xffff) << 32); \ - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ - NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); \ -} \ -void OPPROTO glue(op_iwmmxt_unpack, glue(S, ul_M0))(void) \ -{ \ - M0 = (((M0 >> SH0) & 0xffffffff) << 0); \ - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0 >> 0); \ -} \ -void OPPROTO glue(op_iwmmxt_unpack, glue(S, sb_M0))(void) \ -{ \ - M0 = \ - ((uint64_t) EXTEND8H((M0 >> SH0) & 0xff) << 0) | \ - ((uint64_t) EXTEND8H((M0 >> SH1) & 0xff) << 16) | \ - ((uint64_t) EXTEND8H((M0 >> SH2) & 0xff) << 32) | \ - ((uint64_t) EXTEND8H((M0 >> SH3) & 0xff) << 48); \ - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ - NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | \ - NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); \ -} \ -void OPPROTO glue(op_iwmmxt_unpack, glue(S, sw_M0))(void) \ -{ \ - M0 = \ - ((uint64_t) EXTEND16((M0 >> SH0) & 0xffff) << 0) | \ - ((uint64_t) EXTEND16((M0 >> SH2) & 0xffff) << 32); \ - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ - NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); \ -} \ -void OPPROTO glue(op_iwmmxt_unpack, glue(S, sl_M0))(void) \ -{ \ - M0 = EXTEND32((M0 >> SH0) & 0xffffffff); \ - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0 >> 0); \ -} -IWMMXT_OP_UNPACK(l, 0, 8, 16, 24) -IWMMXT_OP_UNPACK(h, 32, 40, 48, 56) - -#define IWMMXT_OP_CMP(SUFF, Tb, Tw, Tl, O) \ -void OPPROTO glue(op_iwmmxt_, glue(SUFF, b_M0_wRn))(void) \ -{ \ - M0 = \ - CMP(0, Tb, O, 0xff) | CMP(8, Tb, O, 0xff) | \ - CMP(16, Tb, O, 0xff) | CMP(24, Tb, O, 0xff) | \ - CMP(32, Tb, O, 0xff) | CMP(40, Tb, O, 0xff) | \ - CMP(48, Tb, O, 0xff) | CMP(56, Tb, O, 0xff); \ - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ - NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) | \ - NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) | \ - NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) | \ - NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7); \ -} \ -void OPPROTO glue(op_iwmmxt_, glue(SUFF, w_M0_wRn))(void) \ -{ \ - M0 = CMP(0, Tw, O, 0xffff) | CMP(16, Tw, O, 0xffff) | \ - CMP(32, Tw, O, 0xffff) | CMP(48, Tw, O, 0xffff); \ - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ - NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | \ - NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); \ -} \ -void OPPROTO glue(op_iwmmxt_, glue(SUFF, l_M0_wRn))(void) \ -{ \ - M0 = CMP(0, Tl, O, 0xffffffff) | \ - CMP(32, Tl, O, 0xffffffff); \ - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ - NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); \ -} -#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((M0 >> SHR) & MASK) OPER \ - (TYPE) ((M1 >> SHR) & MASK)) ? (uint64_t) MASK : 0) << SHR) -IWMMXT_OP_CMP(cmpeq, uint8_t, uint16_t, uint32_t, ==) -IWMMXT_OP_CMP(cmpgts, int8_t, int16_t, int32_t, >) -IWMMXT_OP_CMP(cmpgtu, uint8_t, uint16_t, uint32_t, >) -#undef CMP -#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((M0 >> SHR) & MASK) OPER \ - (TYPE) ((M1 >> SHR) & MASK)) ? M0 : M1) & ((uint64_t) MASK << SHR)) -IWMMXT_OP_CMP(mins, int8_t, int16_t, int32_t, <) -IWMMXT_OP_CMP(minu, uint8_t, uint16_t, uint32_t, <) -IWMMXT_OP_CMP(maxs, int8_t, int16_t, int32_t, >) -IWMMXT_OP_CMP(maxu, uint8_t, uint16_t, uint32_t, >) -#undef CMP -#define CMP(SHR, TYPE, OPER, MASK) ((uint64_t) (((TYPE) ((M0 >> SHR) & MASK) \ - OPER (TYPE) ((M1 >> SHR) & MASK)) & MASK) << SHR) -IWMMXT_OP_CMP(subn, uint8_t, uint16_t, uint32_t, -) -IWMMXT_OP_CMP(addn, uint8_t, uint16_t, uint32_t, +) -#undef CMP -/* TODO Signed- and Unsigned-Saturation */ -#define CMP(SHR, TYPE, OPER, MASK) ((uint64_t) (((TYPE) ((M0 >> SHR) & MASK) \ - OPER (TYPE) ((M1 >> SHR) & MASK)) & MASK) << SHR) -IWMMXT_OP_CMP(subu, uint8_t, uint16_t, uint32_t, -) -IWMMXT_OP_CMP(addu, uint8_t, uint16_t, uint32_t, +) -IWMMXT_OP_CMP(subs, int8_t, int16_t, int32_t, -) -IWMMXT_OP_CMP(adds, int8_t, int16_t, int32_t, +) -#undef CMP -#undef IWMMXT_OP_CMP - -void OPPROTO op_iwmmxt_avgb_M0_wRn(void) -{ -#define AVGB(SHR) ((( \ - ((M0 >> SHR) & 0xff) + ((M1 >> SHR) & 0xff) + PARAM2) >> 1) << SHR) - M0 = - AVGB(0) | AVGB(8) | AVGB(16) | AVGB(24) | - AVGB(32) | AVGB(40) | AVGB(48) | AVGB(56); - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = - SIMD8_SET(ZBIT8((M0 >> 0) & 0xff), SIMD_ZBIT, 0) | - SIMD8_SET(ZBIT8((M0 >> 8) & 0xff), SIMD_ZBIT, 1) | - SIMD8_SET(ZBIT8((M0 >> 16) & 0xff), SIMD_ZBIT, 2) | - SIMD8_SET(ZBIT8((M0 >> 24) & 0xff), SIMD_ZBIT, 3) | - SIMD8_SET(ZBIT8((M0 >> 32) & 0xff), SIMD_ZBIT, 4) | - SIMD8_SET(ZBIT8((M0 >> 40) & 0xff), SIMD_ZBIT, 5) | - SIMD8_SET(ZBIT8((M0 >> 48) & 0xff), SIMD_ZBIT, 6) | - SIMD8_SET(ZBIT8((M0 >> 56) & 0xff), SIMD_ZBIT, 7); -#undef AVGB -} - -void OPPROTO op_iwmmxt_avgw_M0_wRn(void) -{ -#define AVGW(SHR) ((( \ - ((M0 >> SHR) & 0xffff) + ((M1 >> SHR) & 0xffff) + PARAM2) >> 1) << SHR) - M0 = AVGW(0) | AVGW(16) | AVGW(32) | AVGW(48); - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = - SIMD16_SET(ZBIT16((M0 >> 0) & 0xffff), SIMD_ZBIT, 0) | - SIMD16_SET(ZBIT16((M0 >> 16) & 0xffff), SIMD_ZBIT, 1) | - SIMD16_SET(ZBIT16((M0 >> 32) & 0xffff), SIMD_ZBIT, 2) | - SIMD16_SET(ZBIT16((M0 >> 48) & 0xffff), SIMD_ZBIT, 3); -#undef AVGW -} - -void OPPROTO op_iwmmxt_msadb_M0_wRn(void) -{ - M0 = ((((M0 >> 0) & 0xffff) * ((M1 >> 0) & 0xffff) + - ((M0 >> 16) & 0xffff) * ((M1 >> 16) & 0xffff)) & 0xffffffff) | - ((((M0 >> 32) & 0xffff) * ((M1 >> 32) & 0xffff) + - ((M0 >> 48) & 0xffff) * ((M1 >> 48) & 0xffff)) << 32); -} - -void OPPROTO op_iwmmxt_align_M0_T0_wRn(void) -{ - M0 >>= T0 << 3; - M0 |= M1 << (64 - (T0 << 3)); -} - -void OPPROTO op_iwmmxt_insr_M0_T0_T1(void) -{ - M0 &= ~((uint64_t) T1 << PARAM1); - M0 |= (uint64_t) (T0 & T1) << PARAM1; -} - -void OPPROTO op_iwmmxt_extrsb_T0_M0(void) -{ - T0 = EXTEND8((M0 >> PARAM1) & 0xff); -} - -void OPPROTO op_iwmmxt_extrsw_T0_M0(void) -{ - T0 = EXTEND16((M0 >> PARAM1) & 0xffff); -} - -void OPPROTO op_iwmmxt_extru_T0_M0_T1(void) -{ - T0 = (M0 >> PARAM1) & T1; -} - -void OPPROTO op_iwmmxt_bcstb_M0_T0(void) -{ - T0 &= 0xff; - M0 = - ((uint64_t) T0 << 0) | ((uint64_t) T0 << 8) | - ((uint64_t) T0 << 16) | ((uint64_t) T0 << 24) | - ((uint64_t) T0 << 32) | ((uint64_t) T0 << 40) | - ((uint64_t) T0 << 48) | ((uint64_t) T0 << 56); -} - -void OPPROTO op_iwmmxt_bcstw_M0_T0(void) -{ - T0 &= 0xffff; - M0 = - ((uint64_t) T0 << 0) | ((uint64_t) T0 << 16) | - ((uint64_t) T0 << 32) | ((uint64_t) T0 << 48); -} - -void OPPROTO op_iwmmxt_bcstl_M0_T0(void) -{ - M0 = ((uint64_t) T0 << 0) | ((uint64_t) T0 << 32); -} - -void OPPROTO op_iwmmxt_addcb_M0(void) -{ - M0 = - ((M0 >> 0) & 0xff) + ((M0 >> 8) & 0xff) + - ((M0 >> 16) & 0xff) + ((M0 >> 24) & 0xff) + - ((M0 >> 32) & 0xff) + ((M0 >> 40) & 0xff) + - ((M0 >> 48) & 0xff) + ((M0 >> 56) & 0xff); -} - -void OPPROTO op_iwmmxt_addcw_M0(void) -{ - M0 = - ((M0 >> 0) & 0xffff) + ((M0 >> 16) & 0xffff) + - ((M0 >> 32) & 0xffff) + ((M0 >> 48) & 0xffff); -} - -void OPPROTO op_iwmmxt_addcl_M0(void) -{ - M0 = (M0 & 0xffffffff) + (M0 >> 32); -} - -void OPPROTO op_iwmmxt_msbb_T0_M0(void) -{ - T0 = - ((M0 >> 7) & 0x01) | ((M0 >> 14) & 0x02) | - ((M0 >> 21) & 0x04) | ((M0 >> 28) & 0x08) | - ((M0 >> 35) & 0x10) | ((M0 >> 42) & 0x20) | - ((M0 >> 49) & 0x40) | ((M0 >> 56) & 0x80); -} - -void OPPROTO op_iwmmxt_msbw_T0_M0(void) -{ - T0 = - ((M0 >> 15) & 0x01) | ((M0 >> 30) & 0x02) | - ((M0 >> 45) & 0x04) | ((M0 >> 52) & 0x08); -} - -void OPPROTO op_iwmmxt_msbl_T0_M0(void) -{ - T0 = ((M0 >> 31) & 0x01) | ((M0 >> 62) & 0x02); -} - -void OPPROTO op_iwmmxt_srlw_M0_T0(void) -{ - M0 = - (((M0 & (0xffffll << 0)) >> T0) & (0xffffll << 0)) | - (((M0 & (0xffffll << 16)) >> T0) & (0xffffll << 16)) | - (((M0 & (0xffffll << 32)) >> T0) & (0xffffll << 32)) | - (((M0 & (0xffffll << 48)) >> T0) & (0xffffll << 48)); - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = - NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | - NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); -} - -void OPPROTO op_iwmmxt_srll_M0_T0(void) -{ - M0 = - ((M0 & (0xffffffffll << 0)) >> T0) | - ((M0 >> T0) & (0xffffffffll << 32)); - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = - NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); -} - -void OPPROTO op_iwmmxt_srlq_M0_T0(void) -{ - M0 >>= T0; - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0); -} - -void OPPROTO op_iwmmxt_sllw_M0_T0(void) -{ - M0 = - (((M0 & (0xffffll << 0)) << T0) & (0xffffll << 0)) | - (((M0 & (0xffffll << 16)) << T0) & (0xffffll << 16)) | - (((M0 & (0xffffll << 32)) << T0) & (0xffffll << 32)) | - (((M0 & (0xffffll << 48)) << T0) & (0xffffll << 48)); - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = - NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | - NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); -} - -void OPPROTO op_iwmmxt_slll_M0_T0(void) -{ - M0 = - ((M0 << T0) & (0xffffffffll << 0)) | - ((M0 & (0xffffffffll << 32)) << T0); - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = - NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); -} - -void OPPROTO op_iwmmxt_sllq_M0_T0(void) -{ - M0 <<= T0; - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0); -} - -void OPPROTO op_iwmmxt_sraw_M0_T0(void) -{ - M0 = - ((uint64_t) ((EXTEND16(M0 >> 0) >> T0) & 0xffff) << 0) | - ((uint64_t) ((EXTEND16(M0 >> 16) >> T0) & 0xffff) << 16) | - ((uint64_t) ((EXTEND16(M0 >> 32) >> T0) & 0xffff) << 32) | - ((uint64_t) ((EXTEND16(M0 >> 48) >> T0) & 0xffff) << 48); - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = - NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | - NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); -} - -void OPPROTO op_iwmmxt_sral_M0_T0(void) -{ - M0 = - (((EXTEND32(M0 >> 0) >> T0) & 0xffffffff) << 0) | - (((EXTEND32(M0 >> 32) >> T0) & 0xffffffff) << 32); - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = - NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); -} - -void OPPROTO op_iwmmxt_sraq_M0_T0(void) -{ - M0 = (int64_t) M0 >> T0; - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0); -} - -void OPPROTO op_iwmmxt_rorw_M0_T0(void) -{ - M0 = - ((((M0 & (0xffffll << 0)) >> T0) | - ((M0 & (0xffffll << 0)) << (16 - T0))) & (0xffffll << 0)) | - ((((M0 & (0xffffll << 16)) >> T0) | - ((M0 & (0xffffll << 16)) << (16 - T0))) & (0xffffll << 16)) | - ((((M0 & (0xffffll << 32)) >> T0) | - ((M0 & (0xffffll << 32)) << (16 - T0))) & (0xffffll << 32)) | - ((((M0 & (0xffffll << 48)) >> T0) | - ((M0 & (0xffffll << 48)) << (16 - T0))) & (0xffffll << 48)); - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = - NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | - NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); -} - -void OPPROTO op_iwmmxt_rorl_M0_T0(void) -{ - M0 = - ((M0 & (0xffffffffll << 0)) >> T0) | - ((M0 >> T0) & (0xffffffffll << 32)) | - ((M0 << (32 - T0)) & (0xffffffffll << 0)) | - ((M0 & (0xffffffffll << 32)) << (32 - T0)); - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = - NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); -} - -void OPPROTO op_iwmmxt_rorq_M0_T0(void) -{ - M0 = (M0 >> T0) | (M0 << (64 - T0)); - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0); -} - -void OPPROTO op_iwmmxt_shufh_M0_T0(void) -{ - M0 = - (((M0 >> ((T0 << 4) & 0x30)) & 0xffff) << 0) | - (((M0 >> ((T0 << 2) & 0x30)) & 0xffff) << 16) | - (((M0 >> ((T0 << 0) & 0x30)) & 0xffff) << 32) | - (((M0 >> ((T0 >> 2) & 0x30)) & 0xffff) << 48); - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = - NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | - NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); -} - -/* TODO: Unsigned-Saturation */ -void OPPROTO op_iwmmxt_packuw_M0_wRn(void) -{ - M0 = - (((M0 >> 0) & 0xff) << 0) | (((M0 >> 16) & 0xff) << 8) | - (((M0 >> 32) & 0xff) << 16) | (((M0 >> 48) & 0xff) << 24) | - (((M1 >> 0) & 0xff) << 32) | (((M1 >> 16) & 0xff) << 40) | - (((M1 >> 32) & 0xff) << 48) | (((M1 >> 48) & 0xff) << 56); - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = - NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) | - NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) | - NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) | - NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7); -} - -void OPPROTO op_iwmmxt_packul_M0_wRn(void) -{ - M0 = - (((M0 >> 0) & 0xffff) << 0) | (((M0 >> 32) & 0xffff) << 16) | - (((M1 >> 0) & 0xffff) << 32) | (((M1 >> 32) & 0xffff) << 48); - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = - NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | - NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); -} - -void OPPROTO op_iwmmxt_packuq_M0_wRn(void) -{ - M0 = (M0 & 0xffffffff) | ((M1 & 0xffffffff) << 32); - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = - NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); -} - -/* TODO: Signed-Saturation */ -void OPPROTO op_iwmmxt_packsw_M0_wRn(void) -{ - M0 = - (((M0 >> 0) & 0xff) << 0) | (((M0 >> 16) & 0xff) << 8) | - (((M0 >> 32) & 0xff) << 16) | (((M0 >> 48) & 0xff) << 24) | - (((M1 >> 0) & 0xff) << 32) | (((M1 >> 16) & 0xff) << 40) | - (((M1 >> 32) & 0xff) << 48) | (((M1 >> 48) & 0xff) << 56); - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = - NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) | - NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) | - NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) | - NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7); -} - -void OPPROTO op_iwmmxt_packsl_M0_wRn(void) -{ - M0 = - (((M0 >> 0) & 0xffff) << 0) | (((M0 >> 32) & 0xffff) << 16) | - (((M1 >> 0) & 0xffff) << 32) | (((M1 >> 32) & 0xffff) << 48); - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = - NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | - NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); -} - -void OPPROTO op_iwmmxt_packsq_M0_wRn(void) -{ - M0 = (M0 & 0xffffffff) | ((M1 & 0xffffffff) << 32); - env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = - NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); -} - -void OPPROTO op_iwmmxt_muladdsl_M0_T0_T1(void) -{ - M0 += (int32_t) EXTEND32(T0) * (int32_t) EXTEND32(T1); -} - -void OPPROTO op_iwmmxt_muladdsw_M0_T0_T1(void) -{ - M0 += EXTEND32(EXTEND16S((T0 >> 0) & 0xffff) * - EXTEND16S((T1 >> 0) & 0xffff)); - M0 += EXTEND32(EXTEND16S((T0 >> 16) & 0xffff) * - EXTEND16S((T1 >> 16) & 0xffff)); -} - -void OPPROTO op_iwmmxt_muladdswl_M0_T0_T1(void) -{ - M0 += EXTEND32(EXTEND16S(T0 & 0xffff) * - EXTEND16S(T1 & 0xffff)); -} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/op_mem.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/op_mem.h --- qemu-0.9.1/target-arm/op_mem.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/op_mem.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,149 +0,0 @@ -/* ARM memory operations. */ - -void helper_ld(uint32_t); -/* Load from address T1 into T0. */ -#define MEM_LD_OP(name) \ -void OPPROTO glue(op_ld##name,MEMSUFFIX)(void) \ -{ \ - T0 = glue(ld##name,MEMSUFFIX)(T1); \ - FORCE_RET(); \ -} - -MEM_LD_OP(ub) -MEM_LD_OP(sb) -MEM_LD_OP(uw) -MEM_LD_OP(sw) -MEM_LD_OP(l) - -#undef MEM_LD_OP - -/* Store T0 to address T1. */ -#define MEM_ST_OP(name) \ -void OPPROTO glue(op_st##name,MEMSUFFIX)(void) \ -{ \ - glue(st##name,MEMSUFFIX)(T1, T0); \ - FORCE_RET(); \ -} - -MEM_ST_OP(b) -MEM_ST_OP(w) -MEM_ST_OP(l) - -#undef MEM_ST_OP - -/* Swap T0 with memory at address T1. */ -/* ??? Is this exception safe? */ -#define MEM_SWP_OP(name, lname) \ -void OPPROTO glue(op_swp##name,MEMSUFFIX)(void) \ -{ \ - uint32_t tmp; \ - cpu_lock(); \ - tmp = glue(ld##lname,MEMSUFFIX)(T1); \ - glue(st##name,MEMSUFFIX)(T1, T0); \ - T0 = tmp; \ - cpu_unlock(); \ - FORCE_RET(); \ -} - -MEM_SWP_OP(b, ub) -MEM_SWP_OP(l, l) - -#undef MEM_SWP_OP - -/* Load-locked, store exclusive. */ -#define EXCLUSIVE_OP(suffix, ldsuffix) \ -void OPPROTO glue(op_ld##suffix##ex,MEMSUFFIX)(void) \ -{ \ - cpu_lock(); \ - helper_mark_exclusive(env, T1); \ - T0 = glue(ld##ldsuffix,MEMSUFFIX)(T1); \ - cpu_unlock(); \ - FORCE_RET(); \ -} \ - \ -void OPPROTO glue(op_st##suffix##ex,MEMSUFFIX)(void) \ -{ \ - int failed; \ - cpu_lock(); \ - failed = helper_test_exclusive(env, T1); \ - /* ??? Is it safe to hold the cpu lock over a store? */ \ - if (!failed) { \ - glue(st##suffix,MEMSUFFIX)(T1, T0); \ - } \ - T0 = failed; \ - cpu_unlock(); \ - FORCE_RET(); \ -} - -EXCLUSIVE_OP(b, ub) -EXCLUSIVE_OP(w, uw) -EXCLUSIVE_OP(l, l) - -#undef EXCLUSIVE_OP - -/* Load exclusive T0:T1 from address T1. */ -void OPPROTO glue(op_ldqex,MEMSUFFIX)(void) -{ - cpu_lock(); - helper_mark_exclusive(env, T1); - T0 = glue(ldl,MEMSUFFIX)(T1); - T1 = glue(ldl,MEMSUFFIX)((T1 + 4)); - cpu_unlock(); - FORCE_RET(); -} - -/* Store exclusive T0:T2 to address T1. */ -void OPPROTO glue(op_stqex,MEMSUFFIX)(void) -{ - int failed; - cpu_lock(); - failed = helper_test_exclusive(env, T1); - /* ??? Is it safe to hold the cpu lock over a store? */ - if (!failed) { - glue(stl,MEMSUFFIX)(T1, T0); - glue(stl,MEMSUFFIX)((T1 + 4), T2); - } - T0 = failed; - cpu_unlock(); - FORCE_RET(); -} - -/* Floating point load/store. Address is in T1 */ -#define VFP_MEM_OP(p, w) \ -void OPPROTO glue(op_vfp_ld##p,MEMSUFFIX)(void) \ -{ \ - FT0##p = glue(ldf##w,MEMSUFFIX)(T1); \ - FORCE_RET(); \ -} \ -void OPPROTO glue(op_vfp_st##p,MEMSUFFIX)(void) \ -{ \ - glue(stf##w,MEMSUFFIX)(T1, FT0##p); \ - FORCE_RET(); \ -} - -VFP_MEM_OP(s,l) -VFP_MEM_OP(d,q) - -#undef VFP_MEM_OP - -/* iwMMXt load/store. Address is in T1 */ -#define MMX_MEM_OP(name, ldname) \ -void OPPROTO glue(op_iwmmxt_ld##name,MEMSUFFIX)(void) \ -{ \ - M0 = glue(ld##ldname,MEMSUFFIX)(T1); \ - FORCE_RET(); \ -} \ -void OPPROTO glue(op_iwmmxt_st##name,MEMSUFFIX)(void) \ -{ \ - glue(st##name,MEMSUFFIX)(T1, M0); \ - FORCE_RET(); \ -} - -MMX_MEM_OP(b, ub) -MMX_MEM_OP(w, uw) -MMX_MEM_OP(l, l) -MMX_MEM_OP(q, q) - -#undef MMX_MEM_OP - -#undef MEMSUFFIX diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/op_neon.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/op_neon.h --- qemu-0.9.1/target-arm/op_neon.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/op_neon.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,1754 +0,0 @@ -/* - * ARM NEON vector operations. - * - * Copyright (c) 2007 CodeSourcery. - * Written by Paul Brook - * - * This code is licenced under the GPL. - */ -/* Note that for NEON an "l" prefix means it is a wide operation, unlike - scalar arm ops where it means a word size operation. */ - -/* ??? NEON ops should probably have their own float status. */ -#define NFS &env->vfp.fp_status -#define NEON_OP(name) void OPPROTO op_neon_##name (void) - -NEON_OP(getreg_T0) -{ - T0 = *(uint32_t *)((char *) env + PARAM1); -} - -NEON_OP(getreg_T1) -{ - T1 = *(uint32_t *)((char *) env + PARAM1); -} - -NEON_OP(getreg_T2) -{ - T2 = *(uint32_t *)((char *) env + PARAM1); -} - -NEON_OP(setreg_T0) -{ - *(uint32_t *)((char *) env + PARAM1) = T0; -} - -NEON_OP(setreg_T1) -{ - *(uint32_t *)((char *) env + PARAM1) = T1; -} - -NEON_OP(setreg_T2) -{ - *(uint32_t *)((char *) env + PARAM1) = T2; -} - -#define NEON_TYPE1(name, type) \ -typedef struct \ -{ \ - type v1; \ -} neon_##name; -#ifdef WORDS_BIGENDIAN -#define NEON_TYPE2(name, type) \ -typedef struct \ -{ \ - type v2; \ - type v1; \ -} neon_##name; -#define NEON_TYPE4(name, type) \ -typedef struct \ -{ \ - type v4; \ - type v3; \ - type v2; \ - type v1; \ -} neon_##name; -#else -#define NEON_TYPE2(name, type) \ -typedef struct \ -{ \ - type v1; \ - type v2; \ -} neon_##name; -#define NEON_TYPE4(name, type) \ -typedef struct \ -{ \ - type v1; \ - type v2; \ - type v3; \ - type v4; \ -} neon_##name; -#endif - -NEON_TYPE4(s8, int8_t) -NEON_TYPE4(u8, uint8_t) -NEON_TYPE2(s16, int16_t) -NEON_TYPE2(u16, uint16_t) -NEON_TYPE1(s32, int32_t) -NEON_TYPE1(u32, uint32_t) -#undef NEON_TYPE4 -#undef NEON_TYPE2 -#undef NEON_TYPE1 - -/* Copy from a uint32_t to a vector structure type. */ -#define NEON_UNPACK(vtype, dest, val) do { \ - union { \ - vtype v; \ - uint32_t i; \ - } conv_u; \ - conv_u.i = (val); \ - dest = conv_u.v; \ - } while(0) - -/* Copy from a vector structure type to a uint32_t. */ -#define NEON_PACK(vtype, dest, val) do { \ - union { \ - vtype v; \ - uint32_t i; \ - } conv_u; \ - conv_u.v = (val); \ - dest = conv_u.i; \ - } while(0) - -#define NEON_DO1 \ - NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); -#define NEON_DO2 \ - NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); \ - NEON_FN(vdest.v2, vsrc1.v2, vsrc2.v2); -#define NEON_DO4 \ - NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); \ - NEON_FN(vdest.v2, vsrc1.v2, vsrc2.v2); \ - NEON_FN(vdest.v3, vsrc1.v3, vsrc2.v3); \ - NEON_FN(vdest.v4, vsrc1.v4, vsrc2.v4); - -#define NEON_VOP(name, vtype, n) \ -NEON_OP(name) \ -{ \ - vtype vsrc1; \ - vtype vsrc2; \ - vtype vdest; \ - NEON_UNPACK(vtype, vsrc1, T0); \ - NEON_UNPACK(vtype, vsrc2, T1); \ - NEON_DO##n; \ - NEON_PACK(vtype, T0, vdest); \ - FORCE_RET(); \ -} - -#define NEON_VOP1(name, vtype, n) \ -NEON_OP(name) \ -{ \ - vtype vsrc1; \ - vtype vdest; \ - NEON_UNPACK(vtype, vsrc1, T0); \ - NEON_DO##n; \ - NEON_PACK(vtype, T0, vdest); \ - FORCE_RET(); \ -} - -/* Pairwise operations. */ -/* For 32-bit elements each segment only contains a single element, so - the elementwise and pairwise operations are the same. */ -#define NEON_PDO2 \ - NEON_FN(vdest.v1, vsrc1.v1, vsrc1.v2); \ - NEON_FN(vdest.v2, vsrc2.v1, vsrc2.v2); -#define NEON_PDO4 \ - NEON_FN(vdest.v1, vsrc1.v1, vsrc1.v2); \ - NEON_FN(vdest.v2, vsrc1.v3, vsrc1.v4); \ - NEON_FN(vdest.v3, vsrc2.v1, vsrc2.v2); \ - NEON_FN(vdest.v4, vsrc2.v3, vsrc2.v4); \ - -#define NEON_POP(name, vtype, n) \ -NEON_OP(name) \ -{ \ - vtype vsrc1; \ - vtype vsrc2; \ - vtype vdest; \ - NEON_UNPACK(vtype, vsrc1, T0); \ - NEON_UNPACK(vtype, vsrc2, T1); \ - NEON_PDO##n; \ - NEON_PACK(vtype, T0, vdest); \ - FORCE_RET(); \ -} - -#define NEON_FN(dest, src1, src2) dest = (src1 + src2) >> 1 -NEON_VOP(hadd_s8, neon_s8, 4) -NEON_VOP(hadd_u8, neon_u8, 4) -NEON_VOP(hadd_s16, neon_s16, 2) -NEON_VOP(hadd_u16, neon_u16, 2) -#undef NEON_FN - -NEON_OP(hadd_s32) -{ - int32_t src1 = T0; - int32_t src2 = T1; - int32_t dest; - - dest = (src1 >> 1) + (src2 >> 1); - if (src1 & src2 & 1) - dest++; - T0 = dest; - FORCE_RET(); -} - -NEON_OP(hadd_u32) -{ - uint32_t src1 = T0; - uint32_t src2 = T1; - uint32_t dest; - - dest = (src1 >> 1) + (src2 >> 1); - if (src1 & src2 & 1) - dest++; - T0 = dest; - FORCE_RET(); -} - -#define NEON_FN(dest, src1, src2) dest = (src1 + src2 + 1) >> 1 -NEON_VOP(rhadd_s8, neon_s8, 4) -NEON_VOP(rhadd_u8, neon_u8, 4) -NEON_VOP(rhadd_s16, neon_s16, 2) -NEON_VOP(rhadd_u16, neon_u16, 2) -#undef NEON_FN - -NEON_OP(rhadd_s32) -{ - int32_t src1 = T0; - int32_t src2 = T1; - int32_t dest; - - dest = (src1 >> 1) + (src2 >> 1); - if ((src1 | src2) & 1) - dest++; - T0 = dest; - FORCE_RET(); -} - -NEON_OP(rhadd_u32) -{ - uint32_t src1 = T0; - uint32_t src2 = T1; - uint32_t dest; - - dest = (src1 >> 1) + (src2 >> 1); - if ((src1 | src2) & 1) - dest++; - T0 = dest; - FORCE_RET(); -} - -#define NEON_FN(dest, src1, src2) dest = (src1 - src2) >> 1 -NEON_VOP(hsub_s8, neon_s8, 4) -NEON_VOP(hsub_u8, neon_u8, 4) -NEON_VOP(hsub_s16, neon_s16, 2) -NEON_VOP(hsub_u16, neon_u16, 2) -#undef NEON_FN - -NEON_OP(hsub_s32) -{ - int32_t src1 = T0; - int32_t src2 = T1; - int32_t dest; - - dest = (src1 >> 1) - (src2 >> 1); - if ((~src1) & src2 & 1) - dest--; - T0 = dest; - FORCE_RET(); -} - -NEON_OP(hsub_u32) -{ - uint32_t src1 = T0; - uint32_t src2 = T1; - uint32_t dest; - - dest = (src1 >> 1) - (src2 >> 1); - if ((~src1) & src2 & 1) - dest--; - T0 = dest; - FORCE_RET(); -} - -/* ??? bsl, bif and bit are all the same op, just with the oparands in a - differnet order. It's currently easier to have 3 differnt ops than - rearange the operands. */ - -/* Bitwise Select. */ -NEON_OP(bsl) -{ - T0 = (T0 & T2) | (T1 & ~T2); -} - -/* Bitwise Insert If True. */ -NEON_OP(bit) -{ - T0 = (T0 & T1) | (T2 & ~T1); -} - -/* Bitwise Insert If False. */ -NEON_OP(bif) -{ - T0 = (T2 & T1) | (T0 & ~T1); -} - -#define NEON_USAT(dest, src1, src2, type) do { \ - uint32_t tmp = (uint32_t)src1 + (uint32_t)src2; \ - if (tmp != (type)tmp) { \ - env->QF = 1; \ - dest = ~0; \ - } else { \ - dest = tmp; \ - }} while(0) -#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint8_t) -NEON_VOP(qadd_u8, neon_u8, 4) -#undef NEON_FN -#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint16_t) -NEON_VOP(qadd_u16, neon_u16, 2) -#undef NEON_FN -#undef NEON_USAT - -#define NEON_SSAT(dest, src1, src2, type) do { \ - int32_t tmp = (uint32_t)src1 + (uint32_t)src2; \ - if (tmp != (type)tmp) { \ - env->QF = 1; \ - if (src2 > 0) { \ - tmp = (1 << (sizeof(type) * 8 - 1)) - 1; \ - } else { \ - tmp = 1 << (sizeof(type) * 8 - 1); \ - } \ - } \ - dest = tmp; \ - } while(0) -#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int8_t) -NEON_VOP(qadd_s8, neon_s8, 4) -#undef NEON_FN -#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int16_t) -NEON_VOP(qadd_s16, neon_s16, 2) -#undef NEON_FN -#undef NEON_SSAT - -#define NEON_USAT(dest, src1, src2, type) do { \ - uint32_t tmp = (uint32_t)src1 - (uint32_t)src2; \ - if (tmp != (type)tmp) { \ - env->QF = 1; \ - dest = 0; \ - } else { \ - dest = tmp; \ - }} while(0) -#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint8_t) -NEON_VOP(qsub_u8, neon_u8, 4) -#undef NEON_FN -#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint16_t) -NEON_VOP(qsub_u16, neon_u16, 2) -#undef NEON_FN -#undef NEON_USAT - -#define NEON_SSAT(dest, src1, src2, type) do { \ - int32_t tmp = (uint32_t)src1 - (uint32_t)src2; \ - if (tmp != (type)tmp) { \ - env->QF = 1; \ - if (src2 < 0) { \ - tmp = (1 << (sizeof(type) * 8 - 1)) - 1; \ - } else { \ - tmp = 1 << (sizeof(type) * 8 - 1); \ - } \ - } \ - dest = tmp; \ - } while(0) -#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int8_t) -NEON_VOP(qsub_s8, neon_s8, 4) -#undef NEON_FN -#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int16_t) -NEON_VOP(qsub_s16, neon_s16, 2) -#undef NEON_FN -#undef NEON_SSAT - -#define NEON_FN(dest, src1, src2) dest = (src1 > src2) ? ~0 : 0 -NEON_VOP(cgt_s8, neon_s8, 4) -NEON_VOP(cgt_u8, neon_u8, 4) -NEON_VOP(cgt_s16, neon_s16, 2) -NEON_VOP(cgt_u16, neon_u16, 2) -NEON_VOP(cgt_s32, neon_s32, 1) -NEON_VOP(cgt_u32, neon_u32, 1) -#undef NEON_FN - -#define NEON_FN(dest, src1, src2) dest = (src1 >= src2) ? ~0 : 0 -NEON_VOP(cge_s8, neon_s8, 4) -NEON_VOP(cge_u8, neon_u8, 4) -NEON_VOP(cge_s16, neon_s16, 2) -NEON_VOP(cge_u16, neon_u16, 2) -NEON_VOP(cge_s32, neon_s32, 1) -NEON_VOP(cge_u32, neon_u32, 1) -#undef NEON_FN - -#define NEON_FN(dest, src1, src2) do { \ - int8_t tmp; \ - tmp = (int8_t)src2; \ - if (tmp < 0) { \ - dest = src1 >> -tmp; \ - } else { \ - dest = src1 << tmp; \ - }} while (0) -NEON_VOP(shl_s8, neon_s8, 4) -NEON_VOP(shl_u8, neon_u8, 4) -NEON_VOP(shl_s16, neon_s16, 2) -NEON_VOP(shl_u16, neon_u16, 2) -NEON_VOP(shl_s32, neon_s32, 1) -NEON_VOP(shl_u32, neon_u32, 1) -#undef NEON_FN - -NEON_OP(shl_u64) -{ - int8_t shift = T2; - uint64_t val = T0 | ((uint64_t)T1 << 32); - if (shift < 0) { - val >>= -shift; - } else { - val <<= shift; - } - T0 = val; - T1 = val >> 32; - FORCE_RET(); -} - -NEON_OP(shl_s64) -{ - int8_t shift = T2; - int64_t val = T0 | ((uint64_t)T1 << 32); - if (shift < 0) { - val >>= -shift; - } else { - val <<= shift; - } - T0 = val; - T1 = val >> 32; - FORCE_RET(); -} - -#define NEON_FN(dest, src1, src2) do { \ - int8_t tmp; \ - tmp = (int8_t)src1; \ - if (tmp < 0) { \ - dest = (src2 + (1 << (-1 - tmp))) >> -tmp; \ - } else { \ - dest = src2 << tmp; \ - }} while (0) - -NEON_VOP(rshl_s8, neon_s8, 4) -NEON_VOP(rshl_u8, neon_u8, 4) -NEON_VOP(rshl_s16, neon_s16, 2) -NEON_VOP(rshl_u16, neon_u16, 2) -NEON_VOP(rshl_s32, neon_s32, 1) -NEON_VOP(rshl_u32, neon_u32, 1) -#undef NEON_FN - -NEON_OP(rshl_u64) -{ - int8_t shift = T2; - uint64_t val = T0 | ((uint64_t)T1 << 32); - if (shift < 0) { - val = (val + ((uint64_t)1 << (-1 - shift))) >> -shift; - val >>= -shift; - } else { - val <<= shift; - } - T0 = val; - T1 = val >> 32; - FORCE_RET(); -} - -NEON_OP(rshl_s64) -{ - int8_t shift = T2; - int64_t val = T0 | ((uint64_t)T1 << 32); - if (shift < 0) { - val = (val + ((int64_t)1 << (-1 - shift))) >> -shift; - } else { - val <<= shift; - } - T0 = val; - T1 = val >> 32; - FORCE_RET(); -} - -#define NEON_FN(dest, src1, src2) do { \ - int8_t tmp; \ - tmp = (int8_t)src1; \ - if (tmp < 0) { \ - dest = src2 >> -tmp; \ - } else { \ - dest = src2 << tmp; \ - if ((dest >> tmp) != src2) { \ - env->QF = 1; \ - dest = ~0; \ - } \ - }} while (0) -NEON_VOP(qshl_s8, neon_s8, 4) -NEON_VOP(qshl_s16, neon_s16, 2) -NEON_VOP(qshl_s32, neon_s32, 1) -#undef NEON_FN - -NEON_OP(qshl_s64) -{ - int8_t shift = T2; - int64_t val = T0 | ((uint64_t)T1 << 32); - if (shift < 0) { - val >>= -shift; - } else { - int64_t tmp = val; - val <<= shift; - if ((val >> shift) != tmp) { - env->QF = 1; - val = (tmp >> 63) ^ 0x7fffffffffffffffULL; - } - } - T0 = val; - T1 = val >> 32; - FORCE_RET(); -} - -#define NEON_FN(dest, src1, src2) do { \ - int8_t tmp; \ - tmp = (int8_t)src1; \ - if (tmp < 0) { \ - dest = src2 >> -tmp; \ - } else { \ - dest = src2 << tmp; \ - if ((dest >> tmp) != src2) { \ - env->QF = 1; \ - dest = src2 >> 31; \ - } \ - }} while (0) -NEON_VOP(qshl_u8, neon_u8, 4) -NEON_VOP(qshl_u16, neon_u16, 2) -NEON_VOP(qshl_u32, neon_u32, 1) -#undef NEON_FN - -NEON_OP(qshl_u64) -{ - int8_t shift = T2; - uint64_t val = T0 | ((uint64_t)T1 << 32); - if (shift < 0) { - val >>= -shift; - } else { - uint64_t tmp = val; - val <<= shift; - if ((val >> shift) != tmp) { - env->QF = 1; - val = ~(uint64_t)0; - } - } - T0 = val; - T1 = val >> 32; - FORCE_RET(); -} - -#define NEON_FN(dest, src1, src2) do { \ - int8_t tmp; \ - tmp = (int8_t)src1; \ - if (tmp < 0) { \ - dest = (src2 + (1 << (-1 - tmp))) >> -tmp; \ - } else { \ - dest = src2 << tmp; \ - if ((dest >> tmp) != src2) { \ - dest = ~0; \ - } \ - }} while (0) -NEON_VOP(qrshl_s8, neon_s8, 4) -NEON_VOP(qrshl_s16, neon_s16, 2) -NEON_VOP(qrshl_s32, neon_s32, 1) -#undef NEON_FN - -#define NEON_FN(dest, src1, src2) do { \ - int8_t tmp; \ - tmp = (int8_t)src1; \ - if (tmp < 0) { \ - dest = (src2 + (1 << (-1 - tmp))) >> -tmp; \ - } else { \ - dest = src2 << tmp; \ - if ((dest >> tmp) != src2) { \ - env->QF = 1; \ - dest = src2 >> 31; \ - } \ - }} while (0) -NEON_VOP(qrshl_u8, neon_u8, 4) -NEON_VOP(qrshl_u16, neon_u16, 2) -NEON_VOP(qrshl_u32, neon_u32, 1) -#undef NEON_FN - -#define NEON_FN(dest, src1, src2) dest = (src1 > src2) ? src1 : src2 -NEON_VOP(max_s8, neon_s8, 4) -NEON_VOP(max_u8, neon_u8, 4) -NEON_VOP(max_s16, neon_s16, 2) -NEON_VOP(max_u16, neon_u16, 2) -NEON_VOP(max_s32, neon_s32, 1) -NEON_VOP(max_u32, neon_u32, 1) -NEON_POP(pmax_s8, neon_s8, 4) -NEON_POP(pmax_u8, neon_u8, 4) -NEON_POP(pmax_s16, neon_s16, 2) -NEON_POP(pmax_u16, neon_u16, 2) -#undef NEON_FN - -NEON_OP(max_f32) -{ - float32 f0 = vfp_itos(T0); - float32 f1 = vfp_itos(T1); - T0 = (float32_compare_quiet(f0, f1, NFS) == 1) ? T0 : T1; - FORCE_RET(); -} - -#define NEON_FN(dest, src1, src2) dest = (src1 < src2) ? src1 : src2 -NEON_VOP(min_s8, neon_s8, 4) -NEON_VOP(min_u8, neon_u8, 4) -NEON_VOP(min_s16, neon_s16, 2) -NEON_VOP(min_u16, neon_u16, 2) -NEON_VOP(min_s32, neon_s32, 1) -NEON_VOP(min_u32, neon_u32, 1) -NEON_POP(pmin_s8, neon_s8, 4) -NEON_POP(pmin_u8, neon_u8, 4) -NEON_POP(pmin_s16, neon_s16, 2) -NEON_POP(pmin_u16, neon_u16, 2) -#undef NEON_FN - -NEON_OP(min_f32) -{ - float32 f0 = vfp_itos(T0); - float32 f1 = vfp_itos(T1); - T0 = (float32_compare_quiet(f0, f1, NFS) == -1) ? T0 : T1; - FORCE_RET(); -} - -#define NEON_FN(dest, src1, src2) \ - dest = (src1 > src2) ? (src1 - src2) : (src2 - src1) -NEON_VOP(abd_s8, neon_s8, 4) -NEON_VOP(abd_u8, neon_u8, 4) -NEON_VOP(abd_s16, neon_s16, 2) -NEON_VOP(abd_u16, neon_u16, 2) -NEON_VOP(abd_s32, neon_s32, 1) -NEON_VOP(abd_u32, neon_u32, 1) -#undef NEON_FN - -NEON_OP(abd_f32) -{ - float32 f0 = vfp_itos(T0); - float32 f1 = vfp_itos(T1); - T0 = vfp_stoi((float32_compare_quiet(f0, f1, NFS) == 1) - ? float32_sub(f0, f1, NFS) - : float32_sub(f1, f0, NFS)); - FORCE_RET(); -} - -#define NEON_FN(dest, src1, src2) dest = src1 + src2 -NEON_VOP(add_u8, neon_u8, 4) -NEON_VOP(add_u16, neon_u16, 2) -NEON_POP(padd_u8, neon_u8, 4) -NEON_POP(padd_u16, neon_u16, 2) -#undef NEON_FN - -NEON_OP(add_f32) -{ - T0 = vfp_stoi(float32_add(vfp_itos(T0), vfp_itos(T1), NFS)); - FORCE_RET(); -} - -#define NEON_FN(dest, src1, src2) dest = src1 - src2 -NEON_VOP(sub_u8, neon_u8, 4) -NEON_VOP(sub_u16, neon_u16, 2) -#undef NEON_FN - -NEON_OP(sub_f32) -{ - T0 = vfp_stoi(float32_sub(vfp_itos(T0), vfp_itos(T1), NFS)); - FORCE_RET(); -} - -#define NEON_FN(dest, src1, src2) dest = src2 - src1 -NEON_VOP(rsb_u8, neon_u8, 4) -NEON_VOP(rsb_u16, neon_u16, 2) -#undef NEON_FN - -NEON_OP(rsb_f32) -{ - T0 = vfp_stoi(float32_sub(vfp_itos(T1), vfp_itos(T0), NFS)); - FORCE_RET(); -} - -#define NEON_FN(dest, src1, src2) dest = src1 * src2 -NEON_VOP(mul_u8, neon_u8, 4) -NEON_VOP(mul_u16, neon_u16, 2) -#undef NEON_FN - -NEON_OP(mul_f32) -{ - T0 = vfp_stoi(float32_mul(vfp_itos(T0), vfp_itos(T1), NFS)); - FORCE_RET(); -} - -NEON_OP(mul_p8) -{ - T0 = helper_neon_mul_p8(T0, T1); -} - -#define NEON_FN(dest, src1, src2) dest = (src1 & src2) ? -1 : 0 -NEON_VOP(tst_u8, neon_u8, 4) -NEON_VOP(tst_u16, neon_u16, 2) -NEON_VOP(tst_u32, neon_u32, 1) -#undef NEON_FN - -#define NEON_FN(dest, src1, src2) dest = (src1 == src2) ? -1 : 0 -NEON_VOP(ceq_u8, neon_u8, 4) -NEON_VOP(ceq_u16, neon_u16, 2) -NEON_VOP(ceq_u32, neon_u32, 1) -#undef NEON_FN - -#define NEON_QDMULH16(dest, src1, src2, round) do { \ - uint32_t tmp = (int32_t)(int16_t) src1 * (int16_t) src2; \ - if ((tmp ^ (tmp << 1)) & SIGNBIT) { \ - env->QF = 1; \ - tmp = (tmp >> 31) ^ ~SIGNBIT; \ - } \ - tmp <<= 1; \ - if (round) { \ - int32_t old = tmp; \ - tmp += 1 << 15; \ - if ((int32_t)tmp < old) { \ - env->QF = 1; \ - tmp = SIGNBIT - 1; \ - } \ - } \ - dest = tmp >> 16; \ - } while(0) -#define NEON_FN(dest, src1, src2) NEON_QDMULH16(dest, src1, src2, 0) -NEON_VOP(qdmulh_s16, neon_s16, 2) -#undef NEON_FN -#define NEON_FN(dest, src1, src2) NEON_QDMULH16(dest, src1, src2, 1) -NEON_VOP(qrdmulh_s16, neon_s16, 2) -#undef NEON_FN -#undef NEON_QDMULH16 - -#define SIGNBIT64 ((uint64_t)1 << 63) -#define NEON_QDMULH32(dest, src1, src2, round) do { \ - uint64_t tmp = (int64_t)(int32_t) src1 * (int32_t) src2; \ - if ((tmp ^ (tmp << 1)) & SIGNBIT64) { \ - env->QF = 1; \ - tmp = (tmp >> 63) ^ ~SIGNBIT64; \ - } else { \ - tmp <<= 1; \ - } \ - if (round) { \ - int64_t old = tmp; \ - tmp += (int64_t)1 << 31; \ - if ((int64_t)tmp < old) { \ - env->QF = 1; \ - tmp = SIGNBIT64 - 1; \ - } \ - } \ - dest = tmp >> 32; \ - } while(0) -#define NEON_FN(dest, src1, src2) NEON_QDMULH32(dest, src1, src2, 0) -NEON_VOP(qdmulh_s32, neon_s32, 1) -#undef NEON_FN -#define NEON_FN(dest, src1, src2) NEON_QDMULH32(dest, src1, src2, 1) -NEON_VOP(qrdmulh_s32, neon_s32, 1) -#undef NEON_FN -#undef NEON_QDMULH32 - -NEON_OP(recps_f32) -{ - T0 = vfp_stoi(helper_recps_f32(vfp_itos(T0), vfp_itos(T1))); - FORCE_RET(); -} - -NEON_OP(rsqrts_f32) -{ - T0 = vfp_stoi(helper_rsqrts_f32(vfp_itos(T0), vfp_itos(T1))); - FORCE_RET(); -} - -/* Floating point comparisons produce an integer result. */ -#define NEON_VOP_FCMP(name, cmp) \ -NEON_OP(name) \ -{ \ - if (float32_compare_quiet(vfp_itos(T0), vfp_itos(T1), NFS) cmp 0) \ - T0 = -1; \ - else \ - T0 = 0; \ - FORCE_RET(); \ -} - -NEON_VOP_FCMP(ceq_f32, ==) -NEON_VOP_FCMP(cge_f32, >=) -NEON_VOP_FCMP(cgt_f32, >) - -NEON_OP(acge_f32) -{ - float32 f0 = float32_abs(vfp_itos(T0)); - float32 f1 = float32_abs(vfp_itos(T1)); - T0 = (float32_compare_quiet(f0, f1,NFS) >= 0) ? -1 : 0; - FORCE_RET(); -} - -NEON_OP(acgt_f32) -{ - float32 f0 = float32_abs(vfp_itos(T0)); - float32 f1 = float32_abs(vfp_itos(T1)); - T0 = (float32_compare_quiet(f0, f1, NFS) > 0) ? -1 : 0; - FORCE_RET(); -} - -/* Narrowing instructions. The named type is the destination type. */ -NEON_OP(narrow_u8) -{ - T0 = (T0 & 0xff) | ((T0 >> 8) & 0xff00) - | ((T1 << 16) & 0xff0000) | (T1 << 24); - FORCE_RET(); -} - -NEON_OP(narrow_sat_u8) -{ - neon_u16 src; - neon_u8 dest; -#define SAT8(d, s) \ - if (s > 0xff) { \ - d = 0xff; \ - env->QF = 1; \ - } else { \ - d = s; \ - } - - NEON_UNPACK(neon_u16, src, T0); - SAT8(dest.v1, src.v1); - SAT8(dest.v2, src.v2); - NEON_UNPACK(neon_u16, src, T1); - SAT8(dest.v3, src.v1); - SAT8(dest.v4, src.v2); - NEON_PACK(neon_u8, T0, dest); - FORCE_RET(); -#undef SAT8 -} - -NEON_OP(narrow_sat_s8) -{ - neon_s16 src; - neon_s8 dest; -#define SAT8(d, s) \ - if (s != (uint8_t)s) { \ - d = (s >> 15) ^ 0x7f; \ - env->QF = 1; \ - } else { \ - d = s; \ - } - - NEON_UNPACK(neon_s16, src, T0); - SAT8(dest.v1, src.v1); - SAT8(dest.v2, src.v2); - NEON_UNPACK(neon_s16, src, T1); - SAT8(dest.v3, src.v1); - SAT8(dest.v4, src.v2); - NEON_PACK(neon_s8, T0, dest); - FORCE_RET(); -#undef SAT8 -} - -NEON_OP(narrow_u16) -{ - T0 = (T0 & 0xffff) | (T1 << 16); -} - -NEON_OP(narrow_sat_u16) -{ - if (T0 > 0xffff) { - T0 = 0xffff; - env->QF = 1; - } - if (T1 > 0xffff) { - T1 = 0xffff; - env->QF = 1; - } - T0 |= T1 << 16; - FORCE_RET(); -} - -NEON_OP(narrow_sat_s16) -{ - if ((int32_t)T0 != (int16_t)T0) { - T0 = ((int32_t)T0 >> 31) ^ 0x7fff; - env->QF = 1; - } - if ((int32_t)T1 != (int16_t) T1) { - T1 = ((int32_t)T1 >> 31) ^ 0x7fff; - env->QF = 1; - } - T0 = (uint16_t)T0 | (T1 << 16); - FORCE_RET(); -} - -NEON_OP(narrow_sat_u32) -{ - if (T1) { - T0 = 0xffffffffu; - env->QF = 1; - } - FORCE_RET(); -} - -NEON_OP(narrow_sat_s32) -{ - int32_t sign = (int32_t)T1 >> 31; - - if ((int32_t)T1 != sign) { - T0 = sign ^ 0x7fffffff; - env->QF = 1; - } - FORCE_RET(); -} - -/* Narrowing instructions. Named type is the narrow type. */ -NEON_OP(narrow_high_u8) -{ - T0 = ((T0 >> 8) & 0xff) | ((T0 >> 16) & 0xff00) - | ((T1 << 8) & 0xff0000) | (T1 & 0xff000000); - FORCE_RET(); -} - -NEON_OP(narrow_high_u16) -{ - T0 = (T0 >> 16) | (T1 & 0xffff0000); - FORCE_RET(); -} - -NEON_OP(narrow_high_round_u8) -{ - T0 = (((T0 + 0x80) >> 8) & 0xff) | (((T0 + 0x800000) >> 16) & 0xff00) - | (((T1 + 0x80) << 8) & 0xff0000) | ((T1 + 0x800000) & 0xff000000); - FORCE_RET(); -} - -NEON_OP(narrow_high_round_u16) -{ - T0 = ((T0 + 0x8000) >> 16) | ((T1 + 0x8000) & 0xffff0000); - FORCE_RET(); -} - -NEON_OP(narrow_high_round_u32) -{ - if (T0 >= 0x80000000u) - T0 = T1 + 1; - else - T0 = T1; - FORCE_RET(); -} - -/* Widening instructions. Named type is source type. */ -NEON_OP(widen_s8) -{ - uint32_t src; - - src = T0; - T0 = (uint16_t)(int8_t)src | ((int8_t)(src >> 8) << 16); - T1 = (uint16_t)(int8_t)(src >> 16) | ((int8_t)(src >> 24) << 16); -} - -NEON_OP(widen_u8) -{ - T1 = ((T0 >> 8) & 0xff0000) | ((T0 >> 16) & 0xff); - T0 = ((T0 << 8) & 0xff0000) | (T0 & 0xff); -} - -NEON_OP(widen_s16) -{ - int32_t src; - - src = T0; - T0 = (int16_t)src; - T1 = src >> 16; -} - -NEON_OP(widen_u16) -{ - T1 = T0 >> 16; - T0 &= 0xffff; -} - -NEON_OP(widen_s32) -{ - T1 = (int32_t)T0 >> 31; - FORCE_RET(); -} - -NEON_OP(widen_high_u8) -{ - T1 = (T0 & 0xff000000) | ((T0 >> 8) & 0xff00); - T0 = ((T0 << 16) & 0xff000000) | ((T0 << 8) & 0xff00); -} - -NEON_OP(widen_high_u16) -{ - T1 = T0 & 0xffff0000; - T0 <<= 16; -} - -/* Long operations. The type is the wide type. */ -NEON_OP(shll_u16) -{ - int shift = PARAM1; - uint32_t mask; - - mask = 0xffff >> (16 - shift); - mask |= mask << 16; - mask = ~mask; - - T0 = (T0 << shift) & mask; - T1 = (T1 << shift) & mask; - FORCE_RET(); -} - -NEON_OP(shll_u64) -{ - int shift = PARAM1; - - T1 <<= shift; - T1 |= T0 >> (32 - shift); - T0 <<= shift; - FORCE_RET(); -} - -NEON_OP(addl_u16) -{ - uint32_t tmp; - uint32_t high; - - tmp = env->vfp.scratch[0]; - high = (T0 >> 16) + (tmp >> 16); - T0 = (uint16_t)(T0 + tmp); - T0 |= (high << 16); - tmp = env->vfp.scratch[1]; - high = (T1 >> 16) + (tmp >> 16); - T1 = (uint16_t)(T1 + tmp); - T1 |= (high << 16); - FORCE_RET(); -} - -NEON_OP(addl_u32) -{ - T0 += env->vfp.scratch[0]; - T1 += env->vfp.scratch[1]; - FORCE_RET(); -} - -NEON_OP(addl_u64) -{ - uint64_t tmp; - tmp = T0 | ((uint64_t)T1 << 32); - tmp += env->vfp.scratch[0]; - tmp += (uint64_t)env->vfp.scratch[1] << 32; - T0 = tmp; - T1 = tmp >> 32; - FORCE_RET(); -} - -NEON_OP(subl_u16) -{ - uint32_t tmp; - uint32_t high; - - tmp = env->vfp.scratch[0]; - high = (T0 >> 16) - (tmp >> 16); - T0 = (uint16_t)(T0 - tmp); - T0 |= (high << 16); - tmp = env->vfp.scratch[1]; - high = (T1 >> 16) - (tmp >> 16); - T1 = (uint16_t)(T1 - tmp); - T1 |= (high << 16); - FORCE_RET(); -} - -NEON_OP(subl_u32) -{ - T0 -= env->vfp.scratch[0]; - T1 -= env->vfp.scratch[1]; - FORCE_RET(); -} - -NEON_OP(subl_u64) -{ - uint64_t tmp; - tmp = T0 | ((uint64_t)T1 << 32); - tmp -= env->vfp.scratch[0]; - tmp -= (uint64_t)env->vfp.scratch[1] << 32; - T0 = tmp; - T1 = tmp >> 32; - FORCE_RET(); -} - -#define DO_ABD(dest, x, y, type) do { \ - type tmp_x = x; \ - type tmp_y = y; \ - dest = ((tmp_x > tmp_y) ? tmp_x - tmp_y : tmp_y - tmp_x); \ - } while(0) - -NEON_OP(abdl_u16) -{ - uint32_t tmp; - uint32_t low; - uint32_t high; - - DO_ABD(low, T0, T1, uint8_t); - DO_ABD(tmp, T0 >> 8, T1 >> 8, uint8_t); - low |= tmp << 16; - DO_ABD(high, T0 >> 16, T1 >> 16, uint8_t); - DO_ABD(tmp, T0 >> 24, T1 >> 24, uint8_t); - high |= tmp << 16; - T0 = low; - T1 = high; - FORCE_RET(); -} - -NEON_OP(abdl_s16) -{ - uint32_t tmp; - uint32_t low; - uint32_t high; - - DO_ABD(low, T0, T1, int8_t); - DO_ABD(tmp, T0 >> 8, T1 >> 8, int8_t); - low |= tmp << 16; - DO_ABD(high, T0 >> 16, T1 >> 16, int8_t); - DO_ABD(tmp, T0 >> 24, T1 >> 24, int8_t); - high |= tmp << 16; - T0 = low; - T1 = high; - FORCE_RET(); -} - -NEON_OP(abdl_u32) -{ - uint32_t low; - uint32_t high; - - DO_ABD(low, T0, T1, uint16_t); - DO_ABD(high, T0 >> 16, T1 >> 16, uint16_t); - T0 = low; - T1 = high; - FORCE_RET(); -} - -NEON_OP(abdl_s32) -{ - uint32_t low; - uint32_t high; - - DO_ABD(low, T0, T1, int16_t); - DO_ABD(high, T0 >> 16, T1 >> 16, int16_t); - T0 = low; - T1 = high; - FORCE_RET(); -} - -NEON_OP(abdl_u64) -{ - DO_ABD(T0, T0, T1, uint32_t); - T1 = 0; -} - -NEON_OP(abdl_s64) -{ - DO_ABD(T0, T0, T1, int32_t); - T1 = 0; -} -#undef DO_ABD - -/* Widening multiple. Named type is the source type. */ -#define DO_MULL(dest, x, y, type1, type2) do { \ - type1 tmp_x = x; \ - type1 tmp_y = y; \ - dest = (type2)((type2)tmp_x * (type2)tmp_y); \ - } while(0) - -NEON_OP(mull_u8) -{ - uint32_t tmp; - uint32_t low; - uint32_t high; - - DO_MULL(low, T0, T1, uint8_t, uint16_t); - DO_MULL(tmp, T0 >> 8, T1 >> 8, uint8_t, uint16_t); - low |= tmp << 16; - DO_MULL(high, T0 >> 16, T1 >> 16, uint8_t, uint16_t); - DO_MULL(tmp, T0 >> 24, T1 >> 24, uint8_t, uint16_t); - high |= tmp << 16; - T0 = low; - T1 = high; - FORCE_RET(); -} - -NEON_OP(mull_s8) -{ - uint32_t tmp; - uint32_t low; - uint32_t high; - - DO_MULL(low, T0, T1, int8_t, uint16_t); - DO_MULL(tmp, T0 >> 8, T1 >> 8, int8_t, uint16_t); - low |= tmp << 16; - DO_MULL(high, T0 >> 16, T1 >> 16, int8_t, uint16_t); - DO_MULL(tmp, T0 >> 24, T1 >> 24, int8_t, uint16_t); - high |= tmp << 16; - T0 = low; - T1 = high; - FORCE_RET(); -} - -NEON_OP(mull_u16) -{ - uint32_t low; - uint32_t high; - - DO_MULL(low, T0, T1, uint16_t, uint32_t); - DO_MULL(high, T0 >> 16, T1 >> 16, uint16_t, uint32_t); - T0 = low; - T1 = high; - FORCE_RET(); -} - -NEON_OP(mull_s16) -{ - uint32_t low; - uint32_t high; - - DO_MULL(low, T0, T1, int16_t, uint32_t); - DO_MULL(high, T0 >> 16, T1 >> 16, int16_t, uint32_t); - T0 = low; - T1 = high; - FORCE_RET(); -} - -NEON_OP(addl_saturate_s32) -{ - uint32_t tmp; - uint32_t res; - - tmp = env->vfp.scratch[0]; - res = T0 + tmp; - if (((res ^ T0) & SIGNBIT) && !((T0 ^ tmp) & SIGNBIT)) { - env->QF = 1; - T0 = (T0 >> 31) ^ 0x7fffffff; - } else { - T0 = res; - } - tmp = env->vfp.scratch[1]; - res = T1 + tmp; - if (((res ^ T1) & SIGNBIT) && !((T1 ^ tmp) & SIGNBIT)) { - env->QF = 1; - T1 = (T1 >> 31) ^ 0x7fffffff; - } else { - T1 = res; - } - FORCE_RET(); -} - -NEON_OP(addl_saturate_s64) -{ - uint64_t src1; - uint64_t src2; - uint64_t res; - - src1 = T0 + ((uint64_t)T1 << 32); - src2 = env->vfp.scratch[0] + ((uint64_t)env->vfp.scratch[1] << 32); - res = src1 + src2; - if (((res ^ src1) & SIGNBIT64) && !((src1 ^ src2) & SIGNBIT64)) { - env->QF = 1; - T0 = ~(int64_t)src1 >> 63; - T1 = T0 ^ 0x80000000; - } else { - T0 = res; - T1 = res >> 32; - } - FORCE_RET(); -} - -NEON_OP(addl_saturate_u64) -{ - uint64_t src1; - uint64_t src2; - uint64_t res; - - src1 = T0 + ((uint64_t)T1 << 32); - src2 = env->vfp.scratch[0] + ((uint64_t)env->vfp.scratch[1] << 32); - res = src1 + src2; - if (res < src1) { - env->QF = 1; - T0 = 0xffffffff; - T1 = 0xffffffff; - } else { - T0 = res; - T1 = res >> 32; - } - FORCE_RET(); -} - -NEON_OP(subl_saturate_s64) -{ - uint64_t src1; - uint64_t src2; - uint64_t res; - - src1 = T0 + ((uint64_t)T1 << 32); - src2 = env->vfp.scratch[0] + ((uint64_t)env->vfp.scratch[1] << 32); - res = src1 - src2; - if (((res ^ src1) & SIGNBIT64) && ((src1 ^ src2) & SIGNBIT64)) { - env->QF = 1; - T0 = ~(int64_t)src1 >> 63; - T1 = T0 ^ 0x80000000; - } else { - T0 = res; - T1 = res >> 32; - } - FORCE_RET(); -} - -NEON_OP(subl_saturate_u64) -{ - uint64_t src1; - uint64_t src2; - uint64_t res; - - src1 = T0 + ((uint64_t)T1 << 32); - src2 = env->vfp.scratch[0] + ((uint64_t)env->vfp.scratch[1] << 32); - if (src1 < src2) { - env->QF = 1; - T0 = 0; - T1 = 0; - } else { - res = src1 - src2; - T0 = res; - T1 = res >> 32; - } - FORCE_RET(); -} - -NEON_OP(negl_u16) -{ - uint32_t tmp; - tmp = T0 >> 16; - tmp = -tmp; - T0 = (-T0 & 0xffff) | (tmp << 16); - tmp = T1 >> 16; - tmp = -tmp; - T1 = (-T1 & 0xffff) | (tmp << 16); - FORCE_RET(); -} - -NEON_OP(negl_u32) -{ - T0 = -T0; - T1 = -T1; - FORCE_RET(); -} - -NEON_OP(negl_u64) -{ - uint64_t val; - - val = T0 | ((uint64_t)T1 << 32); - val = -val; - T0 = val; - T1 = val >> 32; - FORCE_RET(); -} - -/* Scalar operations. */ -NEON_OP(dup_low16) -{ - T0 = (T0 & 0xffff) | (T0 << 16); - FORCE_RET(); -} - -NEON_OP(dup_high16) -{ - T0 = (T0 >> 16) | (T0 & 0xffff0000); - FORCE_RET(); -} - -/* Helper for VEXT */ -NEON_OP(extract) -{ - int shift = PARAM1; - T0 = (T0 >> shift) | (T1 << (32 - shift)); - FORCE_RET(); -} - -/* Pairwise add long. Named type is source type. */ -NEON_OP(paddl_s8) -{ - int8_t src1; - int8_t src2; - uint16_t result; - src1 = T0 >> 24; - src2 = T0 >> 16; - result = (uint16_t)src1 + src2; - src1 = T0 >> 8; - src2 = T0; - T0 = (uint16_t)((uint16_t)src1 + src2) | ((uint32_t)result << 16); - FORCE_RET(); -} - -NEON_OP(paddl_u8) -{ - uint8_t src1; - uint8_t src2; - uint16_t result; - src1 = T0 >> 24; - src2 = T0 >> 16; - result = (uint16_t)src1 + src2; - src1 = T0 >> 8; - src2 = T0; - T0 = (uint16_t)((uint16_t)src1 + src2) | ((uint32_t)result << 16); - FORCE_RET(); -} - -NEON_OP(paddl_s16) -{ - T0 = (uint32_t)(int16_t)T0 + (uint32_t)(int16_t)(T0 >> 16); - FORCE_RET(); -} - -NEON_OP(paddl_u16) -{ - T0 = (uint32_t)(uint16_t)T0 + (uint32_t)(uint16_t)(T0 >> 16); - FORCE_RET(); -} - -NEON_OP(paddl_s32) -{ - int64_t tmp; - tmp = (int64_t)(int32_t)T0 + (int64_t)(int32_t)T1; - T0 = tmp; - T1 = tmp >> 32; - FORCE_RET(); -} - -NEON_OP(paddl_u32) -{ - uint64_t tmp; - tmp = (uint64_t)T0 + (uint64_t)T1; - T0 = tmp; - T1 = tmp >> 32; - FORCE_RET(); -} - -/* Count Leading Sign/Zero Bits. */ -static inline int do_clz8(uint8_t x) -{ - int n; - for (n = 8; x; n--) - x >>= 1; - return n; -} - -static inline int do_clz16(uint16_t x) -{ - int n; - for (n = 16; x; n--) - x >>= 1; - return n; -} - -NEON_OP(clz_u8) -{ - uint32_t result; - uint32_t tmp; - - tmp = T0; - result = do_clz8(tmp); - result |= do_clz8(tmp >> 8) << 8; - result |= do_clz8(tmp >> 16) << 16; - result |= do_clz8(tmp >> 24) << 24; - T0 = result; - FORCE_RET(); -} - -NEON_OP(clz_u16) -{ - uint32_t result; - uint32_t tmp; - tmp = T0; - result = do_clz16(tmp); - result |= do_clz16(tmp >> 16) << 16; - T0 = result; - FORCE_RET(); -} - -NEON_OP(cls_s8) -{ - uint32_t result; - int8_t tmp; - tmp = T0; - result = do_clz8((tmp < 0) ? ~tmp : tmp) - 1; - tmp = T0 >> 8; - result |= (do_clz8((tmp < 0) ? ~tmp : tmp) - 1) << 8; - tmp = T0 >> 16; - result |= (do_clz8((tmp < 0) ? ~tmp : tmp) - 1) << 16; - tmp = T0 >> 24; - result |= (do_clz8((tmp < 0) ? ~tmp : tmp) - 1) << 24; - T0 = result; - FORCE_RET(); -} - -NEON_OP(cls_s16) -{ - uint32_t result; - int16_t tmp; - tmp = T0; - result = do_clz16((tmp < 0) ? ~tmp : tmp) - 1; - tmp = T0 >> 16; - result |= (do_clz16((tmp < 0) ? ~tmp : tmp) - 1) << 16; - T0 = result; - FORCE_RET(); -} - -NEON_OP(cls_s32) -{ - int count; - if ((int32_t)T0 < 0) - T0 = ~T0; - for (count = 32; T0 > 0; count--) - T0 = T0 >> 1; - T0 = count - 1; - FORCE_RET(); -} - -/* Bit count. */ -NEON_OP(cnt_u8) -{ - T0 = (T0 & 0x55555555) + ((T0 >> 1) & 0x55555555); - T0 = (T0 & 0x33333333) + ((T0 >> 2) & 0x33333333); - T0 = (T0 & 0x0f0f0f0f) + ((T0 >> 4) & 0x0f0f0f0f); - FORCE_RET(); -} - -/* Saturnating negation. */ -/* ??? Make these use NEON_VOP1 */ -#define DO_QABS8(x) do { \ - if (x == (int8_t)0x80) { \ - x = 0x7f; \ - env->QF = 1; \ - } else if (x < 0) { \ - x = -x; \ - }} while (0) -NEON_OP(qabs_s8) -{ - neon_s8 vec; - NEON_UNPACK(neon_s8, vec, T0); - DO_QABS8(vec.v1); - DO_QABS8(vec.v2); - DO_QABS8(vec.v3); - DO_QABS8(vec.v4); - NEON_PACK(neon_s8, T0, vec); - FORCE_RET(); -} -#undef DO_QABS8 - -#define DO_QNEG8(x) do { \ - if (x == (int8_t)0x80) { \ - x = 0x7f; \ - env->QF = 1; \ - } else { \ - x = -x; \ - }} while (0) -NEON_OP(qneg_s8) -{ - neon_s8 vec; - NEON_UNPACK(neon_s8, vec, T0); - DO_QNEG8(vec.v1); - DO_QNEG8(vec.v2); - DO_QNEG8(vec.v3); - DO_QNEG8(vec.v4); - NEON_PACK(neon_s8, T0, vec); - FORCE_RET(); -} -#undef DO_QNEG8 - -#define DO_QABS16(x) do { \ - if (x == (int16_t)0x8000) { \ - x = 0x7fff; \ - env->QF = 1; \ - } else if (x < 0) { \ - x = -x; \ - }} while (0) -NEON_OP(qabs_s16) -{ - neon_s16 vec; - NEON_UNPACK(neon_s16, vec, T0); - DO_QABS16(vec.v1); - DO_QABS16(vec.v2); - NEON_PACK(neon_s16, T0, vec); - FORCE_RET(); -} -#undef DO_QABS16 - -#define DO_QNEG16(x) do { \ - if (x == (int16_t)0x8000) { \ - x = 0x7fff; \ - env->QF = 1; \ - } else { \ - x = -x; \ - }} while (0) -NEON_OP(qneg_s16) -{ - neon_s16 vec; - NEON_UNPACK(neon_s16, vec, T0); - DO_QNEG16(vec.v1); - DO_QNEG16(vec.v2); - NEON_PACK(neon_s16, T0, vec); - FORCE_RET(); -} -#undef DO_QNEG16 - -NEON_OP(qabs_s32) -{ - if (T0 == 0x80000000) { - T0 = 0x7fffffff; - env->QF = 1; - } else if ((int32_t)T0 < 0) { - T0 = -T0; - } - FORCE_RET(); -} - -NEON_OP(qneg_s32) -{ - if (T0 == 0x80000000) { - T0 = 0x7fffffff; - env->QF = 1; - } else { - T0 = -T0; - } - FORCE_RET(); -} - -/* Unary opperations */ -#define NEON_FN(dest, src, dummy) dest = (src < 0) ? -src : src -NEON_VOP1(abs_s8, neon_s8, 4) -NEON_VOP1(abs_s16, neon_s16, 2) -NEON_OP(abs_s32) -{ - if ((int32_t)T0 < 0) - T0 = -T0; - FORCE_RET(); -} -#undef NEON_FN - -/* Transpose. Argument order is rather strange to avoid special casing - the tranlation code. - On input T0 = rm, T1 = rd. On output T0 = rd, T1 = rm */ -NEON_OP(trn_u8) -{ - uint32_t rd; - uint32_t rm; - rd = ((T0 & 0x00ff00ff) << 8) | (T1 & 0x00ff00ff); - rm = ((T1 & 0xff00ff00) >> 8) | (T0 & 0xff00ff00); - T0 = rd; - T1 = rm; - FORCE_RET(); -} - -NEON_OP(trn_u16) -{ - uint32_t rd; - uint32_t rm; - rd = (T0 << 16) | (T1 & 0xffff); - rm = (T1 >> 16) | (T0 & 0xffff0000); - T0 = rd; - T1 = rm; - FORCE_RET(); -} - -/* Worker routines for zip and unzip. */ -NEON_OP(unzip_u8) -{ - uint32_t rd; - uint32_t rm; - rd = (T0 & 0xff) | ((T0 >> 8) & 0xff00) - | ((T1 << 16) & 0xff0000) | ((T1 << 8) & 0xff000000); - rm = ((T0 >> 8) & 0xff) | ((T0 >> 16) & 0xff00) - | ((T1 << 8) & 0xff0000) | (T1 & 0xff000000); - T0 = rd; - T1 = rm; - FORCE_RET(); -} - -NEON_OP(zip_u8) -{ - uint32_t rd; - uint32_t rm; - rd = (T0 & 0xff) | ((T1 << 8) & 0xff00) - | ((T0 << 16) & 0xff0000) | ((T1 << 24) & 0xff000000); - rm = ((T0 >> 16) & 0xff) | ((T1 >> 8) & 0xff00) - | ((T0 >> 8) & 0xff0000) | (T1 & 0xff000000); - T0 = rd; - T1 = rm; - FORCE_RET(); -} - -NEON_OP(zip_u16) -{ - uint32_t tmp; - - tmp = (T0 & 0xffff) | (T1 << 16); - T1 = (T1 & 0xffff0000) | (T0 >> 16); - T0 = tmp; - FORCE_RET(); -} - -/* Reciprocal/root estimate. */ -NEON_OP(recpe_u32) -{ - T0 = helper_recpe_u32(T0); -} - -NEON_OP(rsqrte_u32) -{ - T0 = helper_rsqrte_u32(T0); -} - -NEON_OP(recpe_f32) -{ - FT0s = helper_recpe_f32(FT0s); -} - -NEON_OP(rsqrte_f32) -{ - FT0s = helper_rsqrte_f32(FT0s); -} - -/* Table lookup. This accessed the register file directly. */ -NEON_OP(tbl) -{ - helper_neon_tbl(PARAM1, PARAM2); -} - -NEON_OP(dup_u8) -{ - T0 = (T0 >> PARAM1) & 0xff; - T0 |= T0 << 8; - T0 |= T0 << 16; - FORCE_RET(); -} - -/* Helpers for element load/store. */ -NEON_OP(insert_elt) -{ - int shift = PARAM1; - uint32_t mask = PARAM2; - T2 = (T2 & mask) | (T0 << shift); - FORCE_RET(); -} - -NEON_OP(extract_elt) -{ - int shift = PARAM1; - uint32_t mask = PARAM2; - T0 = (T2 & mask) >> shift; - FORCE_RET(); -} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/op_template.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/op_template.h --- qemu-0.9.1/target-arm/op_template.h 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/op_template.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,53 +0,0 @@ -/* - * ARM micro operations (templates for various register related - * operations) - * - * Copyright (c) 2003 Fabrice Bellard - * - * 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 - */ - -#ifndef SET_REG -#define SET_REG(x) REG = x -#endif - -void OPPROTO glue(op_movl_T0_, REGNAME)(void) -{ - T0 = REG; -} - -void OPPROTO glue(op_movl_T1_, REGNAME)(void) -{ - T1 = REG; -} - -void OPPROTO glue(op_movl_T2_, REGNAME)(void) -{ - T2 = REG; -} - -void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void) -{ - SET_REG (T0); -} - -void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void) -{ - SET_REG (T1); -} - -#undef REG -#undef REGNAME -#undef SET_REG diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-arm/translate.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-arm/translate.c --- qemu-0.9.1/target-arm/translate.c 2008-01-06 19:38:44.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-arm/translate.c 2008-11-03 19:09:29.000000000 +0000 @@ -28,6 +28,11 @@ #include "cpu.h" #include "exec-all.h" #include "disas.h" +#include "tcg-op.h" +#include "qemu-log.h" + +#define GEN_HELPER 1 +#include "helpers.h" #define ENABLE_ARCH_5J 0 #define ENABLE_ARCH_6 arm_feature(env, ARM_FEATURE_V6) @@ -35,7 +40,7 @@ #define ENABLE_ARCH_6T2 arm_feature(env, ARM_FEATURE_THUMB2) #define ENABLE_ARCH_7 arm_feature(env, ARM_FEATURE_V7) -#define ARCH(x) if (!ENABLE_ARCH_##x) goto illegal_op; +#define ARCH(x) do { if (!ENABLE_ARCH_##x) goto illegal_op; } while(0) /* internal defines */ typedef struct DisasContext { @@ -68,90 +73,690 @@ #define DISAS_WFI 4 #define DISAS_SWI 5 -#ifdef USE_DIRECT_JUMP -#define TBPARAM(x) -#else -#define TBPARAM(x) (long)(x) -#endif +static TCGv cpu_env; +/* We reuse the same 64-bit temporaries for efficiency. */ +static TCGv cpu_V0, cpu_V1, cpu_M0; -/* XXX: move that elsewhere */ -static uint16_t *gen_opc_ptr; -static uint32_t *gen_opparam_ptr; -extern FILE *logfile; -extern int loglevel; - -enum { -#define DEF(s, n, copy_size) INDEX_op_ ## s, -#include "opc.h" -#undef DEF - NB_OPS, -}; +/* FIXME: These should be removed. */ +static TCGv cpu_T[2]; +static TCGv cpu_F0s, cpu_F1s, cpu_F0d, cpu_F1d; + +#define ICOUNT_TEMP cpu_T[0] +#include "gen-icount.h" + +/* initialize TCG globals. */ +void arm_translate_init(void) +{ + cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env"); + + cpu_T[0] = tcg_global_reg_new(TCG_TYPE_I32, TCG_AREG1, "T0"); + cpu_T[1] = tcg_global_reg_new(TCG_TYPE_I32, TCG_AREG2, "T1"); +} + +/* The code generator doesn't like lots of temporaries, so maintain our own + cache for reuse within a function. */ +#define MAX_TEMPS 8 +static int num_temps; +static TCGv temps[MAX_TEMPS]; + +/* Allocate a temporary variable. */ +static TCGv new_tmp(void) +{ + TCGv tmp; + if (num_temps == MAX_TEMPS) + abort(); + + if (GET_TCGV(temps[num_temps])) + return temps[num_temps++]; + + tmp = tcg_temp_new(TCG_TYPE_I32); + temps[num_temps++] = tmp; + return tmp; +} + +/* Release a temporary variable. */ +static void dead_tmp(TCGv tmp) +{ + int i; + num_temps--; + i = num_temps; + if (GET_TCGV(temps[i]) == GET_TCGV(tmp)) + return; + + /* Shuffle this temp to the last slot. */ + while (GET_TCGV(temps[i]) != GET_TCGV(tmp)) + i--; + while (i < num_temps) { + temps[i] = temps[i + 1]; + i++; + } + temps[i] = tmp; +} + +static inline TCGv load_cpu_offset(int offset) +{ + TCGv tmp = new_tmp(); + tcg_gen_ld_i32(tmp, cpu_env, offset); + return tmp; +} + +#define load_cpu_field(name) load_cpu_offset(offsetof(CPUState, name)) + +static inline void store_cpu_offset(TCGv var, int offset) +{ + tcg_gen_st_i32(var, cpu_env, offset); + dead_tmp(var); +} + +#define store_cpu_field(var, name) \ + store_cpu_offset(var, offsetof(CPUState, name)) + +/* Set a variable to the value of a CPU register. */ +static void load_reg_var(DisasContext *s, TCGv var, int reg) +{ + if (reg == 15) { + uint32_t addr; + /* normaly, since we updated PC, we need only to add one insn */ + if (s->thumb) + addr = (long)s->pc + 2; + else + addr = (long)s->pc + 4; + tcg_gen_movi_i32(var, addr); + } else { + tcg_gen_ld_i32(var, cpu_env, offsetof(CPUState, regs[reg])); + } +} + +/* Create a new temporary and set it to the value of a CPU register. */ +static inline TCGv load_reg(DisasContext *s, int reg) +{ + TCGv tmp = new_tmp(); + load_reg_var(s, tmp, reg); + return tmp; +} + +/* Set a CPU register. The source must be a temporary and will be + marked as dead. */ +static void store_reg(DisasContext *s, int reg, TCGv var) +{ + if (reg == 15) { + tcg_gen_andi_i32(var, var, ~1); + s->is_jmp = DISAS_JUMP; + } + tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, regs[reg])); + dead_tmp(var); +} + + +/* Basic operations. */ +#define gen_op_movl_T0_T1() tcg_gen_mov_i32(cpu_T[0], cpu_T[1]) +#define gen_op_movl_T1_T0() tcg_gen_mov_i32(cpu_T[1], cpu_T[0]) +#define gen_op_movl_T0_im(im) tcg_gen_movi_i32(cpu_T[0], im) +#define gen_op_movl_T1_im(im) tcg_gen_movi_i32(cpu_T[1], im) + +#define gen_op_addl_T1_im(im) tcg_gen_addi_i32(cpu_T[1], cpu_T[1], im) +#define gen_op_addl_T0_T1() tcg_gen_add_i32(cpu_T[0], cpu_T[0], cpu_T[1]) +#define gen_op_subl_T0_T1() tcg_gen_sub_i32(cpu_T[0], cpu_T[0], cpu_T[1]) +#define gen_op_rsbl_T0_T1() tcg_gen_sub_i32(cpu_T[0], cpu_T[1], cpu_T[0]) + +#define gen_op_addl_T0_T1_cc() gen_helper_add_cc(cpu_T[0], cpu_T[0], cpu_T[1]) +#define gen_op_adcl_T0_T1_cc() gen_helper_adc_cc(cpu_T[0], cpu_T[0], cpu_T[1]) +#define gen_op_subl_T0_T1_cc() gen_helper_sub_cc(cpu_T[0], cpu_T[0], cpu_T[1]) +#define gen_op_sbcl_T0_T1_cc() gen_helper_sbc_cc(cpu_T[0], cpu_T[0], cpu_T[1]) +#define gen_op_rsbl_T0_T1_cc() gen_helper_sub_cc(cpu_T[0], cpu_T[1], cpu_T[0]) +#define gen_op_rscl_T0_T1_cc() gen_helper_sbc_cc(cpu_T[0], cpu_T[1], cpu_T[0]) + +#define gen_op_andl_T0_T1() tcg_gen_and_i32(cpu_T[0], cpu_T[0], cpu_T[1]) +#define gen_op_xorl_T0_T1() tcg_gen_xor_i32(cpu_T[0], cpu_T[0], cpu_T[1]) +#define gen_op_orl_T0_T1() tcg_gen_or_i32(cpu_T[0], cpu_T[0], cpu_T[1]) +#define gen_op_notl_T0() tcg_gen_not_i32(cpu_T[0], cpu_T[0]) +#define gen_op_notl_T1() tcg_gen_not_i32(cpu_T[1], cpu_T[1]) +#define gen_op_logic_T0_cc() gen_logic_CC(cpu_T[0]); +#define gen_op_logic_T1_cc() gen_logic_CC(cpu_T[1]); + +#define gen_op_shll_T0_im(im) tcg_gen_shli_i32(cpu_T[0], cpu_T[0], im) +#define gen_op_shll_T1_im(im) tcg_gen_shli_i32(cpu_T[1], cpu_T[1], im) +#define gen_op_shrl_T1_im(im) tcg_gen_shri_i32(cpu_T[1], cpu_T[1], im) +#define gen_op_sarl_T1_im(im) tcg_gen_sari_i32(cpu_T[1], cpu_T[1], im) +#define gen_op_rorl_T1_im(im) tcg_gen_rori_i32(cpu_T[1], cpu_T[1], im) + +/* Value extensions. */ +#define gen_uxtb(var) tcg_gen_ext8u_i32(var, var) +#define gen_uxth(var) tcg_gen_ext16u_i32(var, var) +#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var) +#define gen_sxth(var) tcg_gen_ext16s_i32(var, var) -#include "gen-op.h" +#define gen_sxtb16(var) gen_helper_sxtb16(var, var) +#define gen_uxtb16(var) gen_helper_uxtb16(var, var) -#define PAS_OP(pfx) { \ - gen_op_ ## pfx ## add16_T0_T1, \ - gen_op_ ## pfx ## addsubx_T0_T1, \ - gen_op_ ## pfx ## subaddx_T0_T1, \ - gen_op_ ## pfx ## sub16_T0_T1, \ - gen_op_ ## pfx ## add8_T0_T1, \ - NULL, \ - NULL, \ - gen_op_ ## pfx ## sub8_T0_T1 } - -static GenOpFunc *gen_arm_parallel_addsub[8][8] = { - {}, - PAS_OP(s), - PAS_OP(q), - PAS_OP(sh), - {}, - PAS_OP(u), - PAS_OP(uq), - PAS_OP(uh), +#define gen_op_mul_T0_T1() tcg_gen_mul_i32(cpu_T[0], cpu_T[0], cpu_T[1]) + +#define gen_set_cpsr(var, mask) gen_helper_cpsr_write(var, tcg_const_i32(mask)) +/* Set NZCV flags from the high 4 bits of var. */ +#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV) + +static void gen_exception(int excp) +{ + TCGv tmp = new_tmp(); + tcg_gen_movi_i32(tmp, excp); + gen_helper_exception(tmp); + dead_tmp(tmp); +} + +static void gen_smul_dual(TCGv a, TCGv b) +{ + TCGv tmp1 = new_tmp(); + TCGv tmp2 = new_tmp(); + tcg_gen_ext16s_i32(tmp1, a); + tcg_gen_ext16s_i32(tmp2, b); + tcg_gen_mul_i32(tmp1, tmp1, tmp2); + dead_tmp(tmp2); + tcg_gen_sari_i32(a, a, 16); + tcg_gen_sari_i32(b, b, 16); + tcg_gen_mul_i32(b, b, a); + tcg_gen_mov_i32(a, tmp1); + dead_tmp(tmp1); +} + +/* Byteswap each halfword. */ +static void gen_rev16(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_shri_i32(tmp, var, 8); + tcg_gen_andi_i32(tmp, tmp, 0x00ff00ff); + tcg_gen_shli_i32(var, var, 8); + tcg_gen_andi_i32(var, var, 0xff00ff00); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); +} + +/* Byteswap low halfword and sign extend. */ +static void gen_revsh(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_shri_i32(tmp, var, 8); + tcg_gen_andi_i32(tmp, tmp, 0x00ff); + tcg_gen_shli_i32(var, var, 8); + tcg_gen_ext8s_i32(var, var); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); +} + +/* Unsigned bitfield extract. */ +static void gen_ubfx(TCGv var, int shift, uint32_t mask) +{ + if (shift) + tcg_gen_shri_i32(var, var, shift); + tcg_gen_andi_i32(var, var, mask); +} + +/* Signed bitfield extract. */ +static void gen_sbfx(TCGv var, int shift, int width) +{ + uint32_t signbit; + + if (shift) + tcg_gen_sari_i32(var, var, shift); + if (shift + width < 32) { + signbit = 1u << (width - 1); + tcg_gen_andi_i32(var, var, (1u << width) - 1); + tcg_gen_xori_i32(var, var, signbit); + tcg_gen_subi_i32(var, var, signbit); + } +} + +/* Bitfield insertion. Insert val into base. Clobbers base and val. */ +static void gen_bfi(TCGv dest, TCGv base, TCGv val, int shift, uint32_t mask) +{ + tcg_gen_andi_i32(val, val, mask); + tcg_gen_shli_i32(val, val, shift); + tcg_gen_andi_i32(base, base, ~(mask << shift)); + tcg_gen_or_i32(dest, base, val); +} + +/* Round the top 32 bits of a 64-bit value. */ +static void gen_roundqd(TCGv a, TCGv b) +{ + tcg_gen_shri_i32(a, a, 31); + tcg_gen_add_i32(a, a, b); +} + +/* FIXME: Most targets have native widening multiplication. + It would be good to use that instead of a full wide multiply. */ +/* 32x32->64 multiply. Marks inputs as dead. */ +static TCGv gen_mulu_i64_i32(TCGv a, TCGv b) +{ + TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_extu_i32_i64(tmp1, a); + dead_tmp(a); + tcg_gen_extu_i32_i64(tmp2, b); + dead_tmp(b); + tcg_gen_mul_i64(tmp1, tmp1, tmp2); + return tmp1; +} + +static TCGv gen_muls_i64_i32(TCGv a, TCGv b) +{ + TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_ext_i32_i64(tmp1, a); + dead_tmp(a); + tcg_gen_ext_i32_i64(tmp2, b); + dead_tmp(b); + tcg_gen_mul_i64(tmp1, tmp1, tmp2); + return tmp1; +} + +/* Unsigned 32x32->64 multiply. */ +static void gen_op_mull_T0_T1(void) +{ + TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_extu_i32_i64(tmp1, cpu_T[0]); + tcg_gen_extu_i32_i64(tmp2, cpu_T[1]); + tcg_gen_mul_i64(tmp1, tmp1, tmp2); + tcg_gen_trunc_i64_i32(cpu_T[0], tmp1); + tcg_gen_shri_i64(tmp1, tmp1, 32); + tcg_gen_trunc_i64_i32(cpu_T[1], tmp1); +} + +/* Signed 32x32->64 multiply. */ +static void gen_imull(TCGv a, TCGv b) +{ + TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_ext_i32_i64(tmp1, a); + tcg_gen_ext_i32_i64(tmp2, b); + tcg_gen_mul_i64(tmp1, tmp1, tmp2); + tcg_gen_trunc_i64_i32(a, tmp1); + tcg_gen_shri_i64(tmp1, tmp1, 32); + tcg_gen_trunc_i64_i32(b, tmp1); +} +#define gen_op_imull_T0_T1() gen_imull(cpu_T[0], cpu_T[1]) + +/* Swap low and high halfwords. */ +static void gen_swap_half(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_shri_i32(tmp, var, 16); + tcg_gen_shli_i32(var, var, 16); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); +} + +/* Dual 16-bit add. Result placed in t0 and t1 is marked as dead. + tmp = (t0 ^ t1) & 0x8000; + t0 &= ~0x8000; + t1 &= ~0x8000; + t0 = (t0 + t1) ^ tmp; + */ + +static void gen_add16(TCGv t0, TCGv t1) +{ + TCGv tmp = new_tmp(); + tcg_gen_xor_i32(tmp, t0, t1); + tcg_gen_andi_i32(tmp, tmp, 0x8000); + tcg_gen_andi_i32(t0, t0, ~0x8000); + tcg_gen_andi_i32(t1, t1, ~0x8000); + tcg_gen_add_i32(t0, t0, t1); + tcg_gen_xor_i32(t0, t0, tmp); + dead_tmp(tmp); + dead_tmp(t1); +} + +#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, CF)) + +/* Set CF to the top bit of var. */ +static void gen_set_CF_bit31(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_shri_i32(tmp, var, 31); + gen_set_CF(var); + dead_tmp(tmp); +} + +/* Set N and Z flags from var. */ +static inline void gen_logic_CC(TCGv var) +{ + tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, NF)); + tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, ZF)); +} + +/* T0 += T1 + CF. */ +static void gen_adc_T0_T1(void) +{ + TCGv tmp; + gen_op_addl_T0_T1(); + tmp = load_cpu_field(CF); + tcg_gen_add_i32(cpu_T[0], cpu_T[0], tmp); + dead_tmp(tmp); +} + +/* dest = T0 - T1 + CF - 1. */ +static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1) +{ + TCGv tmp; + tcg_gen_sub_i32(dest, t0, t1); + tmp = load_cpu_field(CF); + tcg_gen_add_i32(dest, dest, tmp); + tcg_gen_subi_i32(dest, dest, 1); + dead_tmp(tmp); +} + +#define gen_sbc_T0_T1() gen_sub_carry(cpu_T[0], cpu_T[0], cpu_T[1]) +#define gen_rsc_T0_T1() gen_sub_carry(cpu_T[0], cpu_T[1], cpu_T[0]) + +/* T0 &= ~T1. Clobbers T1. */ +/* FIXME: Implement bic natively. */ +static inline void tcg_gen_bic_i32(TCGv dest, TCGv t0, TCGv t1) +{ + TCGv tmp = new_tmp(); + tcg_gen_not_i32(tmp, t1); + tcg_gen_and_i32(dest, t0, tmp); + dead_tmp(tmp); +} +static inline void gen_op_bicl_T0_T1(void) +{ + gen_op_notl_T1(); + gen_op_andl_T0_T1(); +} + +/* FIXME: Implement this natively. */ +#define tcg_gen_abs_i32(t0, t1) gen_helper_abs(t0, t1) + +/* FIXME: Implement this natively. */ +static void tcg_gen_rori_i32(TCGv t0, TCGv t1, int i) +{ + TCGv tmp; + + if (i == 0) + return; + + tmp = new_tmp(); + tcg_gen_shri_i32(tmp, t1, i); + tcg_gen_shli_i32(t1, t1, 32 - i); + tcg_gen_or_i32(t0, t1, tmp); + dead_tmp(tmp); +} + +static void shifter_out_im(TCGv var, int shift) +{ + TCGv tmp = new_tmp(); + if (shift == 0) { + tcg_gen_andi_i32(tmp, var, 1); + } else { + tcg_gen_shri_i32(tmp, var, shift); + if (shift != 31); + tcg_gen_andi_i32(tmp, tmp, 1); + } + gen_set_CF(tmp); + dead_tmp(tmp); +} + +/* Shift by immediate. Includes special handling for shift == 0. */ +static inline void gen_arm_shift_im(TCGv var, int shiftop, int shift, int flags) +{ + switch (shiftop) { + case 0: /* LSL */ + if (shift != 0) { + if (flags) + shifter_out_im(var, 32 - shift); + tcg_gen_shli_i32(var, var, shift); + } + break; + case 1: /* LSR */ + if (shift == 0) { + if (flags) { + tcg_gen_shri_i32(var, var, 31); + gen_set_CF(var); + } + tcg_gen_movi_i32(var, 0); + } else { + if (flags) + shifter_out_im(var, shift - 1); + tcg_gen_shri_i32(var, var, shift); + } + break; + case 2: /* ASR */ + if (shift == 0) + shift = 32; + if (flags) + shifter_out_im(var, shift - 1); + if (shift == 32) + shift = 31; + tcg_gen_sari_i32(var, var, shift); + break; + case 3: /* ROR/RRX */ + if (shift != 0) { + if (flags) + shifter_out_im(var, shift - 1); + tcg_gen_rori_i32(var, var, shift); break; + } else { + TCGv tmp = load_cpu_field(CF); + if (flags) + shifter_out_im(var, 0); + tcg_gen_shri_i32(var, var, 1); + tcg_gen_shli_i32(tmp, tmp, 31); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); + } + } }; + +static inline void gen_arm_shift_reg(TCGv var, int shiftop, + TCGv shift, int flags) +{ + if (flags) { + switch (shiftop) { + case 0: gen_helper_shl_cc(var, var, shift); break; + case 1: gen_helper_shr_cc(var, var, shift); break; + case 2: gen_helper_sar_cc(var, var, shift); break; + case 3: gen_helper_ror_cc(var, var, shift); break; + } + } else { + switch (shiftop) { + case 0: gen_helper_shl(var, var, shift); break; + case 1: gen_helper_shr(var, var, shift); break; + case 2: gen_helper_sar(var, var, shift); break; + case 3: gen_helper_ror(var, var, shift); break; + } + } + dead_tmp(shift); +} + +#define PAS_OP(pfx) \ + switch (op2) { \ + case 0: gen_pas_helper(glue(pfx,add16)); break; \ + case 1: gen_pas_helper(glue(pfx,addsubx)); break; \ + case 2: gen_pas_helper(glue(pfx,subaddx)); break; \ + case 3: gen_pas_helper(glue(pfx,sub16)); break; \ + case 4: gen_pas_helper(glue(pfx,add8)); break; \ + case 7: gen_pas_helper(glue(pfx,sub8)); break; \ + } +static void gen_arm_parallel_addsub(int op1, int op2, TCGv a, TCGv b) +{ + TCGv tmp; + + switch (op1) { +#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp) + case 1: + tmp = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE)); + PAS_OP(s) + break; + case 5: + tmp = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE)); + PAS_OP(u) + break; +#undef gen_pas_helper +#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b) + case 2: + PAS_OP(q); + break; + case 3: + PAS_OP(sh); + break; + case 6: + PAS_OP(uq); + break; + case 7: + PAS_OP(uh); + break; +#undef gen_pas_helper + } +} #undef PAS_OP -/* For unknown reasons Arm and Thumb-2 use arbitrarily diffenet encodings. */ -#define PAS_OP(pfx) { \ - gen_op_ ## pfx ## add8_T0_T1, \ - gen_op_ ## pfx ## add16_T0_T1, \ - gen_op_ ## pfx ## addsubx_T0_T1, \ - NULL, \ - gen_op_ ## pfx ## sub8_T0_T1, \ - gen_op_ ## pfx ## sub16_T0_T1, \ - gen_op_ ## pfx ## subaddx_T0_T1, \ - NULL } - -static GenOpFunc *gen_thumb2_parallel_addsub[8][8] = { - PAS_OP(s), - PAS_OP(q), - PAS_OP(sh), - {}, - PAS_OP(u), - PAS_OP(uq), - PAS_OP(uh), - {} -}; +/* For unknown reasons Arm and Thumb-2 use arbitrarily different encodings. */ +#define PAS_OP(pfx) \ + switch (op2) { \ + case 0: gen_pas_helper(glue(pfx,add8)); break; \ + case 1: gen_pas_helper(glue(pfx,add16)); break; \ + case 2: gen_pas_helper(glue(pfx,addsubx)); break; \ + case 4: gen_pas_helper(glue(pfx,sub8)); break; \ + case 5: gen_pas_helper(glue(pfx,sub16)); break; \ + case 6: gen_pas_helper(glue(pfx,subaddx)); break; \ + } +static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv a, TCGv b) +{ + TCGv tmp; + + switch (op1) { +#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp) + case 0: + tmp = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE)); + PAS_OP(s) + break; + case 4: + tmp = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE)); + PAS_OP(u) + break; +#undef gen_pas_helper +#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b) + case 1: + PAS_OP(q); + break; + case 2: + PAS_OP(sh); + break; + case 5: + PAS_OP(uq); + break; + case 6: + PAS_OP(uh); + break; +#undef gen_pas_helper + } +} #undef PAS_OP -static GenOpFunc1 *gen_test_cc[14] = { - gen_op_test_eq, - gen_op_test_ne, - gen_op_test_cs, - gen_op_test_cc, - gen_op_test_mi, - gen_op_test_pl, - gen_op_test_vs, - gen_op_test_vc, - gen_op_test_hi, - gen_op_test_ls, - gen_op_test_ge, - gen_op_test_lt, - gen_op_test_gt, - gen_op_test_le, -}; +static void gen_test_cc(int cc, int label) +{ + TCGv tmp; + TCGv tmp2; + int inv; + + switch (cc) { + case 0: /* eq: Z */ + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + break; + case 1: /* ne: !Z */ + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + break; + case 2: /* cs: C */ + tmp = load_cpu_field(CF); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + break; + case 3: /* cc: !C */ + tmp = load_cpu_field(CF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + break; + case 4: /* mi: N */ + tmp = load_cpu_field(NF); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + case 5: /* pl: !N */ + tmp = load_cpu_field(NF); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + break; + case 6: /* vs: V */ + tmp = load_cpu_field(VF); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + case 7: /* vc: !V */ + tmp = load_cpu_field(VF); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + break; + case 8: /* hi: C && !Z */ + inv = gen_new_label(); + tmp = load_cpu_field(CF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv); + dead_tmp(tmp); + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + gen_set_label(inv); + break; + case 9: /* ls: !C || Z */ + tmp = load_cpu_field(CF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + dead_tmp(tmp); + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + break; + case 10: /* ge: N == V -> N ^ V == 0 */ + tmp = load_cpu_field(VF); + tmp2 = load_cpu_field(NF); + tcg_gen_xor_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + break; + case 11: /* lt: N != V -> N ^ V != 0 */ + tmp = load_cpu_field(VF); + tmp2 = load_cpu_field(NF); + tcg_gen_xor_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + case 12: /* gt: !Z && N == V */ + inv = gen_new_label(); + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv); + dead_tmp(tmp); + tmp = load_cpu_field(VF); + tmp2 = load_cpu_field(NF); + tcg_gen_xor_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + gen_set_label(inv); + break; + case 13: /* le: Z || N != V */ + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + dead_tmp(tmp); + tmp = load_cpu_field(VF); + tmp2 = load_cpu_field(NF); + tcg_gen_xor_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + default: + fprintf(stderr, "Bad condition code 0x%x\n", cc); + abort(); + } + dead_tmp(tmp); +} -const uint8_t table_logic_cc[16] = { +static const uint8_t table_logic_cc[16] = { 1, /* and */ 1, /* xor */ 0, /* sub */ @@ -170,182 +775,42 @@ 1, /* mvn */ }; -static GenOpFunc1 *gen_shift_T1_im[4] = { - gen_op_shll_T1_im, - gen_op_shrl_T1_im, - gen_op_sarl_T1_im, - gen_op_rorl_T1_im, -}; - -static GenOpFunc *gen_shift_T1_0[4] = { - NULL, - gen_op_shrl_T1_0, - gen_op_sarl_T1_0, - gen_op_rrxl_T1, -}; - -static GenOpFunc1 *gen_shift_T2_im[4] = { - gen_op_shll_T2_im, - gen_op_shrl_T2_im, - gen_op_sarl_T2_im, - gen_op_rorl_T2_im, -}; - -static GenOpFunc *gen_shift_T2_0[4] = { - NULL, - gen_op_shrl_T2_0, - gen_op_sarl_T2_0, - gen_op_rrxl_T2, -}; - -static GenOpFunc1 *gen_shift_T1_im_cc[4] = { - gen_op_shll_T1_im_cc, - gen_op_shrl_T1_im_cc, - gen_op_sarl_T1_im_cc, - gen_op_rorl_T1_im_cc, -}; - -static GenOpFunc *gen_shift_T1_0_cc[4] = { - NULL, - gen_op_shrl_T1_0_cc, - gen_op_sarl_T1_0_cc, - gen_op_rrxl_T1_cc, -}; - -static GenOpFunc *gen_shift_T1_T0[4] = { - gen_op_shll_T1_T0, - gen_op_shrl_T1_T0, - gen_op_sarl_T1_T0, - gen_op_rorl_T1_T0, -}; - -static GenOpFunc *gen_shift_T1_T0_cc[4] = { - gen_op_shll_T1_T0_cc, - gen_op_shrl_T1_T0_cc, - gen_op_sarl_T1_T0_cc, - gen_op_rorl_T1_T0_cc, -}; - -static GenOpFunc *gen_op_movl_TN_reg[3][16] = { - { - gen_op_movl_T0_r0, - gen_op_movl_T0_r1, - gen_op_movl_T0_r2, - gen_op_movl_T0_r3, - gen_op_movl_T0_r4, - gen_op_movl_T0_r5, - gen_op_movl_T0_r6, - gen_op_movl_T0_r7, - gen_op_movl_T0_r8, - gen_op_movl_T0_r9, - gen_op_movl_T0_r10, - gen_op_movl_T0_r11, - gen_op_movl_T0_r12, - gen_op_movl_T0_r13, - gen_op_movl_T0_r14, - gen_op_movl_T0_r15, - }, - { - gen_op_movl_T1_r0, - gen_op_movl_T1_r1, - gen_op_movl_T1_r2, - gen_op_movl_T1_r3, - gen_op_movl_T1_r4, - gen_op_movl_T1_r5, - gen_op_movl_T1_r6, - gen_op_movl_T1_r7, - gen_op_movl_T1_r8, - gen_op_movl_T1_r9, - gen_op_movl_T1_r10, - gen_op_movl_T1_r11, - gen_op_movl_T1_r12, - gen_op_movl_T1_r13, - gen_op_movl_T1_r14, - gen_op_movl_T1_r15, - }, - { - gen_op_movl_T2_r0, - gen_op_movl_T2_r1, - gen_op_movl_T2_r2, - gen_op_movl_T2_r3, - gen_op_movl_T2_r4, - gen_op_movl_T2_r5, - gen_op_movl_T2_r6, - gen_op_movl_T2_r7, - gen_op_movl_T2_r8, - gen_op_movl_T2_r9, - gen_op_movl_T2_r10, - gen_op_movl_T2_r11, - gen_op_movl_T2_r12, - gen_op_movl_T2_r13, - gen_op_movl_T2_r14, - gen_op_movl_T2_r15, - }, -}; - -static GenOpFunc *gen_op_movl_reg_TN[2][16] = { - { - gen_op_movl_r0_T0, - gen_op_movl_r1_T0, - gen_op_movl_r2_T0, - gen_op_movl_r3_T0, - gen_op_movl_r4_T0, - gen_op_movl_r5_T0, - gen_op_movl_r6_T0, - gen_op_movl_r7_T0, - gen_op_movl_r8_T0, - gen_op_movl_r9_T0, - gen_op_movl_r10_T0, - gen_op_movl_r11_T0, - gen_op_movl_r12_T0, - gen_op_movl_r13_T0, - gen_op_movl_r14_T0, - gen_op_movl_r15_T0, - }, - { - gen_op_movl_r0_T1, - gen_op_movl_r1_T1, - gen_op_movl_r2_T1, - gen_op_movl_r3_T1, - gen_op_movl_r4_T1, - gen_op_movl_r5_T1, - gen_op_movl_r6_T1, - gen_op_movl_r7_T1, - gen_op_movl_r8_T1, - gen_op_movl_r9_T1, - gen_op_movl_r10_T1, - gen_op_movl_r11_T1, - gen_op_movl_r12_T1, - gen_op_movl_r13_T1, - gen_op_movl_r14_T1, - gen_op_movl_r15_T1, - }, -}; - -static GenOpFunc1 *gen_op_movl_TN_im[3] = { - gen_op_movl_T0_im, - gen_op_movl_T1_im, - gen_op_movl_T2_im, -}; - -static GenOpFunc1 *gen_shift_T0_im_thumb_cc[3] = { - gen_op_shll_T0_im_thumb_cc, - gen_op_shrl_T0_im_thumb_cc, - gen_op_sarl_T0_im_thumb_cc, -}; +/* Set PC and Thumb state from an immediate address. */ +static inline void gen_bx_im(DisasContext *s, uint32_t addr) +{ + TCGv tmp; -static GenOpFunc1 *gen_shift_T0_im_thumb[3] = { - gen_op_shll_T0_im_thumb, - gen_op_shrl_T0_im_thumb, - gen_op_sarl_T0_im_thumb, -}; + s->is_jmp = DISAS_UPDATE; + tmp = new_tmp(); + if (s->thumb != (addr & 1)) { + tcg_gen_movi_i32(tmp, addr & 1); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, thumb)); + } + tcg_gen_movi_i32(tmp, addr & ~1); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, regs[15])); + dead_tmp(tmp); +} -static inline void gen_bx(DisasContext *s) +/* Set PC and Thumb state from var. var is marked as dead. */ +static inline void gen_bx(DisasContext *s, TCGv var) { - s->is_jmp = DISAS_UPDATE; - gen_op_bx_T0(); + TCGv tmp; + + s->is_jmp = DISAS_UPDATE; + tmp = new_tmp(); + tcg_gen_andi_i32(tmp, var, 1); + store_cpu_field(tmp, thumb); + tcg_gen_andi_i32(var, var, ~1); + store_cpu_field(var, regs[15]); } +/* TODO: This should be removed. Use gen_bx instead. */ +static inline void gen_bx_T0(DisasContext *s) +{ + TCGv tmp = new_tmp(); + tcg_gen_mov_i32(tmp, cpu_T[0]); + gen_bx(s, tmp); +} #if defined(CONFIG_USER_ONLY) #define gen_ldst(name, s) gen_op_##name##_raw() @@ -358,42 +823,86 @@ gen_op_##name##_kernel(); \ } while (0) #endif - -static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t) +static inline TCGv gen_ld8s(TCGv addr, int index) { - int val; - - if (reg == 15) { - /* normaly, since we updated PC, we need only to add one insn */ - if (s->thumb) - val = (long)s->pc + 2; - else - val = (long)s->pc + 4; - gen_op_movl_TN_im[t](val); - } else { - gen_op_movl_TN_reg[t][reg](); - } + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld8s(tmp, addr, index); + return tmp; +} +static inline TCGv gen_ld8u(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld8u(tmp, addr, index); + return tmp; +} +static inline TCGv gen_ld16s(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld16s(tmp, addr, index); + return tmp; +} +static inline TCGv gen_ld16u(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld16u(tmp, addr, index); + return tmp; +} +static inline TCGv gen_ld32(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld32u(tmp, addr, index); + return tmp; +} +static inline void gen_st8(TCGv val, TCGv addr, int index) +{ + tcg_gen_qemu_st8(val, addr, index); + dead_tmp(val); +} +static inline void gen_st16(TCGv val, TCGv addr, int index) +{ + tcg_gen_qemu_st16(val, addr, index); + dead_tmp(val); +} +static inline void gen_st32(TCGv val, TCGv addr, int index) +{ + tcg_gen_qemu_st32(val, addr, index); + dead_tmp(val); } static inline void gen_movl_T0_reg(DisasContext *s, int reg) { - gen_movl_TN_reg(s, reg, 0); + load_reg_var(s, cpu_T[0], reg); } static inline void gen_movl_T1_reg(DisasContext *s, int reg) { - gen_movl_TN_reg(s, reg, 1); + load_reg_var(s, cpu_T[1], reg); } static inline void gen_movl_T2_reg(DisasContext *s, int reg) { - gen_movl_TN_reg(s, reg, 2); + load_reg_var(s, cpu_T[2], reg); +} + +static inline void gen_set_pc_im(uint32_t val) +{ + TCGv tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + store_cpu_field(tmp, regs[15]); } static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t) { - gen_op_movl_reg_TN[t][reg](); + TCGv tmp; if (reg == 15) { + tmp = new_tmp(); + tcg_gen_andi_i32(tmp, cpu_T[t], ~1); + } else { + tmp = cpu_T[t]; + } + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, regs[reg])); + if (reg == 15) { + dead_tmp(tmp); s->is_jmp = DISAS_JUMP; } } @@ -416,9 +925,11 @@ s->is_jmp = DISAS_UPDATE; } -static inline void gen_add_data_offset(DisasContext *s, unsigned int insn) +static inline void gen_add_data_offset(DisasContext *s, unsigned int insn, + TCGv var) { int val, rm, shift, shiftop; + TCGv offset; if (!(insn & (1 << 25))) { /* immediate */ @@ -426,29 +937,27 @@ if (!(insn & (1 << 23))) val = -val; if (val != 0) - gen_op_addl_T1_im(val); + tcg_gen_addi_i32(var, var, val); } else { /* shift/register */ rm = (insn) & 0xf; shift = (insn >> 7) & 0x1f; - gen_movl_T2_reg(s, rm); shiftop = (insn >> 5) & 3; - if (shift != 0) { - gen_shift_T2_im[shiftop](shift); - } else if (shiftop != 0) { - gen_shift_T2_0[shiftop](); - } + offset = load_reg(s, rm); + gen_arm_shift_im(offset, shiftop, shift, 0); if (!(insn & (1 << 23))) - gen_op_subl_T1_T2(); + tcg_gen_sub_i32(var, var, offset); else - gen_op_addl_T1_T2(); + tcg_gen_add_i32(var, var, offset); + dead_tmp(offset); } } static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn, - int extra) + int extra, TCGv var) { int val, rm; + TCGv offset; if (insn & (1 << 22)) { /* immediate */ @@ -457,27 +966,28 @@ val = -val; val += extra; if (val != 0) - gen_op_addl_T1_im(val); + tcg_gen_addi_i32(var, var, val); } else { /* register */ if (extra) - gen_op_addl_T1_im(extra); + tcg_gen_addi_i32(var, var, extra); rm = (insn) & 0xf; - gen_movl_T2_reg(s, rm); + offset = load_reg(s, rm); if (!(insn & (1 << 23))) - gen_op_subl_T1_T2(); + tcg_gen_sub_i32(var, var, offset); else - gen_op_addl_T1_T2(); + tcg_gen_add_i32(var, var, offset); + dead_tmp(offset); } } -#define VFP_OP(name) \ -static inline void gen_vfp_##name(int dp) \ -{ \ - if (dp) \ - gen_op_vfp_##name##d(); \ - else \ - gen_op_vfp_##name##s(); \ +#define VFP_OP2(name) \ +static inline void gen_vfp_##name(int dp) \ +{ \ + if (dp) \ + gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, cpu_F1d, cpu_env); \ + else \ + gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, cpu_F1s, cpu_env); \ } #define VFP_OP1(name) \ @@ -489,109 +999,457 @@ gen_op_vfp_##name##s(arg); \ } -VFP_OP(add) -VFP_OP(sub) -VFP_OP(mul) -VFP_OP(div) -VFP_OP(neg) -VFP_OP(abs) -VFP_OP(sqrt) -VFP_OP(cmp) -VFP_OP(cmpe) -VFP_OP(F1_ld0) -VFP_OP(uito) -VFP_OP(sito) -VFP_OP(toui) -VFP_OP(touiz) -VFP_OP(tosi) -VFP_OP(tosiz) -VFP_OP1(tosh) -VFP_OP1(tosl) -VFP_OP1(touh) -VFP_OP1(toul) -VFP_OP1(shto) -VFP_OP1(slto) -VFP_OP1(uhto) -VFP_OP1(ulto) +VFP_OP2(add) +VFP_OP2(sub) +VFP_OP2(mul) +VFP_OP2(div) + +#undef VFP_OP2 -#undef VFP_OP +static inline void gen_vfp_abs(int dp) +{ + if (dp) + gen_helper_vfp_absd(cpu_F0d, cpu_F0d); + else + gen_helper_vfp_abss(cpu_F0s, cpu_F0s); +} + +static inline void gen_vfp_neg(int dp) +{ + if (dp) + gen_helper_vfp_negd(cpu_F0d, cpu_F0d); + else + gen_helper_vfp_negs(cpu_F0s, cpu_F0s); +} + +static inline void gen_vfp_sqrt(int dp) +{ + if (dp) + gen_helper_vfp_sqrtd(cpu_F0d, cpu_F0d, cpu_env); + else + gen_helper_vfp_sqrts(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_cmp(int dp) +{ + if (dp) + gen_helper_vfp_cmpd(cpu_F0d, cpu_F1d, cpu_env); + else + gen_helper_vfp_cmps(cpu_F0s, cpu_F1s, cpu_env); +} + +static inline void gen_vfp_cmpe(int dp) +{ + if (dp) + gen_helper_vfp_cmped(cpu_F0d, cpu_F1d, cpu_env); + else + gen_helper_vfp_cmpes(cpu_F0s, cpu_F1s, cpu_env); +} + +static inline void gen_vfp_F1_ld0(int dp) +{ + if (dp) + tcg_gen_movi_i64(cpu_F1d, 0); + else + tcg_gen_movi_i32(cpu_F1s, 0); +} + +static inline void gen_vfp_uito(int dp) +{ + if (dp) + gen_helper_vfp_uitod(cpu_F0d, cpu_F0s, cpu_env); + else + gen_helper_vfp_uitos(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_sito(int dp) +{ + if (dp) + gen_helper_vfp_sitod(cpu_F0d, cpu_F0s, cpu_env); + else + gen_helper_vfp_sitos(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_toui(int dp) +{ + if (dp) + gen_helper_vfp_touid(cpu_F0s, cpu_F0d, cpu_env); + else + gen_helper_vfp_touis(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_touiz(int dp) +{ + if (dp) + gen_helper_vfp_touizd(cpu_F0s, cpu_F0d, cpu_env); + else + gen_helper_vfp_touizs(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_tosi(int dp) +{ + if (dp) + gen_helper_vfp_tosid(cpu_F0s, cpu_F0d, cpu_env); + else + gen_helper_vfp_tosis(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_tosiz(int dp) +{ + if (dp) + gen_helper_vfp_tosizd(cpu_F0s, cpu_F0d, cpu_env); + else + gen_helper_vfp_tosizs(cpu_F0s, cpu_F0s, cpu_env); +} + +#define VFP_GEN_FIX(name) \ +static inline void gen_vfp_##name(int dp, int shift) \ +{ \ + if (dp) \ + gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, tcg_const_i32(shift), cpu_env);\ + else \ + gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, tcg_const_i32(shift), cpu_env);\ +} +VFP_GEN_FIX(tosh) +VFP_GEN_FIX(tosl) +VFP_GEN_FIX(touh) +VFP_GEN_FIX(toul) +VFP_GEN_FIX(shto) +VFP_GEN_FIX(slto) +VFP_GEN_FIX(uhto) +VFP_GEN_FIX(ulto) +#undef VFP_GEN_FIX + +static inline void gen_vfp_ld(DisasContext *s, int dp) +{ + if (dp) + tcg_gen_qemu_ld64(cpu_F0d, cpu_T[1], IS_USER(s)); + else + tcg_gen_qemu_ld32u(cpu_F0s, cpu_T[1], IS_USER(s)); +} + +static inline void gen_vfp_st(DisasContext *s, int dp) +{ + if (dp) + tcg_gen_qemu_st64(cpu_F0d, cpu_T[1], IS_USER(s)); + else + tcg_gen_qemu_st32(cpu_F0s, cpu_T[1], IS_USER(s)); +} + +static inline long +vfp_reg_offset (int dp, int reg) +{ + if (dp) + return offsetof(CPUARMState, vfp.regs[reg]); + else if (reg & 1) { + return offsetof(CPUARMState, vfp.regs[reg >> 1]) + + offsetof(CPU_DoubleU, l.upper); + } else { + return offsetof(CPUARMState, vfp.regs[reg >> 1]) + + offsetof(CPU_DoubleU, l.lower); + } +} + +/* Return the offset of a 32-bit piece of a NEON register. + zero is the least significant end of the register. */ +static inline long +neon_reg_offset (int reg, int n) +{ + int sreg; + sreg = reg * 2 + n; + return vfp_reg_offset(0, sreg); +} + +/* FIXME: Remove these. */ +#define neon_T0 cpu_T[0] +#define neon_T1 cpu_T[1] +#define NEON_GET_REG(T, reg, n) \ + tcg_gen_ld_i32(neon_##T, cpu_env, neon_reg_offset(reg, n)) +#define NEON_SET_REG(T, reg, n) \ + tcg_gen_st_i32(neon_##T, cpu_env, neon_reg_offset(reg, n)) + +static TCGv neon_load_reg(int reg, int pass) +{ + TCGv tmp = new_tmp(); + tcg_gen_ld_i32(tmp, cpu_env, neon_reg_offset(reg, pass)); + return tmp; +} + +static void neon_store_reg(int reg, int pass, TCGv var) +{ + tcg_gen_st_i32(var, cpu_env, neon_reg_offset(reg, pass)); + dead_tmp(var); +} + +static inline void neon_load_reg64(TCGv var, int reg) +{ + tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg)); +} + +static inline void neon_store_reg64(TCGv var, int reg) +{ + tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(1, reg)); +} + +#define tcg_gen_ld_f32 tcg_gen_ld_i32 +#define tcg_gen_ld_f64 tcg_gen_ld_i64 +#define tcg_gen_st_f32 tcg_gen_st_i32 +#define tcg_gen_st_f64 tcg_gen_st_i64 + +static inline void gen_mov_F0_vreg(int dp, int reg) +{ + if (dp) + tcg_gen_ld_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg)); + else + tcg_gen_ld_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg)); +} + +static inline void gen_mov_F1_vreg(int dp, int reg) +{ + if (dp) + tcg_gen_ld_f64(cpu_F1d, cpu_env, vfp_reg_offset(dp, reg)); + else + tcg_gen_ld_f32(cpu_F1s, cpu_env, vfp_reg_offset(dp, reg)); +} + +static inline void gen_mov_vreg_F0(int dp, int reg) +{ + if (dp) + tcg_gen_st_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg)); + else + tcg_gen_st_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg)); +} + +#define ARM_CP_RW_BIT (1 << 20) + +static inline void iwmmxt_load_reg(TCGv var, int reg) +{ + tcg_gen_ld_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg])); +} + +static inline void iwmmxt_store_reg(TCGv var, int reg) +{ + tcg_gen_st_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg])); +} + +static inline void gen_op_iwmmxt_movl_wCx_T0(int reg) +{ + tcg_gen_st_i32(cpu_T[0], cpu_env, offsetof(CPUState, iwmmxt.cregs[reg])); +} + +static inline void gen_op_iwmmxt_movl_T0_wCx(int reg) +{ + tcg_gen_ld_i32(cpu_T[0], cpu_env, offsetof(CPUState, iwmmxt.cregs[reg])); +} + +static inline void gen_op_iwmmxt_movl_T1_wCx(int reg) +{ + tcg_gen_ld_i32(cpu_T[1], cpu_env, offsetof(CPUState, iwmmxt.cregs[reg])); +} + +static inline void gen_op_iwmmxt_movq_wRn_M0(int rn) +{ + iwmmxt_store_reg(cpu_M0, rn); +} + +static inline void gen_op_iwmmxt_movq_M0_wRn(int rn) +{ + iwmmxt_load_reg(cpu_M0, rn); +} + +static inline void gen_op_iwmmxt_orq_M0_wRn(int rn) +{ + iwmmxt_load_reg(cpu_V1, rn); + tcg_gen_or_i64(cpu_M0, cpu_M0, cpu_V1); +} + +static inline void gen_op_iwmmxt_andq_M0_wRn(int rn) +{ + iwmmxt_load_reg(cpu_V1, rn); + tcg_gen_and_i64(cpu_M0, cpu_M0, cpu_V1); +} + +static inline void gen_op_iwmmxt_xorq_M0_wRn(int rn) +{ + iwmmxt_load_reg(cpu_V1, rn); + tcg_gen_xor_i64(cpu_M0, cpu_M0, cpu_V1); +} + +#define IWMMXT_OP(name) \ +static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \ +{ \ + iwmmxt_load_reg(cpu_V1, rn); \ + gen_helper_iwmmxt_##name(cpu_M0, cpu_M0, cpu_V1); \ +} + +#define IWMMXT_OP_ENV(name) \ +static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \ +{ \ + iwmmxt_load_reg(cpu_V1, rn); \ + gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0, cpu_V1); \ +} + +#define IWMMXT_OP_ENV_SIZE(name) \ +IWMMXT_OP_ENV(name##b) \ +IWMMXT_OP_ENV(name##w) \ +IWMMXT_OP_ENV(name##l) + +#define IWMMXT_OP_ENV1(name) \ +static inline void gen_op_iwmmxt_##name##_M0(void) \ +{ \ + gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0); \ +} + +IWMMXT_OP(maddsq) +IWMMXT_OP(madduq) +IWMMXT_OP(sadb) +IWMMXT_OP(sadw) +IWMMXT_OP(mulslw) +IWMMXT_OP(mulshw) +IWMMXT_OP(mululw) +IWMMXT_OP(muluhw) +IWMMXT_OP(macsw) +IWMMXT_OP(macuw) + +IWMMXT_OP_ENV_SIZE(unpackl) +IWMMXT_OP_ENV_SIZE(unpackh) + +IWMMXT_OP_ENV1(unpacklub) +IWMMXT_OP_ENV1(unpackluw) +IWMMXT_OP_ENV1(unpacklul) +IWMMXT_OP_ENV1(unpackhub) +IWMMXT_OP_ENV1(unpackhuw) +IWMMXT_OP_ENV1(unpackhul) +IWMMXT_OP_ENV1(unpacklsb) +IWMMXT_OP_ENV1(unpacklsw) +IWMMXT_OP_ENV1(unpacklsl) +IWMMXT_OP_ENV1(unpackhsb) +IWMMXT_OP_ENV1(unpackhsw) +IWMMXT_OP_ENV1(unpackhsl) + +IWMMXT_OP_ENV_SIZE(cmpeq) +IWMMXT_OP_ENV_SIZE(cmpgtu) +IWMMXT_OP_ENV_SIZE(cmpgts) + +IWMMXT_OP_ENV_SIZE(mins) +IWMMXT_OP_ENV_SIZE(minu) +IWMMXT_OP_ENV_SIZE(maxs) +IWMMXT_OP_ENV_SIZE(maxu) + +IWMMXT_OP_ENV_SIZE(subn) +IWMMXT_OP_ENV_SIZE(addn) +IWMMXT_OP_ENV_SIZE(subu) +IWMMXT_OP_ENV_SIZE(addu) +IWMMXT_OP_ENV_SIZE(subs) +IWMMXT_OP_ENV_SIZE(adds) + +IWMMXT_OP_ENV(avgb0) +IWMMXT_OP_ENV(avgb1) +IWMMXT_OP_ENV(avgw0) +IWMMXT_OP_ENV(avgw1) + +IWMMXT_OP(msadb) + +IWMMXT_OP_ENV(packuw) +IWMMXT_OP_ENV(packul) +IWMMXT_OP_ENV(packuq) +IWMMXT_OP_ENV(packsw) +IWMMXT_OP_ENV(packsl) +IWMMXT_OP_ENV(packsq) + +static inline void gen_op_iwmmxt_muladdsl_M0_T0_T1(void) +{ + gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, cpu_T[0], cpu_T[1]); +} + +static inline void gen_op_iwmmxt_muladdsw_M0_T0_T1(void) +{ + gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, cpu_T[0], cpu_T[1]); +} + +static inline void gen_op_iwmmxt_muladdswl_M0_T0_T1(void) +{ + gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, cpu_T[0], cpu_T[1]); +} + +static inline void gen_op_iwmmxt_align_M0_T0_wRn(int rn) +{ + iwmmxt_load_reg(cpu_V1, rn); + gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, cpu_T[0]); +} -static inline void gen_vfp_fconst(int dp, uint32_t val) +static inline void gen_op_iwmmxt_insr_M0_T0_T1(int shift) { - if (dp) - gen_op_vfp_fconstd(val); - else - gen_op_vfp_fconsts(val); + TCGv tmp = tcg_const_i32(shift); + gen_helper_iwmmxt_insr(cpu_M0, cpu_M0, cpu_T[0], cpu_T[1], tmp); } -static inline void gen_vfp_ld(DisasContext *s, int dp) +static inline void gen_op_iwmmxt_extrsb_T0_M0(int shift) { - if (dp) - gen_ldst(vfp_ldd, s); - else - gen_ldst(vfp_lds, s); + tcg_gen_shri_i64(cpu_M0, cpu_M0, shift); + tcg_gen_trunc_i64_i32(cpu_T[0], cpu_M0); + tcg_gen_ext8s_i32(cpu_T[0], cpu_T[0]); } -static inline void gen_vfp_st(DisasContext *s, int dp) +static inline void gen_op_iwmmxt_extrsw_T0_M0(int shift) { - if (dp) - gen_ldst(vfp_std, s); - else - gen_ldst(vfp_sts, s); + tcg_gen_shri_i64(cpu_M0, cpu_M0, shift); + tcg_gen_trunc_i64_i32(cpu_T[0], cpu_M0); + tcg_gen_ext16s_i32(cpu_T[0], cpu_T[0]); } -static inline long -vfp_reg_offset (int dp, int reg) +static inline void gen_op_iwmmxt_extru_T0_M0(int shift, uint32_t mask) { - if (dp) - return offsetof(CPUARMState, vfp.regs[reg]); - else if (reg & 1) { - return offsetof(CPUARMState, vfp.regs[reg >> 1]) - + offsetof(CPU_DoubleU, l.upper); - } else { - return offsetof(CPUARMState, vfp.regs[reg >> 1]) - + offsetof(CPU_DoubleU, l.lower); - } + tcg_gen_shri_i64(cpu_M0, cpu_M0, shift); + tcg_gen_trunc_i64_i32(cpu_T[0], cpu_M0); + if (mask != ~0u) + tcg_gen_andi_i32(cpu_T[0], cpu_T[0], mask); } -/* Return the offset of a 32-bit piece of a NEON register. - zero is the least significant end of the register. */ -static inline long -neon_reg_offset (int reg, int n) +static void gen_op_iwmmxt_set_mup(void) { - int sreg; - sreg = reg * 2 + n; - return vfp_reg_offset(0, sreg); + TCGv tmp; + tmp = load_cpu_field(iwmmxt.cregs[ARM_IWMMXT_wCon]); + tcg_gen_ori_i32(tmp, tmp, 2); + store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCon]); } -#define NEON_GET_REG(T, reg, n) gen_op_neon_getreg_##T(neon_reg_offset(reg, n)) -#define NEON_SET_REG(T, reg, n) gen_op_neon_setreg_##T(neon_reg_offset(reg, n)) +static void gen_op_iwmmxt_set_cup(void) +{ + TCGv tmp; + tmp = load_cpu_field(iwmmxt.cregs[ARM_IWMMXT_wCon]); + tcg_gen_ori_i32(tmp, tmp, 1); + store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCon]); +} -static inline void gen_mov_F0_vreg(int dp, int reg) +static void gen_op_iwmmxt_setpsr_nz(void) { - if (dp) - gen_op_vfp_getreg_F0d(vfp_reg_offset(dp, reg)); - else - gen_op_vfp_getreg_F0s(vfp_reg_offset(dp, reg)); + TCGv tmp = new_tmp(); + gen_helper_iwmmxt_setpsr_nz(tmp, cpu_M0); + store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCASF]); } -static inline void gen_mov_F1_vreg(int dp, int reg) +static inline void gen_op_iwmmxt_addl_M0_wRn(int rn) { - if (dp) - gen_op_vfp_getreg_F1d(vfp_reg_offset(dp, reg)); - else - gen_op_vfp_getreg_F1s(vfp_reg_offset(dp, reg)); + iwmmxt_load_reg(cpu_V1, rn); + tcg_gen_ext32u_i64(cpu_V1, cpu_V1); + tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1); } -static inline void gen_mov_vreg_F0(int dp, int reg) + +static void gen_iwmmxt_movl_T0_T1_wRn(int rn) { - if (dp) - gen_op_vfp_setreg_F0d(vfp_reg_offset(dp, reg)); - else - gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg)); + iwmmxt_load_reg(cpu_V0, rn); + tcg_gen_trunc_i64_i32(cpu_T[0], cpu_V0); + tcg_gen_shri_i64(cpu_V0, cpu_V0, 32); + tcg_gen_trunc_i64_i32(cpu_T[1], cpu_V0); } -#define ARM_CP_RW_BIT (1 << 20) +static void gen_iwmmxt_movl_wRn_T0_T1(int rn) +{ + tcg_gen_concat_i32_i64(cpu_V0, cpu_T[0], cpu_T[1]); + iwmmxt_store_reg(cpu_V0, rn); +} static inline int gen_iwmmxt_address(DisasContext *s, uint32_t insn) { @@ -634,7 +1492,7 @@ else gen_op_iwmmxt_movl_T0_wCx(rd); else - gen_op_iwmmxt_movl_T0_T1_wRn(rd); + gen_iwmmxt_movl_T0_T1_wRn(rd); gen_op_movl_T1_im(mask); gen_op_andl_T0_T1(); @@ -647,6 +1505,7 @@ { int rd, wrd; int rdhi, rdlo, rd0, rd1, i; + TCGv tmp; if ((insn & 0x0e000e00) == 0x0c000000) { if ((insn & 0x0fe00ff0) == 0x0c400000) { @@ -654,13 +1513,13 @@ rdlo = (insn >> 12) & 0xf; rdhi = (insn >> 16) & 0xf; if (insn & ARM_CP_RW_BIT) { /* TMRRC */ - gen_op_iwmmxt_movl_T0_T1_wRn(wrd); + gen_iwmmxt_movl_T0_T1_wRn(wrd); gen_movl_reg_T0(s, rdlo); gen_movl_reg_T1(s, rdhi); } else { /* TMCRR */ gen_movl_T0_reg(s, rdlo); gen_movl_T1_reg(s, rdhi); - gen_op_iwmmxt_movl_wRn_T0_T1(wrd); + gen_iwmmxt_movl_wRn_T0_T1(wrd); gen_op_iwmmxt_set_mup(); } return 0; @@ -671,37 +1530,58 @@ return 1; if (insn & ARM_CP_RW_BIT) { if ((insn >> 28) == 0xf) { /* WLDRW wCx */ - gen_ldst(ldl, s); + tmp = gen_ld32(cpu_T[1], IS_USER(s)); + tcg_gen_mov_i32(cpu_T[0], tmp); + dead_tmp(tmp); gen_op_iwmmxt_movl_wCx_T0(wrd); } else { - if (insn & (1 << 8)) - if (insn & (1 << 22)) /* WLDRD */ - gen_ldst(iwmmxt_ldq, s); - else /* WLDRW wRd */ - gen_ldst(iwmmxt_ldl, s); - else - if (insn & (1 << 22)) /* WLDRH */ - gen_ldst(iwmmxt_ldw, s); - else /* WLDRB */ - gen_ldst(iwmmxt_ldb, s); + i = 1; + if (insn & (1 << 8)) { + if (insn & (1 << 22)) { /* WLDRD */ + tcg_gen_qemu_ld64(cpu_M0, cpu_T[1], IS_USER(s)); + i = 0; + } else { /* WLDRW wRd */ + tmp = gen_ld32(cpu_T[1], IS_USER(s)); + } + } else { + if (insn & (1 << 22)) { /* WLDRH */ + tmp = gen_ld16u(cpu_T[1], IS_USER(s)); + } else { /* WLDRB */ + tmp = gen_ld8u(cpu_T[1], IS_USER(s)); + } + } + if (i) { + tcg_gen_extu_i32_i64(cpu_M0, tmp); + dead_tmp(tmp); + } gen_op_iwmmxt_movq_wRn_M0(wrd); } } else { if ((insn >> 28) == 0xf) { /* WSTRW wCx */ gen_op_iwmmxt_movl_T0_wCx(wrd); - gen_ldst(stl, s); + tmp = new_tmp(); + tcg_gen_mov_i32(tmp, cpu_T[0]); + gen_st32(tmp, cpu_T[1], IS_USER(s)); } else { gen_op_iwmmxt_movq_M0_wRn(wrd); - if (insn & (1 << 8)) - if (insn & (1 << 22)) /* WSTRD */ - gen_ldst(iwmmxt_stq, s); - else /* WSTRW wRd */ - gen_ldst(iwmmxt_stl, s); - else - if (insn & (1 << 22)) /* WSTRH */ - gen_ldst(iwmmxt_ldw, s); - else /* WSTRB */ - gen_ldst(iwmmxt_stb, s); + tmp = new_tmp(); + if (insn & (1 << 8)) { + if (insn & (1 << 22)) { /* WSTRD */ + dead_tmp(tmp); + tcg_gen_qemu_st64(cpu_M0, cpu_T[1], IS_USER(s)); + } else { /* WSTRW wRd */ + tcg_gen_trunc_i64_i32(tmp, cpu_M0); + gen_st32(tmp, cpu_T[1], IS_USER(s)); + } + } else { + if (insn & (1 << 22)) { /* WSTRH */ + tcg_gen_trunc_i64_i32(tmp, cpu_M0); + gen_st16(tmp, cpu_T[1], IS_USER(s)); + } else { /* WSTRB */ + tcg_gen_trunc_i64_i32(tmp, cpu_M0); + gen_st8(tmp, cpu_T[1], IS_USER(s)); + } + } } } return 0; @@ -776,7 +1656,7 @@ rd0 = (insn >> 0) & 0xf; rd1 = (insn >> 16) & 0xf; gen_op_iwmmxt_movq_M0_wRn(rd0); - gen_op_iwmmxt_negq_M0(); + tcg_gen_neg_i64(cpu_M0, cpu_M0); gen_op_iwmmxt_andq_M0_wRn(rd1); gen_op_iwmmxt_setpsr_nz(); gen_op_iwmmxt_movq_wRn_M0(wrd); @@ -869,10 +1749,17 @@ rd0 = (insn >> 16) & 0xf; rd1 = (insn >> 0) & 0xf; gen_op_iwmmxt_movq_M0_wRn(rd0); - if (insn & (1 << 21)) - gen_op_iwmmxt_mulsw_M0_wRn(rd1, (insn & (1 << 20)) ? 16 : 0); - else - gen_op_iwmmxt_muluw_M0_wRn(rd1, (insn & (1 << 20)) ? 16 : 0); + if (insn & (1 << 21)) { + if (insn & (1 << 20)) + gen_op_iwmmxt_mulshw_M0_wRn(rd1); + else + gen_op_iwmmxt_mulslw_M0_wRn(rd1); + } else { + if (insn & (1 << 20)) + gen_op_iwmmxt_muluhw_M0_wRn(rd1); + else + gen_op_iwmmxt_mululw_M0_wRn(rd1); + } gen_op_iwmmxt_movq_wRn_M0(wrd); gen_op_iwmmxt_set_mup(); break; @@ -886,10 +1773,8 @@ else gen_op_iwmmxt_macuw_M0_wRn(rd1); if (!(insn & (1 << 20))) { - if (insn & (1 << 21)) - gen_op_iwmmxt_addsq_M0_wRn(wrd); - else - gen_op_iwmmxt_adduq_M0_wRn(wrd); + iwmmxt_load_reg(cpu_V1, wrd); + tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1); } gen_op_iwmmxt_movq_wRn_M0(wrd); gen_op_iwmmxt_set_mup(); @@ -921,10 +1806,17 @@ rd0 = (insn >> 16) & 0xf; rd1 = (insn >> 0) & 0xf; gen_op_iwmmxt_movq_M0_wRn(rd0); - if (insn & (1 << 22)) - gen_op_iwmmxt_avgw_M0_wRn(rd1, (insn >> 20) & 1); - else - gen_op_iwmmxt_avgb_M0_wRn(rd1, (insn >> 20) & 1); + if (insn & (1 << 22)) { + if (insn & (1 << 20)) + gen_op_iwmmxt_avgw1_M0_wRn(rd1); + else + gen_op_iwmmxt_avgw0_M0_wRn(rd1); + } else { + if (insn & (1 << 20)) + gen_op_iwmmxt_avgb1_M0_wRn(rd1); + else + gen_op_iwmmxt_avgb0_M0_wRn(rd1); + } gen_op_iwmmxt_movq_wRn_M0(wrd); gen_op_iwmmxt_set_mup(); gen_op_iwmmxt_set_cup(); @@ -976,26 +1868,23 @@ if (insn & 8) gen_op_iwmmxt_extrsb_T0_M0((insn & 7) << 3); else { - gen_op_movl_T1_im(0xff); - gen_op_iwmmxt_extru_T0_M0_T1((insn & 7) << 3); + gen_op_iwmmxt_extru_T0_M0((insn & 7) << 3, 0xff); } break; case 1: if (insn & 8) gen_op_iwmmxt_extrsw_T0_M0((insn & 3) << 4); else { - gen_op_movl_T1_im(0xffff); - gen_op_iwmmxt_extru_T0_M0_T1((insn & 3) << 4); + gen_op_iwmmxt_extru_T0_M0((insn & 3) << 4, 0xffff); } break; case 2: - gen_op_movl_T1_im(0xffffffff); - gen_op_iwmmxt_extru_T0_M0_T1((insn & 1) << 5); + gen_op_iwmmxt_extru_T0_M0((insn & 1) << 5, ~0u); break; case 3: return 1; } - gen_op_movl_reg_TN[0][rd](); + gen_movl_reg_T0(s, rd); break; case 0x117: case 0x517: case 0x917: case 0xd17: /* TEXTRC */ if ((insn & 0x000ff008) != 0x0003f000) @@ -1015,8 +1904,7 @@ return 1; } gen_op_shll_T1_im(28); - gen_op_movl_T0_T1(); - gen_op_movl_cpsr_T0(0xf0000000); + gen_set_nzcv(cpu_T[1]); break; case 0x401: case 0x405: case 0x409: case 0x40d: /* TBCST */ rd = (insn >> 12) & 0xf; @@ -1024,13 +1912,13 @@ gen_movl_T0_reg(s, rd); switch ((insn >> 6) & 3) { case 0: - gen_op_iwmmxt_bcstb_M0_T0(); + gen_helper_iwmmxt_bcstb(cpu_M0, cpu_T[0]); break; case 1: - gen_op_iwmmxt_bcstw_M0_T0(); + gen_helper_iwmmxt_bcstw(cpu_M0, cpu_T[0]); break; case 2: - gen_op_iwmmxt_bcstl_M0_T0(); + gen_helper_iwmmxt_bcstl(cpu_M0, cpu_T[0]); break; case 3: return 1; @@ -1062,7 +1950,7 @@ case 3: return 1; } - gen_op_movl_cpsr_T0(0xf0000000); + gen_set_nzcv(cpu_T[0]); break; case 0x01c: case 0x41c: case 0x81c: case 0xc1c: /* WACC */ wrd = (insn >> 12) & 0xf; @@ -1070,13 +1958,13 @@ gen_op_iwmmxt_movq_M0_wRn(rd0); switch ((insn >> 22) & 3) { case 0: - gen_op_iwmmxt_addcb_M0(); + gen_helper_iwmmxt_addcb(cpu_M0, cpu_M0); break; case 1: - gen_op_iwmmxt_addcw_M0(); + gen_helper_iwmmxt_addcw(cpu_M0, cpu_M0); break; case 2: - gen_op_iwmmxt_addcl_M0(); + gen_helper_iwmmxt_addcl(cpu_M0, cpu_M0); break; case 3: return 1; @@ -1108,9 +1996,7 @@ case 3: return 1; } - gen_op_movl_T1_im(0xf0000000); - gen_op_andl_T0_T1(); - gen_op_movl_cpsr_T0(0xf0000000); + gen_set_nzcv(cpu_T[0]); break; case 0x103: case 0x503: case 0x903: case 0xd03: /* TMOVMSK */ rd = (insn >> 12) & 0xf; @@ -1120,13 +2006,13 @@ gen_op_iwmmxt_movq_M0_wRn(rd0); switch ((insn >> 22) & 3) { case 0: - gen_op_iwmmxt_msbb_T0_M0(); + gen_helper_iwmmxt_msbb(cpu_T[0], cpu_M0); break; case 1: - gen_op_iwmmxt_msbw_T0_M0(); + gen_helper_iwmmxt_msbw(cpu_T[0], cpu_M0); break; case 2: - gen_op_iwmmxt_msbl_T0_M0(); + gen_helper_iwmmxt_msbl(cpu_T[0], cpu_M0); break; case 3: return 1; @@ -1238,13 +2124,13 @@ case 0: return 1; case 1: - gen_op_iwmmxt_srlw_M0_T0(); + gen_helper_iwmmxt_srlw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]); break; case 2: - gen_op_iwmmxt_srll_M0_T0(); + gen_helper_iwmmxt_srll(cpu_M0, cpu_env, cpu_M0, cpu_T[0]); break; case 3: - gen_op_iwmmxt_srlq_M0_T0(); + gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, cpu_T[0]); break; } gen_op_iwmmxt_movq_wRn_M0(wrd); @@ -1262,13 +2148,13 @@ case 0: return 1; case 1: - gen_op_iwmmxt_sraw_M0_T0(); + gen_helper_iwmmxt_sraw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]); break; case 2: - gen_op_iwmmxt_sral_M0_T0(); + gen_helper_iwmmxt_sral(cpu_M0, cpu_env, cpu_M0, cpu_T[0]); break; case 3: - gen_op_iwmmxt_sraq_M0_T0(); + gen_helper_iwmmxt_sraq(cpu_M0, cpu_env, cpu_M0, cpu_T[0]); break; } gen_op_iwmmxt_movq_wRn_M0(wrd); @@ -1286,13 +2172,13 @@ case 0: return 1; case 1: - gen_op_iwmmxt_sllw_M0_T0(); + gen_helper_iwmmxt_sllw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]); break; case 2: - gen_op_iwmmxt_slll_M0_T0(); + gen_helper_iwmmxt_slll(cpu_M0, cpu_env, cpu_M0, cpu_T[0]); break; case 3: - gen_op_iwmmxt_sllq_M0_T0(); + gen_helper_iwmmxt_sllq(cpu_M0, cpu_env, cpu_M0, cpu_T[0]); break; } gen_op_iwmmxt_movq_wRn_M0(wrd); @@ -1310,17 +2196,17 @@ case 1: if (gen_iwmmxt_shift(insn, 0xf)) return 1; - gen_op_iwmmxt_rorw_M0_T0(); + gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]); break; case 2: if (gen_iwmmxt_shift(insn, 0x1f)) return 1; - gen_op_iwmmxt_rorl_M0_T0(); + gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, cpu_T[0]); break; case 3: if (gen_iwmmxt_shift(insn, 0x3f)) return 1; - gen_op_iwmmxt_rorq_M0_T0(); + gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, cpu_T[0]); break; } gen_op_iwmmxt_movq_wRn_M0(wrd); @@ -1451,7 +2337,7 @@ rd0 = (insn >> 16) & 0xf; gen_op_iwmmxt_movq_M0_wRn(rd0); gen_op_movl_T0_im(((insn >> 16) & 0xf0) | (insn & 0x0f)); - gen_op_iwmmxt_shufh_M0_T0(); + gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, cpu_T[0]); gen_op_iwmmxt_movq_wRn_M0(wrd); gen_op_iwmmxt_set_mup(); gen_op_iwmmxt_set_cup(); @@ -1547,21 +2433,21 @@ gen_op_iwmmxt_movq_M0_wRn(wrd); switch ((insn >> 16) & 0xf) { case 0x0: /* TMIA */ - gen_op_movl_TN_reg[0][rd0](); - gen_op_movl_TN_reg[1][rd1](); + gen_movl_T0_reg(s, rd0); + gen_movl_T1_reg(s, rd1); gen_op_iwmmxt_muladdsl_M0_T0_T1(); break; case 0x8: /* TMIAPH */ - gen_op_movl_TN_reg[0][rd0](); - gen_op_movl_TN_reg[1][rd1](); + gen_movl_T0_reg(s, rd0); + gen_movl_T1_reg(s, rd1); gen_op_iwmmxt_muladdsw_M0_T0_T1(); break; case 0xc: case 0xd: case 0xe: case 0xf: /* TMIAxy */ - gen_op_movl_TN_reg[1][rd0](); + gen_movl_T1_reg(s, rd0); if (insn & (1 << 16)) gen_op_shrl_T1_im(16); gen_op_movl_T0_T1(); - gen_op_movl_TN_reg[1][rd1](); + gen_movl_T1_reg(s, rd1); if (insn & (1 << 17)) gen_op_shrl_T1_im(16); gen_op_iwmmxt_muladdswl_M0_T0_T1(); @@ -1596,24 +2482,24 @@ switch ((insn >> 16) & 0xf) { case 0x0: /* MIA */ - gen_op_movl_TN_reg[0][rd0](); - gen_op_movl_TN_reg[1][rd1](); + gen_movl_T0_reg(s, rd0); + gen_movl_T1_reg(s, rd1); gen_op_iwmmxt_muladdsl_M0_T0_T1(); break; case 0x8: /* MIAPH */ - gen_op_movl_TN_reg[0][rd0](); - gen_op_movl_TN_reg[1][rd1](); + gen_movl_T0_reg(s, rd0); + gen_movl_T1_reg(s, rd1); gen_op_iwmmxt_muladdsw_M0_T0_T1(); break; case 0xc: /* MIABB */ case 0xd: /* MIABT */ case 0xe: /* MIATB */ case 0xf: /* MIATT */ - gen_op_movl_TN_reg[1][rd0](); + gen_movl_T1_reg(s, rd0); if (insn & (1 << 16)) gen_op_shrl_T1_im(16); gen_op_movl_T0_T1(); - gen_op_movl_TN_reg[1][rd1](); + gen_movl_T1_reg(s, rd1); if (insn & (1 << 17)) gen_op_shrl_T1_im(16); gen_op_iwmmxt_muladdswl_M0_T0_T1(); @@ -1636,15 +2522,15 @@ return 1; if (insn & ARM_CP_RW_BIT) { /* MRA */ - gen_op_iwmmxt_movl_T0_T1_wRn(acc); - gen_op_movl_reg_TN[0][rdlo](); + gen_iwmmxt_movl_T0_T1_wRn(acc); + gen_movl_reg_T0(s, rdlo); gen_op_movl_T0_im((1 << (40 - 32)) - 1); gen_op_andl_T0_T1(); - gen_op_movl_reg_TN[0][rdhi](); + gen_movl_reg_T0(s, rdhi); } else { /* MAR */ - gen_op_movl_TN_reg[0][rdlo](); - gen_op_movl_TN_reg[1][rdhi](); - gen_op_iwmmxt_movl_wRn_T0_T1(acc); + gen_movl_T0_reg(s, rdlo); + gen_movl_T1_reg(s, rdhi); + gen_iwmmxt_movl_wRn_T0_T1(acc); } return 0; } @@ -1656,6 +2542,7 @@ instruction is not defined. */ static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn) { + TCGv tmp; uint32_t rd = (insn >> 12) & 0xf; uint32_t cp = (insn >> 8) & 0xf; if (IS_USER(s)) { @@ -1665,17 +2552,17 @@ if (insn & ARM_CP_RW_BIT) { if (!env->cp[cp].cp_read) return 1; - gen_op_movl_T0_im((uint32_t) s->pc); - gen_op_movl_reg_TN[0][15](); - gen_op_movl_T0_cp(insn); - gen_movl_reg_T0(s, rd); + gen_set_pc_im(s->pc); + tmp = new_tmp(); + gen_helper_get_cp(tmp, cpu_env, tcg_const_i32(insn)); + store_reg(s, rd, tmp); } else { if (!env->cp[cp].cp_write) return 1; - gen_op_movl_T0_im((uint32_t) s->pc); - gen_op_movl_reg_TN[0][15](); - gen_movl_T0_reg(s, rd); - gen_op_movl_cp_T0(insn); + gen_set_pc_im(s->pc); + tmp = load_reg(s, rd); + gen_helper_set_cp(cpu_env, tcg_const_i32(insn), tmp); + dead_tmp(tmp); } return 0; } @@ -1705,6 +2592,7 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn) { uint32_t rd; + TCGv tmp; /* M profile cores use memory mapped registers instead of cp15. */ if (arm_feature(env, ARM_FEATURE_M)) @@ -1728,20 +2616,23 @@ if ((insn & 0x0fff0fff) == 0x0e070f90 || (insn & 0x0fff0fff) == 0x0e070f58) { /* Wait for interrupt. */ - gen_op_movl_T0_im((long)s->pc); - gen_op_movl_reg_TN[0][15](); + gen_set_pc_im(s->pc); s->is_jmp = DISAS_WFI; return 0; } rd = (insn >> 12) & 0xf; if (insn & ARM_CP_RW_BIT) { - gen_op_movl_T0_cp15(insn); + tmp = new_tmp(); + gen_helper_get_cp15(tmp, cpu_env, tcg_const_i32(insn)); /* If the destination register is r15 then sets condition codes. */ if (rd != 15) - gen_movl_reg_T0(s, rd); + store_reg(s, rd, tmp); + else + dead_tmp(tmp); } else { - gen_movl_T0_reg(s, rd); - gen_op_movl_cp15_T0(insn); + tmp = load_reg(s, rd); + gen_helper_set_cp15(cpu_env, tcg_const_i32(insn), tmp); + dead_tmp(tmp); /* Normally we would always end the TB here, but Linux * arch/arm/mach-pxa/sleep.S expects two instructions following * an MMU enable to execute from cache. Imitate this behaviour. */ @@ -1772,18 +2663,65 @@ #define VFP_SREG_M(insn) VFP_SREG(insn, 0, 5) #define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn, 0, 5) +/* Move between integer and VFP cores. */ +static TCGv gen_vfp_mrs(void) +{ + TCGv tmp = new_tmp(); + tcg_gen_mov_i32(tmp, cpu_F0s); + return tmp; +} + +static void gen_vfp_msr(TCGv tmp) +{ + tcg_gen_mov_i32(cpu_F0s, tmp); + dead_tmp(tmp); +} + static inline int vfp_enabled(CPUState * env) { return ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) != 0); } +static void gen_neon_dup_u8(TCGv var, int shift) +{ + TCGv tmp = new_tmp(); + if (shift) + tcg_gen_shri_i32(var, var, shift); + tcg_gen_ext8u_i32(var, var); + tcg_gen_shli_i32(tmp, var, 8); + tcg_gen_or_i32(var, var, tmp); + tcg_gen_shli_i32(tmp, var, 16); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); +} + +static void gen_neon_dup_low16(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_ext16u_i32(var, var); + tcg_gen_shli_i32(tmp, var, 16); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); +} + +static void gen_neon_dup_high16(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_andi_i32(var, var, 0xffff0000); + tcg_gen_shri_i32(tmp, var, 16); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); +} + /* Disassemble a VFP instruction. Returns nonzero if an error occured (ie. an undefined instruction). */ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) { uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask; int dp, veclen; + TCGv tmp; + TCGv tmp2; if (!arm_feature(env, ARM_FEATURE_VFP)) return 1; @@ -1827,71 +2765,66 @@ } if (insn & ARM_CP_RW_BIT) { /* vfp->arm */ + tmp = neon_load_reg(rn, pass); switch (size) { case 0: - NEON_GET_REG(T1, rn, pass); if (offset) - gen_op_shrl_T1_im(offset); + tcg_gen_shri_i32(tmp, tmp, offset); if (insn & (1 << 23)) - gen_op_uxtb_T1(); + gen_uxtb(tmp); else - gen_op_sxtb_T1(); + gen_sxtb(tmp); break; case 1: - NEON_GET_REG(T1, rn, pass); if (insn & (1 << 23)) { if (offset) { - gen_op_shrl_T1_im(16); + tcg_gen_shri_i32(tmp, tmp, 16); } else { - gen_op_uxth_T1(); + gen_uxth(tmp); } } else { if (offset) { - gen_op_sarl_T1_im(16); + tcg_gen_sari_i32(tmp, tmp, 16); } else { - gen_op_sxth_T1(); + gen_sxth(tmp); } } break; case 2: - NEON_GET_REG(T1, rn, pass); break; } - gen_movl_reg_T1(s, rd); + store_reg(s, rd, tmp); } else { /* arm->vfp */ - gen_movl_T0_reg(s, rd); + tmp = load_reg(s, rd); if (insn & (1 << 23)) { /* VDUP */ if (size == 0) { - gen_op_neon_dup_u8(0); + gen_neon_dup_u8(tmp, 0); } else if (size == 1) { - gen_op_neon_dup_low16(); + gen_neon_dup_low16(tmp); } - NEON_SET_REG(T0, rn, 0); - NEON_SET_REG(T0, rn, 1); + tmp2 = new_tmp(); + tcg_gen_mov_i32(tmp2, tmp); + neon_store_reg(rn, 0, tmp2); + neon_store_reg(rn, 1, tmp); } else { /* VMOV */ switch (size) { case 0: - NEON_GET_REG(T2, rn, pass); - gen_op_movl_T1_im(0xff); - gen_op_andl_T0_T1(); - gen_op_neon_insert_elt(offset, ~(0xff << offset)); - NEON_SET_REG(T2, rn, pass); + tmp2 = neon_load_reg(rn, pass); + gen_bfi(tmp, tmp2, tmp, offset, 0xff); + dead_tmp(tmp2); break; case 1: - NEON_GET_REG(T2, rn, pass); - gen_op_movl_T1_im(0xffff); - gen_op_andl_T0_T1(); - bank_mask = offset ? 0xffff : 0xffff0000; - gen_op_neon_insert_elt(offset, bank_mask); - NEON_SET_REG(T2, rn, pass); + tmp2 = neon_load_reg(rn, pass); + gen_bfi(tmp, tmp2, tmp, offset, 0xffff); + dead_tmp(tmp2); break; case 2: - NEON_SET_REG(T0, rn, pass); break; } + neon_store_reg(rn, pass, tmp); } } } else { /* !dp */ @@ -1906,18 +2839,18 @@ switch (rn) { case ARM_VFP_FPSID: - /* VFP2 allows access for FSID from userspace. + /* VFP2 allows access to FSID from userspace. VFP3 restricts all id registers to privileged accesses. */ if (IS_USER(s) && arm_feature(env, ARM_FEATURE_VFP3)) return 1; - gen_op_vfp_movl_T0_xreg(rn); + tmp = load_cpu_field(vfp.xregs[rn]); break; case ARM_VFP_FPEXC: if (IS_USER(s)) return 1; - gen_op_vfp_movl_T0_xreg(rn); + tmp = load_cpu_field(vfp.xregs[rn]); break; case ARM_VFP_FPINST: case ARM_VFP_FPINST2: @@ -1925,36 +2858,41 @@ if (IS_USER(s) || arm_feature(env, ARM_FEATURE_VFP3)) return 1; - gen_op_vfp_movl_T0_xreg(rn); + tmp = load_cpu_field(vfp.xregs[rn]); break; case ARM_VFP_FPSCR: - if (rd == 15) - gen_op_vfp_movl_T0_fpscr_flags(); - else - gen_op_vfp_movl_T0_fpscr(); + if (rd == 15) { + tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]); + tcg_gen_andi_i32(tmp, tmp, 0xf0000000); + } else { + tmp = new_tmp(); + gen_helper_vfp_get_fpscr(tmp, cpu_env); + } break; case ARM_VFP_MVFR0: case ARM_VFP_MVFR1: if (IS_USER(s) || !arm_feature(env, ARM_FEATURE_VFP3)) return 1; - gen_op_vfp_movl_T0_xreg(rn); + tmp = load_cpu_field(vfp.xregs[rn]); break; default: return 1; } } else { gen_mov_F0_vreg(0, rn); - gen_op_vfp_mrs(); + tmp = gen_vfp_mrs(); } if (rd == 15) { /* Set the 4 flag bits in the CPSR. */ - gen_op_movl_cpsr_T0(0xf0000000); - } else - gen_movl_reg_T0(s, rd); + gen_set_nzcv(tmp); + dead_tmp(tmp); + } else { + store_reg(s, rd, tmp); + } } else { /* arm->vfp */ - gen_movl_T0_reg(s, rd); + tmp = load_reg(s, rd); if (insn & (1 << 21)) { rn >>= 1; /* system register */ @@ -1965,24 +2903,25 @@ /* Writes are ignored. */ break; case ARM_VFP_FPSCR: - gen_op_vfp_movl_fpscr_T0(); + gen_helper_vfp_set_fpscr(cpu_env, tmp); + dead_tmp(tmp); gen_lookup_tb(s); break; case ARM_VFP_FPEXC: if (IS_USER(s)) return 1; - gen_op_vfp_movl_xreg_T0(rn); + store_cpu_field(tmp, vfp.xregs[rn]); gen_lookup_tb(s); break; case ARM_VFP_FPINST: case ARM_VFP_FPINST2: - gen_op_vfp_movl_xreg_T0(rn); + store_cpu_field(tmp, vfp.xregs[rn]); break; default: return 1; } } else { - gen_op_vfp_msr(); + gen_vfp_msr(tmp); gen_mov_vreg_F0(0, rn); } } @@ -2118,9 +3057,9 @@ break; case 3: /* nmsc: -fd - (fn * fm) */ gen_vfp_mul(dp); - gen_mov_F1_vreg(dp, rd); - gen_vfp_add(dp); gen_vfp_neg(dp); + gen_mov_F1_vreg(dp, rd); + gen_vfp_sub(dp); break; case 4: /* mul: fn * fm */ gen_vfp_mul(dp); @@ -2150,14 +3089,15 @@ else i |= 0x4000; n |= i << 16; + tcg_gen_movi_i64(cpu_F0d, ((uint64_t)n) << 32); } else { if (i & 0x40) i |= 0x780; else i |= 0x800; n |= i << 19; + tcg_gen_movi_i32(cpu_F0s, n); } - gen_vfp_fconst(dp, n); break; case 15: /* extension space */ switch (rn) { @@ -2188,9 +3128,9 @@ break; case 15: /* single<->double conversion */ if (dp) - gen_op_vfp_fcvtsd(); + gen_helper_vfp_fcvtsd(cpu_F0s, cpu_F0d, cpu_env); else - gen_op_vfp_fcvtds(); + gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env); break; case 16: /* fuito */ gen_vfp_uito(dp); @@ -2324,31 +3264,35 @@ if (insn & ARM_CP_RW_BIT) { /* vfp->arm */ if (dp) { - gen_mov_F0_vreg(1, rm); - gen_op_vfp_mrrd(); - gen_movl_reg_T0(s, rd); - gen_movl_reg_T1(s, rn); + gen_mov_F0_vreg(0, rm * 2); + tmp = gen_vfp_mrs(); + store_reg(s, rd, tmp); + gen_mov_F0_vreg(0, rm * 2 + 1); + tmp = gen_vfp_mrs(); + store_reg(s, rn, tmp); } else { gen_mov_F0_vreg(0, rm); - gen_op_vfp_mrs(); - gen_movl_reg_T0(s, rn); + tmp = gen_vfp_mrs(); + store_reg(s, rn, tmp); gen_mov_F0_vreg(0, rm + 1); - gen_op_vfp_mrs(); - gen_movl_reg_T0(s, rd); + tmp = gen_vfp_mrs(); + store_reg(s, rd, tmp); } } else { /* arm->vfp */ if (dp) { - gen_movl_T0_reg(s, rd); - gen_movl_T1_reg(s, rn); - gen_op_vfp_mdrr(); - gen_mov_vreg_F0(1, rm); + tmp = load_reg(s, rd); + gen_vfp_msr(tmp); + gen_mov_vreg_F0(0, rm * 2); + tmp = load_reg(s, rn); + gen_vfp_msr(tmp); + gen_mov_vreg_F0(0, rm * 2 + 1); } else { - gen_movl_T0_reg(s, rn); - gen_op_vfp_msr(); + tmp = load_reg(s, rn); + gen_vfp_msr(tmp); gen_mov_vreg_F0(0, rm); - gen_movl_T0_reg(s, rd); - gen_op_vfp_msr(); + tmp = load_reg(s, rd); + gen_vfp_msr(tmp); gen_mov_vreg_F0(0, rm + 1); } } @@ -2432,47 +3376,39 @@ tb = s->tb; if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { - if (n == 0) - gen_op_goto_tb0(TBPARAM(tb)); - else - gen_op_goto_tb1(TBPARAM(tb)); - gen_op_movl_T0_im(dest); - gen_op_movl_r15_T0(); - gen_op_movl_T0_im((long)tb + n); - gen_op_exit_tb(); + tcg_gen_goto_tb(n); + gen_set_pc_im(dest); + tcg_gen_exit_tb((long)tb + n); } else { - gen_op_movl_T0_im(dest); - gen_op_movl_r15_T0(); - gen_op_movl_T0_0(); - gen_op_exit_tb(); + gen_set_pc_im(dest); + tcg_gen_exit_tb(0); } } static inline void gen_jmp (DisasContext *s, uint32_t dest) { - if (__builtin_expect(s->singlestep_enabled, 0)) { + if (unlikely(s->singlestep_enabled)) { /* An indirect jump so that we still trigger the debug exception. */ if (s->thumb) - dest |= 1; - gen_op_movl_T0_im(dest); - gen_bx(s); + dest |= 1; + gen_bx_im(s, dest); } else { gen_goto_tb(s, 0, dest); s->is_jmp = DISAS_TB_JUMP; } } -static inline void gen_mulxy(int x, int y) +static inline void gen_mulxy(TCGv t0, TCGv t1, int x, int y) { if (x) - gen_op_sarl_T0_im(16); + tcg_gen_sari_i32(t0, t0, 16); else - gen_op_sxth_T0(); + gen_sxth(t0); if (y) - gen_op_sarl_T1_im(16); + tcg_gen_sari_i32(t1, t1, 16); else - gen_op_sxth_T1(); - gen_op_mul_T0_T1(); + gen_sxth(t1); + tcg_gen_mul_i32(t0, t0, t1); } /* Return the mask of PSR bits set by a MSR instruction. */ @@ -2507,13 +3443,19 @@ /* Returns nonzero if access to the PSR is not permitted. */ static int gen_set_psr_T0(DisasContext *s, uint32_t mask, int spsr) { + TCGv tmp; if (spsr) { /* ??? This is also undefined in system mode. */ if (IS_USER(s)) return 1; - gen_op_movl_spsr_T0(mask); + + tmp = load_cpu_field(spsr); + tcg_gen_andi_i32(tmp, tmp, ~mask); + tcg_gen_andi_i32(cpu_T[0], cpu_T[0], mask); + tcg_gen_or_i32(tmp, tmp, cpu_T[0]); + store_cpu_field(tmp, spsr); } else { - gen_op_movl_cpsr_T0(mask); + gen_set_cpsr(cpu_T[0], mask); } gen_lookup_tb(s); return 0; @@ -2522,18 +3464,20 @@ /* Generate an old-style exception return. */ static void gen_exception_return(DisasContext *s) { - gen_op_movl_reg_TN[0][15](); - gen_op_movl_T0_spsr(); - gen_op_movl_cpsr_T0(0xffffffff); + TCGv tmp; + gen_movl_reg_T0(s, 15); + tmp = load_cpu_field(spsr); + gen_set_cpsr(tmp, 0xffffffff); + dead_tmp(tmp); s->is_jmp = DISAS_UPDATE; } -/* Generate a v6 exception return. */ -static void gen_rfe(DisasContext *s) +/* Generate a v6 exception return. Marks both values as dead. */ +static void gen_rfe(DisasContext *s, TCGv pc, TCGv cpsr) { - gen_op_movl_cpsr_T0(0xffffffff); - gen_op_movl_T0_T2(); - gen_op_movl_reg_TN[0][15](); + gen_set_cpsr(cpsr, 0xffffffff); + dead_tmp(cpsr); + store_reg(s, 15, pc); s->is_jmp = DISAS_UPDATE; } @@ -2541,7 +3485,10 @@ gen_set_condexec (DisasContext *s) { if (s->condexec_mask) { - gen_op_set_condexec((s->condexec_cond << 4) | (s->condexec_mask >> 1)); + uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1); + TCGv tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + store_cpu_field(tmp, condexec_bits); } } @@ -2549,8 +3496,7 @@ { switch (val) { case 3: /* wfi */ - gen_op_movl_T0_im((long)s->pc); - gen_op_movl_reg_TN[0][15](); + gen_set_pc_im(s->pc); s->is_jmp = DISAS_WFI; break; case 2: /* wfe */ @@ -2561,179 +3507,90 @@ } } -/* Neon shift by constant. The actual ops are the same as used for variable - shifts. [OP][U][SIZE] */ -static GenOpFunc *gen_neon_shift_im[8][2][4] = { - { /* 0 */ /* VSHR */ - { - gen_op_neon_shl_u8, - gen_op_neon_shl_u16, - gen_op_neon_shl_u32, - gen_op_neon_shl_u64 - }, { - gen_op_neon_shl_s8, - gen_op_neon_shl_s16, - gen_op_neon_shl_s32, - gen_op_neon_shl_s64 - } - }, { /* 1 */ /* VSRA */ - { - gen_op_neon_shl_u8, - gen_op_neon_shl_u16, - gen_op_neon_shl_u32, - gen_op_neon_shl_u64 - }, { - gen_op_neon_shl_s8, - gen_op_neon_shl_s16, - gen_op_neon_shl_s32, - gen_op_neon_shl_s64 - } - }, { /* 2 */ /* VRSHR */ - { - gen_op_neon_rshl_u8, - gen_op_neon_rshl_u16, - gen_op_neon_rshl_u32, - gen_op_neon_rshl_u64 - }, { - gen_op_neon_rshl_s8, - gen_op_neon_rshl_s16, - gen_op_neon_rshl_s32, - gen_op_neon_rshl_s64 - } - }, { /* 3 */ /* VRSRA */ - { - gen_op_neon_rshl_u8, - gen_op_neon_rshl_u16, - gen_op_neon_rshl_u32, - gen_op_neon_rshl_u64 - }, { - gen_op_neon_rshl_s8, - gen_op_neon_rshl_s16, - gen_op_neon_rshl_s32, - gen_op_neon_rshl_s64 - } - }, { /* 4 */ - { - NULL, NULL, NULL, NULL - }, { /* VSRI */ - gen_op_neon_shl_u8, - gen_op_neon_shl_u16, - gen_op_neon_shl_u32, - gen_op_neon_shl_u64, - } - }, { /* 5 */ - { /* VSHL */ - gen_op_neon_shl_u8, - gen_op_neon_shl_u16, - gen_op_neon_shl_u32, - gen_op_neon_shl_u64, - }, { /* VSLI */ - gen_op_neon_shl_u8, - gen_op_neon_shl_u16, - gen_op_neon_shl_u32, - gen_op_neon_shl_u64, - } - }, { /* 6 */ /* VQSHL */ - { - gen_op_neon_qshl_u8, - gen_op_neon_qshl_u16, - gen_op_neon_qshl_u32, - gen_op_neon_qshl_u64 - }, { - gen_op_neon_qshl_s8, - gen_op_neon_qshl_s16, - gen_op_neon_qshl_s32, - gen_op_neon_qshl_s64 - } - }, { /* 7 */ /* VQSHLU */ - { - gen_op_neon_qshl_u8, - gen_op_neon_qshl_u16, - gen_op_neon_qshl_u32, - gen_op_neon_qshl_u64 - }, { - gen_op_neon_qshl_u8, - gen_op_neon_qshl_u16, - gen_op_neon_qshl_u32, - gen_op_neon_qshl_u64 - } - } -}; - -/* [R][U][size - 1] */ -static GenOpFunc *gen_neon_shift_im_narrow[2][2][3] = { - { - { - gen_op_neon_shl_u16, - gen_op_neon_shl_u32, - gen_op_neon_shl_u64 - }, { - gen_op_neon_shl_s16, - gen_op_neon_shl_s32, - gen_op_neon_shl_s64 - } - }, { - { - gen_op_neon_rshl_u16, - gen_op_neon_rshl_u32, - gen_op_neon_rshl_u64 - }, { - gen_op_neon_rshl_s16, - gen_op_neon_rshl_s32, - gen_op_neon_rshl_s64 - } - } -}; - -static inline void -gen_op_neon_narrow_u32 () -{ - /* No-op. */ -} - -static GenOpFunc *gen_neon_narrow[3] = { - gen_op_neon_narrow_u8, - gen_op_neon_narrow_u16, - gen_op_neon_narrow_u32 -}; - -static GenOpFunc *gen_neon_narrow_satu[3] = { - gen_op_neon_narrow_sat_u8, - gen_op_neon_narrow_sat_u16, - gen_op_neon_narrow_sat_u32 -}; +/* These macros help make the code more readable when migrating from the + old dyngen helpers. They should probably be removed when + T0/T1 are removed. */ +#define CPU_T001 cpu_T[0], cpu_T[0], cpu_T[1] +#define CPU_T0E01 cpu_T[0], cpu_env, cpu_T[0], cpu_T[1] -static GenOpFunc *gen_neon_narrow_sats[3] = { - gen_op_neon_narrow_sat_s8, - gen_op_neon_narrow_sat_s16, - gen_op_neon_narrow_sat_s32 -}; +#define CPU_V001 cpu_V0, cpu_V0, cpu_V1 static inline int gen_neon_add(int size) { switch (size) { - case 0: gen_op_neon_add_u8(); break; - case 1: gen_op_neon_add_u16(); break; + case 0: gen_helper_neon_add_u8(CPU_T001); break; + case 1: gen_helper_neon_add_u16(CPU_T001); break; case 2: gen_op_addl_T0_T1(); break; default: return 1; } return 0; } -/* 32-bit pairwise ops end up the same as the elementsise versions. */ -#define gen_op_neon_pmax_s32 gen_op_neon_max_s32 -#define gen_op_neon_pmax_u32 gen_op_neon_max_u32 -#define gen_op_neon_pmin_s32 gen_op_neon_min_s32 -#define gen_op_neon_pmin_u32 gen_op_neon_min_u32 +static inline void gen_neon_rsb(int size) +{ + switch (size) { + case 0: gen_helper_neon_sub_u8(cpu_T[0], cpu_T[1], cpu_T[0]); break; + case 1: gen_helper_neon_sub_u16(cpu_T[0], cpu_T[1], cpu_T[0]); break; + case 2: gen_op_rsbl_T0_T1(); break; + default: return; + } +} + +/* 32-bit pairwise ops end up the same as the elementwise versions. */ +#define gen_helper_neon_pmax_s32 gen_helper_neon_max_s32 +#define gen_helper_neon_pmax_u32 gen_helper_neon_max_u32 +#define gen_helper_neon_pmin_s32 gen_helper_neon_min_s32 +#define gen_helper_neon_pmin_u32 gen_helper_neon_min_u32 + +/* FIXME: This is wrong. They set the wrong overflow bit. */ +#define gen_helper_neon_qadd_s32(a, e, b, c) gen_helper_add_saturate(a, b, c) +#define gen_helper_neon_qadd_u32(a, e, b, c) gen_helper_add_usaturate(a, b, c) +#define gen_helper_neon_qsub_s32(a, e, b, c) gen_helper_sub_saturate(a, b, c) +#define gen_helper_neon_qsub_u32(a, e, b, c) gen_helper_sub_usaturate(a, b, c) + +#define GEN_NEON_INTEGER_OP_ENV(name) do { \ + switch ((size << 1) | u) { \ + case 0: \ + gen_helper_neon_##name##_s8(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); \ + break; \ + case 1: \ + gen_helper_neon_##name##_u8(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); \ + break; \ + case 2: \ + gen_helper_neon_##name##_s16(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); \ + break; \ + case 3: \ + gen_helper_neon_##name##_u16(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); \ + break; \ + case 4: \ + gen_helper_neon_##name##_s32(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); \ + break; \ + case 5: \ + gen_helper_neon_##name##_u32(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); \ + break; \ + default: return 1; \ + }} while (0) #define GEN_NEON_INTEGER_OP(name) do { \ switch ((size << 1) | u) { \ - case 0: gen_op_neon_##name##_s8(); break; \ - case 1: gen_op_neon_##name##_u8(); break; \ - case 2: gen_op_neon_##name##_s16(); break; \ - case 3: gen_op_neon_##name##_u16(); break; \ - case 4: gen_op_neon_##name##_s32(); break; \ - case 5: gen_op_neon_##name##_u32(); break; \ + case 0: \ + gen_helper_neon_##name##_s8(cpu_T[0], cpu_T[0], cpu_T[1]); \ + break; \ + case 1: \ + gen_helper_neon_##name##_u8(cpu_T[0], cpu_T[0], cpu_T[1]); \ + break; \ + case 2: \ + gen_helper_neon_##name##_s16(cpu_T[0], cpu_T[0], cpu_T[1]); \ + break; \ + case 3: \ + gen_helper_neon_##name##_u16(cpu_T[0], cpu_T[0], cpu_T[1]); \ + break; \ + case 4: \ + gen_helper_neon_##name##_s32(cpu_T[0], cpu_T[0], cpu_T[1]); \ + break; \ + case 5: \ + gen_helper_neon_##name##_u32(cpu_T[0], cpu_T[0], cpu_T[1]); \ + break; \ default: return 1; \ }} while (0) @@ -2743,7 +3600,7 @@ uint32_t offset; offset = offsetof(CPUARMState, vfp.scratch[scratch]); - gen_op_neon_setreg_T0(offset); + tcg_gen_st_i32(cpu_T[0], cpu_env, offset); } static inline void @@ -2752,7 +3609,7 @@ uint32_t offset; offset = offsetof(CPUARMState, vfp.scratch[scratch]); - gen_op_neon_setreg_T1(offset); + tcg_gen_st_i32(cpu_T[1], cpu_env, offset); } static inline void @@ -2761,7 +3618,7 @@ uint32_t offset; offset = offsetof(CPUARMState, vfp.scratch[scratch]); - gen_op_neon_getreg_T0(offset); + tcg_gen_ld_i32(cpu_T[0], cpu_env, offset); } static inline void @@ -2770,12 +3627,7 @@ uint32_t offset; offset = offsetof(CPUARMState, vfp.scratch[scratch]); - gen_op_neon_getreg_T1(offset); -} - -static inline void gen_op_neon_widen_u32(void) -{ - gen_op_movl_T1_im(0); + tcg_gen_ld_i32(cpu_T[1], cpu_env, offset); } static inline void gen_neon_get_scalar(int size, int reg) @@ -2785,9 +3637,9 @@ } else { NEON_GET_REG(T0, reg >> 2, (reg >> 1) & 1); if (reg & 1) - gen_op_neon_dup_low16(); + gen_neon_dup_low16(cpu_T[0]); else - gen_op_neon_dup_high16(); + gen_neon_dup_high16(cpu_T[0]); } } @@ -2799,8 +3651,8 @@ NEON_GET_REG(T0, reg, n); NEON_GET_REG(T0, reg, n + n); switch (size) { - case 0: gen_op_neon_unzip_u8(); break; - case 1: gen_op_neon_zip_u16(); break; /* zip and unzip are the same. */ + case 0: gen_helper_neon_unzip_u8(); break; + case 1: gen_helper_neon_zip_u16(); break; /* zip and unzip are the same. */ case 2: /* no-op */; break; default: abort(); } @@ -2841,8 +3693,9 @@ int pass; int load; int shift; - uint32_t mask; int n; + TCGv tmp; + TCGv tmp2; if (!vfp_enabled(env)) return 1; @@ -2871,58 +3724,58 @@ for (pass = 0; pass < 2; pass++) { if (size == 2) { if (load) { - gen_ldst(ldl, s); - NEON_SET_REG(T0, rd, pass); + tmp = gen_ld32(cpu_T[1], IS_USER(s)); + neon_store_reg(rd, pass, tmp); } else { - NEON_GET_REG(T0, rd, pass); - gen_ldst(stl, s); + tmp = neon_load_reg(rd, pass); + gen_st32(tmp, cpu_T[1], IS_USER(s)); } gen_op_addl_T1_im(stride); } else if (size == 1) { if (load) { - gen_ldst(lduw, s); + tmp = gen_ld16u(cpu_T[1], IS_USER(s)); gen_op_addl_T1_im(stride); - gen_op_movl_T2_T0(); - gen_ldst(lduw, s); + tmp2 = gen_ld16u(cpu_T[1], IS_USER(s)); gen_op_addl_T1_im(stride); - gen_op_neon_insert_elt(16, 0xffff); - NEON_SET_REG(T2, rd, pass); - } else { - NEON_GET_REG(T2, rd, pass); - gen_op_movl_T0_T2(); - gen_ldst(stw, s); + gen_bfi(tmp, tmp, tmp2, 16, 0xffff); + dead_tmp(tmp2); + neon_store_reg(rd, pass, tmp); + } else { + tmp = neon_load_reg(rd, pass); + tmp2 = new_tmp(); + tcg_gen_shri_i32(tmp2, tmp, 16); + gen_st16(tmp, cpu_T[1], IS_USER(s)); gen_op_addl_T1_im(stride); - gen_op_neon_extract_elt(16, 0xffff0000); - gen_ldst(stw, s); + gen_st16(tmp2, cpu_T[1], IS_USER(s)); gen_op_addl_T1_im(stride); } } else /* size == 0 */ { if (load) { - mask = 0xff; + TCGV_UNUSED(tmp2); for (n = 0; n < 4; n++) { - gen_ldst(ldub, s); + tmp = gen_ld8u(cpu_T[1], IS_USER(s)); gen_op_addl_T1_im(stride); if (n == 0) { - gen_op_movl_T2_T0(); + tmp2 = tmp; } else { - gen_op_neon_insert_elt(n * 8, ~mask); + gen_bfi(tmp2, tmp2, tmp, n * 8, 0xff); + dead_tmp(tmp); } - mask <<= 8; } - NEON_SET_REG(T2, rd, pass); + neon_store_reg(rd, pass, tmp2); } else { - NEON_GET_REG(T2, rd, pass); - mask = 0xff; + tmp2 = neon_load_reg(rd, pass); for (n = 0; n < 4; n++) { + tmp = new_tmp(); if (n == 0) { - gen_op_movl_T0_T2(); + tcg_gen_mov_i32(tmp, tmp2); } else { - gen_op_neon_extract_elt(n * 8, mask); + tcg_gen_shri_i32(tmp, tmp2, n * 8); } - gen_ldst(stb, s); + gen_st8(tmp, cpu_T[1], IS_USER(s)); gen_op_addl_T1_im(stride); - mask <<= 8; } + dead_tmp(tmp2); } } } @@ -2942,22 +3795,26 @@ for (reg = 0; reg < nregs; reg++) { switch (size) { case 0: - gen_ldst(ldub, s); - gen_op_neon_dup_u8(0); + tmp = gen_ld8u(cpu_T[1], IS_USER(s)); + gen_neon_dup_u8(tmp, 0); break; case 1: - gen_ldst(lduw, s); - gen_op_neon_dup_low16(); + tmp = gen_ld16u(cpu_T[1], IS_USER(s)); + gen_neon_dup_low16(tmp); break; case 2: - gen_ldst(ldl, s); + tmp = gen_ld32(cpu_T[0], IS_USER(s)); break; case 3: return 1; + default: /* Avoid compiler warnings. */ + abort(); } gen_op_addl_T1_im(1 << size); - NEON_SET_REG(T0, rd, 0); - NEON_SET_REG(T0, rd, 1); + tmp2 = new_tmp(); + tcg_gen_mov_i32(tmp2, tmp); + neon_store_reg(rd, 0, tmp2); + neon_store_reg(rd, 1, tmp); rd += stride; } stride = (1 << size) * nregs; @@ -2967,17 +3824,14 @@ switch (size) { case 0: shift = ((insn >> 5) & 3) * 8; - mask = 0xff << shift; stride = 1; break; case 1: shift = ((insn >> 6) & 1) * 16; - mask = shift ? 0xffff0000 : 0xffff; stride = (insn & (1 << 5)) ? 2 : 1; break; case 2: shift = 0; - mask = 0xffffffff; stride = (insn & (1 << 6)) ? 2 : 1; break; default: @@ -2987,41 +3841,38 @@ gen_movl_T1_reg(s, rn); for (reg = 0; reg < nregs; reg++) { if (load) { - if (size != 2) { - NEON_GET_REG(T2, rd, pass); - } switch (size) { case 0: - gen_ldst(ldub, s); + tmp = gen_ld8u(cpu_T[1], IS_USER(s)); break; case 1: - gen_ldst(lduw, s); + tmp = gen_ld16u(cpu_T[1], IS_USER(s)); break; case 2: - gen_ldst(ldl, s); - NEON_SET_REG(T0, rd, pass); + tmp = gen_ld32(cpu_T[1], IS_USER(s)); break; + default: /* Avoid compiler warnings. */ + abort(); } if (size != 2) { - gen_op_neon_insert_elt(shift, ~mask); - NEON_SET_REG(T0, rd, pass); + tmp2 = neon_load_reg(rd, pass); + gen_bfi(tmp, tmp2, tmp, shift, size ? 0xffff : 0xff); + dead_tmp(tmp2); } + neon_store_reg(rd, pass, tmp); } else { /* Store */ - if (size == 2) { - NEON_GET_REG(T0, rd, pass); - } else { - NEON_GET_REG(T2, rd, pass); - gen_op_neon_extract_elt(shift, mask); - } + tmp = neon_load_reg(rd, pass); + if (shift) + tcg_gen_shri_i32(tmp, tmp, shift); switch (size) { case 0: - gen_ldst(stb, s); + gen_st8(tmp, cpu_T[1], IS_USER(s)); break; case 1: - gen_ldst(stw, s); + gen_st16(tmp, cpu_T[1], IS_USER(s)); break; case 2: - gen_ldst(stl, s); + gen_st32(tmp, cpu_T[1], IS_USER(s)); break; } } @@ -3032,24 +3883,182 @@ } } if (rm != 15) { - gen_movl_T1_reg(s, rn); + TCGv base; + + base = load_reg(s, rn); if (rm == 13) { - gen_op_addl_T1_im(stride); + tcg_gen_addi_i32(base, base, stride); } else { - gen_movl_T2_reg(s, rm); - gen_op_addl_T1_T2(); + TCGv index; + index = load_reg(s, rm); + tcg_gen_add_i32(base, base, index); + dead_tmp(index); } - gen_movl_reg_T1(s, rn); + store_reg(s, rn, base); } return 0; } +/* Bitwise select. dest = c ? t : f. Clobbers T and F. */ +static void gen_neon_bsl(TCGv dest, TCGv t, TCGv f, TCGv c) +{ + tcg_gen_and_i32(t, t, c); + tcg_gen_bic_i32(f, f, c); + tcg_gen_or_i32(dest, t, f); +} + +static inline void gen_neon_narrow(int size, TCGv dest, TCGv src) +{ + switch (size) { + case 0: gen_helper_neon_narrow_u8(dest, src); break; + case 1: gen_helper_neon_narrow_u16(dest, src); break; + case 2: tcg_gen_trunc_i64_i32(dest, src); break; + default: abort(); + } +} + +static inline void gen_neon_narrow_sats(int size, TCGv dest, TCGv src) +{ + switch (size) { + case 0: gen_helper_neon_narrow_sat_s8(dest, cpu_env, src); break; + case 1: gen_helper_neon_narrow_sat_s16(dest, cpu_env, src); break; + case 2: gen_helper_neon_narrow_sat_s32(dest, cpu_env, src); break; + default: abort(); + } +} + +static inline void gen_neon_narrow_satu(int size, TCGv dest, TCGv src) +{ + switch (size) { + case 0: gen_helper_neon_narrow_sat_u8(dest, cpu_env, src); break; + case 1: gen_helper_neon_narrow_sat_u16(dest, cpu_env, src); break; + case 2: gen_helper_neon_narrow_sat_u32(dest, cpu_env, src); break; + default: abort(); + } +} + +static inline void gen_neon_shift_narrow(int size, TCGv var, TCGv shift, + int q, int u) +{ + if (q) { + if (u) { + switch (size) { + case 1: gen_helper_neon_rshl_u16(var, var, shift); break; + case 2: gen_helper_neon_rshl_u32(var, var, shift); break; + default: abort(); + } + } else { + switch (size) { + case 1: gen_helper_neon_rshl_s16(var, var, shift); break; + case 2: gen_helper_neon_rshl_s32(var, var, shift); break; + default: abort(); + } + } + } else { + if (u) { + switch (size) { + case 1: gen_helper_neon_rshl_u16(var, var, shift); break; + case 2: gen_helper_neon_rshl_u32(var, var, shift); break; + default: abort(); + } + } else { + switch (size) { + case 1: gen_helper_neon_shl_s16(var, var, shift); break; + case 2: gen_helper_neon_shl_s32(var, var, shift); break; + default: abort(); + } + } + } +} + +static inline void gen_neon_widen(TCGv dest, TCGv src, int size, int u) +{ + if (u) { + switch (size) { + case 0: gen_helper_neon_widen_u8(dest, src); break; + case 1: gen_helper_neon_widen_u16(dest, src); break; + case 2: tcg_gen_extu_i32_i64(dest, src); break; + default: abort(); + } + } else { + switch (size) { + case 0: gen_helper_neon_widen_s8(dest, src); break; + case 1: gen_helper_neon_widen_s16(dest, src); break; + case 2: tcg_gen_ext_i32_i64(dest, src); break; + default: abort(); + } + } + dead_tmp(src); +} + +static inline void gen_neon_addl(int size) +{ + switch (size) { + case 0: gen_helper_neon_addl_u16(CPU_V001); break; + case 1: gen_helper_neon_addl_u32(CPU_V001); break; + case 2: tcg_gen_add_i64(CPU_V001); break; + default: abort(); + } +} + +static inline void gen_neon_subl(int size) +{ + switch (size) { + case 0: gen_helper_neon_subl_u16(CPU_V001); break; + case 1: gen_helper_neon_subl_u32(CPU_V001); break; + case 2: tcg_gen_sub_i64(CPU_V001); break; + default: abort(); + } +} + +static inline void gen_neon_negl(TCGv var, int size) +{ + switch (size) { + case 0: gen_helper_neon_negl_u16(var, var); break; + case 1: gen_helper_neon_negl_u32(var, var); break; + case 2: gen_helper_neon_negl_u64(var, var); break; + default: abort(); + } +} + +static inline void gen_neon_addl_saturate(TCGv op0, TCGv op1, int size) +{ + switch (size) { + case 1: gen_helper_neon_addl_saturate_s32(op0, cpu_env, op0, op1); break; + case 2: gen_helper_neon_addl_saturate_s64(op0, cpu_env, op0, op1); break; + default: abort(); + } +} + +static inline void gen_neon_mull(TCGv dest, TCGv a, TCGv b, int size, int u) +{ + TCGv tmp; + + switch ((size << 1) | u) { + case 0: gen_helper_neon_mull_s8(dest, a, b); break; + case 1: gen_helper_neon_mull_u8(dest, a, b); break; + case 2: gen_helper_neon_mull_s16(dest, a, b); break; + case 3: gen_helper_neon_mull_u16(dest, a, b); break; + case 4: + tmp = gen_muls_i64_i32(a, b); + tcg_gen_mov_i64(dest, tmp); + break; + case 5: + tmp = gen_mulu_i64_i32(a, b); + tcg_gen_mov_i64(dest, tmp); + break; + default: abort(); + } + if (size < 2) { + dead_tmp(b); + dead_tmp(a); + } +} + /* Translate a NEON data processing instruction. Return nonzero if the instruction is invalid. - In general we process vectors in 32-bit chunks. This means we can reuse - some of the scalar ops, and hopefully the code generated for 32-bit - hosts won't be too awful. The downside is that the few 64-bit operations - (mainly shifts) get complicated. */ + We process data in a mixture of 32-bit and 64-bit chunks. + Mostly we use 32-bit chunks so we can use normal scalar instructions. */ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) { @@ -3064,6 +4073,9 @@ int u; int n; uint32_t imm; + TCGv tmp; + TCGv tmp2; + TCGv tmp3; if (!vfp_enabled(env)) return 1; @@ -3076,41 +4088,70 @@ if ((insn & (1 << 23)) == 0) { /* Three register same length. */ op = ((insn >> 7) & 0x1e) | ((insn >> 4) & 1); - if (size == 3 && (op == 1 || op == 5 || op == 16)) { + if (size == 3 && (op == 1 || op == 5 || op == 8 || op == 9 + || op == 10 || op == 11 || op == 16)) { + /* 64-bit element instructions. */ for (pass = 0; pass < (q ? 2 : 1); pass++) { - NEON_GET_REG(T0, rm, pass * 2); - NEON_GET_REG(T1, rm, pass * 2 + 1); - gen_neon_movl_scratch_T0(0); - gen_neon_movl_scratch_T1(1); - NEON_GET_REG(T0, rn, pass * 2); - NEON_GET_REG(T1, rn, pass * 2 + 1); + neon_load_reg64(cpu_V0, rn + pass); + neon_load_reg64(cpu_V1, rm + pass); switch (op) { case 1: /* VQADD */ if (u) { - gen_op_neon_addl_saturate_u64(); + gen_helper_neon_add_saturate_u64(CPU_V001); } else { - gen_op_neon_addl_saturate_s64(); + gen_helper_neon_add_saturate_s64(CPU_V001); } break; case 5: /* VQSUB */ if (u) { - gen_op_neon_subl_saturate_u64(); + gen_helper_neon_sub_saturate_u64(CPU_V001); + } else { + gen_helper_neon_sub_saturate_s64(CPU_V001); + } + break; + case 8: /* VSHL */ + if (u) { + gen_helper_neon_shl_u64(cpu_V0, cpu_V1, cpu_V0); + } else { + gen_helper_neon_shl_s64(cpu_V0, cpu_V1, cpu_V0); + } + break; + case 9: /* VQSHL */ + if (u) { + gen_helper_neon_qshl_u64(cpu_V0, cpu_env, + cpu_V0, cpu_V0); + } else { + gen_helper_neon_qshl_s64(cpu_V1, cpu_env, + cpu_V1, cpu_V0); + } + break; + case 10: /* VRSHL */ + if (u) { + gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0); + } else { + gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0); + } + break; + case 11: /* VQRSHL */ + if (u) { + gen_helper_neon_qrshl_u64(cpu_V0, cpu_env, + cpu_V1, cpu_V0); } else { - gen_op_neon_subl_saturate_s64(); + gen_helper_neon_qrshl_s64(cpu_V0, cpu_env, + cpu_V1, cpu_V0); } break; case 16: if (u) { - gen_op_neon_subl_u64(); + tcg_gen_sub_i64(CPU_V001); } else { - gen_op_neon_addl_u64(); + tcg_gen_add_i64(CPU_V001); } break; default: abort(); } - NEON_SET_REG(T0, rd, pass * 2); - NEON_SET_REG(T1, rd, pass * 2 + 1); + neon_store_reg64(cpu_V0, rd + pass); } return 0; } @@ -3118,13 +4159,13 @@ case 8: /* VSHL */ case 9: /* VQSHL */ case 10: /* VRSHL */ - case 11: /* VQSHL */ - /* Shift operations have Rn and Rm reversed. */ + case 11: /* VQRSHL */ { - int tmp; - tmp = rn; + int rtmp; + /* Shift instruction operands are reversed. */ + rtmp = rn; rn = rm; - rm = tmp; + rm = rtmp; pairwise = 0; } break; @@ -3168,15 +4209,7 @@ GEN_NEON_INTEGER_OP(hadd); break; case 1: /* VQADD */ - switch (size << 1| u) { - case 0: gen_op_neon_qadd_s8(); break; - case 1: gen_op_neon_qadd_u8(); break; - case 2: gen_op_neon_qadd_s16(); break; - case 3: gen_op_neon_qadd_u16(); break; - case 4: gen_op_addl_T0_T1_saturate(); break; - case 5: gen_op_addl_T0_T1_usaturate(); break; - default: abort(); - } + GEN_NEON_INTEGER_OP_ENV(qadd); break; case 2: /* VRHADD */ GEN_NEON_INTEGER_OP(rhadd); @@ -3200,16 +4233,19 @@ gen_op_xorl_T0_T1(); break; case 5: /* VBSL */ - NEON_GET_REG(T2, rd, pass); - gen_op_neon_bsl(); + tmp = neon_load_reg(rd, pass); + gen_neon_bsl(cpu_T[0], cpu_T[0], cpu_T[1], tmp); + dead_tmp(tmp); break; case 6: /* VBIT */ - NEON_GET_REG(T2, rd, pass); - gen_op_neon_bit(); + tmp = neon_load_reg(rd, pass); + gen_neon_bsl(cpu_T[0], cpu_T[0], tmp, cpu_T[1]); + dead_tmp(tmp); break; case 7: /* VBIF */ - NEON_GET_REG(T2, rd, pass); - gen_op_neon_bif(); + tmp = neon_load_reg(rd, pass); + gen_neon_bsl(cpu_T[0], tmp, cpu_T[0], cpu_T[1]); + dead_tmp(tmp); break; } break; @@ -3217,15 +4253,7 @@ GEN_NEON_INTEGER_OP(hsub); break; case 5: /* VQSUB */ - switch ((size << 1) | u) { - case 0: gen_op_neon_qsub_s8(); break; - case 1: gen_op_neon_qsub_u8(); break; - case 2: gen_op_neon_qsub_s16(); break; - case 3: gen_op_neon_qsub_u16(); break; - case 4: gen_op_subl_T0_T1_saturate(); break; - case 5: gen_op_subl_T0_T1_usaturate(); break; - default: abort(); - } + GEN_NEON_INTEGER_OP_ENV(qsub); break; case 6: /* VCGT */ GEN_NEON_INTEGER_OP(cgt); @@ -3234,76 +4262,16 @@ GEN_NEON_INTEGER_OP(cge); break; case 8: /* VSHL */ - switch ((size << 1) | u) { - case 0: gen_op_neon_shl_s8(); break; - case 1: gen_op_neon_shl_u8(); break; - case 2: gen_op_neon_shl_s16(); break; - case 3: gen_op_neon_shl_u16(); break; - case 4: gen_op_neon_shl_s32(); break; - case 5: gen_op_neon_shl_u32(); break; -#if 0 - /* ??? Implementing these is tricky because the vector ops work - on 32-bit pieces. */ - case 6: gen_op_neon_shl_s64(); break; - case 7: gen_op_neon_shl_u64(); break; -#else - case 6: case 7: cpu_abort(env, "VSHL.64 not implemented"); -#endif - } + GEN_NEON_INTEGER_OP(shl); break; case 9: /* VQSHL */ - switch ((size << 1) | u) { - case 0: gen_op_neon_qshl_s8(); break; - case 1: gen_op_neon_qshl_u8(); break; - case 2: gen_op_neon_qshl_s16(); break; - case 3: gen_op_neon_qshl_u16(); break; - case 4: gen_op_neon_qshl_s32(); break; - case 5: gen_op_neon_qshl_u32(); break; -#if 0 - /* ??? Implementing these is tricky because the vector ops work - on 32-bit pieces. */ - case 6: gen_op_neon_qshl_s64(); break; - case 7: gen_op_neon_qshl_u64(); break; -#else - case 6: case 7: cpu_abort(env, "VQSHL.64 not implemented"); -#endif - } + GEN_NEON_INTEGER_OP_ENV(qshl); break; case 10: /* VRSHL */ - switch ((size << 1) | u) { - case 0: gen_op_neon_rshl_s8(); break; - case 1: gen_op_neon_rshl_u8(); break; - case 2: gen_op_neon_rshl_s16(); break; - case 3: gen_op_neon_rshl_u16(); break; - case 4: gen_op_neon_rshl_s32(); break; - case 5: gen_op_neon_rshl_u32(); break; -#if 0 - /* ??? Implementing these is tricky because the vector ops work - on 32-bit pieces. */ - case 6: gen_op_neon_rshl_s64(); break; - case 7: gen_op_neon_rshl_u64(); break; -#else - case 6: case 7: cpu_abort(env, "VRSHL.64 not implemented"); -#endif - } + GEN_NEON_INTEGER_OP(rshl); break; case 11: /* VQRSHL */ - switch ((size << 1) | u) { - case 0: gen_op_neon_qrshl_s8(); break; - case 1: gen_op_neon_qrshl_u8(); break; - case 2: gen_op_neon_qrshl_s16(); break; - case 3: gen_op_neon_qrshl_u16(); break; - case 4: gen_op_neon_qrshl_s32(); break; - case 5: gen_op_neon_qrshl_u32(); break; -#if 0 - /* ??? Implementing these is tricky because the vector ops work - on 32-bit pieces. */ - case 6: gen_op_neon_qrshl_s64(); break; - case 7: gen_op_neon_qrshl_u64(); break; -#else - case 6: case 7: cpu_abort(env, "VQRSHL.64 not implemented"); -#endif - } + GEN_NEON_INTEGER_OP_ENV(qrshl); break; case 12: /* VMAX */ GEN_NEON_INTEGER_OP(max); @@ -3325,8 +4293,8 @@ return 1; } else { /* VSUB */ switch (size) { - case 0: gen_op_neon_sub_u8(); break; - case 1: gen_op_neon_sub_u16(); break; + case 0: gen_helper_neon_sub_u8(CPU_T001); break; + case 1: gen_helper_neon_sub_u16(CPU_T001); break; case 2: gen_op_subl_T0_T1(); break; default: return 1; } @@ -3335,46 +4303,41 @@ case 17: if (!u) { /* VTST */ switch (size) { - case 0: gen_op_neon_tst_u8(); break; - case 1: gen_op_neon_tst_u16(); break; - case 2: gen_op_neon_tst_u32(); break; + case 0: gen_helper_neon_tst_u8(CPU_T001); break; + case 1: gen_helper_neon_tst_u16(CPU_T001); break; + case 2: gen_helper_neon_tst_u32(CPU_T001); break; default: return 1; } } else { /* VCEQ */ switch (size) { - case 0: gen_op_neon_ceq_u8(); break; - case 1: gen_op_neon_ceq_u16(); break; - case 2: gen_op_neon_ceq_u32(); break; + case 0: gen_helper_neon_ceq_u8(CPU_T001); break; + case 1: gen_helper_neon_ceq_u16(CPU_T001); break; + case 2: gen_helper_neon_ceq_u32(CPU_T001); break; default: return 1; } } break; case 18: /* Multiply. */ switch (size) { - case 0: gen_op_neon_mul_u8(); break; - case 1: gen_op_neon_mul_u16(); break; + case 0: gen_helper_neon_mul_u8(CPU_T001); break; + case 1: gen_helper_neon_mul_u16(CPU_T001); break; case 2: gen_op_mul_T0_T1(); break; default: return 1; } NEON_GET_REG(T1, rd, pass); if (u) { /* VMLS */ - switch (size) { - case 0: gen_op_neon_rsb_u8(); break; - case 1: gen_op_neon_rsb_u16(); break; - case 2: gen_op_rsbl_T0_T1(); break; - default: return 1; - } + gen_neon_rsb(size); } else { /* VMLA */ gen_neon_add(size); } break; case 19: /* VMUL */ if (u) { /* polynomial */ - gen_op_neon_mul_p8(); + gen_helper_neon_mul_p8(CPU_T001); } else { /* Integer */ switch (size) { - case 0: gen_op_neon_mul_u8(); break; - case 1: gen_op_neon_mul_u16(); break; + case 0: gen_helper_neon_mul_u8(CPU_T001); break; + case 1: gen_helper_neon_mul_u16(CPU_T001); break; case 2: gen_op_mul_T0_T1(); break; default: return 1; } @@ -3389,14 +4352,14 @@ case 22: /* Hultiply high. */ if (!u) { /* VQDMULH */ switch (size) { - case 1: gen_op_neon_qdmulh_s16(); break; - case 2: gen_op_neon_qdmulh_s32(); break; + case 1: gen_helper_neon_qdmulh_s16(CPU_T0E01); break; + case 2: gen_helper_neon_qdmulh_s32(CPU_T0E01); break; default: return 1; } } else { /* VQRDHMUL */ switch (size) { - case 1: gen_op_neon_qrdmulh_s16(); break; - case 2: gen_op_neon_qrdmulh_s32(); break; + case 1: gen_helper_neon_qrdmulh_s16(CPU_T0E01); break; + case 2: gen_helper_neon_qrdmulh_s32(CPU_T0E01); break; default: return 1; } } @@ -3405,8 +4368,8 @@ if (u) return 1; switch (size) { - case 0: gen_op_neon_padd_u8(); break; - case 1: gen_op_neon_padd_u16(); break; + case 0: gen_helper_neon_padd_u8(CPU_T001); break; + case 1: gen_helper_neon_padd_u16(CPU_T001); break; case 2: gen_op_addl_T0_T1(); break; default: return 1; } @@ -3414,61 +4377,61 @@ case 26: /* Floating point arithnetic. */ switch ((u << 2) | size) { case 0: /* VADD */ - gen_op_neon_add_f32(); + gen_helper_neon_add_f32(CPU_T001); break; case 2: /* VSUB */ - gen_op_neon_sub_f32(); + gen_helper_neon_sub_f32(CPU_T001); break; case 4: /* VPADD */ - gen_op_neon_add_f32(); + gen_helper_neon_add_f32(CPU_T001); break; case 6: /* VABD */ - gen_op_neon_abd_f32(); + gen_helper_neon_abd_f32(CPU_T001); break; default: return 1; } break; case 27: /* Float multiply. */ - gen_op_neon_mul_f32(); + gen_helper_neon_mul_f32(CPU_T001); if (!u) { NEON_GET_REG(T1, rd, pass); if (size == 0) { - gen_op_neon_add_f32(); + gen_helper_neon_add_f32(CPU_T001); } else { - gen_op_neon_rsb_f32(); + gen_helper_neon_sub_f32(cpu_T[0], cpu_T[1], cpu_T[0]); } } break; case 28: /* Float compare. */ if (!u) { - gen_op_neon_ceq_f32(); + gen_helper_neon_ceq_f32(CPU_T001); } else { if (size == 0) - gen_op_neon_cge_f32(); + gen_helper_neon_cge_f32(CPU_T001); else - gen_op_neon_cgt_f32(); + gen_helper_neon_cgt_f32(CPU_T001); } break; case 29: /* Float compare absolute. */ if (!u) return 1; if (size == 0) - gen_op_neon_acge_f32(); + gen_helper_neon_acge_f32(CPU_T001); else - gen_op_neon_acgt_f32(); + gen_helper_neon_acgt_f32(CPU_T001); break; case 30: /* Float min/max. */ if (size == 0) - gen_op_neon_max_f32(); + gen_helper_neon_max_f32(CPU_T001); else - gen_op_neon_min_f32(); + gen_helper_neon_min_f32(CPU_T001); break; case 31: if (size == 0) - gen_op_neon_recps_f32(); + gen_helper_recps_f32(cpu_T[0], cpu_T[0], cpu_T[1], cpu_env); else - gen_op_neon_rsqrts_f32(); + gen_helper_rsqrts_f32(cpu_T[0], cpu_T[0], cpu_T[1], cpu_env); break; default: abort(); @@ -3489,6 +4452,7 @@ NEON_SET_REG(T0, rd, pass); } } + /* End of 3 register same size operations. */ } else if (insn & (1 << 4)) { if ((insn & 0x00380080) != 0) { /* Two registers and shift. */ @@ -3511,8 +4475,6 @@ element size in bits. */ if (op <= 4) shift = shift - (1 << (size + 3)); - else - shift++; if (size == 3) { count = q + 1; } else { @@ -3537,197 +4499,235 @@ } for (pass = 0; pass < count; pass++) { - if (size < 3) { - /* Operands in T0 and T1. */ - gen_op_movl_T1_im(imm); - NEON_GET_REG(T0, rm, pass); - } else { - /* Operands in {T0, T1} and env->vfp.scratch. */ - gen_op_movl_T0_im(imm); - gen_neon_movl_scratch_T0(0); - gen_op_movl_T0_im((int32_t)imm >> 31); - gen_neon_movl_scratch_T0(1); - NEON_GET_REG(T0, rm, pass * 2); - NEON_GET_REG(T1, rm, pass * 2 + 1); - } - - if (gen_neon_shift_im[op][u][size] == NULL) - return 1; - gen_neon_shift_im[op][u][size](); - - if (op == 1 || op == 3) { - /* Accumulate. */ - if (size == 3) { - gen_neon_movl_scratch_T0(0); - gen_neon_movl_scratch_T1(1); - NEON_GET_REG(T0, rd, pass * 2); - NEON_GET_REG(T1, rd, pass * 2 + 1); - gen_op_neon_addl_u64(); - } else { - NEON_GET_REG(T1, rd, pass); - gen_neon_add(size); - } - } else if (op == 4 || (op == 5 && u)) { - /* Insert */ - if (size == 3) { - cpu_abort(env, "VS[LR]I.64 not implemented"); - } - switch (size) { - case 0: - if (op == 4) - imm = 0xff >> -shift; + if (size == 3) { + neon_load_reg64(cpu_V0, rm + pass); + tcg_gen_movi_i64(cpu_V1, imm); + switch (op) { + case 0: /* VSHR */ + case 1: /* VSRA */ + if (u) + gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1); else - imm = (uint8_t)(0xff << shift); - imm |= imm << 8; - imm |= imm << 16; + gen_helper_neon_shl_s64(cpu_V0, cpu_V0, cpu_V1); break; - case 1: - if (op == 4) - imm = 0xffff >> -shift; + case 2: /* VRSHR */ + case 3: /* VRSRA */ + if (u) + gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, cpu_V1); else - imm = (uint16_t)(0xffff << shift); - imm |= imm << 16; + gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1); break; - case 2: - if (op == 4) - imm = 0xffffffffu >> -shift; + case 4: /* VSRI */ + if (!u) + return 1; + gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1); + break; + case 5: /* VSHL, VSLI */ + gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1); + break; + case 6: /* VQSHL */ + if (u) + gen_helper_neon_qshl_u64(cpu_V0, cpu_env, cpu_V0, cpu_V1); else - imm = 0xffffffffu << shift; + gen_helper_neon_qshl_s64(cpu_V0, cpu_env, cpu_V0, cpu_V1); + break; + case 7: /* VQSHLU */ + gen_helper_neon_qshl_u64(cpu_V0, cpu_env, cpu_V0, cpu_V1); break; - default: - abort(); } - NEON_GET_REG(T1, rd, pass); - gen_op_movl_T2_im(imm); - gen_op_neon_bsl(); - } - if (size == 3) { - NEON_SET_REG(T0, rd, pass * 2); - NEON_SET_REG(T1, rd, pass * 2 + 1); - } else { + if (op == 1 || op == 3) { + /* Accumulate. */ + neon_load_reg64(cpu_V0, rd + pass); + tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1); + } else if (op == 4 || (op == 5 && u)) { + /* Insert */ + cpu_abort(env, "VS[LR]I.64 not implemented"); + } + neon_store_reg64(cpu_V0, rd + pass); + } else { /* size < 3 */ + /* Operands in T0 and T1. */ + gen_op_movl_T1_im(imm); + NEON_GET_REG(T0, rm, pass); + switch (op) { + case 0: /* VSHR */ + case 1: /* VSRA */ + GEN_NEON_INTEGER_OP(shl); + break; + case 2: /* VRSHR */ + case 3: /* VRSRA */ + GEN_NEON_INTEGER_OP(rshl); + break; + case 4: /* VSRI */ + if (!u) + return 1; + GEN_NEON_INTEGER_OP(shl); + break; + case 5: /* VSHL, VSLI */ + switch (size) { + case 0: gen_helper_neon_shl_u8(CPU_T001); break; + case 1: gen_helper_neon_shl_u16(CPU_T001); break; + case 2: gen_helper_neon_shl_u32(CPU_T001); break; + default: return 1; + } + break; + case 6: /* VQSHL */ + GEN_NEON_INTEGER_OP_ENV(qshl); + break; + case 7: /* VQSHLU */ + switch (size) { + case 0: gen_helper_neon_qshl_u8(CPU_T0E01); break; + case 1: gen_helper_neon_qshl_u16(CPU_T0E01); break; + case 2: gen_helper_neon_qshl_u32(CPU_T0E01); break; + default: return 1; + } + break; + } + + if (op == 1 || op == 3) { + /* Accumulate. */ + NEON_GET_REG(T1, rd, pass); + gen_neon_add(size); + } else if (op == 4 || (op == 5 && u)) { + /* Insert */ + switch (size) { + case 0: + if (op == 4) + imm = 0xff >> -shift; + else + imm = (uint8_t)(0xff << shift); + imm |= imm << 8; + imm |= imm << 16; + break; + case 1: + if (op == 4) + imm = 0xffff >> -shift; + else + imm = (uint16_t)(0xffff << shift); + imm |= imm << 16; + break; + case 2: + if (op == 4) + imm = 0xffffffffu >> -shift; + else + imm = 0xffffffffu << shift; + break; + default: + abort(); + } + tmp = neon_load_reg(rd, pass); + tcg_gen_andi_i32(cpu_T[0], cpu_T[0], imm); + tcg_gen_andi_i32(tmp, tmp, ~imm); + tcg_gen_or_i32(cpu_T[0], cpu_T[0], tmp); + } NEON_SET_REG(T0, rd, pass); } } /* for pass */ } else if (op < 10) { - /* Shift by immedaiate and narrow: + /* Shift by immediate and narrow: VSHRN, VRSHRN, VQSHRN, VQRSHRN. */ shift = shift - (1 << (size + 3)); size++; - if (size == 3) { - count = q + 1; - } else { - count = q ? 4: 2; - } switch (size) { case 1: - imm = (uint16_t) shift; + imm = (uint16_t)shift; imm |= imm << 16; + tmp2 = tcg_const_i32(imm); break; case 2: + imm = (uint32_t)shift; + tmp2 = tcg_const_i32(imm); case 3: - imm = shift; + tmp2 = tcg_const_i64(shift); break; default: abort(); } - /* Processing MSB first means we need to do less shuffling at - the end. */ - for (pass = count - 1; pass >= 0; pass--) { - /* Avoid clobbering the second operand before it has been - written. */ - n = pass; - if (rd == rm) - n ^= (count - 1); - else - n = pass; - - if (size < 3) { - /* Operands in T0 and T1. */ - gen_op_movl_T1_im(imm); - NEON_GET_REG(T0, rm, n); + for (pass = 0; pass < 2; pass++) { + if (size == 3) { + neon_load_reg64(cpu_V0, rm + pass); + if (q) { + if (u) + gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, tmp2); + else + gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, tmp2); + } else { + if (u) + gen_helper_neon_shl_u64(cpu_V0, cpu_V0, tmp2); + else + gen_helper_neon_shl_s64(cpu_V0, cpu_V0, tmp2); + } + } else { + tmp = neon_load_reg(rm + pass, 0); + gen_neon_shift_narrow(size, tmp, tmp2, q, u); + tmp3 = neon_load_reg(rm + pass, 1); + gen_neon_shift_narrow(size, tmp3, tmp2, q, u); + tcg_gen_concat_i32_i64(cpu_V0, tmp, tmp3); + dead_tmp(tmp); + dead_tmp(tmp3); + } + tmp = new_tmp(); + if (op == 8 && !u) { + gen_neon_narrow(size - 1, tmp, cpu_V0); } else { - /* Operands in {T0, T1} and env->vfp.scratch. */ - gen_op_movl_T0_im(imm); - gen_neon_movl_scratch_T0(0); - gen_op_movl_T0_im((int32_t)imm >> 31); - gen_neon_movl_scratch_T0(1); - NEON_GET_REG(T0, rm, n * 2); - NEON_GET_REG(T0, rm, n * 2 + 1); + if (op == 8) + gen_neon_narrow_sats(size - 1, tmp, cpu_V0); + else + gen_neon_narrow_satu(size - 1, tmp, cpu_V0); } - - gen_neon_shift_im_narrow[q][u][size - 1](); - - if (size < 3 && (pass & 1) == 0) { - gen_neon_movl_scratch_T0(0); + if (pass == 0) { + tmp2 = tmp; } else { - uint32_t offset; - - if (size < 3) - gen_neon_movl_T1_scratch(0); - - if (op == 8 && !u) { - gen_neon_narrow[size - 1](); - } else { - if (op == 8) - gen_neon_narrow_sats[size - 2](); - else - gen_neon_narrow_satu[size - 1](); - } - if (size == 3) - offset = neon_reg_offset(rd, n); - else - offset = neon_reg_offset(rd, n >> 1); - gen_op_neon_setreg_T0(offset); + neon_store_reg(rd, 0, tmp2); + neon_store_reg(rd, 1, tmp); } } /* for pass */ } else if (op == 10) { /* VSHLL */ - if (q) + if (q || size == 3) return 1; + tmp = neon_load_reg(rm, 0); + tmp2 = neon_load_reg(rm, 1); for (pass = 0; pass < 2; pass++) { - /* Avoid clobbering the input operand. */ - if (rd == rm) - n = 1 - pass; - else - n = pass; + if (pass == 1) + tmp = tmp2; + + gen_neon_widen(cpu_V0, tmp, size, u); - NEON_GET_REG(T0, rm, n); - GEN_NEON_INTEGER_OP(widen); if (shift != 0) { /* The shift is less than the width of the source - type, so in some cases we can just - shift the whole register. */ - if (size == 1 || (size == 0 && u)) { - gen_op_shll_T0_im(shift); - gen_op_shll_T1_im(shift); - } else { - switch (size) { - case 0: gen_op_neon_shll_u16(shift); break; - case 2: gen_op_neon_shll_u64(shift); break; - default: abort(); + type, so we can just shift the whole register. */ + tcg_gen_shli_i64(cpu_V0, cpu_V0, shift); + if (size < 2 || !u) { + uint64_t imm64; + if (size == 0) { + imm = (0xffu >> (8 - shift)); + imm |= imm << 16; + } else { + imm = 0xffff >> (16 - shift); } + imm64 = imm | (((uint64_t)imm) << 32); + tcg_gen_andi_i64(cpu_V0, cpu_V0, imm64); } } - NEON_SET_REG(T0, rd, n * 2); - NEON_SET_REG(T1, rd, n * 2 + 1); + neon_store_reg64(cpu_V0, rd + pass); } } else if (op == 15 || op == 16) { /* VCVT fixed-point. */ for (pass = 0; pass < (q ? 4 : 2); pass++) { - gen_op_vfp_getreg_F0s(neon_reg_offset(rm, pass)); + tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass)); if (op & 1) { if (u) - gen_op_vfp_ultos(shift); + gen_vfp_ulto(0, shift); else - gen_op_vfp_sltos(shift); + gen_vfp_slto(0, shift); } else { if (u) - gen_op_vfp_touls(shift); + gen_vfp_toul(0, shift); else - gen_op_vfp_tosls(shift); + gen_vfp_tosl(0, shift); } - gen_op_vfp_setreg_F0s(neon_reg_offset(rd, pass)); + tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass)); } } else { return 1; @@ -3782,31 +4782,33 @@ for (pass = 0; pass < (q ? 4 : 2); pass++) { if (op & 1 && op < 12) { - NEON_GET_REG(T0, rd, pass); + tmp = neon_load_reg(rd, pass); if (invert) { /* The immediate value has already been inverted, so BIC becomes AND. */ - gen_op_andl_T0_T1(); + tcg_gen_andi_i32(tmp, tmp, imm); } else { - gen_op_orl_T0_T1(); + tcg_gen_ori_i32(tmp, tmp, imm); } - NEON_SET_REG(T0, rd, pass); } else { + /* VMOV, VMVN. */ + tmp = new_tmp(); if (op == 14 && invert) { - uint32_t tmp; - tmp = 0; + uint32_t val; + val = 0; for (n = 0; n < 4; n++) { if (imm & (1 << (n + (pass & 1) * 4))) - tmp |= 0xff << (n * 8); + val |= 0xff << (n * 8); } - gen_op_movl_T1_im(tmp); + tcg_gen_movi_i32(tmp, val); + } else { + tcg_gen_movi_i32(tmp, imm); } - /* VMOV, VMVN. */ - NEON_SET_REG(T1, rd, pass); } + neon_store_reg(rd, pass, tmp); } } - } else { /* (insn & 0x00800010 == 0x00800010) */ + } else { /* (insn & 0x00800010 == 0x00800000) */ if (size != 3) { op = (insn >> 8) & 0xf; if ((insn & (1 << 6)) == 0) { @@ -3837,96 +4839,86 @@ src1_wide = neon_3reg_wide[op][1]; src2_wide = neon_3reg_wide[op][2]; + if (size == 0 && (op == 9 || op == 11 || op == 13)) + return 1; + /* Avoid overlapping operands. Wide source operands are always aligned so will never overlap with wide destinations in problematic ways. */ - if (rd == rm) { - NEON_GET_REG(T2, rm, 1); - } else if (rd == rn) { - NEON_GET_REG(T2, rn, 1); + if (rd == rm && !src2_wide) { + NEON_GET_REG(T0, rm, 1); + gen_neon_movl_scratch_T0(2); + } else if (rd == rn && !src1_wide) { + NEON_GET_REG(T0, rn, 1); + gen_neon_movl_scratch_T0(2); } + TCGV_UNUSED(tmp3); for (pass = 0; pass < 2; pass++) { - /* Load the second operand into env->vfp.scratch. - Also widen narrow operands. */ - if (pass == 1 && rd == rm) { - if (prewiden) { - gen_op_movl_T0_T2(); + if (src1_wide) { + neon_load_reg64(cpu_V0, rn + pass); + TCGV_UNUSED(tmp); + } else { + if (pass == 1 && rd == rn) { + gen_neon_movl_T0_scratch(2); + tmp = new_tmp(); + tcg_gen_mov_i32(tmp, cpu_T[0]); } else { - gen_op_movl_T1_T2(); + tmp = neon_load_reg(rn, pass); } - } else { - if (src2_wide) { - NEON_GET_REG(T0, rm, pass * 2); - NEON_GET_REG(T1, rm, pass * 2 + 1); - } else { - if (prewiden) { - NEON_GET_REG(T0, rm, pass); - } else { - NEON_GET_REG(T1, rm, pass); - } + if (prewiden) { + gen_neon_widen(cpu_V0, tmp, size, u); } } - if (prewiden && !src2_wide) { - GEN_NEON_INTEGER_OP(widen); - } - if (prewiden || src2_wide) { - gen_neon_movl_scratch_T0(0); - gen_neon_movl_scratch_T1(1); - } - - /* Load the first operand. */ - if (pass == 1 && rd == rn) { - gen_op_movl_T0_T2(); + if (src2_wide) { + neon_load_reg64(cpu_V1, rm + pass); + TCGV_UNUSED(tmp2); } else { - if (src1_wide) { - NEON_GET_REG(T0, rn, pass * 2); - NEON_GET_REG(T1, rn, pass * 2 + 1); + if (pass == 1 && rd == rm) { + gen_neon_movl_T0_scratch(2); + tmp2 = new_tmp(); + tcg_gen_mov_i32(tmp2, cpu_T[0]); } else { - NEON_GET_REG(T0, rn, pass); + tmp2 = neon_load_reg(rm, pass); + } + if (prewiden) { + gen_neon_widen(cpu_V1, tmp2, size, u); } - } - if (prewiden && !src1_wide) { - GEN_NEON_INTEGER_OP(widen); } switch (op) { case 0: case 1: case 4: /* VADDL, VADDW, VADDHN, VRADDHN */ - switch (size) { - case 0: gen_op_neon_addl_u16(); break; - case 1: gen_op_neon_addl_u32(); break; - case 2: gen_op_neon_addl_u64(); break; - default: abort(); - } + gen_neon_addl(size); break; case 2: case 3: case 6: /* VSUBL, VSUBW, VSUBHL, VRSUBHL */ - switch (size) { - case 0: gen_op_neon_subl_u16(); break; - case 1: gen_op_neon_subl_u32(); break; - case 2: gen_op_neon_subl_u64(); break; - default: abort(); - } + gen_neon_subl(size); break; case 5: case 7: /* VABAL, VABDL */ switch ((size << 1) | u) { - case 0: gen_op_neon_abdl_s16(); break; - case 1: gen_op_neon_abdl_u16(); break; - case 2: gen_op_neon_abdl_s32(); break; - case 3: gen_op_neon_abdl_u32(); break; - case 4: gen_op_neon_abdl_s64(); break; - case 5: gen_op_neon_abdl_u64(); break; + case 0: + gen_helper_neon_abdl_s16(cpu_V0, tmp, tmp2); + break; + case 1: + gen_helper_neon_abdl_u16(cpu_V0, tmp, tmp2); + break; + case 2: + gen_helper_neon_abdl_s32(cpu_V0, tmp, tmp2); + break; + case 3: + gen_helper_neon_abdl_u32(cpu_V0, tmp, tmp2); + break; + case 4: + gen_helper_neon_abdl_s64(cpu_V0, tmp, tmp2); + break; + case 5: + gen_helper_neon_abdl_u64(cpu_V0, tmp, tmp2); + break; default: abort(); } + dead_tmp(tmp2); + dead_tmp(tmp); break; case 8: case 9: case 10: case 11: case 12: case 13: /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */ - switch ((size << 1) | u) { - case 0: gen_op_neon_mull_s8(); break; - case 1: gen_op_neon_mull_u8(); break; - case 2: gen_op_neon_mull_s16(); break; - case 3: gen_op_neon_mull_u16(); break; - case 4: gen_op_imull_T0_T1(); break; - case 5: gen_op_mull_T0_T1(); break; - default: abort(); - } + gen_neon_mull(cpu_V0, tmp, tmp2, size, u); break; case 14: /* Polynomial VMULL */ cpu_abort(env, "Polynomial VMULL not implemented"); @@ -3937,72 +4929,71 @@ if (op == 5 || op == 13 || (op >= 8 && op <= 11)) { /* Accumulate. */ if (op == 10 || op == 11) { - switch (size) { - case 0: gen_op_neon_negl_u16(); break; - case 1: gen_op_neon_negl_u32(); break; - case 2: gen_op_neon_negl_u64(); break; - default: abort(); - } + gen_neon_negl(cpu_V0, size); } - gen_neon_movl_scratch_T0(0); - gen_neon_movl_scratch_T1(1); - if (op != 13) { - NEON_GET_REG(T0, rd, pass * 2); - NEON_GET_REG(T1, rd, pass * 2 + 1); + neon_load_reg64(cpu_V1, rd + pass); } switch (op) { case 5: case 8: case 10: /* VABAL, VMLAL, VMLSL */ - switch (size) { - case 0: gen_op_neon_addl_u16(); break; - case 1: gen_op_neon_addl_u32(); break; - case 2: gen_op_neon_addl_u64(); break; - default: abort(); - } + gen_neon_addl(size); break; case 9: case 11: /* VQDMLAL, VQDMLSL */ - switch (size) { - case 1: gen_op_neon_addl_saturate_s32(); break; - case 2: gen_op_neon_addl_saturate_s64(); break; - default: abort(); - } + gen_neon_addl_saturate(cpu_V0, cpu_V0, size); + gen_neon_addl_saturate(cpu_V0, cpu_V1, size); + break; /* Fall through. */ case 13: /* VQDMULL */ - switch (size) { - case 1: gen_op_neon_addl_saturate_s32(); break; - case 2: gen_op_neon_addl_saturate_s64(); break; - default: abort(); - } + gen_neon_addl_saturate(cpu_V0, cpu_V0, size); break; default: abort(); } - NEON_SET_REG(T0, rd, pass * 2); - NEON_SET_REG(T1, rd, pass * 2 + 1); + neon_store_reg64(cpu_V0, rd + pass); } else if (op == 4 || op == 6) { /* Narrowing operation. */ + tmp = new_tmp(); if (u) { switch (size) { - case 0: gen_op_neon_narrow_high_u8(); break; - case 1: gen_op_neon_narrow_high_u16(); break; - case 2: gen_op_movl_T0_T1(); break; + case 0: + gen_helper_neon_narrow_high_u8(tmp, cpu_V0); + break; + case 1: + gen_helper_neon_narrow_high_u16(tmp, cpu_V0); + break; + case 2: + tcg_gen_shri_i64(cpu_V0, cpu_V0, 32); + tcg_gen_trunc_i64_i32(tmp, cpu_V0); + break; default: abort(); } } else { switch (size) { - case 0: gen_op_neon_narrow_high_round_u8(); break; - case 1: gen_op_neon_narrow_high_round_u16(); break; - case 2: gen_op_neon_narrow_high_round_u32(); break; + case 0: + gen_helper_neon_narrow_round_high_u8(tmp, cpu_V0); + break; + case 1: + gen_helper_neon_narrow_round_high_u16(tmp, cpu_V0); + break; + case 2: + tcg_gen_addi_i64(cpu_V0, cpu_V0, 1u << 31); + tcg_gen_shri_i64(cpu_V0, cpu_V0, 32); + tcg_gen_trunc_i64_i32(tmp, cpu_V0); + break; default: abort(); } } - NEON_SET_REG(T0, rd, pass); + if (pass == 0) { + tmp3 = tmp; + } else { + neon_store_reg(rd, 0, tmp3); + neon_store_reg(rd, 1, tmp); + } } else { /* Write back the result. */ - NEON_SET_REG(T0, rd, pass * 2); - NEON_SET_REG(T1, rd, pass * 2 + 1); + neon_store_reg64(cpu_V0, rd + pass); } } } else { @@ -4017,29 +5008,29 @@ case 12: /* VQDMULH scalar */ case 13: /* VQRDMULH scalar */ gen_neon_get_scalar(size, rm); - gen_op_movl_T2_T0(); + gen_neon_movl_scratch_T0(0); for (pass = 0; pass < (u ? 4 : 2); pass++) { if (pass != 0) - gen_op_movl_T0_T2(); + gen_neon_movl_T0_scratch(0); NEON_GET_REG(T1, rn, pass); if (op == 12) { if (size == 1) { - gen_op_neon_qdmulh_s16(); + gen_helper_neon_qdmulh_s16(CPU_T0E01); } else { - gen_op_neon_qdmulh_s32(); + gen_helper_neon_qdmulh_s32(CPU_T0E01); } } else if (op == 13) { if (size == 1) { - gen_op_neon_qrdmulh_s16(); + gen_helper_neon_qrdmulh_s16(CPU_T0E01); } else { - gen_op_neon_qrdmulh_s32(); + gen_helper_neon_qrdmulh_s32(CPU_T0E01); } } else if (op & 1) { - gen_op_neon_mul_f32(); + gen_helper_neon_mul_f32(CPU_T001); } else { switch (size) { - case 0: gen_op_neon_mul_u8(); break; - case 1: gen_op_neon_mul_u16(); break; + case 0: gen_helper_neon_mul_u8(CPU_T001); break; + case 1: gen_helper_neon_mul_u16(CPU_T001); break; case 2: gen_op_mul_T0_T1(); break; default: return 1; } @@ -4052,18 +5043,13 @@ gen_neon_add(size); break; case 1: - gen_op_neon_add_f32(); + gen_helper_neon_add_f32(CPU_T001); break; case 4: - switch (size) { - case 0: gen_op_neon_rsb_u8(); break; - case 1: gen_op_neon_rsb_u16(); break; - case 2: gen_op_rsbl_T0_T1(); break; - default: return 1; - } + gen_neon_rsb(size); break; case 5: - gen_op_neon_rsb_f32(); + gen_helper_neon_sub_f32(cpu_T[0], cpu_T[1], cpu_T[0]); break; default: abort(); @@ -4078,81 +5064,46 @@ case 7: /* VQDMLSL scalar */ case 10: /* VMULL scalar */ case 11: /* VQDMULL scalar */ - if (rd == rn) { - /* Save overlapping operands before they are - clobbered. */ - NEON_GET_REG(T0, rn, 1); - gen_neon_movl_scratch_T0(2); - } + if (size == 0 && (op == 3 || op == 7 || op == 11)) + return 1; + gen_neon_get_scalar(size, rm); - gen_op_movl_T2_T0(); + NEON_GET_REG(T1, rn, 1); + for (pass = 0; pass < 2; pass++) { - if (pass != 0) { - gen_op_movl_T0_T2(); - } - if (pass != 0 && rd == rn) { - gen_neon_movl_T1_scratch(2); + if (pass == 0) { + tmp = neon_load_reg(rn, 0); } else { - NEON_GET_REG(T1, rn, pass); - } - switch ((size << 1) | u) { - case 0: gen_op_neon_mull_s8(); break; - case 1: gen_op_neon_mull_u8(); break; - case 2: gen_op_neon_mull_s16(); break; - case 3: gen_op_neon_mull_u16(); break; - case 4: gen_op_imull_T0_T1(); break; - case 5: gen_op_mull_T0_T1(); break; - default: abort(); + tmp = new_tmp(); + tcg_gen_mov_i32(tmp, cpu_T[1]); } + tmp2 = new_tmp(); + tcg_gen_mov_i32(tmp2, cpu_T[0]); + gen_neon_mull(cpu_V0, tmp, tmp2, size, u); if (op == 6 || op == 7) { - switch (size) { - case 0: gen_op_neon_negl_u16(); break; - case 1: gen_op_neon_negl_u32(); break; - case 2: gen_op_neon_negl_u64(); break; - default: abort(); - } + gen_neon_negl(cpu_V0, size); + } + if (op != 11) { + neon_load_reg64(cpu_V1, rd + pass); } - gen_neon_movl_scratch_T0(0); - gen_neon_movl_scratch_T1(1); - NEON_GET_REG(T0, rd, pass * 2); - NEON_GET_REG(T1, rd, pass * 2 + 1); switch (op) { case 2: case 6: - switch (size) { - case 0: gen_op_neon_addl_u16(); break; - case 1: gen_op_neon_addl_u32(); break; - case 2: gen_op_neon_addl_u64(); break; - default: abort(); - } + gen_neon_addl(size); break; case 3: case 7: - switch (size) { - case 1: - gen_op_neon_addl_saturate_s32(); - gen_op_neon_addl_saturate_s32(); - break; - case 2: - gen_op_neon_addl_saturate_s64(); - gen_op_neon_addl_saturate_s64(); - break; - default: abort(); - } + gen_neon_addl_saturate(cpu_V0, cpu_V0, size); + gen_neon_addl_saturate(cpu_V0, cpu_V1, size); break; case 10: /* no-op */ break; case 11: - switch (size) { - case 1: gen_op_neon_addl_saturate_s32(); break; - case 2: gen_op_neon_addl_saturate_s64(); break; - default: abort(); - } + gen_neon_addl_saturate(cpu_V0, cpu_V0, size); break; default: abort(); } - NEON_SET_REG(T0, rd, pass * 2); - NEON_SET_REG(T1, rd, pass * 2 + 1); + neon_store_reg64(cpu_V0, rd + pass); } break; default: /* 14 and 15 are RESERVED */ @@ -4162,29 +5113,53 @@ } else { /* size == 3 */ if (!u) { /* Extract. */ - int reg; imm = (insn >> 8) & 0xf; - reg = rn; - count = q ? 4 : 2; - n = imm >> 2; - NEON_GET_REG(T0, reg, n); - for (pass = 0; pass < count; pass++) { - n++; - if (n > count) { - reg = rm; - n -= count; - } - if (imm & 3) { - NEON_GET_REG(T1, reg, n); - gen_op_neon_extract((insn << 3) & 0x1f); + count = q + 1; + + if (imm > 7 && !q) + return 1; + + if (imm == 0) { + neon_load_reg64(cpu_V0, rn); + if (q) { + neon_load_reg64(cpu_V1, rn + 1); } - /* ??? This is broken if rd and rm overlap */ - NEON_SET_REG(T0, rd, pass); - if (imm & 3) { - gen_op_movl_T0_T1(); - } else { - NEON_GET_REG(T0, reg, n); + } else if (imm == 8) { + neon_load_reg64(cpu_V0, rn + 1); + if (q) { + neon_load_reg64(cpu_V1, rm); } + } else if (q) { + tmp = tcg_temp_new(TCG_TYPE_I64); + if (imm < 8) { + neon_load_reg64(cpu_V0, rn); + neon_load_reg64(tmp, rn + 1); + } else { + neon_load_reg64(cpu_V0, rn + 1); + neon_load_reg64(tmp, rm); + } + tcg_gen_shri_i64(cpu_V0, cpu_V0, (imm & 7) * 8); + tcg_gen_shli_i64(cpu_V1, tmp, 64 - ((imm & 7) * 8)); + tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1); + if (imm < 8) { + neon_load_reg64(cpu_V1, rm); + } else { + neon_load_reg64(cpu_V1, rm + 1); + imm -= 8; + } + tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8)); + tcg_gen_shri_i64(tmp, tmp, imm * 8); + tcg_gen_or_i64(cpu_V1, cpu_V1, tmp); + } else { + neon_load_reg64(cpu_V0, rn); + tcg_gen_shri_i32(cpu_V0, cpu_V0, imm * 8); + neon_load_reg64(cpu_V1, rm); + tcg_gen_shli_i32(cpu_V1, cpu_V1, 64 - (imm * 8)); + tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1); + } + neon_store_reg64(cpu_V0, rd); + if (q) { + neon_store_reg64(cpu_V1, rd + 1); } } else if ((insn & (1 << 11)) == 0) { /* Two register misc. */ @@ -4198,8 +5173,8 @@ NEON_GET_REG(T0, rm, pass * 2); NEON_GET_REG(T1, rm, pass * 2 + 1); switch (size) { - case 0: gen_op_rev_T0(); break; - case 1: gen_op_revh_T0(); break; + case 0: tcg_gen_bswap_i32(cpu_T[0], cpu_T[0]); break; + case 1: gen_swap_half(cpu_T[0]); break; case 2: /* no-op */ break; default: abort(); } @@ -4209,8 +5184,8 @@ } else { gen_op_movl_T0_T1(); switch (size) { - case 0: gen_op_rev_T0(); break; - case 1: gen_op_revh_T0(); break; + case 0: tcg_gen_bswap_i32(cpu_T[0], cpu_T[0]); break; + case 1: gen_swap_half(cpu_T[0]); break; default: abort(); } NEON_SET_REG(T0, rd, pass * 2); @@ -4219,28 +5194,25 @@ break; case 4: case 5: /* VPADDL */ case 12: case 13: /* VPADAL */ - if (size < 2) - goto elementwise; if (size == 3) return 1; - for (pass = 0; pass < (q ? 2 : 1); pass++) { - NEON_GET_REG(T0, rm, pass * 2); - NEON_GET_REG(T1, rm, pass * 2 + 1); - if (op & 1) - gen_op_neon_paddl_u32(); - else - gen_op_neon_paddl_s32(); + for (pass = 0; pass < q + 1; pass++) { + tmp = neon_load_reg(rm, pass * 2); + gen_neon_widen(cpu_V0, tmp, size, op & 1); + tmp = neon_load_reg(rm, pass * 2 + 1); + gen_neon_widen(cpu_V1, tmp, size, op & 1); + switch (size) { + case 0: gen_helper_neon_paddl_u16(CPU_V001); break; + case 1: gen_helper_neon_paddl_u32(CPU_V001); break; + case 2: tcg_gen_add_i64(CPU_V001); break; + default: abort(); + } if (op >= 12) { /* Accumulate. */ - gen_neon_movl_scratch_T0(0); - gen_neon_movl_scratch_T1(1); - - NEON_GET_REG(T0, rd, pass * 2); - NEON_GET_REG(T1, rd, pass * 2 + 1); - gen_op_neon_addl_u64(); + neon_load_reg64(cpu_V1, rd + pass); + gen_neon_addl(size); } - NEON_SET_REG(T0, rd, pass * 2); - NEON_SET_REG(T1, rd, pass * 2 + 1); + neon_store_reg64(cpu_V0, rd + pass); } break; case 33: /* VTRN */ @@ -4294,8 +5266,8 @@ NEON_GET_REG(T0, rd, n); NEON_GET_REG(T1, rd, n); switch (size) { - case 0: gen_op_neon_zip_u8(); break; - case 1: gen_op_neon_zip_u16(); break; + case 0: gen_helper_neon_zip_u8(); break; + case 1: gen_helper_neon_zip_u16(); break; case 2: /* no-op */; break; default: abort(); } @@ -4309,124 +5281,81 @@ } break; case 36: case 37: /* VMOVN, VQMOVUN, VQMOVN */ + if (size == 3) + return 1; + TCGV_UNUSED(tmp2); for (pass = 0; pass < 2; pass++) { - if (rd == rm + 1) { - n = 1 - pass; - } else { - n = pass; - } - NEON_GET_REG(T0, rm, n * 2); - NEON_GET_REG(T1, rm, n * 2 + 1); + neon_load_reg64(cpu_V0, rm + pass); + tmp = new_tmp(); if (op == 36 && q == 0) { - switch (size) { - case 0: gen_op_neon_narrow_u8(); break; - case 1: gen_op_neon_narrow_u16(); break; - case 2: /* no-op */ break; - default: return 1; - } + gen_neon_narrow(size, tmp, cpu_V0); } else if (q) { - switch (size) { - case 0: gen_op_neon_narrow_sat_u8(); break; - case 1: gen_op_neon_narrow_sat_u16(); break; - case 2: gen_op_neon_narrow_sat_u32(); break; - default: return 1; - } + gen_neon_narrow_satu(size, tmp, cpu_V0); } else { - switch (size) { - case 0: gen_op_neon_narrow_sat_s8(); break; - case 1: gen_op_neon_narrow_sat_s16(); break; - case 2: gen_op_neon_narrow_sat_s32(); break; - default: return 1; - } + gen_neon_narrow_sats(size, tmp, cpu_V0); + } + if (pass == 0) { + tmp2 = tmp; + } else { + neon_store_reg(rd, 0, tmp2); + neon_store_reg(rd, 1, tmp); } - NEON_SET_REG(T0, rd, n); } break; case 38: /* VSHLL */ - if (q) + if (q || size == 3) return 1; - if (rm == rd) { - NEON_GET_REG(T2, rm, 1); - } + tmp = neon_load_reg(rm, 0); + tmp2 = neon_load_reg(rm, 1); for (pass = 0; pass < 2; pass++) { - if (pass == 1 && rm == rd) { - gen_op_movl_T0_T2(); - } else { - NEON_GET_REG(T0, rm, pass); - } - switch (size) { - case 0: gen_op_neon_widen_high_u8(); break; - case 1: gen_op_neon_widen_high_u16(); break; - case 2: - gen_op_movl_T1_T0(); - gen_op_movl_T0_im(0); - break; - default: return 1; - } - NEON_SET_REG(T0, rd, pass * 2); - NEON_SET_REG(T1, rd, pass * 2 + 1); + if (pass == 1) + tmp = tmp2; + gen_neon_widen(cpu_V0, tmp, size, 1); + neon_store_reg64(cpu_V0, rd + pass); } break; default: elementwise: for (pass = 0; pass < (q ? 4 : 2); pass++) { if (op == 30 || op == 31 || op >= 58) { - gen_op_vfp_getreg_F0s(neon_reg_offset(rm, pass)); + tcg_gen_ld_f32(cpu_F0s, cpu_env, + neon_reg_offset(rm, pass)); } else { NEON_GET_REG(T0, rm, pass); } switch (op) { case 1: /* VREV32 */ switch (size) { - case 0: gen_op_rev_T0(); break; - case 1: gen_op_revh_T0(); break; + case 0: tcg_gen_bswap_i32(cpu_T[0], cpu_T[0]); break; + case 1: gen_swap_half(cpu_T[0]); break; default: return 1; } break; case 2: /* VREV16 */ if (size != 0) return 1; - gen_op_rev16_T0(); - break; - case 4: case 5: /* VPADDL */ - case 12: case 13: /* VPADAL */ - switch ((size << 1) | (op & 1)) { - case 0: gen_op_neon_paddl_s8(); break; - case 1: gen_op_neon_paddl_u8(); break; - case 2: gen_op_neon_paddl_s16(); break; - case 3: gen_op_neon_paddl_u16(); break; - default: abort(); - } - if (op >= 12) { - /* Accumulate */ - NEON_GET_REG(T1, rd, pass); - switch (size) { - case 0: gen_op_neon_add_u16(); break; - case 1: gen_op_addl_T0_T1(); break; - default: abort(); - } - } + gen_rev16(cpu_T[0]); break; case 8: /* CLS */ switch (size) { - case 0: gen_op_neon_cls_s8(); break; - case 1: gen_op_neon_cls_s16(); break; - case 2: gen_op_neon_cls_s32(); break; + case 0: gen_helper_neon_cls_s8(cpu_T[0], cpu_T[0]); break; + case 1: gen_helper_neon_cls_s16(cpu_T[0], cpu_T[0]); break; + case 2: gen_helper_neon_cls_s32(cpu_T[0], cpu_T[0]); break; default: return 1; } break; case 9: /* CLZ */ switch (size) { - case 0: gen_op_neon_clz_u8(); break; - case 1: gen_op_neon_clz_u16(); break; - case 2: gen_op_clz_T0(); break; + case 0: gen_helper_neon_clz_u8(cpu_T[0], cpu_T[0]); break; + case 1: gen_helper_neon_clz_u16(cpu_T[0], cpu_T[0]); break; + case 2: gen_helper_clz(cpu_T[0], cpu_T[0]); break; default: return 1; } break; case 10: /* CNT */ if (size != 0) return 1; - gen_op_neon_cnt_u8(); + gen_helper_neon_cnt_u8(cpu_T[0], cpu_T[0]); break; case 11: /* VNOT */ if (size != 0) @@ -4435,26 +5364,26 @@ break; case 14: /* VQABS */ switch (size) { - case 0: gen_op_neon_qabs_s8(); break; - case 1: gen_op_neon_qabs_s16(); break; - case 2: gen_op_neon_qabs_s32(); break; + case 0: gen_helper_neon_qabs_s8(cpu_T[0], cpu_env, cpu_T[0]); break; + case 1: gen_helper_neon_qabs_s16(cpu_T[0], cpu_env, cpu_T[0]); break; + case 2: gen_helper_neon_qabs_s32(cpu_T[0], cpu_env, cpu_T[0]); break; default: return 1; } break; case 15: /* VQNEG */ switch (size) { - case 0: gen_op_neon_qneg_s8(); break; - case 1: gen_op_neon_qneg_s16(); break; - case 2: gen_op_neon_qneg_s32(); break; + case 0: gen_helper_neon_qneg_s8(cpu_T[0], cpu_env, cpu_T[0]); break; + case 1: gen_helper_neon_qneg_s16(cpu_T[0], cpu_env, cpu_T[0]); break; + case 2: gen_helper_neon_qneg_s32(cpu_T[0], cpu_env, cpu_T[0]); break; default: return 1; } break; case 16: case 19: /* VCGT #0, VCLE #0 */ gen_op_movl_T1_im(0); switch(size) { - case 0: gen_op_neon_cgt_s8(); break; - case 1: gen_op_neon_cgt_s16(); break; - case 2: gen_op_neon_cgt_s32(); break; + case 0: gen_helper_neon_cgt_s8(CPU_T001); break; + case 1: gen_helper_neon_cgt_s16(CPU_T001); break; + case 2: gen_helper_neon_cgt_s32(CPU_T001); break; default: return 1; } if (op == 19) @@ -4463,9 +5392,9 @@ case 17: case 20: /* VCGE #0, VCLT #0 */ gen_op_movl_T1_im(0); switch(size) { - case 0: gen_op_neon_cge_s8(); break; - case 1: gen_op_neon_cge_s16(); break; - case 2: gen_op_neon_cge_s32(); break; + case 0: gen_helper_neon_cge_s8(CPU_T001); break; + case 1: gen_helper_neon_cge_s16(CPU_T001); break; + case 2: gen_helper_neon_cge_s32(CPU_T001); break; default: return 1; } if (op == 20) @@ -4474,50 +5403,47 @@ case 18: /* VCEQ #0 */ gen_op_movl_T1_im(0); switch(size) { - case 0: gen_op_neon_ceq_u8(); break; - case 1: gen_op_neon_ceq_u16(); break; - case 2: gen_op_neon_ceq_u32(); break; + case 0: gen_helper_neon_ceq_u8(CPU_T001); break; + case 1: gen_helper_neon_ceq_u16(CPU_T001); break; + case 2: gen_helper_neon_ceq_u32(CPU_T001); break; default: return 1; } break; case 22: /* VABS */ switch(size) { - case 0: gen_op_neon_abs_s8(); break; - case 1: gen_op_neon_abs_s16(); break; - case 2: gen_op_neon_abs_s32(); break; + case 0: gen_helper_neon_abs_s8(cpu_T[0], cpu_T[0]); break; + case 1: gen_helper_neon_abs_s16(cpu_T[0], cpu_T[0]); break; + case 2: tcg_gen_abs_i32(cpu_T[0], cpu_T[0]); break; default: return 1; } break; case 23: /* VNEG */ gen_op_movl_T1_im(0); - switch(size) { - case 0: gen_op_neon_rsb_u8(); break; - case 1: gen_op_neon_rsb_u16(); break; - case 2: gen_op_rsbl_T0_T1(); break; - default: return 1; - } + if (size == 3) + return 1; + gen_neon_rsb(size); break; case 24: case 27: /* Float VCGT #0, Float VCLE #0 */ gen_op_movl_T1_im(0); - gen_op_neon_cgt_f32(); + gen_helper_neon_cgt_f32(CPU_T001); if (op == 27) gen_op_notl_T0(); break; case 25: case 28: /* Float VCGE #0, Float VCLT #0 */ gen_op_movl_T1_im(0); - gen_op_neon_cge_f32(); + gen_helper_neon_cge_f32(CPU_T001); if (op == 28) gen_op_notl_T0(); break; case 26: /* Float VCEQ #0 */ gen_op_movl_T1_im(0); - gen_op_neon_ceq_f32(); + gen_helper_neon_ceq_f32(CPU_T001); break; case 30: /* Float VABS */ - gen_op_vfp_abss(); + gen_vfp_abs(0); break; case 31: /* Float VNEG */ - gen_op_vfp_negs(); + gen_vfp_neg(0); break; case 32: /* VSWP */ NEON_GET_REG(T1, rd, pass); @@ -4526,43 +5452,44 @@ case 33: /* VTRN */ NEON_GET_REG(T1, rd, pass); switch (size) { - case 0: gen_op_neon_trn_u8(); break; - case 1: gen_op_neon_trn_u16(); break; + case 0: gen_helper_neon_trn_u8(); break; + case 1: gen_helper_neon_trn_u16(); break; case 2: abort(); default: return 1; } NEON_SET_REG(T1, rm, pass); break; case 56: /* Integer VRECPE */ - gen_op_neon_recpe_u32(); + gen_helper_recpe_u32(cpu_T[0], cpu_T[0], cpu_env); break; case 57: /* Integer VRSQRTE */ - gen_op_neon_rsqrte_u32(); + gen_helper_rsqrte_u32(cpu_T[0], cpu_T[0], cpu_env); break; case 58: /* Float VRECPE */ - gen_op_neon_recpe_f32(); + gen_helper_recpe_f32(cpu_F0s, cpu_F0s, cpu_env); break; case 59: /* Float VRSQRTE */ - gen_op_neon_rsqrte_f32(); + gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env); break; case 60: /* VCVT.F32.S32 */ - gen_op_vfp_tosizs(); + gen_vfp_tosiz(0); break; case 61: /* VCVT.F32.U32 */ - gen_op_vfp_touizs(); + gen_vfp_touiz(0); break; case 62: /* VCVT.S32.F32 */ - gen_op_vfp_sitos(); + gen_vfp_sito(0); break; case 63: /* VCVT.U32.F32 */ - gen_op_vfp_uitos(); + gen_vfp_uito(0); break; default: /* Reserved: 21, 29, 39-56 */ return 1; } if (op == 30 || op == 31 || op >= 58) { - gen_op_vfp_setreg_F0s(neon_reg_offset(rm, pass)); + tcg_gen_st_f32(cpu_F0s, cpu_env, + neon_reg_offset(rd, pass)); } else { NEON_SET_REG(T0, rd, pass); } @@ -4571,24 +5498,29 @@ } } else if ((insn & (1 << 10)) == 0) { /* VTBL, VTBX. */ - n = (insn >> 5) & 0x18; - NEON_GET_REG(T1, rm, 0); + n = ((insn >> 5) & 0x18) + 8; if (insn & (1 << 6)) { - NEON_GET_REG(T0, rd, 0); + tmp = neon_load_reg(rd, 0); } else { - gen_op_movl_T0_im(0); + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); } - gen_op_neon_tbl(rn, n); - gen_op_movl_T2_T0(); - NEON_GET_REG(T1, rm, 1); + tmp2 = neon_load_reg(rm, 0); + gen_helper_neon_tbl(tmp2, tmp2, tmp, tcg_const_i32(rn), + tcg_const_i32(n)); + dead_tmp(tmp); if (insn & (1 << 6)) { - NEON_GET_REG(T0, rd, 0); + tmp = neon_load_reg(rd, 1); } else { - gen_op_movl_T0_im(0); + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); } - gen_op_neon_tbl(rn, n); - NEON_SET_REG(T2, rd, 0); - NEON_SET_REG(T0, rd, 1); + tmp3 = neon_load_reg(rm, 1); + gen_helper_neon_tbl(tmp3, tmp3, tmp, tcg_const_i32(rn), + tcg_const_i32(n)); + neon_store_reg(rd, 0, tmp2); + neon_store_reg(rd, 1, tmp3); + dead_tmp(tmp); } else if ((insn & 0x380) == 0) { /* VDUP */ if (insn & (1 << 19)) { @@ -4597,12 +5529,12 @@ NEON_SET_REG(T0, rm, 0); } if (insn & (1 << 16)) { - gen_op_neon_dup_u8(((insn >> 17) & 3) * 8); + gen_neon_dup_u8(cpu_T[0], ((insn >> 17) & 3) * 8); } else if (insn & (1 << 17)) { if ((insn >> 18) & 1) - gen_op_neon_dup_high16(); + gen_neon_dup_high16(cpu_T[0]); else - gen_op_neon_dup_low16(); + gen_neon_dup_low16(cpu_T[0]); } for (pass = 0; pass < (q ? 4 : 2); pass++) { NEON_SET_REG(T0, rd, pass); @@ -4644,9 +5576,67 @@ } } + +/* Store a 64-bit value to a register pair. Clobbers val. */ +static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv val) +{ + TCGv tmp; + tmp = new_tmp(); + tcg_gen_trunc_i64_i32(tmp, val); + store_reg(s, rlow, tmp); + tmp = new_tmp(); + tcg_gen_shri_i64(val, val, 32); + tcg_gen_trunc_i64_i32(tmp, val); + store_reg(s, rhigh, tmp); +} + +/* load a 32-bit value from a register and perform a 64-bit accumulate. */ +static void gen_addq_lo(DisasContext *s, TCGv val, int rlow) +{ + TCGv tmp; + TCGv tmp2; + + /* Load value and extend to 64 bits. */ + tmp = tcg_temp_new(TCG_TYPE_I64); + tmp2 = load_reg(s, rlow); + tcg_gen_extu_i32_i64(tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_add_i64(val, val, tmp); +} + +/* load and add a 64-bit value from a register pair. */ +static void gen_addq(DisasContext *s, TCGv val, int rlow, int rhigh) +{ + TCGv tmp; + TCGv tmpl; + TCGv tmph; + + /* Load 64-bit value rd:rn. */ + tmpl = load_reg(s, rlow); + tmph = load_reg(s, rhigh); + tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_concat_i32_i64(tmp, tmpl, tmph); + dead_tmp(tmpl); + dead_tmp(tmph); + tcg_gen_add_i64(val, val, tmp); +} + +/* Set N and Z flags from a 64-bit value. */ +static void gen_logicq_cc(TCGv val) +{ + TCGv tmp = new_tmp(); + gen_helper_logicq_cc(tmp, val); + gen_logic_CC(tmp); + dead_tmp(tmp); +} + static void disas_arm_insn(CPUState * env, DisasContext *s) { unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; + TCGv tmp; + TCGv tmp2; + TCGv tmp3; + TCGv addr; insn = ldl_code(s->pc); s->pc += 4; @@ -4689,7 +5679,7 @@ switch ((insn >> 4) & 0xf) { case 1: /* clrex */ ARCH(6K); - gen_op_clrex(); + gen_helper_clrex(cpu_env); return; case 4: /* dsb */ case 5: /* dmb */ @@ -4708,9 +5698,10 @@ ARCH(6); op1 = (insn & 0x1f); if (op1 == (env->uncached_cpsr & CPSR_M)) { - gen_movl_T1_reg(s, 13); + addr = load_reg(s, 13); } else { - gen_op_movl_T1_r13_banked(op1); + addr = new_tmp(); + gen_helper_get_r13_banked(addr, cpu_env, tcg_const_i32(op1)); } i = (insn >> 23) & 3; switch (i) { @@ -4721,12 +5712,13 @@ default: abort(); } if (offset) - gen_op_addl_T1_im(offset); - gen_movl_T0_reg(s, 14); - gen_ldst(stl, s); - gen_op_movl_T0_cpsr(); - gen_op_addl_T1_im(4); - gen_ldst(stl, s); + tcg_gen_addi_i32(addr, addr, offset); + tmp = load_reg(s, 14); + gen_st32(tmp, addr, 0); + tmp = new_tmp(); + gen_helper_cpsr_read(tmp); + tcg_gen_addi_i32(addr, addr, 4); + gen_st32(tmp, addr, 0); if (insn & (1 << 21)) { /* Base writeback. */ switch (i) { @@ -4737,12 +5729,14 @@ default: abort(); } if (offset) - gen_op_addl_T1_im(offset); + tcg_gen_addi_i32(addr, tmp, offset); if (op1 == (env->uncached_cpsr & CPSR_M)) { gen_movl_reg_T1(s, 13); } else { - gen_op_movl_r13_T1_banked(op1); + gen_helper_set_r13_banked(cpu_env, tcg_const_i32(op1), cpu_T[1]); } + } else { + dead_tmp(addr); } } else if ((insn & 0x0e5fffe0) == 0x081d0a00) { /* rfe */ @@ -4751,51 +5745,52 @@ goto illegal_op; ARCH(6); rn = (insn >> 16) & 0xf; - gen_movl_T1_reg(s, rn); + addr = load_reg(s, rn); i = (insn >> 23) & 3; switch (i) { - case 0: offset = 0; break; /* DA */ - case 1: offset = -4; break; /* DB */ - case 2: offset = 4; break; /* IA */ - case 3: offset = 8; break; /* IB */ + case 0: offset = -4; break; /* DA */ + case 1: offset = -8; break; /* DB */ + case 2: offset = 0; break; /* IA */ + case 3: offset = 4; break; /* IB */ default: abort(); } if (offset) - gen_op_addl_T1_im(offset); - /* Load CPSR into T2 and PC into T0. */ - gen_ldst(ldl, s); - gen_op_movl_T2_T0(); - gen_op_addl_T1_im(-4); - gen_ldst(ldl, s); + tcg_gen_addi_i32(addr, addr, offset); + /* Load PC into tmp and CPSR into tmp2. */ + tmp = gen_ld32(addr, 0); + tcg_gen_addi_i32(addr, addr, 4); + tmp2 = gen_ld32(addr, 0); if (insn & (1 << 21)) { /* Base writeback. */ switch (i) { - case 0: offset = -4; break; - case 1: offset = 0; break; - case 2: offset = 8; break; - case 3: offset = 4; break; + case 0: offset = -8; break; + case 1: offset = -4; break; + case 2: offset = 4; break; + case 3: offset = 0; break; default: abort(); } if (offset) - gen_op_addl_T1_im(offset); - gen_movl_reg_T1(s, rn); + tcg_gen_addi_i32(addr, addr, offset); + store_reg(s, rn, addr); + } else { + dead_tmp(addr); } - gen_rfe(s); + gen_rfe(s, tmp, tmp2); } else if ((insn & 0x0e000000) == 0x0a000000) { /* branch link and change to thumb (blx ) */ int32_t offset; val = (uint32_t)s->pc; - gen_op_movl_T0_im(val); - gen_movl_reg_T0(s, 14); + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + store_reg(s, 14, tmp); /* Sign-extend the 24-bit offset */ offset = (((int32_t)insn) << 8) >> 8; /* offset * 4 + bit24 * 2 + (thumb bit) */ val += (offset << 2) | ((insn >> 23) & 2) | 1; /* pipeline offset */ val += 4; - gen_op_movl_T0_im(val); - gen_bx(s); + gen_bx_im(s, val); return; } else if ((insn & 0x0e000f00) == 0x0c000100) { if (arm_feature(env, ARM_FEATURE_IWMMXT)) { @@ -4808,7 +5803,7 @@ /* Coprocessor double register transfer. */ } else if ((insn & 0x0f000010) == 0x0e000010) { /* Additional coprocessor register transfer. */ - } else if ((insn & 0x0ff10010) == 0x01000000) { + } else if ((insn & 0x0ff10020) == 0x01000000) { uint32_t mask; uint32_t val; /* cps (privileged) */ @@ -4825,7 +5820,7 @@ if (insn & (1 << 18)) val |= mask; } - if (insn & (1 << 14)) { + if (insn & (1 << 17)) { mask |= CPSR_M; val |= (insn & 0x1f); } @@ -4841,7 +5836,7 @@ /* if not always execute, we generate a conditional jump to next instruction */ s->condlabel = gen_new_label(); - gen_test_cc[cond ^ 1](s->condlabel); + gen_test_cc(cond ^ 1, s->condlabel); s->condjmp = 1; } if ((insn & 0x0f900000) == 0x03000000) { @@ -4851,16 +5846,15 @@ val = ((insn >> 4) & 0xf000) | (insn & 0xfff); if ((insn & (1 << 22)) == 0) { /* MOVW */ - gen_op_movl_T0_im(val); + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); } else { /* MOVT */ - gen_movl_T0_reg(s, rd); - gen_op_movl_T1_im(0xffff); - gen_op_andl_T0_T1(); - gen_op_movl_T1_im(val << 16); - gen_op_orl_T0_T1(); + tmp = load_reg(s, rd); + tcg_gen_ext16u_i32(tmp, tmp); + tcg_gen_ori_i32(tmp, tmp, val << 16); } - gen_movl_reg_T0(s, rd); + store_reg(s, rd, tmp); } else { if (((insn >> 12) & 0xf) != 0xf) goto illegal_op; @@ -4898,24 +5892,25 @@ if (op1 & 2) { if (IS_USER(s)) goto illegal_op; - gen_op_movl_T0_spsr(); + tmp = load_cpu_field(spsr); } else { - gen_op_movl_T0_cpsr(); + tmp = new_tmp(); + gen_helper_cpsr_read(tmp); } - gen_movl_reg_T0(s, rd); + store_reg(s, rd, tmp); } break; case 0x1: if (op1 == 1) { /* branch/exchange thumb (bx). */ - gen_movl_T0_reg(s, rm); - gen_bx(s); + tmp = load_reg(s, rm); + gen_bx(s, tmp); } else if (op1 == 3) { /* clz */ rd = (insn >> 12) & 0xf; - gen_movl_T0_reg(s, rm); - gen_op_clz_T0(); - gen_movl_reg_T0(s, rd); + tmp = load_reg(s, rm); + gen_helper_clz(tmp, tmp); + store_reg(s, rd, tmp); } else { goto illegal_op; } @@ -4924,8 +5919,8 @@ if (op1 == 1) { ARCH(5J); /* bxj */ /* Trivial implementation equivalent to bx. */ - gen_movl_T0_reg(s, rm); - gen_bx(s); + tmp = load_reg(s, rm); + gen_bx(s, tmp); } else { goto illegal_op; } @@ -4935,30 +5930,30 @@ goto illegal_op; /* branch link/exchange thumb (blx) */ - val = (uint32_t)s->pc; - gen_op_movl_T1_im(val); - gen_movl_T0_reg(s, rm); - gen_movl_reg_T1(s, 14); - gen_bx(s); + tmp = load_reg(s, rm); + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, s->pc); + store_reg(s, 14, tmp2); + gen_bx(s, tmp); break; case 0x5: /* saturating add/subtract */ rd = (insn >> 12) & 0xf; rn = (insn >> 16) & 0xf; - gen_movl_T0_reg(s, rm); - gen_movl_T1_reg(s, rn); + tmp = load_reg(s, rm); + tmp2 = load_reg(s, rn); if (op1 & 2) - gen_op_double_T1_saturate(); + gen_helper_double_saturate(tmp2, tmp2); if (op1 & 1) - gen_op_subl_T0_T1_saturate(); + gen_helper_sub_saturate(tmp, tmp, tmp2); else - gen_op_addl_T0_T1_saturate(); - gen_movl_reg_T0(s, rd); + gen_helper_add_saturate(tmp, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); break; case 7: /* bkpt */ gen_set_condexec(s); - gen_op_movl_T0_im((long)s->pc - 4); - gen_op_movl_reg_TN[0][15](); - gen_op_bkpt(); + gen_set_pc_im(s->pc - 4); + gen_exception(EXCP_BKPT); s->is_jmp = DISAS_JUMP; break; case 0x8: /* signed multiply */ @@ -4970,34 +5965,41 @@ rd = (insn >> 16) & 0xf; if (op1 == 1) { /* (32 * 16) >> 16 */ - gen_movl_T0_reg(s, rm); - gen_movl_T1_reg(s, rs); + tmp = load_reg(s, rm); + tmp2 = load_reg(s, rs); if (sh & 4) - gen_op_sarl_T1_im(16); + tcg_gen_sari_i32(tmp2, tmp2, 16); else - gen_op_sxth_T1(); - gen_op_imulw_T0_T1(); + gen_sxth(tmp2); + tmp2 = gen_muls_i64_i32(tmp, tmp2); + tcg_gen_shri_i64(tmp2, tmp2, 16); + tmp = new_tmp(); + tcg_gen_trunc_i64_i32(tmp, tmp2); if ((sh & 2) == 0) { - gen_movl_T1_reg(s, rn); - gen_op_addl_T0_T1_setq(); + tmp2 = load_reg(s, rn); + gen_helper_add_setq(tmp, tmp, tmp2); + dead_tmp(tmp2); } - gen_movl_reg_T0(s, rd); + store_reg(s, rd, tmp); } else { /* 16 * 16 */ - gen_movl_T0_reg(s, rm); - gen_movl_T1_reg(s, rs); - gen_mulxy(sh & 2, sh & 4); + tmp = load_reg(s, rm); + tmp2 = load_reg(s, rs); + gen_mulxy(tmp, tmp2, sh & 2, sh & 4); + dead_tmp(tmp2); if (op1 == 2) { - gen_op_signbit_T1_T0(); - gen_op_addq_T0_T1(rn, rd); - gen_movl_reg_T0(s, rn); - gen_movl_reg_T1(s, rd); + tmp2 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_ext_i32_i64(tmp2, tmp); + dead_tmp(tmp); + gen_addq(s, tmp2, rn, rd); + gen_storeq_reg(s, rn, rd, tmp2); } else { if (op1 == 0) { - gen_movl_T1_reg(s, rn); - gen_op_addl_T0_T1_setq(); + tmp2 = load_reg(s, rn); + gen_helper_add_setq(tmp, tmp, tmp2); + dead_tmp(tmp2); } - gen_movl_reg_T0(s, rd); + store_reg(s, rd, tmp); } } break; @@ -5022,7 +6024,7 @@ val = (val >> shift) | (val << (32 - shift)); gen_op_movl_T1_im(val); if (logic_cc && shift) - gen_op_mov_CF_T1(); + gen_set_CF_bit31(cpu_T[1]); } else { /* register */ rm = (insn) & 0xf; @@ -5030,27 +6032,11 @@ shiftop = (insn >> 5) & 3; if (!(insn & (1 << 4))) { shift = (insn >> 7) & 0x1f; - if (shift != 0) { - if (logic_cc) { - gen_shift_T1_im_cc[shiftop](shift); - } else { - gen_shift_T1_im[shiftop](shift); - } - } else if (shiftop != 0) { - if (logic_cc) { - gen_shift_T1_0_cc[shiftop](); - } else { - gen_shift_T1_0[shiftop](); - } - } + gen_arm_shift_im(cpu_T[1], shiftop, shift, logic_cc); } else { rs = (insn >> 8) & 0xf; - gen_movl_T0_reg(s, rs); - if (logic_cc) { - gen_shift_T1_T0_cc[shiftop](); - } else { - gen_shift_T1_T0[shiftop](); - } + tmp = load_reg(s, rs); + gen_arm_shift_reg(cpu_T[1], shiftop, tmp, logic_cc); } } if (op1 != 0x0f && op1 != 0x0d) { @@ -5104,21 +6090,21 @@ if (set_cc) gen_op_adcl_T0_T1_cc(); else - gen_op_adcl_T0_T1(); + gen_adc_T0_T1(); gen_movl_reg_T0(s, rd); break; case 0x06: if (set_cc) gen_op_sbcl_T0_T1_cc(); else - gen_op_sbcl_T0_T1(); + gen_sbc_T0_T1(); gen_movl_reg_T0(s, rd); break; case 0x07: if (set_cc) gen_op_rscl_T0_T1_cc(); else - gen_op_rscl_T0_T1(); + gen_rsc_T0_T1(); gen_movl_reg_T0(s, rd); break; case 0x08: @@ -5194,42 +6180,44 @@ switch (op1) { case 0: case 1: case 2: case 3: case 6: /* 32 bit mul */ - gen_movl_T0_reg(s, rs); - gen_movl_T1_reg(s, rm); - gen_op_mul_T0_T1(); + tmp = load_reg(s, rs); + tmp2 = load_reg(s, rm); + tcg_gen_mul_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); if (insn & (1 << 22)) { /* Subtract (mls) */ ARCH(6T2); - gen_movl_T1_reg(s, rn); - gen_op_rsbl_T0_T1(); + tmp2 = load_reg(s, rn); + tcg_gen_sub_i32(tmp, tmp2, tmp); + dead_tmp(tmp2); } else if (insn & (1 << 21)) { /* Add */ - gen_movl_T1_reg(s, rn); - gen_op_addl_T0_T1(); + tmp2 = load_reg(s, rn); + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); } if (insn & (1 << 20)) - gen_op_logic_T0_cc(); - gen_movl_reg_T0(s, rd); + gen_logic_CC(tmp); + store_reg(s, rd, tmp); break; default: /* 64 bit mul */ - gen_movl_T0_reg(s, rs); - gen_movl_T1_reg(s, rm); + tmp = load_reg(s, rs); + tmp2 = load_reg(s, rm); if (insn & (1 << 22)) - gen_op_imull_T0_T1(); + tmp = gen_muls_i64_i32(tmp, tmp2); else - gen_op_mull_T0_T1(); + tmp = gen_mulu_i64_i32(tmp, tmp2); if (insn & (1 << 21)) /* mult accumulate */ - gen_op_addq_T0_T1(rn, rd); + gen_addq(s, tmp, rn, rd); if (!(insn & (1 << 23))) { /* double accumulate */ ARCH(6); - gen_op_addq_lo_T0_T1(rn); - gen_op_addq_lo_T0_T1(rd); + gen_addq_lo(s, tmp, rn); + gen_addq_lo(s, tmp, rd); } if (insn & (1 << 20)) - gen_op_logicq_cc(); - gen_movl_reg_T0(s, rn); - gen_movl_reg_T1(s, rd); + gen_logicq_cc(tmp); + gen_storeq_reg(s, rn, rd, tmp); break; } } else { @@ -5237,27 +6225,83 @@ rd = (insn >> 12) & 0xf; if (insn & (1 << 23)) { /* load/store exclusive */ + op1 = (insn >> 21) & 0x3; + if (op1) + ARCH(6K); + else + ARCH(6); gen_movl_T1_reg(s, rn); + addr = cpu_T[1]; if (insn & (1 << 20)) { - gen_ldst(ldlex, s); + gen_helper_mark_exclusive(cpu_env, cpu_T[1]); + switch (op1) { + case 0: /* ldrex */ + tmp = gen_ld32(addr, IS_USER(s)); + break; + case 1: /* ldrexd */ + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, rd, tmp); + tcg_gen_addi_i32(addr, addr, 4); + tmp = gen_ld32(addr, IS_USER(s)); + rd++; + break; + case 2: /* ldrexb */ + tmp = gen_ld8u(addr, IS_USER(s)); + break; + case 3: /* ldrexh */ + tmp = gen_ld16u(addr, IS_USER(s)); + break; + default: + abort(); + } + store_reg(s, rd, tmp); } else { + int label = gen_new_label(); rm = insn & 0xf; - gen_movl_T0_reg(s, rm); - gen_ldst(stlex, s); + gen_helper_test_exclusive(cpu_T[0], cpu_env, addr); + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_T[0], + 0, label); + tmp = load_reg(s,rm); + switch (op1) { + case 0: /* strex */ + gen_st32(tmp, addr, IS_USER(s)); + break; + case 1: /* strexd */ + gen_st32(tmp, addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, 4); + tmp = load_reg(s, rm + 1); + gen_st32(tmp, addr, IS_USER(s)); + break; + case 2: /* strexb */ + gen_st8(tmp, addr, IS_USER(s)); + break; + case 3: /* strexh */ + gen_st16(tmp, addr, IS_USER(s)); + break; + default: + abort(); + } + gen_set_label(label); + gen_movl_reg_T0(s, rd); } - gen_movl_reg_T0(s, rd); } else { /* SWP instruction */ rm = (insn) & 0xf; - gen_movl_T0_reg(s, rm); - gen_movl_T1_reg(s, rn); + /* ??? This is not really atomic. However we know + we never have multiple CPUs running in parallel, + so it is good enough. */ + addr = load_reg(s, rn); + tmp = load_reg(s, rm); if (insn & (1 << 22)) { - gen_ldst(swpb, s); + tmp2 = gen_ld8u(addr, IS_USER(s)); + gen_st8(tmp, addr, IS_USER(s)); } else { - gen_ldst(swpl, s); + tmp2 = gen_ld32(addr, IS_USER(s)); + gen_st32(tmp, addr, IS_USER(s)); } - gen_movl_reg_T0(s, rd); + dead_tmp(addr); + store_reg(s, rd, tmp2); } } } else { @@ -5266,22 +6310,22 @@ /* Misc load/store */ rn = (insn >> 16) & 0xf; rd = (insn >> 12) & 0xf; - gen_movl_T1_reg(s, rn); + addr = load_reg(s, rn); if (insn & (1 << 24)) - gen_add_datah_offset(s, insn, 0); + gen_add_datah_offset(s, insn, 0, addr); address_offset = 0; if (insn & (1 << 20)) { /* load */ switch(sh) { case 1: - gen_ldst(lduw, s); + tmp = gen_ld16u(addr, IS_USER(s)); break; case 2: - gen_ldst(ldsb, s); + tmp = gen_ld8s(addr, IS_USER(s)); break; default: case 3: - gen_ldst(ldsw, s); + tmp = gen_ld16s(addr, IS_USER(s)); break; } load = 1; @@ -5289,26 +6333,26 @@ /* doubleword */ if (sh & 1) { /* store */ - gen_movl_T0_reg(s, rd); - gen_ldst(stl, s); - gen_op_addl_T1_im(4); - gen_movl_T0_reg(s, rd + 1); - gen_ldst(stl, s); + tmp = load_reg(s, rd); + gen_st32(tmp, addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, 4); + tmp = load_reg(s, rd + 1); + gen_st32(tmp, addr, IS_USER(s)); load = 0; } else { /* load */ - gen_ldst(ldl, s); - gen_movl_reg_T0(s, rd); - gen_op_addl_T1_im(4); - gen_ldst(ldl, s); + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, rd, tmp); + tcg_gen_addi_i32(addr, addr, 4); + tmp = gen_ld32(addr, IS_USER(s)); rd++; load = 1; } address_offset = -4; } else { /* store */ - gen_movl_T0_reg(s, rd); - gen_ldst(stw, s); + tmp = load_reg(s, rd); + gen_st16(tmp, addr, IS_USER(s)); load = 0; } /* Perform base writeback before the loaded value to @@ -5316,16 +6360,18 @@ ldrd with base writeback is is undefined if the destination and index registers overlap. */ if (!(insn & (1 << 24))) { - gen_add_datah_offset(s, insn, address_offset); - gen_movl_reg_T1(s, rn); + gen_add_datah_offset(s, insn, address_offset, addr); + store_reg(s, rn, addr); } else if (insn & (1 << 21)) { if (address_offset) - gen_op_addl_T1_im(address_offset); - gen_movl_reg_T1(s, rn); + tcg_gen_addi_i32(addr, addr, address_offset); + store_reg(s, rn, addr); + } else { + dead_tmp(addr); } if (load) { /* Complete the load. */ - gen_movl_reg_T0(s, rd); + store_reg(s, rd, tmp); } } break; @@ -5344,156 +6390,174 @@ switch ((insn >> 23) & 3) { case 0: /* Parallel add/subtract. */ op1 = (insn >> 20) & 7; - gen_movl_T0_reg(s, rn); - gen_movl_T1_reg(s, rm); + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); sh = (insn >> 5) & 7; if ((op1 & 3) == 0 || sh == 5 || sh == 6) goto illegal_op; - gen_arm_parallel_addsub[op1][sh](); - gen_movl_reg_T0(s, rd); + gen_arm_parallel_addsub(op1, sh, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); break; case 1: if ((insn & 0x00700020) == 0) { - /* Hafword pack. */ - gen_movl_T0_reg(s, rn); - gen_movl_T1_reg(s, rm); + /* Halfword pack. */ + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); shift = (insn >> 7) & 0x1f; - if (shift) - gen_op_shll_T1_im(shift); - if (insn & (1 << 6)) - gen_op_pkhtb_T0_T1(); - else - gen_op_pkhbt_T0_T1(); - gen_movl_reg_T0(s, rd); + if (insn & (1 << 6)) { + /* pkhtb */ + if (shift == 0) + shift = 31; + tcg_gen_sari_i32(tmp2, tmp2, shift); + tcg_gen_andi_i32(tmp, tmp, 0xffff0000); + tcg_gen_ext16u_i32(tmp2, tmp2); + } else { + /* pkhbt */ + if (shift) + tcg_gen_shli_i32(tmp2, tmp2, shift); + tcg_gen_ext16u_i32(tmp, tmp); + tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000); + } + tcg_gen_or_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); } else if ((insn & 0x00200020) == 0x00200000) { /* [us]sat */ - gen_movl_T1_reg(s, rm); + tmp = load_reg(s, rm); shift = (insn >> 7) & 0x1f; if (insn & (1 << 6)) { if (shift == 0) shift = 31; - gen_op_sarl_T1_im(shift); + tcg_gen_sari_i32(tmp, tmp, shift); } else { - gen_op_shll_T1_im(shift); + tcg_gen_shli_i32(tmp, tmp, shift); } sh = (insn >> 16) & 0x1f; if (sh != 0) { if (insn & (1 << 22)) - gen_op_usat_T1(sh); + gen_helper_usat(tmp, tmp, tcg_const_i32(sh)); else - gen_op_ssat_T1(sh); + gen_helper_ssat(tmp, tmp, tcg_const_i32(sh)); } - gen_movl_T1_reg(s, rd); + store_reg(s, rd, tmp); } else if ((insn & 0x00300fe0) == 0x00200f20) { /* [us]sat16 */ - gen_movl_T1_reg(s, rm); + tmp = load_reg(s, rm); sh = (insn >> 16) & 0x1f; if (sh != 0) { if (insn & (1 << 22)) - gen_op_usat16_T1(sh); + gen_helper_usat16(tmp, tmp, tcg_const_i32(sh)); else - gen_op_ssat16_T1(sh); + gen_helper_ssat16(tmp, tmp, tcg_const_i32(sh)); } - gen_movl_T1_reg(s, rd); + store_reg(s, rd, tmp); } else if ((insn & 0x00700fe0) == 0x00000fa0) { /* Select bytes. */ - gen_movl_T0_reg(s, rn); - gen_movl_T1_reg(s, rm); - gen_op_sel_T0_T1(); - gen_movl_reg_T0(s, rd); + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + tmp3 = new_tmp(); + tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE)); + gen_helper_sel_flags(tmp, tmp3, tmp, tmp2); + dead_tmp(tmp3); + dead_tmp(tmp2); + store_reg(s, rd, tmp); } else if ((insn & 0x000003e0) == 0x00000060) { - gen_movl_T1_reg(s, rm); + tmp = load_reg(s, rm); shift = (insn >> 10) & 3; /* ??? In many cases it's not neccessary to do a rotate, a shift is sufficient. */ if (shift != 0) - gen_op_rorl_T1_im(shift * 8); + tcg_gen_rori_i32(tmp, tmp, shift * 8); op1 = (insn >> 20) & 7; switch (op1) { - case 0: gen_op_sxtb16_T1(); break; - case 2: gen_op_sxtb_T1(); break; - case 3: gen_op_sxth_T1(); break; - case 4: gen_op_uxtb16_T1(); break; - case 6: gen_op_uxtb_T1(); break; - case 7: gen_op_uxth_T1(); break; + case 0: gen_sxtb16(tmp); break; + case 2: gen_sxtb(tmp); break; + case 3: gen_sxth(tmp); break; + case 4: gen_uxtb16(tmp); break; + case 6: gen_uxtb(tmp); break; + case 7: gen_uxth(tmp); break; default: goto illegal_op; } if (rn != 15) { - gen_movl_T2_reg(s, rn); + tmp2 = load_reg(s, rn); if ((op1 & 3) == 0) { - gen_op_add16_T1_T2(); + gen_add16(tmp, tmp2); } else { - gen_op_addl_T1_T2(); + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); } } - gen_movl_reg_T1(s, rd); + store_reg(s, rd, tmp); } else if ((insn & 0x003f0f60) == 0x003f0f20) { /* rev */ - gen_movl_T0_reg(s, rm); + tmp = load_reg(s, rm); if (insn & (1 << 22)) { if (insn & (1 << 7)) { - gen_op_revsh_T0(); + gen_revsh(tmp); } else { ARCH(6T2); - gen_op_rbit_T0(); + gen_helper_rbit(tmp, tmp); } } else { if (insn & (1 << 7)) - gen_op_rev16_T0(); + gen_rev16(tmp); else - gen_op_rev_T0(); + tcg_gen_bswap_i32(tmp, tmp); } - gen_movl_reg_T0(s, rd); + store_reg(s, rd, tmp); } else { goto illegal_op; } break; case 2: /* Multiplies (Type 3). */ - gen_movl_T0_reg(s, rm); - gen_movl_T1_reg(s, rs); + tmp = load_reg(s, rm); + tmp2 = load_reg(s, rs); if (insn & (1 << 20)) { /* Signed multiply most significant [accumulate]. */ - gen_op_imull_T0_T1(); + tmp2 = gen_muls_i64_i32(tmp, tmp2); if (insn & (1 << 5)) - gen_op_roundqd_T0_T1(); - else - gen_op_movl_T0_T1(); + tcg_gen_addi_i64(tmp2, tmp2, 0x80000000u); + tcg_gen_shri_i64(tmp2, tmp2, 32); + tmp = new_tmp(); + tcg_gen_trunc_i64_i32(tmp, tmp2); if (rn != 15) { - gen_movl_T1_reg(s, rn); + tmp2 = load_reg(s, rn); if (insn & (1 << 6)) { - gen_op_addl_T0_T1(); + tcg_gen_sub_i32(tmp, tmp, tmp2); } else { - gen_op_rsbl_T0_T1(); + tcg_gen_add_i32(tmp, tmp, tmp2); } + dead_tmp(tmp2); } - gen_movl_reg_T0(s, rd); + store_reg(s, rd, tmp); } else { if (insn & (1 << 5)) - gen_op_swap_half_T1(); - gen_op_mul_dual_T0_T1(); + gen_swap_half(tmp2); + gen_smul_dual(tmp, tmp2); + /* This addition cannot overflow. */ + if (insn & (1 << 6)) { + tcg_gen_sub_i32(tmp, tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + } + dead_tmp(tmp2); if (insn & (1 << 22)) { - if (insn & (1 << 6)) { - /* smlald */ - gen_op_addq_T0_T1_dual(rn, rd); - } else { - /* smlsld */ - gen_op_subq_T0_T1_dual(rn, rd); - } + /* smlald, smlsld */ + tmp2 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_ext_i32_i64(tmp2, tmp); + dead_tmp(tmp); + gen_addq(s, tmp2, rd, rn); + gen_storeq_reg(s, rd, rn, tmp2); } else { - /* This addition cannot overflow. */ - if (insn & (1 << 6)) { - /* sm[ul]sd */ - gen_op_subl_T0_T1(); - } else { - /* sm[ul]ad */ - gen_op_addl_T0_T1(); - } - if (rn != 15) + /* smuad, smusd, smlad, smlsd */ + if (rd != 15) { - gen_movl_T1_reg(s, rn); - gen_op_addl_T0_T1_setq(); + tmp2 = load_reg(s, rd); + gen_helper_add_setq(tmp, tmp, tmp2); + dead_tmp(tmp2); } - gen_movl_reg_T0(s, rd); + store_reg(s, rn, tmp); } } break; @@ -5501,15 +6565,17 @@ op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7); switch (op1) { case 0: /* Unsigned sum of absolute differences. */ - goto illegal_op; - gen_movl_T0_reg(s, rm); - gen_movl_T1_reg(s, rs); - gen_op_usad8_T0_T1(); + ARCH(6); + tmp = load_reg(s, rm); + tmp2 = load_reg(s, rs); + gen_helper_usad8(tmp, tmp, tmp2); + dead_tmp(tmp2); if (rn != 15) { - gen_movl_T1_reg(s, rn); - gen_op_addl_T0_T1(); + tmp2 = load_reg(s, rn); + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); } - gen_movl_reg_T0(s, rd); + store_reg(s, rd, tmp); break; case 0x20: case 0x24: case 0x28: case 0x2c: /* Bitfield insert/clear. */ @@ -5518,31 +6584,33 @@ i = (insn >> 16) & 0x1f; i = i + 1 - shift; if (rm == 15) { - gen_op_movl_T1_im(0); + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); } else { - gen_movl_T1_reg(s, rm); + tmp = load_reg(s, rm); } if (i != 32) { - gen_movl_T0_reg(s, rd); - gen_op_bfi_T1_T0(shift, ((1u << i) - 1) << shift); + tmp2 = load_reg(s, rd); + gen_bfi(tmp, tmp2, tmp, shift, (1u << i) - 1); + dead_tmp(tmp2); } - gen_movl_reg_T1(s, rd); + store_reg(s, rd, tmp); break; case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */ case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */ - gen_movl_T1_reg(s, rm); + tmp = load_reg(s, rm); shift = (insn >> 7) & 0x1f; i = ((insn >> 16) & 0x1f) + 1; if (shift + i > 32) goto illegal_op; if (i < 32) { if (op1 & 0x20) { - gen_op_ubfx_T1(shift, (1u << i) - 1); + gen_ubfx(tmp, shift, (1u << i) - 1); } else { - gen_op_sbfx_T1(shift, i); + gen_sbfx(tmp, shift, i); } } - gen_movl_reg_T1(s, rd); + store_reg(s, rd, tmp); break; default: goto illegal_op; @@ -5564,71 +6632,47 @@ /* load/store byte/word */ rn = (insn >> 16) & 0xf; rd = (insn >> 12) & 0xf; - gen_movl_T1_reg(s, rn); + tmp2 = load_reg(s, rn); i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000); if (insn & (1 << 24)) - gen_add_data_offset(s, insn); + gen_add_data_offset(s, insn, tmp2); if (insn & (1 << 20)) { /* load */ s->is_mem = 1; -#if defined(CONFIG_USER_ONLY) - if (insn & (1 << 22)) - gen_op_ldub_raw(); - else - gen_op_ldl_raw(); -#else if (insn & (1 << 22)) { - if (i) - gen_op_ldub_user(); - else - gen_op_ldub_kernel(); + tmp = gen_ld8u(tmp2, i); } else { - if (i) - gen_op_ldl_user(); - else - gen_op_ldl_kernel(); + tmp = gen_ld32(tmp2, i); } -#endif } else { /* store */ - gen_movl_T0_reg(s, rd); -#if defined(CONFIG_USER_ONLY) + tmp = load_reg(s, rd); if (insn & (1 << 22)) - gen_op_stb_raw(); + gen_st8(tmp, tmp2, i); else - gen_op_stl_raw(); -#else - if (insn & (1 << 22)) { - if (i) - gen_op_stb_user(); - else - gen_op_stb_kernel(); - } else { - if (i) - gen_op_stl_user(); - else - gen_op_stl_kernel(); - } -#endif + gen_st32(tmp, tmp2, i); } if (!(insn & (1 << 24))) { - gen_add_data_offset(s, insn); - gen_movl_reg_T1(s, rn); - } else if (insn & (1 << 21)) - gen_movl_reg_T1(s, rn); { + gen_add_data_offset(s, insn, tmp2); + store_reg(s, rn, tmp2); + } else if (insn & (1 << 21)) { + store_reg(s, rn, tmp2); + } else { + dead_tmp(tmp2); } if (insn & (1 << 20)) { /* Complete the load. */ if (rd == 15) - gen_bx(s); + gen_bx(s, tmp); else - gen_movl_reg_T0(s, rd); + store_reg(s, rd, tmp); } break; case 0x08: case 0x09: { int j, n, user, loaded_base; + TCGv loaded_var; /* load/store multiple words */ /* XXX: store correct base if write back */ user = 0; @@ -5640,10 +6684,11 @@ user = 1; } rn = (insn >> 16) & 0xf; - gen_movl_T1_reg(s, rn); + addr = load_reg(s, rn); /* compute total size */ loaded_base = 0; + TCGV_UNUSED(loaded_var); n = 0; for(i=0;i<16;i++) { if (insn & (1 << i)) @@ -5653,18 +6698,18 @@ if (insn & (1 << 23)) { if (insn & (1 << 24)) { /* pre increment */ - gen_op_addl_T1_im(4); + tcg_gen_addi_i32(addr, addr, 4); } else { /* post increment */ } } else { if (insn & (1 << 24)) { /* pre decrement */ - gen_op_addl_T1_im(-(n * 4)); + tcg_gen_addi_i32(addr, addr, -(n * 4)); } else { /* post decrement */ if (n != 1) - gen_op_addl_T1_im(-((n - 1) * 4)); + tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); } } j = 0; @@ -5672,34 +6717,37 @@ if (insn & (1 << i)) { if (insn & (1 << 20)) { /* load */ - gen_ldst(ldl, s); + tmp = gen_ld32(addr, IS_USER(s)); if (i == 15) { - gen_bx(s); + gen_bx(s, tmp); } else if (user) { - gen_op_movl_user_T0(i); + gen_helper_set_user_reg(tcg_const_i32(i), tmp); + dead_tmp(tmp); } else if (i == rn) { - gen_op_movl_T2_T0(); + loaded_var = tmp; loaded_base = 1; } else { - gen_movl_reg_T0(s, i); + store_reg(s, i, tmp); } } else { /* store */ if (i == 15) { /* special case: r15 = PC + 8 */ val = (long)s->pc + 4; - gen_op_movl_TN_im[0](val); + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); } else if (user) { - gen_op_movl_T0_user(i); + tmp = new_tmp(); + gen_helper_get_user_reg(tmp, tcg_const_i32(i)); } else { - gen_movl_T0_reg(s, i); + tmp = load_reg(s, i); } - gen_ldst(stl, s); + gen_st32(tmp, addr, IS_USER(s)); } j++; /* no need to add after the last transfer */ if (j != n) - gen_op_addl_T1_im(4); + tcg_gen_addi_i32(addr, addr, 4); } } if (insn & (1 << 21)) { @@ -5709,28 +6757,30 @@ /* pre increment */ } else { /* post increment */ - gen_op_addl_T1_im(4); + tcg_gen_addi_i32(addr, addr, 4); } } else { if (insn & (1 << 24)) { /* pre decrement */ if (n != 1) - gen_op_addl_T1_im(-((n - 1) * 4)); + tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); } else { /* post decrement */ - gen_op_addl_T1_im(-(n * 4)); + tcg_gen_addi_i32(addr, addr, -(n * 4)); } } - gen_movl_reg_T1(s, rn); + store_reg(s, rn, addr); + } else { + dead_tmp(addr); } if (loaded_base) { - gen_op_movl_T0_T2(); - gen_movl_reg_T0(s, rn); + store_reg(s, rn, loaded_var); } if ((insn & (1 << 22)) && !user) { /* Restore CPSR from SPSR. */ - gen_op_movl_T0_spsr(); - gen_op_movl_cpsr_T0(0xffffffff); + tmp = load_cpu_field(spsr); + gen_set_cpsr(tmp, 0xffffffff); + dead_tmp(tmp); s->is_jmp = DISAS_UPDATE; } } @@ -5743,8 +6793,9 @@ /* branch (and link) */ val = (int32_t)s->pc; if (insn & (1 << 24)) { - gen_op_movl_T0_im(val); - gen_op_movl_reg_TN[0][14](); + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + store_reg(s, 14, tmp); } offset = (((int32_t)insn << 8) >> 8); val += (offset << 2) + 4; @@ -5760,16 +6811,14 @@ break; case 0xf: /* swi */ - gen_op_movl_T0_im((long)s->pc); - gen_op_movl_reg_TN[0][15](); + gen_set_pc_im(s->pc); s->is_jmp = DISAS_SWI; break; default: illegal_op: gen_set_condexec(s); - gen_op_movl_T0_im((long)s->pc - 4); - gen_op_movl_reg_TN[0][15](); - gen_op_undef_insn(); + gen_set_pc_im(s->pc - 4); + gen_exception(EXCP_UDEF); s->is_jmp = DISAS_JUMP; break; } @@ -5827,13 +6876,13 @@ if (conds) gen_op_adcl_T0_T1_cc(); else - gen_op_adcl_T0_T1(); + gen_adc_T0_T1(); break; case 11: /* sbc */ if (conds) gen_op_sbcl_T0_T1_cc(); else - gen_op_sbcl_T0_T1(); + gen_sbc_T0_T1(); break; case 13: /* sub */ if (conds) @@ -5853,7 +6902,7 @@ if (logic_cc) { gen_op_logic_T0_cc(); if (shifter_out) - gen_op_mov_CF_T1(); + gen_set_CF_bit31(cpu_T[1]); } return 0; } @@ -5862,8 +6911,12 @@ is not legal. */ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) { - uint32_t insn, imm, shift, offset, addr; + uint32_t insn, imm, shift, offset; uint32_t rd, rn, rm, rs; + TCGv tmp; + TCGv tmp2; + TCGv tmp3; + TCGv addr; int op; int shiftop; int conds; @@ -5871,35 +6924,32 @@ if (!(arm_feature(env, ARM_FEATURE_THUMB2) || arm_feature (env, ARM_FEATURE_M))) { - /* Thumb-1 cores may need to tread bl and blx as a pair of + /* Thumb-1 cores may need to treat bl and blx as a pair of 16-bit instructions to get correct prefetch abort behavior. */ insn = insn_hw1; if ((insn & (1 << 12)) == 0) { /* Second half of blx. */ offset = ((insn & 0x7ff) << 1); - gen_movl_T0_reg(s, 14); - gen_op_movl_T1_im(offset); - gen_op_addl_T0_T1(); - gen_op_movl_T1_im(0xfffffffc); - gen_op_andl_T0_T1(); - - addr = (uint32_t)s->pc; - gen_op_movl_T1_im(addr | 1); - gen_movl_reg_T1(s, 14); - gen_bx(s); + tmp = load_reg(s, 14); + tcg_gen_addi_i32(tmp, tmp, offset); + tcg_gen_andi_i32(tmp, tmp, 0xfffffffc); + + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, s->pc | 1); + store_reg(s, 14, tmp2); + gen_bx(s, tmp); return 0; } if (insn & (1 << 11)) { /* Second half of bl. */ offset = ((insn & 0x7ff) << 1) | 1; - gen_movl_T0_reg(s, 14); - gen_op_movl_T1_im(offset); - gen_op_addl_T0_T1(); + tmp = load_reg(s, 14); + tcg_gen_addi_i32(tmp, tmp, offset); - addr = (uint32_t)s->pc; - gen_op_movl_T1_im(addr | 1); - gen_movl_reg_T1(s, 14); - gen_bx(s); + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, s->pc | 1); + store_reg(s, 14, tmp2); + gen_bx(s, tmp); return 0; } if ((s->pc & ~TARGET_PAGE_MASK) == 0) { @@ -5907,8 +6957,7 @@ 16-bit instructions in case the second half causes an prefetch abort. */ offset = ((int32_t)insn << 21) >> 9; - addr = s->pc + 2 + offset; - gen_op_movl_T0_im(addr); + gen_op_movl_T0_im(s->pc + 2 + offset); gen_movl_reg_T0(s, 14); return 0; } @@ -5937,103 +6986,135 @@ if (insn & 0x01200000) { /* Load/store doubleword. */ if (rn == 15) { - gen_op_movl_T1_im(s->pc & ~3); + addr = new_tmp(); + tcg_gen_movi_i32(addr, s->pc & ~3); } else { - gen_movl_T1_reg(s, rn); + addr = load_reg(s, rn); } offset = (insn & 0xff) * 4; if ((insn & (1 << 23)) == 0) offset = -offset; if (insn & (1 << 24)) { - gen_op_addl_T1_im(offset); + tcg_gen_addi_i32(addr, addr, offset); offset = 0; } if (insn & (1 << 20)) { /* ldrd */ - gen_ldst(ldl, s); - gen_movl_reg_T0(s, rs); - gen_op_addl_T1_im(4); - gen_ldst(ldl, s); - gen_movl_reg_T0(s, rd); + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, rs, tmp); + tcg_gen_addi_i32(addr, addr, 4); + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, rd, tmp); } else { /* strd */ - gen_movl_T0_reg(s, rs); - gen_ldst(stl, s); - gen_op_addl_T1_im(4); - gen_movl_T0_reg(s, rd); - gen_ldst(stl, s); + tmp = load_reg(s, rs); + gen_st32(tmp, addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, 4); + tmp = load_reg(s, rd); + gen_st32(tmp, addr, IS_USER(s)); } if (insn & (1 << 21)) { /* Base writeback. */ if (rn == 15) goto illegal_op; - gen_op_addl_T1_im(offset - 4); - gen_movl_reg_T1(s, rn); + tcg_gen_addi_i32(addr, addr, offset - 4); + store_reg(s, rn, addr); + } else { + dead_tmp(addr); } } else if ((insn & (1 << 23)) == 0) { /* Load/store exclusive word. */ - gen_movl_T0_reg(s, rd); gen_movl_T1_reg(s, rn); + addr = cpu_T[1]; if (insn & (1 << 20)) { - gen_ldst(ldlex, s); - } else { - gen_ldst(stlex, s); + gen_helper_mark_exclusive(cpu_env, cpu_T[1]); + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, rd, tmp); + } else { + int label = gen_new_label(); + gen_helper_test_exclusive(cpu_T[0], cpu_env, addr); + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_T[0], + 0, label); + tmp = load_reg(s, rs); + gen_st32(tmp, cpu_T[1], IS_USER(s)); + gen_set_label(label); + gen_movl_reg_T0(s, rd); } - gen_movl_reg_T0(s, rd); } else if ((insn & (1 << 6)) == 0) { /* Table Branch. */ if (rn == 15) { - gen_op_movl_T1_im(s->pc); + addr = new_tmp(); + tcg_gen_movi_i32(addr, s->pc); } else { - gen_movl_T1_reg(s, rn); + addr = load_reg(s, rn); } - gen_movl_T2_reg(s, rm); - gen_op_addl_T1_T2(); + tmp = load_reg(s, rm); + tcg_gen_add_i32(addr, addr, tmp); if (insn & (1 << 4)) { /* tbh */ - gen_op_addl_T1_T2(); - gen_ldst(lduw, s); + tcg_gen_add_i32(addr, addr, tmp); + dead_tmp(tmp); + tmp = gen_ld16u(addr, IS_USER(s)); } else { /* tbb */ - gen_ldst(ldub, s); + dead_tmp(tmp); + tmp = gen_ld8u(addr, IS_USER(s)); } - gen_op_jmp_T0_im(s->pc); - s->is_jmp = DISAS_JUMP; + dead_tmp(addr); + tcg_gen_shli_i32(tmp, tmp, 1); + tcg_gen_addi_i32(tmp, tmp, s->pc); + store_reg(s, 15, tmp); } else { /* Load/store exclusive byte/halfword/doubleword. */ + /* ??? These are not really atomic. However we know + we never have multiple CPUs running in parallel, + so it is good enough. */ op = (insn >> 4) & 0x3; + /* Must use a global reg for the address because we have + a conditional branch in the store instruction. */ gen_movl_T1_reg(s, rn); + addr = cpu_T[1]; if (insn & (1 << 20)) { + gen_helper_mark_exclusive(cpu_env, addr); switch (op) { case 0: - gen_ldst(ldbex, s); + tmp = gen_ld8u(addr, IS_USER(s)); break; case 1: - gen_ldst(ldwex, s); + tmp = gen_ld16u(addr, IS_USER(s)); break; case 3: - gen_ldst(ldqex, s); - gen_movl_reg_T1(s, rd); + tmp = gen_ld32(addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, 4); + tmp2 = gen_ld32(addr, IS_USER(s)); + store_reg(s, rd, tmp2); break; default: goto illegal_op; } - gen_movl_reg_T0(s, rs); + store_reg(s, rs, tmp); } else { - gen_movl_T0_reg(s, rs); + int label = gen_new_label(); + /* Must use a global that is not killed by the branch. */ + gen_helper_test_exclusive(cpu_T[0], cpu_env, addr); + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_T[0], 0, label); + tmp = load_reg(s, rs); switch (op) { case 0: - gen_ldst(stbex, s); + gen_st8(tmp, addr, IS_USER(s)); break; case 1: - gen_ldst(stwex, s); + gen_st16(tmp, addr, IS_USER(s)); break; case 3: - gen_movl_T2_reg(s, rd); - gen_ldst(stqex, s); + gen_st32(tmp, addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, 4); + tmp = load_reg(s, rd); + gen_st32(tmp, addr, IS_USER(s)); break; default: goto illegal_op; } + gen_set_label(label); gen_movl_reg_T0(s, rm); } } @@ -6041,68 +7122,74 @@ /* Load/store multiple, RFE, SRS. */ if (((insn >> 23) & 1) == ((insn >> 24) & 1)) { /* Not available in user mode. */ - if (!IS_USER(s)) + if (IS_USER(s)) goto illegal_op; if (insn & (1 << 20)) { /* rfe */ - gen_movl_T1_reg(s, rn); - if (insn & (1 << 24)) { - gen_op_addl_T1_im(4); - } else { - gen_op_addl_T1_im(-4); - } - /* Load CPSR into T2 and PC into T0. */ - gen_ldst(ldl, s); - gen_op_movl_T2_T0(); - gen_op_addl_T1_im(-4); - gen_ldst(ldl, s); + addr = load_reg(s, rn); + if ((insn & (1 << 24)) == 0) + tcg_gen_addi_i32(addr, addr, -8); + /* Load PC into tmp and CPSR into tmp2. */ + tmp = gen_ld32(addr, 0); + tcg_gen_addi_i32(addr, addr, 4); + tmp2 = gen_ld32(addr, 0); if (insn & (1 << 21)) { /* Base writeback. */ - if (insn & (1 << 24)) - gen_op_addl_T1_im(8); - gen_movl_reg_T1(s, rn); + if (insn & (1 << 24)) { + tcg_gen_addi_i32(addr, addr, 4); + } else { + tcg_gen_addi_i32(addr, addr, -4); + } + store_reg(s, rn, addr); + } else { + dead_tmp(addr); } - gen_rfe(s); + gen_rfe(s, tmp, tmp2); } else { /* srs */ op = (insn & 0x1f); if (op == (env->uncached_cpsr & CPSR_M)) { - gen_movl_T1_reg(s, 13); + addr = load_reg(s, 13); } else { - gen_op_movl_T1_r13_banked(op); + addr = new_tmp(); + gen_helper_get_r13_banked(addr, cpu_env, tcg_const_i32(op)); } if ((insn & (1 << 24)) == 0) { - gen_op_addl_T1_im(-8); + tcg_gen_addi_i32(addr, addr, -8); } - gen_movl_T0_reg(s, 14); - gen_ldst(stl, s); - gen_op_movl_T0_cpsr(); - gen_op_addl_T1_im(4); - gen_ldst(stl, s); + tmp = load_reg(s, 14); + gen_st32(tmp, addr, 0); + tcg_gen_addi_i32(addr, addr, 4); + tmp = new_tmp(); + gen_helper_cpsr_read(tmp); + gen_st32(tmp, addr, 0); if (insn & (1 << 21)) { if ((insn & (1 << 24)) == 0) { - gen_op_addl_T1_im(-4); + tcg_gen_addi_i32(addr, addr, -4); } else { - gen_op_addl_T1_im(4); + tcg_gen_addi_i32(addr, addr, 4); } if (op == (env->uncached_cpsr & CPSR_M)) { - gen_movl_reg_T1(s, 13); + store_reg(s, 13, addr); } else { - gen_op_movl_r13_T1_banked(op); + gen_helper_set_r13_banked(cpu_env, + tcg_const_i32(op), addr); } + } else { + dead_tmp(addr); } } } else { int i; /* Load/store multiple. */ - gen_movl_T1_reg(s, rn); + addr = load_reg(s, rn); offset = 0; for (i = 0; i < 16; i++) { if (insn & (1 << i)) offset += 4; } if (insn & (1 << 24)) { - gen_op_addl_T1_im(-offset); + tcg_gen_addi_i32(addr, addr, -offset); } for (i = 0; i < 16; i++) { @@ -6110,28 +7197,30 @@ continue; if (insn & (1 << 20)) { /* Load. */ - gen_ldst(ldl, s); + tmp = gen_ld32(addr, IS_USER(s)); if (i == 15) { - gen_bx(s); + gen_bx(s, tmp); } else { - gen_movl_reg_T0(s, i); + store_reg(s, i, tmp); } } else { /* Store. */ - gen_movl_T0_reg(s, i); - gen_ldst(stl, s); + tmp = load_reg(s, i); + gen_st32(tmp, addr, IS_USER(s)); } - gen_op_addl_T1_im(4); + tcg_gen_addi_i32(addr, addr, 4); } if (insn & (1 << 21)) { /* Base register writeback. */ if (insn & (1 << 24)) { - gen_op_addl_T1_im(-offset); + tcg_gen_addi_i32(addr, addr, -offset); } /* Fault if writeback register is in register list. */ if (insn & (1 << rn)) goto illegal_op; - gen_movl_reg_T1(s, rn); + store_reg(s, rn, addr); + } else { + dead_tmp(addr); } } } @@ -6147,19 +7236,7 @@ shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c); conds = (insn & (1 << 20)) != 0; logic_cc = (conds && thumb2_logic_op(op)); - if (shift != 0) { - if (logic_cc) { - gen_shift_T1_im_cc[shiftop](shift); - } else { - gen_shift_T1_im[shiftop](shift); - } - } else if (shiftop != 0) { - if (logic_cc) { - gen_shift_T1_0_cc[shiftop](); - } else { - gen_shift_T1_0[shiftop](); - } - } + gen_arm_shift_im(cpu_T[1], shiftop, shift, logic_cc); if (gen_thumb2_data_op(s, op, conds, 0)) goto illegal_op; if (rd != 15) @@ -6171,228 +7248,248 @@ goto illegal_op; switch (op) { case 0: /* Register controlled shift. */ - gen_movl_T0_reg(s, rm); - gen_movl_T1_reg(s, rn); + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); if ((insn & 0x70) != 0) goto illegal_op; op = (insn >> 21) & 3; - if (insn & (1 << 20)) { - gen_shift_T1_T0_cc[op](); - gen_op_logic_T1_cc(); - } else { - gen_shift_T1_T0[op](); - } - gen_movl_reg_T1(s, rd); + logic_cc = (insn & (1 << 20)) != 0; + gen_arm_shift_reg(tmp, op, tmp2, logic_cc); + if (logic_cc) + gen_logic_CC(tmp); + store_reg(s, rd, tmp); break; case 1: /* Sign/zero extend. */ - gen_movl_T1_reg(s, rm); + tmp = load_reg(s, rm); shift = (insn >> 4) & 3; /* ??? In many cases it's not neccessary to do a rotate, a shift is sufficient. */ if (shift != 0) - gen_op_rorl_T1_im(shift * 8); + tcg_gen_rori_i32(tmp, tmp, shift * 8); op = (insn >> 20) & 7; switch (op) { - case 0: gen_op_sxth_T1(); break; - case 1: gen_op_uxth_T1(); break; - case 2: gen_op_sxtb16_T1(); break; - case 3: gen_op_uxtb16_T1(); break; - case 4: gen_op_sxtb_T1(); break; - case 5: gen_op_uxtb_T1(); break; + case 0: gen_sxth(tmp); break; + case 1: gen_uxth(tmp); break; + case 2: gen_sxtb16(tmp); break; + case 3: gen_uxtb16(tmp); break; + case 4: gen_sxtb(tmp); break; + case 5: gen_uxtb(tmp); break; default: goto illegal_op; } if (rn != 15) { - gen_movl_T2_reg(s, rn); + tmp2 = load_reg(s, rn); if ((op >> 1) == 1) { - gen_op_add16_T1_T2(); + gen_add16(tmp, tmp2); } else { - gen_op_addl_T1_T2(); + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); } } - gen_movl_reg_T1(s, rd); + store_reg(s, rd, tmp); break; case 2: /* SIMD add/subtract. */ op = (insn >> 20) & 7; shift = (insn >> 4) & 7; if ((op & 3) == 3 || (shift & 3) == 3) goto illegal_op; - gen_movl_T0_reg(s, rn); - gen_movl_T1_reg(s, rm); - gen_thumb2_parallel_addsub[op][shift](); - gen_movl_reg_T0(s, rd); + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + gen_thumb2_parallel_addsub(op, shift, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); break; case 3: /* Other data processing. */ op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7); if (op < 4) { /* Saturating add/subtract. */ - gen_movl_T0_reg(s, rm); - gen_movl_T1_reg(s, rn); + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); if (op & 2) - gen_op_double_T1_saturate(); + gen_helper_double_saturate(tmp, tmp); if (op & 1) - gen_op_subl_T0_T1_saturate(); + gen_helper_sub_saturate(tmp, tmp2, tmp); else - gen_op_addl_T0_T1_saturate(); + gen_helper_add_saturate(tmp, tmp, tmp2); + dead_tmp(tmp2); } else { - gen_movl_T0_reg(s, rn); + tmp = load_reg(s, rn); switch (op) { case 0x0a: /* rbit */ - gen_op_rbit_T0(); + gen_helper_rbit(tmp, tmp); break; case 0x08: /* rev */ - gen_op_rev_T0(); + tcg_gen_bswap_i32(tmp, tmp); break; case 0x09: /* rev16 */ - gen_op_rev16_T0(); + gen_rev16(tmp); break; case 0x0b: /* revsh */ - gen_op_revsh_T0(); + gen_revsh(tmp); break; case 0x10: /* sel */ - gen_movl_T1_reg(s, rm); - gen_op_sel_T0_T1(); + tmp2 = load_reg(s, rm); + tmp3 = new_tmp(); + tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE)); + gen_helper_sel_flags(tmp, tmp3, tmp, tmp2); + dead_tmp(tmp3); + dead_tmp(tmp2); break; case 0x18: /* clz */ - gen_op_clz_T0(); + gen_helper_clz(tmp, tmp); break; default: goto illegal_op; } } - gen_movl_reg_T0(s, rd); + store_reg(s, rd, tmp); break; case 4: case 5: /* 32-bit multiply. Sum of absolute differences. */ op = (insn >> 4) & 0xf; - gen_movl_T0_reg(s, rn); - gen_movl_T1_reg(s, rm); + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); switch ((insn >> 20) & 7) { case 0: /* 32 x 32 -> 32 */ - gen_op_mul_T0_T1(); + tcg_gen_mul_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); if (rs != 15) { - gen_movl_T1_reg(s, rs); + tmp2 = load_reg(s, rs); if (op) - gen_op_rsbl_T0_T1(); + tcg_gen_sub_i32(tmp, tmp2, tmp); else - gen_op_addl_T0_T1(); + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); } - gen_movl_reg_T0(s, rd); break; case 1: /* 16 x 16 -> 32 */ - gen_mulxy(op & 2, op & 1); + gen_mulxy(tmp, tmp2, op & 2, op & 1); + dead_tmp(tmp2); if (rs != 15) { - gen_movl_T1_reg(s, rs); - gen_op_addl_T0_T1_setq(); + tmp2 = load_reg(s, rs); + gen_helper_add_setq(tmp, tmp, tmp2); + dead_tmp(tmp2); } - gen_movl_reg_T0(s, rd); break; case 2: /* Dual multiply add. */ case 4: /* Dual multiply subtract. */ if (op) - gen_op_swap_half_T1(); - gen_op_mul_dual_T0_T1(); + gen_swap_half(tmp2); + gen_smul_dual(tmp, tmp2); /* This addition cannot overflow. */ if (insn & (1 << 22)) { - gen_op_subl_T0_T1(); + tcg_gen_sub_i32(tmp, tmp, tmp2); } else { - gen_op_addl_T0_T1(); + tcg_gen_add_i32(tmp, tmp, tmp2); } + dead_tmp(tmp2); if (rs != 15) { - gen_movl_T1_reg(s, rs); - gen_op_addl_T0_T1_setq(); + tmp2 = load_reg(s, rs); + gen_helper_add_setq(tmp, tmp, tmp2); + dead_tmp(tmp2); } - gen_movl_reg_T0(s, rd); break; case 3: /* 32 * 16 -> 32msb */ if (op) - gen_op_sarl_T1_im(16); + tcg_gen_sari_i32(tmp2, tmp2, 16); else - gen_op_sxth_T1(); - gen_op_imulw_T0_T1(); + gen_sxth(tmp2); + tmp2 = gen_muls_i64_i32(tmp, tmp2); + tcg_gen_shri_i64(tmp2, tmp2, 16); + tmp = new_tmp(); + tcg_gen_trunc_i64_i32(tmp, tmp2); if (rs != 15) { - gen_movl_T1_reg(s, rs); - gen_op_addl_T0_T1_setq(); + tmp2 = load_reg(s, rs); + gen_helper_add_setq(tmp, tmp, tmp2); + dead_tmp(tmp2); } - gen_movl_reg_T0(s, rd); break; case 5: case 6: /* 32 * 32 -> 32msb */ - gen_op_imull_T0_T1(); - if (insn & (1 << 5)) - gen_op_roundqd_T0_T1(); - else - gen_op_movl_T0_T1(); + gen_imull(tmp, tmp2); + if (insn & (1 << 5)) { + gen_roundqd(tmp, tmp2); + dead_tmp(tmp2); + } else { + dead_tmp(tmp); + tmp = tmp2; + } if (rs != 15) { - gen_movl_T1_reg(s, rs); + tmp2 = load_reg(s, rs); if (insn & (1 << 21)) { - gen_op_addl_T0_T1(); + tcg_gen_add_i32(tmp, tmp, tmp2); } else { - gen_op_rsbl_T0_T1(); + tcg_gen_sub_i32(tmp, tmp2, tmp); } + dead_tmp(tmp2); } - gen_movl_reg_T0(s, rd); break; case 7: /* Unsigned sum of absolute differences. */ - gen_op_usad8_T0_T1(); + gen_helper_usad8(tmp, tmp, tmp2); + dead_tmp(tmp2); if (rs != 15) { - gen_movl_T1_reg(s, rs); - gen_op_addl_T0_T1(); + tmp2 = load_reg(s, rs); + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); } - gen_movl_reg_T0(s, rd); break; } + store_reg(s, rd, tmp); break; case 6: case 7: /* 64-bit multiply, Divide. */ op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70); - gen_movl_T0_reg(s, rn); - gen_movl_T1_reg(s, rm); + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); if ((op & 0x50) == 0x10) { /* sdiv, udiv */ if (!arm_feature(env, ARM_FEATURE_DIV)) goto illegal_op; if (op & 0x20) - gen_op_udivl_T0_T1(); + gen_helper_udiv(tmp, tmp, tmp2); else - gen_op_sdivl_T0_T1(); - gen_movl_reg_T0(s, rd); + gen_helper_sdiv(tmp, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); } else if ((op & 0xe) == 0xc) { /* Dual multiply accumulate long. */ if (op & 1) - gen_op_swap_half_T1(); - gen_op_mul_dual_T0_T1(); + gen_swap_half(tmp2); + gen_smul_dual(tmp, tmp2); if (op & 0x10) { - gen_op_subl_T0_T1(); + tcg_gen_sub_i32(tmp, tmp, tmp2); } else { - gen_op_addl_T0_T1(); + tcg_gen_add_i32(tmp, tmp, tmp2); } - gen_op_signbit_T1_T0(); - gen_op_addq_T0_T1(rs, rd); - gen_movl_reg_T0(s, rs); - gen_movl_reg_T1(s, rd); + dead_tmp(tmp2); + tmp2 = tcg_temp_new(TCG_TYPE_I64); + gen_addq(s, tmp, rs, rd); + gen_storeq_reg(s, rs, rd, tmp); } else { if (op & 0x20) { /* Unsigned 64-bit multiply */ - gen_op_mull_T0_T1(); + tmp = gen_mulu_i64_i32(tmp, tmp2); } else { if (op & 8) { /* smlalxy */ - gen_mulxy(op & 2, op & 1); - gen_op_signbit_T1_T0(); + gen_mulxy(tmp, tmp2, op & 2, op & 1); + dead_tmp(tmp2); + tmp2 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_ext_i32_i64(tmp2, tmp); + dead_tmp(tmp); + tmp = tmp2; } else { /* Signed 64-bit multiply */ - gen_op_imull_T0_T1(); + tmp = gen_muls_i64_i32(tmp, tmp2); } } if (op & 4) { /* umaal */ - gen_op_addq_lo_T0_T1(rs); - gen_op_addq_lo_T0_T1(rd); + gen_addq_lo(s, tmp, rs); + gen_addq_lo(s, tmp, rd); } else if (op & 0x40) { /* 64-bit accumulate. */ - gen_op_addq_T0_T1(rs, rd); + gen_addq(s, tmp, rs, rd); } - gen_movl_reg_T0(s, rs); - gen_movl_reg_T1(s, rd); + gen_storeq_reg(s, rs, rd, tmp); } break; } @@ -6426,22 +7523,20 @@ offset ^= ((~insn) & (1 << 13)) << 10; offset ^= ((~insn) & (1 << 11)) << 11; - addr = s->pc; if (insn & (1 << 14)) { /* Branch and link. */ - gen_op_movl_T1_im(addr | 1); + gen_op_movl_T1_im(s->pc | 1); gen_movl_reg_T1(s, 14); } - addr += offset; + offset += s->pc; if (insn & (1 << 12)) { /* b/bl */ - gen_jmp(s, addr); + gen_jmp(s, offset); } else { /* blx */ - addr &= ~(uint32_t)2; - gen_op_movl_T0_im(addr); - gen_bx(s); + offset &= ~(uint32_t)2; + gen_bx_im(s, offset); } } else if (((insn >> 23) & 7) == 7) { /* Misc control */ @@ -6456,8 +7551,9 @@ switch (op) { case 0: /* msr cpsr. */ if (IS_M(env)) { - gen_op_v7m_msr_T0(insn & 0xff); - gen_movl_reg_T0(s, rn); + tmp = load_reg(s, rn); + addr = tcg_const_i32(insn & 0xff); + gen_helper_v7m_msr(cpu_env, addr, tmp); gen_lookup_tb(s); break; } @@ -6503,7 +7599,7 @@ op = (insn >> 4) & 0xf; switch (op) { case 2: /* clrex */ - gen_op_clrex(); + gen_helper_clrex(cpu_env); break; case 4: /* dsb */ case 5: /* dmb */ @@ -6517,26 +7613,28 @@ break; case 4: /* bxj */ /* Trivial implementation equivalent to bx. */ - gen_movl_T0_reg(s, rn); - gen_bx(s); + tmp = load_reg(s, rn); + gen_bx(s, tmp); break; case 5: /* Exception return. */ /* Unpredictable in user mode. */ goto illegal_op; case 6: /* mrs cpsr. */ + tmp = new_tmp(); if (IS_M(env)) { - gen_op_v7m_mrs_T0(insn & 0xff); + addr = tcg_const_i32(insn & 0xff); + gen_helper_v7m_mrs(tmp, cpu_env, addr); } else { - gen_op_movl_T0_cpsr(); + gen_helper_cpsr_read(tmp); } - gen_movl_reg_T0(s, rd); + store_reg(s, rd, tmp); break; case 7: /* mrs spsr. */ /* Not accessible in user mode. */ if (IS_USER(s) || IS_M(env)) goto illegal_op; - gen_op_movl_T0_spsr(); - gen_movl_reg_T0(s, rd); + tmp = load_cpu_field(spsr); + store_reg(s, rd, tmp); break; } } @@ -6545,7 +7643,7 @@ op = (insn >> 22) & 0xf; /* Generate a conditional jump to next instruction. */ s->condlabel = gen_new_label(); - gen_test_cc[op ^ 1](s->condlabel); + gen_test_cc(op ^ 1, s->condlabel); s->condjmp = 1; /* offset[11:1] = insn[10:0] */ @@ -6560,8 +7658,7 @@ offset |= (insn & (1 << 11)) << 8; /* jump to the offset */ - addr = s->pc + offset; - gen_jmp(s, addr); + gen_jmp(s, s->pc + offset); } } else { /* Data processing immediate. */ @@ -6573,62 +7670,63 @@ op = (insn >> 21) & 7; imm = insn & 0x1f; shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c); - if (rn == 15) - gen_op_movl_T1_im(0); - else - gen_movl_T1_reg(s, rn); + if (rn == 15) { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); + } else { + tmp = load_reg(s, rn); + } switch (op) { case 2: /* Signed bitfield extract. */ imm++; if (shift + imm > 32) goto illegal_op; if (imm < 32) - gen_op_sbfx_T1(shift, imm); + gen_sbfx(tmp, shift, imm); break; case 6: /* Unsigned bitfield extract. */ imm++; if (shift + imm > 32) goto illegal_op; if (imm < 32) - gen_op_ubfx_T1(shift, (1u << imm) - 1); + gen_ubfx(tmp, shift, (1u << imm) - 1); break; case 3: /* Bitfield insert/clear. */ if (imm < shift) goto illegal_op; imm = imm + 1 - shift; if (imm != 32) { - gen_movl_T0_reg(s, rd); - gen_op_bfi_T1_T0(shift, ((1u << imm) - 1) << shift); + tmp2 = load_reg(s, rd); + gen_bfi(tmp, tmp2, tmp, shift, (1u << imm) - 1); + dead_tmp(tmp2); } break; case 7: goto illegal_op; default: /* Saturate. */ - gen_movl_T1_reg(s, rn); if (shift) { if (op & 1) - gen_op_sarl_T1_im(shift); + tcg_gen_sari_i32(tmp, tmp, shift); else - gen_op_shll_T1_im(shift); + tcg_gen_shli_i32(tmp, tmp, shift); } + tmp2 = tcg_const_i32(imm); if (op & 4) { /* Unsigned. */ - gen_op_ssat_T1(imm); if ((op & 1) && shift == 0) - gen_op_usat16_T1(imm); + gen_helper_usat16(tmp, tmp, tmp2); else - gen_op_usat_T1(imm); + gen_helper_usat(tmp, tmp, tmp2); } else { /* Signed. */ - gen_op_ssat_T1(imm); if ((op & 1) && shift == 0) - gen_op_ssat16_T1(imm); + gen_helper_ssat16(tmp, tmp, tmp2); else - gen_op_ssat_T1(imm); + gen_helper_ssat(tmp, tmp, tmp2); } break; } - gen_movl_reg_T1(s, rd); + store_reg(s, rd, tmp); } else { imm = ((insn & 0x04000000) >> 15) | ((insn & 0x7000) >> 4) | (insn & 0xff); @@ -6637,31 +7735,33 @@ imm |= (insn >> 4) & 0xf000; if (insn & (1 << 23)) { /* movt */ - gen_movl_T0_reg(s, rd); - gen_op_movtop_T0_im(imm << 16); + tmp = load_reg(s, rd); + tcg_gen_ext16u_i32(tmp, tmp); + tcg_gen_ori_i32(tmp, tmp, imm << 16); } else { /* movw */ - gen_op_movl_T0_im(imm); + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, imm); } } else { /* Add/sub 12-bit immediate. */ if (rn == 15) { - addr = s->pc & ~(uint32_t)3; + offset = s->pc & ~(uint32_t)3; if (insn & (1 << 23)) - addr -= imm; + offset -= imm; else - addr += imm; - gen_op_movl_T0_im(addr); + offset += imm; + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, offset); } else { - gen_movl_T0_reg(s, rn); - gen_op_movl_T1_im(imm); + tmp = load_reg(s, rn); if (insn & (1 << 23)) - gen_op_subl_T0_T1(); + tcg_gen_subi_i32(tmp, tmp, imm); else - gen_op_addl_T0_T1(); + tcg_gen_addi_i32(tmp, tmp, imm); } } - gen_movl_reg_T0(s, rd); + store_reg(s, rd, tmp); } } else { int shifter_out = 0; @@ -6711,12 +7811,15 @@ { int postinc = 0; int writeback = 0; + int user; if ((insn & 0x01100000) == 0x01000000) { if (disas_neon_ls_insn(env, s, insn)) goto illegal_op; break; } + user = IS_USER(s); if (rn == 15) { + addr = new_tmp(); /* PC relative. */ /* s->pc has already been incremented by 4. */ imm = s->pc & 0xfffffffc; @@ -6724,13 +7827,13 @@ imm += insn & 0xfff; else imm -= insn & 0xfff; - gen_op_movl_T1_im(imm); + tcg_gen_movi_i32(addr, imm); } else { - gen_movl_T1_reg(s, rn); + addr = load_reg(s, rn); if (insn & (1 << 23)) { /* Positive offset. */ imm = insn & 0xfff; - gen_op_addl_T1_im(imm); + tcg_gen_addi_i32(addr, addr, imm); } else { op = (insn >> 8) & 7; imm = insn & 0xff; @@ -6739,22 +7842,23 @@ shift = (insn >> 4) & 0xf; if (shift > 3) goto illegal_op; - gen_movl_T2_reg(s, rm); + tmp = load_reg(s, rm); if (shift) - gen_op_shll_T2_im(shift); - gen_op_addl_T1_T2(); + tcg_gen_shli_i32(tmp, tmp, shift); + tcg_gen_add_i32(addr, addr, tmp); + dead_tmp(tmp); break; case 4: /* Negative offset. */ - gen_op_addl_T1_im(-imm); + tcg_gen_addi_i32(addr, addr, -imm); break; case 6: /* User privilege. */ - gen_op_addl_T1_im(imm); + tcg_gen_addi_i32(addr, addr, imm); + user = 1; break; case 1: /* Post-decrement. */ imm = -imm; /* Fall through. */ case 3: /* Post-increment. */ - gen_op_movl_T2_im(imm); postinc = 1; writeback = 1; break; @@ -6762,7 +7866,7 @@ imm = -imm; /* Fall through. */ case 7: /* Pre-increment. */ - gen_op_addl_T1_im(imm); + tcg_gen_addi_i32(addr, addr, imm); writeback = 1; break; default: @@ -6779,35 +7883,38 @@ /* Memory hint. Implemented as NOP. */ } else { switch (op) { - case 0: gen_ldst(ldub, s); break; - case 4: gen_ldst(ldsb, s); break; - case 1: gen_ldst(lduw, s); break; - case 5: gen_ldst(ldsw, s); break; - case 2: gen_ldst(ldl, s); break; + case 0: tmp = gen_ld8u(addr, user); break; + case 4: tmp = gen_ld8s(addr, user); break; + case 1: tmp = gen_ld16u(addr, user); break; + case 5: tmp = gen_ld16s(addr, user); break; + case 2: tmp = gen_ld32(addr, user); break; default: goto illegal_op; } if (rs == 15) { - gen_bx(s); + gen_bx(s, tmp); } else { - gen_movl_reg_T0(s, rs); + store_reg(s, rs, tmp); } } } else { /* Store. */ if (rs == 15) goto illegal_op; - gen_movl_T0_reg(s, rs); + tmp = load_reg(s, rs); switch (op) { - case 0: gen_ldst(stb, s); break; - case 1: gen_ldst(stw, s); break; - case 2: gen_ldst(stl, s); break; + case 0: gen_st8(tmp, addr, user); break; + case 1: gen_st16(tmp, addr, user); break; + case 2: gen_st32(tmp, addr, user); break; default: goto illegal_op; } } if (postinc) - gen_op_addl_T1_im(imm); - if (writeback) - gen_movl_reg_T1(s, rn); + tcg_gen_addi_i32(addr, addr, imm); + if (writeback) { + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } } break; default: @@ -6823,11 +7930,14 @@ uint32_t val, insn, op, rm, rn, rd, shift, cond; int32_t offset; int i; + TCGv tmp; + TCGv tmp2; + TCGv addr; if (s->condexec_mask) { cond = s->condexec_cond; s->condlabel = gen_new_label(); - gen_test_cc[cond ^ 1](s->condlabel); + gen_test_cc(cond ^ 1, s->condlabel); s->condjmp = 1; } @@ -6866,12 +7976,11 @@ /* shift immediate */ rm = (insn >> 3) & 7; shift = (insn >> 6) & 0x1f; - gen_movl_T0_reg(s, rm); - if (s->condexec_mask) - gen_shift_T0_im_thumb[op](shift); - else - gen_shift_T0_im_thumb_cc[op](shift); - gen_movl_reg_T0(s, rd); + tmp = load_reg(s, rm); + gen_arm_shift_im(tmp, op, shift, s->condexec_mask == 0); + if (!s->condexec_mask) + gen_logic_CC(tmp); + store_reg(s, rd, tmp); } break; case 2: case 3: @@ -6914,9 +8023,11 @@ /* load pc-relative. Bit 1 of PC is ignored. */ val = s->pc + 2 + ((insn & 0xff) * 4); val &= ~(uint32_t)2; - gen_op_movl_T1_im(val); - gen_ldst(ldl, s); - gen_movl_reg_T0(s, rd); + addr = new_tmp(); + tcg_gen_movi_i32(addr, val); + tmp = gen_ld32(addr, IS_USER(s)); + dead_tmp(addr); + store_reg(s, rd, tmp); break; } if (insn & (1 << 10)) { @@ -6941,13 +8052,14 @@ gen_movl_reg_T0(s, rd); break; case 3:/* branch [and link] exchange thumb register */ + tmp = load_reg(s, rm); if (insn & (1 << 7)) { val = (uint32_t)s->pc | 1; - gen_op_movl_T1_im(val); - gen_movl_reg_T1(s, 14); + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, val); + store_reg(s, 14, tmp2); } - gen_movl_T0_reg(s, rm); - gen_bx(s); + gen_bx(s, tmp); break; } break; @@ -6986,45 +8098,45 @@ break; case 0x2: /* lsl */ if (s->condexec_mask) { - gen_op_shll_T1_T0(); + gen_helper_shl(cpu_T[1], cpu_T[1], cpu_T[0]); } else { - gen_op_shll_T1_T0_cc(); + gen_helper_shl_cc(cpu_T[1], cpu_T[1], cpu_T[0]); gen_op_logic_T1_cc(); } break; case 0x3: /* lsr */ if (s->condexec_mask) { - gen_op_shrl_T1_T0(); + gen_helper_shr(cpu_T[1], cpu_T[1], cpu_T[0]); } else { - gen_op_shrl_T1_T0_cc(); + gen_helper_shr_cc(cpu_T[1], cpu_T[1], cpu_T[0]); gen_op_logic_T1_cc(); } break; case 0x4: /* asr */ if (s->condexec_mask) { - gen_op_sarl_T1_T0(); + gen_helper_sar(cpu_T[1], cpu_T[1], cpu_T[0]); } else { - gen_op_sarl_T1_T0_cc(); + gen_helper_sar_cc(cpu_T[1], cpu_T[1], cpu_T[0]); gen_op_logic_T1_cc(); } break; case 0x5: /* adc */ if (s->condexec_mask) - gen_op_adcl_T0_T1(); + gen_adc_T0_T1(); else gen_op_adcl_T0_T1_cc(); break; case 0x6: /* sbc */ if (s->condexec_mask) - gen_op_sbcl_T0_T1(); + gen_sbc_T0_T1(); else gen_op_sbcl_T0_T1_cc(); break; case 0x7: /* ror */ if (s->condexec_mask) { - gen_op_rorl_T1_T0(); + gen_helper_ror(cpu_T[1], cpu_T[1], cpu_T[0]); } else { - gen_op_rorl_T1_T0_cc(); + gen_helper_ror_cc(cpu_T[1], cpu_T[1], cpu_T[0]); gen_op_logic_T1_cc(); } break; @@ -7035,7 +8147,7 @@ break; case 0x9: /* neg */ if (s->condexec_mask) - gen_op_subl_T0_T1(); + tcg_gen_neg_i32(cpu_T[0], cpu_T[1]); else gen_op_subl_T0_T1_cc(); break; @@ -7084,120 +8196,122 @@ rn = (insn >> 3) & 7; rm = (insn >> 6) & 7; op = (insn >> 9) & 7; - gen_movl_T1_reg(s, rn); - gen_movl_T2_reg(s, rm); - gen_op_addl_T1_T2(); + addr = load_reg(s, rn); + tmp = load_reg(s, rm); + tcg_gen_add_i32(addr, addr, tmp); + dead_tmp(tmp); if (op < 3) /* store */ - gen_movl_T0_reg(s, rd); + tmp = load_reg(s, rd); switch (op) { case 0: /* str */ - gen_ldst(stl, s); + gen_st32(tmp, addr, IS_USER(s)); break; case 1: /* strh */ - gen_ldst(stw, s); + gen_st16(tmp, addr, IS_USER(s)); break; case 2: /* strb */ - gen_ldst(stb, s); + gen_st8(tmp, addr, IS_USER(s)); break; case 3: /* ldrsb */ - gen_ldst(ldsb, s); + tmp = gen_ld8s(addr, IS_USER(s)); break; case 4: /* ldr */ - gen_ldst(ldl, s); + tmp = gen_ld32(addr, IS_USER(s)); break; case 5: /* ldrh */ - gen_ldst(lduw, s); + tmp = gen_ld16u(addr, IS_USER(s)); break; case 6: /* ldrb */ - gen_ldst(ldub, s); + tmp = gen_ld8u(addr, IS_USER(s)); break; case 7: /* ldrsh */ - gen_ldst(ldsw, s); + tmp = gen_ld16s(addr, IS_USER(s)); break; } if (op >= 3) /* load */ - gen_movl_reg_T0(s, rd); + store_reg(s, rd, tmp); + dead_tmp(addr); break; case 6: /* load/store word immediate offset */ rd = insn & 7; rn = (insn >> 3) & 7; - gen_movl_T1_reg(s, rn); + addr = load_reg(s, rn); val = (insn >> 4) & 0x7c; - gen_op_movl_T2_im(val); - gen_op_addl_T1_T2(); + tcg_gen_addi_i32(addr, addr, val); if (insn & (1 << 11)) { /* load */ - gen_ldst(ldl, s); - gen_movl_reg_T0(s, rd); + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, rd, tmp); } else { /* store */ - gen_movl_T0_reg(s, rd); - gen_ldst(stl, s); + tmp = load_reg(s, rd); + gen_st32(tmp, addr, IS_USER(s)); } + dead_tmp(addr); break; case 7: /* load/store byte immediate offset */ rd = insn & 7; rn = (insn >> 3) & 7; - gen_movl_T1_reg(s, rn); + addr = load_reg(s, rn); val = (insn >> 6) & 0x1f; - gen_op_movl_T2_im(val); - gen_op_addl_T1_T2(); + tcg_gen_addi_i32(addr, addr, val); if (insn & (1 << 11)) { /* load */ - gen_ldst(ldub, s); - gen_movl_reg_T0(s, rd); + tmp = gen_ld8u(addr, IS_USER(s)); + store_reg(s, rd, tmp); } else { /* store */ - gen_movl_T0_reg(s, rd); - gen_ldst(stb, s); + tmp = load_reg(s, rd); + gen_st8(tmp, addr, IS_USER(s)); } + dead_tmp(addr); break; case 8: /* load/store halfword immediate offset */ rd = insn & 7; rn = (insn >> 3) & 7; - gen_movl_T1_reg(s, rn); + addr = load_reg(s, rn); val = (insn >> 5) & 0x3e; - gen_op_movl_T2_im(val); - gen_op_addl_T1_T2(); + tcg_gen_addi_i32(addr, addr, val); if (insn & (1 << 11)) { /* load */ - gen_ldst(lduw, s); - gen_movl_reg_T0(s, rd); + tmp = gen_ld16u(addr, IS_USER(s)); + store_reg(s, rd, tmp); } else { /* store */ - gen_movl_T0_reg(s, rd); - gen_ldst(stw, s); + tmp = load_reg(s, rd); + gen_st16(tmp, addr, IS_USER(s)); } + dead_tmp(addr); break; case 9: /* load/store from stack */ rd = (insn >> 8) & 7; - gen_movl_T1_reg(s, 13); + addr = load_reg(s, 13); val = (insn & 0xff) * 4; - gen_op_movl_T2_im(val); - gen_op_addl_T1_T2(); + tcg_gen_addi_i32(addr, addr, val); if (insn & (1 << 11)) { /* load */ - gen_ldst(ldl, s); - gen_movl_reg_T0(s, rd); + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, rd, tmp); } else { /* store */ - gen_movl_T0_reg(s, rd); - gen_ldst(stl, s); + tmp = load_reg(s, rd); + gen_st32(tmp, addr, IS_USER(s)); } + dead_tmp(addr); break; case 10: @@ -7205,15 +8319,15 @@ rd = (insn >> 8) & 7; if (insn & (1 << 11)) { /* SP */ - gen_movl_T0_reg(s, 13); + tmp = load_reg(s, 13); } else { /* PC. bit 1 is ignored. */ - gen_op_movl_T0_im((s->pc + 2) & ~(uint32_t)2); + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, (s->pc + 2) & ~(uint32_t)2); } val = (insn & 0xff) * 4; - gen_op_movl_T1_im(val); - gen_op_addl_T0_T1(); - gen_movl_reg_T0(s, rd); + tcg_gen_addi_i32(tmp, tmp, val); + store_reg(s, rd, tmp); break; case 11: @@ -7222,31 +8336,30 @@ switch (op) { case 0: /* adjust stack pointer */ - gen_movl_T1_reg(s, 13); + tmp = load_reg(s, 13); val = (insn & 0x7f) * 4; if (insn & (1 << 7)) - val = -(int32_t)val; - gen_op_movl_T2_im(val); - gen_op_addl_T1_T2(); - gen_movl_reg_T1(s, 13); + val = -(int32_t)val; + tcg_gen_addi_i32(tmp, tmp, val); + store_reg(s, 13, tmp); break; case 2: /* sign/zero extend. */ ARCH(6); rd = insn & 7; rm = (insn >> 3) & 7; - gen_movl_T1_reg(s, rm); + tmp = load_reg(s, rm); switch ((insn >> 6) & 3) { - case 0: gen_op_sxth_T1(); break; - case 1: gen_op_sxtb_T1(); break; - case 2: gen_op_uxth_T1(); break; - case 3: gen_op_uxtb_T1(); break; + case 0: gen_sxth(tmp); break; + case 1: gen_sxtb(tmp); break; + case 2: gen_uxth(tmp); break; + case 3: gen_uxtb(tmp); break; } - gen_movl_reg_T1(s, rd); + store_reg(s, rd, tmp); break; case 4: case 5: case 0xc: case 0xd: /* push/pop */ - gen_movl_T1_reg(s, 13); + addr = load_reg(s, 13); if (insn & (1 << 8)) offset = 4; else @@ -7256,59 +8369,57 @@ offset += 4; } if ((insn & (1 << 11)) == 0) { - gen_op_movl_T2_im(-offset); - gen_op_addl_T1_T2(); + tcg_gen_addi_i32(addr, addr, -offset); } - gen_op_movl_T2_im(4); for (i = 0; i < 8; i++) { if (insn & (1 << i)) { if (insn & (1 << 11)) { /* pop */ - gen_ldst(ldl, s); - gen_movl_reg_T0(s, i); + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, i, tmp); } else { /* push */ - gen_movl_T0_reg(s, i); - gen_ldst(stl, s); + tmp = load_reg(s, i); + gen_st32(tmp, addr, IS_USER(s)); } /* advance to the next address. */ - gen_op_addl_T1_T2(); + tcg_gen_addi_i32(addr, addr, 4); } } + TCGV_UNUSED(tmp); if (insn & (1 << 8)) { if (insn & (1 << 11)) { /* pop pc */ - gen_ldst(ldl, s); + tmp = gen_ld32(addr, IS_USER(s)); /* don't set the pc until the rest of the instruction has completed */ } else { /* push lr */ - gen_movl_T0_reg(s, 14); - gen_ldst(stl, s); + tmp = load_reg(s, 14); + gen_st32(tmp, addr, IS_USER(s)); } - gen_op_addl_T1_T2(); + tcg_gen_addi_i32(addr, addr, 4); } if ((insn & (1 << 11)) == 0) { - gen_op_movl_T2_im(-offset); - gen_op_addl_T1_T2(); + tcg_gen_addi_i32(addr, addr, -offset); } /* write back the new stack pointer */ - gen_movl_reg_T1(s, 13); + store_reg(s, 13, addr); /* set the new PC value */ if ((insn & 0x0900) == 0x0900) - gen_bx(s); + gen_bx(s, tmp); break; case 1: case 3: case 9: case 11: /* czb */ rm = insn & 7; - gen_movl_T0_reg(s, rm); + tmp = load_reg(s, rm); s->condlabel = gen_new_label(); s->condjmp = 1; if (insn & (1 << 11)) - gen_op_testn_T0(s->condlabel); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, s->condlabel); else - gen_op_test_T0(s->condlabel); - + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, s->condlabel); + dead_tmp(tmp); offset = ((insn & 0xf8) >> 2) | (insn & 0x200) >> 3; val = (uint32_t)s->pc + 2; val += offset; @@ -7328,9 +8439,8 @@ case 0xe: /* bkpt */ gen_set_condexec(s); - gen_op_movl_T0_im((long)s->pc - 2); - gen_op_movl_reg_TN[0][15](); - gen_op_bkpt(); + gen_set_pc_im(s->pc - 2); + gen_exception(EXCP_BKPT); s->is_jmp = DISAS_JUMP; break; @@ -7338,14 +8448,14 @@ ARCH(6); rn = (insn >> 3) & 0x7; rd = insn & 0x7; - gen_movl_T0_reg(s, rn); + tmp = load_reg(s, rn); switch ((insn >> 6) & 3) { - case 0: gen_op_rev_T0(); break; - case 1: gen_op_rev16_T0(); break; - case 3: gen_op_revsh_T0(); break; + case 0: tcg_gen_bswap_i32(tmp, tmp); break; + case 1: gen_rev16(tmp); break; + case 3: gen_revsh(tmp); break; default: goto illegal_op; } - gen_movl_reg_T0(s, rd); + store_reg(s, rd, tmp); break; case 6: /* cps */ @@ -7353,15 +8463,17 @@ if (IS_USER(s)) break; if (IS_M(env)) { - val = (insn & (1 << 4)) != 0; - gen_op_movl_T0_im(val); + tmp = tcg_const_i32((insn & (1 << 4)) != 0); /* PRIMASK */ - if (insn & 1) - gen_op_v7m_msr_T0(16); + if (insn & 1) { + addr = tcg_const_i32(16); + gen_helper_v7m_msr(cpu_env, addr, tmp); + } /* FAULTMASK */ - if (insn & 2) - gen_op_v7m_msr_T0(17); - + if (insn & 2) { + addr = tcg_const_i32(17); + gen_helper_v7m_msr(cpu_env, addr, tmp); + } gen_lookup_tb(s); } else { if (insn & (1 << 4)) @@ -7383,26 +8495,28 @@ case 12: /* load/store multiple */ rn = (insn >> 8) & 0x7; - gen_movl_T1_reg(s, rn); - gen_op_movl_T2_im(4); + addr = load_reg(s, rn); for (i = 0; i < 8; i++) { if (insn & (1 << i)) { if (insn & (1 << 11)) { /* load */ - gen_ldst(ldl, s); - gen_movl_reg_T0(s, i); + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, i, tmp); } else { /* store */ - gen_movl_T0_reg(s, i); - gen_ldst(stl, s); + tmp = load_reg(s, i); + gen_st32(tmp, addr, IS_USER(s)); } /* advance to the next address */ - gen_op_addl_T1_T2(); + tcg_gen_addi_i32(addr, addr, 4); } } /* Base register writeback. */ - if ((insn & (1 << rn)) == 0) - gen_movl_reg_T1(s, rn); + if ((insn & (1 << rn)) == 0) { + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } break; case 13: @@ -7414,15 +8528,13 @@ if (cond == 0xf) { /* swi */ gen_set_condexec(s); - gen_op_movl_T0_im((long)s->pc | 1); - /* Don't set r15. */ - gen_op_movl_reg_TN[0][15](); + gen_set_pc_im(s->pc); s->is_jmp = DISAS_SWI; break; } /* generate a conditional jump to next instruction */ s->condlabel = gen_new_label(); - gen_test_cc[cond ^ 1](s->condlabel); + gen_test_cc(cond ^ 1, s->condlabel); s->condjmp = 1; gen_movl_T1_reg(s, 15); @@ -7448,47 +8560,48 @@ case 15: if (disas_thumb2_insn(env, s, insn)) - goto undef32; + goto undef32; break; } return; undef32: gen_set_condexec(s); - gen_op_movl_T0_im((long)s->pc - 4); - gen_op_movl_reg_TN[0][15](); - gen_op_undef_insn(); + gen_set_pc_im(s->pc - 4); + gen_exception(EXCP_UDEF); s->is_jmp = DISAS_JUMP; return; illegal_op: undef: gen_set_condexec(s); - gen_op_movl_T0_im((long)s->pc - 2); - gen_op_movl_reg_TN[0][15](); - gen_op_undef_insn(); + gen_set_pc_im(s->pc - 2); + gen_exception(EXCP_UDEF); s->is_jmp = DISAS_JUMP; } /* generate intermediate code in gen_opc_buf and gen_opparam_buf for basic block 'tb'. If search_pc is TRUE, also generate PC information for each intermediate instruction. */ -static inline int gen_intermediate_code_internal(CPUState *env, - TranslationBlock *tb, - int search_pc) +static inline void gen_intermediate_code_internal(CPUState *env, + TranslationBlock *tb, + int search_pc) { DisasContext dc1, *dc = &dc1; uint16_t *gen_opc_end; int j, lj; target_ulong pc_start; uint32_t next_page_start; + int num_insns; + int max_insns; /* generate intermediate code */ + num_temps = 0; + memset(temps, 0, sizeof(temps)); + pc_start = tb->pc; dc->tb = tb; - gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; - gen_opparam_ptr = gen_opparam_buf; dc->is_jmp = DISAS_NEXT; dc->pc = pc_start; @@ -7505,19 +8618,47 @@ dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR; } #endif + cpu_F0s = tcg_temp_new(TCG_TYPE_I32); + cpu_F1s = tcg_temp_new(TCG_TYPE_I32); + cpu_F0d = tcg_temp_new(TCG_TYPE_I64); + cpu_F1d = tcg_temp_new(TCG_TYPE_I64); + cpu_V0 = cpu_F0d; + cpu_V1 = cpu_F1d; + /* FIXME: cpu_M0 can probably be the same as cpu_V0. */ + cpu_M0 = tcg_temp_new(TCG_TYPE_I64); next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; - nb_gen_labels = 0; lj = -1; + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + if (max_insns == 0) + max_insns = CF_COUNT_MASK; + + gen_icount_start(); /* Reset the conditional execution bits immediately. This avoids complications trying to do it at the end of the block. */ if (env->condexec_bits) - gen_op_set_condexec(0); + { + TCGv tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); + store_cpu_field(tmp, condexec_bits); + } do { -#ifndef CONFIG_USER_ONLY +#ifdef CONFIG_USER_ONLY + /* Intercept jump to the magic kernel page. */ + if (dc->pc >= 0xffff0000) { + /* We always get here via a jump, so know we are not in a + conditional execution block. */ + gen_exception(EXCP_KERNEL_TRAP); + dc->is_jmp = DISAS_UPDATE; + break; + } +#else if (dc->pc >= 0xfffffff0 && IS_M(env)) { /* We always get here via a jump, so know we are not in a conditional execution block. */ - gen_op_exception_exit(); + gen_exception(EXCP_EXCEPTION_EXIT); + dc->is_jmp = DISAS_UPDATE; + break; } #endif @@ -7525,9 +8666,8 @@ for(j = 0; j < env->nb_breakpoints; j++) { if (env->breakpoints[j] == dc->pc) { gen_set_condexec(dc); - gen_op_movl_T0_im((long)dc->pc); - gen_op_movl_reg_TN[0][15](); - gen_op_debug(); + gen_set_pc_im(dc->pc); + gen_exception(EXCP_DEBUG); dc->is_jmp = DISAS_JUMP; /* Advance PC so that clearing the breakpoint will invalidate this TB. */ @@ -7546,8 +8686,12 @@ } gen_opc_pc[lj] = dc->pc; gen_opc_instr_start[lj] = 1; + gen_opc_icount[lj] = num_insns; } + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) + gen_io_start(); + if (env->thumb) { disas_thumb_insn(env, dc); if (dc->condexec_mask) { @@ -7561,6 +8705,10 @@ } else { disas_arm_insn(env, dc); } + if (num_temps) { + fprintf(stderr, "Internal resource leak before %08x\n", dc->pc); + num_temps = 0; + } if (dc->condjmp && !dc->is_jmp) { gen_set_label(dc->condlabel); @@ -7575,37 +8723,47 @@ /* Translation stops when a conditional branch is enoutered. * Otherwise the subsequent code could get translated several times. * Also stop translation when a page boundary is reached. This - * ensures prefech aborts occur at the right place. */ + * ensures prefetch aborts occur at the right place. */ + num_insns ++; } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && !env->singlestep_enabled && - dc->pc < next_page_start); + dc->pc < next_page_start && + num_insns < max_insns); + + if (tb->cflags & CF_LAST_IO) { + if (dc->condjmp) { + /* FIXME: This can theoretically happen with self-modifying + code. */ + cpu_abort(env, "IO on conditional branch instruction"); + } + gen_io_end(); + } /* At this stage dc->condjmp will only be set when the skipped instruction was a conditional branch or trap, and the PC has already been written. */ - if (__builtin_expect(env->singlestep_enabled, 0)) { + if (unlikely(env->singlestep_enabled)) { /* Make sure the pc is updated, and raise a debug exception. */ if (dc->condjmp) { gen_set_condexec(dc); if (dc->is_jmp == DISAS_SWI) { - gen_op_swi(); + gen_exception(EXCP_SWI); } else { - gen_op_debug(); + gen_exception(EXCP_DEBUG); } gen_set_label(dc->condlabel); } if (dc->condjmp || !dc->is_jmp) { - gen_op_movl_T0_im((long)dc->pc); - gen_op_movl_reg_TN[0][15](); + gen_set_pc_im(dc->pc); dc->condjmp = 0; } gen_set_condexec(dc); if (dc->is_jmp == DISAS_SWI && !dc->condjmp) { - gen_op_swi(); + gen_exception(EXCP_SWI); } else { /* FIXME: Single stepping a WFI insn will not halt the CPU. */ - gen_op_debug(); + gen_exception(EXCP_DEBUG); } } else { /* While branches must always occur at the end of an IT block, @@ -7625,17 +8783,16 @@ case DISAS_JUMP: case DISAS_UPDATE: /* indicate that the hash table must be used to find the next TB */ - gen_op_movl_T0_0(); - gen_op_exit_tb(); + tcg_gen_exit_tb(0); break; case DISAS_TB_JUMP: /* nothing more to generate */ break; case DISAS_WFI: - gen_op_wfi(); + gen_helper_wfi(); break; case DISAS_SWI: - gen_op_swi(); + gen_exception(EXCP_SWI); break; } if (dc->condjmp) { @@ -7645,7 +8802,9 @@ dc->condjmp = 0; } } + done_generating: + gen_icount_end(tb, num_insns); *gen_opc_ptr = INDEX_op_end; #ifdef DEBUG_DISAS @@ -7654,11 +8813,6 @@ fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); target_disas(logfile, pc_start, dc->pc - pc_start, env->thumb); fprintf(logfile, "\n"); - if (loglevel & (CPU_LOG_TB_OP)) { - fprintf(logfile, "OP:\n"); - dump_ops(gen_opc_buf, gen_opparam_buf); - fprintf(logfile, "\n"); - } } #endif if (search_pc) { @@ -7668,18 +8822,18 @@ gen_opc_instr_start[lj++] = 0; } else { tb->size = dc->pc - pc_start; + tb->icount = num_insns; } - return 0; } -int gen_intermediate_code(CPUState *env, TranslationBlock *tb) +void gen_intermediate_code(CPUState *env, TranslationBlock *tb) { - return gen_intermediate_code_internal(env, tb, 0); + gen_intermediate_code_internal(env, tb, 0); } -int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) +void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) { - return gen_intermediate_code_internal(env, tb, 1); + gen_intermediate_code_internal(env, tb, 1); } static const char *cpu_mode_names[16] = { @@ -7692,6 +8846,7 @@ int flags) { int i; +#if 0 union { uint32_t i; float s; @@ -7703,6 +8858,7 @@ float64 f64; double d; } d0; +#endif uint32_t psr; for(i=0;i<16;i++) { @@ -7722,6 +8878,7 @@ psr & CPSR_T ? 'T' : 'A', cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26); +#if 0 for (i = 0; i < 16; i++) { d.d = env->vfp.regs[i]; s0.i = d.l.lower; @@ -7734,5 +8891,11 @@ d0.d); } cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]); +#endif } +void gen_pc_load(CPUState *env, TranslationBlock *tb, + unsigned long searched_pc, int pc_pos, void *puc) +{ + env->regs[15] = gen_opc_pc[pc_pos]; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-cris/cpu.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-cris/cpu.h --- qemu-0.9.1/target-cris/cpu.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-cris/cpu.h 2008-10-06 19:46:28.000000000 +0100 @@ -25,20 +25,42 @@ #include "cpu-defs.h" -#include "softfloat.h" - #define TARGET_HAS_ICE 1 #define ELF_MACHINE EM_CRIS -#define EXCP_MMU_EXEC 0 -#define EXCP_MMU_READ 1 -#define EXCP_MMU_WRITE 2 -#define EXCP_MMU_FLUSH 3 -#define EXCP_MMU_MISS 4 -#define EXCP_BREAK 16 /* trap. */ +#define EXCP_NMI 1 +#define EXCP_GURU 2 +#define EXCP_BUSFAULT 3 +#define EXCP_IRQ 4 +#define EXCP_BREAK 5 + +/* Register aliases. R0 - R15 */ +#define R_FP 8 +#define R_SP 14 +#define R_ACR 15 + +/* Support regs, P0 - P15 */ +#define PR_BZ 0 +#define PR_VR 1 +#define PR_PID 2 +#define PR_SRS 3 +#define PR_WZ 4 +#define PR_EXS 5 +#define PR_EDA 6 +#define PR_MOF 7 +#define PR_DZ 8 +#define PR_EBP 9 +#define PR_ERP 10 +#define PR_SRP 11 +#define PR_NRP 12 +#define PR_CCS 13 +#define PR_USP 14 +#define PR_SPC 15 /* CPU flags. */ +#define Q_FLAG 0x80000000 +#define M_FLAG 0x40000000 #define S_FLAG 0x200 #define R_FLAG 0x100 #define P_FLAG 0x80 @@ -77,41 +99,20 @@ #define NB_MMU_MODES 2 typedef struct CPUCRISState { - uint32_t debug1; - uint32_t debug2; - uint32_t debug3; - - /* - * We just store the stores to the tlbset here for later evaluation - * when the hw needs access to them. - * - * One for I and another for D. - */ - struct - { - uint32_t hi; - uint32_t lo; - } tlbsets[2][4][16]; - - uint32_t sregs[256][16]; /* grrr why so many?? */ uint32_t regs[16]; + /* P0 - P15 are referred to as special registers in the docs. */ uint32_t pregs[16]; + + /* Pseudo register for the PC. Not directly accessable on CRIS. */ uint32_t pc; - uint32_t sr; - uint32_t flag_mask; /* Per insn mask of affected flags. */ - /* SSP and USP. */ - int current_sp; - uint32_t sp[2]; - - /* These are setup up by the guest code just before transfering the - control back to the host. */ - int jmp; - uint32_t btarget; - int btaken; + /* Pseudo register for the kernel stack. */ + uint32_t ksp; - /* for traps. */ - int trapnr; + /* Branch. */ + int dslot; + int btaken; + uint32_t btarget; /* Condition flag tracking. */ uint32_t cc_op; @@ -119,31 +120,41 @@ uint32_t cc_dest; uint32_t cc_src; uint32_t cc_result; - /* size of the operation, 1 = byte, 2 = word, 4 = dword. */ int cc_size; - - /* extended arithmetics. */ - int cc_x_live; + /* X flag at the time of cc snapshot. */ int cc_x; - int features; - - uint64_t pending_interrupts; - int interrupt_request; - int exception_index; - int user_mode_only; - int halted; + int interrupt_vector; + int fault_vector; + int trap_vector; + + /* FIXME: add a check in the translator to avoid writing to support + register sets beyond the 4th. The ISA allows up to 256! but in + practice there is no core that implements more than 4. + + Support function registers are used to control units close to the + core. Accesses do not pass down the normal hierarchy. + */ + uint32_t sregs[4][16]; + + /* Linear feedback shift reg in the mmu. Used to provide pseudo + randomness for the 'hint' the mmu gives to sw for chosing valid + sets on TLB refills. */ + uint32_t mmu_rand_lfsr; + /* + * We just store the stores to the tlbset here for later evaluation + * when the hw needs access to them. + * + * One for I and another for D. + */ struct { - int exec_insns; - int exec_loads; - int exec_stores; - } stats; - + uint32_t hi; + uint32_t lo; + } tlbsets[2][4][16]; - jmp_buf jmp_env; CPU_COMMON } CPUCRISState; @@ -156,20 +167,14 @@ is returned if the signal was handled by the virtual CPU. */ int cpu_cris_signal_handler(int host_signum, void *pinfo, void *puc); -void cpu_cris_flush_flags(CPUCRISState *, int); - - void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, - int is_asi); + int is_asi, int size); enum { CC_OP_DYNAMIC, /* Use env->cc_op */ CC_OP_FLAGS, - CC_OP_LOGIC, CC_OP_CMP, CC_OP_MOVE, - CC_OP_MOVE_PD, - CC_OP_MOVE_SD, CC_OP_ADD, CC_OP_ADDC, CC_OP_MCP, @@ -192,34 +197,9 @@ CC_OP_LZ }; -#define CCF_C 0x01 -#define CCF_V 0x02 -#define CCF_Z 0x04 -#define CCF_N 0x08 -#define CCF_X 0x10 - -#define CRIS_SSP 0 -#define CRIS_USP 1 - -void cris_set_irq_level(CPUCRISState *env, int level, uint8_t vector); -void cris_set_macsr(CPUCRISState *env, uint32_t val); -void cris_switch_sp(CPUCRISState *env); - -void do_cris_semihosting(CPUCRISState *env, int nr); - -enum cris_features { - CRIS_FEATURE_CF_ISA_MUL, -}; - -static inline int cris_feature(CPUCRISState *env, int feature) -{ - return (env->features & (1u << feature)) != 0; -} - -void register_cris_insns (CPUCRISState *env); - /* CRIS uses 8k pages. */ #define TARGET_PAGE_BITS 13 +#define MMAP_SHIFT TARGET_PAGE_BITS #define CPUState CPUCRISState #define cpu_init cpu_cris_init @@ -227,38 +207,37 @@ #define cpu_gen_code cpu_cris_gen_code #define cpu_signal_handler cpu_cris_signal_handler +#define CPU_SAVE_VERSION 1 + /* MMU modes definitions */ #define MMU_MODE0_SUFFIX _kernel #define MMU_MODE1_SUFFIX _user #define MMU_USER_IDX 1 -/* CRIS FIXME: I guess we want to validate supervisor mode acceses here. */ static inline int cpu_mmu_index (CPUState *env) { - return 0; + return !!(env->pregs[PR_CCS] & U_FLAG); } -#include "cpu-all.h" - -/* Register aliases. */ -#define REG_SP 14 -#define REG_ACR 15 -#define REG_MOF 7 - -/* Support regs. */ -#define SR_PID 2 -#define SR_SRS 3 -#define SR_EBP 9 -#define SR_ERP 10 -#define SR_CCS 13 +#if defined(CONFIG_USER_ONLY) +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) +{ + if (newsp) + env->regs[14] = newsp; + env->regs[10] = 0; +} +#endif -/* Support func regs. */ +/* Support function regs. */ #define SFR_RW_GC_CFG 0][0 -#define SFR_RW_MM_CFG 1][0 -#define SFR_RW_MM_KBASE_LO 1][1 -#define SFR_RW_MM_KBASE_HI 1][2 -#define SFR_R_MM_CAUSE 1][3 -#define SFR_RW_MM_TLB_SEL 1][4 -#define SFR_RW_MM_TLB_LO 1][5 -#define SFR_RW_MM_TLB_HI 1][6 +#define SFR_RW_MM_CFG env->pregs[PR_SRS]][0 +#define SFR_RW_MM_KBASE_LO env->pregs[PR_SRS]][1 +#define SFR_RW_MM_KBASE_HI env->pregs[PR_SRS]][2 +#define SFR_R_MM_CAUSE env->pregs[PR_SRS]][3 +#define SFR_RW_MM_TLB_SEL env->pregs[PR_SRS]][4 +#define SFR_RW_MM_TLB_LO env->pregs[PR_SRS]][5 +#define SFR_RW_MM_TLB_HI env->pregs[PR_SRS]][6 + +#define CPU_PC_FROM_TB(env, tb) env->pc = tb->pc +#include "cpu-all.h" #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-cris/crisv32-decode.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-cris/crisv32-decode.h --- qemu-0.9.1/target-cris/crisv32-decode.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-cris/crisv32-decode.h 2008-02-25 09:58:22.000000000 +0000 @@ -124,3 +124,6 @@ #define DEC_BASC_IM {B8(11101111), B8(11111111)} #define DEC_MOVEM_MR {B8(10111011), B8(10111111)} #define DEC_MOVEM_RM {B8(10111111), B8(10111111)} + +#define DEC_FTAG_FIDX_D_M {B8(10101011), B8(11111111)} +#define DEC_FTAG_FIDX_I_M {B8(11010011), B8(11111111)} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-cris/exec.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-cris/exec.h --- qemu-0.9.1/target-cris/exec.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-cris/exec.h 2008-10-27 20:24:59.000000000 +0000 @@ -20,17 +20,8 @@ */ #include "dyngen-exec.h" -#if 1 register struct CPUCRISState *env asm(AREG0); -/* This is only used for tb lookup. */ -register uint32_t T0 asm(AREG1); -register uint32_t T1 asm(AREG2); -#else -struct CPUCRISState *env; -/* This is only used for tb lookup. */ -uint32_t T0; -uint32_t T1; -#endif + #include "cpu.h" #include "exec-all.h" @@ -46,7 +37,6 @@ int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int mmu_idx, int is_softmmu); -void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr); #if !defined(CONFIG_USER_ONLY) #include "softmmu_exec.h" diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-cris/helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-cris/helper.c --- qemu-0.9.1/target-cris/helper.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-cris/helper.c 2008-10-08 15:22:17.000000000 +0100 @@ -28,146 +28,165 @@ #include "exec-all.h" #include "host-utils.h" +#define D(x) + #if defined(CONFIG_USER_ONLY) void do_interrupt (CPUState *env) { - env->exception_index = -1; + env->exception_index = -1; + env->pregs[PR_ERP] = env->pc; } int cpu_cris_handle_mmu_fault(CPUState * env, target_ulong address, int rw, int mmu_idx, int is_softmmu) { - env->exception_index = 0xaa; - env->debug1 = address; - cpu_dump_state(env, stderr, fprintf, 0); - printf("%s addr=%x env->pc=%x\n", __func__, address, env->pc); - return 1; + env->exception_index = 0xaa; + env->pregs[PR_EDA] = address; + cpu_dump_state(env, stderr, fprintf, 0); + return 1; } target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) { - return addr; + return addr; } #else /* !CONFIG_USER_ONLY */ + +static void cris_shift_ccs(CPUState *env) +{ + uint32_t ccs; + /* Apply the ccs shift. */ + ccs = env->pregs[PR_CCS]; + ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff; + env->pregs[PR_CCS] = ccs; +} + int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int mmu_idx, int is_softmmu) { struct cris_mmu_result_t res; int prot, miss; + int r = -1; target_ulong phy; + D(printf ("%s addr=%x pc=%x rw=%x\n", __func__, address, env->pc, rw)); address &= TARGET_PAGE_MASK; - prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; -// printf ("%s pc=%x %x w=%d smmu=%d\n", __func__, env->pc, address, rw, is_softmmu); miss = cris_mmu_translate(&res, env, address, rw, mmu_idx); if (miss) { - /* handle the miss. */ - phy = 0; - env->exception_index = EXCP_MMU_MISS; + if (env->exception_index == EXCP_BUSFAULT) + cpu_abort(env, + "CRIS: Illegal recursive bus fault." + "addr=%x rw=%d\n", + address, rw); + + env->exception_index = EXCP_BUSFAULT; + env->fault_vector = res.bf_vec; + r = 1; } else { - phy = res.phy; + /* + * Mask off the cache selection bit. The ETRAX busses do not + * see the top bit. + */ + phy = res.phy & ~0x80000000; + prot = res.prot; + r = tlb_set_page(env, address, phy, prot, mmu_idx, is_softmmu); } -// printf ("a=%x phy=%x\n", address, phy); - return tlb_set_page(env, address, phy, prot, mmu_idx, is_softmmu); -} - - -static void cris_shift_ccs(CPUState *env) -{ - uint32_t ccs; - /* Apply the ccs shift. */ - ccs = env->pregs[SR_CCS]; - ccs = (ccs & 0xc0000000) | ((ccs << 12) >> 2); -// printf ("ccs=%x %x\n", env->pregs[SR_CCS], ccs); - env->pregs[SR_CCS] = ccs; + if (r > 0) + D(fprintf(logfile, "%s returns %d irqreq=%x addr=%x" + " phy=%x ismmu=%d vec=%x pc=%x\n", + __func__, r, env->interrupt_request, + address, res.phy, is_softmmu, res.bf_vec, env->pc)); + return r; } void do_interrupt(CPUState *env) { - uint32_t ebp, isr; - int irqnum; + int ex_vec = -1; - fflush(NULL); - -#if 0 - printf ("exception index=%d interrupt_req=%d\n", - env->exception_index, - env->interrupt_request); -#endif + D(fprintf (logfile, "exception index=%d interrupt_req=%d\n", + env->exception_index, + env->interrupt_request)); switch (env->exception_index) { case EXCP_BREAK: -// printf ("BREAK! %d\n", env->trapnr); - irqnum = env->trapnr; - ebp = env->pregs[SR_EBP]; - isr = ldl_code(ebp + irqnum * 4); - env->pregs[SR_ERP] = env->pc + 2; - env->pc = isr; - - cris_shift_ccs(env); + /* These exceptions are genereated by the core itself. + ERP should point to the insn following the brk. */ + ex_vec = env->trap_vector; + env->pregs[PR_ERP] = env->pc; + break; + case EXCP_NMI: + /* NMI is hardwired to vector zero. */ + ex_vec = 0; + env->pregs[PR_CCS] &= ~M_FLAG; + env->pregs[PR_NRP] = env->pc; break; - case EXCP_MMU_MISS: -// printf ("MMU miss\n"); - irqnum = 4; - ebp = env->pregs[SR_EBP]; - isr = ldl_code(ebp + irqnum * 4); - env->pregs[SR_ERP] = env->pc; - env->pc = isr; - cris_shift_ccs(env); + + case EXCP_BUSFAULT: + ex_vec = env->fault_vector; + env->pregs[PR_ERP] = env->pc; break; default: - { - /* Maybe the irq was acked by sw before we got a - change to take it. */ - if (env->interrupt_request & CPU_INTERRUPT_HARD) { - if (!env->pending_interrupts) - return; - if (!(env->pregs[SR_CCS] & I_FLAG)) { - return; - } - - irqnum = 31 - clz32(env->pending_interrupts); - irqnum += 0x30; - ebp = env->pregs[SR_EBP]; - isr = ldl_code(ebp + irqnum * 4); - env->pregs[SR_ERP] = env->pc; - env->pc = isr; - - cris_shift_ccs(env); -#if 0 - printf ("%s ebp=%x %x isr=%x %d" - " ir=%x pending=%x\n", - __func__, - ebp, ebp + irqnum * 4, - isr, env->exception_index, - env->interrupt_request, - env->pending_interrupts); -#endif - } + /* The interrupt controller gives us the vector. */ + ex_vec = env->interrupt_vector; + /* Normal interrupts are taken between + TB's. env->pc is valid here. */ + env->pregs[PR_ERP] = env->pc; + break; + } + + /* Fill in the IDX field. */ + env->pregs[PR_EXS] = (ex_vec & 0xff) << 8; - } - break; + if (env->dslot) { + D(fprintf(logfile, "excp isr=%x PC=%x ds=%d SP=%x" + " ERP=%x pid=%x ccs=%x cc=%d %x\n", + ex_vec, env->pc, env->dslot, + env->regs[R_SP], + env->pregs[PR_ERP], env->pregs[PR_PID], + env->pregs[PR_CCS], + env->cc_op, env->cc_mask)); + /* We loose the btarget, btaken state here so rexec the + branch. */ + env->pregs[PR_ERP] -= env->dslot; + /* Exception starts with dslot cleared. */ + env->dslot = 0; } + + env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4); + + if (env->pregs[PR_CCS] & U_FLAG) { + /* Swap stack pointers. */ + env->pregs[PR_USP] = env->regs[R_SP]; + env->regs[R_SP] = env->ksp; + } + + /* Apply the CRIS CCS shift. Clears U if set. */ + cris_shift_ccs(env); + D(fprintf (logfile, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", + __func__, env->pc, ex_vec, + env->pregs[PR_CCS], + env->pregs[PR_PID], + env->pregs[PR_ERP])); } target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) { -// printf ("%s\n", __func__); uint32_t phy = addr; struct cris_mmu_result_t res; int miss; miss = cris_mmu_translate(&res, env, addr, 0, 0); if (!miss) phy = res.phy; + D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy)); return phy; } #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-cris/helper.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-cris/helper.h --- qemu-0.9.1/target-cris/helper.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-cris/helper.h 2008-10-07 23:48:41.000000000 +0100 @@ -0,0 +1,20 @@ +#define TCG_HELPER_PROTO + +void TCG_HELPER_PROTO helper_raise_exception(uint32_t index); +void TCG_HELPER_PROTO helper_tlb_flush_pid(uint32_t pid); +void TCG_HELPER_PROTO helper_spc_write(uint32_t pid); +void TCG_HELPER_PROTO helper_dump(uint32_t a0, uint32_t a1, uint32_t a2); +void TCG_HELPER_PROTO helper_rfe(void); +void TCG_HELPER_PROTO helper_rfn(void); + +void TCG_HELPER_PROTO helper_movl_sreg_reg (uint32_t sreg, uint32_t reg); +void TCG_HELPER_PROTO helper_movl_reg_sreg (uint32_t reg, uint32_t sreg); + +void TCG_HELPER_PROTO helper_evaluate_flags_muls(void); +void TCG_HELPER_PROTO helper_evaluate_flags_mulu(void); +void TCG_HELPER_PROTO helper_evaluate_flags_mcp(void); +void TCG_HELPER_PROTO helper_evaluate_flags_alu_4(void); +void TCG_HELPER_PROTO helper_evaluate_flags_move_4 (void); +void TCG_HELPER_PROTO helper_evaluate_flags_move_2 (void); +void TCG_HELPER_PROTO helper_evaluate_flags (void); +void TCG_HELPER_PROTO helper_top_evaluate_flags(void); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-cris/machine.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-cris/machine.c --- qemu-0.9.1/target-cris/machine.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-cris/machine.c 2008-06-10 00:44:20.000000000 +0100 @@ -0,0 +1,95 @@ +#include "hw/hw.h" +#include "hw/boards.h" + +void register_machines(void) +{ + qemu_register_machine(&bareetraxfs_machine); +} + +void cpu_save(QEMUFile *f, void *opaque) +{ + CPUCRISState *env = opaque; + int i; + int s; + int mmu; + + for (i = 0; i < 16; i++) + qemu_put_be32(f, env->regs[i]); + for (i = 0; i < 16; i++) + qemu_put_be32(f, env->pregs[i]); + + qemu_put_be32(f, env->pc); + qemu_put_be32(f, env->ksp); + + qemu_put_be32(f, env->dslot); + qemu_put_be32(f, env->btaken); + qemu_put_be32(f, env->btarget); + + qemu_put_be32(f, env->cc_op); + qemu_put_be32(f, env->cc_mask); + qemu_put_be32(f, env->cc_dest); + qemu_put_be32(f, env->cc_src); + qemu_put_be32(f, env->cc_result); + qemu_put_be32(f, env->cc_size); + qemu_put_be32(f, env->cc_x); + + for (s = 0; s < 4; i++) { + for (i = 0; i < 16; i++) + qemu_put_be32(f, env->sregs[s][i]); + } + + qemu_put_be32(f, env->mmu_rand_lfsr); + for (mmu = 0; mmu < 2; mmu++) { + for (s = 0; s < 4; i++) { + for (i = 0; i < 16; i++) { + qemu_put_be32(f, env->tlbsets[mmu][s][i].lo); + qemu_put_be32(f, env->tlbsets[mmu][s][i].hi); + } + } + } +} + +int cpu_load(QEMUFile *f, void *opaque, int version_id) +{ + CPUCRISState *env = opaque; + int i; + int s; + int mmu; + + for (i = 0; i < 16; i++) + env->regs[i] = qemu_get_be32(f); + for (i = 0; i < 16; i++) + env->pregs[i] = qemu_get_be32(f); + + env->pc = qemu_get_be32(f); + env->ksp = qemu_get_be32(f); + + env->dslot = qemu_get_be32(f); + env->btaken = qemu_get_be32(f); + env->btarget = qemu_get_be32(f); + + env->cc_op = qemu_get_be32(f); + env->cc_mask = qemu_get_be32(f); + env->cc_dest = qemu_get_be32(f); + env->cc_src = qemu_get_be32(f); + env->cc_result = qemu_get_be32(f); + env->cc_size = qemu_get_be32(f); + env->cc_x = qemu_get_be32(f); + + for (s = 0; s < 4; i++) { + for (i = 0; i < 16; i++) + env->sregs[s][i] = qemu_get_be32(f); + } + + env->mmu_rand_lfsr = qemu_get_be32(f); + for (mmu = 0; mmu < 2; mmu++) { + for (s = 0; s < 4; i++) { + for (i = 0; i < 16; i++) { + env->tlbsets[mmu][s][i].lo = qemu_get_be32(f); + env->tlbsets[mmu][s][i].hi = qemu_get_be32(f); + } + } + } + + return 0; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-cris/mmu.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-cris/mmu.c --- qemu-0.9.1/target-cris/mmu.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-cris/mmu.c 2008-09-22 21:51:28.000000000 +0100 @@ -30,13 +30,36 @@ #include "mmu.h" #include "exec-all.h" +#ifdef DEBUG +#define D(x) x +#else +#define D(x) +#endif + +void cris_mmu_init(CPUState *env) +{ + env->mmu_rand_lfsr = 0xcccc; +} -static int cris_mmu_enabled(uint32_t rw_gc_cfg) +#define SR_POLYNOM 0x8805 +static inline unsigned int compute_polynom(unsigned int sr) +{ + unsigned int i; + unsigned int f; + + f = 0; + for (i = 0; i < 16; i++) + f += ((SR_POLYNOM >> i) & 1) & ((sr >> i) & 1); + + return f; +} + +static inline int cris_mmu_enabled(uint32_t rw_gc_cfg) { return (rw_gc_cfg & 12) != 0; } -static int cris_mmu_segmented_addr(int seg, uint32_t rw_mm_cfg) +static inline int cris_mmu_segmented_addr(int seg, uint32_t rw_mm_cfg) { return (1 << seg) & rw_mm_cfg; } @@ -60,55 +83,250 @@ } /* Used by the tlb decoder. */ #define EXTRACT_FIELD(src, start, end) \ - (((src) >> start) & ((1 << (end - start + 1)) - 1)) + (((src) >> start) & ((1 << (end - start + 1)) - 1)) + +static inline void set_field(uint32_t *dst, unsigned int val, + unsigned int offset, unsigned int width) +{ + uint32_t mask; + + mask = (1 << width) - 1; + mask <<= offset; + val <<= offset; + + val &= mask; + *dst &= ~(mask); + *dst |= val; +} +#ifdef DEBUG +static void dump_tlb(CPUState *env, int mmu) +{ + int set; + int idx; + uint32_t hi, lo, tlb_vpn, tlb_pfn; + + for (set = 0; set < 4; set++) { + for (idx = 0; idx < 16; idx++) { + lo = env->tlbsets[mmu][set][idx].lo; + hi = env->tlbsets[mmu][set][idx].hi; + tlb_vpn = EXTRACT_FIELD(hi, 13, 31); + tlb_pfn = EXTRACT_FIELD(lo, 13, 31); + + printf ("TLB: [%d][%d] hi=%x lo=%x v=%x p=%x\n", + set, idx, hi, lo, tlb_vpn, tlb_pfn); + } + } +} +#endif + +/* rw 0 = read, 1 = write, 2 = exec. */ static int cris_mmu_translate_page(struct cris_mmu_result_t *res, CPUState *env, uint32_t vaddr, int rw, int usermode) { unsigned int vpage; unsigned int idx; - uint32_t lo, hi; - uint32_t vpn, pfn = 0, pid, fg, fv, fk, fw, fx; - int i, match = 0; + uint32_t pid, lo, hi; + uint32_t tlb_vpn, tlb_pfn = 0; + int tlb_pid, tlb_g, tlb_v, tlb_k, tlb_w, tlb_x; + int cfg_v, cfg_k, cfg_w, cfg_x; + int set, match = 0; + uint32_t r_cause; + uint32_t r_cfg; + int rwcause; + int mmu = 1; /* Data mmu is default. */ + int vect_base; + + r_cause = env->sregs[SFR_R_MM_CAUSE]; + r_cfg = env->sregs[SFR_RW_MM_CFG]; + pid = env->pregs[PR_PID] & 0xff; + + switch (rw) { + case 2: rwcause = CRIS_MMU_ERR_EXEC; mmu = 0; break; + case 1: rwcause = CRIS_MMU_ERR_WRITE; break; + default: + case 0: rwcause = CRIS_MMU_ERR_READ; break; + } + + /* I exception vectors 4 - 7, D 8 - 11. */ + vect_base = (mmu + 1) * 4; vpage = vaddr >> 13; - idx = vpage & 31; - vpage >>= 4; /* We know the index which to check on each set. Scan both I and D. */ - for (i = 0; i < 4; i++) - { - lo = env->tlbsets[0][i][idx].lo; - hi = env->tlbsets[0][i][idx].hi; +#if 0 + for (set = 0; set < 4; set++) { + for (idx = 0; idx < 16; idx++) { + lo = env->tlbsets[mmu][set][idx].lo; + hi = env->tlbsets[mmu][set][idx].hi; + tlb_vpn = EXTRACT_FIELD(hi, 13, 31); + tlb_pfn = EXTRACT_FIELD(lo, 13, 31); - vpn = EXTRACT_FIELD(hi, 13, 31); - pid = EXTRACT_FIELD(hi, 0, 7); + printf ("TLB: [%d][%d] hi=%x lo=%x v=%x p=%x\n", + set, idx, hi, lo, tlb_vpn, tlb_pfn); + } + } +#endif + + idx = vpage & 15; + for (set = 0; set < 4; set++) + { + lo = env->tlbsets[mmu][set][idx].lo; + hi = env->tlbsets[mmu][set][idx].hi; - if (vpn == vpage - && pid == env->pregs[SR_PID]) { + tlb_vpn = hi >> 13; + tlb_pid = EXTRACT_FIELD(hi, 0, 7); + tlb_g = EXTRACT_FIELD(lo, 4, 4); + + D(fprintf(logfile, + "TLB[%d][%d][%d] v=%x vpage=%x lo=%x hi=%x\n", + mmu, set, idx, tlb_vpn, vpage, lo, hi)); + if ((tlb_g || (tlb_pid == pid)) + && tlb_vpn == vpage) { match = 1; break; } } + res->bf_vec = vect_base; if (match) { - pfn = EXTRACT_FIELD(lo, 13, 31); - fg = EXTRACT_FIELD(lo, 4, 4); - fv = EXTRACT_FIELD(lo, 3, 3); - fk = EXTRACT_FIELD(lo, 2, 2); - fw = EXTRACT_FIELD(lo, 1, 1); - fx = EXTRACT_FIELD(lo, 0, 0); - } - printf ("%s match=%d vaddr=%x vpage=%x vpn=%x pfn=%x pid=%x %x\n", - __func__, match, - vaddr, vpage, - vpn, pfn, pid, env->pregs[SR_PID]); - res->pfn = pfn; + cfg_w = EXTRACT_FIELD(r_cfg, 19, 19); + cfg_k = EXTRACT_FIELD(r_cfg, 18, 18); + cfg_x = EXTRACT_FIELD(r_cfg, 17, 17); + cfg_v = EXTRACT_FIELD(r_cfg, 16, 16); + + tlb_pfn = EXTRACT_FIELD(lo, 13, 31); + tlb_v = EXTRACT_FIELD(lo, 3, 3); + tlb_k = EXTRACT_FIELD(lo, 2, 2); + tlb_w = EXTRACT_FIELD(lo, 1, 1); + tlb_x = EXTRACT_FIELD(lo, 0, 0); + + /* + set_exception_vector(0x04, i_mmu_refill); + set_exception_vector(0x05, i_mmu_invalid); + set_exception_vector(0x06, i_mmu_access); + set_exception_vector(0x07, i_mmu_execute); + set_exception_vector(0x08, d_mmu_refill); + set_exception_vector(0x09, d_mmu_invalid); + set_exception_vector(0x0a, d_mmu_access); + set_exception_vector(0x0b, d_mmu_write); + */ + if (cfg_k && tlb_k && usermode) { + D(printf ("tlb: kernel protected %x lo=%x pc=%x\n", + vaddr, lo, env->pc)); + match = 0; + res->bf_vec = vect_base + 2; + } else if (rw == 1 && cfg_w && !tlb_w) { + D(printf ("tlb: write protected %x lo=%x pc=%x\n", + vaddr, lo, env->pc)); + match = 0; + /* write accesses never go through the I mmu. */ + res->bf_vec = vect_base + 3; + } else if (rw == 2 && cfg_x && !tlb_x) { + D(printf ("tlb: exec protected %x lo=%x pc=%x\n", + vaddr, lo, env->pc)); + match = 0; + res->bf_vec = vect_base + 3; + } else if (cfg_v && !tlb_v) { + D(printf ("tlb: invalid %x\n", vaddr)); + match = 0; + res->bf_vec = vect_base + 1; + } + + res->prot = 0; + if (match) { + res->prot |= PAGE_READ; + if (tlb_w) + res->prot |= PAGE_WRITE; + if (tlb_x) + res->prot |= PAGE_EXEC; + } + else + D(dump_tlb(env, mmu)); + } else { + /* If refill, provide a randomized set. */ + set = env->mmu_rand_lfsr & 3; + } + + if (!match) { + unsigned int f; + + /* Update lfsr at every fault. */ + f = compute_polynom(env->mmu_rand_lfsr); + env->mmu_rand_lfsr >>= 1; + env->mmu_rand_lfsr |= (f << 15); + env->mmu_rand_lfsr &= 0xffff; + + /* Compute index. */ + idx = vpage & 15; + + /* Update RW_MM_TLB_SEL. */ + env->sregs[SFR_RW_MM_TLB_SEL] = 0; + set_field(&env->sregs[SFR_RW_MM_TLB_SEL], idx, 0, 4); + set_field(&env->sregs[SFR_RW_MM_TLB_SEL], set, 4, 2); + + /* Update RW_MM_CAUSE. */ + set_field(&r_cause, rwcause, 8, 2); + set_field(&r_cause, vpage, 13, 19); + set_field(&r_cause, pid, 0, 8); + env->sregs[SFR_R_MM_CAUSE] = r_cause; + D(printf("refill vaddr=%x pc=%x\n", vaddr, env->pc)); + } + + D(printf ("%s rw=%d mtch=%d pc=%x va=%x vpn=%x tlbvpn=%x pfn=%x pid=%x" + " %x cause=%x sel=%x sp=%x %x %x\n", + __func__, rw, match, env->pc, + vaddr, vpage, + tlb_vpn, tlb_pfn, tlb_pid, + pid, + r_cause, + env->sregs[SFR_RW_MM_TLB_SEL], + env->regs[R_SP], env->pregs[PR_USP], env->ksp)); + + res->pfn = tlb_pfn; return !match; } +void cris_mmu_flush_pid(CPUState *env, uint32_t pid) +{ + target_ulong vaddr; + unsigned int idx; + uint32_t lo, hi; + uint32_t tlb_vpn; + int tlb_pid, tlb_g, tlb_v, tlb_k; + unsigned int set; + unsigned int mmu; + + pid &= 0xff; + for (mmu = 0; mmu < 2; mmu++) { + for (set = 0; set < 4; set++) + { + for (idx = 0; idx < 16; idx++) { + lo = env->tlbsets[mmu][set][idx].lo; + hi = env->tlbsets[mmu][set][idx].hi; + + tlb_vpn = EXTRACT_FIELD(hi, 13, 31); + tlb_pid = EXTRACT_FIELD(hi, 0, 7); + tlb_g = EXTRACT_FIELD(lo, 4, 4); + tlb_v = EXTRACT_FIELD(lo, 3, 3); + tlb_k = EXTRACT_FIELD(lo, 2, 2); + + /* Kernel protected areas need to be flushed + as well. */ + if (tlb_v && !tlb_g && (tlb_pid == pid || tlb_k)) { + vaddr = tlb_vpn << TARGET_PAGE_BITS; + D(fprintf(logfile, + "flush pid=%x vaddr=%x\n", + pid, vaddr)); + tlb_flush_page(env, vaddr); + } + } + } + } +} + int cris_mmu_translate(struct cris_mmu_result_t *res, CPUState *env, uint32_t vaddr, int rw, int mmu_idx) @@ -116,11 +334,18 @@ uint32_t phy = vaddr; int seg; int miss = 0; - int is_user = mmu_idx == MMU_USER_IDX; + int is_user = mmu_idx == MMU_USER_IDX; + uint32_t old_srs; + + old_srs= env->pregs[PR_SRS]; + + /* rw == 2 means exec, map the access to the insn mmu. */ + env->pregs[PR_SRS] = rw == 2 ? 1 : 2; if (!cris_mmu_enabled(env->sregs[SFR_RW_GC_CFG])) { res->phy = vaddr; - return 0; + res->prot = PAGE_BITS; + goto done; } seg = vaddr >> 28; @@ -132,17 +357,16 @@ base = cris_mmu_translate_seg(env, seg); phy = base | (0x0fffffff & vaddr); res->phy = phy; + res->prot = PAGE_BITS; } else { miss = cris_mmu_translate_page(res, env, vaddr, rw, is_user); - if (!miss) { - phy &= 8191; - phy |= (res->pfn << 13); - res->phy = phy; - } + phy = (res->pfn << 13); + res->phy = phy; } -// printf ("miss=%d v=%x -> p=%x\n", miss, vaddr, phy); + done: + env->pregs[PR_SRS] = old_srs; return miss; } #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-cris/mmu.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-cris/mmu.h --- qemu-0.9.1/target-cris/mmu.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-cris/mmu.h 2008-05-13 11:59:14.000000000 +0100 @@ -7,14 +7,11 @@ { uint32_t phy; uint32_t pfn; - int g:1; - int v:1; - int k:1; - int w:1; - int e:1; - int cause_op; + int prot; + int bf_vec; }; +void cris_mmu_flush_pid(CPUState *env, uint32_t pid); int cris_mmu_translate(struct cris_mmu_result_t *res, CPUState *env, uint32_t vaddr, int rw, int mmu_idx); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-cris/op.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-cris/op.c --- qemu-0.9.1/target-cris/op.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-cris/op.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,1287 +0,0 @@ -/* - * CRIS emulation micro-operations for qemu. - * - * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB. - * - * 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 "exec.h" -#include "host-utils.h" - -#define REGNAME r0 -#define REG (env->regs[0]) -#include "op_template.h" - -#define REGNAME r1 -#define REG (env->regs[1]) -#include "op_template.h" - -#define REGNAME r2 -#define REG (env->regs[2]) -#include "op_template.h" - -#define REGNAME r3 -#define REG (env->regs[3]) -#include "op_template.h" - -#define REGNAME r4 -#define REG (env->regs[4]) -#include "op_template.h" - -#define REGNAME r5 -#define REG (env->regs[5]) -#include "op_template.h" - -#define REGNAME r6 -#define REG (env->regs[6]) -#include "op_template.h" - -#define REGNAME r7 -#define REG (env->regs[7]) -#include "op_template.h" - -#define REGNAME r8 -#define REG (env->regs[8]) -#include "op_template.h" - -#define REGNAME r9 -#define REG (env->regs[9]) -#include "op_template.h" - -#define REGNAME r10 -#define REG (env->regs[10]) -#include "op_template.h" - -#define REGNAME r11 -#define REG (env->regs[11]) -#include "op_template.h" - -#define REGNAME r12 -#define REG (env->regs[12]) -#include "op_template.h" - -#define REGNAME r13 -#define REG (env->regs[13]) -#include "op_template.h" - -#define REGNAME r14 -#define REG (env->regs[14]) -#include "op_template.h" - -#define REGNAME r15 -#define REG (env->regs[15]) -#include "op_template.h" - - -#define REGNAME p0 -#define REG (env->pregs[0]) -#include "op_template.h" - -#define REGNAME p1 -#define REG (env->pregs[1]) -#include "op_template.h" - -#define REGNAME p2 -#define REG (env->pregs[2]) -#include "op_template.h" - -#define REGNAME p3 -#define REG (env->pregs[3]) -#include "op_template.h" - -#define REGNAME p4 -#define REG (env->pregs[4]) -#include "op_template.h" - -#define REGNAME p5 -#define REG (env->pregs[5]) -#include "op_template.h" - -#define REGNAME p6 -#define REG (env->pregs[6]) -#include "op_template.h" - -#define REGNAME p7 -#define REG (env->pregs[7]) -#include "op_template.h" - -#define REGNAME p8 -#define REG (env->pregs[8]) -#include "op_template.h" - -#define REGNAME p9 -#define REG (env->pregs[9]) -#include "op_template.h" - -#define REGNAME p10 -#define REG (env->pregs[10]) -#include "op_template.h" - -#define REGNAME p11 -#define REG (env->pregs[11]) -#include "op_template.h" - -#define REGNAME p12 -#define REG (env->pregs[12]) -#include "op_template.h" - -#define REGNAME p13 -#define REG (env->pregs[13]) -#include "op_template.h" - -#define REGNAME p14 -#define REG (env->pregs[14]) -#include "op_template.h" - -#define REGNAME p15 -#define REG (env->pregs[15]) -#include "op_template.h" - -/* Microcode. */ - -void OPPROTO op_exit_tb (void) -{ - EXIT_TB(); -} - -void OPPROTO op_goto_tb0 (void) -{ - GOTO_TB(op_goto_tb0, PARAM1, 0); - RETURN(); -} - -void OPPROTO op_goto_tb1 (void) -{ - GOTO_TB(op_goto_tb1, PARAM1, 1); - RETURN(); -} - -void OPPROTO op_break_im(void) -{ - env->trapnr = PARAM1; - env->exception_index = EXCP_BREAK; - cpu_loop_exit(); -} - -void OPPROTO op_debug(void) -{ - env->exception_index = EXCP_DEBUG; - cpu_loop_exit(); -} - -void OPPROTO op_exec_insn(void) -{ - env->stats.exec_insns++; - RETURN(); -} -void OPPROTO op_exec_load(void) -{ - env->stats.exec_loads++; - RETURN(); -} -void OPPROTO op_exec_store(void) -{ - env->stats.exec_stores++; - RETURN(); -} - -void OPPROTO op_ccs_lshift (void) -{ - uint32_t ccs; - - /* Apply the ccs shift. */ - ccs = env->pregs[SR_CCS]; - ccs = (ccs & 0xc0000000) | ((ccs << 12) >> 2); - env->pregs[SR_CCS] = ccs; -} -void OPPROTO op_ccs_rshift (void) -{ - uint32_t ccs; - - /* Apply the ccs shift. */ - ccs = env->pregs[SR_CCS]; - ccs = (ccs & 0xc0000000) | (ccs >> 10); - env->pregs[SR_CCS] = ccs; -} - -void OPPROTO op_setf (void) -{ - env->pregs[SR_CCS] |= PARAM1; - RETURN(); -} - -void OPPROTO op_clrf (void) -{ - env->pregs[SR_CCS] &= ~PARAM1; - RETURN(); -} - -void OPPROTO op_movl_debug1_T0 (void) -{ - env->debug1 = T0; - RETURN(); -} - -void OPPROTO op_movl_debug2_T0 (void) -{ - env->debug2 = T0; - RETURN(); -} - -void OPPROTO op_movl_debug3_T0 (void) -{ - env->debug3 = T0; - RETURN(); -} -void OPPROTO op_movl_debug1_T1 (void) -{ - env->debug1 = T1; - RETURN(); -} - -void OPPROTO op_movl_debug2_T1 (void) -{ - env->debug2 = T1; - RETURN(); -} - -void OPPROTO op_movl_debug3_T1 (void) -{ - env->debug3 = T1; - RETURN(); -} -void OPPROTO op_movl_debug3_im (void) -{ - env->debug3 = PARAM1; - RETURN(); -} -void OPPROTO op_movl_T0_flags (void) -{ - T0 = env->pregs[SR_CCS]; - RETURN(); -} -void OPPROTO op_movl_flags_T0 (void) -{ - env->pregs[SR_CCS] = T0; - RETURN(); -} - -void OPPROTO op_movl_sreg_T0 (void) -{ - env->sregs[env->pregs[SR_SRS]][PARAM1] = T0; - RETURN(); -} - -void OPPROTO op_movl_tlb_lo_T0 (void) -{ - int srs; - srs = env->pregs[SR_SRS]; - if (srs == 1 || srs == 2) - { - int set; - int idx; - uint32_t lo, hi; - - idx = set = env->sregs[SFR_RW_MM_TLB_SEL]; - set >>= 4; - set &= 3; - - idx &= 31; - /* We've just made a write to tlb_lo. */ - lo = env->sregs[SFR_RW_MM_TLB_LO]; - hi = env->sregs[SFR_RW_MM_TLB_HI]; - env->tlbsets[srs - 1][set][idx].lo = lo; - env->tlbsets[srs - 1][set][idx].hi = hi; - } - - RETURN(); -} - -void OPPROTO op_movl_T0_sreg (void) -{ - T0 = env->sregs[env->pregs[SR_SRS]][PARAM1]; - RETURN(); -} - -void OPPROTO op_update_cc (void) -{ - env->cc_op = PARAM1; - env->cc_dest = PARAM2; - env->cc_src = PARAM3; - RETURN(); -} - -void OPPROTO op_update_cc_op (void) -{ - env->cc_op = PARAM1; - RETURN(); -} - -void OPPROTO op_update_cc_mask (void) -{ - env->cc_mask = PARAM1; - RETURN(); -} - -void OPPROTO op_update_cc_dest_T0 (void) -{ - env->cc_dest = T0; - RETURN(); -} - -void OPPROTO op_update_cc_result_T0 (void) -{ - env->cc_result = T0; - RETURN(); -} - -void OPPROTO op_update_cc_size_im (void) -{ - env->cc_size = PARAM1; - RETURN(); -} - -void OPPROTO op_update_cc_src_T1 (void) -{ - env->cc_src = T1; - RETURN(); -} -void OPPROTO op_update_cc_x (void) -{ - env->cc_x_live = PARAM1; - env->cc_x = PARAM2; - RETURN(); -} - -/* FIXME: is this allowed? */ -extern inline void evaluate_flags_writeback(uint32_t flags) -{ - int x; - - /* Extended arithmetics, leave the z flag alone. */ - env->debug3 = env->pregs[SR_CCS]; - - if (env->cc_x_live) - x = env->cc_x; - else - x = env->pregs[SR_CCS] & X_FLAG; - - if ((x || env->cc_op == CC_OP_ADDC) - && flags & Z_FLAG) - env->cc_mask &= ~Z_FLAG; - - /* all insn clear the x-flag except setf or clrf. */ - env->pregs[SR_CCS] &= ~(env->cc_mask | X_FLAG); - flags &= env->cc_mask; - env->pregs[SR_CCS] |= flags; - RETURN(); -} - -void OPPROTO op_evaluate_flags_muls(void) -{ - uint32_t src; - uint32_t dst; - uint32_t res; - uint32_t flags = 0; - /* were gonna have to redo the muls. */ - int64_t tmp, t0 ,t1; - int32_t mof; - int dneg; - - src = env->cc_src; - dst = env->cc_dest; - res = env->cc_result; - - - /* cast into signed values to make GCC sign extend. */ - t0 = (int32_t)src; - t1 = (int32_t)dst; - dneg = ((int32_t)res) < 0; - - tmp = t0 * t1; - mof = tmp >> 32; - if (tmp == 0) - flags |= Z_FLAG; - else if (tmp < 0) - flags |= N_FLAG; - if ((dneg && mof != -1) - || (!dneg && mof != 0)) - flags |= V_FLAG; - evaluate_flags_writeback(flags); - RETURN(); -} - -void OPPROTO op_evaluate_flags_mulu(void) -{ - uint32_t src; - uint32_t dst; - uint32_t res; - uint32_t flags = 0; - /* were gonna have to redo the muls. */ - uint64_t tmp, t0 ,t1; - uint32_t mof; - - src = env->cc_src; - dst = env->cc_dest; - res = env->cc_result; - - - /* cast into signed values to make GCC sign extend. */ - t0 = src; - t1 = dst; - - tmp = t0 * t1; - mof = tmp >> 32; - if (tmp == 0) - flags |= Z_FLAG; - else if (tmp >> 63) - flags |= N_FLAG; - if (mof) - flags |= V_FLAG; - - evaluate_flags_writeback(flags); - RETURN(); -} - -void OPPROTO op_evaluate_flags_mcp(void) -{ - uint32_t src; - uint32_t dst; - uint32_t res; - uint32_t flags = 0; - - src = env->cc_src; - dst = env->cc_dest; - res = env->cc_result; - - if ((res & 0x80000000L) != 0L) - { - flags |= N_FLAG; - if (((src & 0x80000000L) == 0L) - && ((dst & 0x80000000L) == 0L)) - { - flags |= V_FLAG; - } - else if (((src & 0x80000000L) != 0L) && - ((dst & 0x80000000L) != 0L)) - { - flags |= R_FLAG; - } - } - else - { - if (res == 0L) - flags |= Z_FLAG; - if (((src & 0x80000000L) != 0L) - && ((dst & 0x80000000L) != 0L)) - flags |= V_FLAG; - if ((dst & 0x80000000L) != 0L - || (src & 0x80000000L) != 0L) - flags |= R_FLAG; - } - - evaluate_flags_writeback(flags); - RETURN(); -} - -void OPPROTO op_evaluate_flags_alu_4(void) -{ - uint32_t src; - uint32_t dst; - uint32_t res; - uint32_t flags = 0; - - src = env->cc_src; - dst = env->cc_dest; - res = env->cc_result; - - if ((res & 0x80000000L) != 0L) - { - flags |= N_FLAG; - if (((src & 0x80000000L) == 0L) - && ((dst & 0x80000000L) == 0L)) - { - flags |= V_FLAG; - } - else if (((src & 0x80000000L) != 0L) && - ((dst & 0x80000000L) != 0L)) - { - flags |= C_FLAG; - } - } - else - { - if (res == 0L) - flags |= Z_FLAG; - if (((src & 0x80000000L) != 0L) - && ((dst & 0x80000000L) != 0L)) - flags |= V_FLAG; - if ((dst & 0x80000000L) != 0L - || (src & 0x80000000L) != 0L) - flags |= C_FLAG; - } - - if (env->cc_op == CC_OP_SUB - || env->cc_op == CC_OP_CMP) { - flags ^= C_FLAG; - } - evaluate_flags_writeback(flags); - RETURN(); -} - -void OPPROTO op_evaluate_flags_move_4 (void) -{ - uint32_t src; - uint32_t res; - uint32_t flags = 0; - - src = env->cc_src; - res = env->cc_result; - - if ((int32_t)res < 0) - flags |= N_FLAG; - else if (res == 0L) - flags |= Z_FLAG; - - evaluate_flags_writeback(flags); - RETURN(); -} -void OPPROTO op_evaluate_flags_move_2 (void) -{ - uint32_t src; - uint32_t flags = 0; - uint16_t res; - - src = env->cc_src; - res = env->cc_result; - - if ((int16_t)res < 0L) - flags |= N_FLAG; - else if (res == 0) - flags |= Z_FLAG; - - evaluate_flags_writeback(flags); - RETURN(); -} - -/* TODO: This is expensive. We could split things up and only evaluate part of - CCR on a need to know basis. For now, we simply re-evaluate everything. */ -void OPPROTO op_evaluate_flags (void) -{ - uint32_t src; - uint32_t dst; - uint32_t res; - uint32_t flags = 0; - - src = env->cc_src; - dst = env->cc_dest; - res = env->cc_result; - - - /* Now, evaluate the flags. This stuff is based on - Per Zander's CRISv10 simulator. */ - switch (env->cc_size) - { - case 1: - if ((res & 0x80L) != 0L) - { - flags |= N_FLAG; - if (((src & 0x80L) == 0L) - && ((dst & 0x80L) == 0L)) - { - flags |= V_FLAG; - } - else if (((src & 0x80L) != 0L) - && ((dst & 0x80L) != 0L)) - { - flags |= C_FLAG; - } - } - else - { - if ((res & 0xFFL) == 0L) - { - flags |= Z_FLAG; - } - if (((src & 0x80L) != 0L) - && ((dst & 0x80L) != 0L)) - { - flags |= V_FLAG; - } - if ((dst & 0x80L) != 0L - || (src & 0x80L) != 0L) - { - flags |= C_FLAG; - } - } - break; - case 2: - if ((res & 0x8000L) != 0L) - { - flags |= N_FLAG; - if (((src & 0x8000L) == 0L) - && ((dst & 0x8000L) == 0L)) - { - flags |= V_FLAG; - } - else if (((src & 0x8000L) != 0L) - && ((dst & 0x8000L) != 0L)) - { - flags |= C_FLAG; - } - } - else - { - if ((res & 0xFFFFL) == 0L) - { - flags |= Z_FLAG; - } - if (((src & 0x8000L) != 0L) - && ((dst & 0x8000L) != 0L)) - { - flags |= V_FLAG; - } - if ((dst & 0x8000L) != 0L - || (src & 0x8000L) != 0L) - { - flags |= C_FLAG; - } - } - break; - case 4: - if ((res & 0x80000000L) != 0L) - { - flags |= N_FLAG; - if (((src & 0x80000000L) == 0L) - && ((dst & 0x80000000L) == 0L)) - { - flags |= V_FLAG; - } - else if (((src & 0x80000000L) != 0L) && - ((dst & 0x80000000L) != 0L)) - { - flags |= C_FLAG; - } - } - else - { - if (res == 0L) - flags |= Z_FLAG; - if (((src & 0x80000000L) != 0L) - && ((dst & 0x80000000L) != 0L)) - flags |= V_FLAG; - if ((dst & 0x80000000L) != 0L - || (src & 0x80000000L) != 0L) - flags |= C_FLAG; - } - break; - default: - break; - } - - if (env->cc_op == CC_OP_SUB - || env->cc_op == CC_OP_CMP) { - flags ^= C_FLAG; - } - evaluate_flags_writeback(flags); - RETURN(); -} - -void OPPROTO op_extb_T0_T0 (void) -{ - T0 = ((int8_t)T0); - RETURN(); -} -void OPPROTO op_extb_T1_T0 (void) -{ - T1 = ((int8_t)T0); - RETURN(); -} -void OPPROTO op_extb_T1_T1 (void) -{ - T1 = ((int8_t)T1); - RETURN(); -} -void OPPROTO op_zextb_T0_T0 (void) -{ - T0 = ((uint8_t)T0); - RETURN(); -} -void OPPROTO op_zextb_T1_T0 (void) -{ - T1 = ((uint8_t)T0); - RETURN(); -} -void OPPROTO op_zextb_T1_T1 (void) -{ - T1 = ((uint8_t)T1); - RETURN(); -} -void OPPROTO op_extw_T0_T0 (void) -{ - T0 = ((int16_t)T0); - RETURN(); -} -void OPPROTO op_extw_T1_T0 (void) -{ - T1 = ((int16_t)T0); - RETURN(); -} -void OPPROTO op_extw_T1_T1 (void) -{ - T1 = ((int16_t)T1); - RETURN(); -} - -void OPPROTO op_zextw_T0_T0 (void) -{ - T0 = ((uint16_t)T0); - RETURN(); -} -void OPPROTO op_zextw_T1_T0 (void) -{ - T1 = ((uint16_t)T0); - RETURN(); -} - -void OPPROTO op_zextw_T1_T1 (void) -{ - T1 = ((uint16_t)T1); - RETURN(); -} - -void OPPROTO op_movl_T0_im (void) -{ - T0 = PARAM1; - RETURN(); -} -void OPPROTO op_movl_T1_im (void) -{ - T1 = PARAM1; - RETURN(); -} - -void OPPROTO op_addl_T0_im (void) -{ - T0 += PARAM1; - RETURN(); -} - -void OPPROTO op_addl_T1_im (void) -{ - T1 += PARAM1; - RETURN(); - -} -void OPPROTO op_subl_T0_im (void) -{ - T0 -= PARAM1; - RETURN(); -} - -void OPPROTO op_addxl_T0_C (void) -{ - if (env->pregs[SR_CCS] & X_FLAG) - T0 += !!(env->pregs[SR_CCS] & C_FLAG); - RETURN(); -} -void OPPROTO op_subxl_T0_C (void) -{ - if (env->pregs[SR_CCS] & X_FLAG) - T0 -= !!(env->pregs[SR_CCS] & C_FLAG); - RETURN(); -} -void OPPROTO op_addl_T0_C (void) -{ - T0 += !!(env->pregs[SR_CCS] & C_FLAG); - RETURN(); -} -void OPPROTO op_addl_T0_R (void) -{ - T0 += !!(env->pregs[SR_CCS] & R_FLAG); - RETURN(); -} - -void OPPROTO op_clr_R (void) -{ - env->pregs[SR_CCS] &= ~R_FLAG; - RETURN(); -} - - -void OPPROTO op_andl_T0_im (void) -{ - T0 &= PARAM1; - RETURN(); -} - -void OPPROTO op_andl_T1_im (void) -{ - T1 &= PARAM1; - RETURN(); -} - -void OPPROTO op_movl_T0_T1 (void) -{ - T0 = T1; - RETURN(); -} - -void OPPROTO op_swp_T0_T1 (void) -{ - T0 ^= T1; - T1 ^= T0; - T0 ^= T1; - RETURN(); -} - -void OPPROTO op_movl_T1_T0 (void) -{ - T1 = T0; - RETURN(); -} - -void OPPROTO op_movl_pc_T0 (void) -{ - env->pc = T0; - RETURN(); -} - -void OPPROTO op_movl_T0_0 (void) -{ - T0 = 0; - RETURN(); -} - -void OPPROTO op_addl_T0_T1 (void) -{ - T0 += T1; - RETURN(); -} - -void OPPROTO op_subl_T0_T1 (void) -{ - T0 -= T1; - RETURN(); -} - -void OPPROTO op_absl_T1_T1 (void) -{ - int32_t st = T1; - - T1 = st < 0 ? -st : st; - RETURN(); -} - -void OPPROTO op_muls_T0_T1 (void) -{ - int64_t tmp, t0 ,t1; - - /* cast into signed values to make GCC sign extend these babies. */ - t0 = (int32_t)T0; - t1 = (int32_t)T1; - - tmp = t0 * t1; - T0 = tmp & 0xffffffff; - env->pregs[REG_MOF] = tmp >> 32; - RETURN(); -} - -void OPPROTO op_mulu_T0_T1 (void) -{ - uint64_t tmp, t0 ,t1; - t0 = T0; - t1 = T1; - - tmp = t0 * t1; - T0 = tmp & 0xffffffff; - env->pregs[REG_MOF] = tmp >> 32; - RETURN(); -} - -void OPPROTO op_dstep_T0_T1 (void) -{ - T0 <<= 1; - if (T0 >= T1) - T0 -= T1; - RETURN(); -} - -void OPPROTO op_orl_T0_T1 (void) -{ - T0 |= T1; - RETURN(); -} - -void OPPROTO op_andl_T0_T1 (void) -{ - T0 &= T1; - RETURN(); -} - -void OPPROTO op_xorl_T0_T1 (void) -{ - T0 ^= T1; - RETURN(); -} - -void OPPROTO op_lsll_T0_T1 (void) -{ - int s = T1; - if (s > 31) - T0 = 0; - else - T0 <<= s; - RETURN(); -} - -void OPPROTO op_lsll_T0_im (void) -{ - T0 <<= PARAM1; - RETURN(); -} - -void OPPROTO op_lsrl_T0_T1 (void) -{ - int s = T1; - if (s > 31) - T0 = 0; - else - T0 >>= s; - RETURN(); -} - -/* Rely on GCC emitting an arithmetic shift for signed right shifts. */ -void OPPROTO op_asrl_T0_T1 (void) -{ - int s = T1; - if (s > 31) - T0 = T0 & 0x80000000 ? -1 : 0; - else - T0 = (int32_t)T0 >> s; - RETURN(); -} - -void OPPROTO op_btst_T0_T1 (void) -{ - /* FIXME: clean this up. */ - - /* des ref: - The N flag is set according to the selected bit in the dest reg. - The Z flag is set if the selected bit and all bits to the right are - zero. - The destination reg is not affected.*/ - unsigned int fz, sbit, bset, mask, masked_t0; - - sbit = T1 & 31; - bset = !!(T0 & (1 << sbit)); - mask = sbit == 31 ? -1 : (1 << (sbit + 1)) - 1; - masked_t0 = T0 & mask; - fz = !(masked_t0 | bset); - /* Set the N and Z flags accordingly. */ - T0 = (bset << 3) | (fz << 2); - RETURN(); -} - -void OPPROTO op_bound_T0_T1 (void) -{ - if (T0 > T1) - T0 = T1; - RETURN(); -} - -void OPPROTO op_lz_T0_T1 (void) -{ - T0 = clz32(T1); - RETURN(); -} - -void OPPROTO op_negl_T0_T1 (void) -{ - T0 = -T1; - RETURN(); -} - -void OPPROTO op_negl_T1_T1 (void) -{ - T1 = -T1; - RETURN(); -} - -void OPPROTO op_not_T0_T0 (void) -{ - T0 = ~(T0); - RETURN(); -} -void OPPROTO op_not_T1_T1 (void) -{ - T1 = ~(T1); - RETURN(); -} - -void OPPROTO op_swapw_T0_T0 (void) -{ - T0 = (T0 << 16) | ((T0 >> 16)); - RETURN(); -} - -void OPPROTO op_swapb_T0_T0 (void) -{ - T0 = ((T0 << 8) & 0xff00ff00) | ((T0 >> 8) & 0x00ff00ff); - RETURN(); -} - -void OPPROTO op_swapr_T0_T0 (void) -{ - T0 = (((T0 << 7) & 0x80808080) | - ((T0 << 5) & 0x40404040) | - ((T0 << 3) & 0x20202020) | - ((T0 << 1) & 0x10101010) | - ((T0 >> 1) & 0x08080808) | - ((T0 >> 3) & 0x04040404) | - ((T0 >> 5) & 0x02020202) | - ((T0 >> 7) & 0x01010101)); - RETURN(); -} - -void OPPROTO op_tst_cc_eq (void) { - uint32_t flags = env->pregs[SR_CCS]; - int z_set; - - z_set = !!(flags & Z_FLAG); - T0 = z_set; - RETURN(); -} - -void OPPROTO op_tst_cc_eq_fast (void) { - T0 = !(env->cc_result); - RETURN(); -} - -void OPPROTO op_tst_cc_ne (void) { - uint32_t flags = env->pregs[SR_CCS]; - int z_set; - - z_set = !!(flags & Z_FLAG); - T0 = !z_set; - RETURN(); -} -void OPPROTO op_tst_cc_ne_fast (void) { - T0 = !!(env->cc_result); - RETURN(); -} - -void OPPROTO op_tst_cc_cc (void) { - uint32_t flags = env->pregs[SR_CCS]; - int c_set; - - c_set = !!(flags & C_FLAG); - T0 = !c_set; - RETURN(); -} -void OPPROTO op_tst_cc_cs (void) { - uint32_t flags = env->pregs[SR_CCS]; - int c_set; - - c_set = !!(flags & C_FLAG); - T0 = c_set; - RETURN(); -} - -void OPPROTO op_tst_cc_vc (void) { - uint32_t flags = env->pregs[SR_CCS]; - int v_set; - - v_set = !!(flags & V_FLAG); - T0 = !v_set; - RETURN(); -} -void OPPROTO op_tst_cc_vs (void) { - uint32_t flags = env->pregs[SR_CCS]; - int v_set; - - v_set = !!(flags & V_FLAG); - T0 = v_set; - RETURN(); -} -void OPPROTO op_tst_cc_pl (void) { - uint32_t flags = env->pregs[SR_CCS]; - int n_set; - - n_set = !!(flags & N_FLAG); - T0 = !n_set; - RETURN(); -} -void OPPROTO op_tst_cc_pl_fast (void) { - T0 = ((int32_t)env->cc_result) >= 0; - RETURN(); -} - -void OPPROTO op_tst_cc_mi (void) { - uint32_t flags = env->pregs[SR_CCS]; - int n_set; - - n_set = !!(flags & N_FLAG); - T0 = n_set; - RETURN(); -} -void OPPROTO op_tst_cc_mi_fast (void) { - T0 = ((int32_t)env->cc_result) < 0; - RETURN(); -} - -void OPPROTO op_tst_cc_ls (void) { - uint32_t flags = env->pregs[SR_CCS]; - int c_set; - int z_set; - - c_set = !!(flags & C_FLAG); - z_set = !!(flags & Z_FLAG); - T0 = c_set || z_set; - RETURN(); -} -void OPPROTO op_tst_cc_hi (void) { - uint32_t flags = env->pregs[SR_CCS]; - int z_set; - int c_set; - - z_set = !!(flags & Z_FLAG); - c_set = !!(flags & C_FLAG); - T0 = !c_set && !z_set; - RETURN(); - -} - -void OPPROTO op_tst_cc_ge (void) { - uint32_t flags = env->pregs[SR_CCS]; - int n_set; - int v_set; - - n_set = !!(flags & N_FLAG); - v_set = !!(flags & V_FLAG); - T0 = (n_set && v_set) || (!n_set && !v_set); - RETURN(); -} - -void OPPROTO op_tst_cc_ge_fast (void) { - T0 = ((int32_t)env->cc_src < (int32_t)env->cc_dest); - RETURN(); -} - -void OPPROTO op_tst_cc_lt (void) { - uint32_t flags = env->pregs[SR_CCS]; - int n_set; - int v_set; - - n_set = !!(flags & N_FLAG); - v_set = !!(flags & V_FLAG); - T0 = (n_set && !v_set) || (!n_set && v_set); - RETURN(); -} - -void OPPROTO op_tst_cc_gt (void) { - uint32_t flags = env->pregs[SR_CCS]; - int n_set; - int v_set; - int z_set; - - n_set = !!(flags & N_FLAG); - v_set = !!(flags & V_FLAG); - z_set = !!(flags & Z_FLAG); - T0 = (n_set && v_set && !z_set) - || (!n_set && !v_set && !z_set); - RETURN(); -} - -void OPPROTO op_tst_cc_le (void) { - uint32_t flags = env->pregs[SR_CCS]; - int n_set; - int v_set; - int z_set; - - n_set = !!(flags & N_FLAG); - v_set = !!(flags & V_FLAG); - z_set = !!(flags & Z_FLAG); - T0 = z_set || (n_set && !v_set) || (!n_set && v_set); - RETURN(); -} - -void OPPROTO op_tst_cc_p (void) { - uint32_t flags = env->pregs[SR_CCS]; - int p_set; - - p_set = !!(flags & P_FLAG); - T0 = p_set; - RETURN(); -} - -/* Evaluate the if the branch should be taken or not. Needs to be done in - the original sequence. The acutal branch is rescheduled to right after the - delay-slot. */ -void OPPROTO op_evaluate_bcc (void) -{ - env->btaken = T0; - RETURN(); -} - -/* this one is used on every alu op, optimize it!. */ -void OPPROTO op_goto_if_not_x (void) -{ - if (env->pregs[SR_CCS] & X_FLAG) - GOTO_LABEL_PARAM(1); - RETURN(); -} - -void OPPROTO op_cc_jmp (void) -{ - if (env->btaken) - env->pc = PARAM1; - else - env->pc = PARAM2; - RETURN(); -} - -void OPPROTO op_cc_ngoto (void) -{ - if (!env->btaken) - GOTO_LABEL_PARAM(1); - RETURN(); -} - -void OPPROTO op_movl_btarget_T0 (void) -{ - env->btarget = T0; - RETURN(); -} - -void OPPROTO op_jmp (void) -{ - env->pc = env->btarget; - RETURN(); -} - -/* Load and store */ -#define MEMSUFFIX _raw -#include "op_mem.c" -#undef MEMSUFFIX -#if !defined(CONFIG_USER_ONLY) -#define MEMSUFFIX _user -#include "op_mem.c" -#undef MEMSUFFIX - -#define MEMSUFFIX _kernel -#include "op_mem.c" -#undef MEMSUFFIX -#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-cris/op_helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-cris/op_helper.c --- qemu-0.9.1/target-cris/op_helper.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-cris/op_helper.c 2008-10-07 23:48:41.000000000 +0100 @@ -21,13 +21,14 @@ #include #include "exec.h" +#include "mmu.h" +#include "helper.h" + +#define D(x) + +#if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _mmu -#ifdef __s390__ -# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) -#else -# define GETPC() (__builtin_return_address(0)) -#endif #define SHIFT 0 #include "softmmu_template.h" @@ -56,8 +57,11 @@ generated code */ saved_env = env; env = cpu_single_env; + + D(fprintf(logfile, "%s pc=%x tpc=%x ra=%x\n", __func__, + env->pc, env->debug1, retaddr)); ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); - if (__builtin_expect(ret, 0)) { + if (unlikely(ret)) { if (retaddr) { /* now we have a real cpu fault */ pc = (unsigned long)retaddr; @@ -66,6 +70,9 @@ /* the PC is inside the translated code. It means that we have a virtual CPU fault */ cpu_restore_state(tb, env, pc, NULL); + + /* Evaluate flags after retranslation. */ + helper_top_evaluate_flags(); } } cpu_loop_exit(); @@ -73,8 +80,553 @@ env = saved_env; } +#endif + +void helper_raise_exception(uint32_t index) +{ + env->exception_index = index; + cpu_loop_exit(); +} + +void helper_tlb_flush_pid(uint32_t pid) +{ +#if !defined(CONFIG_USER_ONLY) + pid &= 0xff; + if (pid != (env->pregs[PR_PID] & 0xff)) + cris_mmu_flush_pid(env, env->pregs[PR_PID]); +#endif +} + +void helper_spc_write(uint32_t new_spc) +{ +#if !defined(CONFIG_USER_ONLY) + tlb_flush_page(env, env->pregs[PR_SPC]); + tlb_flush_page(env, new_spc); +#endif +} + +void helper_dump(uint32_t a0, uint32_t a1, uint32_t a2) +{ + (fprintf(logfile, "%s: a0=%x a1=%x\n", __func__, a0, a1)); +} + +/* Used by the tlb decoder. */ +#define EXTRACT_FIELD(src, start, end) \ + (((src) >> start) & ((1 << (end - start + 1)) - 1)) + +void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg) +{ + uint32_t srs; + srs = env->pregs[PR_SRS]; + srs &= 3; + env->sregs[srs][sreg] = env->regs[reg]; + +#if !defined(CONFIG_USER_ONLY) + if (srs == 1 || srs == 2) { + if (sreg == 6) { + /* Writes to tlb-hi write to mm_cause as a side + effect. */ + env->sregs[SFR_RW_MM_TLB_HI] = env->regs[reg]; + env->sregs[SFR_R_MM_CAUSE] = env->regs[reg]; + } + else if (sreg == 5) { + uint32_t set; + uint32_t idx; + uint32_t lo, hi; + uint32_t vaddr; + int tlb_v; + + idx = set = env->sregs[SFR_RW_MM_TLB_SEL]; + set >>= 4; + set &= 3; + + idx &= 15; + /* We've just made a write to tlb_lo. */ + lo = env->sregs[SFR_RW_MM_TLB_LO]; + /* Writes are done via r_mm_cause. */ + hi = env->sregs[SFR_R_MM_CAUSE]; + + vaddr = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].hi, + 13, 31); + vaddr <<= TARGET_PAGE_BITS; + tlb_v = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].lo, + 3, 3); + env->tlbsets[srs - 1][set][idx].lo = lo; + env->tlbsets[srs - 1][set][idx].hi = hi; + + D(fprintf(logfile, + "tlb flush vaddr=%x v=%d pc=%x\n", + vaddr, tlb_v, env->pc)); + tlb_flush_page(env, vaddr); + } + } +#endif +} + +void helper_movl_reg_sreg (uint32_t reg, uint32_t sreg) +{ + uint32_t srs; + env->pregs[PR_SRS] &= 3; + srs = env->pregs[PR_SRS]; + +#if !defined(CONFIG_USER_ONLY) + if (srs == 1 || srs == 2) + { + uint32_t set; + uint32_t idx; + uint32_t lo, hi; + + idx = set = env->sregs[SFR_RW_MM_TLB_SEL]; + set >>= 4; + set &= 3; + idx &= 15; + + /* Update the mirror regs. */ + hi = env->tlbsets[srs - 1][set][idx].hi; + lo = env->tlbsets[srs - 1][set][idx].lo; + env->sregs[SFR_RW_MM_TLB_HI] = hi; + env->sregs[SFR_RW_MM_TLB_LO] = lo; + } +#endif + env->regs[reg] = env->sregs[srs][sreg]; + RETURN(); +} + +static void cris_ccs_rshift(CPUState *env) +{ + uint32_t ccs; + + /* Apply the ccs shift. */ + ccs = env->pregs[PR_CCS]; + ccs = (ccs & 0xc0000000) | ((ccs & 0x0fffffff) >> 10); + if (ccs & U_FLAG) + { + /* Enter user mode. */ + env->ksp = env->regs[R_SP]; + env->regs[R_SP] = env->pregs[PR_USP]; + } + + env->pregs[PR_CCS] = ccs; +} + +void helper_rfe(void) +{ + int rflag = env->pregs[PR_CCS] & R_FLAG; + + D(fprintf(logfile, "rfe: erp=%x pid=%x ccs=%x btarget=%x\n", + env->pregs[PR_ERP], env->pregs[PR_PID], + env->pregs[PR_CCS], + env->btarget)); + + cris_ccs_rshift(env); + + /* RFE sets the P_FLAG only if the R_FLAG is not set. */ + if (!rflag) + env->pregs[PR_CCS] |= P_FLAG; +} + +void helper_rfn(void) +{ + int rflag = env->pregs[PR_CCS] & R_FLAG; + + D(fprintf(logfile, "rfn: erp=%x pid=%x ccs=%x btarget=%x\n", + env->pregs[PR_ERP], env->pregs[PR_PID], + env->pregs[PR_CCS], + env->btarget)); + + cris_ccs_rshift(env); + + /* Set the P_FLAG only if the R_FLAG is not set. */ + if (!rflag) + env->pregs[PR_CCS] |= P_FLAG; + + /* Always set the M flag. */ + env->pregs[PR_CCS] |= M_FLAG; +} + void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, - int is_asi) + int is_asi, int size) +{ + D(printf("%s addr=%x w=%d ex=%d asi=%d, size=%d\n", + __func__, addr, is_write, is_exec, is_asi, size)); +} + +static void evaluate_flags_writeback(uint32_t flags) +{ + int x; + + /* Extended arithmetics, leave the z flag alone. */ + x = env->cc_x; + if ((x || env->cc_op == CC_OP_ADDC) + && flags & Z_FLAG) + env->cc_mask &= ~Z_FLAG; + + /* all insn clear the x-flag except setf or clrf. */ + env->pregs[PR_CCS] &= ~(env->cc_mask | X_FLAG); + flags &= env->cc_mask; + env->pregs[PR_CCS] |= flags; +} + +void helper_evaluate_flags_muls(void) { + uint32_t src; + uint32_t dst; + uint32_t res; + uint32_t flags = 0; + int64_t tmp; + int32_t mof; + int dneg; + + src = env->cc_src; + dst = env->cc_dest; + res = env->cc_result; + + dneg = ((int32_t)res) < 0; + + mof = env->pregs[PR_MOF]; + tmp = mof; + tmp <<= 32; + tmp |= res; + if (tmp == 0) + flags |= Z_FLAG; + else if (tmp < 0) + flags |= N_FLAG; + if ((dneg && mof != -1) + || (!dneg && mof != 0)) + flags |= V_FLAG; + evaluate_flags_writeback(flags); +} +void helper_evaluate_flags_mulu(void) +{ + uint32_t src; + uint32_t dst; + uint32_t res; + uint32_t flags = 0; + uint64_t tmp; + uint32_t mof; + + src = env->cc_src; + dst = env->cc_dest; + res = env->cc_result; + + mof = env->pregs[PR_MOF]; + tmp = mof; + tmp <<= 32; + tmp |= res; + if (tmp == 0) + flags |= Z_FLAG; + else if (tmp >> 63) + flags |= N_FLAG; + if (mof) + flags |= V_FLAG; + + evaluate_flags_writeback(flags); +} + +void helper_evaluate_flags_mcp(void) +{ + uint32_t src; + uint32_t dst; + uint32_t res; + uint32_t flags = 0; + + src = env->cc_src; + dst = env->cc_dest; + res = env->cc_result; + + if ((res & 0x80000000L) != 0L) + { + flags |= N_FLAG; + if (((src & 0x80000000L) == 0L) + && ((dst & 0x80000000L) == 0L)) + { + flags |= V_FLAG; + } + else if (((src & 0x80000000L) != 0L) && + ((dst & 0x80000000L) != 0L)) + { + flags |= R_FLAG; + } + } + else + { + if (res == 0L) + flags |= Z_FLAG; + if (((src & 0x80000000L) != 0L) + && ((dst & 0x80000000L) != 0L)) + flags |= V_FLAG; + if ((dst & 0x80000000L) != 0L + || (src & 0x80000000L) != 0L) + flags |= R_FLAG; + } + + evaluate_flags_writeback(flags); +} + +void helper_evaluate_flags_alu_4(void) +{ + uint32_t src; + uint32_t dst; + uint32_t res; + uint32_t flags = 0; + + src = env->cc_src; + dst = env->cc_dest; + + /* Reconstruct the result. */ + switch (env->cc_op) + { + case CC_OP_SUB: + res = dst - src; + break; + case CC_OP_ADD: + res = dst + src; + break; + default: + res = env->cc_result; + break; + } + + if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP) + src = ~src; + + if ((res & 0x80000000L) != 0L) + { + flags |= N_FLAG; + if (((src & 0x80000000L) == 0L) + && ((dst & 0x80000000L) == 0L)) + { + flags |= V_FLAG; + } + else if (((src & 0x80000000L) != 0L) && + ((dst & 0x80000000L) != 0L)) + { + flags |= C_FLAG; + } + } + else + { + if (res == 0L) + flags |= Z_FLAG; + if (((src & 0x80000000L) != 0L) + && ((dst & 0x80000000L) != 0L)) + flags |= V_FLAG; + if ((dst & 0x80000000L) != 0L + || (src & 0x80000000L) != 0L) + flags |= C_FLAG; + } + + if (env->cc_op == CC_OP_SUB + || env->cc_op == CC_OP_CMP) { + flags ^= C_FLAG; + } + evaluate_flags_writeback(flags); +} + +void helper_evaluate_flags_move_4 (void) +{ + uint32_t res; + uint32_t flags = 0; + + res = env->cc_result; + + if ((int32_t)res < 0) + flags |= N_FLAG; + else if (res == 0L) + flags |= Z_FLAG; + + evaluate_flags_writeback(flags); +} +void helper_evaluate_flags_move_2 (void) +{ + uint32_t src; + uint32_t flags = 0; + uint16_t res; + + src = env->cc_src; + res = env->cc_result; + + if ((int16_t)res < 0L) + flags |= N_FLAG; + else if (res == 0) + flags |= Z_FLAG; + + evaluate_flags_writeback(flags); +} + +/* TODO: This is expensive. We could split things up and only evaluate part of + CCR on a need to know basis. For now, we simply re-evaluate everything. */ +void helper_evaluate_flags (void) +{ + uint32_t src; + uint32_t dst; + uint32_t res; + uint32_t flags = 0; + + src = env->cc_src; + dst = env->cc_dest; + res = env->cc_result; + + if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP) + src = ~src; + + /* Now, evaluate the flags. This stuff is based on + Per Zander's CRISv10 simulator. */ + switch (env->cc_size) + { + case 1: + if ((res & 0x80L) != 0L) + { + flags |= N_FLAG; + if (((src & 0x80L) == 0L) + && ((dst & 0x80L) == 0L)) + { + flags |= V_FLAG; + } + else if (((src & 0x80L) != 0L) + && ((dst & 0x80L) != 0L)) + { + flags |= C_FLAG; + } + } + else + { + if ((res & 0xFFL) == 0L) + { + flags |= Z_FLAG; + } + if (((src & 0x80L) != 0L) + && ((dst & 0x80L) != 0L)) + { + flags |= V_FLAG; + } + if ((dst & 0x80L) != 0L + || (src & 0x80L) != 0L) + { + flags |= C_FLAG; + } + } + break; + case 2: + if ((res & 0x8000L) != 0L) + { + flags |= N_FLAG; + if (((src & 0x8000L) == 0L) + && ((dst & 0x8000L) == 0L)) + { + flags |= V_FLAG; + } + else if (((src & 0x8000L) != 0L) + && ((dst & 0x8000L) != 0L)) + { + flags |= C_FLAG; + } + } + else + { + if ((res & 0xFFFFL) == 0L) + { + flags |= Z_FLAG; + } + if (((src & 0x8000L) != 0L) + && ((dst & 0x8000L) != 0L)) + { + flags |= V_FLAG; + } + if ((dst & 0x8000L) != 0L + || (src & 0x8000L) != 0L) + { + flags |= C_FLAG; + } + } + break; + case 4: + if ((res & 0x80000000L) != 0L) + { + flags |= N_FLAG; + if (((src & 0x80000000L) == 0L) + && ((dst & 0x80000000L) == 0L)) + { + flags |= V_FLAG; + } + else if (((src & 0x80000000L) != 0L) && + ((dst & 0x80000000L) != 0L)) + { + flags |= C_FLAG; + } + } + else + { + if (res == 0L) + flags |= Z_FLAG; + if (((src & 0x80000000L) != 0L) + && ((dst & 0x80000000L) != 0L)) + flags |= V_FLAG; + if ((dst & 0x80000000L) != 0L + || (src & 0x80000000L) != 0L) + flags |= C_FLAG; + } + break; + default: + break; + } + + if (env->cc_op == CC_OP_SUB + || env->cc_op == CC_OP_CMP) { + flags ^= C_FLAG; + } + evaluate_flags_writeback(flags); +} + +void helper_top_evaluate_flags(void) +{ + switch (env->cc_op) + { + case CC_OP_MCP: + helper_evaluate_flags_mcp(); + break; + case CC_OP_MULS: + helper_evaluate_flags_muls(); + break; + case CC_OP_MULU: + helper_evaluate_flags_mulu(); + break; + case CC_OP_MOVE: + case CC_OP_AND: + case CC_OP_OR: + case CC_OP_XOR: + case CC_OP_ASR: + case CC_OP_LSR: + case CC_OP_LSL: + switch (env->cc_size) + { + case 4: + helper_evaluate_flags_move_4(); + break; + case 2: + helper_evaluate_flags_move_2(); + break; + default: + helper_evaluate_flags(); + break; + } + break; + case CC_OP_FLAGS: + /* live. */ + break; + default: + { + switch (env->cc_size) + { + case 4: + helper_evaluate_flags_alu_4(); + break; + default: + helper_evaluate_flags(); + break; + } + } + break; + } } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-cris/op_mem.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-cris/op_mem.c --- qemu-0.9.1/target-cris/op_mem.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-cris/op_mem.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,59 +0,0 @@ -/* - * CRIS memory access (load and store) micro operations. - * - * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB. - * - * 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 - */ - -void glue(op_ldb_T0_T0, MEMSUFFIX) (void) { - T0 = glue(ldsb, MEMSUFFIX) (T0); - RETURN(); -} - -void glue(op_ldub_T0_T0, MEMSUFFIX) (void) { - T0 = glue(ldub, MEMSUFFIX) (T0); - RETURN(); -} - -void glue(op_stb_T0_T1, MEMSUFFIX) (void) { - glue(stb, MEMSUFFIX) (T0, T1); - RETURN(); -} - -void glue(op_ldw_T0_T0, MEMSUFFIX) (void) { - T0 = glue(ldsw, MEMSUFFIX) (T0); - RETURN(); -} - -void glue(op_lduw_T0_T0, MEMSUFFIX) (void) { - T0 = glue(lduw, MEMSUFFIX) (T0); - RETURN(); -} - -void glue(op_stw_T0_T1, MEMSUFFIX) (void) { - glue(stw, MEMSUFFIX) (T0, T1); - RETURN(); -} - -void glue(op_ldl_T0_T0, MEMSUFFIX) (void) { - T0 = glue(ldl, MEMSUFFIX) (T0); - RETURN(); -} - -void glue(op_stl_T0_T1, MEMSUFFIX) (void) { - glue(stl, MEMSUFFIX) (T0, T1); - RETURN(); -} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-cris/translate.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-cris/translate.c --- qemu-0.9.1/target-cris/translate.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-cris/translate.c 2008-11-01 00:53:30.000000000 +0000 @@ -1,7 +1,7 @@ /* * CRIS emulation for qemu: main translation routines. * - * Copyright (c) 2007 AXIS Communications AB + * Copyright (c) 2008 AXIS Communications AB * Written by Edgar E. Iglesias. * * This library is free software; you can redistribute it and/or @@ -20,25 +20,8 @@ */ /* - * This file implements a CRIS decoder-stage in SW. The decoder translates the - * guest (CRIS) machine-code into host machine code via dyngen using the - * micro-operations described in op.c - * - * The micro-operations for CRIS translation implement a RISC style ISA. - * Note that the micro-operations typically order their operands - * starting with the dst. CRIS asm, does the opposite. - * - * For example the following CRIS code: - * add.d [$r0], $r1 - * - * translates into: - * - * gen_movl_T0_reg(0); // Fetch $r0 into T0 - * gen_load_T0_T0(); // Load T0, @T0 - * gen_movl_reg_T0(1); // Writeback T0 into $r1 - * - * The actual names for the micro-code generators vary but the example - * illustrates the point. + * FIXME: + * The condition code translation is in need of attention. */ #include @@ -51,31 +34,24 @@ #include "cpu.h" #include "exec-all.h" #include "disas.h" +#include "tcg-op.h" +#include "helper.h" #include "crisv32-decode.h" - -#define CRIS_STATS 0 -#if CRIS_STATS -#define STATS(x) x -#else -#define STATS(x) -#endif +#include "qemu-common.h" #define DISAS_CRIS 0 #if DISAS_CRIS -#define DIS(x) x +#define DIS(x) if (loglevel & CPU_LOG_TB_IN_ASM) x #else #define DIS(x) #endif -#ifdef USE_DIRECT_JUMP -#define TBPARAM(x) -#else -#define TBPARAM(x) (long)(x) -#endif - +#define D(x) #define BUG() (gen_BUG(dc, __FILE__, __LINE__)) #define BUG_ON(x) ({if (x) BUG();}) +#define DISAS_SWI 5 + /* Used by the decoder. */ #define EXTRACT_FIELD(src, start, end) \ (((src) >> start) & ((1 << (end - start + 1)) - 1)) @@ -85,21 +61,27 @@ #define CC_MASK_NZVC 0xf #define CC_MASK_RNZV 0x10e -static uint16_t *gen_opc_ptr; -static uint32_t *gen_opparam_ptr; +static TCGv cpu_env; +static TCGv cpu_R[16]; +static TCGv cpu_PR[16]; +static TCGv cc_x; +static TCGv cc_src; +static TCGv cc_dest; +static TCGv cc_result; +static TCGv cc_op; +static TCGv cc_size; +static TCGv cc_mask; + +static TCGv env_btaken; +static TCGv env_btarget; +static TCGv env_pc; -enum { -#define DEF(s, n, copy_size) INDEX_op_ ## s, -#include "opc.h" -#undef DEF - NB_OPS, -}; -#include "gen-op.h" +#include "gen-icount.h" /* This is the state at translation time. */ typedef struct DisasContext { CPUState *env; - target_ulong pc, insn_pc; + target_ulong pc, ppc; /* Decoder. */ uint32_t ir; @@ -110,174 +92,564 @@ unsigned int mode; unsigned int postinc; - - struct - { - int op; - int size; - unsigned int mask; - } cc_state[3]; - int cc_i; - int update_cc; int cc_op; int cc_size; uint32_t cc_mask; - int flags_live; - int flagx_live; + + int cc_size_uptodate; /* -1 invalid or last written value. */ + + int cc_x_uptodate; /* 1 - ccs, 2 - known | X_FLAG. 0 not uptodate. */ + int flags_uptodate; /* Wether or not $ccs is uptodate. */ + int flagx_known; /* Wether or not flags_x has the x flag known at + translation time. */ int flags_x; - uint32_t tb_entry_flags; - int memidx; /* user or kernel mode. */ + int clear_x; /* Clear x after this insn? */ + int cpustate_changed; + unsigned int tb_flags; /* tb dependent flags. */ int is_jmp; - int dyn_jmp; - uint32_t delayed_pc; +#define JMP_NOJMP 0 +#define JMP_DIRECT 1 +#define JMP_INDIRECT 2 + int jmp; /* 0=nojmp, 1=direct, 2=indirect. */ + uint32_t jmp_pc; + int delayed_branch; - int bcc; - uint32_t condlabel; struct TranslationBlock *tb; int singlestep_enabled; } DisasContext; -void cris_prepare_jmp (DisasContext *dc, uint32_t dst); -static void gen_BUG(DisasContext *dc, char *file, int line) +static void gen_BUG(DisasContext *dc, const char *file, int line) { printf ("BUG: pc=%x %s %d\n", dc->pc, file, line); fprintf (logfile, "BUG: pc=%x %s %d\n", dc->pc, file, line); - cpu_dump_state (dc->env, stdout, fprintf, 0); - fflush(NULL); - cris_prepare_jmp (dc, 0x70000000 + line); + cpu_abort(dc->env, "%s:%d\n", file, line); } -/* Table to generate quick moves from T0 onto any register. */ -static GenOpFunc *gen_movl_reg_T0[16] = +static const char *regnames[] = { - gen_op_movl_r0_T0, gen_op_movl_r1_T0, - gen_op_movl_r2_T0, gen_op_movl_r3_T0, - gen_op_movl_r4_T0, gen_op_movl_r5_T0, - gen_op_movl_r6_T0, gen_op_movl_r7_T0, - gen_op_movl_r8_T0, gen_op_movl_r9_T0, - gen_op_movl_r10_T0, gen_op_movl_r11_T0, - gen_op_movl_r12_T0, gen_op_movl_r13_T0, - gen_op_movl_r14_T0, gen_op_movl_r15_T0, + "$r0", "$r1", "$r2", "$r3", + "$r4", "$r5", "$r6", "$r7", + "$r8", "$r9", "$r10", "$r11", + "$r12", "$r13", "$sp", "$acr", }; -static GenOpFunc *gen_movl_T0_reg[16] = +static const char *pregnames[] = { - gen_op_movl_T0_r0, gen_op_movl_T0_r1, - gen_op_movl_T0_r2, gen_op_movl_T0_r3, - gen_op_movl_T0_r4, gen_op_movl_T0_r5, - gen_op_movl_T0_r6, gen_op_movl_T0_r7, - gen_op_movl_T0_r8, gen_op_movl_T0_r9, - gen_op_movl_T0_r10, gen_op_movl_T0_r11, - gen_op_movl_T0_r12, gen_op_movl_T0_r13, - gen_op_movl_T0_r14, gen_op_movl_T0_r15, + "$bz", "$vr", "$pid", "$srs", + "$wz", "$exs", "$eda", "$mof", + "$dz", "$ebp", "$erp", "$srp", + "$nrp", "$ccs", "$usp", "$spc", }; -static void noop_write(void) { - /* nop. */ +/* We need this table to handle preg-moves with implicit width. */ +static int preg_sizes[] = { + 1, /* bz. */ + 1, /* vr. */ + 4, /* pid. */ + 1, /* srs. */ + 2, /* wz. */ + 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, +}; + +#define t_gen_mov_TN_env(tn, member) \ + _t_gen_mov_TN_env((tn), offsetof(CPUState, member)) +#define t_gen_mov_env_TN(member, tn) \ + _t_gen_mov_env_TN(offsetof(CPUState, member), (tn)) + +static inline void t_gen_mov_TN_reg(TCGv tn, int r) +{ + if (r < 0 || r > 15) + fprintf(stderr, "wrong register read $r%d\n", r); + tcg_gen_mov_tl(tn, cpu_R[r]); +} +static inline void t_gen_mov_reg_TN(int r, TCGv tn) +{ + if (r < 0 || r > 15) + fprintf(stderr, "wrong register write $r%d\n", r); + tcg_gen_mov_tl(cpu_R[r], tn); } -static void gen_vr_read(void) { - gen_op_movl_T0_im(32); +static inline void _t_gen_mov_TN_env(TCGv tn, int offset) +{ + if (offset > sizeof (CPUState)) + fprintf(stderr, "wrong load from env from off=%d\n", offset); + tcg_gen_ld_tl(tn, cpu_env, offset); +} +static inline void _t_gen_mov_env_TN(int offset, TCGv tn) +{ + if (offset > sizeof (CPUState)) + fprintf(stderr, "wrong store to env at off=%d\n", offset); + tcg_gen_st_tl(tn, cpu_env, offset); } -static void gen_ccs_read(void) { - gen_op_movl_T0_p13(); +static inline void t_gen_mov_TN_preg(TCGv tn, int r) +{ + if (r < 0 || r > 15) + fprintf(stderr, "wrong register read $p%d\n", r); + if (r == PR_BZ || r == PR_WZ || r == PR_DZ) + tcg_gen_mov_tl(tn, tcg_const_tl(0)); + else if (r == PR_VR) + tcg_gen_mov_tl(tn, tcg_const_tl(32)); + else if (r == PR_EDA) { + printf("read from EDA!\n"); + tcg_gen_mov_tl(tn, cpu_PR[r]); + } + else + tcg_gen_mov_tl(tn, cpu_PR[r]); +} +static inline void t_gen_mov_preg_TN(DisasContext *dc, int r, TCGv tn) +{ + if (r < 0 || r > 15) + fprintf(stderr, "wrong register write $p%d\n", r); + if (r == PR_BZ || r == PR_WZ || r == PR_DZ) + return; + else if (r == PR_SRS) + tcg_gen_andi_tl(cpu_PR[r], tn, 3); + else { + if (r == PR_PID) + tcg_gen_helper_0_1(helper_tlb_flush_pid, tn); + if (dc->tb_flags & S_FLAG && r == PR_SPC) + tcg_gen_helper_0_1(helper_spc_write, tn); + else if (r == PR_CCS) + dc->cpustate_changed = 1; + tcg_gen_mov_tl(cpu_PR[r], tn); + } } -static void gen_ccs_write(void) { - gen_op_movl_p13_T0(); +static inline void t_gen_raise_exception(uint32_t index) +{ + tcg_gen_helper_0_1(helper_raise_exception, tcg_const_tl(index)); } -/* Table to generate quick moves from T0 onto any register. */ -static GenOpFunc *gen_movl_preg_T0[16] = +static void t_gen_lsl(TCGv d, TCGv a, TCGv b) { - noop_write, /* bz, not writeable. */ - noop_write, /* vr, not writeable. */ - gen_op_movl_p2_T0, gen_op_movl_p3_T0, - noop_write, /* wz, not writeable. */ - gen_op_movl_p5_T0, - gen_op_movl_p6_T0, gen_op_movl_p7_T0, - noop_write, /* dz, not writeable. */ - gen_op_movl_p9_T0, - gen_op_movl_p10_T0, gen_op_movl_p11_T0, - gen_op_movl_p12_T0, - gen_ccs_write, /* ccs needs special treatment. */ - gen_op_movl_p14_T0, gen_op_movl_p15_T0, -}; -static GenOpFunc *gen_movl_T0_preg[16] = + TCGv t0, t_31; + + t0 = tcg_temp_new(TCG_TYPE_TL); + t_31 = tcg_const_tl(31); + tcg_gen_shl_tl(d, a, b); + + tcg_gen_sub_tl(t0, t_31, b); + tcg_gen_sar_tl(t0, t0, t_31); + tcg_gen_and_tl(t0, t0, d); + tcg_gen_xor_tl(d, d, t0); + tcg_temp_free(t0); + tcg_temp_free(t_31); +} + +static void t_gen_lsr(TCGv d, TCGv a, TCGv b) { - gen_op_movl_T0_p0, - gen_vr_read, - gen_op_movl_T0_p2, gen_op_movl_T0_p3, - gen_op_movl_T0_p4, gen_op_movl_T0_p5, - gen_op_movl_T0_p6, gen_op_movl_T0_p7, - gen_op_movl_T0_p8, gen_op_movl_T0_p9, - gen_op_movl_T0_p10, gen_op_movl_T0_p11, - gen_op_movl_T0_p12, - gen_ccs_read, /* ccs needs special treatment. */ - gen_op_movl_T0_p14, gen_op_movl_T0_p15, -}; + TCGv t0, t_31; -/* We need this table to handle moves with implicit width. */ -int preg_sizes[] = { - 1, /* bz. */ - 1, /* vr. */ - 4, /* pid. */ - 1, /* srs. */ - 2, /* wz. */ - 4, 4, 4, - 4, 4, 4, 4, - 4, 4, 4, 4, -}; + t0 = tcg_temp_new(TCG_TYPE_TL); + t_31 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_shr_tl(d, a, b); -#ifdef CONFIG_USER_ONLY -#define GEN_OP_LD(width, reg) \ - void gen_op_ld##width##_T0_##reg (DisasContext *dc) { \ - gen_op_ld##width##_T0_##reg##_raw(); \ - } -#define GEN_OP_ST(width, reg) \ - void gen_op_st##width##_##reg##_T1 (DisasContext *dc) { \ - gen_op_st##width##_##reg##_T1_raw(); \ - } -#else -#define GEN_OP_LD(width, reg) \ - void gen_op_ld##width##_T0_##reg (DisasContext *dc) { \ - if (dc->memidx) gen_op_ld##width##_T0_##reg##_kernel(); \ - else gen_op_ld##width##_T0_##reg##_user();\ - } -#define GEN_OP_ST(width, reg) \ - void gen_op_st##width##_##reg##_T1 (DisasContext *dc) { \ - if (dc->memidx) gen_op_st##width##_##reg##_T1_kernel(); \ - else gen_op_st##width##_##reg##_T1_user();\ - } -#endif + tcg_gen_movi_tl(t_31, 31); + tcg_gen_sub_tl(t0, t_31, b); + tcg_gen_sar_tl(t0, t0, t_31); + tcg_gen_and_tl(t0, t0, d); + tcg_gen_xor_tl(d, d, t0); + tcg_temp_free(t0); + tcg_temp_free(t_31); +} + +static void t_gen_asr(TCGv d, TCGv a, TCGv b) +{ + TCGv t0, t_31; + + t0 = tcg_temp_new(TCG_TYPE_TL); + t_31 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_sar_tl(d, a, b); + + tcg_gen_movi_tl(t_31, 31); + tcg_gen_sub_tl(t0, t_31, b); + tcg_gen_sar_tl(t0, t0, t_31); + tcg_gen_or_tl(d, d, t0); + tcg_temp_free(t0); + tcg_temp_free(t_31); +} + +/* 64-bit signed mul, lower result in d and upper in d2. */ +static void t_gen_muls(TCGv d, TCGv d2, TCGv a, TCGv b) +{ + TCGv t0, t1; + + t0 = tcg_temp_new(TCG_TYPE_I64); + t1 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_ext32s_i64(t0, a); + tcg_gen_ext32s_i64(t1, b); + tcg_gen_mul_i64(t0, t0, t1); + + tcg_gen_trunc_i64_i32(d, t0); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_trunc_i64_i32(d2, t0); + + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +/* 64-bit unsigned muls, lower result in d and upper in d2. */ +static void t_gen_mulu(TCGv d, TCGv d2, TCGv a, TCGv b) +{ + TCGv t0, t1; + + t0 = tcg_temp_new(TCG_TYPE_I64); + t1 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_extu_i32_i64(t0, a); + tcg_gen_extu_i32_i64(t1, b); + tcg_gen_mul_i64(t0, t0, t1); + + tcg_gen_trunc_i64_i32(d, t0); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_trunc_i64_i32(d2, t0); + + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +/* 32bit branch-free binary search for counting leading zeros. */ +static void t_gen_lz_i32(TCGv d, TCGv x) +{ + TCGv y, m, n; + + y = tcg_temp_new(TCG_TYPE_I32); + m = tcg_temp_new(TCG_TYPE_I32); + n = tcg_temp_new(TCG_TYPE_I32); + + /* y = -(x >> 16) */ + tcg_gen_shri_i32(y, x, 16); + tcg_gen_neg_i32(y, y); + + /* m = (y >> 16) & 16 */ + tcg_gen_sari_i32(m, y, 16); + tcg_gen_andi_i32(m, m, 16); + + /* n = 16 - m */ + tcg_gen_sub_i32(n, tcg_const_i32(16), m); + /* x = x >> m */ + tcg_gen_shr_i32(x, x, m); + + /* y = x - 0x100 */ + tcg_gen_subi_i32(y, x, 0x100); + /* m = (y >> 16) & 8 */ + tcg_gen_sari_i32(m, y, 16); + tcg_gen_andi_i32(m, m, 8); + /* n = n + m */ + tcg_gen_add_i32(n, n, m); + /* x = x << m */ + tcg_gen_shl_i32(x, x, m); + + /* y = x - 0x1000 */ + tcg_gen_subi_i32(y, x, 0x1000); + /* m = (y >> 16) & 4 */ + tcg_gen_sari_i32(m, y, 16); + tcg_gen_andi_i32(m, m, 4); + /* n = n + m */ + tcg_gen_add_i32(n, n, m); + /* x = x << m */ + tcg_gen_shl_i32(x, x, m); + + /* y = x - 0x4000 */ + tcg_gen_subi_i32(y, x, 0x4000); + /* m = (y >> 16) & 2 */ + tcg_gen_sari_i32(m, y, 16); + tcg_gen_andi_i32(m, m, 2); + /* n = n + m */ + tcg_gen_add_i32(n, n, m); + /* x = x << m */ + tcg_gen_shl_i32(x, x, m); -GEN_OP_LD(ub, T0) -GEN_OP_LD(b, T0) -GEN_OP_ST(b, T0) -GEN_OP_LD(uw, T0) -GEN_OP_LD(w, T0) -GEN_OP_ST(w, T0) -GEN_OP_LD(l, T0) -GEN_OP_ST(l, T0) + /* y = x >> 14 */ + tcg_gen_shri_i32(y, x, 14); + /* m = y & ~(y >> 1) */ + tcg_gen_sari_i32(m, y, 1); + tcg_gen_not_i32(m, m); + tcg_gen_and_i32(m, m, y); + + /* d = n + 2 - m */ + tcg_gen_addi_i32(d, n, 2); + tcg_gen_sub_i32(d, d, m); + + tcg_temp_free(y); + tcg_temp_free(m); + tcg_temp_free(n); +} + +static void t_gen_btst(TCGv d, TCGv a, TCGv b) +{ + TCGv sbit; + TCGv bset; + TCGv t0; + int l1; + + /* des ref: + The N flag is set according to the selected bit in the dest reg. + The Z flag is set if the selected bit and all bits to the right are + zero. + The X flag is cleared. + Other flags are left untouched. + The destination reg is not affected. + + unsigned int fz, sbit, bset, mask, masked_t0; + + sbit = T1 & 31; + bset = !!(T0 & (1 << sbit)); + mask = sbit == 31 ? -1 : (1 << (sbit + 1)) - 1; + masked_t0 = T0 & mask; + fz = !(masked_t0 | bset); + + // Clear the X, N and Z flags. + T0 = env->pregs[PR_CCS] & ~(X_FLAG | N_FLAG | Z_FLAG); + // Set the N and Z flags accordingly. + T0 |= (bset << 3) | (fz << 2); + */ + + l1 = gen_new_label(); + sbit = tcg_temp_new(TCG_TYPE_TL); + bset = tcg_temp_new(TCG_TYPE_TL); + t0 = tcg_temp_new(TCG_TYPE_TL); + + /* Compute bset and sbit. */ + tcg_gen_andi_tl(sbit, b, 31); + tcg_gen_shl_tl(t0, tcg_const_tl(1), sbit); + tcg_gen_and_tl(bset, a, t0); + tcg_gen_shr_tl(bset, bset, sbit); + /* Displace to N_FLAG. */ + tcg_gen_shli_tl(bset, bset, 3); + + tcg_gen_shl_tl(sbit, tcg_const_tl(2), sbit); + tcg_gen_subi_tl(sbit, sbit, 1); + tcg_gen_and_tl(sbit, a, sbit); + + tcg_gen_andi_tl(d, cpu_PR[PR_CCS], ~(X_FLAG | N_FLAG | Z_FLAG)); + /* or in the N_FLAG. */ + tcg_gen_or_tl(d, d, bset); + tcg_gen_brcondi_tl(TCG_COND_NE, sbit, 0, l1); + /* or in the Z_FLAG. */ + tcg_gen_ori_tl(d, d, Z_FLAG); + gen_set_label(l1); + + tcg_temp_free(sbit); + tcg_temp_free(bset); +} + +static void t_gen_cris_dstep(TCGv d, TCGv a, TCGv b) +{ + int l1; + + l1 = gen_new_label(); + + /* + * d <<= 1 + * if (d >= s) + * d -= s; + */ + tcg_gen_shli_tl(d, a, 1); + tcg_gen_brcond_tl(TCG_COND_LTU, d, b, l1); + tcg_gen_sub_tl(d, d, b); + gen_set_label(l1); +} + +/* Extended arithmetics on CRIS. */ +static inline void t_gen_add_flag(TCGv d, int flag) +{ + TCGv c; + + c = tcg_temp_new(TCG_TYPE_TL); + t_gen_mov_TN_preg(c, PR_CCS); + /* Propagate carry into d. */ + tcg_gen_andi_tl(c, c, 1 << flag); + if (flag) + tcg_gen_shri_tl(c, c, flag); + tcg_gen_add_tl(d, d, c); + tcg_temp_free(c); +} + +static inline void t_gen_addx_carry(DisasContext *dc, TCGv d) +{ + if (dc->flagx_known) { + if (dc->flags_x) { + TCGv c; + + c = tcg_temp_new(TCG_TYPE_TL); + t_gen_mov_TN_preg(c, PR_CCS); + /* C flag is already at bit 0. */ + tcg_gen_andi_tl(c, c, C_FLAG); + tcg_gen_add_tl(d, d, c); + tcg_temp_free(c); + } + } else { + TCGv x, c; + + x = tcg_temp_new(TCG_TYPE_TL); + c = tcg_temp_new(TCG_TYPE_TL); + t_gen_mov_TN_preg(x, PR_CCS); + tcg_gen_mov_tl(c, x); + + /* Propagate carry into d if X is set. Branch free. */ + tcg_gen_andi_tl(c, c, C_FLAG); + tcg_gen_andi_tl(x, x, X_FLAG); + tcg_gen_shri_tl(x, x, 4); + + tcg_gen_and_tl(x, x, c); + tcg_gen_add_tl(d, d, x); + tcg_temp_free(x); + tcg_temp_free(c); + } +} + +static inline void t_gen_subx_carry(DisasContext *dc, TCGv d) +{ + if (dc->flagx_known) { + if (dc->flags_x) { + TCGv c; + + c = tcg_temp_new(TCG_TYPE_TL); + t_gen_mov_TN_preg(c, PR_CCS); + /* C flag is already at bit 0. */ + tcg_gen_andi_tl(c, c, C_FLAG); + tcg_gen_sub_tl(d, d, c); + tcg_temp_free(c); + } + } else { + TCGv x, c; + + x = tcg_temp_new(TCG_TYPE_TL); + c = tcg_temp_new(TCG_TYPE_TL); + t_gen_mov_TN_preg(x, PR_CCS); + tcg_gen_mov_tl(c, x); + + /* Propagate carry into d if X is set. Branch free. */ + tcg_gen_andi_tl(c, c, C_FLAG); + tcg_gen_andi_tl(x, x, X_FLAG); + tcg_gen_shri_tl(x, x, 4); + + tcg_gen_and_tl(x, x, c); + tcg_gen_sub_tl(d, d, x); + tcg_temp_free(x); + tcg_temp_free(c); + } +} + +/* Swap the two bytes within each half word of the s operand. + T0 = ((T0 << 8) & 0xff00ff00) | ((T0 >> 8) & 0x00ff00ff) */ +static inline void t_gen_swapb(TCGv d, TCGv s) +{ + TCGv t, org_s; + + t = tcg_temp_new(TCG_TYPE_TL); + org_s = tcg_temp_new(TCG_TYPE_TL); + + /* d and s may refer to the same object. */ + tcg_gen_mov_tl(org_s, s); + tcg_gen_shli_tl(t, org_s, 8); + tcg_gen_andi_tl(d, t, 0xff00ff00); + tcg_gen_shri_tl(t, org_s, 8); + tcg_gen_andi_tl(t, t, 0x00ff00ff); + tcg_gen_or_tl(d, d, t); + tcg_temp_free(t); + tcg_temp_free(org_s); +} + +/* Swap the halfwords of the s operand. */ +static inline void t_gen_swapw(TCGv d, TCGv s) +{ + TCGv t; + /* d and s refer the same object. */ + t = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_mov_tl(t, s); + tcg_gen_shli_tl(d, t, 16); + tcg_gen_shri_tl(t, t, 16); + tcg_gen_or_tl(d, d, t); + tcg_temp_free(t); +} + +/* Reverse the within each byte. + T0 = (((T0 << 7) & 0x80808080) | + ((T0 << 5) & 0x40404040) | + ((T0 << 3) & 0x20202020) | + ((T0 << 1) & 0x10101010) | + ((T0 >> 1) & 0x08080808) | + ((T0 >> 3) & 0x04040404) | + ((T0 >> 5) & 0x02020202) | + ((T0 >> 7) & 0x01010101)); + */ +static inline void t_gen_swapr(TCGv d, TCGv s) +{ + struct { + int shift; /* LSL when positive, LSR when negative. */ + uint32_t mask; + } bitrev [] = { + {7, 0x80808080}, + {5, 0x40404040}, + {3, 0x20202020}, + {1, 0x10101010}, + {-1, 0x08080808}, + {-3, 0x04040404}, + {-5, 0x02020202}, + {-7, 0x01010101} + }; + int i; + TCGv t, org_s; + + /* d and s refer the same object. */ + t = tcg_temp_new(TCG_TYPE_TL); + org_s = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_mov_tl(org_s, s); + + tcg_gen_shli_tl(t, org_s, bitrev[0].shift); + tcg_gen_andi_tl(d, t, bitrev[0].mask); + for (i = 1; i < sizeof bitrev / sizeof bitrev[0]; i++) { + if (bitrev[i].shift >= 0) { + tcg_gen_shli_tl(t, org_s, bitrev[i].shift); + } else { + tcg_gen_shri_tl(t, org_s, -bitrev[i].shift); + } + tcg_gen_andi_tl(t, t, bitrev[i].mask); + tcg_gen_or_tl(d, d, t); + } + tcg_temp_free(t); + tcg_temp_free(org_s); +} + +static void t_gen_cc_jmp(TCGv pc_true, TCGv pc_false) +{ + TCGv btaken; + int l1; + + l1 = gen_new_label(); + btaken = tcg_temp_new(TCG_TYPE_TL); + + /* Conditional jmp. */ + tcg_gen_mov_tl(btaken, env_btaken); + tcg_gen_mov_tl(env_pc, pc_false); + tcg_gen_brcondi_tl(TCG_COND_EQ, btaken, 0, l1); + tcg_gen_mov_tl(env_pc, pc_true); + gen_set_label(l1); + + tcg_temp_free(btaken); +} static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) { TranslationBlock *tb; tb = dc->tb; if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { - if (n == 0) - gen_op_goto_tb0(TBPARAM(tb)); - else - gen_op_goto_tb1(TBPARAM(tb)); - gen_op_movl_T0_0(); + tcg_gen_goto_tb(n); + tcg_gen_movi_tl(env_pc, dest); + tcg_gen_exit_tb((long)tb + n); } else { - gen_op_movl_T0_0(); + tcg_gen_movi_tl(env_pc, dest); + tcg_gen_exit_tb(0); } - gen_op_exit_tb(); } /* Sign extend at translation time. */ @@ -293,51 +665,88 @@ return sval; } +static inline void cris_clear_x_flag(DisasContext *dc) +{ + if (dc->flagx_known && dc->flags_x) + dc->flags_uptodate = 0; + + dc->flagx_known = 1; + dc->flags_x = 0; +} + +static void cris_flush_cc_state(DisasContext *dc) +{ + if (dc->cc_size_uptodate != dc->cc_size) { + tcg_gen_movi_tl(cc_size, dc->cc_size); + dc->cc_size_uptodate = dc->cc_size; + } + tcg_gen_movi_tl(cc_op, dc->cc_op); + tcg_gen_movi_tl(cc_mask, dc->cc_mask); +} + static void cris_evaluate_flags(DisasContext *dc) { - if (!dc->flags_live) { + if (!dc->flags_uptodate) { + cris_flush_cc_state(dc); switch (dc->cc_op) { case CC_OP_MCP: - gen_op_evaluate_flags_mcp (); + tcg_gen_helper_0_0(helper_evaluate_flags_mcp); break; case CC_OP_MULS: - gen_op_evaluate_flags_muls (); + tcg_gen_helper_0_0(helper_evaluate_flags_muls); break; case CC_OP_MULU: - gen_op_evaluate_flags_mulu (); + tcg_gen_helper_0_0(helper_evaluate_flags_mulu); break; case CC_OP_MOVE: + case CC_OP_AND: + case CC_OP_OR: + case CC_OP_XOR: + case CC_OP_ASR: + case CC_OP_LSR: + case CC_OP_LSL: switch (dc->cc_size) { case 4: - gen_op_evaluate_flags_move_4(); + tcg_gen_helper_0_0(helper_evaluate_flags_move_4); break; case 2: - gen_op_evaluate_flags_move_2(); + tcg_gen_helper_0_0(helper_evaluate_flags_move_2); break; default: - gen_op_evaluate_flags (); + tcg_gen_helper_0_0(helper_evaluate_flags); break; } break; - + case CC_OP_FLAGS: + /* live. */ + break; default: { switch (dc->cc_size) { case 4: - gen_op_evaluate_flags_alu_4 (); + tcg_gen_helper_0_0(helper_evaluate_flags_alu_4); break; default: - gen_op_evaluate_flags (); + tcg_gen_helper_0_0(helper_evaluate_flags); break; } } break; } - dc->flags_live = 1; + if (dc->flagx_known) { + if (dc->flags_x) + tcg_gen_ori_tl(cpu_PR[PR_CCS], + cpu_PR[PR_CCS], X_FLAG); + else + tcg_gen_andi_tl(cpu_PR[PR_CCS], + cpu_PR[PR_CCS], ~X_FLAG); + } + + dc->flags_uptodate = 1; } } @@ -345,135 +754,157 @@ { uint32_t ovl; + if (!mask) { + dc->update_cc = 0; + return; + } + + /* Check if we need to evaluate the condition codes due to + CC overlaying. */ ovl = (dc->cc_mask ^ mask) & ~mask; if (ovl) { /* TODO: optimize this case. It trigs all the time. */ cris_evaluate_flags (dc); } dc->cc_mask = mask; - dc->update_cc = 1; - if (mask == 0) - dc->update_cc = 0; - else { - gen_op_update_cc_mask(mask); - dc->flags_live = 0; - } } -static void cris_update_cc_op(DisasContext *dc, int op) +static void cris_update_cc_op(DisasContext *dc, int op, int size) { dc->cc_op = op; - gen_op_update_cc_op(op); - dc->flags_live = 0; + dc->cc_size = size; + dc->flags_uptodate = 0; } -static void cris_update_cc_size(DisasContext *dc, int size) + +static inline void cris_update_cc_x(DisasContext *dc) { - dc->cc_size = size; - gen_op_update_cc_size_im(size); + /* Save the x flag state at the time of the cc snapshot. */ + if (dc->flagx_known) { + if (dc->cc_x_uptodate == (2 | dc->flags_x)) + return; + tcg_gen_movi_tl(cc_x, dc->flags_x); + dc->cc_x_uptodate = 2 | dc->flags_x; + } + else { + tcg_gen_andi_tl(cc_x, cpu_PR[PR_CCS], X_FLAG); + dc->cc_x_uptodate = 1; + } } -/* op is the operation. - T0, T1 are the operands. - dst is the destination reg. -*/ -static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size) +/* Update cc prior to executing ALU op. Needs source operands untouched. */ +static void cris_pre_alu_update_cc(DisasContext *dc, int op, + TCGv dst, TCGv src, int size) { - int writeback = 1; if (dc->update_cc) { - cris_update_cc_op(dc, op); - cris_update_cc_size(dc, size); - gen_op_update_cc_x(dc->flagx_live, dc->flags_x); - gen_op_update_cc_dest_T0(); + cris_update_cc_op(dc, op, size); + tcg_gen_mov_tl(cc_src, src); + + if (op != CC_OP_MOVE + && op != CC_OP_AND + && op != CC_OP_OR + && op != CC_OP_XOR + && op != CC_OP_ASR + && op != CC_OP_LSR + && op != CC_OP_LSL) + tcg_gen_mov_tl(cc_dest, dst); + + cris_update_cc_x(dc); } +} +/* Update cc after executing ALU op. needs the result. */ +static inline void cris_update_result(DisasContext *dc, TCGv res) +{ + if (dc->update_cc) { + if (dc->cc_size == 4 && + (dc->cc_op == CC_OP_SUB + || dc->cc_op == CC_OP_ADD)) + return; + tcg_gen_mov_tl(cc_result, res); + } +} + +/* Returns one if the write back stage should execute. */ +static void cris_alu_op_exec(DisasContext *dc, int op, + TCGv dst, TCGv a, TCGv b, int size) +{ /* Emit the ALU insns. */ switch (op) { case CC_OP_ADD: - gen_op_addl_T0_T1(); + tcg_gen_add_tl(dst, a, b); /* Extended arithmetics. */ - if (!dc->flagx_live) - gen_op_addxl_T0_C(); - else if (dc->flags_x) - gen_op_addxl_T0_C(); + t_gen_addx_carry(dc, dst); break; case CC_OP_ADDC: - gen_op_addl_T0_T1(); - gen_op_addl_T0_C(); + tcg_gen_add_tl(dst, a, b); + t_gen_add_flag(dst, 0); /* C_FLAG. */ break; case CC_OP_MCP: - gen_op_addl_T0_T1(); - gen_op_addl_T0_R(); + tcg_gen_add_tl(dst, a, b); + t_gen_add_flag(dst, 8); /* R_FLAG. */ break; case CC_OP_SUB: - gen_op_negl_T1_T1(); - gen_op_addl_T0_T1(); - /* CRIS flag evaluation needs ~src. */ - gen_op_negl_T1_T1(); - gen_op_not_T1_T1(); - + tcg_gen_sub_tl(dst, a, b); /* Extended arithmetics. */ - if (!dc->flagx_live) - gen_op_subxl_T0_C(); - else if (dc->flags_x) - gen_op_subxl_T0_C(); + t_gen_subx_carry(dc, dst); break; case CC_OP_MOVE: - gen_op_movl_T0_T1(); + tcg_gen_mov_tl(dst, b); break; case CC_OP_OR: - gen_op_orl_T0_T1(); + tcg_gen_or_tl(dst, a, b); break; case CC_OP_AND: - gen_op_andl_T0_T1(); + tcg_gen_and_tl(dst, a, b); break; case CC_OP_XOR: - gen_op_xorl_T0_T1(); + tcg_gen_xor_tl(dst, a, b); break; case CC_OP_LSL: - gen_op_lsll_T0_T1(); + t_gen_lsl(dst, a, b); break; case CC_OP_LSR: - gen_op_lsrl_T0_T1(); + t_gen_lsr(dst, a, b); break; case CC_OP_ASR: - gen_op_asrl_T0_T1(); + t_gen_asr(dst, a, b); break; case CC_OP_NEG: - gen_op_negl_T0_T1(); + tcg_gen_neg_tl(dst, b); /* Extended arithmetics. */ - gen_op_subxl_T0_C(); + t_gen_subx_carry(dc, dst); break; case CC_OP_LZ: - gen_op_lz_T0_T1(); + t_gen_lz_i32(dst, b); break; case CC_OP_BTST: - gen_op_btst_T0_T1(); - writeback = 0; + t_gen_btst(dst, a, b); break; case CC_OP_MULS: - gen_op_muls_T0_T1(); + t_gen_muls(dst, cpu_PR[PR_MOF], a, b); break; case CC_OP_MULU: - gen_op_mulu_T0_T1(); + t_gen_mulu(dst, cpu_PR[PR_MOF], a, b); break; case CC_OP_DSTEP: - gen_op_dstep_T0_T1(); + t_gen_cris_dstep(dst, a, b); break; case CC_OP_BOUND: - gen_op_bound_T0_T1(); - break; + { + int l1; + l1 = gen_new_label(); + tcg_gen_mov_tl(dst, a); + tcg_gen_brcond_tl(TCG_COND_LEU, a, b, l1); + tcg_gen_mov_tl(dst, b); + gen_set_label(l1); + } + break; case CC_OP_CMP: - gen_op_negl_T1_T1(); - gen_op_addl_T0_T1(); - /* CRIS flag evaluation needs ~src. */ - gen_op_negl_T1_T1(); - gen_op_not_T1_T1(); - + tcg_gen_sub_tl(dst, a, b); /* Extended arithmetics. */ - gen_op_subxl_T0_C(); - writeback = 0; + t_gen_subx_carry(dc, dst); break; default: fprintf (logfile, "illegal ALU op.\n"); @@ -481,49 +912,66 @@ break; } - if (dc->update_cc) - gen_op_update_cc_src_T1(); - if (size == 1) - gen_op_andl_T0_im(0xff); + tcg_gen_andi_tl(dst, dst, 0xff); else if (size == 2) - gen_op_andl_T0_im(0xffff); + tcg_gen_andi_tl(dst, dst, 0xffff); +} + +static void cris_alu(DisasContext *dc, int op, + TCGv d, TCGv op_a, TCGv op_b, int size) +{ + TCGv tmp; + int writeback; + + writeback = 1; + + if (op == CC_OP_BOUND || op == CC_OP_BTST) + tmp = tcg_temp_local_new(TCG_TYPE_TL); + + if (op == CC_OP_CMP) { + tmp = tcg_temp_new(TCG_TYPE_TL); + writeback = 0; + } else if (size == 4) { + tmp = d; + writeback = 0; + } else + tmp = tcg_temp_new(TCG_TYPE_TL); + + + cris_pre_alu_update_cc(dc, op, op_a, op_b, size); + cris_alu_op_exec(dc, op, tmp, op_a, op_b, size); + cris_update_result(dc, tmp); + /* Writeback. */ if (writeback) { - if (size == 4) - gen_movl_reg_T0[rd](); - else { - gen_op_movl_T1_T0(); - gen_movl_T0_reg[rd](); - if (size == 1) - gen_op_andl_T0_im(~0xff); - else - gen_op_andl_T0_im(~0xffff); - gen_op_orl_T0_T1(); - gen_movl_reg_T0[rd](); - gen_op_movl_T0_T1(); - } - } - if (dc->update_cc) - gen_op_update_cc_result_T0(); - - { - /* TODO: Optimize this. */ - if (!dc->flagx_live) - cris_evaluate_flags(dc); + if (size == 1) + tcg_gen_andi_tl(d, d, ~0xff); + else + tcg_gen_andi_tl(d, d, ~0xffff); + tcg_gen_or_tl(d, d, tmp); } + if (GET_TCGV(tmp) != GET_TCGV(d)) + tcg_temp_free(tmp); } static int arith_cc(DisasContext *dc) { if (dc->update_cc) { switch (dc->cc_op) { + case CC_OP_ADDC: return 1; case CC_OP_ADD: return 1; case CC_OP_SUB: return 1; + case CC_OP_DSTEP: return 1; case CC_OP_LSL: return 1; case CC_OP_LSR: return 1; case CC_OP_ASR: return 1; case CC_OP_CMP: return 1; + case CC_OP_NEG: return 1; + case CC_OP_OR: return 1; + case CC_OP_XOR: return 1; + case CC_OP_MULU: return 1; + case CC_OP_MULS: return 1; default: return 0; } @@ -531,92 +979,194 @@ return 0; } -static void gen_tst_cc (DisasContext *dc, int cond) +static void gen_tst_cc (DisasContext *dc, TCGv cc, int cond) { - int arith_opt; + int arith_opt, move_opt; /* TODO: optimize more condition codes. */ - arith_opt = arith_cc(dc) && !dc->flags_live; + + /* + * If the flags are live, we've gotta look into the bits of CCS. + * Otherwise, if we just did an arithmetic operation we try to + * evaluate the condition code faster. + * + * When this function is done, T0 should be non-zero if the condition + * code is true. + */ + arith_opt = arith_cc(dc) && !dc->flags_uptodate; + move_opt = (dc->cc_op == CC_OP_MOVE) && dc->flags_uptodate; switch (cond) { case CC_EQ: - if (arith_opt) - gen_op_tst_cc_eq_fast (); + if (arith_opt || move_opt) { + /* If cc_result is zero, T0 should be + non-zero otherwise T0 should be zero. */ + int l1; + l1 = gen_new_label(); + tcg_gen_movi_tl(cc, 0); + tcg_gen_brcondi_tl(TCG_COND_NE, cc_result, + 0, l1); + tcg_gen_movi_tl(cc, 1); + gen_set_label(l1); + } else { cris_evaluate_flags(dc); - gen_op_tst_cc_eq (); + tcg_gen_andi_tl(cc, + cpu_PR[PR_CCS], Z_FLAG); } break; case CC_NE: - if (arith_opt) - gen_op_tst_cc_ne_fast (); + if (arith_opt || move_opt) + tcg_gen_mov_tl(cc, cc_result); else { cris_evaluate_flags(dc); - gen_op_tst_cc_ne (); + tcg_gen_xori_tl(cc, cpu_PR[PR_CCS], + Z_FLAG); + tcg_gen_andi_tl(cc, cc, Z_FLAG); } break; case CC_CS: cris_evaluate_flags(dc); - gen_op_tst_cc_cs (); + tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], C_FLAG); break; case CC_CC: cris_evaluate_flags(dc); - gen_op_tst_cc_cc (); + tcg_gen_xori_tl(cc, cpu_PR[PR_CCS], C_FLAG); + tcg_gen_andi_tl(cc, cc, C_FLAG); break; case CC_VS: cris_evaluate_flags(dc); - gen_op_tst_cc_vs (); + tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], V_FLAG); break; case CC_VC: cris_evaluate_flags(dc); - gen_op_tst_cc_vc (); + tcg_gen_xori_tl(cc, cpu_PR[PR_CCS], + V_FLAG); + tcg_gen_andi_tl(cc, cc, V_FLAG); break; case CC_PL: - if (arith_opt) - gen_op_tst_cc_pl_fast (); - else { + if (arith_opt || move_opt) { + int bits = 31; + + if (dc->cc_size == 1) + bits = 7; + else if (dc->cc_size == 2) + bits = 15; + + tcg_gen_shri_tl(cc, cc_result, bits); + tcg_gen_xori_tl(cc, cc, 1); + } else { cris_evaluate_flags(dc); - gen_op_tst_cc_pl (); + tcg_gen_xori_tl(cc, cpu_PR[PR_CCS], + N_FLAG); + tcg_gen_andi_tl(cc, cc, N_FLAG); } break; case CC_MI: - if (arith_opt) - gen_op_tst_cc_mi_fast (); + if (arith_opt || move_opt) { + int bits = 31; + + if (dc->cc_size == 1) + bits = 7; + else if (dc->cc_size == 2) + bits = 15; + + tcg_gen_shri_tl(cc, cc_result, 31); + } else { cris_evaluate_flags(dc); - gen_op_tst_cc_mi (); + tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], + N_FLAG); } break; case CC_LS: cris_evaluate_flags(dc); - gen_op_tst_cc_ls (); + tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], + C_FLAG | Z_FLAG); break; case CC_HI: cris_evaluate_flags(dc); - gen_op_tst_cc_hi (); + { + TCGv tmp; + + tmp = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_xori_tl(tmp, cpu_PR[PR_CCS], + C_FLAG | Z_FLAG); + /* Overlay the C flag on top of the Z. */ + tcg_gen_shli_tl(cc, tmp, 2); + tcg_gen_and_tl(cc, tmp, cc); + tcg_gen_andi_tl(cc, cc, Z_FLAG); + + tcg_temp_free(tmp); + } break; case CC_GE: cris_evaluate_flags(dc); - gen_op_tst_cc_ge (); + /* Overlay the V flag on top of the N. */ + tcg_gen_shli_tl(cc, cpu_PR[PR_CCS], 2); + tcg_gen_xor_tl(cc, + cpu_PR[PR_CCS], cc); + tcg_gen_andi_tl(cc, cc, N_FLAG); + tcg_gen_xori_tl(cc, cc, N_FLAG); break; case CC_LT: cris_evaluate_flags(dc); - gen_op_tst_cc_lt (); + /* Overlay the V flag on top of the N. */ + tcg_gen_shli_tl(cc, cpu_PR[PR_CCS], 2); + tcg_gen_xor_tl(cc, + cpu_PR[PR_CCS], cc); + tcg_gen_andi_tl(cc, cc, N_FLAG); break; case CC_GT: cris_evaluate_flags(dc); - gen_op_tst_cc_gt (); + { + TCGv n, z; + + n = tcg_temp_new(TCG_TYPE_TL); + z = tcg_temp_new(TCG_TYPE_TL); + + /* To avoid a shift we overlay everything on + the V flag. */ + tcg_gen_shri_tl(n, cpu_PR[PR_CCS], 2); + tcg_gen_shri_tl(z, cpu_PR[PR_CCS], 1); + /* invert Z. */ + tcg_gen_xori_tl(z, z, 2); + + tcg_gen_xor_tl(n, n, cpu_PR[PR_CCS]); + tcg_gen_xori_tl(n, n, 2); + tcg_gen_and_tl(cc, z, n); + tcg_gen_andi_tl(cc, cc, 2); + + tcg_temp_free(n); + tcg_temp_free(z); + } break; case CC_LE: cris_evaluate_flags(dc); - gen_op_tst_cc_le (); + { + TCGv n, z; + + n = tcg_temp_new(TCG_TYPE_TL); + z = tcg_temp_new(TCG_TYPE_TL); + + /* To avoid a shift we overlay everything on + the V flag. */ + tcg_gen_shri_tl(n, cpu_PR[PR_CCS], 2); + tcg_gen_shri_tl(z, cpu_PR[PR_CCS], 1); + + tcg_gen_xor_tl(n, n, cpu_PR[PR_CCS]); + tcg_gen_or_tl(cc, z, n); + tcg_gen_andi_tl(cc, cc, 2); + + tcg_temp_free(n); + tcg_temp_free(z); + } break; case CC_P: cris_evaluate_flags(dc); - gen_op_tst_cc_p (); + tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], P_FLAG); break; case CC_A: - cris_evaluate_flags(dc); - gen_op_movl_T0_im (1); + tcg_gen_movi_tl(cc, 1); break; default: BUG(); @@ -624,121 +1174,128 @@ }; } -static void cris_prepare_cc_branch (DisasContext *dc, int offset, int cond) +static void cris_store_direct_jmp(DisasContext *dc) { - /* This helps us re-schedule the micro-code to insns in delay-slots - before the actual jump. */ - dc->delayed_branch = 2; - dc->delayed_pc = dc->pc + offset; - dc->bcc = cond; - if (cond != CC_A) - { - gen_tst_cc (dc, cond); - gen_op_evaluate_bcc (); + /* Store the direct jmp state into the cpu-state. */ + if (dc->jmp == JMP_DIRECT) { + tcg_gen_movi_tl(env_btarget, dc->jmp_pc); + tcg_gen_movi_tl(env_btaken, 1); } - gen_op_movl_T0_im (dc->delayed_pc); - gen_op_movl_btarget_T0 (); } -/* Dynamic jumps, when the dest is in a live reg for example. */ -void cris_prepare_dyn_jmp (DisasContext *dc) +static void cris_prepare_cc_branch (DisasContext *dc, + int offset, int cond) { /* This helps us re-schedule the micro-code to insns in delay-slots before the actual jump. */ dc->delayed_branch = 2; - dc->dyn_jmp = 1; - dc->bcc = CC_A; + dc->jmp_pc = dc->pc + offset; + + if (cond != CC_A) + { + dc->jmp = JMP_INDIRECT; + gen_tst_cc (dc, env_btaken, cond); + tcg_gen_movi_tl(env_btarget, dc->jmp_pc); + } else { + /* Allow chaining. */ + dc->jmp = JMP_DIRECT; + } } -void cris_prepare_jmp (DisasContext *dc, uint32_t dst) + +/* jumps, when the dest is in a live reg for example. Direct should be set + when the dest addr is constant to allow tb chaining. */ +static inline void cris_prepare_jmp (DisasContext *dc, unsigned int type) { /* This helps us re-schedule the micro-code to insns in delay-slots before the actual jump. */ dc->delayed_branch = 2; - dc->delayed_pc = dst; - dc->dyn_jmp = 0; - dc->bcc = CC_A; + dc->jmp = type; + if (type == JMP_INDIRECT) + tcg_gen_movi_tl(env_btaken, 1); } -void gen_load_T0_T0 (DisasContext *dc, unsigned int size, int sign) +static void gen_load(DisasContext *dc, TCGv dst, TCGv addr, + unsigned int size, int sign) { + int mem_index = cpu_mmu_index(dc->env); + + /* If we get a fault on a delayslot we must keep the jmp state in + the cpu-state to be able to re-execute the jmp. */ + if (dc->delayed_branch == 1) + cris_store_direct_jmp(dc); + if (size == 1) { if (sign) - gen_op_ldb_T0_T0(dc); + tcg_gen_qemu_ld8s(dst, addr, mem_index); else - gen_op_ldub_T0_T0(dc); + tcg_gen_qemu_ld8u(dst, addr, mem_index); } else if (size == 2) { if (sign) - gen_op_ldw_T0_T0(dc); + tcg_gen_qemu_ld16s(dst, addr, mem_index); else - gen_op_lduw_T0_T0(dc); + tcg_gen_qemu_ld16u(dst, addr, mem_index); } - else { - gen_op_ldl_T0_T0(dc); + else if (size == 4) { + tcg_gen_qemu_ld32u(dst, addr, mem_index); } -} - -void gen_store_T0_T1 (DisasContext *dc, unsigned int size) -{ - /* Remember, operands are flipped. CRIS has reversed order. */ - if (size == 1) { - gen_op_stb_T0_T1(dc); - } - else if (size == 2) { - gen_op_stw_T0_T1(dc); + else if (size == 8) { + tcg_gen_qemu_ld64(dst, addr, mem_index); } - else - gen_op_stl_T0_T1(dc); } -/* sign extend T1 according to size. */ -static void gen_sext_T1_T0(int size) +static void gen_store (DisasContext *dc, TCGv addr, TCGv val, + unsigned int size) { - if (size == 1) - gen_op_extb_T1_T0(); - else if (size == 2) - gen_op_extw_T1_T0(); -} + int mem_index = cpu_mmu_index(dc->env); -static void gen_sext_T1_T1(int size) -{ - if (size == 1) - gen_op_extb_T1_T1(); - else if (size == 2) - gen_op_extw_T1_T1(); -} + /* If we get a fault on a delayslot we must keep the jmp state in + the cpu-state to be able to re-execute the jmp. */ + if (dc->delayed_branch == 1) + cris_store_direct_jmp(dc); -static void gen_sext_T0_T0(int size) -{ - if (size == 1) - gen_op_extb_T0_T0(); - else if (size == 2) - gen_op_extw_T0_T0(); -} -static void gen_zext_T0_T0(int size) -{ + /* Conditional writes. We only support the kind were X and P are known + at translation time. */ + if (dc->flagx_known && dc->flags_x && (dc->tb_flags & P_FLAG)) { + dc->postinc = 0; + cris_evaluate_flags(dc); + tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], C_FLAG); + return; + } + if (size == 1) - gen_op_zextb_T0_T0(); + tcg_gen_qemu_st8(val, addr, mem_index); else if (size == 2) - gen_op_zextw_T0_T0(); + tcg_gen_qemu_st16(val, addr, mem_index); + else + tcg_gen_qemu_st32(val, addr, mem_index); + + if (dc->flagx_known && dc->flags_x) { + cris_evaluate_flags(dc); + tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~C_FLAG); + } } -static void gen_zext_T1_T0(int size) +static inline void t_gen_sext(TCGv d, TCGv s, int size) { if (size == 1) - gen_op_zextb_T1_T0(); + tcg_gen_ext8s_i32(d, s); else if (size == 2) - gen_op_zextw_T1_T0(); + tcg_gen_ext16s_i32(d, s); + else if(GET_TCGV(d) != GET_TCGV(s)) + tcg_gen_mov_tl(d, s); } -static void gen_zext_T1_T1(int size) +static inline void t_gen_zext(TCGv d, TCGv s, int size) { if (size == 1) - gen_op_zextb_T1_T1(); + tcg_gen_ext8u_i32(d, s); else if (size == 2) - gen_op_zextw_T1_T1(); + tcg_gen_ext16u_i32(d, s); + else if (GET_TCGV(d) != GET_TCGV(s)) + tcg_gen_mov_tl(d, s); } #if DISAS_CRIS @@ -756,12 +1313,12 @@ } #endif -static unsigned int memsize_z(DisasContext *dc) +static inline unsigned int memsize_z(DisasContext *dc) { return dc->zsize + 1; } -static unsigned int memsize_zz(DisasContext *dc) +static inline unsigned int memsize_zz(DisasContext *dc) { switch (dc->zzsize) { @@ -772,46 +1329,37 @@ } } -static void do_postinc (DisasContext *dc, int size) +static inline void do_postinc (DisasContext *dc, int size) { - if (!dc->postinc) - return; - gen_movl_T0_reg[dc->op1](); - gen_op_addl_T0_im(size); - gen_movl_reg_T0[dc->op1](); + if (dc->postinc) + tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], size); } - -static void dec_prep_move_r(DisasContext *dc, int rs, int rd, - int size, int s_ext) +static inline void dec_prep_move_r(DisasContext *dc, int rs, int rd, + int size, int s_ext, TCGv dst) { - gen_movl_T0_reg[rs](); - gen_op_movl_T1_T0(); if (s_ext) - gen_sext_T1_T1(size); + t_gen_sext(dst, cpu_R[rs], size); else - gen_zext_T1_T1(size); + t_gen_zext(dst, cpu_R[rs], size); } /* Prepare T0 and T1 for a register alu operation. s_ext decides if the operand1 should be sign-extended or zero-extended when needed. */ static void dec_prep_alu_r(DisasContext *dc, int rs, int rd, - int size, int s_ext) + int size, int s_ext, TCGv dst, TCGv src) { - dec_prep_move_r(dc, rs, rd, size, s_ext); + dec_prep_move_r(dc, rs, rd, size, s_ext, src); - gen_movl_T0_reg[rd](); if (s_ext) - gen_sext_T0_T0(size); + t_gen_sext(dst, cpu_R[rd], size); else - gen_zext_T0_T0(size); + t_gen_zext(dst, cpu_R[rd], size); } -/* Prepare T0 and T1 for a memory + alu operation. - s_ext decides if the operand1 should be sign-extended or zero-extended when - needed. */ -static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize) +static int dec_prep_move_m(DisasContext *dc, int s_ext, int memsize, + TCGv dst) { unsigned int rs, rd; uint32_t imm; @@ -828,40 +1376,51 @@ if (memsize == 1) insn_len++; - imm = ldl_code(dc->pc + 2); if (memsize != 4) { if (s_ext) { - imm = sign_extend(imm, (memsize * 8) - 1); + if (memsize == 1) + imm = ldsb_code(dc->pc + 2); + else + imm = ldsw_code(dc->pc + 2); } else { if (memsize == 1) - imm &= 0xff; + imm = ldub_code(dc->pc + 2); else - imm &= 0xffff; + imm = lduw_code(dc->pc + 2); } - } - DIS(fprintf (logfile, "imm=%x rd=%d sext=%d ms=%d\n", - imm, rd, s_ext, memsize)); - gen_op_movl_T1_im (imm); + } else + imm = ldl_code(dc->pc + 2); + + tcg_gen_movi_tl(dst, imm); dc->postinc = 0; } else { - gen_movl_T0_reg[rs](); - gen_load_T0_T0(dc, memsize, 0); - gen_op_movl_T1_T0(); + cris_flush_cc_state(dc); + gen_load(dc, dst, cpu_R[rs], memsize, 0); if (s_ext) - gen_sext_T1_T1(memsize); + t_gen_sext(dst, dst, memsize); else - gen_zext_T1_T1(memsize); + t_gen_zext(dst, dst, memsize); } + return insn_len; +} - /* put dest in T0. */ - gen_movl_T0_reg[rd](); +/* Prepare T0 and T1 for a memory + alu operation. + s_ext decides if the operand1 should be sign-extended or zero-extended when + needed. */ +static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize, + TCGv dst, TCGv src) +{ + int insn_len; + + insn_len = dec_prep_move_m(dc, s_ext, memsize, src); + tcg_gen_mov_tl(dst, cpu_R[dc->op2]); return insn_len; } #if DISAS_CRIS static const char *cc_name(int cc) { - static char *cc_names[16] = { + static const char *cc_names[16] = { "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi", "ls", "hi", "ge", "lt", "gt", "le", "a", "p" }; @@ -870,6 +1429,8 @@ } #endif +/* Start of insn decoders. */ + static unsigned int dec_bccq(DisasContext *dc) { int32_t offset; @@ -885,6 +1446,8 @@ tmp = offset; offset = sign_extend(offset, 8); + DIS(fprintf (logfile, "b%s %x\n", cc_name(cond), dc->pc + offset)); + /* op2 holds the condition-code. */ cris_cc_mask(dc, 0); cris_prepare_cc_branch (dc, offset, cond); @@ -892,7 +1455,7 @@ } static unsigned int dec_addoq(DisasContext *dc) { - uint32_t imm; + int32_t imm; dc->op1 = EXTRACT_FIELD(dc->ir, 0, 7); imm = sign_extend(dc->op1, 7); @@ -900,9 +1463,8 @@ DIS(fprintf (logfile, "addoq %d, $r%u\n", imm, dc->op2)); cris_cc_mask(dc, 0); /* Fetch register operand, */ - gen_movl_T0_reg[dc->op2](); - gen_op_movl_T1_im(imm); - crisv32_alu_op(dc, CC_OP_ADD, REG_ACR, 4); + tcg_gen_addi_tl(cpu_R[R_ACR], cpu_R[dc->op2], imm); + return 2; } static unsigned int dec_addq(DisasContext *dc) @@ -912,10 +1474,9 @@ dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); cris_cc_mask(dc, CC_MASK_NZVC); - /* Fetch register operand, */ - gen_movl_T0_reg[dc->op2](); - gen_op_movl_T1_im(dc->op1); - crisv32_alu_op(dc, CC_OP_ADD, dc->op2, 4); + + cris_alu(dc, CC_OP_ADD, + cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(dc->op1), 4); return 2; } static unsigned int dec_moveq(DisasContext *dc) @@ -926,10 +1487,7 @@ imm = sign_extend(dc->op1, 5); DIS(fprintf (logfile, "moveq %d, $r%u\n", imm, dc->op2)); - cris_cc_mask(dc, 0); - gen_op_movl_T1_im(imm); - crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, 4); - + tcg_gen_mov_tl(cpu_R[dc->op2], tcg_const_tl(imm)); return 2; } static unsigned int dec_subq(DisasContext *dc) @@ -939,10 +1497,8 @@ DIS(fprintf (logfile, "subq %u, $r%u\n", dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZVC); - /* Fetch register operand, */ - gen_movl_T0_reg[dc->op2](); - gen_op_movl_T1_im(dc->op1); - crisv32_alu_op(dc, CC_OP_SUB, dc->op2, 4); + cris_alu(dc, CC_OP_SUB, + cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(dc->op1), 4); return 2; } static unsigned int dec_cmpq(DisasContext *dc) @@ -953,9 +1509,9 @@ DIS(fprintf (logfile, "cmpq %d, $r%d\n", imm, dc->op2)); cris_cc_mask(dc, CC_MASK_NZVC); - gen_movl_T0_reg[dc->op2](); - gen_op_movl_T1_im(imm); - crisv32_alu_op(dc, CC_OP_CMP, dc->op2, 4); + + cris_alu(dc, CC_OP_CMP, + cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(imm), 4); return 2; } static unsigned int dec_andq(DisasContext *dc) @@ -966,9 +1522,9 @@ DIS(fprintf (logfile, "andq %d, $r%d\n", imm, dc->op2)); cris_cc_mask(dc, CC_MASK_NZ); - gen_movl_T0_reg[dc->op2](); - gen_op_movl_T1_im(imm); - crisv32_alu_op(dc, CC_OP_AND, dc->op2, 4); + + cris_alu(dc, CC_OP_AND, + cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(imm), 4); return 2; } static unsigned int dec_orq(DisasContext *dc) @@ -978,24 +1534,25 @@ imm = sign_extend(dc->op1, 5); DIS(fprintf (logfile, "orq %d, $r%d\n", imm, dc->op2)); cris_cc_mask(dc, CC_MASK_NZ); - gen_movl_T0_reg[dc->op2](); - gen_op_movl_T1_im(imm); - crisv32_alu_op(dc, CC_OP_OR, dc->op2, 4); + + cris_alu(dc, CC_OP_OR, + cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(imm), 4); return 2; } static unsigned int dec_btstq(DisasContext *dc) { + TCGv l0; dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); DIS(fprintf (logfile, "btstq %u, $r%d\n", dc->op1, dc->op2)); - cris_evaluate_flags(dc); + cris_cc_mask(dc, CC_MASK_NZ); - gen_movl_T0_reg[dc->op2](); - gen_op_movl_T1_im(dc->op1); - crisv32_alu_op(dc, CC_OP_BTST, dc->op2, 4); - - cris_update_cc_op(dc, CC_OP_FLAGS); - gen_op_movl_flags_T0(); - dc->flags_live = 1; + l0 = tcg_temp_local_new(TCG_TYPE_TL); + cris_alu(dc, CC_OP_BTST, + l0, cpu_R[dc->op2], tcg_const_tl(dc->op1), 4); + cris_update_cc_op(dc, CC_OP_FLAGS, 4); + t_gen_mov_preg_TN(dc, PR_CCS, l0); + dc->flags_uptodate = 1; + tcg_temp_free(l0); return 2; } static unsigned int dec_asrq(DisasContext *dc) @@ -1003,9 +1560,11 @@ dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); DIS(fprintf (logfile, "asrq %u, $r%d\n", dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZ); - gen_movl_T0_reg[dc->op2](); - gen_op_movl_T1_im(dc->op1); - crisv32_alu_op(dc, CC_OP_ASR, dc->op2, 4); + + tcg_gen_sari_tl(cpu_R[dc->op2], cpu_R[dc->op2], dc->op1); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], + cpu_R[dc->op2], cpu_R[dc->op2], 4); return 2; } static unsigned int dec_lslq(DisasContext *dc) @@ -1014,9 +1573,12 @@ DIS(fprintf (logfile, "lslq %u, $r%d\n", dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZ); - gen_movl_T0_reg[dc->op2](); - gen_op_movl_T1_im(dc->op1); - crisv32_alu_op(dc, CC_OP_LSL, dc->op2, 4); + + tcg_gen_shli_tl(cpu_R[dc->op2], cpu_R[dc->op2], dc->op1); + + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], + cpu_R[dc->op2], cpu_R[dc->op2], 4); return 2; } static unsigned int dec_lsrq(DisasContext *dc) @@ -1025,9 +1587,11 @@ DIS(fprintf (logfile, "lsrq %u, $r%d\n", dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZ); - gen_movl_T0_reg[dc->op2](); - gen_op_movl_T1_im(dc->op1); - crisv32_alu_op(dc, CC_OP_LSR, dc->op2, 4); + + tcg_gen_shri_tl(cpu_R[dc->op2], cpu_R[dc->op2], dc->op1); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], + cpu_R[dc->op2], cpu_R[dc->op2], 4); return 2; } @@ -1039,8 +1603,23 @@ memsize_char(size), dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZ); - dec_prep_move_r(dc, dc->op1, dc->op2, size, 0); - crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, size); + if (size == 4) { + dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, cpu_R[dc->op2]); + cris_cc_mask(dc, CC_MASK_NZ); + cris_update_cc_op(dc, CC_OP_MOVE, 4); + cris_update_cc_x(dc); + cris_update_result(dc, cpu_R[dc->op2]); + } + else { + TCGv t0; + + t0 = tcg_temp_new(TCG_TYPE_TL); + dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, t0); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], + cpu_R[dc->op2], t0, size); + tcg_temp_free(t0); + } return 2; } @@ -1053,101 +1632,150 @@ if (cond != CC_A) { - gen_tst_cc (dc, cond); - gen_op_movl_T1_T0(); + int l1; + + gen_tst_cc (dc, cpu_R[dc->op1], cond); + l1 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_R[dc->op1], 0, l1); + tcg_gen_movi_tl(cpu_R[dc->op1], 1); + gen_set_label(l1); } else - gen_op_movl_T1_im(1); + tcg_gen_movi_tl(cpu_R[dc->op1], 1); cris_cc_mask(dc, 0); - crisv32_alu_op(dc, CC_OP_MOVE, dc->op1, 4); return 2; } +static inline void cris_alu_alloc_temps(DisasContext *dc, int size, TCGv *t) +{ + if (size == 4) { + t[0] = cpu_R[dc->op2]; + t[1] = cpu_R[dc->op1]; + } else { + t[0] = tcg_temp_new(TCG_TYPE_TL); + t[1] = tcg_temp_new(TCG_TYPE_TL); + } +} + +static inline void cris_alu_free_temps(DisasContext *dc, int size, TCGv *t) +{ + if (size != 4) { + tcg_temp_free(t[0]); + tcg_temp_free(t[1]); + } +} + static unsigned int dec_and_r(DisasContext *dc) { + TCGv t[2]; int size = memsize_zz(dc); DIS(fprintf (logfile, "and.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZ); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); - crisv32_alu_op(dc, CC_OP_AND, dc->op2, size); + + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + cris_alu(dc, CC_OP_AND, cpu_R[dc->op2], t[0], t[1], size); + cris_alu_free_temps(dc, size, t); return 2; } static unsigned int dec_lz_r(DisasContext *dc) { + TCGv t0; DIS(fprintf (logfile, "lz $r%u, $r%u\n", dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZ); - dec_prep_alu_r(dc, dc->op1, dc->op2, 4, 0); - crisv32_alu_op(dc, CC_OP_LZ, dc->op2, 4); + t0 = tcg_temp_new(TCG_TYPE_TL); + dec_prep_alu_r(dc, dc->op1, dc->op2, 4, 0, cpu_R[dc->op2], t0); + cris_alu(dc, CC_OP_LZ, cpu_R[dc->op2], cpu_R[dc->op2], t0, 4); + tcg_temp_free(t0); return 2; } static unsigned int dec_lsl_r(DisasContext *dc) { + TCGv t[2]; int size = memsize_zz(dc); DIS(fprintf (logfile, "lsl.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZ); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); - gen_op_andl_T1_im(63); - crisv32_alu_op(dc, CC_OP_LSL, dc->op2, size); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + tcg_gen_andi_tl(t[1], t[1], 63); + cris_alu(dc, CC_OP_LSL, cpu_R[dc->op2], t[0], t[1], size); + cris_alu_alloc_temps(dc, size, t); return 2; } static unsigned int dec_lsr_r(DisasContext *dc) { + TCGv t[2]; int size = memsize_zz(dc); DIS(fprintf (logfile, "lsr.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZ); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); - gen_op_andl_T1_im(63); - crisv32_alu_op(dc, CC_OP_LSR, dc->op2, size); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + tcg_gen_andi_tl(t[1], t[1], 63); + cris_alu(dc, CC_OP_LSR, cpu_R[dc->op2], t[0], t[1], size); + cris_alu_free_temps(dc, size, t); return 2; } static unsigned int dec_asr_r(DisasContext *dc) { + TCGv t[2]; int size = memsize_zz(dc); DIS(fprintf (logfile, "asr.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZ); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 1); - gen_op_andl_T1_im(63); - crisv32_alu_op(dc, CC_OP_ASR, dc->op2, size); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 1, t[0], t[1]); + tcg_gen_andi_tl(t[1], t[1], 63); + cris_alu(dc, CC_OP_ASR, cpu_R[dc->op2], t[0], t[1], size); + cris_alu_free_temps(dc, size, t); return 2; } static unsigned int dec_muls_r(DisasContext *dc) { + TCGv t[2]; int size = memsize_zz(dc); DIS(fprintf (logfile, "muls.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZV); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 1); - gen_sext_T0_T0(size); - crisv32_alu_op(dc, CC_OP_MULS, dc->op2, 4); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 1, t[0], t[1]); + + cris_alu(dc, CC_OP_MULS, cpu_R[dc->op2], t[0], t[1], 4); + cris_alu_free_temps(dc, size, t); return 2; } static unsigned int dec_mulu_r(DisasContext *dc) { + TCGv t[2]; int size = memsize_zz(dc); DIS(fprintf (logfile, "mulu.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZV); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); - gen_zext_T0_T0(size); - crisv32_alu_op(dc, CC_OP_MULU, dc->op2, 4); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + + cris_alu(dc, CC_OP_MULU, cpu_R[dc->op2], t[0], t[1], 4); + cris_alu_alloc_temps(dc, size, t); return 2; } @@ -1156,69 +1784,87 @@ { DIS(fprintf (logfile, "dstep $r%u, $r%u\n", dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZ); - gen_movl_T0_reg[dc->op1](); - gen_op_movl_T1_T0(); - gen_movl_T0_reg[dc->op2](); - crisv32_alu_op(dc, CC_OP_DSTEP, dc->op2, 4); + cris_alu(dc, CC_OP_DSTEP, + cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op1], 4); return 2; } static unsigned int dec_xor_r(DisasContext *dc) { + TCGv t[2]; int size = memsize_zz(dc); DIS(fprintf (logfile, "xor.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); BUG_ON(size != 4); /* xor is dword. */ cris_cc_mask(dc, CC_MASK_NZ); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); - crisv32_alu_op(dc, CC_OP_XOR, dc->op2, 4); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + + cris_alu(dc, CC_OP_XOR, cpu_R[dc->op2], t[0], t[1], 4); + cris_alu_free_temps(dc, size, t); return 2; } static unsigned int dec_bound_r(DisasContext *dc) { + TCGv l0; int size = memsize_zz(dc); DIS(fprintf (logfile, "bound.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZ); - /* TODO: needs optmimization. */ - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); - /* rd should be 4. */ - gen_movl_T0_reg[dc->op2](); - crisv32_alu_op(dc, CC_OP_BOUND, dc->op2, 4); + l0 = tcg_temp_local_new(TCG_TYPE_TL); + dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, l0); + cris_alu(dc, CC_OP_BOUND, cpu_R[dc->op2], cpu_R[dc->op2], l0, 4); + tcg_temp_free(l0); return 2; } static unsigned int dec_cmp_r(DisasContext *dc) { + TCGv t[2]; int size = memsize_zz(dc); DIS(fprintf (logfile, "cmp.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZVC); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); - crisv32_alu_op(dc, CC_OP_CMP, dc->op2, size); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + + cris_alu(dc, CC_OP_CMP, cpu_R[dc->op2], t[0], t[1], size); + cris_alu_free_temps(dc, size, t); return 2; } static unsigned int dec_abs_r(DisasContext *dc) { + TCGv t0; + DIS(fprintf (logfile, "abs $r%u, $r%u\n", dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZ); - dec_prep_move_r(dc, dc->op1, dc->op2, 4, 0); - gen_op_absl_T1_T1(); - crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, 4); + + t0 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_sari_tl(t0, cpu_R[dc->op1], 31); + tcg_gen_xor_tl(cpu_R[dc->op2], cpu_R[dc->op1], t0); + tcg_gen_sub_tl(cpu_R[dc->op2], cpu_R[dc->op2], t0); + tcg_temp_free(t0); + + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op2], 4); return 2; } static unsigned int dec_add_r(DisasContext *dc) { + TCGv t[2]; int size = memsize_zz(dc); DIS(fprintf (logfile, "add.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZVC); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); - crisv32_alu_op(dc, CC_OP_ADD, dc->op2, size); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + + cris_alu(dc, CC_OP_ADD, cpu_R[dc->op2], t[0], t[1], size); + cris_alu_free_temps(dc, size, t); return 2; } @@ -1228,8 +1874,8 @@ dc->op1, dc->op2)); cris_evaluate_flags(dc); cris_cc_mask(dc, CC_MASK_NZVC); - dec_prep_alu_r(dc, dc->op1, dc->op2, 4, 0); - crisv32_alu_op(dc, CC_OP_ADDC, dc->op2, 4); + cris_alu(dc, CC_OP_ADDC, + cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op1], 4); return 2; } @@ -1239,10 +1885,8 @@ dc->op2, dc->op1)); cris_evaluate_flags(dc); cris_cc_mask(dc, CC_MASK_RNZV); - gen_movl_T0_preg[dc->op2](); - gen_op_movl_T1_T0(); - gen_movl_T0_reg[dc->op1](); - crisv32_alu_op(dc, CC_OP_MCP, dc->op1, 4); + cris_alu(dc, CC_OP_MCP, + cpu_R[dc->op1], cpu_R[dc->op1], cpu_PR[dc->op2], 4); return 2; } @@ -1264,191 +1908,224 @@ static unsigned int dec_swap_r(DisasContext *dc) { - DIS(char modename[4]); + TCGv t0; +#if DISAS_CRIS + char modename[4]; +#endif DIS(fprintf (logfile, "swap%s $r%u\n", swapmode_name(dc->op2, modename), dc->op1)); cris_cc_mask(dc, CC_MASK_NZ); - gen_movl_T0_reg[dc->op1](); + t0 = tcg_temp_new(TCG_TYPE_TL); + t_gen_mov_TN_reg(t0, dc->op1); if (dc->op2 & 8) - gen_op_not_T0_T0(); + tcg_gen_not_tl(t0, t0); if (dc->op2 & 4) - gen_op_swapw_T0_T0(); + t_gen_swapw(t0, t0); if (dc->op2 & 2) - gen_op_swapb_T0_T0(); + t_gen_swapb(t0, t0); if (dc->op2 & 1) - gen_op_swapr_T0_T0(); - gen_op_movl_T1_T0(); - crisv32_alu_op(dc, CC_OP_MOVE, dc->op1, 4); + t_gen_swapr(t0, t0); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op1], cpu_R[dc->op1], t0, 4); + tcg_temp_free(t0); return 2; } static unsigned int dec_or_r(DisasContext *dc) { + TCGv t[2]; int size = memsize_zz(dc); DIS(fprintf (logfile, "or.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZ); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); - crisv32_alu_op(dc, CC_OP_OR, dc->op2, size); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + cris_alu(dc, CC_OP_OR, cpu_R[dc->op2], t[0], t[1], size); + cris_alu_free_temps(dc, size, t); return 2; } static unsigned int dec_addi_r(DisasContext *dc) { + TCGv t0; DIS(fprintf (logfile, "addi.%c $r%u, $r%u\n", memsize_char(memsize_zz(dc)), dc->op2, dc->op1)); cris_cc_mask(dc, 0); - dec_prep_alu_r(dc, dc->op1, dc->op2, 4, 0); - gen_op_lsll_T0_im(dc->zzsize); - gen_op_addl_T0_T1(); - gen_movl_reg_T0[dc->op1](); + t0 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_shl_tl(t0, cpu_R[dc->op2], tcg_const_tl(dc->zzsize)); + tcg_gen_add_tl(cpu_R[dc->op1], cpu_R[dc->op1], t0); + tcg_temp_free(t0); return 2; } static unsigned int dec_addi_acr(DisasContext *dc) { + TCGv t0; DIS(fprintf (logfile, "addi.%c $r%u, $r%u, $acr\n", - memsize_char(memsize_zz(dc)), dc->op2, dc->op1)); + memsize_char(memsize_zz(dc)), dc->op2, dc->op1)); cris_cc_mask(dc, 0); - dec_prep_alu_r(dc, dc->op1, dc->op2, 4, 0); - gen_op_lsll_T0_im(dc->zzsize); - gen_op_addl_T0_T1(); - gen_movl_reg_T0[REG_ACR](); + t0 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_shl_tl(t0, cpu_R[dc->op2], tcg_const_tl(dc->zzsize)); + tcg_gen_add_tl(cpu_R[R_ACR], cpu_R[dc->op1], t0); + tcg_temp_free(t0); return 2; } static unsigned int dec_neg_r(DisasContext *dc) { + TCGv t[2]; int size = memsize_zz(dc); DIS(fprintf (logfile, "neg.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZVC); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); - crisv32_alu_op(dc, CC_OP_NEG, dc->op2, size); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + + cris_alu(dc, CC_OP_NEG, cpu_R[dc->op2], t[0], t[1], size); + cris_alu_free_temps(dc, size, t); return 2; } static unsigned int dec_btst_r(DisasContext *dc) { + TCGv l0; DIS(fprintf (logfile, "btst $r%u, $r%u\n", dc->op1, dc->op2)); - cris_evaluate_flags(dc); cris_cc_mask(dc, CC_MASK_NZ); - dec_prep_alu_r(dc, dc->op1, dc->op2, 4, 0); - crisv32_alu_op(dc, CC_OP_BTST, dc->op2, 4); - cris_update_cc_op(dc, CC_OP_FLAGS); - gen_op_movl_flags_T0(); - dc->flags_live = 1; + l0 = tcg_temp_local_new(TCG_TYPE_TL); + cris_alu(dc, CC_OP_BTST, l0, cpu_R[dc->op2], cpu_R[dc->op1], 4); + cris_update_cc_op(dc, CC_OP_FLAGS, 4); + t_gen_mov_preg_TN(dc, PR_CCS, l0); + dc->flags_uptodate = 1; + tcg_temp_free(l0); return 2; } static unsigned int dec_sub_r(DisasContext *dc) { + TCGv t[2]; int size = memsize_zz(dc); DIS(fprintf (logfile, "sub.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZVC); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); - crisv32_alu_op(dc, CC_OP_SUB, dc->op2, size); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], t[0], t[1], size); + cris_alu_free_temps(dc, size, t); return 2; } /* Zero extension. From size to dword. */ static unsigned int dec_movu_r(DisasContext *dc) { + TCGv t0; int size = memsize_z(dc); DIS(fprintf (logfile, "movu.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZ); - dec_prep_move_r(dc, dc->op1, dc->op2, size, 0); - crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, 4); + t0 = tcg_temp_new(TCG_TYPE_TL); + dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, t0); + cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op2], cpu_R[dc->op2], t0, 4); + tcg_temp_free(t0); return 2; } /* Sign extension. From size to dword. */ static unsigned int dec_movs_r(DisasContext *dc) { + TCGv t0; int size = memsize_z(dc); DIS(fprintf (logfile, "movs.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZ); - gen_movl_T0_reg[dc->op1](); + t0 = tcg_temp_new(TCG_TYPE_TL); /* Size can only be qi or hi. */ - gen_sext_T1_T0(size); - crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, 4); + t_gen_sext(t0, cpu_R[dc->op1], size); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], cpu_R[dc->op1], t0, 4); + tcg_temp_free(t0); return 2; } /* zero extension. From size to dword. */ static unsigned int dec_addu_r(DisasContext *dc) { + TCGv t0; int size = memsize_z(dc); DIS(fprintf (logfile, "addu.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZVC); - gen_movl_T0_reg[dc->op1](); + t0 = tcg_temp_new(TCG_TYPE_TL); /* Size can only be qi or hi. */ - gen_zext_T1_T0(size); - gen_movl_T0_reg[dc->op2](); - crisv32_alu_op(dc, CC_OP_ADD, dc->op2, 4); + t_gen_zext(t0, cpu_R[dc->op1], size); + cris_alu(dc, CC_OP_ADD, + cpu_R[dc->op2], cpu_R[dc->op2], t0, 4); + tcg_temp_free(t0); return 2; } + /* Sign extension. From size to dword. */ static unsigned int dec_adds_r(DisasContext *dc) { + TCGv t0; int size = memsize_z(dc); DIS(fprintf (logfile, "adds.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZVC); - gen_movl_T0_reg[dc->op1](); + t0 = tcg_temp_new(TCG_TYPE_TL); /* Size can only be qi or hi. */ - gen_sext_T1_T0(size); - gen_movl_T0_reg[dc->op2](); - crisv32_alu_op(dc, CC_OP_ADD, dc->op2, 4); + t_gen_sext(t0, cpu_R[dc->op1], size); + cris_alu(dc, CC_OP_ADD, + cpu_R[dc->op2], cpu_R[dc->op2], t0, 4); + tcg_temp_free(t0); return 2; } /* Zero extension. From size to dword. */ static unsigned int dec_subu_r(DisasContext *dc) { + TCGv t0; int size = memsize_z(dc); DIS(fprintf (logfile, "subu.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZVC); - gen_movl_T0_reg[dc->op1](); + t0 = tcg_temp_new(TCG_TYPE_TL); /* Size can only be qi or hi. */ - gen_zext_T1_T0(size); - gen_movl_T0_reg[dc->op2](); - crisv32_alu_op(dc, CC_OP_SUB, dc->op2, 4); + t_gen_zext(t0, cpu_R[dc->op1], size); + cris_alu(dc, CC_OP_SUB, + cpu_R[dc->op2], cpu_R[dc->op2], t0, 4); + tcg_temp_free(t0); return 2; } /* Sign extension. From size to dword. */ static unsigned int dec_subs_r(DisasContext *dc) { + TCGv t0; int size = memsize_z(dc); DIS(fprintf (logfile, "subs.%c $r%u, $r%u\n", memsize_char(size), dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZVC); - gen_movl_T0_reg[dc->op1](); + t0 = tcg_temp_new(TCG_TYPE_TL); /* Size can only be qi or hi. */ - gen_sext_T1_T0(size); - gen_movl_T0_reg[dc->op2](); - crisv32_alu_op(dc, CC_OP_SUB, dc->op2, 4); + t_gen_sext(t0, cpu_R[dc->op1], size); + cris_alu(dc, CC_OP_SUB, + cpu_R[dc->op2], cpu_R[dc->op2], t0, 4); + tcg_temp_free(t0); return 2; } @@ -1457,31 +2134,68 @@ uint32_t flags; int set = (~dc->opcode >> 2) & 1; + flags = (EXTRACT_FIELD(dc->ir, 12, 15) << 4) | EXTRACT_FIELD(dc->ir, 0, 3); - DIS(fprintf (logfile, "set=%d flags=%x\n", set, flags)); - if (set && flags == 0) + if (set && flags == 0) { DIS(fprintf (logfile, "nop\n")); - else if (!set && (flags & 0x20)) + return 2; + } else if (!set && (flags & 0x20)) { DIS(fprintf (logfile, "di\n")); - else + } + else { DIS(fprintf (logfile, "%sf %x\n", - set ? "set" : "clr", + set ? "set" : "clr", flags)); + } - if (set && (flags & X_FLAG)) { - dc->flagx_live = 1; - dc->flags_x = 1; + /* User space is not allowed to touch these. Silently ignore. */ + if (dc->tb_flags & U_FLAG) { + flags &= ~(S_FLAG | I_FLAG | U_FLAG); + } + + if (flags & X_FLAG) { + dc->flagx_known = 1; + if (set) + dc->flags_x = X_FLAG; + else + dc->flags_x = 0; + } + + /* Break the TB if the P flag changes. */ + if (flags & P_FLAG) { + if ((set && !(dc->tb_flags & P_FLAG)) + || (!set && (dc->tb_flags & P_FLAG))) { + tcg_gen_movi_tl(env_pc, dc->pc + 2); + dc->is_jmp = DISAS_UPDATE; + dc->cpustate_changed = 1; + } } + if (flags & S_FLAG) { + dc->cpustate_changed = 1; + } + /* Simply decode the flags. */ cris_evaluate_flags (dc); - cris_update_cc_op(dc, CC_OP_FLAGS); - if (set) - gen_op_setf (flags); + cris_update_cc_op(dc, CC_OP_FLAGS, 4); + cris_update_cc_x(dc); + tcg_gen_movi_tl(cc_op, dc->cc_op); + + if (set) { + if (!(dc->tb_flags & U_FLAG) && (flags & U_FLAG)) { + /* Enter user mode. */ + t_gen_mov_env_TN(ksp, cpu_R[R_SP]); + tcg_gen_mov_tl(cpu_R[R_SP], cpu_PR[PR_USP]); + dc->cpustate_changed = 1; + } + tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], flags); + } else - gen_op_clrf (flags); - dc->flags_live = 1; + tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~flags); + + dc->flags_uptodate = 1; + dc->clear_x = 0; return 2; } @@ -1489,38 +2203,63 @@ { DIS(fprintf (logfile, "move $r%u, $s%u\n", dc->op1, dc->op2)); cris_cc_mask(dc, 0); - gen_movl_T0_reg[dc->op1](); - gen_op_movl_sreg_T0(dc->op2); - - if (dc->op2 == 5) /* srs is checked at runtime. */ - gen_op_movl_tlb_lo_T0(); + tcg_gen_helper_0_2(helper_movl_sreg_reg, + tcg_const_tl(dc->op2), tcg_const_tl(dc->op1)); return 2; } static unsigned int dec_move_sr(DisasContext *dc) { - DIS(fprintf (logfile, "move $s%u, $r%u\n", dc->op1, dc->op2)); + DIS(fprintf (logfile, "move $s%u, $r%u\n", dc->op2, dc->op1)); cris_cc_mask(dc, 0); - gen_op_movl_T0_sreg(dc->op1); - gen_op_movl_T1_T0(); - crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, 4); + tcg_gen_helper_0_2(helper_movl_reg_sreg, + tcg_const_tl(dc->op1), tcg_const_tl(dc->op2)); return 2; } + static unsigned int dec_move_rp(DisasContext *dc) { + TCGv t[2]; DIS(fprintf (logfile, "move $r%u, $p%u\n", dc->op1, dc->op2)); cris_cc_mask(dc, 0); - gen_movl_T0_reg[dc->op1](); - gen_op_movl_T1_T0(); - gen_movl_preg_T0[dc->op2](); + + t[0] = tcg_temp_new(TCG_TYPE_TL); + if (dc->op2 == PR_CCS) { + cris_evaluate_flags(dc); + t_gen_mov_TN_reg(t[0], dc->op1); + if (dc->tb_flags & U_FLAG) { + t[1] = tcg_temp_new(TCG_TYPE_TL); + /* User space is not allowed to touch all flags. */ + tcg_gen_andi_tl(t[0], t[0], 0x39f); + tcg_gen_andi_tl(t[1], cpu_PR[PR_CCS], ~0x39f); + tcg_gen_or_tl(t[0], t[1], t[0]); + tcg_temp_free(t[1]); + } + } + else + t_gen_mov_TN_reg(t[0], dc->op1); + + t_gen_mov_preg_TN(dc, dc->op2, t[0]); + if (dc->op2 == PR_CCS) { + cris_update_cc_op(dc, CC_OP_FLAGS, 4); + dc->flags_uptodate = 1; + } + tcg_temp_free(t[0]); return 2; } static unsigned int dec_move_pr(DisasContext *dc) { + TCGv t0; DIS(fprintf (logfile, "move $p%u, $r%u\n", dc->op1, dc->op2)); cris_cc_mask(dc, 0); - gen_movl_T0_preg[dc->op2](); - gen_op_movl_T1_T0(); - crisv32_alu_op(dc, CC_OP_MOVE, dc->op1, preg_sizes[dc->op2]); + + if (dc->op2 == PR_CCS) + cris_evaluate_flags(dc); + + t0 = tcg_temp_new(TCG_TYPE_TL); + t_gen_mov_TN_preg(t0, dc->op2); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op1], cpu_R[dc->op1], t0, preg_sizes[dc->op2]); + tcg_temp_free(t0); return 2; } @@ -1533,15 +2272,42 @@ dc->op1, dc->postinc ? "+]" : "]", dc->op2)); - cris_cc_mask(dc, CC_MASK_NZ); - insn_len = dec_prep_alu_m(dc, 0, memsize); - crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, memsize); + if (memsize == 4) { + insn_len = dec_prep_move_m(dc, 0, 4, cpu_R[dc->op2]); + cris_cc_mask(dc, CC_MASK_NZ); + cris_update_cc_op(dc, CC_OP_MOVE, 4); + cris_update_cc_x(dc); + cris_update_result(dc, cpu_R[dc->op2]); + } + else { + TCGv t0; + + t0 = tcg_temp_new(TCG_TYPE_TL); + insn_len = dec_prep_move_m(dc, 0, memsize, t0); + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], cpu_R[dc->op2], t0, memsize); + tcg_temp_free(t0); + } do_postinc(dc, memsize); return insn_len; } +static inline void cris_alu_m_alloc_temps(TCGv *t) +{ + t[0] = tcg_temp_new(TCG_TYPE_TL); + t[1] = tcg_temp_new(TCG_TYPE_TL); +} + +static inline void cris_alu_m_free_temps(TCGv *t) +{ + tcg_temp_free(t[0]); + tcg_temp_free(t[1]); +} + static unsigned int dec_movs_m(DisasContext *dc) { + TCGv t[2]; int memsize = memsize_z(dc); int insn_len; DIS(fprintf (logfile, "movs.%c [$r%u%s, $r%u\n", @@ -1549,16 +2315,20 @@ dc->op1, dc->postinc ? "+]" : "]", dc->op2)); + cris_alu_m_alloc_temps(t); /* sign extend. */ + insn_len = dec_prep_alu_m(dc, 1, memsize, t[0], t[1]); cris_cc_mask(dc, CC_MASK_NZ); - insn_len = dec_prep_alu_m(dc, 1, memsize); - crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, 4); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); do_postinc(dc, memsize); + cris_alu_m_free_temps(t); return insn_len; } static unsigned int dec_addu_m(DisasContext *dc) { + TCGv t[2]; int memsize = memsize_z(dc); int insn_len; DIS(fprintf (logfile, "addu.%c [$r%u%s, $r%u\n", @@ -1566,16 +2336,20 @@ dc->op1, dc->postinc ? "+]" : "]", dc->op2)); + cris_alu_m_alloc_temps(t); /* sign extend. */ + insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); cris_cc_mask(dc, CC_MASK_NZVC); - insn_len = dec_prep_alu_m(dc, 0, memsize); - crisv32_alu_op(dc, CC_OP_ADD, dc->op2, 4); + cris_alu(dc, CC_OP_ADD, + cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); do_postinc(dc, memsize); + cris_alu_m_free_temps(t); return insn_len; } static unsigned int dec_adds_m(DisasContext *dc) { + TCGv t[2]; int memsize = memsize_z(dc); int insn_len; DIS(fprintf (logfile, "adds.%c [$r%u%s, $r%u\n", @@ -1583,16 +2357,19 @@ dc->op1, dc->postinc ? "+]" : "]", dc->op2)); + cris_alu_m_alloc_temps(t); /* sign extend. */ + insn_len = dec_prep_alu_m(dc, 1, memsize, t[0], t[1]); cris_cc_mask(dc, CC_MASK_NZVC); - insn_len = dec_prep_alu_m(dc, 1, memsize); - crisv32_alu_op(dc, CC_OP_ADD, dc->op2, 4); + cris_alu(dc, CC_OP_ADD, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); do_postinc(dc, memsize); + cris_alu_m_free_temps(t); return insn_len; } static unsigned int dec_subu_m(DisasContext *dc) { + TCGv t[2]; int memsize = memsize_z(dc); int insn_len; DIS(fprintf (logfile, "subu.%c [$r%u%s, $r%u\n", @@ -1600,16 +2377,19 @@ dc->op1, dc->postinc ? "+]" : "]", dc->op2)); + cris_alu_m_alloc_temps(t); /* sign extend. */ + insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); cris_cc_mask(dc, CC_MASK_NZVC); - insn_len = dec_prep_alu_m(dc, 0, memsize); - crisv32_alu_op(dc, CC_OP_SUB, dc->op2, 4); + cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); do_postinc(dc, memsize); + cris_alu_m_free_temps(t); return insn_len; } static unsigned int dec_subs_m(DisasContext *dc) { + TCGv t[2]; int memsize = memsize_z(dc); int insn_len; DIS(fprintf (logfile, "subs.%c [$r%u%s, $r%u\n", @@ -1617,16 +2397,19 @@ dc->op1, dc->postinc ? "+]" : "]", dc->op2)); + cris_alu_m_alloc_temps(t); /* sign extend. */ + insn_len = dec_prep_alu_m(dc, 1, memsize, t[0], t[1]); cris_cc_mask(dc, CC_MASK_NZVC); - insn_len = dec_prep_alu_m(dc, 1, memsize); - crisv32_alu_op(dc, CC_OP_SUB, dc->op2, 4); + cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); do_postinc(dc, memsize); + cris_alu_m_free_temps(t); return insn_len; } static unsigned int dec_movu_m(DisasContext *dc) { + TCGv t[2]; int memsize = memsize_z(dc); int insn_len; @@ -1635,15 +2418,18 @@ dc->op1, dc->postinc ? "+]" : "]", dc->op2)); + cris_alu_m_alloc_temps(t); + insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); cris_cc_mask(dc, CC_MASK_NZ); - insn_len = dec_prep_alu_m(dc, 0, memsize); - crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, 4); + cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); do_postinc(dc, memsize); + cris_alu_m_free_temps(t); return insn_len; } static unsigned int dec_cmpu_m(DisasContext *dc) { + TCGv t[2]; int memsize = memsize_z(dc); int insn_len; DIS(fprintf (logfile, "cmpu.%c [$r%u%s, $r%u\n", @@ -1651,15 +2437,18 @@ dc->op1, dc->postinc ? "+]" : "]", dc->op2)); + cris_alu_m_alloc_temps(t); + insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); cris_cc_mask(dc, CC_MASK_NZVC); - insn_len = dec_prep_alu_m(dc, 0, memsize); - crisv32_alu_op(dc, CC_OP_CMP, dc->op2, 4); + cris_alu(dc, CC_OP_CMP, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); do_postinc(dc, memsize); + cris_alu_m_free_temps(t); return insn_len; } static unsigned int dec_cmps_m(DisasContext *dc) { + TCGv t[2]; int memsize = memsize_z(dc); int insn_len; DIS(fprintf (logfile, "cmps.%c [$r%u%s, $r%u\n", @@ -1667,15 +2456,20 @@ dc->op1, dc->postinc ? "+]" : "]", dc->op2)); + cris_alu_m_alloc_temps(t); + insn_len = dec_prep_alu_m(dc, 1, memsize, t[0], t[1]); cris_cc_mask(dc, CC_MASK_NZVC); - insn_len = dec_prep_alu_m(dc, 1, memsize); - crisv32_alu_op(dc, CC_OP_CMP, dc->op2, memsize_zz(dc)); + cris_alu(dc, CC_OP_CMP, + cpu_R[dc->op2], cpu_R[dc->op2], t[1], + memsize_zz(dc)); do_postinc(dc, memsize); + cris_alu_m_free_temps(t); return insn_len; } static unsigned int dec_cmp_m(DisasContext *dc) { + TCGv t[2]; int memsize = memsize_zz(dc); int insn_len; DIS(fprintf (logfile, "cmp.%c [$r%u%s, $r%u\n", @@ -1683,15 +2477,20 @@ dc->op1, dc->postinc ? "+]" : "]", dc->op2)); + cris_alu_m_alloc_temps(t); + insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); cris_cc_mask(dc, CC_MASK_NZVC); - insn_len = dec_prep_alu_m(dc, 0, memsize); - crisv32_alu_op(dc, CC_OP_CMP, dc->op2, memsize_zz(dc)); + cris_alu(dc, CC_OP_CMP, + cpu_R[dc->op2], cpu_R[dc->op2], t[1], + memsize_zz(dc)); do_postinc(dc, memsize); + cris_alu_m_free_temps(t); return insn_len; } static unsigned int dec_test_m(DisasContext *dc) { + TCGv t[2]; int memsize = memsize_zz(dc); int insn_len; DIS(fprintf (logfile, "test.%d [$r%u%s] op2=%x\n", @@ -1699,18 +2498,23 @@ dc->op1, dc->postinc ? "+]" : "]", dc->op2)); + cris_evaluate_flags(dc); + + cris_alu_m_alloc_temps(t); + insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); cris_cc_mask(dc, CC_MASK_NZ); - gen_op_clrf(3); - insn_len = dec_prep_alu_m(dc, 0, memsize); - gen_op_swp_T0_T1(); - gen_op_movl_T1_im(0); - crisv32_alu_op(dc, CC_OP_CMP, dc->op2, memsize_zz(dc)); + tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~3); + + cris_alu(dc, CC_OP_CMP, + cpu_R[dc->op2], t[1], tcg_const_tl(0), memsize_zz(dc)); do_postinc(dc, memsize); + cris_alu_m_free_temps(t); return insn_len; } static unsigned int dec_and_m(DisasContext *dc) { + TCGv t[2]; int memsize = memsize_zz(dc); int insn_len; DIS(fprintf (logfile, "and.%d [$r%u%s, $r%u\n", @@ -1718,15 +2522,18 @@ dc->op1, dc->postinc ? "+]" : "]", dc->op2)); + cris_alu_m_alloc_temps(t); + insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); cris_cc_mask(dc, CC_MASK_NZ); - insn_len = dec_prep_alu_m(dc, 0, memsize); - crisv32_alu_op(dc, CC_OP_AND, dc->op2, memsize_zz(dc)); + cris_alu(dc, CC_OP_AND, cpu_R[dc->op2], t[0], t[1], memsize_zz(dc)); do_postinc(dc, memsize); + cris_alu_m_free_temps(t); return insn_len; } static unsigned int dec_add_m(DisasContext *dc) { + TCGv t[2]; int memsize = memsize_zz(dc); int insn_len; DIS(fprintf (logfile, "add.%d [$r%u%s, $r%u\n", @@ -1734,15 +2541,19 @@ dc->op1, dc->postinc ? "+]" : "]", dc->op2)); + cris_alu_m_alloc_temps(t); + insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); cris_cc_mask(dc, CC_MASK_NZVC); - insn_len = dec_prep_alu_m(dc, 0, memsize); - crisv32_alu_op(dc, CC_OP_ADD, dc->op2, memsize_zz(dc)); + cris_alu(dc, CC_OP_ADD, + cpu_R[dc->op2], t[0], t[1], memsize_zz(dc)); do_postinc(dc, memsize); + cris_alu_m_free_temps(t); return insn_len; } static unsigned int dec_addo_m(DisasContext *dc) { + TCGv t[2]; int memsize = memsize_zz(dc); int insn_len; DIS(fprintf (logfile, "add.%d [$r%u%s, $r%u\n", @@ -1750,15 +2561,18 @@ dc->op1, dc->postinc ? "+]" : "]", dc->op2)); + cris_alu_m_alloc_temps(t); + insn_len = dec_prep_alu_m(dc, 1, memsize, t[0], t[1]); cris_cc_mask(dc, 0); - insn_len = dec_prep_alu_m(dc, 1, memsize); - crisv32_alu_op(dc, CC_OP_ADD, REG_ACR, 4); + cris_alu(dc, CC_OP_ADD, cpu_R[R_ACR], t[0], t[1], 4); do_postinc(dc, memsize); + cris_alu_m_free_temps(t); return insn_len; } static unsigned int dec_bound_m(DisasContext *dc) { + TCGv l[2]; int memsize = memsize_zz(dc); int insn_len; DIS(fprintf (logfile, "bound.%d [$r%u%s, $r%u\n", @@ -1766,30 +2580,38 @@ dc->op1, dc->postinc ? "+]" : "]", dc->op2)); + l[0] = tcg_temp_local_new(TCG_TYPE_TL); + l[1] = tcg_temp_local_new(TCG_TYPE_TL); + insn_len = dec_prep_alu_m(dc, 0, memsize, l[0], l[1]); cris_cc_mask(dc, CC_MASK_NZ); - insn_len = dec_prep_alu_m(dc, 0, memsize); - crisv32_alu_op(dc, CC_OP_BOUND, dc->op2, 4); + cris_alu(dc, CC_OP_BOUND, cpu_R[dc->op2], l[0], l[1], 4); do_postinc(dc, memsize); + tcg_temp_free(l[0]); + tcg_temp_free(l[1]); return insn_len; } static unsigned int dec_addc_mr(DisasContext *dc) { + TCGv t[2]; int insn_len = 2; DIS(fprintf (logfile, "addc [$r%u%s, $r%u\n", dc->op1, dc->postinc ? "+]" : "]", dc->op2)); cris_evaluate_flags(dc); + cris_alu_m_alloc_temps(t); + insn_len = dec_prep_alu_m(dc, 0, 4, t[0], t[1]); cris_cc_mask(dc, CC_MASK_NZVC); - insn_len = dec_prep_alu_m(dc, 0, 4); - crisv32_alu_op(dc, CC_OP_ADDC, dc->op2, 4); + cris_alu(dc, CC_OP_ADDC, cpu_R[dc->op2], t[0], t[1], 4); do_postinc(dc, 4); + cris_alu_m_free_temps(t); return insn_len; } static unsigned int dec_sub_m(DisasContext *dc) { + TCGv t[2]; int memsize = memsize_zz(dc); int insn_len; DIS(fprintf (logfile, "sub.%c [$r%u%s, $r%u ir=%x zz=%x\n", @@ -1797,15 +2619,18 @@ dc->op1, dc->postinc ? "+]" : "]", dc->op2, dc->ir, dc->zzsize)); + cris_alu_m_alloc_temps(t); + insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); cris_cc_mask(dc, CC_MASK_NZVC); - insn_len = dec_prep_alu_m(dc, 0, memsize); - crisv32_alu_op(dc, CC_OP_SUB, dc->op2, memsize); + cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], t[0], t[1], memsize); do_postinc(dc, memsize); + cris_alu_m_free_temps(t); return insn_len; } static unsigned int dec_or_m(DisasContext *dc) { + TCGv t[2]; int memsize = memsize_zz(dc); int insn_len; DIS(fprintf (logfile, "or.%d [$r%u%s, $r%u pc=%x\n", @@ -1813,15 +2638,19 @@ dc->op1, dc->postinc ? "+]" : "]", dc->op2, dc->pc)); + cris_alu_m_alloc_temps(t); + insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); cris_cc_mask(dc, CC_MASK_NZ); - insn_len = dec_prep_alu_m(dc, 0, memsize); - crisv32_alu_op(dc, CC_OP_OR, dc->op2, memsize_zz(dc)); + cris_alu(dc, CC_OP_OR, + cpu_R[dc->op2], t[0], t[1], memsize_zz(dc)); do_postinc(dc, memsize); + cris_alu_m_free_temps(t); return insn_len; } static unsigned int dec_move_mp(DisasContext *dc) { + TCGv t[2]; int memsize = memsize_zz(dc); int insn_len = 2; @@ -1831,91 +2660,123 @@ dc->postinc ? "+]" : "]", dc->op2)); + cris_alu_m_alloc_temps(t); + insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); cris_cc_mask(dc, 0); - insn_len = dec_prep_alu_m(dc, 0, memsize); - gen_op_movl_T0_T1(); - gen_movl_preg_T0[dc->op2](); + if (dc->op2 == PR_CCS) { + cris_evaluate_flags(dc); + if (dc->tb_flags & U_FLAG) { + /* User space is not allowed to touch all flags. */ + tcg_gen_andi_tl(t[1], t[1], 0x39f); + tcg_gen_andi_tl(t[0], cpu_PR[PR_CCS], ~0x39f); + tcg_gen_or_tl(t[1], t[0], t[1]); + } + } + + t_gen_mov_preg_TN(dc, dc->op2, t[1]); do_postinc(dc, memsize); + cris_alu_m_free_temps(t); return insn_len; } static unsigned int dec_move_pm(DisasContext *dc) { + TCGv t0; int memsize; memsize = preg_sizes[dc->op2]; - DIS(fprintf (logfile, "move.%d $p%u, [$r%u%s\n", - memsize, dc->op2, dc->op1, dc->postinc ? "+]" : "]")); + DIS(fprintf (logfile, "move.%c $p%u, [$r%u%s\n", + memsize_char(memsize), + dc->op2, dc->op1, dc->postinc ? "+]" : "]")); + + /* prepare store. Address in T0, value in T1. */ + if (dc->op2 == PR_CCS) + cris_evaluate_flags(dc); + t0 = tcg_temp_new(TCG_TYPE_TL); + t_gen_mov_TN_preg(t0, dc->op2); + cris_flush_cc_state(dc); + gen_store(dc, cpu_R[dc->op1], t0, memsize); + tcg_temp_free(t0); cris_cc_mask(dc, 0); - /* prepare store. */ - gen_movl_T0_preg[dc->op2](); - gen_op_movl_T1_T0(); - gen_movl_T0_reg[dc->op1](); - gen_store_T0_T1(dc, memsize); if (dc->postinc) - { - gen_op_addl_T0_im(memsize); - gen_movl_reg_T0[dc->op1](); - } + tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], memsize); return 2; } static unsigned int dec_movem_mr(DisasContext *dc) { + TCGv tmp[16]; + TCGv addr; int i; + int nr = dc->op2 + 1; DIS(fprintf (logfile, "movem [$r%u%s, $r%u\n", dc->op1, dc->postinc ? "+]" : "]", dc->op2)); - cris_cc_mask(dc, 0); - /* fetch the address into T1. */ - gen_movl_T0_reg[dc->op1](); - gen_op_movl_T1_T0(); - for (i = 0; i <= dc->op2; i++) { - /* Perform the load onto regnum i. Always dword wide. */ - gen_load_T0_T0(dc, 4, 0); - gen_movl_reg_T0[i](); - /* Update the address. */ - gen_op_addl_T1_im(4); - gen_op_movl_T0_T1(); - } - if (dc->postinc) { - /* writeback the updated pointer value. */ - gen_movl_reg_T0[dc->op1](); + addr = tcg_temp_new(TCG_TYPE_TL); + /* There are probably better ways of doing this. */ + cris_flush_cc_state(dc); + for (i = 0; i < (nr >> 1); i++) { + tmp[i] = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_addi_tl(addr, cpu_R[dc->op1], i * 8); + gen_load(dc, tmp[i], addr, 8, 0); + } + if (nr & 1) { + tmp[i] = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_addi_tl(addr, cpu_R[dc->op1], i * 8); + gen_load(dc, tmp[i], addr, 4, 0); + } + tcg_temp_free(addr); + + for (i = 0; i < (nr >> 1); i++) { + tcg_gen_trunc_i64_i32(cpu_R[i * 2], tmp[i]); + tcg_gen_shri_i64(tmp[i], tmp[i], 32); + tcg_gen_trunc_i64_i32(cpu_R[i * 2 + 1], tmp[i]); + tcg_temp_free(tmp[i]); + } + if (nr & 1) { + tcg_gen_mov_tl(cpu_R[dc->op2], tmp[i]); + tcg_temp_free(tmp[i]); } + + /* writeback the updated pointer value. */ + if (dc->postinc) + tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], nr * 4); + + /* gen_load might want to evaluate the previous insns flags. */ + cris_cc_mask(dc, 0); return 2; } static unsigned int dec_movem_rm(DisasContext *dc) { + TCGv tmp; + TCGv addr; int i; DIS(fprintf (logfile, "movem $r%u, [$r%u%s\n", dc->op2, dc->op1, dc->postinc ? "+]" : "]")); - cris_cc_mask(dc, 0); - for (i = 0; i <= dc->op2; i++) { - /* Fetch register i into T1. */ - gen_movl_T0_reg[i](); - gen_op_movl_T1_T0(); - - /* Fetch the address into T0. */ - gen_movl_T0_reg[dc->op1](); - /* Displace it. */ - gen_op_addl_T0_im(i * 4); + cris_flush_cc_state(dc); + tmp = tcg_temp_new(TCG_TYPE_TL); + addr = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_movi_tl(tmp, 4); + tcg_gen_mov_tl(addr, cpu_R[dc->op1]); + for (i = 0; i <= dc->op2; i++) { + /* Displace addr. */ /* Perform the store. */ - gen_store_T0_T1(dc, 4); - } - if (dc->postinc) { - /* Update the address. */ - gen_op_addl_T0_im(4); - /* writeback the updated pointer value. */ - gen_movl_reg_T0[dc->op1](); + gen_store(dc, addr, cpu_R[i], 4); + tcg_gen_add_tl(addr, addr, tmp); } + if (dc->postinc) + tcg_gen_mov_tl(cpu_R[dc->op1], addr); + cris_cc_mask(dc, 0); + tcg_temp_free(tmp); + tcg_temp_free(addr); return 2; } @@ -1928,28 +2789,22 @@ DIS(fprintf (logfile, "move.%d $r%u, [$r%u]\n", memsize, dc->op2, dc->op1)); - cris_cc_mask(dc, 0); /* prepare store. */ - gen_movl_T0_reg[dc->op2](); - gen_op_movl_T1_T0(); - gen_movl_T0_reg[dc->op1](); - gen_store_T0_T1(dc, memsize); + cris_flush_cc_state(dc); + gen_store(dc, cpu_R[dc->op1], cpu_R[dc->op2], memsize); + if (dc->postinc) - { - gen_op_addl_T0_im(memsize); - gen_movl_reg_T0[dc->op1](); - } + tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], memsize); + cris_cc_mask(dc, 0); return 2; } - static unsigned int dec_lapcq(DisasContext *dc) { DIS(fprintf (logfile, "lapcq %x, $r%u\n", dc->pc + dc->op1*2, dc->op2)); cris_cc_mask(dc, 0); - gen_op_movl_T1_im(dc->pc + dc->op1*2); - crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, 4); + tcg_gen_movi_tl(cpu_R[dc->op2], dc->pc + dc->op1 * 2); return 2; } @@ -1957,27 +2812,32 @@ { unsigned int rd; int32_t imm; - int insn_len = 6; + int32_t pc; rd = dc->op2; cris_cc_mask(dc, 0); imm = ldl_code(dc->pc + 2); DIS(fprintf (logfile, "lapc 0x%x, $r%u\n", imm + dc->pc, dc->op2)); - gen_op_movl_T0_im (dc->pc + imm); - gen_movl_reg_T0[rd] (); - return insn_len; + + pc = dc->pc; + pc += imm; + t_gen_mov_reg_TN(rd, tcg_const_tl(pc)); + return 6; } /* Jump to special reg. */ static unsigned int dec_jump_p(DisasContext *dc) { DIS(fprintf (logfile, "jump $p%u\n", dc->op2)); + + if (dc->op2 == PR_CCS) + cris_evaluate_flags(dc); + t_gen_mov_TN_preg(env_btarget, dc->op2); + /* rete will often have low bit set to indicate delayslot. */ + tcg_gen_andi_tl(env_btarget, env_btarget, ~1); cris_cc_mask(dc, 0); - /* Store the return address in Pd. */ - gen_movl_T0_preg[dc->op2](); - gen_op_movl_btarget_T0(); - cris_prepare_dyn_jmp(dc); + cris_prepare_jmp(dc, JMP_INDIRECT); return 2; } @@ -1986,12 +2846,13 @@ { DIS(fprintf (logfile, "jas $r%u, $p%u\n", dc->op1, dc->op2)); cris_cc_mask(dc, 0); - /* Stor the return address in Pd. */ - gen_movl_T0_reg[dc->op1](); - gen_op_movl_btarget_T0(); - gen_op_movl_T0_im(dc->pc + 4); - gen_movl_preg_T0[dc->op2](); - cris_prepare_dyn_jmp(dc); + /* Store the return address in Pd. */ + tcg_gen_mov_tl(env_btarget, cpu_R[dc->op1]); + if (dc->op2 > 15) + abort(); + t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 4)); + + cris_prepare_jmp(dc, JMP_INDIRECT); return 2; } @@ -2003,12 +2864,11 @@ DIS(fprintf (logfile, "jas 0x%x\n", imm)); cris_cc_mask(dc, 0); - /* Stor the return address in Pd. */ - gen_op_movl_T0_im(imm); - gen_op_movl_btarget_T0(); - gen_op_movl_T0_im(dc->pc + 8); - gen_movl_preg_T0[dc->op2](); - cris_prepare_dyn_jmp(dc); + /* Store the return address in Pd. */ + t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 8)); + + dc->jmp_pc = imm; + cris_prepare_jmp(dc, JMP_DIRECT); return 6; } @@ -2020,12 +2880,11 @@ DIS(fprintf (logfile, "jasc 0x%x\n", imm)); cris_cc_mask(dc, 0); - /* Stor the return address in Pd. */ - gen_op_movl_T0_im(imm); - gen_op_movl_btarget_T0(); - gen_op_movl_T0_im(dc->pc + 8 + 4); - gen_movl_preg_T0[dc->op2](); - cris_prepare_dyn_jmp(dc); + /* Store the return address in Pd. */ + t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 8 + 4)); + + dc->jmp_pc = imm; + cris_prepare_jmp(dc, JMP_DIRECT); return 6; } @@ -2033,12 +2892,10 @@ { DIS(fprintf (logfile, "jasc_r $r%u, $p%u\n", dc->op1, dc->op2)); cris_cc_mask(dc, 0); - /* Stor the return address in Pd. */ - gen_movl_T0_reg[dc->op1](); - gen_op_movl_btarget_T0(); - gen_op_movl_T0_im(dc->pc + 4 + 4); - gen_movl_preg_T0[dc->op2](); - cris_prepare_dyn_jmp(dc); + /* Store the return address in Pd. */ + tcg_gen_mov_tl(env_btarget, cpu_R[dc->op1]); + t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 4 + 4)); + cris_prepare_jmp(dc, JMP_INDIRECT); return 2; } @@ -2047,8 +2904,7 @@ int32_t offset; uint32_t cond = dc->op2; - offset = ldl_code(dc->pc + 2); - offset = sign_extend(offset, 15); + offset = ldsw_code(dc->pc + 2); DIS(fprintf (logfile, "b%s %d pc=%x dst=%x\n", cc_name(cond), offset, @@ -2069,12 +2925,11 @@ DIS(fprintf (logfile, "bas 0x%x, $p%u\n", dc->pc + simm, dc->op2)); cris_cc_mask(dc, 0); - /* Stor the return address in Pd. */ - gen_op_movl_T0_im(dc->pc + simm); - gen_op_movl_btarget_T0(); - gen_op_movl_T0_im(dc->pc + 8); - gen_movl_preg_T0[dc->op2](); - cris_prepare_dyn_jmp(dc); + /* Store the return address in Pd. */ + t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 8)); + + dc->jmp_pc = dc->pc + simm; + cris_prepare_jmp(dc, JMP_DIRECT); return 6; } @@ -2085,41 +2940,47 @@ DIS(fprintf (logfile, "basc 0x%x, $p%u\n", dc->pc + simm, dc->op2)); cris_cc_mask(dc, 0); - /* Stor the return address in Pd. */ - gen_op_movl_T0_im(dc->pc + simm); - gen_op_movl_btarget_T0(); - gen_op_movl_T0_im(dc->pc + 12); - gen_movl_preg_T0[dc->op2](); - cris_prepare_dyn_jmp(dc); + /* Store the return address in Pd. */ + t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 12)); + + dc->jmp_pc = dc->pc + simm; + cris_prepare_jmp(dc, JMP_DIRECT); return 6; } static unsigned int dec_rfe_etc(DisasContext *dc) { - DIS(fprintf (logfile, "rfe_etc opc=%x pc=0x%x op1=%d op2=%d\n", - dc->opcode, dc->pc, dc->op1, dc->op2)); - cris_cc_mask(dc, 0); if (dc->op2 == 15) /* ignore halt. */ - goto done; + return 2; switch (dc->op2 & 7) { case 2: /* rfe. */ + DIS(fprintf(logfile, "rfe\n")); cris_evaluate_flags(dc); - gen_op_ccs_rshift(); + tcg_gen_helper_0_0(helper_rfe); + dc->is_jmp = DISAS_UPDATE; break; case 5: /* rfn. */ - BUG(); + DIS(fprintf(logfile, "rfn\n")); + cris_evaluate_flags(dc); + tcg_gen_helper_0_0(helper_rfn); + dc->is_jmp = DISAS_UPDATE; break; case 6: + DIS(fprintf(logfile, "break %d\n", dc->op1)); + cris_evaluate_flags (dc); /* break. */ - gen_op_movl_T0_im(dc->pc); - gen_op_movl_pc_T0(); + tcg_gen_movi_tl(env_pc, dc->pc + 2); + /* Breaks start at 16 in the exception vector. */ - gen_op_break_im(dc->op1 + 16); + t_gen_mov_env_TN(trap_vector, + tcg_const_tl(dc->op1 + 16)); + t_gen_raise_exception(EXCP_BREAK); + dc->is_jmp = DISAS_UPDATE; break; default: printf ("op2=%x\n", dc->op2); @@ -2127,7 +2988,16 @@ break; } - done: + return 2; +} + +static unsigned int dec_ftag_fidx_d_m(DisasContext *dc) +{ + return 2; +} + +static unsigned int dec_ftag_fidx_i_m(DisasContext *dc) +{ return 2; } @@ -2140,7 +3010,7 @@ return 2; } -struct decoder_info { +static struct decoder_info { struct { uint32_t bits; uint32_t mask; @@ -2221,8 +3091,8 @@ {DEC_NEG_R, dec_neg_r}, {DEC_MOVE_R, dec_move_r}, - /* ftag_fidx_i_m. */ - /* ftag_fidx_d_m. */ + {DEC_FTAG_FIDX_I_M, dec_ftag_fidx_i_m}, + {DEC_FTAG_FIDX_D_M, dec_ftag_fidx_d_m}, {DEC_MULS_R, dec_muls_r}, {DEC_MULU_R, dec_mulu_r}, @@ -2255,12 +3125,13 @@ cris_decoder(DisasContext *dc) { unsigned int insn_len = 2; - uint32_t tmp; int i; + if (unlikely(loglevel & CPU_LOG_TB_OP)) + tcg_gen_debug_insn_start(dc->pc); + /* Load a halfword onto the instruction register. */ - tmp = ldl_code(dc->pc); - dc->ir = tmp & 0xffff; + dc->ir = lduw_code(dc->pc); /* Now decode it. */ dc->opcode = EXTRACT_FIELD(dc->ir, 4, 11); @@ -2279,6 +3150,22 @@ } } +#if !defined(CONFIG_USER_ONLY) + /* Single-stepping ? */ + if (dc->tb_flags & S_FLAG) { + int l1; + + l1 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_NE, cpu_PR[PR_SPC], dc->pc, l1); + /* We treat SPC as a break with an odd trap vector. */ + cris_evaluate_flags (dc); + t_gen_mov_env_TN(trap_vector, tcg_const_tl(3)); + tcg_gen_movi_tl(env_pc, dc->pc + insn_len); + tcg_gen_movi_tl(cpu_PR[PR_SPC], dc->pc + insn_len); + t_gen_raise_exception(EXCP_BREAK); + gen_set_label(l1); + } +#endif return insn_len; } @@ -2289,9 +3176,8 @@ for(j = 0; j < env->nb_breakpoints; j++) { if (env->breakpoints[j] == dc->pc) { cris_evaluate_flags (dc); - gen_op_movl_T0_im((long)dc->pc); - gen_op_movl_pc_T0(); - gen_op_debug(); + tcg_gen_movi_tl(env_pc, dc->pc); + t_gen_raise_exception(EXCP_DEBUG); dc->is_jmp = DISAS_UPDATE; } } @@ -2299,9 +3185,42 @@ } +/* + * Delay slots on QEMU/CRIS. + * + * If an exception hits on a delayslot, the core will let ERP (the Exception + * Return Pointer) point to the branch (the previous) insn and set the lsb to + * to give SW a hint that the exception actually hit on the dslot. + * + * CRIS expects all PC addresses to be 16-bit aligned. The lsb is ignored by + * the core and any jmp to an odd addresses will mask off that lsb. It is + * simply there to let sw know there was an exception on a dslot. + * + * When the software returns from an exception, the branch will re-execute. + * On QEMU care needs to be taken when a branch+delayslot sequence is broken + * and the branch and delayslot dont share pages. + * + * The TB contaning the branch insn will set up env->btarget and evaluate + * env->btaken. When the translation loop exits we will note that the branch + * sequence is broken and let env->dslot be the size of the branch insn (those + * vary in length). + * + * The TB contaning the delayslot will have the PC of its real insn (i.e no lsb + * set). It will also expect to have env->dslot setup with the size of the + * delay slot so that env->pc - env->dslot point to the branch insn. This TB + * will execute the dslot and take the branch, either to btarget or just one + * insn ahead. + * + * When exceptions occur, we check for env->dslot in do_interrupt to detect + * broken branch sequences and setup $erp accordingly (i.e let it point to the + * branch and set lsb). Then env->dslot gets cleared so that the exception + * handler can enter. When returning from exceptions (jump $erp) the lsb gets + * masked off and we will reexecute the branch insn. + * + */ + /* generate intermediate code for basic block 'tb'. */ -struct DisasContext ctx; -static int +static void gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, int search_pc) { @@ -2309,29 +3228,83 @@ uint32_t pc_start; unsigned int insn_len; int j, lj; + struct DisasContext ctx; struct DisasContext *dc = &ctx; uint32_t next_page_start; - - pc_start = tb->pc; + target_ulong npc; + int num_insns; + int max_insns; + + if (!logfile) + logfile = stderr; + + /* Odd PC indicates that branch is rexecuting due to exception in the + * delayslot, like in real hw. + */ + pc_start = tb->pc & ~1; dc->env = env; dc->tb = tb; - gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; - gen_opparam_ptr = gen_opparam_buf; dc->is_jmp = DISAS_NEXT; + dc->ppc = pc_start; dc->pc = pc_start; dc->singlestep_enabled = env->singlestep_enabled; - dc->flagx_live = 0; - dc->flags_x = 0; + dc->flags_uptodate = 1; + dc->flagx_known = 1; + dc->flags_x = tb->flags & X_FLAG; + dc->cc_x_uptodate = 0; + dc->cc_mask = 0; + dc->update_cc = 0; + + cris_update_cc_op(dc, CC_OP_FLAGS, 4); + dc->cc_size_uptodate = -1; + + /* Decode TB flags. */ + dc->tb_flags = tb->flags & (S_FLAG | P_FLAG | U_FLAG | X_FLAG); + dc->delayed_branch = !!(tb->flags & 7); + if (dc->delayed_branch) + dc->jmp = JMP_INDIRECT; + else + dc->jmp = JMP_NOJMP; + + dc->cpustate_changed = 0; + + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, + "srch=%d pc=%x %x flg=%llx bt=%x ds=%u ccs=%x\n" + "pid=%x usp=%x\n" + "%x.%x.%x.%x\n" + "%x.%x.%x.%x\n" + "%x.%x.%x.%x\n" + "%x.%x.%x.%x\n", + search_pc, dc->pc, dc->ppc, + (unsigned long long)tb->flags, + env->btarget, (unsigned)tb->flags & 7, + env->pregs[PR_CCS], + env->pregs[PR_PID], env->pregs[PR_USP], + env->regs[0], env->regs[1], env->regs[2], env->regs[3], + env->regs[4], env->regs[5], env->regs[6], env->regs[7], + env->regs[8], env->regs[9], + env->regs[10], env->regs[11], + env->regs[12], env->regs[13], + env->regs[14], env->regs[15]); + fprintf(logfile, "--------------\n"); + fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); + } + next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; lj = -1; + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + if (max_insns == 0) + max_insns = CF_COUNT_MASK; + + gen_icount_start(); do { check_breakpoint(env, dc); - if (dc->is_jmp == DISAS_JUMP) - goto done; if (search_pc) { j = gen_opc_ptr - gen_opc_buf; @@ -2340,75 +3313,103 @@ while (lj < j) gen_opc_instr_start[lj++] = 0; } - gen_opc_pc[lj] = dc->pc; + if (dc->delayed_branch == 1) + gen_opc_pc[lj] = dc->ppc | 1; + else + gen_opc_pc[lj] = dc->pc; gen_opc_instr_start[lj] = 1; + gen_opc_icount[lj] = num_insns; } - insn_len = cris_decoder(dc); - STATS(gen_op_exec_insn()); + /* Pretty disas. */ + DIS(fprintf(logfile, "%8.8x:\t", dc->pc)); + + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) + gen_io_start(); + dc->clear_x = 1; + + insn_len = cris_decoder(dc); + dc->ppc = dc->pc; dc->pc += insn_len; - if (!dc->flagx_live - || (dc->flagx_live && - !(dc->cc_op == CC_OP_FLAGS && dc->flags_x))) { - gen_movl_T0_preg[SR_CCS](); - gen_op_andl_T0_im(~X_FLAG); - gen_movl_preg_T0[SR_CCS](); - dc->flagx_live = 1; - dc->flags_x = 0; - } + if (dc->clear_x) + cris_clear_x_flag(dc); + num_insns++; /* Check for delayed branches here. If we do it before - actually genereating any host code, the simulator will just + actually generating any host code, the simulator will just loop doing nothing for on this program location. */ if (dc->delayed_branch) { dc->delayed_branch--; if (dc->delayed_branch == 0) { - if (dc->bcc == CC_A) { - gen_op_jmp (); - dc->is_jmp = DISAS_UPDATE; - } - else { - /* Conditional jmp. */ - gen_op_cc_jmp (dc->delayed_pc, dc->pc); - dc->is_jmp = DISAS_UPDATE; + if (tb->flags & 7) + t_gen_mov_env_TN(dslot, + tcg_const_tl(0)); + if (dc->jmp == JMP_DIRECT) { + dc->is_jmp = DISAS_NEXT; + } else { + t_gen_cc_jmp(env_btarget, + tcg_const_tl(dc->pc)); + dc->is_jmp = DISAS_JUMP; } + break; } } - if (env->singlestep_enabled) - break; - } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end - && dc->pc < next_page_start); - - if (!dc->is_jmp) { - gen_op_movl_T0_im((long)dc->pc); - gen_op_movl_pc_T0(); + /* If we are rexecuting a branch due to exceptions on + delay slots dont break. */ + if (!(tb->pc & 1) && env->singlestep_enabled) + break; + } while (!dc->is_jmp && !dc->cpustate_changed + && gen_opc_ptr < gen_opc_end + && (dc->pc < next_page_start) + && num_insns < max_insns); + + npc = dc->pc; + if (dc->jmp == JMP_DIRECT && !dc->delayed_branch) + npc = dc->jmp_pc; + + if (tb->cflags & CF_LAST_IO) + gen_io_end(); + /* Force an update if the per-tb cpu state has changed. */ + if (dc->is_jmp == DISAS_NEXT + && (dc->cpustate_changed || !dc->flagx_known + || (dc->flags_x != (tb->flags & X_FLAG)))) { + dc->is_jmp = DISAS_UPDATE; + tcg_gen_movi_tl(env_pc, npc); + } + /* Broken branch+delayslot sequence. */ + if (dc->delayed_branch == 1) { + /* Set env->dslot to the size of the branch insn. */ + t_gen_mov_env_TN(dslot, tcg_const_tl(dc->pc - dc->ppc)); + cris_store_direct_jmp(dc); } cris_evaluate_flags (dc); - done: - if (__builtin_expect(env->singlestep_enabled, 0)) { - gen_op_debug(); + + if (unlikely(env->singlestep_enabled)) { + if (dc->is_jmp == DISAS_NEXT) + tcg_gen_movi_tl(env_pc, npc); + t_gen_raise_exception(EXCP_DEBUG); } else { switch(dc->is_jmp) { case DISAS_NEXT: - gen_goto_tb(dc, 1, dc->pc); + gen_goto_tb(dc, 1, npc); break; default: case DISAS_JUMP: case DISAS_UPDATE: /* indicate that the hash table must be used to find the next TB */ - /* T0 is used to index the jmp tables. */ - gen_op_movl_T0_0(); - gen_op_exit_tb(); + tcg_gen_exit_tb(0); break; + case DISAS_SWI: case DISAS_TB_JUMP: /* nothing more to generate */ break; } } + gen_icount_end(tb, num_insns); *gen_opc_ptr = INDEX_op_end; if (search_pc) { j = gen_opc_ptr - gen_opc_buf; @@ -2417,32 +3418,28 @@ gen_opc_instr_start[lj++] = 0; } else { tb->size = dc->pc - pc_start; + tb->icount = num_insns; } #ifdef DEBUG_DISAS +#if !DISAS_CRIS if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "--------------\n"); - fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); - target_disas(logfile, pc_start, dc->pc + 4 - pc_start, 0); - fprintf(logfile, "\n"); - if (loglevel & CPU_LOG_TB_OP) { - fprintf(logfile, "OP:\n"); - dump_ops(gen_opc_buf, gen_opparam_buf); - fprintf(logfile, "\n"); - } + target_disas(logfile, pc_start, dc->pc - pc_start, 0); + fprintf(logfile, "\nisize=%d osize=%zd\n", + dc->pc - pc_start, gen_opc_ptr - gen_opc_buf); } #endif - return 0; +#endif } -int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) +void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) { - return gen_intermediate_code_internal(env, tb, 0); + gen_intermediate_code_internal(env, tb, 0); } -int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) +void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) { - return gen_intermediate_code_internal(env, tb, 1); + gen_intermediate_code_internal(env, tb, 1); } void cpu_dump_state (CPUState *env, FILE *f, @@ -2456,12 +3453,11 @@ return; cpu_fprintf(f, "PC=%x CCS=%x btaken=%d btarget=%x\n" - "cc_op=%d cc_src=%d cc_dest=%d cc_result=%x cc_mask=%x\n" - "debug=%x %x %x\n", - env->pc, env->pregs[SR_CCS], env->btaken, env->btarget, + "cc_op=%d cc_src=%d cc_dest=%d cc_result=%x cc_mask=%x\n", + env->pc, env->pregs[PR_CCS], env->btaken, env->btarget, env->cc_op, - env->cc_src, env->cc_dest, env->cc_result, env->cc_mask, - env->debug1, env->debug2, env->debug3); + env->cc_src, env->cc_dest, env->cc_result, env->cc_mask); + for (i = 0; i < 16; i++) { cpu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); @@ -2474,8 +3470,8 @@ if ((i + 1) % 4 == 0) cpu_fprintf(f, "\n"); } - srs = env->pregs[SR_SRS]; - cpu_fprintf(f, "\nsupport function regs bank %d:\n", srs); + srs = env->pregs[PR_SRS]; + cpu_fprintf(f, "\nsupport function regs bank %x:\n", srs); if (srs < 256) { for (i = 0; i < 16; i++) { cpu_fprintf(f, "s%2.2d=%8.8x ", @@ -2491,12 +3487,78 @@ CPUCRISState *cpu_cris_init (const char *cpu_model) { CPUCRISState *env; + static int tcg_initialized = 0; + int i; env = qemu_mallocz(sizeof(CPUCRISState)); if (!env) return NULL; + cpu_exec_init(env); cpu_reset(env); + + if (tcg_initialized) + return env; + + tcg_initialized = 1; + + cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env"); + cc_x = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, cc_x), "cc_x"); + cc_src = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, cc_src), "cc_src"); + cc_dest = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, cc_dest), + "cc_dest"); + cc_result = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, cc_result), + "cc_result"); + cc_op = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, cc_op), "cc_op"); + cc_size = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, cc_size), + "cc_size"); + cc_mask = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, cc_mask), + "cc_mask"); + + env_pc = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, pc), + "pc"); + env_btarget = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, btarget), + "btarget"); + env_btaken = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, btaken), + "btaken"); + for (i = 0; i < 16; i++) { + cpu_R[i] = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, regs[i]), + regnames[i]); + } + for (i = 0; i < 16; i++) { + cpu_PR[i] = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, pregs[i]), + pregnames[i]); + } + + TCG_HELPER(helper_raise_exception); + TCG_HELPER(helper_dump); + + TCG_HELPER(helper_tlb_flush_pid); + TCG_HELPER(helper_movl_sreg_reg); + TCG_HELPER(helper_movl_reg_sreg); + TCG_HELPER(helper_rfe); + TCG_HELPER(helper_rfn); + + TCG_HELPER(helper_evaluate_flags_muls); + TCG_HELPER(helper_evaluate_flags_mulu); + TCG_HELPER(helper_evaluate_flags_mcp); + TCG_HELPER(helper_evaluate_flags_alu_4); + TCG_HELPER(helper_evaluate_flags_move_4); + TCG_HELPER(helper_evaluate_flags_move_2); + TCG_HELPER(helper_evaluate_flags); + TCG_HELPER(helper_top_evaluate_flags); return env; } @@ -2504,4 +3566,18 @@ { memset(env, 0, offsetof(CPUCRISState, breakpoints)); tlb_flush(env, 1); + + env->pregs[PR_VR] = 32; +#if defined(CONFIG_USER_ONLY) + /* start in user mode with interrupts enabled. */ + env->pregs[PR_CCS] |= U_FLAG | I_FLAG; +#else + env->pregs[PR_CCS] = 0; +#endif +} + +void gen_pc_load(CPUState *env, struct TranslationBlock *tb, + unsigned long searched_pc, int pc_pos, void *puc) +{ + env->pc = gen_opc_pc[pc_pos]; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/cpu.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/cpu.h --- qemu-0.9.1/target-i386/cpu.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-i386/cpu.h 2008-11-05 16:04:33.000000000 +0000 @@ -119,9 +119,9 @@ #define ID_MASK 0x00200000 /* hidden flags - used internally by qemu to represent additional cpu - states. Only the CPL, INHIBIT_IRQ and HALTED are not redundant. We avoid - using the IOPL_MASK, TF_MASK and VM_MASK bit position to ease oring - with eflags. */ + states. Only the CPL, INHIBIT_IRQ, SMM and SVMI are not + redundant. We avoid using the IOPL_MASK, TF_MASK and VM_MASK bit + position to ease oring with eflags. */ /* current cpl */ #define HF_CPL_SHIFT 0 /* true if soft mmu is being used */ @@ -144,10 +144,9 @@ #define HF_CS64_SHIFT 15 /* only used on x86_64: 64 bit code segment */ #define HF_OSFXSR_SHIFT 16 /* CR4.OSFXSR */ #define HF_VM_SHIFT 17 /* must be same as eflags */ -#define HF_HALTED_SHIFT 18 /* CPU halted */ #define HF_SMM_SHIFT 19 /* CPU in SMM mode */ -#define HF_GIF_SHIFT 20 /* if set CPU takes interrupts */ -#define HF_HIF_SHIFT 21 /* shadow copy of IF_MASK when in SVM */ +#define HF_SVME_SHIFT 20 /* SVME enabled (copy of EFER.SVME) */ +#define HF_SVMI_SHIFT 21 /* SVM intercepts are active */ #define HF_CPL_MASK (3 << HF_CPL_SHIFT) #define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT) @@ -160,13 +159,29 @@ #define HF_MP_MASK (1 << HF_MP_SHIFT) #define HF_EM_MASK (1 << HF_EM_SHIFT) #define HF_TS_MASK (1 << HF_TS_SHIFT) +#define HF_IOPL_MASK (3 << HF_IOPL_SHIFT) #define HF_LMA_MASK (1 << HF_LMA_SHIFT) #define HF_CS64_MASK (1 << HF_CS64_SHIFT) #define HF_OSFXSR_MASK (1 << HF_OSFXSR_SHIFT) -#define HF_HALTED_MASK (1 << HF_HALTED_SHIFT) +#define HF_VM_MASK (1 << HF_VM_SHIFT) #define HF_SMM_MASK (1 << HF_SMM_SHIFT) -#define HF_GIF_MASK (1 << HF_GIF_SHIFT) -#define HF_HIF_MASK (1 << HF_HIF_SHIFT) +#define HF_SVME_MASK (1 << HF_SVME_SHIFT) +#define HF_SVMI_MASK (1 << HF_SVMI_SHIFT) + +/* hflags2 */ + +#define HF2_GIF_SHIFT 0 /* if set CPU takes interrupts */ +#define HF2_HIF_SHIFT 1 /* value of IF_MASK when entering SVM */ +#define HF2_NMI_SHIFT 2 /* CPU serving NMI */ +#define HF2_VINTR_SHIFT 3 /* value of V_INTR_MASKING bit */ + +#define HF2_GIF_MASK (1 << HF2_GIF_SHIFT) +#define HF2_HIF_MASK (1 << HF2_HIF_SHIFT) +#define HF2_NMI_MASK (1 << HF2_NMI_SHIFT) +#define HF2_VINTR_MASK (1 << HF2_VINTR_SHIFT) + +#define CR0_PE_SHIFT 0 +#define CR0_MP_SHIFT 1 #define CR0_PE_MASK (1 << 0) #define CR0_MP_MASK (1 << 1) @@ -186,7 +201,8 @@ #define CR4_PAE_MASK (1 << 5) #define CR4_PGE_MASK (1 << 7) #define CR4_PCE_MASK (1 << 8) -#define CR4_OSFXSR_MASK (1 << 9) +#define CR4_OSFXSR_SHIFT 9 +#define CR4_OSFXSR_MASK (1 << CR4_OSFXSR_SHIFT) #define CR4_OSXMMEXCPT_MASK (1 << 10) #define PG_PRESENT_BIT 0 @@ -219,6 +235,7 @@ #define PG_ERROR_RSVD_MASK 0x08 #define PG_ERROR_I_D_MASK 0x10 +#define MSR_IA32_TSC 0x10 #define MSR_IA32_APICBASE 0x1b #define MSR_IA32_APICBASE_BSP (1<<8) #define MSR_IA32_APICBASE_ENABLE (1<<11) @@ -232,6 +249,8 @@ #define MSR_MCG_STATUS 0x17a #define MSR_MCG_CTL 0x17b +#define MSR_IA32_PERF_STATUS 0x198 + #define MSR_PAT 0x277 #define MSR_EFER 0xc0000080 @@ -240,6 +259,7 @@ #define MSR_EFER_LME (1 << 8) #define MSR_EFER_LMA (1 << 10) #define MSR_EFER_NXE (1 << 11) +#define MSR_EFER_SVME (1 << 12) #define MSR_EFER_FFXSR (1 << 14) #define MSR_STAR 0xc0000081 @@ -285,6 +305,7 @@ #define CPUID_PBE (1 << 31) #define CPUID_EXT_SSE3 (1 << 0) +#define CPUID_EXT_DTES64 (1 << 2) #define CPUID_EXT_MONITOR (1 << 3) #define CPUID_EXT_DSCPL (1 << 4) #define CPUID_EXT_VMX (1 << 5) @@ -295,8 +316,15 @@ #define CPUID_EXT_CID (1 << 10) #define CPUID_EXT_CX16 (1 << 13) #define CPUID_EXT_XTPR (1 << 14) -#define CPUID_EXT_DCA (1 << 17) -#define CPUID_EXT_POPCNT (1 << 22) +#define CPUID_EXT_PDCM (1 << 15) +#define CPUID_EXT_DCA (1 << 18) +#define CPUID_EXT_SSE41 (1 << 19) +#define CPUID_EXT_SSE42 (1 << 20) +#define CPUID_EXT_X2APIC (1 << 21) +#define CPUID_EXT_MOVBE (1 << 22) +#define CPUID_EXT_POPCNT (1 << 23) +#define CPUID_EXT_XSAVE (1 << 26) +#define CPUID_EXT_OSXSAVE (1 << 27) #define CPUID_EXT2_SYSCALL (1 << 11) #define CPUID_EXT2_MP (1 << 19) @@ -320,6 +348,18 @@ #define CPUID_EXT3_3DNOWPREFETCH (1 << 8) #define CPUID_EXT3_OSVW (1 << 9) #define CPUID_EXT3_IBS (1 << 10) +#define CPUID_EXT3_SKINIT (1 << 12) + +#define CPUID_VENDOR_INTEL_1 0x756e6547 /* "Genu" */ +#define CPUID_VENDOR_INTEL_2 0x49656e69 /* "ineI" */ +#define CPUID_VENDOR_INTEL_3 0x6c65746e /* "ntel" */ + +#define CPUID_VENDOR_AMD_1 0x68747541 /* "Auth" */ +#define CPUID_VENDOR_AMD_2 0x69746e65 /* "enti" */ +#define CPUID_VENDOR_AMD_3 0x444d4163 /* "cAMD" */ + +#define CPUID_MWAIT_IBE (1 << 1) /* Interrupts can exit capability */ +#define CPUID_MWAIT_EMX (1 << 0) /* enumeration supported */ #define EXCP00_DIVZ 0 #define EXCP01_SSTP 1 @@ -345,7 +385,7 @@ enum { CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ - CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */ + CC_OP_EFLAGS, /* all cc are explicitly computed, CC_SRC = flags */ CC_OP_MULB, /* modify all flags, C, O = (CC_SRC != 0) */ CC_OP_MULW, @@ -428,8 +468,9 @@ typedef union { uint8_t _b[8]; - uint16_t _w[2]; - uint32_t _l[1]; + uint16_t _w[4]; + uint32_t _l[2]; + float32 _s[2]; uint64_t q; } MMXReg; @@ -444,6 +485,7 @@ #define MMX_B(n) _b[7 - (n)] #define MMX_W(n) _w[3 - (n)] #define MMX_L(n) _l[1 - (n)] +#define MMX_S(n) _s[1 - (n)] #else #define XMM_B(n) _b[n] #define XMM_W(n) _w[n] @@ -455,6 +497,7 @@ #define MMX_B(n) _b[n] #define MMX_W(n) _w[n] #define MMX_L(n) _l[n] +#define MMX_S(n) _s[n] #endif #define MMX_Q(n) q @@ -467,11 +510,6 @@ #define NB_MMU_MODES 2 typedef struct CPUX86State { -#if TARGET_LONG_BITS > HOST_LONG_BITS - /* temporaries if we cannot store them in host registers */ - target_ulong t0, t1, t2; -#endif - /* standard registers */ target_ulong regs[CPU_NB_REGS]; target_ulong eip; @@ -484,7 +522,9 @@ target_ulong cc_dst; uint32_t cc_op; int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */ - uint32_t hflags; /* hidden flags, see HF_xxx constants */ + uint32_t hflags; /* TB flags, see HF_xxx constants. These flags + are known at translation time. */ + uint32_t hflags2; /* various other flags, see HF2_xxx constants. */ /* segments */ SegmentCache segs[6]; /* selector values */ @@ -494,7 +534,7 @@ SegmentCache idt; /* only base and limit are used */ target_ulong cr[5]; /* NOTE: cr1 is unused */ - uint32_t a20_mask; + uint64_t a20_mask; /* FPU state */ unsigned int fpstt; /* top of stack index */ @@ -513,34 +553,32 @@ /* emulator internal variables */ float_status fp_status; CPU86_LDouble ft0; - union { - float f; - double d; - int i32; - int64_t i64; - } fp_convert; + float_status mmx_status; /* for 3DNow! float ops */ float_status sse_status; uint32_t mxcsr; XMMReg xmm_regs[CPU_NB_REGS]; XMMReg xmm_t0; MMXReg mmx_t0; + target_ulong cc_tmp; /* temporary for rcr/rcl */ /* sysenter registers */ uint32_t sysenter_cs; - uint32_t sysenter_esp; - uint32_t sysenter_eip; + target_ulong sysenter_esp; + target_ulong sysenter_eip; uint64_t efer; uint64_t star; - target_phys_addr_t vm_hsave; - target_phys_addr_t vm_vmcb; + uint64_t vm_hsave; + uint64_t vm_vmcb; + uint64_t tsc_offset; uint64_t intercept; uint16_t intercept_cr_read; uint16_t intercept_cr_write; uint16_t intercept_dr_read; uint16_t intercept_dr_write; uint32_t intercept_exceptions; + uint8_t v_tpr; #ifdef TARGET_X86_64 target_ulong lstar; @@ -549,18 +587,16 @@ target_ulong kernelgsbase; #endif + uint64_t tsc; + uint64_t pat; /* exception/interrupt handling */ - jmp_buf jmp_env; - int exception_index; int error_code; int exception_is_int; target_ulong exception_next_eip; target_ulong dr[8]; /* debug registers */ uint32_t smbase; - int interrupt_request; - int user_mode_only; /* user mode only simulation */ int old_exception; /* exception in flight */ CPU_COMMON @@ -583,6 +619,10 @@ int kqemu_enabled; int last_io_time; #endif + + /* For KVM */ + uint64_t interrupt_bitmap[256 / 64]; + /* in order to simplify APIC support, we leave this pointer to the user */ struct APICState *apic_state; @@ -696,6 +736,10 @@ /* will be suppressed */ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0); +void cpu_x86_cpuid(CPUX86State *env, uint32_t index, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx); + /* used to debug */ #define X86_DUMP_FPU 0x0001 /* dump FPU state too */ #define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */ @@ -718,6 +762,8 @@ #define cpu_signal_handler cpu_x86_signal_handler #define cpu_list x86_cpu_list +#define CPU_SAVE_VERSION 7 + /* MMU modes definitions */ #define MMU_MODE0_SUFFIX _kernel #define MMU_MODE1_SUFFIX _user @@ -727,6 +773,26 @@ return (env->hflags & HF_CPL_MASK) == 3 ? 1 : 0; } +void optimize_flags_init(void); + +typedef struct CCTable { + int (*compute_all)(void); /* return all the flags */ + int (*compute_c)(void); /* return the C flag */ +} CCTable; + +extern CCTable cc_table[]; + +#if defined(CONFIG_USER_ONLY) +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) +{ + if (newsp) + env->regs[R_ESP] = newsp; + env->regs[R_EAX] = 0; +} +#endif + +#define CPU_PC_FROM_TB(env, tb) env->eip = tb->pc - tb->cs_base + #include "cpu-all.h" #include "svm.h" diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/exec.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/exec.h --- qemu-0.9.1/target-i386/exec.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-i386/exec.h 2008-08-30 10:51:20.000000000 +0100 @@ -29,97 +29,19 @@ #include "cpu-defs.h" -/* at least 4 register variables are defined */ register struct CPUX86State *env asm(AREG0); -#if TARGET_LONG_BITS > HOST_LONG_BITS +#include "qemu-log.h" -/* no registers can be used */ -#define T0 (env->t0) -#define T1 (env->t1) -#define T2 (env->t2) - -#else - -/* XXX: use unsigned long instead of target_ulong - better code will - be generated for 64 bit CPUs */ -register target_ulong T0 asm(AREG1); -register target_ulong T1 asm(AREG2); -register target_ulong T2 asm(AREG3); - -/* if more registers are available, we define some registers too */ -#ifdef AREG4 -register target_ulong EAX asm(AREG4); -#define reg_EAX -#endif - -#ifdef AREG5 -register target_ulong ESP asm(AREG5); -#define reg_ESP -#endif - -#ifdef AREG6 -register target_ulong EBP asm(AREG6); -#define reg_EBP -#endif - -#ifdef AREG7 -register target_ulong ECX asm(AREG7); -#define reg_ECX -#endif - -#ifdef AREG8 -register target_ulong EDX asm(AREG8); -#define reg_EDX -#endif - -#ifdef AREG9 -register target_ulong EBX asm(AREG9); -#define reg_EBX -#endif - -#ifdef AREG10 -register target_ulong ESI asm(AREG10); -#define reg_ESI -#endif - -#ifdef AREG11 -register target_ulong EDI asm(AREG11); -#define reg_EDI -#endif - -#endif /* ! (TARGET_LONG_BITS > HOST_LONG_BITS) */ - -#define A0 T2 - -extern FILE *logfile; -extern int loglevel; - -#ifndef reg_EAX #define EAX (env->regs[R_EAX]) -#endif -#ifndef reg_ECX #define ECX (env->regs[R_ECX]) -#endif -#ifndef reg_EDX #define EDX (env->regs[R_EDX]) -#endif -#ifndef reg_EBX #define EBX (env->regs[R_EBX]) -#endif -#ifndef reg_ESP #define ESP (env->regs[R_ESP]) -#endif -#ifndef reg_EBP #define EBP (env->regs[R_EBP]) -#endif -#ifndef reg_ESI #define ESI (env->regs[R_ESI]) -#endif -#ifndef reg_EDI #define EDI (env->regs[R_EDI]) -#endif -#define EIP (env->eip) +#define EIP (env->eip) #define DF (env->df) #define CC_SRC (env->cc_src) @@ -132,40 +54,13 @@ #define ST(n) (env->fpregs[(env->fpstt + (n)) & 7].d) #define ST1 ST(1) -#ifdef USE_FP_CONVERT -#define FP_CONVERT (env->fp_convert) -#endif - #include "cpu.h" #include "exec-all.h" -typedef struct CCTable { - int (*compute_all)(void); /* return all the flags */ - int (*compute_c)(void); /* return the C flag */ -} CCTable; - -extern CCTable cc_table[]; - -void load_seg(int seg_reg, int selector); -void helper_ljmp_protected_T0_T1(int next_eip); -void helper_lcall_real_T0_T1(int shift, int next_eip); -void helper_lcall_protected_T0_T1(int shift, int next_eip); -void helper_iret_real(int shift); -void helper_iret_protected(int shift, int next_eip); -void helper_lret_protected(int shift, int addend); -void helper_lldt_T0(void); -void helper_ltr_T0(void); -void helper_movl_crN_T0(int reg); -void helper_movl_drN_T0(int reg); -void helper_invlpg(target_ulong addr); -void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0); void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3); void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4); -void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr); int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, int is_write, int mmu_idx, int is_softmmu); -void tlb_fill(target_ulong addr, int is_write, int mmu_idx, - void *retaddr); void __hidden cpu_lock(void); void __hidden cpu_unlock(void); void do_interrupt(int intno, int is_int, int error_code, @@ -181,83 +76,26 @@ void OPPROTO op_movl_eflags_T0(void); void OPPROTO op_movl_T0_eflags(void); -void helper_divl_EAX_T0(void); -void helper_idivl_EAX_T0(void); -void helper_mulq_EAX_T0(void); -void helper_imulq_EAX_T0(void); -void helper_imulq_T0_T1(void); -void helper_divq_EAX_T0(void); -void helper_idivq_EAX_T0(void); -void helper_bswapq_T0(void); -void helper_cmpxchg8b(void); -void helper_single_step(void); -void helper_cpuid(void); -void helper_enter_level(int level, int data32); -void helper_enter64_level(int level, int data64); -void helper_sysenter(void); -void helper_sysexit(void); -void helper_syscall(int next_eip_addend); -void helper_sysret(int dflag); -void helper_rdtsc(void); -void helper_rdpmc(void); -void helper_rdmsr(void); -void helper_wrmsr(void); -void helper_lsl(void); -void helper_lar(void); -void helper_verr(void); -void helper_verw(void); -void helper_rsm(void); - -void check_iob_T0(void); -void check_iow_T0(void); -void check_iol_T0(void); -void check_iob_DX(void); -void check_iow_DX(void); -void check_iol_DX(void); - -#if !defined(CONFIG_USER_ONLY) - -#include "softmmu_exec.h" -static inline double ldfq(target_ulong ptr) +/* n must be a constant to be efficient */ +static inline target_long lshift(target_long x, int n) { - union { - double d; - uint64_t i; - } u; - u.i = ldq(ptr); - return u.d; + if (n >= 0) + return x << n; + else + return x >> (-n); } -static inline void stfq(target_ulong ptr, double v) -{ - union { - double d; - uint64_t i; - } u; - u.d = v; - stq(ptr, u.i); -} +#include "helper.h" -static inline float ldfl(target_ulong ptr) +static inline void svm_check_intercept(uint32_t type) { - union { - float f; - uint32_t i; - } u; - u.i = ldl(ptr); - return u.f; + helper_svm_check_intercept_param(type, 0); } -static inline void stfl(target_ulong ptr, float v) -{ - union { - float f; - uint32_t i; - } u; - u.f = v; - stl(ptr, u.i); -} +#if !defined(CONFIG_USER_ONLY) + +#include "softmmu_exec.h" #endif /* !defined(CONFIG_USER_ONLY) */ @@ -267,26 +105,28 @@ #define floatx_to_int64 floatx80_to_int64 #define floatx_to_int32_round_to_zero floatx80_to_int32_round_to_zero #define floatx_to_int64_round_to_zero floatx80_to_int64_round_to_zero +#define int32_to_floatx int32_to_floatx80 +#define int64_to_floatx int64_to_floatx80 +#define float32_to_floatx float32_to_floatx80 +#define float64_to_floatx float64_to_floatx80 +#define floatx_to_float32 floatx80_to_float32 +#define floatx_to_float64 floatx80_to_float64 #define floatx_abs floatx80_abs #define floatx_chs floatx80_chs #define floatx_round_to_int floatx80_round_to_int #define floatx_compare floatx80_compare #define floatx_compare_quiet floatx80_compare_quiet -#define sin sinl -#define cos cosl -#define sqrt sqrtl -#define pow powl -#define log logl -#define tan tanl -#define atan2 atan2l -#define floor floorl -#define ceil ceill -#define ldexp ldexpl #else #define floatx_to_int32 float64_to_int32 #define floatx_to_int64 float64_to_int64 #define floatx_to_int32_round_to_zero float64_to_int32_round_to_zero #define floatx_to_int64_round_to_zero float64_to_int64_round_to_zero +#define int32_to_floatx int32_to_float64 +#define int64_to_floatx int64_to_float64 +#define float32_to_floatx float32_to_float64 +#define float64_to_floatx(x, e) (x) +#define floatx_to_float32 float64_to_float32 +#define floatx_to_float64(x, e) (x) #define floatx_abs float64_abs #define floatx_chs float64_chs #define floatx_round_to_int float64_round_to_int @@ -294,16 +134,6 @@ #define floatx_compare_quiet float64_compare_quiet #endif -extern CPU86_LDouble sin(CPU86_LDouble x); -extern CPU86_LDouble cos(CPU86_LDouble x); -extern CPU86_LDouble sqrt(CPU86_LDouble x); -extern CPU86_LDouble pow(CPU86_LDouble, CPU86_LDouble); -extern CPU86_LDouble log(CPU86_LDouble x); -extern CPU86_LDouble tan(CPU86_LDouble x); -extern CPU86_LDouble atan2(CPU86_LDouble, CPU86_LDouble); -extern CPU86_LDouble floor(CPU86_LDouble x); -extern CPU86_LDouble ceil(CPU86_LDouble x); - #define RC_MASK 0xc00 #define RC_NEAR 0x000 #define RC_DOWN 0x400 @@ -414,22 +244,6 @@ } #else -/* XXX: same endianness assumed */ - -#ifdef CONFIG_USER_ONLY - -static inline CPU86_LDouble helper_fldt(target_ulong ptr) -{ - return *(CPU86_LDouble *)(unsigned long)ptr; -} - -static inline void helper_fstt(CPU86_LDouble f, target_ulong ptr) -{ - *(CPU86_LDouble *)(unsigned long)ptr = f; -} - -#else - /* we use memory access macros */ static inline CPU86_LDouble helper_fldt(target_ulong ptr) @@ -450,8 +264,6 @@ stw(ptr + 8, temp.l.upper); } -#endif /* !CONFIG_USER_ONLY */ - #endif /* USE_X86LDOUBLE */ #define FPUS_IE (1 << 0) @@ -468,50 +280,9 @@ extern const CPU86_LDouble f15rk[7]; -void helper_fldt_ST0_A0(void); -void helper_fstt_ST0_A0(void); void fpu_raise_exception(void); -CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b); -void helper_fbld_ST0_A0(void); -void helper_fbst_ST0_A0(void); -void helper_f2xm1(void); -void helper_fyl2x(void); -void helper_fptan(void); -void helper_fpatan(void); -void helper_fxtract(void); -void helper_fprem1(void); -void helper_fprem(void); -void helper_fyl2xp1(void); -void helper_fsqrt(void); -void helper_fsincos(void); -void helper_frndint(void); -void helper_fscale(void); -void helper_fsin(void); -void helper_fcos(void); -void helper_fxam_ST0(void); -void helper_fstenv(target_ulong ptr, int data32); -void helper_fldenv(target_ulong ptr, int data32); -void helper_fsave(target_ulong ptr, int data32); -void helper_frstor(target_ulong ptr, int data32); -void helper_fxsave(target_ulong ptr, int data64); -void helper_fxrstor(target_ulong ptr, int data64); void restore_native_fp_state(CPUState *env); void save_native_fp_state(CPUState *env); -float approx_rsqrt(float a); -float approx_rcp(float a); -void update_fp_status(void); -void helper_hlt(void); -void helper_monitor(void); -void helper_mwait(void); -void helper_vmrun(target_ulong addr); -void helper_vmmcall(void); -void helper_vmload(target_ulong addr); -void helper_vmsave(target_ulong addr); -void helper_stgi(void); -void helper_clgi(void); -void helper_skinit(void); -void helper_invlpga(void); -void vmexit(uint64_t exit_code, uint64_t exit_info_1); extern const uint8_t parity_table[256]; extern const uint8_t rclw_table[32]; @@ -528,7 +299,7 @@ CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); DF = 1 - (2 * ((eflags >> 10) & 1)); env->eflags = (env->eflags & ~update_mask) | - (eflags & update_mask); + (eflags & update_mask) | 0x2; } static inline void env_to_regs(void) @@ -589,14 +360,26 @@ static inline int cpu_halted(CPUState *env) { /* handle exit of HALTED state */ - if (!(env->hflags & HF_HALTED_MASK)) + if (!env->halted) return 0; /* disable halt condition */ - if ((env->interrupt_request & CPU_INTERRUPT_HARD) && - (env->eflags & IF_MASK)) { - env->hflags &= ~HF_HALTED_MASK; + if (((env->interrupt_request & CPU_INTERRUPT_HARD) && + (env->eflags & IF_MASK)) || + (env->interrupt_request & CPU_INTERRUPT_NMI)) { + env->halted = 0; return 0; } return EXCP_HALTED; } +/* load efer and update the corresponding hflags. XXX: do consistency + checks with cpuid bits ? */ +static inline void cpu_load_efer(CPUState *env, uint64_t val) +{ + env->efer = val; + env->hflags &= ~(HF_LMA_MASK | HF_SVME_MASK); + if (env->efer & MSR_EFER_LMA) + env->hflags |= HF_LMA_MASK; + if (env->efer & MSR_EFER_SVME) + env->hflags |= HF_SVME_MASK; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/helper2.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/helper2.c --- qemu-0.9.1/target-i386/helper2.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-i386/helper2.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,1167 +0,0 @@ -/* - * i386 helpers (without register variable usage) - * - * Copyright (c) 2003 Fabrice Bellard - * - * 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 -#include -#include -#include -#include -#include -#include - -#include "cpu.h" -#include "exec-all.h" -#include "svm.h" - -//#define DEBUG_MMU - -static int cpu_x86_register (CPUX86State *env, const char *cpu_model); - -static void add_flagname_to_bitmaps(char *flagname, uint32_t *features, - uint32_t *ext_features, - uint32_t *ext2_features, - uint32_t *ext3_features) -{ - int i; - /* feature flags taken from "Intel Processor Identification and the CPUID - * Instruction" and AMD's "CPUID Specification". In cases of disagreement - * about feature names, the Linux name is used. */ - const char *feature_name[] = { - "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", - "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", - "pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */, NULL, "ds" /* Intel dts */, "acpi", "mmx", - "fxsr", "sse", "sse2", "ss", "ht" /* Intel htt */, "tm", "ia64", "pbe", - }; - const char *ext_feature_name[] = { - "pni" /* Intel,AMD sse3 */, NULL, NULL, "monitor", "ds_cpl", "vmx", NULL /* Linux smx */, "est", - "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL, - NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt", - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - }; - const char *ext2_feature_name[] = { - "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", - "cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall", "mttr", "pge", "mca", "cmov", - "pat", "pse36", NULL, NULL /* Linux mp */, "nx" /* Intel xd */, NULL, "mmxext", "mmx", - "fxsr", "fxsr_opt" /* AMD ffxsr */, "pdpe1gb" /* AMD Page1GB */, "rdtscp", NULL, "lm" /* Intel 64 */, "3dnowext", "3dnow", - }; - const char *ext3_feature_name[] = { - "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */, "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse", - "3dnowprefetch", "osvw", NULL /* Linux ibs */, NULL, "skinit", "wdt", NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - }; - - for ( i = 0 ; i < 32 ; i++ ) - if (feature_name[i] && !strcmp (flagname, feature_name[i])) { - *features |= 1 << i; - return; - } - for ( i = 0 ; i < 32 ; i++ ) - if (ext_feature_name[i] && !strcmp (flagname, ext_feature_name[i])) { - *ext_features |= 1 << i; - return; - } - for ( i = 0 ; i < 32 ; i++ ) - if (ext2_feature_name[i] && !strcmp (flagname, ext2_feature_name[i])) { - *ext2_features |= 1 << i; - return; - } - for ( i = 0 ; i < 32 ; i++ ) - if (ext3_feature_name[i] && !strcmp (flagname, ext3_feature_name[i])) { - *ext3_features |= 1 << i; - return; - } - fprintf(stderr, "CPU feature %s not found\n", flagname); -} - -CPUX86State *cpu_x86_init(const char *cpu_model) -{ - CPUX86State *env; - static int inited; - - env = qemu_mallocz(sizeof(CPUX86State)); - if (!env) - return NULL; - cpu_exec_init(env); - env->cpu_model_str = cpu_model; - - /* init various static tables */ - if (!inited) { - inited = 1; - optimize_flags_init(); - } - if (cpu_x86_register(env, cpu_model) < 0) { - cpu_x86_close(env); - return NULL; - } - cpu_reset(env); -#ifdef USE_KQEMU - kqemu_init(env); -#endif - return env; -} - -typedef struct x86_def_t { - const char *name; - uint32_t level; - uint32_t vendor1, vendor2, vendor3; - int family; - int model; - int stepping; - uint32_t features, ext_features, ext2_features, ext3_features; - uint32_t xlevel; -} x86_def_t; - -#define PPRO_FEATURES (CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | \ - CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | \ - CPUID_PAT | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | \ - CPUID_PAE | CPUID_SEP | CPUID_APIC) -static x86_def_t x86_defs[] = { -#ifdef TARGET_X86_64 - { - .name = "qemu64", - .level = 2, - .vendor1 = 0x68747541, /* "Auth" */ - .vendor2 = 0x69746e65, /* "enti" */ - .vendor3 = 0x444d4163, /* "cAMD" */ - .family = 6, - .model = 2, - .stepping = 3, - .features = PPRO_FEATURES | - /* these features are needed for Win64 and aren't fully implemented */ - CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | - /* this feature is needed for Solaris and isn't fully implemented */ - CPUID_PSE36, - .ext_features = CPUID_EXT_SSE3, - .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | - CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, - .ext3_features = CPUID_EXT3_SVM, - .xlevel = 0x8000000A, - }, -#endif - { - .name = "qemu32", - .level = 2, - .family = 6, - .model = 3, - .stepping = 3, - .features = PPRO_FEATURES, - .ext_features = CPUID_EXT_SSE3, - .xlevel = 0, - }, - { - .name = "486", - .level = 0, - .family = 4, - .model = 0, - .stepping = 0, - .features = 0x0000000B, - .xlevel = 0, - }, - { - .name = "pentium", - .level = 1, - .family = 5, - .model = 4, - .stepping = 3, - .features = 0x008001BF, - .xlevel = 0, - }, - { - .name = "pentium2", - .level = 2, - .family = 6, - .model = 5, - .stepping = 2, - .features = 0x0183F9FF, - .xlevel = 0, - }, - { - .name = "pentium3", - .level = 2, - .family = 6, - .model = 7, - .stepping = 3, - .features = 0x0383F9FF, - .xlevel = 0, - }, -}; - -static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model) -{ - unsigned int i; - x86_def_t *def; - - char *s = strdup(cpu_model); - char *featurestr, *name = strtok(s, ","); - uint32_t plus_features = 0, plus_ext_features = 0, plus_ext2_features = 0, plus_ext3_features = 0; - uint32_t minus_features = 0, minus_ext_features = 0, minus_ext2_features = 0, minus_ext3_features = 0; - int family = -1, model = -1, stepping = -1; - - def = NULL; - for (i = 0; i < sizeof(x86_defs) / sizeof(x86_def_t); i++) { - if (strcmp(name, x86_defs[i].name) == 0) { - def = &x86_defs[i]; - break; - } - } - if (!def) - goto error; - memcpy(x86_cpu_def, def, sizeof(*def)); - - featurestr = strtok(NULL, ","); - - while (featurestr) { - char *val; - if (featurestr[0] == '+') { - add_flagname_to_bitmaps(featurestr + 1, &plus_features, &plus_ext_features, &plus_ext2_features, &plus_ext3_features); - } else if (featurestr[0] == '-') { - add_flagname_to_bitmaps(featurestr + 1, &minus_features, &minus_ext_features, &minus_ext2_features, &minus_ext3_features); - } else if ((val = strchr(featurestr, '='))) { - *val = 0; val++; - if (!strcmp(featurestr, "family")) { - char *err; - family = strtol(val, &err, 10); - if (!*val || *err || family < 0) { - fprintf(stderr, "bad numerical value %s\n", val); - x86_cpu_def = 0; - goto error; - } - x86_cpu_def->family = family; - } else if (!strcmp(featurestr, "model")) { - char *err; - model = strtol(val, &err, 10); - if (!*val || *err || model < 0 || model > 0xf) { - fprintf(stderr, "bad numerical value %s\n", val); - x86_cpu_def = 0; - goto error; - } - x86_cpu_def->model = model; - } else if (!strcmp(featurestr, "stepping")) { - char *err; - stepping = strtol(val, &err, 10); - if (!*val || *err || stepping < 0 || stepping > 0xf) { - fprintf(stderr, "bad numerical value %s\n", val); - x86_cpu_def = 0; - goto error; - } - x86_cpu_def->stepping = stepping; - } else { - fprintf(stderr, "unrecognized feature %s\n", featurestr); - x86_cpu_def = 0; - goto error; - } - } else { - fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr); - x86_cpu_def = 0; - goto error; - } - featurestr = strtok(NULL, ","); - } - x86_cpu_def->features |= plus_features; - x86_cpu_def->ext_features |= plus_ext_features; - x86_cpu_def->ext2_features |= plus_ext2_features; - x86_cpu_def->ext3_features |= plus_ext3_features; - x86_cpu_def->features &= ~minus_features; - x86_cpu_def->ext_features &= ~minus_ext_features; - x86_cpu_def->ext2_features &= ~minus_ext2_features; - x86_cpu_def->ext3_features &= ~minus_ext3_features; - free(s); - return 0; - -error: - free(s); - return -1; -} - -void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) -{ - unsigned int i; - - for (i = 0; i < sizeof(x86_defs) / sizeof(x86_def_t); i++) - (*cpu_fprintf)(f, "x86 %16s\n", x86_defs[i].name); -} - -static int cpu_x86_register (CPUX86State *env, const char *cpu_model) -{ - x86_def_t def1, *def = &def1; - - if (cpu_x86_find_by_name(def, cpu_model) < 0) - return -1; - if (def->vendor1) { - env->cpuid_vendor1 = def->vendor1; - env->cpuid_vendor2 = def->vendor2; - env->cpuid_vendor3 = def->vendor3; - } else { - env->cpuid_vendor1 = 0x756e6547; /* "Genu" */ - env->cpuid_vendor2 = 0x49656e69; /* "ineI" */ - env->cpuid_vendor3 = 0x6c65746e; /* "ntel" */ - } - env->cpuid_level = def->level; - env->cpuid_version = (def->family << 8) | (def->model << 4) | def->stepping; - env->cpuid_features = def->features; - env->pat = 0x0007040600070406ULL; - env->cpuid_ext_features = def->ext_features; - env->cpuid_ext2_features = def->ext2_features; - env->cpuid_xlevel = def->xlevel; - env->cpuid_ext3_features = def->ext3_features; - { - const char *model_id = "QEMU Virtual CPU version " QEMU_VERSION; - int c, len, i; - len = strlen(model_id); - for(i = 0; i < 48; i++) { - if (i >= len) - c = '\0'; - else - c = model_id[i]; - env->cpuid_model[i >> 2] |= c << (8 * (i & 3)); - } - } - return 0; -} - -/* NOTE: must be called outside the CPU execute loop */ -void cpu_reset(CPUX86State *env) -{ - int i; - - memset(env, 0, offsetof(CPUX86State, breakpoints)); - - tlb_flush(env, 1); - - env->old_exception = -1; - - /* init to reset state */ - -#ifdef CONFIG_SOFTMMU - env->hflags |= HF_SOFTMMU_MASK; -#endif - env->hflags |= HF_GIF_MASK; - - cpu_x86_update_cr0(env, 0x60000010); - env->a20_mask = 0xffffffff; - env->smbase = 0x30000; - - env->idt.limit = 0xffff; - env->gdt.limit = 0xffff; - env->ldt.limit = 0xffff; - env->ldt.flags = DESC_P_MASK; - env->tr.limit = 0xffff; - env->tr.flags = DESC_P_MASK; - - cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff, 0); - cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffff, 0); - cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffff, 0); - cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffff, 0); - cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffff, 0); - cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff, 0); - - env->eip = 0xfff0; - env->regs[R_EDX] = env->cpuid_version; - - env->eflags = 0x2; - - /* FPU init */ - for(i = 0;i < 8; i++) - env->fptags[i] = 1; - env->fpuc = 0x37f; - - env->mxcsr = 0x1f80; -} - -void cpu_x86_close(CPUX86State *env) -{ - free(env); -} - -/***********************************************************/ -/* x86 debug */ - -static const char *cc_op_str[] = { - "DYNAMIC", - "EFLAGS", - - "MULB", - "MULW", - "MULL", - "MULQ", - - "ADDB", - "ADDW", - "ADDL", - "ADDQ", - - "ADCB", - "ADCW", - "ADCL", - "ADCQ", - - "SUBB", - "SUBW", - "SUBL", - "SUBQ", - - "SBBB", - "SBBW", - "SBBL", - "SBBQ", - - "LOGICB", - "LOGICW", - "LOGICL", - "LOGICQ", - - "INCB", - "INCW", - "INCL", - "INCQ", - - "DECB", - "DECW", - "DECL", - "DECQ", - - "SHLB", - "SHLW", - "SHLL", - "SHLQ", - - "SARB", - "SARW", - "SARL", - "SARQ", -}; - -void cpu_dump_state(CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), - int flags) -{ - int eflags, i, nb; - char cc_op_name[32]; - static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" }; - - eflags = env->eflags; -#ifdef TARGET_X86_64 - if (env->hflags & HF_CS64_MASK) { - cpu_fprintf(f, - "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n" - "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n" - "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n" - "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n" - "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n", - env->regs[R_EAX], - env->regs[R_EBX], - env->regs[R_ECX], - env->regs[R_EDX], - env->regs[R_ESI], - env->regs[R_EDI], - env->regs[R_EBP], - env->regs[R_ESP], - env->regs[8], - env->regs[9], - env->regs[10], - env->regs[11], - env->regs[12], - env->regs[13], - env->regs[14], - env->regs[15], - env->eip, eflags, - eflags & DF_MASK ? 'D' : '-', - eflags & CC_O ? 'O' : '-', - eflags & CC_S ? 'S' : '-', - eflags & CC_Z ? 'Z' : '-', - eflags & CC_A ? 'A' : '-', - eflags & CC_P ? 'P' : '-', - eflags & CC_C ? 'C' : '-', - env->hflags & HF_CPL_MASK, - (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, - (env->a20_mask >> 20) & 1, - (env->hflags >> HF_SMM_SHIFT) & 1, - (env->hflags >> HF_HALTED_SHIFT) & 1); - } else -#endif - { - cpu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" - "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" - "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n", - (uint32_t)env->regs[R_EAX], - (uint32_t)env->regs[R_EBX], - (uint32_t)env->regs[R_ECX], - (uint32_t)env->regs[R_EDX], - (uint32_t)env->regs[R_ESI], - (uint32_t)env->regs[R_EDI], - (uint32_t)env->regs[R_EBP], - (uint32_t)env->regs[R_ESP], - (uint32_t)env->eip, eflags, - eflags & DF_MASK ? 'D' : '-', - eflags & CC_O ? 'O' : '-', - eflags & CC_S ? 'S' : '-', - eflags & CC_Z ? 'Z' : '-', - eflags & CC_A ? 'A' : '-', - eflags & CC_P ? 'P' : '-', - eflags & CC_C ? 'C' : '-', - env->hflags & HF_CPL_MASK, - (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, - (env->a20_mask >> 20) & 1, - (env->hflags >> HF_SMM_SHIFT) & 1, - (env->hflags >> HF_HALTED_SHIFT) & 1); - } - -#ifdef TARGET_X86_64 - if (env->hflags & HF_LMA_MASK) { - for(i = 0; i < 6; i++) { - SegmentCache *sc = &env->segs[i]; - cpu_fprintf(f, "%s =%04x %016" PRIx64 " %08x %08x\n", - seg_name[i], - sc->selector, - sc->base, - sc->limit, - sc->flags); - } - cpu_fprintf(f, "LDT=%04x %016" PRIx64 " %08x %08x\n", - env->ldt.selector, - env->ldt.base, - env->ldt.limit, - env->ldt.flags); - cpu_fprintf(f, "TR =%04x %016" PRIx64 " %08x %08x\n", - env->tr.selector, - env->tr.base, - env->tr.limit, - env->tr.flags); - cpu_fprintf(f, "GDT= %016" PRIx64 " %08x\n", - env->gdt.base, env->gdt.limit); - cpu_fprintf(f, "IDT= %016" PRIx64 " %08x\n", - env->idt.base, env->idt.limit); - cpu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n", - (uint32_t)env->cr[0], - env->cr[2], - env->cr[3], - (uint32_t)env->cr[4]); - } else -#endif - { - for(i = 0; i < 6; i++) { - SegmentCache *sc = &env->segs[i]; - cpu_fprintf(f, "%s =%04x %08x %08x %08x\n", - seg_name[i], - sc->selector, - (uint32_t)sc->base, - sc->limit, - sc->flags); - } - cpu_fprintf(f, "LDT=%04x %08x %08x %08x\n", - env->ldt.selector, - (uint32_t)env->ldt.base, - env->ldt.limit, - env->ldt.flags); - cpu_fprintf(f, "TR =%04x %08x %08x %08x\n", - env->tr.selector, - (uint32_t)env->tr.base, - env->tr.limit, - env->tr.flags); - cpu_fprintf(f, "GDT= %08x %08x\n", - (uint32_t)env->gdt.base, env->gdt.limit); - cpu_fprintf(f, "IDT= %08x %08x\n", - (uint32_t)env->idt.base, env->idt.limit); - cpu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n", - (uint32_t)env->cr[0], - (uint32_t)env->cr[2], - (uint32_t)env->cr[3], - (uint32_t)env->cr[4]); - } - if (flags & X86_DUMP_CCOP) { - if ((unsigned)env->cc_op < CC_OP_NB) - snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]); - else - snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); -#ifdef TARGET_X86_64 - if (env->hflags & HF_CS64_MASK) { - cpu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%-8s\n", - env->cc_src, env->cc_dst, - cc_op_name); - } else -#endif - { - cpu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", - (uint32_t)env->cc_src, (uint32_t)env->cc_dst, - cc_op_name); - } - } - if (flags & X86_DUMP_FPU) { - int fptag; - fptag = 0; - for(i = 0; i < 8; i++) { - fptag |= ((!env->fptags[i]) << i); - } - cpu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n", - env->fpuc, - (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11, - env->fpstt, - fptag, - env->mxcsr); - for(i=0;i<8;i++) { -#if defined(USE_X86LDOUBLE) - union { - long double d; - struct { - uint64_t lower; - uint16_t upper; - } l; - } tmp; - tmp.d = env->fpregs[i].d; - cpu_fprintf(f, "FPR%d=%016" PRIx64 " %04x", - i, tmp.l.lower, tmp.l.upper); -#else - cpu_fprintf(f, "FPR%d=%016" PRIx64, - i, env->fpregs[i].mmx.q); -#endif - if ((i & 1) == 1) - cpu_fprintf(f, "\n"); - else - cpu_fprintf(f, " "); - } - if (env->hflags & HF_CS64_MASK) - nb = 16; - else - nb = 8; - for(i=0;ixmm_regs[i].XMM_L(3), - env->xmm_regs[i].XMM_L(2), - env->xmm_regs[i].XMM_L(1), - env->xmm_regs[i].XMM_L(0)); - if ((i & 1) == 1) - cpu_fprintf(f, "\n"); - else - cpu_fprintf(f, " "); - } - } -} - -/***********************************************************/ -/* x86 mmu */ -/* XXX: add PGE support */ - -void cpu_x86_set_a20(CPUX86State *env, int a20_state) -{ - a20_state = (a20_state != 0); - if (a20_state != ((env->a20_mask >> 20) & 1)) { -#if defined(DEBUG_MMU) - printf("A20 update: a20=%d\n", a20_state); -#endif - /* if the cpu is currently executing code, we must unlink it and - all the potentially executing TB */ - cpu_interrupt(env, CPU_INTERRUPT_EXITTB); - - /* when a20 is changed, all the MMU mappings are invalid, so - we must flush everything */ - tlb_flush(env, 1); - env->a20_mask = 0xffefffff | (a20_state << 20); - } -} - -void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0) -{ - int pe_state; - -#if defined(DEBUG_MMU) - printf("CR0 update: CR0=0x%08x\n", new_cr0); -#endif - if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) != - (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) { - tlb_flush(env, 1); - } - -#ifdef TARGET_X86_64 - if (!(env->cr[0] & CR0_PG_MASK) && (new_cr0 & CR0_PG_MASK) && - (env->efer & MSR_EFER_LME)) { - /* enter in long mode */ - /* XXX: generate an exception */ - if (!(env->cr[4] & CR4_PAE_MASK)) - return; - env->efer |= MSR_EFER_LMA; - env->hflags |= HF_LMA_MASK; - } else if ((env->cr[0] & CR0_PG_MASK) && !(new_cr0 & CR0_PG_MASK) && - (env->efer & MSR_EFER_LMA)) { - /* exit long mode */ - env->efer &= ~MSR_EFER_LMA; - env->hflags &= ~(HF_LMA_MASK | HF_CS64_MASK); - env->eip &= 0xffffffff; - } -#endif - env->cr[0] = new_cr0 | CR0_ET_MASK; - - /* update PE flag in hidden flags */ - pe_state = (env->cr[0] & CR0_PE_MASK); - env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT); - /* ensure that ADDSEG is always set in real mode */ - env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT); - /* update FPU flags */ - env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) | - ((new_cr0 << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)); -} - -/* XXX: in legacy PAE mode, generate a GPF if reserved bits are set in - the PDPT */ -void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3) -{ - env->cr[3] = new_cr3; - if (env->cr[0] & CR0_PG_MASK) { -#if defined(DEBUG_MMU) - printf("CR3 update: CR3=" TARGET_FMT_lx "\n", new_cr3); -#endif - tlb_flush(env, 0); - } -} - -void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4) -{ -#if defined(DEBUG_MMU) - printf("CR4 update: CR4=%08x\n", (uint32_t)env->cr[4]); -#endif - if ((new_cr4 & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK)) != - (env->cr[4] & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK))) { - tlb_flush(env, 1); - } - /* SSE handling */ - if (!(env->cpuid_features & CPUID_SSE)) - new_cr4 &= ~CR4_OSFXSR_MASK; - if (new_cr4 & CR4_OSFXSR_MASK) - env->hflags |= HF_OSFXSR_MASK; - else - env->hflags &= ~HF_OSFXSR_MASK; - - env->cr[4] = new_cr4; -} - -/* XXX: also flush 4MB pages */ -void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr) -{ - tlb_flush_page(env, addr); -} - -#if defined(CONFIG_USER_ONLY) - -int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, - int is_write, int mmu_idx, int is_softmmu) -{ - /* user mode only emulation */ - is_write &= 1; - env->cr[2] = addr; - env->error_code = (is_write << PG_ERROR_W_BIT); - env->error_code |= PG_ERROR_U_MASK; - env->exception_index = EXCP0E_PAGE; - return 1; -} - -target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) -{ - return addr; -} - -#else - -#define PHYS_ADDR_MASK 0xfffff000 - -/* return value: - -1 = cannot handle fault - 0 = nothing more to do - 1 = generate PF fault - 2 = soft MMU activation required for this block -*/ -int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, - int is_write1, int mmu_idx, int is_softmmu) -{ - uint64_t ptep, pte; - uint32_t pdpe_addr, pde_addr, pte_addr; - int error_code, is_dirty, prot, page_size, ret, is_write, is_user; - unsigned long paddr, page_offset; - target_ulong vaddr, virt_addr; - - is_user = mmu_idx == MMU_USER_IDX; -#if defined(DEBUG_MMU) - printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n", - addr, is_write1, is_user, env->eip); -#endif - is_write = is_write1 & 1; - - if (!(env->cr[0] & CR0_PG_MASK)) { - pte = addr; - virt_addr = addr & TARGET_PAGE_MASK; - prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - page_size = 4096; - goto do_mapping; - } - - if (env->cr[4] & CR4_PAE_MASK) { - uint64_t pde, pdpe; - - /* XXX: we only use 32 bit physical addresses */ -#ifdef TARGET_X86_64 - if (env->hflags & HF_LMA_MASK) { - uint32_t pml4e_addr; - uint64_t pml4e; - int32_t sext; - - /* test virtual address sign extension */ - sext = (int64_t)addr >> 47; - if (sext != 0 && sext != -1) { - env->error_code = 0; - env->exception_index = EXCP0D_GPF; - return 1; - } - - pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & - env->a20_mask; - pml4e = ldq_phys(pml4e_addr); - if (!(pml4e & PG_PRESENT_MASK)) { - error_code = 0; - goto do_fault; - } - if (!(env->efer & MSR_EFER_NXE) && (pml4e & PG_NX_MASK)) { - error_code = PG_ERROR_RSVD_MASK; - goto do_fault; - } - if (!(pml4e & PG_ACCESSED_MASK)) { - pml4e |= PG_ACCESSED_MASK; - stl_phys_notdirty(pml4e_addr, pml4e); - } - ptep = pml4e ^ PG_NX_MASK; - pdpe_addr = ((pml4e & PHYS_ADDR_MASK) + (((addr >> 30) & 0x1ff) << 3)) & - env->a20_mask; - pdpe = ldq_phys(pdpe_addr); - if (!(pdpe & PG_PRESENT_MASK)) { - error_code = 0; - goto do_fault; - } - if (!(env->efer & MSR_EFER_NXE) && (pdpe & PG_NX_MASK)) { - error_code = PG_ERROR_RSVD_MASK; - goto do_fault; - } - ptep &= pdpe ^ PG_NX_MASK; - if (!(pdpe & PG_ACCESSED_MASK)) { - pdpe |= PG_ACCESSED_MASK; - stl_phys_notdirty(pdpe_addr, pdpe); - } - } else -#endif - { - /* XXX: load them when cr3 is loaded ? */ - pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & - env->a20_mask; - pdpe = ldq_phys(pdpe_addr); - if (!(pdpe & PG_PRESENT_MASK)) { - error_code = 0; - goto do_fault; - } - ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; - } - - pde_addr = ((pdpe & PHYS_ADDR_MASK) + (((addr >> 21) & 0x1ff) << 3)) & - env->a20_mask; - pde = ldq_phys(pde_addr); - if (!(pde & PG_PRESENT_MASK)) { - error_code = 0; - goto do_fault; - } - if (!(env->efer & MSR_EFER_NXE) && (pde & PG_NX_MASK)) { - error_code = PG_ERROR_RSVD_MASK; - goto do_fault; - } - ptep &= pde ^ PG_NX_MASK; - if (pde & PG_PSE_MASK) { - /* 2 MB page */ - page_size = 2048 * 1024; - ptep ^= PG_NX_MASK; - if ((ptep & PG_NX_MASK) && is_write1 == 2) - goto do_fault_protect; - if (is_user) { - if (!(ptep & PG_USER_MASK)) - goto do_fault_protect; - if (is_write && !(ptep & PG_RW_MASK)) - goto do_fault_protect; - } else { - if ((env->cr[0] & CR0_WP_MASK) && - is_write && !(ptep & PG_RW_MASK)) - goto do_fault_protect; - } - is_dirty = is_write && !(pde & PG_DIRTY_MASK); - if (!(pde & PG_ACCESSED_MASK) || is_dirty) { - pde |= PG_ACCESSED_MASK; - if (is_dirty) - pde |= PG_DIRTY_MASK; - stl_phys_notdirty(pde_addr, pde); - } - /* align to page_size */ - pte = pde & ((PHYS_ADDR_MASK & ~(page_size - 1)) | 0xfff); - virt_addr = addr & ~(page_size - 1); - } else { - /* 4 KB page */ - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - stl_phys_notdirty(pde_addr, pde); - } - pte_addr = ((pde & PHYS_ADDR_MASK) + (((addr >> 12) & 0x1ff) << 3)) & - env->a20_mask; - pte = ldq_phys(pte_addr); - if (!(pte & PG_PRESENT_MASK)) { - error_code = 0; - goto do_fault; - } - if (!(env->efer & MSR_EFER_NXE) && (pte & PG_NX_MASK)) { - error_code = PG_ERROR_RSVD_MASK; - goto do_fault; - } - /* combine pde and pte nx, user and rw protections */ - ptep &= pte ^ PG_NX_MASK; - ptep ^= PG_NX_MASK; - if ((ptep & PG_NX_MASK) && is_write1 == 2) - goto do_fault_protect; - if (is_user) { - if (!(ptep & PG_USER_MASK)) - goto do_fault_protect; - if (is_write && !(ptep & PG_RW_MASK)) - goto do_fault_protect; - } else { - if ((env->cr[0] & CR0_WP_MASK) && - is_write && !(ptep & PG_RW_MASK)) - goto do_fault_protect; - } - is_dirty = is_write && !(pte & PG_DIRTY_MASK); - if (!(pte & PG_ACCESSED_MASK) || is_dirty) { - pte |= PG_ACCESSED_MASK; - if (is_dirty) - pte |= PG_DIRTY_MASK; - stl_phys_notdirty(pte_addr, pte); - } - page_size = 4096; - virt_addr = addr & ~0xfff; - pte = pte & (PHYS_ADDR_MASK | 0xfff); - } - } else { - uint32_t pde; - - /* page directory entry */ - pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & - env->a20_mask; - pde = ldl_phys(pde_addr); - if (!(pde & PG_PRESENT_MASK)) { - error_code = 0; - goto do_fault; - } - /* if PSE bit is set, then we use a 4MB page */ - if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { - page_size = 4096 * 1024; - if (is_user) { - if (!(pde & PG_USER_MASK)) - goto do_fault_protect; - if (is_write && !(pde & PG_RW_MASK)) - goto do_fault_protect; - } else { - if ((env->cr[0] & CR0_WP_MASK) && - is_write && !(pde & PG_RW_MASK)) - goto do_fault_protect; - } - is_dirty = is_write && !(pde & PG_DIRTY_MASK); - if (!(pde & PG_ACCESSED_MASK) || is_dirty) { - pde |= PG_ACCESSED_MASK; - if (is_dirty) - pde |= PG_DIRTY_MASK; - stl_phys_notdirty(pde_addr, pde); - } - - pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */ - ptep = pte; - virt_addr = addr & ~(page_size - 1); - } else { - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - stl_phys_notdirty(pde_addr, pde); - } - - /* page directory entry */ - pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & - env->a20_mask; - pte = ldl_phys(pte_addr); - if (!(pte & PG_PRESENT_MASK)) { - error_code = 0; - goto do_fault; - } - /* combine pde and pte user and rw protections */ - ptep = pte & pde; - if (is_user) { - if (!(ptep & PG_USER_MASK)) - goto do_fault_protect; - if (is_write && !(ptep & PG_RW_MASK)) - goto do_fault_protect; - } else { - if ((env->cr[0] & CR0_WP_MASK) && - is_write && !(ptep & PG_RW_MASK)) - goto do_fault_protect; - } - is_dirty = is_write && !(pte & PG_DIRTY_MASK); - if (!(pte & PG_ACCESSED_MASK) || is_dirty) { - pte |= PG_ACCESSED_MASK; - if (is_dirty) - pte |= PG_DIRTY_MASK; - stl_phys_notdirty(pte_addr, pte); - } - page_size = 4096; - virt_addr = addr & ~0xfff; - } - } - /* the page can be put in the TLB */ - prot = PAGE_READ; - if (!(ptep & PG_NX_MASK)) - prot |= PAGE_EXEC; - if (pte & PG_DIRTY_MASK) { - /* only set write access if already dirty... otherwise wait - for dirty access */ - if (is_user) { - if (ptep & PG_RW_MASK) - prot |= PAGE_WRITE; - } else { - if (!(env->cr[0] & CR0_WP_MASK) || - (ptep & PG_RW_MASK)) - prot |= PAGE_WRITE; - } - } - do_mapping: - pte = pte & env->a20_mask; - - /* Even if 4MB pages, we map only one 4KB page in the cache to - avoid filling it too fast */ - page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); - paddr = (pte & TARGET_PAGE_MASK) + page_offset; - vaddr = virt_addr + page_offset; - - ret = tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu); - return ret; - do_fault_protect: - error_code = PG_ERROR_P_MASK; - do_fault: - error_code |= (is_write << PG_ERROR_W_BIT); - if (is_user) - error_code |= PG_ERROR_U_MASK; - if (is_write1 == 2 && - (env->efer & MSR_EFER_NXE) && - (env->cr[4] & CR4_PAE_MASK)) - error_code |= PG_ERROR_I_D_MASK; - if (INTERCEPTEDl(_exceptions, 1 << EXCP0E_PAGE)) { - stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), addr); - } else { - env->cr[2] = addr; - } - env->error_code = error_code; - env->exception_index = EXCP0E_PAGE; - /* the VMM will handle this */ - if (INTERCEPTEDl(_exceptions, 1 << EXCP0E_PAGE)) - return 2; - return 1; -} - -target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) -{ - uint32_t pde_addr, pte_addr; - uint32_t pde, pte, paddr, page_offset, page_size; - - if (env->cr[4] & CR4_PAE_MASK) { - uint32_t pdpe_addr, pde_addr, pte_addr; - uint32_t pdpe; - - /* XXX: we only use 32 bit physical addresses */ -#ifdef TARGET_X86_64 - if (env->hflags & HF_LMA_MASK) { - uint32_t pml4e_addr, pml4e; - int32_t sext; - - /* test virtual address sign extension */ - sext = (int64_t)addr >> 47; - if (sext != 0 && sext != -1) - return -1; - - pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & - env->a20_mask; - pml4e = ldl_phys(pml4e_addr); - if (!(pml4e & PG_PRESENT_MASK)) - return -1; - - pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) & - env->a20_mask; - pdpe = ldl_phys(pdpe_addr); - if (!(pdpe & PG_PRESENT_MASK)) - return -1; - } else -#endif - { - pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & - env->a20_mask; - pdpe = ldl_phys(pdpe_addr); - if (!(pdpe & PG_PRESENT_MASK)) - return -1; - } - - pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) & - env->a20_mask; - pde = ldl_phys(pde_addr); - if (!(pde & PG_PRESENT_MASK)) { - return -1; - } - if (pde & PG_PSE_MASK) { - /* 2 MB page */ - page_size = 2048 * 1024; - pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */ - } else { - /* 4 KB page */ - pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) & - env->a20_mask; - page_size = 4096; - pte = ldl_phys(pte_addr); - } - } else { - if (!(env->cr[0] & CR0_PG_MASK)) { - pte = addr; - page_size = 4096; - } else { - /* page directory entry */ - pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & env->a20_mask; - pde = ldl_phys(pde_addr); - if (!(pde & PG_PRESENT_MASK)) - return -1; - if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { - pte = pde & ~0x003ff000; /* align to 4MB */ - page_size = 4096 * 1024; - } else { - /* page directory entry */ - pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask; - pte = ldl_phys(pte_addr); - if (!(pte & PG_PRESENT_MASK)) - return -1; - page_size = 4096; - } - } - pte = pte & env->a20_mask; - } - - page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); - paddr = (pte & TARGET_PAGE_MASK) + page_offset; - return paddr; -} -#endif /* !CONFIG_USER_ONLY */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/helper.c --- qemu-0.9.1/target-i386/helper.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-i386/helper.c 2008-11-10 01:05:01.000000000 +0000 @@ -1,5 +1,5 @@ /* - * i386 helpers + * i386 helpers (without register variable usage) * * Copyright (c) 2003 Fabrice Bellard * @@ -17,4428 +17,1517 @@ * 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 "exec.h" -#include "host-utils.h" - -//#define DEBUG_PCALL - -#if 0 -#define raise_exception_err(a, b)\ -do {\ - if (logfile)\ - fprintf(logfile, "raise_exception line=%d\n", __LINE__);\ - (raise_exception_err)(a, b);\ -} while (0) -#endif +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "svm.h" +#include "qemu-common.h" +#include "kvm.h" + +//#define DEBUG_MMU + +static int cpu_x86_register (CPUX86State *env, const char *cpu_model); + +static void add_flagname_to_bitmaps(char *flagname, uint32_t *features, + uint32_t *ext_features, + uint32_t *ext2_features, + uint32_t *ext3_features) +{ + int i; + /* feature flags taken from "Intel Processor Identification and the CPUID + * Instruction" and AMD's "CPUID Specification". In cases of disagreement + * about feature names, the Linux name is used. */ + static const char *feature_name[] = { + "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", + "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", + "pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */, NULL, "ds" /* Intel dts */, "acpi", "mmx", + "fxsr", "sse", "sse2", "ss", "ht" /* Intel htt */, "tm", "ia64", "pbe", + }; + static const char *ext_feature_name[] = { + "pni" /* Intel,AMD sse3 */, NULL, NULL, "monitor", "ds_cpl", "vmx", NULL /* Linux smx */, "est", + "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL, + NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + }; + static const char *ext2_feature_name[] = { + "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", + "cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall", "mttr", "pge", "mca", "cmov", + "pat", "pse36", NULL, NULL /* Linux mp */, "nx" /* Intel xd */, NULL, "mmxext", "mmx", + "fxsr", "fxsr_opt" /* AMD ffxsr */, "pdpe1gb" /* AMD Page1GB */, "rdtscp", NULL, "lm" /* Intel 64 */, "3dnowext", "3dnow", + }; + static const char *ext3_feature_name[] = { + "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */, "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse", + "3dnowprefetch", "osvw", NULL /* Linux ibs */, NULL, "skinit", "wdt", NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + }; + + for ( i = 0 ; i < 32 ; i++ ) + if (feature_name[i] && !strcmp (flagname, feature_name[i])) { + *features |= 1 << i; + return; + } + for ( i = 0 ; i < 32 ; i++ ) + if (ext_feature_name[i] && !strcmp (flagname, ext_feature_name[i])) { + *ext_features |= 1 << i; + return; + } + for ( i = 0 ; i < 32 ; i++ ) + if (ext2_feature_name[i] && !strcmp (flagname, ext2_feature_name[i])) { + *ext2_features |= 1 << i; + return; + } + for ( i = 0 ; i < 32 ; i++ ) + if (ext3_feature_name[i] && !strcmp (flagname, ext3_feature_name[i])) { + *ext3_features |= 1 << i; + return; + } + fprintf(stderr, "CPU feature %s not found\n", flagname); +} -const uint8_t parity_table[256] = { - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, -}; +CPUX86State *cpu_x86_init(const char *cpu_model) +{ + CPUX86State *env; + static int inited; -/* modulo 17 table */ -const uint8_t rclw_table[32] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9,10,11,12,13,14,15, - 16, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9,10,11,12,13,14, -}; + env = qemu_mallocz(sizeof(CPUX86State)); + if (!env) + return NULL; + cpu_exec_init(env); + env->cpu_model_str = cpu_model; -/* modulo 9 table */ -const uint8_t rclb_table[32] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 0, 1, 2, 3, 4, 5, - 6, 7, 8, 0, 1, 2, 3, 4, + /* init various static tables */ + if (!inited) { + inited = 1; + optimize_flags_init(); + } + if (cpu_x86_register(env, cpu_model) < 0) { + cpu_x86_close(env); + return NULL; + } + cpu_reset(env); +#ifdef USE_KQEMU + kqemu_init(env); +#endif + if (kvm_enabled()) + kvm_init_vcpu(env); + return env; +} + +typedef struct x86_def_t { + const char *name; + uint32_t level; + uint32_t vendor1, vendor2, vendor3; + int family; + int model; + int stepping; + uint32_t features, ext_features, ext2_features, ext3_features; + uint32_t xlevel; + char model_id[48]; +} x86_def_t; + +#define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE) +#define PENTIUM_FEATURES (I486_FEATURES | CPUID_DE | CPUID_TSC | \ + CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_MMX) +#define PENTIUM2_FEATURES (PENTIUM_FEATURES | CPUID_PAE | CPUID_SEP | \ + CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | CPUID_PAT | \ + CPUID_PSE36 | CPUID_FXSR) +#define PENTIUM3_FEATURES (PENTIUM2_FEATURES | CPUID_SSE) +#define PPRO_FEATURES (CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | \ + CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | \ + CPUID_PAT | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | \ + CPUID_PAE | CPUID_SEP | CPUID_APIC) +static x86_def_t x86_defs[] = { +#ifdef TARGET_X86_64 + { + .name = "qemu64", + .level = 2, + .vendor1 = CPUID_VENDOR_AMD_1, + .vendor2 = CPUID_VENDOR_AMD_2, + .vendor3 = CPUID_VENDOR_AMD_3, + .family = 6, + .model = 2, + .stepping = 3, + .features = PPRO_FEATURES | + /* these features are needed for Win64 and aren't fully implemented */ + CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | + /* this feature is needed for Solaris and isn't fully implemented */ + CPUID_PSE36, + .ext_features = CPUID_EXT_SSE3, + .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | + CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | + CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT, + .ext3_features = CPUID_EXT3_SVM, + .xlevel = 0x8000000A, + .model_id = "QEMU Virtual CPU version " QEMU_VERSION, + }, + { + .name = "core2duo", + .level = 10, + .family = 6, + .model = 15, + .stepping = 11, + /* The original CPU also implements these features: + CPUID_VME, CPUID_DTS, CPUID_ACPI, CPUID_SS, CPUID_HT, + CPUID_TM, CPUID_PBE */ + .features = PPRO_FEATURES | + CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | + CPUID_PSE36, + /* The original CPU also implements these ext features: + CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_VMX, CPUID_EXT_EST, + CPUID_EXT_TM2, CPUID_EXT_CX16, CPUID_EXT_XTPR, CPUID_EXT_PDCM */ + .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3, + .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, + /* Missing: .ext3_features = CPUID_EXT3_LAHF_LM */ + .xlevel = 0x80000008, + .model_id = "Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz", + }, +#endif + { + .name = "qemu32", + .level = 2, + .family = 6, + .model = 3, + .stepping = 3, + .features = PPRO_FEATURES, + .ext_features = CPUID_EXT_SSE3, + .xlevel = 0, + .model_id = "QEMU Virtual CPU version " QEMU_VERSION, + }, + { + .name = "coreduo", + .level = 10, + .family = 6, + .model = 14, + .stepping = 8, + /* The original CPU also implements these features: + CPUID_DTS, CPUID_ACPI, CPUID_SS, CPUID_HT, + CPUID_TM, CPUID_PBE */ + .features = PPRO_FEATURES | CPUID_VME | + CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA, + /* The original CPU also implements these ext features: + CPUID_EXT_VMX, CPUID_EXT_EST, CPUID_EXT_TM2, CPUID_EXT_XTPR, + CPUID_EXT_PDCM */ + .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR, + .ext2_features = CPUID_EXT2_NX, + .xlevel = 0x80000008, + .model_id = "Genuine Intel(R) CPU T2600 @ 2.16GHz", + }, + { + .name = "486", + .level = 0, + .family = 4, + .model = 0, + .stepping = 0, + .features = I486_FEATURES, + .xlevel = 0, + }, + { + .name = "pentium", + .level = 1, + .family = 5, + .model = 4, + .stepping = 3, + .features = PENTIUM_FEATURES, + .xlevel = 0, + }, + { + .name = "pentium2", + .level = 2, + .family = 6, + .model = 5, + .stepping = 2, + .features = PENTIUM2_FEATURES, + .xlevel = 0, + }, + { + .name = "pentium3", + .level = 2, + .family = 6, + .model = 7, + .stepping = 3, + .features = PENTIUM3_FEATURES, + .xlevel = 0, + }, + { + .name = "athlon", + .level = 2, + .vendor1 = 0x68747541, /* "Auth" */ + .vendor2 = 0x69746e65, /* "enti" */ + .vendor3 = 0x444d4163, /* "cAMD" */ + .family = 6, + .model = 2, + .stepping = 3, + .features = PPRO_FEATURES | CPUID_PSE36 | CPUID_VME | CPUID_MTRR | CPUID_MCA, + .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | CPUID_EXT2_MMXEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT, + .xlevel = 0x80000008, + /* XXX: put another string ? */ + .model_id = "QEMU Virtual CPU version " QEMU_VERSION, + }, + { + .name = "n270", + /* original is on level 10 */ + .level = 5, + .family = 6, + .model = 28, + .stepping = 2, + .features = PPRO_FEATURES | + CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_VME, + /* Missing: CPUID_DTS | CPUID_ACPI | CPUID_SS | + * CPUID_HT | CPUID_TM | CPUID_PBE */ + /* Some CPUs got no CPUID_SEP */ + .ext_features = CPUID_EXT_MONITOR | + CPUID_EXT_SSE3 /* PNI */ | CPUID_EXT_SSSE3, + /* Missing: CPUID_EXT_DSCPL | CPUID_EXT_EST | + * CPUID_EXT_TM2 | CPUID_EXT_XTPR */ + .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | CPUID_EXT2_NX, + /* Missing: .ext3_features = CPUID_EXT3_LAHF_LM */ + .xlevel = 0x8000000A, + .model_id = "Intel(R) Atom(TM) CPU N270 @ 1.60GHz", + }, }; -const CPU86_LDouble f15rk[7] = +static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model) { - 0.00000000000000000000L, - 1.00000000000000000000L, - 3.14159265358979323851L, /*pi*/ - 0.30102999566398119523L, /*lg2*/ - 0.69314718055994530943L, /*ln2*/ - 1.44269504088896340739L, /*l2e*/ - 3.32192809488736234781L, /*l2t*/ -}; + unsigned int i; + x86_def_t *def; -/* thread support */ - -spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; + char *s = strdup(cpu_model); + char *featurestr, *name = strtok(s, ","); + uint32_t plus_features = 0, plus_ext_features = 0, plus_ext2_features = 0, plus_ext3_features = 0; + uint32_t minus_features = 0, minus_ext_features = 0, minus_ext2_features = 0, minus_ext3_features = 0; + int family = -1, model = -1, stepping = -1; + + def = NULL; + for (i = 0; i < sizeof(x86_defs) / sizeof(x86_def_t); i++) { + if (strcmp(name, x86_defs[i].name) == 0) { + def = &x86_defs[i]; + break; + } + } + if (!def) + goto error; + memcpy(x86_cpu_def, def, sizeof(*def)); + + featurestr = strtok(NULL, ","); + + while (featurestr) { + char *val; + if (featurestr[0] == '+') { + add_flagname_to_bitmaps(featurestr + 1, &plus_features, &plus_ext_features, &plus_ext2_features, &plus_ext3_features); + } else if (featurestr[0] == '-') { + add_flagname_to_bitmaps(featurestr + 1, &minus_features, &minus_ext_features, &minus_ext2_features, &minus_ext3_features); + } else if ((val = strchr(featurestr, '='))) { + *val = 0; val++; + if (!strcmp(featurestr, "family")) { + char *err; + family = strtol(val, &err, 10); + if (!*val || *err || family < 0) { + fprintf(stderr, "bad numerical value %s\n", val); + goto error; + } + x86_cpu_def->family = family; + } else if (!strcmp(featurestr, "model")) { + char *err; + model = strtol(val, &err, 10); + if (!*val || *err || model < 0 || model > 0xff) { + fprintf(stderr, "bad numerical value %s\n", val); + goto error; + } + x86_cpu_def->model = model; + } else if (!strcmp(featurestr, "stepping")) { + char *err; + stepping = strtol(val, &err, 10); + if (!*val || *err || stepping < 0 || stepping > 0xf) { + fprintf(stderr, "bad numerical value %s\n", val); + goto error; + } + x86_cpu_def->stepping = stepping; + } else if (!strcmp(featurestr, "vendor")) { + if (strlen(val) != 12) { + fprintf(stderr, "vendor string must be 12 chars long\n"); + goto error; + } + x86_cpu_def->vendor1 = 0; + x86_cpu_def->vendor2 = 0; + x86_cpu_def->vendor3 = 0; + for(i = 0; i < 4; i++) { + x86_cpu_def->vendor1 |= ((uint8_t)val[i ]) << (8 * i); + x86_cpu_def->vendor2 |= ((uint8_t)val[i + 4]) << (8 * i); + x86_cpu_def->vendor3 |= ((uint8_t)val[i + 8]) << (8 * i); + } + } else if (!strcmp(featurestr, "model_id")) { + pstrcpy(x86_cpu_def->model_id, sizeof(x86_cpu_def->model_id), + val); + } else { + fprintf(stderr, "unrecognized feature %s\n", featurestr); + goto error; + } + } else { + fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr); + goto error; + } + featurestr = strtok(NULL, ","); + } + x86_cpu_def->features |= plus_features; + x86_cpu_def->ext_features |= plus_ext_features; + x86_cpu_def->ext2_features |= plus_ext2_features; + x86_cpu_def->ext3_features |= plus_ext3_features; + x86_cpu_def->features &= ~minus_features; + x86_cpu_def->ext_features &= ~minus_ext_features; + x86_cpu_def->ext2_features &= ~minus_ext2_features; + x86_cpu_def->ext3_features &= ~minus_ext3_features; + free(s); + return 0; -void cpu_lock(void) -{ - spin_lock(&global_cpu_lock); +error: + free(s); + return -1; } -void cpu_unlock(void) +void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) { - spin_unlock(&global_cpu_lock); + unsigned int i; + + for (i = 0; i < sizeof(x86_defs) / sizeof(x86_def_t); i++) + (*cpu_fprintf)(f, "x86 %16s\n", x86_defs[i].name); } -/* return non zero if error */ -static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, - int selector) +static int cpu_x86_register (CPUX86State *env, const char *cpu_model) { - SegmentCache *dt; - int index; - target_ulong ptr; + x86_def_t def1, *def = &def1; - if (selector & 0x4) - dt = &env->ldt; - else - dt = &env->gdt; - index = selector & ~7; - if ((index + 7) > dt->limit) + if (cpu_x86_find_by_name(def, cpu_model) < 0) return -1; - ptr = dt->base + index; - *e1_ptr = ldl_kernel(ptr); - *e2_ptr = ldl_kernel(ptr + 4); + if (def->vendor1) { + env->cpuid_vendor1 = def->vendor1; + env->cpuid_vendor2 = def->vendor2; + env->cpuid_vendor3 = def->vendor3; + } else { + env->cpuid_vendor1 = CPUID_VENDOR_INTEL_1; + env->cpuid_vendor2 = CPUID_VENDOR_INTEL_2; + env->cpuid_vendor3 = CPUID_VENDOR_INTEL_3; + } + env->cpuid_level = def->level; + if (def->family > 0x0f) + env->cpuid_version = 0xf00 | ((def->family - 0x0f) << 20); + else + env->cpuid_version = def->family << 8; + env->cpuid_version |= ((def->model & 0xf) << 4) | ((def->model >> 4) << 16); + env->cpuid_version |= def->stepping; + env->cpuid_features = def->features; + env->pat = 0x0007040600070406ULL; + env->cpuid_ext_features = def->ext_features; + env->cpuid_ext2_features = def->ext2_features; + env->cpuid_xlevel = def->xlevel; + env->cpuid_ext3_features = def->ext3_features; + { + const char *model_id = def->model_id; + int c, len, i; + if (!model_id) + model_id = ""; + len = strlen(model_id); + for(i = 0; i < 48; i++) { + if (i >= len) + c = '\0'; + else + c = (uint8_t)model_id[i]; + env->cpuid_model[i >> 2] |= c << (8 * (i & 3)); + } + } return 0; } -static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) +/* NOTE: must be called outside the CPU execute loop */ +void cpu_reset(CPUX86State *env) { - unsigned int limit; - limit = (e1 & 0xffff) | (e2 & 0x000f0000); - if (e2 & DESC_G_MASK) - limit = (limit << 12) | 0xfff; - return limit; -} + int i; -static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2) -{ - return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); -} + memset(env, 0, offsetof(CPUX86State, breakpoints)); -static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2) -{ - sc->base = get_seg_base(e1, e2); - sc->limit = get_seg_limit(e1, e2); - sc->flags = e2; -} + tlb_flush(env, 1); -/* init the segment cache in vm86 mode. */ -static inline void load_seg_vm(int seg, int selector) -{ - selector &= 0xffff; - cpu_x86_load_seg_cache(env, seg, selector, - (selector << 4), 0xffff, 0); -} + env->old_exception = -1; -static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, - uint32_t *esp_ptr, int dpl) -{ - int type, index, shift; + /* init to reset state */ -#if 0 - { - int i; - printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit); - for(i=0;itr.limit;i++) { - printf("%02x ", env->tr.base[i]); - if ((i & 7) == 7) printf("\n"); - } - printf("\n"); - } +#ifdef CONFIG_SOFTMMU + env->hflags |= HF_SOFTMMU_MASK; #endif + env->hflags2 |= HF2_GIF_MASK; - if (!(env->tr.flags & DESC_P_MASK)) - cpu_abort(env, "invalid tss"); - type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; - if ((type & 7) != 1) - cpu_abort(env, "invalid tss type"); - shift = type >> 3; - index = (dpl * 4 + 2) << shift; - if (index + (4 << shift) - 1 > env->tr.limit) - raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); - if (shift == 0) { - *esp_ptr = lduw_kernel(env->tr.base + index); - *ss_ptr = lduw_kernel(env->tr.base + index + 2); - } else { - *esp_ptr = ldl_kernel(env->tr.base + index); - *ss_ptr = lduw_kernel(env->tr.base + index + 4); - } -} - -/* XXX: merge with load_seg() */ -static void tss_load_seg(int seg_reg, int selector) -{ - uint32_t e1, e2; - int rpl, dpl, cpl; + cpu_x86_update_cr0(env, 0x60000010); + env->a20_mask = ~0x0; + env->smbase = 0x30000; + + env->idt.limit = 0xffff; + env->gdt.limit = 0xffff; + env->ldt.limit = 0xffff; + env->ldt.flags = DESC_P_MASK | (2 << DESC_TYPE_SHIFT); + env->tr.limit = 0xffff; + env->tr.flags = DESC_P_MASK | (11 << DESC_TYPE_SHIFT); + + cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff, + DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK | DESC_R_MASK); + cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffff, + DESC_P_MASK | DESC_S_MASK | DESC_W_MASK); + cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffff, + DESC_P_MASK | DESC_S_MASK | DESC_W_MASK); + cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffff, + DESC_P_MASK | DESC_S_MASK | DESC_W_MASK); + cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffff, + DESC_P_MASK | DESC_S_MASK | DESC_W_MASK); + cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff, + DESC_P_MASK | DESC_S_MASK | DESC_W_MASK); + + env->eip = 0xfff0; + env->regs[R_EDX] = env->cpuid_version; + + env->eflags = 0x2; + + /* FPU init */ + for(i = 0;i < 8; i++) + env->fptags[i] = 1; + env->fpuc = 0x37f; - if ((selector & 0xfffc) != 0) { - if (load_segment(&e1, &e2, selector) != 0) - raise_exception_err(EXCP0A_TSS, selector & 0xfffc); - if (!(e2 & DESC_S_MASK)) - raise_exception_err(EXCP0A_TSS, selector & 0xfffc); - rpl = selector & 3; - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->hflags & HF_CPL_MASK; - if (seg_reg == R_CS) { - if (!(e2 & DESC_CS_MASK)) - raise_exception_err(EXCP0A_TSS, selector & 0xfffc); - /* XXX: is it correct ? */ - if (dpl != rpl) - raise_exception_err(EXCP0A_TSS, selector & 0xfffc); - if ((e2 & DESC_C_MASK) && dpl > rpl) - raise_exception_err(EXCP0A_TSS, selector & 0xfffc); - } else if (seg_reg == R_SS) { - /* SS must be writable data */ - if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) - raise_exception_err(EXCP0A_TSS, selector & 0xfffc); - if (dpl != cpl || dpl != rpl) - raise_exception_err(EXCP0A_TSS, selector & 0xfffc); - } else { - /* not readable code */ - if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK)) - raise_exception_err(EXCP0A_TSS, selector & 0xfffc); - /* if data or non conforming code, checks the rights */ - if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) { - if (dpl < cpl || dpl < rpl) - raise_exception_err(EXCP0A_TSS, selector & 0xfffc); - } - } - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - cpu_x86_load_seg_cache(env, seg_reg, selector, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), - e2); - } else { - if (seg_reg == R_SS || seg_reg == R_CS) - raise_exception_err(EXCP0A_TSS, selector & 0xfffc); - } + env->mxcsr = 0x1f80; } -#define SWITCH_TSS_JMP 0 -#define SWITCH_TSS_IRET 1 -#define SWITCH_TSS_CALL 2 - -/* XXX: restore CPU state in registers (PowerPC case) */ -static void switch_tss(int tss_selector, - uint32_t e1, uint32_t e2, int source, - uint32_t next_eip) +void cpu_x86_close(CPUX86State *env) { - int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i; - target_ulong tss_base; - uint32_t new_regs[8], new_segs[6]; - uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap; - uint32_t old_eflags, eflags_mask; - SegmentCache *dt; - int index; - target_ulong ptr; - - type = (e2 >> DESC_TYPE_SHIFT) & 0xf; -#ifdef DEBUG_PCALL - if (loglevel & CPU_LOG_PCALL) - fprintf(logfile, "switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source); -#endif - - /* if task gate, we read the TSS segment and we load it */ - if (type == 5) { - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc); - tss_selector = e1 >> 16; - if (tss_selector & 4) - raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); - if (load_segment(&e1, &e2, tss_selector) != 0) - raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); - if (e2 & DESC_S_MASK) - raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); - type = (e2 >> DESC_TYPE_SHIFT) & 0xf; - if ((type & 7) != 1) - raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); - } - - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc); - - if (type & 8) - tss_limit_max = 103; - else - tss_limit_max = 43; - tss_limit = get_seg_limit(e1, e2); - tss_base = get_seg_base(e1, e2); - if ((tss_selector & 4) != 0 || - tss_limit < tss_limit_max) - raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); - old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; - if (old_type & 8) - old_tss_limit_max = 103; - else - old_tss_limit_max = 43; + qemu_free(env); +} - /* read all the registers from the new TSS */ - if (type & 8) { - /* 32 bit */ - new_cr3 = ldl_kernel(tss_base + 0x1c); - new_eip = ldl_kernel(tss_base + 0x20); - new_eflags = ldl_kernel(tss_base + 0x24); - for(i = 0; i < 8; i++) - new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4)); - for(i = 0; i < 6; i++) - new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4)); - new_ldt = lduw_kernel(tss_base + 0x60); - new_trap = ldl_kernel(tss_base + 0x64); - } else { - /* 16 bit */ - new_cr3 = 0; - new_eip = lduw_kernel(tss_base + 0x0e); - new_eflags = lduw_kernel(tss_base + 0x10); - for(i = 0; i < 8; i++) - new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000; - for(i = 0; i < 4; i++) - new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4)); - new_ldt = lduw_kernel(tss_base + 0x2a); - new_segs[R_FS] = 0; - new_segs[R_GS] = 0; - new_trap = 0; - } +/***********************************************************/ +/* x86 debug */ + +static const char *cc_op_str[] = { + "DYNAMIC", + "EFLAGS", + + "MULB", + "MULW", + "MULL", + "MULQ", + + "ADDB", + "ADDW", + "ADDL", + "ADDQ", + + "ADCB", + "ADCW", + "ADCL", + "ADCQ", + + "SUBB", + "SUBW", + "SUBL", + "SUBQ", + + "SBBB", + "SBBW", + "SBBL", + "SBBQ", + + "LOGICB", + "LOGICW", + "LOGICL", + "LOGICQ", + + "INCB", + "INCW", + "INCL", + "INCQ", + + "DECB", + "DECW", + "DECL", + "DECQ", + + "SHLB", + "SHLW", + "SHLL", + "SHLQ", + + "SARB", + "SARW", + "SARL", + "SARQ", +}; - /* NOTE: we must avoid memory exceptions during the task switch, - so we make dummy accesses before */ - /* XXX: it can still fail in some cases, so a bigger hack is - necessary to valid the TLB after having done the accesses */ - - v1 = ldub_kernel(env->tr.base); - v2 = ldub_kernel(env->tr.base + old_tss_limit_max); - stb_kernel(env->tr.base, v1); - stb_kernel(env->tr.base + old_tss_limit_max, v2); - - /* clear busy bit (it is restartable) */ - if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) { - target_ulong ptr; - uint32_t e2; - ptr = env->gdt.base + (env->tr.selector & ~7); - e2 = ldl_kernel(ptr + 4); - e2 &= ~DESC_TSS_BUSY_MASK; - stl_kernel(ptr + 4, e2); - } - old_eflags = compute_eflags(); - if (source == SWITCH_TSS_IRET) - old_eflags &= ~NT_MASK; - - /* save the current state in the old TSS */ - if (type & 8) { - /* 32 bit */ - stl_kernel(env->tr.base + 0x20, next_eip); - stl_kernel(env->tr.base + 0x24, old_eflags); - stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX); - stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX); - stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX); - stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX); - stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP); - stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP); - stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI); - stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI); - for(i = 0; i < 6; i++) - stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector); - } else { - /* 16 bit */ - stw_kernel(env->tr.base + 0x0e, next_eip); - stw_kernel(env->tr.base + 0x10, old_eflags); - stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX); - stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX); - stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX); - stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX); - stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP); - stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP); - stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI); - stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI); - for(i = 0; i < 4; i++) - stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector); +void cpu_dump_state(CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) +{ + int eflags, i, nb; + char cc_op_name[32]; + static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" }; + + eflags = env->eflags; +#ifdef TARGET_X86_64 + if (env->hflags & HF_CS64_MASK) { + cpu_fprintf(f, + "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n" + "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n" + "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n" + "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n" + "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n", + env->regs[R_EAX], + env->regs[R_EBX], + env->regs[R_ECX], + env->regs[R_EDX], + env->regs[R_ESI], + env->regs[R_EDI], + env->regs[R_EBP], + env->regs[R_ESP], + env->regs[8], + env->regs[9], + env->regs[10], + env->regs[11], + env->regs[12], + env->regs[13], + env->regs[14], + env->regs[15], + env->eip, eflags, + eflags & DF_MASK ? 'D' : '-', + eflags & CC_O ? 'O' : '-', + eflags & CC_S ? 'S' : '-', + eflags & CC_Z ? 'Z' : '-', + eflags & CC_A ? 'A' : '-', + eflags & CC_P ? 'P' : '-', + eflags & CC_C ? 'C' : '-', + env->hflags & HF_CPL_MASK, + (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, + (int)(env->a20_mask >> 20) & 1, + (env->hflags >> HF_SMM_SHIFT) & 1, + env->halted); + } else +#endif + { + cpu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" + "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" + "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n", + (uint32_t)env->regs[R_EAX], + (uint32_t)env->regs[R_EBX], + (uint32_t)env->regs[R_ECX], + (uint32_t)env->regs[R_EDX], + (uint32_t)env->regs[R_ESI], + (uint32_t)env->regs[R_EDI], + (uint32_t)env->regs[R_EBP], + (uint32_t)env->regs[R_ESP], + (uint32_t)env->eip, eflags, + eflags & DF_MASK ? 'D' : '-', + eflags & CC_O ? 'O' : '-', + eflags & CC_S ? 'S' : '-', + eflags & CC_Z ? 'Z' : '-', + eflags & CC_A ? 'A' : '-', + eflags & CC_P ? 'P' : '-', + eflags & CC_C ? 'C' : '-', + env->hflags & HF_CPL_MASK, + (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, + (int)(env->a20_mask >> 20) & 1, + (env->hflags >> HF_SMM_SHIFT) & 1, + env->halted); } - /* now if an exception occurs, it will occurs in the next task - context */ - - if (source == SWITCH_TSS_CALL) { - stw_kernel(tss_base, env->tr.selector); - new_eflags |= NT_MASK; +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + for(i = 0; i < 6; i++) { + SegmentCache *sc = &env->segs[i]; + cpu_fprintf(f, "%s =%04x %016" PRIx64 " %08x %08x\n", + seg_name[i], + sc->selector, + sc->base, + sc->limit, + sc->flags); + } + cpu_fprintf(f, "LDT=%04x %016" PRIx64 " %08x %08x\n", + env->ldt.selector, + env->ldt.base, + env->ldt.limit, + env->ldt.flags); + cpu_fprintf(f, "TR =%04x %016" PRIx64 " %08x %08x\n", + env->tr.selector, + env->tr.base, + env->tr.limit, + env->tr.flags); + cpu_fprintf(f, "GDT= %016" PRIx64 " %08x\n", + env->gdt.base, env->gdt.limit); + cpu_fprintf(f, "IDT= %016" PRIx64 " %08x\n", + env->idt.base, env->idt.limit); + cpu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n", + (uint32_t)env->cr[0], + env->cr[2], + env->cr[3], + (uint32_t)env->cr[4]); + } else +#endif + { + for(i = 0; i < 6; i++) { + SegmentCache *sc = &env->segs[i]; + cpu_fprintf(f, "%s =%04x %08x %08x %08x\n", + seg_name[i], + sc->selector, + (uint32_t)sc->base, + sc->limit, + sc->flags); + } + cpu_fprintf(f, "LDT=%04x %08x %08x %08x\n", + env->ldt.selector, + (uint32_t)env->ldt.base, + env->ldt.limit, + env->ldt.flags); + cpu_fprintf(f, "TR =%04x %08x %08x %08x\n", + env->tr.selector, + (uint32_t)env->tr.base, + env->tr.limit, + env->tr.flags); + cpu_fprintf(f, "GDT= %08x %08x\n", + (uint32_t)env->gdt.base, env->gdt.limit); + cpu_fprintf(f, "IDT= %08x %08x\n", + (uint32_t)env->idt.base, env->idt.limit); + cpu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n", + (uint32_t)env->cr[0], + (uint32_t)env->cr[2], + (uint32_t)env->cr[3], + (uint32_t)env->cr[4]); + } + if (flags & X86_DUMP_CCOP) { + if ((unsigned)env->cc_op < CC_OP_NB) + snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]); + else + snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); +#ifdef TARGET_X86_64 + if (env->hflags & HF_CS64_MASK) { + cpu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%-8s\n", + env->cc_src, env->cc_dst, + cc_op_name); + } else +#endif + { + cpu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", + (uint32_t)env->cc_src, (uint32_t)env->cc_dst, + cc_op_name); + } + } + if (flags & X86_DUMP_FPU) { + int fptag; + fptag = 0; + for(i = 0; i < 8; i++) { + fptag |= ((!env->fptags[i]) << i); + } + cpu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n", + env->fpuc, + (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11, + env->fpstt, + fptag, + env->mxcsr); + for(i=0;i<8;i++) { +#if defined(USE_X86LDOUBLE) + union { + long double d; + struct { + uint64_t lower; + uint16_t upper; + } l; + } tmp; + tmp.d = env->fpregs[i].d; + cpu_fprintf(f, "FPR%d=%016" PRIx64 " %04x", + i, tmp.l.lower, tmp.l.upper); +#else + cpu_fprintf(f, "FPR%d=%016" PRIx64, + i, env->fpregs[i].mmx.q); +#endif + if ((i & 1) == 1) + cpu_fprintf(f, "\n"); + else + cpu_fprintf(f, " "); + } + if (env->hflags & HF_CS64_MASK) + nb = 16; + else + nb = 8; + for(i=0;ixmm_regs[i].XMM_L(3), + env->xmm_regs[i].XMM_L(2), + env->xmm_regs[i].XMM_L(1), + env->xmm_regs[i].XMM_L(0)); + if ((i & 1) == 1) + cpu_fprintf(f, "\n"); + else + cpu_fprintf(f, " "); + } } +} - /* set busy bit */ - if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) { - target_ulong ptr; - uint32_t e2; - ptr = env->gdt.base + (tss_selector & ~7); - e2 = ldl_kernel(ptr + 4); - e2 |= DESC_TSS_BUSY_MASK; - stl_kernel(ptr + 4, e2); - } +/***********************************************************/ +/* x86 mmu */ +/* XXX: add PGE support */ - /* set the new CPU state */ - /* from this point, any exception which occurs can give problems */ - env->cr[0] |= CR0_TS_MASK; - env->hflags |= HF_TS_MASK; - env->tr.selector = tss_selector; - env->tr.base = tss_base; - env->tr.limit = tss_limit; - env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK; +void cpu_x86_set_a20(CPUX86State *env, int a20_state) +{ + a20_state = (a20_state != 0); + if (a20_state != ((env->a20_mask >> 20) & 1)) { +#if defined(DEBUG_MMU) + printf("A20 update: a20=%d\n", a20_state); +#endif + /* if the cpu is currently executing code, we must unlink it and + all the potentially executing TB */ + cpu_interrupt(env, CPU_INTERRUPT_EXITTB); - if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) { - cpu_x86_update_cr3(env, new_cr3); + /* when a20 is changed, all the MMU mappings are invalid, so + we must flush everything */ + tlb_flush(env, 1); + env->a20_mask = (~0x100000) | (a20_state << 20); } +} - /* load all registers without an exception, then reload them with - possible exception */ - env->eip = new_eip; - eflags_mask = TF_MASK | AC_MASK | ID_MASK | - IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK; - if (!(type & 8)) - eflags_mask &= 0xffff; - load_eflags(new_eflags, eflags_mask); - /* XXX: what to do in 16 bit case ? */ - EAX = new_regs[0]; - ECX = new_regs[1]; - EDX = new_regs[2]; - EBX = new_regs[3]; - ESP = new_regs[4]; - EBP = new_regs[5]; - ESI = new_regs[6]; - EDI = new_regs[7]; - if (new_eflags & VM_MASK) { - for(i = 0; i < 6; i++) - load_seg_vm(i, new_segs[i]); - /* in vm86, CPL is always 3 */ - cpu_x86_set_cpl(env, 3); - } else { - /* CPL is set the RPL of CS */ - cpu_x86_set_cpl(env, new_segs[R_CS] & 3); - /* first just selectors as the rest may trigger exceptions */ - for(i = 0; i < 6; i++) - cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0); - } +void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0) +{ + int pe_state; - env->ldt.selector = new_ldt & ~4; - env->ldt.base = 0; - env->ldt.limit = 0; - env->ldt.flags = 0; - - /* load the LDT */ - if (new_ldt & 4) - raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); - - if ((new_ldt & 0xfffc) != 0) { - dt = &env->gdt; - index = new_ldt & ~7; - if ((index + 7) > dt->limit) - raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); - ptr = dt->base + index; - e1 = ldl_kernel(ptr); - e2 = ldl_kernel(ptr + 4); - if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) - raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); - load_seg_cache_raw_dt(&env->ldt, e1, e2); +#if defined(DEBUG_MMU) + printf("CR0 update: CR0=0x%08x\n", new_cr0); +#endif + if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) != + (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) { + tlb_flush(env, 1); } - /* load the segments */ - if (!(new_eflags & VM_MASK)) { - tss_load_seg(R_CS, new_segs[R_CS]); - tss_load_seg(R_SS, new_segs[R_SS]); - tss_load_seg(R_ES, new_segs[R_ES]); - tss_load_seg(R_DS, new_segs[R_DS]); - tss_load_seg(R_FS, new_segs[R_FS]); - tss_load_seg(R_GS, new_segs[R_GS]); +#ifdef TARGET_X86_64 + if (!(env->cr[0] & CR0_PG_MASK) && (new_cr0 & CR0_PG_MASK) && + (env->efer & MSR_EFER_LME)) { + /* enter in long mode */ + /* XXX: generate an exception */ + if (!(env->cr[4] & CR4_PAE_MASK)) + return; + env->efer |= MSR_EFER_LMA; + env->hflags |= HF_LMA_MASK; + } else if ((env->cr[0] & CR0_PG_MASK) && !(new_cr0 & CR0_PG_MASK) && + (env->efer & MSR_EFER_LMA)) { + /* exit long mode */ + env->efer &= ~MSR_EFER_LMA; + env->hflags &= ~(HF_LMA_MASK | HF_CS64_MASK); + env->eip &= 0xffffffff; } +#endif + env->cr[0] = new_cr0 | CR0_ET_MASK; - /* check that EIP is in the CS segment limits */ - if (new_eip > env->segs[R_CS].limit) { - /* XXX: different exception if CALL ? */ - raise_exception_err(EXCP0D_GPF, 0); - } + /* update PE flag in hidden flags */ + pe_state = (env->cr[0] & CR0_PE_MASK); + env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT); + /* ensure that ADDSEG is always set in real mode */ + env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT); + /* update FPU flags */ + env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) | + ((new_cr0 << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)); } -/* check if Port I/O is allowed in TSS */ -static inline void check_io(int addr, int size) +/* XXX: in legacy PAE mode, generate a GPF if reserved bits are set in + the PDPT */ +void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3) { - int io_offset, val, mask; - - /* TSS must be a valid 32 bit one */ - if (!(env->tr.flags & DESC_P_MASK) || - ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 || - env->tr.limit < 103) - goto fail; - io_offset = lduw_kernel(env->tr.base + 0x66); - io_offset += (addr >> 3); - /* Note: the check needs two bytes */ - if ((io_offset + 1) > env->tr.limit) - goto fail; - val = lduw_kernel(env->tr.base + io_offset); - val >>= (addr & 7); - mask = (1 << size) - 1; - /* all bits must be zero to allow the I/O */ - if ((val & mask) != 0) { - fail: - raise_exception_err(EXCP0D_GPF, 0); + env->cr[3] = new_cr3; + if (env->cr[0] & CR0_PG_MASK) { +#if defined(DEBUG_MMU) + printf("CR3 update: CR3=" TARGET_FMT_lx "\n", new_cr3); +#endif + tlb_flush(env, 0); } } -void check_iob_T0(void) -{ - check_io(T0, 1); -} - -void check_iow_T0(void) +void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4) { - check_io(T0, 2); -} +#if defined(DEBUG_MMU) + printf("CR4 update: CR4=%08x\n", (uint32_t)env->cr[4]); +#endif + if ((new_cr4 & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK)) != + (env->cr[4] & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK))) { + tlb_flush(env, 1); + } + /* SSE handling */ + if (!(env->cpuid_features & CPUID_SSE)) + new_cr4 &= ~CR4_OSFXSR_MASK; + if (new_cr4 & CR4_OSFXSR_MASK) + env->hflags |= HF_OSFXSR_MASK; + else + env->hflags &= ~HF_OSFXSR_MASK; -void check_iol_T0(void) -{ - check_io(T0, 4); + env->cr[4] = new_cr4; } -void check_iob_DX(void) +/* XXX: also flush 4MB pages */ +void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr) { - check_io(EDX & 0xffff, 1); + tlb_flush_page(env, addr); } -void check_iow_DX(void) -{ - check_io(EDX & 0xffff, 2); -} +#if defined(CONFIG_USER_ONLY) -void check_iol_DX(void) +int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, + int is_write, int mmu_idx, int is_softmmu) { - check_io(EDX & 0xffff, 4); + /* user mode only emulation */ + is_write &= 1; + env->cr[2] = addr; + env->error_code = (is_write << PG_ERROR_W_BIT); + env->error_code |= PG_ERROR_U_MASK; + env->exception_index = EXCP0E_PAGE; + return 1; } -static inline unsigned int get_sp_mask(unsigned int e2) +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { - if (e2 & DESC_B_MASK) - return 0xffffffff; - else - return 0xffff; + return addr; } -#ifdef TARGET_X86_64 -#define SET_ESP(val, sp_mask)\ -do {\ - if ((sp_mask) == 0xffff)\ - ESP = (ESP & ~0xffff) | ((val) & 0xffff);\ - else if ((sp_mask) == 0xffffffffLL)\ - ESP = (uint32_t)(val);\ - else\ - ESP = (val);\ -} while (0) #else -#define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask)) -#endif -/* XXX: add a is_user flag to have proper security support */ -#define PUSHW(ssp, sp, sp_mask, val)\ -{\ - sp -= 2;\ - stw_kernel((ssp) + (sp & (sp_mask)), (val));\ -} +/* XXX: This value should match the one returned by CPUID + * and in exec.c */ +#if defined(USE_KQEMU) +#define PHYS_ADDR_MASK 0xfffff000LL +#else +# if defined(TARGET_X86_64) +# define PHYS_ADDR_MASK 0xfffffff000LL +# else +# define PHYS_ADDR_MASK 0xffffff000LL +# endif +#endif + +/* return value: + -1 = cannot handle fault + 0 = nothing more to do + 1 = generate PF fault + 2 = soft MMU activation required for this block +*/ +int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, + int is_write1, int mmu_idx, int is_softmmu) +{ + uint64_t ptep, pte; + target_ulong pde_addr, pte_addr; + int error_code, is_dirty, prot, page_size, ret, is_write, is_user; + target_phys_addr_t paddr; + uint32_t page_offset; + target_ulong vaddr, virt_addr; + + is_user = mmu_idx == MMU_USER_IDX; +#if defined(DEBUG_MMU) + printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n", + addr, is_write1, is_user, env->eip); +#endif + is_write = is_write1 & 1; + + if (!(env->cr[0] & CR0_PG_MASK)) { + pte = addr; + virt_addr = addr & TARGET_PAGE_MASK; + prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + page_size = 4096; + goto do_mapping; + } + + if (env->cr[4] & CR4_PAE_MASK) { + uint64_t pde, pdpe; + target_ulong pdpe_addr; -#define PUSHL(ssp, sp, sp_mask, val)\ -{\ - sp -= 4;\ - stl_kernel((ssp) + (sp & (sp_mask)), (val));\ -} +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + uint64_t pml4e_addr, pml4e; + int32_t sext; -#define POPW(ssp, sp, sp_mask, val)\ -{\ - val = lduw_kernel((ssp) + (sp & (sp_mask)));\ - sp += 2;\ -} + /* test virtual address sign extension */ + sext = (int64_t)addr >> 47; + if (sext != 0 && sext != -1) { + env->error_code = 0; + env->exception_index = EXCP0D_GPF; + return 1; + } -#define POPL(ssp, sp, sp_mask, val)\ -{\ - val = (uint32_t)ldl_kernel((ssp) + (sp & (sp_mask)));\ - sp += 4;\ -} + pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & + env->a20_mask; + pml4e = ldq_phys(pml4e_addr); + if (!(pml4e & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; + } + if (!(env->efer & MSR_EFER_NXE) && (pml4e & PG_NX_MASK)) { + error_code = PG_ERROR_RSVD_MASK; + goto do_fault; + } + if (!(pml4e & PG_ACCESSED_MASK)) { + pml4e |= PG_ACCESSED_MASK; + stl_phys_notdirty(pml4e_addr, pml4e); + } + ptep = pml4e ^ PG_NX_MASK; + pdpe_addr = ((pml4e & PHYS_ADDR_MASK) + (((addr >> 30) & 0x1ff) << 3)) & + env->a20_mask; + pdpe = ldq_phys(pdpe_addr); + if (!(pdpe & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; + } + if (!(env->efer & MSR_EFER_NXE) && (pdpe & PG_NX_MASK)) { + error_code = PG_ERROR_RSVD_MASK; + goto do_fault; + } + ptep &= pdpe ^ PG_NX_MASK; + if (!(pdpe & PG_ACCESSED_MASK)) { + pdpe |= PG_ACCESSED_MASK; + stl_phys_notdirty(pdpe_addr, pdpe); + } + } else +#endif + { + /* XXX: load them when cr3 is loaded ? */ + pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & + env->a20_mask; + pdpe = ldq_phys(pdpe_addr); + if (!(pdpe & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; + } + ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; + } -/* protected mode interrupt */ -static void do_interrupt_protected(int intno, int is_int, int error_code, - unsigned int next_eip, int is_hw) -{ - SegmentCache *dt; - target_ulong ptr, ssp; - int type, dpl, selector, ss_dpl, cpl; - int has_error_code, new_stack, shift; - uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2; - uint32_t old_eip, sp_mask; - int svm_should_check = 1; - - if ((env->intercept & INTERCEPT_SVM_MASK) && !is_int && next_eip==-1) { - next_eip = EIP; - svm_should_check = 0; - } + pde_addr = ((pdpe & PHYS_ADDR_MASK) + (((addr >> 21) & 0x1ff) << 3)) & + env->a20_mask; + pde = ldq_phys(pde_addr); + if (!(pde & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; + } + if (!(env->efer & MSR_EFER_NXE) && (pde & PG_NX_MASK)) { + error_code = PG_ERROR_RSVD_MASK; + goto do_fault; + } + ptep &= pde ^ PG_NX_MASK; + if (pde & PG_PSE_MASK) { + /* 2 MB page */ + page_size = 2048 * 1024; + ptep ^= PG_NX_MASK; + if ((ptep & PG_NX_MASK) && is_write1 == 2) + goto do_fault_protect; + if (is_user) { + if (!(ptep & PG_USER_MASK)) + goto do_fault_protect; + if (is_write && !(ptep & PG_RW_MASK)) + goto do_fault_protect; + } else { + if ((env->cr[0] & CR0_WP_MASK) && + is_write && !(ptep & PG_RW_MASK)) + goto do_fault_protect; + } + is_dirty = is_write && !(pde & PG_DIRTY_MASK); + if (!(pde & PG_ACCESSED_MASK) || is_dirty) { + pde |= PG_ACCESSED_MASK; + if (is_dirty) + pde |= PG_DIRTY_MASK; + stl_phys_notdirty(pde_addr, pde); + } + /* align to page_size */ + pte = pde & ((PHYS_ADDR_MASK & ~(page_size - 1)) | 0xfff); + virt_addr = addr & ~(page_size - 1); + } else { + /* 4 KB page */ + if (!(pde & PG_ACCESSED_MASK)) { + pde |= PG_ACCESSED_MASK; + stl_phys_notdirty(pde_addr, pde); + } + pte_addr = ((pde & PHYS_ADDR_MASK) + (((addr >> 12) & 0x1ff) << 3)) & + env->a20_mask; + pte = ldq_phys(pte_addr); + if (!(pte & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; + } + if (!(env->efer & MSR_EFER_NXE) && (pte & PG_NX_MASK)) { + error_code = PG_ERROR_RSVD_MASK; + goto do_fault; + } + /* combine pde and pte nx, user and rw protections */ + ptep &= pte ^ PG_NX_MASK; + ptep ^= PG_NX_MASK; + if ((ptep & PG_NX_MASK) && is_write1 == 2) + goto do_fault_protect; + if (is_user) { + if (!(ptep & PG_USER_MASK)) + goto do_fault_protect; + if (is_write && !(ptep & PG_RW_MASK)) + goto do_fault_protect; + } else { + if ((env->cr[0] & CR0_WP_MASK) && + is_write && !(ptep & PG_RW_MASK)) + goto do_fault_protect; + } + is_dirty = is_write && !(pte & PG_DIRTY_MASK); + if (!(pte & PG_ACCESSED_MASK) || is_dirty) { + pte |= PG_ACCESSED_MASK; + if (is_dirty) + pte |= PG_DIRTY_MASK; + stl_phys_notdirty(pte_addr, pte); + } + page_size = 4096; + virt_addr = addr & ~0xfff; + pte = pte & (PHYS_ADDR_MASK | 0xfff); + } + } else { + uint32_t pde; + + /* page directory entry */ + pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & + env->a20_mask; + pde = ldl_phys(pde_addr); + if (!(pde & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; + } + /* if PSE bit is set, then we use a 4MB page */ + if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + page_size = 4096 * 1024; + if (is_user) { + if (!(pde & PG_USER_MASK)) + goto do_fault_protect; + if (is_write && !(pde & PG_RW_MASK)) + goto do_fault_protect; + } else { + if ((env->cr[0] & CR0_WP_MASK) && + is_write && !(pde & PG_RW_MASK)) + goto do_fault_protect; + } + is_dirty = is_write && !(pde & PG_DIRTY_MASK); + if (!(pde & PG_ACCESSED_MASK) || is_dirty) { + pde |= PG_ACCESSED_MASK; + if (is_dirty) + pde |= PG_DIRTY_MASK; + stl_phys_notdirty(pde_addr, pde); + } - if (svm_should_check - && (INTERCEPTEDl(_exceptions, 1 << intno) - && !is_int)) { - raise_interrupt(intno, is_int, error_code, 0); - } - has_error_code = 0; - if (!is_int && !is_hw) { - switch(intno) { - case 8: - case 10: - case 11: - case 12: - case 13: - case 14: - case 17: - has_error_code = 1; - break; - } - } - if (is_int) - old_eip = next_eip; - else - old_eip = env->eip; + pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */ + ptep = pte; + virt_addr = addr & ~(page_size - 1); + } else { + if (!(pde & PG_ACCESSED_MASK)) { + pde |= PG_ACCESSED_MASK; + stl_phys_notdirty(pde_addr, pde); + } - dt = &env->idt; - if (intno * 8 + 7 > dt->limit) - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); - ptr = dt->base + intno * 8; - e1 = ldl_kernel(ptr); - e2 = ldl_kernel(ptr + 4); - /* check gate type */ - type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; - switch(type) { - case 5: /* task gate */ - /* must do that check here to return the correct error code */ - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); - switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip); - if (has_error_code) { - int type; - uint32_t mask; - /* push the error code */ - type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; - shift = type >> 3; - if (env->segs[R_SS].flags & DESC_B_MASK) - mask = 0xffffffff; - else - mask = 0xffff; - esp = (ESP - (2 << shift)) & mask; - ssp = env->segs[R_SS].base + esp; - if (shift) - stl_kernel(ssp, error_code); - else - stw_kernel(ssp, error_code); - SET_ESP(esp, mask); + /* page directory entry */ + pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & + env->a20_mask; + pte = ldl_phys(pte_addr); + if (!(pte & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; + } + /* combine pde and pte user and rw protections */ + ptep = pte & pde; + if (is_user) { + if (!(ptep & PG_USER_MASK)) + goto do_fault_protect; + if (is_write && !(ptep & PG_RW_MASK)) + goto do_fault_protect; + } else { + if ((env->cr[0] & CR0_WP_MASK) && + is_write && !(ptep & PG_RW_MASK)) + goto do_fault_protect; + } + is_dirty = is_write && !(pte & PG_DIRTY_MASK); + if (!(pte & PG_ACCESSED_MASK) || is_dirty) { + pte |= PG_ACCESSED_MASK; + if (is_dirty) + pte |= PG_DIRTY_MASK; + stl_phys_notdirty(pte_addr, pte); + } + page_size = 4096; + virt_addr = addr & ~0xfff; } - return; - case 6: /* 286 interrupt gate */ - case 7: /* 286 trap gate */ - case 14: /* 386 interrupt gate */ - case 15: /* 386 trap gate */ - break; - default: - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); - break; } - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->hflags & HF_CPL_MASK; - /* check privledge if software int */ - if (is_int && dpl < cpl) - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); - /* check valid bit */ - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); - selector = e1 >> 16; - offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); - if ((selector & 0xfffc) == 0) - raise_exception_err(EXCP0D_GPF, 0); - - if (load_segment(&e1, &e2, selector) != 0) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (dpl > cpl) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - if (!(e2 & DESC_C_MASK) && dpl < cpl) { - /* to inner privilege */ - get_ss_esp_from_tss(&ss, &esp, dpl); - if ((ss & 0xfffc) == 0) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if ((ss & 3) != dpl) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if (load_segment(&ss_e1, &ss_e2, ss) != 0) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; - if (ss_dpl != dpl) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if (!(ss_e2 & DESC_S_MASK) || - (ss_e2 & DESC_CS_MASK) || - !(ss_e2 & DESC_W_MASK)) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if (!(ss_e2 & DESC_P_MASK)) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - new_stack = 1; - sp_mask = get_sp_mask(ss_e2); - ssp = get_seg_base(ss_e1, ss_e2); - } else if ((e2 & DESC_C_MASK) || dpl == cpl) { - /* to same privilege */ - if (env->eflags & VM_MASK) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - new_stack = 0; - sp_mask = get_sp_mask(env->segs[R_SS].flags); - ssp = env->segs[R_SS].base; - esp = ESP; - dpl = cpl; + /* the page can be put in the TLB */ + prot = PAGE_READ; + if (!(ptep & PG_NX_MASK)) + prot |= PAGE_EXEC; + if (pte & PG_DIRTY_MASK) { + /* only set write access if already dirty... otherwise wait + for dirty access */ + if (is_user) { + if (ptep & PG_RW_MASK) + prot |= PAGE_WRITE; + } else { + if (!(env->cr[0] & CR0_WP_MASK) || + (ptep & PG_RW_MASK)) + prot |= PAGE_WRITE; + } + } + do_mapping: + pte = pte & env->a20_mask; + + /* Even if 4MB pages, we map only one 4KB page in the cache to + avoid filling it too fast */ + page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); + paddr = (pte & TARGET_PAGE_MASK) + page_offset; + vaddr = virt_addr + page_offset; + + ret = tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu); + return ret; + do_fault_protect: + error_code = PG_ERROR_P_MASK; + do_fault: + error_code |= (is_write << PG_ERROR_W_BIT); + if (is_user) + error_code |= PG_ERROR_U_MASK; + if (is_write1 == 2 && + (env->efer & MSR_EFER_NXE) && + (env->cr[4] & CR4_PAE_MASK)) + error_code |= PG_ERROR_I_D_MASK; + if (env->intercept_exceptions & (1 << EXCP0E_PAGE)) { + /* cr2 is not modified in case of exceptions */ + stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), + addr); } else { - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - new_stack = 0; /* avoid warning */ - sp_mask = 0; /* avoid warning */ - ssp = 0; /* avoid warning */ - esp = 0; /* avoid warning */ + env->cr[2] = addr; } + env->error_code = error_code; + env->exception_index = EXCP0E_PAGE; + return 1; +} + +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + target_ulong pde_addr, pte_addr; + uint64_t pte; + target_phys_addr_t paddr; + uint32_t page_offset; + int page_size; + + if (env->cr[4] & CR4_PAE_MASK) { + target_ulong pdpe_addr; + uint64_t pde, pdpe; - shift = type >> 3; +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + uint64_t pml4e_addr, pml4e; + int32_t sext; -#if 0 - /* XXX: check that enough room is available */ - push_size = 6 + (new_stack << 2) + (has_error_code << 1); - if (env->eflags & VM_MASK) - push_size += 8; - push_size <<= shift; + /* test virtual address sign extension */ + sext = (int64_t)addr >> 47; + if (sext != 0 && sext != -1) + return -1; + + pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & + env->a20_mask; + pml4e = ldq_phys(pml4e_addr); + if (!(pml4e & PG_PRESENT_MASK)) + return -1; + + pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) & + env->a20_mask; + pdpe = ldq_phys(pdpe_addr); + if (!(pdpe & PG_PRESENT_MASK)) + return -1; + } else #endif - if (shift == 1) { - if (new_stack) { - if (env->eflags & VM_MASK) { - PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector); - PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector); - PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector); - PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector); - } - PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector); - PUSHL(ssp, esp, sp_mask, ESP); - } - PUSHL(ssp, esp, sp_mask, compute_eflags()); - PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector); - PUSHL(ssp, esp, sp_mask, old_eip); - if (has_error_code) { - PUSHL(ssp, esp, sp_mask, error_code); - } - } else { - if (new_stack) { - if (env->eflags & VM_MASK) { - PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector); - PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector); - PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector); - PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector); + { + pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & + env->a20_mask; + pdpe = ldq_phys(pdpe_addr); + if (!(pdpe & PG_PRESENT_MASK)) + return -1; + } + + pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) & + env->a20_mask; + pde = ldq_phys(pde_addr); + if (!(pde & PG_PRESENT_MASK)) { + return -1; + } + if (pde & PG_PSE_MASK) { + /* 2 MB page */ + page_size = 2048 * 1024; + pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */ + } else { + /* 4 KB page */ + pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) & + env->a20_mask; + page_size = 4096; + pte = ldq_phys(pte_addr); + } + if (!(pte & PG_PRESENT_MASK)) + return -1; + } else { + uint32_t pde; + + if (!(env->cr[0] & CR0_PG_MASK)) { + pte = addr; + page_size = 4096; + } else { + /* page directory entry */ + pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & env->a20_mask; + pde = ldl_phys(pde_addr); + if (!(pde & PG_PRESENT_MASK)) + return -1; + if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + pte = pde & ~0x003ff000; /* align to 4MB */ + page_size = 4096 * 1024; + } else { + /* page directory entry */ + pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask; + pte = ldl_phys(pte_addr); + if (!(pte & PG_PRESENT_MASK)) + return -1; + page_size = 4096; } - PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector); - PUSHW(ssp, esp, sp_mask, ESP); - } - PUSHW(ssp, esp, sp_mask, compute_eflags()); - PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector); - PUSHW(ssp, esp, sp_mask, old_eip); - if (has_error_code) { - PUSHW(ssp, esp, sp_mask, error_code); - } - } - - if (new_stack) { - if (env->eflags & VM_MASK) { - cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0); - cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0); - cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0); - cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0); } - ss = (ss & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_SS, ss, - ssp, get_seg_limit(ss_e1, ss_e2), ss_e2); - } - SET_ESP(esp, sp_mask); - - selector = (selector & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_CS, selector, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), - e2); - cpu_x86_set_cpl(env, dpl); - env->eip = offset; - - /* interrupt gate clear IF mask */ - if ((type & 1) == 0) { - env->eflags &= ~IF_MASK; + pte = pte & env->a20_mask; } - env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); -} -#ifdef TARGET_X86_64 - -#define PUSHQ(sp, val)\ -{\ - sp -= 8;\ - stq_kernel(sp, (val));\ + page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); + paddr = (pte & TARGET_PAGE_MASK) + page_offset; + return paddr; } +#endif /* !CONFIG_USER_ONLY */ -#define POPQ(sp, val)\ -{\ - val = ldq_kernel(sp);\ - sp += 8;\ +#if defined(CONFIG_KVM) +static void host_cpuid(uint32_t function, uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + uint32_t vec[4]; + +#ifdef __x86_64__ + asm volatile("cpuid" + : "=a"(vec[0]), "=b"(vec[1]), + "=c"(vec[2]), "=d"(vec[3]) + : "0"(function) : "cc"); +#else + asm volatile("pusha \n\t" + "cpuid \n\t" + "mov %%eax, 0(%1) \n\t" + "mov %%ebx, 4(%1) \n\t" + "mov %%ecx, 8(%1) \n\t" + "mov %%edx, 12(%1) \n\t" + "popa" + : : "a"(function), "S"(vec) + : "memory", "cc"); +#endif + + if (eax) + *eax = vec[0]; + if (ebx) + *ebx = vec[1]; + if (ecx) + *ecx = vec[2]; + if (edx) + *edx = vec[3]; } - -static inline target_ulong get_rsp_from_tss(int level) -{ - int index; - -#if 0 - printf("TR: base=" TARGET_FMT_lx " limit=%x\n", - env->tr.base, env->tr.limit); #endif - if (!(env->tr.flags & DESC_P_MASK)) - cpu_abort(env, "invalid tss"); - index = 8 * level + 4; - if ((index + 7) > env->tr.limit) - raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); - return ldq_kernel(env->tr.base + index); -} - -/* 64 bit interrupt */ -static void do_interrupt64(int intno, int is_int, int error_code, - target_ulong next_eip, int is_hw) +void cpu_x86_cpuid(CPUX86State *env, uint32_t index, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) { - SegmentCache *dt; - target_ulong ptr; - int type, dpl, selector, cpl, ist; - int has_error_code, new_stack; - uint32_t e1, e2, e3, ss; - target_ulong old_eip, esp, offset; - int svm_should_check = 1; - - if ((env->intercept & INTERCEPT_SVM_MASK) && !is_int && next_eip==-1) { - next_eip = EIP; - svm_should_check = 0; - } - if (svm_should_check - && INTERCEPTEDl(_exceptions, 1 << intno) - && !is_int) { - raise_interrupt(intno, is_int, error_code, 0); - } - has_error_code = 0; - if (!is_int && !is_hw) { - switch(intno) { - case 8: - case 10: - case 11: - case 12: - case 13: - case 14: - case 17: - has_error_code = 1; - break; - } + /* test if maximum index reached */ + if (index & 0x80000000) { + if (index > env->cpuid_xlevel) + index = env->cpuid_level; + } else { + if (index > env->cpuid_level) + index = env->cpuid_level; } - if (is_int) - old_eip = next_eip; - else - old_eip = env->eip; - dt = &env->idt; - if (intno * 16 + 15 > dt->limit) - raise_exception_err(EXCP0D_GPF, intno * 16 + 2); - ptr = dt->base + intno * 16; - e1 = ldl_kernel(ptr); - e2 = ldl_kernel(ptr + 4); - e3 = ldl_kernel(ptr + 8); - /* check gate type */ - type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; - switch(type) { - case 14: /* 386 interrupt gate */ - case 15: /* 386 trap gate */ + switch(index) { + case 0: + *eax = env->cpuid_level; + *ebx = env->cpuid_vendor1; + *edx = env->cpuid_vendor2; + *ecx = env->cpuid_vendor3; + + /* sysenter isn't supported on compatibility mode on AMD. and syscall + * isn't supported in compatibility mode on Intel. so advertise the + * actuall cpu, and say goodbye to migration between different vendors + * is you use compatibility mode. */ + if (kvm_enabled()) + host_cpuid(0, NULL, ebx, ecx, edx); break; - default: - raise_exception_err(EXCP0D_GPF, intno * 16 + 2); + case 1: + *eax = env->cpuid_version; + *ebx = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */ + *ecx = env->cpuid_ext_features; + *edx = env->cpuid_features; + + /* "Hypervisor present" bit required for Microsoft SVVP */ + if (kvm_enabled()) + *ecx |= (1 << 31); break; - } - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->hflags & HF_CPL_MASK; - /* check privledge if software int */ - if (is_int && dpl < cpl) - raise_exception_err(EXCP0D_GPF, intno * 16 + 2); - /* check valid bit */ - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2); - selector = e1 >> 16; - offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff); - ist = e2 & 7; - if ((selector & 0xfffc) == 0) - raise_exception_err(EXCP0D_GPF, 0); - - if (load_segment(&e1, &e2, selector) != 0) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (dpl > cpl) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK)) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) { - /* to inner privilege */ - if (ist != 0) - esp = get_rsp_from_tss(ist + 3); - else - esp = get_rsp_from_tss(dpl); - esp &= ~0xfLL; /* align stack */ - ss = 0; - new_stack = 1; - } else if ((e2 & DESC_C_MASK) || dpl == cpl) { - /* to same privilege */ - if (env->eflags & VM_MASK) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - new_stack = 0; - if (ist != 0) - esp = get_rsp_from_tss(ist + 3); - else - esp = ESP; - esp &= ~0xfLL; /* align stack */ - dpl = cpl; - } else { - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - new_stack = 0; /* avoid warning */ - esp = 0; /* avoid warning */ - } - - PUSHQ(esp, env->segs[R_SS].selector); - PUSHQ(esp, ESP); - PUSHQ(esp, compute_eflags()); - PUSHQ(esp, env->segs[R_CS].selector); - PUSHQ(esp, old_eip); - if (has_error_code) { - PUSHQ(esp, error_code); - } - - if (new_stack) { - ss = 0 | dpl; - cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0); - } - ESP = esp; - - selector = (selector & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_CS, selector, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), - e2); - cpu_x86_set_cpl(env, dpl); - env->eip = offset; - - /* interrupt gate clear IF mask */ - if ((type & 1) == 0) { - env->eflags &= ~IF_MASK; - } - env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); -} -#endif - -#if defined(CONFIG_USER_ONLY) -void helper_syscall(int next_eip_addend) -{ - env->exception_index = EXCP_SYSCALL; - env->exception_next_eip = env->eip + next_eip_addend; - cpu_loop_exit(); -} -#else -void helper_syscall(int next_eip_addend) -{ - int selector; - - if (!(env->efer & MSR_EFER_SCE)) { - raise_exception_err(EXCP06_ILLOP, 0); - } - selector = (env->star >> 32) & 0xffff; -#ifdef TARGET_X86_64 - if (env->hflags & HF_LMA_MASK) { - int code64; - - ECX = env->eip + next_eip_addend; - env->regs[11] = compute_eflags(); - - code64 = env->hflags & HF_CS64_MASK; - - cpu_x86_set_cpl(env, 0); - cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, - 0, 0xffffffff, - DESC_G_MASK | DESC_P_MASK | - DESC_S_MASK | - DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); - cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | - DESC_W_MASK | DESC_A_MASK); - env->eflags &= ~env->fmask; - if (code64) - env->eip = env->lstar; - else - env->eip = env->cstar; - } else -#endif - { - ECX = (uint32_t)(env->eip + next_eip_addend); - - cpu_x86_set_cpl(env, 0); - cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | - DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); - cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | - DESC_W_MASK | DESC_A_MASK); - env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK); - env->eip = (uint32_t)env->star; - } -} -#endif - -void helper_sysret(int dflag) -{ - int cpl, selector; - - if (!(env->efer & MSR_EFER_SCE)) { - raise_exception_err(EXCP06_ILLOP, 0); - } - cpl = env->hflags & HF_CPL_MASK; - if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) { - raise_exception_err(EXCP0D_GPF, 0); - } - selector = (env->star >> 48) & 0xffff; -#ifdef TARGET_X86_64 - if (env->hflags & HF_LMA_MASK) { - if (dflag == 2) { - cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, - 0, 0xffffffff, - DESC_G_MASK | DESC_P_MASK | - DESC_S_MASK | (3 << DESC_DPL_SHIFT) | - DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | - DESC_L_MASK); - env->eip = ECX; - } else { - cpu_x86_load_seg_cache(env, R_CS, selector | 3, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | (3 << DESC_DPL_SHIFT) | - DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); - env->eip = (uint32_t)ECX; - } - cpu_x86_load_seg_cache(env, R_SS, selector + 8, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | (3 << DESC_DPL_SHIFT) | - DESC_W_MASK | DESC_A_MASK); - load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK | - IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK); - cpu_x86_set_cpl(env, 3); - } else -#endif - { - cpu_x86_load_seg_cache(env, R_CS, selector | 3, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | (3 << DESC_DPL_SHIFT) | - DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); - env->eip = (uint32_t)ECX; - cpu_x86_load_seg_cache(env, R_SS, selector + 8, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | (3 << DESC_DPL_SHIFT) | - DESC_W_MASK | DESC_A_MASK); - env->eflags |= IF_MASK; - cpu_x86_set_cpl(env, 3); - } -#ifdef USE_KQEMU - if (kqemu_is_ok(env)) { - if (env->hflags & HF_LMA_MASK) - CC_OP = CC_OP_EFLAGS; - env->exception_index = -1; - cpu_loop_exit(); - } -#endif -} - -/* real mode interrupt */ -static void do_interrupt_real(int intno, int is_int, int error_code, - unsigned int next_eip) -{ - SegmentCache *dt; - target_ulong ptr, ssp; - int selector; - uint32_t offset, esp; - uint32_t old_cs, old_eip; - int svm_should_check = 1; - - if ((env->intercept & INTERCEPT_SVM_MASK) && !is_int && next_eip==-1) { - next_eip = EIP; - svm_should_check = 0; - } - if (svm_should_check - && INTERCEPTEDl(_exceptions, 1 << intno) - && !is_int) { - raise_interrupt(intno, is_int, error_code, 0); - } - /* real mode (simpler !) */ - dt = &env->idt; - if (intno * 4 + 3 > dt->limit) - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); - ptr = dt->base + intno * 4; - offset = lduw_kernel(ptr); - selector = lduw_kernel(ptr + 2); - esp = ESP; - ssp = env->segs[R_SS].base; - if (is_int) - old_eip = next_eip; - else - old_eip = env->eip; - old_cs = env->segs[R_CS].selector; - /* XXX: use SS segment size ? */ - PUSHW(ssp, esp, 0xffff, compute_eflags()); - PUSHW(ssp, esp, 0xffff, old_cs); - PUSHW(ssp, esp, 0xffff, old_eip); - - /* update processor state */ - ESP = (ESP & ~0xffff) | (esp & 0xffff); - env->eip = offset; - env->segs[R_CS].selector = selector; - env->segs[R_CS].base = (selector << 4); - env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK); -} - -/* fake user mode interrupt */ -void do_interrupt_user(int intno, int is_int, int error_code, - target_ulong next_eip) -{ - SegmentCache *dt; - target_ulong ptr; - int dpl, cpl, shift; - uint32_t e2; - - dt = &env->idt; - if (env->hflags & HF_LMA_MASK) { - shift = 4; - } else { - shift = 3; - } - ptr = dt->base + (intno << shift); - e2 = ldl_kernel(ptr + 4); - - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->hflags & HF_CPL_MASK; - /* check privledge if software int */ - if (is_int && dpl < cpl) - raise_exception_err(EXCP0D_GPF, (intno << shift) + 2); - - /* Since we emulate only user space, we cannot do more than - exiting the emulation with the suitable exception and error - code */ - if (is_int) - EIP = next_eip; -} - -/* - * Begin execution of an interruption. is_int is TRUE if coming from - * the int instruction. next_eip is the EIP value AFTER the interrupt - * instruction. It is only relevant if is_int is TRUE. - */ -void do_interrupt(int intno, int is_int, int error_code, - target_ulong next_eip, int is_hw) -{ - if (loglevel & CPU_LOG_INT) { - if ((env->cr[0] & CR0_PE_MASK)) { - static int count; - fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx, - count, intno, error_code, is_int, - env->hflags & HF_CPL_MASK, - env->segs[R_CS].selector, EIP, - (int)env->segs[R_CS].base + EIP, - env->segs[R_SS].selector, ESP); - if (intno == 0x0e) { - fprintf(logfile, " CR2=" TARGET_FMT_lx, env->cr[2]); - } else { - fprintf(logfile, " EAX=" TARGET_FMT_lx, EAX); - } - fprintf(logfile, "\n"); - cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); -#if 0 - { - int i; - uint8_t *ptr; - fprintf(logfile, " code="); - ptr = env->segs[R_CS].base + env->eip; - for(i = 0; i < 16; i++) { - fprintf(logfile, " %02x", ldub(ptr + i)); - } - fprintf(logfile, "\n"); - } -#endif - count++; - } - } - if (env->cr[0] & CR0_PE_MASK) { -#if TARGET_X86_64 - if (env->hflags & HF_LMA_MASK) { - do_interrupt64(intno, is_int, error_code, next_eip, is_hw); - } else -#endif - { - do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw); + case 2: + /* cache info: needed for Pentium Pro compatibility */ + *eax = 1; + *ebx = 0; + *ecx = 0; + *edx = 0x2c307d; + break; + case 4: + /* cache info: needed for Core compatibility */ + switch (*ecx) { + case 0: /* L1 dcache info */ + *eax = 0x0000121; + *ebx = 0x1c0003f; + *ecx = 0x000003f; + *edx = 0x0000001; + break; + case 1: /* L1 icache info */ + *eax = 0x0000122; + *ebx = 0x1c0003f; + *ecx = 0x000003f; + *edx = 0x0000001; + break; + case 2: /* L2 cache info */ + *eax = 0x0000143; + *ebx = 0x3c0003f; + *ecx = 0x0000fff; + *edx = 0x0000001; + break; + default: /* end of info */ + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; + break; } - } else { - do_interrupt_real(intno, is_int, error_code, next_eip); - } -} - -/* - * Check nested exceptions and change to double or triple fault if - * needed. It should only be called, if this is not an interrupt. - * Returns the new exception number. - */ -static int check_exception(int intno, int *error_code) -{ - char first_contributory = env->old_exception == 0 || - (env->old_exception >= 10 && - env->old_exception <= 13); - char second_contributory = intno == 0 || - (intno >= 10 && intno <= 13); - - if (loglevel & CPU_LOG_INT) - fprintf(logfile, "check_exception old: %x new %x\n", - env->old_exception, intno); - - if (env->old_exception == EXCP08_DBLE) - cpu_abort(env, "triple fault"); - - if ((first_contributory && second_contributory) - || (env->old_exception == EXCP0E_PAGE && - (second_contributory || (intno == EXCP0E_PAGE)))) { - intno = EXCP08_DBLE; - *error_code = 0; - } - - if (second_contributory || (intno == EXCP0E_PAGE) || - (intno == EXCP08_DBLE)) - env->old_exception = intno; - - return intno; -} - -/* - * Signal an interruption. It is executed in the main CPU loop. - * is_int is TRUE if coming from the int instruction. next_eip is the - * EIP value AFTER the interrupt instruction. It is only relevant if - * is_int is TRUE. - */ -void raise_interrupt(int intno, int is_int, int error_code, - int next_eip_addend) -{ - if (!is_int) { - svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code); - intno = check_exception(intno, &error_code); - } - - env->exception_index = intno; - env->error_code = error_code; - env->exception_is_int = is_int; - env->exception_next_eip = env->eip + next_eip_addend; - cpu_loop_exit(); -} - -/* same as raise_exception_err, but do not restore global registers */ -static void raise_exception_err_norestore(int exception_index, int error_code) -{ - exception_index = check_exception(exception_index, &error_code); - - env->exception_index = exception_index; - env->error_code = error_code; - env->exception_is_int = 0; - env->exception_next_eip = 0; - longjmp(env->jmp_env, 1); -} - -/* shortcuts to generate exceptions */ - -void (raise_exception_err)(int exception_index, int error_code) -{ - raise_interrupt(exception_index, 0, error_code, 0); -} - -void raise_exception(int exception_index) -{ - raise_interrupt(exception_index, 0, 0, 0); -} - -/* SMM support */ - -#if defined(CONFIG_USER_ONLY) - -void do_smm_enter(void) -{ -} - -void helper_rsm(void) -{ -} - -#else - -#ifdef TARGET_X86_64 -#define SMM_REVISION_ID 0x00020064 -#else -#define SMM_REVISION_ID 0x00020000 -#endif -void do_smm_enter(void) -{ - target_ulong sm_state; - SegmentCache *dt; - int i, offset; - - if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "SMM: enter\n"); - cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); - } - - env->hflags |= HF_SMM_MASK; - cpu_smm_update(env); - - sm_state = env->smbase + 0x8000; - -#ifdef TARGET_X86_64 - for(i = 0; i < 6; i++) { - dt = &env->segs[i]; - offset = 0x7e00 + i * 16; - stw_phys(sm_state + offset, dt->selector); - stw_phys(sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff); - stl_phys(sm_state + offset + 4, dt->limit); - stq_phys(sm_state + offset + 8, dt->base); - } - - stq_phys(sm_state + 0x7e68, env->gdt.base); - stl_phys(sm_state + 0x7e64, env->gdt.limit); - - stw_phys(sm_state + 0x7e70, env->ldt.selector); - stq_phys(sm_state + 0x7e78, env->ldt.base); - stl_phys(sm_state + 0x7e74, env->ldt.limit); - stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff); - - stq_phys(sm_state + 0x7e88, env->idt.base); - stl_phys(sm_state + 0x7e84, env->idt.limit); - - stw_phys(sm_state + 0x7e90, env->tr.selector); - stq_phys(sm_state + 0x7e98, env->tr.base); - stl_phys(sm_state + 0x7e94, env->tr.limit); - stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff); - - stq_phys(sm_state + 0x7ed0, env->efer); - - stq_phys(sm_state + 0x7ff8, EAX); - stq_phys(sm_state + 0x7ff0, ECX); - stq_phys(sm_state + 0x7fe8, EDX); - stq_phys(sm_state + 0x7fe0, EBX); - stq_phys(sm_state + 0x7fd8, ESP); - stq_phys(sm_state + 0x7fd0, EBP); - stq_phys(sm_state + 0x7fc8, ESI); - stq_phys(sm_state + 0x7fc0, EDI); - for(i = 8; i < 16; i++) - stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]); - stq_phys(sm_state + 0x7f78, env->eip); - stl_phys(sm_state + 0x7f70, compute_eflags()); - stl_phys(sm_state + 0x7f68, env->dr[6]); - stl_phys(sm_state + 0x7f60, env->dr[7]); - - stl_phys(sm_state + 0x7f48, env->cr[4]); - stl_phys(sm_state + 0x7f50, env->cr[3]); - stl_phys(sm_state + 0x7f58, env->cr[0]); - - stl_phys(sm_state + 0x7efc, SMM_REVISION_ID); - stl_phys(sm_state + 0x7f00, env->smbase); -#else - stl_phys(sm_state + 0x7ffc, env->cr[0]); - stl_phys(sm_state + 0x7ff8, env->cr[3]); - stl_phys(sm_state + 0x7ff4, compute_eflags()); - stl_phys(sm_state + 0x7ff0, env->eip); - stl_phys(sm_state + 0x7fec, EDI); - stl_phys(sm_state + 0x7fe8, ESI); - stl_phys(sm_state + 0x7fe4, EBP); - stl_phys(sm_state + 0x7fe0, ESP); - stl_phys(sm_state + 0x7fdc, EBX); - stl_phys(sm_state + 0x7fd8, EDX); - stl_phys(sm_state + 0x7fd4, ECX); - stl_phys(sm_state + 0x7fd0, EAX); - stl_phys(sm_state + 0x7fcc, env->dr[6]); - stl_phys(sm_state + 0x7fc8, env->dr[7]); - - stl_phys(sm_state + 0x7fc4, env->tr.selector); - stl_phys(sm_state + 0x7f64, env->tr.base); - stl_phys(sm_state + 0x7f60, env->tr.limit); - stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff); - - stl_phys(sm_state + 0x7fc0, env->ldt.selector); - stl_phys(sm_state + 0x7f80, env->ldt.base); - stl_phys(sm_state + 0x7f7c, env->ldt.limit); - stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff); - - stl_phys(sm_state + 0x7f74, env->gdt.base); - stl_phys(sm_state + 0x7f70, env->gdt.limit); - - stl_phys(sm_state + 0x7f58, env->idt.base); - stl_phys(sm_state + 0x7f54, env->idt.limit); - - for(i = 0; i < 6; i++) { - dt = &env->segs[i]; - if (i < 3) - offset = 0x7f84 + i * 12; - else - offset = 0x7f2c + (i - 3) * 12; - stl_phys(sm_state + 0x7fa8 + i * 4, dt->selector); - stl_phys(sm_state + offset + 8, dt->base); - stl_phys(sm_state + offset + 4, dt->limit); - stl_phys(sm_state + offset, (dt->flags >> 8) & 0xf0ff); - } - stl_phys(sm_state + 0x7f14, env->cr[4]); - - stl_phys(sm_state + 0x7efc, SMM_REVISION_ID); - stl_phys(sm_state + 0x7ef8, env->smbase); -#endif - /* init SMM cpu state */ - -#ifdef TARGET_X86_64 - env->efer = 0; - env->hflags &= ~HF_LMA_MASK; -#endif - load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); - env->eip = 0x00008000; - cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase, - 0xffffffff, 0); - cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, 0); - cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffffffff, 0); - cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0); - cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0); - cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0); - - cpu_x86_update_cr0(env, - env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK)); - cpu_x86_update_cr4(env, 0); - env->dr[7] = 0x00000400; - CC_OP = CC_OP_EFLAGS; -} - -void helper_rsm(void) -{ - target_ulong sm_state; - int i, offset; - uint32_t val; - - sm_state = env->smbase + 0x8000; -#ifdef TARGET_X86_64 - env->efer = ldq_phys(sm_state + 0x7ed0); - if (env->efer & MSR_EFER_LMA) - env->hflags |= HF_LMA_MASK; - else - env->hflags &= ~HF_LMA_MASK; - - for(i = 0; i < 6; i++) { - offset = 0x7e00 + i * 16; - cpu_x86_load_seg_cache(env, i, - lduw_phys(sm_state + offset), - ldq_phys(sm_state + offset + 8), - ldl_phys(sm_state + offset + 4), - (lduw_phys(sm_state + offset + 2) & 0xf0ff) << 8); - } - - env->gdt.base = ldq_phys(sm_state + 0x7e68); - env->gdt.limit = ldl_phys(sm_state + 0x7e64); - - env->ldt.selector = lduw_phys(sm_state + 0x7e70); - env->ldt.base = ldq_phys(sm_state + 0x7e78); - env->ldt.limit = ldl_phys(sm_state + 0x7e74); - env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8; - - env->idt.base = ldq_phys(sm_state + 0x7e88); - env->idt.limit = ldl_phys(sm_state + 0x7e84); - - env->tr.selector = lduw_phys(sm_state + 0x7e90); - env->tr.base = ldq_phys(sm_state + 0x7e98); - env->tr.limit = ldl_phys(sm_state + 0x7e94); - env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8; - - EAX = ldq_phys(sm_state + 0x7ff8); - ECX = ldq_phys(sm_state + 0x7ff0); - EDX = ldq_phys(sm_state + 0x7fe8); - EBX = ldq_phys(sm_state + 0x7fe0); - ESP = ldq_phys(sm_state + 0x7fd8); - EBP = ldq_phys(sm_state + 0x7fd0); - ESI = ldq_phys(sm_state + 0x7fc8); - EDI = ldq_phys(sm_state + 0x7fc0); - for(i = 8; i < 16; i++) - env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8); - env->eip = ldq_phys(sm_state + 0x7f78); - load_eflags(ldl_phys(sm_state + 0x7f70), - ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); - env->dr[6] = ldl_phys(sm_state + 0x7f68); - env->dr[7] = ldl_phys(sm_state + 0x7f60); - - cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f48)); - cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7f50)); - cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7f58)); - - val = ldl_phys(sm_state + 0x7efc); /* revision ID */ - if (val & 0x20000) { - env->smbase = ldl_phys(sm_state + 0x7f00) & ~0x7fff; - } -#else - cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc)); - cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8)); - load_eflags(ldl_phys(sm_state + 0x7ff4), - ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); - env->eip = ldl_phys(sm_state + 0x7ff0); - EDI = ldl_phys(sm_state + 0x7fec); - ESI = ldl_phys(sm_state + 0x7fe8); - EBP = ldl_phys(sm_state + 0x7fe4); - ESP = ldl_phys(sm_state + 0x7fe0); - EBX = ldl_phys(sm_state + 0x7fdc); - EDX = ldl_phys(sm_state + 0x7fd8); - ECX = ldl_phys(sm_state + 0x7fd4); - EAX = ldl_phys(sm_state + 0x7fd0); - env->dr[6] = ldl_phys(sm_state + 0x7fcc); - env->dr[7] = ldl_phys(sm_state + 0x7fc8); - - env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff; - env->tr.base = ldl_phys(sm_state + 0x7f64); - env->tr.limit = ldl_phys(sm_state + 0x7f60); - env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8; - - env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff; - env->ldt.base = ldl_phys(sm_state + 0x7f80); - env->ldt.limit = ldl_phys(sm_state + 0x7f7c); - env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8; - - env->gdt.base = ldl_phys(sm_state + 0x7f74); - env->gdt.limit = ldl_phys(sm_state + 0x7f70); - - env->idt.base = ldl_phys(sm_state + 0x7f58); - env->idt.limit = ldl_phys(sm_state + 0x7f54); - - for(i = 0; i < 6; i++) { - if (i < 3) - offset = 0x7f84 + i * 12; - else - offset = 0x7f2c + (i - 3) * 12; - cpu_x86_load_seg_cache(env, i, - ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff, - ldl_phys(sm_state + offset + 8), - ldl_phys(sm_state + offset + 4), - (ldl_phys(sm_state + offset) & 0xf0ff) << 8); - } - cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f14)); - - val = ldl_phys(sm_state + 0x7efc); /* revision ID */ - if (val & 0x20000) { - env->smbase = ldl_phys(sm_state + 0x7ef8) & ~0x7fff; - } -#endif - CC_OP = CC_OP_EFLAGS; - env->hflags &= ~HF_SMM_MASK; - cpu_smm_update(env); - - if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "SMM: after RSM\n"); - cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); - } -} - -#endif /* !CONFIG_USER_ONLY */ - - -#ifdef BUGGY_GCC_DIV64 -/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we - call it from another function */ -uint32_t div32(uint64_t *q_ptr, uint64_t num, uint32_t den) -{ - *q_ptr = num / den; - return num % den; -} - -int32_t idiv32(int64_t *q_ptr, int64_t num, int32_t den) -{ - *q_ptr = num / den; - return num % den; -} -#endif - -void helper_divl_EAX_T0(void) -{ - unsigned int den, r; - uint64_t num, q; - - num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); - den = T0; - if (den == 0) { - raise_exception(EXCP00_DIVZ); - } -#ifdef BUGGY_GCC_DIV64 - r = div32(&q, num, den); -#else - q = (num / den); - r = (num % den); -#endif - if (q > 0xffffffff) - raise_exception(EXCP00_DIVZ); - EAX = (uint32_t)q; - EDX = (uint32_t)r; -} - -void helper_idivl_EAX_T0(void) -{ - int den, r; - int64_t num, q; - - num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); - den = T0; - if (den == 0) { - raise_exception(EXCP00_DIVZ); - } -#ifdef BUGGY_GCC_DIV64 - r = idiv32(&q, num, den); -#else - q = (num / den); - r = (num % den); -#endif - if (q != (int32_t)q) - raise_exception(EXCP00_DIVZ); - EAX = (uint32_t)q; - EDX = (uint32_t)r; -} - -void helper_cmpxchg8b(void) -{ - uint64_t d; - int eflags; - - eflags = cc_table[CC_OP].compute_all(); - d = ldq(A0); - if (d == (((uint64_t)EDX << 32) | EAX)) { - stq(A0, ((uint64_t)ECX << 32) | EBX); - eflags |= CC_Z; - } else { - EDX = d >> 32; - EAX = d; - eflags &= ~CC_Z; - } - CC_SRC = eflags; -} - -void helper_single_step() -{ - env->dr[6] |= 0x4000; - raise_exception(EXCP01_SSTP); -} - -void helper_cpuid(void) -{ - uint32_t index; - index = (uint32_t)EAX; - - /* test if maximum index reached */ - if (index & 0x80000000) { - if (index > env->cpuid_xlevel) - index = env->cpuid_level; - } else { - if (index > env->cpuid_level) - index = env->cpuid_level; - } - - switch(index) { - case 0: - EAX = env->cpuid_level; - EBX = env->cpuid_vendor1; - EDX = env->cpuid_vendor2; - ECX = env->cpuid_vendor3; - break; - case 1: - EAX = env->cpuid_version; - EBX = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */ - ECX = env->cpuid_ext_features; - EDX = env->cpuid_features; break; - case 2: - /* cache info: needed for Pentium Pro compatibility */ - EAX = 1; - EBX = 0; - ECX = 0; - EDX = 0x2c307d; + case 5: + /* mwait info: needed for Core compatibility */ + *eax = 0; /* Smallest monitor-line size in bytes */ + *ebx = 0; /* Largest monitor-line size in bytes */ + *ecx = CPUID_MWAIT_EMX | CPUID_MWAIT_IBE; + *edx = 0; + break; + case 6: + /* Thermal and Power Leaf */ + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; + break; + case 9: + /* Direct Cache Access Information Leaf */ + *eax = 0; /* Bits 0-31 in DCA_CAP MSR */ + *ebx = 0; + *ecx = 0; + *edx = 0; + break; + case 0xA: + /* Architectural Performance Monitoring Leaf */ + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; break; case 0x80000000: - EAX = env->cpuid_xlevel; - EBX = env->cpuid_vendor1; - EDX = env->cpuid_vendor2; - ECX = env->cpuid_vendor3; + *eax = env->cpuid_xlevel; + *ebx = env->cpuid_vendor1; + *edx = env->cpuid_vendor2; + *ecx = env->cpuid_vendor3; break; case 0x80000001: - EAX = env->cpuid_features; - EBX = 0; - ECX = env->cpuid_ext3_features; - EDX = env->cpuid_ext2_features; + *eax = env->cpuid_features; + *ebx = 0; + *ecx = env->cpuid_ext3_features; + *edx = env->cpuid_ext2_features; + + if (kvm_enabled()) { + uint32_t h_eax, h_edx; + + host_cpuid(0x80000001, &h_eax, NULL, NULL, &h_edx); + + /* disable CPU features that the host does not support */ + + /* long mode */ + if ((h_edx & 0x20000000) == 0 /* || !lm_capable_kernel */) + *edx &= ~0x20000000; + /* syscall */ + if ((h_edx & 0x00000800) == 0) + *edx &= ~0x00000800; + /* nx */ + if ((h_edx & 0x00100000) == 0) + *edx &= ~0x00100000; + + /* disable CPU features that KVM cannot support */ + + /* svm */ + *ecx &= ~4UL; + /* 3dnow */ + *edx = ~0xc0000000; + } break; case 0x80000002: case 0x80000003: case 0x80000004: - EAX = env->cpuid_model[(index - 0x80000002) * 4 + 0]; - EBX = env->cpuid_model[(index - 0x80000002) * 4 + 1]; - ECX = env->cpuid_model[(index - 0x80000002) * 4 + 2]; - EDX = env->cpuid_model[(index - 0x80000002) * 4 + 3]; + *eax = env->cpuid_model[(index - 0x80000002) * 4 + 0]; + *ebx = env->cpuid_model[(index - 0x80000002) * 4 + 1]; + *ecx = env->cpuid_model[(index - 0x80000002) * 4 + 2]; + *edx = env->cpuid_model[(index - 0x80000002) * 4 + 3]; break; case 0x80000005: /* cache info (L1 cache) */ - EAX = 0x01ff01ff; - EBX = 0x01ff01ff; - ECX = 0x40020140; - EDX = 0x40020140; + *eax = 0x01ff01ff; + *ebx = 0x01ff01ff; + *ecx = 0x40020140; + *edx = 0x40020140; break; case 0x80000006: /* cache info (L2 cache) */ - EAX = 0; - EBX = 0x42004200; - ECX = 0x02008140; - EDX = 0; + *eax = 0; + *ebx = 0x42004200; + *ecx = 0x02008140; + *edx = 0; break; case 0x80000008: /* virtual & phys address size in low 2 bytes. */ - EAX = 0x00003028; - EBX = 0; - ECX = 0; - EDX = 0; +/* XXX: This value must match the one used in the MMU code. */ + if (env->cpuid_ext2_features & CPUID_EXT2_LM) { + /* 64 bit processor */ +#if defined(USE_KQEMU) + *eax = 0x00003020; /* 48 bits virtual, 32 bits physical */ +#else +/* XXX: The physical address space is limited to 42 bits in exec.c. */ + *eax = 0x00003028; /* 48 bits virtual, 40 bits physical */ +#endif + } else { +#if defined(USE_KQEMU) + *eax = 0x00000020; /* 32 bits physical */ +#else + if (env->cpuid_features & CPUID_PSE36) + *eax = 0x00000024; /* 36 bits physical */ + else + *eax = 0x00000020; /* 32 bits physical */ +#endif + } + *ebx = 0; + *ecx = 0; + *edx = 0; break; case 0x8000000A: - EAX = 0x00000001; - EBX = 0; - ECX = 0; - EDX = 0; + *eax = 0x00000001; /* SVM Revision */ + *ebx = 0x00000010; /* nr of ASIDs */ + *ecx = 0; + *edx = 0; /* optional features */ break; default: /* reserved values: zero */ - EAX = 0; - EBX = 0; - ECX = 0; - EDX = 0; + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; break; } } - -void helper_enter_level(int level, int data32) -{ - target_ulong ssp; - uint32_t esp_mask, esp, ebp; - - esp_mask = get_sp_mask(env->segs[R_SS].flags); - ssp = env->segs[R_SS].base; - ebp = EBP; - esp = ESP; - if (data32) { - /* 32 bit */ - esp -= 4; - while (--level) { - esp -= 4; - ebp -= 4; - stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask))); - } - esp -= 4; - stl(ssp + (esp & esp_mask), T1); - } else { - /* 16 bit */ - esp -= 2; - while (--level) { - esp -= 2; - ebp -= 2; - stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask))); - } - esp -= 2; - stw(ssp + (esp & esp_mask), T1); - } -} - -#ifdef TARGET_X86_64 -void helper_enter64_level(int level, int data64) -{ - target_ulong esp, ebp; - ebp = EBP; - esp = ESP; - - if (data64) { - /* 64 bit */ - esp -= 8; - while (--level) { - esp -= 8; - ebp -= 8; - stq(esp, ldq(ebp)); - } - esp -= 8; - stq(esp, T1); - } else { - /* 16 bit */ - esp -= 2; - while (--level) { - esp -= 2; - ebp -= 2; - stw(esp, lduw(ebp)); - } - esp -= 2; - stw(esp, T1); - } -} -#endif - -void helper_lldt_T0(void) -{ - int selector; - SegmentCache *dt; - uint32_t e1, e2; - int index, entry_limit; - target_ulong ptr; - - selector = T0 & 0xffff; - if ((selector & 0xfffc) == 0) { - /* XXX: NULL selector case: invalid LDT */ - env->ldt.base = 0; - env->ldt.limit = 0; - } else { - if (selector & 0x4) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - dt = &env->gdt; - index = selector & ~7; -#ifdef TARGET_X86_64 - if (env->hflags & HF_LMA_MASK) - entry_limit = 15; - else -#endif - entry_limit = 7; - if ((index + entry_limit) > dt->limit) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - ptr = dt->base + index; - e1 = ldl_kernel(ptr); - e2 = ldl_kernel(ptr + 4); - if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); -#ifdef TARGET_X86_64 - if (env->hflags & HF_LMA_MASK) { - uint32_t e3; - e3 = ldl_kernel(ptr + 8); - load_seg_cache_raw_dt(&env->ldt, e1, e2); - env->ldt.base |= (target_ulong)e3 << 32; - } else -#endif - { - load_seg_cache_raw_dt(&env->ldt, e1, e2); - } - } - env->ldt.selector = selector; -} - -void helper_ltr_T0(void) -{ - int selector; - SegmentCache *dt; - uint32_t e1, e2; - int index, type, entry_limit; - target_ulong ptr; - - selector = T0 & 0xffff; - if ((selector & 0xfffc) == 0) { - /* NULL selector case: invalid TR */ - env->tr.base = 0; - env->tr.limit = 0; - env->tr.flags = 0; - } else { - if (selector & 0x4) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - dt = &env->gdt; - index = selector & ~7; -#ifdef TARGET_X86_64 - if (env->hflags & HF_LMA_MASK) - entry_limit = 15; - else -#endif - entry_limit = 7; - if ((index + entry_limit) > dt->limit) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - ptr = dt->base + index; - e1 = ldl_kernel(ptr); - e2 = ldl_kernel(ptr + 4); - type = (e2 >> DESC_TYPE_SHIFT) & 0xf; - if ((e2 & DESC_S_MASK) || - (type != 1 && type != 9)) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); -#ifdef TARGET_X86_64 - if (env->hflags & HF_LMA_MASK) { - uint32_t e3, e4; - e3 = ldl_kernel(ptr + 8); - e4 = ldl_kernel(ptr + 12); - if ((e4 >> DESC_TYPE_SHIFT) & 0xf) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - load_seg_cache_raw_dt(&env->tr, e1, e2); - env->tr.base |= (target_ulong)e3 << 32; - } else -#endif - { - load_seg_cache_raw_dt(&env->tr, e1, e2); - } - e2 |= DESC_TSS_BUSY_MASK; - stl_kernel(ptr + 4, e2); - } - env->tr.selector = selector; -} - -/* only works if protected mode and not VM86. seg_reg must be != R_CS */ -void load_seg(int seg_reg, int selector) -{ - uint32_t e1, e2; - int cpl, dpl, rpl; - SegmentCache *dt; - int index; - target_ulong ptr; - - selector &= 0xffff; - cpl = env->hflags & HF_CPL_MASK; - if ((selector & 0xfffc) == 0) { - /* null selector case */ - if (seg_reg == R_SS -#ifdef TARGET_X86_64 - && (!(env->hflags & HF_CS64_MASK) || cpl == 3) -#endif - ) - raise_exception_err(EXCP0D_GPF, 0); - cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0); - } else { - - if (selector & 0x4) - dt = &env->ldt; - else - dt = &env->gdt; - index = selector & ~7; - if ((index + 7) > dt->limit) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - ptr = dt->base + index; - e1 = ldl_kernel(ptr); - e2 = ldl_kernel(ptr + 4); - - if (!(e2 & DESC_S_MASK)) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - rpl = selector & 3; - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (seg_reg == R_SS) { - /* must be writable segment */ - if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (rpl != cpl || dpl != cpl) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } else { - /* must be readable segment */ - if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - - if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { - /* if not conforming code, test rights */ - if (dpl < cpl || dpl < rpl) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } - } - - if (!(e2 & DESC_P_MASK)) { - if (seg_reg == R_SS) - raise_exception_err(EXCP0C_STACK, selector & 0xfffc); - else - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - } - - /* set the access bit if not already set */ - if (!(e2 & DESC_A_MASK)) { - e2 |= DESC_A_MASK; - stl_kernel(ptr + 4, e2); - } - - cpu_x86_load_seg_cache(env, seg_reg, selector, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), - e2); -#if 0 - fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", - selector, (unsigned long)sc->base, sc->limit, sc->flags); -#endif - } -} - -/* protected mode jump */ -void helper_ljmp_protected_T0_T1(int next_eip_addend) -{ - int new_cs, gate_cs, type; - uint32_t e1, e2, cpl, dpl, rpl, limit; - target_ulong new_eip, next_eip; - - new_cs = T0; - new_eip = T1; - if ((new_cs & 0xfffc) == 0) - raise_exception_err(EXCP0D_GPF, 0); - if (load_segment(&e1, &e2, new_cs) != 0) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - cpl = env->hflags & HF_CPL_MASK; - if (e2 & DESC_S_MASK) { - if (!(e2 & DESC_CS_MASK)) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (e2 & DESC_C_MASK) { - /* conforming code segment */ - if (dpl > cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - } else { - /* non conforming code segment */ - rpl = new_cs & 3; - if (rpl > cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - if (dpl != cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - } - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); - limit = get_seg_limit(e1, e2); - if (new_eip > limit && - !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK)) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, - get_seg_base(e1, e2), limit, e2); - EIP = new_eip; - } else { - /* jump to call or task gate */ - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - rpl = new_cs & 3; - cpl = env->hflags & HF_CPL_MASK; - type = (e2 >> DESC_TYPE_SHIFT) & 0xf; - switch(type) { - case 1: /* 286 TSS */ - case 9: /* 386 TSS */ - case 5: /* task gate */ - if (dpl < cpl || dpl < rpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - next_eip = env->eip + next_eip_addend; - switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip); - CC_OP = CC_OP_EFLAGS; - break; - case 4: /* 286 call gate */ - case 12: /* 386 call gate */ - if ((dpl < cpl) || (dpl < rpl)) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); - gate_cs = e1 >> 16; - new_eip = (e1 & 0xffff); - if (type == 12) - new_eip |= (e2 & 0xffff0000); - if (load_segment(&e1, &e2, gate_cs) != 0) - raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - /* must be code segment */ - if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) != - (DESC_S_MASK | DESC_CS_MASK))) - raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); - if (((e2 & DESC_C_MASK) && (dpl > cpl)) || - (!(e2 & DESC_C_MASK) && (dpl != cpl))) - raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); - limit = get_seg_limit(e1, e2); - if (new_eip > limit) - raise_exception_err(EXCP0D_GPF, 0); - cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl, - get_seg_base(e1, e2), limit, e2); - EIP = new_eip; - break; - default: - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - break; - } - } -} - -/* real mode call */ -void helper_lcall_real_T0_T1(int shift, int next_eip) -{ - int new_cs, new_eip; - uint32_t esp, esp_mask; - target_ulong ssp; - - new_cs = T0; - new_eip = T1; - esp = ESP; - esp_mask = get_sp_mask(env->segs[R_SS].flags); - ssp = env->segs[R_SS].base; - if (shift) { - PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector); - PUSHL(ssp, esp, esp_mask, next_eip); - } else { - PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector); - PUSHW(ssp, esp, esp_mask, next_eip); - } - - SET_ESP(esp, esp_mask); - env->eip = new_eip; - env->segs[R_CS].selector = new_cs; - env->segs[R_CS].base = (new_cs << 4); -} - -/* protected mode call */ -void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) -{ - int new_cs, new_stack, i; - uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; - uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask; - uint32_t val, limit, old_sp_mask; - target_ulong ssp, old_ssp, next_eip, new_eip; - - new_cs = T0; - new_eip = T1; - next_eip = env->eip + next_eip_addend; -#ifdef DEBUG_PCALL - if (loglevel & CPU_LOG_PCALL) { - fprintf(logfile, "lcall %04x:%08x s=%d\n", - new_cs, (uint32_t)new_eip, shift); - cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); - } -#endif - if ((new_cs & 0xfffc) == 0) - raise_exception_err(EXCP0D_GPF, 0); - if (load_segment(&e1, &e2, new_cs) != 0) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - cpl = env->hflags & HF_CPL_MASK; -#ifdef DEBUG_PCALL - if (loglevel & CPU_LOG_PCALL) { - fprintf(logfile, "desc=%08x:%08x\n", e1, e2); - } -#endif - if (e2 & DESC_S_MASK) { - if (!(e2 & DESC_CS_MASK)) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (e2 & DESC_C_MASK) { - /* conforming code segment */ - if (dpl > cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - } else { - /* non conforming code segment */ - rpl = new_cs & 3; - if (rpl > cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - if (dpl != cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - } - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); - -#ifdef TARGET_X86_64 - /* XXX: check 16/32 bit cases in long mode */ - if (shift == 2) { - target_ulong rsp; - /* 64 bit case */ - rsp = ESP; - PUSHQ(rsp, env->segs[R_CS].selector); - PUSHQ(rsp, next_eip); - /* from this point, not restartable */ - ESP = rsp; - cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), e2); - EIP = new_eip; - } else -#endif - { - sp = ESP; - sp_mask = get_sp_mask(env->segs[R_SS].flags); - ssp = env->segs[R_SS].base; - if (shift) { - PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); - PUSHL(ssp, sp, sp_mask, next_eip); - } else { - PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); - PUSHW(ssp, sp, sp_mask, next_eip); - } - - limit = get_seg_limit(e1, e2); - if (new_eip > limit) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - /* from this point, not restartable */ - SET_ESP(sp, sp_mask); - cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, - get_seg_base(e1, e2), limit, e2); - EIP = new_eip; - } - } else { - /* check gate type */ - type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - rpl = new_cs & 3; - switch(type) { - case 1: /* available 286 TSS */ - case 9: /* available 386 TSS */ - case 5: /* task gate */ - if (dpl < cpl || dpl < rpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip); - CC_OP = CC_OP_EFLAGS; - return; - case 4: /* 286 call gate */ - case 12: /* 386 call gate */ - break; - default: - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - break; - } - shift = type >> 3; - - if (dpl < cpl || dpl < rpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - /* check valid bit */ - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); - selector = e1 >> 16; - offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); - param_count = e2 & 0x1f; - if ((selector & 0xfffc) == 0) - raise_exception_err(EXCP0D_GPF, 0); - - if (load_segment(&e1, &e2, selector) != 0) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (dpl > cpl) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - - if (!(e2 & DESC_C_MASK) && dpl < cpl) { - /* to inner privilege */ - get_ss_esp_from_tss(&ss, &sp, dpl); -#ifdef DEBUG_PCALL - if (loglevel & CPU_LOG_PCALL) - fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n", - ss, sp, param_count, ESP); -#endif - if ((ss & 0xfffc) == 0) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if ((ss & 3) != dpl) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if (load_segment(&ss_e1, &ss_e2, ss) != 0) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; - if (ss_dpl != dpl) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if (!(ss_e2 & DESC_S_MASK) || - (ss_e2 & DESC_CS_MASK) || - !(ss_e2 & DESC_W_MASK)) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if (!(ss_e2 & DESC_P_MASK)) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - - // push_size = ((param_count * 2) + 8) << shift; - - old_sp_mask = get_sp_mask(env->segs[R_SS].flags); - old_ssp = env->segs[R_SS].base; - - sp_mask = get_sp_mask(ss_e2); - ssp = get_seg_base(ss_e1, ss_e2); - if (shift) { - PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector); - PUSHL(ssp, sp, sp_mask, ESP); - for(i = param_count - 1; i >= 0; i--) { - val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask)); - PUSHL(ssp, sp, sp_mask, val); - } - } else { - PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector); - PUSHW(ssp, sp, sp_mask, ESP); - for(i = param_count - 1; i >= 0; i--) { - val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask)); - PUSHW(ssp, sp, sp_mask, val); - } - } - new_stack = 1; - } else { - /* to same privilege */ - sp = ESP; - sp_mask = get_sp_mask(env->segs[R_SS].flags); - ssp = env->segs[R_SS].base; - // push_size = (4 << shift); - new_stack = 0; - } - - if (shift) { - PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); - PUSHL(ssp, sp, sp_mask, next_eip); - } else { - PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); - PUSHW(ssp, sp, sp_mask, next_eip); - } - - /* from this point, not restartable */ - - if (new_stack) { - ss = (ss & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_SS, ss, - ssp, - get_seg_limit(ss_e1, ss_e2), - ss_e2); - } - - selector = (selector & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_CS, selector, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), - e2); - cpu_x86_set_cpl(env, dpl); - SET_ESP(sp, sp_mask); - EIP = offset; - } -#ifdef USE_KQEMU - if (kqemu_is_ok(env)) { - env->exception_index = -1; - cpu_loop_exit(); - } -#endif -} - -/* real and vm86 mode iret */ -void helper_iret_real(int shift) -{ - uint32_t sp, new_cs, new_eip, new_eflags, sp_mask; - target_ulong ssp; - int eflags_mask; - - sp_mask = 0xffff; /* XXXX: use SS segment size ? */ - sp = ESP; - ssp = env->segs[R_SS].base; - if (shift == 1) { - /* 32 bits */ - POPL(ssp, sp, sp_mask, new_eip); - POPL(ssp, sp, sp_mask, new_cs); - new_cs &= 0xffff; - POPL(ssp, sp, sp_mask, new_eflags); - } else { - /* 16 bits */ - POPW(ssp, sp, sp_mask, new_eip); - POPW(ssp, sp, sp_mask, new_cs); - POPW(ssp, sp, sp_mask, new_eflags); - } - ESP = (ESP & ~sp_mask) | (sp & sp_mask); - load_seg_vm(R_CS, new_cs); - env->eip = new_eip; - if (env->eflags & VM_MASK) - eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK; - else - eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK; - if (shift == 0) - eflags_mask &= 0xffff; - load_eflags(new_eflags, eflags_mask); -} - -static inline void validate_seg(int seg_reg, int cpl) -{ - int dpl; - uint32_t e2; - - /* XXX: on x86_64, we do not want to nullify FS and GS because - they may still contain a valid base. I would be interested to - know how a real x86_64 CPU behaves */ - if ((seg_reg == R_FS || seg_reg == R_GS) && - (env->segs[seg_reg].selector & 0xfffc) == 0) - return; - - e2 = env->segs[seg_reg].flags; - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { - /* data or non conforming code segment */ - if (dpl < cpl) { - cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0); - } - } -} - -/* protected mode iret */ -static inline void helper_ret_protected(int shift, int is_iret, int addend) -{ - uint32_t new_cs, new_eflags, new_ss; - uint32_t new_es, new_ds, new_fs, new_gs; - uint32_t e1, e2, ss_e1, ss_e2; - int cpl, dpl, rpl, eflags_mask, iopl; - target_ulong ssp, sp, new_eip, new_esp, sp_mask; - -#ifdef TARGET_X86_64 - if (shift == 2) - sp_mask = -1; - else -#endif - sp_mask = get_sp_mask(env->segs[R_SS].flags); - sp = ESP; - ssp = env->segs[R_SS].base; - new_eflags = 0; /* avoid warning */ -#ifdef TARGET_X86_64 - if (shift == 2) { - POPQ(sp, new_eip); - POPQ(sp, new_cs); - new_cs &= 0xffff; - if (is_iret) { - POPQ(sp, new_eflags); - } - } else -#endif - if (shift == 1) { - /* 32 bits */ - POPL(ssp, sp, sp_mask, new_eip); - POPL(ssp, sp, sp_mask, new_cs); - new_cs &= 0xffff; - if (is_iret) { - POPL(ssp, sp, sp_mask, new_eflags); - if (new_eflags & VM_MASK) - goto return_to_vm86; - } - } else { - /* 16 bits */ - POPW(ssp, sp, sp_mask, new_eip); - POPW(ssp, sp, sp_mask, new_cs); - if (is_iret) - POPW(ssp, sp, sp_mask, new_eflags); - } -#ifdef DEBUG_PCALL - if (loglevel & CPU_LOG_PCALL) { - fprintf(logfile, "lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n", - new_cs, new_eip, shift, addend); - cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); - } -#endif - if ((new_cs & 0xfffc) == 0) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - if (load_segment(&e1, &e2, new_cs) != 0) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - if (!(e2 & DESC_S_MASK) || - !(e2 & DESC_CS_MASK)) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - cpl = env->hflags & HF_CPL_MASK; - rpl = new_cs & 3; - if (rpl < cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (e2 & DESC_C_MASK) { - if (dpl > rpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - } else { - if (dpl != rpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - } - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); - - sp += addend; - if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) || - ((env->hflags & HF_CS64_MASK) && !is_iret))) { - /* return to same priledge level */ - cpu_x86_load_seg_cache(env, R_CS, new_cs, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), - e2); - } else { - /* return to different privilege level */ -#ifdef TARGET_X86_64 - if (shift == 2) { - POPQ(sp, new_esp); - POPQ(sp, new_ss); - new_ss &= 0xffff; - } else -#endif - if (shift == 1) { - /* 32 bits */ - POPL(ssp, sp, sp_mask, new_esp); - POPL(ssp, sp, sp_mask, new_ss); - new_ss &= 0xffff; - } else { - /* 16 bits */ - POPW(ssp, sp, sp_mask, new_esp); - POPW(ssp, sp, sp_mask, new_ss); - } -#ifdef DEBUG_PCALL - if (loglevel & CPU_LOG_PCALL) { - fprintf(logfile, "new ss:esp=%04x:" TARGET_FMT_lx "\n", - new_ss, new_esp); - } -#endif - if ((new_ss & 0xfffc) == 0) { -#ifdef TARGET_X86_64 - /* NULL ss is allowed in long mode if cpl != 3*/ - /* XXX: test CS64 ? */ - if ((env->hflags & HF_LMA_MASK) && rpl != 3) { - cpu_x86_load_seg_cache(env, R_SS, new_ss, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | (rpl << DESC_DPL_SHIFT) | - DESC_W_MASK | DESC_A_MASK); - ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */ - } else -#endif - { - raise_exception_err(EXCP0D_GPF, 0); - } - } else { - if ((new_ss & 3) != rpl) - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - if (load_segment(&ss_e1, &ss_e2, new_ss) != 0) - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - if (!(ss_e2 & DESC_S_MASK) || - (ss_e2 & DESC_CS_MASK) || - !(ss_e2 & DESC_W_MASK)) - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; - if (dpl != rpl) - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - if (!(ss_e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); - cpu_x86_load_seg_cache(env, R_SS, new_ss, - get_seg_base(ss_e1, ss_e2), - get_seg_limit(ss_e1, ss_e2), - ss_e2); - } - - cpu_x86_load_seg_cache(env, R_CS, new_cs, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), - e2); - cpu_x86_set_cpl(env, rpl); - sp = new_esp; -#ifdef TARGET_X86_64 - if (env->hflags & HF_CS64_MASK) - sp_mask = -1; - else -#endif - sp_mask = get_sp_mask(ss_e2); - - /* validate data segments */ - validate_seg(R_ES, rpl); - validate_seg(R_DS, rpl); - validate_seg(R_FS, rpl); - validate_seg(R_GS, rpl); - - sp += addend; - } - SET_ESP(sp, sp_mask); - env->eip = new_eip; - if (is_iret) { - /* NOTE: 'cpl' is the _old_ CPL */ - eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK; - if (cpl == 0) - eflags_mask |= IOPL_MASK; - iopl = (env->eflags >> IOPL_SHIFT) & 3; - if (cpl <= iopl) - eflags_mask |= IF_MASK; - if (shift == 0) - eflags_mask &= 0xffff; - load_eflags(new_eflags, eflags_mask); - } - return; - - return_to_vm86: - POPL(ssp, sp, sp_mask, new_esp); - POPL(ssp, sp, sp_mask, new_ss); - POPL(ssp, sp, sp_mask, new_es); - POPL(ssp, sp, sp_mask, new_ds); - POPL(ssp, sp, sp_mask, new_fs); - POPL(ssp, sp, sp_mask, new_gs); - - /* modify processor state */ - load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK | - IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK); - load_seg_vm(R_CS, new_cs & 0xffff); - cpu_x86_set_cpl(env, 3); - load_seg_vm(R_SS, new_ss & 0xffff); - load_seg_vm(R_ES, new_es & 0xffff); - load_seg_vm(R_DS, new_ds & 0xffff); - load_seg_vm(R_FS, new_fs & 0xffff); - load_seg_vm(R_GS, new_gs & 0xffff); - - env->eip = new_eip & 0xffff; - ESP = new_esp; -} - -void helper_iret_protected(int shift, int next_eip) -{ - int tss_selector, type; - uint32_t e1, e2; - - /* specific case for TSS */ - if (env->eflags & NT_MASK) { -#ifdef TARGET_X86_64 - if (env->hflags & HF_LMA_MASK) - raise_exception_err(EXCP0D_GPF, 0); -#endif - tss_selector = lduw_kernel(env->tr.base + 0); - if (tss_selector & 4) - raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); - if (load_segment(&e1, &e2, tss_selector) != 0) - raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); - type = (e2 >> DESC_TYPE_SHIFT) & 0x17; - /* NOTE: we check both segment and busy TSS */ - if (type != 3) - raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); - switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip); - } else { - helper_ret_protected(shift, 1, 0); - } -#ifdef USE_KQEMU - if (kqemu_is_ok(env)) { - CC_OP = CC_OP_EFLAGS; - env->exception_index = -1; - cpu_loop_exit(); - } -#endif -} - -void helper_lret_protected(int shift, int addend) -{ - helper_ret_protected(shift, 0, addend); -#ifdef USE_KQEMU - if (kqemu_is_ok(env)) { - env->exception_index = -1; - cpu_loop_exit(); - } -#endif -} - -void helper_sysenter(void) -{ - if (env->sysenter_cs == 0) { - raise_exception_err(EXCP0D_GPF, 0); - } - env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK); - cpu_x86_set_cpl(env, 0); - cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | - DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); - cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | - DESC_W_MASK | DESC_A_MASK); - ESP = env->sysenter_esp; - EIP = env->sysenter_eip; -} - -void helper_sysexit(void) -{ - int cpl; - - cpl = env->hflags & HF_CPL_MASK; - if (env->sysenter_cs == 0 || cpl != 0) { - raise_exception_err(EXCP0D_GPF, 0); - } - cpu_x86_set_cpl(env, 3); - cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | (3 << DESC_DPL_SHIFT) | - DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); - cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | (3 << DESC_DPL_SHIFT) | - DESC_W_MASK | DESC_A_MASK); - ESP = ECX; - EIP = EDX; -#ifdef USE_KQEMU - if (kqemu_is_ok(env)) { - env->exception_index = -1; - cpu_loop_exit(); - } -#endif -} - -void helper_movl_crN_T0(int reg) -{ -#if !defined(CONFIG_USER_ONLY) - switch(reg) { - case 0: - cpu_x86_update_cr0(env, T0); - break; - case 3: - cpu_x86_update_cr3(env, T0); - break; - case 4: - cpu_x86_update_cr4(env, T0); - break; - case 8: - cpu_set_apic_tpr(env, T0); - break; - default: - env->cr[reg] = T0; - break; - } -#endif -} - -/* XXX: do more */ -void helper_movl_drN_T0(int reg) -{ - env->dr[reg] = T0; -} - -void helper_invlpg(target_ulong addr) -{ - cpu_x86_flush_tlb(env, addr); -} - -void helper_rdtsc(void) -{ - uint64_t val; - - if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) { - raise_exception(EXCP0D_GPF); - } - val = cpu_get_tsc(env); - EAX = (uint32_t)(val); - EDX = (uint32_t)(val >> 32); -} - -void helper_rdpmc(void) -{ - if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) { - raise_exception(EXCP0D_GPF); - } - - if (!svm_check_intercept_param(SVM_EXIT_RDPMC, 0)) { - /* currently unimplemented */ - raise_exception_err(EXCP06_ILLOP, 0); - } -} - -#if defined(CONFIG_USER_ONLY) -void helper_wrmsr(void) -{ -} - -void helper_rdmsr(void) -{ -} -#else -void helper_wrmsr(void) -{ - uint64_t val; - - val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); - - switch((uint32_t)ECX) { - case MSR_IA32_SYSENTER_CS: - env->sysenter_cs = val & 0xffff; - break; - case MSR_IA32_SYSENTER_ESP: - env->sysenter_esp = val; - break; - case MSR_IA32_SYSENTER_EIP: - env->sysenter_eip = val; - break; - case MSR_IA32_APICBASE: - cpu_set_apic_base(env, val); - break; - case MSR_EFER: - { - uint64_t update_mask; - update_mask = 0; - if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL) - update_mask |= MSR_EFER_SCE; - if (env->cpuid_ext2_features & CPUID_EXT2_LM) - update_mask |= MSR_EFER_LME; - if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR) - update_mask |= MSR_EFER_FFXSR; - if (env->cpuid_ext2_features & CPUID_EXT2_NX) - update_mask |= MSR_EFER_NXE; - env->efer = (env->efer & ~update_mask) | - (val & update_mask); - } - break; - case MSR_STAR: - env->star = val; - break; - case MSR_PAT: - env->pat = val; - break; - case MSR_VM_HSAVE_PA: - env->vm_hsave = val; - break; -#ifdef TARGET_X86_64 - case MSR_LSTAR: - env->lstar = val; - break; - case MSR_CSTAR: - env->cstar = val; - break; - case MSR_FMASK: - env->fmask = val; - break; - case MSR_FSBASE: - env->segs[R_FS].base = val; - break; - case MSR_GSBASE: - env->segs[R_GS].base = val; - break; - case MSR_KERNELGSBASE: - env->kernelgsbase = val; - break; -#endif - default: - /* XXX: exception ? */ - break; - } -} - -void helper_rdmsr(void) -{ - uint64_t val; - switch((uint32_t)ECX) { - case MSR_IA32_SYSENTER_CS: - val = env->sysenter_cs; - break; - case MSR_IA32_SYSENTER_ESP: - val = env->sysenter_esp; - break; - case MSR_IA32_SYSENTER_EIP: - val = env->sysenter_eip; - break; - case MSR_IA32_APICBASE: - val = cpu_get_apic_base(env); - break; - case MSR_EFER: - val = env->efer; - break; - case MSR_STAR: - val = env->star; - break; - case MSR_PAT: - val = env->pat; - break; - case MSR_VM_HSAVE_PA: - val = env->vm_hsave; - break; -#ifdef TARGET_X86_64 - case MSR_LSTAR: - val = env->lstar; - break; - case MSR_CSTAR: - val = env->cstar; - break; - case MSR_FMASK: - val = env->fmask; - break; - case MSR_FSBASE: - val = env->segs[R_FS].base; - break; - case MSR_GSBASE: - val = env->segs[R_GS].base; - break; - case MSR_KERNELGSBASE: - val = env->kernelgsbase; - break; -#endif - default: - /* XXX: exception ? */ - val = 0; - break; - } - EAX = (uint32_t)(val); - EDX = (uint32_t)(val >> 32); -} -#endif - -void helper_lsl(void) -{ - unsigned int selector, limit; - uint32_t e1, e2, eflags; - int rpl, dpl, cpl, type; - - eflags = cc_table[CC_OP].compute_all(); - selector = T0 & 0xffff; - if (load_segment(&e1, &e2, selector) != 0) - goto fail; - rpl = selector & 3; - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->hflags & HF_CPL_MASK; - if (e2 & DESC_S_MASK) { - if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) { - /* conforming */ - } else { - if (dpl < cpl || dpl < rpl) - goto fail; - } - } else { - type = (e2 >> DESC_TYPE_SHIFT) & 0xf; - switch(type) { - case 1: - case 2: - case 3: - case 9: - case 11: - break; - default: - goto fail; - } - if (dpl < cpl || dpl < rpl) { - fail: - CC_SRC = eflags & ~CC_Z; - return; - } - } - limit = get_seg_limit(e1, e2); - T1 = limit; - CC_SRC = eflags | CC_Z; -} - -void helper_lar(void) -{ - unsigned int selector; - uint32_t e1, e2, eflags; - int rpl, dpl, cpl, type; - - eflags = cc_table[CC_OP].compute_all(); - selector = T0 & 0xffff; - if ((selector & 0xfffc) == 0) - goto fail; - if (load_segment(&e1, &e2, selector) != 0) - goto fail; - rpl = selector & 3; - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->hflags & HF_CPL_MASK; - if (e2 & DESC_S_MASK) { - if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) { - /* conforming */ - } else { - if (dpl < cpl || dpl < rpl) - goto fail; - } - } else { - type = (e2 >> DESC_TYPE_SHIFT) & 0xf; - switch(type) { - case 1: - case 2: - case 3: - case 4: - case 5: - case 9: - case 11: - case 12: - break; - default: - goto fail; - } - if (dpl < cpl || dpl < rpl) { - fail: - CC_SRC = eflags & ~CC_Z; - return; - } - } - T1 = e2 & 0x00f0ff00; - CC_SRC = eflags | CC_Z; -} - -void helper_verr(void) -{ - unsigned int selector; - uint32_t e1, e2, eflags; - int rpl, dpl, cpl; - - eflags = cc_table[CC_OP].compute_all(); - selector = T0 & 0xffff; - if ((selector & 0xfffc) == 0) - goto fail; - if (load_segment(&e1, &e2, selector) != 0) - goto fail; - if (!(e2 & DESC_S_MASK)) - goto fail; - rpl = selector & 3; - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->hflags & HF_CPL_MASK; - if (e2 & DESC_CS_MASK) { - if (!(e2 & DESC_R_MASK)) - goto fail; - if (!(e2 & DESC_C_MASK)) { - if (dpl < cpl || dpl < rpl) - goto fail; - } - } else { - if (dpl < cpl || dpl < rpl) { - fail: - CC_SRC = eflags & ~CC_Z; - return; - } - } - CC_SRC = eflags | CC_Z; -} - -void helper_verw(void) -{ - unsigned int selector; - uint32_t e1, e2, eflags; - int rpl, dpl, cpl; - - eflags = cc_table[CC_OP].compute_all(); - selector = T0 & 0xffff; - if ((selector & 0xfffc) == 0) - goto fail; - if (load_segment(&e1, &e2, selector) != 0) - goto fail; - if (!(e2 & DESC_S_MASK)) - goto fail; - rpl = selector & 3; - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->hflags & HF_CPL_MASK; - if (e2 & DESC_CS_MASK) { - goto fail; - } else { - if (dpl < cpl || dpl < rpl) - goto fail; - if (!(e2 & DESC_W_MASK)) { - fail: - CC_SRC = eflags & ~CC_Z; - return; - } - } - CC_SRC = eflags | CC_Z; -} - -/* FPU helpers */ - -void helper_fldt_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt].d = helper_fldt(A0); - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -void helper_fstt_ST0_A0(void) -{ - helper_fstt(ST0, A0); -} - -static void fpu_set_exception(int mask) -{ - env->fpus |= mask; - if (env->fpus & (~env->fpuc & FPUC_EM)) - env->fpus |= FPUS_SE | FPUS_B; -} - -CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b) -{ - if (b == 0.0) - fpu_set_exception(FPUS_ZE); - return a / b; -} - -void fpu_raise_exception(void) -{ - if (env->cr[0] & CR0_NE_MASK) { - raise_exception(EXCP10_COPR); - } -#if !defined(CONFIG_USER_ONLY) - else { - cpu_set_ferr(env); - } -#endif -} - -/* BCD ops */ - -void helper_fbld_ST0_A0(void) -{ - CPU86_LDouble tmp; - uint64_t val; - unsigned int v; - int i; - - val = 0; - for(i = 8; i >= 0; i--) { - v = ldub(A0 + i); - val = (val * 100) + ((v >> 4) * 10) + (v & 0xf); - } - tmp = val; - if (ldub(A0 + 9) & 0x80) - tmp = -tmp; - fpush(); - ST0 = tmp; -} - -void helper_fbst_ST0_A0(void) -{ - int v; - target_ulong mem_ref, mem_end; - int64_t val; - - val = floatx_to_int64(ST0, &env->fp_status); - mem_ref = A0; - mem_end = mem_ref + 9; - if (val < 0) { - stb(mem_end, 0x80); - val = -val; - } else { - stb(mem_end, 0x00); - } - while (mem_ref < mem_end) { - if (val == 0) - break; - v = val % 100; - val = val / 100; - v = ((v / 10) << 4) | (v % 10); - stb(mem_ref++, v); - } - while (mem_ref < mem_end) { - stb(mem_ref++, 0); - } -} - -void helper_f2xm1(void) -{ - ST0 = pow(2.0,ST0) - 1.0; -} - -void helper_fyl2x(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if (fptemp>0.0){ - fptemp = log(fptemp)/log(2.0); /* log2(ST) */ - ST1 *= fptemp; - fpop(); - } else { - env->fpus &= (~0x4700); - env->fpus |= 0x400; - } -} - -void helper_fptan(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = tan(fptemp); - fpush(); - ST0 = 1.0; - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg| < 2**52 only */ - } -} - -void helper_fpatan(void) -{ - CPU86_LDouble fptemp, fpsrcop; - - fpsrcop = ST1; - fptemp = ST0; - ST1 = atan2(fpsrcop,fptemp); - fpop(); -} - -void helper_fxtract(void) -{ - CPU86_LDoubleU temp; - unsigned int expdif; - - temp.d = ST0; - expdif = EXPD(temp) - EXPBIAS; - /*DP exponent bias*/ - ST0 = expdif; - fpush(); - BIASEXPONENT(temp); - ST0 = temp.d; -} - -void helper_fprem1(void) -{ - CPU86_LDouble dblq, fpsrcop, fptemp; - CPU86_LDoubleU fpsrcop1, fptemp1; - int expdif; - signed long long int q; - - if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) { - ST0 = 0.0 / 0.0; /* NaN */ - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - return; - } - - fpsrcop = ST0; - fptemp = ST1; - fpsrcop1.d = fpsrcop; - fptemp1.d = fptemp; - expdif = EXPD(fpsrcop1) - EXPD(fptemp1); - - if (expdif < 0) { - /* optimisation? taken from the AMD docs */ - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - /* ST0 is unchanged */ - return; - } - - if (expdif < 53) { - dblq = fpsrcop / fptemp; - /* round dblq towards nearest integer */ - dblq = rint(dblq); - ST0 = fpsrcop - fptemp * dblq; - - /* convert dblq to q by truncating towards zero */ - if (dblq < 0.0) - q = (signed long long int)(-dblq); - else - q = (signed long long int)dblq; - - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - /* (C0,C3,C1) <-- (q2,q1,q0) */ - env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */ - env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */ - env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */ - } else { - env->fpus |= 0x400; /* C2 <-- 1 */ - fptemp = pow(2.0, expdif - 50); - fpsrcop = (ST0 / ST1) / fptemp; - /* fpsrcop = integer obtained by chopping */ - fpsrcop = (fpsrcop < 0.0) ? - -(floor(fabs(fpsrcop))) : floor(fpsrcop); - ST0 -= (ST1 * fpsrcop * fptemp); - } -} - -void helper_fprem(void) -{ - CPU86_LDouble dblq, fpsrcop, fptemp; - CPU86_LDoubleU fpsrcop1, fptemp1; - int expdif; - signed long long int q; - - if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) { - ST0 = 0.0 / 0.0; /* NaN */ - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - return; - } - - fpsrcop = (CPU86_LDouble)ST0; - fptemp = (CPU86_LDouble)ST1; - fpsrcop1.d = fpsrcop; - fptemp1.d = fptemp; - expdif = EXPD(fpsrcop1) - EXPD(fptemp1); - - if (expdif < 0) { - /* optimisation? taken from the AMD docs */ - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - /* ST0 is unchanged */ - return; - } - - if ( expdif < 53 ) { - dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/; - /* round dblq towards zero */ - dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq); - ST0 = fpsrcop/*ST0*/ - fptemp * dblq; - - /* convert dblq to q by truncating towards zero */ - if (dblq < 0.0) - q = (signed long long int)(-dblq); - else - q = (signed long long int)dblq; - - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - /* (C0,C3,C1) <-- (q2,q1,q0) */ - env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */ - env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */ - env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */ - } else { - int N = 32 + (expdif % 32); /* as per AMD docs */ - env->fpus |= 0x400; /* C2 <-- 1 */ - fptemp = pow(2.0, (double)(expdif - N)); - fpsrcop = (ST0 / ST1) / fptemp; - /* fpsrcop = integer obtained by chopping */ - fpsrcop = (fpsrcop < 0.0) ? - -(floor(fabs(fpsrcop))) : floor(fpsrcop); - ST0 -= (ST1 * fpsrcop * fptemp); - } -} - -void helper_fyl2xp1(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if ((fptemp+1.0)>0.0) { - fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ - ST1 *= fptemp; - fpop(); - } else { - env->fpus &= (~0x4700); - env->fpus |= 0x400; - } -} - -void helper_fsqrt(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if (fptemp<0.0) { - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - env->fpus |= 0x400; - } - ST0 = sqrt(fptemp); -} - -void helper_fsincos(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = sin(fptemp); - fpush(); - ST0 = cos(fptemp); - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg| < 2**63 only */ - } -} - -void helper_frndint(void) -{ - ST0 = floatx_round_to_int(ST0, &env->fp_status); -} - -void helper_fscale(void) -{ - ST0 = ldexp (ST0, (int)(ST1)); -} - -void helper_fsin(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = sin(fptemp); - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg| < 2**53 only */ - } -} - -void helper_fcos(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = cos(fptemp); - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg5 < 2**63 only */ - } -} - -void helper_fxam_ST0(void) -{ - CPU86_LDoubleU temp; - int expdif; - - temp.d = ST0; - - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - if (SIGND(temp)) - env->fpus |= 0x200; /* C1 <-- 1 */ - - /* XXX: test fptags too */ - expdif = EXPD(temp); - if (expdif == MAXEXPD) { -#ifdef USE_X86LDOUBLE - if (MANTD(temp) == 0x8000000000000000ULL) -#else - if (MANTD(temp) == 0) -#endif - env->fpus |= 0x500 /*Infinity*/; - else - env->fpus |= 0x100 /*NaN*/; - } else if (expdif == 0) { - if (MANTD(temp) == 0) - env->fpus |= 0x4000 /*Zero*/; - else - env->fpus |= 0x4400 /*Denormal*/; - } else { - env->fpus |= 0x400; - } -} - -void helper_fstenv(target_ulong ptr, int data32) -{ - int fpus, fptag, exp, i; - uint64_t mant; - CPU86_LDoubleU tmp; - - fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; - fptag = 0; - for (i=7; i>=0; i--) { - fptag <<= 2; - if (env->fptags[i]) { - fptag |= 3; - } else { - tmp.d = env->fpregs[i].d; - exp = EXPD(tmp); - mant = MANTD(tmp); - if (exp == 0 && mant == 0) { - /* zero */ - fptag |= 1; - } else if (exp == 0 || exp == MAXEXPD -#ifdef USE_X86LDOUBLE - || (mant & (1LL << 63)) == 0 -#endif - ) { - /* NaNs, infinity, denormal */ - fptag |= 2; - } - } - } - if (data32) { - /* 32 bit */ - stl(ptr, env->fpuc); - stl(ptr + 4, fpus); - stl(ptr + 8, fptag); - stl(ptr + 12, 0); /* fpip */ - stl(ptr + 16, 0); /* fpcs */ - stl(ptr + 20, 0); /* fpoo */ - stl(ptr + 24, 0); /* fpos */ - } else { - /* 16 bit */ - stw(ptr, env->fpuc); - stw(ptr + 2, fpus); - stw(ptr + 4, fptag); - stw(ptr + 6, 0); - stw(ptr + 8, 0); - stw(ptr + 10, 0); - stw(ptr + 12, 0); - } -} - -void helper_fldenv(target_ulong ptr, int data32) -{ - int i, fpus, fptag; - - if (data32) { - env->fpuc = lduw(ptr); - fpus = lduw(ptr + 4); - fptag = lduw(ptr + 8); - } - else { - env->fpuc = lduw(ptr); - fpus = lduw(ptr + 2); - fptag = lduw(ptr + 4); - } - env->fpstt = (fpus >> 11) & 7; - env->fpus = fpus & ~0x3800; - for(i = 0;i < 8; i++) { - env->fptags[i] = ((fptag & 3) == 3); - fptag >>= 2; - } -} - -void helper_fsave(target_ulong ptr, int data32) -{ - CPU86_LDouble tmp; - int i; - - helper_fstenv(ptr, data32); - - ptr += (14 << data32); - for(i = 0;i < 8; i++) { - tmp = ST(i); - helper_fstt(tmp, ptr); - ptr += 10; - } - - /* fninit */ - env->fpus = 0; - env->fpstt = 0; - env->fpuc = 0x37f; - env->fptags[0] = 1; - env->fptags[1] = 1; - env->fptags[2] = 1; - env->fptags[3] = 1; - env->fptags[4] = 1; - env->fptags[5] = 1; - env->fptags[6] = 1; - env->fptags[7] = 1; -} - -void helper_frstor(target_ulong ptr, int data32) -{ - CPU86_LDouble tmp; - int i; - - helper_fldenv(ptr, data32); - ptr += (14 << data32); - - for(i = 0;i < 8; i++) { - tmp = helper_fldt(ptr); - ST(i) = tmp; - ptr += 10; - } -} - -void helper_fxsave(target_ulong ptr, int data64) -{ - int fpus, fptag, i, nb_xmm_regs; - CPU86_LDouble tmp; - target_ulong addr; - - fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; - fptag = 0; - for(i = 0; i < 8; i++) { - fptag |= (env->fptags[i] << i); - } - stw(ptr, env->fpuc); - stw(ptr + 2, fpus); - stw(ptr + 4, fptag ^ 0xff); - - addr = ptr + 0x20; - for(i = 0;i < 8; i++) { - tmp = ST(i); - helper_fstt(tmp, addr); - addr += 16; - } - - if (env->cr[4] & CR4_OSFXSR_MASK) { - /* XXX: finish it */ - stl(ptr + 0x18, env->mxcsr); /* mxcsr */ - stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */ - nb_xmm_regs = 8 << data64; - addr = ptr + 0xa0; - for(i = 0; i < nb_xmm_regs; i++) { - stq(addr, env->xmm_regs[i].XMM_Q(0)); - stq(addr + 8, env->xmm_regs[i].XMM_Q(1)); - addr += 16; - } - } -} - -void helper_fxrstor(target_ulong ptr, int data64) -{ - int i, fpus, fptag, nb_xmm_regs; - CPU86_LDouble tmp; - target_ulong addr; - - env->fpuc = lduw(ptr); - fpus = lduw(ptr + 2); - fptag = lduw(ptr + 4); - env->fpstt = (fpus >> 11) & 7; - env->fpus = fpus & ~0x3800; - fptag ^= 0xff; - for(i = 0;i < 8; i++) { - env->fptags[i] = ((fptag >> i) & 1); - } - - addr = ptr + 0x20; - for(i = 0;i < 8; i++) { - tmp = helper_fldt(addr); - ST(i) = tmp; - addr += 16; - } - - if (env->cr[4] & CR4_OSFXSR_MASK) { - /* XXX: finish it */ - env->mxcsr = ldl(ptr + 0x18); - //ldl(ptr + 0x1c); - nb_xmm_regs = 8 << data64; - addr = ptr + 0xa0; - for(i = 0; i < nb_xmm_regs; i++) { - env->xmm_regs[i].XMM_Q(0) = ldq(addr); - env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8); - addr += 16; - } - } -} - -#ifndef USE_X86LDOUBLE - -void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f) -{ - CPU86_LDoubleU temp; - int e; - - temp.d = f; - /* mantissa */ - *pmant = (MANTD(temp) << 11) | (1LL << 63); - /* exponent + sign */ - e = EXPD(temp) - EXPBIAS + 16383; - e |= SIGND(temp) >> 16; - *pexp = e; -} - -CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper) -{ - CPU86_LDoubleU temp; - int e; - uint64_t ll; - - /* XXX: handle overflow ? */ - e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ - e |= (upper >> 4) & 0x800; /* sign */ - ll = (mant >> 11) & ((1LL << 52) - 1); -#ifdef __arm__ - temp.l.upper = (e << 20) | (ll >> 32); - temp.l.lower = ll; -#else - temp.ll = ll | ((uint64_t)e << 52); -#endif - return temp.d; -} - -#else - -void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f) -{ - CPU86_LDoubleU temp; - - temp.d = f; - *pmant = temp.l.lower; - *pexp = temp.l.upper; -} - -CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper) -{ - CPU86_LDoubleU temp; - - temp.l.upper = upper; - temp.l.lower = mant; - return temp.d; -} -#endif - -#ifdef TARGET_X86_64 - -//#define DEBUG_MULDIV - -static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) -{ - *plow += a; - /* carry test */ - if (*plow < a) - (*phigh)++; - *phigh += b; -} - -static void neg128(uint64_t *plow, uint64_t *phigh) -{ - *plow = ~ *plow; - *phigh = ~ *phigh; - add128(plow, phigh, 1, 0); -} - -/* return TRUE if overflow */ -static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b) -{ - uint64_t q, r, a1, a0; - int i, qb, ab; - - a0 = *plow; - a1 = *phigh; - if (a1 == 0) { - q = a0 / b; - r = a0 % b; - *plow = q; - *phigh = r; - } else { - if (a1 >= b) - return 1; - /* XXX: use a better algorithm */ - for(i = 0; i < 64; i++) { - ab = a1 >> 63; - a1 = (a1 << 1) | (a0 >> 63); - if (ab || a1 >= b) { - a1 -= b; - qb = 1; - } else { - qb = 0; - } - a0 = (a0 << 1) | qb; - } -#if defined(DEBUG_MULDIV) - printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n", - *phigh, *plow, b, a0, a1); -#endif - *plow = a0; - *phigh = a1; - } - return 0; -} - -/* return TRUE if overflow */ -static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) -{ - int sa, sb; - sa = ((int64_t)*phigh < 0); - if (sa) - neg128(plow, phigh); - sb = (b < 0); - if (sb) - b = -b; - if (div64(plow, phigh, b) != 0) - return 1; - if (sa ^ sb) { - if (*plow > (1ULL << 63)) - return 1; - *plow = - *plow; - } else { - if (*plow >= (1ULL << 63)) - return 1; - } - if (sa) - *phigh = - *phigh; - return 0; -} - -void helper_mulq_EAX_T0(void) -{ - uint64_t r0, r1; - - mulu64(&r0, &r1, EAX, T0); - EAX = r0; - EDX = r1; - CC_DST = r0; - CC_SRC = r1; -} - -void helper_imulq_EAX_T0(void) -{ - uint64_t r0, r1; - - muls64(&r0, &r1, EAX, T0); - EAX = r0; - EDX = r1; - CC_DST = r0; - CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); -} - -void helper_imulq_T0_T1(void) -{ - uint64_t r0, r1; - - muls64(&r0, &r1, T0, T1); - T0 = r0; - CC_DST = r0; - CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); -} - -void helper_divq_EAX_T0(void) -{ - uint64_t r0, r1; - if (T0 == 0) { - raise_exception(EXCP00_DIVZ); - } - r0 = EAX; - r1 = EDX; - if (div64(&r0, &r1, T0)) - raise_exception(EXCP00_DIVZ); - EAX = r0; - EDX = r1; -} - -void helper_idivq_EAX_T0(void) -{ - uint64_t r0, r1; - if (T0 == 0) { - raise_exception(EXCP00_DIVZ); - } - r0 = EAX; - r1 = EDX; - if (idiv64(&r0, &r1, T0)) - raise_exception(EXCP00_DIVZ); - EAX = r0; - EDX = r1; -} - -void helper_bswapq_T0(void) -{ - T0 = bswap64(T0); -} -#endif - -void helper_hlt(void) -{ - env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */ - env->hflags |= HF_HALTED_MASK; - env->exception_index = EXCP_HLT; - cpu_loop_exit(); -} - -void helper_monitor(void) -{ - if ((uint32_t)ECX != 0) - raise_exception(EXCP0D_GPF); - /* XXX: store address ? */ -} - -void helper_mwait(void) -{ - if ((uint32_t)ECX != 0) - raise_exception(EXCP0D_GPF); - /* XXX: not complete but not completely erroneous */ - if (env->cpu_index != 0 || env->next_cpu != NULL) { - /* more than one CPU: do not sleep because another CPU may - wake this one */ - } else { - helper_hlt(); - } -} - -float approx_rsqrt(float a) -{ - return 1.0 / sqrt(a); -} - -float approx_rcp(float a) -{ - return 1.0 / a; -} - -void update_fp_status(void) -{ - int rnd_type; - - /* set rounding mode */ - switch(env->fpuc & RC_MASK) { - default: - case RC_NEAR: - rnd_type = float_round_nearest_even; - break; - case RC_DOWN: - rnd_type = float_round_down; - break; - case RC_UP: - rnd_type = float_round_up; - break; - case RC_CHOP: - rnd_type = float_round_to_zero; - break; - } - set_float_rounding_mode(rnd_type, &env->fp_status); -#ifdef FLOATX80 - switch((env->fpuc >> 8) & 3) { - case 0: - rnd_type = 32; - break; - case 2: - rnd_type = 64; - break; - case 3: - default: - rnd_type = 80; - break; - } - set_floatx80_rounding_precision(rnd_type, &env->fp_status); -#endif -} - -#if !defined(CONFIG_USER_ONLY) - -#define MMUSUFFIX _mmu -#ifdef __s390__ -# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) -#else -# define GETPC() (__builtin_return_address(0)) -#endif - -#define SHIFT 0 -#include "softmmu_template.h" - -#define SHIFT 1 -#include "softmmu_template.h" - -#define SHIFT 2 -#include "softmmu_template.h" - -#define SHIFT 3 -#include "softmmu_template.h" - -#endif - -/* try to fill the TLB and return an exception if error. If retaddr is - NULL, it means that the function was called in C code (i.e. not - from generated code or from helper.c) */ -/* XXX: fix it to restore all registers */ -void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) -{ - TranslationBlock *tb; - int ret; - unsigned long pc; - CPUX86State *saved_env; - - /* XXX: hack to restore env in all cases, even if not called from - generated code */ - saved_env = env; - env = cpu_single_env; - - ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); - if (ret) { - if (retaddr) { - /* now we have a real cpu fault */ - pc = (unsigned long)retaddr; - tb = tb_find_pc(pc); - if (tb) { - /* the PC is inside the translated code. It means that we have - a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); - } - } - if (retaddr) - raise_exception_err(env->exception_index, env->error_code); - else - raise_exception_err_norestore(env->exception_index, env->error_code); - } - env = saved_env; -} - - -/* Secure Virtual Machine helpers */ - -void helper_stgi(void) -{ - env->hflags |= HF_GIF_MASK; -} - -void helper_clgi(void) -{ - env->hflags &= ~HF_GIF_MASK; -} - -#if defined(CONFIG_USER_ONLY) - -void helper_vmrun(target_ulong addr) { } -void helper_vmmcall(void) { } -void helper_vmload(target_ulong addr) { } -void helper_vmsave(target_ulong addr) { } -void helper_skinit(void) { } -void helper_invlpga(void) { } -void vmexit(uint64_t exit_code, uint64_t exit_info_1) { } -int svm_check_intercept_param(uint32_t type, uint64_t param) -{ - return 0; -} - -#else - -static inline uint32_t -vmcb2cpu_attrib(uint16_t vmcb_attrib, uint32_t vmcb_base, uint32_t vmcb_limit) -{ - return ((vmcb_attrib & 0x00ff) << 8) /* Type, S, DPL, P */ - | ((vmcb_attrib & 0x0f00) << 12) /* AVL, L, DB, G */ - | ((vmcb_base >> 16) & 0xff) /* Base 23-16 */ - | (vmcb_base & 0xff000000) /* Base 31-24 */ - | (vmcb_limit & 0xf0000); /* Limit 19-16 */ -} - -static inline uint16_t cpu2vmcb_attrib(uint32_t cpu_attrib) -{ - return ((cpu_attrib >> 8) & 0xff) /* Type, S, DPL, P */ - | ((cpu_attrib & 0xf00000) >> 12); /* AVL, L, DB, G */ -} - -extern uint8_t *phys_ram_base; -void helper_vmrun(target_ulong addr) -{ - uint32_t event_inj; - uint32_t int_ctl; - - if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile,"vmrun! " TARGET_FMT_lx "\n", addr); - - env->vm_vmcb = addr; - regs_to_env(); - - /* save the current CPU state in the hsave page */ - stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base); - stl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit); - - stq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base), env->idt.base); - stl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), env->idt.limit); - - stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]); - stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]); - stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]); - stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]); - stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr8), env->cr[8]); - stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]); - stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]); - - stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer); - stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags), compute_eflags()); - - SVM_SAVE_SEG(env->vm_hsave, segs[R_ES], es); - SVM_SAVE_SEG(env->vm_hsave, segs[R_CS], cs); - SVM_SAVE_SEG(env->vm_hsave, segs[R_SS], ss); - SVM_SAVE_SEG(env->vm_hsave, segs[R_DS], ds); - - stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip), EIP); - stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP); - stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX); - - /* load the interception bitmaps so we do not need to access the - vmcb in svm mode */ - /* We shift all the intercept bits so we can OR them with the TB - flags later on */ - env->intercept = (ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept)) << INTERCEPT_INTR) | INTERCEPT_SVM_MASK; - env->intercept_cr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_read)); - env->intercept_cr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_write)); - env->intercept_dr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_read)); - env->intercept_dr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_write)); - env->intercept_exceptions = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_exceptions)); - - env->gdt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base)); - env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit)); - - env->idt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base)); - env->idt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit)); - - /* clear exit_info_2 so we behave like the real hardware */ - stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0); - - cpu_x86_update_cr0(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0))); - cpu_x86_update_cr4(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4))); - cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3))); - env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2)); - int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)); - if (int_ctl & V_INTR_MASKING_MASK) { - env->cr[8] = int_ctl & V_TPR_MASK; - if (env->eflags & IF_MASK) - env->hflags |= HF_HIF_MASK; - } - -#ifdef TARGET_X86_64 - env->efer = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer)); - env->hflags &= ~HF_LMA_MASK; - if (env->efer & MSR_EFER_LMA) - env->hflags |= HF_LMA_MASK; -#endif - env->eflags = 0; - load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)), - ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); - CC_OP = CC_OP_EFLAGS; - CC_DST = 0xffffffff; - - SVM_LOAD_SEG(env->vm_vmcb, ES, es); - SVM_LOAD_SEG(env->vm_vmcb, CS, cs); - SVM_LOAD_SEG(env->vm_vmcb, SS, ss); - SVM_LOAD_SEG(env->vm_vmcb, DS, ds); - - EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip)); - env->eip = EIP; - ESP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp)); - EAX = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax)); - env->dr[7] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7)); - env->dr[6] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6)); - cpu_x86_set_cpl(env, ldub_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl))); - - /* FIXME: guest state consistency checks */ - - switch(ldub_phys(env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) { - case TLB_CONTROL_DO_NOTHING: - break; - case TLB_CONTROL_FLUSH_ALL_ASID: - /* FIXME: this is not 100% correct but should work for now */ - tlb_flush(env, 1); - break; - } - - helper_stgi(); - - regs_to_env(); - - /* maybe we need to inject an event */ - event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)); - if (event_inj & SVM_EVTINJ_VALID) { - uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK; - uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR; - uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err)); - stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID); - - if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile, "Injecting(%#hx): ", valid_err); - /* FIXME: need to implement valid_err */ - switch (event_inj & SVM_EVTINJ_TYPE_MASK) { - case SVM_EVTINJ_TYPE_INTR: - env->exception_index = vector; - env->error_code = event_inj_err; - env->exception_is_int = 1; - env->exception_next_eip = -1; - if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile, "INTR"); - break; - case SVM_EVTINJ_TYPE_NMI: - env->exception_index = vector; - env->error_code = event_inj_err; - env->exception_is_int = 1; - env->exception_next_eip = EIP; - if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile, "NMI"); - break; - case SVM_EVTINJ_TYPE_EXEPT: - env->exception_index = vector; - env->error_code = event_inj_err; - env->exception_is_int = 0; - env->exception_next_eip = -1; - if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile, "EXEPT"); - break; - case SVM_EVTINJ_TYPE_SOFT: - env->exception_index = vector; - env->error_code = event_inj_err; - env->exception_is_int = 1; - env->exception_next_eip = EIP; - if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile, "SOFT"); - break; - } - if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile, " %#x %#x\n", env->exception_index, env->error_code); - } - if ((int_ctl & V_IRQ_MASK) || (env->intercept & INTERCEPT_VINTR)) { - env->interrupt_request |= CPU_INTERRUPT_VIRQ; - } - - cpu_loop_exit(); -} - -void helper_vmmcall(void) -{ - if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile,"vmmcall!\n"); -} - -void helper_vmload(target_ulong addr) -{ - if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile,"vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", - addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)), - env->segs[R_FS].base); - - SVM_LOAD_SEG2(addr, segs[R_FS], fs); - SVM_LOAD_SEG2(addr, segs[R_GS], gs); - SVM_LOAD_SEG2(addr, tr, tr); - SVM_LOAD_SEG2(addr, ldt, ldtr); - -#ifdef TARGET_X86_64 - env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base)); - env->lstar = ldq_phys(addr + offsetof(struct vmcb, save.lstar)); - env->cstar = ldq_phys(addr + offsetof(struct vmcb, save.cstar)); - env->fmask = ldq_phys(addr + offsetof(struct vmcb, save.sfmask)); -#endif - env->star = ldq_phys(addr + offsetof(struct vmcb, save.star)); - env->sysenter_cs = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_cs)); - env->sysenter_esp = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_esp)); - env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_eip)); -} - -void helper_vmsave(target_ulong addr) -{ - if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile,"vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", - addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)), - env->segs[R_FS].base); - - SVM_SAVE_SEG(addr, segs[R_FS], fs); - SVM_SAVE_SEG(addr, segs[R_GS], gs); - SVM_SAVE_SEG(addr, tr, tr); - SVM_SAVE_SEG(addr, ldt, ldtr); - -#ifdef TARGET_X86_64 - stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base), env->kernelgsbase); - stq_phys(addr + offsetof(struct vmcb, save.lstar), env->lstar); - stq_phys(addr + offsetof(struct vmcb, save.cstar), env->cstar); - stq_phys(addr + offsetof(struct vmcb, save.sfmask), env->fmask); -#endif - stq_phys(addr + offsetof(struct vmcb, save.star), env->star); - stq_phys(addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs); - stq_phys(addr + offsetof(struct vmcb, save.sysenter_esp), env->sysenter_esp); - stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_eip); -} - -void helper_skinit(void) -{ - if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile,"skinit!\n"); -} - -void helper_invlpga(void) -{ - tlb_flush(env, 0); -} - -int svm_check_intercept_param(uint32_t type, uint64_t param) -{ - switch(type) { - case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8: - if (INTERCEPTEDw(_cr_read, (1 << (type - SVM_EXIT_READ_CR0)))) { - vmexit(type, param); - return 1; - } - break; - case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 8: - if (INTERCEPTEDw(_dr_read, (1 << (type - SVM_EXIT_READ_DR0)))) { - vmexit(type, param); - return 1; - } - break; - case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8: - if (INTERCEPTEDw(_cr_write, (1 << (type - SVM_EXIT_WRITE_CR0)))) { - vmexit(type, param); - return 1; - } - break; - case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 8: - if (INTERCEPTEDw(_dr_write, (1 << (type - SVM_EXIT_WRITE_DR0)))) { - vmexit(type, param); - return 1; - } - break; - case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 16: - if (INTERCEPTEDl(_exceptions, (1 << (type - SVM_EXIT_EXCP_BASE)))) { - vmexit(type, param); - return 1; - } - break; - case SVM_EXIT_IOIO: - if (INTERCEPTED(1ULL << INTERCEPT_IOIO_PROT)) { - /* FIXME: this should be read in at vmrun (faster this way?) */ - uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa)); - uint16_t port = (uint16_t) (param >> 16); - - uint16_t mask = (1 << ((param >> 4) & 7)) - 1; - if(lduw_phys(addr + port / 8) & (mask << (port & 7))) - vmexit(type, param); - } - break; - - case SVM_EXIT_MSR: - if (INTERCEPTED(1ULL << INTERCEPT_MSR_PROT)) { - /* FIXME: this should be read in at vmrun (faster this way?) */ - uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa)); - switch((uint32_t)ECX) { - case 0 ... 0x1fff: - T0 = (ECX * 2) % 8; - T1 = ECX / 8; - break; - case 0xc0000000 ... 0xc0001fff: - T0 = (8192 + ECX - 0xc0000000) * 2; - T1 = (T0 / 8); - T0 %= 8; - break; - case 0xc0010000 ... 0xc0011fff: - T0 = (16384 + ECX - 0xc0010000) * 2; - T1 = (T0 / 8); - T0 %= 8; - break; - default: - vmexit(type, param); - return 1; - } - if (ldub_phys(addr + T1) & ((1 << param) << T0)) - vmexit(type, param); - return 1; - } - break; - default: - if (INTERCEPTED((1ULL << ((type - SVM_EXIT_INTR) + INTERCEPT_INTR)))) { - vmexit(type, param); - return 1; - } - break; - } - return 0; -} - -void vmexit(uint64_t exit_code, uint64_t exit_info_1) -{ - uint32_t int_ctl; - - if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile,"vmexit(%016" PRIx64 ", %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n", - exit_code, exit_info_1, - ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)), - EIP); - - if(env->hflags & HF_INHIBIT_IRQ_MASK) { - stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), SVM_INTERRUPT_SHADOW_MASK); - env->hflags &= ~HF_INHIBIT_IRQ_MASK; - } else { - stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0); - } - - /* Save the VM state in the vmcb */ - SVM_SAVE_SEG(env->vm_vmcb, segs[R_ES], es); - SVM_SAVE_SEG(env->vm_vmcb, segs[R_CS], cs); - SVM_SAVE_SEG(env->vm_vmcb, segs[R_SS], ss); - SVM_SAVE_SEG(env->vm_vmcb, segs[R_DS], ds); - - stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), env->gdt.base); - stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit); - - stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), env->idt.base); - stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), env->idt.limit); - - stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer); - stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]); - stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]); - stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]); - stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]); - - if ((int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl))) & V_INTR_MASKING_MASK) { - int_ctl &= ~V_TPR_MASK; - int_ctl |= env->cr[8] & V_TPR_MASK; - stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl); - } - - stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags), compute_eflags()); - stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip); - stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP); - stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX); - stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]); - stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]); - stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl), env->hflags & HF_CPL_MASK); - - /* Reload the host state from vm_hsave */ - env->hflags &= ~HF_HIF_MASK; - env->intercept = 0; - env->intercept_exceptions = 0; - env->interrupt_request &= ~CPU_INTERRUPT_VIRQ; - - env->gdt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base)); - env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit)); - - env->idt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base)); - env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit)); - - cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0)) | CR0_PE_MASK); - cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4))); - cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3))); - if (int_ctl & V_INTR_MASKING_MASK) - env->cr[8] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr8)); - /* we need to set the efer after the crs so the hidden flags get set properly */ -#ifdef TARGET_X86_64 - env->efer = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer)); - env->hflags &= ~HF_LMA_MASK; - if (env->efer & MSR_EFER_LMA) - env->hflags |= HF_LMA_MASK; -#endif - - env->eflags = 0; - load_eflags(ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags)), - ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); - CC_OP = CC_OP_EFLAGS; - - SVM_LOAD_SEG(env->vm_hsave, ES, es); - SVM_LOAD_SEG(env->vm_hsave, CS, cs); - SVM_LOAD_SEG(env->vm_hsave, SS, ss); - SVM_LOAD_SEG(env->vm_hsave, DS, ds); - - EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip)); - ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp)); - EAX = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax)); - - env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6)); - env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7)); - - /* other setups */ - cpu_x86_set_cpl(env, 0); - stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code_hi), (uint32_t)(exit_code >> 32)); - stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code); - stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1); - - helper_clgi(); - /* FIXME: Resets the current ASID register to zero (host ASID). */ - - /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */ - - /* Clears the TSC_OFFSET inside the processor. */ - - /* If the host is in PAE mode, the processor reloads the host's PDPEs - from the page table indicated the host's CR3. If the PDPEs contain - illegal state, the processor causes a shutdown. */ - - /* Forces CR0.PE = 1, RFLAGS.VM = 0. */ - env->cr[0] |= CR0_PE_MASK; - env->eflags &= ~VM_MASK; - - /* Disables all breakpoints in the host DR7 register. */ - - /* Checks the reloaded host state for consistency. */ - - /* If the host's rIP reloaded by #VMEXIT is outside the limit of the - host's code segment or non-canonical (in the case of long mode), a - #GP fault is delivered inside the host.) */ - - /* remove any pending exception */ - env->exception_index = -1; - env->error_code = 0; - env->old_exception = -1; - - regs_to_env(); - cpu_loop_exit(); -} - -#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/helper.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/helper.h --- qemu-0.9.1/target-i386/helper.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-i386/helper.h 2008-09-25 19:16:18.000000000 +0100 @@ -0,0 +1,220 @@ +#ifndef DEF_HELPER +#define DEF_HELPER(ret, name, params) ret name params; +#endif + +DEF_HELPER(void, helper_lock, (void)) +DEF_HELPER(void, helper_unlock, (void)) +DEF_HELPER(void, helper_write_eflags, (target_ulong t0, uint32_t update_mask)) +DEF_HELPER(target_ulong, helper_read_eflags, (void)) +DEF_HELPER(void, helper_divb_AL, (target_ulong t0)) +DEF_HELPER(void, helper_idivb_AL, (target_ulong t0)) +DEF_HELPER(void, helper_divw_AX, (target_ulong t0)) +DEF_HELPER(void, helper_idivw_AX, (target_ulong t0)) +DEF_HELPER(void, helper_divl_EAX, (target_ulong t0)) +DEF_HELPER(void, helper_idivl_EAX, (target_ulong t0)) +#ifdef TARGET_X86_64 +DEF_HELPER(void, helper_mulq_EAX_T0, (target_ulong t0)) +DEF_HELPER(void, helper_imulq_EAX_T0, (target_ulong t0)) +DEF_HELPER(target_ulong, helper_imulq_T0_T1, (target_ulong t0, target_ulong t1)) +DEF_HELPER(void, helper_divq_EAX, (target_ulong t0)) +DEF_HELPER(void, helper_idivq_EAX, (target_ulong t0)) +#endif + +DEF_HELPER(void, helper_aam, (int base)) +DEF_HELPER(void, helper_aad, (int base)) +DEF_HELPER(void, helper_aaa, (void)) +DEF_HELPER(void, helper_aas, (void)) +DEF_HELPER(void, helper_daa, (void)) +DEF_HELPER(void, helper_das, (void)) + +DEF_HELPER(target_ulong, helper_lsl, (target_ulong selector1)) +DEF_HELPER(target_ulong, helper_lar, (target_ulong selector1)) +DEF_HELPER(void, helper_verr, (target_ulong selector1)) +DEF_HELPER(void, helper_verw, (target_ulong selector1)) +DEF_HELPER(void, helper_lldt, (int selector)) +DEF_HELPER(void, helper_ltr, (int selector)) +DEF_HELPER(void, helper_load_seg, (int seg_reg, int selector)) +DEF_HELPER(void, helper_ljmp_protected, (int new_cs, target_ulong new_eip, + int next_eip_addend)) +DEF_HELPER(void, helper_lcall_real, (int new_cs, target_ulong new_eip1, + int shift, int next_eip)) +DEF_HELPER(void, helper_lcall_protected, (int new_cs, target_ulong new_eip, + int shift, int next_eip_addend)) +DEF_HELPER(void, helper_iret_real, (int shift)) +DEF_HELPER(void, helper_iret_protected, (int shift, int next_eip)) +DEF_HELPER(void, helper_lret_protected, (int shift, int addend)) +DEF_HELPER(target_ulong, helper_read_crN, (int reg)) +DEF_HELPER(void, helper_write_crN, (int reg, target_ulong t0)) +DEF_HELPER(void, helper_lmsw, (target_ulong t0)) +DEF_HELPER(void, helper_clts, (void)) +DEF_HELPER(void, helper_movl_drN_T0, (int reg, target_ulong t0)) +DEF_HELPER(void, helper_invlpg, (target_ulong addr)) + +DEF_HELPER(void, helper_enter_level, (int level, int data32, target_ulong t1)) +#ifdef TARGET_X86_64 +DEF_HELPER(void, helper_enter64_level, (int level, int data64, target_ulong t1)) +#endif +DEF_HELPER(void, helper_sysenter, (void)) +DEF_HELPER(void, helper_sysexit, (int dflag)) +#ifdef TARGET_X86_64 +DEF_HELPER(void, helper_syscall, (int next_eip_addend)) +DEF_HELPER(void, helper_sysret, (int dflag)) +#endif +DEF_HELPER(void, helper_hlt, (int next_eip_addend)) +DEF_HELPER(void, helper_monitor, (target_ulong ptr)) +DEF_HELPER(void, helper_mwait, (int next_eip_addend)) +DEF_HELPER(void, helper_debug, (void)) +DEF_HELPER(void, helper_raise_interrupt, (int intno, int next_eip_addend)) +DEF_HELPER(void, helper_raise_exception, (int exception_index)) +DEF_HELPER(void, helper_cli, (void)) +DEF_HELPER(void, helper_sti, (void)) +DEF_HELPER(void, helper_set_inhibit_irq, (void)) +DEF_HELPER(void, helper_reset_inhibit_irq, (void)) +DEF_HELPER(void, helper_boundw, (target_ulong a0, int v)) +DEF_HELPER(void, helper_boundl, (target_ulong a0, int v)) +DEF_HELPER(void, helper_rsm, (void)) +DEF_HELPER(void, helper_into, (int next_eip_addend)) +DEF_HELPER(void, helper_cmpxchg8b, (target_ulong a0)) +#ifdef TARGET_X86_64 +DEF_HELPER(void, helper_cmpxchg16b, (target_ulong a0)) +#endif +DEF_HELPER(void, helper_single_step, (void)) +DEF_HELPER(void, helper_cpuid, (void)) +DEF_HELPER(void, helper_rdtsc, (void)) +DEF_HELPER(void, helper_rdpmc, (void)) +DEF_HELPER(void, helper_rdmsr, (void)) +DEF_HELPER(void, helper_wrmsr, (void)) + +DEF_HELPER(void, helper_check_iob, (uint32_t t0)) +DEF_HELPER(void, helper_check_iow, (uint32_t t0)) +DEF_HELPER(void, helper_check_iol, (uint32_t t0)) +DEF_HELPER(void, helper_outb, (uint32_t port, uint32_t data)) +DEF_HELPER(target_ulong, helper_inb, (uint32_t port)) +DEF_HELPER(void, helper_outw, (uint32_t port, uint32_t data)) +DEF_HELPER(target_ulong, helper_inw, (uint32_t port)) +DEF_HELPER(void, helper_outl, (uint32_t port, uint32_t data)) +DEF_HELPER(target_ulong, helper_inl, (uint32_t port)) + +DEF_HELPER(void, helper_svm_check_intercept_param, (uint32_t type, uint64_t param)) +DEF_HELPER(void, helper_vmexit, (uint32_t exit_code, uint64_t exit_info_1)) +DEF_HELPER(void, helper_svm_check_io, (uint32_t port, uint32_t param, + uint32_t next_eip_addend)) +DEF_HELPER(void, helper_vmrun, (int aflag, int next_eip_addend)) +DEF_HELPER(void, helper_vmmcall, (void)) +DEF_HELPER(void, helper_vmload, (int aflag)) +DEF_HELPER(void, helper_vmsave, (int aflag)) +DEF_HELPER(void, helper_stgi, (void)) +DEF_HELPER(void, helper_clgi, (void)) +DEF_HELPER(void, helper_skinit, (void)) +DEF_HELPER(void, helper_invlpga, (int aflag)) + +/* x86 FPU */ + +DEF_HELPER(void, helper_flds_FT0, (uint32_t val)) +DEF_HELPER(void, helper_fldl_FT0, (uint64_t val)) +DEF_HELPER(void, helper_fildl_FT0, (int32_t val)) +DEF_HELPER(void, helper_flds_ST0, (uint32_t val)) +DEF_HELPER(void, helper_fldl_ST0, (uint64_t val)) +DEF_HELPER(void, helper_fildl_ST0, (int32_t val)) +DEF_HELPER(void, helper_fildll_ST0, (int64_t val)) +DEF_HELPER(uint32_t, helper_fsts_ST0, (void)) +DEF_HELPER(uint64_t, helper_fstl_ST0, (void)) +DEF_HELPER(int32_t, helper_fist_ST0, (void)) +DEF_HELPER(int32_t, helper_fistl_ST0, (void)) +DEF_HELPER(int64_t, helper_fistll_ST0, (void)) +DEF_HELPER(int32_t, helper_fistt_ST0, (void)) +DEF_HELPER(int32_t, helper_fisttl_ST0, (void)) +DEF_HELPER(int64_t, helper_fisttll_ST0, (void)) +DEF_HELPER(void, helper_fldt_ST0, (target_ulong ptr)) +DEF_HELPER(void, helper_fstt_ST0, (target_ulong ptr)) +DEF_HELPER(void, helper_fpush, (void)) +DEF_HELPER(void, helper_fpop, (void)) +DEF_HELPER(void, helper_fdecstp, (void)) +DEF_HELPER(void, helper_fincstp, (void)) +DEF_HELPER(void, helper_ffree_STN, (int st_index)) +DEF_HELPER(void, helper_fmov_ST0_FT0, (void)) +DEF_HELPER(void, helper_fmov_FT0_STN, (int st_index)) +DEF_HELPER(void, helper_fmov_ST0_STN, (int st_index)) +DEF_HELPER(void, helper_fmov_STN_ST0, (int st_index)) +DEF_HELPER(void, helper_fxchg_ST0_STN, (int st_index)) +DEF_HELPER(void, helper_fcom_ST0_FT0, (void)) +DEF_HELPER(void, helper_fucom_ST0_FT0, (void)) +DEF_HELPER(void, helper_fcomi_ST0_FT0, (void)) +DEF_HELPER(void, helper_fucomi_ST0_FT0, (void)) +DEF_HELPER(void, helper_fadd_ST0_FT0, (void)) +DEF_HELPER(void, helper_fmul_ST0_FT0, (void)) +DEF_HELPER(void, helper_fsub_ST0_FT0, (void)) +DEF_HELPER(void, helper_fsubr_ST0_FT0, (void)) +DEF_HELPER(void, helper_fdiv_ST0_FT0, (void)) +DEF_HELPER(void, helper_fdivr_ST0_FT0, (void)) +DEF_HELPER(void, helper_fadd_STN_ST0, (int st_index)) +DEF_HELPER(void, helper_fmul_STN_ST0, (int st_index)) +DEF_HELPER(void, helper_fsub_STN_ST0, (int st_index)) +DEF_HELPER(void, helper_fsubr_STN_ST0, (int st_index)) +DEF_HELPER(void, helper_fdiv_STN_ST0, (int st_index)) +DEF_HELPER(void, helper_fdivr_STN_ST0, (int st_index)) +DEF_HELPER(void, helper_fchs_ST0, (void)) +DEF_HELPER(void, helper_fabs_ST0, (void)) +DEF_HELPER(void, helper_fxam_ST0, (void)) +DEF_HELPER(void, helper_fld1_ST0, (void)) +DEF_HELPER(void, helper_fldl2t_ST0, (void)) +DEF_HELPER(void, helper_fldl2e_ST0, (void)) +DEF_HELPER(void, helper_fldpi_ST0, (void)) +DEF_HELPER(void, helper_fldlg2_ST0, (void)) +DEF_HELPER(void, helper_fldln2_ST0, (void)) +DEF_HELPER(void, helper_fldz_ST0, (void)) +DEF_HELPER(void, helper_fldz_FT0, (void)) +DEF_HELPER(uint32_t, helper_fnstsw, (void)) +DEF_HELPER(uint32_t, helper_fnstcw, (void)) +DEF_HELPER(void, helper_fldcw, (uint32_t val)) +DEF_HELPER(void, helper_fclex, (void)) +DEF_HELPER(void, helper_fwait, (void)) +DEF_HELPER(void, helper_fninit, (void)) +DEF_HELPER(void, helper_fbld_ST0, (target_ulong ptr)) +DEF_HELPER(void, helper_fbst_ST0, (target_ulong ptr)) +DEF_HELPER(void, helper_f2xm1, (void)) +DEF_HELPER(void, helper_fyl2x, (void)) +DEF_HELPER(void, helper_fptan, (void)) +DEF_HELPER(void, helper_fpatan, (void)) +DEF_HELPER(void, helper_fxtract, (void)) +DEF_HELPER(void, helper_fprem1, (void)) +DEF_HELPER(void, helper_fprem, (void)) +DEF_HELPER(void, helper_fyl2xp1, (void)) +DEF_HELPER(void, helper_fsqrt, (void)) +DEF_HELPER(void, helper_fsincos, (void)) +DEF_HELPER(void, helper_frndint, (void)) +DEF_HELPER(void, helper_fscale, (void)) +DEF_HELPER(void, helper_fsin, (void)) +DEF_HELPER(void, helper_fcos, (void)) +DEF_HELPER(void, helper_fstenv, (target_ulong ptr, int data32)) +DEF_HELPER(void, helper_fldenv, (target_ulong ptr, int data32)) +DEF_HELPER(void, helper_fsave, (target_ulong ptr, int data32)) +DEF_HELPER(void, helper_frstor, (target_ulong ptr, int data32)) +DEF_HELPER(void, helper_fxsave, (target_ulong ptr, int data64)) +DEF_HELPER(void, helper_fxrstor, (target_ulong ptr, int data64)) +DEF_HELPER(target_ulong, helper_bsf, (target_ulong t0)) +DEF_HELPER(target_ulong, helper_bsr, (target_ulong t0)) + +/* MMX/SSE */ + +DEF_HELPER(void, helper_enter_mmx, (void)) +DEF_HELPER(void, helper_emms, (void)) +DEF_HELPER(void, helper_movq, (uint64_t *d, uint64_t *s)) + +#define SHIFT 0 +#include "ops_sse_header.h" +#define SHIFT 1 +#include "ops_sse_header.h" + +DEF_HELPER(target_ulong, helper_rclb, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, helper_rclw, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, helper_rcll, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, helper_rcrb, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, helper_rcrw, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, helper_rcrl, (target_ulong t0, target_ulong t1)) +#ifdef TARGET_X86_64 +DEF_HELPER(target_ulong, helper_rclq, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, helper_rcrq, (target_ulong t0, target_ulong t1)) +#endif + +#undef DEF_HELPER diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/helper_template.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/helper_template.h --- qemu-0.9.1/target-i386/helper_template.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-i386/helper_template.h 2008-05-25 18:26:41.000000000 +0100 @@ -0,0 +1,335 @@ +/* + * i386 helpers + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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 + */ +#define DATA_BITS (1 << (3 + SHIFT)) +#define SHIFT_MASK (DATA_BITS - 1) +#define SIGN_MASK (((target_ulong)1) << (DATA_BITS - 1)) +#if DATA_BITS <= 32 +#define SHIFT1_MASK 0x1f +#else +#define SHIFT1_MASK 0x3f +#endif + +#if DATA_BITS == 8 +#define SUFFIX b +#define DATA_TYPE uint8_t +#define DATA_STYPE int8_t +#define DATA_MASK 0xff +#elif DATA_BITS == 16 +#define SUFFIX w +#define DATA_TYPE uint16_t +#define DATA_STYPE int16_t +#define DATA_MASK 0xffff +#elif DATA_BITS == 32 +#define SUFFIX l +#define DATA_TYPE uint32_t +#define DATA_STYPE int32_t +#define DATA_MASK 0xffffffff +#elif DATA_BITS == 64 +#define SUFFIX q +#define DATA_TYPE uint64_t +#define DATA_STYPE int64_t +#define DATA_MASK 0xffffffffffffffffULL +#else +#error unhandled operand size +#endif + +/* dynamic flags computation */ + +static int glue(compute_all_add, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + target_long src1, src2; + src1 = CC_SRC; + src2 = CC_DST - CC_SRC; + cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_add, SUFFIX)(void) +{ + int cf; + target_long src1; + src1 = CC_SRC; + cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1; + return cf; +} + +static int glue(compute_all_adc, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + target_long src1, src2; + src1 = CC_SRC; + src2 = CC_DST - CC_SRC - 1; + cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_adc, SUFFIX)(void) +{ + int cf; + target_long src1; + src1 = CC_SRC; + cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1; + return cf; +} + +static int glue(compute_all_sub, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + target_long src1, src2; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; + cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_sub, SUFFIX)(void) +{ + int cf; + target_long src1, src2; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; + cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; + return cf; +} + +static int glue(compute_all_sbb, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + target_long src1, src2; + src1 = CC_DST + CC_SRC + 1; + src2 = CC_SRC; + cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_sbb, SUFFIX)(void) +{ + int cf; + target_long src1, src2; + src1 = CC_DST + CC_SRC + 1; + src2 = CC_SRC; + cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; + return cf; +} + +static int glue(compute_all_logic, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + cf = 0; + pf = parity_table[(uint8_t)CC_DST]; + af = 0; + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = 0; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_logic, SUFFIX)(void) +{ + return 0; +} + +static int glue(compute_all_inc, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + target_long src1, src2; + src1 = CC_DST - 1; + src2 = 1; + cf = CC_SRC; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = ((CC_DST & DATA_MASK) == SIGN_MASK) << 11; + return cf | pf | af | zf | sf | of; +} + +#if DATA_BITS == 32 +static int glue(compute_c_inc, SUFFIX)(void) +{ + return CC_SRC; +} +#endif + +static int glue(compute_all_dec, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + target_long src1, src2; + src1 = CC_DST + 1; + src2 = 1; + cf = CC_SRC; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = ((CC_DST & DATA_MASK) == ((target_ulong)SIGN_MASK - 1)) << 11; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_all_shl, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + cf = (CC_SRC >> (DATA_BITS - 1)) & CC_C; + pf = parity_table[(uint8_t)CC_DST]; + af = 0; /* undefined */ + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + /* of is defined if shift count == 1 */ + of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_shl, SUFFIX)(void) +{ + return (CC_SRC >> (DATA_BITS - 1)) & CC_C; +} + +#if DATA_BITS == 32 +static int glue(compute_c_sar, SUFFIX)(void) +{ + return CC_SRC & 1; +} +#endif + +static int glue(compute_all_sar, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + cf = CC_SRC & 1; + pf = parity_table[(uint8_t)CC_DST]; + af = 0; /* undefined */ + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + /* of is defined if shift count == 1 */ + of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; + return cf | pf | af | zf | sf | of; +} + +#if DATA_BITS == 32 +static int glue(compute_c_mul, SUFFIX)(void) +{ + int cf; + cf = (CC_SRC != 0); + return cf; +} +#endif + +/* NOTE: we compute the flags like the P4. On olders CPUs, only OF and + CF are modified and it is slower to do that. */ +static int glue(compute_all_mul, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + cf = (CC_SRC != 0); + pf = parity_table[(uint8_t)CC_DST]; + af = 0; /* undefined */ + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = cf << 11; + return cf | pf | af | zf | sf | of; +} + +/* shifts */ + +target_ulong glue(helper_rcl, SUFFIX)(target_ulong t0, target_ulong t1) +{ + int count, eflags; + target_ulong src; + target_long res; + + count = t1 & SHIFT1_MASK; +#if DATA_BITS == 16 + count = rclw_table[count]; +#elif DATA_BITS == 8 + count = rclb_table[count]; +#endif + if (count) { + eflags = cc_table[CC_OP].compute_all(); + t0 &= DATA_MASK; + src = t0; + res = (t0 << count) | ((target_ulong)(eflags & CC_C) << (count - 1)); + if (count > 1) + res |= t0 >> (DATA_BITS + 1 - count); + t0 = res; + env->cc_tmp = (eflags & ~(CC_C | CC_O)) | + (lshift(src ^ t0, 11 - (DATA_BITS - 1)) & CC_O) | + ((src >> (DATA_BITS - count)) & CC_C); + } else { + env->cc_tmp = -1; + } + return t0; +} + +target_ulong glue(helper_rcr, SUFFIX)(target_ulong t0, target_ulong t1) +{ + int count, eflags; + target_ulong src; + target_long res; + + count = t1 & SHIFT1_MASK; +#if DATA_BITS == 16 + count = rclw_table[count]; +#elif DATA_BITS == 8 + count = rclb_table[count]; +#endif + if (count) { + eflags = cc_table[CC_OP].compute_all(); + t0 &= DATA_MASK; + src = t0; + res = (t0 >> count) | ((target_ulong)(eflags & CC_C) << (DATA_BITS - count)); + if (count > 1) + res |= t0 << (DATA_BITS + 1 - count); + t0 = res; + env->cc_tmp = (eflags & ~(CC_C | CC_O)) | + (lshift(src ^ t0, 11 - (DATA_BITS - 1)) & CC_O) | + ((src >> (count - 1)) & CC_C); + } else { + env->cc_tmp = -1; + } + return t0; +} + +#undef DATA_BITS +#undef SHIFT_MASK +#undef SHIFT1_MASK +#undef SIGN_MASK +#undef DATA_TYPE +#undef DATA_STYPE +#undef DATA_MASK +#undef SUFFIX diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/kvm.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/kvm.c --- qemu-0.9.1/target-i386/kvm.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-i386/kvm.c 2008-11-05 16:29:27.000000000 +0000 @@ -0,0 +1,638 @@ +/* + * QEMU KVM support + * + * Copyright (C) 2006-2008 Qumranet Technologies + * Copyright IBM, Corp. 2008 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include +#include +#include + +#include + +#include "qemu-common.h" +#include "sysemu.h" +#include "kvm.h" +#include "cpu.h" + +//#define DEBUG_KVM + +#ifdef DEBUG_KVM +#define dprintf(fmt, ...) \ + do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) +#else +#define dprintf(fmt, ...) \ + do { } while (0) +#endif + +int kvm_arch_init_vcpu(CPUState *env) +{ + struct { + struct kvm_cpuid cpuid; + struct kvm_cpuid_entry entries[100]; + } __attribute__((packed)) cpuid_data; + int limit, i, cpuid_i; + uint32_t eax, ebx, ecx, edx; + + cpuid_i = 0; + + cpu_x86_cpuid(env, 0, &eax, &ebx, &ecx, &edx); + limit = eax; + + for (i = 0; i <= limit; i++) { + struct kvm_cpuid_entry *c = &cpuid_data.entries[cpuid_i++]; + + cpu_x86_cpuid(env, i, &eax, &ebx, &ecx, &edx); + c->function = i; + c->eax = eax; + c->ebx = ebx; + c->ecx = ecx; + c->edx = edx; + } + + cpu_x86_cpuid(env, 0x80000000, &eax, &ebx, &ecx, &edx); + limit = eax; + + for (i = 0x80000000; i <= limit; i++) { + struct kvm_cpuid_entry *c = &cpuid_data.entries[cpuid_i++]; + + cpu_x86_cpuid(env, i, &eax, &ebx, &ecx, &edx); + c->function = i; + c->eax = eax; + c->ebx = ebx; + c->ecx = ecx; + c->edx = edx; + } + + cpuid_data.cpuid.nent = cpuid_i; + + return kvm_vcpu_ioctl(env, KVM_SET_CPUID, &cpuid_data); +} + +static int kvm_has_msr_star(CPUState *env) +{ + static int has_msr_star; + int ret; + + /* first time */ + if (has_msr_star == 0) { + struct kvm_msr_list msr_list, *kvm_msr_list; + + has_msr_star = -1; + + /* Obtain MSR list from KVM. These are the MSRs that we must + * save/restore */ + ret = kvm_ioctl(env->kvm_state, KVM_GET_MSR_INDEX_LIST, &msr_list); + if (ret < 0) + return 0; + + msr_list.nmsrs = 0; + kvm_msr_list = qemu_mallocz(sizeof(msr_list) + + msr_list.nmsrs * sizeof(msr_list.indices[0])); + if (kvm_msr_list == NULL) + return 0; + + ret = kvm_ioctl(env->kvm_state, KVM_GET_MSR_INDEX_LIST, kvm_msr_list); + if (ret >= 0) { + int i; + + for (i = 0; i < kvm_msr_list->nmsrs; i++) { + if (kvm_msr_list->indices[i] == MSR_STAR) { + has_msr_star = 1; + break; + } + } + } + + free(kvm_msr_list); + } + + if (has_msr_star == 1) + return 1; + return 0; +} + +int kvm_arch_init(KVMState *s, int smp_cpus) +{ + int ret; + + /* create vm86 tss. KVM uses vm86 mode to emulate 16-bit code + * directly. In order to use vm86 mode, a TSS is needed. Since this + * must be part of guest physical memory, we need to allocate it. Older + * versions of KVM just assumed that it would be at the end of physical + * memory but that doesn't work with more than 4GB of memory. We simply + * refuse to work with those older versions of KVM. */ + ret = kvm_ioctl(s, KVM_CHECK_EXTENSION, (void *)KVM_CAP_SET_TSS_ADDR); + if (ret <= 0) { + fprintf(stderr, "kvm does not support KVM_CAP_SET_TSS_ADDR\n"); + return ret; + } + + /* this address is 3 pages before the bios, and the bios should present + * as unavaible memory. FIXME, need to ensure the e820 map deals with + * this? + */ + return kvm_vm_ioctl(s, KVM_SET_TSS_ADDR, (void *)0xfffbd000); +} + +static void set_v8086_seg(struct kvm_segment *lhs, const SegmentCache *rhs) +{ + lhs->selector = rhs->selector; + lhs->base = rhs->base; + lhs->limit = rhs->limit; + lhs->type = 3; + lhs->present = 1; + lhs->dpl = 3; + lhs->db = 0; + lhs->s = 1; + lhs->l = 0; + lhs->g = 0; + lhs->avl = 0; + lhs->unusable = 0; +} + +static void set_seg(struct kvm_segment *lhs, const SegmentCache *rhs) +{ + unsigned flags = rhs->flags; + lhs->selector = rhs->selector; + lhs->base = rhs->base; + lhs->limit = rhs->limit; + lhs->type = (flags >> DESC_TYPE_SHIFT) & 15; + lhs->present = (flags & DESC_P_MASK) != 0; + lhs->dpl = rhs->selector & 3; + lhs->db = (flags >> DESC_B_SHIFT) & 1; + lhs->s = (flags & DESC_S_MASK) != 0; + lhs->l = (flags >> DESC_L_SHIFT) & 1; + lhs->g = (flags & DESC_G_MASK) != 0; + lhs->avl = (flags & DESC_AVL_MASK) != 0; + lhs->unusable = 0; +} + +static void get_seg(SegmentCache *lhs, const struct kvm_segment *rhs) +{ + lhs->selector = rhs->selector; + lhs->base = rhs->base; + lhs->limit = rhs->limit; + lhs->flags = + (rhs->type << DESC_TYPE_SHIFT) + | (rhs->present * DESC_P_MASK) + | (rhs->dpl << DESC_DPL_SHIFT) + | (rhs->db << DESC_B_SHIFT) + | (rhs->s * DESC_S_MASK) + | (rhs->l << DESC_L_SHIFT) + | (rhs->g * DESC_G_MASK) + | (rhs->avl * DESC_AVL_MASK); +} + +static void kvm_getput_reg(__u64 *kvm_reg, target_ulong *qemu_reg, int set) +{ + if (set) + *kvm_reg = *qemu_reg; + else + *qemu_reg = *kvm_reg; +} + +static int kvm_getput_regs(CPUState *env, int set) +{ + struct kvm_regs regs; + int ret = 0; + + if (!set) { + ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, ®s); + if (ret < 0) + return ret; + } + + kvm_getput_reg(®s.rax, &env->regs[R_EAX], set); + kvm_getput_reg(®s.rbx, &env->regs[R_EBX], set); + kvm_getput_reg(®s.rcx, &env->regs[R_ECX], set); + kvm_getput_reg(®s.rdx, &env->regs[R_EDX], set); + kvm_getput_reg(®s.rsi, &env->regs[R_ESI], set); + kvm_getput_reg(®s.rdi, &env->regs[R_EDI], set); + kvm_getput_reg(®s.rsp, &env->regs[R_ESP], set); + kvm_getput_reg(®s.rbp, &env->regs[R_EBP], set); +#ifdef TARGET_X86_64 + kvm_getput_reg(®s.r8, &env->regs[8], set); + kvm_getput_reg(®s.r9, &env->regs[9], set); + kvm_getput_reg(®s.r10, &env->regs[10], set); + kvm_getput_reg(®s.r11, &env->regs[11], set); + kvm_getput_reg(®s.r12, &env->regs[12], set); + kvm_getput_reg(®s.r13, &env->regs[13], set); + kvm_getput_reg(®s.r14, &env->regs[14], set); + kvm_getput_reg(®s.r15, &env->regs[15], set); +#endif + + kvm_getput_reg(®s.rflags, &env->eflags, set); + kvm_getput_reg(®s.rip, &env->eip, set); + + if (set) + ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, ®s); + + return ret; +} + +static int kvm_put_fpu(CPUState *env) +{ + struct kvm_fpu fpu; + int i; + + memset(&fpu, 0, sizeof fpu); + fpu.fsw = env->fpus & ~(7 << 11); + fpu.fsw |= (env->fpstt & 7) << 11; + fpu.fcw = env->fpuc; + for (i = 0; i < 8; ++i) + fpu.ftwx |= (!env->fptags[i]) << i; + memcpy(fpu.fpr, env->fpregs, sizeof env->fpregs); + memcpy(fpu.xmm, env->xmm_regs, sizeof env->xmm_regs); + fpu.mxcsr = env->mxcsr; + + return kvm_vcpu_ioctl(env, KVM_SET_FPU, &fpu); +} + +static int kvm_put_sregs(CPUState *env) +{ + struct kvm_sregs sregs; + + memcpy(sregs.interrupt_bitmap, + env->interrupt_bitmap, + sizeof(sregs.interrupt_bitmap)); + + if ((env->eflags & VM_MASK)) { + set_v8086_seg(&sregs.cs, &env->segs[R_CS]); + set_v8086_seg(&sregs.ds, &env->segs[R_DS]); + set_v8086_seg(&sregs.es, &env->segs[R_ES]); + set_v8086_seg(&sregs.fs, &env->segs[R_FS]); + set_v8086_seg(&sregs.gs, &env->segs[R_GS]); + set_v8086_seg(&sregs.ss, &env->segs[R_SS]); + } else { + set_seg(&sregs.cs, &env->segs[R_CS]); + set_seg(&sregs.ds, &env->segs[R_DS]); + set_seg(&sregs.es, &env->segs[R_ES]); + set_seg(&sregs.fs, &env->segs[R_FS]); + set_seg(&sregs.gs, &env->segs[R_GS]); + set_seg(&sregs.ss, &env->segs[R_SS]); + + if (env->cr[0] & CR0_PE_MASK) { + /* force ss cpl to cs cpl */ + sregs.ss.selector = (sregs.ss.selector & ~3) | + (sregs.cs.selector & 3); + sregs.ss.dpl = sregs.ss.selector & 3; + } + } + + set_seg(&sregs.tr, &env->tr); + set_seg(&sregs.ldt, &env->ldt); + + sregs.idt.limit = env->idt.limit; + sregs.idt.base = env->idt.base; + sregs.gdt.limit = env->gdt.limit; + sregs.gdt.base = env->gdt.base; + + sregs.cr0 = env->cr[0]; + sregs.cr2 = env->cr[2]; + sregs.cr3 = env->cr[3]; + sregs.cr4 = env->cr[4]; + + sregs.cr8 = cpu_get_apic_tpr(env); + sregs.apic_base = cpu_get_apic_base(env); + + sregs.efer = env->efer; + + return kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs); +} + +static void kvm_msr_entry_set(struct kvm_msr_entry *entry, + uint32_t index, uint64_t value) +{ + entry->index = index; + entry->data = value; +} + +static int kvm_put_msrs(CPUState *env) +{ + struct { + struct kvm_msrs info; + struct kvm_msr_entry entries[100]; + } msr_data; + struct kvm_msr_entry *msrs = msr_data.entries; + int n = 0; + + kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_CS, env->sysenter_cs); + kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_ESP, env->sysenter_esp); + kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_EIP, env->sysenter_eip); + if (kvm_has_msr_star(env)) + kvm_msr_entry_set(&msrs[n++], MSR_STAR, env->star); + kvm_msr_entry_set(&msrs[n++], MSR_IA32_TSC, env->tsc); +#ifdef TARGET_X86_64 + /* FIXME if lm capable */ + kvm_msr_entry_set(&msrs[n++], MSR_CSTAR, env->cstar); + kvm_msr_entry_set(&msrs[n++], MSR_KERNELGSBASE, env->kernelgsbase); + kvm_msr_entry_set(&msrs[n++], MSR_FMASK, env->fmask); + kvm_msr_entry_set(&msrs[n++], MSR_LSTAR, env->lstar); +#endif + msr_data.info.nmsrs = n; + + return kvm_vcpu_ioctl(env, KVM_SET_MSRS, &msr_data); + +} + + +static int kvm_get_fpu(CPUState *env) +{ + struct kvm_fpu fpu; + int i, ret; + + ret = kvm_vcpu_ioctl(env, KVM_GET_FPU, &fpu); + if (ret < 0) + return ret; + + env->fpstt = (fpu.fsw >> 11) & 7; + env->fpus = fpu.fsw; + env->fpuc = fpu.fcw; + for (i = 0; i < 8; ++i) + env->fptags[i] = !((fpu.ftwx >> i) & 1); + memcpy(env->fpregs, fpu.fpr, sizeof env->fpregs); + memcpy(env->xmm_regs, fpu.xmm, sizeof env->xmm_regs); + env->mxcsr = fpu.mxcsr; + + return 0; +} + +static int kvm_get_sregs(CPUState *env) +{ + struct kvm_sregs sregs; + uint32_t hflags; + int ret; + + ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs); + if (ret < 0) + return ret; + + memcpy(env->interrupt_bitmap, + sregs.interrupt_bitmap, + sizeof(sregs.interrupt_bitmap)); + + get_seg(&env->segs[R_CS], &sregs.cs); + get_seg(&env->segs[R_DS], &sregs.ds); + get_seg(&env->segs[R_ES], &sregs.es); + get_seg(&env->segs[R_FS], &sregs.fs); + get_seg(&env->segs[R_GS], &sregs.gs); + get_seg(&env->segs[R_SS], &sregs.ss); + + get_seg(&env->tr, &sregs.tr); + get_seg(&env->ldt, &sregs.ldt); + + env->idt.limit = sregs.idt.limit; + env->idt.base = sregs.idt.base; + env->gdt.limit = sregs.gdt.limit; + env->gdt.base = sregs.gdt.base; + + env->cr[0] = sregs.cr0; + env->cr[2] = sregs.cr2; + env->cr[3] = sregs.cr3; + env->cr[4] = sregs.cr4; + + cpu_set_apic_base(env, sregs.apic_base); + + env->efer = sregs.efer; + //cpu_set_apic_tpr(env, sregs.cr8); + +#define HFLAG_COPY_MASK ~( \ + HF_CPL_MASK | HF_PE_MASK | HF_MP_MASK | HF_EM_MASK | \ + HF_TS_MASK | HF_TF_MASK | HF_VM_MASK | HF_IOPL_MASK | \ + HF_OSFXSR_MASK | HF_LMA_MASK | HF_CS32_MASK | \ + HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK) + + + + hflags = (env->segs[R_CS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK; + hflags |= (env->cr[0] & CR0_PE_MASK) << (HF_PE_SHIFT - CR0_PE_SHIFT); + hflags |= (env->cr[0] << (HF_MP_SHIFT - CR0_MP_SHIFT)) & + (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK); + hflags |= (env->eflags & (HF_TF_MASK | HF_VM_MASK | HF_IOPL_MASK)); + hflags |= (env->cr[4] & CR4_OSFXSR_MASK) << + (HF_OSFXSR_SHIFT - CR4_OSFXSR_SHIFT); + + if (env->efer & MSR_EFER_LMA) { + hflags |= HF_LMA_MASK; + } + + if ((hflags & HF_LMA_MASK) && (env->segs[R_CS].flags & DESC_L_MASK)) { + hflags |= HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK; + } else { + hflags |= (env->segs[R_CS].flags & DESC_B_MASK) >> + (DESC_B_SHIFT - HF_CS32_SHIFT); + hflags |= (env->segs[R_SS].flags & DESC_B_MASK) >> + (DESC_B_SHIFT - HF_SS32_SHIFT); + if (!(env->cr[0] & CR0_PE_MASK) || + (env->eflags & VM_MASK) || + !(hflags & HF_CS32_MASK)) { + hflags |= HF_ADDSEG_MASK; + } else { + hflags |= ((env->segs[R_DS].base | + env->segs[R_ES].base | + env->segs[R_SS].base) != 0) << + HF_ADDSEG_SHIFT; + } + } + env->hflags = (env->hflags & HFLAG_COPY_MASK) | hflags; + env->cc_src = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + env->df = 1 - (2 * ((env->eflags >> 10) & 1)); + env->cc_op = CC_OP_EFLAGS; + env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + + return 0; +} + +static int kvm_get_msrs(CPUState *env) +{ + struct { + struct kvm_msrs info; + struct kvm_msr_entry entries[100]; + } msr_data; + struct kvm_msr_entry *msrs = msr_data.entries; + int ret, i, n; + + n = 0; + msrs[n++].index = MSR_IA32_SYSENTER_CS; + msrs[n++].index = MSR_IA32_SYSENTER_ESP; + msrs[n++].index = MSR_IA32_SYSENTER_EIP; + if (kvm_has_msr_star(env)) + msrs[n++].index = MSR_STAR; + msrs[n++].index = MSR_IA32_TSC; +#ifdef TARGET_X86_64 + /* FIXME lm_capable_kernel */ + msrs[n++].index = MSR_CSTAR; + msrs[n++].index = MSR_KERNELGSBASE; + msrs[n++].index = MSR_FMASK; + msrs[n++].index = MSR_LSTAR; +#endif + msr_data.info.nmsrs = n; + ret = kvm_vcpu_ioctl(env, KVM_GET_MSRS, &msr_data); + if (ret < 0) + return ret; + + for (i = 0; i < ret; i++) { + switch (msrs[i].index) { + case MSR_IA32_SYSENTER_CS: + env->sysenter_cs = msrs[i].data; + break; + case MSR_IA32_SYSENTER_ESP: + env->sysenter_esp = msrs[i].data; + break; + case MSR_IA32_SYSENTER_EIP: + env->sysenter_eip = msrs[i].data; + break; + case MSR_STAR: + env->star = msrs[i].data; + break; +#ifdef TARGET_X86_64 + case MSR_CSTAR: + env->cstar = msrs[i].data; + break; + case MSR_KERNELGSBASE: + env->kernelgsbase = msrs[i].data; + break; + case MSR_FMASK: + env->fmask = msrs[i].data; + break; + case MSR_LSTAR: + env->lstar = msrs[i].data; + break; +#endif + case MSR_IA32_TSC: + env->tsc = msrs[i].data; + break; + } + } + + return 0; +} + +int kvm_arch_put_registers(CPUState *env) +{ + int ret; + + ret = kvm_getput_regs(env, 1); + if (ret < 0) + return ret; + + ret = kvm_put_fpu(env); + if (ret < 0) + return ret; + + ret = kvm_put_sregs(env); + if (ret < 0) + return ret; + + ret = kvm_put_msrs(env); + if (ret < 0) + return ret; + + return 0; +} + +int kvm_arch_get_registers(CPUState *env) +{ + int ret; + + ret = kvm_getput_regs(env, 0); + if (ret < 0) + return ret; + + ret = kvm_get_fpu(env); + if (ret < 0) + return ret; + + ret = kvm_get_sregs(env); + if (ret < 0) + return ret; + + ret = kvm_get_msrs(env); + if (ret < 0) + return ret; + + return 0; +} + +int kvm_arch_pre_run(CPUState *env, struct kvm_run *run) +{ + /* Try to inject an interrupt if the guest can accept it */ + if (run->ready_for_interrupt_injection && + (env->interrupt_request & CPU_INTERRUPT_HARD) && + (env->eflags & IF_MASK)) { + int irq; + + env->interrupt_request &= ~CPU_INTERRUPT_HARD; + irq = cpu_get_pic_interrupt(env); + if (irq >= 0) { + struct kvm_interrupt intr; + intr.irq = irq; + /* FIXME: errors */ + dprintf("injected interrupt %d\n", irq); + kvm_vcpu_ioctl(env, KVM_INTERRUPT, &intr); + } + } + + /* If we have an interrupt but the guest is not ready to receive an + * interrupt, request an interrupt window exit. This will + * cause a return to userspace as soon as the guest is ready to + * receive interrupts. */ + if ((env->interrupt_request & CPU_INTERRUPT_HARD)) + run->request_interrupt_window = 1; + else + run->request_interrupt_window = 0; + + dprintf("setting tpr\n"); + run->cr8 = cpu_get_apic_tpr(env); + + return 0; +} + +int kvm_arch_post_run(CPUState *env, struct kvm_run *run) +{ + if (run->if_flag) + env->eflags |= IF_MASK; + else + env->eflags &= ~IF_MASK; + + cpu_set_apic_tpr(env, run->cr8); + cpu_set_apic_base(env, run->apic_base); + + return 0; +} + +static int kvm_handle_halt(CPUState *env) +{ + if (!((env->interrupt_request & CPU_INTERRUPT_HARD) && + (env->eflags & IF_MASK)) && + !(env->interrupt_request & CPU_INTERRUPT_NMI)) { + env->halted = 1; + env->exception_index = EXCP_HLT; + return 0; + } + + return 1; +} + +int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run) +{ + int ret = 0; + + switch (run->exit_reason) { + case KVM_EXIT_HLT: + dprintf("handle_hlt\n"); + ret = kvm_handle_halt(env); + break; + } + + return ret; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/machine.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/machine.c --- qemu-0.9.1/target-i386/machine.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-i386/machine.c 2008-10-29 14:16:31.000000000 +0000 @@ -0,0 +1,306 @@ +#include "hw/hw.h" +#include "hw/boards.h" +#include "hw/pc.h" +#include "hw/isa.h" + +#include "exec-all.h" + +void register_machines(void) +{ + qemu_register_machine(&pc_machine); + qemu_register_machine(&isapc_machine); +} + +static void cpu_put_seg(QEMUFile *f, SegmentCache *dt) +{ + qemu_put_be32(f, dt->selector); + qemu_put_betl(f, dt->base); + qemu_put_be32(f, dt->limit); + qemu_put_be32(f, dt->flags); +} + +static void cpu_get_seg(QEMUFile *f, SegmentCache *dt) +{ + dt->selector = qemu_get_be32(f); + dt->base = qemu_get_betl(f); + dt->limit = qemu_get_be32(f); + dt->flags = qemu_get_be32(f); +} + +void cpu_save(QEMUFile *f, void *opaque) +{ + CPUState *env = opaque; + uint16_t fptag, fpus, fpuc, fpregs_format; + uint32_t hflags; + int32_t a20_mask; + int i; + + for(i = 0; i < CPU_NB_REGS; i++) + qemu_put_betls(f, &env->regs[i]); + qemu_put_betls(f, &env->eip); + qemu_put_betls(f, &env->eflags); + hflags = env->hflags; /* XXX: suppress most of the redundant hflags */ + qemu_put_be32s(f, &hflags); + + /* FPU */ + fpuc = env->fpuc; + fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + fptag = 0; + for(i = 0; i < 8; i++) { + fptag |= ((!env->fptags[i]) << i); + } + + qemu_put_be16s(f, &fpuc); + qemu_put_be16s(f, &fpus); + qemu_put_be16s(f, &fptag); + +#ifdef USE_X86LDOUBLE + fpregs_format = 0; +#else + fpregs_format = 1; +#endif + qemu_put_be16s(f, &fpregs_format); + + for(i = 0; i < 8; i++) { +#ifdef USE_X86LDOUBLE + { + uint64_t mant; + uint16_t exp; + /* we save the real CPU data (in case of MMX usage only 'mant' + contains the MMX register */ + cpu_get_fp80(&mant, &exp, env->fpregs[i].d); + qemu_put_be64(f, mant); + qemu_put_be16(f, exp); + } +#else + /* if we use doubles for float emulation, we save the doubles to + avoid losing information in case of MMX usage. It can give + problems if the image is restored on a CPU where long + doubles are used instead. */ + qemu_put_be64(f, env->fpregs[i].mmx.MMX_Q(0)); +#endif + } + + for(i = 0; i < 6; i++) + cpu_put_seg(f, &env->segs[i]); + cpu_put_seg(f, &env->ldt); + cpu_put_seg(f, &env->tr); + cpu_put_seg(f, &env->gdt); + cpu_put_seg(f, &env->idt); + + qemu_put_be32s(f, &env->sysenter_cs); + qemu_put_betls(f, &env->sysenter_esp); + qemu_put_betls(f, &env->sysenter_eip); + + qemu_put_betls(f, &env->cr[0]); + qemu_put_betls(f, &env->cr[2]); + qemu_put_betls(f, &env->cr[3]); + qemu_put_betls(f, &env->cr[4]); + + for(i = 0; i < 8; i++) + qemu_put_betls(f, &env->dr[i]); + + /* MMU */ + a20_mask = (int32_t) env->a20_mask; + qemu_put_sbe32s(f, &a20_mask); + + /* XMM */ + qemu_put_be32s(f, &env->mxcsr); + for(i = 0; i < CPU_NB_REGS; i++) { + qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(0)); + qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(1)); + } + +#ifdef TARGET_X86_64 + qemu_put_be64s(f, &env->efer); + qemu_put_be64s(f, &env->star); + qemu_put_be64s(f, &env->lstar); + qemu_put_be64s(f, &env->cstar); + qemu_put_be64s(f, &env->fmask); + qemu_put_be64s(f, &env->kernelgsbase); +#endif + qemu_put_be32s(f, &env->smbase); + + qemu_put_be64s(f, &env->pat); + qemu_put_be32s(f, &env->hflags2); + + qemu_put_be64s(f, &env->vm_hsave); + qemu_put_be64s(f, &env->vm_vmcb); + qemu_put_be64s(f, &env->tsc_offset); + qemu_put_be64s(f, &env->intercept); + qemu_put_be16s(f, &env->intercept_cr_read); + qemu_put_be16s(f, &env->intercept_cr_write); + qemu_put_be16s(f, &env->intercept_dr_read); + qemu_put_be16s(f, &env->intercept_dr_write); + qemu_put_be32s(f, &env->intercept_exceptions); + qemu_put_8s(f, &env->v_tpr); +} + +#ifdef USE_X86LDOUBLE +/* XXX: add that in a FPU generic layer */ +union x86_longdouble { + uint64_t mant; + uint16_t exp; +}; + +#define MANTD1(fp) (fp & ((1LL << 52) - 1)) +#define EXPBIAS1 1023 +#define EXPD1(fp) ((fp >> 52) & 0x7FF) +#define SIGND1(fp) ((fp >> 32) & 0x80000000) + +static void fp64_to_fp80(union x86_longdouble *p, uint64_t temp) +{ + int e; + /* mantissa */ + p->mant = (MANTD1(temp) << 11) | (1LL << 63); + /* exponent + sign */ + e = EXPD1(temp) - EXPBIAS1 + 16383; + e |= SIGND1(temp) >> 16; + p->exp = e; +} +#endif + +int cpu_load(QEMUFile *f, void *opaque, int version_id) +{ + CPUState *env = opaque; + int i, guess_mmx; + uint32_t hflags; + uint16_t fpus, fpuc, fptag, fpregs_format; + int32_t a20_mask; + + if (version_id != 3 && version_id != 4 && version_id != 5 + && version_id != 6 && version_id != 7) + return -EINVAL; + for(i = 0; i < CPU_NB_REGS; i++) + qemu_get_betls(f, &env->regs[i]); + qemu_get_betls(f, &env->eip); + qemu_get_betls(f, &env->eflags); + qemu_get_be32s(f, &hflags); + + qemu_get_be16s(f, &fpuc); + qemu_get_be16s(f, &fpus); + qemu_get_be16s(f, &fptag); + qemu_get_be16s(f, &fpregs_format); + + /* NOTE: we cannot always restore the FPU state if the image come + from a host with a different 'USE_X86LDOUBLE' define. We guess + if we are in an MMX state to restore correctly in that case. */ + guess_mmx = ((fptag == 0xff) && (fpus & 0x3800) == 0); + for(i = 0; i < 8; i++) { + uint64_t mant; + uint16_t exp; + + switch(fpregs_format) { + case 0: + mant = qemu_get_be64(f); + exp = qemu_get_be16(f); +#ifdef USE_X86LDOUBLE + env->fpregs[i].d = cpu_set_fp80(mant, exp); +#else + /* difficult case */ + if (guess_mmx) + env->fpregs[i].mmx.MMX_Q(0) = mant; + else + env->fpregs[i].d = cpu_set_fp80(mant, exp); +#endif + break; + case 1: + mant = qemu_get_be64(f); +#ifdef USE_X86LDOUBLE + { + union x86_longdouble *p; + /* difficult case */ + p = (void *)&env->fpregs[i]; + if (guess_mmx) { + p->mant = mant; + p->exp = 0xffff; + } else { + fp64_to_fp80(p, mant); + } + } +#else + env->fpregs[i].mmx.MMX_Q(0) = mant; +#endif + break; + default: + return -EINVAL; + } + } + + env->fpuc = fpuc; + /* XXX: restore FPU round state */ + env->fpstt = (fpus >> 11) & 7; + env->fpus = fpus & ~0x3800; + fptag ^= 0xff; + for(i = 0; i < 8; i++) { + env->fptags[i] = (fptag >> i) & 1; + } + + for(i = 0; i < 6; i++) + cpu_get_seg(f, &env->segs[i]); + cpu_get_seg(f, &env->ldt); + cpu_get_seg(f, &env->tr); + cpu_get_seg(f, &env->gdt); + cpu_get_seg(f, &env->idt); + + qemu_get_be32s(f, &env->sysenter_cs); + if (version_id >= 7) { + qemu_get_betls(f, &env->sysenter_esp); + qemu_get_betls(f, &env->sysenter_eip); + } else { + env->sysenter_esp = qemu_get_be32(f); + env->sysenter_eip = qemu_get_be32(f); + } + + qemu_get_betls(f, &env->cr[0]); + qemu_get_betls(f, &env->cr[2]); + qemu_get_betls(f, &env->cr[3]); + qemu_get_betls(f, &env->cr[4]); + + for(i = 0; i < 8; i++) + qemu_get_betls(f, &env->dr[i]); + + /* MMU */ + qemu_get_sbe32s(f, &a20_mask); + env->a20_mask = a20_mask; + + qemu_get_be32s(f, &env->mxcsr); + for(i = 0; i < CPU_NB_REGS; i++) { + qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(0)); + qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(1)); + } + +#ifdef TARGET_X86_64 + qemu_get_be64s(f, &env->efer); + qemu_get_be64s(f, &env->star); + qemu_get_be64s(f, &env->lstar); + qemu_get_be64s(f, &env->cstar); + qemu_get_be64s(f, &env->fmask); + qemu_get_be64s(f, &env->kernelgsbase); +#endif + if (version_id >= 4) { + qemu_get_be32s(f, &env->smbase); + } + if (version_id >= 5) { + qemu_get_be64s(f, &env->pat); + qemu_get_be32s(f, &env->hflags2); + if (version_id < 6) + qemu_get_be32s(f, &env->halted); + + qemu_get_be64s(f, &env->vm_hsave); + qemu_get_be64s(f, &env->vm_vmcb); + qemu_get_be64s(f, &env->tsc_offset); + qemu_get_be64s(f, &env->intercept); + qemu_get_be16s(f, &env->intercept_cr_read); + qemu_get_be16s(f, &env->intercept_cr_write); + qemu_get_be16s(f, &env->intercept_dr_read); + qemu_get_be16s(f, &env->intercept_dr_write); + qemu_get_be32s(f, &env->intercept_exceptions); + qemu_get_8s(f, &env->v_tpr); + } + /* XXX: ensure compatiblity for halted bit ? */ + /* XXX: compute redundant hflags bits */ + env->hflags = hflags; + tlb_flush(env, 1); + return 0; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/op.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/op.c --- qemu-0.9.1/target-i386/op.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-i386/op.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,2541 +0,0 @@ -/* - * i386 micro operations - * - * Copyright (c) 2003 Fabrice Bellard - * - * 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 - */ - -#define ASM_SOFTMMU -#include "exec.h" - -/* n must be a constant to be efficient */ -static inline target_long lshift(target_long x, int n) -{ - if (n >= 0) - return x << n; - else - return x >> (-n); -} - -/* we define the various pieces of code used by the JIT */ - -#define REG EAX -#define REGNAME _EAX -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG ECX -#define REGNAME _ECX -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG EDX -#define REGNAME _EDX -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG EBX -#define REGNAME _EBX -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG ESP -#define REGNAME _ESP -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG EBP -#define REGNAME _EBP -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG ESI -#define REGNAME _ESI -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG EDI -#define REGNAME _EDI -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#ifdef TARGET_X86_64 - -#define REG (env->regs[8]) -#define REGNAME _R8 -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG (env->regs[9]) -#define REGNAME _R9 -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG (env->regs[10]) -#define REGNAME _R10 -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG (env->regs[11]) -#define REGNAME _R11 -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG (env->regs[12]) -#define REGNAME _R12 -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG (env->regs[13]) -#define REGNAME _R13 -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG (env->regs[14]) -#define REGNAME _R14 -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG (env->regs[15]) -#define REGNAME _R15 -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#endif - -/* operations with flags */ - -/* update flags with T0 and T1 (add/sub case) */ -void OPPROTO op_update2_cc(void) -{ - CC_SRC = T1; - CC_DST = T0; -} - -/* update flags with T0 (logic operation case) */ -void OPPROTO op_update1_cc(void) -{ - CC_DST = T0; -} - -void OPPROTO op_update_neg_cc(void) -{ - CC_SRC = -T0; - CC_DST = T0; -} - -void OPPROTO op_cmpl_T0_T1_cc(void) -{ - CC_SRC = T1; - CC_DST = T0 - T1; -} - -void OPPROTO op_update_inc_cc(void) -{ - CC_SRC = cc_table[CC_OP].compute_c(); - CC_DST = T0; -} - -void OPPROTO op_testl_T0_T1_cc(void) -{ - CC_DST = T0 & T1; -} - -/* operations without flags */ - -void OPPROTO op_addl_T0_T1(void) -{ - T0 += T1; -} - -void OPPROTO op_orl_T0_T1(void) -{ - T0 |= T1; -} - -void OPPROTO op_andl_T0_T1(void) -{ - T0 &= T1; -} - -void OPPROTO op_subl_T0_T1(void) -{ - T0 -= T1; -} - -void OPPROTO op_xorl_T0_T1(void) -{ - T0 ^= T1; -} - -void OPPROTO op_negl_T0(void) -{ - T0 = -T0; -} - -void OPPROTO op_incl_T0(void) -{ - T0++; -} - -void OPPROTO op_decl_T0(void) -{ - T0--; -} - -void OPPROTO op_notl_T0(void) -{ - T0 = ~T0; -} - -void OPPROTO op_bswapl_T0(void) -{ - T0 = bswap32(T0); -} - -#ifdef TARGET_X86_64 -void OPPROTO op_bswapq_T0(void) -{ - helper_bswapq_T0(); -} -#endif - -/* multiply/divide */ - -/* XXX: add eflags optimizations */ -/* XXX: add non P4 style flags */ - -void OPPROTO op_mulb_AL_T0(void) -{ - unsigned int res; - res = (uint8_t)EAX * (uint8_t)T0; - EAX = (EAX & ~0xffff) | res; - CC_DST = res; - CC_SRC = (res & 0xff00); -} - -void OPPROTO op_imulb_AL_T0(void) -{ - int res; - res = (int8_t)EAX * (int8_t)T0; - EAX = (EAX & ~0xffff) | (res & 0xffff); - CC_DST = res; - CC_SRC = (res != (int8_t)res); -} - -void OPPROTO op_mulw_AX_T0(void) -{ - unsigned int res; - res = (uint16_t)EAX * (uint16_t)T0; - EAX = (EAX & ~0xffff) | (res & 0xffff); - EDX = (EDX & ~0xffff) | ((res >> 16) & 0xffff); - CC_DST = res; - CC_SRC = res >> 16; -} - -void OPPROTO op_imulw_AX_T0(void) -{ - int res; - res = (int16_t)EAX * (int16_t)T0; - EAX = (EAX & ~0xffff) | (res & 0xffff); - EDX = (EDX & ~0xffff) | ((res >> 16) & 0xffff); - CC_DST = res; - CC_SRC = (res != (int16_t)res); -} - -void OPPROTO op_mull_EAX_T0(void) -{ - uint64_t res; - res = (uint64_t)((uint32_t)EAX) * (uint64_t)((uint32_t)T0); - EAX = (uint32_t)res; - EDX = (uint32_t)(res >> 32); - CC_DST = (uint32_t)res; - CC_SRC = (uint32_t)(res >> 32); -} - -void OPPROTO op_imull_EAX_T0(void) -{ - int64_t res; - res = (int64_t)((int32_t)EAX) * (int64_t)((int32_t)T0); - EAX = (uint32_t)(res); - EDX = (uint32_t)(res >> 32); - CC_DST = res; - CC_SRC = (res != (int32_t)res); -} - -void OPPROTO op_imulw_T0_T1(void) -{ - int res; - res = (int16_t)T0 * (int16_t)T1; - T0 = res; - CC_DST = res; - CC_SRC = (res != (int16_t)res); -} - -void OPPROTO op_imull_T0_T1(void) -{ - int64_t res; - res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1); - T0 = res; - CC_DST = res; - CC_SRC = (res != (int32_t)res); -} - -#ifdef TARGET_X86_64 -void OPPROTO op_mulq_EAX_T0(void) -{ - helper_mulq_EAX_T0(); -} - -void OPPROTO op_imulq_EAX_T0(void) -{ - helper_imulq_EAX_T0(); -} - -void OPPROTO op_imulq_T0_T1(void) -{ - helper_imulq_T0_T1(); -} -#endif - -/* division, flags are undefined */ - -void OPPROTO op_divb_AL_T0(void) -{ - unsigned int num, den, q, r; - - num = (EAX & 0xffff); - den = (T0 & 0xff); - if (den == 0) { - raise_exception(EXCP00_DIVZ); - } - q = (num / den); - if (q > 0xff) - raise_exception(EXCP00_DIVZ); - q &= 0xff; - r = (num % den) & 0xff; - EAX = (EAX & ~0xffff) | (r << 8) | q; -} - -void OPPROTO op_idivb_AL_T0(void) -{ - int num, den, q, r; - - num = (int16_t)EAX; - den = (int8_t)T0; - if (den == 0) { - raise_exception(EXCP00_DIVZ); - } - q = (num / den); - if (q != (int8_t)q) - raise_exception(EXCP00_DIVZ); - q &= 0xff; - r = (num % den) & 0xff; - EAX = (EAX & ~0xffff) | (r << 8) | q; -} - -void OPPROTO op_divw_AX_T0(void) -{ - unsigned int num, den, q, r; - - num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); - den = (T0 & 0xffff); - if (den == 0) { - raise_exception(EXCP00_DIVZ); - } - q = (num / den); - if (q > 0xffff) - raise_exception(EXCP00_DIVZ); - q &= 0xffff; - r = (num % den) & 0xffff; - EAX = (EAX & ~0xffff) | q; - EDX = (EDX & ~0xffff) | r; -} - -void OPPROTO op_idivw_AX_T0(void) -{ - int num, den, q, r; - - num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); - den = (int16_t)T0; - if (den == 0) { - raise_exception(EXCP00_DIVZ); - } - q = (num / den); - if (q != (int16_t)q) - raise_exception(EXCP00_DIVZ); - q &= 0xffff; - r = (num % den) & 0xffff; - EAX = (EAX & ~0xffff) | q; - EDX = (EDX & ~0xffff) | r; -} - -void OPPROTO op_divl_EAX_T0(void) -{ - helper_divl_EAX_T0(); -} - -void OPPROTO op_idivl_EAX_T0(void) -{ - helper_idivl_EAX_T0(); -} - -#ifdef TARGET_X86_64 -void OPPROTO op_divq_EAX_T0(void) -{ - helper_divq_EAX_T0(); -} - -void OPPROTO op_idivq_EAX_T0(void) -{ - helper_idivq_EAX_T0(); -} -#endif - -/* constant load & misc op */ - -/* XXX: consistent names */ -void OPPROTO op_movl_T0_imu(void) -{ - T0 = (uint32_t)PARAM1; -} - -void OPPROTO op_movl_T0_im(void) -{ - T0 = (int32_t)PARAM1; -} - -void OPPROTO op_addl_T0_im(void) -{ - T0 += PARAM1; -} - -void OPPROTO op_andl_T0_ffff(void) -{ - T0 = T0 & 0xffff; -} - -void OPPROTO op_andl_T0_im(void) -{ - T0 = T0 & PARAM1; -} - -void OPPROTO op_movl_T0_T1(void) -{ - T0 = T1; -} - -void OPPROTO op_movl_T1_imu(void) -{ - T1 = (uint32_t)PARAM1; -} - -void OPPROTO op_movl_T1_im(void) -{ - T1 = (int32_t)PARAM1; -} - -void OPPROTO op_addl_T1_im(void) -{ - T1 += PARAM1; -} - -void OPPROTO op_movl_T1_A0(void) -{ - T1 = A0; -} - -void OPPROTO op_movl_A0_im(void) -{ - A0 = (uint32_t)PARAM1; -} - -void OPPROTO op_addl_A0_im(void) -{ - A0 = (uint32_t)(A0 + PARAM1); -} - -void OPPROTO op_movl_A0_seg(void) -{ - A0 = (uint32_t)*(target_ulong *)((char *)env + PARAM1); -} - -void OPPROTO op_addl_A0_seg(void) -{ - A0 = (uint32_t)(A0 + *(target_ulong *)((char *)env + PARAM1)); -} - -void OPPROTO op_addl_A0_AL(void) -{ - A0 = (uint32_t)(A0 + (EAX & 0xff)); -} - -#ifdef WORDS_BIGENDIAN -typedef union UREG64 { - struct { uint16_t v3, v2, v1, v0; } w; - struct { uint32_t v1, v0; } l; - uint64_t q; -} UREG64; -#else -typedef union UREG64 { - struct { uint16_t v0, v1, v2, v3; } w; - struct { uint32_t v0, v1; } l; - uint64_t q; -} UREG64; -#endif - -#define PARAMQ1 \ -({\ - UREG64 __p;\ - __p.l.v1 = PARAM1;\ - __p.l.v0 = PARAM2;\ - __p.q;\ -}) - -#ifdef TARGET_X86_64 - -void OPPROTO op_movq_T0_im64(void) -{ - T0 = PARAMQ1; -} - -void OPPROTO op_movq_T1_im64(void) -{ - T1 = PARAMQ1; -} - -void OPPROTO op_movq_A0_im(void) -{ - A0 = (int32_t)PARAM1; -} - -void OPPROTO op_movq_A0_im64(void) -{ - A0 = PARAMQ1; -} - -void OPPROTO op_addq_A0_im(void) -{ - A0 = (A0 + (int32_t)PARAM1); -} - -void OPPROTO op_addq_A0_im64(void) -{ - A0 = (A0 + PARAMQ1); -} - -void OPPROTO op_movq_A0_seg(void) -{ - A0 = *(target_ulong *)((char *)env + PARAM1); -} - -void OPPROTO op_addq_A0_seg(void) -{ - A0 += *(target_ulong *)((char *)env + PARAM1); -} - -void OPPROTO op_addq_A0_AL(void) -{ - A0 = (A0 + (EAX & 0xff)); -} - -#endif - -void OPPROTO op_andl_A0_ffff(void) -{ - A0 = A0 & 0xffff; -} - -/* memory access */ - -#define MEMSUFFIX _raw -#include "ops_mem.h" - -#if !defined(CONFIG_USER_ONLY) -#define MEMSUFFIX _kernel -#include "ops_mem.h" - -#define MEMSUFFIX _user -#include "ops_mem.h" -#endif - -/* indirect jump */ - -void OPPROTO op_jmp_T0(void) -{ - EIP = T0; -} - -void OPPROTO op_movl_eip_im(void) -{ - EIP = (uint32_t)PARAM1; -} - -#ifdef TARGET_X86_64 -void OPPROTO op_movq_eip_im(void) -{ - EIP = (int32_t)PARAM1; -} - -void OPPROTO op_movq_eip_im64(void) -{ - EIP = PARAMQ1; -} -#endif - -void OPPROTO op_hlt(void) -{ - helper_hlt(); -} - -void OPPROTO op_monitor(void) -{ - helper_monitor(); -} - -void OPPROTO op_mwait(void) -{ - helper_mwait(); -} - -void OPPROTO op_debug(void) -{ - env->exception_index = EXCP_DEBUG; - cpu_loop_exit(); -} - -void OPPROTO op_raise_interrupt(void) -{ - int intno, next_eip_addend; - intno = PARAM1; - next_eip_addend = PARAM2; - raise_interrupt(intno, 1, 0, next_eip_addend); -} - -void OPPROTO op_raise_exception(void) -{ - int exception_index; - exception_index = PARAM1; - raise_exception(exception_index); -} - -void OPPROTO op_into(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if (eflags & CC_O) { - raise_interrupt(EXCP04_INTO, 1, 0, PARAM1); - } - FORCE_RET(); -} - -void OPPROTO op_cli(void) -{ - env->eflags &= ~IF_MASK; -} - -void OPPROTO op_sti(void) -{ - env->eflags |= IF_MASK; -} - -void OPPROTO op_set_inhibit_irq(void) -{ - env->hflags |= HF_INHIBIT_IRQ_MASK; -} - -void OPPROTO op_reset_inhibit_irq(void) -{ - env->hflags &= ~HF_INHIBIT_IRQ_MASK; -} - -void OPPROTO op_rsm(void) -{ - helper_rsm(); -} - -#if 0 -/* vm86plus instructions */ -void OPPROTO op_cli_vm(void) -{ - env->eflags &= ~VIF_MASK; -} - -void OPPROTO op_sti_vm(void) -{ - env->eflags |= VIF_MASK; - if (env->eflags & VIP_MASK) { - EIP = PARAM1; - raise_exception(EXCP0D_GPF); - } - FORCE_RET(); -} -#endif - -void OPPROTO op_boundw(void) -{ - int low, high, v; - low = ldsw(A0); - high = ldsw(A0 + 2); - v = (int16_t)T0; - if (v < low || v > high) { - raise_exception(EXCP05_BOUND); - } - FORCE_RET(); -} - -void OPPROTO op_boundl(void) -{ - int low, high, v; - low = ldl(A0); - high = ldl(A0 + 4); - v = T0; - if (v < low || v > high) { - raise_exception(EXCP05_BOUND); - } - FORCE_RET(); -} - -void OPPROTO op_cmpxchg8b(void) -{ - helper_cmpxchg8b(); -} - -void OPPROTO op_single_step(void) -{ - helper_single_step(); -} - -void OPPROTO op_movl_T0_0(void) -{ - T0 = 0; -} - -void OPPROTO op_exit_tb(void) -{ - EXIT_TB(); -} - -/* multiple size ops */ - -#define ldul ldl - -#define SHIFT 0 -#include "ops_template.h" -#undef SHIFT - -#define SHIFT 1 -#include "ops_template.h" -#undef SHIFT - -#define SHIFT 2 -#include "ops_template.h" -#undef SHIFT - -#ifdef TARGET_X86_64 - -#define SHIFT 3 -#include "ops_template.h" -#undef SHIFT - -#endif - -/* sign extend */ - -void OPPROTO op_movsbl_T0_T0(void) -{ - T0 = (int8_t)T0; -} - -void OPPROTO op_movzbl_T0_T0(void) -{ - T0 = (uint8_t)T0; -} - -void OPPROTO op_movswl_T0_T0(void) -{ - T0 = (int16_t)T0; -} - -void OPPROTO op_movzwl_T0_T0(void) -{ - T0 = (uint16_t)T0; -} - -void OPPROTO op_movswl_EAX_AX(void) -{ - EAX = (uint32_t)((int16_t)EAX); -} - -#ifdef TARGET_X86_64 -void OPPROTO op_movslq_T0_T0(void) -{ - T0 = (int32_t)T0; -} - -void OPPROTO op_movslq_RAX_EAX(void) -{ - EAX = (int32_t)EAX; -} -#endif - -void OPPROTO op_movsbw_AX_AL(void) -{ - EAX = (EAX & ~0xffff) | ((int8_t)EAX & 0xffff); -} - -void OPPROTO op_movslq_EDX_EAX(void) -{ - EDX = (uint32_t)((int32_t)EAX >> 31); -} - -void OPPROTO op_movswl_DX_AX(void) -{ - EDX = (EDX & ~0xffff) | (((int16_t)EAX >> 15) & 0xffff); -} - -#ifdef TARGET_X86_64 -void OPPROTO op_movsqo_RDX_RAX(void) -{ - EDX = (int64_t)EAX >> 63; -} -#endif - -/* string ops helpers */ - -void OPPROTO op_addl_ESI_T0(void) -{ - ESI = (uint32_t)(ESI + T0); -} - -void OPPROTO op_addw_ESI_T0(void) -{ - ESI = (ESI & ~0xffff) | ((ESI + T0) & 0xffff); -} - -void OPPROTO op_addl_EDI_T0(void) -{ - EDI = (uint32_t)(EDI + T0); -} - -void OPPROTO op_addw_EDI_T0(void) -{ - EDI = (EDI & ~0xffff) | ((EDI + T0) & 0xffff); -} - -void OPPROTO op_decl_ECX(void) -{ - ECX = (uint32_t)(ECX - 1); -} - -void OPPROTO op_decw_ECX(void) -{ - ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff); -} - -#ifdef TARGET_X86_64 -void OPPROTO op_addq_ESI_T0(void) -{ - ESI = (ESI + T0); -} - -void OPPROTO op_addq_EDI_T0(void) -{ - EDI = (EDI + T0); -} - -void OPPROTO op_decq_ECX(void) -{ - ECX--; -} -#endif - -/* push/pop utils */ - -void op_addl_A0_SS(void) -{ - A0 = (uint32_t)(A0 + env->segs[R_SS].base); -} - -void op_subl_A0_2(void) -{ - A0 = (uint32_t)(A0 - 2); -} - -void op_subl_A0_4(void) -{ - A0 = (uint32_t)(A0 - 4); -} - -void op_addl_ESP_4(void) -{ - ESP = (uint32_t)(ESP + 4); -} - -void op_addl_ESP_2(void) -{ - ESP = (uint32_t)(ESP + 2); -} - -void op_addw_ESP_4(void) -{ - ESP = (ESP & ~0xffff) | ((ESP + 4) & 0xffff); -} - -void op_addw_ESP_2(void) -{ - ESP = (ESP & ~0xffff) | ((ESP + 2) & 0xffff); -} - -void op_addl_ESP_im(void) -{ - ESP = (uint32_t)(ESP + PARAM1); -} - -void op_addw_ESP_im(void) -{ - ESP = (ESP & ~0xffff) | ((ESP + PARAM1) & 0xffff); -} - -#ifdef TARGET_X86_64 -void op_subq_A0_2(void) -{ - A0 -= 2; -} - -void op_subq_A0_8(void) -{ - A0 -= 8; -} - -void op_addq_ESP_8(void) -{ - ESP += 8; -} - -void op_addq_ESP_im(void) -{ - ESP += PARAM1; -} -#endif - -void OPPROTO op_rdtsc(void) -{ - helper_rdtsc(); -} - -void OPPROTO op_rdpmc(void) -{ - helper_rdpmc(); -} - -void OPPROTO op_cpuid(void) -{ - helper_cpuid(); -} - -void OPPROTO op_enter_level(void) -{ - helper_enter_level(PARAM1, PARAM2); -} - -#ifdef TARGET_X86_64 -void OPPROTO op_enter64_level(void) -{ - helper_enter64_level(PARAM1, PARAM2); -} -#endif - -void OPPROTO op_sysenter(void) -{ - helper_sysenter(); -} - -void OPPROTO op_sysexit(void) -{ - helper_sysexit(); -} - -#ifdef TARGET_X86_64 -void OPPROTO op_syscall(void) -{ - helper_syscall(PARAM1); -} - -void OPPROTO op_sysret(void) -{ - helper_sysret(PARAM1); -} -#endif - -void OPPROTO op_rdmsr(void) -{ - helper_rdmsr(); -} - -void OPPROTO op_wrmsr(void) -{ - helper_wrmsr(); -} - -/* bcd */ - -/* XXX: exception */ -void OPPROTO op_aam(void) -{ - int base = PARAM1; - int al, ah; - al = EAX & 0xff; - ah = al / base; - al = al % base; - EAX = (EAX & ~0xffff) | al | (ah << 8); - CC_DST = al; -} - -void OPPROTO op_aad(void) -{ - int base = PARAM1; - int al, ah; - al = EAX & 0xff; - ah = (EAX >> 8) & 0xff; - al = ((ah * base) + al) & 0xff; - EAX = (EAX & ~0xffff) | al; - CC_DST = al; -} - -void OPPROTO op_aaa(void) -{ - int icarry; - int al, ah, af; - int eflags; - - eflags = cc_table[CC_OP].compute_all(); - af = eflags & CC_A; - al = EAX & 0xff; - ah = (EAX >> 8) & 0xff; - - icarry = (al > 0xf9); - if (((al & 0x0f) > 9 ) || af) { - al = (al + 6) & 0x0f; - ah = (ah + 1 + icarry) & 0xff; - eflags |= CC_C | CC_A; - } else { - eflags &= ~(CC_C | CC_A); - al &= 0x0f; - } - EAX = (EAX & ~0xffff) | al | (ah << 8); - CC_SRC = eflags; - FORCE_RET(); -} - -void OPPROTO op_aas(void) -{ - int icarry; - int al, ah, af; - int eflags; - - eflags = cc_table[CC_OP].compute_all(); - af = eflags & CC_A; - al = EAX & 0xff; - ah = (EAX >> 8) & 0xff; - - icarry = (al < 6); - if (((al & 0x0f) > 9 ) || af) { - al = (al - 6) & 0x0f; - ah = (ah - 1 - icarry) & 0xff; - eflags |= CC_C | CC_A; - } else { - eflags &= ~(CC_C | CC_A); - al &= 0x0f; - } - EAX = (EAX & ~0xffff) | al | (ah << 8); - CC_SRC = eflags; - FORCE_RET(); -} - -void OPPROTO op_daa(void) -{ - int al, af, cf; - int eflags; - - eflags = cc_table[CC_OP].compute_all(); - cf = eflags & CC_C; - af = eflags & CC_A; - al = EAX & 0xff; - - eflags = 0; - if (((al & 0x0f) > 9 ) || af) { - al = (al + 6) & 0xff; - eflags |= CC_A; - } - if ((al > 0x9f) || cf) { - al = (al + 0x60) & 0xff; - eflags |= CC_C; - } - EAX = (EAX & ~0xff) | al; - /* well, speed is not an issue here, so we compute the flags by hand */ - eflags |= (al == 0) << 6; /* zf */ - eflags |= parity_table[al]; /* pf */ - eflags |= (al & 0x80); /* sf */ - CC_SRC = eflags; - FORCE_RET(); -} - -void OPPROTO op_das(void) -{ - int al, al1, af, cf; - int eflags; - - eflags = cc_table[CC_OP].compute_all(); - cf = eflags & CC_C; - af = eflags & CC_A; - al = EAX & 0xff; - - eflags = 0; - al1 = al; - if (((al & 0x0f) > 9 ) || af) { - eflags |= CC_A; - if (al < 6 || cf) - eflags |= CC_C; - al = (al - 6) & 0xff; - } - if ((al1 > 0x99) || cf) { - al = (al - 0x60) & 0xff; - eflags |= CC_C; - } - EAX = (EAX & ~0xff) | al; - /* well, speed is not an issue here, so we compute the flags by hand */ - eflags |= (al == 0) << 6; /* zf */ - eflags |= parity_table[al]; /* pf */ - eflags |= (al & 0x80); /* sf */ - CC_SRC = eflags; - FORCE_RET(); -} - -/* segment handling */ - -/* never use it with R_CS */ -void OPPROTO op_movl_seg_T0(void) -{ - load_seg(PARAM1, T0); -} - -/* faster VM86 version */ -void OPPROTO op_movl_seg_T0_vm(void) -{ - int selector; - SegmentCache *sc; - - selector = T0 & 0xffff; - /* env->segs[] access */ - sc = (SegmentCache *)((char *)env + PARAM1); - sc->selector = selector; - sc->base = (selector << 4); -} - -void OPPROTO op_movl_T0_seg(void) -{ - T0 = env->segs[PARAM1].selector; -} - -void OPPROTO op_lsl(void) -{ - helper_lsl(); -} - -void OPPROTO op_lar(void) -{ - helper_lar(); -} - -void OPPROTO op_verr(void) -{ - helper_verr(); -} - -void OPPROTO op_verw(void) -{ - helper_verw(); -} - -void OPPROTO op_arpl(void) -{ - if ((T0 & 3) < (T1 & 3)) { - /* XXX: emulate bug or 0xff3f0000 oring as in bochs ? */ - T0 = (T0 & ~3) | (T1 & 3); - T1 = CC_Z; - } else { - T1 = 0; - } - FORCE_RET(); -} - -void OPPROTO op_arpl_update(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - CC_SRC = (eflags & ~CC_Z) | T1; -} - -/* T0: segment, T1:eip */ -void OPPROTO op_ljmp_protected_T0_T1(void) -{ - helper_ljmp_protected_T0_T1(PARAM1); -} - -void OPPROTO op_lcall_real_T0_T1(void) -{ - helper_lcall_real_T0_T1(PARAM1, PARAM2); -} - -void OPPROTO op_lcall_protected_T0_T1(void) -{ - helper_lcall_protected_T0_T1(PARAM1, PARAM2); -} - -void OPPROTO op_iret_real(void) -{ - helper_iret_real(PARAM1); -} - -void OPPROTO op_iret_protected(void) -{ - helper_iret_protected(PARAM1, PARAM2); -} - -void OPPROTO op_lret_protected(void) -{ - helper_lret_protected(PARAM1, PARAM2); -} - -void OPPROTO op_lldt_T0(void) -{ - helper_lldt_T0(); -} - -void OPPROTO op_ltr_T0(void) -{ - helper_ltr_T0(); -} - -/* CR registers access. */ -void OPPROTO op_movl_crN_T0(void) -{ - helper_movl_crN_T0(PARAM1); -} - -/* These pseudo-opcodes check for SVM intercepts. */ -void OPPROTO op_svm_check_intercept(void) -{ - A0 = PARAM1 & PARAM2; - svm_check_intercept(PARAMQ1); -} - -void OPPROTO op_svm_check_intercept_param(void) -{ - A0 = PARAM1 & PARAM2; - svm_check_intercept_param(PARAMQ1, T1); -} - -void OPPROTO op_svm_vmexit(void) -{ - A0 = PARAM1 & PARAM2; - vmexit(PARAMQ1, T1); -} - -void OPPROTO op_geneflags(void) -{ - CC_SRC = cc_table[CC_OP].compute_all(); -} - -/* This pseudo-opcode checks for IO intercepts. */ -#if !defined(CONFIG_USER_ONLY) -void OPPROTO op_svm_check_intercept_io(void) -{ - A0 = PARAM1 & PARAM2; - /* PARAMQ1 = TYPE (0 = OUT, 1 = IN; 4 = STRING; 8 = REP) - T0 = PORT - T1 = next eip */ - stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), T1); - /* ASIZE does not appear on real hw */ - svm_check_intercept_param(SVM_EXIT_IOIO, - (PARAMQ1 & ~SVM_IOIO_ASIZE_MASK) | - ((T0 & 0xffff) << 16)); -} -#endif - -#if !defined(CONFIG_USER_ONLY) -void OPPROTO op_movtl_T0_cr8(void) -{ - T0 = cpu_get_apic_tpr(env); -} -#endif - -/* DR registers access */ -void OPPROTO op_movl_drN_T0(void) -{ - helper_movl_drN_T0(PARAM1); -} - -void OPPROTO op_lmsw_T0(void) -{ - /* only 4 lower bits of CR0 are modified. PE cannot be set to zero - if already set to one. */ - T0 = (env->cr[0] & ~0xe) | (T0 & 0xf); - helper_movl_crN_T0(0); -} - -void OPPROTO op_invlpg_A0(void) -{ - helper_invlpg(A0); -} - -void OPPROTO op_movl_T0_env(void) -{ - T0 = *(uint32_t *)((char *)env + PARAM1); -} - -void OPPROTO op_movl_env_T0(void) -{ - *(uint32_t *)((char *)env + PARAM1) = T0; -} - -void OPPROTO op_movl_env_T1(void) -{ - *(uint32_t *)((char *)env + PARAM1) = T1; -} - -void OPPROTO op_movtl_T0_env(void) -{ - T0 = *(target_ulong *)((char *)env + PARAM1); -} - -void OPPROTO op_movtl_env_T0(void) -{ - *(target_ulong *)((char *)env + PARAM1) = T0; -} - -void OPPROTO op_movtl_T1_env(void) -{ - T1 = *(target_ulong *)((char *)env + PARAM1); -} - -void OPPROTO op_movtl_env_T1(void) -{ - *(target_ulong *)((char *)env + PARAM1) = T1; -} - -void OPPROTO op_clts(void) -{ - env->cr[0] &= ~CR0_TS_MASK; - env->hflags &= ~HF_TS_MASK; -} - -/* flags handling */ - -void OPPROTO op_goto_tb0(void) -{ - GOTO_TB(op_goto_tb0, PARAM1, 0); -} - -void OPPROTO op_goto_tb1(void) -{ - GOTO_TB(op_goto_tb1, PARAM1, 1); -} - -void OPPROTO op_jmp_label(void) -{ - GOTO_LABEL_PARAM(1); -} - -void OPPROTO op_jnz_T0_label(void) -{ - if (T0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO op_jz_T0_label(void) -{ - if (!T0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -/* slow set cases (compute x86 flags) */ -void OPPROTO op_seto_T0_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - T0 = (eflags >> 11) & 1; -} - -void OPPROTO op_setb_T0_cc(void) -{ - T0 = cc_table[CC_OP].compute_c(); -} - -void OPPROTO op_setz_T0_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - T0 = (eflags >> 6) & 1; -} - -void OPPROTO op_setbe_T0_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - T0 = (eflags & (CC_Z | CC_C)) != 0; -} - -void OPPROTO op_sets_T0_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - T0 = (eflags >> 7) & 1; -} - -void OPPROTO op_setp_T0_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - T0 = (eflags >> 2) & 1; -} - -void OPPROTO op_setl_T0_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - T0 = ((eflags ^ (eflags >> 4)) >> 7) & 1; -} - -void OPPROTO op_setle_T0_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - T0 = (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z)) != 0; -} - -void OPPROTO op_xor_T0_1(void) -{ - T0 ^= 1; -} - -void OPPROTO op_set_cc_op(void) -{ - CC_OP = PARAM1; -} - -void OPPROTO op_mov_T0_cc(void) -{ - T0 = cc_table[CC_OP].compute_all(); -} - -/* XXX: clear VIF/VIP in all ops ? */ - -void OPPROTO op_movl_eflags_T0(void) -{ - load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | NT_MASK)); -} - -void OPPROTO op_movw_eflags_T0(void) -{ - load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | NT_MASK) & 0xffff); -} - -void OPPROTO op_movl_eflags_T0_io(void) -{ - load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK)); -} - -void OPPROTO op_movw_eflags_T0_io(void) -{ - load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK) & 0xffff); -} - -void OPPROTO op_movl_eflags_T0_cpl0(void) -{ - load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK | IOPL_MASK)); -} - -void OPPROTO op_movw_eflags_T0_cpl0(void) -{ - load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK | IOPL_MASK) & 0xffff); -} - -#if 0 -/* vm86plus version */ -void OPPROTO op_movw_eflags_T0_vm(void) -{ - int eflags; - eflags = T0; - CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); - DF = 1 - (2 * ((eflags >> 10) & 1)); - /* we also update some system flags as in user mode */ - env->eflags = (env->eflags & ~(FL_UPDATE_MASK16 | VIF_MASK)) | - (eflags & FL_UPDATE_MASK16); - if (eflags & IF_MASK) { - env->eflags |= VIF_MASK; - if (env->eflags & VIP_MASK) { - EIP = PARAM1; - raise_exception(EXCP0D_GPF); - } - } - FORCE_RET(); -} - -void OPPROTO op_movl_eflags_T0_vm(void) -{ - int eflags; - eflags = T0; - CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); - DF = 1 - (2 * ((eflags >> 10) & 1)); - /* we also update some system flags as in user mode */ - env->eflags = (env->eflags & ~(FL_UPDATE_MASK32 | VIF_MASK)) | - (eflags & FL_UPDATE_MASK32); - if (eflags & IF_MASK) { - env->eflags |= VIF_MASK; - if (env->eflags & VIP_MASK) { - EIP = PARAM1; - raise_exception(EXCP0D_GPF); - } - } - FORCE_RET(); -} -#endif - -/* XXX: compute only O flag */ -void OPPROTO op_movb_eflags_T0(void) -{ - int of; - of = cc_table[CC_OP].compute_all() & CC_O; - CC_SRC = (T0 & (CC_S | CC_Z | CC_A | CC_P | CC_C)) | of; -} - -void OPPROTO op_movl_T0_eflags(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - eflags |= (DF & DF_MASK); - eflags |= env->eflags & ~(VM_MASK | RF_MASK); - T0 = eflags; -} - -/* vm86plus version */ -#if 0 -void OPPROTO op_movl_T0_eflags_vm(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - eflags |= (DF & DF_MASK); - eflags |= env->eflags & ~(VM_MASK | RF_MASK | IF_MASK); - if (env->eflags & VIF_MASK) - eflags |= IF_MASK; - T0 = eflags; -} -#endif - -void OPPROTO op_cld(void) -{ - DF = 1; -} - -void OPPROTO op_std(void) -{ - DF = -1; -} - -void OPPROTO op_clc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - eflags &= ~CC_C; - CC_SRC = eflags; -} - -void OPPROTO op_stc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - eflags |= CC_C; - CC_SRC = eflags; -} - -void OPPROTO op_cmc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - eflags ^= CC_C; - CC_SRC = eflags; -} - -void OPPROTO op_salc(void) -{ - int cf; - cf = cc_table[CC_OP].compute_c(); - EAX = (EAX & ~0xff) | ((-cf) & 0xff); -} - -static int compute_all_eflags(void) -{ - return CC_SRC; -} - -static int compute_c_eflags(void) -{ - return CC_SRC & CC_C; -} - -CCTable cc_table[CC_OP_NB] = { - [CC_OP_DYNAMIC] = { /* should never happen */ }, - - [CC_OP_EFLAGS] = { compute_all_eflags, compute_c_eflags }, - - [CC_OP_MULB] = { compute_all_mulb, compute_c_mull }, - [CC_OP_MULW] = { compute_all_mulw, compute_c_mull }, - [CC_OP_MULL] = { compute_all_mull, compute_c_mull }, - - [CC_OP_ADDB] = { compute_all_addb, compute_c_addb }, - [CC_OP_ADDW] = { compute_all_addw, compute_c_addw }, - [CC_OP_ADDL] = { compute_all_addl, compute_c_addl }, - - [CC_OP_ADCB] = { compute_all_adcb, compute_c_adcb }, - [CC_OP_ADCW] = { compute_all_adcw, compute_c_adcw }, - [CC_OP_ADCL] = { compute_all_adcl, compute_c_adcl }, - - [CC_OP_SUBB] = { compute_all_subb, compute_c_subb }, - [CC_OP_SUBW] = { compute_all_subw, compute_c_subw }, - [CC_OP_SUBL] = { compute_all_subl, compute_c_subl }, - - [CC_OP_SBBB] = { compute_all_sbbb, compute_c_sbbb }, - [CC_OP_SBBW] = { compute_all_sbbw, compute_c_sbbw }, - [CC_OP_SBBL] = { compute_all_sbbl, compute_c_sbbl }, - - [CC_OP_LOGICB] = { compute_all_logicb, compute_c_logicb }, - [CC_OP_LOGICW] = { compute_all_logicw, compute_c_logicw }, - [CC_OP_LOGICL] = { compute_all_logicl, compute_c_logicl }, - - [CC_OP_INCB] = { compute_all_incb, compute_c_incl }, - [CC_OP_INCW] = { compute_all_incw, compute_c_incl }, - [CC_OP_INCL] = { compute_all_incl, compute_c_incl }, - - [CC_OP_DECB] = { compute_all_decb, compute_c_incl }, - [CC_OP_DECW] = { compute_all_decw, compute_c_incl }, - [CC_OP_DECL] = { compute_all_decl, compute_c_incl }, - - [CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb }, - [CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw }, - [CC_OP_SHLL] = { compute_all_shll, compute_c_shll }, - - [CC_OP_SARB] = { compute_all_sarb, compute_c_sarl }, - [CC_OP_SARW] = { compute_all_sarw, compute_c_sarl }, - [CC_OP_SARL] = { compute_all_sarl, compute_c_sarl }, - -#ifdef TARGET_X86_64 - [CC_OP_MULQ] = { compute_all_mulq, compute_c_mull }, - - [CC_OP_ADDQ] = { compute_all_addq, compute_c_addq }, - - [CC_OP_ADCQ] = { compute_all_adcq, compute_c_adcq }, - - [CC_OP_SUBQ] = { compute_all_subq, compute_c_subq }, - - [CC_OP_SBBQ] = { compute_all_sbbq, compute_c_sbbq }, - - [CC_OP_LOGICQ] = { compute_all_logicq, compute_c_logicq }, - - [CC_OP_INCQ] = { compute_all_incq, compute_c_incl }, - - [CC_OP_DECQ] = { compute_all_decq, compute_c_incl }, - - [CC_OP_SHLQ] = { compute_all_shlq, compute_c_shlq }, - - [CC_OP_SARQ] = { compute_all_sarq, compute_c_sarl }, -#endif -}; - -/* floating point support. Some of the code for complicated x87 - functions comes from the LGPL'ed x86 emulator found in the Willows - TWIN windows emulator. */ - -/* fp load FT0 */ - -void OPPROTO op_flds_FT0_A0(void) -{ -#ifdef USE_FP_CONVERT - FP_CONVERT.i32 = ldl(A0); - FT0 = FP_CONVERT.f; -#else - FT0 = ldfl(A0); -#endif -} - -void OPPROTO op_fldl_FT0_A0(void) -{ -#ifdef USE_FP_CONVERT - FP_CONVERT.i64 = ldq(A0); - FT0 = FP_CONVERT.d; -#else - FT0 = ldfq(A0); -#endif -} - -/* helpers are needed to avoid static constant reference. XXX: find a better way */ -#ifdef USE_INT_TO_FLOAT_HELPERS - -void helper_fild_FT0_A0(void) -{ - FT0 = (CPU86_LDouble)ldsw(A0); -} - -void helper_fildl_FT0_A0(void) -{ - FT0 = (CPU86_LDouble)((int32_t)ldl(A0)); -} - -void helper_fildll_FT0_A0(void) -{ - FT0 = (CPU86_LDouble)((int64_t)ldq(A0)); -} - -void OPPROTO op_fild_FT0_A0(void) -{ - helper_fild_FT0_A0(); -} - -void OPPROTO op_fildl_FT0_A0(void) -{ - helper_fildl_FT0_A0(); -} - -void OPPROTO op_fildll_FT0_A0(void) -{ - helper_fildll_FT0_A0(); -} - -#else - -void OPPROTO op_fild_FT0_A0(void) -{ -#ifdef USE_FP_CONVERT - FP_CONVERT.i32 = ldsw(A0); - FT0 = (CPU86_LDouble)FP_CONVERT.i32; -#else - FT0 = (CPU86_LDouble)ldsw(A0); -#endif -} - -void OPPROTO op_fildl_FT0_A0(void) -{ -#ifdef USE_FP_CONVERT - FP_CONVERT.i32 = (int32_t) ldl(A0); - FT0 = (CPU86_LDouble)FP_CONVERT.i32; -#else - FT0 = (CPU86_LDouble)((int32_t)ldl(A0)); -#endif -} - -void OPPROTO op_fildll_FT0_A0(void) -{ -#ifdef USE_FP_CONVERT - FP_CONVERT.i64 = (int64_t) ldq(A0); - FT0 = (CPU86_LDouble)FP_CONVERT.i64; -#else - FT0 = (CPU86_LDouble)((int64_t)ldq(A0)); -#endif -} -#endif - -/* fp load ST0 */ - -void OPPROTO op_flds_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; -#ifdef USE_FP_CONVERT - FP_CONVERT.i32 = ldl(A0); - env->fpregs[new_fpstt].d = FP_CONVERT.f; -#else - env->fpregs[new_fpstt].d = ldfl(A0); -#endif - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -void OPPROTO op_fldl_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; -#ifdef USE_FP_CONVERT - FP_CONVERT.i64 = ldq(A0); - env->fpregs[new_fpstt].d = FP_CONVERT.d; -#else - env->fpregs[new_fpstt].d = ldfq(A0); -#endif - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -void OPPROTO op_fldt_ST0_A0(void) -{ - helper_fldt_ST0_A0(); -} - -/* helpers are needed to avoid static constant reference. XXX: find a better way */ -#ifdef USE_INT_TO_FLOAT_HELPERS - -void helper_fild_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt].d = (CPU86_LDouble)ldsw(A0); - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -void helper_fildl_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt].d = (CPU86_LDouble)((int32_t)ldl(A0)); - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -void helper_fildll_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt].d = (CPU86_LDouble)((int64_t)ldq(A0)); - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -void OPPROTO op_fild_ST0_A0(void) -{ - helper_fild_ST0_A0(); -} - -void OPPROTO op_fildl_ST0_A0(void) -{ - helper_fildl_ST0_A0(); -} - -void OPPROTO op_fildll_ST0_A0(void) -{ - helper_fildll_ST0_A0(); -} - -#else - -void OPPROTO op_fild_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; -#ifdef USE_FP_CONVERT - FP_CONVERT.i32 = ldsw(A0); - env->fpregs[new_fpstt].d = (CPU86_LDouble)FP_CONVERT.i32; -#else - env->fpregs[new_fpstt].d = (CPU86_LDouble)ldsw(A0); -#endif - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -void OPPROTO op_fildl_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; -#ifdef USE_FP_CONVERT - FP_CONVERT.i32 = (int32_t) ldl(A0); - env->fpregs[new_fpstt].d = (CPU86_LDouble)FP_CONVERT.i32; -#else - env->fpregs[new_fpstt].d = (CPU86_LDouble)((int32_t)ldl(A0)); -#endif - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -void OPPROTO op_fildll_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; -#ifdef USE_FP_CONVERT - FP_CONVERT.i64 = (int64_t) ldq(A0); - env->fpregs[new_fpstt].d = (CPU86_LDouble)FP_CONVERT.i64; -#else - env->fpregs[new_fpstt].d = (CPU86_LDouble)((int64_t)ldq(A0)); -#endif - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -#endif - -/* fp store */ - -void OPPROTO op_fsts_ST0_A0(void) -{ -#ifdef USE_FP_CONVERT - FP_CONVERT.f = (float)ST0; - stfl(A0, FP_CONVERT.f); -#else - stfl(A0, (float)ST0); -#endif - FORCE_RET(); -} - -void OPPROTO op_fstl_ST0_A0(void) -{ - stfq(A0, (double)ST0); - FORCE_RET(); -} - -void OPPROTO op_fstt_ST0_A0(void) -{ - helper_fstt_ST0_A0(); -} - -void OPPROTO op_fist_ST0_A0(void) -{ -#if defined(__sparc__) && !defined(__sparc_v9__) - register CPU86_LDouble d asm("o0"); -#else - CPU86_LDouble d; -#endif - int val; - - d = ST0; - val = floatx_to_int32(d, &env->fp_status); - if (val != (int16_t)val) - val = -32768; - stw(A0, val); - FORCE_RET(); -} - -void OPPROTO op_fistl_ST0_A0(void) -{ -#if defined(__sparc__) && !defined(__sparc_v9__) - register CPU86_LDouble d asm("o0"); -#else - CPU86_LDouble d; -#endif - int val; - - d = ST0; - val = floatx_to_int32(d, &env->fp_status); - stl(A0, val); - FORCE_RET(); -} - -void OPPROTO op_fistll_ST0_A0(void) -{ -#if defined(__sparc__) && !defined(__sparc_v9__) - register CPU86_LDouble d asm("o0"); -#else - CPU86_LDouble d; -#endif - int64_t val; - - d = ST0; - val = floatx_to_int64(d, &env->fp_status); - stq(A0, val); - FORCE_RET(); -} - -void OPPROTO op_fistt_ST0_A0(void) -{ -#if defined(__sparc__) && !defined(__sparc_v9__) - register CPU86_LDouble d asm("o0"); -#else - CPU86_LDouble d; -#endif - int val; - - d = ST0; - val = floatx_to_int32_round_to_zero(d, &env->fp_status); - if (val != (int16_t)val) - val = -32768; - stw(A0, val); - FORCE_RET(); -} - -void OPPROTO op_fisttl_ST0_A0(void) -{ -#if defined(__sparc__) && !defined(__sparc_v9__) - register CPU86_LDouble d asm("o0"); -#else - CPU86_LDouble d; -#endif - int val; - - d = ST0; - val = floatx_to_int32_round_to_zero(d, &env->fp_status); - stl(A0, val); - FORCE_RET(); -} - -void OPPROTO op_fisttll_ST0_A0(void) -{ -#if defined(__sparc__) && !defined(__sparc_v9__) - register CPU86_LDouble d asm("o0"); -#else - CPU86_LDouble d; -#endif - int64_t val; - - d = ST0; - val = floatx_to_int64_round_to_zero(d, &env->fp_status); - stq(A0, val); - FORCE_RET(); -} - -void OPPROTO op_fbld_ST0_A0(void) -{ - helper_fbld_ST0_A0(); -} - -void OPPROTO op_fbst_ST0_A0(void) -{ - helper_fbst_ST0_A0(); -} - -/* FPU move */ - -void OPPROTO op_fpush(void) -{ - fpush(); -} - -void OPPROTO op_fpop(void) -{ - fpop(); -} - -void OPPROTO op_fdecstp(void) -{ - env->fpstt = (env->fpstt - 1) & 7; - env->fpus &= (~0x4700); -} - -void OPPROTO op_fincstp(void) -{ - env->fpstt = (env->fpstt + 1) & 7; - env->fpus &= (~0x4700); -} - -void OPPROTO op_ffree_STN(void) -{ - env->fptags[(env->fpstt + PARAM1) & 7] = 1; -} - -void OPPROTO op_fmov_ST0_FT0(void) -{ - ST0 = FT0; -} - -void OPPROTO op_fmov_FT0_STN(void) -{ - FT0 = ST(PARAM1); -} - -void OPPROTO op_fmov_ST0_STN(void) -{ - ST0 = ST(PARAM1); -} - -void OPPROTO op_fmov_STN_ST0(void) -{ - ST(PARAM1) = ST0; -} - -void OPPROTO op_fxchg_ST0_STN(void) -{ - CPU86_LDouble tmp; - tmp = ST(PARAM1); - ST(PARAM1) = ST0; - ST0 = tmp; -} - -/* FPU operations */ - -const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500}; - -void OPPROTO op_fcom_ST0_FT0(void) -{ - int ret; - - ret = floatx_compare(ST0, FT0, &env->fp_status); - env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1]; - FORCE_RET(); -} - -void OPPROTO op_fucom_ST0_FT0(void) -{ - int ret; - - ret = floatx_compare_quiet(ST0, FT0, &env->fp_status); - env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret+ 1]; - FORCE_RET(); -} - -const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C}; - -void OPPROTO op_fcomi_ST0_FT0(void) -{ - int eflags; - int ret; - - ret = floatx_compare(ST0, FT0, &env->fp_status); - eflags = cc_table[CC_OP].compute_all(); - eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1]; - CC_SRC = eflags; - FORCE_RET(); -} - -void OPPROTO op_fucomi_ST0_FT0(void) -{ - int eflags; - int ret; - - ret = floatx_compare_quiet(ST0, FT0, &env->fp_status); - eflags = cc_table[CC_OP].compute_all(); - eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1]; - CC_SRC = eflags; - FORCE_RET(); -} - -void OPPROTO op_fcmov_ST0_STN_T0(void) -{ - if (T0) { - ST0 = ST(PARAM1); - } - FORCE_RET(); -} - -void OPPROTO op_fadd_ST0_FT0(void) -{ - ST0 += FT0; -} - -void OPPROTO op_fmul_ST0_FT0(void) -{ - ST0 *= FT0; -} - -void OPPROTO op_fsub_ST0_FT0(void) -{ - ST0 -= FT0; -} - -void OPPROTO op_fsubr_ST0_FT0(void) -{ - ST0 = FT0 - ST0; -} - -void OPPROTO op_fdiv_ST0_FT0(void) -{ - ST0 = helper_fdiv(ST0, FT0); -} - -void OPPROTO op_fdivr_ST0_FT0(void) -{ - ST0 = helper_fdiv(FT0, ST0); -} - -/* fp operations between STN and ST0 */ - -void OPPROTO op_fadd_STN_ST0(void) -{ - ST(PARAM1) += ST0; -} - -void OPPROTO op_fmul_STN_ST0(void) -{ - ST(PARAM1) *= ST0; -} - -void OPPROTO op_fsub_STN_ST0(void) -{ - ST(PARAM1) -= ST0; -} - -void OPPROTO op_fsubr_STN_ST0(void) -{ - CPU86_LDouble *p; - p = &ST(PARAM1); - *p = ST0 - *p; -} - -void OPPROTO op_fdiv_STN_ST0(void) -{ - CPU86_LDouble *p; - p = &ST(PARAM1); - *p = helper_fdiv(*p, ST0); -} - -void OPPROTO op_fdivr_STN_ST0(void) -{ - CPU86_LDouble *p; - p = &ST(PARAM1); - *p = helper_fdiv(ST0, *p); -} - -/* misc FPU operations */ -void OPPROTO op_fchs_ST0(void) -{ - ST0 = floatx_chs(ST0); -} - -void OPPROTO op_fabs_ST0(void) -{ - ST0 = floatx_abs(ST0); -} - -void OPPROTO op_fxam_ST0(void) -{ - helper_fxam_ST0(); -} - -void OPPROTO op_fld1_ST0(void) -{ - ST0 = f15rk[1]; -} - -void OPPROTO op_fldl2t_ST0(void) -{ - ST0 = f15rk[6]; -} - -void OPPROTO op_fldl2e_ST0(void) -{ - ST0 = f15rk[5]; -} - -void OPPROTO op_fldpi_ST0(void) -{ - ST0 = f15rk[2]; -} - -void OPPROTO op_fldlg2_ST0(void) -{ - ST0 = f15rk[3]; -} - -void OPPROTO op_fldln2_ST0(void) -{ - ST0 = f15rk[4]; -} - -void OPPROTO op_fldz_ST0(void) -{ - ST0 = f15rk[0]; -} - -void OPPROTO op_fldz_FT0(void) -{ - FT0 = f15rk[0]; -} - -/* associated heplers to reduce generated code length and to simplify - relocation (FP constants are usually stored in .rodata section) */ - -void OPPROTO op_f2xm1(void) -{ - helper_f2xm1(); -} - -void OPPROTO op_fyl2x(void) -{ - helper_fyl2x(); -} - -void OPPROTO op_fptan(void) -{ - helper_fptan(); -} - -void OPPROTO op_fpatan(void) -{ - helper_fpatan(); -} - -void OPPROTO op_fxtract(void) -{ - helper_fxtract(); -} - -void OPPROTO op_fprem1(void) -{ - helper_fprem1(); -} - - -void OPPROTO op_fprem(void) -{ - helper_fprem(); -} - -void OPPROTO op_fyl2xp1(void) -{ - helper_fyl2xp1(); -} - -void OPPROTO op_fsqrt(void) -{ - helper_fsqrt(); -} - -void OPPROTO op_fsincos(void) -{ - helper_fsincos(); -} - -void OPPROTO op_frndint(void) -{ - helper_frndint(); -} - -void OPPROTO op_fscale(void) -{ - helper_fscale(); -} - -void OPPROTO op_fsin(void) -{ - helper_fsin(); -} - -void OPPROTO op_fcos(void) -{ - helper_fcos(); -} - -void OPPROTO op_fnstsw_A0(void) -{ - int fpus; - fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; - stw(A0, fpus); - FORCE_RET(); -} - -void OPPROTO op_fnstsw_EAX(void) -{ - int fpus; - fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; - EAX = (EAX & ~0xffff) | fpus; -} - -void OPPROTO op_fnstcw_A0(void) -{ - stw(A0, env->fpuc); - FORCE_RET(); -} - -void OPPROTO op_fldcw_A0(void) -{ - env->fpuc = lduw(A0); - update_fp_status(); -} - -void OPPROTO op_fclex(void) -{ - env->fpus &= 0x7f00; -} - -void OPPROTO op_fwait(void) -{ - if (env->fpus & FPUS_SE) - fpu_raise_exception(); - FORCE_RET(); -} - -void OPPROTO op_fninit(void) -{ - env->fpus = 0; - env->fpstt = 0; - env->fpuc = 0x37f; - env->fptags[0] = 1; - env->fptags[1] = 1; - env->fptags[2] = 1; - env->fptags[3] = 1; - env->fptags[4] = 1; - env->fptags[5] = 1; - env->fptags[6] = 1; - env->fptags[7] = 1; -} - -void OPPROTO op_fnstenv_A0(void) -{ - helper_fstenv(A0, PARAM1); -} - -void OPPROTO op_fldenv_A0(void) -{ - helper_fldenv(A0, PARAM1); -} - -void OPPROTO op_fnsave_A0(void) -{ - helper_fsave(A0, PARAM1); -} - -void OPPROTO op_frstor_A0(void) -{ - helper_frstor(A0, PARAM1); -} - -/* threading support */ -void OPPROTO op_lock(void) -{ - cpu_lock(); -} - -void OPPROTO op_unlock(void) -{ - cpu_unlock(); -} - -/* SSE support */ -static inline void memcpy16(void *d, void *s) -{ - ((uint32_t *)d)[0] = ((uint32_t *)s)[0]; - ((uint32_t *)d)[1] = ((uint32_t *)s)[1]; - ((uint32_t *)d)[2] = ((uint32_t *)s)[2]; - ((uint32_t *)d)[3] = ((uint32_t *)s)[3]; -} - -void OPPROTO op_movo(void) -{ - /* XXX: badly generated code */ - XMMReg *d, *s; - d = (XMMReg *)((char *)env + PARAM1); - s = (XMMReg *)((char *)env + PARAM2); - memcpy16(d, s); -} - -void OPPROTO op_movq(void) -{ - uint64_t *d, *s; - d = (uint64_t *)((char *)env + PARAM1); - s = (uint64_t *)((char *)env + PARAM2); - *d = *s; -} - -void OPPROTO op_movl(void) -{ - uint32_t *d, *s; - d = (uint32_t *)((char *)env + PARAM1); - s = (uint32_t *)((char *)env + PARAM2); - *d = *s; -} - -void OPPROTO op_movq_env_0(void) -{ - uint64_t *d; - d = (uint64_t *)((char *)env + PARAM1); - *d = 0; -} - -void OPPROTO op_fxsave_A0(void) -{ - helper_fxsave(A0, PARAM1); -} - -void OPPROTO op_fxrstor_A0(void) -{ - helper_fxrstor(A0, PARAM1); -} - -/* XXX: optimize by storing fptt and fptags in the static cpu state */ -void OPPROTO op_enter_mmx(void) -{ - env->fpstt = 0; - *(uint32_t *)(env->fptags) = 0; - *(uint32_t *)(env->fptags + 4) = 0; -} - -void OPPROTO op_emms(void) -{ - /* set to empty state */ - *(uint32_t *)(env->fptags) = 0x01010101; - *(uint32_t *)(env->fptags + 4) = 0x01010101; -} - -#define SHIFT 0 -#include "ops_sse.h" - -#define SHIFT 1 -#include "ops_sse.h" - -/* Secure Virtual Machine ops */ - -void OPPROTO op_vmrun(void) -{ - helper_vmrun(EAX); -} - -void OPPROTO op_vmmcall(void) -{ - helper_vmmcall(); -} - -void OPPROTO op_vmload(void) -{ - helper_vmload(EAX); -} - -void OPPROTO op_vmsave(void) -{ - helper_vmsave(EAX); -} - -void OPPROTO op_stgi(void) -{ - helper_stgi(); -} - -void OPPROTO op_clgi(void) -{ - helper_clgi(); -} - -void OPPROTO op_skinit(void) -{ - helper_skinit(); -} - -void OPPROTO op_invlpga(void) -{ - helper_invlpga(); -} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/op_helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/op_helper.c --- qemu-0.9.1/target-i386/op_helper.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-i386/op_helper.c 2008-11-05 15:34:06.000000000 +0000 @@ -0,0 +1,5420 @@ +/* + * i386 helpers + * + * Copyright (c) 2003 Fabrice Bellard + * + * 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 + */ +#define CPU_NO_GLOBAL_REGS +#include "exec.h" +#include "host-utils.h" + +//#define DEBUG_PCALL + +#if 0 +#define raise_exception_err(a, b)\ +do {\ + if (logfile)\ + fprintf(logfile, "raise_exception line=%d\n", __LINE__);\ + (raise_exception_err)(a, b);\ +} while (0) +#endif + +const uint8_t parity_table[256] = { + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +}; + +/* modulo 17 table */ +const uint8_t rclw_table[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9,10,11,12,13,14,15, + 16, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9,10,11,12,13,14, +}; + +/* modulo 9 table */ +const uint8_t rclb_table[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 0, 1, 2, 3, 4, +}; + +const CPU86_LDouble f15rk[7] = +{ + 0.00000000000000000000L, + 1.00000000000000000000L, + 3.14159265358979323851L, /*pi*/ + 0.30102999566398119523L, /*lg2*/ + 0.69314718055994530943L, /*ln2*/ + 1.44269504088896340739L, /*l2e*/ + 3.32192809488736234781L, /*l2t*/ +}; + +/* broken thread support */ + +static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; + +void helper_lock(void) +{ + spin_lock(&global_cpu_lock); +} + +void helper_unlock(void) +{ + spin_unlock(&global_cpu_lock); +} + +void helper_write_eflags(target_ulong t0, uint32_t update_mask) +{ + load_eflags(t0, update_mask); +} + +target_ulong helper_read_eflags(void) +{ + uint32_t eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags |= (DF & DF_MASK); + eflags |= env->eflags & ~(VM_MASK | RF_MASK); + return eflags; +} + +/* return non zero if error */ +static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, + int selector) +{ + SegmentCache *dt; + int index; + target_ulong ptr; + + if (selector & 0x4) + dt = &env->ldt; + else + dt = &env->gdt; + index = selector & ~7; + if ((index + 7) > dt->limit) + return -1; + ptr = dt->base + index; + *e1_ptr = ldl_kernel(ptr); + *e2_ptr = ldl_kernel(ptr + 4); + return 0; +} + +static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) +{ + unsigned int limit; + limit = (e1 & 0xffff) | (e2 & 0x000f0000); + if (e2 & DESC_G_MASK) + limit = (limit << 12) | 0xfff; + return limit; +} + +static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2) +{ + return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); +} + +static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2) +{ + sc->base = get_seg_base(e1, e2); + sc->limit = get_seg_limit(e1, e2); + sc->flags = e2; +} + +/* init the segment cache in vm86 mode. */ +static inline void load_seg_vm(int seg, int selector) +{ + selector &= 0xffff; + cpu_x86_load_seg_cache(env, seg, selector, + (selector << 4), 0xffff, 0); +} + +static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, + uint32_t *esp_ptr, int dpl) +{ + int type, index, shift; + +#if 0 + { + int i; + printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit); + for(i=0;itr.limit;i++) { + printf("%02x ", env->tr.base[i]); + if ((i & 7) == 7) printf("\n"); + } + printf("\n"); + } +#endif + + if (!(env->tr.flags & DESC_P_MASK)) + cpu_abort(env, "invalid tss"); + type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; + if ((type & 7) != 1) + cpu_abort(env, "invalid tss type"); + shift = type >> 3; + index = (dpl * 4 + 2) << shift; + if (index + (4 << shift) - 1 > env->tr.limit) + raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); + if (shift == 0) { + *esp_ptr = lduw_kernel(env->tr.base + index); + *ss_ptr = lduw_kernel(env->tr.base + index + 2); + } else { + *esp_ptr = ldl_kernel(env->tr.base + index); + *ss_ptr = lduw_kernel(env->tr.base + index + 4); + } +} + +/* XXX: merge with load_seg() */ +static void tss_load_seg(int seg_reg, int selector) +{ + uint32_t e1, e2; + int rpl, dpl, cpl; + + if ((selector & 0xfffc) != 0) { + if (load_segment(&e1, &e2, selector) != 0) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + if (!(e2 & DESC_S_MASK)) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + rpl = selector & 3; + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + if (seg_reg == R_CS) { + if (!(e2 & DESC_CS_MASK)) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + /* XXX: is it correct ? */ + if (dpl != rpl) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + if ((e2 & DESC_C_MASK) && dpl > rpl) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + } else if (seg_reg == R_SS) { + /* SS must be writable data */ + if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + if (dpl != cpl || dpl != rpl) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + } else { + /* not readable code */ + if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK)) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + /* if data or non conforming code, checks the rights */ + if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) { + if (dpl < cpl || dpl < rpl) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + } + } + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + cpu_x86_load_seg_cache(env, seg_reg, selector, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); + } else { + if (seg_reg == R_SS || seg_reg == R_CS) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + } +} + +#define SWITCH_TSS_JMP 0 +#define SWITCH_TSS_IRET 1 +#define SWITCH_TSS_CALL 2 + +/* XXX: restore CPU state in registers (PowerPC case) */ +static void switch_tss(int tss_selector, + uint32_t e1, uint32_t e2, int source, + uint32_t next_eip) +{ + int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i; + target_ulong tss_base; + uint32_t new_regs[8], new_segs[6]; + uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap; + uint32_t old_eflags, eflags_mask; + SegmentCache *dt; + int index; + target_ulong ptr; + + type = (e2 >> DESC_TYPE_SHIFT) & 0xf; +#ifdef DEBUG_PCALL + if (loglevel & CPU_LOG_PCALL) + fprintf(logfile, "switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source); +#endif + + /* if task gate, we read the TSS segment and we load it */ + if (type == 5) { + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc); + tss_selector = e1 >> 16; + if (tss_selector & 4) + raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); + if (load_segment(&e1, &e2, tss_selector) != 0) + raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); + if (e2 & DESC_S_MASK) + raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); + type = (e2 >> DESC_TYPE_SHIFT) & 0xf; + if ((type & 7) != 1) + raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); + } + + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc); + + if (type & 8) + tss_limit_max = 103; + else + tss_limit_max = 43; + tss_limit = get_seg_limit(e1, e2); + tss_base = get_seg_base(e1, e2); + if ((tss_selector & 4) != 0 || + tss_limit < tss_limit_max) + raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); + old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; + if (old_type & 8) + old_tss_limit_max = 103; + else + old_tss_limit_max = 43; + + /* read all the registers from the new TSS */ + if (type & 8) { + /* 32 bit */ + new_cr3 = ldl_kernel(tss_base + 0x1c); + new_eip = ldl_kernel(tss_base + 0x20); + new_eflags = ldl_kernel(tss_base + 0x24); + for(i = 0; i < 8; i++) + new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4)); + for(i = 0; i < 6; i++) + new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4)); + new_ldt = lduw_kernel(tss_base + 0x60); + new_trap = ldl_kernel(tss_base + 0x64); + } else { + /* 16 bit */ + new_cr3 = 0; + new_eip = lduw_kernel(tss_base + 0x0e); + new_eflags = lduw_kernel(tss_base + 0x10); + for(i = 0; i < 8; i++) + new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000; + for(i = 0; i < 4; i++) + new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4)); + new_ldt = lduw_kernel(tss_base + 0x2a); + new_segs[R_FS] = 0; + new_segs[R_GS] = 0; + new_trap = 0; + } + + /* NOTE: we must avoid memory exceptions during the task switch, + so we make dummy accesses before */ + /* XXX: it can still fail in some cases, so a bigger hack is + necessary to valid the TLB after having done the accesses */ + + v1 = ldub_kernel(env->tr.base); + v2 = ldub_kernel(env->tr.base + old_tss_limit_max); + stb_kernel(env->tr.base, v1); + stb_kernel(env->tr.base + old_tss_limit_max, v2); + + /* clear busy bit (it is restartable) */ + if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) { + target_ulong ptr; + uint32_t e2; + ptr = env->gdt.base + (env->tr.selector & ~7); + e2 = ldl_kernel(ptr + 4); + e2 &= ~DESC_TSS_BUSY_MASK; + stl_kernel(ptr + 4, e2); + } + old_eflags = compute_eflags(); + if (source == SWITCH_TSS_IRET) + old_eflags &= ~NT_MASK; + + /* save the current state in the old TSS */ + if (type & 8) { + /* 32 bit */ + stl_kernel(env->tr.base + 0x20, next_eip); + stl_kernel(env->tr.base + 0x24, old_eflags); + stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX); + stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX); + stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX); + stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX); + stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP); + stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP); + stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI); + stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI); + for(i = 0; i < 6; i++) + stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector); + } else { + /* 16 bit */ + stw_kernel(env->tr.base + 0x0e, next_eip); + stw_kernel(env->tr.base + 0x10, old_eflags); + stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX); + stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX); + stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX); + stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX); + stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP); + stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP); + stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI); + stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI); + for(i = 0; i < 4; i++) + stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector); + } + + /* now if an exception occurs, it will occurs in the next task + context */ + + if (source == SWITCH_TSS_CALL) { + stw_kernel(tss_base, env->tr.selector); + new_eflags |= NT_MASK; + } + + /* set busy bit */ + if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) { + target_ulong ptr; + uint32_t e2; + ptr = env->gdt.base + (tss_selector & ~7); + e2 = ldl_kernel(ptr + 4); + e2 |= DESC_TSS_BUSY_MASK; + stl_kernel(ptr + 4, e2); + } + + /* set the new CPU state */ + /* from this point, any exception which occurs can give problems */ + env->cr[0] |= CR0_TS_MASK; + env->hflags |= HF_TS_MASK; + env->tr.selector = tss_selector; + env->tr.base = tss_base; + env->tr.limit = tss_limit; + env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK; + + if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) { + cpu_x86_update_cr3(env, new_cr3); + } + + /* load all registers without an exception, then reload them with + possible exception */ + env->eip = new_eip; + eflags_mask = TF_MASK | AC_MASK | ID_MASK | + IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK; + if (!(type & 8)) + eflags_mask &= 0xffff; + load_eflags(new_eflags, eflags_mask); + /* XXX: what to do in 16 bit case ? */ + EAX = new_regs[0]; + ECX = new_regs[1]; + EDX = new_regs[2]; + EBX = new_regs[3]; + ESP = new_regs[4]; + EBP = new_regs[5]; + ESI = new_regs[6]; + EDI = new_regs[7]; + if (new_eflags & VM_MASK) { + for(i = 0; i < 6; i++) + load_seg_vm(i, new_segs[i]); + /* in vm86, CPL is always 3 */ + cpu_x86_set_cpl(env, 3); + } else { + /* CPL is set the RPL of CS */ + cpu_x86_set_cpl(env, new_segs[R_CS] & 3); + /* first just selectors as the rest may trigger exceptions */ + for(i = 0; i < 6; i++) + cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0); + } + + env->ldt.selector = new_ldt & ~4; + env->ldt.base = 0; + env->ldt.limit = 0; + env->ldt.flags = 0; + + /* load the LDT */ + if (new_ldt & 4) + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); + + if ((new_ldt & 0xfffc) != 0) { + dt = &env->gdt; + index = new_ldt & ~7; + if ((index + 7) > dt->limit) + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); + ptr = dt->base + index; + e1 = ldl_kernel(ptr); + e2 = ldl_kernel(ptr + 4); + if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); + load_seg_cache_raw_dt(&env->ldt, e1, e2); + } + + /* load the segments */ + if (!(new_eflags & VM_MASK)) { + tss_load_seg(R_CS, new_segs[R_CS]); + tss_load_seg(R_SS, new_segs[R_SS]); + tss_load_seg(R_ES, new_segs[R_ES]); + tss_load_seg(R_DS, new_segs[R_DS]); + tss_load_seg(R_FS, new_segs[R_FS]); + tss_load_seg(R_GS, new_segs[R_GS]); + } + + /* check that EIP is in the CS segment limits */ + if (new_eip > env->segs[R_CS].limit) { + /* XXX: different exception if CALL ? */ + raise_exception_err(EXCP0D_GPF, 0); + } +} + +/* check if Port I/O is allowed in TSS */ +static inline void check_io(int addr, int size) +{ + int io_offset, val, mask; + + /* TSS must be a valid 32 bit one */ + if (!(env->tr.flags & DESC_P_MASK) || + ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 || + env->tr.limit < 103) + goto fail; + io_offset = lduw_kernel(env->tr.base + 0x66); + io_offset += (addr >> 3); + /* Note: the check needs two bytes */ + if ((io_offset + 1) > env->tr.limit) + goto fail; + val = lduw_kernel(env->tr.base + io_offset); + val >>= (addr & 7); + mask = (1 << size) - 1; + /* all bits must be zero to allow the I/O */ + if ((val & mask) != 0) { + fail: + raise_exception_err(EXCP0D_GPF, 0); + } +} + +void helper_check_iob(uint32_t t0) +{ + check_io(t0, 1); +} + +void helper_check_iow(uint32_t t0) +{ + check_io(t0, 2); +} + +void helper_check_iol(uint32_t t0) +{ + check_io(t0, 4); +} + +void helper_outb(uint32_t port, uint32_t data) +{ + cpu_outb(env, port, data & 0xff); +} + +target_ulong helper_inb(uint32_t port) +{ + return cpu_inb(env, port); +} + +void helper_outw(uint32_t port, uint32_t data) +{ + cpu_outw(env, port, data & 0xffff); +} + +target_ulong helper_inw(uint32_t port) +{ + return cpu_inw(env, port); +} + +void helper_outl(uint32_t port, uint32_t data) +{ + cpu_outl(env, port, data); +} + +target_ulong helper_inl(uint32_t port) +{ + return cpu_inl(env, port); +} + +static inline unsigned int get_sp_mask(unsigned int e2) +{ + if (e2 & DESC_B_MASK) + return 0xffffffff; + else + return 0xffff; +} + +#ifdef TARGET_X86_64 +#define SET_ESP(val, sp_mask)\ +do {\ + if ((sp_mask) == 0xffff)\ + ESP = (ESP & ~0xffff) | ((val) & 0xffff);\ + else if ((sp_mask) == 0xffffffffLL)\ + ESP = (uint32_t)(val);\ + else\ + ESP = (val);\ +} while (0) +#else +#define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask)) +#endif + +/* in 64-bit machines, this can overflow. So this segment addition macro + * can be used to trim the value to 32-bit whenever needed */ +#define SEG_ADDL(ssp, sp, sp_mask) ((uint32_t)((ssp) + (sp & (sp_mask)))) + +/* XXX: add a is_user flag to have proper security support */ +#define PUSHW(ssp, sp, sp_mask, val)\ +{\ + sp -= 2;\ + stw_kernel((ssp) + (sp & (sp_mask)), (val));\ +} + +#define PUSHL(ssp, sp, sp_mask, val)\ +{\ + sp -= 4;\ + stl_kernel(SEG_ADDL(ssp, sp, sp_mask), (uint32_t)(val));\ +} + +#define POPW(ssp, sp, sp_mask, val)\ +{\ + val = lduw_kernel((ssp) + (sp & (sp_mask)));\ + sp += 2;\ +} + +#define POPL(ssp, sp, sp_mask, val)\ +{\ + val = (uint32_t)ldl_kernel(SEG_ADDL(ssp, sp, sp_mask));\ + sp += 4;\ +} + +/* protected mode interrupt */ +static void do_interrupt_protected(int intno, int is_int, int error_code, + unsigned int next_eip, int is_hw) +{ + SegmentCache *dt; + target_ulong ptr, ssp; + int type, dpl, selector, ss_dpl, cpl; + int has_error_code, new_stack, shift; + uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2; + uint32_t old_eip, sp_mask; + + has_error_code = 0; + if (!is_int && !is_hw) { + switch(intno) { + case 8: + case 10: + case 11: + case 12: + case 13: + case 14: + case 17: + has_error_code = 1; + break; + } + } + if (is_int) + old_eip = next_eip; + else + old_eip = env->eip; + + dt = &env->idt; + if (intno * 8 + 7 > dt->limit) + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + ptr = dt->base + intno * 8; + e1 = ldl_kernel(ptr); + e2 = ldl_kernel(ptr + 4); + /* check gate type */ + type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; + switch(type) { + case 5: /* task gate */ + /* must do that check here to return the correct error code */ + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); + switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip); + if (has_error_code) { + int type; + uint32_t mask; + /* push the error code */ + type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; + shift = type >> 3; + if (env->segs[R_SS].flags & DESC_B_MASK) + mask = 0xffffffff; + else + mask = 0xffff; + esp = (ESP - (2 << shift)) & mask; + ssp = env->segs[R_SS].base + esp; + if (shift) + stl_kernel(ssp, error_code); + else + stw_kernel(ssp, error_code); + SET_ESP(esp, mask); + } + return; + case 6: /* 286 interrupt gate */ + case 7: /* 286 trap gate */ + case 14: /* 386 interrupt gate */ + case 15: /* 386 trap gate */ + break; + default: + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + break; + } + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + /* check privilege if software int */ + if (is_int && dpl < cpl) + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + /* check valid bit */ + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); + selector = e1 >> 16; + offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); + if ((selector & 0xfffc) == 0) + raise_exception_err(EXCP0D_GPF, 0); + + if (load_segment(&e1, &e2, selector) != 0) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (dpl > cpl) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + if (!(e2 & DESC_C_MASK) && dpl < cpl) { + /* to inner privilege */ + get_ss_esp_from_tss(&ss, &esp, dpl); + if ((ss & 0xfffc) == 0) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if ((ss & 3) != dpl) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if (load_segment(&ss_e1, &ss_e2, ss) != 0) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; + if (ss_dpl != dpl) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if (!(ss_e2 & DESC_S_MASK) || + (ss_e2 & DESC_CS_MASK) || + !(ss_e2 & DESC_W_MASK)) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if (!(ss_e2 & DESC_P_MASK)) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + new_stack = 1; + sp_mask = get_sp_mask(ss_e2); + ssp = get_seg_base(ss_e1, ss_e2); + } else if ((e2 & DESC_C_MASK) || dpl == cpl) { + /* to same privilege */ + if (env->eflags & VM_MASK) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + new_stack = 0; + sp_mask = get_sp_mask(env->segs[R_SS].flags); + ssp = env->segs[R_SS].base; + esp = ESP; + dpl = cpl; + } else { + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + new_stack = 0; /* avoid warning */ + sp_mask = 0; /* avoid warning */ + ssp = 0; /* avoid warning */ + esp = 0; /* avoid warning */ + } + + shift = type >> 3; + +#if 0 + /* XXX: check that enough room is available */ + push_size = 6 + (new_stack << 2) + (has_error_code << 1); + if (env->eflags & VM_MASK) + push_size += 8; + push_size <<= shift; +#endif + if (shift == 1) { + if (new_stack) { + if (env->eflags & VM_MASK) { + PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector); + PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector); + PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector); + PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector); + } + PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector); + PUSHL(ssp, esp, sp_mask, ESP); + } + PUSHL(ssp, esp, sp_mask, compute_eflags()); + PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector); + PUSHL(ssp, esp, sp_mask, old_eip); + if (has_error_code) { + PUSHL(ssp, esp, sp_mask, error_code); + } + } else { + if (new_stack) { + if (env->eflags & VM_MASK) { + PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector); + PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector); + PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector); + PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector); + } + PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector); + PUSHW(ssp, esp, sp_mask, ESP); + } + PUSHW(ssp, esp, sp_mask, compute_eflags()); + PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector); + PUSHW(ssp, esp, sp_mask, old_eip); + if (has_error_code) { + PUSHW(ssp, esp, sp_mask, error_code); + } + } + + if (new_stack) { + if (env->eflags & VM_MASK) { + cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0); + cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0); + cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0); + cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0); + } + ss = (ss & ~3) | dpl; + cpu_x86_load_seg_cache(env, R_SS, ss, + ssp, get_seg_limit(ss_e1, ss_e2), ss_e2); + } + SET_ESP(esp, sp_mask); + + selector = (selector & ~3) | dpl; + cpu_x86_load_seg_cache(env, R_CS, selector, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); + cpu_x86_set_cpl(env, dpl); + env->eip = offset; + + /* interrupt gate clear IF mask */ + if ((type & 1) == 0) { + env->eflags &= ~IF_MASK; + } + env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); +} + +#ifdef TARGET_X86_64 + +#define PUSHQ(sp, val)\ +{\ + sp -= 8;\ + stq_kernel(sp, (val));\ +} + +#define POPQ(sp, val)\ +{\ + val = ldq_kernel(sp);\ + sp += 8;\ +} + +static inline target_ulong get_rsp_from_tss(int level) +{ + int index; + +#if 0 + printf("TR: base=" TARGET_FMT_lx " limit=%x\n", + env->tr.base, env->tr.limit); +#endif + + if (!(env->tr.flags & DESC_P_MASK)) + cpu_abort(env, "invalid tss"); + index = 8 * level + 4; + if ((index + 7) > env->tr.limit) + raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); + return ldq_kernel(env->tr.base + index); +} + +/* 64 bit interrupt */ +static void do_interrupt64(int intno, int is_int, int error_code, + target_ulong next_eip, int is_hw) +{ + SegmentCache *dt; + target_ulong ptr; + int type, dpl, selector, cpl, ist; + int has_error_code, new_stack; + uint32_t e1, e2, e3, ss; + target_ulong old_eip, esp, offset; + + has_error_code = 0; + if (!is_int && !is_hw) { + switch(intno) { + case 8: + case 10: + case 11: + case 12: + case 13: + case 14: + case 17: + has_error_code = 1; + break; + } + } + if (is_int) + old_eip = next_eip; + else + old_eip = env->eip; + + dt = &env->idt; + if (intno * 16 + 15 > dt->limit) + raise_exception_err(EXCP0D_GPF, intno * 16 + 2); + ptr = dt->base + intno * 16; + e1 = ldl_kernel(ptr); + e2 = ldl_kernel(ptr + 4); + e3 = ldl_kernel(ptr + 8); + /* check gate type */ + type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; + switch(type) { + case 14: /* 386 interrupt gate */ + case 15: /* 386 trap gate */ + break; + default: + raise_exception_err(EXCP0D_GPF, intno * 16 + 2); + break; + } + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + /* check privilege if software int */ + if (is_int && dpl < cpl) + raise_exception_err(EXCP0D_GPF, intno * 16 + 2); + /* check valid bit */ + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2); + selector = e1 >> 16; + offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff); + ist = e2 & 7; + if ((selector & 0xfffc) == 0) + raise_exception_err(EXCP0D_GPF, 0); + + if (load_segment(&e1, &e2, selector) != 0) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (dpl > cpl) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK)) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) { + /* to inner privilege */ + if (ist != 0) + esp = get_rsp_from_tss(ist + 3); + else + esp = get_rsp_from_tss(dpl); + esp &= ~0xfLL; /* align stack */ + ss = 0; + new_stack = 1; + } else if ((e2 & DESC_C_MASK) || dpl == cpl) { + /* to same privilege */ + if (env->eflags & VM_MASK) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + new_stack = 0; + if (ist != 0) + esp = get_rsp_from_tss(ist + 3); + else + esp = ESP; + esp &= ~0xfLL; /* align stack */ + dpl = cpl; + } else { + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + new_stack = 0; /* avoid warning */ + esp = 0; /* avoid warning */ + } + + PUSHQ(esp, env->segs[R_SS].selector); + PUSHQ(esp, ESP); + PUSHQ(esp, compute_eflags()); + PUSHQ(esp, env->segs[R_CS].selector); + PUSHQ(esp, old_eip); + if (has_error_code) { + PUSHQ(esp, error_code); + } + + if (new_stack) { + ss = 0 | dpl; + cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0); + } + ESP = esp; + + selector = (selector & ~3) | dpl; + cpu_x86_load_seg_cache(env, R_CS, selector, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); + cpu_x86_set_cpl(env, dpl); + env->eip = offset; + + /* interrupt gate clear IF mask */ + if ((type & 1) == 0) { + env->eflags &= ~IF_MASK; + } + env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); +} +#endif + +#if defined(CONFIG_USER_ONLY) +void helper_syscall(int next_eip_addend) +{ + env->exception_index = EXCP_SYSCALL; + env->exception_next_eip = env->eip + next_eip_addend; + cpu_loop_exit(); +} +#else +void helper_syscall(int next_eip_addend) +{ + int selector; + + if (!(env->efer & MSR_EFER_SCE)) { + raise_exception_err(EXCP06_ILLOP, 0); + } + selector = (env->star >> 32) & 0xffff; +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + int code64; + + ECX = env->eip + next_eip_addend; + env->regs[11] = compute_eflags(); + + code64 = env->hflags & HF_CS64_MASK; + + cpu_x86_set_cpl(env, 0); + cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); + cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_W_MASK | DESC_A_MASK); + env->eflags &= ~env->fmask; + load_eflags(env->eflags, 0); + if (code64) + env->eip = env->lstar; + else + env->eip = env->cstar; + } else +#endif + { + ECX = (uint32_t)(env->eip + next_eip_addend); + + cpu_x86_set_cpl(env, 0); + cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); + cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_W_MASK | DESC_A_MASK); + env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK); + env->eip = (uint32_t)env->star; + } +} +#endif + +void helper_sysret(int dflag) +{ + int cpl, selector; + + if (!(env->efer & MSR_EFER_SCE)) { + raise_exception_err(EXCP06_ILLOP, 0); + } + cpl = env->hflags & HF_CPL_MASK; + if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) { + raise_exception_err(EXCP0D_GPF, 0); + } + selector = (env->star >> 48) & 0xffff; +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + if (dflag == 2) { + cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, + 0, 0xffffffff, + DESC_G_MASK | DESC_P_MASK | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | + DESC_L_MASK); + env->eip = ECX; + } else { + cpu_x86_load_seg_cache(env, R_CS, selector | 3, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); + env->eip = (uint32_t)ECX; + } + cpu_x86_load_seg_cache(env, R_SS, selector + 8, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | + DESC_W_MASK | DESC_A_MASK); + load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK | + IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK); + cpu_x86_set_cpl(env, 3); + } else +#endif + { + cpu_x86_load_seg_cache(env, R_CS, selector | 3, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); + env->eip = (uint32_t)ECX; + cpu_x86_load_seg_cache(env, R_SS, selector + 8, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | + DESC_W_MASK | DESC_A_MASK); + env->eflags |= IF_MASK; + cpu_x86_set_cpl(env, 3); + } +#ifdef USE_KQEMU + if (kqemu_is_ok(env)) { + if (env->hflags & HF_LMA_MASK) + CC_OP = CC_OP_EFLAGS; + env->exception_index = -1; + cpu_loop_exit(); + } +#endif +} + +/* real mode interrupt */ +static void do_interrupt_real(int intno, int is_int, int error_code, + unsigned int next_eip) +{ + SegmentCache *dt; + target_ulong ptr, ssp; + int selector; + uint32_t offset, esp; + uint32_t old_cs, old_eip; + + /* real mode (simpler !) */ + dt = &env->idt; + if (intno * 4 + 3 > dt->limit) + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + ptr = dt->base + intno * 4; + offset = lduw_kernel(ptr); + selector = lduw_kernel(ptr + 2); + esp = ESP; + ssp = env->segs[R_SS].base; + if (is_int) + old_eip = next_eip; + else + old_eip = env->eip; + old_cs = env->segs[R_CS].selector; + /* XXX: use SS segment size ? */ + PUSHW(ssp, esp, 0xffff, compute_eflags()); + PUSHW(ssp, esp, 0xffff, old_cs); + PUSHW(ssp, esp, 0xffff, old_eip); + + /* update processor state */ + ESP = (ESP & ~0xffff) | (esp & 0xffff); + env->eip = offset; + env->segs[R_CS].selector = selector; + env->segs[R_CS].base = (selector << 4); + env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK); +} + +/* fake user mode interrupt */ +void do_interrupt_user(int intno, int is_int, int error_code, + target_ulong next_eip) +{ + SegmentCache *dt; + target_ulong ptr; + int dpl, cpl, shift; + uint32_t e2; + + dt = &env->idt; + if (env->hflags & HF_LMA_MASK) { + shift = 4; + } else { + shift = 3; + } + ptr = dt->base + (intno << shift); + e2 = ldl_kernel(ptr + 4); + + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + /* check privilege if software int */ + if (is_int && dpl < cpl) + raise_exception_err(EXCP0D_GPF, (intno << shift) + 2); + + /* Since we emulate only user space, we cannot do more than + exiting the emulation with the suitable exception and error + code */ + if (is_int) + EIP = next_eip; +} + +/* + * Begin execution of an interruption. is_int is TRUE if coming from + * the int instruction. next_eip is the EIP value AFTER the interrupt + * instruction. It is only relevant if is_int is TRUE. + */ +void do_interrupt(int intno, int is_int, int error_code, + target_ulong next_eip, int is_hw) +{ + if (loglevel & CPU_LOG_INT) { + if ((env->cr[0] & CR0_PE_MASK)) { + static int count; + fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx, + count, intno, error_code, is_int, + env->hflags & HF_CPL_MASK, + env->segs[R_CS].selector, EIP, + (int)env->segs[R_CS].base + EIP, + env->segs[R_SS].selector, ESP); + if (intno == 0x0e) { + fprintf(logfile, " CR2=" TARGET_FMT_lx, env->cr[2]); + } else { + fprintf(logfile, " EAX=" TARGET_FMT_lx, EAX); + } + fprintf(logfile, "\n"); + cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); +#if 0 + { + int i; + uint8_t *ptr; + fprintf(logfile, " code="); + ptr = env->segs[R_CS].base + env->eip; + for(i = 0; i < 16; i++) { + fprintf(logfile, " %02x", ldub(ptr + i)); + } + fprintf(logfile, "\n"); + } +#endif + count++; + } + } + if (env->cr[0] & CR0_PE_MASK) { +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + do_interrupt64(intno, is_int, error_code, next_eip, is_hw); + } else +#endif + { + do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw); + } + } else { + do_interrupt_real(intno, is_int, error_code, next_eip); + } +} + +/* + * Check nested exceptions and change to double or triple fault if + * needed. It should only be called, if this is not an interrupt. + * Returns the new exception number. + */ +static int check_exception(int intno, int *error_code) +{ + int first_contributory = env->old_exception == 0 || + (env->old_exception >= 10 && + env->old_exception <= 13); + int second_contributory = intno == 0 || + (intno >= 10 && intno <= 13); + + if (loglevel & CPU_LOG_INT) + fprintf(logfile, "check_exception old: 0x%x new 0x%x\n", + env->old_exception, intno); + + if (env->old_exception == EXCP08_DBLE) + cpu_abort(env, "triple fault"); + + if ((first_contributory && second_contributory) + || (env->old_exception == EXCP0E_PAGE && + (second_contributory || (intno == EXCP0E_PAGE)))) { + intno = EXCP08_DBLE; + *error_code = 0; + } + + if (second_contributory || (intno == EXCP0E_PAGE) || + (intno == EXCP08_DBLE)) + env->old_exception = intno; + + return intno; +} + +/* + * Signal an interruption. It is executed in the main CPU loop. + * is_int is TRUE if coming from the int instruction. next_eip is the + * EIP value AFTER the interrupt instruction. It is only relevant if + * is_int is TRUE. + */ +void raise_interrupt(int intno, int is_int, int error_code, + int next_eip_addend) +{ + if (!is_int) { + helper_svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code); + intno = check_exception(intno, &error_code); + } else { + helper_svm_check_intercept_param(SVM_EXIT_SWINT, 0); + } + + env->exception_index = intno; + env->error_code = error_code; + env->exception_is_int = is_int; + env->exception_next_eip = env->eip + next_eip_addend; + cpu_loop_exit(); +} + +/* shortcuts to generate exceptions */ + +void (raise_exception_err)(int exception_index, int error_code) +{ + raise_interrupt(exception_index, 0, error_code, 0); +} + +void raise_exception(int exception_index) +{ + raise_interrupt(exception_index, 0, 0, 0); +} + +/* SMM support */ + +#if defined(CONFIG_USER_ONLY) + +void do_smm_enter(void) +{ +} + +void helper_rsm(void) +{ +} + +#else + +#ifdef TARGET_X86_64 +#define SMM_REVISION_ID 0x00020064 +#else +#define SMM_REVISION_ID 0x00020000 +#endif + +void do_smm_enter(void) +{ + target_ulong sm_state; + SegmentCache *dt; + int i, offset; + + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "SMM: enter\n"); + cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); + } + + env->hflags |= HF_SMM_MASK; + cpu_smm_update(env); + + sm_state = env->smbase + 0x8000; + +#ifdef TARGET_X86_64 + for(i = 0; i < 6; i++) { + dt = &env->segs[i]; + offset = 0x7e00 + i * 16; + stw_phys(sm_state + offset, dt->selector); + stw_phys(sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff); + stl_phys(sm_state + offset + 4, dt->limit); + stq_phys(sm_state + offset + 8, dt->base); + } + + stq_phys(sm_state + 0x7e68, env->gdt.base); + stl_phys(sm_state + 0x7e64, env->gdt.limit); + + stw_phys(sm_state + 0x7e70, env->ldt.selector); + stq_phys(sm_state + 0x7e78, env->ldt.base); + stl_phys(sm_state + 0x7e74, env->ldt.limit); + stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff); + + stq_phys(sm_state + 0x7e88, env->idt.base); + stl_phys(sm_state + 0x7e84, env->idt.limit); + + stw_phys(sm_state + 0x7e90, env->tr.selector); + stq_phys(sm_state + 0x7e98, env->tr.base); + stl_phys(sm_state + 0x7e94, env->tr.limit); + stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff); + + stq_phys(sm_state + 0x7ed0, env->efer); + + stq_phys(sm_state + 0x7ff8, EAX); + stq_phys(sm_state + 0x7ff0, ECX); + stq_phys(sm_state + 0x7fe8, EDX); + stq_phys(sm_state + 0x7fe0, EBX); + stq_phys(sm_state + 0x7fd8, ESP); + stq_phys(sm_state + 0x7fd0, EBP); + stq_phys(sm_state + 0x7fc8, ESI); + stq_phys(sm_state + 0x7fc0, EDI); + for(i = 8; i < 16; i++) + stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]); + stq_phys(sm_state + 0x7f78, env->eip); + stl_phys(sm_state + 0x7f70, compute_eflags()); + stl_phys(sm_state + 0x7f68, env->dr[6]); + stl_phys(sm_state + 0x7f60, env->dr[7]); + + stl_phys(sm_state + 0x7f48, env->cr[4]); + stl_phys(sm_state + 0x7f50, env->cr[3]); + stl_phys(sm_state + 0x7f58, env->cr[0]); + + stl_phys(sm_state + 0x7efc, SMM_REVISION_ID); + stl_phys(sm_state + 0x7f00, env->smbase); +#else + stl_phys(sm_state + 0x7ffc, env->cr[0]); + stl_phys(sm_state + 0x7ff8, env->cr[3]); + stl_phys(sm_state + 0x7ff4, compute_eflags()); + stl_phys(sm_state + 0x7ff0, env->eip); + stl_phys(sm_state + 0x7fec, EDI); + stl_phys(sm_state + 0x7fe8, ESI); + stl_phys(sm_state + 0x7fe4, EBP); + stl_phys(sm_state + 0x7fe0, ESP); + stl_phys(sm_state + 0x7fdc, EBX); + stl_phys(sm_state + 0x7fd8, EDX); + stl_phys(sm_state + 0x7fd4, ECX); + stl_phys(sm_state + 0x7fd0, EAX); + stl_phys(sm_state + 0x7fcc, env->dr[6]); + stl_phys(sm_state + 0x7fc8, env->dr[7]); + + stl_phys(sm_state + 0x7fc4, env->tr.selector); + stl_phys(sm_state + 0x7f64, env->tr.base); + stl_phys(sm_state + 0x7f60, env->tr.limit); + stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff); + + stl_phys(sm_state + 0x7fc0, env->ldt.selector); + stl_phys(sm_state + 0x7f80, env->ldt.base); + stl_phys(sm_state + 0x7f7c, env->ldt.limit); + stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff); + + stl_phys(sm_state + 0x7f74, env->gdt.base); + stl_phys(sm_state + 0x7f70, env->gdt.limit); + + stl_phys(sm_state + 0x7f58, env->idt.base); + stl_phys(sm_state + 0x7f54, env->idt.limit); + + for(i = 0; i < 6; i++) { + dt = &env->segs[i]; + if (i < 3) + offset = 0x7f84 + i * 12; + else + offset = 0x7f2c + (i - 3) * 12; + stl_phys(sm_state + 0x7fa8 + i * 4, dt->selector); + stl_phys(sm_state + offset + 8, dt->base); + stl_phys(sm_state + offset + 4, dt->limit); + stl_phys(sm_state + offset, (dt->flags >> 8) & 0xf0ff); + } + stl_phys(sm_state + 0x7f14, env->cr[4]); + + stl_phys(sm_state + 0x7efc, SMM_REVISION_ID); + stl_phys(sm_state + 0x7ef8, env->smbase); +#endif + /* init SMM cpu state */ + +#ifdef TARGET_X86_64 + cpu_load_efer(env, 0); +#endif + load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); + env->eip = 0x00008000; + cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase, + 0xffffffff, 0); + cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, 0); + cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffffffff, 0); + cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0); + cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0); + cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0); + + cpu_x86_update_cr0(env, + env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK)); + cpu_x86_update_cr4(env, 0); + env->dr[7] = 0x00000400; + CC_OP = CC_OP_EFLAGS; +} + +void helper_rsm(void) +{ + target_ulong sm_state; + int i, offset; + uint32_t val; + + sm_state = env->smbase + 0x8000; +#ifdef TARGET_X86_64 + cpu_load_efer(env, ldq_phys(sm_state + 0x7ed0)); + + for(i = 0; i < 6; i++) { + offset = 0x7e00 + i * 16; + cpu_x86_load_seg_cache(env, i, + lduw_phys(sm_state + offset), + ldq_phys(sm_state + offset + 8), + ldl_phys(sm_state + offset + 4), + (lduw_phys(sm_state + offset + 2) & 0xf0ff) << 8); + } + + env->gdt.base = ldq_phys(sm_state + 0x7e68); + env->gdt.limit = ldl_phys(sm_state + 0x7e64); + + env->ldt.selector = lduw_phys(sm_state + 0x7e70); + env->ldt.base = ldq_phys(sm_state + 0x7e78); + env->ldt.limit = ldl_phys(sm_state + 0x7e74); + env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8; + + env->idt.base = ldq_phys(sm_state + 0x7e88); + env->idt.limit = ldl_phys(sm_state + 0x7e84); + + env->tr.selector = lduw_phys(sm_state + 0x7e90); + env->tr.base = ldq_phys(sm_state + 0x7e98); + env->tr.limit = ldl_phys(sm_state + 0x7e94); + env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8; + + EAX = ldq_phys(sm_state + 0x7ff8); + ECX = ldq_phys(sm_state + 0x7ff0); + EDX = ldq_phys(sm_state + 0x7fe8); + EBX = ldq_phys(sm_state + 0x7fe0); + ESP = ldq_phys(sm_state + 0x7fd8); + EBP = ldq_phys(sm_state + 0x7fd0); + ESI = ldq_phys(sm_state + 0x7fc8); + EDI = ldq_phys(sm_state + 0x7fc0); + for(i = 8; i < 16; i++) + env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8); + env->eip = ldq_phys(sm_state + 0x7f78); + load_eflags(ldl_phys(sm_state + 0x7f70), + ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); + env->dr[6] = ldl_phys(sm_state + 0x7f68); + env->dr[7] = ldl_phys(sm_state + 0x7f60); + + cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f48)); + cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7f50)); + cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7f58)); + + val = ldl_phys(sm_state + 0x7efc); /* revision ID */ + if (val & 0x20000) { + env->smbase = ldl_phys(sm_state + 0x7f00) & ~0x7fff; + } +#else + cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc)); + cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8)); + load_eflags(ldl_phys(sm_state + 0x7ff4), + ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); + env->eip = ldl_phys(sm_state + 0x7ff0); + EDI = ldl_phys(sm_state + 0x7fec); + ESI = ldl_phys(sm_state + 0x7fe8); + EBP = ldl_phys(sm_state + 0x7fe4); + ESP = ldl_phys(sm_state + 0x7fe0); + EBX = ldl_phys(sm_state + 0x7fdc); + EDX = ldl_phys(sm_state + 0x7fd8); + ECX = ldl_phys(sm_state + 0x7fd4); + EAX = ldl_phys(sm_state + 0x7fd0); + env->dr[6] = ldl_phys(sm_state + 0x7fcc); + env->dr[7] = ldl_phys(sm_state + 0x7fc8); + + env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff; + env->tr.base = ldl_phys(sm_state + 0x7f64); + env->tr.limit = ldl_phys(sm_state + 0x7f60); + env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8; + + env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff; + env->ldt.base = ldl_phys(sm_state + 0x7f80); + env->ldt.limit = ldl_phys(sm_state + 0x7f7c); + env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8; + + env->gdt.base = ldl_phys(sm_state + 0x7f74); + env->gdt.limit = ldl_phys(sm_state + 0x7f70); + + env->idt.base = ldl_phys(sm_state + 0x7f58); + env->idt.limit = ldl_phys(sm_state + 0x7f54); + + for(i = 0; i < 6; i++) { + if (i < 3) + offset = 0x7f84 + i * 12; + else + offset = 0x7f2c + (i - 3) * 12; + cpu_x86_load_seg_cache(env, i, + ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff, + ldl_phys(sm_state + offset + 8), + ldl_phys(sm_state + offset + 4), + (ldl_phys(sm_state + offset) & 0xf0ff) << 8); + } + cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f14)); + + val = ldl_phys(sm_state + 0x7efc); /* revision ID */ + if (val & 0x20000) { + env->smbase = ldl_phys(sm_state + 0x7ef8) & ~0x7fff; + } +#endif + CC_OP = CC_OP_EFLAGS; + env->hflags &= ~HF_SMM_MASK; + cpu_smm_update(env); + + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "SMM: after RSM\n"); + cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); + } +} + +#endif /* !CONFIG_USER_ONLY */ + + +/* division, flags are undefined */ + +void helper_divb_AL(target_ulong t0) +{ + unsigned int num, den, q, r; + + num = (EAX & 0xffff); + den = (t0 & 0xff); + if (den == 0) { + raise_exception(EXCP00_DIVZ); + } + q = (num / den); + if (q > 0xff) + raise_exception(EXCP00_DIVZ); + q &= 0xff; + r = (num % den) & 0xff; + EAX = (EAX & ~0xffff) | (r << 8) | q; +} + +void helper_idivb_AL(target_ulong t0) +{ + int num, den, q, r; + + num = (int16_t)EAX; + den = (int8_t)t0; + if (den == 0) { + raise_exception(EXCP00_DIVZ); + } + q = (num / den); + if (q != (int8_t)q) + raise_exception(EXCP00_DIVZ); + q &= 0xff; + r = (num % den) & 0xff; + EAX = (EAX & ~0xffff) | (r << 8) | q; +} + +void helper_divw_AX(target_ulong t0) +{ + unsigned int num, den, q, r; + + num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); + den = (t0 & 0xffff); + if (den == 0) { + raise_exception(EXCP00_DIVZ); + } + q = (num / den); + if (q > 0xffff) + raise_exception(EXCP00_DIVZ); + q &= 0xffff; + r = (num % den) & 0xffff; + EAX = (EAX & ~0xffff) | q; + EDX = (EDX & ~0xffff) | r; +} + +void helper_idivw_AX(target_ulong t0) +{ + int num, den, q, r; + + num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); + den = (int16_t)t0; + if (den == 0) { + raise_exception(EXCP00_DIVZ); + } + q = (num / den); + if (q != (int16_t)q) + raise_exception(EXCP00_DIVZ); + q &= 0xffff; + r = (num % den) & 0xffff; + EAX = (EAX & ~0xffff) | q; + EDX = (EDX & ~0xffff) | r; +} + +void helper_divl_EAX(target_ulong t0) +{ + unsigned int den, r; + uint64_t num, q; + + num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); + den = t0; + if (den == 0) { + raise_exception(EXCP00_DIVZ); + } + q = (num / den); + r = (num % den); + if (q > 0xffffffff) + raise_exception(EXCP00_DIVZ); + EAX = (uint32_t)q; + EDX = (uint32_t)r; +} + +void helper_idivl_EAX(target_ulong t0) +{ + int den, r; + int64_t num, q; + + num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); + den = t0; + if (den == 0) { + raise_exception(EXCP00_DIVZ); + } + q = (num / den); + r = (num % den); + if (q != (int32_t)q) + raise_exception(EXCP00_DIVZ); + EAX = (uint32_t)q; + EDX = (uint32_t)r; +} + +/* bcd */ + +/* XXX: exception */ +void helper_aam(int base) +{ + int al, ah; + al = EAX & 0xff; + ah = al / base; + al = al % base; + EAX = (EAX & ~0xffff) | al | (ah << 8); + CC_DST = al; +} + +void helper_aad(int base) +{ + int al, ah; + al = EAX & 0xff; + ah = (EAX >> 8) & 0xff; + al = ((ah * base) + al) & 0xff; + EAX = (EAX & ~0xffff) | al; + CC_DST = al; +} + +void helper_aaa(void) +{ + int icarry; + int al, ah, af; + int eflags; + + eflags = cc_table[CC_OP].compute_all(); + af = eflags & CC_A; + al = EAX & 0xff; + ah = (EAX >> 8) & 0xff; + + icarry = (al > 0xf9); + if (((al & 0x0f) > 9 ) || af) { + al = (al + 6) & 0x0f; + ah = (ah + 1 + icarry) & 0xff; + eflags |= CC_C | CC_A; + } else { + eflags &= ~(CC_C | CC_A); + al &= 0x0f; + } + EAX = (EAX & ~0xffff) | al | (ah << 8); + CC_SRC = eflags; + FORCE_RET(); +} + +void helper_aas(void) +{ + int icarry; + int al, ah, af; + int eflags; + + eflags = cc_table[CC_OP].compute_all(); + af = eflags & CC_A; + al = EAX & 0xff; + ah = (EAX >> 8) & 0xff; + + icarry = (al < 6); + if (((al & 0x0f) > 9 ) || af) { + al = (al - 6) & 0x0f; + ah = (ah - 1 - icarry) & 0xff; + eflags |= CC_C | CC_A; + } else { + eflags &= ~(CC_C | CC_A); + al &= 0x0f; + } + EAX = (EAX & ~0xffff) | al | (ah << 8); + CC_SRC = eflags; + FORCE_RET(); +} + +void helper_daa(void) +{ + int al, af, cf; + int eflags; + + eflags = cc_table[CC_OP].compute_all(); + cf = eflags & CC_C; + af = eflags & CC_A; + al = EAX & 0xff; + + eflags = 0; + if (((al & 0x0f) > 9 ) || af) { + al = (al + 6) & 0xff; + eflags |= CC_A; + } + if ((al > 0x9f) || cf) { + al = (al + 0x60) & 0xff; + eflags |= CC_C; + } + EAX = (EAX & ~0xff) | al; + /* well, speed is not an issue here, so we compute the flags by hand */ + eflags |= (al == 0) << 6; /* zf */ + eflags |= parity_table[al]; /* pf */ + eflags |= (al & 0x80); /* sf */ + CC_SRC = eflags; + FORCE_RET(); +} + +void helper_das(void) +{ + int al, al1, af, cf; + int eflags; + + eflags = cc_table[CC_OP].compute_all(); + cf = eflags & CC_C; + af = eflags & CC_A; + al = EAX & 0xff; + + eflags = 0; + al1 = al; + if (((al & 0x0f) > 9 ) || af) { + eflags |= CC_A; + if (al < 6 || cf) + eflags |= CC_C; + al = (al - 6) & 0xff; + } + if ((al1 > 0x99) || cf) { + al = (al - 0x60) & 0xff; + eflags |= CC_C; + } + EAX = (EAX & ~0xff) | al; + /* well, speed is not an issue here, so we compute the flags by hand */ + eflags |= (al == 0) << 6; /* zf */ + eflags |= parity_table[al]; /* pf */ + eflags |= (al & 0x80); /* sf */ + CC_SRC = eflags; + FORCE_RET(); +} + +void helper_into(int next_eip_addend) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + if (eflags & CC_O) { + raise_interrupt(EXCP04_INTO, 1, 0, next_eip_addend); + } +} + +void helper_cmpxchg8b(target_ulong a0) +{ + uint64_t d; + int eflags; + + eflags = cc_table[CC_OP].compute_all(); + d = ldq(a0); + if (d == (((uint64_t)EDX << 32) | (uint32_t)EAX)) { + stq(a0, ((uint64_t)ECX << 32) | (uint32_t)EBX); + eflags |= CC_Z; + } else { + /* always do the store */ + stq(a0, d); + EDX = (uint32_t)(d >> 32); + EAX = (uint32_t)d; + eflags &= ~CC_Z; + } + CC_SRC = eflags; +} + +#ifdef TARGET_X86_64 +void helper_cmpxchg16b(target_ulong a0) +{ + uint64_t d0, d1; + int eflags; + + if ((a0 & 0xf) != 0) + raise_exception(EXCP0D_GPF); + eflags = cc_table[CC_OP].compute_all(); + d0 = ldq(a0); + d1 = ldq(a0 + 8); + if (d0 == EAX && d1 == EDX) { + stq(a0, EBX); + stq(a0 + 8, ECX); + eflags |= CC_Z; + } else { + /* always do the store */ + stq(a0, d0); + stq(a0 + 8, d1); + EDX = d1; + EAX = d0; + eflags &= ~CC_Z; + } + CC_SRC = eflags; +} +#endif + +void helper_single_step(void) +{ + env->dr[6] |= 0x4000; + raise_exception(EXCP01_SSTP); +} + +void helper_cpuid(void) +{ + uint32_t eax, ebx, ecx, edx; + + helper_svm_check_intercept_param(SVM_EXIT_CPUID, 0); + + cpu_x86_cpuid(env, (uint32_t)EAX, &eax, &ebx, &ecx, &edx); + EAX = eax; + EBX = ebx; + ECX = ecx; + EDX = edx; +} + +void helper_enter_level(int level, int data32, target_ulong t1) +{ + target_ulong ssp; + uint32_t esp_mask, esp, ebp; + + esp_mask = get_sp_mask(env->segs[R_SS].flags); + ssp = env->segs[R_SS].base; + ebp = EBP; + esp = ESP; + if (data32) { + /* 32 bit */ + esp -= 4; + while (--level) { + esp -= 4; + ebp -= 4; + stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask))); + } + esp -= 4; + stl(ssp + (esp & esp_mask), t1); + } else { + /* 16 bit */ + esp -= 2; + while (--level) { + esp -= 2; + ebp -= 2; + stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask))); + } + esp -= 2; + stw(ssp + (esp & esp_mask), t1); + } +} + +#ifdef TARGET_X86_64 +void helper_enter64_level(int level, int data64, target_ulong t1) +{ + target_ulong esp, ebp; + ebp = EBP; + esp = ESP; + + if (data64) { + /* 64 bit */ + esp -= 8; + while (--level) { + esp -= 8; + ebp -= 8; + stq(esp, ldq(ebp)); + } + esp -= 8; + stq(esp, t1); + } else { + /* 16 bit */ + esp -= 2; + while (--level) { + esp -= 2; + ebp -= 2; + stw(esp, lduw(ebp)); + } + esp -= 2; + stw(esp, t1); + } +} +#endif + +void helper_lldt(int selector) +{ + SegmentCache *dt; + uint32_t e1, e2; + int index, entry_limit; + target_ulong ptr; + + selector &= 0xffff; + if ((selector & 0xfffc) == 0) { + /* XXX: NULL selector case: invalid LDT */ + env->ldt.base = 0; + env->ldt.limit = 0; + } else { + if (selector & 0x4) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + dt = &env->gdt; + index = selector & ~7; +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) + entry_limit = 15; + else +#endif + entry_limit = 7; + if ((index + entry_limit) > dt->limit) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + ptr = dt->base + index; + e1 = ldl_kernel(ptr); + e2 = ldl_kernel(ptr + 4); + if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + uint32_t e3; + e3 = ldl_kernel(ptr + 8); + load_seg_cache_raw_dt(&env->ldt, e1, e2); + env->ldt.base |= (target_ulong)e3 << 32; + } else +#endif + { + load_seg_cache_raw_dt(&env->ldt, e1, e2); + } + } + env->ldt.selector = selector; +} + +void helper_ltr(int selector) +{ + SegmentCache *dt; + uint32_t e1, e2; + int index, type, entry_limit; + target_ulong ptr; + + selector &= 0xffff; + if ((selector & 0xfffc) == 0) { + /* NULL selector case: invalid TR */ + env->tr.base = 0; + env->tr.limit = 0; + env->tr.flags = 0; + } else { + if (selector & 0x4) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + dt = &env->gdt; + index = selector & ~7; +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) + entry_limit = 15; + else +#endif + entry_limit = 7; + if ((index + entry_limit) > dt->limit) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + ptr = dt->base + index; + e1 = ldl_kernel(ptr); + e2 = ldl_kernel(ptr + 4); + type = (e2 >> DESC_TYPE_SHIFT) & 0xf; + if ((e2 & DESC_S_MASK) || + (type != 1 && type != 9)) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + uint32_t e3, e4; + e3 = ldl_kernel(ptr + 8); + e4 = ldl_kernel(ptr + 12); + if ((e4 >> DESC_TYPE_SHIFT) & 0xf) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + load_seg_cache_raw_dt(&env->tr, e1, e2); + env->tr.base |= (target_ulong)e3 << 32; + } else +#endif + { + load_seg_cache_raw_dt(&env->tr, e1, e2); + } + e2 |= DESC_TSS_BUSY_MASK; + stl_kernel(ptr + 4, e2); + } + env->tr.selector = selector; +} + +/* only works if protected mode and not VM86. seg_reg must be != R_CS */ +void helper_load_seg(int seg_reg, int selector) +{ + uint32_t e1, e2; + int cpl, dpl, rpl; + SegmentCache *dt; + int index; + target_ulong ptr; + + selector &= 0xffff; + cpl = env->hflags & HF_CPL_MASK; + if ((selector & 0xfffc) == 0) { + /* null selector case */ + if (seg_reg == R_SS +#ifdef TARGET_X86_64 + && (!(env->hflags & HF_CS64_MASK) || cpl == 3) +#endif + ) + raise_exception_err(EXCP0D_GPF, 0); + cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0); + } else { + + if (selector & 0x4) + dt = &env->ldt; + else + dt = &env->gdt; + index = selector & ~7; + if ((index + 7) > dt->limit) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + ptr = dt->base + index; + e1 = ldl_kernel(ptr); + e2 = ldl_kernel(ptr + 4); + + if (!(e2 & DESC_S_MASK)) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + rpl = selector & 3; + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (seg_reg == R_SS) { + /* must be writable segment */ + if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (rpl != cpl || dpl != cpl) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } else { + /* must be readable segment */ + if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + + if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { + /* if not conforming code, test rights */ + if (dpl < cpl || dpl < rpl) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } + } + + if (!(e2 & DESC_P_MASK)) { + if (seg_reg == R_SS) + raise_exception_err(EXCP0C_STACK, selector & 0xfffc); + else + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + } + + /* set the access bit if not already set */ + if (!(e2 & DESC_A_MASK)) { + e2 |= DESC_A_MASK; + stl_kernel(ptr + 4, e2); + } + + cpu_x86_load_seg_cache(env, seg_reg, selector, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); +#if 0 + fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", + selector, (unsigned long)sc->base, sc->limit, sc->flags); +#endif + } +} + +/* protected mode jump */ +void helper_ljmp_protected(int new_cs, target_ulong new_eip, + int next_eip_addend) +{ + int gate_cs, type; + uint32_t e1, e2, cpl, dpl, rpl, limit; + target_ulong next_eip; + + if ((new_cs & 0xfffc) == 0) + raise_exception_err(EXCP0D_GPF, 0); + if (load_segment(&e1, &e2, new_cs) != 0) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + cpl = env->hflags & HF_CPL_MASK; + if (e2 & DESC_S_MASK) { + if (!(e2 & DESC_CS_MASK)) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (e2 & DESC_C_MASK) { + /* conforming code segment */ + if (dpl > cpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + } else { + /* non conforming code segment */ + rpl = new_cs & 3; + if (rpl > cpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + if (dpl != cpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + } + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); + limit = get_seg_limit(e1, e2); + if (new_eip > limit && + !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK)) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, + get_seg_base(e1, e2), limit, e2); + EIP = new_eip; + } else { + /* jump to call or task gate */ + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + rpl = new_cs & 3; + cpl = env->hflags & HF_CPL_MASK; + type = (e2 >> DESC_TYPE_SHIFT) & 0xf; + switch(type) { + case 1: /* 286 TSS */ + case 9: /* 386 TSS */ + case 5: /* task gate */ + if (dpl < cpl || dpl < rpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + next_eip = env->eip + next_eip_addend; + switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip); + CC_OP = CC_OP_EFLAGS; + break; + case 4: /* 286 call gate */ + case 12: /* 386 call gate */ + if ((dpl < cpl) || (dpl < rpl)) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); + gate_cs = e1 >> 16; + new_eip = (e1 & 0xffff); + if (type == 12) + new_eip |= (e2 & 0xffff0000); + if (load_segment(&e1, &e2, gate_cs) != 0) + raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + /* must be code segment */ + if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) != + (DESC_S_MASK | DESC_CS_MASK))) + raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); + if (((e2 & DESC_C_MASK) && (dpl > cpl)) || + (!(e2 & DESC_C_MASK) && (dpl != cpl))) + raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); + limit = get_seg_limit(e1, e2); + if (new_eip > limit) + raise_exception_err(EXCP0D_GPF, 0); + cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl, + get_seg_base(e1, e2), limit, e2); + EIP = new_eip; + break; + default: + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + break; + } + } +} + +/* real mode call */ +void helper_lcall_real(int new_cs, target_ulong new_eip1, + int shift, int next_eip) +{ + int new_eip; + uint32_t esp, esp_mask; + target_ulong ssp; + + new_eip = new_eip1; + esp = ESP; + esp_mask = get_sp_mask(env->segs[R_SS].flags); + ssp = env->segs[R_SS].base; + if (shift) { + PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector); + PUSHL(ssp, esp, esp_mask, next_eip); + } else { + PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector); + PUSHW(ssp, esp, esp_mask, next_eip); + } + + SET_ESP(esp, esp_mask); + env->eip = new_eip; + env->segs[R_CS].selector = new_cs; + env->segs[R_CS].base = (new_cs << 4); +} + +/* protected mode call */ +void helper_lcall_protected(int new_cs, target_ulong new_eip, + int shift, int next_eip_addend) +{ + int new_stack, i; + uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; + uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask; + uint32_t val, limit, old_sp_mask; + target_ulong ssp, old_ssp, next_eip; + + next_eip = env->eip + next_eip_addend; +#ifdef DEBUG_PCALL + if (loglevel & CPU_LOG_PCALL) { + fprintf(logfile, "lcall %04x:%08x s=%d\n", + new_cs, (uint32_t)new_eip, shift); + cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); + } +#endif + if ((new_cs & 0xfffc) == 0) + raise_exception_err(EXCP0D_GPF, 0); + if (load_segment(&e1, &e2, new_cs) != 0) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + cpl = env->hflags & HF_CPL_MASK; +#ifdef DEBUG_PCALL + if (loglevel & CPU_LOG_PCALL) { + fprintf(logfile, "desc=%08x:%08x\n", e1, e2); + } +#endif + if (e2 & DESC_S_MASK) { + if (!(e2 & DESC_CS_MASK)) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (e2 & DESC_C_MASK) { + /* conforming code segment */ + if (dpl > cpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + } else { + /* non conforming code segment */ + rpl = new_cs & 3; + if (rpl > cpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + if (dpl != cpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + } + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); + +#ifdef TARGET_X86_64 + /* XXX: check 16/32 bit cases in long mode */ + if (shift == 2) { + target_ulong rsp; + /* 64 bit case */ + rsp = ESP; + PUSHQ(rsp, env->segs[R_CS].selector); + PUSHQ(rsp, next_eip); + /* from this point, not restartable */ + ESP = rsp; + cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), e2); + EIP = new_eip; + } else +#endif + { + sp = ESP; + sp_mask = get_sp_mask(env->segs[R_SS].flags); + ssp = env->segs[R_SS].base; + if (shift) { + PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); + PUSHL(ssp, sp, sp_mask, next_eip); + } else { + PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); + PUSHW(ssp, sp, sp_mask, next_eip); + } + + limit = get_seg_limit(e1, e2); + if (new_eip > limit) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + /* from this point, not restartable */ + SET_ESP(sp, sp_mask); + cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, + get_seg_base(e1, e2), limit, e2); + EIP = new_eip; + } + } else { + /* check gate type */ + type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + rpl = new_cs & 3; + switch(type) { + case 1: /* available 286 TSS */ + case 9: /* available 386 TSS */ + case 5: /* task gate */ + if (dpl < cpl || dpl < rpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip); + CC_OP = CC_OP_EFLAGS; + return; + case 4: /* 286 call gate */ + case 12: /* 386 call gate */ + break; + default: + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + break; + } + shift = type >> 3; + + if (dpl < cpl || dpl < rpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + /* check valid bit */ + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); + selector = e1 >> 16; + offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); + param_count = e2 & 0x1f; + if ((selector & 0xfffc) == 0) + raise_exception_err(EXCP0D_GPF, 0); + + if (load_segment(&e1, &e2, selector) != 0) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (dpl > cpl) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + + if (!(e2 & DESC_C_MASK) && dpl < cpl) { + /* to inner privilege */ + get_ss_esp_from_tss(&ss, &sp, dpl); +#ifdef DEBUG_PCALL + if (loglevel & CPU_LOG_PCALL) + fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n", + ss, sp, param_count, ESP); +#endif + if ((ss & 0xfffc) == 0) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if ((ss & 3) != dpl) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if (load_segment(&ss_e1, &ss_e2, ss) != 0) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; + if (ss_dpl != dpl) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if (!(ss_e2 & DESC_S_MASK) || + (ss_e2 & DESC_CS_MASK) || + !(ss_e2 & DESC_W_MASK)) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if (!(ss_e2 & DESC_P_MASK)) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + + // push_size = ((param_count * 2) + 8) << shift; + + old_sp_mask = get_sp_mask(env->segs[R_SS].flags); + old_ssp = env->segs[R_SS].base; + + sp_mask = get_sp_mask(ss_e2); + ssp = get_seg_base(ss_e1, ss_e2); + if (shift) { + PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector); + PUSHL(ssp, sp, sp_mask, ESP); + for(i = param_count - 1; i >= 0; i--) { + val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask)); + PUSHL(ssp, sp, sp_mask, val); + } + } else { + PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector); + PUSHW(ssp, sp, sp_mask, ESP); + for(i = param_count - 1; i >= 0; i--) { + val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask)); + PUSHW(ssp, sp, sp_mask, val); + } + } + new_stack = 1; + } else { + /* to same privilege */ + sp = ESP; + sp_mask = get_sp_mask(env->segs[R_SS].flags); + ssp = env->segs[R_SS].base; + // push_size = (4 << shift); + new_stack = 0; + } + + if (shift) { + PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); + PUSHL(ssp, sp, sp_mask, next_eip); + } else { + PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); + PUSHW(ssp, sp, sp_mask, next_eip); + } + + /* from this point, not restartable */ + + if (new_stack) { + ss = (ss & ~3) | dpl; + cpu_x86_load_seg_cache(env, R_SS, ss, + ssp, + get_seg_limit(ss_e1, ss_e2), + ss_e2); + } + + selector = (selector & ~3) | dpl; + cpu_x86_load_seg_cache(env, R_CS, selector, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); + cpu_x86_set_cpl(env, dpl); + SET_ESP(sp, sp_mask); + EIP = offset; + } +#ifdef USE_KQEMU + if (kqemu_is_ok(env)) { + env->exception_index = -1; + cpu_loop_exit(); + } +#endif +} + +/* real and vm86 mode iret */ +void helper_iret_real(int shift) +{ + uint32_t sp, new_cs, new_eip, new_eflags, sp_mask; + target_ulong ssp; + int eflags_mask; + + sp_mask = 0xffff; /* XXXX: use SS segment size ? */ + sp = ESP; + ssp = env->segs[R_SS].base; + if (shift == 1) { + /* 32 bits */ + POPL(ssp, sp, sp_mask, new_eip); + POPL(ssp, sp, sp_mask, new_cs); + new_cs &= 0xffff; + POPL(ssp, sp, sp_mask, new_eflags); + } else { + /* 16 bits */ + POPW(ssp, sp, sp_mask, new_eip); + POPW(ssp, sp, sp_mask, new_cs); + POPW(ssp, sp, sp_mask, new_eflags); + } + ESP = (ESP & ~sp_mask) | (sp & sp_mask); + env->segs[R_CS].selector = new_cs; + env->segs[R_CS].base = (new_cs << 4); + env->eip = new_eip; + if (env->eflags & VM_MASK) + eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK; + else + eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK; + if (shift == 0) + eflags_mask &= 0xffff; + load_eflags(new_eflags, eflags_mask); + env->hflags2 &= ~HF2_NMI_MASK; +} + +static inline void validate_seg(int seg_reg, int cpl) +{ + int dpl; + uint32_t e2; + + /* XXX: on x86_64, we do not want to nullify FS and GS because + they may still contain a valid base. I would be interested to + know how a real x86_64 CPU behaves */ + if ((seg_reg == R_FS || seg_reg == R_GS) && + (env->segs[seg_reg].selector & 0xfffc) == 0) + return; + + e2 = env->segs[seg_reg].flags; + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { + /* data or non conforming code segment */ + if (dpl < cpl) { + cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0); + } + } +} + +/* protected mode iret */ +static inline void helper_ret_protected(int shift, int is_iret, int addend) +{ + uint32_t new_cs, new_eflags, new_ss; + uint32_t new_es, new_ds, new_fs, new_gs; + uint32_t e1, e2, ss_e1, ss_e2; + int cpl, dpl, rpl, eflags_mask, iopl; + target_ulong ssp, sp, new_eip, new_esp, sp_mask; + +#ifdef TARGET_X86_64 + if (shift == 2) + sp_mask = -1; + else +#endif + sp_mask = get_sp_mask(env->segs[R_SS].flags); + sp = ESP; + ssp = env->segs[R_SS].base; + new_eflags = 0; /* avoid warning */ +#ifdef TARGET_X86_64 + if (shift == 2) { + POPQ(sp, new_eip); + POPQ(sp, new_cs); + new_cs &= 0xffff; + if (is_iret) { + POPQ(sp, new_eflags); + } + } else +#endif + if (shift == 1) { + /* 32 bits */ + POPL(ssp, sp, sp_mask, new_eip); + POPL(ssp, sp, sp_mask, new_cs); + new_cs &= 0xffff; + if (is_iret) { + POPL(ssp, sp, sp_mask, new_eflags); + if (new_eflags & VM_MASK) + goto return_to_vm86; + } + } else { + /* 16 bits */ + POPW(ssp, sp, sp_mask, new_eip); + POPW(ssp, sp, sp_mask, new_cs); + if (is_iret) + POPW(ssp, sp, sp_mask, new_eflags); + } +#ifdef DEBUG_PCALL + if (loglevel & CPU_LOG_PCALL) { + fprintf(logfile, "lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n", + new_cs, new_eip, shift, addend); + cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); + } +#endif + if ((new_cs & 0xfffc) == 0) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + if (load_segment(&e1, &e2, new_cs) != 0) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + if (!(e2 & DESC_S_MASK) || + !(e2 & DESC_CS_MASK)) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + cpl = env->hflags & HF_CPL_MASK; + rpl = new_cs & 3; + if (rpl < cpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (e2 & DESC_C_MASK) { + if (dpl > rpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + } else { + if (dpl != rpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + } + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); + + sp += addend; + if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) || + ((env->hflags & HF_CS64_MASK) && !is_iret))) { + /* return to same privilege level */ + cpu_x86_load_seg_cache(env, R_CS, new_cs, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); + } else { + /* return to different privilege level */ +#ifdef TARGET_X86_64 + if (shift == 2) { + POPQ(sp, new_esp); + POPQ(sp, new_ss); + new_ss &= 0xffff; + } else +#endif + if (shift == 1) { + /* 32 bits */ + POPL(ssp, sp, sp_mask, new_esp); + POPL(ssp, sp, sp_mask, new_ss); + new_ss &= 0xffff; + } else { + /* 16 bits */ + POPW(ssp, sp, sp_mask, new_esp); + POPW(ssp, sp, sp_mask, new_ss); + } +#ifdef DEBUG_PCALL + if (loglevel & CPU_LOG_PCALL) { + fprintf(logfile, "new ss:esp=%04x:" TARGET_FMT_lx "\n", + new_ss, new_esp); + } +#endif + if ((new_ss & 0xfffc) == 0) { +#ifdef TARGET_X86_64 + /* NULL ss is allowed in long mode if cpl != 3*/ + /* XXX: test CS64 ? */ + if ((env->hflags & HF_LMA_MASK) && rpl != 3) { + cpu_x86_load_seg_cache(env, R_SS, new_ss, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (rpl << DESC_DPL_SHIFT) | + DESC_W_MASK | DESC_A_MASK); + ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */ + } else +#endif + { + raise_exception_err(EXCP0D_GPF, 0); + } + } else { + if ((new_ss & 3) != rpl) + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); + if (load_segment(&ss_e1, &ss_e2, new_ss) != 0) + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); + if (!(ss_e2 & DESC_S_MASK) || + (ss_e2 & DESC_CS_MASK) || + !(ss_e2 & DESC_W_MASK)) + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); + dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; + if (dpl != rpl) + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); + if (!(ss_e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); + cpu_x86_load_seg_cache(env, R_SS, new_ss, + get_seg_base(ss_e1, ss_e2), + get_seg_limit(ss_e1, ss_e2), + ss_e2); + } + + cpu_x86_load_seg_cache(env, R_CS, new_cs, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); + cpu_x86_set_cpl(env, rpl); + sp = new_esp; +#ifdef TARGET_X86_64 + if (env->hflags & HF_CS64_MASK) + sp_mask = -1; + else +#endif + sp_mask = get_sp_mask(ss_e2); + + /* validate data segments */ + validate_seg(R_ES, rpl); + validate_seg(R_DS, rpl); + validate_seg(R_FS, rpl); + validate_seg(R_GS, rpl); + + sp += addend; + } + SET_ESP(sp, sp_mask); + env->eip = new_eip; + if (is_iret) { + /* NOTE: 'cpl' is the _old_ CPL */ + eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK; + if (cpl == 0) + eflags_mask |= IOPL_MASK; + iopl = (env->eflags >> IOPL_SHIFT) & 3; + if (cpl <= iopl) + eflags_mask |= IF_MASK; + if (shift == 0) + eflags_mask &= 0xffff; + load_eflags(new_eflags, eflags_mask); + } + return; + + return_to_vm86: + POPL(ssp, sp, sp_mask, new_esp); + POPL(ssp, sp, sp_mask, new_ss); + POPL(ssp, sp, sp_mask, new_es); + POPL(ssp, sp, sp_mask, new_ds); + POPL(ssp, sp, sp_mask, new_fs); + POPL(ssp, sp, sp_mask, new_gs); + + /* modify processor state */ + load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK | + IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK); + load_seg_vm(R_CS, new_cs & 0xffff); + cpu_x86_set_cpl(env, 3); + load_seg_vm(R_SS, new_ss & 0xffff); + load_seg_vm(R_ES, new_es & 0xffff); + load_seg_vm(R_DS, new_ds & 0xffff); + load_seg_vm(R_FS, new_fs & 0xffff); + load_seg_vm(R_GS, new_gs & 0xffff); + + env->eip = new_eip & 0xffff; + ESP = new_esp; +} + +void helper_iret_protected(int shift, int next_eip) +{ + int tss_selector, type; + uint32_t e1, e2; + + /* specific case for TSS */ + if (env->eflags & NT_MASK) { +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) + raise_exception_err(EXCP0D_GPF, 0); +#endif + tss_selector = lduw_kernel(env->tr.base + 0); + if (tss_selector & 4) + raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); + if (load_segment(&e1, &e2, tss_selector) != 0) + raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); + type = (e2 >> DESC_TYPE_SHIFT) & 0x17; + /* NOTE: we check both segment and busy TSS */ + if (type != 3) + raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); + switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip); + } else { + helper_ret_protected(shift, 1, 0); + } + env->hflags2 &= ~HF2_NMI_MASK; +#ifdef USE_KQEMU + if (kqemu_is_ok(env)) { + CC_OP = CC_OP_EFLAGS; + env->exception_index = -1; + cpu_loop_exit(); + } +#endif +} + +void helper_lret_protected(int shift, int addend) +{ + helper_ret_protected(shift, 0, addend); +#ifdef USE_KQEMU + if (kqemu_is_ok(env)) { + env->exception_index = -1; + cpu_loop_exit(); + } +#endif +} + +void helper_sysenter(void) +{ + if (env->sysenter_cs == 0) { + raise_exception_err(EXCP0D_GPF, 0); + } + env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK); + cpu_x86_set_cpl(env, 0); + +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); + } else +#endif + { + cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); + } + cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_W_MASK | DESC_A_MASK); + ESP = env->sysenter_esp; + EIP = env->sysenter_eip; +} + +void helper_sysexit(int dflag) +{ + int cpl; + + cpl = env->hflags & HF_CPL_MASK; + if (env->sysenter_cs == 0 || cpl != 0) { + raise_exception_err(EXCP0D_GPF, 0); + } + cpu_x86_set_cpl(env, 3); +#ifdef TARGET_X86_64 + if (dflag == 2) { + cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 32) & 0xfffc) | 3, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); + cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 40) & 0xfffc) | 3, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | + DESC_W_MASK | DESC_A_MASK); + } else +#endif + { + cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); + cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | + DESC_W_MASK | DESC_A_MASK); + } + ESP = ECX; + EIP = EDX; +#ifdef USE_KQEMU + if (kqemu_is_ok(env)) { + env->exception_index = -1; + cpu_loop_exit(); + } +#endif +} + +#if defined(CONFIG_USER_ONLY) +target_ulong helper_read_crN(int reg) +{ + return 0; +} + +void helper_write_crN(int reg, target_ulong t0) +{ +} +#else +target_ulong helper_read_crN(int reg) +{ + target_ulong val; + + helper_svm_check_intercept_param(SVM_EXIT_READ_CR0 + reg, 0); + switch(reg) { + default: + val = env->cr[reg]; + break; + case 8: + if (!(env->hflags2 & HF2_VINTR_MASK)) { + val = cpu_get_apic_tpr(env); + } else { + val = env->v_tpr; + } + break; + } + return val; +} + +void helper_write_crN(int reg, target_ulong t0) +{ + helper_svm_check_intercept_param(SVM_EXIT_WRITE_CR0 + reg, 0); + switch(reg) { + case 0: + cpu_x86_update_cr0(env, t0); + break; + case 3: + cpu_x86_update_cr3(env, t0); + break; + case 4: + cpu_x86_update_cr4(env, t0); + break; + case 8: + if (!(env->hflags2 & HF2_VINTR_MASK)) { + cpu_set_apic_tpr(env, t0); + } + env->v_tpr = t0 & 0x0f; + break; + default: + env->cr[reg] = t0; + break; + } +} +#endif + +void helper_lmsw(target_ulong t0) +{ + /* only 4 lower bits of CR0 are modified. PE cannot be set to zero + if already set to one. */ + t0 = (env->cr[0] & ~0xe) | (t0 & 0xf); + helper_write_crN(0, t0); +} + +void helper_clts(void) +{ + env->cr[0] &= ~CR0_TS_MASK; + env->hflags &= ~HF_TS_MASK; +} + +/* XXX: do more */ +void helper_movl_drN_T0(int reg, target_ulong t0) +{ + env->dr[reg] = t0; +} + +void helper_invlpg(target_ulong addr) +{ + helper_svm_check_intercept_param(SVM_EXIT_INVLPG, 0); + tlb_flush_page(env, addr); +} + +void helper_rdtsc(void) +{ + uint64_t val; + + if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) { + raise_exception(EXCP0D_GPF); + } + helper_svm_check_intercept_param(SVM_EXIT_RDTSC, 0); + + val = cpu_get_tsc(env) + env->tsc_offset; + EAX = (uint32_t)(val); + EDX = (uint32_t)(val >> 32); +} + +void helper_rdpmc(void) +{ + if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) { + raise_exception(EXCP0D_GPF); + } + helper_svm_check_intercept_param(SVM_EXIT_RDPMC, 0); + + /* currently unimplemented */ + raise_exception_err(EXCP06_ILLOP, 0); +} + +#if defined(CONFIG_USER_ONLY) +void helper_wrmsr(void) +{ +} + +void helper_rdmsr(void) +{ +} +#else +void helper_wrmsr(void) +{ + uint64_t val; + + helper_svm_check_intercept_param(SVM_EXIT_MSR, 1); + + val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); + + switch((uint32_t)ECX) { + case MSR_IA32_SYSENTER_CS: + env->sysenter_cs = val & 0xffff; + break; + case MSR_IA32_SYSENTER_ESP: + env->sysenter_esp = val; + break; + case MSR_IA32_SYSENTER_EIP: + env->sysenter_eip = val; + break; + case MSR_IA32_APICBASE: + cpu_set_apic_base(env, val); + break; + case MSR_EFER: + { + uint64_t update_mask; + update_mask = 0; + if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL) + update_mask |= MSR_EFER_SCE; + if (env->cpuid_ext2_features & CPUID_EXT2_LM) + update_mask |= MSR_EFER_LME; + if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR) + update_mask |= MSR_EFER_FFXSR; + if (env->cpuid_ext2_features & CPUID_EXT2_NX) + update_mask |= MSR_EFER_NXE; + if (env->cpuid_ext3_features & CPUID_EXT3_SVM) + update_mask |= MSR_EFER_SVME; + cpu_load_efer(env, (env->efer & ~update_mask) | + (val & update_mask)); + } + break; + case MSR_STAR: + env->star = val; + break; + case MSR_PAT: + env->pat = val; + break; + case MSR_VM_HSAVE_PA: + env->vm_hsave = val; + break; +#ifdef TARGET_X86_64 + case MSR_LSTAR: + env->lstar = val; + break; + case MSR_CSTAR: + env->cstar = val; + break; + case MSR_FMASK: + env->fmask = val; + break; + case MSR_FSBASE: + env->segs[R_FS].base = val; + break; + case MSR_GSBASE: + env->segs[R_GS].base = val; + break; + case MSR_KERNELGSBASE: + env->kernelgsbase = val; + break; +#endif + default: + /* XXX: exception ? */ + break; + } +} + +void helper_rdmsr(void) +{ + uint64_t val; + + helper_svm_check_intercept_param(SVM_EXIT_MSR, 0); + + switch((uint32_t)ECX) { + case MSR_IA32_SYSENTER_CS: + val = env->sysenter_cs; + break; + case MSR_IA32_SYSENTER_ESP: + val = env->sysenter_esp; + break; + case MSR_IA32_SYSENTER_EIP: + val = env->sysenter_eip; + break; + case MSR_IA32_APICBASE: + val = cpu_get_apic_base(env); + break; + case MSR_EFER: + val = env->efer; + break; + case MSR_STAR: + val = env->star; + break; + case MSR_PAT: + val = env->pat; + break; + case MSR_VM_HSAVE_PA: + val = env->vm_hsave; + break; + case MSR_IA32_PERF_STATUS: + /* tsc_increment_by_tick */ + val = 1000ULL; + /* CPU multiplier */ + val |= (((uint64_t)4ULL) << 40); + break; +#ifdef TARGET_X86_64 + case MSR_LSTAR: + val = env->lstar; + break; + case MSR_CSTAR: + val = env->cstar; + break; + case MSR_FMASK: + val = env->fmask; + break; + case MSR_FSBASE: + val = env->segs[R_FS].base; + break; + case MSR_GSBASE: + val = env->segs[R_GS].base; + break; + case MSR_KERNELGSBASE: + val = env->kernelgsbase; + break; +#endif +#ifdef USE_KQEMU + case MSR_QPI_COMMBASE: + if (env->kqemu_enabled) { + val = kqemu_comm_base; + } else { + val = 0; + } + break; +#endif + default: + /* XXX: exception ? */ + val = 0; + break; + } + EAX = (uint32_t)(val); + EDX = (uint32_t)(val >> 32); +} +#endif + +target_ulong helper_lsl(target_ulong selector1) +{ + unsigned int limit; + uint32_t e1, e2, eflags, selector; + int rpl, dpl, cpl, type; + + selector = selector1 & 0xffff; + eflags = cc_table[CC_OP].compute_all(); + if (load_segment(&e1, &e2, selector) != 0) + goto fail; + rpl = selector & 3; + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + if (e2 & DESC_S_MASK) { + if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) { + /* conforming */ + } else { + if (dpl < cpl || dpl < rpl) + goto fail; + } + } else { + type = (e2 >> DESC_TYPE_SHIFT) & 0xf; + switch(type) { + case 1: + case 2: + case 3: + case 9: + case 11: + break; + default: + goto fail; + } + if (dpl < cpl || dpl < rpl) { + fail: + CC_SRC = eflags & ~CC_Z; + return 0; + } + } + limit = get_seg_limit(e1, e2); + CC_SRC = eflags | CC_Z; + return limit; +} + +target_ulong helper_lar(target_ulong selector1) +{ + uint32_t e1, e2, eflags, selector; + int rpl, dpl, cpl, type; + + selector = selector1 & 0xffff; + eflags = cc_table[CC_OP].compute_all(); + if ((selector & 0xfffc) == 0) + goto fail; + if (load_segment(&e1, &e2, selector) != 0) + goto fail; + rpl = selector & 3; + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + if (e2 & DESC_S_MASK) { + if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) { + /* conforming */ + } else { + if (dpl < cpl || dpl < rpl) + goto fail; + } + } else { + type = (e2 >> DESC_TYPE_SHIFT) & 0xf; + switch(type) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 9: + case 11: + case 12: + break; + default: + goto fail; + } + if (dpl < cpl || dpl < rpl) { + fail: + CC_SRC = eflags & ~CC_Z; + return 0; + } + } + CC_SRC = eflags | CC_Z; + return e2 & 0x00f0ff00; +} + +void helper_verr(target_ulong selector1) +{ + uint32_t e1, e2, eflags, selector; + int rpl, dpl, cpl; + + selector = selector1 & 0xffff; + eflags = cc_table[CC_OP].compute_all(); + if ((selector & 0xfffc) == 0) + goto fail; + if (load_segment(&e1, &e2, selector) != 0) + goto fail; + if (!(e2 & DESC_S_MASK)) + goto fail; + rpl = selector & 3; + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + if (e2 & DESC_CS_MASK) { + if (!(e2 & DESC_R_MASK)) + goto fail; + if (!(e2 & DESC_C_MASK)) { + if (dpl < cpl || dpl < rpl) + goto fail; + } + } else { + if (dpl < cpl || dpl < rpl) { + fail: + CC_SRC = eflags & ~CC_Z; + return; + } + } + CC_SRC = eflags | CC_Z; +} + +void helper_verw(target_ulong selector1) +{ + uint32_t e1, e2, eflags, selector; + int rpl, dpl, cpl; + + selector = selector1 & 0xffff; + eflags = cc_table[CC_OP].compute_all(); + if ((selector & 0xfffc) == 0) + goto fail; + if (load_segment(&e1, &e2, selector) != 0) + goto fail; + if (!(e2 & DESC_S_MASK)) + goto fail; + rpl = selector & 3; + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + if (e2 & DESC_CS_MASK) { + goto fail; + } else { + if (dpl < cpl || dpl < rpl) + goto fail; + if (!(e2 & DESC_W_MASK)) { + fail: + CC_SRC = eflags & ~CC_Z; + return; + } + } + CC_SRC = eflags | CC_Z; +} + +/* x87 FPU helpers */ + +static void fpu_set_exception(int mask) +{ + env->fpus |= mask; + if (env->fpus & (~env->fpuc & FPUC_EM)) + env->fpus |= FPUS_SE | FPUS_B; +} + +static inline CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b) +{ + if (b == 0.0) + fpu_set_exception(FPUS_ZE); + return a / b; +} + +void fpu_raise_exception(void) +{ + if (env->cr[0] & CR0_NE_MASK) { + raise_exception(EXCP10_COPR); + } +#if !defined(CONFIG_USER_ONLY) + else { + cpu_set_ferr(env); + } +#endif +} + +void helper_flds_FT0(uint32_t val) +{ + union { + float32 f; + uint32_t i; + } u; + u.i = val; + FT0 = float32_to_floatx(u.f, &env->fp_status); +} + +void helper_fldl_FT0(uint64_t val) +{ + union { + float64 f; + uint64_t i; + } u; + u.i = val; + FT0 = float64_to_floatx(u.f, &env->fp_status); +} + +void helper_fildl_FT0(int32_t val) +{ + FT0 = int32_to_floatx(val, &env->fp_status); +} + +void helper_flds_ST0(uint32_t val) +{ + int new_fpstt; + union { + float32 f; + uint32_t i; + } u; + new_fpstt = (env->fpstt - 1) & 7; + u.i = val; + env->fpregs[new_fpstt].d = float32_to_floatx(u.f, &env->fp_status); + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ +} + +void helper_fldl_ST0(uint64_t val) +{ + int new_fpstt; + union { + float64 f; + uint64_t i; + } u; + new_fpstt = (env->fpstt - 1) & 7; + u.i = val; + env->fpregs[new_fpstt].d = float64_to_floatx(u.f, &env->fp_status); + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ +} + +void helper_fildl_ST0(int32_t val) +{ + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; + env->fpregs[new_fpstt].d = int32_to_floatx(val, &env->fp_status); + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ +} + +void helper_fildll_ST0(int64_t val) +{ + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; + env->fpregs[new_fpstt].d = int64_to_floatx(val, &env->fp_status); + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ +} + +uint32_t helper_fsts_ST0(void) +{ + union { + float32 f; + uint32_t i; + } u; + u.f = floatx_to_float32(ST0, &env->fp_status); + return u.i; +} + +uint64_t helper_fstl_ST0(void) +{ + union { + float64 f; + uint64_t i; + } u; + u.f = floatx_to_float64(ST0, &env->fp_status); + return u.i; +} + +int32_t helper_fist_ST0(void) +{ + int32_t val; + val = floatx_to_int32(ST0, &env->fp_status); + if (val != (int16_t)val) + val = -32768; + return val; +} + +int32_t helper_fistl_ST0(void) +{ + int32_t val; + val = floatx_to_int32(ST0, &env->fp_status); + return val; +} + +int64_t helper_fistll_ST0(void) +{ + int64_t val; + val = floatx_to_int64(ST0, &env->fp_status); + return val; +} + +int32_t helper_fistt_ST0(void) +{ + int32_t val; + val = floatx_to_int32_round_to_zero(ST0, &env->fp_status); + if (val != (int16_t)val) + val = -32768; + return val; +} + +int32_t helper_fisttl_ST0(void) +{ + int32_t val; + val = floatx_to_int32_round_to_zero(ST0, &env->fp_status); + return val; +} + +int64_t helper_fisttll_ST0(void) +{ + int64_t val; + val = floatx_to_int64_round_to_zero(ST0, &env->fp_status); + return val; +} + +void helper_fldt_ST0(target_ulong ptr) +{ + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; + env->fpregs[new_fpstt].d = helper_fldt(ptr); + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ +} + +void helper_fstt_ST0(target_ulong ptr) +{ + helper_fstt(ST0, ptr); +} + +void helper_fpush(void) +{ + fpush(); +} + +void helper_fpop(void) +{ + fpop(); +} + +void helper_fdecstp(void) +{ + env->fpstt = (env->fpstt - 1) & 7; + env->fpus &= (~0x4700); +} + +void helper_fincstp(void) +{ + env->fpstt = (env->fpstt + 1) & 7; + env->fpus &= (~0x4700); +} + +/* FPU move */ + +void helper_ffree_STN(int st_index) +{ + env->fptags[(env->fpstt + st_index) & 7] = 1; +} + +void helper_fmov_ST0_FT0(void) +{ + ST0 = FT0; +} + +void helper_fmov_FT0_STN(int st_index) +{ + FT0 = ST(st_index); +} + +void helper_fmov_ST0_STN(int st_index) +{ + ST0 = ST(st_index); +} + +void helper_fmov_STN_ST0(int st_index) +{ + ST(st_index) = ST0; +} + +void helper_fxchg_ST0_STN(int st_index) +{ + CPU86_LDouble tmp; + tmp = ST(st_index); + ST(st_index) = ST0; + ST0 = tmp; +} + +/* FPU operations */ + +static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500}; + +void helper_fcom_ST0_FT0(void) +{ + int ret; + + ret = floatx_compare(ST0, FT0, &env->fp_status); + env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1]; + FORCE_RET(); +} + +void helper_fucom_ST0_FT0(void) +{ + int ret; + + ret = floatx_compare_quiet(ST0, FT0, &env->fp_status); + env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret+ 1]; + FORCE_RET(); +} + +static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C}; + +void helper_fcomi_ST0_FT0(void) +{ + int eflags; + int ret; + + ret = floatx_compare(ST0, FT0, &env->fp_status); + eflags = cc_table[CC_OP].compute_all(); + eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1]; + CC_SRC = eflags; + FORCE_RET(); +} + +void helper_fucomi_ST0_FT0(void) +{ + int eflags; + int ret; + + ret = floatx_compare_quiet(ST0, FT0, &env->fp_status); + eflags = cc_table[CC_OP].compute_all(); + eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1]; + CC_SRC = eflags; + FORCE_RET(); +} + +void helper_fadd_ST0_FT0(void) +{ + ST0 += FT0; +} + +void helper_fmul_ST0_FT0(void) +{ + ST0 *= FT0; +} + +void helper_fsub_ST0_FT0(void) +{ + ST0 -= FT0; +} + +void helper_fsubr_ST0_FT0(void) +{ + ST0 = FT0 - ST0; +} + +void helper_fdiv_ST0_FT0(void) +{ + ST0 = helper_fdiv(ST0, FT0); +} + +void helper_fdivr_ST0_FT0(void) +{ + ST0 = helper_fdiv(FT0, ST0); +} + +/* fp operations between STN and ST0 */ + +void helper_fadd_STN_ST0(int st_index) +{ + ST(st_index) += ST0; +} + +void helper_fmul_STN_ST0(int st_index) +{ + ST(st_index) *= ST0; +} + +void helper_fsub_STN_ST0(int st_index) +{ + ST(st_index) -= ST0; +} + +void helper_fsubr_STN_ST0(int st_index) +{ + CPU86_LDouble *p; + p = &ST(st_index); + *p = ST0 - *p; +} + +void helper_fdiv_STN_ST0(int st_index) +{ + CPU86_LDouble *p; + p = &ST(st_index); + *p = helper_fdiv(*p, ST0); +} + +void helper_fdivr_STN_ST0(int st_index) +{ + CPU86_LDouble *p; + p = &ST(st_index); + *p = helper_fdiv(ST0, *p); +} + +/* misc FPU operations */ +void helper_fchs_ST0(void) +{ + ST0 = floatx_chs(ST0); +} + +void helper_fabs_ST0(void) +{ + ST0 = floatx_abs(ST0); +} + +void helper_fld1_ST0(void) +{ + ST0 = f15rk[1]; +} + +void helper_fldl2t_ST0(void) +{ + ST0 = f15rk[6]; +} + +void helper_fldl2e_ST0(void) +{ + ST0 = f15rk[5]; +} + +void helper_fldpi_ST0(void) +{ + ST0 = f15rk[2]; +} + +void helper_fldlg2_ST0(void) +{ + ST0 = f15rk[3]; +} + +void helper_fldln2_ST0(void) +{ + ST0 = f15rk[4]; +} + +void helper_fldz_ST0(void) +{ + ST0 = f15rk[0]; +} + +void helper_fldz_FT0(void) +{ + FT0 = f15rk[0]; +} + +uint32_t helper_fnstsw(void) +{ + return (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; +} + +uint32_t helper_fnstcw(void) +{ + return env->fpuc; +} + +static void update_fp_status(void) +{ + int rnd_type; + + /* set rounding mode */ + switch(env->fpuc & RC_MASK) { + default: + case RC_NEAR: + rnd_type = float_round_nearest_even; + break; + case RC_DOWN: + rnd_type = float_round_down; + break; + case RC_UP: + rnd_type = float_round_up; + break; + case RC_CHOP: + rnd_type = float_round_to_zero; + break; + } + set_float_rounding_mode(rnd_type, &env->fp_status); +#ifdef FLOATX80 + switch((env->fpuc >> 8) & 3) { + case 0: + rnd_type = 32; + break; + case 2: + rnd_type = 64; + break; + case 3: + default: + rnd_type = 80; + break; + } + set_floatx80_rounding_precision(rnd_type, &env->fp_status); +#endif +} + +void helper_fldcw(uint32_t val) +{ + env->fpuc = val; + update_fp_status(); +} + +void helper_fclex(void) +{ + env->fpus &= 0x7f00; +} + +void helper_fwait(void) +{ + if (env->fpus & FPUS_SE) + fpu_raise_exception(); + FORCE_RET(); +} + +void helper_fninit(void) +{ + env->fpus = 0; + env->fpstt = 0; + env->fpuc = 0x37f; + env->fptags[0] = 1; + env->fptags[1] = 1; + env->fptags[2] = 1; + env->fptags[3] = 1; + env->fptags[4] = 1; + env->fptags[5] = 1; + env->fptags[6] = 1; + env->fptags[7] = 1; +} + +/* BCD ops */ + +void helper_fbld_ST0(target_ulong ptr) +{ + CPU86_LDouble tmp; + uint64_t val; + unsigned int v; + int i; + + val = 0; + for(i = 8; i >= 0; i--) { + v = ldub(ptr + i); + val = (val * 100) + ((v >> 4) * 10) + (v & 0xf); + } + tmp = val; + if (ldub(ptr + 9) & 0x80) + tmp = -tmp; + fpush(); + ST0 = tmp; +} + +void helper_fbst_ST0(target_ulong ptr) +{ + int v; + target_ulong mem_ref, mem_end; + int64_t val; + + val = floatx_to_int64(ST0, &env->fp_status); + mem_ref = ptr; + mem_end = mem_ref + 9; + if (val < 0) { + stb(mem_end, 0x80); + val = -val; + } else { + stb(mem_end, 0x00); + } + while (mem_ref < mem_end) { + if (val == 0) + break; + v = val % 100; + val = val / 100; + v = ((v / 10) << 4) | (v % 10); + stb(mem_ref++, v); + } + while (mem_ref < mem_end) { + stb(mem_ref++, 0); + } +} + +void helper_f2xm1(void) +{ + ST0 = pow(2.0,ST0) - 1.0; +} + +void helper_fyl2x(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if (fptemp>0.0){ + fptemp = log(fptemp)/log(2.0); /* log2(ST) */ + ST1 *= fptemp; + fpop(); + } else { + env->fpus &= (~0x4700); + env->fpus |= 0x400; + } +} + +void helper_fptan(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = tan(fptemp); + fpush(); + ST0 = 1.0; + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg| < 2**52 only */ + } +} + +void helper_fpatan(void) +{ + CPU86_LDouble fptemp, fpsrcop; + + fpsrcop = ST1; + fptemp = ST0; + ST1 = atan2(fpsrcop,fptemp); + fpop(); +} + +void helper_fxtract(void) +{ + CPU86_LDoubleU temp; + unsigned int expdif; + + temp.d = ST0; + expdif = EXPD(temp) - EXPBIAS; + /*DP exponent bias*/ + ST0 = expdif; + fpush(); + BIASEXPONENT(temp); + ST0 = temp.d; +} + +void helper_fprem1(void) +{ + CPU86_LDouble dblq, fpsrcop, fptemp; + CPU86_LDoubleU fpsrcop1, fptemp1; + int expdif; + signed long long int q; + + if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) { + ST0 = 0.0 / 0.0; /* NaN */ + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + return; + } + + fpsrcop = ST0; + fptemp = ST1; + fpsrcop1.d = fpsrcop; + fptemp1.d = fptemp; + expdif = EXPD(fpsrcop1) - EXPD(fptemp1); + + if (expdif < 0) { + /* optimisation? taken from the AMD docs */ + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + /* ST0 is unchanged */ + return; + } + + if (expdif < 53) { + dblq = fpsrcop / fptemp; + /* round dblq towards nearest integer */ + dblq = rint(dblq); + ST0 = fpsrcop - fptemp * dblq; + + /* convert dblq to q by truncating towards zero */ + if (dblq < 0.0) + q = (signed long long int)(-dblq); + else + q = (signed long long int)dblq; + + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + /* (C0,C3,C1) <-- (q2,q1,q0) */ + env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */ + env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */ + env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */ + } else { + env->fpus |= 0x400; /* C2 <-- 1 */ + fptemp = pow(2.0, expdif - 50); + fpsrcop = (ST0 / ST1) / fptemp; + /* fpsrcop = integer obtained by chopping */ + fpsrcop = (fpsrcop < 0.0) ? + -(floor(fabs(fpsrcop))) : floor(fpsrcop); + ST0 -= (ST1 * fpsrcop * fptemp); + } +} + +void helper_fprem(void) +{ + CPU86_LDouble dblq, fpsrcop, fptemp; + CPU86_LDoubleU fpsrcop1, fptemp1; + int expdif; + signed long long int q; + + if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) { + ST0 = 0.0 / 0.0; /* NaN */ + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + return; + } + + fpsrcop = (CPU86_LDouble)ST0; + fptemp = (CPU86_LDouble)ST1; + fpsrcop1.d = fpsrcop; + fptemp1.d = fptemp; + expdif = EXPD(fpsrcop1) - EXPD(fptemp1); + + if (expdif < 0) { + /* optimisation? taken from the AMD docs */ + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + /* ST0 is unchanged */ + return; + } + + if ( expdif < 53 ) { + dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/; + /* round dblq towards zero */ + dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq); + ST0 = fpsrcop/*ST0*/ - fptemp * dblq; + + /* convert dblq to q by truncating towards zero */ + if (dblq < 0.0) + q = (signed long long int)(-dblq); + else + q = (signed long long int)dblq; + + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + /* (C0,C3,C1) <-- (q2,q1,q0) */ + env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */ + env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */ + env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */ + } else { + int N = 32 + (expdif % 32); /* as per AMD docs */ + env->fpus |= 0x400; /* C2 <-- 1 */ + fptemp = pow(2.0, (double)(expdif - N)); + fpsrcop = (ST0 / ST1) / fptemp; + /* fpsrcop = integer obtained by chopping */ + fpsrcop = (fpsrcop < 0.0) ? + -(floor(fabs(fpsrcop))) : floor(fpsrcop); + ST0 -= (ST1 * fpsrcop * fptemp); + } +} + +void helper_fyl2xp1(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if ((fptemp+1.0)>0.0) { + fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ + ST1 *= fptemp; + fpop(); + } else { + env->fpus &= (~0x4700); + env->fpus |= 0x400; + } +} + +void helper_fsqrt(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if (fptemp<0.0) { + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + env->fpus |= 0x400; + } + ST0 = sqrt(fptemp); +} + +void helper_fsincos(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = sin(fptemp); + fpush(); + ST0 = cos(fptemp); + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg| < 2**63 only */ + } +} + +void helper_frndint(void) +{ + ST0 = floatx_round_to_int(ST0, &env->fp_status); +} + +void helper_fscale(void) +{ + ST0 = ldexp (ST0, (int)(ST1)); +} + +void helper_fsin(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = sin(fptemp); + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg| < 2**53 only */ + } +} + +void helper_fcos(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = cos(fptemp); + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg5 < 2**63 only */ + } +} + +void helper_fxam_ST0(void) +{ + CPU86_LDoubleU temp; + int expdif; + + temp.d = ST0; + + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + if (SIGND(temp)) + env->fpus |= 0x200; /* C1 <-- 1 */ + + /* XXX: test fptags too */ + expdif = EXPD(temp); + if (expdif == MAXEXPD) { +#ifdef USE_X86LDOUBLE + if (MANTD(temp) == 0x8000000000000000ULL) +#else + if (MANTD(temp) == 0) +#endif + env->fpus |= 0x500 /*Infinity*/; + else + env->fpus |= 0x100 /*NaN*/; + } else if (expdif == 0) { + if (MANTD(temp) == 0) + env->fpus |= 0x4000 /*Zero*/; + else + env->fpus |= 0x4400 /*Denormal*/; + } else { + env->fpus |= 0x400; + } +} + +void helper_fstenv(target_ulong ptr, int data32) +{ + int fpus, fptag, exp, i; + uint64_t mant; + CPU86_LDoubleU tmp; + + fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + fptag = 0; + for (i=7; i>=0; i--) { + fptag <<= 2; + if (env->fptags[i]) { + fptag |= 3; + } else { + tmp.d = env->fpregs[i].d; + exp = EXPD(tmp); + mant = MANTD(tmp); + if (exp == 0 && mant == 0) { + /* zero */ + fptag |= 1; + } else if (exp == 0 || exp == MAXEXPD +#ifdef USE_X86LDOUBLE + || (mant & (1LL << 63)) == 0 +#endif + ) { + /* NaNs, infinity, denormal */ + fptag |= 2; + } + } + } + if (data32) { + /* 32 bit */ + stl(ptr, env->fpuc); + stl(ptr + 4, fpus); + stl(ptr + 8, fptag); + stl(ptr + 12, 0); /* fpip */ + stl(ptr + 16, 0); /* fpcs */ + stl(ptr + 20, 0); /* fpoo */ + stl(ptr + 24, 0); /* fpos */ + } else { + /* 16 bit */ + stw(ptr, env->fpuc); + stw(ptr + 2, fpus); + stw(ptr + 4, fptag); + stw(ptr + 6, 0); + stw(ptr + 8, 0); + stw(ptr + 10, 0); + stw(ptr + 12, 0); + } +} + +void helper_fldenv(target_ulong ptr, int data32) +{ + int i, fpus, fptag; + + if (data32) { + env->fpuc = lduw(ptr); + fpus = lduw(ptr + 4); + fptag = lduw(ptr + 8); + } + else { + env->fpuc = lduw(ptr); + fpus = lduw(ptr + 2); + fptag = lduw(ptr + 4); + } + env->fpstt = (fpus >> 11) & 7; + env->fpus = fpus & ~0x3800; + for(i = 0;i < 8; i++) { + env->fptags[i] = ((fptag & 3) == 3); + fptag >>= 2; + } +} + +void helper_fsave(target_ulong ptr, int data32) +{ + CPU86_LDouble tmp; + int i; + + helper_fstenv(ptr, data32); + + ptr += (14 << data32); + for(i = 0;i < 8; i++) { + tmp = ST(i); + helper_fstt(tmp, ptr); + ptr += 10; + } + + /* fninit */ + env->fpus = 0; + env->fpstt = 0; + env->fpuc = 0x37f; + env->fptags[0] = 1; + env->fptags[1] = 1; + env->fptags[2] = 1; + env->fptags[3] = 1; + env->fptags[4] = 1; + env->fptags[5] = 1; + env->fptags[6] = 1; + env->fptags[7] = 1; +} + +void helper_frstor(target_ulong ptr, int data32) +{ + CPU86_LDouble tmp; + int i; + + helper_fldenv(ptr, data32); + ptr += (14 << data32); + + for(i = 0;i < 8; i++) { + tmp = helper_fldt(ptr); + ST(i) = tmp; + ptr += 10; + } +} + +void helper_fxsave(target_ulong ptr, int data64) +{ + int fpus, fptag, i, nb_xmm_regs; + CPU86_LDouble tmp; + target_ulong addr; + + fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + fptag = 0; + for(i = 0; i < 8; i++) { + fptag |= (env->fptags[i] << i); + } + stw(ptr, env->fpuc); + stw(ptr + 2, fpus); + stw(ptr + 4, fptag ^ 0xff); +#ifdef TARGET_X86_64 + if (data64) { + stq(ptr + 0x08, 0); /* rip */ + stq(ptr + 0x10, 0); /* rdp */ + } else +#endif + { + stl(ptr + 0x08, 0); /* eip */ + stl(ptr + 0x0c, 0); /* sel */ + stl(ptr + 0x10, 0); /* dp */ + stl(ptr + 0x14, 0); /* sel */ + } + + addr = ptr + 0x20; + for(i = 0;i < 8; i++) { + tmp = ST(i); + helper_fstt(tmp, addr); + addr += 16; + } + + if (env->cr[4] & CR4_OSFXSR_MASK) { + /* XXX: finish it */ + stl(ptr + 0x18, env->mxcsr); /* mxcsr */ + stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */ + if (env->hflags & HF_CS64_MASK) + nb_xmm_regs = 16; + else + nb_xmm_regs = 8; + addr = ptr + 0xa0; + for(i = 0; i < nb_xmm_regs; i++) { + stq(addr, env->xmm_regs[i].XMM_Q(0)); + stq(addr + 8, env->xmm_regs[i].XMM_Q(1)); + addr += 16; + } + } +} + +void helper_fxrstor(target_ulong ptr, int data64) +{ + int i, fpus, fptag, nb_xmm_regs; + CPU86_LDouble tmp; + target_ulong addr; + + env->fpuc = lduw(ptr); + fpus = lduw(ptr + 2); + fptag = lduw(ptr + 4); + env->fpstt = (fpus >> 11) & 7; + env->fpus = fpus & ~0x3800; + fptag ^= 0xff; + for(i = 0;i < 8; i++) { + env->fptags[i] = ((fptag >> i) & 1); + } + + addr = ptr + 0x20; + for(i = 0;i < 8; i++) { + tmp = helper_fldt(addr); + ST(i) = tmp; + addr += 16; + } + + if (env->cr[4] & CR4_OSFXSR_MASK) { + /* XXX: finish it */ + env->mxcsr = ldl(ptr + 0x18); + //ldl(ptr + 0x1c); + if (env->hflags & HF_CS64_MASK) + nb_xmm_regs = 16; + else + nb_xmm_regs = 8; + addr = ptr + 0xa0; + for(i = 0; i < nb_xmm_regs; i++) { + env->xmm_regs[i].XMM_Q(0) = ldq(addr); + env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8); + addr += 16; + } + } +} + +#ifndef USE_X86LDOUBLE + +void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f) +{ + CPU86_LDoubleU temp; + int e; + + temp.d = f; + /* mantissa */ + *pmant = (MANTD(temp) << 11) | (1LL << 63); + /* exponent + sign */ + e = EXPD(temp) - EXPBIAS + 16383; + e |= SIGND(temp) >> 16; + *pexp = e; +} + +CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper) +{ + CPU86_LDoubleU temp; + int e; + uint64_t ll; + + /* XXX: handle overflow ? */ + e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ + e |= (upper >> 4) & 0x800; /* sign */ + ll = (mant >> 11) & ((1LL << 52) - 1); +#ifdef __arm__ + temp.l.upper = (e << 20) | (ll >> 32); + temp.l.lower = ll; +#else + temp.ll = ll | ((uint64_t)e << 52); +#endif + return temp.d; +} + +#else + +void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f) +{ + CPU86_LDoubleU temp; + + temp.d = f; + *pmant = temp.l.lower; + *pexp = temp.l.upper; +} + +CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper) +{ + CPU86_LDoubleU temp; + + temp.l.upper = upper; + temp.l.lower = mant; + return temp.d; +} +#endif + +#ifdef TARGET_X86_64 + +//#define DEBUG_MULDIV + +static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) +{ + *plow += a; + /* carry test */ + if (*plow < a) + (*phigh)++; + *phigh += b; +} + +static void neg128(uint64_t *plow, uint64_t *phigh) +{ + *plow = ~ *plow; + *phigh = ~ *phigh; + add128(plow, phigh, 1, 0); +} + +/* return TRUE if overflow */ +static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b) +{ + uint64_t q, r, a1, a0; + int i, qb, ab; + + a0 = *plow; + a1 = *phigh; + if (a1 == 0) { + q = a0 / b; + r = a0 % b; + *plow = q; + *phigh = r; + } else { + if (a1 >= b) + return 1; + /* XXX: use a better algorithm */ + for(i = 0; i < 64; i++) { + ab = a1 >> 63; + a1 = (a1 << 1) | (a0 >> 63); + if (ab || a1 >= b) { + a1 -= b; + qb = 1; + } else { + qb = 0; + } + a0 = (a0 << 1) | qb; + } +#if defined(DEBUG_MULDIV) + printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n", + *phigh, *plow, b, a0, a1); +#endif + *plow = a0; + *phigh = a1; + } + return 0; +} + +/* return TRUE if overflow */ +static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) +{ + int sa, sb; + sa = ((int64_t)*phigh < 0); + if (sa) + neg128(plow, phigh); + sb = (b < 0); + if (sb) + b = -b; + if (div64(plow, phigh, b) != 0) + return 1; + if (sa ^ sb) { + if (*plow > (1ULL << 63)) + return 1; + *plow = - *plow; + } else { + if (*plow >= (1ULL << 63)) + return 1; + } + if (sa) + *phigh = - *phigh; + return 0; +} + +void helper_mulq_EAX_T0(target_ulong t0) +{ + uint64_t r0, r1; + + mulu64(&r0, &r1, EAX, t0); + EAX = r0; + EDX = r1; + CC_DST = r0; + CC_SRC = r1; +} + +void helper_imulq_EAX_T0(target_ulong t0) +{ + uint64_t r0, r1; + + muls64(&r0, &r1, EAX, t0); + EAX = r0; + EDX = r1; + CC_DST = r0; + CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); +} + +target_ulong helper_imulq_T0_T1(target_ulong t0, target_ulong t1) +{ + uint64_t r0, r1; + + muls64(&r0, &r1, t0, t1); + CC_DST = r0; + CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); + return r0; +} + +void helper_divq_EAX(target_ulong t0) +{ + uint64_t r0, r1; + if (t0 == 0) { + raise_exception(EXCP00_DIVZ); + } + r0 = EAX; + r1 = EDX; + if (div64(&r0, &r1, t0)) + raise_exception(EXCP00_DIVZ); + EAX = r0; + EDX = r1; +} + +void helper_idivq_EAX(target_ulong t0) +{ + uint64_t r0, r1; + if (t0 == 0) { + raise_exception(EXCP00_DIVZ); + } + r0 = EAX; + r1 = EDX; + if (idiv64(&r0, &r1, t0)) + raise_exception(EXCP00_DIVZ); + EAX = r0; + EDX = r1; +} +#endif + +static void do_hlt(void) +{ + env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */ + env->halted = 1; + env->exception_index = EXCP_HLT; + cpu_loop_exit(); +} + +void helper_hlt(int next_eip_addend) +{ + helper_svm_check_intercept_param(SVM_EXIT_HLT, 0); + EIP += next_eip_addend; + + do_hlt(); +} + +void helper_monitor(target_ulong ptr) +{ + if ((uint32_t)ECX != 0) + raise_exception(EXCP0D_GPF); + /* XXX: store address ? */ + helper_svm_check_intercept_param(SVM_EXIT_MONITOR, 0); +} + +void helper_mwait(int next_eip_addend) +{ + if ((uint32_t)ECX != 0) + raise_exception(EXCP0D_GPF); + helper_svm_check_intercept_param(SVM_EXIT_MWAIT, 0); + EIP += next_eip_addend; + + /* XXX: not complete but not completely erroneous */ + if (env->cpu_index != 0 || env->next_cpu != NULL) { + /* more than one CPU: do not sleep because another CPU may + wake this one */ + } else { + do_hlt(); + } +} + +void helper_debug(void) +{ + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(); +} + +void helper_raise_interrupt(int intno, int next_eip_addend) +{ + raise_interrupt(intno, 1, 0, next_eip_addend); +} + +void helper_raise_exception(int exception_index) +{ + raise_exception(exception_index); +} + +void helper_cli(void) +{ + env->eflags &= ~IF_MASK; +} + +void helper_sti(void) +{ + env->eflags |= IF_MASK; +} + +#if 0 +/* vm86plus instructions */ +void helper_cli_vm(void) +{ + env->eflags &= ~VIF_MASK; +} + +void helper_sti_vm(void) +{ + env->eflags |= VIF_MASK; + if (env->eflags & VIP_MASK) { + raise_exception(EXCP0D_GPF); + } +} +#endif + +void helper_set_inhibit_irq(void) +{ + env->hflags |= HF_INHIBIT_IRQ_MASK; +} + +void helper_reset_inhibit_irq(void) +{ + env->hflags &= ~HF_INHIBIT_IRQ_MASK; +} + +void helper_boundw(target_ulong a0, int v) +{ + int low, high; + low = ldsw(a0); + high = ldsw(a0 + 2); + v = (int16_t)v; + if (v < low || v > high) { + raise_exception(EXCP05_BOUND); + } + FORCE_RET(); +} + +void helper_boundl(target_ulong a0, int v) +{ + int low, high; + low = ldl(a0); + high = ldl(a0 + 4); + if (v < low || v > high) { + raise_exception(EXCP05_BOUND); + } + FORCE_RET(); +} + +static float approx_rsqrt(float a) +{ + return 1.0 / sqrt(a); +} + +static float approx_rcp(float a) +{ + return 1.0 / a; +} + +#if !defined(CONFIG_USER_ONLY) + +#define MMUSUFFIX _mmu + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +#endif + +/* try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +/* XXX: fix it to restore all registers */ +void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) +{ + TranslationBlock *tb; + int ret; + unsigned long pc; + CPUX86State *saved_env; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + + ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); + if (ret) { + if (retaddr) { + /* now we have a real cpu fault */ + pc = (unsigned long)retaddr; + tb = tb_find_pc(pc); + if (tb) { + /* the PC is inside the translated code. It means that we have + a virtual CPU fault */ + cpu_restore_state(tb, env, pc, NULL); + } + } + raise_exception_err(env->exception_index, env->error_code); + } + env = saved_env; +} + + +/* Secure Virtual Machine helpers */ + +#if defined(CONFIG_USER_ONLY) + +void helper_vmrun(int aflag, int next_eip_addend) +{ +} +void helper_vmmcall(void) +{ +} +void helper_vmload(int aflag) +{ +} +void helper_vmsave(int aflag) +{ +} +void helper_stgi(void) +{ +} +void helper_clgi(void) +{ +} +void helper_skinit(void) +{ +} +void helper_invlpga(int aflag) +{ +} +void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1) +{ +} +void helper_svm_check_intercept_param(uint32_t type, uint64_t param) +{ +} + +void helper_svm_check_io(uint32_t port, uint32_t param, + uint32_t next_eip_addend) +{ +} +#else + +static inline void svm_save_seg(target_phys_addr_t addr, + const SegmentCache *sc) +{ + stw_phys(addr + offsetof(struct vmcb_seg, selector), + sc->selector); + stq_phys(addr + offsetof(struct vmcb_seg, base), + sc->base); + stl_phys(addr + offsetof(struct vmcb_seg, limit), + sc->limit); + stw_phys(addr + offsetof(struct vmcb_seg, attrib), + ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00)); +} + +static inline void svm_load_seg(target_phys_addr_t addr, SegmentCache *sc) +{ + unsigned int flags; + + sc->selector = lduw_phys(addr + offsetof(struct vmcb_seg, selector)); + sc->base = ldq_phys(addr + offsetof(struct vmcb_seg, base)); + sc->limit = ldl_phys(addr + offsetof(struct vmcb_seg, limit)); + flags = lduw_phys(addr + offsetof(struct vmcb_seg, attrib)); + sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12); +} + +static inline void svm_load_seg_cache(target_phys_addr_t addr, + CPUState *env, int seg_reg) +{ + SegmentCache sc1, *sc = &sc1; + svm_load_seg(addr, sc); + cpu_x86_load_seg_cache(env, seg_reg, sc->selector, + sc->base, sc->limit, sc->flags); +} + +void helper_vmrun(int aflag, int next_eip_addend) +{ + target_ulong addr; + uint32_t event_inj; + uint32_t int_ctl; + + helper_svm_check_intercept_param(SVM_EXIT_VMRUN, 0); + + if (aflag == 2) + addr = EAX; + else + addr = (uint32_t)EAX; + + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile,"vmrun! " TARGET_FMT_lx "\n", addr); + + env->vm_vmcb = addr; + + /* save the current CPU state in the hsave page */ + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base); + stl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit); + + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base), env->idt.base); + stl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), env->idt.limit); + + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]); + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]); + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]); + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]); + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]); + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]); + + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer); + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags), compute_eflags()); + + svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.es), + &env->segs[R_ES]); + svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.cs), + &env->segs[R_CS]); + svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ss), + &env->segs[R_SS]); + svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ds), + &env->segs[R_DS]); + + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip), + EIP + next_eip_addend); + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP); + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX); + + /* load the interception bitmaps so we do not need to access the + vmcb in svm mode */ + env->intercept = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept)); + env->intercept_cr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_read)); + env->intercept_cr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_write)); + env->intercept_dr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_read)); + env->intercept_dr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_write)); + env->intercept_exceptions = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_exceptions)); + + /* enable intercepts */ + env->hflags |= HF_SVMI_MASK; + + env->tsc_offset = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.tsc_offset)); + + env->gdt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base)); + env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit)); + + env->idt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base)); + env->idt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit)); + + /* clear exit_info_2 so we behave like the real hardware */ + stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0); + + cpu_x86_update_cr0(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0))); + cpu_x86_update_cr4(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4))); + cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3))); + env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2)); + int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)); + env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK); + if (int_ctl & V_INTR_MASKING_MASK) { + env->v_tpr = int_ctl & V_TPR_MASK; + env->hflags2 |= HF2_VINTR_MASK; + if (env->eflags & IF_MASK) + env->hflags2 |= HF2_HIF_MASK; + } + + cpu_load_efer(env, + ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer))); + env->eflags = 0; + load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)), + ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); + CC_OP = CC_OP_EFLAGS; + + svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.es), + env, R_ES); + svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.cs), + env, R_CS); + svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ss), + env, R_SS); + svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ds), + env, R_DS); + + EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip)); + env->eip = EIP; + ESP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp)); + EAX = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax)); + env->dr[7] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7)); + env->dr[6] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6)); + cpu_x86_set_cpl(env, ldub_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl))); + + /* FIXME: guest state consistency checks */ + + switch(ldub_phys(env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) { + case TLB_CONTROL_DO_NOTHING: + break; + case TLB_CONTROL_FLUSH_ALL_ASID: + /* FIXME: this is not 100% correct but should work for now */ + tlb_flush(env, 1); + break; + } + + env->hflags2 |= HF2_GIF_MASK; + + if (int_ctl & V_IRQ_MASK) { + env->interrupt_request |= CPU_INTERRUPT_VIRQ; + } + + /* maybe we need to inject an event */ + event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)); + if (event_inj & SVM_EVTINJ_VALID) { + uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK; + uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR; + uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err)); + stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID); + + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, "Injecting(%#hx): ", valid_err); + /* FIXME: need to implement valid_err */ + switch (event_inj & SVM_EVTINJ_TYPE_MASK) { + case SVM_EVTINJ_TYPE_INTR: + env->exception_index = vector; + env->error_code = event_inj_err; + env->exception_is_int = 0; + env->exception_next_eip = -1; + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, "INTR"); + /* XXX: is it always correct ? */ + do_interrupt(vector, 0, 0, 0, 1); + break; + case SVM_EVTINJ_TYPE_NMI: + env->exception_index = EXCP02_NMI; + env->error_code = event_inj_err; + env->exception_is_int = 0; + env->exception_next_eip = EIP; + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, "NMI"); + cpu_loop_exit(); + break; + case SVM_EVTINJ_TYPE_EXEPT: + env->exception_index = vector; + env->error_code = event_inj_err; + env->exception_is_int = 0; + env->exception_next_eip = -1; + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, "EXEPT"); + cpu_loop_exit(); + break; + case SVM_EVTINJ_TYPE_SOFT: + env->exception_index = vector; + env->error_code = event_inj_err; + env->exception_is_int = 1; + env->exception_next_eip = EIP; + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, "SOFT"); + cpu_loop_exit(); + break; + } + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, " %#x %#x\n", env->exception_index, env->error_code); + } +} + +void helper_vmmcall(void) +{ + helper_svm_check_intercept_param(SVM_EXIT_VMMCALL, 0); + raise_exception(EXCP06_ILLOP); +} + +void helper_vmload(int aflag) +{ + target_ulong addr; + helper_svm_check_intercept_param(SVM_EXIT_VMLOAD, 0); + + if (aflag == 2) + addr = EAX; + else + addr = (uint32_t)EAX; + + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile,"vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", + addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)), + env->segs[R_FS].base); + + svm_load_seg_cache(addr + offsetof(struct vmcb, save.fs), + env, R_FS); + svm_load_seg_cache(addr + offsetof(struct vmcb, save.gs), + env, R_GS); + svm_load_seg(addr + offsetof(struct vmcb, save.tr), + &env->tr); + svm_load_seg(addr + offsetof(struct vmcb, save.ldtr), + &env->ldt); + +#ifdef TARGET_X86_64 + env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base)); + env->lstar = ldq_phys(addr + offsetof(struct vmcb, save.lstar)); + env->cstar = ldq_phys(addr + offsetof(struct vmcb, save.cstar)); + env->fmask = ldq_phys(addr + offsetof(struct vmcb, save.sfmask)); +#endif + env->star = ldq_phys(addr + offsetof(struct vmcb, save.star)); + env->sysenter_cs = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_cs)); + env->sysenter_esp = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_esp)); + env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_eip)); +} + +void helper_vmsave(int aflag) +{ + target_ulong addr; + helper_svm_check_intercept_param(SVM_EXIT_VMSAVE, 0); + + if (aflag == 2) + addr = EAX; + else + addr = (uint32_t)EAX; + + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile,"vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", + addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)), + env->segs[R_FS].base); + + svm_save_seg(addr + offsetof(struct vmcb, save.fs), + &env->segs[R_FS]); + svm_save_seg(addr + offsetof(struct vmcb, save.gs), + &env->segs[R_GS]); + svm_save_seg(addr + offsetof(struct vmcb, save.tr), + &env->tr); + svm_save_seg(addr + offsetof(struct vmcb, save.ldtr), + &env->ldt); + +#ifdef TARGET_X86_64 + stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base), env->kernelgsbase); + stq_phys(addr + offsetof(struct vmcb, save.lstar), env->lstar); + stq_phys(addr + offsetof(struct vmcb, save.cstar), env->cstar); + stq_phys(addr + offsetof(struct vmcb, save.sfmask), env->fmask); +#endif + stq_phys(addr + offsetof(struct vmcb, save.star), env->star); + stq_phys(addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs); + stq_phys(addr + offsetof(struct vmcb, save.sysenter_esp), env->sysenter_esp); + stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_eip); +} + +void helper_stgi(void) +{ + helper_svm_check_intercept_param(SVM_EXIT_STGI, 0); + env->hflags2 |= HF2_GIF_MASK; +} + +void helper_clgi(void) +{ + helper_svm_check_intercept_param(SVM_EXIT_CLGI, 0); + env->hflags2 &= ~HF2_GIF_MASK; +} + +void helper_skinit(void) +{ + helper_svm_check_intercept_param(SVM_EXIT_SKINIT, 0); + /* XXX: not implemented */ + raise_exception(EXCP06_ILLOP); +} + +void helper_invlpga(int aflag) +{ + target_ulong addr; + helper_svm_check_intercept_param(SVM_EXIT_INVLPGA, 0); + + if (aflag == 2) + addr = EAX; + else + addr = (uint32_t)EAX; + + /* XXX: could use the ASID to see if it is needed to do the + flush */ + tlb_flush_page(env, addr); +} + +void helper_svm_check_intercept_param(uint32_t type, uint64_t param) +{ + if (likely(!(env->hflags & HF_SVMI_MASK))) + return; + switch(type) { + case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8: + if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) { + helper_vmexit(type, param); + } + break; + case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8: + if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) { + helper_vmexit(type, param); + } + break; + case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7: + if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) { + helper_vmexit(type, param); + } + break; + case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7: + if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) { + helper_vmexit(type, param); + } + break; + case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31: + if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) { + helper_vmexit(type, param); + } + break; + case SVM_EXIT_MSR: + if (env->intercept & (1ULL << (SVM_EXIT_MSR - SVM_EXIT_INTR))) { + /* FIXME: this should be read in at vmrun (faster this way?) */ + uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa)); + uint32_t t0, t1; + switch((uint32_t)ECX) { + case 0 ... 0x1fff: + t0 = (ECX * 2) % 8; + t1 = ECX / 8; + break; + case 0xc0000000 ... 0xc0001fff: + t0 = (8192 + ECX - 0xc0000000) * 2; + t1 = (t0 / 8); + t0 %= 8; + break; + case 0xc0010000 ... 0xc0011fff: + t0 = (16384 + ECX - 0xc0010000) * 2; + t1 = (t0 / 8); + t0 %= 8; + break; + default: + helper_vmexit(type, param); + t0 = 0; + t1 = 0; + break; + } + if (ldub_phys(addr + t1) & ((1 << param) << t0)) + helper_vmexit(type, param); + } + break; + default: + if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) { + helper_vmexit(type, param); + } + break; + } +} + +void helper_svm_check_io(uint32_t port, uint32_t param, + uint32_t next_eip_addend) +{ + if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) { + /* FIXME: this should be read in at vmrun (faster this way?) */ + uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa)); + uint16_t mask = (1 << ((param >> 4) & 7)) - 1; + if(lduw_phys(addr + port / 8) & (mask << (port & 7))) { + /* next EIP */ + stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), + env->eip + next_eip_addend); + helper_vmexit(SVM_EXIT_IOIO, param | (port << 16)); + } + } +} + +/* Note: currently only 32 bits of exit_code are used */ +void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1) +{ + uint32_t int_ctl; + + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile,"vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n", + exit_code, exit_info_1, + ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)), + EIP); + + if(env->hflags & HF_INHIBIT_IRQ_MASK) { + stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), SVM_INTERRUPT_SHADOW_MASK); + env->hflags &= ~HF_INHIBIT_IRQ_MASK; + } else { + stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0); + } + + /* Save the VM state in the vmcb */ + svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.es), + &env->segs[R_ES]); + svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.cs), + &env->segs[R_CS]); + svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ss), + &env->segs[R_SS]); + svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ds), + &env->segs[R_DS]); + + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), env->gdt.base); + stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit); + + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), env->idt.base); + stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), env->idt.limit); + + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]); + + int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)); + int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK); + int_ctl |= env->v_tpr & V_TPR_MASK; + if (env->interrupt_request & CPU_INTERRUPT_VIRQ) + int_ctl |= V_IRQ_MASK; + stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl); + + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags), compute_eflags()); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]); + stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl), env->hflags & HF_CPL_MASK); + + /* Reload the host state from vm_hsave */ + env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK); + env->hflags &= ~HF_SVMI_MASK; + env->intercept = 0; + env->intercept_exceptions = 0; + env->interrupt_request &= ~CPU_INTERRUPT_VIRQ; + env->tsc_offset = 0; + + env->gdt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base)); + env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit)); + + env->idt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base)); + env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit)); + + cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0)) | CR0_PE_MASK); + cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4))); + cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3))); + /* we need to set the efer after the crs so the hidden flags get + set properly */ + cpu_load_efer(env, + ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer))); + env->eflags = 0; + load_eflags(ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags)), + ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); + CC_OP = CC_OP_EFLAGS; + + svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.es), + env, R_ES); + svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.cs), + env, R_CS); + svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ss), + env, R_SS); + svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ds), + env, R_DS); + + EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip)); + ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp)); + EAX = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax)); + + env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6)); + env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7)); + + /* other setups */ + cpu_x86_set_cpl(env, 0); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1); + + env->hflags2 &= ~HF2_GIF_MASK; + /* FIXME: Resets the current ASID register to zero (host ASID). */ + + /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */ + + /* Clears the TSC_OFFSET inside the processor. */ + + /* If the host is in PAE mode, the processor reloads the host's PDPEs + from the page table indicated the host's CR3. If the PDPEs contain + illegal state, the processor causes a shutdown. */ + + /* Forces CR0.PE = 1, RFLAGS.VM = 0. */ + env->cr[0] |= CR0_PE_MASK; + env->eflags &= ~VM_MASK; + + /* Disables all breakpoints in the host DR7 register. */ + + /* Checks the reloaded host state for consistency. */ + + /* If the host's rIP reloaded by #VMEXIT is outside the limit of the + host's code segment or non-canonical (in the case of long mode), a + #GP fault is delivered inside the host.) */ + + /* remove any pending exception */ + env->exception_index = -1; + env->error_code = 0; + env->old_exception = -1; + + cpu_loop_exit(); +} + +#endif + +/* MMX/SSE */ +/* XXX: optimize by storing fptt and fptags in the static cpu state */ +void helper_enter_mmx(void) +{ + env->fpstt = 0; + *(uint32_t *)(env->fptags) = 0; + *(uint32_t *)(env->fptags + 4) = 0; +} + +void helper_emms(void) +{ + /* set to empty state */ + *(uint32_t *)(env->fptags) = 0x01010101; + *(uint32_t *)(env->fptags + 4) = 0x01010101; +} + +/* XXX: suppress */ +void helper_movq(uint64_t *d, uint64_t *s) +{ + *d = *s; +} + +#define SHIFT 0 +#include "ops_sse.h" + +#define SHIFT 1 +#include "ops_sse.h" + +#define SHIFT 0 +#include "helper_template.h" +#undef SHIFT + +#define SHIFT 1 +#include "helper_template.h" +#undef SHIFT + +#define SHIFT 2 +#include "helper_template.h" +#undef SHIFT + +#ifdef TARGET_X86_64 + +#define SHIFT 3 +#include "helper_template.h" +#undef SHIFT + +#endif + +/* bit operations */ +target_ulong helper_bsf(target_ulong t0) +{ + int count; + target_ulong res; + + res = t0; + count = 0; + while ((res & 1) == 0) { + count++; + res >>= 1; + } + return count; +} + +target_ulong helper_bsr(target_ulong t0) +{ + int count; + target_ulong res, mask; + + res = t0; + count = TARGET_LONG_BITS - 1; + mask = (target_ulong)1 << (TARGET_LONG_BITS - 1); + while ((res & mask) == 0) { + count--; + res <<= 1; + } + return count; +} + + +static int compute_all_eflags(void) +{ + return CC_SRC; +} + +static int compute_c_eflags(void) +{ + return CC_SRC & CC_C; +} + +CCTable cc_table[CC_OP_NB] = { + [CC_OP_DYNAMIC] = { /* should never happen */ }, + + [CC_OP_EFLAGS] = { compute_all_eflags, compute_c_eflags }, + + [CC_OP_MULB] = { compute_all_mulb, compute_c_mull }, + [CC_OP_MULW] = { compute_all_mulw, compute_c_mull }, + [CC_OP_MULL] = { compute_all_mull, compute_c_mull }, + + [CC_OP_ADDB] = { compute_all_addb, compute_c_addb }, + [CC_OP_ADDW] = { compute_all_addw, compute_c_addw }, + [CC_OP_ADDL] = { compute_all_addl, compute_c_addl }, + + [CC_OP_ADCB] = { compute_all_adcb, compute_c_adcb }, + [CC_OP_ADCW] = { compute_all_adcw, compute_c_adcw }, + [CC_OP_ADCL] = { compute_all_adcl, compute_c_adcl }, + + [CC_OP_SUBB] = { compute_all_subb, compute_c_subb }, + [CC_OP_SUBW] = { compute_all_subw, compute_c_subw }, + [CC_OP_SUBL] = { compute_all_subl, compute_c_subl }, + + [CC_OP_SBBB] = { compute_all_sbbb, compute_c_sbbb }, + [CC_OP_SBBW] = { compute_all_sbbw, compute_c_sbbw }, + [CC_OP_SBBL] = { compute_all_sbbl, compute_c_sbbl }, + + [CC_OP_LOGICB] = { compute_all_logicb, compute_c_logicb }, + [CC_OP_LOGICW] = { compute_all_logicw, compute_c_logicw }, + [CC_OP_LOGICL] = { compute_all_logicl, compute_c_logicl }, + + [CC_OP_INCB] = { compute_all_incb, compute_c_incl }, + [CC_OP_INCW] = { compute_all_incw, compute_c_incl }, + [CC_OP_INCL] = { compute_all_incl, compute_c_incl }, + + [CC_OP_DECB] = { compute_all_decb, compute_c_incl }, + [CC_OP_DECW] = { compute_all_decw, compute_c_incl }, + [CC_OP_DECL] = { compute_all_decl, compute_c_incl }, + + [CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb }, + [CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw }, + [CC_OP_SHLL] = { compute_all_shll, compute_c_shll }, + + [CC_OP_SARB] = { compute_all_sarb, compute_c_sarl }, + [CC_OP_SARW] = { compute_all_sarw, compute_c_sarl }, + [CC_OP_SARL] = { compute_all_sarl, compute_c_sarl }, + +#ifdef TARGET_X86_64 + [CC_OP_MULQ] = { compute_all_mulq, compute_c_mull }, + + [CC_OP_ADDQ] = { compute_all_addq, compute_c_addq }, + + [CC_OP_ADCQ] = { compute_all_adcq, compute_c_adcq }, + + [CC_OP_SUBQ] = { compute_all_subq, compute_c_subq }, + + [CC_OP_SBBQ] = { compute_all_sbbq, compute_c_sbbq }, + + [CC_OP_LOGICQ] = { compute_all_logicq, compute_c_logicq }, + + [CC_OP_INCQ] = { compute_all_incq, compute_c_incl }, + + [CC_OP_DECQ] = { compute_all_decq, compute_c_incl }, + + [CC_OP_SHLQ] = { compute_all_shlq, compute_c_shlq }, + + [CC_OP_SARQ] = { compute_all_sarq, compute_c_sarl }, +#endif +}; + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/opreg_template.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/opreg_template.h --- qemu-0.9.1/target-i386/opreg_template.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-i386/opreg_template.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,190 +0,0 @@ -/* - * i386 micro operations (templates for various register related - * operations) - * - * Copyright (c) 2003 Fabrice Bellard - * - * 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 - */ -void OPPROTO glue(op_movl_A0,REGNAME)(void) -{ - A0 = (uint32_t)REG; -} - -void OPPROTO glue(op_addl_A0,REGNAME)(void) -{ - A0 = (uint32_t)(A0 + REG); -} - -void OPPROTO glue(glue(op_addl_A0,REGNAME),_s1)(void) -{ - A0 = (uint32_t)(A0 + (REG << 1)); -} - -void OPPROTO glue(glue(op_addl_A0,REGNAME),_s2)(void) -{ - A0 = (uint32_t)(A0 + (REG << 2)); -} - -void OPPROTO glue(glue(op_addl_A0,REGNAME),_s3)(void) -{ - A0 = (uint32_t)(A0 + (REG << 3)); -} - -#ifdef TARGET_X86_64 -void OPPROTO glue(op_movq_A0,REGNAME)(void) -{ - A0 = REG; -} - -void OPPROTO glue(op_addq_A0,REGNAME)(void) -{ - A0 = (A0 + REG); -} - -void OPPROTO glue(glue(op_addq_A0,REGNAME),_s1)(void) -{ - A0 = (A0 + (REG << 1)); -} - -void OPPROTO glue(glue(op_addq_A0,REGNAME),_s2)(void) -{ - A0 = (A0 + (REG << 2)); -} - -void OPPROTO glue(glue(op_addq_A0,REGNAME),_s3)(void) -{ - A0 = (A0 + (REG << 3)); -} -#endif - -void OPPROTO glue(op_movl_T0,REGNAME)(void) -{ - T0 = REG; -} - -void OPPROTO glue(op_movl_T1,REGNAME)(void) -{ - T1 = REG; -} - -void OPPROTO glue(op_movh_T0,REGNAME)(void) -{ - T0 = REG >> 8; -} - -void OPPROTO glue(op_movh_T1,REGNAME)(void) -{ - T1 = REG >> 8; -} - -void OPPROTO glue(glue(op_movl,REGNAME),_T0)(void) -{ - REG = (uint32_t)T0; -} - -void OPPROTO glue(glue(op_movl,REGNAME),_T1)(void) -{ - REG = (uint32_t)T1; -} - -void OPPROTO glue(glue(op_movl,REGNAME),_A0)(void) -{ - REG = (uint32_t)A0; -} - -#ifdef TARGET_X86_64 -void OPPROTO glue(glue(op_movq,REGNAME),_T0)(void) -{ - REG = T0; -} - -void OPPROTO glue(glue(op_movq,REGNAME),_T1)(void) -{ - REG = T1; -} - -void OPPROTO glue(glue(op_movq,REGNAME),_A0)(void) -{ - REG = A0; -} -#endif - -/* mov T1 to REG if T0 is true */ -void OPPROTO glue(glue(op_cmovw,REGNAME),_T1_T0)(void) -{ - if (T0) - REG = (REG & ~0xffff) | (T1 & 0xffff); - FORCE_RET(); -} - -void OPPROTO glue(glue(op_cmovl,REGNAME),_T1_T0)(void) -{ - if (T0) - REG = (uint32_t)T1; - FORCE_RET(); -} - -#ifdef TARGET_X86_64 -void OPPROTO glue(glue(op_cmovq,REGNAME),_T1_T0)(void) -{ - if (T0) - REG = T1; - FORCE_RET(); -} -#endif - -/* NOTE: T0 high order bits are ignored */ -void OPPROTO glue(glue(op_movw,REGNAME),_T0)(void) -{ - REG = (REG & ~0xffff) | (T0 & 0xffff); -} - -/* NOTE: T0 high order bits are ignored */ -void OPPROTO glue(glue(op_movw,REGNAME),_T1)(void) -{ - REG = (REG & ~0xffff) | (T1 & 0xffff); -} - -/* NOTE: A0 high order bits are ignored */ -void OPPROTO glue(glue(op_movw,REGNAME),_A0)(void) -{ - REG = (REG & ~0xffff) | (A0 & 0xffff); -} - -/* NOTE: T0 high order bits are ignored */ -void OPPROTO glue(glue(op_movb,REGNAME),_T0)(void) -{ - REG = (REG & ~0xff) | (T0 & 0xff); -} - -/* NOTE: T0 high order bits are ignored */ -void OPPROTO glue(glue(op_movh,REGNAME),_T0)(void) -{ - REG = (REG & ~0xff00) | ((T0 & 0xff) << 8); -} - -/* NOTE: T1 high order bits are ignored */ -void OPPROTO glue(glue(op_movb,REGNAME),_T1)(void) -{ - REG = (REG & ~0xff) | (T1 & 0xff); -} - -/* NOTE: T1 high order bits are ignored */ -void OPPROTO glue(glue(op_movh,REGNAME),_T1)(void) -{ - REG = (REG & ~0xff00) | ((T1 & 0xff) << 8); -} - diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/ops_mem.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/ops_mem.h --- qemu-0.9.1/target-i386/ops_mem.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-i386/ops_mem.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,156 +0,0 @@ -void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T0_A0)(void) -{ - T0 = glue(ldub, MEMSUFFIX)(A0); -} - -void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T0_A0)(void) -{ - T0 = glue(ldsb, MEMSUFFIX)(A0); -} - -void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T0_A0)(void) -{ - T0 = glue(lduw, MEMSUFFIX)(A0); -} - -void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T0_A0)(void) -{ - T0 = glue(ldsw, MEMSUFFIX)(A0); -} - -void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T0_A0)(void) -{ - T0 = (uint32_t)glue(ldl, MEMSUFFIX)(A0); -} - -void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T1_A0)(void) -{ - T1 = glue(ldub, MEMSUFFIX)(A0); -} - -void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T1_A0)(void) -{ - T1 = glue(ldsb, MEMSUFFIX)(A0); -} - -void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T1_A0)(void) -{ - T1 = glue(lduw, MEMSUFFIX)(A0); -} - -void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T1_A0)(void) -{ - T1 = glue(ldsw, MEMSUFFIX)(A0); -} - -void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T1_A0)(void) -{ - T1 = (uint32_t)glue(ldl, MEMSUFFIX)(A0); -} - -void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T0_A0)(void) -{ - glue(stb, MEMSUFFIX)(A0, T0); - FORCE_RET(); -} - -void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T0_A0)(void) -{ - glue(stw, MEMSUFFIX)(A0, T0); - FORCE_RET(); -} - -void OPPROTO glue(glue(op_stl, MEMSUFFIX), _T0_A0)(void) -{ - glue(stl, MEMSUFFIX)(A0, T0); - FORCE_RET(); -} - -#if 0 -void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T1_A0)(void) -{ - glue(stb, MEMSUFFIX)(A0, T1); - FORCE_RET(); -} -#endif - -void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T1_A0)(void) -{ - glue(stw, MEMSUFFIX)(A0, T1); - FORCE_RET(); -} - -void OPPROTO glue(glue(op_stl, MEMSUFFIX), _T1_A0)(void) -{ - glue(stl, MEMSUFFIX)(A0, T1); - FORCE_RET(); -} - -/* SSE/MMX support */ -void OPPROTO glue(glue(op_ldq, MEMSUFFIX), _env_A0)(void) -{ - uint64_t *p; - p = (uint64_t *)((char *)env + PARAM1); - *p = glue(ldq, MEMSUFFIX)(A0); -} - -void OPPROTO glue(glue(op_stq, MEMSUFFIX), _env_A0)(void) -{ - uint64_t *p; - p = (uint64_t *)((char *)env + PARAM1); - glue(stq, MEMSUFFIX)(A0, *p); - FORCE_RET(); -} - -void OPPROTO glue(glue(op_ldo, MEMSUFFIX), _env_A0)(void) -{ - XMMReg *p; - p = (XMMReg *)((char *)env + PARAM1); - p->XMM_Q(0) = glue(ldq, MEMSUFFIX)(A0); - p->XMM_Q(1) = glue(ldq, MEMSUFFIX)(A0 + 8); -} - -void OPPROTO glue(glue(op_sto, MEMSUFFIX), _env_A0)(void) -{ - XMMReg *p; - p = (XMMReg *)((char *)env + PARAM1); - glue(stq, MEMSUFFIX)(A0, p->XMM_Q(0)); - glue(stq, MEMSUFFIX)(A0 + 8, p->XMM_Q(1)); - FORCE_RET(); -} - -#ifdef TARGET_X86_64 -void OPPROTO glue(glue(op_ldsl, MEMSUFFIX), _T0_A0)(void) -{ - T0 = (int32_t)glue(ldl, MEMSUFFIX)(A0); -} - -void OPPROTO glue(glue(op_ldsl, MEMSUFFIX), _T1_A0)(void) -{ - T1 = (int32_t)glue(ldl, MEMSUFFIX)(A0); -} - -void OPPROTO glue(glue(op_ldq, MEMSUFFIX), _T0_A0)(void) -{ - T0 = glue(ldq, MEMSUFFIX)(A0); -} - -void OPPROTO glue(glue(op_ldq, MEMSUFFIX), _T1_A0)(void) -{ - T1 = glue(ldq, MEMSUFFIX)(A0); -} - -void OPPROTO glue(glue(op_stq, MEMSUFFIX), _T0_A0)(void) -{ - glue(stq, MEMSUFFIX)(A0, T0); - FORCE_RET(); -} - -void OPPROTO glue(glue(op_stq, MEMSUFFIX), _T1_A0)(void) -{ - glue(stq, MEMSUFFIX)(A0, T1); - FORCE_RET(); -} -#endif - -#undef MEMSUFFIX diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/ops_sse.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/ops_sse.h --- qemu-0.9.1/target-i386/ops_sse.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-i386/ops_sse.h 2008-10-04 12:33:52.000000000 +0100 @@ -1,7 +1,8 @@ /* - * MMX/SSE/SSE2/PNI support + * MMX/3DNow!/SSE/SSE2/SSE3/SSSE3/SSE4/PNI support * * Copyright (c) 2005 Fabrice Bellard + * Copyright (c) 2008 Intel Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -35,14 +36,10 @@ #define SUFFIX _xmm #endif -void OPPROTO glue(op_psrlw, SUFFIX)(void) +void glue(helper_psrlw, SUFFIX)(Reg *d, Reg *s) { - Reg *d, *s; int shift; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); - if (s->Q(0) > 15) { d->Q(0) = 0; #if SHIFT == 1 @@ -64,14 +61,10 @@ FORCE_RET(); } -void OPPROTO glue(op_psraw, SUFFIX)(void) +void glue(helper_psraw, SUFFIX)(Reg *d, Reg *s) { - Reg *d, *s; int shift; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); - if (s->Q(0) > 15) { shift = 15; } else { @@ -89,14 +82,10 @@ #endif } -void OPPROTO glue(op_psllw, SUFFIX)(void) +void glue(helper_psllw, SUFFIX)(Reg *d, Reg *s) { - Reg *d, *s; int shift; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); - if (s->Q(0) > 15) { d->Q(0) = 0; #if SHIFT == 1 @@ -118,14 +107,10 @@ FORCE_RET(); } -void OPPROTO glue(op_psrld, SUFFIX)(void) +void glue(helper_psrld, SUFFIX)(Reg *d, Reg *s) { - Reg *d, *s; int shift; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); - if (s->Q(0) > 31) { d->Q(0) = 0; #if SHIFT == 1 @@ -143,14 +128,10 @@ FORCE_RET(); } -void OPPROTO glue(op_psrad, SUFFIX)(void) +void glue(helper_psrad, SUFFIX)(Reg *d, Reg *s) { - Reg *d, *s; int shift; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); - if (s->Q(0) > 31) { shift = 31; } else { @@ -164,14 +145,10 @@ #endif } -void OPPROTO glue(op_pslld, SUFFIX)(void) +void glue(helper_pslld, SUFFIX)(Reg *d, Reg *s) { - Reg *d, *s; int shift; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); - if (s->Q(0) > 31) { d->Q(0) = 0; #if SHIFT == 1 @@ -189,14 +166,10 @@ FORCE_RET(); } -void OPPROTO glue(op_psrlq, SUFFIX)(void) +void glue(helper_psrlq, SUFFIX)(Reg *d, Reg *s) { - Reg *d, *s; int shift; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); - if (s->Q(0) > 63) { d->Q(0) = 0; #if SHIFT == 1 @@ -212,14 +185,10 @@ FORCE_RET(); } -void OPPROTO glue(op_psllq, SUFFIX)(void) +void glue(helper_psllq, SUFFIX)(Reg *d, Reg *s) { - Reg *d, *s; int shift; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); - if (s->Q(0) > 63) { d->Q(0) = 0; #if SHIFT == 1 @@ -236,13 +205,10 @@ } #if SHIFT == 1 -void OPPROTO glue(op_psrldq, SUFFIX)(void) +void glue(helper_psrldq, SUFFIX)(Reg *d, Reg *s) { - Reg *d, *s; int shift, i; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); shift = s->L(0); if (shift > 16) shift = 16; @@ -253,13 +219,10 @@ FORCE_RET(); } -void OPPROTO glue(op_pslldq, SUFFIX)(void) +void glue(helper_pslldq, SUFFIX)(Reg *d, Reg *s) { - Reg *d, *s; int shift, i; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); shift = s->L(0); if (shift > 16) shift = 16; @@ -271,12 +234,9 @@ } #endif -#define SSE_OP_B(name, F)\ -void OPPROTO glue(name, SUFFIX) (void)\ +#define SSE_HELPER_B(name, F)\ +void glue(name, SUFFIX) (Reg *d, Reg *s)\ {\ - Reg *d, *s;\ - d = (Reg *)((char *)env + PARAM1);\ - s = (Reg *)((char *)env + PARAM2);\ d->B(0) = F(d->B(0), s->B(0));\ d->B(1) = F(d->B(1), s->B(1));\ d->B(2) = F(d->B(2), s->B(2));\ @@ -297,12 +257,9 @@ )\ } -#define SSE_OP_W(name, F)\ -void OPPROTO glue(name, SUFFIX) (void)\ +#define SSE_HELPER_W(name, F)\ +void glue(name, SUFFIX) (Reg *d, Reg *s)\ {\ - Reg *d, *s;\ - d = (Reg *)((char *)env + PARAM1);\ - s = (Reg *)((char *)env + PARAM2);\ d->W(0) = F(d->W(0), s->W(0));\ d->W(1) = F(d->W(1), s->W(1));\ d->W(2) = F(d->W(2), s->W(2));\ @@ -315,12 +272,9 @@ )\ } -#define SSE_OP_L(name, F)\ -void OPPROTO glue(name, SUFFIX) (void)\ +#define SSE_HELPER_L(name, F)\ +void glue(name, SUFFIX) (Reg *d, Reg *s)\ {\ - Reg *d, *s;\ - d = (Reg *)((char *)env + PARAM1);\ - s = (Reg *)((char *)env + PARAM2);\ d->L(0) = F(d->L(0), s->L(0));\ d->L(1) = F(d->L(1), s->L(1));\ XMM_ONLY(\ @@ -329,12 +283,9 @@ )\ } -#define SSE_OP_Q(name, F)\ -void OPPROTO glue(name, SUFFIX) (void)\ +#define SSE_HELPER_Q(name, F)\ +void glue(name, SUFFIX) (Reg *d, Reg *s)\ {\ - Reg *d, *s;\ - d = (Reg *)((char *)env + PARAM1);\ - s = (Reg *)((char *)env + PARAM2);\ d->Q(0) = F(d->Q(0), s->Q(0));\ XMM_ONLY(\ d->Q(1) = F(d->Q(1), s->Q(1));\ @@ -409,76 +360,73 @@ #define FCMPEQ(a, b) (a) == (b) ? -1 : 0 #define FMULLW(a, b) (a) * (b) +#define FMULHRW(a, b) ((int16_t)(a) * (int16_t)(b) + 0x8000) >> 16 #define FMULHUW(a, b) (a) * (b) >> 16 #define FMULHW(a, b) (int16_t)(a) * (int16_t)(b) >> 16 #define FAVG(a, b) ((a) + (b) + 1) >> 1 #endif -SSE_OP_B(op_paddb, FADD) -SSE_OP_W(op_paddw, FADD) -SSE_OP_L(op_paddl, FADD) -SSE_OP_Q(op_paddq, FADD) - -SSE_OP_B(op_psubb, FSUB) -SSE_OP_W(op_psubw, FSUB) -SSE_OP_L(op_psubl, FSUB) -SSE_OP_Q(op_psubq, FSUB) - -SSE_OP_B(op_paddusb, FADDUB) -SSE_OP_B(op_paddsb, FADDSB) -SSE_OP_B(op_psubusb, FSUBUB) -SSE_OP_B(op_psubsb, FSUBSB) - -SSE_OP_W(op_paddusw, FADDUW) -SSE_OP_W(op_paddsw, FADDSW) -SSE_OP_W(op_psubusw, FSUBUW) -SSE_OP_W(op_psubsw, FSUBSW) - -SSE_OP_B(op_pminub, FMINUB) -SSE_OP_B(op_pmaxub, FMAXUB) - -SSE_OP_W(op_pminsw, FMINSW) -SSE_OP_W(op_pmaxsw, FMAXSW) - -SSE_OP_Q(op_pand, FAND) -SSE_OP_Q(op_pandn, FANDN) -SSE_OP_Q(op_por, FOR) -SSE_OP_Q(op_pxor, FXOR) - -SSE_OP_B(op_pcmpgtb, FCMPGTB) -SSE_OP_W(op_pcmpgtw, FCMPGTW) -SSE_OP_L(op_pcmpgtl, FCMPGTL) - -SSE_OP_B(op_pcmpeqb, FCMPEQ) -SSE_OP_W(op_pcmpeqw, FCMPEQ) -SSE_OP_L(op_pcmpeql, FCMPEQ) - -SSE_OP_W(op_pmullw, FMULLW) -SSE_OP_W(op_pmulhuw, FMULHUW) -SSE_OP_W(op_pmulhw, FMULHW) - -SSE_OP_B(op_pavgb, FAVG) -SSE_OP_W(op_pavgw, FAVG) - -void OPPROTO glue(op_pmuludq, SUFFIX) (void) -{ - Reg *d, *s; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); +SSE_HELPER_B(helper_paddb, FADD) +SSE_HELPER_W(helper_paddw, FADD) +SSE_HELPER_L(helper_paddl, FADD) +SSE_HELPER_Q(helper_paddq, FADD) + +SSE_HELPER_B(helper_psubb, FSUB) +SSE_HELPER_W(helper_psubw, FSUB) +SSE_HELPER_L(helper_psubl, FSUB) +SSE_HELPER_Q(helper_psubq, FSUB) + +SSE_HELPER_B(helper_paddusb, FADDUB) +SSE_HELPER_B(helper_paddsb, FADDSB) +SSE_HELPER_B(helper_psubusb, FSUBUB) +SSE_HELPER_B(helper_psubsb, FSUBSB) + +SSE_HELPER_W(helper_paddusw, FADDUW) +SSE_HELPER_W(helper_paddsw, FADDSW) +SSE_HELPER_W(helper_psubusw, FSUBUW) +SSE_HELPER_W(helper_psubsw, FSUBSW) + +SSE_HELPER_B(helper_pminub, FMINUB) +SSE_HELPER_B(helper_pmaxub, FMAXUB) + +SSE_HELPER_W(helper_pminsw, FMINSW) +SSE_HELPER_W(helper_pmaxsw, FMAXSW) + +SSE_HELPER_Q(helper_pand, FAND) +SSE_HELPER_Q(helper_pandn, FANDN) +SSE_HELPER_Q(helper_por, FOR) +SSE_HELPER_Q(helper_pxor, FXOR) + +SSE_HELPER_B(helper_pcmpgtb, FCMPGTB) +SSE_HELPER_W(helper_pcmpgtw, FCMPGTW) +SSE_HELPER_L(helper_pcmpgtl, FCMPGTL) + +SSE_HELPER_B(helper_pcmpeqb, FCMPEQ) +SSE_HELPER_W(helper_pcmpeqw, FCMPEQ) +SSE_HELPER_L(helper_pcmpeql, FCMPEQ) +SSE_HELPER_W(helper_pmullw, FMULLW) +#if SHIFT == 0 +SSE_HELPER_W(helper_pmulhrw, FMULHRW) +#endif +SSE_HELPER_W(helper_pmulhuw, FMULHUW) +SSE_HELPER_W(helper_pmulhw, FMULHW) + +SSE_HELPER_B(helper_pavgb, FAVG) +SSE_HELPER_W(helper_pavgw, FAVG) + +void glue(helper_pmuludq, SUFFIX) (Reg *d, Reg *s) +{ d->Q(0) = (uint64_t)s->L(0) * (uint64_t)d->L(0); #if SHIFT == 1 d->Q(1) = (uint64_t)s->L(2) * (uint64_t)d->L(2); #endif } -void OPPROTO glue(op_pmaddwd, SUFFIX) (void) +void glue(helper_pmaddwd, SUFFIX) (Reg *d, Reg *s) { int i; - Reg *d, *s; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); for(i = 0; i < (2 << SHIFT); i++) { d->L(i) = (int16_t)s->W(2*i) * (int16_t)d->W(2*i) + @@ -496,12 +444,9 @@ return a; } #endif -void OPPROTO glue(op_psadbw, SUFFIX) (void) +void glue(helper_psadbw, SUFFIX) (Reg *d, Reg *s) { unsigned int val; - Reg *d, *s; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); val = 0; val += abs1(d->B(0) - s->B(0)); @@ -527,64 +472,39 @@ #endif } -void OPPROTO glue(op_maskmov, SUFFIX) (void) +void glue(helper_maskmov, SUFFIX) (Reg *d, Reg *s, target_ulong a0) { int i; - Reg *d, *s; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); for(i = 0; i < (8 << SHIFT); i++) { if (s->B(i) & 0x80) - stb(A0 + i, d->B(i)); + stb(a0 + i, d->B(i)); } FORCE_RET(); } -void OPPROTO glue(op_movl_mm_T0, SUFFIX) (void) +void glue(helper_movl_mm_T0, SUFFIX) (Reg *d, uint32_t val) { - Reg *d; - d = (Reg *)((char *)env + PARAM1); - d->L(0) = T0; + d->L(0) = val; d->L(1) = 0; #if SHIFT == 1 d->Q(1) = 0; #endif } -void OPPROTO glue(op_movl_T0_mm, SUFFIX) (void) -{ - Reg *s; - s = (Reg *)((char *)env + PARAM1); - T0 = s->L(0); -} - #ifdef TARGET_X86_64 -void OPPROTO glue(op_movq_mm_T0, SUFFIX) (void) +void glue(helper_movq_mm_T0, SUFFIX) (Reg *d, uint64_t val) { - Reg *d; - d = (Reg *)((char *)env + PARAM1); - d->Q(0) = T0; + d->Q(0) = val; #if SHIFT == 1 d->Q(1) = 0; #endif } - -void OPPROTO glue(op_movq_T0_mm, SUFFIX) (void) -{ - Reg *s; - s = (Reg *)((char *)env + PARAM1); - T0 = s->Q(0); -} #endif #if SHIFT == 0 -void OPPROTO glue(op_pshufw, SUFFIX) (void) +void glue(helper_pshufw, SUFFIX) (Reg *d, Reg *s, int order) { - Reg r, *d, *s; - int order; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); - order = PARAM3; + Reg r; r.W(0) = s->W(order & 3); r.W(1) = s->W((order >> 2) & 3); r.W(2) = s->W((order >> 4) & 3); @@ -592,13 +512,9 @@ *d = r; } #else -void OPPROTO op_shufps(void) +void helper_shufps(Reg *d, Reg *s, int order) { - Reg r, *d, *s; - int order; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); - order = PARAM3; + Reg r; r.L(0) = d->L(order & 3); r.L(1) = d->L((order >> 2) & 3); r.L(2) = s->L((order >> 4) & 3); @@ -606,25 +522,17 @@ *d = r; } -void OPPROTO op_shufpd(void) +void helper_shufpd(Reg *d, Reg *s, int order) { - Reg r, *d, *s; - int order; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); - order = PARAM3; + Reg r; r.Q(0) = d->Q(order & 1); r.Q(1) = s->Q((order >> 1) & 1); *d = r; } -void OPPROTO glue(op_pshufd, SUFFIX) (void) +void glue(helper_pshufd, SUFFIX) (Reg *d, Reg *s, int order) { - Reg r, *d, *s; - int order; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); - order = PARAM3; + Reg r; r.L(0) = s->L(order & 3); r.L(1) = s->L((order >> 2) & 3); r.L(2) = s->L((order >> 4) & 3); @@ -632,13 +540,9 @@ *d = r; } -void OPPROTO glue(op_pshuflw, SUFFIX) (void) +void glue(helper_pshuflw, SUFFIX) (Reg *d, Reg *s, int order) { - Reg r, *d, *s; - int order; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); - order = PARAM3; + Reg r; r.W(0) = s->W(order & 3); r.W(1) = s->W((order >> 2) & 3); r.W(2) = s->W((order >> 4) & 3); @@ -647,13 +551,9 @@ *d = r; } -void OPPROTO glue(op_pshufhw, SUFFIX) (void) +void glue(helper_pshufhw, SUFFIX) (Reg *d, Reg *s, int order) { - Reg r, *d, *s; - int order; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); - order = PARAM3; + Reg r; r.Q(0) = s->Q(0); r.W(4) = s->W(4 + (order & 3)); r.W(5) = s->W(4 + ((order >> 2) & 3)); @@ -667,39 +567,27 @@ /* FPU ops */ /* XXX: not accurate */ -#define SSE_OP_S(name, F)\ -void OPPROTO op_ ## name ## ps (void)\ +#define SSE_HELPER_S(name, F)\ +void helper_ ## name ## ps (Reg *d, Reg *s)\ {\ - Reg *d, *s;\ - d = (Reg *)((char *)env + PARAM1);\ - s = (Reg *)((char *)env + PARAM2);\ d->XMM_S(0) = F(32, d->XMM_S(0), s->XMM_S(0));\ d->XMM_S(1) = F(32, d->XMM_S(1), s->XMM_S(1));\ d->XMM_S(2) = F(32, d->XMM_S(2), s->XMM_S(2));\ d->XMM_S(3) = F(32, d->XMM_S(3), s->XMM_S(3));\ }\ \ -void OPPROTO op_ ## name ## ss (void)\ +void helper_ ## name ## ss (Reg *d, Reg *s)\ {\ - Reg *d, *s;\ - d = (Reg *)((char *)env + PARAM1);\ - s = (Reg *)((char *)env + PARAM2);\ d->XMM_S(0) = F(32, d->XMM_S(0), s->XMM_S(0));\ }\ -void OPPROTO op_ ## name ## pd (void)\ +void helper_ ## name ## pd (Reg *d, Reg *s)\ {\ - Reg *d, *s;\ - d = (Reg *)((char *)env + PARAM1);\ - s = (Reg *)((char *)env + PARAM2);\ d->XMM_D(0) = F(64, d->XMM_D(0), s->XMM_D(0));\ d->XMM_D(1) = F(64, d->XMM_D(1), s->XMM_D(1));\ }\ \ -void OPPROTO op_ ## name ## sd (void)\ +void helper_ ## name ## sd (Reg *d, Reg *s)\ {\ - Reg *d, *s;\ - d = (Reg *)((char *)env + PARAM1);\ - s = (Reg *)((char *)env + PARAM2);\ d->XMM_D(0) = F(64, d->XMM_D(0), s->XMM_D(0));\ } @@ -711,69 +599,53 @@ #define FPU_MAX(size, a, b) (a) > (b) ? (a) : (b) #define FPU_SQRT(size, a, b) float ## size ## _sqrt(b, &env->sse_status) -SSE_OP_S(add, FPU_ADD) -SSE_OP_S(sub, FPU_SUB) -SSE_OP_S(mul, FPU_MUL) -SSE_OP_S(div, FPU_DIV) -SSE_OP_S(min, FPU_MIN) -SSE_OP_S(max, FPU_MAX) -SSE_OP_S(sqrt, FPU_SQRT) +SSE_HELPER_S(add, FPU_ADD) +SSE_HELPER_S(sub, FPU_SUB) +SSE_HELPER_S(mul, FPU_MUL) +SSE_HELPER_S(div, FPU_DIV) +SSE_HELPER_S(min, FPU_MIN) +SSE_HELPER_S(max, FPU_MAX) +SSE_HELPER_S(sqrt, FPU_SQRT) /* float to float conversions */ -void OPPROTO op_cvtps2pd(void) +void helper_cvtps2pd(Reg *d, Reg *s) { float32 s0, s1; - Reg *d, *s; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); s0 = s->XMM_S(0); s1 = s->XMM_S(1); d->XMM_D(0) = float32_to_float64(s0, &env->sse_status); d->XMM_D(1) = float32_to_float64(s1, &env->sse_status); } -void OPPROTO op_cvtpd2ps(void) +void helper_cvtpd2ps(Reg *d, Reg *s) { - Reg *d, *s; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); d->XMM_S(0) = float64_to_float32(s->XMM_D(0), &env->sse_status); d->XMM_S(1) = float64_to_float32(s->XMM_D(1), &env->sse_status); d->Q(1) = 0; } -void OPPROTO op_cvtss2sd(void) +void helper_cvtss2sd(Reg *d, Reg *s) { - Reg *d, *s; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); d->XMM_D(0) = float32_to_float64(s->XMM_S(0), &env->sse_status); } -void OPPROTO op_cvtsd2ss(void) +void helper_cvtsd2ss(Reg *d, Reg *s) { - Reg *d, *s; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); d->XMM_S(0) = float64_to_float32(s->XMM_D(0), &env->sse_status); } /* integer to float */ -void OPPROTO op_cvtdq2ps(void) +void helper_cvtdq2ps(Reg *d, Reg *s) { - XMMReg *d = (XMMReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); d->XMM_S(0) = int32_to_float32(s->XMM_L(0), &env->sse_status); d->XMM_S(1) = int32_to_float32(s->XMM_L(1), &env->sse_status); d->XMM_S(2) = int32_to_float32(s->XMM_L(2), &env->sse_status); d->XMM_S(3) = int32_to_float32(s->XMM_L(3), &env->sse_status); } -void OPPROTO op_cvtdq2pd(void) +void helper_cvtdq2pd(Reg *d, Reg *s) { - XMMReg *d = (XMMReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); int32_t l0, l1; l0 = (int32_t)s->XMM_L(0); l1 = (int32_t)s->XMM_L(1); @@ -781,210 +653,168 @@ d->XMM_D(1) = int32_to_float64(l1, &env->sse_status); } -void OPPROTO op_cvtpi2ps(void) +void helper_cvtpi2ps(XMMReg *d, MMXReg *s) { - XMMReg *d = (Reg *)((char *)env + PARAM1); - MMXReg *s = (MMXReg *)((char *)env + PARAM2); d->XMM_S(0) = int32_to_float32(s->MMX_L(0), &env->sse_status); d->XMM_S(1) = int32_to_float32(s->MMX_L(1), &env->sse_status); } -void OPPROTO op_cvtpi2pd(void) +void helper_cvtpi2pd(XMMReg *d, MMXReg *s) { - XMMReg *d = (Reg *)((char *)env + PARAM1); - MMXReg *s = (MMXReg *)((char *)env + PARAM2); d->XMM_D(0) = int32_to_float64(s->MMX_L(0), &env->sse_status); d->XMM_D(1) = int32_to_float64(s->MMX_L(1), &env->sse_status); } -void OPPROTO op_cvtsi2ss(void) +void helper_cvtsi2ss(XMMReg *d, uint32_t val) { - XMMReg *d = (Reg *)((char *)env + PARAM1); - d->XMM_S(0) = int32_to_float32(T0, &env->sse_status); + d->XMM_S(0) = int32_to_float32(val, &env->sse_status); } -void OPPROTO op_cvtsi2sd(void) +void helper_cvtsi2sd(XMMReg *d, uint32_t val) { - XMMReg *d = (Reg *)((char *)env + PARAM1); - d->XMM_D(0) = int32_to_float64(T0, &env->sse_status); + d->XMM_D(0) = int32_to_float64(val, &env->sse_status); } #ifdef TARGET_X86_64 -void OPPROTO op_cvtsq2ss(void) +void helper_cvtsq2ss(XMMReg *d, uint64_t val) { - XMMReg *d = (Reg *)((char *)env + PARAM1); - d->XMM_S(0) = int64_to_float32(T0, &env->sse_status); + d->XMM_S(0) = int64_to_float32(val, &env->sse_status); } -void OPPROTO op_cvtsq2sd(void) +void helper_cvtsq2sd(XMMReg *d, uint64_t val) { - XMMReg *d = (Reg *)((char *)env + PARAM1); - d->XMM_D(0) = int64_to_float64(T0, &env->sse_status); + d->XMM_D(0) = int64_to_float64(val, &env->sse_status); } #endif /* float to integer */ -void OPPROTO op_cvtps2dq(void) +void helper_cvtps2dq(XMMReg *d, XMMReg *s) { - XMMReg *d = (XMMReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); d->XMM_L(0) = float32_to_int32(s->XMM_S(0), &env->sse_status); d->XMM_L(1) = float32_to_int32(s->XMM_S(1), &env->sse_status); d->XMM_L(2) = float32_to_int32(s->XMM_S(2), &env->sse_status); d->XMM_L(3) = float32_to_int32(s->XMM_S(3), &env->sse_status); } -void OPPROTO op_cvtpd2dq(void) +void helper_cvtpd2dq(XMMReg *d, XMMReg *s) { - XMMReg *d = (XMMReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); d->XMM_L(0) = float64_to_int32(s->XMM_D(0), &env->sse_status); d->XMM_L(1) = float64_to_int32(s->XMM_D(1), &env->sse_status); d->XMM_Q(1) = 0; } -void OPPROTO op_cvtps2pi(void) +void helper_cvtps2pi(MMXReg *d, XMMReg *s) { - MMXReg *d = (MMXReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); d->MMX_L(0) = float32_to_int32(s->XMM_S(0), &env->sse_status); d->MMX_L(1) = float32_to_int32(s->XMM_S(1), &env->sse_status); } -void OPPROTO op_cvtpd2pi(void) +void helper_cvtpd2pi(MMXReg *d, XMMReg *s) { - MMXReg *d = (MMXReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); d->MMX_L(0) = float64_to_int32(s->XMM_D(0), &env->sse_status); d->MMX_L(1) = float64_to_int32(s->XMM_D(1), &env->sse_status); } -void OPPROTO op_cvtss2si(void) +int32_t helper_cvtss2si(XMMReg *s) { - XMMReg *s = (XMMReg *)((char *)env + PARAM1); - T0 = float32_to_int32(s->XMM_S(0), &env->sse_status); + return float32_to_int32(s->XMM_S(0), &env->sse_status); } -void OPPROTO op_cvtsd2si(void) +int32_t helper_cvtsd2si(XMMReg *s) { - XMMReg *s = (XMMReg *)((char *)env + PARAM1); - T0 = float64_to_int32(s->XMM_D(0), &env->sse_status); + return float64_to_int32(s->XMM_D(0), &env->sse_status); } #ifdef TARGET_X86_64 -void OPPROTO op_cvtss2sq(void) +int64_t helper_cvtss2sq(XMMReg *s) { - XMMReg *s = (XMMReg *)((char *)env + PARAM1); - T0 = float32_to_int64(s->XMM_S(0), &env->sse_status); + return float32_to_int64(s->XMM_S(0), &env->sse_status); } -void OPPROTO op_cvtsd2sq(void) +int64_t helper_cvtsd2sq(XMMReg *s) { - XMMReg *s = (XMMReg *)((char *)env + PARAM1); - T0 = float64_to_int64(s->XMM_D(0), &env->sse_status); + return float64_to_int64(s->XMM_D(0), &env->sse_status); } #endif /* float to integer truncated */ -void OPPROTO op_cvttps2dq(void) +void helper_cvttps2dq(XMMReg *d, XMMReg *s) { - XMMReg *d = (XMMReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); d->XMM_L(0) = float32_to_int32_round_to_zero(s->XMM_S(0), &env->sse_status); d->XMM_L(1) = float32_to_int32_round_to_zero(s->XMM_S(1), &env->sse_status); d->XMM_L(2) = float32_to_int32_round_to_zero(s->XMM_S(2), &env->sse_status); d->XMM_L(3) = float32_to_int32_round_to_zero(s->XMM_S(3), &env->sse_status); } -void OPPROTO op_cvttpd2dq(void) +void helper_cvttpd2dq(XMMReg *d, XMMReg *s) { - XMMReg *d = (XMMReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); d->XMM_L(0) = float64_to_int32_round_to_zero(s->XMM_D(0), &env->sse_status); d->XMM_L(1) = float64_to_int32_round_to_zero(s->XMM_D(1), &env->sse_status); d->XMM_Q(1) = 0; } -void OPPROTO op_cvttps2pi(void) +void helper_cvttps2pi(MMXReg *d, XMMReg *s) { - MMXReg *d = (MMXReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); d->MMX_L(0) = float32_to_int32_round_to_zero(s->XMM_S(0), &env->sse_status); d->MMX_L(1) = float32_to_int32_round_to_zero(s->XMM_S(1), &env->sse_status); } -void OPPROTO op_cvttpd2pi(void) +void helper_cvttpd2pi(MMXReg *d, XMMReg *s) { - MMXReg *d = (MMXReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); d->MMX_L(0) = float64_to_int32_round_to_zero(s->XMM_D(0), &env->sse_status); d->MMX_L(1) = float64_to_int32_round_to_zero(s->XMM_D(1), &env->sse_status); } -void OPPROTO op_cvttss2si(void) +int32_t helper_cvttss2si(XMMReg *s) { - XMMReg *s = (XMMReg *)((char *)env + PARAM1); - T0 = float32_to_int32_round_to_zero(s->XMM_S(0), &env->sse_status); + return float32_to_int32_round_to_zero(s->XMM_S(0), &env->sse_status); } -void OPPROTO op_cvttsd2si(void) +int32_t helper_cvttsd2si(XMMReg *s) { - XMMReg *s = (XMMReg *)((char *)env + PARAM1); - T0 = float64_to_int32_round_to_zero(s->XMM_D(0), &env->sse_status); + return float64_to_int32_round_to_zero(s->XMM_D(0), &env->sse_status); } #ifdef TARGET_X86_64 -void OPPROTO op_cvttss2sq(void) +int64_t helper_cvttss2sq(XMMReg *s) { - XMMReg *s = (XMMReg *)((char *)env + PARAM1); - T0 = float32_to_int64_round_to_zero(s->XMM_S(0), &env->sse_status); + return float32_to_int64_round_to_zero(s->XMM_S(0), &env->sse_status); } -void OPPROTO op_cvttsd2sq(void) +int64_t helper_cvttsd2sq(XMMReg *s) { - XMMReg *s = (XMMReg *)((char *)env + PARAM1); - T0 = float64_to_int64_round_to_zero(s->XMM_D(0), &env->sse_status); + return float64_to_int64_round_to_zero(s->XMM_D(0), &env->sse_status); } #endif -void OPPROTO op_rsqrtps(void) +void helper_rsqrtps(XMMReg *d, XMMReg *s) { - XMMReg *d = (XMMReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); d->XMM_S(0) = approx_rsqrt(s->XMM_S(0)); d->XMM_S(1) = approx_rsqrt(s->XMM_S(1)); d->XMM_S(2) = approx_rsqrt(s->XMM_S(2)); d->XMM_S(3) = approx_rsqrt(s->XMM_S(3)); } -void OPPROTO op_rsqrtss(void) +void helper_rsqrtss(XMMReg *d, XMMReg *s) { - XMMReg *d = (XMMReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); d->XMM_S(0) = approx_rsqrt(s->XMM_S(0)); } -void OPPROTO op_rcpps(void) +void helper_rcpps(XMMReg *d, XMMReg *s) { - XMMReg *d = (XMMReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); d->XMM_S(0) = approx_rcp(s->XMM_S(0)); d->XMM_S(1) = approx_rcp(s->XMM_S(1)); d->XMM_S(2) = approx_rcp(s->XMM_S(2)); d->XMM_S(3) = approx_rcp(s->XMM_S(3)); } -void OPPROTO op_rcpss(void) +void helper_rcpss(XMMReg *d, XMMReg *s) { - XMMReg *d = (XMMReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); d->XMM_S(0) = approx_rcp(s->XMM_S(0)); } -void OPPROTO op_haddps(void) +void helper_haddps(XMMReg *d, XMMReg *s) { - XMMReg *d = (XMMReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); XMMReg r; r.XMM_S(0) = d->XMM_S(0) + d->XMM_S(1); r.XMM_S(1) = d->XMM_S(2) + d->XMM_S(3); @@ -993,20 +823,16 @@ *d = r; } -void OPPROTO op_haddpd(void) +void helper_haddpd(XMMReg *d, XMMReg *s) { - XMMReg *d = (XMMReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); XMMReg r; r.XMM_D(0) = d->XMM_D(0) + d->XMM_D(1); r.XMM_D(1) = s->XMM_D(0) + s->XMM_D(1); *d = r; } -void OPPROTO op_hsubps(void) +void helper_hsubps(XMMReg *d, XMMReg *s) { - XMMReg *d = (XMMReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); XMMReg r; r.XMM_S(0) = d->XMM_S(0) - d->XMM_S(1); r.XMM_S(1) = d->XMM_S(2) - d->XMM_S(3); @@ -1015,68 +841,50 @@ *d = r; } -void OPPROTO op_hsubpd(void) +void helper_hsubpd(XMMReg *d, XMMReg *s) { - XMMReg *d = (XMMReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); XMMReg r; r.XMM_D(0) = d->XMM_D(0) - d->XMM_D(1); r.XMM_D(1) = s->XMM_D(0) - s->XMM_D(1); *d = r; } -void OPPROTO op_addsubps(void) +void helper_addsubps(XMMReg *d, XMMReg *s) { - XMMReg *d = (XMMReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); d->XMM_S(0) = d->XMM_S(0) - s->XMM_S(0); d->XMM_S(1) = d->XMM_S(1) + s->XMM_S(1); d->XMM_S(2) = d->XMM_S(2) - s->XMM_S(2); d->XMM_S(3) = d->XMM_S(3) + s->XMM_S(3); } -void OPPROTO op_addsubpd(void) +void helper_addsubpd(XMMReg *d, XMMReg *s) { - XMMReg *d = (XMMReg *)((char *)env + PARAM1); - XMMReg *s = (XMMReg *)((char *)env + PARAM2); d->XMM_D(0) = d->XMM_D(0) - s->XMM_D(0); d->XMM_D(1) = d->XMM_D(1) + s->XMM_D(1); } /* XXX: unordered */ -#define SSE_OP_CMP(name, F)\ -void OPPROTO op_ ## name ## ps (void)\ +#define SSE_HELPER_CMP(name, F)\ +void helper_ ## name ## ps (Reg *d, Reg *s)\ {\ - Reg *d, *s;\ - d = (Reg *)((char *)env + PARAM1);\ - s = (Reg *)((char *)env + PARAM2);\ d->XMM_L(0) = F(32, d->XMM_S(0), s->XMM_S(0));\ d->XMM_L(1) = F(32, d->XMM_S(1), s->XMM_S(1));\ d->XMM_L(2) = F(32, d->XMM_S(2), s->XMM_S(2));\ d->XMM_L(3) = F(32, d->XMM_S(3), s->XMM_S(3));\ }\ \ -void OPPROTO op_ ## name ## ss (void)\ +void helper_ ## name ## ss (Reg *d, Reg *s)\ {\ - Reg *d, *s;\ - d = (Reg *)((char *)env + PARAM1);\ - s = (Reg *)((char *)env + PARAM2);\ d->XMM_L(0) = F(32, d->XMM_S(0), s->XMM_S(0));\ }\ -void OPPROTO op_ ## name ## pd (void)\ +void helper_ ## name ## pd (Reg *d, Reg *s)\ {\ - Reg *d, *s;\ - d = (Reg *)((char *)env + PARAM1);\ - s = (Reg *)((char *)env + PARAM2);\ d->XMM_Q(0) = F(64, d->XMM_D(0), s->XMM_D(0));\ d->XMM_Q(1) = F(64, d->XMM_D(1), s->XMM_D(1));\ }\ \ -void OPPROTO op_ ## name ## sd (void)\ +void helper_ ## name ## sd (Reg *d, Reg *s)\ {\ - Reg *d, *s;\ - d = (Reg *)((char *)env + PARAM1);\ - s = (Reg *)((char *)env + PARAM2);\ d->XMM_Q(0) = F(64, d->XMM_D(0), s->XMM_D(0));\ } @@ -1089,24 +897,21 @@ #define FPU_CMPNLE(size, a, b) float ## size ## _le(a, b, &env->sse_status) ? 0 : -1 #define FPU_CMPORD(size, a, b) float ## size ## _unordered(a, b, &env->sse_status) ? 0 : -1 -SSE_OP_CMP(cmpeq, FPU_CMPEQ) -SSE_OP_CMP(cmplt, FPU_CMPLT) -SSE_OP_CMP(cmple, FPU_CMPLE) -SSE_OP_CMP(cmpunord, FPU_CMPUNORD) -SSE_OP_CMP(cmpneq, FPU_CMPNEQ) -SSE_OP_CMP(cmpnlt, FPU_CMPNLT) -SSE_OP_CMP(cmpnle, FPU_CMPNLE) -SSE_OP_CMP(cmpord, FPU_CMPORD) +SSE_HELPER_CMP(cmpeq, FPU_CMPEQ) +SSE_HELPER_CMP(cmplt, FPU_CMPLT) +SSE_HELPER_CMP(cmple, FPU_CMPLE) +SSE_HELPER_CMP(cmpunord, FPU_CMPUNORD) +SSE_HELPER_CMP(cmpneq, FPU_CMPNEQ) +SSE_HELPER_CMP(cmpnlt, FPU_CMPNLT) +SSE_HELPER_CMP(cmpnle, FPU_CMPNLE) +SSE_HELPER_CMP(cmpord, FPU_CMPORD) const int comis_eflags[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C}; -void OPPROTO op_ucomiss(void) +void helper_ucomiss(Reg *d, Reg *s) { int ret; float32 s0, s1; - Reg *d, *s; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); s0 = d->XMM_S(0); s1 = s->XMM_S(0); @@ -1115,13 +920,10 @@ FORCE_RET(); } -void OPPROTO op_comiss(void) +void helper_comiss(Reg *d, Reg *s) { int ret; float32 s0, s1; - Reg *d, *s; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); s0 = d->XMM_S(0); s1 = s->XMM_S(0); @@ -1130,13 +932,10 @@ FORCE_RET(); } -void OPPROTO op_ucomisd(void) +void helper_ucomisd(Reg *d, Reg *s) { int ret; float64 d0, d1; - Reg *d, *s; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); d0 = d->XMM_D(0); d1 = s->XMM_D(0); @@ -1145,13 +944,10 @@ FORCE_RET(); } -void OPPROTO op_comisd(void) +void helper_comisd(Reg *d, Reg *s) { int ret; float64 d0, d1; - Reg *d, *s; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); d0 = d->XMM_D(0); d1 = s->XMM_D(0); @@ -1160,76 +956,54 @@ FORCE_RET(); } -void OPPROTO op_movmskps(void) +uint32_t helper_movmskps(Reg *s) { int b0, b1, b2, b3; - Reg *s; - s = (Reg *)((char *)env + PARAM1); b0 = s->XMM_L(0) >> 31; b1 = s->XMM_L(1) >> 31; b2 = s->XMM_L(2) >> 31; b3 = s->XMM_L(3) >> 31; - T0 = b0 | (b1 << 1) | (b2 << 2) | (b3 << 3); + return b0 | (b1 << 1) | (b2 << 2) | (b3 << 3); } -void OPPROTO op_movmskpd(void) +uint32_t helper_movmskpd(Reg *s) { int b0, b1; - Reg *s; - s = (Reg *)((char *)env + PARAM1); b0 = s->XMM_L(1) >> 31; b1 = s->XMM_L(3) >> 31; - T0 = b0 | (b1 << 1); + return b0 | (b1 << 1); } #endif -void OPPROTO glue(op_pmovmskb, SUFFIX)(void) +uint32_t glue(helper_pmovmskb, SUFFIX)(Reg *s) { - Reg *s; - s = (Reg *)((char *)env + PARAM1); - T0 = 0; - T0 |= (s->XMM_B(0) >> 7); - T0 |= (s->XMM_B(1) >> 6) & 0x02; - T0 |= (s->XMM_B(2) >> 5) & 0x04; - T0 |= (s->XMM_B(3) >> 4) & 0x08; - T0 |= (s->XMM_B(4) >> 3) & 0x10; - T0 |= (s->XMM_B(5) >> 2) & 0x20; - T0 |= (s->XMM_B(6) >> 1) & 0x40; - T0 |= (s->XMM_B(7)) & 0x80; -#if SHIFT == 1 - T0 |= (s->XMM_B(8) << 1) & 0x0100; - T0 |= (s->XMM_B(9) << 2) & 0x0200; - T0 |= (s->XMM_B(10) << 3) & 0x0400; - T0 |= (s->XMM_B(11) << 4) & 0x0800; - T0 |= (s->XMM_B(12) << 5) & 0x1000; - T0 |= (s->XMM_B(13) << 6) & 0x2000; - T0 |= (s->XMM_B(14) << 7) & 0x4000; - T0 |= (s->XMM_B(15) << 8) & 0x8000; + uint32_t val; + val = 0; + val |= (s->XMM_B(0) >> 7); + val |= (s->XMM_B(1) >> 6) & 0x02; + val |= (s->XMM_B(2) >> 5) & 0x04; + val |= (s->XMM_B(3) >> 4) & 0x08; + val |= (s->XMM_B(4) >> 3) & 0x10; + val |= (s->XMM_B(5) >> 2) & 0x20; + val |= (s->XMM_B(6) >> 1) & 0x40; + val |= (s->XMM_B(7)) & 0x80; +#if SHIFT == 1 + val |= (s->XMM_B(8) << 1) & 0x0100; + val |= (s->XMM_B(9) << 2) & 0x0200; + val |= (s->XMM_B(10) << 3) & 0x0400; + val |= (s->XMM_B(11) << 4) & 0x0800; + val |= (s->XMM_B(12) << 5) & 0x1000; + val |= (s->XMM_B(13) << 6) & 0x2000; + val |= (s->XMM_B(14) << 7) & 0x4000; + val |= (s->XMM_B(15) << 8) & 0x8000; #endif + return val; } -void OPPROTO glue(op_pinsrw, SUFFIX) (void) -{ - Reg *d = (Reg *)((char *)env + PARAM1); - int pos = PARAM2; - - d->W(pos) = T0; -} - -void OPPROTO glue(op_pextrw, SUFFIX) (void) -{ - Reg *s = (Reg *)((char *)env + PARAM1); - int pos = PARAM2; - - T0 = s->W(pos); -} - -void OPPROTO glue(op_packsswb, SUFFIX) (void) +void glue(helper_packsswb, SUFFIX) (Reg *d, Reg *s) { - Reg r, *d, *s; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); + Reg r; r.B(0) = satsb((int16_t)d->W(0)); r.B(1) = satsb((int16_t)d->W(1)); @@ -1254,11 +1028,9 @@ *d = r; } -void OPPROTO glue(op_packuswb, SUFFIX) (void) +void glue(helper_packuswb, SUFFIX) (Reg *d, Reg *s) { - Reg r, *d, *s; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); + Reg r; r.B(0) = satub((int16_t)d->W(0)); r.B(1) = satub((int16_t)d->W(1)); @@ -1283,11 +1055,9 @@ *d = r; } -void OPPROTO glue(op_packssdw, SUFFIX) (void) +void glue(helper_packssdw, SUFFIX) (Reg *d, Reg *s) { - Reg r, *d, *s; - d = (Reg *)((char *)env + PARAM1); - s = (Reg *)((char *)env + PARAM2); + Reg r; r.W(0) = satsw(d->L(0)); r.W(1) = satsw(d->L(1)); @@ -1306,11 +1076,9 @@ #define UNPCK_OP(base_name, base) \ \ -void OPPROTO glue(op_punpck ## base_name ## bw, SUFFIX) (void) \ +void glue(helper_punpck ## base_name ## bw, SUFFIX) (Reg *d, Reg *s) \ { \ - Reg r, *d, *s; \ - d = (Reg *)((char *)env + PARAM1); \ - s = (Reg *)((char *)env + PARAM2); \ + Reg r; \ \ r.B(0) = d->B((base << (SHIFT + 2)) + 0); \ r.B(1) = s->B((base << (SHIFT + 2)) + 0); \ @@ -1333,11 +1101,9 @@ *d = r; \ } \ \ -void OPPROTO glue(op_punpck ## base_name ## wd, SUFFIX) (void) \ +void glue(helper_punpck ## base_name ## wd, SUFFIX) (Reg *d, Reg *s) \ { \ - Reg r, *d, *s; \ - d = (Reg *)((char *)env + PARAM1); \ - s = (Reg *)((char *)env + PARAM2); \ + Reg r; \ \ r.W(0) = d->W((base << (SHIFT + 1)) + 0); \ r.W(1) = s->W((base << (SHIFT + 1)) + 0); \ @@ -1352,11 +1118,9 @@ *d = r; \ } \ \ -void OPPROTO glue(op_punpck ## base_name ## dq, SUFFIX) (void) \ +void glue(helper_punpck ## base_name ## dq, SUFFIX) (Reg *d, Reg *s) \ { \ - Reg r, *d, *s; \ - d = (Reg *)((char *)env + PARAM1); \ - s = (Reg *)((char *)env + PARAM2); \ + Reg r; \ \ r.L(0) = d->L((base << SHIFT) + 0); \ r.L(1) = s->L((base << SHIFT) + 0); \ @@ -1368,11 +1132,9 @@ } \ \ XMM_ONLY( \ -void OPPROTO glue(op_punpck ## base_name ## qdq, SUFFIX) (void) \ +void glue(helper_punpck ## base_name ## qdq, SUFFIX) (Reg *d, Reg *s) \ { \ - Reg r, *d, *s; \ - d = (Reg *)((char *)env + PARAM1); \ - s = (Reg *)((char *)env + PARAM2); \ + Reg r; \ \ r.Q(0) = d->Q(base); \ r.Q(1) = s->Q(base); \ @@ -1383,6 +1145,897 @@ UNPCK_OP(l, 0) UNPCK_OP(h, 1) +/* 3DNow! float ops */ +#if SHIFT == 0 +void helper_pi2fd(MMXReg *d, MMXReg *s) +{ + d->MMX_S(0) = int32_to_float32(s->MMX_L(0), &env->mmx_status); + d->MMX_S(1) = int32_to_float32(s->MMX_L(1), &env->mmx_status); +} + +void helper_pi2fw(MMXReg *d, MMXReg *s) +{ + d->MMX_S(0) = int32_to_float32((int16_t)s->MMX_W(0), &env->mmx_status); + d->MMX_S(1) = int32_to_float32((int16_t)s->MMX_W(2), &env->mmx_status); +} + +void helper_pf2id(MMXReg *d, MMXReg *s) +{ + d->MMX_L(0) = float32_to_int32_round_to_zero(s->MMX_S(0), &env->mmx_status); + d->MMX_L(1) = float32_to_int32_round_to_zero(s->MMX_S(1), &env->mmx_status); +} + +void helper_pf2iw(MMXReg *d, MMXReg *s) +{ + d->MMX_L(0) = satsw(float32_to_int32_round_to_zero(s->MMX_S(0), &env->mmx_status)); + d->MMX_L(1) = satsw(float32_to_int32_round_to_zero(s->MMX_S(1), &env->mmx_status)); +} + +void helper_pfacc(MMXReg *d, MMXReg *s) +{ + MMXReg r; + r.MMX_S(0) = float32_add(d->MMX_S(0), d->MMX_S(1), &env->mmx_status); + r.MMX_S(1) = float32_add(s->MMX_S(0), s->MMX_S(1), &env->mmx_status); + *d = r; +} + +void helper_pfadd(MMXReg *d, MMXReg *s) +{ + d->MMX_S(0) = float32_add(d->MMX_S(0), s->MMX_S(0), &env->mmx_status); + d->MMX_S(1) = float32_add(d->MMX_S(1), s->MMX_S(1), &env->mmx_status); +} + +void helper_pfcmpeq(MMXReg *d, MMXReg *s) +{ + d->MMX_L(0) = float32_eq(d->MMX_S(0), s->MMX_S(0), &env->mmx_status) ? -1 : 0; + d->MMX_L(1) = float32_eq(d->MMX_S(1), s->MMX_S(1), &env->mmx_status) ? -1 : 0; +} + +void helper_pfcmpge(MMXReg *d, MMXReg *s) +{ + d->MMX_L(0) = float32_le(s->MMX_S(0), d->MMX_S(0), &env->mmx_status) ? -1 : 0; + d->MMX_L(1) = float32_le(s->MMX_S(1), d->MMX_S(1), &env->mmx_status) ? -1 : 0; +} + +void helper_pfcmpgt(MMXReg *d, MMXReg *s) +{ + d->MMX_L(0) = float32_lt(s->MMX_S(0), d->MMX_S(0), &env->mmx_status) ? -1 : 0; + d->MMX_L(1) = float32_lt(s->MMX_S(1), d->MMX_S(1), &env->mmx_status) ? -1 : 0; +} + +void helper_pfmax(MMXReg *d, MMXReg *s) +{ + if (float32_lt(d->MMX_S(0), s->MMX_S(0), &env->mmx_status)) + d->MMX_S(0) = s->MMX_S(0); + if (float32_lt(d->MMX_S(1), s->MMX_S(1), &env->mmx_status)) + d->MMX_S(1) = s->MMX_S(1); +} + +void helper_pfmin(MMXReg *d, MMXReg *s) +{ + if (float32_lt(s->MMX_S(0), d->MMX_S(0), &env->mmx_status)) + d->MMX_S(0) = s->MMX_S(0); + if (float32_lt(s->MMX_S(1), d->MMX_S(1), &env->mmx_status)) + d->MMX_S(1) = s->MMX_S(1); +} + +void helper_pfmul(MMXReg *d, MMXReg *s) +{ + d->MMX_S(0) = float32_mul(d->MMX_S(0), s->MMX_S(0), &env->mmx_status); + d->MMX_S(1) = float32_mul(d->MMX_S(1), s->MMX_S(1), &env->mmx_status); +} + +void helper_pfnacc(MMXReg *d, MMXReg *s) +{ + MMXReg r; + r.MMX_S(0) = float32_sub(d->MMX_S(0), d->MMX_S(1), &env->mmx_status); + r.MMX_S(1) = float32_sub(s->MMX_S(0), s->MMX_S(1), &env->mmx_status); + *d = r; +} + +void helper_pfpnacc(MMXReg *d, MMXReg *s) +{ + MMXReg r; + r.MMX_S(0) = float32_sub(d->MMX_S(0), d->MMX_S(1), &env->mmx_status); + r.MMX_S(1) = float32_add(s->MMX_S(0), s->MMX_S(1), &env->mmx_status); + *d = r; +} + +void helper_pfrcp(MMXReg *d, MMXReg *s) +{ + d->MMX_S(0) = approx_rcp(s->MMX_S(0)); + d->MMX_S(1) = d->MMX_S(0); +} + +void helper_pfrsqrt(MMXReg *d, MMXReg *s) +{ + d->MMX_L(1) = s->MMX_L(0) & 0x7fffffff; + d->MMX_S(1) = approx_rsqrt(d->MMX_S(1)); + d->MMX_L(1) |= s->MMX_L(0) & 0x80000000; + d->MMX_L(0) = d->MMX_L(1); +} + +void helper_pfsub(MMXReg *d, MMXReg *s) +{ + d->MMX_S(0) = float32_sub(d->MMX_S(0), s->MMX_S(0), &env->mmx_status); + d->MMX_S(1) = float32_sub(d->MMX_S(1), s->MMX_S(1), &env->mmx_status); +} + +void helper_pfsubr(MMXReg *d, MMXReg *s) +{ + d->MMX_S(0) = float32_sub(s->MMX_S(0), d->MMX_S(0), &env->mmx_status); + d->MMX_S(1) = float32_sub(s->MMX_S(1), d->MMX_S(1), &env->mmx_status); +} + +void helper_pswapd(MMXReg *d, MMXReg *s) +{ + MMXReg r; + r.MMX_L(0) = s->MMX_L(1); + r.MMX_L(1) = s->MMX_L(0); + *d = r; +} +#endif + +/* SSSE3 op helpers */ +void glue(helper_pshufb, SUFFIX) (Reg *d, Reg *s) +{ + int i; + Reg r; + + for (i = 0; i < (8 << SHIFT); i++) + r.B(i) = (s->B(i) & 0x80) ? 0 : (d->B(s->B(i) & ((8 << SHIFT) - 1))); + + *d = r; +} + +void glue(helper_phaddw, SUFFIX) (Reg *d, Reg *s) +{ + d->W(0) = (int16_t)d->W(0) + (int16_t)d->W(1); + d->W(1) = (int16_t)d->W(2) + (int16_t)d->W(3); + XMM_ONLY(d->W(2) = (int16_t)d->W(4) + (int16_t)d->W(5)); + XMM_ONLY(d->W(3) = (int16_t)d->W(6) + (int16_t)d->W(7)); + d->W((2 << SHIFT) + 0) = (int16_t)s->W(0) + (int16_t)s->W(1); + d->W((2 << SHIFT) + 1) = (int16_t)s->W(2) + (int16_t)s->W(3); + XMM_ONLY(d->W(6) = (int16_t)s->W(4) + (int16_t)s->W(5)); + XMM_ONLY(d->W(7) = (int16_t)s->W(6) + (int16_t)s->W(7)); +} + +void glue(helper_phaddd, SUFFIX) (Reg *d, Reg *s) +{ + d->L(0) = (int32_t)d->L(0) + (int32_t)d->L(1); + XMM_ONLY(d->L(1) = (int32_t)d->L(2) + (int32_t)d->L(3)); + d->L((1 << SHIFT) + 0) = (int32_t)s->L(0) + (int32_t)s->L(1); + XMM_ONLY(d->L(3) = (int32_t)s->L(2) + (int32_t)s->L(3)); +} + +void glue(helper_phaddsw, SUFFIX) (Reg *d, Reg *s) +{ + d->W(0) = satsw((int16_t)d->W(0) + (int16_t)d->W(1)); + d->W(1) = satsw((int16_t)d->W(2) + (int16_t)d->W(3)); + XMM_ONLY(d->W(2) = satsw((int16_t)d->W(4) + (int16_t)d->W(5))); + XMM_ONLY(d->W(3) = satsw((int16_t)d->W(6) + (int16_t)d->W(7))); + d->W((2 << SHIFT) + 0) = satsw((int16_t)s->W(0) + (int16_t)s->W(1)); + d->W((2 << SHIFT) + 1) = satsw((int16_t)s->W(2) + (int16_t)s->W(3)); + XMM_ONLY(d->W(6) = satsw((int16_t)s->W(4) + (int16_t)s->W(5))); + XMM_ONLY(d->W(7) = satsw((int16_t)s->W(6) + (int16_t)s->W(7))); +} + +void glue(helper_pmaddubsw, SUFFIX) (Reg *d, Reg *s) +{ + d->W(0) = satsw((int8_t)s->B( 0) * (uint8_t)d->B( 0) + + (int8_t)s->B( 1) * (uint8_t)d->B( 1)); + d->W(1) = satsw((int8_t)s->B( 2) * (uint8_t)d->B( 2) + + (int8_t)s->B( 3) * (uint8_t)d->B( 3)); + d->W(2) = satsw((int8_t)s->B( 4) * (uint8_t)d->B( 4) + + (int8_t)s->B( 5) * (uint8_t)d->B( 5)); + d->W(3) = satsw((int8_t)s->B( 6) * (uint8_t)d->B( 6) + + (int8_t)s->B( 7) * (uint8_t)d->B( 7)); +#if SHIFT == 1 + d->W(4) = satsw((int8_t)s->B( 8) * (uint8_t)d->B( 8) + + (int8_t)s->B( 9) * (uint8_t)d->B( 9)); + d->W(5) = satsw((int8_t)s->B(10) * (uint8_t)d->B(10) + + (int8_t)s->B(11) * (uint8_t)d->B(11)); + d->W(6) = satsw((int8_t)s->B(12) * (uint8_t)d->B(12) + + (int8_t)s->B(13) * (uint8_t)d->B(13)); + d->W(7) = satsw((int8_t)s->B(14) * (uint8_t)d->B(14) + + (int8_t)s->B(15) * (uint8_t)d->B(15)); +#endif +} + +void glue(helper_phsubw, SUFFIX) (Reg *d, Reg *s) +{ + d->W(0) = (int16_t)d->W(0) - (int16_t)d->W(1); + d->W(1) = (int16_t)d->W(2) - (int16_t)d->W(3); + XMM_ONLY(d->W(2) = (int16_t)d->W(4) - (int16_t)d->W(5)); + XMM_ONLY(d->W(3) = (int16_t)d->W(6) - (int16_t)d->W(7)); + d->W((2 << SHIFT) + 0) = (int16_t)s->W(0) - (int16_t)s->W(1); + d->W((2 << SHIFT) + 1) = (int16_t)s->W(2) - (int16_t)s->W(3); + XMM_ONLY(d->W(6) = (int16_t)s->W(4) - (int16_t)s->W(5)); + XMM_ONLY(d->W(7) = (int16_t)s->W(6) - (int16_t)s->W(7)); +} + +void glue(helper_phsubd, SUFFIX) (Reg *d, Reg *s) +{ + d->L(0) = (int32_t)d->L(0) - (int32_t)d->L(1); + XMM_ONLY(d->L(1) = (int32_t)d->L(2) - (int32_t)d->L(3)); + d->L((1 << SHIFT) + 0) = (int32_t)s->L(0) - (int32_t)s->L(1); + XMM_ONLY(d->L(3) = (int32_t)s->L(2) - (int32_t)s->L(3)); +} + +void glue(helper_phsubsw, SUFFIX) (Reg *d, Reg *s) +{ + d->W(0) = satsw((int16_t)d->W(0) - (int16_t)d->W(1)); + d->W(1) = satsw((int16_t)d->W(2) - (int16_t)d->W(3)); + XMM_ONLY(d->W(2) = satsw((int16_t)d->W(4) - (int16_t)d->W(5))); + XMM_ONLY(d->W(3) = satsw((int16_t)d->W(6) - (int16_t)d->W(7))); + d->W((2 << SHIFT) + 0) = satsw((int16_t)s->W(0) - (int16_t)s->W(1)); + d->W((2 << SHIFT) + 1) = satsw((int16_t)s->W(2) - (int16_t)s->W(3)); + XMM_ONLY(d->W(6) = satsw((int16_t)s->W(4) - (int16_t)s->W(5))); + XMM_ONLY(d->W(7) = satsw((int16_t)s->W(6) - (int16_t)s->W(7))); +} + +#define FABSB(_, x) x > INT8_MAX ? -(int8_t ) x : x +#define FABSW(_, x) x > INT16_MAX ? -(int16_t) x : x +#define FABSL(_, x) x > INT32_MAX ? -(int32_t) x : x +SSE_HELPER_B(helper_pabsb, FABSB) +SSE_HELPER_W(helper_pabsw, FABSW) +SSE_HELPER_L(helper_pabsd, FABSL) + +#define FMULHRSW(d, s) ((int16_t) d * (int16_t) s + 0x4000) >> 15 +SSE_HELPER_W(helper_pmulhrsw, FMULHRSW) + +#define FSIGNB(d, s) s <= INT8_MAX ? s ? d : 0 : -(int8_t ) d +#define FSIGNW(d, s) s <= INT16_MAX ? s ? d : 0 : -(int16_t) d +#define FSIGNL(d, s) s <= INT32_MAX ? s ? d : 0 : -(int32_t) d +SSE_HELPER_B(helper_psignb, FSIGNB) +SSE_HELPER_W(helper_psignw, FSIGNW) +SSE_HELPER_L(helper_psignd, FSIGNL) + +void glue(helper_palignr, SUFFIX) (Reg *d, Reg *s, int32_t shift) +{ + Reg r; + + /* XXX could be checked during translation */ + if (shift >= (16 << SHIFT)) { + r.Q(0) = 0; + XMM_ONLY(r.Q(1) = 0); + } else { + shift <<= 3; +#define SHR(v, i) (i < 64 && i > -64 ? i > 0 ? v >> (i) : (v << -(i)) : 0) +#if SHIFT == 0 + r.Q(0) = SHR(s->Q(0), shift - 0) | + SHR(d->Q(0), shift - 64); +#else + r.Q(0) = SHR(s->Q(0), shift - 0) | + SHR(s->Q(1), shift - 64) | + SHR(d->Q(0), shift - 128) | + SHR(d->Q(1), shift - 192); + r.Q(1) = SHR(s->Q(0), shift + 64) | + SHR(s->Q(1), shift - 0) | + SHR(d->Q(0), shift - 64) | + SHR(d->Q(1), shift - 128); +#endif +#undef SHR + } + + *d = r; +} + +#define XMM0 env->xmm_regs[0] + +#if SHIFT == 1 +#define SSE_HELPER_V(name, elem, num, F)\ +void glue(name, SUFFIX) (Reg *d, Reg *s)\ +{\ + d->elem(0) = F(d->elem(0), s->elem(0), XMM0.elem(0));\ + d->elem(1) = F(d->elem(1), s->elem(1), XMM0.elem(1));\ + if (num > 2) {\ + d->elem(2) = F(d->elem(2), s->elem(2), XMM0.elem(2));\ + d->elem(3) = F(d->elem(3), s->elem(3), XMM0.elem(3));\ + if (num > 4) {\ + d->elem(4) = F(d->elem(4), s->elem(4), XMM0.elem(4));\ + d->elem(5) = F(d->elem(5), s->elem(5), XMM0.elem(5));\ + d->elem(6) = F(d->elem(6), s->elem(6), XMM0.elem(6));\ + d->elem(7) = F(d->elem(7), s->elem(7), XMM0.elem(7));\ + if (num > 8) {\ + d->elem(8) = F(d->elem(8), s->elem(8), XMM0.elem(8));\ + d->elem(9) = F(d->elem(9), s->elem(9), XMM0.elem(9));\ + d->elem(10) = F(d->elem(10), s->elem(10), XMM0.elem(10));\ + d->elem(11) = F(d->elem(11), s->elem(11), XMM0.elem(11));\ + d->elem(12) = F(d->elem(12), s->elem(12), XMM0.elem(12));\ + d->elem(13) = F(d->elem(13), s->elem(13), XMM0.elem(13));\ + d->elem(14) = F(d->elem(14), s->elem(14), XMM0.elem(14));\ + d->elem(15) = F(d->elem(15), s->elem(15), XMM0.elem(15));\ + }\ + }\ + }\ +} + +#define SSE_HELPER_I(name, elem, num, F)\ +void glue(name, SUFFIX) (Reg *d, Reg *s, uint32_t imm)\ +{\ + d->elem(0) = F(d->elem(0), s->elem(0), ((imm >> 0) & 1));\ + d->elem(1) = F(d->elem(1), s->elem(1), ((imm >> 1) & 1));\ + if (num > 2) {\ + d->elem(2) = F(d->elem(2), s->elem(2), ((imm >> 2) & 1));\ + d->elem(3) = F(d->elem(3), s->elem(3), ((imm >> 3) & 1));\ + if (num > 4) {\ + d->elem(4) = F(d->elem(4), s->elem(4), ((imm >> 4) & 1));\ + d->elem(5) = F(d->elem(5), s->elem(5), ((imm >> 5) & 1));\ + d->elem(6) = F(d->elem(6), s->elem(6), ((imm >> 6) & 1));\ + d->elem(7) = F(d->elem(7), s->elem(7), ((imm >> 7) & 1));\ + if (num > 8) {\ + d->elem(8) = F(d->elem(8), s->elem(8), ((imm >> 8) & 1));\ + d->elem(9) = F(d->elem(9), s->elem(9), ((imm >> 9) & 1));\ + d->elem(10) = F(d->elem(10), s->elem(10), ((imm >> 10) & 1));\ + d->elem(11) = F(d->elem(11), s->elem(11), ((imm >> 11) & 1));\ + d->elem(12) = F(d->elem(12), s->elem(12), ((imm >> 12) & 1));\ + d->elem(13) = F(d->elem(13), s->elem(13), ((imm >> 13) & 1));\ + d->elem(14) = F(d->elem(14), s->elem(14), ((imm >> 14) & 1));\ + d->elem(15) = F(d->elem(15), s->elem(15), ((imm >> 15) & 1));\ + }\ + }\ + }\ +} + +/* SSE4.1 op helpers */ +#define FBLENDVB(d, s, m) (m & 0x80) ? s : d +#define FBLENDVPS(d, s, m) (m & 0x80000000) ? s : d +#define FBLENDVPD(d, s, m) (m & 0x8000000000000000LL) ? s : d +SSE_HELPER_V(helper_pblendvb, B, 16, FBLENDVB) +SSE_HELPER_V(helper_blendvps, L, 4, FBLENDVPS) +SSE_HELPER_V(helper_blendvpd, Q, 2, FBLENDVPD) + +void glue(helper_ptest, SUFFIX) (Reg *d, Reg *s) +{ + uint64_t zf = (s->Q(0) & d->Q(0)) | (s->Q(1) & d->Q(1)); + uint64_t cf = (s->Q(0) & ~d->Q(0)) | (s->Q(1) & ~d->Q(1)); + + CC_SRC = (zf ? 0 : CC_Z) | (cf ? 0 : CC_C); +} + +#define SSE_HELPER_F(name, elem, num, F)\ +void glue(name, SUFFIX) (Reg *d, Reg *s)\ +{\ + d->elem(0) = F(0);\ + d->elem(1) = F(1);\ + d->elem(2) = F(2);\ + d->elem(3) = F(3);\ + if (num > 3) {\ + d->elem(4) = F(4);\ + d->elem(5) = F(5);\ + if (num > 5) {\ + d->elem(6) = F(6);\ + d->elem(7) = F(7);\ + }\ + }\ +} + +SSE_HELPER_F(helper_pmovsxbw, W, 8, (int8_t) s->B) +SSE_HELPER_F(helper_pmovsxbd, L, 4, (int8_t) s->B) +SSE_HELPER_F(helper_pmovsxbq, Q, 2, (int8_t) s->B) +SSE_HELPER_F(helper_pmovsxwd, L, 4, (int16_t) s->W) +SSE_HELPER_F(helper_pmovsxwq, Q, 2, (int16_t) s->W) +SSE_HELPER_F(helper_pmovsxdq, Q, 2, (int32_t) s->L) +SSE_HELPER_F(helper_pmovzxbw, W, 8, s->B) +SSE_HELPER_F(helper_pmovzxbd, L, 4, s->B) +SSE_HELPER_F(helper_pmovzxbq, Q, 2, s->B) +SSE_HELPER_F(helper_pmovzxwd, L, 4, s->W) +SSE_HELPER_F(helper_pmovzxwq, Q, 2, s->W) +SSE_HELPER_F(helper_pmovzxdq, Q, 2, s->L) + +void glue(helper_pmuldq, SUFFIX) (Reg *d, Reg *s) +{ + d->Q(0) = (int64_t) (int32_t) d->L(0) * (int32_t) s->L(0); + d->Q(1) = (int64_t) (int32_t) d->L(2) * (int32_t) s->L(2); +} + +#define FCMPEQQ(d, s) d == s ? -1 : 0 +SSE_HELPER_Q(helper_pcmpeqq, FCMPEQQ) + +void glue(helper_packusdw, SUFFIX) (Reg *d, Reg *s) +{ + d->W(0) = satuw((int32_t) d->L(0)); + d->W(1) = satuw((int32_t) d->L(1)); + d->W(2) = satuw((int32_t) d->L(2)); + d->W(3) = satuw((int32_t) d->L(3)); + d->W(4) = satuw((int32_t) s->L(0)); + d->W(5) = satuw((int32_t) s->L(1)); + d->W(6) = satuw((int32_t) s->L(2)); + d->W(7) = satuw((int32_t) s->L(3)); +} + +#define FMINSB(d, s) MIN((int8_t) d, (int8_t) s) +#define FMINSD(d, s) MIN((int32_t) d, (int32_t) s) +#define FMAXSB(d, s) MAX((int8_t) d, (int8_t) s) +#define FMAXSD(d, s) MAX((int32_t) d, (int32_t) s) +SSE_HELPER_B(helper_pminsb, FMINSB) +SSE_HELPER_L(helper_pminsd, FMINSD) +SSE_HELPER_W(helper_pminuw, MIN) +SSE_HELPER_L(helper_pminud, MIN) +SSE_HELPER_B(helper_pmaxsb, FMAXSB) +SSE_HELPER_L(helper_pmaxsd, FMAXSD) +SSE_HELPER_W(helper_pmaxuw, MAX) +SSE_HELPER_L(helper_pmaxud, MAX) + +#define FMULLD(d, s) (int32_t) d * (int32_t) s +SSE_HELPER_L(helper_pmulld, FMULLD) + +void glue(helper_phminposuw, SUFFIX) (Reg *d, Reg *s) +{ + int idx = 0; + + if (s->W(1) < s->W(idx)) + idx = 1; + if (s->W(2) < s->W(idx)) + idx = 2; + if (s->W(3) < s->W(idx)) + idx = 3; + if (s->W(4) < s->W(idx)) + idx = 4; + if (s->W(5) < s->W(idx)) + idx = 5; + if (s->W(6) < s->W(idx)) + idx = 6; + if (s->W(7) < s->W(idx)) + idx = 7; + + d->Q(1) = 0; + d->L(1) = 0; + d->W(1) = idx; + d->W(0) = s->W(idx); +} + +void glue(helper_roundps, SUFFIX) (Reg *d, Reg *s, uint32_t mode) +{ + signed char prev_rounding_mode; + + prev_rounding_mode = env->sse_status.float_rounding_mode; + if (!(mode & (1 << 2))) + switch (mode & 3) { + case 0: + set_float_rounding_mode(float_round_nearest_even, &env->sse_status); + break; + case 1: + set_float_rounding_mode(float_round_down, &env->sse_status); + break; + case 2: + set_float_rounding_mode(float_round_up, &env->sse_status); + break; + case 3: + set_float_rounding_mode(float_round_to_zero, &env->sse_status); + break; + } + + d->L(0) = float64_round_to_int(s->L(0), &env->sse_status); + d->L(1) = float64_round_to_int(s->L(1), &env->sse_status); + d->L(2) = float64_round_to_int(s->L(2), &env->sse_status); + d->L(3) = float64_round_to_int(s->L(3), &env->sse_status); + +#if 0 /* TODO */ + if (mode & (1 << 3)) + set_float_exception_flags( + get_float_exception_flags(&env->sse_status) & + ~float_flag_inexact, + &env->sse_status); +#endif + env->sse_status.float_rounding_mode = prev_rounding_mode; +} + +void glue(helper_roundpd, SUFFIX) (Reg *d, Reg *s, uint32_t mode) +{ + signed char prev_rounding_mode; + + prev_rounding_mode = env->sse_status.float_rounding_mode; + if (!(mode & (1 << 2))) + switch (mode & 3) { + case 0: + set_float_rounding_mode(float_round_nearest_even, &env->sse_status); + break; + case 1: + set_float_rounding_mode(float_round_down, &env->sse_status); + break; + case 2: + set_float_rounding_mode(float_round_up, &env->sse_status); + break; + case 3: + set_float_rounding_mode(float_round_to_zero, &env->sse_status); + break; + } + + d->Q(0) = float64_round_to_int(s->Q(0), &env->sse_status); + d->Q(1) = float64_round_to_int(s->Q(1), &env->sse_status); + +#if 0 /* TODO */ + if (mode & (1 << 3)) + set_float_exception_flags( + get_float_exception_flags(&env->sse_status) & + ~float_flag_inexact, + &env->sse_status); +#endif + env->sse_status.float_rounding_mode = prev_rounding_mode; +} + +void glue(helper_roundss, SUFFIX) (Reg *d, Reg *s, uint32_t mode) +{ + signed char prev_rounding_mode; + + prev_rounding_mode = env->sse_status.float_rounding_mode; + if (!(mode & (1 << 2))) + switch (mode & 3) { + case 0: + set_float_rounding_mode(float_round_nearest_even, &env->sse_status); + break; + case 1: + set_float_rounding_mode(float_round_down, &env->sse_status); + break; + case 2: + set_float_rounding_mode(float_round_up, &env->sse_status); + break; + case 3: + set_float_rounding_mode(float_round_to_zero, &env->sse_status); + break; + } + + d->L(0) = float64_round_to_int(s->L(0), &env->sse_status); + +#if 0 /* TODO */ + if (mode & (1 << 3)) + set_float_exception_flags( + get_float_exception_flags(&env->sse_status) & + ~float_flag_inexact, + &env->sse_status); +#endif + env->sse_status.float_rounding_mode = prev_rounding_mode; +} + +void glue(helper_roundsd, SUFFIX) (Reg *d, Reg *s, uint32_t mode) +{ + signed char prev_rounding_mode; + + prev_rounding_mode = env->sse_status.float_rounding_mode; + if (!(mode & (1 << 2))) + switch (mode & 3) { + case 0: + set_float_rounding_mode(float_round_nearest_even, &env->sse_status); + break; + case 1: + set_float_rounding_mode(float_round_down, &env->sse_status); + break; + case 2: + set_float_rounding_mode(float_round_up, &env->sse_status); + break; + case 3: + set_float_rounding_mode(float_round_to_zero, &env->sse_status); + break; + } + + d->Q(0) = float64_round_to_int(s->Q(0), &env->sse_status); + +#if 0 /* TODO */ + if (mode & (1 << 3)) + set_float_exception_flags( + get_float_exception_flags(&env->sse_status) & + ~float_flag_inexact, + &env->sse_status); +#endif + env->sse_status.float_rounding_mode = prev_rounding_mode; +} + +#define FBLENDP(d, s, m) m ? s : d +SSE_HELPER_I(helper_blendps, L, 4, FBLENDP) +SSE_HELPER_I(helper_blendpd, Q, 2, FBLENDP) +SSE_HELPER_I(helper_pblendw, W, 8, FBLENDP) + +void glue(helper_dpps, SUFFIX) (Reg *d, Reg *s, uint32_t mask) +{ + float32 iresult = 0 /*float32_zero*/; + + if (mask & (1 << 4)) + iresult = float32_add(iresult, + float32_mul(d->L(0), s->L(0), &env->sse_status), + &env->sse_status); + if (mask & (1 << 5)) + iresult = float32_add(iresult, + float32_mul(d->L(1), s->L(1), &env->sse_status), + &env->sse_status); + if (mask & (1 << 6)) + iresult = float32_add(iresult, + float32_mul(d->L(2), s->L(2), &env->sse_status), + &env->sse_status); + if (mask & (1 << 7)) + iresult = float32_add(iresult, + float32_mul(d->L(3), s->L(3), &env->sse_status), + &env->sse_status); + d->L(0) = (mask & (1 << 0)) ? iresult : 0 /*float32_zero*/; + d->L(1) = (mask & (1 << 1)) ? iresult : 0 /*float32_zero*/; + d->L(2) = (mask & (1 << 2)) ? iresult : 0 /*float32_zero*/; + d->L(3) = (mask & (1 << 3)) ? iresult : 0 /*float32_zero*/; +} + +void glue(helper_dppd, SUFFIX) (Reg *d, Reg *s, uint32_t mask) +{ + float64 iresult = 0 /*float64_zero*/; + + if (mask & (1 << 4)) + iresult = float64_add(iresult, + float64_mul(d->Q(0), s->Q(0), &env->sse_status), + &env->sse_status); + if (mask & (1 << 5)) + iresult = float64_add(iresult, + float64_mul(d->Q(1), s->Q(1), &env->sse_status), + &env->sse_status); + d->Q(0) = (mask & (1 << 0)) ? iresult : 0 /*float64_zero*/; + d->Q(1) = (mask & (1 << 1)) ? iresult : 0 /*float64_zero*/; +} + +void glue(helper_mpsadbw, SUFFIX) (Reg *d, Reg *s, uint32_t offset) +{ + int s0 = (offset & 3) << 2; + int d0 = (offset & 4) << 0; + int i; + Reg r; + + for (i = 0; i < 8; i++, d0++) { + r.W(i) = 0; + r.W(i) += abs1(d->B(d0 + 0) - s->B(s0 + 0)); + r.W(i) += abs1(d->B(d0 + 1) - s->B(s0 + 1)); + r.W(i) += abs1(d->B(d0 + 2) - s->B(s0 + 2)); + r.W(i) += abs1(d->B(d0 + 3) - s->B(s0 + 3)); + } + + *d = r; +} + +/* SSE4.2 op helpers */ +/* it's unclear whether signed or unsigned */ +#define FCMPGTQ(d, s) d > s ? -1 : 0 +SSE_HELPER_Q(helper_pcmpgtq, FCMPGTQ) + +static inline int pcmp_elen(int reg, uint32_t ctrl) +{ + int val; + + /* Presence of REX.W is indicated by a bit higher than 7 set */ + if (ctrl >> 8) + val = abs1((int64_t) env->regs[reg]); + else + val = abs1((int32_t) env->regs[reg]); + + if (ctrl & 1) { + if (val > 8) + return 8; + } else + if (val > 16) + return 16; + + return val; +} + +static inline int pcmp_ilen(Reg *r, uint8_t ctrl) +{ + int val = 0; + + if (ctrl & 1) { + while (val < 8 && r->W(val)) + val++; + } else + while (val < 16 && r->B(val)) + val++; + + return val; +} + +static inline int pcmp_val(Reg *r, uint8_t ctrl, int i) +{ + switch ((ctrl >> 0) & 3) { + case 0: + return r->B(i); + case 1: + return r->W(i); + case 2: + return (int8_t) r->B(i); + case 3: + default: + return (int16_t) r->W(i); + } +} + +static inline unsigned pcmpxstrx(Reg *d, Reg *s, + int8_t ctrl, int valids, int validd) +{ + unsigned int res = 0; + int v; + int j, i; + int upper = (ctrl & 1) ? 7 : 15; + + valids--; + validd--; + + CC_SRC = (valids < upper ? CC_Z : 0) | (validd < upper ? CC_S : 0); + + switch ((ctrl >> 2) & 3) { + case 0: + for (j = valids; j >= 0; j--) { + res <<= 1; + v = pcmp_val(s, ctrl, j); + for (i = validd; i >= 0; i--) + res |= (v == pcmp_val(d, ctrl, i)); + } + break; + case 1: + for (j = valids; j >= 0; j--) { + res <<= 1; + v = pcmp_val(s, ctrl, j); + for (i = ((validd - 1) | 1); i >= 0; i -= 2) + res |= (pcmp_val(d, ctrl, i - 0) <= v && + pcmp_val(d, ctrl, i - 1) >= v); + } + break; + case 2: + res = (2 << (upper - MAX(valids, validd))) - 1; + res <<= MAX(valids, validd) - MIN(valids, validd); + for (i = MIN(valids, validd); i >= 0; i--) { + res <<= 1; + v = pcmp_val(s, ctrl, i); + res |= (v == pcmp_val(d, ctrl, i)); + } + break; + case 3: + for (j = valids - validd; j >= 0; j--) { + res <<= 1; + res |= 1; + for (i = MIN(upper - j, validd); i >= 0; i--) + res &= (pcmp_val(s, ctrl, i + j) == pcmp_val(d, ctrl, i)); + } + break; + } + + switch ((ctrl >> 4) & 3) { + case 1: + res ^= (2 << upper) - 1; + break; + case 3: + res ^= (2 << valids) - 1; + break; + } + + if (res) + CC_SRC |= CC_C; + if (res & 1) + CC_SRC |= CC_O; + + return res; +} + +static inline int rffs1(unsigned int val) +{ + int ret = 1, hi; + + for (hi = sizeof(val) * 4; hi; hi /= 2) + if (val >> hi) { + val >>= hi; + ret += hi; + } + + return ret; +} + +static inline int ffs1(unsigned int val) +{ + int ret = 1, hi; + + for (hi = sizeof(val) * 4; hi; hi /= 2) + if (val << hi) { + val <<= hi; + ret += hi; + } + + return ret; +} + +void glue(helper_pcmpestri, SUFFIX) (Reg *d, Reg *s, uint32_t ctrl) +{ + unsigned int res = pcmpxstrx(d, s, ctrl, + pcmp_elen(R_EDX, ctrl), + pcmp_elen(R_EAX, ctrl)); + + if (res) + env->regs[R_ECX] = ((ctrl & (1 << 6)) ? rffs1 : ffs1)(res) - 1; + else + env->regs[R_ECX] = 16 >> (ctrl & (1 << 0)); +} + +void glue(helper_pcmpestrm, SUFFIX) (Reg *d, Reg *s, uint32_t ctrl) +{ + int i; + unsigned int res = pcmpxstrx(d, s, ctrl, + pcmp_elen(R_EDX, ctrl), + pcmp_elen(R_EAX, ctrl)); + + if ((ctrl >> 6) & 1) { + if (ctrl & 1) + for (i = 0; i <= 8; i--, res >>= 1) + d->W(i) = (res & 1) ? ~0 : 0; + else + for (i = 0; i <= 16; i--, res >>= 1) + d->B(i) = (res & 1) ? ~0 : 0; + } else { + d->Q(1) = 0; + d->Q(0) = res; + } +} + +void glue(helper_pcmpistri, SUFFIX) (Reg *d, Reg *s, uint32_t ctrl) +{ + unsigned int res = pcmpxstrx(d, s, ctrl, + pcmp_ilen(s, ctrl), + pcmp_ilen(d, ctrl)); + + if (res) + env->regs[R_ECX] = ((ctrl & (1 << 6)) ? rffs1 : ffs1)(res) - 1; + else + env->regs[R_ECX] = 16 >> (ctrl & (1 << 0)); +} + +void glue(helper_pcmpistrm, SUFFIX) (Reg *d, Reg *s, uint32_t ctrl) +{ + int i; + unsigned int res = pcmpxstrx(d, s, ctrl, + pcmp_ilen(s, ctrl), + pcmp_ilen(d, ctrl)); + + if ((ctrl >> 6) & 1) { + if (ctrl & 1) + for (i = 0; i <= 8; i--, res >>= 1) + d->W(i) = (res & 1) ? ~0 : 0; + else + for (i = 0; i <= 16; i--, res >>= 1) + d->B(i) = (res & 1) ? ~0 : 0; + } else { + d->Q(1) = 0; + d->Q(0) = res; + } +} + +#define CRCPOLY 0x1edc6f41 +#define CRCPOLY_BITREV 0x82f63b78 +target_ulong helper_crc32(uint32_t crc1, target_ulong msg, uint32_t len) +{ + target_ulong crc = (msg & ((target_ulong) -1 >> + (TARGET_LONG_BITS - len))) ^ crc1; + + while (len--) + crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_BITREV : 0); + + return crc; +} + +#define POPMASK(i) ((target_ulong) -1 / ((1LL << (1 << i)) + 1)) +#define POPCOUNT(n, i) (n & POPMASK(i)) + ((n >> (1 << i)) & POPMASK(i)) +target_ulong helper_popcnt(target_ulong n, uint32_t type) +{ + CC_SRC = n ? 0 : CC_Z; + + n = POPCOUNT(n, 0); + n = POPCOUNT(n, 1); + n = POPCOUNT(n, 2); + n = POPCOUNT(n, 3); + if (type == 1) + return n & 0xff; + + n = POPCOUNT(n, 4); +#ifndef TARGET_X86_64 + return n; +#else + if (type == 2) + return n & 0xff; + + return POPCOUNT(n, 5); +#endif +} +#endif + #undef SHIFT #undef XMM_ONLY #undef Reg diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/ops_sse_header.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/ops_sse_header.h --- qemu-0.9.1/target-i386/ops_sse_header.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-i386/ops_sse_header.h 2008-10-04 04:27:44.000000000 +0100 @@ -0,0 +1,337 @@ +/* + * MMX/3DNow!/SSE/SSE2/SSE3/SSSE3/SSE4/PNI support + * + * Copyright (c) 2005 Fabrice Bellard + * + * 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 + */ +#if SHIFT == 0 +#define Reg MMXReg +#define SUFFIX _mmx +#else +#define Reg XMMReg +#define SUFFIX _xmm +#endif + +DEF_HELPER(void, glue(helper_psrlw, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_psraw, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_psllw, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_psrld, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_psrad, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pslld, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_psrlq, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_psllq, SUFFIX), (Reg *d, Reg *s)) + +#if SHIFT == 1 +DEF_HELPER(void, glue(helper_psrldq, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pslldq, SUFFIX), (Reg *d, Reg *s)) +#endif + +#define SSE_HELPER_B(name, F)\ + DEF_HELPER(void, glue(name, SUFFIX), (Reg *d, Reg *s)) + +#define SSE_HELPER_W(name, F)\ + DEF_HELPER(void, glue(name, SUFFIX), (Reg *d, Reg *s)) + +#define SSE_HELPER_L(name, F)\ + DEF_HELPER(void, glue(name, SUFFIX), (Reg *d, Reg *s)) + +#define SSE_HELPER_Q(name, F)\ + DEF_HELPER(void, glue(name, SUFFIX), (Reg *d, Reg *s)) + +SSE_HELPER_B(helper_paddb, FADD) +SSE_HELPER_W(helper_paddw, FADD) +SSE_HELPER_L(helper_paddl, FADD) +SSE_HELPER_Q(helper_paddq, FADD) + +SSE_HELPER_B(helper_psubb, FSUB) +SSE_HELPER_W(helper_psubw, FSUB) +SSE_HELPER_L(helper_psubl, FSUB) +SSE_HELPER_Q(helper_psubq, FSUB) + +SSE_HELPER_B(helper_paddusb, FADDUB) +SSE_HELPER_B(helper_paddsb, FADDSB) +SSE_HELPER_B(helper_psubusb, FSUBUB) +SSE_HELPER_B(helper_psubsb, FSUBSB) + +SSE_HELPER_W(helper_paddusw, FADDUW) +SSE_HELPER_W(helper_paddsw, FADDSW) +SSE_HELPER_W(helper_psubusw, FSUBUW) +SSE_HELPER_W(helper_psubsw, FSUBSW) + +SSE_HELPER_B(helper_pminub, FMINUB) +SSE_HELPER_B(helper_pmaxub, FMAXUB) + +SSE_HELPER_W(helper_pminsw, FMINSW) +SSE_HELPER_W(helper_pmaxsw, FMAXSW) + +SSE_HELPER_Q(helper_pand, FAND) +SSE_HELPER_Q(helper_pandn, FANDN) +SSE_HELPER_Q(helper_por, FOR) +SSE_HELPER_Q(helper_pxor, FXOR) + +SSE_HELPER_B(helper_pcmpgtb, FCMPGTB) +SSE_HELPER_W(helper_pcmpgtw, FCMPGTW) +SSE_HELPER_L(helper_pcmpgtl, FCMPGTL) + +SSE_HELPER_B(helper_pcmpeqb, FCMPEQ) +SSE_HELPER_W(helper_pcmpeqw, FCMPEQ) +SSE_HELPER_L(helper_pcmpeql, FCMPEQ) + +SSE_HELPER_W(helper_pmullw, FMULLW) +#if SHIFT == 0 +SSE_HELPER_W(helper_pmulhrw, FMULHRW) +#endif +SSE_HELPER_W(helper_pmulhuw, FMULHUW) +SSE_HELPER_W(helper_pmulhw, FMULHW) + +SSE_HELPER_B(helper_pavgb, FAVG) +SSE_HELPER_W(helper_pavgw, FAVG) + +DEF_HELPER(void, glue(helper_pmuludq, SUFFIX) , (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmaddwd, SUFFIX) , (Reg *d, Reg *s)) + +DEF_HELPER(void, glue(helper_psadbw, SUFFIX) , (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_maskmov, SUFFIX) , (Reg *d, Reg *s, target_ulong a0)) +DEF_HELPER(void, glue(helper_movl_mm_T0, SUFFIX) , (Reg *d, uint32_t val)) +#ifdef TARGET_X86_64 +DEF_HELPER(void, glue(helper_movq_mm_T0, SUFFIX) , (Reg *d, uint64_t val)) +#endif + +#if SHIFT == 0 +DEF_HELPER(void, glue(helper_pshufw, SUFFIX) , (Reg *d, Reg *s, int order)) +#else +DEF_HELPER(void, helper_shufps, (Reg *d, Reg *s, int order)) +DEF_HELPER(void, helper_shufpd, (Reg *d, Reg *s, int order)) +DEF_HELPER(void, glue(helper_pshufd, SUFFIX) , (Reg *d, Reg *s, int order)) +DEF_HELPER(void, glue(helper_pshuflw, SUFFIX) , (Reg *d, Reg *s, int order)) +DEF_HELPER(void, glue(helper_pshufhw, SUFFIX) , (Reg *d, Reg *s, int order)) +#endif + +#if SHIFT == 1 +/* FPU ops */ +/* XXX: not accurate */ + +#define SSE_HELPER_S(name, F)\ + DEF_HELPER(void, helper_ ## name ## ps , (Reg *d, Reg *s)) \ + DEF_HELPER(void, helper_ ## name ## ss , (Reg *d, Reg *s)) \ + DEF_HELPER(void, helper_ ## name ## pd , (Reg *d, Reg *s)) \ + DEF_HELPER(void, helper_ ## name ## sd , (Reg *d, Reg *s)) + +SSE_HELPER_S(add, FPU_ADD) +SSE_HELPER_S(sub, FPU_SUB) +SSE_HELPER_S(mul, FPU_MUL) +SSE_HELPER_S(div, FPU_DIV) +SSE_HELPER_S(min, FPU_MIN) +SSE_HELPER_S(max, FPU_MAX) +SSE_HELPER_S(sqrt, FPU_SQRT) + + +DEF_HELPER(void, helper_cvtps2pd, (Reg *d, Reg *s)) +DEF_HELPER(void, helper_cvtpd2ps, (Reg *d, Reg *s)) +DEF_HELPER(void, helper_cvtss2sd, (Reg *d, Reg *s)) +DEF_HELPER(void, helper_cvtsd2ss, (Reg *d, Reg *s)) +DEF_HELPER(void, helper_cvtdq2ps, (Reg *d, Reg *s)) +DEF_HELPER(void, helper_cvtdq2pd, (Reg *d, Reg *s)) +DEF_HELPER(void, helper_cvtpi2ps, (XMMReg *d, MMXReg *s)) +DEF_HELPER(void, helper_cvtpi2pd, (XMMReg *d, MMXReg *s)) +DEF_HELPER(void, helper_cvtsi2ss, (XMMReg *d, uint32_t val)) +DEF_HELPER(void, helper_cvtsi2sd, (XMMReg *d, uint32_t val)) + +#ifdef TARGET_X86_64 +DEF_HELPER(void, helper_cvtsq2ss, (XMMReg *d, uint64_t val)) +DEF_HELPER(void, helper_cvtsq2sd, (XMMReg *d, uint64_t val)) +#endif + +DEF_HELPER(void, helper_cvtps2dq, (XMMReg *d, XMMReg *s)) +DEF_HELPER(void, helper_cvtpd2dq, (XMMReg *d, XMMReg *s)) +DEF_HELPER(void, helper_cvtps2pi, (MMXReg *d, XMMReg *s)) +DEF_HELPER(void, helper_cvtpd2pi, (MMXReg *d, XMMReg *s)) +DEF_HELPER(int32_t, helper_cvtss2si, (XMMReg *s)) +DEF_HELPER(int32_t, helper_cvtsd2si, (XMMReg *s)) +#ifdef TARGET_X86_64 +DEF_HELPER(int64_t, helper_cvtss2sq, (XMMReg *s)) +DEF_HELPER(int64_t, helper_cvtsd2sq, (XMMReg *s)) +#endif + +DEF_HELPER(void, helper_cvttps2dq, (XMMReg *d, XMMReg *s)) +DEF_HELPER(void, helper_cvttpd2dq, (XMMReg *d, XMMReg *s)) +DEF_HELPER(void, helper_cvttps2pi, (MMXReg *d, XMMReg *s)) +DEF_HELPER(void, helper_cvttpd2pi, (MMXReg *d, XMMReg *s)) +DEF_HELPER(int32_t, helper_cvttss2si, (XMMReg *s)) +DEF_HELPER(int32_t, helper_cvttsd2si, (XMMReg *s)) +#ifdef TARGET_X86_64 +DEF_HELPER(int64_t, helper_cvttss2sq, (XMMReg *s)) +DEF_HELPER(int64_t, helper_cvttsd2sq, (XMMReg *s)) +#endif + +DEF_HELPER(void, helper_rsqrtps, (XMMReg *d, XMMReg *s)) +DEF_HELPER(void, helper_rsqrtss, (XMMReg *d, XMMReg *s)) +DEF_HELPER(void, helper_rcpps, (XMMReg *d, XMMReg *s)) +DEF_HELPER(void, helper_rcpss, (XMMReg *d, XMMReg *s)) +DEF_HELPER(void, helper_haddps, (XMMReg *d, XMMReg *s)) +DEF_HELPER(void, helper_haddpd, (XMMReg *d, XMMReg *s)) +DEF_HELPER(void, helper_hsubps, (XMMReg *d, XMMReg *s)) +DEF_HELPER(void, helper_hsubpd, (XMMReg *d, XMMReg *s)) +DEF_HELPER(void, helper_addsubps, (XMMReg *d, XMMReg *s)) +DEF_HELPER(void, helper_addsubpd, (XMMReg *d, XMMReg *s)) + +#define SSE_HELPER_CMP(name, F)\ + DEF_HELPER(void, helper_ ## name ## ps , (Reg *d, Reg *s)) \ + DEF_HELPER(void, helper_ ## name ## ss , (Reg *d, Reg *s)) \ + DEF_HELPER(void, helper_ ## name ## pd , (Reg *d, Reg *s)) \ + DEF_HELPER(void, helper_ ## name ## sd , (Reg *d, Reg *s)) + +SSE_HELPER_CMP(cmpeq, FPU_CMPEQ) +SSE_HELPER_CMP(cmplt, FPU_CMPLT) +SSE_HELPER_CMP(cmple, FPU_CMPLE) +SSE_HELPER_CMP(cmpunord, FPU_CMPUNORD) +SSE_HELPER_CMP(cmpneq, FPU_CMPNEQ) +SSE_HELPER_CMP(cmpnlt, FPU_CMPNLT) +SSE_HELPER_CMP(cmpnle, FPU_CMPNLE) +SSE_HELPER_CMP(cmpord, FPU_CMPORD) + +DEF_HELPER(void, helper_ucomiss, (Reg *d, Reg *s)) +DEF_HELPER(void, helper_comiss, (Reg *d, Reg *s)) +DEF_HELPER(void, helper_ucomisd, (Reg *d, Reg *s)) +DEF_HELPER(void, helper_comisd, (Reg *d, Reg *s)) +DEF_HELPER(uint32_t, helper_movmskps, (Reg *s)) +DEF_HELPER(uint32_t, helper_movmskpd, (Reg *s)) +#endif + +DEF_HELPER(uint32_t, glue(helper_pmovmskb, SUFFIX), (Reg *s)) +DEF_HELPER(void, glue(helper_packsswb, SUFFIX) , (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_packuswb, SUFFIX) , (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_packssdw, SUFFIX) , (Reg *d, Reg *s)) +#define UNPCK_OP(base_name, base) \ + DEF_HELPER(void, glue(helper_punpck ## base_name ## bw, SUFFIX) , (Reg *d, Reg *s)) \ + DEF_HELPER(void, glue(helper_punpck ## base_name ## wd, SUFFIX) , (Reg *d, Reg *s)) \ + DEF_HELPER(void, glue(helper_punpck ## base_name ## dq, SUFFIX) , (Reg *d, Reg *s)) + +UNPCK_OP(l, 0) +UNPCK_OP(h, 1) + +#if SHIFT == 1 +DEF_HELPER(void, glue(helper_punpcklqdq, SUFFIX) , (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_punpckhqdq, SUFFIX) , (Reg *d, Reg *s)) +#endif + +/* 3DNow! float ops */ +#if SHIFT == 0 +DEF_HELPER(void, helper_pi2fd, (MMXReg *d, MMXReg *s)) +DEF_HELPER(void, helper_pi2fw, (MMXReg *d, MMXReg *s)) +DEF_HELPER(void, helper_pf2id, (MMXReg *d, MMXReg *s)) +DEF_HELPER(void, helper_pf2iw, (MMXReg *d, MMXReg *s)) +DEF_HELPER(void, helper_pfacc, (MMXReg *d, MMXReg *s)) +DEF_HELPER(void, helper_pfadd, (MMXReg *d, MMXReg *s)) +DEF_HELPER(void, helper_pfcmpeq, (MMXReg *d, MMXReg *s)) +DEF_HELPER(void, helper_pfcmpge, (MMXReg *d, MMXReg *s)) +DEF_HELPER(void, helper_pfcmpgt, (MMXReg *d, MMXReg *s)) +DEF_HELPER(void, helper_pfmax, (MMXReg *d, MMXReg *s)) +DEF_HELPER(void, helper_pfmin, (MMXReg *d, MMXReg *s)) +DEF_HELPER(void, helper_pfmul, (MMXReg *d, MMXReg *s)) +DEF_HELPER(void, helper_pfnacc, (MMXReg *d, MMXReg *s)) +DEF_HELPER(void, helper_pfpnacc, (MMXReg *d, MMXReg *s)) +DEF_HELPER(void, helper_pfrcp, (MMXReg *d, MMXReg *s)) +DEF_HELPER(void, helper_pfrsqrt, (MMXReg *d, MMXReg *s)) +DEF_HELPER(void, helper_pfsub, (MMXReg *d, MMXReg *s)) +DEF_HELPER(void, helper_pfsubr, (MMXReg *d, MMXReg *s)) +DEF_HELPER(void, helper_pswapd, (MMXReg *d, MMXReg *s)) +#endif + +/* SSSE3 op helpers */ +DEF_HELPER(void, glue(helper_phaddw, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_phaddd, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_phaddsw, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_phsubw, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_phsubd, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_phsubsw, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pabsb, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pabsw, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pabsd, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmaddubsw, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmulhrsw, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pshufb, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_psignb, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_psignw, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_psignd, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_palignr, SUFFIX), (Reg *d, Reg *s, int32_t shift)) + +/* SSE4.1 op helpers */ +#if SHIFT == 1 +DEF_HELPER(void, glue(helper_pblendvb, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_blendvps, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_blendvpd, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_ptest, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmovsxbw, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmovsxbd, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmovsxbq, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmovsxwd, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmovsxwq, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmovsxdq, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmovzxbw, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmovzxbd, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmovzxbq, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmovzxwd, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmovzxwq, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmovzxdq, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmuldq, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pcmpeqq, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_packusdw, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pminsb, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pminsd, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pminuw, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pminud, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmaxsb, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmaxsd, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmaxuw, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmaxud, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pmulld, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_phminposuw, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_roundps, SUFFIX), (Reg *d, Reg *s, uint32_t mode)) +DEF_HELPER(void, glue(helper_roundpd, SUFFIX), (Reg *d, Reg *s, uint32_t mode)) +DEF_HELPER(void, glue(helper_roundss, SUFFIX), (Reg *d, Reg *s, uint32_t mode)) +DEF_HELPER(void, glue(helper_roundsd, SUFFIX), (Reg *d, Reg *s, uint32_t mode)) +DEF_HELPER(void, glue(helper_blendps, SUFFIX), (Reg *d, Reg *s, uint32_t imm)) +DEF_HELPER(void, glue(helper_blendpd, SUFFIX), (Reg *d, Reg *s, uint32_t imm)) +DEF_HELPER(void, glue(helper_pblendw, SUFFIX), (Reg *d, Reg *s, uint32_t imm)) +DEF_HELPER(void, glue(helper_dpps, SUFFIX), (Reg *d, Reg *s, uint32_t mask)) +DEF_HELPER(void, glue(helper_dppd, SUFFIX), (Reg *d, Reg *s, uint32_t mask)) +DEF_HELPER(void, glue(helper_mpsadbw, SUFFIX), (Reg *d, Reg *s, uint32_t off)) +#endif + +/* SSE4.2 op helpers */ +#if SHIFT == 1 +DEF_HELPER(void, glue(helper_pcmpgtq, SUFFIX), (Reg *d, Reg *s)) +DEF_HELPER(void, glue(helper_pcmpestri, SUFFIX), (Reg *d, Reg *s, uint32_t ctl)) +DEF_HELPER(void, glue(helper_pcmpestrm, SUFFIX), (Reg *d, Reg *s, uint32_t ctl)) +DEF_HELPER(void, glue(helper_pcmpistri, SUFFIX), (Reg *d, Reg *s, uint32_t ctl)) +DEF_HELPER(void, glue(helper_pcmpistrm, SUFFIX), (Reg *d, Reg *s, uint32_t ctl)) +DEF_HELPER(target_ulong, helper_crc32, + (uint32_t crc1, target_ulong msg, uint32_t len)) +DEF_HELPER(target_ulong, helper_popcnt, (target_ulong n, uint32_t type)) +#endif + +#undef SHIFT +#undef Reg +#undef SUFFIX + +#undef SSE_HELPER_B +#undef SSE_HELPER_W +#undef SSE_HELPER_L +#undef SSE_HELPER_Q +#undef SSE_HELPER_S +#undef SSE_HELPER_CMP +#undef UNPCK_OP diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/ops_template.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/ops_template.h --- qemu-0.9.1/target-i386/ops_template.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-i386/ops_template.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,597 +0,0 @@ -/* - * i386 micro operations (included several times to generate - * different operand sizes) - * - * Copyright (c) 2003 Fabrice Bellard - * - * 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 - */ -#define DATA_BITS (1 << (3 + SHIFT)) -#define SHIFT_MASK (DATA_BITS - 1) -#define SIGN_MASK (((target_ulong)1) << (DATA_BITS - 1)) -#if DATA_BITS <= 32 -#define SHIFT1_MASK 0x1f -#else -#define SHIFT1_MASK 0x3f -#endif - -#if DATA_BITS == 8 -#define SUFFIX b -#define DATA_TYPE uint8_t -#define DATA_STYPE int8_t -#define DATA_MASK 0xff -#elif DATA_BITS == 16 -#define SUFFIX w -#define DATA_TYPE uint16_t -#define DATA_STYPE int16_t -#define DATA_MASK 0xffff -#elif DATA_BITS == 32 -#define SUFFIX l -#define DATA_TYPE uint32_t -#define DATA_STYPE int32_t -#define DATA_MASK 0xffffffff -#elif DATA_BITS == 64 -#define SUFFIX q -#define DATA_TYPE uint64_t -#define DATA_STYPE int64_t -#define DATA_MASK 0xffffffffffffffffULL -#else -#error unhandled operand size -#endif - -/* dynamic flags computation */ - -static int glue(compute_all_add, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - target_long src1, src2; - src1 = CC_SRC; - src2 = CC_DST - CC_SRC; - cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; - return cf | pf | af | zf | sf | of; -} - -static int glue(compute_c_add, SUFFIX)(void) -{ - int cf; - target_long src1; - src1 = CC_SRC; - cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1; - return cf; -} - -static int glue(compute_all_adc, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - target_long src1, src2; - src1 = CC_SRC; - src2 = CC_DST - CC_SRC - 1; - cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; - return cf | pf | af | zf | sf | of; -} - -static int glue(compute_c_adc, SUFFIX)(void) -{ - int cf; - target_long src1; - src1 = CC_SRC; - cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1; - return cf; -} - -static int glue(compute_all_sub, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - target_long src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; - return cf | pf | af | zf | sf | of; -} - -static int glue(compute_c_sub, SUFFIX)(void) -{ - int cf; - target_long src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; - return cf; -} - -static int glue(compute_all_sbb, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - target_long src1, src2; - src1 = CC_DST + CC_SRC + 1; - src2 = CC_SRC; - cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; - return cf | pf | af | zf | sf | of; -} - -static int glue(compute_c_sbb, SUFFIX)(void) -{ - int cf; - target_long src1, src2; - src1 = CC_DST + CC_SRC + 1; - src2 = CC_SRC; - cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; - return cf; -} - -static int glue(compute_all_logic, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - cf = 0; - pf = parity_table[(uint8_t)CC_DST]; - af = 0; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = 0; - return cf | pf | af | zf | sf | of; -} - -static int glue(compute_c_logic, SUFFIX)(void) -{ - return 0; -} - -static int glue(compute_all_inc, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - target_long src1, src2; - src1 = CC_DST - 1; - src2 = 1; - cf = CC_SRC; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = ((CC_DST & DATA_MASK) == SIGN_MASK) << 11; - return cf | pf | af | zf | sf | of; -} - -#if DATA_BITS == 32 -static int glue(compute_c_inc, SUFFIX)(void) -{ - return CC_SRC; -} -#endif - -static int glue(compute_all_dec, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - target_long src1, src2; - src1 = CC_DST + 1; - src2 = 1; - cf = CC_SRC; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = ((CC_DST & DATA_MASK) == ((target_ulong)SIGN_MASK - 1)) << 11; - return cf | pf | af | zf | sf | of; -} - -static int glue(compute_all_shl, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - cf = (CC_SRC >> (DATA_BITS - 1)) & CC_C; - pf = parity_table[(uint8_t)CC_DST]; - af = 0; /* undefined */ - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - /* of is defined if shift count == 1 */ - of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; - return cf | pf | af | zf | sf | of; -} - -static int glue(compute_c_shl, SUFFIX)(void) -{ - return (CC_SRC >> (DATA_BITS - 1)) & CC_C; -} - -#if DATA_BITS == 32 -static int glue(compute_c_sar, SUFFIX)(void) -{ - return CC_SRC & 1; -} -#endif - -static int glue(compute_all_sar, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - cf = CC_SRC & 1; - pf = parity_table[(uint8_t)CC_DST]; - af = 0; /* undefined */ - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - /* of is defined if shift count == 1 */ - of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; - return cf | pf | af | zf | sf | of; -} - -#if DATA_BITS == 32 -static int glue(compute_c_mul, SUFFIX)(void) -{ - int cf; - cf = (CC_SRC != 0); - return cf; -} -#endif - -/* NOTE: we compute the flags like the P4. On olders CPUs, only OF and - CF are modified and it is slower to do that. */ -static int glue(compute_all_mul, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - cf = (CC_SRC != 0); - pf = parity_table[(uint8_t)CC_DST]; - af = 0; /* undefined */ - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = cf << 11; - return cf | pf | af | zf | sf | of; -} - -/* various optimized jumps cases */ - -void OPPROTO glue(op_jb_sub, SUFFIX)(void) -{ - target_long src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - - if ((DATA_TYPE)src1 < (DATA_TYPE)src2) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO glue(op_jz_sub, SUFFIX)(void) -{ - if ((DATA_TYPE)CC_DST == 0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO glue(op_jnz_sub, SUFFIX)(void) -{ - if ((DATA_TYPE)CC_DST != 0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO glue(op_jbe_sub, SUFFIX)(void) -{ - target_long src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - - if ((DATA_TYPE)src1 <= (DATA_TYPE)src2) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO glue(op_js_sub, SUFFIX)(void) -{ - if (CC_DST & SIGN_MASK) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO glue(op_jl_sub, SUFFIX)(void) -{ - target_long src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - - if ((DATA_STYPE)src1 < (DATA_STYPE)src2) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO glue(op_jle_sub, SUFFIX)(void) -{ - target_long src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - - if ((DATA_STYPE)src1 <= (DATA_STYPE)src2) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -/* oldies */ - -#if DATA_BITS >= 16 - -void OPPROTO glue(op_loopnz, SUFFIX)(void) -{ - if ((DATA_TYPE)ECX != 0 && !(T0 & CC_Z)) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO glue(op_loopz, SUFFIX)(void) -{ - if ((DATA_TYPE)ECX != 0 && (T0 & CC_Z)) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO glue(op_jz_ecx, SUFFIX)(void) -{ - if ((DATA_TYPE)ECX == 0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO glue(op_jnz_ecx, SUFFIX)(void) -{ - if ((DATA_TYPE)ECX != 0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -#endif - -/* various optimized set cases */ - -void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void) -{ - target_long src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - - T0 = ((DATA_TYPE)src1 < (DATA_TYPE)src2); -} - -void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void) -{ - T0 = ((DATA_TYPE)CC_DST == 0); -} - -void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void) -{ - target_long src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - - T0 = ((DATA_TYPE)src1 <= (DATA_TYPE)src2); -} - -void OPPROTO glue(op_sets_T0_sub, SUFFIX)(void) -{ - T0 = lshift(CC_DST, -(DATA_BITS - 1)) & 1; -} - -void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void) -{ - target_long src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - - T0 = ((DATA_STYPE)src1 < (DATA_STYPE)src2); -} - -void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void) -{ - target_long src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - - T0 = ((DATA_STYPE)src1 <= (DATA_STYPE)src2); -} - -/* shifts */ - -void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void) -{ - int count; - count = T1 & SHIFT1_MASK; - T0 = T0 << count; - FORCE_RET(); -} - -void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void) -{ - int count; - count = T1 & SHIFT1_MASK; - T0 &= DATA_MASK; - T0 = T0 >> count; - FORCE_RET(); -} - -void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void) -{ - int count; - target_long src; - - count = T1 & SHIFT1_MASK; - src = (DATA_STYPE)T0; - T0 = src >> count; - FORCE_RET(); -} - -#undef MEM_WRITE -#include "ops_template_mem.h" - -#define MEM_WRITE 0 -#include "ops_template_mem.h" - -#if !defined(CONFIG_USER_ONLY) -#define MEM_WRITE 1 -#include "ops_template_mem.h" - -#define MEM_WRITE 2 -#include "ops_template_mem.h" -#endif - -/* bit operations */ -#if DATA_BITS >= 16 - -void OPPROTO glue(glue(op_bt, SUFFIX), _T0_T1_cc)(void) -{ - int count; - count = T1 & SHIFT_MASK; - CC_SRC = T0 >> count; -} - -void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void) -{ - int count; - count = T1 & SHIFT_MASK; - T1 = T0 >> count; - T0 |= (((target_long)1) << count); -} - -void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void) -{ - int count; - count = T1 & SHIFT_MASK; - T1 = T0 >> count; - T0 &= ~(((target_long)1) << count); -} - -void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void) -{ - int count; - count = T1 & SHIFT_MASK; - T1 = T0 >> count; - T0 ^= (((target_long)1) << count); -} - -void OPPROTO glue(glue(op_add_bit, SUFFIX), _A0_T1)(void) -{ - A0 += ((DATA_STYPE)T1 >> (3 + SHIFT)) << SHIFT; -} - -void OPPROTO glue(glue(op_bsf, SUFFIX), _T0_cc)(void) -{ - int count; - target_long res; - - res = T0 & DATA_MASK; - if (res != 0) { - count = 0; - while ((res & 1) == 0) { - count++; - res >>= 1; - } - T1 = count; - CC_DST = 1; /* ZF = 0 */ - } else { - CC_DST = 0; /* ZF = 1 */ - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void) -{ - int count; - target_long res; - - res = T0 & DATA_MASK; - if (res != 0) { - count = DATA_BITS - 1; - while ((res & SIGN_MASK) == 0) { - count--; - res <<= 1; - } - T1 = count; - CC_DST = 1; /* ZF = 0 */ - } else { - CC_DST = 0; /* ZF = 1 */ - } - FORCE_RET(); -} - -#endif - -#if DATA_BITS == 32 -void OPPROTO op_update_bt_cc(void) -{ - CC_SRC = T1; -} -#endif - -/* string operations */ - -void OPPROTO glue(op_movl_T0_Dshift, SUFFIX)(void) -{ - T0 = DF << SHIFT; -} - -/* port I/O */ -#if DATA_BITS <= 32 -void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void) -{ - glue(cpu_out, SUFFIX)(env, T0, T1 & DATA_MASK); -} - -void OPPROTO glue(glue(op_in, SUFFIX), _T0_T1)(void) -{ - T1 = glue(cpu_in, SUFFIX)(env, T0); -} - -void OPPROTO glue(glue(op_in, SUFFIX), _DX_T0)(void) -{ - T0 = glue(cpu_in, SUFFIX)(env, EDX & 0xffff); -} - -void OPPROTO glue(glue(op_out, SUFFIX), _DX_T0)(void) -{ - glue(cpu_out, SUFFIX)(env, EDX & 0xffff, T0); -} - -void OPPROTO glue(glue(op_check_io, SUFFIX), _T0)(void) -{ - glue(glue(check_io, SUFFIX), _T0)(); -} - -void OPPROTO glue(glue(op_check_io, SUFFIX), _DX)(void) -{ - glue(glue(check_io, SUFFIX), _DX)(); -} -#endif - -#undef DATA_BITS -#undef SHIFT_MASK -#undef SHIFT1_MASK -#undef SIGN_MASK -#undef DATA_TYPE -#undef DATA_STYPE -#undef DATA_MASK -#undef SUFFIX diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/ops_template_mem.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/ops_template_mem.h --- qemu-0.9.1/target-i386/ops_template_mem.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-i386/ops_template_mem.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,483 +0,0 @@ -/* - * i386 micro operations (included several times to generate - * different operand sizes) - * - * Copyright (c) 2003 Fabrice Bellard - * - * 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 - */ -#ifdef MEM_WRITE - -#if MEM_WRITE == 0 - -#if DATA_BITS == 8 -#define MEM_SUFFIX b_raw -#elif DATA_BITS == 16 -#define MEM_SUFFIX w_raw -#elif DATA_BITS == 32 -#define MEM_SUFFIX l_raw -#elif DATA_BITS == 64 -#define MEM_SUFFIX q_raw -#endif - -#elif MEM_WRITE == 1 - -#if DATA_BITS == 8 -#define MEM_SUFFIX b_kernel -#elif DATA_BITS == 16 -#define MEM_SUFFIX w_kernel -#elif DATA_BITS == 32 -#define MEM_SUFFIX l_kernel -#elif DATA_BITS == 64 -#define MEM_SUFFIX q_kernel -#endif - -#elif MEM_WRITE == 2 - -#if DATA_BITS == 8 -#define MEM_SUFFIX b_user -#elif DATA_BITS == 16 -#define MEM_SUFFIX w_user -#elif DATA_BITS == 32 -#define MEM_SUFFIX l_user -#elif DATA_BITS == 64 -#define MEM_SUFFIX q_user -#endif - -#else - -#error invalid MEM_WRITE - -#endif - -#else - -#define MEM_SUFFIX SUFFIX - -#endif - -void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int count; - target_long src; - - if (T1 & SHIFT1_MASK) { - count = T1 & SHIFT_MASK; - src = T0; - T0 &= DATA_MASK; - T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#else - /* gcc 3.2 workaround. This is really a bug in gcc. */ - asm volatile("" : : "r" (T0)); -#endif - CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) | - (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | - (T0 & CC_C); - CC_OP = CC_OP_EFLAGS; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int count; - target_long src; - - if (T1 & SHIFT1_MASK) { - count = T1 & SHIFT_MASK; - src = T0; - T0 &= DATA_MASK; - T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#else - /* gcc 3.2 workaround. This is really a bug in gcc. */ - asm volatile("" : : "r" (T0)); -#endif - CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) | - (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | - ((T0 >> (DATA_BITS - 1)) & CC_C); - CC_OP = CC_OP_EFLAGS; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1)(void) -{ - int count; - count = T1 & SHIFT_MASK; - if (count) { - T0 &= DATA_MASK; - T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1)(void) -{ - int count; - count = T1 & SHIFT_MASK; - if (count) { - T0 &= DATA_MASK; - T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int count, eflags; - target_ulong src; - target_long res; - - count = T1 & SHIFT1_MASK; -#if DATA_BITS == 16 - count = rclw_table[count]; -#elif DATA_BITS == 8 - count = rclb_table[count]; -#endif - if (count) { - eflags = cc_table[CC_OP].compute_all(); - T0 &= DATA_MASK; - src = T0; - res = (T0 << count) | ((target_ulong)(eflags & CC_C) << (count - 1)); - if (count > 1) - res |= T0 >> (DATA_BITS + 1 - count); - T0 = res; -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - CC_SRC = (eflags & ~(CC_C | CC_O)) | - (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | - ((src >> (DATA_BITS - count)) & CC_C); - CC_OP = CC_OP_EFLAGS; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int count, eflags; - target_ulong src; - target_long res; - - count = T1 & SHIFT1_MASK; -#if DATA_BITS == 16 - count = rclw_table[count]; -#elif DATA_BITS == 8 - count = rclb_table[count]; -#endif - if (count) { - eflags = cc_table[CC_OP].compute_all(); - T0 &= DATA_MASK; - src = T0; - res = (T0 >> count) | ((target_ulong)(eflags & CC_C) << (DATA_BITS - count)); - if (count > 1) - res |= T0 << (DATA_BITS + 1 - count); - T0 = res; -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - CC_SRC = (eflags & ~(CC_C | CC_O)) | - (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | - ((src >> (count - 1)) & CC_C); - CC_OP = CC_OP_EFLAGS; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_shl, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int count; - target_long src; - - count = T1 & SHIFT1_MASK; - if (count) { - src = (DATA_TYPE)T0 << (count - 1); - T0 = T0 << count; -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - CC_SRC = src; - CC_DST = T0; - CC_OP = CC_OP_SHLB + SHIFT; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_shr, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int count; - target_long src; - - count = T1 & SHIFT1_MASK; - if (count) { - T0 &= DATA_MASK; - src = T0 >> (count - 1); - T0 = T0 >> count; -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - CC_SRC = src; - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_sar, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int count; - target_long src; - - count = T1 & SHIFT1_MASK; - if (count) { - src = (DATA_STYPE)T0; - T0 = src >> count; - src = src >> (count - 1); -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - CC_SRC = src; - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} - -#if DATA_BITS == 16 -/* XXX: overflow flag might be incorrect in some cases in shldw */ -void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void) -{ - int count; - unsigned int res, tmp; - count = PARAM1; - T1 &= 0xffff; - res = T1 | (T0 << 16); - tmp = res >> (32 - count); - res <<= count; - if (count > 16) - res |= T1 << (count - 16); - T0 = res >> 16; -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - CC_SRC = tmp; - CC_DST = T0; -} - -void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void) -{ - int count; - unsigned int res, tmp; - count = ECX & 0x1f; - if (count) { - T1 &= 0xffff; - res = T1 | (T0 << 16); - tmp = res >> (32 - count); - res <<= count; - if (count > 16) - res |= T1 << (count - 16); - T0 = res >> 16; -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - CC_SRC = tmp; - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void) -{ - int count; - unsigned int res, tmp; - - count = PARAM1; - res = (T0 & 0xffff) | (T1 << 16); - tmp = res >> (count - 1); - res >>= count; - if (count > 16) - res |= T1 << (32 - count); - T0 = res; -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - CC_SRC = tmp; - CC_DST = T0; -} - - -void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void) -{ - int count; - unsigned int res, tmp; - - count = ECX & 0x1f; - if (count) { - res = (T0 & 0xffff) | (T1 << 16); - tmp = res >> (count - 1); - res >>= count; - if (count > 16) - res |= T1 << (32 - count); - T0 = res; -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - CC_SRC = tmp; - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} -#endif - -#if DATA_BITS >= 32 -void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void) -{ - int count; - target_long tmp; - - count = PARAM1; - T0 &= DATA_MASK; - T1 &= DATA_MASK; - tmp = T0 << (count - 1); - T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - CC_SRC = tmp; - CC_DST = T0; -} - -void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void) -{ - int count; - target_long tmp; - - count = ECX & SHIFT1_MASK; - if (count) { - T0 &= DATA_MASK; - T1 &= DATA_MASK; - tmp = T0 << (count - 1); - T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - CC_SRC = tmp; - CC_DST = T0; - CC_OP = CC_OP_SHLB + SHIFT; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void) -{ - int count; - target_long tmp; - - count = PARAM1; - T0 &= DATA_MASK; - T1 &= DATA_MASK; - tmp = T0 >> (count - 1); - T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - CC_SRC = tmp; - CC_DST = T0; -} - - -void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void) -{ - int count; - target_long tmp; - - count = ECX & SHIFT1_MASK; - if (count) { - T0 &= DATA_MASK; - T1 &= DATA_MASK; - tmp = T0 >> (count - 1); - T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - CC_SRC = tmp; - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} -#endif - -/* carry add/sub (we only need to set CC_OP differently) */ - -void OPPROTO glue(glue(op_adc, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int cf; - cf = cc_table[CC_OP].compute_c(); - T0 = T0 + T1 + cf; -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - CC_SRC = T1; - CC_DST = T0; - CC_OP = CC_OP_ADDB + SHIFT + cf * 4; -} - -void OPPROTO glue(glue(op_sbb, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int cf; - cf = cc_table[CC_OP].compute_c(); - T0 = T0 - T1 - cf; -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - CC_SRC = T1; - CC_DST = T0; - CC_OP = CC_OP_SUBB + SHIFT + cf * 4; -} - -void OPPROTO glue(glue(op_cmpxchg, MEM_SUFFIX), _T0_T1_EAX_cc)(void) -{ - target_ulong src, dst; - - src = T0; - dst = EAX - T0; - if ((DATA_TYPE)dst == 0) { - T0 = T1; -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - } else { - EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK); - } - CC_SRC = src; - CC_DST = dst; - FORCE_RET(); -} - -#undef MEM_SUFFIX -#undef MEM_WRITE diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/svm.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/svm.h --- qemu-0.9.1/target-i386/svm.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-i386/svm.h 2008-06-04 18:02:19.000000000 +0100 @@ -1,92 +1,6 @@ #ifndef __SVM_H #define __SVM_H -enum { - /* We shift all the intercept bits so we can OR them with the - TB flags later on */ - INTERCEPT_INTR = HF_HIF_SHIFT, - INTERCEPT_NMI, - INTERCEPT_SMI, - INTERCEPT_INIT, - INTERCEPT_VINTR, - INTERCEPT_SELECTIVE_CR0, - INTERCEPT_STORE_IDTR, - INTERCEPT_STORE_GDTR, - INTERCEPT_STORE_LDTR, - INTERCEPT_STORE_TR, - INTERCEPT_LOAD_IDTR, - INTERCEPT_LOAD_GDTR, - INTERCEPT_LOAD_LDTR, - INTERCEPT_LOAD_TR, - INTERCEPT_RDTSC, - INTERCEPT_RDPMC, - INTERCEPT_PUSHF, - INTERCEPT_POPF, - INTERCEPT_CPUID, - INTERCEPT_RSM, - INTERCEPT_IRET, - INTERCEPT_INTn, - INTERCEPT_INVD, - INTERCEPT_PAUSE, - INTERCEPT_HLT, - INTERCEPT_INVLPG, - INTERCEPT_INVLPGA, - INTERCEPT_IOIO_PROT, - INTERCEPT_MSR_PROT, - INTERCEPT_TASK_SWITCH, - INTERCEPT_FERR_FREEZE, - INTERCEPT_SHUTDOWN, - INTERCEPT_VMRUN, - INTERCEPT_VMMCALL, - INTERCEPT_VMLOAD, - INTERCEPT_VMSAVE, - INTERCEPT_STGI, - INTERCEPT_CLGI, - INTERCEPT_SKINIT, - INTERCEPT_RDTSCP, - INTERCEPT_ICEBP, - INTERCEPT_WBINVD, -}; -/* This is not really an intercept but rather a placeholder to - show that we are in an SVM (just like a hidden flag, but keeps the - TBs clean) */ -#define INTERCEPT_SVM 63 -#define INTERCEPT_SVM_MASK (1ULL << INTERCEPT_SVM) - -struct __attribute__ ((__packed__)) vmcb_control_area { - uint16_t intercept_cr_read; - uint16_t intercept_cr_write; - uint16_t intercept_dr_read; - uint16_t intercept_dr_write; - uint32_t intercept_exceptions; - uint64_t intercept; - uint8_t reserved_1[44]; - uint64_t iopm_base_pa; - uint64_t msrpm_base_pa; - uint64_t tsc_offset; - uint32_t asid; - uint8_t tlb_ctl; - uint8_t reserved_2[3]; - uint32_t int_ctl; - uint32_t int_vector; - uint32_t int_state; - uint8_t reserved_3[4]; - uint32_t exit_code; - uint32_t exit_code_hi; - uint64_t exit_info_1; - uint64_t exit_info_2; - uint32_t exit_int_info; - uint32_t exit_int_info_err; - uint64_t nested_ctl; - uint8_t reserved_4[16]; - uint32_t event_inj; - uint32_t event_inj_err; - uint64_t nested_cr3; - uint64_t lbr_ctl; - uint8_t reserved_5[832]; -}; - - #define TLB_CONTROL_DO_NOTHING 0 #define TLB_CONTROL_FLUSH_ALL_ASID 1 @@ -117,104 +31,6 @@ #define SVM_IOIO_SIZE_MASK (7 << SVM_IOIO_SIZE_SHIFT) #define SVM_IOIO_ASIZE_MASK (7 << SVM_IOIO_ASIZE_SHIFT) -struct __attribute__ ((__packed__)) vmcb_seg { - uint16_t selector; - uint16_t attrib; - uint32_t limit; - uint64_t base; -}; - -struct __attribute__ ((__packed__)) vmcb_save_area { - struct vmcb_seg es; - struct vmcb_seg cs; - struct vmcb_seg ss; - struct vmcb_seg ds; - struct vmcb_seg fs; - struct vmcb_seg gs; - struct vmcb_seg gdtr; - struct vmcb_seg ldtr; - struct vmcb_seg idtr; - struct vmcb_seg tr; - uint8_t reserved_1[43]; - uint8_t cpl; - uint8_t reserved_2[4]; - uint64_t efer; - uint8_t reserved_3[112]; - uint64_t cr4; - uint64_t cr3; - uint64_t cr0; - uint64_t dr7; - uint64_t dr6; - uint64_t rflags; - uint64_t rip; - uint8_t reserved_4[88]; - uint64_t rsp; - uint8_t reserved_5[24]; - uint64_t rax; - uint64_t star; - uint64_t lstar; - uint64_t cstar; - uint64_t sfmask; - uint64_t kernel_gs_base; - uint64_t sysenter_cs; - uint64_t sysenter_esp; - uint64_t sysenter_eip; - uint64_t cr2; - /* qemu: cr8 added to reuse this as hsave */ - uint64_t cr8; - uint8_t reserved_6[32 - 8]; /* originally 32 */ - uint64_t g_pat; - uint64_t dbgctl; - uint64_t br_from; - uint64_t br_to; - uint64_t last_excp_from; - uint64_t last_excp_to; -}; - -struct __attribute__ ((__packed__)) vmcb { - struct vmcb_control_area control; - struct vmcb_save_area save; -}; - -#define SVM_CPUID_FEATURE_SHIFT 2 -#define SVM_CPUID_FUNC 0x8000000a - -#define MSR_EFER_SVME_MASK (1ULL << 12) - -#define SVM_SELECTOR_S_SHIFT 4 -#define SVM_SELECTOR_DPL_SHIFT 5 -#define SVM_SELECTOR_P_SHIFT 7 -#define SVM_SELECTOR_AVL_SHIFT 8 -#define SVM_SELECTOR_L_SHIFT 9 -#define SVM_SELECTOR_DB_SHIFT 10 -#define SVM_SELECTOR_G_SHIFT 11 - -#define SVM_SELECTOR_TYPE_MASK (0xf) -#define SVM_SELECTOR_S_MASK (1 << SVM_SELECTOR_S_SHIFT) -#define SVM_SELECTOR_DPL_MASK (3 << SVM_SELECTOR_DPL_SHIFT) -#define SVM_SELECTOR_P_MASK (1 << SVM_SELECTOR_P_SHIFT) -#define SVM_SELECTOR_AVL_MASK (1 << SVM_SELECTOR_AVL_SHIFT) -#define SVM_SELECTOR_L_MASK (1 << SVM_SELECTOR_L_SHIFT) -#define SVM_SELECTOR_DB_MASK (1 << SVM_SELECTOR_DB_SHIFT) -#define SVM_SELECTOR_G_MASK (1 << SVM_SELECTOR_G_SHIFT) - -#define SVM_SELECTOR_WRITE_MASK (1 << 1) -#define SVM_SELECTOR_READ_MASK SVM_SELECTOR_WRITE_MASK -#define SVM_SELECTOR_CODE_MASK (1 << 3) - -#define INTERCEPT_CR0_MASK 1 -#define INTERCEPT_CR3_MASK (1 << 3) -#define INTERCEPT_CR4_MASK (1 << 4) - -#define INTERCEPT_DR0_MASK 1 -#define INTERCEPT_DR1_MASK (1 << 1) -#define INTERCEPT_DR2_MASK (1 << 2) -#define INTERCEPT_DR3_MASK (1 << 3) -#define INTERCEPT_DR4_MASK (1 << 4) -#define INTERCEPT_DR5_MASK (1 << 5) -#define INTERCEPT_DR6_MASK (1 << 6) -#define INTERCEPT_DR7_MASK (1 << 7) - #define SVM_EVTINJ_VEC_MASK 0xff #define SVM_EVTINJ_TYPE_SHIFT 8 @@ -314,45 +130,93 @@ #define SVM_CR0_SELECTIVE_MASK (1 << 3 | 1) /* TS and MP */ -#define SVM_VMLOAD ".byte 0x0f, 0x01, 0xda" -#define SVM_VMRUN ".byte 0x0f, 0x01, 0xd8" -#define SVM_VMSAVE ".byte 0x0f, 0x01, 0xdb" -#define SVM_CLGI ".byte 0x0f, 0x01, 0xdd" -#define SVM_STGI ".byte 0x0f, 0x01, 0xdc" -#define SVM_INVLPGA ".byte 0x0f, 0x01, 0xdf" - -/* function references */ - -void helper_stgi(); -void vmexit(uint64_t exit_code, uint64_t exit_info_1); -int svm_check_intercept_param(uint32_t type, uint64_t param); -static inline int svm_check_intercept(unsigned int type) { - return svm_check_intercept_param(type, 0); -} - - -#define INTERCEPTED(mask) (env->intercept & mask) -#define INTERCEPTEDw(var, mask) (env->intercept ## var & mask) -#define INTERCEPTEDl(var, mask) (env->intercept ## var & mask) - -#define SVM_LOAD_SEG(addr, seg_index, seg) \ - cpu_x86_load_seg_cache(env, \ - R_##seg_index, \ - lduw_phys(addr + offsetof(struct vmcb, save.seg.selector)),\ - ldq_phys(addr + offsetof(struct vmcb, save.seg.base)),\ - ldl_phys(addr + offsetof(struct vmcb, save.seg.limit)),\ - vmcb2cpu_attrib(lduw_phys(addr + offsetof(struct vmcb, save.seg.attrib)), ldq_phys(addr + offsetof(struct vmcb, save.seg.base)), ldl_phys(addr + offsetof(struct vmcb, save.seg.limit)))) - -#define SVM_LOAD_SEG2(addr, seg_qemu, seg_vmcb) \ - env->seg_qemu.selector = lduw_phys(addr + offsetof(struct vmcb, save.seg_vmcb.selector)); \ - env->seg_qemu.base = ldq_phys(addr + offsetof(struct vmcb, save.seg_vmcb.base)); \ - env->seg_qemu.limit = ldl_phys(addr + offsetof(struct vmcb, save.seg_vmcb.limit)); \ - env->seg_qemu.flags = vmcb2cpu_attrib(lduw_phys(addr + offsetof(struct vmcb, save.seg_vmcb.attrib)), env->seg_qemu.base, env->seg_qemu.limit) - -#define SVM_SAVE_SEG(addr, seg_qemu, seg_vmcb) \ - stw_phys(addr + offsetof(struct vmcb, save.seg_vmcb.selector), env->seg_qemu.selector); \ - stq_phys(addr + offsetof(struct vmcb, save.seg_vmcb.base), env->seg_qemu.base); \ - stl_phys(addr + offsetof(struct vmcb, save.seg_vmcb.limit), env->seg_qemu.limit); \ - stw_phys(addr + offsetof(struct vmcb, save.seg_vmcb.attrib), cpu2vmcb_attrib(env->seg_qemu.flags)) +struct __attribute__ ((__packed__)) vmcb_control_area { + uint16_t intercept_cr_read; + uint16_t intercept_cr_write; + uint16_t intercept_dr_read; + uint16_t intercept_dr_write; + uint32_t intercept_exceptions; + uint64_t intercept; + uint8_t reserved_1[44]; + uint64_t iopm_base_pa; + uint64_t msrpm_base_pa; + uint64_t tsc_offset; + uint32_t asid; + uint8_t tlb_ctl; + uint8_t reserved_2[3]; + uint32_t int_ctl; + uint32_t int_vector; + uint32_t int_state; + uint8_t reserved_3[4]; + uint64_t exit_code; + uint64_t exit_info_1; + uint64_t exit_info_2; + uint32_t exit_int_info; + uint32_t exit_int_info_err; + uint64_t nested_ctl; + uint8_t reserved_4[16]; + uint32_t event_inj; + uint32_t event_inj_err; + uint64_t nested_cr3; + uint64_t lbr_ctl; + uint8_t reserved_5[832]; +}; + +struct __attribute__ ((__packed__)) vmcb_seg { + uint16_t selector; + uint16_t attrib; + uint32_t limit; + uint64_t base; +}; + +struct __attribute__ ((__packed__)) vmcb_save_area { + struct vmcb_seg es; + struct vmcb_seg cs; + struct vmcb_seg ss; + struct vmcb_seg ds; + struct vmcb_seg fs; + struct vmcb_seg gs; + struct vmcb_seg gdtr; + struct vmcb_seg ldtr; + struct vmcb_seg idtr; + struct vmcb_seg tr; + uint8_t reserved_1[43]; + uint8_t cpl; + uint8_t reserved_2[4]; + uint64_t efer; + uint8_t reserved_3[112]; + uint64_t cr4; + uint64_t cr3; + uint64_t cr0; + uint64_t dr7; + uint64_t dr6; + uint64_t rflags; + uint64_t rip; + uint8_t reserved_4[88]; + uint64_t rsp; + uint8_t reserved_5[24]; + uint64_t rax; + uint64_t star; + uint64_t lstar; + uint64_t cstar; + uint64_t sfmask; + uint64_t kernel_gs_base; + uint64_t sysenter_cs; + uint64_t sysenter_esp; + uint64_t sysenter_eip; + uint64_t cr2; + uint8_t reserved_6[32]; + uint64_t g_pat; + uint64_t dbgctl; + uint64_t br_from; + uint64_t br_to; + uint64_t last_excp_from; + uint64_t last_excp_to; +}; + +struct __attribute__ ((__packed__)) vmcb { + struct vmcb_control_area control; + struct vmcb_save_area save; +}; #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/TODO /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/TODO --- qemu-0.9.1/target-i386/TODO 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-i386/TODO 2008-05-28 17:16:54.000000000 +0100 @@ -0,0 +1,33 @@ +Correctness issues: + +- some eflags manipulation incorrectly reset the bit 0x2. +- SVM: test, cpu save/restore, SMM save/restore. +- x86_64: lcall/ljmp intel/amd differences ? +- better code fetch (different exception handling + CS.limit support) +- user/kernel PUSHL/POPL in helper.c +- add missing cpuid tests +- return UD exception if LOCK prefix incorrectly used +- test ldt limit < 7 ? +- fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret) +- full support of segment limit/rights +- full x87 exception support +- improve x87 bit exactness (use bochs code ?) +- DRx register support +- CR0.AC emulation +- SSE alignment checks +- fix SSE min/max with nans + +Optimizations/Features: + +- add SVM nested paging support +- add VMX support +- add AVX support +- add SSE5 support +- fxsave/fxrstor AMD extensions +- improve monitor/mwait support +- faster EFLAGS update: consider SZAP, C, O can be updated separately + with a bit field in CC_OP and more state variables. +- evaluate x87 stack pointer statically +- find a way to avoid translating several time the same TB if CR0.TS + is set or not. +- move kqemu support outside target-i386. diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-i386/translate.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-i386/translate.c --- qemu-0.9.1/target-i386/translate.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-i386/translate.c 2008-10-04 12:33:52.000000000 +0100 @@ -28,10 +28,8 @@ #include "cpu.h" #include "exec-all.h" #include "disas.h" - -/* XXX: move that elsewhere */ -static uint16_t *gen_opc_ptr; -static uint32_t *gen_opparam_ptr; +#include "helper.h" +#include "tcg-op.h" #define PREFIX_REPZ 0x01 #define PREFIX_REPNZ 0x02 @@ -57,16 +55,22 @@ #define REX_B(s) 0 #endif +//#define MACRO_TEST 1 + +/* global register indexes */ +static TCGv cpu_env, cpu_A0, cpu_cc_op, cpu_cc_src, cpu_cc_dst, cpu_cc_tmp; +/* local temps */ +static TCGv cpu_T[2], cpu_T3; +/* local register indexes (only used inside old micro ops) */ +static TCGv cpu_tmp0, cpu_tmp1_i64, cpu_tmp2_i32, cpu_tmp3_i32, cpu_tmp4, cpu_ptr0, cpu_ptr1; +static TCGv cpu_tmp5, cpu_tmp6; + +#include "gen-icount.h" + #ifdef TARGET_X86_64 static int x86_64_hregs; #endif -#ifdef USE_DIRECT_JUMP -#define TBPARAM(x) -#else -#define TBPARAM(x) (long)(x) -#endif - typedef struct DisasContext { /* current insn context */ int override; /* -1 if no override */ @@ -101,6 +105,8 @@ int rip_offset; /* only used in x86_64, but left for simplicity */ int cpuid_features; int cpuid_ext_features; + int cpuid_ext2_features; + int cpuid_ext3_features; } DisasContext; static void gen_eob(DisasContext *s); @@ -132,14 +138,16 @@ }; enum { -#define DEF(s, n, copy_size) INDEX_op_ ## s, -#include "opc.h" -#undef DEF - NB_OPS, + JCC_O, + JCC_B, + JCC_Z, + JCC_BE, + JCC_S, + JCC_P, + JCC_L, + JCC_LE, }; -#include "gen-op.h" - /* operand size */ enum { OT_BYTE = 0, @@ -164,664 +172,437 @@ OR_A0, /* temporary register used when doing address evaluation */ }; -#ifdef TARGET_X86_64 - -#define NB_OP_SIZES 4 +static inline void gen_op_movl_T0_0(void) +{ + tcg_gen_movi_tl(cpu_T[0], 0); +} -#define DEF_REGS(prefix, suffix) \ - prefix ## EAX ## suffix,\ - prefix ## ECX ## suffix,\ - prefix ## EDX ## suffix,\ - prefix ## EBX ## suffix,\ - prefix ## ESP ## suffix,\ - prefix ## EBP ## suffix,\ - prefix ## ESI ## suffix,\ - prefix ## EDI ## suffix,\ - prefix ## R8 ## suffix,\ - prefix ## R9 ## suffix,\ - prefix ## R10 ## suffix,\ - prefix ## R11 ## suffix,\ - prefix ## R12 ## suffix,\ - prefix ## R13 ## suffix,\ - prefix ## R14 ## suffix,\ - prefix ## R15 ## suffix, - -#define DEF_BREGS(prefixb, prefixh, suffix) \ - \ -static void prefixb ## ESP ## suffix ## _wrapper(void) \ -{ \ - if (x86_64_hregs) \ - prefixb ## ESP ## suffix (); \ - else \ - prefixh ## EAX ## suffix (); \ -} \ - \ -static void prefixb ## EBP ## suffix ## _wrapper(void) \ -{ \ - if (x86_64_hregs) \ - prefixb ## EBP ## suffix (); \ - else \ - prefixh ## ECX ## suffix (); \ -} \ - \ -static void prefixb ## ESI ## suffix ## _wrapper(void) \ -{ \ - if (x86_64_hregs) \ - prefixb ## ESI ## suffix (); \ - else \ - prefixh ## EDX ## suffix (); \ -} \ - \ -static void prefixb ## EDI ## suffix ## _wrapper(void) \ -{ \ - if (x86_64_hregs) \ - prefixb ## EDI ## suffix (); \ - else \ - prefixh ## EBX ## suffix (); \ -} - -DEF_BREGS(gen_op_movb_, gen_op_movh_, _T0) -DEF_BREGS(gen_op_movb_, gen_op_movh_, _T1) -DEF_BREGS(gen_op_movl_T0_, gen_op_movh_T0_, ) -DEF_BREGS(gen_op_movl_T1_, gen_op_movh_T1_, ) +static inline void gen_op_movl_T0_im(int32_t val) +{ + tcg_gen_movi_tl(cpu_T[0], val); +} -#else /* !TARGET_X86_64 */ +static inline void gen_op_movl_T0_imu(uint32_t val) +{ + tcg_gen_movi_tl(cpu_T[0], val); +} -#define NB_OP_SIZES 3 +static inline void gen_op_movl_T1_im(int32_t val) +{ + tcg_gen_movi_tl(cpu_T[1], val); +} -#define DEF_REGS(prefix, suffix) \ - prefix ## EAX ## suffix,\ - prefix ## ECX ## suffix,\ - prefix ## EDX ## suffix,\ - prefix ## EBX ## suffix,\ - prefix ## ESP ## suffix,\ - prefix ## EBP ## suffix,\ - prefix ## ESI ## suffix,\ - prefix ## EDI ## suffix, +static inline void gen_op_movl_T1_imu(uint32_t val) +{ + tcg_gen_movi_tl(cpu_T[1], val); +} -#endif /* !TARGET_X86_64 */ +static inline void gen_op_movl_A0_im(uint32_t val) +{ + tcg_gen_movi_tl(cpu_A0, val); +} -static GenOpFunc *gen_op_mov_reg_T0[NB_OP_SIZES][CPU_NB_REGS] = { - [OT_BYTE] = { - gen_op_movb_EAX_T0, - gen_op_movb_ECX_T0, - gen_op_movb_EDX_T0, - gen_op_movb_EBX_T0, -#ifdef TARGET_X86_64 - gen_op_movb_ESP_T0_wrapper, - gen_op_movb_EBP_T0_wrapper, - gen_op_movb_ESI_T0_wrapper, - gen_op_movb_EDI_T0_wrapper, - gen_op_movb_R8_T0, - gen_op_movb_R9_T0, - gen_op_movb_R10_T0, - gen_op_movb_R11_T0, - gen_op_movb_R12_T0, - gen_op_movb_R13_T0, - gen_op_movb_R14_T0, - gen_op_movb_R15_T0, -#else - gen_op_movh_EAX_T0, - gen_op_movh_ECX_T0, - gen_op_movh_EDX_T0, - gen_op_movh_EBX_T0, -#endif - }, - [OT_WORD] = { - DEF_REGS(gen_op_movw_, _T0) - }, - [OT_LONG] = { - DEF_REGS(gen_op_movl_, _T0) - }, -#ifdef TARGET_X86_64 - [OT_QUAD] = { - DEF_REGS(gen_op_movq_, _T0) - }, +#ifdef TARGET_X86_64 +static inline void gen_op_movq_A0_im(int64_t val) +{ + tcg_gen_movi_tl(cpu_A0, val); +} #endif -}; -static GenOpFunc *gen_op_mov_reg_T1[NB_OP_SIZES][CPU_NB_REGS] = { - [OT_BYTE] = { - gen_op_movb_EAX_T1, - gen_op_movb_ECX_T1, - gen_op_movb_EDX_T1, - gen_op_movb_EBX_T1, -#ifdef TARGET_X86_64 - gen_op_movb_ESP_T1_wrapper, - gen_op_movb_EBP_T1_wrapper, - gen_op_movb_ESI_T1_wrapper, - gen_op_movb_EDI_T1_wrapper, - gen_op_movb_R8_T1, - gen_op_movb_R9_T1, - gen_op_movb_R10_T1, - gen_op_movb_R11_T1, - gen_op_movb_R12_T1, - gen_op_movb_R13_T1, - gen_op_movb_R14_T1, - gen_op_movb_R15_T1, -#else - gen_op_movh_EAX_T1, - gen_op_movh_ECX_T1, - gen_op_movh_EDX_T1, - gen_op_movh_EBX_T1, -#endif - }, - [OT_WORD] = { - DEF_REGS(gen_op_movw_, _T1) - }, - [OT_LONG] = { - DEF_REGS(gen_op_movl_, _T1) - }, -#ifdef TARGET_X86_64 - [OT_QUAD] = { - DEF_REGS(gen_op_movq_, _T1) - }, -#endif -}; +static inline void gen_movtl_T0_im(target_ulong val) +{ + tcg_gen_movi_tl(cpu_T[0], val); +} -static GenOpFunc *gen_op_mov_reg_A0[NB_OP_SIZES - 1][CPU_NB_REGS] = { - [0] = { - DEF_REGS(gen_op_movw_, _A0) - }, - [1] = { - DEF_REGS(gen_op_movl_, _A0) - }, -#ifdef TARGET_X86_64 - [2] = { - DEF_REGS(gen_op_movq_, _A0) - }, -#endif -}; +static inline void gen_movtl_T1_im(target_ulong val) +{ + tcg_gen_movi_tl(cpu_T[1], val); +} -static GenOpFunc *gen_op_mov_TN_reg[NB_OP_SIZES][2][CPU_NB_REGS] = +static inline void gen_op_andl_T0_ffff(void) { - [OT_BYTE] = { - { - gen_op_movl_T0_EAX, - gen_op_movl_T0_ECX, - gen_op_movl_T0_EDX, - gen_op_movl_T0_EBX, -#ifdef TARGET_X86_64 - gen_op_movl_T0_ESP_wrapper, - gen_op_movl_T0_EBP_wrapper, - gen_op_movl_T0_ESI_wrapper, - gen_op_movl_T0_EDI_wrapper, - gen_op_movl_T0_R8, - gen_op_movl_T0_R9, - gen_op_movl_T0_R10, - gen_op_movl_T0_R11, - gen_op_movl_T0_R12, - gen_op_movl_T0_R13, - gen_op_movl_T0_R14, - gen_op_movl_T0_R15, -#else - gen_op_movh_T0_EAX, - gen_op_movh_T0_ECX, - gen_op_movh_T0_EDX, - gen_op_movh_T0_EBX, -#endif - }, - { - gen_op_movl_T1_EAX, - gen_op_movl_T1_ECX, - gen_op_movl_T1_EDX, - gen_op_movl_T1_EBX, -#ifdef TARGET_X86_64 - gen_op_movl_T1_ESP_wrapper, - gen_op_movl_T1_EBP_wrapper, - gen_op_movl_T1_ESI_wrapper, - gen_op_movl_T1_EDI_wrapper, - gen_op_movl_T1_R8, - gen_op_movl_T1_R9, - gen_op_movl_T1_R10, - gen_op_movl_T1_R11, - gen_op_movl_T1_R12, - gen_op_movl_T1_R13, - gen_op_movl_T1_R14, - gen_op_movl_T1_R15, -#else - gen_op_movh_T1_EAX, - gen_op_movh_T1_ECX, - gen_op_movh_T1_EDX, - gen_op_movh_T1_EBX, -#endif - }, - }, - [OT_WORD] = { - { - DEF_REGS(gen_op_movl_T0_, ) - }, - { - DEF_REGS(gen_op_movl_T1_, ) - }, - }, - [OT_LONG] = { - { - DEF_REGS(gen_op_movl_T0_, ) - }, - { - DEF_REGS(gen_op_movl_T1_, ) - }, - }, -#ifdef TARGET_X86_64 - [OT_QUAD] = { - { - DEF_REGS(gen_op_movl_T0_, ) - }, - { - DEF_REGS(gen_op_movl_T1_, ) - }, - }, -#endif -}; + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 0xffff); +} -static GenOpFunc *gen_op_movl_A0_reg[CPU_NB_REGS] = { - DEF_REGS(gen_op_movl_A0_, ) -}; +static inline void gen_op_andl_T0_im(uint32_t val) +{ + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], val); +} -static GenOpFunc *gen_op_addl_A0_reg_sN[4][CPU_NB_REGS] = { - [0] = { - DEF_REGS(gen_op_addl_A0_, ) - }, - [1] = { - DEF_REGS(gen_op_addl_A0_, _s1) - }, - [2] = { - DEF_REGS(gen_op_addl_A0_, _s2) - }, - [3] = { - DEF_REGS(gen_op_addl_A0_, _s3) - }, -}; +static inline void gen_op_movl_T0_T1(void) +{ + tcg_gen_mov_tl(cpu_T[0], cpu_T[1]); +} -#ifdef TARGET_X86_64 -static GenOpFunc *gen_op_movq_A0_reg[CPU_NB_REGS] = { - DEF_REGS(gen_op_movq_A0_, ) -}; +static inline void gen_op_andl_A0_ffff(void) +{ + tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffff); +} -static GenOpFunc *gen_op_addq_A0_reg_sN[4][CPU_NB_REGS] = { - [0] = { - DEF_REGS(gen_op_addq_A0_, ) - }, - [1] = { - DEF_REGS(gen_op_addq_A0_, _s1) - }, - [2] = { - DEF_REGS(gen_op_addq_A0_, _s2) - }, - [3] = { - DEF_REGS(gen_op_addq_A0_, _s3) - }, -}; -#endif +#ifdef TARGET_X86_64 -static GenOpFunc *gen_op_cmov_reg_T1_T0[NB_OP_SIZES - 1][CPU_NB_REGS] = { - [0] = { - DEF_REGS(gen_op_cmovw_, _T1_T0) - }, - [1] = { - DEF_REGS(gen_op_cmovl_, _T1_T0) - }, -#ifdef TARGET_X86_64 - [2] = { - DEF_REGS(gen_op_cmovq_, _T1_T0) - }, -#endif -}; +#define NB_OP_SIZES 4 -static GenOpFunc *gen_op_arith_T0_T1_cc[8] = { - NULL, - gen_op_orl_T0_T1, - NULL, - NULL, - gen_op_andl_T0_T1, - NULL, - gen_op_xorl_T0_T1, - NULL, -}; +#else /* !TARGET_X86_64 */ -#define DEF_ARITHC(SUFFIX)\ - {\ - gen_op_adcb ## SUFFIX ## _T0_T1_cc,\ - gen_op_sbbb ## SUFFIX ## _T0_T1_cc,\ - },\ - {\ - gen_op_adcw ## SUFFIX ## _T0_T1_cc,\ - gen_op_sbbw ## SUFFIX ## _T0_T1_cc,\ - },\ - {\ - gen_op_adcl ## SUFFIX ## _T0_T1_cc,\ - gen_op_sbbl ## SUFFIX ## _T0_T1_cc,\ - },\ - {\ - X86_64_ONLY(gen_op_adcq ## SUFFIX ## _T0_T1_cc),\ - X86_64_ONLY(gen_op_sbbq ## SUFFIX ## _T0_T1_cc),\ - }, +#define NB_OP_SIZES 3 -static GenOpFunc *gen_op_arithc_T0_T1_cc[4][2] = { - DEF_ARITHC( ) -}; +#endif /* !TARGET_X86_64 */ -static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[3 * 4][2] = { - DEF_ARITHC(_raw) -#ifndef CONFIG_USER_ONLY - DEF_ARITHC(_kernel) - DEF_ARITHC(_user) +#if defined(WORDS_BIGENDIAN) +#define REG_B_OFFSET (sizeof(target_ulong) - 1) +#define REG_H_OFFSET (sizeof(target_ulong) - 2) +#define REG_W_OFFSET (sizeof(target_ulong) - 2) +#define REG_L_OFFSET (sizeof(target_ulong) - 4) +#define REG_LH_OFFSET (sizeof(target_ulong) - 8) +#else +#define REG_B_OFFSET 0 +#define REG_H_OFFSET 1 +#define REG_W_OFFSET 0 +#define REG_L_OFFSET 0 +#define REG_LH_OFFSET 4 #endif -}; - -static const int cc_op_arithb[8] = { - CC_OP_ADDB, - CC_OP_LOGICB, - CC_OP_ADDB, - CC_OP_SUBB, - CC_OP_LOGICB, - CC_OP_SUBB, - CC_OP_LOGICB, - CC_OP_SUBB, -}; - -#define DEF_CMPXCHG(SUFFIX)\ - gen_op_cmpxchgb ## SUFFIX ## _T0_T1_EAX_cc,\ - gen_op_cmpxchgw ## SUFFIX ## _T0_T1_EAX_cc,\ - gen_op_cmpxchgl ## SUFFIX ## _T0_T1_EAX_cc,\ - X86_64_ONLY(gen_op_cmpxchgq ## SUFFIX ## _T0_T1_EAX_cc), - -static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[4] = { - DEF_CMPXCHG( ) -}; -static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[3 * 4] = { - DEF_CMPXCHG(_raw) -#ifndef CONFIG_USER_ONLY - DEF_CMPXCHG(_kernel) - DEF_CMPXCHG(_user) +static inline void gen_op_mov_reg_v(int ot, int reg, TCGv t0) +{ + switch(ot) { + case OT_BYTE: + if (reg < 4 X86_64_DEF( || reg >= 8 || x86_64_hregs)) { + tcg_gen_st8_tl(t0, cpu_env, offsetof(CPUState, regs[reg]) + REG_B_OFFSET); + } else { + tcg_gen_st8_tl(t0, cpu_env, offsetof(CPUState, regs[reg - 4]) + REG_H_OFFSET); + } + break; + case OT_WORD: + tcg_gen_st16_tl(t0, cpu_env, offsetof(CPUState, regs[reg]) + REG_W_OFFSET); + break; +#ifdef TARGET_X86_64 + case OT_LONG: + tcg_gen_st32_tl(t0, cpu_env, offsetof(CPUState, regs[reg]) + REG_L_OFFSET); + /* high part of register set to zero */ + tcg_gen_movi_tl(cpu_tmp0, 0); + tcg_gen_st32_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]) + REG_LH_OFFSET); + break; + default: + case OT_QUAD: + tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, regs[reg])); + break; +#else + default: + case OT_LONG: + tcg_gen_st32_tl(t0, cpu_env, offsetof(CPUState, regs[reg]) + REG_L_OFFSET); + break; #endif -}; + } +} -#define DEF_SHIFT(SUFFIX)\ - {\ - gen_op_rolb ## SUFFIX ## _T0_T1_cc,\ - gen_op_rorb ## SUFFIX ## _T0_T1_cc,\ - gen_op_rclb ## SUFFIX ## _T0_T1_cc,\ - gen_op_rcrb ## SUFFIX ## _T0_T1_cc,\ - gen_op_shlb ## SUFFIX ## _T0_T1_cc,\ - gen_op_shrb ## SUFFIX ## _T0_T1_cc,\ - gen_op_shlb ## SUFFIX ## _T0_T1_cc,\ - gen_op_sarb ## SUFFIX ## _T0_T1_cc,\ - },\ - {\ - gen_op_rolw ## SUFFIX ## _T0_T1_cc,\ - gen_op_rorw ## SUFFIX ## _T0_T1_cc,\ - gen_op_rclw ## SUFFIX ## _T0_T1_cc,\ - gen_op_rcrw ## SUFFIX ## _T0_T1_cc,\ - gen_op_shlw ## SUFFIX ## _T0_T1_cc,\ - gen_op_shrw ## SUFFIX ## _T0_T1_cc,\ - gen_op_shlw ## SUFFIX ## _T0_T1_cc,\ - gen_op_sarw ## SUFFIX ## _T0_T1_cc,\ - },\ - {\ - gen_op_roll ## SUFFIX ## _T0_T1_cc,\ - gen_op_rorl ## SUFFIX ## _T0_T1_cc,\ - gen_op_rcll ## SUFFIX ## _T0_T1_cc,\ - gen_op_rcrl ## SUFFIX ## _T0_T1_cc,\ - gen_op_shll ## SUFFIX ## _T0_T1_cc,\ - gen_op_shrl ## SUFFIX ## _T0_T1_cc,\ - gen_op_shll ## SUFFIX ## _T0_T1_cc,\ - gen_op_sarl ## SUFFIX ## _T0_T1_cc,\ - },\ - {\ - X86_64_ONLY(gen_op_rolq ## SUFFIX ## _T0_T1_cc),\ - X86_64_ONLY(gen_op_rorq ## SUFFIX ## _T0_T1_cc),\ - X86_64_ONLY(gen_op_rclq ## SUFFIX ## _T0_T1_cc),\ - X86_64_ONLY(gen_op_rcrq ## SUFFIX ## _T0_T1_cc),\ - X86_64_ONLY(gen_op_shlq ## SUFFIX ## _T0_T1_cc),\ - X86_64_ONLY(gen_op_shrq ## SUFFIX ## _T0_T1_cc),\ - X86_64_ONLY(gen_op_shlq ## SUFFIX ## _T0_T1_cc),\ - X86_64_ONLY(gen_op_sarq ## SUFFIX ## _T0_T1_cc),\ - }, +static inline void gen_op_mov_reg_T0(int ot, int reg) +{ + gen_op_mov_reg_v(ot, reg, cpu_T[0]); +} -static GenOpFunc *gen_op_shift_T0_T1_cc[4][8] = { - DEF_SHIFT( ) -}; +static inline void gen_op_mov_reg_T1(int ot, int reg) +{ + gen_op_mov_reg_v(ot, reg, cpu_T[1]); +} -static GenOpFunc *gen_op_shift_mem_T0_T1_cc[3 * 4][8] = { - DEF_SHIFT(_raw) -#ifndef CONFIG_USER_ONLY - DEF_SHIFT(_kernel) - DEF_SHIFT(_user) +static inline void gen_op_mov_reg_A0(int size, int reg) +{ + switch(size) { + case 0: + tcg_gen_st16_tl(cpu_A0, cpu_env, offsetof(CPUState, regs[reg]) + REG_W_OFFSET); + break; +#ifdef TARGET_X86_64 + case 1: + tcg_gen_st32_tl(cpu_A0, cpu_env, offsetof(CPUState, regs[reg]) + REG_L_OFFSET); + /* high part of register set to zero */ + tcg_gen_movi_tl(cpu_tmp0, 0); + tcg_gen_st32_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]) + REG_LH_OFFSET); + break; + default: + case 2: + tcg_gen_st_tl(cpu_A0, cpu_env, offsetof(CPUState, regs[reg])); + break; +#else + default: + case 1: + tcg_gen_st32_tl(cpu_A0, cpu_env, offsetof(CPUState, regs[reg]) + REG_L_OFFSET); + break; #endif -}; + } +} -#define DEF_SHIFTD(SUFFIX, op)\ - {\ - NULL,\ - NULL,\ - },\ - {\ - gen_op_shldw ## SUFFIX ## _T0_T1_ ## op ## _cc,\ - gen_op_shrdw ## SUFFIX ## _T0_T1_ ## op ## _cc,\ - },\ - {\ - gen_op_shldl ## SUFFIX ## _T0_T1_ ## op ## _cc,\ - gen_op_shrdl ## SUFFIX ## _T0_T1_ ## op ## _cc,\ - },\ - {\ -X86_64_DEF(gen_op_shldq ## SUFFIX ## _T0_T1_ ## op ## _cc,\ - gen_op_shrdq ## SUFFIX ## _T0_T1_ ## op ## _cc,)\ - }, +static inline void gen_op_mov_v_reg(int ot, TCGv t0, int reg) +{ + switch(ot) { + case OT_BYTE: + if (reg < 4 X86_64_DEF( || reg >= 8 || x86_64_hregs)) { + goto std_case; + } else { + tcg_gen_ld8u_tl(t0, cpu_env, offsetof(CPUState, regs[reg - 4]) + REG_H_OFFSET); + } + break; + default: + std_case: + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, regs[reg])); + break; + } +} -static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[4][2] = { - DEF_SHIFTD(, im) -}; +static inline void gen_op_mov_TN_reg(int ot, int t_index, int reg) +{ + gen_op_mov_v_reg(ot, cpu_T[t_index], reg); +} -static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[4][2] = { - DEF_SHIFTD(, ECX) -}; +static inline void gen_op_movl_A0_reg(int reg) +{ + tcg_gen_ld32u_tl(cpu_A0, cpu_env, offsetof(CPUState, regs[reg]) + REG_L_OFFSET); +} -static GenOpFunc1 *gen_op_shiftd_mem_T0_T1_im_cc[3 * 4][2] = { - DEF_SHIFTD(_raw, im) -#ifndef CONFIG_USER_ONLY - DEF_SHIFTD(_kernel, im) - DEF_SHIFTD(_user, im) +static inline void gen_op_addl_A0_im(int32_t val) +{ + tcg_gen_addi_tl(cpu_A0, cpu_A0, val); +#ifdef TARGET_X86_64 + tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffffffff); #endif -}; +} -static GenOpFunc *gen_op_shiftd_mem_T0_T1_ECX_cc[3 * 4][2] = { - DEF_SHIFTD(_raw, ECX) -#ifndef CONFIG_USER_ONLY - DEF_SHIFTD(_kernel, ECX) - DEF_SHIFTD(_user, ECX) +#ifdef TARGET_X86_64 +static inline void gen_op_addq_A0_im(int64_t val) +{ + tcg_gen_addi_tl(cpu_A0, cpu_A0, val); +} #endif -}; - -static GenOpFunc *gen_op_btx_T0_T1_cc[3][4] = { - [0] = { - gen_op_btw_T0_T1_cc, - gen_op_btsw_T0_T1_cc, - gen_op_btrw_T0_T1_cc, - gen_op_btcw_T0_T1_cc, - }, - [1] = { - gen_op_btl_T0_T1_cc, - gen_op_btsl_T0_T1_cc, - gen_op_btrl_T0_T1_cc, - gen_op_btcl_T0_T1_cc, - }, -#ifdef TARGET_X86_64 - [2] = { - gen_op_btq_T0_T1_cc, - gen_op_btsq_T0_T1_cc, - gen_op_btrq_T0_T1_cc, - gen_op_btcq_T0_T1_cc, - }, + +static void gen_add_A0_im(DisasContext *s, int val) +{ +#ifdef TARGET_X86_64 + if (CODE64(s)) + gen_op_addq_A0_im(val); + else #endif -}; - -static GenOpFunc *gen_op_add_bit_A0_T1[3] = { - gen_op_add_bitw_A0_T1, - gen_op_add_bitl_A0_T1, - X86_64_ONLY(gen_op_add_bitq_A0_T1), -}; + gen_op_addl_A0_im(val); +} -static GenOpFunc *gen_op_bsx_T0_cc[3][2] = { - [0] = { - gen_op_bsfw_T0_cc, - gen_op_bsrw_T0_cc, - }, - [1] = { - gen_op_bsfl_T0_cc, - gen_op_bsrl_T0_cc, - }, -#ifdef TARGET_X86_64 - [2] = { - gen_op_bsfq_T0_cc, - gen_op_bsrq_T0_cc, - }, -#endif -}; +static inline void gen_op_addl_T0_T1(void) +{ + tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_T[1]); +} -static GenOpFunc *gen_op_lds_T0_A0[3 * 4] = { - gen_op_ldsb_raw_T0_A0, - gen_op_ldsw_raw_T0_A0, - X86_64_ONLY(gen_op_ldsl_raw_T0_A0), - NULL, -#ifndef CONFIG_USER_ONLY - gen_op_ldsb_kernel_T0_A0, - gen_op_ldsw_kernel_T0_A0, - X86_64_ONLY(gen_op_ldsl_kernel_T0_A0), - NULL, +static inline void gen_op_jmp_T0(void) +{ + tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUState, eip)); +} - gen_op_ldsb_user_T0_A0, - gen_op_ldsw_user_T0_A0, - X86_64_ONLY(gen_op_ldsl_user_T0_A0), - NULL, +static inline void gen_op_add_reg_im(int size, int reg, int32_t val) +{ + switch(size) { + case 0: + tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg])); + tcg_gen_addi_tl(cpu_tmp0, cpu_tmp0, val); + tcg_gen_st16_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]) + REG_W_OFFSET); + break; + case 1: + tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg])); + tcg_gen_addi_tl(cpu_tmp0, cpu_tmp0, val); +#ifdef TARGET_X86_64 + tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0xffffffff); #endif -}; + tcg_gen_st_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg])); + break; +#ifdef TARGET_X86_64 + case 2: + tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg])); + tcg_gen_addi_tl(cpu_tmp0, cpu_tmp0, val); + tcg_gen_st_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg])); + break; +#endif + } +} -static GenOpFunc *gen_op_ldu_T0_A0[3 * 4] = { - gen_op_ldub_raw_T0_A0, - gen_op_lduw_raw_T0_A0, - NULL, - NULL, +static inline void gen_op_add_reg_T0(int size, int reg) +{ + switch(size) { + case 0: + tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg])); + tcg_gen_add_tl(cpu_tmp0, cpu_tmp0, cpu_T[0]); + tcg_gen_st16_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]) + REG_W_OFFSET); + break; + case 1: + tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg])); + tcg_gen_add_tl(cpu_tmp0, cpu_tmp0, cpu_T[0]); +#ifdef TARGET_X86_64 + tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0xffffffff); +#endif + tcg_gen_st_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg])); + break; +#ifdef TARGET_X86_64 + case 2: + tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg])); + tcg_gen_add_tl(cpu_tmp0, cpu_tmp0, cpu_T[0]); + tcg_gen_st_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg])); + break; +#endif + } +} -#ifndef CONFIG_USER_ONLY - gen_op_ldub_kernel_T0_A0, - gen_op_lduw_kernel_T0_A0, - NULL, - NULL, +static inline void gen_op_set_cc_op(int32_t val) +{ + tcg_gen_movi_i32(cpu_cc_op, val); +} - gen_op_ldub_user_T0_A0, - gen_op_lduw_user_T0_A0, - NULL, - NULL, +static inline void gen_op_addl_A0_reg_sN(int shift, int reg) +{ + tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg])); + if (shift != 0) + tcg_gen_shli_tl(cpu_tmp0, cpu_tmp0, shift); + tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0); +#ifdef TARGET_X86_64 + tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffffffff); #endif -}; +} -/* sign does not matter, except for lidt/lgdt call (TODO: fix it) */ -static GenOpFunc *gen_op_ld_T0_A0[3 * 4] = { - gen_op_ldub_raw_T0_A0, - gen_op_lduw_raw_T0_A0, - gen_op_ldl_raw_T0_A0, - X86_64_ONLY(gen_op_ldq_raw_T0_A0), - -#ifndef CONFIG_USER_ONLY - gen_op_ldub_kernel_T0_A0, - gen_op_lduw_kernel_T0_A0, - gen_op_ldl_kernel_T0_A0, - X86_64_ONLY(gen_op_ldq_kernel_T0_A0), - - gen_op_ldub_user_T0_A0, - gen_op_lduw_user_T0_A0, - gen_op_ldl_user_T0_A0, - X86_64_ONLY(gen_op_ldq_user_T0_A0), -#endif -}; +static inline void gen_op_movl_A0_seg(int reg) +{ + tcg_gen_ld32u_tl(cpu_A0, cpu_env, offsetof(CPUState, segs[reg].base) + REG_L_OFFSET); +} -static GenOpFunc *gen_op_ld_T1_A0[3 * 4] = { - gen_op_ldub_raw_T1_A0, - gen_op_lduw_raw_T1_A0, - gen_op_ldl_raw_T1_A0, - X86_64_ONLY(gen_op_ldq_raw_T1_A0), - -#ifndef CONFIG_USER_ONLY - gen_op_ldub_kernel_T1_A0, - gen_op_lduw_kernel_T1_A0, - gen_op_ldl_kernel_T1_A0, - X86_64_ONLY(gen_op_ldq_kernel_T1_A0), - - gen_op_ldub_user_T1_A0, - gen_op_lduw_user_T1_A0, - gen_op_ldl_user_T1_A0, - X86_64_ONLY(gen_op_ldq_user_T1_A0), +static inline void gen_op_addl_A0_seg(int reg) +{ + tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, segs[reg].base)); + tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0); +#ifdef TARGET_X86_64 + tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffffffff); #endif -}; +} -static GenOpFunc *gen_op_st_T0_A0[3 * 4] = { - gen_op_stb_raw_T0_A0, - gen_op_stw_raw_T0_A0, - gen_op_stl_raw_T0_A0, - X86_64_ONLY(gen_op_stq_raw_T0_A0), - -#ifndef CONFIG_USER_ONLY - gen_op_stb_kernel_T0_A0, - gen_op_stw_kernel_T0_A0, - gen_op_stl_kernel_T0_A0, - X86_64_ONLY(gen_op_stq_kernel_T0_A0), - - gen_op_stb_user_T0_A0, - gen_op_stw_user_T0_A0, - gen_op_stl_user_T0_A0, - X86_64_ONLY(gen_op_stq_user_T0_A0), -#endif -}; +#ifdef TARGET_X86_64 +static inline void gen_op_movq_A0_seg(int reg) +{ + tcg_gen_ld_tl(cpu_A0, cpu_env, offsetof(CPUState, segs[reg].base)); +} -static GenOpFunc *gen_op_st_T1_A0[3 * 4] = { - NULL, - gen_op_stw_raw_T1_A0, - gen_op_stl_raw_T1_A0, - X86_64_ONLY(gen_op_stq_raw_T1_A0), +static inline void gen_op_addq_A0_seg(int reg) +{ + tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, segs[reg].base)); + tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0); +} -#ifndef CONFIG_USER_ONLY - NULL, - gen_op_stw_kernel_T1_A0, - gen_op_stl_kernel_T1_A0, - X86_64_ONLY(gen_op_stq_kernel_T1_A0), +static inline void gen_op_movq_A0_reg(int reg) +{ + tcg_gen_ld_tl(cpu_A0, cpu_env, offsetof(CPUState, regs[reg])); +} - NULL, - gen_op_stw_user_T1_A0, - gen_op_stl_user_T1_A0, - X86_64_ONLY(gen_op_stq_user_T1_A0), +static inline void gen_op_addq_A0_reg_sN(int shift, int reg) +{ + tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg])); + if (shift != 0) + tcg_gen_shli_tl(cpu_tmp0, cpu_tmp0, shift); + tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0); +} #endif -}; -static inline void gen_jmp_im(target_ulong pc) +static inline void gen_op_lds_T0_A0(int idx) { -#ifdef TARGET_X86_64 - if (pc == (uint32_t)pc) { - gen_op_movl_eip_im(pc); - } else if (pc == (int32_t)pc) { - gen_op_movq_eip_im(pc); - } else { - gen_op_movq_eip_im64(pc >> 32, pc); + int mem_index = (idx >> 2) - 1; + switch(idx & 3) { + case 0: + tcg_gen_qemu_ld8s(cpu_T[0], cpu_A0, mem_index); + break; + case 1: + tcg_gen_qemu_ld16s(cpu_T[0], cpu_A0, mem_index); + break; + default: + case 2: + tcg_gen_qemu_ld32s(cpu_T[0], cpu_A0, mem_index); + break; } -#else - gen_op_movl_eip_im(pc); -#endif } -static inline void gen_string_movl_A0_ESI(DisasContext *s) +static inline void gen_op_ld_v(int idx, TCGv t0, TCGv a0) { - int override; + int mem_index = (idx >> 2) - 1; + switch(idx & 3) { + case 0: + tcg_gen_qemu_ld8u(t0, a0, mem_index); + break; + case 1: + tcg_gen_qemu_ld16u(t0, a0, mem_index); + break; + case 2: + tcg_gen_qemu_ld32u(t0, a0, mem_index); + break; + default: + case 3: + tcg_gen_qemu_ld64(t0, a0, mem_index); + break; + } +} - override = s->override; -#ifdef TARGET_X86_64 - if (s->aflag == 2) { - if (override >= 0) { - gen_op_movq_A0_seg(offsetof(CPUX86State,segs[override].base)); - gen_op_addq_A0_reg_sN[0][R_ESI](); - } else { - gen_op_movq_A0_reg[R_ESI](); +/* XXX: always use ldu or lds */ +static inline void gen_op_ld_T0_A0(int idx) +{ + gen_op_ld_v(idx, cpu_T[0], cpu_A0); +} + +static inline void gen_op_ldu_T0_A0(int idx) +{ + gen_op_ld_v(idx, cpu_T[0], cpu_A0); +} + +static inline void gen_op_ld_T1_A0(int idx) +{ + gen_op_ld_v(idx, cpu_T[1], cpu_A0); +} + +static inline void gen_op_st_v(int idx, TCGv t0, TCGv a0) +{ + int mem_index = (idx >> 2) - 1; + switch(idx & 3) { + case 0: + tcg_gen_qemu_st8(t0, a0, mem_index); + break; + case 1: + tcg_gen_qemu_st16(t0, a0, mem_index); + break; + case 2: + tcg_gen_qemu_st32(t0, a0, mem_index); + break; + default: + case 3: + tcg_gen_qemu_st64(t0, a0, mem_index); + break; + } +} + +static inline void gen_op_st_T0_A0(int idx) +{ + gen_op_st_v(idx, cpu_T[0], cpu_A0); +} + +static inline void gen_op_st_T1_A0(int idx) +{ + gen_op_st_v(idx, cpu_T[1], cpu_A0); +} + +static inline void gen_jmp_im(target_ulong pc) +{ + tcg_gen_movi_tl(cpu_tmp0, pc); + tcg_gen_st_tl(cpu_tmp0, cpu_env, offsetof(CPUState, eip)); +} + +static inline void gen_string_movl_A0_ESI(DisasContext *s) +{ + int override; + + override = s->override; +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + if (override >= 0) { + gen_op_movq_A0_seg(override); + gen_op_addq_A0_reg_sN(0, R_ESI); + } else { + gen_op_movq_A0_reg(R_ESI); } } else #endif @@ -830,18 +611,18 @@ if (s->addseg && override < 0) override = R_DS; if (override >= 0) { - gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base)); - gen_op_addl_A0_reg_sN[0][R_ESI](); + gen_op_movl_A0_seg(override); + gen_op_addl_A0_reg_sN(0, R_ESI); } else { - gen_op_movl_A0_reg[R_ESI](); + gen_op_movl_A0_reg(R_ESI); } } else { /* 16 address, always override */ if (override < 0) override = R_DS; - gen_op_movl_A0_reg[R_ESI](); + gen_op_movl_A0_reg(R_ESI); gen_op_andl_A0_ffff(); - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + gen_op_addl_A0_seg(override); } } @@ -849,132 +630,137 @@ { #ifdef TARGET_X86_64 if (s->aflag == 2) { - gen_op_movq_A0_reg[R_EDI](); + gen_op_movq_A0_reg(R_EDI); } else #endif if (s->aflag) { if (s->addseg) { - gen_op_movl_A0_seg(offsetof(CPUX86State,segs[R_ES].base)); - gen_op_addl_A0_reg_sN[0][R_EDI](); + gen_op_movl_A0_seg(R_ES); + gen_op_addl_A0_reg_sN(0, R_EDI); } else { - gen_op_movl_A0_reg[R_EDI](); + gen_op_movl_A0_reg(R_EDI); } } else { - gen_op_movl_A0_reg[R_EDI](); + gen_op_movl_A0_reg(R_EDI); gen_op_andl_A0_ffff(); - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_ES].base)); + gen_op_addl_A0_seg(R_ES); } } -static GenOpFunc *gen_op_movl_T0_Dshift[4] = { - gen_op_movl_T0_Dshiftb, - gen_op_movl_T0_Dshiftw, - gen_op_movl_T0_Dshiftl, - X86_64_ONLY(gen_op_movl_T0_Dshiftq), -}; - -static GenOpFunc1 *gen_op_jnz_ecx[3] = { - gen_op_jnz_ecxw, - gen_op_jnz_ecxl, - X86_64_ONLY(gen_op_jnz_ecxq), -}; - -static GenOpFunc1 *gen_op_jz_ecx[3] = { - gen_op_jz_ecxw, - gen_op_jz_ecxl, - X86_64_ONLY(gen_op_jz_ecxq), -}; - -static GenOpFunc *gen_op_dec_ECX[3] = { - gen_op_decw_ECX, - gen_op_decl_ECX, - X86_64_ONLY(gen_op_decq_ECX), +static inline void gen_op_movl_T0_Dshift(int ot) +{ + tcg_gen_ld32s_tl(cpu_T[0], cpu_env, offsetof(CPUState, df)); + tcg_gen_shli_tl(cpu_T[0], cpu_T[0], ot); }; -static GenOpFunc1 *gen_op_string_jnz_sub[2][4] = { - { - gen_op_jnz_subb, - gen_op_jnz_subw, - gen_op_jnz_subl, - X86_64_ONLY(gen_op_jnz_subq), - }, - { - gen_op_jz_subb, - gen_op_jz_subw, - gen_op_jz_subl, - X86_64_ONLY(gen_op_jz_subq), - }, -}; +static void gen_extu(int ot, TCGv reg) +{ + switch(ot) { + case OT_BYTE: + tcg_gen_ext8u_tl(reg, reg); + break; + case OT_WORD: + tcg_gen_ext16u_tl(reg, reg); + break; + case OT_LONG: + tcg_gen_ext32u_tl(reg, reg); + break; + default: + break; + } +} -static GenOpFunc *gen_op_in_DX_T0[3] = { - gen_op_inb_DX_T0, - gen_op_inw_DX_T0, - gen_op_inl_DX_T0, -}; +static void gen_exts(int ot, TCGv reg) +{ + switch(ot) { + case OT_BYTE: + tcg_gen_ext8s_tl(reg, reg); + break; + case OT_WORD: + tcg_gen_ext16s_tl(reg, reg); + break; + case OT_LONG: + tcg_gen_ext32s_tl(reg, reg); + break; + default: + break; + } +} -static GenOpFunc *gen_op_out_DX_T0[3] = { - gen_op_outb_DX_T0, - gen_op_outw_DX_T0, - gen_op_outl_DX_T0, -}; +static inline void gen_op_jnz_ecx(int size, int label1) +{ + tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[R_ECX])); + gen_extu(size + 1, cpu_tmp0); + tcg_gen_brcondi_tl(TCG_COND_NE, cpu_tmp0, 0, label1); +} -static GenOpFunc *gen_op_in[3] = { - gen_op_inb_T0_T1, - gen_op_inw_T0_T1, - gen_op_inl_T0_T1, -}; +static inline void gen_op_jz_ecx(int size, int label1) +{ + tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[R_ECX])); + gen_extu(size + 1, cpu_tmp0); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, label1); +} -static GenOpFunc *gen_op_out[3] = { - gen_op_outb_T0_T1, - gen_op_outw_T0_T1, - gen_op_outl_T0_T1, +static void *helper_in_func[3] = { + helper_inb, + helper_inw, + helper_inl, }; -static GenOpFunc *gen_check_io_T0[3] = { - gen_op_check_iob_T0, - gen_op_check_iow_T0, - gen_op_check_iol_T0, +static void *helper_out_func[3] = { + helper_outb, + helper_outw, + helper_outl, }; -static GenOpFunc *gen_check_io_DX[3] = { - gen_op_check_iob_DX, - gen_op_check_iow_DX, - gen_op_check_iol_DX, +static void *gen_check_io_func[3] = { + helper_check_iob, + helper_check_iow, + helper_check_iol, }; -static void gen_check_io(DisasContext *s, int ot, int use_dx, target_ulong cur_eip) +static void gen_check_io(DisasContext *s, int ot, target_ulong cur_eip, + uint32_t svm_flags) { + int state_saved; + target_ulong next_eip; + + state_saved = 0; if (s->pe && (s->cpl > s->iopl || s->vm86)) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(cur_eip); - if (use_dx) - gen_check_io_DX[ot](); - else - gen_check_io_T0[ot](); + state_saved = 1; + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_0_1(gen_check_io_func[ot], + cpu_tmp2_i32); + } + if(s->flags & HF_SVMI_MASK) { + if (!state_saved) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(cur_eip); + state_saved = 1; + } + svm_flags |= (1 << (4 + ot)); + next_eip = s->pc - s->cs_base; + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_0_3(helper_svm_check_io, + cpu_tmp2_i32, + tcg_const_i32(svm_flags), + tcg_const_i32(next_eip - cur_eip)); } } static inline void gen_movs(DisasContext *s, int ot) { gen_string_movl_A0_ESI(s); - gen_op_ld_T0_A0[ot + s->mem_index](); + gen_op_ld_T0_A0(ot + s->mem_index); gen_string_movl_A0_EDI(s); - gen_op_st_T0_A0[ot + s->mem_index](); - gen_op_movl_T0_Dshift[ot](); -#ifdef TARGET_X86_64 - if (s->aflag == 2) { - gen_op_addq_ESI_T0(); - gen_op_addq_EDI_T0(); - } else -#endif - if (s->aflag) { - gen_op_addl_ESI_T0(); - gen_op_addl_EDI_T0(); - } else { - gen_op_addw_ESI_T0(); - gen_op_addw_EDI_T0(); - } + gen_op_st_T0_A0(ot + s->mem_index); + gen_op_movl_T0_Dshift(ot); + gen_op_add_reg_T0(s->aflag, R_ESI); + gen_op_add_reg_T0(s->aflag, R_EDI); } static inline void gen_update_cc_op(DisasContext *s) @@ -985,6 +771,383 @@ } } +static void gen_op_update1_cc(void) +{ + tcg_gen_discard_tl(cpu_cc_src); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); +} + +static void gen_op_update2_cc(void) +{ + tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); +} + +static inline void gen_op_cmpl_T0_T1_cc(void) +{ + tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]); + tcg_gen_sub_tl(cpu_cc_dst, cpu_T[0], cpu_T[1]); +} + +static inline void gen_op_testl_T0_T1_cc(void) +{ + tcg_gen_discard_tl(cpu_cc_src); + tcg_gen_and_tl(cpu_cc_dst, cpu_T[0], cpu_T[1]); +} + +static void gen_op_update_neg_cc(void) +{ + tcg_gen_neg_tl(cpu_cc_src, cpu_T[0]); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); +} + +/* compute eflags.C to reg */ +static void gen_compute_eflags_c(TCGv reg) +{ +#if TCG_TARGET_REG_BITS == 32 + tcg_gen_shli_i32(cpu_tmp2_i32, cpu_cc_op, 3); + tcg_gen_addi_i32(cpu_tmp2_i32, cpu_tmp2_i32, + (long)cc_table + offsetof(CCTable, compute_c)); + tcg_gen_ld_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0); + tcg_gen_call(&tcg_ctx, cpu_tmp2_i32, TCG_CALL_PURE, + 1, &cpu_tmp2_i32, 0, NULL); +#else + tcg_gen_extu_i32_tl(cpu_tmp1_i64, cpu_cc_op); + tcg_gen_shli_i64(cpu_tmp1_i64, cpu_tmp1_i64, 4); + tcg_gen_addi_i64(cpu_tmp1_i64, cpu_tmp1_i64, + (long)cc_table + offsetof(CCTable, compute_c)); + tcg_gen_ld_i64(cpu_tmp1_i64, cpu_tmp1_i64, 0); + tcg_gen_call(&tcg_ctx, cpu_tmp1_i64, TCG_CALL_PURE, + 1, &cpu_tmp2_i32, 0, NULL); +#endif + tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32); +} + +/* compute all eflags to cc_src */ +static void gen_compute_eflags(TCGv reg) +{ +#if TCG_TARGET_REG_BITS == 32 + tcg_gen_shli_i32(cpu_tmp2_i32, cpu_cc_op, 3); + tcg_gen_addi_i32(cpu_tmp2_i32, cpu_tmp2_i32, + (long)cc_table + offsetof(CCTable, compute_all)); + tcg_gen_ld_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0); + tcg_gen_call(&tcg_ctx, cpu_tmp2_i32, TCG_CALL_PURE, + 1, &cpu_tmp2_i32, 0, NULL); +#else + tcg_gen_extu_i32_tl(cpu_tmp1_i64, cpu_cc_op); + tcg_gen_shli_i64(cpu_tmp1_i64, cpu_tmp1_i64, 4); + tcg_gen_addi_i64(cpu_tmp1_i64, cpu_tmp1_i64, + (long)cc_table + offsetof(CCTable, compute_all)); + tcg_gen_ld_i64(cpu_tmp1_i64, cpu_tmp1_i64, 0); + tcg_gen_call(&tcg_ctx, cpu_tmp1_i64, TCG_CALL_PURE, + 1, &cpu_tmp2_i32, 0, NULL); +#endif + tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32); +} + +static inline void gen_setcc_slow_T0(DisasContext *s, int jcc_op) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + switch(jcc_op) { + case JCC_O: + gen_compute_eflags(cpu_T[0]); + tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 11); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); + break; + case JCC_B: + gen_compute_eflags_c(cpu_T[0]); + break; + case JCC_Z: + gen_compute_eflags(cpu_T[0]); + tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 6); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); + break; + case JCC_BE: + gen_compute_eflags(cpu_tmp0); + tcg_gen_shri_tl(cpu_T[0], cpu_tmp0, 6); + tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); + break; + case JCC_S: + gen_compute_eflags(cpu_T[0]); + tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 7); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); + break; + case JCC_P: + gen_compute_eflags(cpu_T[0]); + tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 2); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); + break; + case JCC_L: + gen_compute_eflags(cpu_tmp0); + tcg_gen_shri_tl(cpu_T[0], cpu_tmp0, 11); /* CC_O */ + tcg_gen_shri_tl(cpu_tmp0, cpu_tmp0, 7); /* CC_S */ + tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp0); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); + break; + default: + case JCC_LE: + gen_compute_eflags(cpu_tmp0); + tcg_gen_shri_tl(cpu_T[0], cpu_tmp0, 11); /* CC_O */ + tcg_gen_shri_tl(cpu_tmp4, cpu_tmp0, 7); /* CC_S */ + tcg_gen_shri_tl(cpu_tmp0, cpu_tmp0, 6); /* CC_Z */ + tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp4); + tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); + break; + } +} + +/* return true if setcc_slow is not needed (WARNING: must be kept in + sync with gen_jcc1) */ +static int is_fast_jcc_case(DisasContext *s, int b) +{ + int jcc_op; + jcc_op = (b >> 1) & 7; + switch(s->cc_op) { + /* we optimize the cmp/jcc case */ + case CC_OP_SUBB: + case CC_OP_SUBW: + case CC_OP_SUBL: + case CC_OP_SUBQ: + if (jcc_op == JCC_O || jcc_op == JCC_P) + goto slow_jcc; + break; + + /* some jumps are easy to compute */ + case CC_OP_ADDB: + case CC_OP_ADDW: + case CC_OP_ADDL: + case CC_OP_ADDQ: + + case CC_OP_LOGICB: + case CC_OP_LOGICW: + case CC_OP_LOGICL: + case CC_OP_LOGICQ: + + case CC_OP_INCB: + case CC_OP_INCW: + case CC_OP_INCL: + case CC_OP_INCQ: + + case CC_OP_DECB: + case CC_OP_DECW: + case CC_OP_DECL: + case CC_OP_DECQ: + + case CC_OP_SHLB: + case CC_OP_SHLW: + case CC_OP_SHLL: + case CC_OP_SHLQ: + if (jcc_op != JCC_Z && jcc_op != JCC_S) + goto slow_jcc; + break; + default: + slow_jcc: + return 0; + } + return 1; +} + +/* generate a conditional jump to label 'l1' according to jump opcode + value 'b'. In the fast case, T0 is guaranted not to be used. */ +static inline void gen_jcc1(DisasContext *s, int cc_op, int b, int l1) +{ + int inv, jcc_op, size, cond; + TCGv t0; + + inv = b & 1; + jcc_op = (b >> 1) & 7; + + switch(cc_op) { + /* we optimize the cmp/jcc case */ + case CC_OP_SUBB: + case CC_OP_SUBW: + case CC_OP_SUBL: + case CC_OP_SUBQ: + + size = cc_op - CC_OP_SUBB; + switch(jcc_op) { + case JCC_Z: + fast_jcc_z: + switch(size) { + case 0: + tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0xff); + t0 = cpu_tmp0; + break; + case 1: + tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0xffff); + t0 = cpu_tmp0; + break; +#ifdef TARGET_X86_64 + case 2: + tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0xffffffff); + t0 = cpu_tmp0; + break; +#endif + default: + t0 = cpu_cc_dst; + break; + } + tcg_gen_brcondi_tl(inv ? TCG_COND_NE : TCG_COND_EQ, t0, 0, l1); + break; + case JCC_S: + fast_jcc_s: + switch(size) { + case 0: + tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0x80); + tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0, + 0, l1); + break; + case 1: + tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0x8000); + tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0, + 0, l1); + break; +#ifdef TARGET_X86_64 + case 2: + tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0x80000000); + tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0, + 0, l1); + break; +#endif + default: + tcg_gen_brcondi_tl(inv ? TCG_COND_GE : TCG_COND_LT, cpu_cc_dst, + 0, l1); + break; + } + break; + + case JCC_B: + cond = inv ? TCG_COND_GEU : TCG_COND_LTU; + goto fast_jcc_b; + case JCC_BE: + cond = inv ? TCG_COND_GTU : TCG_COND_LEU; + fast_jcc_b: + tcg_gen_add_tl(cpu_tmp4, cpu_cc_dst, cpu_cc_src); + switch(size) { + case 0: + t0 = cpu_tmp0; + tcg_gen_andi_tl(cpu_tmp4, cpu_tmp4, 0xff); + tcg_gen_andi_tl(t0, cpu_cc_src, 0xff); + break; + case 1: + t0 = cpu_tmp0; + tcg_gen_andi_tl(cpu_tmp4, cpu_tmp4, 0xffff); + tcg_gen_andi_tl(t0, cpu_cc_src, 0xffff); + break; +#ifdef TARGET_X86_64 + case 2: + t0 = cpu_tmp0; + tcg_gen_andi_tl(cpu_tmp4, cpu_tmp4, 0xffffffff); + tcg_gen_andi_tl(t0, cpu_cc_src, 0xffffffff); + break; +#endif + default: + t0 = cpu_cc_src; + break; + } + tcg_gen_brcond_tl(cond, cpu_tmp4, t0, l1); + break; + + case JCC_L: + cond = inv ? TCG_COND_GE : TCG_COND_LT; + goto fast_jcc_l; + case JCC_LE: + cond = inv ? TCG_COND_GT : TCG_COND_LE; + fast_jcc_l: + tcg_gen_add_tl(cpu_tmp4, cpu_cc_dst, cpu_cc_src); + switch(size) { + case 0: + t0 = cpu_tmp0; + tcg_gen_ext8s_tl(cpu_tmp4, cpu_tmp4); + tcg_gen_ext8s_tl(t0, cpu_cc_src); + break; + case 1: + t0 = cpu_tmp0; + tcg_gen_ext16s_tl(cpu_tmp4, cpu_tmp4); + tcg_gen_ext16s_tl(t0, cpu_cc_src); + break; +#ifdef TARGET_X86_64 + case 2: + t0 = cpu_tmp0; + tcg_gen_ext32s_tl(cpu_tmp4, cpu_tmp4); + tcg_gen_ext32s_tl(t0, cpu_cc_src); + break; +#endif + default: + t0 = cpu_cc_src; + break; + } + tcg_gen_brcond_tl(cond, cpu_tmp4, t0, l1); + break; + + default: + goto slow_jcc; + } + break; + + /* some jumps are easy to compute */ + case CC_OP_ADDB: + case CC_OP_ADDW: + case CC_OP_ADDL: + case CC_OP_ADDQ: + + case CC_OP_ADCB: + case CC_OP_ADCW: + case CC_OP_ADCL: + case CC_OP_ADCQ: + + case CC_OP_SBBB: + case CC_OP_SBBW: + case CC_OP_SBBL: + case CC_OP_SBBQ: + + case CC_OP_LOGICB: + case CC_OP_LOGICW: + case CC_OP_LOGICL: + case CC_OP_LOGICQ: + + case CC_OP_INCB: + case CC_OP_INCW: + case CC_OP_INCL: + case CC_OP_INCQ: + + case CC_OP_DECB: + case CC_OP_DECW: + case CC_OP_DECL: + case CC_OP_DECQ: + + case CC_OP_SHLB: + case CC_OP_SHLW: + case CC_OP_SHLL: + case CC_OP_SHLQ: + + case CC_OP_SARB: + case CC_OP_SARW: + case CC_OP_SARL: + case CC_OP_SARQ: + switch(jcc_op) { + case JCC_Z: + size = (cc_op - CC_OP_ADDB) & 3; + goto fast_jcc_z; + case JCC_S: + size = (cc_op - CC_OP_ADDB) & 3; + goto fast_jcc_s; + default: + goto slow_jcc; + } + break; + default: + slow_jcc: + gen_setcc_slow_T0(s, jcc_op); + tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, + cpu_T[0], 0, l1); + break; + } +} + /* XXX: does not work with gdbstub "ice" single step - not a serious problem */ static int gen_jz_ecx_string(DisasContext *s, target_ulong next_eip) @@ -993,7 +1156,7 @@ l1 = gen_new_label(); l2 = gen_new_label(); - gen_op_jnz_ecx[s->aflag](l1); + gen_op_jnz_ecx(s->aflag, l1); gen_set_label(l2); gen_jmp_tb(s, next_eip, 1); gen_set_label(l1); @@ -1002,118 +1165,81 @@ static inline void gen_stos(DisasContext *s, int ot) { - gen_op_mov_TN_reg[OT_LONG][0][R_EAX](); + gen_op_mov_TN_reg(OT_LONG, 0, R_EAX); gen_string_movl_A0_EDI(s); - gen_op_st_T0_A0[ot + s->mem_index](); - gen_op_movl_T0_Dshift[ot](); -#ifdef TARGET_X86_64 - if (s->aflag == 2) { - gen_op_addq_EDI_T0(); - } else -#endif - if (s->aflag) { - gen_op_addl_EDI_T0(); - } else { - gen_op_addw_EDI_T0(); - } + gen_op_st_T0_A0(ot + s->mem_index); + gen_op_movl_T0_Dshift(ot); + gen_op_add_reg_T0(s->aflag, R_EDI); } static inline void gen_lods(DisasContext *s, int ot) { gen_string_movl_A0_ESI(s); - gen_op_ld_T0_A0[ot + s->mem_index](); - gen_op_mov_reg_T0[ot][R_EAX](); - gen_op_movl_T0_Dshift[ot](); -#ifdef TARGET_X86_64 - if (s->aflag == 2) { - gen_op_addq_ESI_T0(); - } else -#endif - if (s->aflag) { - gen_op_addl_ESI_T0(); - } else { - gen_op_addw_ESI_T0(); - } + gen_op_ld_T0_A0(ot + s->mem_index); + gen_op_mov_reg_T0(ot, R_EAX); + gen_op_movl_T0_Dshift(ot); + gen_op_add_reg_T0(s->aflag, R_ESI); } static inline void gen_scas(DisasContext *s, int ot) { - gen_op_mov_TN_reg[OT_LONG][0][R_EAX](); + gen_op_mov_TN_reg(OT_LONG, 0, R_EAX); gen_string_movl_A0_EDI(s); - gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_ld_T1_A0(ot + s->mem_index); gen_op_cmpl_T0_T1_cc(); - gen_op_movl_T0_Dshift[ot](); -#ifdef TARGET_X86_64 - if (s->aflag == 2) { - gen_op_addq_EDI_T0(); - } else -#endif - if (s->aflag) { - gen_op_addl_EDI_T0(); - } else { - gen_op_addw_EDI_T0(); - } + gen_op_movl_T0_Dshift(ot); + gen_op_add_reg_T0(s->aflag, R_EDI); } static inline void gen_cmps(DisasContext *s, int ot) { gen_string_movl_A0_ESI(s); - gen_op_ld_T0_A0[ot + s->mem_index](); + gen_op_ld_T0_A0(ot + s->mem_index); gen_string_movl_A0_EDI(s); - gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_ld_T1_A0(ot + s->mem_index); gen_op_cmpl_T0_T1_cc(); - gen_op_movl_T0_Dshift[ot](); -#ifdef TARGET_X86_64 - if (s->aflag == 2) { - gen_op_addq_ESI_T0(); - gen_op_addq_EDI_T0(); - } else -#endif - if (s->aflag) { - gen_op_addl_ESI_T0(); - gen_op_addl_EDI_T0(); - } else { - gen_op_addw_ESI_T0(); - gen_op_addw_EDI_T0(); - } + gen_op_movl_T0_Dshift(ot); + gen_op_add_reg_T0(s->aflag, R_ESI); + gen_op_add_reg_T0(s->aflag, R_EDI); } static inline void gen_ins(DisasContext *s, int ot) { + if (use_icount) + gen_io_start(); gen_string_movl_A0_EDI(s); + /* Note: we must do this dummy write first to be restartable in + case of page fault. */ gen_op_movl_T0_0(); - gen_op_st_T0_A0[ot + s->mem_index](); - gen_op_in_DX_T0[ot](); - gen_op_st_T0_A0[ot + s->mem_index](); - gen_op_movl_T0_Dshift[ot](); -#ifdef TARGET_X86_64 - if (s->aflag == 2) { - gen_op_addq_EDI_T0(); - } else -#endif - if (s->aflag) { - gen_op_addl_EDI_T0(); - } else { - gen_op_addw_EDI_T0(); - } + gen_op_st_T0_A0(ot + s->mem_index); + gen_op_mov_TN_reg(OT_WORD, 1, R_EDX); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[1]); + tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff); + tcg_gen_helper_1_1(helper_in_func[ot], cpu_T[0], cpu_tmp2_i32); + gen_op_st_T0_A0(ot + s->mem_index); + gen_op_movl_T0_Dshift(ot); + gen_op_add_reg_T0(s->aflag, R_EDI); + if (use_icount) + gen_io_end(); } static inline void gen_outs(DisasContext *s, int ot) { + if (use_icount) + gen_io_start(); gen_string_movl_A0_ESI(s); - gen_op_ld_T0_A0[ot + s->mem_index](); - gen_op_out_DX_T0[ot](); - gen_op_movl_T0_Dshift[ot](); -#ifdef TARGET_X86_64 - if (s->aflag == 2) { - gen_op_addq_ESI_T0(); - } else -#endif - if (s->aflag) { - gen_op_addl_ESI_T0(); - } else { - gen_op_addw_ESI_T0(); - } + gen_op_ld_T0_A0(ot + s->mem_index); + + gen_op_mov_TN_reg(OT_WORD, 1, R_EDX); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[1]); + tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff); + tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[0]); + tcg_gen_helper_0_2(helper_out_func[ot], cpu_tmp2_i32, cpu_tmp3_i32); + + gen_op_movl_T0_Dshift(ot); + gen_op_add_reg_T0(s->aflag, R_ESI); + if (use_icount) + gen_io_end(); } /* same method as Valgrind : we generate jumps to current or next @@ -1126,11 +1252,11 @@ gen_update_cc_op(s); \ l2 = gen_jz_ecx_string(s, next_eip); \ gen_ ## op(s, ot); \ - gen_op_dec_ECX[s->aflag](); \ + gen_op_add_reg_im(s->aflag, R_ECX, -1); \ /* a loop would cause two single step exceptions if ECX = 1 \ before rep string_insn */ \ if (!s->jmp_opt) \ - gen_op_jz_ecx[s->aflag](l2); \ + gen_op_jz_ecx(s->aflag, l2); \ gen_jmp(s, cur_eip); \ } @@ -1144,11 +1270,11 @@ gen_update_cc_op(s); \ l2 = gen_jz_ecx_string(s, next_eip); \ gen_ ## op(s, ot); \ - gen_op_dec_ECX[s->aflag](); \ + gen_op_add_reg_im(s->aflag, R_ECX, -1); \ gen_op_set_cc_op(CC_OP_SUBB + ot); \ - gen_op_string_jnz_sub[nz][ot](l2);\ + gen_jcc1(s, CC_OP_SUBB + ot, (JCC_Z << 1) | (nz ^ 1), l2); \ if (!s->jmp_opt) \ - gen_op_jz_ecx[s->aflag](l2); \ + gen_op_jz_ecx(s->aflag, l2); \ gen_jmp(s, cur_eip); \ } @@ -1160,269 +1286,600 @@ GEN_REPZ2(scas) GEN_REPZ2(cmps) -enum { - JCC_O, - JCC_B, - JCC_Z, - JCC_BE, - JCC_S, - JCC_P, - JCC_L, - JCC_LE, +static void *helper_fp_arith_ST0_FT0[8] = { + helper_fadd_ST0_FT0, + helper_fmul_ST0_FT0, + helper_fcom_ST0_FT0, + helper_fcom_ST0_FT0, + helper_fsub_ST0_FT0, + helper_fsubr_ST0_FT0, + helper_fdiv_ST0_FT0, + helper_fdivr_ST0_FT0, }; -static GenOpFunc1 *gen_jcc_sub[4][8] = { - [OT_BYTE] = { - NULL, - gen_op_jb_subb, - gen_op_jz_subb, - gen_op_jbe_subb, - gen_op_js_subb, - NULL, - gen_op_jl_subb, - gen_op_jle_subb, - }, - [OT_WORD] = { - NULL, - gen_op_jb_subw, - gen_op_jz_subw, - gen_op_jbe_subw, - gen_op_js_subw, - NULL, - gen_op_jl_subw, - gen_op_jle_subw, - }, - [OT_LONG] = { - NULL, - gen_op_jb_subl, - gen_op_jz_subl, - gen_op_jbe_subl, - gen_op_js_subl, - NULL, - gen_op_jl_subl, - gen_op_jle_subl, - }, -#ifdef TARGET_X86_64 - [OT_QUAD] = { - NULL, - BUGGY_64(gen_op_jb_subq), - gen_op_jz_subq, - BUGGY_64(gen_op_jbe_subq), - gen_op_js_subq, - NULL, - BUGGY_64(gen_op_jl_subq), - BUGGY_64(gen_op_jle_subq), - }, -#endif -}; -static GenOpFunc1 *gen_op_loop[3][4] = { - [0] = { - gen_op_loopnzw, - gen_op_loopzw, - gen_op_jnz_ecxw, - }, - [1] = { - gen_op_loopnzl, - gen_op_loopzl, - gen_op_jnz_ecxl, - }, -#ifdef TARGET_X86_64 - [2] = { - gen_op_loopnzq, - gen_op_loopzq, - gen_op_jnz_ecxq, - }, -#endif +/* NOTE the exception in "r" op ordering */ +static void *helper_fp_arith_STN_ST0[8] = { + helper_fadd_STN_ST0, + helper_fmul_STN_ST0, + NULL, + NULL, + helper_fsubr_STN_ST0, + helper_fsub_STN_ST0, + helper_fdivr_STN_ST0, + helper_fdiv_STN_ST0, }; -static GenOpFunc *gen_setcc_slow[8] = { - gen_op_seto_T0_cc, - gen_op_setb_T0_cc, - gen_op_setz_T0_cc, - gen_op_setbe_T0_cc, - gen_op_sets_T0_cc, - gen_op_setp_T0_cc, - gen_op_setl_T0_cc, - gen_op_setle_T0_cc, -}; +/* if d == OR_TMP0, it means memory operand (address in A0) */ +static void gen_op(DisasContext *s1, int op, int ot, int d) +{ + if (d != OR_TMP0) { + gen_op_mov_TN_reg(ot, 0, d); + } else { + gen_op_ld_T0_A0(ot + s1->mem_index); + } + switch(op) { + case OP_ADCL: + if (s1->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s1->cc_op); + gen_compute_eflags_c(cpu_tmp4); + tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_tmp4); + if (d != OR_TMP0) + gen_op_mov_reg_T0(ot, d); + else + gen_op_st_T0_A0(ot + s1->mem_index); + tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp4); + tcg_gen_shli_i32(cpu_tmp2_i32, cpu_tmp2_i32, 2); + tcg_gen_addi_i32(cpu_cc_op, cpu_tmp2_i32, CC_OP_ADDB + ot); + s1->cc_op = CC_OP_DYNAMIC; + break; + case OP_SBBL: + if (s1->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s1->cc_op); + gen_compute_eflags_c(cpu_tmp4); + tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_tmp4); + if (d != OR_TMP0) + gen_op_mov_reg_T0(ot, d); + else + gen_op_st_T0_A0(ot + s1->mem_index); + tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp4); + tcg_gen_shli_i32(cpu_tmp2_i32, cpu_tmp2_i32, 2); + tcg_gen_addi_i32(cpu_cc_op, cpu_tmp2_i32, CC_OP_SUBB + ot); + s1->cc_op = CC_OP_DYNAMIC; + break; + case OP_ADDL: + gen_op_addl_T0_T1(); + if (d != OR_TMP0) + gen_op_mov_reg_T0(ot, d); + else + gen_op_st_T0_A0(ot + s1->mem_index); + gen_op_update2_cc(); + s1->cc_op = CC_OP_ADDB + ot; + break; + case OP_SUBL: + tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + if (d != OR_TMP0) + gen_op_mov_reg_T0(ot, d); + else + gen_op_st_T0_A0(ot + s1->mem_index); + gen_op_update2_cc(); + s1->cc_op = CC_OP_SUBB + ot; + break; + default: + case OP_ANDL: + tcg_gen_and_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + if (d != OR_TMP0) + gen_op_mov_reg_T0(ot, d); + else + gen_op_st_T0_A0(ot + s1->mem_index); + gen_op_update1_cc(); + s1->cc_op = CC_OP_LOGICB + ot; + break; + case OP_ORL: + tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + if (d != OR_TMP0) + gen_op_mov_reg_T0(ot, d); + else + gen_op_st_T0_A0(ot + s1->mem_index); + gen_op_update1_cc(); + s1->cc_op = CC_OP_LOGICB + ot; + break; + case OP_XORL: + tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + if (d != OR_TMP0) + gen_op_mov_reg_T0(ot, d); + else + gen_op_st_T0_A0(ot + s1->mem_index); + gen_op_update1_cc(); + s1->cc_op = CC_OP_LOGICB + ot; + break; + case OP_CMPL: + gen_op_cmpl_T0_T1_cc(); + s1->cc_op = CC_OP_SUBB + ot; + break; + } +} -static GenOpFunc *gen_setcc_sub[4][8] = { - [OT_BYTE] = { - NULL, - gen_op_setb_T0_subb, - gen_op_setz_T0_subb, - gen_op_setbe_T0_subb, - gen_op_sets_T0_subb, - NULL, - gen_op_setl_T0_subb, - gen_op_setle_T0_subb, - }, - [OT_WORD] = { - NULL, - gen_op_setb_T0_subw, - gen_op_setz_T0_subw, - gen_op_setbe_T0_subw, - gen_op_sets_T0_subw, - NULL, - gen_op_setl_T0_subw, - gen_op_setle_T0_subw, - }, - [OT_LONG] = { - NULL, - gen_op_setb_T0_subl, - gen_op_setz_T0_subl, - gen_op_setbe_T0_subl, - gen_op_sets_T0_subl, - NULL, - gen_op_setl_T0_subl, - gen_op_setle_T0_subl, - }, -#ifdef TARGET_X86_64 - [OT_QUAD] = { - NULL, - gen_op_setb_T0_subq, - gen_op_setz_T0_subq, - gen_op_setbe_T0_subq, - gen_op_sets_T0_subq, - NULL, - gen_op_setl_T0_subq, - gen_op_setle_T0_subq, - }, -#endif -}; +/* if d == OR_TMP0, it means memory operand (address in A0) */ +static void gen_inc(DisasContext *s1, int ot, int d, int c) +{ + if (d != OR_TMP0) + gen_op_mov_TN_reg(ot, 0, d); + else + gen_op_ld_T0_A0(ot + s1->mem_index); + if (s1->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s1->cc_op); + if (c > 0) { + tcg_gen_addi_tl(cpu_T[0], cpu_T[0], 1); + s1->cc_op = CC_OP_INCB + ot; + } else { + tcg_gen_addi_tl(cpu_T[0], cpu_T[0], -1); + s1->cc_op = CC_OP_DECB + ot; + } + if (d != OR_TMP0) + gen_op_mov_reg_T0(ot, d); + else + gen_op_st_T0_A0(ot + s1->mem_index); + gen_compute_eflags_c(cpu_cc_src); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); +} + +static void gen_shift_rm_T1(DisasContext *s, int ot, int op1, + int is_right, int is_arith) +{ + target_ulong mask; + int shift_label; + TCGv t0, t1; + + if (ot == OT_QUAD) + mask = 0x3f; + else + mask = 0x1f; + + /* load */ + if (op1 == OR_TMP0) + gen_op_ld_T0_A0(ot + s->mem_index); + else + gen_op_mov_TN_reg(ot, 0, op1); + + tcg_gen_andi_tl(cpu_T[1], cpu_T[1], mask); + + tcg_gen_addi_tl(cpu_tmp5, cpu_T[1], -1); + + if (is_right) { + if (is_arith) { + gen_exts(ot, cpu_T[0]); + tcg_gen_sar_tl(cpu_T3, cpu_T[0], cpu_tmp5); + tcg_gen_sar_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + } else { + gen_extu(ot, cpu_T[0]); + tcg_gen_shr_tl(cpu_T3, cpu_T[0], cpu_tmp5); + tcg_gen_shr_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + } + } else { + tcg_gen_shl_tl(cpu_T3, cpu_T[0], cpu_tmp5); + tcg_gen_shl_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + } + + /* store */ + if (op1 == OR_TMP0) + gen_op_st_T0_A0(ot + s->mem_index); + else + gen_op_mov_reg_T0(ot, op1); + + /* update eflags if non zero shift */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + + /* XXX: inefficient */ + t0 = tcg_temp_local_new(TCG_TYPE_TL); + t1 = tcg_temp_local_new(TCG_TYPE_TL); + + tcg_gen_mov_tl(t0, cpu_T[0]); + tcg_gen_mov_tl(t1, cpu_T3); + + shift_label = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_T[1], 0, shift_label); + + tcg_gen_mov_tl(cpu_cc_src, t1); + tcg_gen_mov_tl(cpu_cc_dst, t0); + if (is_right) + tcg_gen_movi_i32(cpu_cc_op, CC_OP_SARB + ot); + else + tcg_gen_movi_i32(cpu_cc_op, CC_OP_SHLB + ot); + + gen_set_label(shift_label); + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ + + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void gen_shift_rm_im(DisasContext *s, int ot, int op1, int op2, + int is_right, int is_arith) +{ + int mask; + + if (ot == OT_QUAD) + mask = 0x3f; + else + mask = 0x1f; + + /* load */ + if (op1 == OR_TMP0) + gen_op_ld_T0_A0(ot + s->mem_index); + else + gen_op_mov_TN_reg(ot, 0, op1); + + op2 &= mask; + if (op2 != 0) { + if (is_right) { + if (is_arith) { + gen_exts(ot, cpu_T[0]); + tcg_gen_sari_tl(cpu_tmp4, cpu_T[0], op2 - 1); + tcg_gen_sari_tl(cpu_T[0], cpu_T[0], op2); + } else { + gen_extu(ot, cpu_T[0]); + tcg_gen_shri_tl(cpu_tmp4, cpu_T[0], op2 - 1); + tcg_gen_shri_tl(cpu_T[0], cpu_T[0], op2); + } + } else { + tcg_gen_shli_tl(cpu_tmp4, cpu_T[0], op2 - 1); + tcg_gen_shli_tl(cpu_T[0], cpu_T[0], op2); + } + } + + /* store */ + if (op1 == OR_TMP0) + gen_op_st_T0_A0(ot + s->mem_index); + else + gen_op_mov_reg_T0(ot, op1); + + /* update eflags if non zero shift */ + if (op2 != 0) { + tcg_gen_mov_tl(cpu_cc_src, cpu_tmp4); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + if (is_right) + s->cc_op = CC_OP_SARB + ot; + else + s->cc_op = CC_OP_SHLB + ot; + } +} + +static inline void tcg_gen_lshift(TCGv ret, TCGv arg1, target_long arg2) +{ + if (arg2 >= 0) + tcg_gen_shli_tl(ret, arg1, arg2); + else + tcg_gen_shri_tl(ret, arg1, -arg2); +} + +/* XXX: add faster immediate case */ +static void gen_rot_rm_T1(DisasContext *s, int ot, int op1, + int is_right) +{ + target_ulong mask; + int label1, label2, data_bits; + TCGv t0, t1, t2, a0; + + /* XXX: inefficient, but we must use local temps */ + t0 = tcg_temp_local_new(TCG_TYPE_TL); + t1 = tcg_temp_local_new(TCG_TYPE_TL); + t2 = tcg_temp_local_new(TCG_TYPE_TL); + a0 = tcg_temp_local_new(TCG_TYPE_TL); + + if (ot == OT_QUAD) + mask = 0x3f; + else + mask = 0x1f; + + /* load */ + if (op1 == OR_TMP0) { + tcg_gen_mov_tl(a0, cpu_A0); + gen_op_ld_v(ot + s->mem_index, t0, a0); + } else { + gen_op_mov_v_reg(ot, t0, op1); + } + + tcg_gen_mov_tl(t1, cpu_T[1]); + + tcg_gen_andi_tl(t1, t1, mask); + + /* Must test zero case to avoid using undefined behaviour in TCG + shifts. */ + label1 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, label1); + + if (ot <= OT_WORD) + tcg_gen_andi_tl(cpu_tmp0, t1, (1 << (3 + ot)) - 1); + else + tcg_gen_mov_tl(cpu_tmp0, t1); + + gen_extu(ot, t0); + tcg_gen_mov_tl(t2, t0); + + data_bits = 8 << ot; + /* XXX: rely on behaviour of shifts when operand 2 overflows (XXX: + fix TCG definition) */ + if (is_right) { + tcg_gen_shr_tl(cpu_tmp4, t0, cpu_tmp0); + tcg_gen_sub_tl(cpu_tmp0, tcg_const_tl(data_bits), cpu_tmp0); + tcg_gen_shl_tl(t0, t0, cpu_tmp0); + } else { + tcg_gen_shl_tl(cpu_tmp4, t0, cpu_tmp0); + tcg_gen_sub_tl(cpu_tmp0, tcg_const_tl(data_bits), cpu_tmp0); + tcg_gen_shr_tl(t0, t0, cpu_tmp0); + } + tcg_gen_or_tl(t0, t0, cpu_tmp4); + + gen_set_label(label1); + /* store */ + if (op1 == OR_TMP0) { + gen_op_st_v(ot + s->mem_index, t0, a0); + } else { + gen_op_mov_reg_v(ot, op1, t0); + } + + /* update eflags */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + + label2 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, label2); + + gen_compute_eflags(cpu_cc_src); + tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~(CC_O | CC_C)); + tcg_gen_xor_tl(cpu_tmp0, t2, t0); + tcg_gen_lshift(cpu_tmp0, cpu_tmp0, 11 - (data_bits - 1)); + tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, CC_O); + tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_tmp0); + if (is_right) { + tcg_gen_shri_tl(t0, t0, data_bits - 1); + } + tcg_gen_andi_tl(t0, t0, CC_C); + tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t0); + + tcg_gen_discard_tl(cpu_cc_dst); + tcg_gen_movi_i32(cpu_cc_op, CC_OP_EFLAGS); + + gen_set_label(label2); + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ + + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free(t2); + tcg_temp_free(a0); +} + +static void *helper_rotc[8] = { + helper_rclb, + helper_rclw, + helper_rcll, + X86_64_ONLY(helper_rclq), + helper_rcrb, + helper_rcrw, + helper_rcrl, + X86_64_ONLY(helper_rcrq), +}; + +/* XXX: add faster immediate = 1 case */ +static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1, + int is_right) +{ + int label1; + + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); -static GenOpFunc *gen_op_fp_arith_ST0_FT0[8] = { - gen_op_fadd_ST0_FT0, - gen_op_fmul_ST0_FT0, - gen_op_fcom_ST0_FT0, - gen_op_fcom_ST0_FT0, - gen_op_fsub_ST0_FT0, - gen_op_fsubr_ST0_FT0, - gen_op_fdiv_ST0_FT0, - gen_op_fdivr_ST0_FT0, -}; + /* load */ + if (op1 == OR_TMP0) + gen_op_ld_T0_A0(ot + s->mem_index); + else + gen_op_mov_TN_reg(ot, 0, op1); + + tcg_gen_helper_1_2(helper_rotc[ot + (is_right * 4)], + cpu_T[0], cpu_T[0], cpu_T[1]); + /* store */ + if (op1 == OR_TMP0) + gen_op_st_T0_A0(ot + s->mem_index); + else + gen_op_mov_reg_T0(ot, op1); -/* NOTE the exception in "r" op ordering */ -static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = { - gen_op_fadd_STN_ST0, - gen_op_fmul_STN_ST0, - NULL, - NULL, - gen_op_fsubr_STN_ST0, - gen_op_fsub_STN_ST0, - gen_op_fdivr_STN_ST0, - gen_op_fdiv_STN_ST0, -}; + /* update eflags */ + label1 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_cc_tmp, -1, label1); + + tcg_gen_mov_tl(cpu_cc_src, cpu_cc_tmp); + tcg_gen_discard_tl(cpu_cc_dst); + tcg_gen_movi_i32(cpu_cc_op, CC_OP_EFLAGS); + + gen_set_label(label1); + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ +} + +/* XXX: add faster immediate case */ +static void gen_shiftd_rm_T1_T3(DisasContext *s, int ot, int op1, + int is_right) +{ + int label1, label2, data_bits; + target_ulong mask; + TCGv t0, t1, t2, a0; + + t0 = tcg_temp_local_new(TCG_TYPE_TL); + t1 = tcg_temp_local_new(TCG_TYPE_TL); + t2 = tcg_temp_local_new(TCG_TYPE_TL); + a0 = tcg_temp_local_new(TCG_TYPE_TL); -/* if d == OR_TMP0, it means memory operand (address in A0) */ -static void gen_op(DisasContext *s1, int op, int ot, int d) -{ - GenOpFunc *gen_update_cc; + if (ot == OT_QUAD) + mask = 0x3f; + else + mask = 0x1f; - if (d != OR_TMP0) { - gen_op_mov_TN_reg[ot][0][d](); + /* load */ + if (op1 == OR_TMP0) { + tcg_gen_mov_tl(a0, cpu_A0); + gen_op_ld_v(ot + s->mem_index, t0, a0); } else { - gen_op_ld_T0_A0[ot + s1->mem_index](); + gen_op_mov_v_reg(ot, t0, op1); } - switch(op) { - case OP_ADCL: - case OP_SBBL: - if (s1->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s1->cc_op); - if (d != OR_TMP0) { - gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL](); - gen_op_mov_reg_T0[ot][d](); - } else { - gen_op_arithc_mem_T0_T1_cc[ot + s1->mem_index][op - OP_ADCL](); + + tcg_gen_andi_tl(cpu_T3, cpu_T3, mask); + + tcg_gen_mov_tl(t1, cpu_T[1]); + tcg_gen_mov_tl(t2, cpu_T3); + + /* Must test zero case to avoid using undefined behaviour in TCG + shifts. */ + label1 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label1); + + tcg_gen_addi_tl(cpu_tmp5, t2, -1); + if (ot == OT_WORD) { + /* Note: we implement the Intel behaviour for shift count > 16 */ + if (is_right) { + tcg_gen_andi_tl(t0, t0, 0xffff); + tcg_gen_shli_tl(cpu_tmp0, t1, 16); + tcg_gen_or_tl(t0, t0, cpu_tmp0); + tcg_gen_ext32u_tl(t0, t0); + + tcg_gen_shr_tl(cpu_tmp4, t0, cpu_tmp5); + + /* only needed if count > 16, but a test would complicate */ + tcg_gen_sub_tl(cpu_tmp5, tcg_const_tl(32), t2); + tcg_gen_shl_tl(cpu_tmp0, t0, cpu_tmp5); + + tcg_gen_shr_tl(t0, t0, t2); + + tcg_gen_or_tl(t0, t0, cpu_tmp0); + } else { + /* XXX: not optimal */ + tcg_gen_andi_tl(t0, t0, 0xffff); + tcg_gen_shli_tl(t1, t1, 16); + tcg_gen_or_tl(t1, t1, t0); + tcg_gen_ext32u_tl(t1, t1); + + tcg_gen_shl_tl(cpu_tmp4, t0, cpu_tmp5); + tcg_gen_sub_tl(cpu_tmp0, tcg_const_tl(32), cpu_tmp5); + tcg_gen_shr_tl(cpu_tmp6, t1, cpu_tmp0); + tcg_gen_or_tl(cpu_tmp4, cpu_tmp4, cpu_tmp6); + + tcg_gen_shl_tl(t0, t0, t2); + tcg_gen_sub_tl(cpu_tmp5, tcg_const_tl(32), t2); + tcg_gen_shr_tl(t1, t1, cpu_tmp5); + tcg_gen_or_tl(t0, t0, t1); } - s1->cc_op = CC_OP_DYNAMIC; - goto the_end; - case OP_ADDL: - gen_op_addl_T0_T1(); - s1->cc_op = CC_OP_ADDB + ot; - gen_update_cc = gen_op_update2_cc; - break; - case OP_SUBL: - gen_op_subl_T0_T1(); - s1->cc_op = CC_OP_SUBB + ot; - gen_update_cc = gen_op_update2_cc; - break; - default: - case OP_ANDL: - case OP_ORL: - case OP_XORL: - gen_op_arith_T0_T1_cc[op](); - s1->cc_op = CC_OP_LOGICB + ot; - gen_update_cc = gen_op_update1_cc; - break; - case OP_CMPL: - gen_op_cmpl_T0_T1_cc(); - s1->cc_op = CC_OP_SUBB + ot; - gen_update_cc = NULL; - break; - } - if (op != OP_CMPL) { - if (d != OR_TMP0) - gen_op_mov_reg_T0[ot][d](); - else - gen_op_st_T0_A0[ot + s1->mem_index](); + } else { + data_bits = 8 << ot; + if (is_right) { + if (ot == OT_LONG) + tcg_gen_ext32u_tl(t0, t0); + + tcg_gen_shr_tl(cpu_tmp4, t0, cpu_tmp5); + + tcg_gen_shr_tl(t0, t0, t2); + tcg_gen_sub_tl(cpu_tmp5, tcg_const_tl(data_bits), t2); + tcg_gen_shl_tl(t1, t1, cpu_tmp5); + tcg_gen_or_tl(t0, t0, t1); + + } else { + if (ot == OT_LONG) + tcg_gen_ext32u_tl(t1, t1); + + tcg_gen_shl_tl(cpu_tmp4, t0, cpu_tmp5); + + tcg_gen_shl_tl(t0, t0, t2); + tcg_gen_sub_tl(cpu_tmp5, tcg_const_tl(data_bits), t2); + tcg_gen_shr_tl(t1, t1, cpu_tmp5); + tcg_gen_or_tl(t0, t0, t1); + } + } + tcg_gen_mov_tl(t1, cpu_tmp4); + + gen_set_label(label1); + /* store */ + if (op1 == OR_TMP0) { + gen_op_st_v(ot + s->mem_index, t0, a0); + } else { + gen_op_mov_reg_v(ot, op1, t0); } - /* the flags update must happen after the memory write (precise - exception support) */ - if (gen_update_cc) - gen_update_cc(); - the_end: ; -} + + /* update eflags */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); -/* if d == OR_TMP0, it means memory operand (address in A0) */ -static void gen_inc(DisasContext *s1, int ot, int d, int c) -{ - if (d != OR_TMP0) - gen_op_mov_TN_reg[ot][0][d](); - else - gen_op_ld_T0_A0[ot + s1->mem_index](); - if (s1->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s1->cc_op); - if (c > 0) { - gen_op_incl_T0(); - s1->cc_op = CC_OP_INCB + ot; + label2 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label2); + + tcg_gen_mov_tl(cpu_cc_src, t1); + tcg_gen_mov_tl(cpu_cc_dst, t0); + if (is_right) { + tcg_gen_movi_i32(cpu_cc_op, CC_OP_SARB + ot); } else { - gen_op_decl_T0(); - s1->cc_op = CC_OP_DECB + ot; + tcg_gen_movi_i32(cpu_cc_op, CC_OP_SHLB + ot); } - if (d != OR_TMP0) - gen_op_mov_reg_T0[ot][d](); - else - gen_op_st_T0_A0[ot + s1->mem_index](); - gen_op_update_inc_cc(); + gen_set_label(label2); + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ + + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free(t2); + tcg_temp_free(a0); } static void gen_shift(DisasContext *s1, int op, int ot, int d, int s) { - if (d != OR_TMP0) - gen_op_mov_TN_reg[ot][0][d](); - else - gen_op_ld_T0_A0[ot + s1->mem_index](); if (s != OR_TMP1) - gen_op_mov_TN_reg[ot][1][s](); - /* for zero counts, flags are not updated, so must do it dynamically */ - if (s1->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s1->cc_op); - - if (d != OR_TMP0) - gen_op_shift_T0_T1_cc[ot][op](); - else - gen_op_shift_mem_T0_T1_cc[ot + s1->mem_index][op](); - if (d != OR_TMP0) - gen_op_mov_reg_T0[ot][d](); - s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ + gen_op_mov_TN_reg(ot, 1, s); + switch(op) { + case OP_ROL: + gen_rot_rm_T1(s1, ot, d, 0); + break; + case OP_ROR: + gen_rot_rm_T1(s1, ot, d, 1); + break; + case OP_SHL: + case OP_SHL1: + gen_shift_rm_T1(s1, ot, d, 0, 0); + break; + case OP_SHR: + gen_shift_rm_T1(s1, ot, d, 1, 0); + break; + case OP_SAR: + gen_shift_rm_T1(s1, ot, d, 1, 1); + break; + case OP_RCL: + gen_rotc_rm_T1(s1, ot, d, 0); + break; + case OP_RCR: + gen_rotc_rm_T1(s1, ot, d, 1); + break; + } } static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c) { - /* currently not optimized */ - gen_op_movl_T1_im(c); - gen_shift(s1, op, ot, d, OR_TMP1); + switch(op) { + case OP_SHL: + case OP_SHL1: + gen_shift_rm_im(s1, ot, d, c, 0, 0); + break; + case OP_SHR: + gen_shift_rm_im(s1, ot, d, c, 1, 0); + break; + case OP_SAR: + gen_shift_rm_im(s1, ot, d, c, 1, 1); + break; + default: + /* currently not optimized */ + gen_op_movl_T1_im(c); + gen_shift(s1, op, ot, d, OR_TMP1); + break; + } } static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr) @@ -1487,27 +1944,21 @@ disp += s->popl_esp_hack; #ifdef TARGET_X86_64 if (s->aflag == 2) { - gen_op_movq_A0_reg[base](); + gen_op_movq_A0_reg(base); if (disp != 0) { - if ((int32_t)disp == disp) - gen_op_addq_A0_im(disp); - else - gen_op_addq_A0_im64(disp >> 32, disp); + gen_op_addq_A0_im(disp); } } else #endif { - gen_op_movl_A0_reg[base](); + gen_op_movl_A0_reg(base); if (disp != 0) gen_op_addl_A0_im(disp); } } else { #ifdef TARGET_X86_64 if (s->aflag == 2) { - if ((int32_t)disp == disp) - gen_op_movq_A0_im(disp); - else - gen_op_movq_A0_im64(disp >> 32, disp); + gen_op_movq_A0_im(disp); } else #endif { @@ -1518,11 +1969,11 @@ if (havesib && (index != 4 || scale != 0)) { #ifdef TARGET_X86_64 if (s->aflag == 2) { - gen_op_addq_A0_reg_sN[scale][index](); + gen_op_addq_A0_reg_sN(scale, index); } else #endif { - gen_op_addl_A0_reg_sN[scale][index](); + gen_op_addl_A0_reg_sN(scale, index); } } if (must_add_seg) { @@ -1534,11 +1985,11 @@ } #ifdef TARGET_X86_64 if (s->aflag == 2) { - gen_op_addq_A0_seg(offsetof(CPUX86State,segs[override].base)); + gen_op_addq_A0_seg(override); } else #endif { - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + gen_op_addl_A0_seg(override); } } } else { @@ -1565,33 +2016,33 @@ } switch(rm) { case 0: - gen_op_movl_A0_reg[R_EBX](); - gen_op_addl_A0_reg_sN[0][R_ESI](); + gen_op_movl_A0_reg(R_EBX); + gen_op_addl_A0_reg_sN(0, R_ESI); break; case 1: - gen_op_movl_A0_reg[R_EBX](); - gen_op_addl_A0_reg_sN[0][R_EDI](); + gen_op_movl_A0_reg(R_EBX); + gen_op_addl_A0_reg_sN(0, R_EDI); break; case 2: - gen_op_movl_A0_reg[R_EBP](); - gen_op_addl_A0_reg_sN[0][R_ESI](); + gen_op_movl_A0_reg(R_EBP); + gen_op_addl_A0_reg_sN(0, R_ESI); break; case 3: - gen_op_movl_A0_reg[R_EBP](); - gen_op_addl_A0_reg_sN[0][R_EDI](); + gen_op_movl_A0_reg(R_EBP); + gen_op_addl_A0_reg_sN(0, R_EDI); break; case 4: - gen_op_movl_A0_reg[R_ESI](); + gen_op_movl_A0_reg(R_ESI); break; case 5: - gen_op_movl_A0_reg[R_EDI](); + gen_op_movl_A0_reg(R_EDI); break; case 6: - gen_op_movl_A0_reg[R_EBP](); + gen_op_movl_A0_reg(R_EBP); break; default: case 7: - gen_op_movl_A0_reg[R_EBX](); + gen_op_movl_A0_reg(R_EBX); break; } if (disp != 0) @@ -1605,7 +2056,7 @@ else override = R_DS; } - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + gen_op_addl_A0_seg(override); } } @@ -1680,16 +2131,16 @@ if (must_add_seg) { #ifdef TARGET_X86_64 if (CODE64(s)) { - gen_op_addq_A0_seg(offsetof(CPUX86State,segs[override].base)); + gen_op_addq_A0_seg(override); } else #endif { - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + gen_op_addl_A0_seg(override); } } } -/* generate modrm memory load or store of 'reg'. TMP0 is used if reg != +/* generate modrm memory load or store of 'reg'. TMP0 is used if reg == OR_TMP0 */ static void gen_ldst_modrm(DisasContext *s, int modrm, int ot, int reg, int is_store) { @@ -1700,23 +2151,23 @@ if (mod == 3) { if (is_store) { if (reg != OR_TMP0) - gen_op_mov_TN_reg[ot][0][reg](); - gen_op_mov_reg_T0[ot][rm](); + gen_op_mov_TN_reg(ot, 0, reg); + gen_op_mov_reg_T0(ot, rm); } else { - gen_op_mov_TN_reg[ot][0][rm](); + gen_op_mov_TN_reg(ot, 0, rm); if (reg != OR_TMP0) - gen_op_mov_reg_T0[ot][reg](); + gen_op_mov_reg_T0(ot, reg); } } else { gen_lea_modrm(s, modrm, &opreg, &disp); if (is_store) { if (reg != OR_TMP0) - gen_op_mov_TN_reg[ot][0][reg](); - gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_mov_TN_reg(ot, 0, reg); + gen_op_st_T0_A0(ot + s->mem_index); } else { - gen_op_ld_T0_A0[ot + s->mem_index](); + gen_op_ld_T0_A0(ot + s->mem_index); if (reg != OR_TMP0) - gen_op_mov_reg_T0[ot][reg](); + gen_op_mov_reg_T0(ot, reg); } } } @@ -1762,13 +2213,9 @@ if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) || (pc & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK)) { /* jump to same page: we can use a direct jump */ - if (tb_num == 0) - gen_op_goto_tb0(TBPARAM(tb)); - else - gen_op_goto_tb1(TBPARAM(tb)); + tcg_gen_goto_tb(tb_num); gen_jmp_im(eip); - gen_op_movl_T0_im((long)tb + tb_num); - gen_op_exit_tb(); + tcg_gen_exit_tb((long)tb + tb_num); } else { /* jump to another page: currently not optimized */ gen_jmp_im(eip); @@ -1779,125 +2226,31 @@ static inline void gen_jcc(DisasContext *s, int b, target_ulong val, target_ulong next_eip) { - TranslationBlock *tb; - int inv, jcc_op; - GenOpFunc1 *func; - target_ulong tmp; - int l1, l2; - - inv = b & 1; - jcc_op = (b >> 1) & 7; + int l1, l2, cc_op; + cc_op = s->cc_op; + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } if (s->jmp_opt) { - switch(s->cc_op) { - /* we optimize the cmp/jcc case */ - case CC_OP_SUBB: - case CC_OP_SUBW: - case CC_OP_SUBL: - case CC_OP_SUBQ: - func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; - break; - - /* some jumps are easy to compute */ - case CC_OP_ADDB: - case CC_OP_ADDW: - case CC_OP_ADDL: - case CC_OP_ADDQ: - - case CC_OP_ADCB: - case CC_OP_ADCW: - case CC_OP_ADCL: - case CC_OP_ADCQ: - - case CC_OP_SBBB: - case CC_OP_SBBW: - case CC_OP_SBBL: - case CC_OP_SBBQ: - - case CC_OP_LOGICB: - case CC_OP_LOGICW: - case CC_OP_LOGICL: - case CC_OP_LOGICQ: - - case CC_OP_INCB: - case CC_OP_INCW: - case CC_OP_INCL: - case CC_OP_INCQ: - - case CC_OP_DECB: - case CC_OP_DECW: - case CC_OP_DECL: - case CC_OP_DECQ: - - case CC_OP_SHLB: - case CC_OP_SHLW: - case CC_OP_SHLL: - case CC_OP_SHLQ: - - case CC_OP_SARB: - case CC_OP_SARW: - case CC_OP_SARL: - case CC_OP_SARQ: - switch(jcc_op) { - case JCC_Z: - func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 4][jcc_op]; - break; - case JCC_S: - func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 4][jcc_op]; - break; - default: - func = NULL; - break; - } - break; - default: - func = NULL; - break; - } - - if (s->cc_op != CC_OP_DYNAMIC) { - gen_op_set_cc_op(s->cc_op); - s->cc_op = CC_OP_DYNAMIC; - } - - if (!func) { - gen_setcc_slow[jcc_op](); - func = gen_op_jnz_T0_label; - } - - if (inv) { - tmp = val; - val = next_eip; - next_eip = tmp; - } - tb = s->tb; - l1 = gen_new_label(); - func(l1); - + gen_jcc1(s, cc_op, b, l1); + gen_goto_tb(s, 0, next_eip); gen_set_label(l1); gen_goto_tb(s, 1, val); - s->is_jmp = 3; } else { - if (s->cc_op != CC_OP_DYNAMIC) { - gen_op_set_cc_op(s->cc_op); - s->cc_op = CC_OP_DYNAMIC; - } - gen_setcc_slow[jcc_op](); - if (inv) { - tmp = val; - val = next_eip; - next_eip = tmp; - } l1 = gen_new_label(); l2 = gen_new_label(); - gen_op_jnz_T0_label(l1); + gen_jcc1(s, cc_op, b, l1); + gen_jmp_im(next_eip); - gen_op_jmp_label(l2); + tcg_gen_br(l2); + gen_set_label(l1); gen_jmp_im(val); gen_set_label(l2); @@ -1907,71 +2260,49 @@ static void gen_setcc(DisasContext *s, int b) { - int inv, jcc_op; - GenOpFunc *func; - - inv = b & 1; - jcc_op = (b >> 1) & 7; - switch(s->cc_op) { - /* we optimize the cmp/jcc case */ - case CC_OP_SUBB: - case CC_OP_SUBW: - case CC_OP_SUBL: - case CC_OP_SUBQ: - func = gen_setcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; - if (!func) - goto slow_jcc; - break; - - /* some jumps are easy to compute */ - case CC_OP_ADDB: - case CC_OP_ADDW: - case CC_OP_ADDL: - case CC_OP_ADDQ: + int inv, jcc_op, l1; + TCGv t0; - case CC_OP_LOGICB: - case CC_OP_LOGICW: - case CC_OP_LOGICL: - case CC_OP_LOGICQ: - - case CC_OP_INCB: - case CC_OP_INCW: - case CC_OP_INCL: - case CC_OP_INCQ: - - case CC_OP_DECB: - case CC_OP_DECW: - case CC_OP_DECL: - case CC_OP_DECQ: - - case CC_OP_SHLB: - case CC_OP_SHLW: - case CC_OP_SHLL: - case CC_OP_SHLQ: - switch(jcc_op) { - case JCC_Z: - func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 4][jcc_op]; - break; - case JCC_S: - func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 4][jcc_op]; - break; - default: - goto slow_jcc; + if (is_fast_jcc_case(s, b)) { + /* nominal case: we use a jump */ + /* XXX: make it faster by adding new instructions in TCG */ + t0 = tcg_temp_local_new(TCG_TYPE_TL); + tcg_gen_movi_tl(t0, 0); + l1 = gen_new_label(); + gen_jcc1(s, s->cc_op, b ^ 1, l1); + tcg_gen_movi_tl(t0, 1); + gen_set_label(l1); + tcg_gen_mov_tl(cpu_T[0], t0); + tcg_temp_free(t0); + } else { + /* slow case: it is more efficient not to generate a jump, + although it is questionnable whether this optimization is + worth to */ + inv = b & 1; + jcc_op = (b >> 1) & 7; + gen_setcc_slow_T0(s, jcc_op); + if (inv) { + tcg_gen_xori_tl(cpu_T[0], cpu_T[0], 1); } - break; - default: - slow_jcc: - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - func = gen_setcc_slow[jcc_op]; - break; - } - func(); - if (inv) { - gen_op_xor_T0_1(); } } +static inline void gen_op_movl_T0_seg(int seg_reg) +{ + tcg_gen_ld32u_tl(cpu_T[0], cpu_env, + offsetof(CPUX86State,segs[seg_reg].selector)); +} + +static inline void gen_op_movl_seg_T0_vm(int seg_reg) +{ + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 0xffff); + tcg_gen_st32_tl(cpu_T[0], cpu_env, + offsetof(CPUX86State,segs[seg_reg].selector)); + tcg_gen_shli_tl(cpu_T[0], cpu_T[0], 4); + tcg_gen_st_tl(cpu_T[0], cpu_env, + offsetof(CPUX86State,segs[seg_reg].base)); +} + /* move T0 to seg_reg and compute if the CPU state may change. Never call this function with seg_reg == R_CS */ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, target_ulong cur_eip) @@ -1981,7 +2312,8 @@ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(cur_eip); - gen_op_movl_seg_T0(seg_reg); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_0_2(helper_load_seg, tcg_const_i32(seg_reg), cpu_tmp2_i32); /* abort translation because the addseg value may change or because ss32 may change. For R_SS, translation must always stop as a special handling must be done to disable hardware @@ -1989,128 +2321,48 @@ if (seg_reg == R_SS || (s->code32 && seg_reg < R_FS)) s->is_jmp = 3; } else { - gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg])); + gen_op_movl_seg_T0_vm(seg_reg); if (seg_reg == R_SS) s->is_jmp = 3; } } -#ifdef TARGET_X86_64 -#define SVM_movq_T1_im(x) gen_op_movq_T1_im64((x) >> 32, x) -#else -#define SVM_movq_T1_im(x) gen_op_movl_T1_im(x) -#endif - -static inline int -gen_svm_check_io(DisasContext *s, target_ulong pc_start, uint64_t type) -{ -#if !defined(CONFIG_USER_ONLY) - if(s->flags & (1ULL << INTERCEPT_IOIO_PROT)) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - SVM_movq_T1_im(s->pc - s->cs_base); - gen_jmp_im(pc_start - s->cs_base); - gen_op_geneflags(); - gen_op_svm_check_intercept_io((uint32_t)(type >> 32), (uint32_t)type); - s->cc_op = CC_OP_DYNAMIC; - /* FIXME: maybe we could move the io intercept vector to the TB as well - so we know if this is an EOB or not ... let's assume it's not - for now. */ - } -#endif - return 0; -} - static inline int svm_is_rep(int prefixes) { return ((prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) ? 8 : 0); } -static inline int +static inline void gen_svm_check_intercept_param(DisasContext *s, target_ulong pc_start, - uint64_t type, uint64_t param) + uint32_t type, uint64_t param) { - if(!(s->flags & (INTERCEPT_SVM_MASK))) - /* no SVM activated */ - return 0; - switch(type) { - /* CRx and DRx reads/writes */ - case SVM_EXIT_READ_CR0 ... SVM_EXIT_EXCP_BASE - 1: - if (s->cc_op != CC_OP_DYNAMIC) { - gen_op_set_cc_op(s->cc_op); - s->cc_op = CC_OP_DYNAMIC; - } - gen_jmp_im(pc_start - s->cs_base); - SVM_movq_T1_im(param); - gen_op_geneflags(); - gen_op_svm_check_intercept_param((uint32_t)(type >> 32), (uint32_t)type); - /* this is a special case as we do not know if the interception occurs - so we assume there was none */ - return 0; - case SVM_EXIT_MSR: - if(s->flags & (1ULL << INTERCEPT_MSR_PROT)) { - if (s->cc_op != CC_OP_DYNAMIC) { - gen_op_set_cc_op(s->cc_op); - s->cc_op = CC_OP_DYNAMIC; - } - gen_jmp_im(pc_start - s->cs_base); - SVM_movq_T1_im(param); - gen_op_geneflags(); - gen_op_svm_check_intercept_param((uint32_t)(type >> 32), (uint32_t)type); - /* this is a special case as we do not know if the interception occurs - so we assume there was none */ - return 0; - } - break; - default: - if(s->flags & (1ULL << ((type - SVM_EXIT_INTR) + INTERCEPT_INTR))) { - if (s->cc_op != CC_OP_DYNAMIC) { - gen_op_set_cc_op(s->cc_op); - s->cc_op = CC_OP_EFLAGS; - } - gen_jmp_im(pc_start - s->cs_base); - SVM_movq_T1_im(param); - gen_op_geneflags(); - gen_op_svm_vmexit(type >> 32, type); - /* we can optimize this one so TBs don't get longer - than up to vmexit */ - gen_eob(s); - return 1; - } - } - return 0; + /* no SVM activated; fast case */ + if (likely(!(s->flags & HF_SVMI_MASK))) + return; + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(pc_start - s->cs_base); + tcg_gen_helper_0_2(helper_svm_check_intercept_param, + tcg_const_i32(type), tcg_const_i64(param)); } -static inline int +static inline void gen_svm_check_intercept(DisasContext *s, target_ulong pc_start, uint64_t type) { - return gen_svm_check_intercept_param(s, pc_start, type, 0); + gen_svm_check_intercept_param(s, pc_start, type, 0); } static inline void gen_stack_update(DisasContext *s, int addend) { #ifdef TARGET_X86_64 if (CODE64(s)) { - if (addend == 8) - gen_op_addq_ESP_8(); - else - gen_op_addq_ESP_im(addend); + gen_op_add_reg_im(2, R_ESP, addend); } else #endif if (s->ss32) { - if (addend == 2) - gen_op_addl_ESP_2(); - else if (addend == 4) - gen_op_addl_ESP_4(); - else - gen_op_addl_ESP_im(addend); + gen_op_add_reg_im(1, R_ESP, addend); } else { - if (addend == 2) - gen_op_addw_ESP_2(); - else if (addend == 4) - gen_op_addw_ESP_4(); - else - gen_op_addw_ESP_im(addend); + gen_op_add_reg_im(0, R_ESP, addend); } } @@ -2119,38 +2371,38 @@ { #ifdef TARGET_X86_64 if (CODE64(s)) { - gen_op_movq_A0_reg[R_ESP](); + gen_op_movq_A0_reg(R_ESP); if (s->dflag) { - gen_op_subq_A0_8(); - gen_op_st_T0_A0[OT_QUAD + s->mem_index](); + gen_op_addq_A0_im(-8); + gen_op_st_T0_A0(OT_QUAD + s->mem_index); } else { - gen_op_subq_A0_2(); - gen_op_st_T0_A0[OT_WORD + s->mem_index](); + gen_op_addq_A0_im(-2); + gen_op_st_T0_A0(OT_WORD + s->mem_index); } - gen_op_movq_ESP_A0(); + gen_op_mov_reg_A0(2, R_ESP); } else #endif { - gen_op_movl_A0_reg[R_ESP](); + gen_op_movl_A0_reg(R_ESP); if (!s->dflag) - gen_op_subl_A0_2(); + gen_op_addl_A0_im(-2); else - gen_op_subl_A0_4(); + gen_op_addl_A0_im(-4); if (s->ss32) { if (s->addseg) { - gen_op_movl_T1_A0(); - gen_op_addl_A0_SS(); + tcg_gen_mov_tl(cpu_T[1], cpu_A0); + gen_op_addl_A0_seg(R_SS); } } else { gen_op_andl_A0_ffff(); - gen_op_movl_T1_A0(); - gen_op_addl_A0_SS(); + tcg_gen_mov_tl(cpu_T[1], cpu_A0); + gen_op_addl_A0_seg(R_SS); } - gen_op_st_T0_A0[s->dflag + 1 + s->mem_index](); + gen_op_st_T0_A0(s->dflag + 1 + s->mem_index); if (s->ss32 && !s->addseg) - gen_op_movl_ESP_A0(); + gen_op_mov_reg_A0(1, R_ESP); else - gen_op_mov_reg_T1[s->ss32 + 1][R_ESP](); + gen_op_mov_reg_T1(s->ss32 + 1, R_ESP); } } @@ -2160,35 +2412,35 @@ { #ifdef TARGET_X86_64 if (CODE64(s)) { - gen_op_movq_A0_reg[R_ESP](); + gen_op_movq_A0_reg(R_ESP); if (s->dflag) { - gen_op_subq_A0_8(); - gen_op_st_T1_A0[OT_QUAD + s->mem_index](); + gen_op_addq_A0_im(-8); + gen_op_st_T1_A0(OT_QUAD + s->mem_index); } else { - gen_op_subq_A0_2(); - gen_op_st_T0_A0[OT_WORD + s->mem_index](); + gen_op_addq_A0_im(-2); + gen_op_st_T0_A0(OT_WORD + s->mem_index); } - gen_op_movq_ESP_A0(); + gen_op_mov_reg_A0(2, R_ESP); } else #endif { - gen_op_movl_A0_reg[R_ESP](); + gen_op_movl_A0_reg(R_ESP); if (!s->dflag) - gen_op_subl_A0_2(); + gen_op_addl_A0_im(-2); else - gen_op_subl_A0_4(); + gen_op_addl_A0_im(-4); if (s->ss32) { if (s->addseg) { - gen_op_addl_A0_SS(); + gen_op_addl_A0_seg(R_SS); } } else { gen_op_andl_A0_ffff(); - gen_op_addl_A0_SS(); + gen_op_addl_A0_seg(R_SS); } - gen_op_st_T1_A0[s->dflag + 1 + s->mem_index](); + gen_op_st_T1_A0(s->dflag + 1 + s->mem_index); if (s->ss32 && !s->addseg) - gen_op_movl_ESP_A0(); + gen_op_mov_reg_A0(1, R_ESP); else gen_stack_update(s, (-2) << s->dflag); } @@ -2199,20 +2451,20 @@ { #ifdef TARGET_X86_64 if (CODE64(s)) { - gen_op_movq_A0_reg[R_ESP](); - gen_op_ld_T0_A0[(s->dflag ? OT_QUAD : OT_WORD) + s->mem_index](); + gen_op_movq_A0_reg(R_ESP); + gen_op_ld_T0_A0((s->dflag ? OT_QUAD : OT_WORD) + s->mem_index); } else #endif { - gen_op_movl_A0_reg[R_ESP](); + gen_op_movl_A0_reg(R_ESP); if (s->ss32) { if (s->addseg) - gen_op_addl_A0_SS(); + gen_op_addl_A0_seg(R_SS); } else { gen_op_andl_A0_ffff(); - gen_op_addl_A0_SS(); + gen_op_addl_A0_seg(R_SS); } - gen_op_ld_T0_A0[s->dflag + 1 + s->mem_index](); + gen_op_ld_T0_A0(s->dflag + 1 + s->mem_index); } } @@ -2230,53 +2482,53 @@ static void gen_stack_A0(DisasContext *s) { - gen_op_movl_A0_ESP(); + gen_op_movl_A0_reg(R_ESP); if (!s->ss32) gen_op_andl_A0_ffff(); - gen_op_movl_T1_A0(); + tcg_gen_mov_tl(cpu_T[1], cpu_A0); if (s->addseg) - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); + gen_op_addl_A0_seg(R_SS); } /* NOTE: wrap around in 16 bit not fully handled */ static void gen_pusha(DisasContext *s) { int i; - gen_op_movl_A0_ESP(); + gen_op_movl_A0_reg(R_ESP); gen_op_addl_A0_im(-16 << s->dflag); if (!s->ss32) gen_op_andl_A0_ffff(); - gen_op_movl_T1_A0(); + tcg_gen_mov_tl(cpu_T[1], cpu_A0); if (s->addseg) - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); + gen_op_addl_A0_seg(R_SS); for(i = 0;i < 8; i++) { - gen_op_mov_TN_reg[OT_LONG][0][7 - i](); - gen_op_st_T0_A0[OT_WORD + s->dflag + s->mem_index](); + gen_op_mov_TN_reg(OT_LONG, 0, 7 - i); + gen_op_st_T0_A0(OT_WORD + s->dflag + s->mem_index); gen_op_addl_A0_im(2 << s->dflag); } - gen_op_mov_reg_T1[OT_WORD + s->ss32][R_ESP](); + gen_op_mov_reg_T1(OT_WORD + s->ss32, R_ESP); } /* NOTE: wrap around in 16 bit not fully handled */ static void gen_popa(DisasContext *s) { int i; - gen_op_movl_A0_ESP(); + gen_op_movl_A0_reg(R_ESP); if (!s->ss32) gen_op_andl_A0_ffff(); - gen_op_movl_T1_A0(); - gen_op_addl_T1_im(16 << s->dflag); + tcg_gen_mov_tl(cpu_T[1], cpu_A0); + tcg_gen_addi_tl(cpu_T[1], cpu_T[1], 16 << s->dflag); if (s->addseg) - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); + gen_op_addl_A0_seg(R_SS); for(i = 0;i < 8; i++) { /* ESP is not reloaded */ if (i != 3) { - gen_op_ld_T0_A0[OT_WORD + s->dflag + s->mem_index](); - gen_op_mov_reg_T0[OT_WORD + s->dflag][7 - i](); + gen_op_ld_T0_A0(OT_WORD + s->dflag + s->mem_index); + gen_op_mov_reg_T0(OT_WORD + s->dflag, 7 - i); } gen_op_addl_A0_im(2 << s->dflag); } - gen_op_mov_reg_T1[OT_WORD + s->ss32][R_ESP](); + gen_op_mov_reg_T1(OT_WORD + s->ss32, R_ESP); } static void gen_enter(DisasContext *s, int esp_addend, int level) @@ -2289,41 +2541,49 @@ ot = s->dflag ? OT_QUAD : OT_WORD; opsize = 1 << ot; - gen_op_movl_A0_ESP(); + gen_op_movl_A0_reg(R_ESP); gen_op_addq_A0_im(-opsize); - gen_op_movl_T1_A0(); + tcg_gen_mov_tl(cpu_T[1], cpu_A0); /* push bp */ - gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); - gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_mov_TN_reg(OT_LONG, 0, R_EBP); + gen_op_st_T0_A0(ot + s->mem_index); if (level) { - gen_op_enter64_level(level, (ot == OT_QUAD)); - } - gen_op_mov_reg_T1[ot][R_EBP](); - gen_op_addl_T1_im( -esp_addend + (-opsize * level) ); - gen_op_mov_reg_T1[OT_QUAD][R_ESP](); + /* XXX: must save state */ + tcg_gen_helper_0_3(helper_enter64_level, + tcg_const_i32(level), + tcg_const_i32((ot == OT_QUAD)), + cpu_T[1]); + } + gen_op_mov_reg_T1(ot, R_EBP); + tcg_gen_addi_tl(cpu_T[1], cpu_T[1], -esp_addend + (-opsize * level)); + gen_op_mov_reg_T1(OT_QUAD, R_ESP); } else #endif { ot = s->dflag + OT_WORD; opsize = 2 << s->dflag; - gen_op_movl_A0_ESP(); + gen_op_movl_A0_reg(R_ESP); gen_op_addl_A0_im(-opsize); if (!s->ss32) gen_op_andl_A0_ffff(); - gen_op_movl_T1_A0(); + tcg_gen_mov_tl(cpu_T[1], cpu_A0); if (s->addseg) - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); + gen_op_addl_A0_seg(R_SS); /* push bp */ - gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); - gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_mov_TN_reg(OT_LONG, 0, R_EBP); + gen_op_st_T0_A0(ot + s->mem_index); if (level) { - gen_op_enter_level(level, s->dflag); - } - gen_op_mov_reg_T1[ot][R_EBP](); - gen_op_addl_T1_im( -esp_addend + (-opsize * level) ); - gen_op_mov_reg_T1[OT_WORD + s->ss32][R_ESP](); + /* XXX: must save state */ + tcg_gen_helper_0_3(helper_enter_level, + tcg_const_i32(level), + tcg_const_i32(s->dflag), + cpu_T[1]); + } + gen_op_mov_reg_T1(ot, R_EBP); + tcg_gen_addi_tl(cpu_T[1], cpu_T[1], -esp_addend + (-opsize * level)); + gen_op_mov_reg_T1(OT_WORD + s->ss32, R_ESP); } } @@ -2332,7 +2592,7 @@ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(cur_eip); - gen_op_raise_exception(trapno); + tcg_gen_helper_0_1(helper_raise_exception, tcg_const_i32(trapno)); s->is_jmp = 3; } @@ -2344,7 +2604,9 @@ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(cur_eip); - gen_op_raise_interrupt(intno, (int)(next_eip - cur_eip)); + tcg_gen_helper_0_2(helper_raise_interrupt, + tcg_const_i32(intno), + tcg_const_i32(next_eip - cur_eip)); s->is_jmp = 3; } @@ -2353,7 +2615,7 @@ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(cur_eip); - gen_op_debug(); + tcg_gen_helper_0_0(helper_debug); s->is_jmp = 3; } @@ -2364,15 +2626,14 @@ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); if (s->tb->flags & HF_INHIBIT_IRQ_MASK) { - gen_op_reset_inhibit_irq(); + tcg_gen_helper_0_0(helper_reset_inhibit_irq); } if (s->singlestep_enabled) { - gen_op_debug(); + tcg_gen_helper_0_0(helper_debug); } else if (s->tf) { - gen_op_single_step(); + tcg_gen_helper_0_0(helper_single_step); } else { - gen_op_movl_T0_0(); - gen_op_exit_tb(); + tcg_gen_exit_tb(0); } s->is_jmp = 3; } @@ -2399,88 +2660,84 @@ gen_jmp_tb(s, eip, 0); } -static void gen_movtl_T0_im(target_ulong val) +static inline void gen_ldq_env_A0(int idx, int offset) { -#ifdef TARGET_X86_64 - if ((int32_t)val == val) { - gen_op_movl_T0_im(val); - } else { - gen_op_movq_T0_im64(val >> 32, val); - } -#else - gen_op_movl_T0_im(val); -#endif + int mem_index = (idx >> 2) - 1; + tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, mem_index); + tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, offset); } -static void gen_movtl_T1_im(target_ulong val) +static inline void gen_stq_env_A0(int idx, int offset) { -#ifdef TARGET_X86_64 - if ((int32_t)val == val) { - gen_op_movl_T1_im(val); - } else { - gen_op_movq_T1_im64(val >> 32, val); - } -#else - gen_op_movl_T1_im(val); -#endif + int mem_index = (idx >> 2) - 1; + tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, offset); + tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, mem_index); } -static void gen_add_A0_im(DisasContext *s, int val) +static inline void gen_ldo_env_A0(int idx, int offset) { -#ifdef TARGET_X86_64 - if (CODE64(s)) - gen_op_addq_A0_im(val); - else -#endif - gen_op_addl_A0_im(val); + int mem_index = (idx >> 2) - 1; + tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, mem_index); + tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, offset + offsetof(XMMReg, XMM_Q(0))); + tcg_gen_addi_tl(cpu_tmp0, cpu_A0, 8); + tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_tmp0, mem_index); + tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, offset + offsetof(XMMReg, XMM_Q(1))); } -static GenOpFunc1 *gen_ldq_env_A0[3] = { - gen_op_ldq_raw_env_A0, -#ifndef CONFIG_USER_ONLY - gen_op_ldq_kernel_env_A0, - gen_op_ldq_user_env_A0, -#endif -}; +static inline void gen_sto_env_A0(int idx, int offset) +{ + int mem_index = (idx >> 2) - 1; + tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, offset + offsetof(XMMReg, XMM_Q(0))); + tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, mem_index); + tcg_gen_addi_tl(cpu_tmp0, cpu_A0, 8); + tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, offset + offsetof(XMMReg, XMM_Q(1))); + tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_tmp0, mem_index); +} -static GenOpFunc1 *gen_stq_env_A0[3] = { - gen_op_stq_raw_env_A0, -#ifndef CONFIG_USER_ONLY - gen_op_stq_kernel_env_A0, - gen_op_stq_user_env_A0, -#endif -}; +static inline void gen_op_movo(int d_offset, int s_offset) +{ + tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, s_offset); + tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, d_offset); + tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, s_offset + 8); + tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, d_offset + 8); +} + +static inline void gen_op_movq(int d_offset, int s_offset) +{ + tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, s_offset); + tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, d_offset); +} -static GenOpFunc1 *gen_ldo_env_A0[3] = { - gen_op_ldo_raw_env_A0, -#ifndef CONFIG_USER_ONLY - gen_op_ldo_kernel_env_A0, - gen_op_ldo_user_env_A0, -#endif -}; +static inline void gen_op_movl(int d_offset, int s_offset) +{ + tcg_gen_ld_i32(cpu_tmp2_i32, cpu_env, s_offset); + tcg_gen_st_i32(cpu_tmp2_i32, cpu_env, d_offset); +} -static GenOpFunc1 *gen_sto_env_A0[3] = { - gen_op_sto_raw_env_A0, -#ifndef CONFIG_USER_ONLY - gen_op_sto_kernel_env_A0, - gen_op_sto_user_env_A0, -#endif -}; +static inline void gen_op_movq_env_0(int d_offset) +{ + tcg_gen_movi_i64(cpu_tmp1_i64, 0); + tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, d_offset); +} -#define SSE_SPECIAL ((GenOpFunc2 *)1) +#define SSE_SPECIAL ((void *)1) +#define SSE_DUMMY ((void *)2) -#define MMX_OP2(x) { gen_op_ ## x ## _mmx, gen_op_ ## x ## _xmm } -#define SSE_FOP(x) { gen_op_ ## x ## ps, gen_op_ ## x ## pd, \ - gen_op_ ## x ## ss, gen_op_ ## x ## sd, } +#define MMX_OP2(x) { helper_ ## x ## _mmx, helper_ ## x ## _xmm } +#define SSE_FOP(x) { helper_ ## x ## ps, helper_ ## x ## pd, \ + helper_ ## x ## ss, helper_ ## x ## sd, } -static GenOpFunc2 *sse_op_table1[256][4] = { +static void *sse_op_table1[256][4] = { + /* 3DNow! extensions */ + [0x0e] = { SSE_DUMMY }, /* femms */ + [0x0f] = { SSE_DUMMY }, /* pf... */ /* pure SSE operations */ [0x10] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */ [0x11] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */ [0x12] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd, movsldup, movddup */ [0x13] = { SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd */ - [0x14] = { gen_op_punpckldq_xmm, gen_op_punpcklqdq_xmm }, - [0x15] = { gen_op_punpckhdq_xmm, gen_op_punpckhqdq_xmm }, + [0x14] = { helper_punpckldq_xmm, helper_punpcklqdq_xmm }, + [0x15] = { helper_punpckhdq_xmm, helper_punpckhqdq_xmm }, [0x16] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movhps, movhpd, movshdup */ [0x17] = { SSE_SPECIAL, SSE_SPECIAL }, /* movhps, movhpd */ @@ -2490,28 +2747,31 @@ [0x2b] = { SSE_SPECIAL, SSE_SPECIAL }, /* movntps, movntpd */ [0x2c] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvttps2pi, cvttpd2pi, cvttsd2si, cvttss2si */ [0x2d] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvtps2pi, cvtpd2pi, cvtsd2si, cvtss2si */ - [0x2e] = { gen_op_ucomiss, gen_op_ucomisd }, - [0x2f] = { gen_op_comiss, gen_op_comisd }, + [0x2e] = { helper_ucomiss, helper_ucomisd }, + [0x2f] = { helper_comiss, helper_comisd }, [0x50] = { SSE_SPECIAL, SSE_SPECIAL }, /* movmskps, movmskpd */ [0x51] = SSE_FOP(sqrt), - [0x52] = { gen_op_rsqrtps, NULL, gen_op_rsqrtss, NULL }, - [0x53] = { gen_op_rcpps, NULL, gen_op_rcpss, NULL }, - [0x54] = { gen_op_pand_xmm, gen_op_pand_xmm }, /* andps, andpd */ - [0x55] = { gen_op_pandn_xmm, gen_op_pandn_xmm }, /* andnps, andnpd */ - [0x56] = { gen_op_por_xmm, gen_op_por_xmm }, /* orps, orpd */ - [0x57] = { gen_op_pxor_xmm, gen_op_pxor_xmm }, /* xorps, xorpd */ + [0x52] = { helper_rsqrtps, NULL, helper_rsqrtss, NULL }, + [0x53] = { helper_rcpps, NULL, helper_rcpss, NULL }, + [0x54] = { helper_pand_xmm, helper_pand_xmm }, /* andps, andpd */ + [0x55] = { helper_pandn_xmm, helper_pandn_xmm }, /* andnps, andnpd */ + [0x56] = { helper_por_xmm, helper_por_xmm }, /* orps, orpd */ + [0x57] = { helper_pxor_xmm, helper_pxor_xmm }, /* xorps, xorpd */ [0x58] = SSE_FOP(add), [0x59] = SSE_FOP(mul), - [0x5a] = { gen_op_cvtps2pd, gen_op_cvtpd2ps, - gen_op_cvtss2sd, gen_op_cvtsd2ss }, - [0x5b] = { gen_op_cvtdq2ps, gen_op_cvtps2dq, gen_op_cvttps2dq }, + [0x5a] = { helper_cvtps2pd, helper_cvtpd2ps, + helper_cvtss2sd, helper_cvtsd2ss }, + [0x5b] = { helper_cvtdq2ps, helper_cvtps2dq, helper_cvttps2dq }, [0x5c] = SSE_FOP(sub), [0x5d] = SSE_FOP(min), [0x5e] = SSE_FOP(div), [0x5f] = SSE_FOP(max), [0xc2] = SSE_FOP(cmpeq), - [0xc6] = { (GenOpFunc2 *)gen_op_shufps, (GenOpFunc2 *)gen_op_shufpd }, + [0xc6] = { helper_shufps, helper_shufpd }, + + [0x38] = { SSE_SPECIAL, SSE_SPECIAL, NULL, SSE_SPECIAL }, /* SSSE3/SSE4 */ + [0x3a] = { SSE_SPECIAL, SSE_SPECIAL }, /* SSSE3/SSE4 */ /* MMX ops and their SSE extensions */ [0x60] = MMX_OP2(punpcklbw), @@ -2526,28 +2786,28 @@ [0x69] = MMX_OP2(punpckhwd), [0x6a] = MMX_OP2(punpckhdq), [0x6b] = MMX_OP2(packssdw), - [0x6c] = { NULL, gen_op_punpcklqdq_xmm }, - [0x6d] = { NULL, gen_op_punpckhqdq_xmm }, + [0x6c] = { NULL, helper_punpcklqdq_xmm }, + [0x6d] = { NULL, helper_punpckhqdq_xmm }, [0x6e] = { SSE_SPECIAL, SSE_SPECIAL }, /* movd mm, ea */ [0x6f] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movq, movdqa, , movqdu */ - [0x70] = { (GenOpFunc2 *)gen_op_pshufw_mmx, - (GenOpFunc2 *)gen_op_pshufd_xmm, - (GenOpFunc2 *)gen_op_pshufhw_xmm, - (GenOpFunc2 *)gen_op_pshuflw_xmm }, + [0x70] = { helper_pshufw_mmx, + helper_pshufd_xmm, + helper_pshufhw_xmm, + helper_pshuflw_xmm }, [0x71] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftw */ [0x72] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftd */ [0x73] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftq */ [0x74] = MMX_OP2(pcmpeqb), [0x75] = MMX_OP2(pcmpeqw), [0x76] = MMX_OP2(pcmpeql), - [0x77] = { SSE_SPECIAL }, /* emms */ - [0x7c] = { NULL, gen_op_haddpd, NULL, gen_op_haddps }, - [0x7d] = { NULL, gen_op_hsubpd, NULL, gen_op_hsubps }, + [0x77] = { SSE_DUMMY }, /* emms */ + [0x7c] = { NULL, helper_haddpd, NULL, helper_haddps }, + [0x7d] = { NULL, helper_hsubpd, NULL, helper_hsubps }, [0x7e] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movd, movd, , movq */ [0x7f] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movq, movdqa, movdqu */ [0xc4] = { SSE_SPECIAL, SSE_SPECIAL }, /* pinsrw */ [0xc5] = { SSE_SPECIAL, SSE_SPECIAL }, /* pextrw */ - [0xd0] = { NULL, gen_op_addsubpd, NULL, gen_op_addsubps }, + [0xd0] = { NULL, helper_addsubpd, NULL, helper_addsubps }, [0xd1] = MMX_OP2(psrlw), [0xd2] = MMX_OP2(psrld), [0xd3] = MMX_OP2(psrlq), @@ -2569,7 +2829,7 @@ [0xe3] = MMX_OP2(pavgw), [0xe4] = MMX_OP2(pmulhuw), [0xe5] = MMX_OP2(pmulhw), - [0xe6] = { NULL, gen_op_cvttpd2dq, gen_op_cvtdq2pd, gen_op_cvtpd2dq }, + [0xe6] = { NULL, helper_cvttpd2dq, helper_cvtdq2pd, helper_cvtpd2dq }, [0xe7] = { SSE_SPECIAL , SSE_SPECIAL }, /* movntq, movntq */ [0xe8] = MMX_OP2(psubsb), [0xe9] = MMX_OP2(psubsw), @@ -2596,7 +2856,7 @@ [0xfe] = MMX_OP2(paddl), }; -static GenOpFunc2 *sse_op_table2[3 * 8][2] = { +static void *sse_op_table2[3 * 8][2] = { [0 + 2] = MMX_OP2(psrlw), [0 + 4] = MMX_OP2(psraw), [0 + 6] = MMX_OP2(psllw), @@ -2604,29 +2864,29 @@ [8 + 4] = MMX_OP2(psrad), [8 + 6] = MMX_OP2(pslld), [16 + 2] = MMX_OP2(psrlq), - [16 + 3] = { NULL, gen_op_psrldq_xmm }, + [16 + 3] = { NULL, helper_psrldq_xmm }, [16 + 6] = MMX_OP2(psllq), - [16 + 7] = { NULL, gen_op_pslldq_xmm }, + [16 + 7] = { NULL, helper_pslldq_xmm }, }; -static GenOpFunc1 *sse_op_table3[4 * 3] = { - gen_op_cvtsi2ss, - gen_op_cvtsi2sd, - X86_64_ONLY(gen_op_cvtsq2ss), - X86_64_ONLY(gen_op_cvtsq2sd), - - gen_op_cvttss2si, - gen_op_cvttsd2si, - X86_64_ONLY(gen_op_cvttss2sq), - X86_64_ONLY(gen_op_cvttsd2sq), - - gen_op_cvtss2si, - gen_op_cvtsd2si, - X86_64_ONLY(gen_op_cvtss2sq), - X86_64_ONLY(gen_op_cvtsd2sq), +static void *sse_op_table3[4 * 3] = { + helper_cvtsi2ss, + helper_cvtsi2sd, + X86_64_ONLY(helper_cvtsq2ss), + X86_64_ONLY(helper_cvtsq2sd), + + helper_cvttss2si, + helper_cvttsd2si, + X86_64_ONLY(helper_cvttss2sq), + X86_64_ONLY(helper_cvttsd2sq), + + helper_cvtss2si, + helper_cvtsd2si, + X86_64_ONLY(helper_cvtss2sq), + X86_64_ONLY(helper_cvtsd2sq), }; -static GenOpFunc2 *sse_op_table4[8][4] = { +static void *sse_op_table4[8][4] = { SSE_FOP(cmpeq), SSE_FOP(cmplt), SSE_FOP(cmple), @@ -2637,12 +2897,119 @@ SSE_FOP(cmpord), }; +static void *sse_op_table5[256] = { + [0x0c] = helper_pi2fw, + [0x0d] = helper_pi2fd, + [0x1c] = helper_pf2iw, + [0x1d] = helper_pf2id, + [0x8a] = helper_pfnacc, + [0x8e] = helper_pfpnacc, + [0x90] = helper_pfcmpge, + [0x94] = helper_pfmin, + [0x96] = helper_pfrcp, + [0x97] = helper_pfrsqrt, + [0x9a] = helper_pfsub, + [0x9e] = helper_pfadd, + [0xa0] = helper_pfcmpgt, + [0xa4] = helper_pfmax, + [0xa6] = helper_movq, /* pfrcpit1; no need to actually increase precision */ + [0xa7] = helper_movq, /* pfrsqit1 */ + [0xaa] = helper_pfsubr, + [0xae] = helper_pfacc, + [0xb0] = helper_pfcmpeq, + [0xb4] = helper_pfmul, + [0xb6] = helper_movq, /* pfrcpit2 */ + [0xb7] = helper_pmulhrw_mmx, + [0xbb] = helper_pswapd, + [0xbf] = helper_pavgb_mmx /* pavgusb */ +}; + +struct sse_op_helper_s { + void *op[2]; uint32_t ext_mask; +}; +#define SSSE3_OP(x) { MMX_OP2(x), CPUID_EXT_SSSE3 } +#define SSE41_OP(x) { { NULL, helper_ ## x ## _xmm }, CPUID_EXT_SSE41 } +#define SSE42_OP(x) { { NULL, helper_ ## x ## _xmm }, CPUID_EXT_SSE42 } +#define SSE41_SPECIAL { { NULL, SSE_SPECIAL }, CPUID_EXT_SSE41 } +static struct sse_op_helper_s sse_op_table6[256] = { + [0x00] = SSSE3_OP(pshufb), + [0x01] = SSSE3_OP(phaddw), + [0x02] = SSSE3_OP(phaddd), + [0x03] = SSSE3_OP(phaddsw), + [0x04] = SSSE3_OP(pmaddubsw), + [0x05] = SSSE3_OP(phsubw), + [0x06] = SSSE3_OP(phsubd), + [0x07] = SSSE3_OP(phsubsw), + [0x08] = SSSE3_OP(psignb), + [0x09] = SSSE3_OP(psignw), + [0x0a] = SSSE3_OP(psignd), + [0x0b] = SSSE3_OP(pmulhrsw), + [0x10] = SSE41_OP(pblendvb), + [0x14] = SSE41_OP(blendvps), + [0x15] = SSE41_OP(blendvpd), + [0x17] = SSE41_OP(ptest), + [0x1c] = SSSE3_OP(pabsb), + [0x1d] = SSSE3_OP(pabsw), + [0x1e] = SSSE3_OP(pabsd), + [0x20] = SSE41_OP(pmovsxbw), + [0x21] = SSE41_OP(pmovsxbd), + [0x22] = SSE41_OP(pmovsxbq), + [0x23] = SSE41_OP(pmovsxwd), + [0x24] = SSE41_OP(pmovsxwq), + [0x25] = SSE41_OP(pmovsxdq), + [0x28] = SSE41_OP(pmuldq), + [0x29] = SSE41_OP(pcmpeqq), + [0x2a] = SSE41_SPECIAL, /* movntqda */ + [0x2b] = SSE41_OP(packusdw), + [0x30] = SSE41_OP(pmovzxbw), + [0x31] = SSE41_OP(pmovzxbd), + [0x32] = SSE41_OP(pmovzxbq), + [0x33] = SSE41_OP(pmovzxwd), + [0x34] = SSE41_OP(pmovzxwq), + [0x35] = SSE41_OP(pmovzxdq), + [0x37] = SSE42_OP(pcmpgtq), + [0x38] = SSE41_OP(pminsb), + [0x39] = SSE41_OP(pminsd), + [0x3a] = SSE41_OP(pminuw), + [0x3b] = SSE41_OP(pminud), + [0x3c] = SSE41_OP(pmaxsb), + [0x3d] = SSE41_OP(pmaxsd), + [0x3e] = SSE41_OP(pmaxuw), + [0x3f] = SSE41_OP(pmaxud), + [0x40] = SSE41_OP(pmulld), + [0x41] = SSE41_OP(phminposuw), +}; + +static struct sse_op_helper_s sse_op_table7[256] = { + [0x08] = SSE41_OP(roundps), + [0x09] = SSE41_OP(roundpd), + [0x0a] = SSE41_OP(roundss), + [0x0b] = SSE41_OP(roundsd), + [0x0c] = SSE41_OP(blendps), + [0x0d] = SSE41_OP(blendpd), + [0x0e] = SSE41_OP(pblendw), + [0x0f] = SSSE3_OP(palignr), + [0x14] = SSE41_SPECIAL, /* pextrb */ + [0x15] = SSE41_SPECIAL, /* pextrw */ + [0x16] = SSE41_SPECIAL, /* pextrd/pextrq */ + [0x17] = SSE41_SPECIAL, /* extractps */ + [0x20] = SSE41_SPECIAL, /* pinsrb */ + [0x21] = SSE41_SPECIAL, /* insertps */ + [0x22] = SSE41_SPECIAL, /* pinsrd/pinsrq */ + [0x40] = SSE41_OP(dpps), + [0x41] = SSE41_OP(dppd), + [0x42] = SSE41_OP(mpsadbw), + [0x60] = SSE42_OP(pcmpestrm), + [0x61] = SSE42_OP(pcmpestri), + [0x62] = SSE42_OP(pcmpistrm), + [0x63] = SSE42_OP(pcmpistri), +}; + static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) { int b1, op1_offset, op2_offset, is_xmm, val, ot; int modrm, mod, rm, reg, reg_addr, offset_addr; - GenOpFunc2 *sse_op2; - GenOpFunc3 *sse_op3; + void *sse_op2; b &= 0xff; if (s->prefix & PREFIX_DATA) @@ -2656,7 +3023,7 @@ sse_op2 = sse_op_table1[b][b1]; if (!sse_op2) goto illegal_op; - if (b <= 0x5f || b == 0xc6 || b == 0xc2) { + if ((b <= 0x5f && b >= 0x10) || b == 0xc6 || b == 0xc2) { is_xmm = 1; } else { if (b1 == 0) { @@ -2677,16 +3044,24 @@ return; } if (is_xmm && !(s->flags & HF_OSFXSR_MASK)) - goto illegal_op; + if ((b != 0x38 && b != 0x3a) || (s->prefix & PREFIX_DATA)) + goto illegal_op; + if (b == 0x0e) { + if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW)) + goto illegal_op; + /* femms */ + tcg_gen_helper_0_0(helper_emms); + return; + } if (b == 0x77) { /* emms */ - gen_op_emms(); + tcg_gen_helper_0_0(helper_emms); return; } /* prepare MMX state (XXX: optimize by storing fptt and fptags in the static cpu state) */ if (!is_xmm) { - gen_op_enter_mmx(); + tcg_gen_helper_0_0(helper_enter_mmx); } modrm = ldub_code(s->pc++); @@ -2701,7 +3076,7 @@ if (mod == 3) goto illegal_op; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,fpregs[reg].mmx)); + gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,fpregs[reg].mmx)); break; case 0x1e7: /* movntdq */ case 0x02b: /* movntps */ @@ -2710,40 +3085,49 @@ if (mod == 3) goto illegal_op; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_sto_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); + gen_sto_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg])); break; case 0x6e: /* movd mm, ea */ #ifdef TARGET_X86_64 if (s->dflag == 2) { gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 0); - gen_op_movq_mm_T0_mmx(offsetof(CPUX86State,fpregs[reg].mmx)); + tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,fpregs[reg].mmx)); } else #endif { gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0); - gen_op_movl_mm_T0_mmx(offsetof(CPUX86State,fpregs[reg].mmx)); + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, + offsetof(CPUX86State,fpregs[reg].mmx)); + tcg_gen_helper_0_2(helper_movl_mm_T0_mmx, cpu_ptr0, cpu_T[0]); } break; case 0x16e: /* movd xmm, ea */ #ifdef TARGET_X86_64 if (s->dflag == 2) { gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 0); - gen_op_movq_mm_T0_xmm(offsetof(CPUX86State,xmm_regs[reg])); + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, + offsetof(CPUX86State,xmm_regs[reg])); + tcg_gen_helper_0_2(helper_movq_mm_T0_xmm, cpu_ptr0, cpu_T[0]); } else #endif { gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0); - gen_op_movl_mm_T0_xmm(offsetof(CPUX86State,xmm_regs[reg])); + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, + offsetof(CPUX86State,xmm_regs[reg])); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_0_2(helper_movl_mm_T0_xmm, cpu_ptr0, cpu_tmp2_i32); } break; case 0x6f: /* movq mm, ea */ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,fpregs[reg].mmx)); + gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,fpregs[reg].mmx)); } else { rm = (modrm & 7); - gen_op_movq(offsetof(CPUX86State,fpregs[reg].mmx), - offsetof(CPUX86State,fpregs[rm].mmx)); + tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, + offsetof(CPUX86State,fpregs[rm].mmx)); + tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, + offsetof(CPUX86State,fpregs[reg].mmx)); } break; case 0x010: /* movups */ @@ -2754,7 +3138,7 @@ case 0x26f: /* movdqu xmm, ea */ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_ldo_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); + gen_ldo_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg])); } else { rm = (modrm & 7) | REX_B(s); gen_op_movo(offsetof(CPUX86State,xmm_regs[reg]), @@ -2764,12 +3148,12 @@ case 0x210: /* movss xmm, ea */ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[OT_LONG + s->mem_index](); - gen_op_movl_env_T0(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0))); + gen_op_ld_T0_A0(OT_LONG + s->mem_index); + tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(0))); gen_op_movl_T0_0(); - gen_op_movl_env_T0(offsetof(CPUX86State,xmm_regs[reg].XMM_L(1))); - gen_op_movl_env_T0(offsetof(CPUX86State,xmm_regs[reg].XMM_L(2))); - gen_op_movl_env_T0(offsetof(CPUX86State,xmm_regs[reg].XMM_L(3))); + tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(1))); + tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(2))); + tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(3))); } else { rm = (modrm & 7) | REX_B(s); gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)), @@ -2779,10 +3163,10 @@ case 0x310: /* movsd xmm, ea */ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); gen_op_movl_T0_0(); - gen_op_movl_env_T0(offsetof(CPUX86State,xmm_regs[reg].XMM_L(2))); - gen_op_movl_env_T0(offsetof(CPUX86State,xmm_regs[reg].XMM_L(3))); + tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(2))); + tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(3))); } else { rm = (modrm & 7) | REX_B(s); gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)), @@ -2793,7 +3177,7 @@ case 0x112: /* movlpd */ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); } else { /* movhlps */ rm = (modrm & 7) | REX_B(s); @@ -2804,7 +3188,7 @@ case 0x212: /* movsldup */ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_ldo_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); + gen_ldo_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg])); } else { rm = (modrm & 7) | REX_B(s); gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)), @@ -2820,7 +3204,7 @@ case 0x312: /* movddup */ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); } else { rm = (modrm & 7) | REX_B(s); gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)), @@ -2833,7 +3217,7 @@ case 0x116: /* movhpd */ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1))); + gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1))); } else { /* movlhps */ rm = (modrm & 7) | REX_B(s); @@ -2844,7 +3228,7 @@ case 0x216: /* movshdup */ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_ldo_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); + gen_ldo_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg])); } else { rm = (modrm & 7) | REX_B(s); gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(1)), @@ -2860,31 +3244,35 @@ case 0x7e: /* movd ea, mm */ #ifdef TARGET_X86_64 if (s->dflag == 2) { - gen_op_movq_T0_mm_mmx(offsetof(CPUX86State,fpregs[reg].mmx)); + tcg_gen_ld_i64(cpu_T[0], cpu_env, + offsetof(CPUX86State,fpregs[reg].mmx)); gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 1); } else #endif { - gen_op_movl_T0_mm_mmx(offsetof(CPUX86State,fpregs[reg].mmx)); + tcg_gen_ld32u_tl(cpu_T[0], cpu_env, + offsetof(CPUX86State,fpregs[reg].mmx.MMX_L(0))); gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1); } break; case 0x17e: /* movd ea, xmm */ #ifdef TARGET_X86_64 if (s->dflag == 2) { - gen_op_movq_T0_mm_xmm(offsetof(CPUX86State,xmm_regs[reg])); + tcg_gen_ld_i64(cpu_T[0], cpu_env, + offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 1); } else #endif { - gen_op_movl_T0_mm_xmm(offsetof(CPUX86State,xmm_regs[reg])); + tcg_gen_ld32u_tl(cpu_T[0], cpu_env, + offsetof(CPUX86State,xmm_regs[reg].XMM_L(0))); gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1); } break; case 0x27e: /* movq xmm, ea */ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); } else { rm = (modrm & 7) | REX_B(s); gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)), @@ -2895,7 +3283,7 @@ case 0x7f: /* movq ea, mm */ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,fpregs[reg].mmx)); + gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,fpregs[reg].mmx)); } else { rm = (modrm & 7); gen_op_movq(offsetof(CPUX86State,fpregs[rm].mmx), @@ -2910,7 +3298,7 @@ case 0x27f: /* movdqu ea, xmm */ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_sto_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); + gen_sto_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg])); } else { rm = (modrm & 7) | REX_B(s); gen_op_movo(offsetof(CPUX86State,xmm_regs[rm]), @@ -2920,8 +3308,8 @@ case 0x211: /* movss ea, xmm */ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_movl_T0_env(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0))); - gen_op_st_T0_A0[OT_LONG + s->mem_index](); + tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(0))); + gen_op_st_T0_A0(OT_LONG + s->mem_index); } else { rm = (modrm & 7) | REX_B(s); gen_op_movl(offsetof(CPUX86State,xmm_regs[rm].XMM_L(0)), @@ -2931,7 +3319,7 @@ case 0x311: /* movsd ea, xmm */ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); } else { rm = (modrm & 7) | REX_B(s); gen_op_movq(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)), @@ -2942,7 +3330,7 @@ case 0x113: /* movlpd */ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); } else { goto illegal_op; } @@ -2951,7 +3339,7 @@ case 0x117: /* movhpd */ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1))); + gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1))); } else { goto illegal_op; } @@ -2965,15 +3353,15 @@ val = ldub_code(s->pc++); if (is_xmm) { gen_op_movl_T0_im(val); - gen_op_movl_env_T0(offsetof(CPUX86State,xmm_t0.XMM_L(0))); + tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(0))); gen_op_movl_T0_0(); - gen_op_movl_env_T0(offsetof(CPUX86State,xmm_t0.XMM_L(1))); + tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(1))); op1_offset = offsetof(CPUX86State,xmm_t0); } else { gen_op_movl_T0_im(val); - gen_op_movl_env_T0(offsetof(CPUX86State,mmx_t0.MMX_L(0))); + tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,mmx_t0.MMX_L(0))); gen_op_movl_T0_0(); - gen_op_movl_env_T0(offsetof(CPUX86State,mmx_t0.MMX_L(1))); + tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,mmx_t0.MMX_L(1))); op1_offset = offsetof(CPUX86State,mmx_t0); } sse_op2 = sse_op_table2[((b - 1) & 3) * 8 + (((modrm >> 3)) & 7)][b1]; @@ -2986,37 +3374,47 @@ rm = (modrm & 7); op2_offset = offsetof(CPUX86State,fpregs[rm].mmx); } - sse_op2(op2_offset, op1_offset); + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op2_offset); + tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op1_offset); + tcg_gen_helper_0_2(sse_op2, cpu_ptr0, cpu_ptr1); break; case 0x050: /* movmskps */ rm = (modrm & 7) | REX_B(s); - gen_op_movmskps(offsetof(CPUX86State,xmm_regs[rm])); - gen_op_mov_reg_T0[OT_LONG][reg](); + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, + offsetof(CPUX86State,xmm_regs[rm])); + tcg_gen_helper_1_1(helper_movmskps, cpu_tmp2_i32, cpu_ptr0); + tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); + gen_op_mov_reg_T0(OT_LONG, reg); break; case 0x150: /* movmskpd */ rm = (modrm & 7) | REX_B(s); - gen_op_movmskpd(offsetof(CPUX86State,xmm_regs[rm])); - gen_op_mov_reg_T0[OT_LONG][reg](); + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, + offsetof(CPUX86State,xmm_regs[rm])); + tcg_gen_helper_1_1(helper_movmskpd, cpu_tmp2_i32, cpu_ptr0); + tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); + gen_op_mov_reg_T0(OT_LONG, reg); break; case 0x02a: /* cvtpi2ps */ case 0x12a: /* cvtpi2pd */ - gen_op_enter_mmx(); + tcg_gen_helper_0_0(helper_enter_mmx); if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); op2_offset = offsetof(CPUX86State,mmx_t0); - gen_ldq_env_A0[s->mem_index >> 2](op2_offset); + gen_ldq_env_A0(s->mem_index, op2_offset); } else { rm = (modrm & 7); op2_offset = offsetof(CPUX86State,fpregs[rm].mmx); } op1_offset = offsetof(CPUX86State,xmm_regs[reg]); + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset); + tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset); switch(b >> 8) { case 0x0: - gen_op_cvtpi2ps(op1_offset, op2_offset); + tcg_gen_helper_0_2(helper_cvtpi2ps, cpu_ptr0, cpu_ptr1); break; default: case 0x1: - gen_op_cvtpi2pd(op1_offset, op2_offset); + tcg_gen_helper_0_2(helper_cvtpi2pd, cpu_ptr0, cpu_ptr1); break; } break; @@ -3025,34 +3423,43 @@ ot = (s->dflag == 2) ? OT_QUAD : OT_LONG; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); op1_offset = offsetof(CPUX86State,xmm_regs[reg]); - sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2)](op1_offset); + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset); + sse_op2 = sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2)]; + if (ot == OT_LONG) { + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_0_2(sse_op2, cpu_ptr0, cpu_tmp2_i32); + } else { + tcg_gen_helper_0_2(sse_op2, cpu_ptr0, cpu_T[0]); + } break; case 0x02c: /* cvttps2pi */ case 0x12c: /* cvttpd2pi */ case 0x02d: /* cvtps2pi */ case 0x12d: /* cvtpd2pi */ - gen_op_enter_mmx(); + tcg_gen_helper_0_0(helper_enter_mmx); if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); op2_offset = offsetof(CPUX86State,xmm_t0); - gen_ldo_env_A0[s->mem_index >> 2](op2_offset); + gen_ldo_env_A0(s->mem_index, op2_offset); } else { rm = (modrm & 7) | REX_B(s); op2_offset = offsetof(CPUX86State,xmm_regs[rm]); } op1_offset = offsetof(CPUX86State,fpregs[reg & 7].mmx); + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset); + tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset); switch(b) { case 0x02c: - gen_op_cvttps2pi(op1_offset, op2_offset); + tcg_gen_helper_0_2(helper_cvttps2pi, cpu_ptr0, cpu_ptr1); break; case 0x12c: - gen_op_cvttpd2pi(op1_offset, op2_offset); + tcg_gen_helper_0_2(helper_cvttpd2pi, cpu_ptr0, cpu_ptr1); break; case 0x02d: - gen_op_cvtps2pi(op1_offset, op2_offset); + tcg_gen_helper_0_2(helper_cvtps2pi, cpu_ptr0, cpu_ptr1); break; case 0x12d: - gen_op_cvtpd2pi(op1_offset, op2_offset); + tcg_gen_helper_0_2(helper_cvtpd2pi, cpu_ptr0, cpu_ptr1); break; } break; @@ -3064,19 +3471,26 @@ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); if ((b >> 8) & 1) { - gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_t0.XMM_Q(0))); + gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_t0.XMM_Q(0))); } else { - gen_op_ld_T0_A0[OT_LONG + s->mem_index](); - gen_op_movl_env_T0(offsetof(CPUX86State,xmm_t0.XMM_L(0))); + gen_op_ld_T0_A0(OT_LONG + s->mem_index); + tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(0))); } op2_offset = offsetof(CPUX86State,xmm_t0); } else { rm = (modrm & 7) | REX_B(s); op2_offset = offsetof(CPUX86State,xmm_regs[rm]); } - sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2) + 4 + - (b & 1) * 4](op2_offset); - gen_op_mov_reg_T0[ot][reg](); + sse_op2 = sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2) + 4 + + (b & 1) * 4]; + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op2_offset); + if (ot == OT_LONG) { + tcg_gen_helper_1_1(sse_op2, cpu_tmp2_i32, cpu_ptr0); + tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); + } else { + tcg_gen_helper_1_1(sse_op2, cpu_T[0], cpu_ptr0); + } + gen_op_mov_reg_T0(ot, reg); break; case 0xc4: /* pinsrw */ case 0x1c4: @@ -3085,33 +3499,38 @@ val = ldub_code(s->pc++); if (b1) { val &= 7; - gen_op_pinsrw_xmm(offsetof(CPUX86State,xmm_regs[reg]), val); + tcg_gen_st16_tl(cpu_T[0], cpu_env, + offsetof(CPUX86State,xmm_regs[reg].XMM_W(val))); } else { val &= 3; - gen_op_pinsrw_mmx(offsetof(CPUX86State,fpregs[reg].mmx), val); + tcg_gen_st16_tl(cpu_T[0], cpu_env, + offsetof(CPUX86State,fpregs[reg].mmx.MMX_W(val))); } break; case 0xc5: /* pextrw */ case 0x1c5: if (mod != 3) goto illegal_op; + ot = (s->dflag == 2) ? OT_QUAD : OT_LONG; val = ldub_code(s->pc++); if (b1) { val &= 7; rm = (modrm & 7) | REX_B(s); - gen_op_pextrw_xmm(offsetof(CPUX86State,xmm_regs[rm]), val); + tcg_gen_ld16u_tl(cpu_T[0], cpu_env, + offsetof(CPUX86State,xmm_regs[rm].XMM_W(val))); } else { val &= 3; rm = (modrm & 7); - gen_op_pextrw_mmx(offsetof(CPUX86State,fpregs[rm].mmx), val); + tcg_gen_ld16u_tl(cpu_T[0], cpu_env, + offsetof(CPUX86State,fpregs[rm].mmx.MMX_W(val))); } reg = ((modrm >> 3) & 7) | rex_r; - gen_op_mov_reg_T0[OT_LONG][reg](); + gen_op_mov_reg_T0(ot, reg); break; case 0x1d6: /* movq ea, xmm */ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); } else { rm = (modrm & 7) | REX_B(s); gen_op_movq(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)), @@ -3120,14 +3539,14 @@ } break; case 0x2d6: /* movq2dq */ - gen_op_enter_mmx(); + tcg_gen_helper_0_0(helper_enter_mmx); rm = (modrm & 7); gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)), offsetof(CPUX86State,fpregs[rm].mmx)); gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1))); break; case 0x3d6: /* movdq2q */ - gen_op_enter_mmx(); + tcg_gen_helper_0_0(helper_enter_mmx); rm = (modrm & 7) | REX_B(s); gen_op_movq(offsetof(CPUX86State,fpregs[reg & 7].mmx), offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0))); @@ -3138,13 +3557,281 @@ goto illegal_op; if (b1) { rm = (modrm & 7) | REX_B(s); - gen_op_pmovmskb_xmm(offsetof(CPUX86State,xmm_regs[rm])); + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, offsetof(CPUX86State,xmm_regs[rm])); + tcg_gen_helper_1_1(helper_pmovmskb_xmm, cpu_tmp2_i32, cpu_ptr0); } else { rm = (modrm & 7); - gen_op_pmovmskb_mmx(offsetof(CPUX86State,fpregs[rm].mmx)); + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, offsetof(CPUX86State,fpregs[rm].mmx)); + tcg_gen_helper_1_1(helper_pmovmskb_mmx, cpu_tmp2_i32, cpu_ptr0); + } + tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); + reg = ((modrm >> 3) & 7) | rex_r; + gen_op_mov_reg_T0(OT_LONG, reg); + break; + case 0x138: + if (s->prefix & PREFIX_REPNZ) + goto crc32; + case 0x038: + b = modrm; + modrm = ldub_code(s->pc++); + rm = modrm & 7; + reg = ((modrm >> 3) & 7) | rex_r; + mod = (modrm >> 6) & 3; + + sse_op2 = sse_op_table6[b].op[b1]; + if (!sse_op2) + goto illegal_op; + if (!(s->cpuid_ext_features & sse_op_table6[b].ext_mask)) + goto illegal_op; + + if (b1) { + op1_offset = offsetof(CPUX86State,xmm_regs[reg]); + if (mod == 3) { + op2_offset = offsetof(CPUX86State,xmm_regs[rm | REX_B(s)]); + } else { + op2_offset = offsetof(CPUX86State,xmm_t0); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + switch (b) { + case 0x20: case 0x30: /* pmovsxbw, pmovzxbw */ + case 0x23: case 0x33: /* pmovsxwd, pmovzxwd */ + case 0x25: case 0x35: /* pmovsxdq, pmovzxdq */ + gen_ldq_env_A0(s->mem_index, op2_offset + + offsetof(XMMReg, XMM_Q(0))); + break; + case 0x21: case 0x31: /* pmovsxbd, pmovzxbd */ + case 0x24: case 0x34: /* pmovsxwq, pmovzxwq */ + tcg_gen_qemu_ld32u(cpu_tmp2_i32, cpu_A0, + (s->mem_index >> 2) - 1); + tcg_gen_st_i32(cpu_tmp2_i32, cpu_env, op2_offset + + offsetof(XMMReg, XMM_L(0))); + break; + case 0x22: case 0x32: /* pmovsxbq, pmovzxbq */ + tcg_gen_qemu_ld16u(cpu_tmp0, cpu_A0, + (s->mem_index >> 2) - 1); + tcg_gen_st16_tl(cpu_tmp0, cpu_env, op2_offset + + offsetof(XMMReg, XMM_W(0))); + break; + case 0x2a: /* movntqda */ + gen_ldo_env_A0(s->mem_index, op1_offset); + return; + default: + gen_ldo_env_A0(s->mem_index, op2_offset); + } + } + } else { + op1_offset = offsetof(CPUX86State,fpregs[reg].mmx); + if (mod == 3) { + op2_offset = offsetof(CPUX86State,fpregs[rm].mmx); + } else { + op2_offset = offsetof(CPUX86State,mmx_t0); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_ldq_env_A0(s->mem_index, op2_offset); + } } + if (sse_op2 == SSE_SPECIAL) + goto illegal_op; + + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset); + tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset); + tcg_gen_helper_0_2(sse_op2, cpu_ptr0, cpu_ptr1); + + if (b == 0x17) + s->cc_op = CC_OP_EFLAGS; + break; + case 0x338: /* crc32 */ + crc32: + b = modrm; + modrm = ldub_code(s->pc++); + reg = ((modrm >> 3) & 7) | rex_r; + + if (b != 0xf0 && b != 0xf1) + goto illegal_op; + if (!(s->cpuid_ext_features & CPUID_EXT_SSE42)) + goto illegal_op; + + if (b == 0xf0) + ot = OT_BYTE; + else if (b == 0xf1 && s->dflag != 2) + if (s->prefix & PREFIX_DATA) + ot = OT_WORD; + else + ot = OT_LONG; + else + ot = OT_QUAD; + + gen_op_mov_TN_reg(OT_LONG, 0, reg); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + tcg_gen_helper_1_3(helper_crc32, cpu_T[0], cpu_tmp2_i32, + cpu_T[0], tcg_const_i32(8 << ot)); + + ot = (s->dflag == 2) ? OT_QUAD : OT_LONG; + gen_op_mov_reg_T0(ot, reg); + break; + case 0x03a: + case 0x13a: + b = modrm; + modrm = ldub_code(s->pc++); + rm = modrm & 7; reg = ((modrm >> 3) & 7) | rex_r; - gen_op_mov_reg_T0[OT_LONG][reg](); + mod = (modrm >> 6) & 3; + + sse_op2 = sse_op_table7[b].op[b1]; + if (!sse_op2) + goto illegal_op; + if (!(s->cpuid_ext_features & sse_op_table7[b].ext_mask)) + goto illegal_op; + + if (sse_op2 == SSE_SPECIAL) { + ot = (s->dflag == 2) ? OT_QUAD : OT_LONG; + rm = (modrm & 7) | REX_B(s); + if (mod != 3) + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + reg = ((modrm >> 3) & 7) | rex_r; + val = ldub_code(s->pc++); + switch (b) { + case 0x14: /* pextrb */ + tcg_gen_ld8u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, + xmm_regs[reg].XMM_B(val & 15))); + if (mod == 3) + gen_op_mov_reg_T0(ot, rm); + else + tcg_gen_qemu_st8(cpu_T[0], cpu_A0, + (s->mem_index >> 2) - 1); + break; + case 0x15: /* pextrw */ + tcg_gen_ld16u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, + xmm_regs[reg].XMM_W(val & 7))); + if (mod == 3) + gen_op_mov_reg_T0(ot, rm); + else + tcg_gen_qemu_st16(cpu_T[0], cpu_A0, + (s->mem_index >> 2) - 1); + break; + case 0x16: + if (ot == OT_LONG) { /* pextrd */ + tcg_gen_ld_i32(cpu_tmp2_i32, cpu_env, + offsetof(CPUX86State, + xmm_regs[reg].XMM_L(val & 3))); + if (mod == 3) + gen_op_mov_reg_v(ot, rm, cpu_tmp2_i32); + else + tcg_gen_qemu_st32(cpu_tmp2_i32, cpu_A0, + (s->mem_index >> 2) - 1); + } else { /* pextrq */ + tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, + offsetof(CPUX86State, + xmm_regs[reg].XMM_Q(val & 1))); + if (mod == 3) + gen_op_mov_reg_v(ot, rm, cpu_tmp1_i64); + else + tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, + (s->mem_index >> 2) - 1); + } + break; + case 0x17: /* extractps */ + tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, + xmm_regs[reg].XMM_L(val & 3))); + if (mod == 3) + gen_op_mov_reg_T0(ot, rm); + else + tcg_gen_qemu_st32(cpu_T[0], cpu_A0, + (s->mem_index >> 2) - 1); + break; + case 0x20: /* pinsrb */ + if (mod == 3) + gen_op_mov_TN_reg(OT_LONG, 0, rm); + else + tcg_gen_qemu_ld8u(cpu_T[0], cpu_A0, + (s->mem_index >> 2) - 1); + tcg_gen_st8_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, + xmm_regs[reg].XMM_B(val & 15))); + break; + case 0x21: /* insertps */ + if (mod == 3) + tcg_gen_ld_i32(cpu_tmp2_i32, cpu_env, + offsetof(CPUX86State,xmm_regs[rm] + .XMM_L((val >> 6) & 3))); + else + tcg_gen_qemu_ld32u(cpu_tmp2_i32, cpu_A0, + (s->mem_index >> 2) - 1); + tcg_gen_st_i32(cpu_tmp2_i32, cpu_env, + offsetof(CPUX86State,xmm_regs[reg] + .XMM_L((val >> 4) & 3))); + if ((val >> 0) & 1) + tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/), + cpu_env, offsetof(CPUX86State, + xmm_regs[reg].XMM_L(0))); + if ((val >> 1) & 1) + tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/), + cpu_env, offsetof(CPUX86State, + xmm_regs[reg].XMM_L(1))); + if ((val >> 2) & 1) + tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/), + cpu_env, offsetof(CPUX86State, + xmm_regs[reg].XMM_L(2))); + if ((val >> 3) & 1) + tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/), + cpu_env, offsetof(CPUX86State, + xmm_regs[reg].XMM_L(3))); + break; + case 0x22: + if (ot == OT_LONG) { /* pinsrd */ + if (mod == 3) + gen_op_mov_v_reg(ot, cpu_tmp2_i32, rm); + else + tcg_gen_qemu_ld32u(cpu_tmp2_i32, cpu_A0, + (s->mem_index >> 2) - 1); + tcg_gen_st_i32(cpu_tmp2_i32, cpu_env, + offsetof(CPUX86State, + xmm_regs[reg].XMM_L(val & 3))); + } else { /* pinsrq */ + if (mod == 3) + gen_op_mov_v_reg(ot, cpu_tmp1_i64, rm); + else + tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, + (s->mem_index >> 2) - 1); + tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, + offsetof(CPUX86State, + xmm_regs[reg].XMM_Q(val & 1))); + } + break; + } + return; + } + + if (b1) { + op1_offset = offsetof(CPUX86State,xmm_regs[reg]); + if (mod == 3) { + op2_offset = offsetof(CPUX86State,xmm_regs[rm | REX_B(s)]); + } else { + op2_offset = offsetof(CPUX86State,xmm_t0); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_ldo_env_A0(s->mem_index, op2_offset); + } + } else { + op1_offset = offsetof(CPUX86State,fpregs[reg].mmx); + if (mod == 3) { + op2_offset = offsetof(CPUX86State,fpregs[rm].mmx); + } else { + op2_offset = offsetof(CPUX86State,mmx_t0); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_ldq_env_A0(s->mem_index, op2_offset); + } + } + val = ldub_code(s->pc++); + + if ((b & 0xfc) == 0x60) { /* pcmpXstrX */ + s->cc_op = CC_OP_EFLAGS; + + if (s->dflag == 2) + /* The helper must use entire 64-bit gp registers */ + val |= 1 << 8; + } + + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset); + tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset); + tcg_gen_helper_0_3(sse_op2, cpu_ptr0, cpu_ptr1, tcg_const_i32(val)); break; default: goto illegal_op; @@ -3152,22 +3839,6 @@ } else { /* generic MMX or SSE operation */ switch(b) { - case 0xf7: - /* maskmov : we must prepare A0 */ - if (mod != 3) - goto illegal_op; -#ifdef TARGET_X86_64 - if (s->aflag == 2) { - gen_op_movq_A0_reg[R_EDI](); - } else -#endif - { - gen_op_movl_A0_reg[R_EDI](); - if (s->aflag == 0) - gen_op_andl_A0_ffff(); - } - gen_add_A0_ds_seg(s); - break; case 0x70: /* pshufx insn */ case 0xc6: /* pshufx insn */ case 0xc2: /* compare insns */ @@ -3186,14 +3857,14 @@ /* specific case for SSE single instructions */ if (b1 == 2) { /* 32 bit access */ - gen_op_ld_T0_A0[OT_LONG + s->mem_index](); - gen_op_movl_env_T0(offsetof(CPUX86State,xmm_t0.XMM_L(0))); + gen_op_ld_T0_A0(OT_LONG + s->mem_index); + tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(0))); } else { /* 64 bit access */ - gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_t0.XMM_D(0))); + gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_t0.XMM_D(0))); } } else { - gen_ldo_env_A0[s->mem_index >> 2](op2_offset); + gen_ldo_env_A0(s->mem_index, op2_offset); } } else { rm = (modrm & 7) | REX_B(s); @@ -3204,18 +3875,30 @@ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); op2_offset = offsetof(CPUX86State,mmx_t0); - gen_ldq_env_A0[s->mem_index >> 2](op2_offset); + gen_ldq_env_A0(s->mem_index, op2_offset); } else { rm = (modrm & 7); op2_offset = offsetof(CPUX86State,fpregs[rm].mmx); } } switch(b) { + case 0x0f: /* 3DNow! data insns */ + if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW)) + goto illegal_op; + val = ldub_code(s->pc++); + sse_op2 = sse_op_table5[val]; + if (!sse_op2) + goto illegal_op; + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset); + tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset); + tcg_gen_helper_0_2(sse_op2, cpu_ptr0, cpu_ptr1); + break; case 0x70: /* pshufx insn */ case 0xc6: /* pshufx insn */ val = ldub_code(s->pc++); - sse_op3 = (GenOpFunc3 *)sse_op2; - sse_op3(op1_offset, op2_offset, val); + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset); + tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset); + tcg_gen_helper_0_3(sse_op2, cpu_ptr0, cpu_ptr1, tcg_const_i32(val)); break; case 0xc2: /* compare insns */ @@ -3223,10 +3906,34 @@ if (val >= 8) goto illegal_op; sse_op2 = sse_op_table4[val][b1]; - sse_op2(op1_offset, op2_offset); + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset); + tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset); + tcg_gen_helper_0_2(sse_op2, cpu_ptr0, cpu_ptr1); + break; + case 0xf7: + /* maskmov : we must prepare A0 */ + if (mod != 3) + goto illegal_op; +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + gen_op_movq_A0_reg(R_EDI); + } else +#endif + { + gen_op_movl_A0_reg(R_EDI); + if (s->aflag == 0) + gen_op_andl_A0_ffff(); + } + gen_add_A0_ds_seg(s); + + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset); + tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset); + tcg_gen_helper_0_3(sse_op2, cpu_ptr0, cpu_ptr1, cpu_A0); break; default: - sse_op2(op1_offset, op2_offset); + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset); + tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset); + tcg_gen_helper_0_2(sse_op2, cpu_ptr0, cpu_ptr1); break; } if (b == 0x2e || b == 0x2f) { @@ -3235,7 +3942,6 @@ } } - /* convert one instruction. s->is_jmp is set if the translation must be stopped. Return the next pc value */ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) @@ -3246,6 +3952,8 @@ target_ulong next_eip, tval; int rex_w, rex_r; + if (unlikely(loglevel & CPU_LOG_TB_OP)) + tcg_gen_debug_insn_start(pc_start); s->pc = pc_start; prefixes = 0; aflag = s->code32; @@ -3367,7 +4075,7 @@ /* lock generation */ if (prefixes & PREFIX_LOCK) - gen_op_lock(); + tcg_gen_helper_0_0(helper_lock); /* now check op code */ reswitch: @@ -3412,13 +4120,13 @@ /* xor reg, reg optimisation */ gen_op_movl_T0_0(); s->cc_op = CC_OP_LOGICB + ot; - gen_op_mov_reg_T0[ot][reg](); + gen_op_mov_reg_T0(ot, reg); gen_op_update1_cc(); break; } else { opreg = rm; } - gen_op_mov_TN_reg[ot][1][reg](); + gen_op_mov_TN_reg(ot, 1, reg); gen_op(s, op, ot, opreg); break; case 1: /* OP Gv, Ev */ @@ -3428,11 +4136,11 @@ rm = (modrm & 7) | REX_B(s); if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_ld_T1_A0(ot + s->mem_index); } else if (op == OP_XORL && rm == reg) { goto xor_zero; } else { - gen_op_mov_TN_reg[ot][1][rm](); + gen_op_mov_TN_reg(ot, 1, rm); } gen_op(s, op, ot, reg); break; @@ -3445,9 +4153,11 @@ } break; + case 0x82: + if (CODE64(s)) + goto illegal_op; case 0x80: /* GRP1 */ case 0x81: - case 0x82: case 0x83: { int val; @@ -3514,9 +4224,9 @@ if (op == 0) s->rip_offset = insn_const_size(ot); gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot + s->mem_index](); + gen_op_ld_T0_A0(ot + s->mem_index); } else { - gen_op_mov_TN_reg[ot][0][rm](); + gen_op_mov_TN_reg(ot, 0, rm); } switch(op) { @@ -3527,19 +4237,19 @@ s->cc_op = CC_OP_LOGICB + ot; break; case 2: /* not */ - gen_op_notl_T0(); + tcg_gen_not_tl(cpu_T[0], cpu_T[0]); if (mod != 3) { - gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_st_T0_A0(ot + s->mem_index); } else { - gen_op_mov_reg_T0[ot][rm](); + gen_op_mov_reg_T0(ot, rm); } break; case 3: /* neg */ - gen_op_negl_T0(); + tcg_gen_neg_tl(cpu_T[0], cpu_T[0]); if (mod != 3) { - gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_st_T0_A0(ot + s->mem_index); } else { - gen_op_mov_reg_T0[ot][rm](); + gen_op_mov_reg_T0(ot, rm); } gen_op_update_neg_cc(); s->cc_op = CC_OP_SUBB + ot; @@ -3547,21 +4257,64 @@ case 4: /* mul */ switch(ot) { case OT_BYTE: - gen_op_mulb_AL_T0(); + gen_op_mov_TN_reg(OT_BYTE, 1, R_EAX); + tcg_gen_ext8u_tl(cpu_T[0], cpu_T[0]); + tcg_gen_ext8u_tl(cpu_T[1], cpu_T[1]); + /* XXX: use 32 bit mul which could be faster */ + tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + gen_op_mov_reg_T0(OT_WORD, R_EAX); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + tcg_gen_andi_tl(cpu_cc_src, cpu_T[0], 0xff00); s->cc_op = CC_OP_MULB; break; case OT_WORD: - gen_op_mulw_AX_T0(); + gen_op_mov_TN_reg(OT_WORD, 1, R_EAX); + tcg_gen_ext16u_tl(cpu_T[0], cpu_T[0]); + tcg_gen_ext16u_tl(cpu_T[1], cpu_T[1]); + /* XXX: use 32 bit mul which could be faster */ + tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + gen_op_mov_reg_T0(OT_WORD, R_EAX); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 16); + gen_op_mov_reg_T0(OT_WORD, R_EDX); + tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]); s->cc_op = CC_OP_MULW; break; default: case OT_LONG: - gen_op_mull_EAX_T0(); +#ifdef TARGET_X86_64 + gen_op_mov_TN_reg(OT_LONG, 1, R_EAX); + tcg_gen_ext32u_tl(cpu_T[0], cpu_T[0]); + tcg_gen_ext32u_tl(cpu_T[1], cpu_T[1]); + tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + gen_op_mov_reg_T0(OT_LONG, R_EAX); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 32); + gen_op_mov_reg_T0(OT_LONG, R_EDX); + tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]); +#else + { + TCGv t0, t1; + t0 = tcg_temp_new(TCG_TYPE_I64); + t1 = tcg_temp_new(TCG_TYPE_I64); + gen_op_mov_TN_reg(OT_LONG, 1, R_EAX); + tcg_gen_extu_i32_i64(t0, cpu_T[0]); + tcg_gen_extu_i32_i64(t1, cpu_T[1]); + tcg_gen_mul_i64(t0, t0, t1); + tcg_gen_trunc_i64_i32(cpu_T[0], t0); + gen_op_mov_reg_T0(OT_LONG, R_EAX); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_trunc_i64_i32(cpu_T[0], t0); + gen_op_mov_reg_T0(OT_LONG, R_EDX); + tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]); + } +#endif s->cc_op = CC_OP_MULL; break; #ifdef TARGET_X86_64 case OT_QUAD: - gen_op_mulq_EAX_T0(); + tcg_gen_helper_0_1(helper_mulq_EAX_T0, cpu_T[0]); s->cc_op = CC_OP_MULQ; break; #endif @@ -3570,21 +4323,68 @@ case 5: /* imul */ switch(ot) { case OT_BYTE: - gen_op_imulb_AL_T0(); + gen_op_mov_TN_reg(OT_BYTE, 1, R_EAX); + tcg_gen_ext8s_tl(cpu_T[0], cpu_T[0]); + tcg_gen_ext8s_tl(cpu_T[1], cpu_T[1]); + /* XXX: use 32 bit mul which could be faster */ + tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + gen_op_mov_reg_T0(OT_WORD, R_EAX); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + tcg_gen_ext8s_tl(cpu_tmp0, cpu_T[0]); + tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); s->cc_op = CC_OP_MULB; break; case OT_WORD: - gen_op_imulw_AX_T0(); + gen_op_mov_TN_reg(OT_WORD, 1, R_EAX); + tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]); + tcg_gen_ext16s_tl(cpu_T[1], cpu_T[1]); + /* XXX: use 32 bit mul which could be faster */ + tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + gen_op_mov_reg_T0(OT_WORD, R_EAX); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + tcg_gen_ext16s_tl(cpu_tmp0, cpu_T[0]); + tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); + tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 16); + gen_op_mov_reg_T0(OT_WORD, R_EDX); s->cc_op = CC_OP_MULW; break; default: case OT_LONG: - gen_op_imull_EAX_T0(); +#ifdef TARGET_X86_64 + gen_op_mov_TN_reg(OT_LONG, 1, R_EAX); + tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]); + tcg_gen_ext32s_tl(cpu_T[1], cpu_T[1]); + tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + gen_op_mov_reg_T0(OT_LONG, R_EAX); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + tcg_gen_ext32s_tl(cpu_tmp0, cpu_T[0]); + tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); + tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 32); + gen_op_mov_reg_T0(OT_LONG, R_EDX); +#else + { + TCGv t0, t1; + t0 = tcg_temp_new(TCG_TYPE_I64); + t1 = tcg_temp_new(TCG_TYPE_I64); + gen_op_mov_TN_reg(OT_LONG, 1, R_EAX); + tcg_gen_ext_i32_i64(t0, cpu_T[0]); + tcg_gen_ext_i32_i64(t1, cpu_T[1]); + tcg_gen_mul_i64(t0, t0, t1); + tcg_gen_trunc_i64_i32(cpu_T[0], t0); + gen_op_mov_reg_T0(OT_LONG, R_EAX); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + tcg_gen_sari_tl(cpu_tmp0, cpu_T[0], 31); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_trunc_i64_i32(cpu_T[0], t0); + gen_op_mov_reg_T0(OT_LONG, R_EDX); + tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); + } +#endif s->cc_op = CC_OP_MULL; break; #ifdef TARGET_X86_64 case OT_QUAD: - gen_op_imulq_EAX_T0(); + tcg_gen_helper_0_1(helper_imulq_EAX_T0, cpu_T[0]); s->cc_op = CC_OP_MULQ; break; #endif @@ -3594,21 +4394,21 @@ switch(ot) { case OT_BYTE: gen_jmp_im(pc_start - s->cs_base); - gen_op_divb_AL_T0(); + tcg_gen_helper_0_1(helper_divb_AL, cpu_T[0]); break; case OT_WORD: gen_jmp_im(pc_start - s->cs_base); - gen_op_divw_AX_T0(); + tcg_gen_helper_0_1(helper_divw_AX, cpu_T[0]); break; default: case OT_LONG: gen_jmp_im(pc_start - s->cs_base); - gen_op_divl_EAX_T0(); + tcg_gen_helper_0_1(helper_divl_EAX, cpu_T[0]); break; #ifdef TARGET_X86_64 case OT_QUAD: gen_jmp_im(pc_start - s->cs_base); - gen_op_divq_EAX_T0(); + tcg_gen_helper_0_1(helper_divq_EAX, cpu_T[0]); break; #endif } @@ -3617,21 +4417,21 @@ switch(ot) { case OT_BYTE: gen_jmp_im(pc_start - s->cs_base); - gen_op_idivb_AL_T0(); + tcg_gen_helper_0_1(helper_idivb_AL, cpu_T[0]); break; case OT_WORD: gen_jmp_im(pc_start - s->cs_base); - gen_op_idivw_AX_T0(); + tcg_gen_helper_0_1(helper_idivw_AX, cpu_T[0]); break; default: case OT_LONG: gen_jmp_im(pc_start - s->cs_base); - gen_op_idivl_EAX_T0(); + tcg_gen_helper_0_1(helper_idivl_EAX, cpu_T[0]); break; #ifdef TARGET_X86_64 case OT_QUAD: gen_jmp_im(pc_start - s->cs_base); - gen_op_idivq_EAX_T0(); + tcg_gen_helper_0_1(helper_idivq_EAX, cpu_T[0]); break; #endif } @@ -3671,9 +4471,9 @@ if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); if (op >= 2 && op != 3 && op != 5) - gen_op_ld_T0_A0[ot + s->mem_index](); + gen_op_ld_T0_A0(ot + s->mem_index); } else { - gen_op_mov_TN_reg[ot][0][rm](); + gen_op_mov_TN_reg(ot, 0, rm); } switch(op) { @@ -3702,17 +4502,25 @@ gen_eob(s); break; case 3: /* lcall Ev */ - gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_ld_T1_A0(ot + s->mem_index); gen_add_A0_im(s, 1 << (ot - OT_WORD + 1)); - gen_op_ldu_T0_A0[OT_WORD + s->mem_index](); + gen_op_ldu_T0_A0(OT_WORD + s->mem_index); do_lcall: if (s->pe && !s->vm86) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); - gen_op_lcall_protected_T0_T1(dflag, s->pc - pc_start); - } else { - gen_op_lcall_real_T0_T1(dflag, s->pc - s->cs_base); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_0_4(helper_lcall_protected, + cpu_tmp2_i32, cpu_T[1], + tcg_const_i32(dflag), + tcg_const_i32(s->pc - pc_start)); + } else { + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_0_4(helper_lcall_real, + cpu_tmp2_i32, cpu_T[1], + tcg_const_i32(dflag), + tcg_const_i32(s->pc - s->cs_base)); } gen_eob(s); break; @@ -3723,17 +4531,21 @@ gen_eob(s); break; case 5: /* ljmp Ev */ - gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_ld_T1_A0(ot + s->mem_index); gen_add_A0_im(s, 1 << (ot - OT_WORD + 1)); - gen_op_ldu_T0_A0[OT_WORD + s->mem_index](); + gen_op_ldu_T0_A0(OT_WORD + s->mem_index); do_ljmp: if (s->pe && !s->vm86) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); - gen_op_ljmp_protected_T0_T1(s->pc - pc_start); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_0_3(helper_ljmp_protected, + cpu_tmp2_i32, + cpu_T[1], + tcg_const_i32(s->pc - pc_start)); } else { - gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); + gen_op_movl_seg_T0_vm(R_CS); gen_op_movl_T0_T1(); gen_op_jmp_T0(); } @@ -3760,7 +4572,7 @@ reg = ((modrm >> 3) & 7) | rex_r; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); - gen_op_mov_TN_reg[ot][1][reg](); + gen_op_mov_TN_reg(ot, 1, reg); gen_op_testl_T0_T1_cc(); s->cc_op = CC_OP_LOGICB + ot; break; @@ -3773,7 +4585,7 @@ ot = dflag + OT_WORD; val = insn_get(s, ot); - gen_op_mov_TN_reg[ot][0][OR_EAX](); + gen_op_mov_TN_reg(ot, 0, OR_EAX); gen_op_movl_T1_im(val); gen_op_testl_T0_T1_cc(); s->cc_op = CC_OP_LOGICB + ot; @@ -3782,24 +4594,40 @@ case 0x98: /* CWDE/CBW */ #ifdef TARGET_X86_64 if (dflag == 2) { - gen_op_movslq_RAX_EAX(); + gen_op_mov_TN_reg(OT_LONG, 0, R_EAX); + tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]); + gen_op_mov_reg_T0(OT_QUAD, R_EAX); } else #endif - if (dflag == 1) - gen_op_movswl_EAX_AX(); - else - gen_op_movsbw_AX_AL(); + if (dflag == 1) { + gen_op_mov_TN_reg(OT_WORD, 0, R_EAX); + tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]); + gen_op_mov_reg_T0(OT_LONG, R_EAX); + } else { + gen_op_mov_TN_reg(OT_BYTE, 0, R_EAX); + tcg_gen_ext8s_tl(cpu_T[0], cpu_T[0]); + gen_op_mov_reg_T0(OT_WORD, R_EAX); + } break; case 0x99: /* CDQ/CWD */ #ifdef TARGET_X86_64 if (dflag == 2) { - gen_op_movsqo_RDX_RAX(); + gen_op_mov_TN_reg(OT_QUAD, 0, R_EAX); + tcg_gen_sari_tl(cpu_T[0], cpu_T[0], 63); + gen_op_mov_reg_T0(OT_QUAD, R_EDX); } else #endif - if (dflag == 1) - gen_op_movslq_EDX_EAX(); - else - gen_op_movswl_DX_AX(); + if (dflag == 1) { + gen_op_mov_TN_reg(OT_LONG, 0, R_EAX); + tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]); + tcg_gen_sari_tl(cpu_T[0], cpu_T[0], 31); + gen_op_mov_reg_T0(OT_LONG, R_EDX); + } else { + gen_op_mov_TN_reg(OT_WORD, 0, R_EAX); + tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]); + tcg_gen_sari_tl(cpu_T[0], cpu_T[0], 15); + gen_op_mov_reg_T0(OT_WORD, R_EDX); + } break; case 0x1af: /* imul Gv, Ev */ case 0x69: /* imul Gv, Ev, I */ @@ -3819,20 +4647,48 @@ val = (int8_t)insn_get(s, OT_BYTE); gen_op_movl_T1_im(val); } else { - gen_op_mov_TN_reg[ot][1][reg](); + gen_op_mov_TN_reg(ot, 1, reg); } #ifdef TARGET_X86_64 if (ot == OT_QUAD) { - gen_op_imulq_T0_T1(); + tcg_gen_helper_1_2(helper_imulq_T0_T1, cpu_T[0], cpu_T[0], cpu_T[1]); } else #endif if (ot == OT_LONG) { - gen_op_imull_T0_T1(); +#ifdef TARGET_X86_64 + tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]); + tcg_gen_ext32s_tl(cpu_T[1], cpu_T[1]); + tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + tcg_gen_ext32s_tl(cpu_tmp0, cpu_T[0]); + tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); +#else + { + TCGv t0, t1; + t0 = tcg_temp_new(TCG_TYPE_I64); + t1 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_ext_i32_i64(t0, cpu_T[0]); + tcg_gen_ext_i32_i64(t1, cpu_T[1]); + tcg_gen_mul_i64(t0, t0, t1); + tcg_gen_trunc_i64_i32(cpu_T[0], t0); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + tcg_gen_sari_tl(cpu_tmp0, cpu_T[0], 31); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_trunc_i64_i32(cpu_T[1], t0); + tcg_gen_sub_tl(cpu_cc_src, cpu_T[1], cpu_tmp0); + } +#endif } else { - gen_op_imulw_T0_T1(); + tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]); + tcg_gen_ext16s_tl(cpu_T[1], cpu_T[1]); + /* XXX: use 32 bit mul which could be faster */ + tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + tcg_gen_ext16s_tl(cpu_tmp0, cpu_T[0]); + tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); } - gen_op_mov_reg_T0[ot][reg](); + gen_op_mov_reg_T0(ot, reg); s->cc_op = CC_OP_MULB + ot; break; case 0x1c0: @@ -3846,61 +4702,109 @@ mod = (modrm >> 6) & 3; if (mod == 3) { rm = (modrm & 7) | REX_B(s); - gen_op_mov_TN_reg[ot][0][reg](); - gen_op_mov_TN_reg[ot][1][rm](); + gen_op_mov_TN_reg(ot, 0, reg); + gen_op_mov_TN_reg(ot, 1, rm); gen_op_addl_T0_T1(); - gen_op_mov_reg_T1[ot][reg](); - gen_op_mov_reg_T0[ot][rm](); + gen_op_mov_reg_T1(ot, reg); + gen_op_mov_reg_T0(ot, rm); } else { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_mov_TN_reg[ot][0][reg](); - gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_mov_TN_reg(ot, 0, reg); + gen_op_ld_T1_A0(ot + s->mem_index); gen_op_addl_T0_T1(); - gen_op_st_T0_A0[ot + s->mem_index](); - gen_op_mov_reg_T1[ot][reg](); + gen_op_st_T0_A0(ot + s->mem_index); + gen_op_mov_reg_T1(ot, reg); } gen_op_update2_cc(); s->cc_op = CC_OP_ADDB + ot; break; case 0x1b0: case 0x1b1: /* cmpxchg Ev, Gv */ - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag + OT_WORD; - modrm = ldub_code(s->pc++); - reg = ((modrm >> 3) & 7) | rex_r; - mod = (modrm >> 6) & 3; - gen_op_mov_TN_reg[ot][1][reg](); - if (mod == 3) { - rm = (modrm & 7) | REX_B(s); - gen_op_mov_TN_reg[ot][0][rm](); - gen_op_cmpxchg_T0_T1_EAX_cc[ot](); - gen_op_mov_reg_T0[ot][rm](); - } else { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot + s->mem_index](); - gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot + s->mem_index](); + { + int label1, label2; + TCGv t0, t1, t2, a0; + + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag + OT_WORD; + modrm = ldub_code(s->pc++); + reg = ((modrm >> 3) & 7) | rex_r; + mod = (modrm >> 6) & 3; + t0 = tcg_temp_local_new(TCG_TYPE_TL); + t1 = tcg_temp_local_new(TCG_TYPE_TL); + t2 = tcg_temp_local_new(TCG_TYPE_TL); + a0 = tcg_temp_local_new(TCG_TYPE_TL); + gen_op_mov_v_reg(ot, t1, reg); + if (mod == 3) { + rm = (modrm & 7) | REX_B(s); + gen_op_mov_v_reg(ot, t0, rm); + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + tcg_gen_mov_tl(a0, cpu_A0); + gen_op_ld_v(ot + s->mem_index, t0, a0); + rm = 0; /* avoid warning */ + } + label1 = gen_new_label(); + tcg_gen_ld_tl(t2, cpu_env, offsetof(CPUState, regs[R_EAX])); + tcg_gen_sub_tl(t2, t2, t0); + gen_extu(ot, t2); + tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label1); + if (mod == 3) { + label2 = gen_new_label(); + gen_op_mov_reg_v(ot, R_EAX, t0); + tcg_gen_br(label2); + gen_set_label(label1); + gen_op_mov_reg_v(ot, rm, t1); + gen_set_label(label2); + } else { + tcg_gen_mov_tl(t1, t0); + gen_op_mov_reg_v(ot, R_EAX, t0); + gen_set_label(label1); + /* always store */ + gen_op_st_v(ot + s->mem_index, t1, a0); + } + tcg_gen_mov_tl(cpu_cc_src, t0); + tcg_gen_mov_tl(cpu_cc_dst, t2); + s->cc_op = CC_OP_SUBB + ot; + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free(t2); + tcg_temp_free(a0); } - s->cc_op = CC_OP_SUBB + ot; break; case 0x1c7: /* cmpxchg8b */ modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; if ((mod == 3) || ((modrm & 0x38) != 0x8)) goto illegal_op; - gen_jmp_im(pc_start - s->cs_base); - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_cmpxchg8b(); +#ifdef TARGET_X86_64 + if (dflag == 2) { + if (!(s->cpuid_ext_features & CPUID_EXT_CX16)) + goto illegal_op; + gen_jmp_im(pc_start - s->cs_base); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + tcg_gen_helper_0_1(helper_cmpxchg16b, cpu_A0); + } else +#endif + { + if (!(s->cpuid_features & CPUID_CX8)) + goto illegal_op; + gen_jmp_im(pc_start - s->cs_base); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + tcg_gen_helper_0_1(helper_cmpxchg8b, cpu_A0); + } s->cc_op = CC_OP_EFLAGS; break; /**************************/ /* push/pop */ case 0x50 ... 0x57: /* push */ - gen_op_mov_TN_reg[OT_LONG][0][(b & 7) | REX_B(s)](); + gen_op_mov_TN_reg(OT_LONG, 0, (b & 7) | REX_B(s)); gen_push_T0(s); break; case 0x58 ... 0x5f: /* pop */ @@ -3912,7 +4816,7 @@ gen_pop_T0(s); /* NOTE: order is important for pop %sp */ gen_pop_update(s); - gen_op_mov_reg_T0[ot][(b & 7) | REX_B(s)](); + gen_op_mov_reg_T0(ot, (b & 7) | REX_B(s)); break; case 0x60: /* pusha */ if (CODE64(s)) @@ -3951,7 +4855,7 @@ /* NOTE: order is important for pop %sp */ gen_pop_update(s); rm = (modrm & 7) | REX_B(s); - gen_op_mov_reg_T0[ot][rm](); + gen_op_mov_reg_T0(ot, rm); } else { /* NOTE: order is important too for MMU exceptions */ s->popl_esp_hack = 1 << ot; @@ -3972,14 +4876,14 @@ case 0xc9: /* leave */ /* XXX: exception not precise (ESP is updated before potential exception) */ if (CODE64(s)) { - gen_op_mov_TN_reg[OT_QUAD][0][R_EBP](); - gen_op_mov_reg_T0[OT_QUAD][R_ESP](); + gen_op_mov_TN_reg(OT_QUAD, 0, R_EBP); + gen_op_mov_reg_T0(OT_QUAD, R_ESP); } else if (s->ss32) { - gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); - gen_op_mov_reg_T0[OT_LONG][R_ESP](); + gen_op_mov_TN_reg(OT_LONG, 0, R_EBP); + gen_op_mov_reg_T0(OT_LONG, R_ESP); } else { - gen_op_mov_TN_reg[OT_WORD][0][R_EBP](); - gen_op_mov_reg_T0[OT_WORD][R_ESP](); + gen_op_mov_TN_reg(OT_WORD, 0, R_EBP); + gen_op_mov_reg_T0(OT_WORD, R_ESP); } gen_pop_T0(s); if (CODE64(s)) { @@ -3987,7 +4891,7 @@ } else { ot = dflag + OT_WORD; } - gen_op_mov_reg_T0[ot][R_EBP](); + gen_op_mov_reg_T0(ot, R_EBP); gen_pop_update(s); break; case 0x06: /* push es */ @@ -4018,7 +4922,7 @@ /* If several instructions disable interrupts, only the _first_ does it */ if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK)) - gen_op_set_inhibit_irq(); + tcg_gen_helper_0_0(helper_set_inhibit_irq); s->tf = 0; } if (s->is_jmp) { @@ -4066,9 +4970,9 @@ val = insn_get(s, ot); gen_op_movl_T0_im(val); if (mod != 3) - gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_st_T0_A0(ot + s->mem_index); else - gen_op_mov_reg_T0[ot][(modrm & 7) | REX_B(s)](); + gen_op_mov_reg_T0(ot, (modrm & 7) | REX_B(s)); break; case 0x8a: case 0x8b: /* mov Ev, Gv */ @@ -4080,7 +4984,7 @@ reg = ((modrm >> 3) & 7) | rex_r; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); - gen_op_mov_reg_T0[ot][reg](); + gen_op_mov_reg_T0(ot, reg); break; case 0x8e: /* mov seg, Gv */ modrm = ldub_code(s->pc++); @@ -4094,7 +4998,7 @@ /* If several instructions disable interrupts, only the _first_ does it */ if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK)) - gen_op_set_inhibit_irq(); + tcg_gen_helper_0_0(helper_set_inhibit_irq); s->tf = 0; } if (s->is_jmp) { @@ -4132,31 +5036,31 @@ rm = (modrm & 7) | REX_B(s); if (mod == 3) { - gen_op_mov_TN_reg[ot][0][rm](); + gen_op_mov_TN_reg(ot, 0, rm); switch(ot | (b & 8)) { case OT_BYTE: - gen_op_movzbl_T0_T0(); + tcg_gen_ext8u_tl(cpu_T[0], cpu_T[0]); break; case OT_BYTE | 8: - gen_op_movsbl_T0_T0(); + tcg_gen_ext8s_tl(cpu_T[0], cpu_T[0]); break; case OT_WORD: - gen_op_movzwl_T0_T0(); + tcg_gen_ext16u_tl(cpu_T[0], cpu_T[0]); break; default: case OT_WORD | 8: - gen_op_movswl_T0_T0(); + tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]); break; } - gen_op_mov_reg_T0[d_ot][reg](); + gen_op_mov_reg_T0(d_ot, reg); } else { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); if (b & 8) { - gen_op_lds_T0_A0[ot + s->mem_index](); + gen_op_lds_T0_A0(ot + s->mem_index); } else { - gen_op_ldu_T0_A0[ot + s->mem_index](); + gen_op_ldu_T0_A0(ot + s->mem_index); } - gen_op_mov_reg_T0[d_ot][reg](); + gen_op_mov_reg_T0(d_ot, reg); } } break; @@ -4174,7 +5078,7 @@ s->addseg = 0; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); s->addseg = val; - gen_op_mov_reg_A0[ot - OT_WORD][reg](); + gen_op_mov_reg_A0(ot - OT_WORD, reg); break; case 0xa0: /* mov EAX, Ov */ @@ -4192,10 +5096,7 @@ if (s->aflag == 2) { offset_addr = ldq_code(s->pc); s->pc += 8; - if (offset_addr == (int32_t)offset_addr) - gen_op_movq_A0_im(offset_addr); - else - gen_op_movq_A0_im64(offset_addr >> 32, offset_addr); + gen_op_movq_A0_im(offset_addr); } else #endif { @@ -4208,35 +5109,41 @@ } gen_add_A0_ds_seg(s); if ((b & 2) == 0) { - gen_op_ld_T0_A0[ot + s->mem_index](); - gen_op_mov_reg_T0[ot][R_EAX](); + gen_op_ld_T0_A0(ot + s->mem_index); + gen_op_mov_reg_T0(ot, R_EAX); } else { - gen_op_mov_TN_reg[ot][0][R_EAX](); - gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_mov_TN_reg(ot, 0, R_EAX); + gen_op_st_T0_A0(ot + s->mem_index); } } break; case 0xd7: /* xlat */ #ifdef TARGET_X86_64 if (s->aflag == 2) { - gen_op_movq_A0_reg[R_EBX](); - gen_op_addq_A0_AL(); + gen_op_movq_A0_reg(R_EBX); + gen_op_mov_TN_reg(OT_QUAD, 0, R_EAX); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 0xff); + tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_T[0]); } else #endif { - gen_op_movl_A0_reg[R_EBX](); - gen_op_addl_A0_AL(); + gen_op_movl_A0_reg(R_EBX); + gen_op_mov_TN_reg(OT_LONG, 0, R_EAX); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 0xff); + tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_T[0]); if (s->aflag == 0) gen_op_andl_A0_ffff(); + else + tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffffffff); } gen_add_A0_ds_seg(s); - gen_op_ldu_T0_A0[OT_BYTE + s->mem_index](); - gen_op_mov_reg_T0[OT_BYTE][R_EAX](); + gen_op_ldu_T0_A0(OT_BYTE + s->mem_index); + gen_op_mov_reg_T0(OT_BYTE, R_EAX); break; case 0xb0 ... 0xb7: /* mov R, Ib */ val = insn_get(s, OT_BYTE); gen_op_movl_T0_im(val); - gen_op_mov_reg_T0[OT_BYTE][(b & 7) | REX_B(s)](); + gen_op_mov_reg_T0(OT_BYTE, (b & 7) | REX_B(s)); break; case 0xb8 ... 0xbf: /* mov R, Iv */ #ifdef TARGET_X86_64 @@ -4247,7 +5154,7 @@ s->pc += 8; reg = (b & 7) | REX_B(s); gen_movtl_T0_im(tmp); - gen_op_mov_reg_T0[OT_QUAD][reg](); + gen_op_mov_reg_T0(OT_QUAD, reg); } else #endif { @@ -4255,7 +5162,7 @@ val = insn_get(s, ot); reg = (b & 7) | REX_B(s); gen_op_movl_T0_im(val); - gen_op_mov_reg_T0[ot][reg](); + gen_op_mov_reg_T0(ot, reg); } break; @@ -4276,21 +5183,21 @@ if (mod == 3) { rm = (modrm & 7) | REX_B(s); do_xchg_reg: - gen_op_mov_TN_reg[ot][0][reg](); - gen_op_mov_TN_reg[ot][1][rm](); - gen_op_mov_reg_T0[ot][rm](); - gen_op_mov_reg_T1[ot][reg](); + gen_op_mov_TN_reg(ot, 0, reg); + gen_op_mov_TN_reg(ot, 1, rm); + gen_op_mov_reg_T0(ot, rm); + gen_op_mov_reg_T1(ot, reg); } else { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_mov_TN_reg[ot][0][reg](); + gen_op_mov_TN_reg(ot, 0, reg); /* for xchg, lock is implicit */ if (!(prefixes & PREFIX_LOCK)) - gen_op_lock(); - gen_op_ld_T1_A0[ot + s->mem_index](); - gen_op_st_T0_A0[ot + s->mem_index](); + tcg_gen_helper_0_0(helper_lock); + gen_op_ld_T1_A0(ot + s->mem_index); + gen_op_st_T0_A0(ot + s->mem_index); if (!(prefixes & PREFIX_LOCK)) - gen_op_unlock(); - gen_op_mov_reg_T1[ot][reg](); + tcg_gen_helper_0_0(helper_unlock); + gen_op_mov_reg_T1(ot, reg); } break; case 0xc4: /* les Gv */ @@ -4319,13 +5226,13 @@ if (mod == 3) goto illegal_op; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_ld_T1_A0(ot + s->mem_index); gen_add_A0_im(s, 1 << (ot - OT_WORD + 1)); /* load the segment first to handle exceptions properly */ - gen_op_ldu_T0_A0[OT_WORD + s->mem_index](); + gen_op_ldu_T0_A0(OT_WORD + s->mem_index); gen_movl_seg_T0(s, op, pc_start - s->cs_base); /* then put the data */ - gen_op_mov_reg_T1[ot][reg](); + gen_op_mov_reg_T1(ot, reg); if (s->is_jmp) { gen_jmp_im(s->pc - s->cs_base); gen_eob(s); @@ -4402,43 +5309,21 @@ mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); reg = ((modrm >> 3) & 7) | rex_r; - if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot + s->mem_index](); + opreg = OR_TMP0; } else { - gen_op_mov_TN_reg[ot][0][rm](); + opreg = rm; } - gen_op_mov_TN_reg[ot][1][reg](); + gen_op_mov_TN_reg(ot, 1, reg); if (shift) { val = ldub_code(s->pc++); - if (ot == OT_QUAD) - val &= 0x3f; - else - val &= 0x1f; - if (val) { - if (mod == 3) - gen_op_shiftd_T0_T1_im_cc[ot][op](val); - else - gen_op_shiftd_mem_T0_T1_im_cc[ot + s->mem_index][op](val); - if (op == 0 && ot != OT_WORD) - s->cc_op = CC_OP_SHLB + ot; - else - s->cc_op = CC_OP_SARB + ot; - } + tcg_gen_movi_tl(cpu_T3, val); } else { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - if (mod == 3) - gen_op_shiftd_T0_T1_ECX_cc[ot][op](); - else - gen_op_shiftd_mem_T0_T1_ECX_cc[ot + s->mem_index][op](); - s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ - } - if (mod == 3) { - gen_op_mov_reg_T0[ot][rm](); + tcg_gen_ld_tl(cpu_T3, cpu_env, offsetof(CPUState, regs[R_ECX])); } + gen_shiftd_rm_T1_T3(s, ot, opreg, op); break; /************************/ @@ -4468,24 +5353,32 @@ switch(op >> 4) { case 0: - gen_op_flds_FT0_A0(); + gen_op_ld_T0_A0(OT_LONG + s->mem_index); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_0_1(helper_flds_FT0, cpu_tmp2_i32); break; case 1: - gen_op_fildl_FT0_A0(); + gen_op_ld_T0_A0(OT_LONG + s->mem_index); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_0_1(helper_fildl_FT0, cpu_tmp2_i32); break; case 2: - gen_op_fldl_FT0_A0(); + tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, + (s->mem_index >> 2) - 1); + tcg_gen_helper_0_1(helper_fldl_FT0, cpu_tmp1_i64); break; case 3: default: - gen_op_fild_FT0_A0(); + gen_op_lds_T0_A0(OT_WORD + s->mem_index); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_0_1(helper_fildl_FT0, cpu_tmp2_i32); break; } - gen_op_fp_arith_ST0_FT0[op1](); + tcg_gen_helper_0_0(helper_fp_arith_ST0_FT0[op1]); if (op1 == 3) { /* fcomp needs pop */ - gen_op_fpop(); + tcg_gen_helper_0_0(helper_fpop); } } break; @@ -4499,96 +5392,158 @@ case 0: switch(op >> 4) { case 0: - gen_op_flds_ST0_A0(); + gen_op_ld_T0_A0(OT_LONG + s->mem_index); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_0_1(helper_flds_ST0, cpu_tmp2_i32); break; case 1: - gen_op_fildl_ST0_A0(); + gen_op_ld_T0_A0(OT_LONG + s->mem_index); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_0_1(helper_fildl_ST0, cpu_tmp2_i32); break; case 2: - gen_op_fldl_ST0_A0(); + tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, + (s->mem_index >> 2) - 1); + tcg_gen_helper_0_1(helper_fldl_ST0, cpu_tmp1_i64); break; case 3: default: - gen_op_fild_ST0_A0(); + gen_op_lds_T0_A0(OT_WORD + s->mem_index); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_0_1(helper_fildl_ST0, cpu_tmp2_i32); break; } break; case 1: + /* XXX: the corresponding CPUID bit must be tested ! */ switch(op >> 4) { case 1: - gen_op_fisttl_ST0_A0(); + tcg_gen_helper_1_0(helper_fisttl_ST0, cpu_tmp2_i32); + tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); + gen_op_st_T0_A0(OT_LONG + s->mem_index); break; case 2: - gen_op_fisttll_ST0_A0(); + tcg_gen_helper_1_0(helper_fisttll_ST0, cpu_tmp1_i64); + tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, + (s->mem_index >> 2) - 1); break; case 3: default: - gen_op_fistt_ST0_A0(); + tcg_gen_helper_1_0(helper_fistt_ST0, cpu_tmp2_i32); + tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); + gen_op_st_T0_A0(OT_WORD + s->mem_index); + break; } - gen_op_fpop(); + tcg_gen_helper_0_0(helper_fpop); break; default: switch(op >> 4) { case 0: - gen_op_fsts_ST0_A0(); + tcg_gen_helper_1_0(helper_fsts_ST0, cpu_tmp2_i32); + tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); + gen_op_st_T0_A0(OT_LONG + s->mem_index); break; case 1: - gen_op_fistl_ST0_A0(); + tcg_gen_helper_1_0(helper_fistl_ST0, cpu_tmp2_i32); + tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); + gen_op_st_T0_A0(OT_LONG + s->mem_index); break; case 2: - gen_op_fstl_ST0_A0(); + tcg_gen_helper_1_0(helper_fstl_ST0, cpu_tmp1_i64); + tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, + (s->mem_index >> 2) - 1); break; case 3: default: - gen_op_fist_ST0_A0(); + tcg_gen_helper_1_0(helper_fist_ST0, cpu_tmp2_i32); + tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); + gen_op_st_T0_A0(OT_WORD + s->mem_index); break; } if ((op & 7) == 3) - gen_op_fpop(); + tcg_gen_helper_0_0(helper_fpop); break; } break; case 0x0c: /* fldenv mem */ - gen_op_fldenv_A0(s->dflag); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(pc_start - s->cs_base); + tcg_gen_helper_0_2(helper_fldenv, + cpu_A0, tcg_const_i32(s->dflag)); break; case 0x0d: /* fldcw mem */ - gen_op_fldcw_A0(); + gen_op_ld_T0_A0(OT_WORD + s->mem_index); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_0_1(helper_fldcw, cpu_tmp2_i32); break; case 0x0e: /* fnstenv mem */ - gen_op_fnstenv_A0(s->dflag); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(pc_start - s->cs_base); + tcg_gen_helper_0_2(helper_fstenv, + cpu_A0, tcg_const_i32(s->dflag)); break; case 0x0f: /* fnstcw mem */ - gen_op_fnstcw_A0(); + tcg_gen_helper_1_0(helper_fnstcw, cpu_tmp2_i32); + tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); + gen_op_st_T0_A0(OT_WORD + s->mem_index); break; case 0x1d: /* fldt mem */ - gen_op_fldt_ST0_A0(); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(pc_start - s->cs_base); + tcg_gen_helper_0_1(helper_fldt_ST0, cpu_A0); break; case 0x1f: /* fstpt mem */ - gen_op_fstt_ST0_A0(); - gen_op_fpop(); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(pc_start - s->cs_base); + tcg_gen_helper_0_1(helper_fstt_ST0, cpu_A0); + tcg_gen_helper_0_0(helper_fpop); break; case 0x2c: /* frstor mem */ - gen_op_frstor_A0(s->dflag); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(pc_start - s->cs_base); + tcg_gen_helper_0_2(helper_frstor, + cpu_A0, tcg_const_i32(s->dflag)); break; case 0x2e: /* fnsave mem */ - gen_op_fnsave_A0(s->dflag); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(pc_start - s->cs_base); + tcg_gen_helper_0_2(helper_fsave, + cpu_A0, tcg_const_i32(s->dflag)); break; case 0x2f: /* fnstsw mem */ - gen_op_fnstsw_A0(); + tcg_gen_helper_1_0(helper_fnstsw, cpu_tmp2_i32); + tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); + gen_op_st_T0_A0(OT_WORD + s->mem_index); break; case 0x3c: /* fbld */ - gen_op_fbld_ST0_A0(); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(pc_start - s->cs_base); + tcg_gen_helper_0_1(helper_fbld_ST0, cpu_A0); break; case 0x3e: /* fbstp */ - gen_op_fbst_ST0_A0(); - gen_op_fpop(); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(pc_start - s->cs_base); + tcg_gen_helper_0_1(helper_fbst_ST0, cpu_A0); + tcg_gen_helper_0_0(helper_fpop); break; case 0x3d: /* fildll */ - gen_op_fildll_ST0_A0(); + tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, + (s->mem_index >> 2) - 1); + tcg_gen_helper_0_1(helper_fildll_ST0, cpu_tmp1_i64); break; case 0x3f: /* fistpll */ - gen_op_fistll_ST0_A0(); - gen_op_fpop(); + tcg_gen_helper_1_0(helper_fistll_ST0, cpu_tmp1_i64); + tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, + (s->mem_index >> 2) - 1); + tcg_gen_helper_0_0(helper_fpop); break; default: goto illegal_op; @@ -4599,13 +5554,13 @@ switch(op) { case 0x08: /* fld sti */ - gen_op_fpush(); - gen_op_fmov_ST0_STN((opreg + 1) & 7); + tcg_gen_helper_0_0(helper_fpush); + tcg_gen_helper_0_1(helper_fmov_ST0_STN, tcg_const_i32((opreg + 1) & 7)); break; case 0x09: /* fxchg sti */ case 0x29: /* fxchg4 sti, undocumented op */ case 0x39: /* fxchg7 sti, undocumented op */ - gen_op_fxchg_ST0_STN(opreg); + tcg_gen_helper_0_1(helper_fxchg_ST0_STN, tcg_const_i32(opreg)); break; case 0x0a: /* grp d9/2 */ switch(rm) { @@ -4614,7 +5569,7 @@ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); - gen_op_fwait(); + tcg_gen_helper_0_0(helper_fwait); break; default: goto illegal_op; @@ -4623,17 +5578,17 @@ case 0x0c: /* grp d9/4 */ switch(rm) { case 0: /* fchs */ - gen_op_fchs_ST0(); + tcg_gen_helper_0_0(helper_fchs_ST0); break; case 1: /* fabs */ - gen_op_fabs_ST0(); + tcg_gen_helper_0_0(helper_fabs_ST0); break; case 4: /* ftst */ - gen_op_fldz_FT0(); - gen_op_fcom_ST0_FT0(); + tcg_gen_helper_0_0(helper_fldz_FT0); + tcg_gen_helper_0_0(helper_fcom_ST0_FT0); break; case 5: /* fxam */ - gen_op_fxam_ST0(); + tcg_gen_helper_0_0(helper_fxam_ST0); break; default: goto illegal_op; @@ -4643,32 +5598,32 @@ { switch(rm) { case 0: - gen_op_fpush(); - gen_op_fld1_ST0(); + tcg_gen_helper_0_0(helper_fpush); + tcg_gen_helper_0_0(helper_fld1_ST0); break; case 1: - gen_op_fpush(); - gen_op_fldl2t_ST0(); + tcg_gen_helper_0_0(helper_fpush); + tcg_gen_helper_0_0(helper_fldl2t_ST0); break; case 2: - gen_op_fpush(); - gen_op_fldl2e_ST0(); + tcg_gen_helper_0_0(helper_fpush); + tcg_gen_helper_0_0(helper_fldl2e_ST0); break; case 3: - gen_op_fpush(); - gen_op_fldpi_ST0(); + tcg_gen_helper_0_0(helper_fpush); + tcg_gen_helper_0_0(helper_fldpi_ST0); break; case 4: - gen_op_fpush(); - gen_op_fldlg2_ST0(); + tcg_gen_helper_0_0(helper_fpush); + tcg_gen_helper_0_0(helper_fldlg2_ST0); break; case 5: - gen_op_fpush(); - gen_op_fldln2_ST0(); + tcg_gen_helper_0_0(helper_fpush); + tcg_gen_helper_0_0(helper_fldln2_ST0); break; case 6: - gen_op_fpush(); - gen_op_fldz_ST0(); + tcg_gen_helper_0_0(helper_fpush); + tcg_gen_helper_0_0(helper_fldz_ST0); break; default: goto illegal_op; @@ -4678,58 +5633,58 @@ case 0x0e: /* grp d9/6 */ switch(rm) { case 0: /* f2xm1 */ - gen_op_f2xm1(); + tcg_gen_helper_0_0(helper_f2xm1); break; case 1: /* fyl2x */ - gen_op_fyl2x(); + tcg_gen_helper_0_0(helper_fyl2x); break; case 2: /* fptan */ - gen_op_fptan(); + tcg_gen_helper_0_0(helper_fptan); break; case 3: /* fpatan */ - gen_op_fpatan(); + tcg_gen_helper_0_0(helper_fpatan); break; case 4: /* fxtract */ - gen_op_fxtract(); + tcg_gen_helper_0_0(helper_fxtract); break; case 5: /* fprem1 */ - gen_op_fprem1(); + tcg_gen_helper_0_0(helper_fprem1); break; case 6: /* fdecstp */ - gen_op_fdecstp(); + tcg_gen_helper_0_0(helper_fdecstp); break; default: case 7: /* fincstp */ - gen_op_fincstp(); + tcg_gen_helper_0_0(helper_fincstp); break; } break; case 0x0f: /* grp d9/7 */ switch(rm) { case 0: /* fprem */ - gen_op_fprem(); + tcg_gen_helper_0_0(helper_fprem); break; case 1: /* fyl2xp1 */ - gen_op_fyl2xp1(); + tcg_gen_helper_0_0(helper_fyl2xp1); break; case 2: /* fsqrt */ - gen_op_fsqrt(); + tcg_gen_helper_0_0(helper_fsqrt); break; case 3: /* fsincos */ - gen_op_fsincos(); + tcg_gen_helper_0_0(helper_fsincos); break; case 5: /* fscale */ - gen_op_fscale(); + tcg_gen_helper_0_0(helper_fscale); break; case 4: /* frndint */ - gen_op_frndint(); + tcg_gen_helper_0_0(helper_frndint); break; case 6: /* fsin */ - gen_op_fsin(); + tcg_gen_helper_0_0(helper_fsin); break; default: case 7: /* fcos */ - gen_op_fcos(); + tcg_gen_helper_0_0(helper_fcos); break; } break; @@ -4741,34 +5696,34 @@ op1 = op & 7; if (op >= 0x20) { - gen_op_fp_arith_STN_ST0[op1](opreg); + tcg_gen_helper_0_1(helper_fp_arith_STN_ST0[op1], tcg_const_i32(opreg)); if (op >= 0x30) - gen_op_fpop(); + tcg_gen_helper_0_0(helper_fpop); } else { - gen_op_fmov_FT0_STN(opreg); - gen_op_fp_arith_ST0_FT0[op1](); + tcg_gen_helper_0_1(helper_fmov_FT0_STN, tcg_const_i32(opreg)); + tcg_gen_helper_0_0(helper_fp_arith_ST0_FT0[op1]); } } break; case 0x02: /* fcom */ case 0x22: /* fcom2, undocumented op */ - gen_op_fmov_FT0_STN(opreg); - gen_op_fcom_ST0_FT0(); + tcg_gen_helper_0_1(helper_fmov_FT0_STN, tcg_const_i32(opreg)); + tcg_gen_helper_0_0(helper_fcom_ST0_FT0); break; case 0x03: /* fcomp */ case 0x23: /* fcomp3, undocumented op */ case 0x32: /* fcomp5, undocumented op */ - gen_op_fmov_FT0_STN(opreg); - gen_op_fcom_ST0_FT0(); - gen_op_fpop(); + tcg_gen_helper_0_1(helper_fmov_FT0_STN, tcg_const_i32(opreg)); + tcg_gen_helper_0_0(helper_fcom_ST0_FT0); + tcg_gen_helper_0_0(helper_fpop); break; case 0x15: /* da/5 */ switch(rm) { case 1: /* fucompp */ - gen_op_fmov_FT0_STN(1); - gen_op_fucom_ST0_FT0(); - gen_op_fpop(); - gen_op_fpop(); + tcg_gen_helper_0_1(helper_fmov_FT0_STN, tcg_const_i32(1)); + tcg_gen_helper_0_0(helper_fucom_ST0_FT0); + tcg_gen_helper_0_0(helper_fpop); + tcg_gen_helper_0_0(helper_fpop); break; default: goto illegal_op; @@ -4781,10 +5736,10 @@ case 1: /* fdisi (287 only, just do nop here) */ break; case 2: /* fclex */ - gen_op_fclex(); + tcg_gen_helper_0_0(helper_fclex); break; case 3: /* fninit */ - gen_op_fninit(); + tcg_gen_helper_0_0(helper_fninit); break; case 4: /* fsetpm (287 only, just do nop here) */ break; @@ -4795,59 +5750,61 @@ case 0x1d: /* fucomi */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_fmov_FT0_STN(opreg); - gen_op_fucomi_ST0_FT0(); + tcg_gen_helper_0_1(helper_fmov_FT0_STN, tcg_const_i32(opreg)); + tcg_gen_helper_0_0(helper_fucomi_ST0_FT0); s->cc_op = CC_OP_EFLAGS; break; case 0x1e: /* fcomi */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_fmov_FT0_STN(opreg); - gen_op_fcomi_ST0_FT0(); + tcg_gen_helper_0_1(helper_fmov_FT0_STN, tcg_const_i32(opreg)); + tcg_gen_helper_0_0(helper_fcomi_ST0_FT0); s->cc_op = CC_OP_EFLAGS; break; case 0x28: /* ffree sti */ - gen_op_ffree_STN(opreg); + tcg_gen_helper_0_1(helper_ffree_STN, tcg_const_i32(opreg)); break; case 0x2a: /* fst sti */ - gen_op_fmov_STN_ST0(opreg); + tcg_gen_helper_0_1(helper_fmov_STN_ST0, tcg_const_i32(opreg)); break; case 0x2b: /* fstp sti */ case 0x0b: /* fstp1 sti, undocumented op */ case 0x3a: /* fstp8 sti, undocumented op */ case 0x3b: /* fstp9 sti, undocumented op */ - gen_op_fmov_STN_ST0(opreg); - gen_op_fpop(); + tcg_gen_helper_0_1(helper_fmov_STN_ST0, tcg_const_i32(opreg)); + tcg_gen_helper_0_0(helper_fpop); break; case 0x2c: /* fucom st(i) */ - gen_op_fmov_FT0_STN(opreg); - gen_op_fucom_ST0_FT0(); + tcg_gen_helper_0_1(helper_fmov_FT0_STN, tcg_const_i32(opreg)); + tcg_gen_helper_0_0(helper_fucom_ST0_FT0); break; case 0x2d: /* fucomp st(i) */ - gen_op_fmov_FT0_STN(opreg); - gen_op_fucom_ST0_FT0(); - gen_op_fpop(); + tcg_gen_helper_0_1(helper_fmov_FT0_STN, tcg_const_i32(opreg)); + tcg_gen_helper_0_0(helper_fucom_ST0_FT0); + tcg_gen_helper_0_0(helper_fpop); break; case 0x33: /* de/3 */ switch(rm) { case 1: /* fcompp */ - gen_op_fmov_FT0_STN(1); - gen_op_fcom_ST0_FT0(); - gen_op_fpop(); - gen_op_fpop(); + tcg_gen_helper_0_1(helper_fmov_FT0_STN, tcg_const_i32(1)); + tcg_gen_helper_0_0(helper_fcom_ST0_FT0); + tcg_gen_helper_0_0(helper_fpop); + tcg_gen_helper_0_0(helper_fpop); break; default: goto illegal_op; } break; case 0x38: /* ffreep sti, undocumented op */ - gen_op_ffree_STN(opreg); - gen_op_fpop(); + tcg_gen_helper_0_1(helper_ffree_STN, tcg_const_i32(opreg)); + tcg_gen_helper_0_0(helper_fpop); break; case 0x3c: /* df/4 */ switch(rm) { case 0: - gen_op_fnstsw_EAX(); + tcg_gen_helper_1_0(helper_fnstsw, cpu_tmp2_i32); + tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); + gen_op_mov_reg_T0(OT_WORD, R_EAX); break; default: goto illegal_op; @@ -4856,32 +5813,34 @@ case 0x3d: /* fucomip */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_fmov_FT0_STN(opreg); - gen_op_fucomi_ST0_FT0(); - gen_op_fpop(); + tcg_gen_helper_0_1(helper_fmov_FT0_STN, tcg_const_i32(opreg)); + tcg_gen_helper_0_0(helper_fucomi_ST0_FT0); + tcg_gen_helper_0_0(helper_fpop); s->cc_op = CC_OP_EFLAGS; break; case 0x3e: /* fcomip */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_fmov_FT0_STN(opreg); - gen_op_fcomi_ST0_FT0(); - gen_op_fpop(); + tcg_gen_helper_0_1(helper_fmov_FT0_STN, tcg_const_i32(opreg)); + tcg_gen_helper_0_0(helper_fcomi_ST0_FT0); + tcg_gen_helper_0_0(helper_fpop); s->cc_op = CC_OP_EFLAGS; break; case 0x10 ... 0x13: /* fcmovxx */ case 0x18 ... 0x1b: { - int op1; - const static uint8_t fcmov_cc[8] = { + int op1, l1; + static const uint8_t fcmov_cc[8] = { (JCC_B << 1), (JCC_Z << 1), (JCC_BE << 1), (JCC_P << 1), }; - op1 = fcmov_cc[op & 3] | ((op >> 3) & 1); - gen_setcc(s, op1); - gen_op_fcmov_ST0_STN_T0(opreg); + op1 = fcmov_cc[op & 3] | (((op >> 3) & 1) ^ 1); + l1 = gen_new_label(); + gen_jcc1(s, s->cc_op, op1, l1); + tcg_gen_helper_0_1(helper_fmov_ST0_STN, tcg_const_i32(opreg)); + gen_set_label(l1); } break; default: @@ -4968,17 +5927,17 @@ ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - gen_check_io(s, ot, 1, pc_start - s->cs_base); - gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_op_mov_TN_reg(OT_WORD, 0, R_EDX); gen_op_andl_T0_ffff(); - if (gen_svm_check_io(s, pc_start, - SVM_IOIO_TYPE_MASK | (1 << (4+ot)) | - svm_is_rep(prefixes) | 4 | (1 << (7+s->aflag)))) - break; + gen_check_io(s, ot, pc_start - s->cs_base, + SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | 4); if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { gen_ins(s, ot); + if (use_icount) { + gen_jmp(s, s->pc - s->cs_base); + } } break; case 0x6e: /* outsS */ @@ -4987,17 +5946,17 @@ ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - gen_check_io(s, ot, 1, pc_start - s->cs_base); - gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_op_mov_TN_reg(OT_WORD, 0, R_EDX); gen_op_andl_T0_ffff(); - if (gen_svm_check_io(s, pc_start, - (1 << (4+ot)) | svm_is_rep(prefixes) | - 4 | (1 << (7+s->aflag)))) - break; + gen_check_io(s, ot, pc_start - s->cs_base, + svm_is_rep(prefixes) | 4); if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { gen_outs(s, ot); + if (use_icount) { + gen_jmp(s, s->pc - s->cs_base); + } } break; @@ -5012,13 +5971,17 @@ ot = dflag ? OT_LONG : OT_WORD; val = ldub_code(s->pc++); gen_op_movl_T0_im(val); - gen_check_io(s, ot, 0, pc_start - s->cs_base); - if (gen_svm_check_io(s, pc_start, - SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | - (1 << (4+ot)))) - break; - gen_op_in[ot](); - gen_op_mov_reg_T1[ot][R_EAX](); + gen_check_io(s, ot, pc_start - s->cs_base, + SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes)); + if (use_icount) + gen_io_start(); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_1_1(helper_in_func[ot], cpu_T[1], cpu_tmp2_i32); + gen_op_mov_reg_T1(ot, R_EAX); + if (use_icount) { + gen_io_end(); + gen_jmp(s, s->pc - s->cs_base); + } break; case 0xe6: case 0xe7: @@ -5028,12 +5991,20 @@ ot = dflag ? OT_LONG : OT_WORD; val = ldub_code(s->pc++); gen_op_movl_T0_im(val); - gen_check_io(s, ot, 0, pc_start - s->cs_base); - if (gen_svm_check_io(s, pc_start, svm_is_rep(prefixes) | - (1 << (4+ot)))) - break; - gen_op_mov_TN_reg[ot][1][R_EAX](); - gen_op_out[ot](); + gen_check_io(s, ot, pc_start - s->cs_base, + svm_is_rep(prefixes)); + gen_op_mov_TN_reg(ot, 1, R_EAX); + + if (use_icount) + gen_io_start(); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff); + tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]); + tcg_gen_helper_0_2(helper_out_func[ot], cpu_tmp2_i32, cpu_tmp3_i32); + if (use_icount) { + gen_io_end(); + gen_jmp(s, s->pc - s->cs_base); + } break; case 0xec: case 0xed: @@ -5041,15 +6012,19 @@ ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_op_mov_TN_reg(OT_WORD, 0, R_EDX); gen_op_andl_T0_ffff(); - gen_check_io(s, ot, 0, pc_start - s->cs_base); - if (gen_svm_check_io(s, pc_start, - SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | - (1 << (4+ot)))) - break; - gen_op_in[ot](); - gen_op_mov_reg_T1[ot][R_EAX](); + gen_check_io(s, ot, pc_start - s->cs_base, + SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes)); + if (use_icount) + gen_io_start(); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_1_1(helper_in_func[ot], cpu_T[1], cpu_tmp2_i32); + gen_op_mov_reg_T1(ot, R_EAX); + if (use_icount) { + gen_io_end(); + gen_jmp(s, s->pc - s->cs_base); + } break; case 0xee: case 0xef: @@ -5057,14 +6032,22 @@ ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_op_mov_TN_reg(OT_WORD, 0, R_EDX); gen_op_andl_T0_ffff(); - gen_check_io(s, ot, 0, pc_start - s->cs_base); - if (gen_svm_check_io(s, pc_start, - svm_is_rep(prefixes) | (1 << (4+ot)))) - break; - gen_op_mov_TN_reg[ot][1][R_EAX](); - gen_op_out[ot](); + gen_check_io(s, ot, pc_start - s->cs_base, + svm_is_rep(prefixes)); + gen_op_mov_TN_reg(ot, 1, R_EAX); + + if (use_icount) + gen_io_start(); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff); + tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]); + tcg_gen_helper_0_2(helper_out_func[ot], cpu_tmp2_i32, cpu_tmp3_i32); + if (use_icount) { + gen_io_end(); + gen_jmp(s, s->pc - s->cs_base); + } break; /************************/ @@ -5097,11 +6080,13 @@ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); - gen_op_lret_protected(s->dflag, val); + tcg_gen_helper_0_2(helper_lret_protected, + tcg_const_i32(s->dflag), + tcg_const_i32(val)); } else { gen_stack_A0(s); /* pop offset */ - gen_op_ld_T0_A0[1 + s->dflag + s->mem_index](); + gen_op_ld_T0_A0(1 + s->dflag + s->mem_index); if (s->dflag == 0) gen_op_andl_T0_ffff(); /* NOTE: keeping EIP updated is not a problem in case of @@ -5109,8 +6094,8 @@ gen_op_jmp_T0(); /* pop selector */ gen_op_addl_A0_im(2 << s->dflag); - gen_op_ld_T0_A0[1 + s->dflag + s->mem_index](); - gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); + gen_op_ld_T0_A0(1 + s->dflag + s->mem_index); + gen_op_movl_seg_T0_vm(R_CS); /* add stack offset */ gen_stack_update(s, val + (4 << s->dflag)); } @@ -5120,24 +6105,25 @@ val = 0; goto do_lret; case 0xcf: /* iret */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_IRET)) - break; + gen_svm_check_intercept(s, pc_start, SVM_EXIT_IRET); if (!s->pe) { /* real mode */ - gen_op_iret_real(s->dflag); + tcg_gen_helper_0_1(helper_iret_real, tcg_const_i32(s->dflag)); s->cc_op = CC_OP_EFLAGS; } else if (s->vm86) { if (s->iopl != 3) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - gen_op_iret_real(s->dflag); + tcg_gen_helper_0_1(helper_iret_real, tcg_const_i32(s->dflag)); s->cc_op = CC_OP_EFLAGS; } } else { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); - gen_op_iret_protected(s->dflag, s->pc - s->cs_base); + tcg_gen_helper_0_2(helper_iret_protected, + tcg_const_i32(s->dflag), + tcg_const_i32(s->pc - s->cs_base)); s->cc_op = CC_OP_EFLAGS; } gen_eob(s); @@ -5225,60 +6211,86 @@ gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1); break; case 0x140 ... 0x14f: /* cmov Gv, Ev */ - ot = dflag + OT_WORD; - modrm = ldub_code(s->pc++); - reg = ((modrm >> 3) & 7) | rex_r; - mod = (modrm >> 6) & 3; - gen_setcc(s, b); - if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T1_A0[ot + s->mem_index](); - } else { - rm = (modrm & 7) | REX_B(s); - gen_op_mov_TN_reg[ot][1][rm](); + { + int l1; + TCGv t0; + + ot = dflag + OT_WORD; + modrm = ldub_code(s->pc++); + reg = ((modrm >> 3) & 7) | rex_r; + mod = (modrm >> 6) & 3; + t0 = tcg_temp_local_new(TCG_TYPE_TL); + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_v(ot + s->mem_index, t0, cpu_A0); + } else { + rm = (modrm & 7) | REX_B(s); + gen_op_mov_v_reg(ot, t0, rm); + } +#ifdef TARGET_X86_64 + if (ot == OT_LONG) { + /* XXX: specific Intel behaviour ? */ + l1 = gen_new_label(); + gen_jcc1(s, s->cc_op, b ^ 1, l1); + tcg_gen_st32_tl(t0, cpu_env, offsetof(CPUState, regs[reg]) + REG_L_OFFSET); + gen_set_label(l1); + tcg_gen_movi_tl(cpu_tmp0, 0); + tcg_gen_st32_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]) + REG_LH_OFFSET); + } else +#endif + { + l1 = gen_new_label(); + gen_jcc1(s, s->cc_op, b ^ 1, l1); + gen_op_mov_reg_v(ot, reg, t0); + gen_set_label(l1); + } + tcg_temp_free(t0); } - gen_op_cmov_reg_T1_T0[ot - OT_WORD][reg](); break; /************************/ /* flags */ case 0x9c: /* pushf */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_PUSHF)) - break; + gen_svm_check_intercept(s, pc_start, SVM_EXIT_PUSHF); if (s->vm86 && s->iopl != 3) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_movl_T0_eflags(); + tcg_gen_helper_1_0(helper_read_eflags, cpu_T[0]); gen_push_T0(s); } break; case 0x9d: /* popf */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_POPF)) - break; + gen_svm_check_intercept(s, pc_start, SVM_EXIT_POPF); if (s->vm86 && s->iopl != 3) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_pop_T0(s); if (s->cpl == 0) { if (s->dflag) { - gen_op_movl_eflags_T0_cpl0(); + tcg_gen_helper_0_2(helper_write_eflags, cpu_T[0], + tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK | IOPL_MASK))); } else { - gen_op_movw_eflags_T0_cpl0(); + tcg_gen_helper_0_2(helper_write_eflags, cpu_T[0], + tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK | IOPL_MASK) & 0xffff)); } } else { if (s->cpl <= s->iopl) { if (s->dflag) { - gen_op_movl_eflags_T0_io(); + tcg_gen_helper_0_2(helper_write_eflags, cpu_T[0], + tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK))); } else { - gen_op_movw_eflags_T0_io(); + tcg_gen_helper_0_2(helper_write_eflags, cpu_T[0], + tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK) & 0xffff)); } } else { if (s->dflag) { - gen_op_movl_eflags_T0(); + tcg_gen_helper_0_2(helper_write_eflags, cpu_T[0], + tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK))); } else { - gen_op_movw_eflags_T0(); + tcg_gen_helper_0_2(helper_write_eflags, cpu_T[0], + tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK) & 0xffff)); } } } @@ -5290,45 +6302,55 @@ } break; case 0x9e: /* sahf */ - if (CODE64(s)) + if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM)) goto illegal_op; - gen_op_mov_TN_reg[OT_BYTE][0][R_AH](); + gen_op_mov_TN_reg(OT_BYTE, 0, R_AH); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_movb_eflags_T0(); + gen_compute_eflags(cpu_cc_src); + tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, CC_O); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], CC_S | CC_Z | CC_A | CC_P | CC_C); + tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_T[0]); s->cc_op = CC_OP_EFLAGS; break; case 0x9f: /* lahf */ - if (CODE64(s)) + if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM)) goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_movl_T0_eflags(); - gen_op_mov_reg_T0[OT_BYTE][R_AH](); + gen_compute_eflags(cpu_T[0]); + /* Note: gen_compute_eflags() only gives the condition codes */ + tcg_gen_ori_tl(cpu_T[0], cpu_T[0], 0x02); + gen_op_mov_reg_T0(OT_BYTE, R_AH); break; case 0xf5: /* cmc */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_cmc(); + gen_compute_eflags(cpu_cc_src); + tcg_gen_xori_tl(cpu_cc_src, cpu_cc_src, CC_C); s->cc_op = CC_OP_EFLAGS; break; case 0xf8: /* clc */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_clc(); + gen_compute_eflags(cpu_cc_src); + tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~CC_C); s->cc_op = CC_OP_EFLAGS; break; case 0xf9: /* stc */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_stc(); + gen_compute_eflags(cpu_cc_src); + tcg_gen_ori_tl(cpu_cc_src, cpu_cc_src, CC_C); s->cc_op = CC_OP_EFLAGS; break; case 0xfc: /* cld */ - gen_op_cld(); + tcg_gen_movi_i32(cpu_tmp2_i32, 1); + tcg_gen_st_i32(cpu_tmp2_i32, cpu_env, offsetof(CPUState, df)); break; case 0xfd: /* std */ - gen_op_std(); + tcg_gen_movi_i32(cpu_tmp2_i32, -1); + tcg_gen_st_i32(cpu_tmp2_i32, cpu_env, offsetof(CPUState, df)); break; /************************/ @@ -5342,9 +6364,9 @@ if (mod != 3) { s->rip_offset = 1; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot + s->mem_index](); + gen_op_ld_T0_A0(ot + s->mem_index); } else { - gen_op_mov_TN_reg[ot][0][rm](); + gen_op_mov_TN_reg(ot, 0, rm); } /* load shift */ val = ldub_code(s->pc++); @@ -5352,16 +6374,7 @@ if (op < 4) goto illegal_op; op -= 4; - gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); - s->cc_op = CC_OP_SARB + ot; - if (op != 0) { - if (mod != 3) - gen_op_st_T0_A0[ot + s->mem_index](); - else - gen_op_mov_reg_T0[ot][rm](); - gen_op_update_bt_cc(); - } - break; + goto bt_op; case 0x1a3: /* bt Gv, Ev */ op = 0; goto do_btx; @@ -5379,37 +6392,84 @@ reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); - gen_op_mov_TN_reg[OT_LONG][1][reg](); + gen_op_mov_TN_reg(OT_LONG, 1, reg); if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); /* specific case: we need to add a displacement */ - gen_op_add_bit_A0_T1[ot - OT_WORD](); - gen_op_ld_T0_A0[ot + s->mem_index](); + gen_exts(ot, cpu_T[1]); + tcg_gen_sari_tl(cpu_tmp0, cpu_T[1], 3 + ot); + tcg_gen_shli_tl(cpu_tmp0, cpu_tmp0, ot); + tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0); + gen_op_ld_T0_A0(ot + s->mem_index); } else { - gen_op_mov_TN_reg[ot][0][rm](); + gen_op_mov_TN_reg(ot, 0, rm); + } + bt_op: + tcg_gen_andi_tl(cpu_T[1], cpu_T[1], (1 << (3 + ot)) - 1); + switch(op) { + case 0: + tcg_gen_shr_tl(cpu_cc_src, cpu_T[0], cpu_T[1]); + tcg_gen_movi_tl(cpu_cc_dst, 0); + break; + case 1: + tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]); + tcg_gen_movi_tl(cpu_tmp0, 1); + tcg_gen_shl_tl(cpu_tmp0, cpu_tmp0, cpu_T[1]); + tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0); + break; + case 2: + tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]); + tcg_gen_movi_tl(cpu_tmp0, 1); + tcg_gen_shl_tl(cpu_tmp0, cpu_tmp0, cpu_T[1]); + tcg_gen_not_tl(cpu_tmp0, cpu_tmp0); + tcg_gen_and_tl(cpu_T[0], cpu_T[0], cpu_tmp0); + break; + default: + case 3: + tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]); + tcg_gen_movi_tl(cpu_tmp0, 1); + tcg_gen_shl_tl(cpu_tmp0, cpu_tmp0, cpu_T[1]); + tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp0); + break; } - gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); s->cc_op = CC_OP_SARB + ot; if (op != 0) { if (mod != 3) - gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_st_T0_A0(ot + s->mem_index); else - gen_op_mov_reg_T0[ot][rm](); - gen_op_update_bt_cc(); + gen_op_mov_reg_T0(ot, rm); + tcg_gen_mov_tl(cpu_cc_src, cpu_tmp4); + tcg_gen_movi_tl(cpu_cc_dst, 0); } break; case 0x1bc: /* bsf */ case 0x1bd: /* bsr */ - ot = dflag + OT_WORD; - modrm = ldub_code(s->pc++); - reg = ((modrm >> 3) & 7) | rex_r; - gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); - /* NOTE: in order to handle the 0 case, we must load the - result. It could be optimized with a generated jump */ - gen_op_mov_TN_reg[ot][1][reg](); - gen_op_bsx_T0_cc[ot - OT_WORD][b & 1](); - gen_op_mov_reg_T1[ot][reg](); - s->cc_op = CC_OP_LOGICB + ot; + { + int label1; + TCGv t0; + + ot = dflag + OT_WORD; + modrm = ldub_code(s->pc++); + reg = ((modrm >> 3) & 7) | rex_r; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + gen_extu(ot, cpu_T[0]); + label1 = gen_new_label(); + tcg_gen_movi_tl(cpu_cc_dst, 0); + t0 = tcg_temp_local_new(TCG_TYPE_TL); + tcg_gen_mov_tl(t0, cpu_T[0]); + tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, label1); + if (b & 1) { + tcg_gen_helper_1_1(helper_bsr, cpu_T[0], t0); + } else { + tcg_gen_helper_1_1(helper_bsf, cpu_T[0], t0); + } + gen_op_mov_reg_T0(ot, reg); + tcg_gen_movi_tl(cpu_cc_dst, 1); + gen_set_label(label1); + tcg_gen_discard_tl(cpu_cc_src); + s->cc_op = CC_OP_LOGICB + ot; + tcg_temp_free(t0); + } break; /************************/ /* bcd */ @@ -5418,7 +6478,7 @@ goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_daa(); + tcg_gen_helper_0_0(helper_daa); s->cc_op = CC_OP_EFLAGS; break; case 0x2f: /* das */ @@ -5426,7 +6486,7 @@ goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_das(); + tcg_gen_helper_0_0(helper_das); s->cc_op = CC_OP_EFLAGS; break; case 0x37: /* aaa */ @@ -5434,7 +6494,7 @@ goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_aaa(); + tcg_gen_helper_0_0(helper_aaa); s->cc_op = CC_OP_EFLAGS; break; case 0x3f: /* aas */ @@ -5442,7 +6502,7 @@ goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_aas(); + tcg_gen_helper_0_0(helper_aas); s->cc_op = CC_OP_EFLAGS; break; case 0xd4: /* aam */ @@ -5452,7 +6512,7 @@ if (val == 0) { gen_exception(s, EXCP00_DIVZ, pc_start - s->cs_base); } else { - gen_op_aam(val); + tcg_gen_helper_0_1(helper_aam, tcg_const_i32(val)); s->cc_op = CC_OP_LOGICB; } break; @@ -5460,7 +6520,7 @@ if (CODE64(s)) goto illegal_op; val = ldub_code(s->pc++); - gen_op_aad(val); + tcg_gen_helper_0_1(helper_aad, tcg_const_i32(val)); s->cc_op = CC_OP_LOGICB; break; /************************/ @@ -5482,18 +6542,14 @@ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); - gen_op_fwait(); + tcg_gen_helper_0_0(helper_fwait); } break; case 0xcc: /* int3 */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_SWINT)) - break; gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base); break; case 0xcd: /* int N */ val = ldub_code(s->pc++); - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_SWINT)) - break; if (s->vm86 && s->iopl != 3) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { @@ -5503,16 +6559,13 @@ case 0xce: /* into */ if (CODE64(s)) goto illegal_op; - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_SWINT)) - break; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); - gen_op_into(s->pc - pc_start); + tcg_gen_helper_0_1(helper_into, tcg_const_i32(s->pc - pc_start)); break; case 0xf1: /* icebp (undocumented, exits to external debugger) */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_ICEBP)) - break; + gen_svm_check_intercept(s, pc_start, SVM_EXIT_ICEBP); #if 1 gen_debug(s, pc_start - s->cs_base); #else @@ -5524,13 +6577,13 @@ case 0xfa: /* cli */ if (!s->vm86) { if (s->cpl <= s->iopl) { - gen_op_cli(); + tcg_gen_helper_0_0(helper_cli); } else { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } } else { if (s->iopl == 3) { - gen_op_cli(); + tcg_gen_helper_0_0(helper_cli); } else { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } @@ -5540,12 +6593,12 @@ if (!s->vm86) { if (s->cpl <= s->iopl) { gen_sti: - gen_op_sti(); + tcg_gen_helper_0_0(helper_sti); /* interruptions are enabled only the first insn after sti */ /* If several instructions disable interrupts, only the _first_ does it */ if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK)) - gen_op_set_inhibit_irq(); + tcg_gen_helper_0_0(helper_set_inhibit_irq); /* give a chance to handle pending irqs */ gen_jmp_im(s->pc - s->cs_base); gen_eob(s); @@ -5569,45 +6622,56 @@ mod = (modrm >> 6) & 3; if (mod == 3) goto illegal_op; - gen_op_mov_TN_reg[ot][0][reg](); + gen_op_mov_TN_reg(ot, 0, reg); gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_jmp_im(pc_start - s->cs_base); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); if (ot == OT_WORD) - gen_op_boundw(); + tcg_gen_helper_0_2(helper_boundw, cpu_A0, cpu_tmp2_i32); else - gen_op_boundl(); + tcg_gen_helper_0_2(helper_boundl, cpu_A0, cpu_tmp2_i32); break; case 0x1c8 ... 0x1cf: /* bswap reg */ reg = (b & 7) | REX_B(s); #ifdef TARGET_X86_64 if (dflag == 2) { - gen_op_mov_TN_reg[OT_QUAD][0][reg](); - gen_op_bswapq_T0(); - gen_op_mov_reg_T0[OT_QUAD][reg](); + gen_op_mov_TN_reg(OT_QUAD, 0, reg); + tcg_gen_bswap_i64(cpu_T[0], cpu_T[0]); + gen_op_mov_reg_T0(OT_QUAD, reg); } else -#endif { - gen_op_mov_TN_reg[OT_LONG][0][reg](); - gen_op_bswapl_T0(); - gen_op_mov_reg_T0[OT_LONG][reg](); + TCGv tmp0; + gen_op_mov_TN_reg(OT_LONG, 0, reg); + + tmp0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_trunc_i64_i32(tmp0, cpu_T[0]); + tcg_gen_bswap_i32(tmp0, tmp0); + tcg_gen_extu_i32_i64(cpu_T[0], tmp0); + gen_op_mov_reg_T0(OT_LONG, reg); + } +#else + { + gen_op_mov_TN_reg(OT_LONG, 0, reg); + tcg_gen_bswap_i32(cpu_T[0], cpu_T[0]); + gen_op_mov_reg_T0(OT_LONG, reg); } +#endif break; case 0xd6: /* salc */ if (CODE64(s)) goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_salc(); + gen_compute_eflags_c(cpu_T[0]); + tcg_gen_neg_tl(cpu_T[0], cpu_T[0]); + gen_op_mov_reg_T0(OT_BYTE, R_EAX); break; case 0xe0: /* loopnz */ case 0xe1: /* loopz */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - /* FALL THRU */ case 0xe2: /* loop */ case 0xe3: /* jecxz */ { - int l1, l2; + int l1, l2, l3; tval = (int8_t)insn_get(s, OT_BYTE); next_eip = s->pc - s->cs_base; @@ -5617,18 +6681,37 @@ l1 = gen_new_label(); l2 = gen_new_label(); + l3 = gen_new_label(); b &= 3; - if (b == 3) { - gen_op_jz_ecx[s->aflag](l1); - } else { - gen_op_dec_ECX[s->aflag](); - if (b <= 1) - gen_op_mov_T0_cc(); - gen_op_loop[s->aflag][b](l1); + switch(b) { + case 0: /* loopnz */ + case 1: /* loopz */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_add_reg_im(s->aflag, R_ECX, -1); + gen_op_jz_ecx(s->aflag, l3); + gen_compute_eflags(cpu_tmp0); + tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, CC_Z); + if (b == 0) { + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, l1); + } else { + tcg_gen_brcondi_tl(TCG_COND_NE, cpu_tmp0, 0, l1); + } + break; + case 2: /* loop */ + gen_op_add_reg_im(s->aflag, R_ECX, -1); + gen_op_jnz_ecx(s->aflag, l1); + break; + default: + case 3: /* jcxz */ + gen_op_jz_ecx(s->aflag, l1); + break; } + gen_set_label(l3); gen_jmp_im(next_eip); - gen_op_jmp_label(l2); + tcg_gen_br(l2); + gen_set_label(l1); gen_jmp_im(tval); gen_set_label(l2); @@ -5640,30 +6723,37 @@ if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - int retval = 0; + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(pc_start - s->cs_base); if (b & 2) { - retval = gen_svm_check_intercept_param(s, pc_start, SVM_EXIT_MSR, 0); - gen_op_rdmsr(); + tcg_gen_helper_0_0(helper_rdmsr); } else { - retval = gen_svm_check_intercept_param(s, pc_start, SVM_EXIT_MSR, 1); - gen_op_wrmsr(); + tcg_gen_helper_0_0(helper_wrmsr); } - if(retval) - gen_eob(s); } break; case 0x131: /* rdtsc */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_RDTSC)) - break; + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); - gen_op_rdtsc(); + if (use_icount) + gen_io_start(); + tcg_gen_helper_0_0(helper_rdtsc); + if (use_icount) { + gen_io_end(); + gen_jmp(s, s->pc - s->cs_base); + } break; case 0x133: /* rdpmc */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); - gen_op_rdpmc(); + tcg_gen_helper_0_0(helper_rdpmc); break; case 0x134: /* sysenter */ - if (CODE64(s)) + /* For Intel SYSENTER is valid on 64-bit */ + if (CODE64(s) && cpu_single_env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) goto illegal_op; if (!s->pe) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); @@ -5673,12 +6763,13 @@ s->cc_op = CC_OP_DYNAMIC; } gen_jmp_im(pc_start - s->cs_base); - gen_op_sysenter(); + tcg_gen_helper_0_0(helper_sysenter); gen_eob(s); } break; case 0x135: /* sysexit */ - if (CODE64(s)) + /* For Intel SYSEXIT is valid on 64-bit */ + if (CODE64(s) && cpu_single_env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) goto illegal_op; if (!s->pe) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); @@ -5688,7 +6779,7 @@ s->cc_op = CC_OP_DYNAMIC; } gen_jmp_im(pc_start - s->cs_base); - gen_op_sysexit(); + tcg_gen_helper_0_1(helper_sysexit, tcg_const_i32(dflag)); gen_eob(s); } break; @@ -5700,7 +6791,7 @@ s->cc_op = CC_OP_DYNAMIC; } gen_jmp_im(pc_start - s->cs_base); - gen_op_syscall(s->pc - pc_start); + tcg_gen_helper_0_1(helper_syscall, tcg_const_i32(s->pc - pc_start)); gen_eob(s); break; case 0x107: /* sysret */ @@ -5712,7 +6803,7 @@ s->cc_op = CC_OP_DYNAMIC; } gen_jmp_im(pc_start - s->cs_base); - gen_op_sysret(s->dflag); + tcg_gen_helper_0_1(helper_sysret, tcg_const_i32(s->dflag)); /* condition codes are modified only in long mode */ if (s->lma) s->cc_op = CC_OP_EFLAGS; @@ -5721,20 +6812,19 @@ break; #endif case 0x1a2: /* cpuid */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_CPUID)) - break; - gen_op_cpuid(); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(pc_start - s->cs_base); + tcg_gen_helper_0_0(helper_cpuid); break; case 0xf4: /* hlt */ if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_HLT)) - break; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_jmp_im(s->pc - s->cs_base); - gen_op_hlt(); + gen_jmp_im(pc_start - s->cs_base); + tcg_gen_helper_0_1(helper_hlt, tcg_const_i32(s->pc - pc_start)); s->is_jmp = 3; } break; @@ -5746,9 +6836,8 @@ case 0: /* sldt */ if (!s->pe || s->vm86) goto illegal_op; - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_READ)) - break; - gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector)); + gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_READ); + tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,ldt.selector)); ot = OT_WORD; if (mod == 3) ot += s->dflag; @@ -5760,19 +6849,18 @@ if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_WRITE)) - break; + gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_WRITE); gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); gen_jmp_im(pc_start - s->cs_base); - gen_op_lldt_T0(); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_0_1(helper_lldt, cpu_tmp2_i32); } break; case 1: /* str */ if (!s->pe || s->vm86) goto illegal_op; - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_READ)) - break; - gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector)); + gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_READ); + tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,tr.selector)); ot = OT_WORD; if (mod == 3) ot += s->dflag; @@ -5784,11 +6872,11 @@ if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_WRITE)) - break; + gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_WRITE); gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); gen_jmp_im(pc_start - s->cs_base); - gen_op_ltr_T0(); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_helper_0_1(helper_ltr, cpu_tmp2_i32); } break; case 4: /* verr */ @@ -5799,9 +6887,9 @@ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); if (op == 4) - gen_op_verr(); + tcg_gen_helper_0_1(helper_verr, cpu_T[0]); else - gen_op_verw(); + tcg_gen_helper_0_1(helper_verw, cpu_T[0]); s->cc_op = CC_OP_EFLAGS; break; default: @@ -5817,16 +6905,15 @@ case 0: /* sgdt */ if (mod == 3) goto illegal_op; - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_READ)) - break; + gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_READ); gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_movl_T0_env(offsetof(CPUX86State, gdt.limit)); - gen_op_st_T0_A0[OT_WORD + s->mem_index](); + tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, gdt.limit)); + gen_op_st_T0_A0(OT_WORD + s->mem_index); gen_add_A0_im(s, 2); - gen_op_movtl_T0_env(offsetof(CPUX86State, gdt.base)); + tcg_gen_ld_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, gdt.base)); if (!s->dflag) gen_op_andl_T0_im(0xffffff); - gen_op_st_T0_A0[CODE64(s) + OT_LONG + s->mem_index](); + gen_op_st_T0_A0(CODE64(s) + OT_LONG + s->mem_index); break; case 1: if (mod == 3) { @@ -5835,23 +6922,21 @@ if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || s->cpl != 0) goto illegal_op; - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_MONITOR)) - break; + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); #ifdef TARGET_X86_64 if (s->aflag == 2) { - gen_op_movq_A0_reg[R_EBX](); - gen_op_addq_A0_AL(); + gen_op_movq_A0_reg(R_EAX); } else #endif { - gen_op_movl_A0_reg[R_EBX](); - gen_op_addl_A0_AL(); + gen_op_movl_A0_reg(R_EAX); if (s->aflag == 0) gen_op_andl_A0_ffff(); } gen_add_A0_ds_seg(s); - gen_op_monitor(); + tcg_gen_helper_0_1(helper_monitor, cpu_A0); break; case 1: /* mwait */ if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || @@ -5861,77 +6946,112 @@ gen_op_set_cc_op(s->cc_op); s->cc_op = CC_OP_DYNAMIC; } - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_MWAIT)) - break; - gen_jmp_im(s->pc - s->cs_base); - gen_op_mwait(); + gen_jmp_im(pc_start - s->cs_base); + tcg_gen_helper_0_1(helper_mwait, tcg_const_i32(s->pc - pc_start)); gen_eob(s); break; default: goto illegal_op; } } else { /* sidt */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ)) - break; + gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ); gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_movl_T0_env(offsetof(CPUX86State, idt.limit)); - gen_op_st_T0_A0[OT_WORD + s->mem_index](); + tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, idt.limit)); + gen_op_st_T0_A0(OT_WORD + s->mem_index); gen_add_A0_im(s, 2); - gen_op_movtl_T0_env(offsetof(CPUX86State, idt.base)); + tcg_gen_ld_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, idt.base)); if (!s->dflag) gen_op_andl_T0_im(0xffffff); - gen_op_st_T0_A0[CODE64(s) + OT_LONG + s->mem_index](); + gen_op_st_T0_A0(CODE64(s) + OT_LONG + s->mem_index); } break; case 2: /* lgdt */ case 3: /* lidt */ if (mod == 3) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(pc_start - s->cs_base); switch(rm) { case 0: /* VMRUN */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_VMRUN)) + if (!(s->flags & HF_SVME_MASK) || !s->pe) + goto illegal_op; + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); break; - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_jmp_im(s->pc - s->cs_base); - gen_op_vmrun(); - s->cc_op = CC_OP_EFLAGS; - gen_eob(s); + } else { + tcg_gen_helper_0_2(helper_vmrun, + tcg_const_i32(s->aflag), + tcg_const_i32(s->pc - pc_start)); + tcg_gen_exit_tb(0); + s->is_jmp = 3; + } break; case 1: /* VMMCALL */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_VMMCALL)) - break; - /* FIXME: cause #UD if hflags & SVM */ - gen_op_vmmcall(); + if (!(s->flags & HF_SVME_MASK)) + goto illegal_op; + tcg_gen_helper_0_0(helper_vmmcall); break; case 2: /* VMLOAD */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_VMLOAD)) - break; - gen_op_vmload(); + if (!(s->flags & HF_SVME_MASK) || !s->pe) + goto illegal_op; + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + break; + } else { + tcg_gen_helper_0_1(helper_vmload, + tcg_const_i32(s->aflag)); + } break; case 3: /* VMSAVE */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_VMSAVE)) - break; - gen_op_vmsave(); + if (!(s->flags & HF_SVME_MASK) || !s->pe) + goto illegal_op; + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + break; + } else { + tcg_gen_helper_0_1(helper_vmsave, + tcg_const_i32(s->aflag)); + } break; case 4: /* STGI */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_STGI)) - break; - gen_op_stgi(); + if ((!(s->flags & HF_SVME_MASK) && + !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) || + !s->pe) + goto illegal_op; + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + break; + } else { + tcg_gen_helper_0_0(helper_stgi); + } break; case 5: /* CLGI */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_CLGI)) - break; - gen_op_clgi(); + if (!(s->flags & HF_SVME_MASK) || !s->pe) + goto illegal_op; + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + break; + } else { + tcg_gen_helper_0_0(helper_clgi); + } break; case 6: /* SKINIT */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_SKINIT)) - break; - gen_op_skinit(); + if ((!(s->flags & HF_SVME_MASK) && + !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) || + !s->pe) + goto illegal_op; + tcg_gen_helper_0_0(helper_skinit); break; case 7: /* INVLPGA */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_INVLPGA)) - break; - gen_op_invlpga(); + if (!(s->flags & HF_SVME_MASK) || !s->pe) + goto illegal_op; + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + break; + } else { + tcg_gen_helper_0_1(helper_invlpga, + tcg_const_i32(s->aflag)); + } break; default: goto illegal_op; @@ -5939,38 +7059,35 @@ } else if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - if (gen_svm_check_intercept(s, pc_start, - op==2 ? SVM_EXIT_GDTR_WRITE : SVM_EXIT_IDTR_WRITE)) - break; + gen_svm_check_intercept(s, pc_start, + op==2 ? SVM_EXIT_GDTR_WRITE : SVM_EXIT_IDTR_WRITE); gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T1_A0[OT_WORD + s->mem_index](); + gen_op_ld_T1_A0(OT_WORD + s->mem_index); gen_add_A0_im(s, 2); - gen_op_ld_T0_A0[CODE64(s) + OT_LONG + s->mem_index](); + gen_op_ld_T0_A0(CODE64(s) + OT_LONG + s->mem_index); if (!s->dflag) gen_op_andl_T0_im(0xffffff); if (op == 2) { - gen_op_movtl_env_T0(offsetof(CPUX86State,gdt.base)); - gen_op_movl_env_T1(offsetof(CPUX86State,gdt.limit)); + tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,gdt.base)); + tcg_gen_st32_tl(cpu_T[1], cpu_env, offsetof(CPUX86State,gdt.limit)); } else { - gen_op_movtl_env_T0(offsetof(CPUX86State,idt.base)); - gen_op_movl_env_T1(offsetof(CPUX86State,idt.limit)); + tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,idt.base)); + tcg_gen_st32_tl(cpu_T[1], cpu_env, offsetof(CPUX86State,idt.limit)); } } break; case 4: /* smsw */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0)) - break; - gen_op_movl_T0_env(offsetof(CPUX86State,cr[0])); + gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0); + tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,cr[0])); gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 1); break; case 6: /* lmsw */ if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0)) - break; + gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0); gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); - gen_op_lmsw_T0(); + tcg_gen_helper_0_1(helper_lmsw, cpu_T[0]); gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } @@ -5983,20 +7100,21 @@ #ifdef TARGET_X86_64 if (CODE64(s) && rm == 0) { /* swapgs */ - gen_op_movtl_T0_env(offsetof(CPUX86State,segs[R_GS].base)); - gen_op_movtl_T1_env(offsetof(CPUX86State,kernelgsbase)); - gen_op_movtl_env_T1(offsetof(CPUX86State,segs[R_GS].base)); - gen_op_movtl_env_T0(offsetof(CPUX86State,kernelgsbase)); + tcg_gen_ld_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,segs[R_GS].base)); + tcg_gen_ld_tl(cpu_T[1], cpu_env, offsetof(CPUX86State,kernelgsbase)); + tcg_gen_st_tl(cpu_T[1], cpu_env, offsetof(CPUX86State,segs[R_GS].base)); + tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,kernelgsbase)); } else #endif { goto illegal_op; } } else { - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_INVLPG)) - break; + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(pc_start - s->cs_base); gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_invlpg_A0(); + tcg_gen_helper_0_1(helper_invlpg, cpu_A0); gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } @@ -6011,8 +7129,7 @@ if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - if (gen_svm_check_intercept(s, pc_start, (b & 2) ? SVM_EXIT_INVD : SVM_EXIT_WBINVD)) - break; + gen_svm_check_intercept(s, pc_start, (b & 2) ? SVM_EXIT_INVD : SVM_EXIT_WBINVD); /* nothing to do */ } break; @@ -6029,65 +7146,94 @@ rm = (modrm & 7) | REX_B(s); if (mod == 3) { - gen_op_mov_TN_reg[OT_LONG][0][rm](); + gen_op_mov_TN_reg(OT_LONG, 0, rm); /* sign extend */ if (d_ot == OT_QUAD) - gen_op_movslq_T0_T0(); - gen_op_mov_reg_T0[d_ot][reg](); + tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]); + gen_op_mov_reg_T0(d_ot, reg); } else { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); if (d_ot == OT_QUAD) { - gen_op_lds_T0_A0[OT_LONG + s->mem_index](); + gen_op_lds_T0_A0(OT_LONG + s->mem_index); } else { - gen_op_ld_T0_A0[OT_LONG + s->mem_index](); + gen_op_ld_T0_A0(OT_LONG + s->mem_index); } - gen_op_mov_reg_T0[d_ot][reg](); + gen_op_mov_reg_T0(d_ot, reg); } } else #endif { + int label1; + TCGv t0, t1, t2; + if (!s->pe || s->vm86) goto illegal_op; - ot = dflag ? OT_LONG : OT_WORD; + t0 = tcg_temp_local_new(TCG_TYPE_TL); + t1 = tcg_temp_local_new(TCG_TYPE_TL); + t2 = tcg_temp_local_new(TCG_TYPE_TL); + ot = OT_WORD; modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; mod = (modrm >> 6) & 3; rm = modrm & 7; if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot + s->mem_index](); + gen_op_ld_v(ot + s->mem_index, t0, cpu_A0); } else { - gen_op_mov_TN_reg[ot][0][rm](); + gen_op_mov_v_reg(ot, t0, rm); } - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_arpl(); - s->cc_op = CC_OP_EFLAGS; + gen_op_mov_v_reg(ot, t1, reg); + tcg_gen_andi_tl(cpu_tmp0, t0, 3); + tcg_gen_andi_tl(t1, t1, 3); + tcg_gen_movi_tl(t2, 0); + label1 = gen_new_label(); + tcg_gen_brcond_tl(TCG_COND_GE, cpu_tmp0, t1, label1); + tcg_gen_andi_tl(t0, t0, ~3); + tcg_gen_or_tl(t0, t0, t1); + tcg_gen_movi_tl(t2, CC_Z); + gen_set_label(label1); if (mod != 3) { - gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_st_v(ot + s->mem_index, t0, cpu_A0); } else { - gen_op_mov_reg_T0[ot][rm](); + gen_op_mov_reg_v(ot, rm, t0); } - gen_op_arpl_update(); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_compute_eflags(cpu_cc_src); + tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~CC_Z); + tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t2); + s->cc_op = CC_OP_EFLAGS; + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free(t2); } break; case 0x102: /* lar */ case 0x103: /* lsl */ - if (!s->pe || s->vm86) - goto illegal_op; - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub_code(s->pc++); - reg = ((modrm >> 3) & 7) | rex_r; - gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); - gen_op_mov_TN_reg[ot][1][reg](); - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - if (b == 0x102) - gen_op_lar(); - else - gen_op_lsl(); - s->cc_op = CC_OP_EFLAGS; - gen_op_mov_reg_T1[ot][reg](); + { + int label1; + TCGv t0; + if (!s->pe || s->vm86) + goto illegal_op; + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub_code(s->pc++); + reg = ((modrm >> 3) & 7) | rex_r; + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); + t0 = tcg_temp_local_new(TCG_TYPE_TL); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + if (b == 0x102) + tcg_gen_helper_1_1(helper_lar, t0, cpu_T[0]); + else + tcg_gen_helper_1_1(helper_lsl, t0, cpu_T[0]); + tcg_gen_andi_tl(cpu_tmp0, cpu_cc_src, CC_Z); + label1 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, label1); + gen_op_mov_reg_v(ot, reg, t0); + gen_set_label(label1); + s->cc_op = CC_OP_EFLAGS; + tcg_temp_free(t0); + } break; case 0x118: modrm = ldub_code(s->pc++); @@ -6132,21 +7278,19 @@ case 3: case 4: case 8: + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(pc_start - s->cs_base); if (b & 2) { - gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0 + reg); - gen_op_mov_TN_reg[ot][0][rm](); - gen_op_movl_crN_T0(reg); + gen_op_mov_TN_reg(ot, 0, rm); + tcg_gen_helper_0_2(helper_write_crN, + tcg_const_i32(reg), cpu_T[0]); gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } else { - gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0 + reg); -#if !defined(CONFIG_USER_ONLY) - if (reg == 8) - gen_op_movtl_T0_cr8(); - else -#endif - gen_op_movtl_T0_env(offsetof(CPUX86State,cr[reg])); - gen_op_mov_reg_T0[ot][rm](); + tcg_gen_helper_1_1(helper_read_crN, + cpu_T[0], tcg_const_i32(reg)); + gen_op_mov_reg_T0(ot, rm); } break; default: @@ -6173,14 +7317,15 @@ goto illegal_op; if (b & 2) { gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_DR0 + reg); - gen_op_mov_TN_reg[ot][0][rm](); - gen_op_movl_drN_T0(reg); + gen_op_mov_TN_reg(ot, 0, rm); + tcg_gen_helper_0_2(helper_movl_drN_T0, + tcg_const_i32(reg), cpu_T[0]); gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } else { gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_DR0 + reg); - gen_op_movtl_T0_env(offsetof(CPUX86State,dr[reg])); - gen_op_mov_reg_T0[ot][rm](); + tcg_gen_ld_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,dr[reg])); + gen_op_mov_reg_T0(ot, rm); } } break; @@ -6189,13 +7334,13 @@ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0); - gen_op_clts(); + tcg_gen_helper_0_0(helper_clts); /* abort block because static cpu state changed */ gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } break; - /* MMX/SSE/SSE2/PNI support */ + /* MMX/3DNow!/SSE/SSE2/SSE3/SSSE3/SSE4 support */ case 0x1c3: /* MOVNTI reg, mem */ if (!(s->cpuid_features & CPUID_SSE2)) goto illegal_op; @@ -6222,7 +7367,11 @@ break; } gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_fxsave_A0((s->dflag == 2)); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(pc_start - s->cs_base); + tcg_gen_helper_0_2(helper_fxsave, + cpu_A0, tcg_const_i32((s->dflag == 2))); break; case 1: /* fxrstor */ if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) || @@ -6233,7 +7382,11 @@ break; } gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_fxrstor_A0((s->dflag == 2)); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(pc_start - s->cs_base); + tcg_gen_helper_0_2(helper_fxrstor, + cpu_A0, tcg_const_i32((s->dflag == 2))); break; case 2: /* ldmxcsr */ case 3: /* stmxcsr */ @@ -6246,11 +7399,11 @@ goto illegal_op; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); if (op == 2) { - gen_op_ld_T0_A0[OT_LONG + s->mem_index](); - gen_op_movl_env_T0(offsetof(CPUX86State, mxcsr)); + gen_op_ld_T0_A0(OT_LONG + s->mem_index); + tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, mxcsr)); } else { - gen_op_movl_T0_env(offsetof(CPUX86State, mxcsr)); - gen_op_st_T0_A0[OT_LONG + s->mem_index](); + tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, mxcsr)); + gen_op_st_T0_A0(OT_LONG + s->mem_index); } break; case 5: /* lfence */ @@ -6261,6 +7414,7 @@ case 7: /* sfence / clflush */ if ((modrm & 0xc7) == 0xc0) { /* sfence */ + /* XXX: also check for cpuid_ext2_features & CPUID_EXT2_EMMX */ if (!(s->cpuid_features & CPUID_SSE)) goto illegal_op; } else { @@ -6274,14 +7428,16 @@ goto illegal_op; } break; - case 0x10d: /* prefetch */ + case 0x10d: /* 3DNow! prefetch(w) */ modrm = ldub_code(s->pc++); + mod = (modrm >> 6) & 3; + if (mod == 3) + goto illegal_op; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); /* ignore for now */ break; case 0x1aa: /* rsm */ - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_RSM)) - break; + gen_svm_check_intercept(s, pc_start, SVM_EXIT_RSM); if (!(s->flags & HF_SMM_MASK)) goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) { @@ -6289,11 +7445,39 @@ s->cc_op = CC_OP_DYNAMIC; } gen_jmp_im(s->pc - s->cs_base); - gen_op_rsm(); + tcg_gen_helper_0_0(helper_rsm); gen_eob(s); break; + case 0x1b8: /* SSE4.2 popcnt */ + if ((prefixes & (PREFIX_REPZ | PREFIX_LOCK | PREFIX_REPNZ)) != + PREFIX_REPZ) + goto illegal_op; + if (!(s->cpuid_ext_features & CPUID_EXT_POPCNT)) + goto illegal_op; + + modrm = ldub_code(s->pc++); + reg = ((modrm >> 3) & 7); + + if (s->prefix & PREFIX_DATA) + ot = OT_WORD; + else if (s->dflag != 2) + ot = OT_LONG; + else + ot = OT_QUAD; + + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + tcg_gen_helper_1_2(helper_popcnt, + cpu_T[0], cpu_T[0], tcg_const_i32(ot)); + gen_op_mov_reg_T0(ot, reg); + + s->cc_op = CC_OP_EFLAGS; + break; + case 0x10e ... 0x10f: + /* 3DNow! instructions, ignore prefixes */ + s->prefix &= ~(PREFIX_REPZ | PREFIX_REPNZ | PREFIX_DATA); case 0x110 ... 0x117: case 0x128 ... 0x12f: + case 0x138 ... 0x13a: case 0x150 ... 0x177: case 0x17c ... 0x17f: case 0x1c2: @@ -6306,390 +7490,45 @@ } /* lock generation */ if (s->prefix & PREFIX_LOCK) - gen_op_unlock(); + tcg_gen_helper_0_0(helper_unlock); return s->pc; illegal_op: if (s->prefix & PREFIX_LOCK) - gen_op_unlock(); + tcg_gen_helper_0_0(helper_unlock); /* XXX: ensure that no lock was generated */ gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base); return s->pc; } -#define CC_OSZAPC (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C) -#define CC_OSZAP (CC_O | CC_S | CC_Z | CC_A | CC_P) - -/* flags read by an operation */ -static uint16_t opc_read_flags[NB_OPS] = { - [INDEX_op_aas] = CC_A, - [INDEX_op_aaa] = CC_A, - [INDEX_op_das] = CC_A | CC_C, - [INDEX_op_daa] = CC_A | CC_C, - - /* subtle: due to the incl/decl implementation, C is used */ - [INDEX_op_update_inc_cc] = CC_C, - - [INDEX_op_into] = CC_O, - - [INDEX_op_jb_subb] = CC_C, - [INDEX_op_jb_subw] = CC_C, - [INDEX_op_jb_subl] = CC_C, - - [INDEX_op_jz_subb] = CC_Z, - [INDEX_op_jz_subw] = CC_Z, - [INDEX_op_jz_subl] = CC_Z, - - [INDEX_op_jbe_subb] = CC_Z | CC_C, - [INDEX_op_jbe_subw] = CC_Z | CC_C, - [INDEX_op_jbe_subl] = CC_Z | CC_C, - - [INDEX_op_js_subb] = CC_S, - [INDEX_op_js_subw] = CC_S, - [INDEX_op_js_subl] = CC_S, - - [INDEX_op_jl_subb] = CC_O | CC_S, - [INDEX_op_jl_subw] = CC_O | CC_S, - [INDEX_op_jl_subl] = CC_O | CC_S, - - [INDEX_op_jle_subb] = CC_O | CC_S | CC_Z, - [INDEX_op_jle_subw] = CC_O | CC_S | CC_Z, - [INDEX_op_jle_subl] = CC_O | CC_S | CC_Z, - - [INDEX_op_loopnzw] = CC_Z, - [INDEX_op_loopnzl] = CC_Z, - [INDEX_op_loopzw] = CC_Z, - [INDEX_op_loopzl] = CC_Z, - - [INDEX_op_seto_T0_cc] = CC_O, - [INDEX_op_setb_T0_cc] = CC_C, - [INDEX_op_setz_T0_cc] = CC_Z, - [INDEX_op_setbe_T0_cc] = CC_Z | CC_C, - [INDEX_op_sets_T0_cc] = CC_S, - [INDEX_op_setp_T0_cc] = CC_P, - [INDEX_op_setl_T0_cc] = CC_O | CC_S, - [INDEX_op_setle_T0_cc] = CC_O | CC_S | CC_Z, - - [INDEX_op_setb_T0_subb] = CC_C, - [INDEX_op_setb_T0_subw] = CC_C, - [INDEX_op_setb_T0_subl] = CC_C, - - [INDEX_op_setz_T0_subb] = CC_Z, - [INDEX_op_setz_T0_subw] = CC_Z, - [INDEX_op_setz_T0_subl] = CC_Z, - - [INDEX_op_setbe_T0_subb] = CC_Z | CC_C, - [INDEX_op_setbe_T0_subw] = CC_Z | CC_C, - [INDEX_op_setbe_T0_subl] = CC_Z | CC_C, - - [INDEX_op_sets_T0_subb] = CC_S, - [INDEX_op_sets_T0_subw] = CC_S, - [INDEX_op_sets_T0_subl] = CC_S, - - [INDEX_op_setl_T0_subb] = CC_O | CC_S, - [INDEX_op_setl_T0_subw] = CC_O | CC_S, - [INDEX_op_setl_T0_subl] = CC_O | CC_S, - - [INDEX_op_setle_T0_subb] = CC_O | CC_S | CC_Z, - [INDEX_op_setle_T0_subw] = CC_O | CC_S | CC_Z, - [INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z, - - [INDEX_op_movl_T0_eflags] = CC_OSZAPC, - [INDEX_op_cmc] = CC_C, - [INDEX_op_salc] = CC_C, - - /* needed for correct flag optimisation before string ops */ - [INDEX_op_jnz_ecxw] = CC_OSZAPC, - [INDEX_op_jnz_ecxl] = CC_OSZAPC, - [INDEX_op_jz_ecxw] = CC_OSZAPC, - [INDEX_op_jz_ecxl] = CC_OSZAPC, - -#ifdef TARGET_X86_64 - [INDEX_op_jb_subq] = CC_C, - [INDEX_op_jz_subq] = CC_Z, - [INDEX_op_jbe_subq] = CC_Z | CC_C, - [INDEX_op_js_subq] = CC_S, - [INDEX_op_jl_subq] = CC_O | CC_S, - [INDEX_op_jle_subq] = CC_O | CC_S | CC_Z, - - [INDEX_op_loopnzq] = CC_Z, - [INDEX_op_loopzq] = CC_Z, - - [INDEX_op_setb_T0_subq] = CC_C, - [INDEX_op_setz_T0_subq] = CC_Z, - [INDEX_op_setbe_T0_subq] = CC_Z | CC_C, - [INDEX_op_sets_T0_subq] = CC_S, - [INDEX_op_setl_T0_subq] = CC_O | CC_S, - [INDEX_op_setle_T0_subq] = CC_O | CC_S | CC_Z, - - [INDEX_op_jnz_ecxq] = CC_OSZAPC, - [INDEX_op_jz_ecxq] = CC_OSZAPC, -#endif - -#define DEF_READF(SUFFIX)\ - [INDEX_op_adcb ## SUFFIX ## _T0_T1_cc] = CC_C,\ - [INDEX_op_adcw ## SUFFIX ## _T0_T1_cc] = CC_C,\ - [INDEX_op_adcl ## SUFFIX ## _T0_T1_cc] = CC_C,\ - X86_64_DEF([INDEX_op_adcq ## SUFFIX ## _T0_T1_cc] = CC_C,)\ - [INDEX_op_sbbb ## SUFFIX ## _T0_T1_cc] = CC_C,\ - [INDEX_op_sbbw ## SUFFIX ## _T0_T1_cc] = CC_C,\ - [INDEX_op_sbbl ## SUFFIX ## _T0_T1_cc] = CC_C,\ - X86_64_DEF([INDEX_op_sbbq ## SUFFIX ## _T0_T1_cc] = CC_C,)\ -\ - [INDEX_op_rclb ## SUFFIX ## _T0_T1_cc] = CC_C,\ - [INDEX_op_rclw ## SUFFIX ## _T0_T1_cc] = CC_C,\ - [INDEX_op_rcll ## SUFFIX ## _T0_T1_cc] = CC_C,\ - X86_64_DEF([INDEX_op_rclq ## SUFFIX ## _T0_T1_cc] = CC_C,)\ - [INDEX_op_rcrb ## SUFFIX ## _T0_T1_cc] = CC_C,\ - [INDEX_op_rcrw ## SUFFIX ## _T0_T1_cc] = CC_C,\ - [INDEX_op_rcrl ## SUFFIX ## _T0_T1_cc] = CC_C,\ - X86_64_DEF([INDEX_op_rcrq ## SUFFIX ## _T0_T1_cc] = CC_C,) - - DEF_READF( ) - DEF_READF(_raw) -#ifndef CONFIG_USER_ONLY - DEF_READF(_kernel) - DEF_READF(_user) -#endif -}; - -/* flags written by an operation */ -static uint16_t opc_write_flags[NB_OPS] = { - [INDEX_op_update2_cc] = CC_OSZAPC, - [INDEX_op_update1_cc] = CC_OSZAPC, - [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_update_neg_cc] = CC_OSZAPC, - /* subtle: due to the incl/decl implementation, C is used */ - [INDEX_op_update_inc_cc] = CC_OSZAPC, - [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC, - - [INDEX_op_mulb_AL_T0] = CC_OSZAPC, - [INDEX_op_mulw_AX_T0] = CC_OSZAPC, - [INDEX_op_mull_EAX_T0] = CC_OSZAPC, - X86_64_DEF([INDEX_op_mulq_EAX_T0] = CC_OSZAPC,) - [INDEX_op_imulb_AL_T0] = CC_OSZAPC, - [INDEX_op_imulw_AX_T0] = CC_OSZAPC, - [INDEX_op_imull_EAX_T0] = CC_OSZAPC, - X86_64_DEF([INDEX_op_imulq_EAX_T0] = CC_OSZAPC,) - [INDEX_op_imulw_T0_T1] = CC_OSZAPC, - [INDEX_op_imull_T0_T1] = CC_OSZAPC, - X86_64_DEF([INDEX_op_imulq_T0_T1] = CC_OSZAPC,) - - /* sse */ - [INDEX_op_ucomiss] = CC_OSZAPC, - [INDEX_op_ucomisd] = CC_OSZAPC, - [INDEX_op_comiss] = CC_OSZAPC, - [INDEX_op_comisd] = CC_OSZAPC, - - /* bcd */ - [INDEX_op_aam] = CC_OSZAPC, - [INDEX_op_aad] = CC_OSZAPC, - [INDEX_op_aas] = CC_OSZAPC, - [INDEX_op_aaa] = CC_OSZAPC, - [INDEX_op_das] = CC_OSZAPC, - [INDEX_op_daa] = CC_OSZAPC, - - [INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C, - [INDEX_op_movw_eflags_T0] = CC_OSZAPC, - [INDEX_op_movl_eflags_T0] = CC_OSZAPC, - [INDEX_op_movw_eflags_T0_io] = CC_OSZAPC, - [INDEX_op_movl_eflags_T0_io] = CC_OSZAPC, - [INDEX_op_movw_eflags_T0_cpl0] = CC_OSZAPC, - [INDEX_op_movl_eflags_T0_cpl0] = CC_OSZAPC, - [INDEX_op_clc] = CC_C, - [INDEX_op_stc] = CC_C, - [INDEX_op_cmc] = CC_C, - - [INDEX_op_btw_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_btl_T0_T1_cc] = CC_OSZAPC, - X86_64_DEF([INDEX_op_btq_T0_T1_cc] = CC_OSZAPC,) - [INDEX_op_btsw_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_btsl_T0_T1_cc] = CC_OSZAPC, - X86_64_DEF([INDEX_op_btsq_T0_T1_cc] = CC_OSZAPC,) - [INDEX_op_btrw_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_btrl_T0_T1_cc] = CC_OSZAPC, - X86_64_DEF([INDEX_op_btrq_T0_T1_cc] = CC_OSZAPC,) - [INDEX_op_btcw_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_btcl_T0_T1_cc] = CC_OSZAPC, - X86_64_DEF([INDEX_op_btcq_T0_T1_cc] = CC_OSZAPC,) - - [INDEX_op_bsfw_T0_cc] = CC_OSZAPC, - [INDEX_op_bsfl_T0_cc] = CC_OSZAPC, - X86_64_DEF([INDEX_op_bsfq_T0_cc] = CC_OSZAPC,) - [INDEX_op_bsrw_T0_cc] = CC_OSZAPC, - [INDEX_op_bsrl_T0_cc] = CC_OSZAPC, - X86_64_DEF([INDEX_op_bsrq_T0_cc] = CC_OSZAPC,) - - [INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC, - [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC, - [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, - X86_64_DEF([INDEX_op_cmpxchgq_T0_T1_EAX_cc] = CC_OSZAPC,) - - [INDEX_op_cmpxchg8b] = CC_Z, - [INDEX_op_lar] = CC_Z, - [INDEX_op_lsl] = CC_Z, - [INDEX_op_verr] = CC_Z, - [INDEX_op_verw] = CC_Z, - [INDEX_op_fcomi_ST0_FT0] = CC_Z | CC_P | CC_C, - [INDEX_op_fucomi_ST0_FT0] = CC_Z | CC_P | CC_C, - -#define DEF_WRITEF(SUFFIX)\ - [INDEX_op_adcb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ - [INDEX_op_adcw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ - [INDEX_op_adcl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ - X86_64_DEF([INDEX_op_adcq ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,)\ - [INDEX_op_sbbb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ - [INDEX_op_sbbw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ - [INDEX_op_sbbl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ - X86_64_DEF([INDEX_op_sbbq ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,)\ -\ - [INDEX_op_rolb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ - [INDEX_op_rolw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ - [INDEX_op_roll ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ - X86_64_DEF([INDEX_op_rolq ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,)\ - [INDEX_op_rorb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ - [INDEX_op_rorw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ - [INDEX_op_rorl ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ - X86_64_DEF([INDEX_op_rorq ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,)\ -\ - [INDEX_op_rclb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ - [INDEX_op_rclw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ - [INDEX_op_rcll ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ - X86_64_DEF([INDEX_op_rclq ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,)\ - [INDEX_op_rcrb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ - [INDEX_op_rcrw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ - [INDEX_op_rcrl ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ - X86_64_DEF([INDEX_op_rcrq ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,)\ -\ - [INDEX_op_shlb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ - [INDEX_op_shlw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ - [INDEX_op_shll ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ - X86_64_DEF([INDEX_op_shlq ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,)\ -\ - [INDEX_op_shrb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ - [INDEX_op_shrw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ - [INDEX_op_shrl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ - X86_64_DEF([INDEX_op_shrq ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,)\ -\ - [INDEX_op_sarb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ - [INDEX_op_sarw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ - [INDEX_op_sarl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ - X86_64_DEF([INDEX_op_sarq ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,)\ -\ - [INDEX_op_shldw ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\ - [INDEX_op_shldl ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\ - X86_64_DEF([INDEX_op_shldq ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,)\ - [INDEX_op_shldw ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\ - [INDEX_op_shldl ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\ - X86_64_DEF([INDEX_op_shldq ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,)\ -\ - [INDEX_op_shrdw ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\ - [INDEX_op_shrdl ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\ - X86_64_DEF([INDEX_op_shrdq ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,)\ - [INDEX_op_shrdw ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\ - [INDEX_op_shrdl ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\ - X86_64_DEF([INDEX_op_shrdq ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,)\ -\ - [INDEX_op_cmpxchgb ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,\ - [INDEX_op_cmpxchgw ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,\ - [INDEX_op_cmpxchgl ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,\ - X86_64_DEF([INDEX_op_cmpxchgq ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,) - - - DEF_WRITEF( ) - DEF_WRITEF(_raw) -#ifndef CONFIG_USER_ONLY - DEF_WRITEF(_kernel) - DEF_WRITEF(_user) -#endif -}; - -/* simpler form of an operation if no flags need to be generated */ -static uint16_t opc_simpler[NB_OPS] = { - [INDEX_op_update2_cc] = INDEX_op_nop, - [INDEX_op_update1_cc] = INDEX_op_nop, - [INDEX_op_update_neg_cc] = INDEX_op_nop, -#if 0 - /* broken: CC_OP logic must be rewritten */ - [INDEX_op_update_inc_cc] = INDEX_op_nop, -#endif - - [INDEX_op_shlb_T0_T1_cc] = INDEX_op_shlb_T0_T1, - [INDEX_op_shlw_T0_T1_cc] = INDEX_op_shlw_T0_T1, - [INDEX_op_shll_T0_T1_cc] = INDEX_op_shll_T0_T1, - X86_64_DEF([INDEX_op_shlq_T0_T1_cc] = INDEX_op_shlq_T0_T1,) - - [INDEX_op_shrb_T0_T1_cc] = INDEX_op_shrb_T0_T1, - [INDEX_op_shrw_T0_T1_cc] = INDEX_op_shrw_T0_T1, - [INDEX_op_shrl_T0_T1_cc] = INDEX_op_shrl_T0_T1, - X86_64_DEF([INDEX_op_shrq_T0_T1_cc] = INDEX_op_shrq_T0_T1,) - - [INDEX_op_sarb_T0_T1_cc] = INDEX_op_sarb_T0_T1, - [INDEX_op_sarw_T0_T1_cc] = INDEX_op_sarw_T0_T1, - [INDEX_op_sarl_T0_T1_cc] = INDEX_op_sarl_T0_T1, - X86_64_DEF([INDEX_op_sarq_T0_T1_cc] = INDEX_op_sarq_T0_T1,) - -#define DEF_SIMPLER(SUFFIX)\ - [INDEX_op_rolb ## SUFFIX ## _T0_T1_cc] = INDEX_op_rolb ## SUFFIX ## _T0_T1,\ - [INDEX_op_rolw ## SUFFIX ## _T0_T1_cc] = INDEX_op_rolw ## SUFFIX ## _T0_T1,\ - [INDEX_op_roll ## SUFFIX ## _T0_T1_cc] = INDEX_op_roll ## SUFFIX ## _T0_T1,\ - X86_64_DEF([INDEX_op_rolq ## SUFFIX ## _T0_T1_cc] = INDEX_op_rolq ## SUFFIX ## _T0_T1,)\ -\ - [INDEX_op_rorb ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorb ## SUFFIX ## _T0_T1,\ - [INDEX_op_rorw ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorw ## SUFFIX ## _T0_T1,\ - [INDEX_op_rorl ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorl ## SUFFIX ## _T0_T1,\ - X86_64_DEF([INDEX_op_rorq ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorq ## SUFFIX ## _T0_T1,) - - DEF_SIMPLER( ) - DEF_SIMPLER(_raw) -#ifndef CONFIG_USER_ONLY - DEF_SIMPLER(_kernel) - DEF_SIMPLER(_user) -#endif -}; - void optimize_flags_init(void) { - int i; - /* put default values in arrays */ - for(i = 0; i < NB_OPS; i++) { - if (opc_simpler[i] == 0) - opc_simpler[i] = i; - } -} +#if TCG_TARGET_REG_BITS == 32 + assert(sizeof(CCTable) == (1 << 3)); +#else + assert(sizeof(CCTable) == (1 << 4)); +#endif + cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env"); + cpu_cc_op = tcg_global_mem_new(TCG_TYPE_I32, + TCG_AREG0, offsetof(CPUState, cc_op), "cc_op"); + cpu_cc_src = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, offsetof(CPUState, cc_src), "cc_src"); + cpu_cc_dst = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, offsetof(CPUState, cc_dst), "cc_dst"); + cpu_cc_tmp = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, offsetof(CPUState, cc_tmp), "cc_tmp"); -/* CPU flags computation optimization: we move backward thru the - generated code to see which flags are needed. The operation is - modified if suitable */ -static void optimize_flags(uint16_t *opc_buf, int opc_buf_len) -{ - uint16_t *opc_ptr; - int live_flags, write_flags, op; - - opc_ptr = opc_buf + opc_buf_len; - /* live_flags contains the flags needed by the next instructions - in the code. At the end of the block, we consider that all the - flags are live. */ - live_flags = CC_OSZAPC; - while (opc_ptr > opc_buf) { - op = *--opc_ptr; - /* if none of the flags written by the instruction is used, - then we can try to find a simpler instruction */ - write_flags = opc_write_flags[op]; - if ((live_flags & write_flags) == 0) { - *opc_ptr = opc_simpler[op]; - } - /* compute the live flags before the instruction */ - live_flags &= ~write_flags; - live_flags |= opc_read_flags[op]; - } + /* register helpers */ + +#define DEF_HELPER(ret, name, params) tcg_register_helper(name, #name); +#include "helper.h" } /* generate intermediate code in gen_opc_buf and gen_opparam_buf for basic block 'tb'. If search_pc is TRUE, also generate PC information for each intermediate instruction. */ -static inline int gen_intermediate_code_internal(CPUState *env, - TranslationBlock *tb, - int search_pc) +static inline void gen_intermediate_code_internal(CPUState *env, + TranslationBlock *tb, + int search_pc) { DisasContext dc1, *dc = &dc1; target_ulong pc_ptr; @@ -6698,6 +7537,8 @@ uint64_t flags; target_ulong pc_start; target_ulong cs_base; + int num_insns; + int max_insns; /* generate intermediate code */ pc_start = tb->pc; @@ -6729,6 +7570,8 @@ } dc->cpuid_features = env->cpuid_features; dc->cpuid_ext_features = env->cpuid_ext_features; + dc->cpuid_ext2_features = env->cpuid_ext2_features; + dc->cpuid_ext3_features = env->cpuid_ext3_features; #ifdef TARGET_X86_64 dc->lma = (flags >> HF_LMA_SHIFT) & 1; dc->code64 = (flags >> HF_CS64_SHIFT) & 1; @@ -6746,15 +7589,32 @@ printf("ERROR addseg\n"); #endif - gen_opc_ptr = gen_opc_buf; + cpu_T[0] = tcg_temp_new(TCG_TYPE_TL); + cpu_T[1] = tcg_temp_new(TCG_TYPE_TL); + cpu_A0 = tcg_temp_new(TCG_TYPE_TL); + cpu_T3 = tcg_temp_new(TCG_TYPE_TL); + + cpu_tmp0 = tcg_temp_new(TCG_TYPE_TL); + cpu_tmp1_i64 = tcg_temp_new(TCG_TYPE_I64); + cpu_tmp2_i32 = tcg_temp_new(TCG_TYPE_I32); + cpu_tmp3_i32 = tcg_temp_new(TCG_TYPE_I32); + cpu_tmp4 = tcg_temp_new(TCG_TYPE_TL); + cpu_tmp5 = tcg_temp_new(TCG_TYPE_TL); + cpu_tmp6 = tcg_temp_new(TCG_TYPE_TL); + cpu_ptr0 = tcg_temp_new(TCG_TYPE_PTR); + cpu_ptr1 = tcg_temp_new(TCG_TYPE_PTR); + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; - gen_opparam_ptr = gen_opparam_buf; - nb_gen_labels = 0; dc->is_jmp = DISAS_NEXT; pc_ptr = pc_start; lj = -1; + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + if (max_insns == 0) + max_insns = CF_COUNT_MASK; + gen_icount_start(); for(;;) { if (env->nb_breakpoints > 0) { for(j = 0; j < env->nb_breakpoints; j++) { @@ -6774,8 +7634,13 @@ gen_opc_pc[lj] = pc_ptr; gen_opc_cc_op[lj] = dc->cc_op; gen_opc_instr_start[lj] = 1; + gen_opc_icount[lj] = num_insns; } + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) + gen_io_start(); + pc_ptr = disas_insn(dc, pc_ptr); + num_insns++; /* stop translation if indicated */ if (dc->is_jmp) break; @@ -6785,20 +7650,23 @@ the flag and abort the translation to give the irqs a change to be happen */ if (dc->tf || dc->singlestep_enabled || - (flags & HF_INHIBIT_IRQ_MASK) || - (cflags & CF_SINGLE_INSN)) { + (flags & HF_INHIBIT_IRQ_MASK)) { gen_jmp_im(pc_ptr - dc->cs_base); gen_eob(dc); break; } /* if too long translation, stop generation too */ if (gen_opc_ptr >= gen_opc_end || - (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32)) { + (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32) || + num_insns >= max_insns) { gen_jmp_im(pc_ptr - dc->cs_base); gen_eob(dc); break; } } + if (tb->cflags & CF_LAST_IO) + gen_io_end(); + gen_icount_end(tb, num_insns); *gen_opc_ptr = INDEX_op_end; /* we don't forget to fill the last values */ if (search_pc) { @@ -6824,36 +7692,45 @@ disas_flags = !dc->code32; target_disas(logfile, pc_start, pc_ptr - pc_start, disas_flags); fprintf(logfile, "\n"); - if (loglevel & CPU_LOG_TB_OP) { - fprintf(logfile, "OP:\n"); - dump_ops(gen_opc_buf, gen_opparam_buf); - fprintf(logfile, "\n"); - } } #endif - /* optimize flag computations */ - optimize_flags(gen_opc_buf, gen_opc_ptr - gen_opc_buf); - -#ifdef DEBUG_DISAS - if (loglevel & CPU_LOG_TB_OP_OPT) { - fprintf(logfile, "AFTER FLAGS OPT:\n"); - dump_ops(gen_opc_buf, gen_opparam_buf); - fprintf(logfile, "\n"); - } -#endif - if (!search_pc) + if (!search_pc) { tb->size = pc_ptr - pc_start; - return 0; + tb->icount = num_insns; + } } -int gen_intermediate_code(CPUState *env, TranslationBlock *tb) +void gen_intermediate_code(CPUState *env, TranslationBlock *tb) { - return gen_intermediate_code_internal(env, tb, 0); + gen_intermediate_code_internal(env, tb, 0); } -int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) +void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) { - return gen_intermediate_code_internal(env, tb, 1); + gen_intermediate_code_internal(env, tb, 1); } +void gen_pc_load(CPUState *env, TranslationBlock *tb, + unsigned long searched_pc, int pc_pos, void *puc) +{ + int cc_op; +#ifdef DEBUG_DISAS + if (loglevel & CPU_LOG_TB_OP) { + int i; + fprintf(logfile, "RESTORE:\n"); + for(i = 0;i <= pc_pos; i++) { + if (gen_opc_instr_start[i]) { + fprintf(logfile, "0x%04x: " TARGET_FMT_lx "\n", i, gen_opc_pc[i]); + } + } + fprintf(logfile, "spc=0x%08lx pc_pos=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n", + searched_pc, pc_pos, gen_opc_pc[pc_pos] - tb->cs_base, + (uint32_t)tb->cs_base); + } +#endif + env->eip = gen_opc_pc[pc_pos] - tb->cs_base; + cc_op = gen_opc_cc_op[pc_pos]; + if (cc_op != CC_OP_DYNAMIC) + env->cc_op = cc_op; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-m68k/cpu.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-m68k/cpu.h --- qemu-0.9.1/target-m68k/cpu.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-m68k/cpu.h 2008-07-01 21:01:19.000000000 +0100 @@ -103,13 +103,6 @@ /* ??? remove this. */ uint32_t t1; - /* exception/interrupt handling */ - jmp_buf jmp_env; - int exception_index; - int interrupt_request; - int user_mode_only; - int halted; - int pending_vector; int pending_level; @@ -120,6 +113,7 @@ uint32_t features; } CPUM68KState; +void m68k_tcg_init(void); CPUM68KState *cpu_m68k_init(const char *cpu_model); int cpu_m68k_exec(CPUM68KState *s); void cpu_m68k_close(CPUM68KState *s); @@ -141,9 +135,7 @@ CC_OP_CMPW, /* CC_DEST = result, CC_SRC = source */ CC_OP_ADDX, /* CC_DEST = result, CC_SRC = source */ CC_OP_SUBX, /* CC_DEST = result, CC_SRC = source */ - CC_OP_SHL, /* CC_DEST = source, CC_SRC = shift */ - CC_OP_SHR, /* CC_DEST = source, CC_SRC = shift */ - CC_OP_SAR, /* CC_DEST = source, CC_SRC = shift */ + CC_OP_SHIFT, /* CC_DEST = result, CC_SRC = carry */ }; #define CCF_C 0x01 @@ -230,6 +222,17 @@ return (env->sr & SR_S) == 0 ? 1 : 0; } +#if defined(CONFIG_USER_ONLY) +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) +{ + if (newsp) + env->aregs[7] = newsp; + env->dregs[0] = 0; +} +#endif + +#define CPU_PC_FROM_TB(env, tb) env->pc = tb->pc + #include "cpu-all.h" #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-m68k/exec.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-m68k/exec.h --- qemu-0.9.1/target-m68k/exec.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-m68k/exec.h 2008-08-30 10:51:20.000000000 +0100 @@ -44,10 +44,6 @@ #include "softmmu_exec.h" #endif -void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op); -float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1); -void helper_movec(CPUM68KState *env, int reg, uint32_t val); - void cpu_loop_exit(void); static inline int cpu_halted(CPUState *env) { diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-m68k/helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-m68k/helper.c --- qemu-0.9.1/target-m68k/helper.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-m68k/helper.c 2008-10-11 18:55:29.000000000 +0100 @@ -25,6 +25,12 @@ #include "config.h" #include "cpu.h" #include "exec-all.h" +#include "qemu-common.h" +#include "gdbstub.h" + +#include "helpers.h" + +#define SIGNBIT (1u << 31) enum m68k_cpuid { M68K_CPUID_M5206, @@ -48,6 +54,33 @@ {NULL, 0}, }; +static int fpu_gdb_get_reg(CPUState *env, uint8_t *mem_buf, int n) +{ + if (n < 8) { + stfq_p(mem_buf, env->fregs[n]); + return 8; + } + if (n < 11) { + /* FP control registers (not implemented) */ + memset(mem_buf, 0, 4); + return 4; + } + return 0; +} + +static int fpu_gdb_set_reg(CPUState *env, uint8_t *mem_buf, int n) +{ + if (n < 8) { + env->fregs[n] = ldfq_p(mem_buf); + return 8; + } + if (n < 11) { + /* FP control registers (not implemented) */ + return 4; + } + return 0; +} + static void m68k_set_feature(CPUM68KState *env, int feature) { env->features |= (1u << feature); @@ -100,6 +133,11 @@ } register_m68k_insns(env); + if (m68k_feature (env, M68K_FEATURE_CF_FPU)) { + gdb_register_coprocessor(env, fpu_gdb_get_reg, fpu_gdb_set_reg, + 11, "cf-fp.xml", 18); + } + /* TODO: Add [E]MAC registers. */ return 0; } @@ -120,11 +158,16 @@ CPUM68KState *cpu_m68k_init(const char *cpu_model) { CPUM68KState *env; + static int inited; env = malloc(sizeof(CPUM68KState)); if (!env) return NULL; cpu_exec_init(env); + if (!inited) { + inited = 1; + m68k_tcg_init(); + } env->cpu_model_str = cpu_model; @@ -210,34 +253,9 @@ if (HIGHBIT & (tmp ^ dest) & (tmp ^ src)) flags |= CCF_V; break; - case CC_OP_SHL: - if (src >= 32) { - SET_NZ(0); - } else { - tmp = dest << src; - SET_NZ(tmp); - } - if (src && src <= 32 && (dest & (1 << (32 - src)))) - flags |= CCF_C; - break; - case CC_OP_SHR: - if (src >= 32) { - SET_NZ(0); - } else { - tmp = dest >> src; - SET_NZ(tmp); - } - if (src && src <= 32 && ((dest >> (src - 1)) & 1)) - flags |= CCF_C; - break; - case CC_OP_SAR: - if (src >= 32) { - SET_NZ(-1); - } else { - tmp = (int32_t)dest >> src; - SET_NZ(tmp); - } - if (src && src <= 32 && (((int32_t)dest >> (src - 1)) & 1)) + case CC_OP_SHIFT: + SET_NZ(dest); + if (src) flags |= CCF_C; break; default: @@ -247,25 +265,7 @@ env->cc_dest = flags; } -float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1) -{ - /* ??? This may incorrectly raise exceptions. */ - /* ??? Should flush denormals to zero. */ - float64 res; - res = float64_sub(src0, src1, &env->fp_status); - if (float64_is_nan(res)) { - /* +/-inf compares equal against itself, but sub returns nan. */ - if (!float64_is_nan(src0) - && !float64_is_nan(src1)) { - res = float64_zero; - if (float64_lt_quiet(src0, res, &env->fp_status)) - res = float64_chs(res); - } - } - return res; -} - -void helper_movec(CPUM68KState *env, int reg, uint32_t val) +void HELPER(movec)(CPUM68KState *env, uint32_t reg, uint32_t val) { switch (reg) { case 0x02: /* CACR */ @@ -285,7 +285,7 @@ } } -void m68k_set_macsr(CPUM68KState *env, uint32_t val) +void HELPER(set_macsr)(CPUM68KState *env, uint32_t val) { uint32_t acc; int8_t exthigh; @@ -375,3 +375,541 @@ } #endif + +uint32_t HELPER(bitrev)(uint32_t x) +{ + x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau); + x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu); + x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u); + return bswap32(x); +} + +uint32_t HELPER(ff1)(uint32_t x) +{ + int n; + for (n = 32; x; n--) + x >>= 1; + return n; +} + +uint32_t HELPER(sats)(uint32_t val, uint32_t ccr) +{ + /* The result has the opposite sign to the original value. */ + if (ccr & CCF_V) + val = (((int32_t)val) >> 31) ^ SIGNBIT; + return val; +} + +uint32_t HELPER(subx_cc)(CPUState *env, uint32_t op1, uint32_t op2) +{ + uint32_t res; + uint32_t old_flags; + + old_flags = env->cc_dest; + if (env->cc_x) { + env->cc_x = (op1 <= op2); + env->cc_op = CC_OP_SUBX; + res = op1 - (op2 + 1); + } else { + env->cc_x = (op1 < op2); + env->cc_op = CC_OP_SUB; + res = op1 - op2; + } + env->cc_dest = res; + env->cc_src = op2; + cpu_m68k_flush_flags(env, env->cc_op); + /* !Z is sticky. */ + env->cc_dest &= (old_flags | ~CCF_Z); + return res; +} + +uint32_t HELPER(addx_cc)(CPUState *env, uint32_t op1, uint32_t op2) +{ + uint32_t res; + uint32_t old_flags; + + old_flags = env->cc_dest; + if (env->cc_x) { + res = op1 + op2 + 1; + env->cc_x = (res <= op2); + env->cc_op = CC_OP_ADDX; + } else { + res = op1 + op2; + env->cc_x = (res < op2); + env->cc_op = CC_OP_ADD; + } + env->cc_dest = res; + env->cc_src = op2; + cpu_m68k_flush_flags(env, env->cc_op); + /* !Z is sticky. */ + env->cc_dest &= (old_flags | ~CCF_Z); + return res; +} + +uint32_t HELPER(xflag_lt)(uint32_t a, uint32_t b) +{ + return a < b; +} + +uint32_t HELPER(btest)(uint32_t x) +{ + return x != 0; +} + +void HELPER(set_sr)(CPUState *env, uint32_t val) +{ + env->sr = val & 0xffff; + m68k_switch_sp(env); +} + +uint32_t HELPER(shl_cc)(CPUState *env, uint32_t val, uint32_t shift) +{ + uint32_t result; + uint32_t cf; + + shift &= 63; + if (shift == 0) { + result = val; + cf = env->cc_src & CCF_C; + } else if (shift < 32) { + result = val << shift; + cf = (val >> (32 - shift)) & 1; + } else if (shift == 32) { + result = 0; + cf = val & 1; + } else /* shift > 32 */ { + result = 0; + cf = 0; + } + env->cc_src = cf; + env->cc_x = (cf != 0); + env->cc_dest = result; + return result; +} + +uint32_t HELPER(shr_cc)(CPUState *env, uint32_t val, uint32_t shift) +{ + uint32_t result; + uint32_t cf; + + shift &= 63; + if (shift == 0) { + result = val; + cf = env->cc_src & CCF_C; + } else if (shift < 32) { + result = val >> shift; + cf = (val >> (shift - 1)) & 1; + } else if (shift == 32) { + result = 0; + cf = val >> 31; + } else /* shift > 32 */ { + result = 0; + cf = 0; + } + env->cc_src = cf; + env->cc_x = (cf != 0); + env->cc_dest = result; + return result; +} + +uint32_t HELPER(sar_cc)(CPUState *env, uint32_t val, uint32_t shift) +{ + uint32_t result; + uint32_t cf; + + shift &= 63; + if (shift == 0) { + result = val; + cf = (env->cc_src & CCF_C) != 0; + } else if (shift < 32) { + result = (int32_t)val >> shift; + cf = (val >> (shift - 1)) & 1; + } else /* shift >= 32 */ { + result = (int32_t)val >> 31; + cf = val >> 31; + } + env->cc_src = cf; + env->cc_x = cf; + env->cc_dest = result; + return result; +} + +/* FPU helpers. */ +uint32_t HELPER(f64_to_i32)(CPUState *env, float64 val) +{ + return float64_to_int32(val, &env->fp_status); +} + +float32 HELPER(f64_to_f32)(CPUState *env, float64 val) +{ + return float64_to_float32(val, &env->fp_status); +} + +float64 HELPER(i32_to_f64)(CPUState *env, uint32_t val) +{ + return int32_to_float64(val, &env->fp_status); +} + +float64 HELPER(f32_to_f64)(CPUState *env, float32 val) +{ + return float32_to_float64(val, &env->fp_status); +} + +float64 HELPER(iround_f64)(CPUState *env, float64 val) +{ + return float64_round_to_int(val, &env->fp_status); +} + +float64 HELPER(itrunc_f64)(CPUState *env, float64 val) +{ + return float64_trunc_to_int(val, &env->fp_status); +} + +float64 HELPER(sqrt_f64)(CPUState *env, float64 val) +{ + return float64_sqrt(val, &env->fp_status); +} + +float64 HELPER(abs_f64)(float64 val) +{ + return float64_abs(val); +} + +float64 HELPER(chs_f64)(float64 val) +{ + return float64_chs(val); +} + +float64 HELPER(add_f64)(CPUState *env, float64 a, float64 b) +{ + return float64_add(a, b, &env->fp_status); +} + +float64 HELPER(sub_f64)(CPUState *env, float64 a, float64 b) +{ + return float64_sub(a, b, &env->fp_status); +} + +float64 HELPER(mul_f64)(CPUState *env, float64 a, float64 b) +{ + return float64_mul(a, b, &env->fp_status); +} + +float64 HELPER(div_f64)(CPUState *env, float64 a, float64 b) +{ + return float64_div(a, b, &env->fp_status); +} + +float64 HELPER(sub_cmp_f64)(CPUState *env, float64 a, float64 b) +{ + /* ??? This may incorrectly raise exceptions. */ + /* ??? Should flush denormals to zero. */ + float64 res; + res = float64_sub(a, b, &env->fp_status); + if (float64_is_nan(res)) { + /* +/-inf compares equal against itself, but sub returns nan. */ + if (!float64_is_nan(a) + && !float64_is_nan(b)) { + res = float64_zero; + if (float64_lt_quiet(a, res, &env->fp_status)) + res = float64_chs(res); + } + } + return res; +} + +uint32_t HELPER(compare_f64)(CPUState *env, float64 val) +{ + return float64_compare_quiet(val, float64_zero, &env->fp_status); +} + +/* MAC unit. */ +/* FIXME: The MAC unit implementation is a bit of a mess. Some helpers + take values, others take register numbers and manipulate the contents + in-place. */ +void HELPER(mac_move)(CPUState *env, uint32_t dest, uint32_t src) +{ + uint32_t mask; + env->macc[dest] = env->macc[src]; + mask = MACSR_PAV0 << dest; + if (env->macsr & (MACSR_PAV0 << src)) + env->macsr |= mask; + else + env->macsr &= ~mask; +} + +uint64_t HELPER(macmuls)(CPUState *env, uint32_t op1, uint32_t op2) +{ + int64_t product; + int64_t res; + + product = (uint64_t)op1 * op2; + res = (product << 24) >> 24; + if (res != product) { + env->macsr |= MACSR_V; + if (env->macsr & MACSR_OMC) { + /* Make sure the accumulate operation overflows. */ + if (product < 0) + res = ~(1ll << 50); + else + res = 1ll << 50; + } + } + return res; +} + +uint64_t HELPER(macmulu)(CPUState *env, uint32_t op1, uint32_t op2) +{ + uint64_t product; + + product = (uint64_t)op1 * op2; + if (product & (0xffffffull << 40)) { + env->macsr |= MACSR_V; + if (env->macsr & MACSR_OMC) { + /* Make sure the accumulate operation overflows. */ + product = 1ll << 50; + } else { + product &= ((1ull << 40) - 1); + } + } + return product; +} + +uint64_t HELPER(macmulf)(CPUState *env, uint32_t op1, uint32_t op2) +{ + uint64_t product; + uint32_t remainder; + + product = (uint64_t)op1 * op2; + if (env->macsr & MACSR_RT) { + remainder = product & 0xffffff; + product >>= 24; + if (remainder > 0x800000) + product++; + else if (remainder == 0x800000) + product += (product & 1); + } else { + product >>= 24; + } + return product; +} + +void HELPER(macsats)(CPUState *env, uint32_t acc) +{ + int64_t tmp; + int64_t result; + tmp = env->macc[acc]; + result = ((tmp << 16) >> 16); + if (result != tmp) { + env->macsr |= MACSR_V; + } + if (env->macsr & MACSR_V) { + env->macsr |= MACSR_PAV0 << acc; + if (env->macsr & MACSR_OMC) { + /* The result is saturated to 32 bits, despite overflow occuring + at 48 bits. Seems weird, but that's what the hardware docs + say. */ + result = (result >> 63) ^ 0x7fffffff; + } + } + env->macc[acc] = result; +} + +void HELPER(macsatu)(CPUState *env, uint32_t acc) +{ + uint64_t val; + + val = env->macc[acc]; + if (val & (0xffffull << 48)) { + env->macsr |= MACSR_V; + } + if (env->macsr & MACSR_V) { + env->macsr |= MACSR_PAV0 << acc; + if (env->macsr & MACSR_OMC) { + if (val > (1ull << 53)) + val = 0; + else + val = (1ull << 48) - 1; + } else { + val &= ((1ull << 48) - 1); + } + } + env->macc[acc] = val; +} + +void HELPER(macsatf)(CPUState *env, uint32_t acc) +{ + int64_t sum; + int64_t result; + + sum = env->macc[acc]; + result = (sum << 16) >> 16; + if (result != sum) { + env->macsr |= MACSR_V; + } + if (env->macsr & MACSR_V) { + env->macsr |= MACSR_PAV0 << acc; + if (env->macsr & MACSR_OMC) { + result = (result >> 63) ^ 0x7fffffffffffll; + } + } + env->macc[acc] = result; +} + +void HELPER(mac_set_flags)(CPUState *env, uint32_t acc) +{ + uint64_t val; + val = env->macc[acc]; + if (val == 0) + env->macsr |= MACSR_Z; + else if (val & (1ull << 47)); + env->macsr |= MACSR_N; + if (env->macsr & (MACSR_PAV0 << acc)) { + env->macsr |= MACSR_V; + } + if (env->macsr & MACSR_FI) { + val = ((int64_t)val) >> 40; + if (val != 0 && val != -1) + env->macsr |= MACSR_EV; + } else if (env->macsr & MACSR_SU) { + val = ((int64_t)val) >> 32; + if (val != 0 && val != -1) + env->macsr |= MACSR_EV; + } else { + if ((val >> 32) != 0) + env->macsr |= MACSR_EV; + } +} + +void HELPER(flush_flags)(CPUState *env, uint32_t cc_op) +{ + cpu_m68k_flush_flags(env, cc_op); +} + +uint32_t HELPER(get_macf)(CPUState *env, uint64_t val) +{ + int rem; + uint32_t result; + + if (env->macsr & MACSR_SU) { + /* 16-bit rounding. */ + rem = val & 0xffffff; + val = (val >> 24) & 0xffffu; + if (rem > 0x800000) + val++; + else if (rem == 0x800000) + val += (val & 1); + } else if (env->macsr & MACSR_RT) { + /* 32-bit rounding. */ + rem = val & 0xff; + val >>= 8; + if (rem > 0x80) + val++; + else if (rem == 0x80) + val += (val & 1); + } else { + /* No rounding. */ + val >>= 8; + } + if (env->macsr & MACSR_OMC) { + /* Saturate. */ + if (env->macsr & MACSR_SU) { + if (val != (uint16_t) val) { + result = ((val >> 63) ^ 0x7fff) & 0xffff; + } else { + result = val & 0xffff; + } + } else { + if (val != (uint32_t)val) { + result = ((uint32_t)(val >> 63) & 0x7fffffff); + } else { + result = (uint32_t)val; + } + } + } else { + /* No saturation. */ + if (env->macsr & MACSR_SU) { + result = val & 0xffff; + } else { + result = (uint32_t)val; + } + } + return result; +} + +uint32_t HELPER(get_macs)(uint64_t val) +{ + if (val == (int32_t)val) { + return (int32_t)val; + } else { + return (val >> 61) ^ ~SIGNBIT; + } +} + +uint32_t HELPER(get_macu)(uint64_t val) +{ + if ((val >> 32) == 0) { + return (uint32_t)val; + } else { + return 0xffffffffu; + } +} + +uint32_t HELPER(get_mac_extf)(CPUState *env, uint32_t acc) +{ + uint32_t val; + val = env->macc[acc] & 0x00ff; + val = (env->macc[acc] >> 32) & 0xff00; + val |= (env->macc[acc + 1] << 16) & 0x00ff0000; + val |= (env->macc[acc + 1] >> 16) & 0xff000000; + return val; +} + +uint32_t HELPER(get_mac_exti)(CPUState *env, uint32_t acc) +{ + uint32_t val; + val = (env->macc[acc] >> 32) & 0xffff; + val |= (env->macc[acc + 1] >> 16) & 0xffff0000; + return val; +} + +void HELPER(set_mac_extf)(CPUState *env, uint32_t val, uint32_t acc) +{ + int64_t res; + int32_t tmp; + res = env->macc[acc] & 0xffffffff00ull; + tmp = (int16_t)(val & 0xff00); + res |= ((int64_t)tmp) << 32; + res |= val & 0xff; + env->macc[acc] = res; + res = env->macc[acc + 1] & 0xffffffff00ull; + tmp = (val & 0xff000000); + res |= ((int64_t)tmp) << 16; + res |= (val >> 16) & 0xff; + env->macc[acc + 1] = res; +} + +void HELPER(set_mac_exts)(CPUState *env, uint32_t val, uint32_t acc) +{ + int64_t res; + int32_t tmp; + res = (uint32_t)env->macc[acc]; + tmp = (int16_t)val; + res |= ((int64_t)tmp) << 32; + env->macc[acc] = res; + res = (uint32_t)env->macc[acc + 1]; + tmp = val & 0xffff0000; + res |= (int64_t)tmp << 16; + env->macc[acc + 1] = res; +} + +void HELPER(set_mac_extu)(CPUState *env, uint32_t val, uint32_t acc) +{ + uint64_t res; + res = (uint32_t)env->macc[acc]; + res |= ((uint64_t)(val & 0xffff)) << 32; + env->macc[acc] = res; + res = (uint32_t)env->macc[acc + 1]; + res |= (uint64_t)(val & 0xffff0000) << 16; + env->macc[acc + 1] = res; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-m68k/helpers.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-m68k/helpers.h --- qemu-0.9.1/target-m68k/helpers.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-m68k/helpers.h 2008-05-24 23:29:16.000000000 +0100 @@ -0,0 +1,138 @@ +#ifndef DEF_HELPER +#define DEF_HELPER(name, ret, args) ret glue(helper_,name) args; +#endif + +#ifdef GEN_HELPER +#define DEF_HELPER_0_0(name, ret, args) \ +DEF_HELPER(name, ret, args) \ +static inline void gen_helper_##name(void) \ +{ \ + tcg_gen_helper_0_0(helper_##name); \ +} +#define DEF_HELPER_0_1(name, ret, args) \ +DEF_HELPER(name, ret, args) \ +static inline void gen_helper_##name(TCGv arg1) \ +{ \ + tcg_gen_helper_0_1(helper_##name, arg1); \ +} +#define DEF_HELPER_0_2(name, ret, args) \ +DEF_HELPER(name, ret, args) \ +static inline void gen_helper_##name(TCGv arg1, TCGv arg2) \ +{ \ + tcg_gen_helper_0_2(helper_##name, arg1, arg2); \ +} +#define DEF_HELPER_0_3(name, ret, args) \ +DEF_HELPER(name, ret, args) \ +static inline void gen_helper_##name( \ + TCGv arg1, TCGv arg2, TCGv arg3) \ +{ \ + tcg_gen_helper_0_3(helper_##name, arg1, arg2, arg3); \ +} +#define DEF_HELPER_1_0(name, ret, args) \ +DEF_HELPER(name, ret, args) \ +static inline void gen_helper_##name(TCGv ret) \ +{ \ + tcg_gen_helper_1_0(helper_##name, ret); \ +} +#define DEF_HELPER_1_1(name, ret, args) \ +DEF_HELPER(name, ret, args) \ +static inline void gen_helper_##name(TCGv ret, TCGv arg1) \ +{ \ + tcg_gen_helper_1_1(helper_##name, ret, arg1); \ +} +#define DEF_HELPER_1_2(name, ret, args) \ +DEF_HELPER(name, ret, args) \ +static inline void gen_helper_##name(TCGv ret, TCGv arg1, TCGv arg2) \ +{ \ + tcg_gen_helper_1_2(helper_##name, ret, arg1, arg2); \ +} +#define DEF_HELPER_1_3(name, ret, args) \ +DEF_HELPER(name, ret, args) \ +static inline void gen_helper_##name(TCGv ret, \ + TCGv arg1, TCGv arg2, TCGv arg3) \ +{ \ + tcg_gen_helper_1_3(helper_##name, ret, arg1, arg2, arg3); \ +} +#define DEF_HELPER_1_4(name, ret, args) \ +DEF_HELPER(name, ret, args) \ +static inline void gen_helper_##name(TCGv ret, \ + TCGv arg1, TCGv arg2, TCGv arg3, TCGv arg4) \ +{ \ + tcg_gen_helper_1_4(helper_##name, ret, arg1, arg2, arg3, arg4); \ +} +#else /* !GEN_HELPER */ +#define DEF_HELPER_0_0 DEF_HELPER +#define DEF_HELPER_0_1 DEF_HELPER +#define DEF_HELPER_0_2 DEF_HELPER +#define DEF_HELPER_0_3 DEF_HELPER +#define DEF_HELPER_1_0 DEF_HELPER +#define DEF_HELPER_1_1 DEF_HELPER +#define DEF_HELPER_1_2 DEF_HELPER +#define DEF_HELPER_1_3 DEF_HELPER +#define DEF_HELPER_1_4 DEF_HELPER +#define HELPER(x) glue(helper_,x) +#endif + +DEF_HELPER_1_1(bitrev, uint32_t, (uint32_t)) +DEF_HELPER_1_1(ff1, uint32_t, (uint32_t)) +DEF_HELPER_1_2(sats, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_0_2(divu, void, (CPUState *, uint32_t)) +DEF_HELPER_0_2(divs, void, (CPUState *, uint32_t)) +DEF_HELPER_1_3(addx_cc, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(subx_cc, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(shl_cc, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(shr_cc, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(sar_cc, uint32_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_2(xflag_lt, uint32_t, (uint32_t, uint32_t)) +DEF_HELPER_0_2(set_sr, void, (CPUState *, uint32_t)) +DEF_HELPER_0_3(movec, void, (CPUState *, uint32_t, uint32_t)) + +DEF_HELPER_1_2(f64_to_i32, float32, (CPUState *, float64)) +DEF_HELPER_1_2(f64_to_f32, float32, (CPUState *, float64)) +DEF_HELPER_1_2(i32_to_f64, float64, (CPUState *, uint32_t)) +DEF_HELPER_1_2(f32_to_f64, float64, (CPUState *, float32)) +DEF_HELPER_1_2(iround_f64, float64, (CPUState *, float64)) +DEF_HELPER_1_2(itrunc_f64, float64, (CPUState *, float64)) +DEF_HELPER_1_2(sqrt_f64, float64, (CPUState *, float64)) +DEF_HELPER_1_1(abs_f64, float64, (float64)) +DEF_HELPER_1_1(chs_f64, float64, (float64)) +DEF_HELPER_1_3(add_f64, float64, (CPUState *, float64, float64)) +DEF_HELPER_1_3(sub_f64, float64, (CPUState *, float64, float64)) +DEF_HELPER_1_3(mul_f64, float64, (CPUState *, float64, float64)) +DEF_HELPER_1_3(div_f64, float64, (CPUState *, float64, float64)) +DEF_HELPER_1_3(sub_cmp_f64, float64, (CPUState *, float64, float64)) +DEF_HELPER_1_2(compare_f64, uint32_t, (CPUState *, float64)) + +DEF_HELPER_0_3(mac_move, void, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(macmulf, uint64_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(macmuls, uint64_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_1_3(macmulu, uint64_t, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_0_2(macsats, void, (CPUState *, uint32_t)) +DEF_HELPER_0_2(macsatu, void, (CPUState *, uint32_t)) +DEF_HELPER_0_2(macsatf, void, (CPUState *, uint32_t)) +DEF_HELPER_0_2(mac_set_flags, void, (CPUState *, uint32_t)) +DEF_HELPER_0_2(set_macsr, void, (CPUState *, uint32_t)) +DEF_HELPER_1_2(get_macf, uint32_t, (CPUState *, uint64_t)) +DEF_HELPER_1_1(get_macs, uint32_t, (uint64_t)) +DEF_HELPER_1_1(get_macu, uint32_t, (uint64_t)) +DEF_HELPER_1_2(get_mac_extf, uint32_t, (CPUState *, uint32_t)) +DEF_HELPER_1_2(get_mac_exti, uint32_t, (CPUState *, uint32_t)) +DEF_HELPER_0_3(set_mac_extf, void, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_0_3(set_mac_exts, void, (CPUState *, uint32_t, uint32_t)) +DEF_HELPER_0_3(set_mac_extu, void, (CPUState *, uint32_t, uint32_t)) + +DEF_HELPER_0_2(flush_flags, void, (CPUState *, uint32_t)) +DEF_HELPER_0_1(raise_exception, void, (uint32_t)) + +#undef DEF_HELPER +#undef DEF_HELPER_0_0 +#undef DEF_HELPER_0_1 +#undef DEF_HELPER_0_2 +#undef DEF_HELPER_0_3 +#undef DEF_HELPER_1_0 +#undef DEF_HELPER_1_1 +#undef DEF_HELPER_1_2 +#undef DEF_HELPER_1_3 +#undef DEF_HELPER_1_4 +#undef GEN_HELPER +#undef DEF_HELPER diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-m68k/machine.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-m68k/machine.c --- qemu-0.9.1/target-m68k/machine.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-m68k/machine.c 2008-05-04 14:11:44.000000000 +0100 @@ -0,0 +1,9 @@ +#include "hw/hw.h" +#include "hw/boards.h" + +void register_machines(void) +{ + qemu_register_machine(&mcf5208evb_machine); + qemu_register_machine(&an5206_machine); + qemu_register_machine(&dummy_m68k_machine); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-m68k/op.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-m68k/op.c --- qemu-0.9.1/target-m68k/op.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-m68k/op.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,1075 +0,0 @@ -/* - * m68k micro operations - * - * Copyright (c) 2006-2007 CodeSourcery - * Written by Paul Brook - * - * 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 - * 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 "exec.h" -#include "m68k-qreg.h" - -#ifndef offsetof -#define offsetof(type, field) ((size_t) &((type *)0)->field) -#endif - -static long qreg_offsets[] = { -#define DEFO32(name, offset) offsetof(CPUState, offset), -#define DEFR(name, reg, mode) -1, -#define DEFF64(name, offset) offsetof(CPUState, offset), - 0, -#include "qregs.def" -}; - -#define CPU_FP_STATUS env->fp_status - -#define RAISE_EXCEPTION(n) do { \ - env->exception_index = n; \ - cpu_loop_exit(); \ - } while(0) - -#define get_op helper_get_op -#define set_op helper_set_op -#define get_opf64 helper_get_opf64 -#define set_opf64 helper_set_opf64 -uint32_t -get_op(int qreg) -{ - if (qreg >= TARGET_NUM_QREGS) { - return env->qregs[qreg - TARGET_NUM_QREGS]; - } else if (qreg == QREG_T0) { - return T0; - } else { - return *(uint32_t *)(((long)env) + qreg_offsets[qreg]); - } -} - -void set_op(int qreg, uint32_t val) -{ - if (qreg >= TARGET_NUM_QREGS) { - env->qregs[qreg - TARGET_NUM_QREGS] = val; - } else if (qreg == QREG_T0) { - T0 = val; - } else { - *(uint32_t *)(((long)env) + qreg_offsets[qreg]) = val; - } -} - -float64 get_opf64(int qreg) -{ - if (qreg < TARGET_NUM_QREGS) { - return *(float64 *)(((long)env) + qreg_offsets[qreg]); - } else { - return *(float64 *)&env->qregs[qreg - TARGET_NUM_QREGS]; - } -} - -void set_opf64(int qreg, float64 val) -{ - if (qreg < TARGET_NUM_QREGS) { - *(float64 *)(((long)env) + qreg_offsets[qreg]) = val; - } else { - *(float64 *)&env->qregs[qreg - TARGET_NUM_QREGS] = val; - } -} - -#define OP(name) void OPPROTO glue(op_,name) (void) - -OP(mov32) -{ - set_op(PARAM1, get_op(PARAM2)); - FORCE_RET(); -} - -OP(mov32_im) -{ - set_op(PARAM1, PARAM2); - FORCE_RET(); -} - -OP(movf64) -{ - set_opf64(PARAM1, get_opf64(PARAM2)); - FORCE_RET(); -} - -OP(zerof64) -{ - set_opf64(PARAM1, float64_zero); - FORCE_RET(); -} - -OP(add32) -{ - uint32_t op2 = get_op(PARAM2); - uint32_t op3 = get_op(PARAM3); - set_op(PARAM1, op2 + op3); - FORCE_RET(); -} - -OP(sub32) -{ - uint32_t op2 = get_op(PARAM2); - uint32_t op3 = get_op(PARAM3); - set_op(PARAM1, op2 - op3); - FORCE_RET(); -} - -OP(mul32) -{ - uint32_t op2 = get_op(PARAM2); - uint32_t op3 = get_op(PARAM3); - set_op(PARAM1, op2 * op3); - FORCE_RET(); -} - -OP(not32) -{ - uint32_t arg = get_op(PARAM2); - set_op(PARAM1, ~arg); - FORCE_RET(); -} - -OP(neg32) -{ - uint32_t arg = get_op(PARAM2); - set_op(PARAM1, -arg); - FORCE_RET(); -} - -OP(bswap32) -{ - uint32_t arg = get_op(PARAM2); - arg = (arg >> 24) | (arg << 24) - | ((arg >> 16) & 0xff00) | ((arg << 16) & 0xff0000); - set_op(PARAM1, arg); - FORCE_RET(); -} - -OP(btest) -{ - uint32_t op1 = get_op(PARAM1); - uint32_t op2 = get_op(PARAM2); - if (op1 & op2) - env->cc_dest &= ~CCF_Z; - else - env->cc_dest |= CCF_Z; - FORCE_RET(); -} - -OP(ff1) -{ - uint32_t arg = get_op(PARAM2); - int n; - for (n = 32; arg; n--) - arg >>= 1; - set_op(PARAM1, n); - FORCE_RET(); -} - -OP(subx_cc) -{ - uint32_t op1 = get_op(PARAM1); - uint32_t op2 = get_op(PARAM2); - uint32_t res; - if (env->cc_x) { - env->cc_x = (op1 <= op2); - env->cc_op = CC_OP_SUBX; - res = op1 - (op2 + 1); - } else { - env->cc_x = (op1 < op2); - env->cc_op = CC_OP_SUB; - res = op1 - op2; - } - set_op(PARAM1, res); - FORCE_RET(); -} - -OP(addx_cc) -{ - uint32_t op1 = get_op(PARAM1); - uint32_t op2 = get_op(PARAM2); - uint32_t res; - if (env->cc_x) { - res = op1 + op2 + 1; - env->cc_x = (res <= op2); - env->cc_op = CC_OP_ADDX; - } else { - res = op1 + op2; - env->cc_x = (res < op2); - env->cc_op = CC_OP_ADD; - } - set_op(PARAM1, res); - FORCE_RET(); -} - -/* Logic ops. */ - -OP(and32) -{ - uint32_t op2 = get_op(PARAM2); - uint32_t op3 = get_op(PARAM3); - set_op(PARAM1, op2 & op3); - FORCE_RET(); -} - -OP(or32) -{ - uint32_t op2 = get_op(PARAM2); - uint32_t op3 = get_op(PARAM3); - set_op(PARAM1, op2 | op3); - FORCE_RET(); -} - -OP(xor32) -{ - uint32_t op2 = get_op(PARAM2); - uint32_t op3 = get_op(PARAM3); - set_op(PARAM1, op2 ^ op3); - FORCE_RET(); -} - -/* Shifts. */ -OP(shl32) -{ - uint32_t op2 = get_op(PARAM2); - uint32_t op3 = get_op(PARAM3); - uint32_t result; - result = op2 << op3; - set_op(PARAM1, result); - FORCE_RET(); -} - -OP(shl_cc) -{ - uint32_t op1 = get_op(PARAM1); - uint32_t op2 = get_op(PARAM2); - uint32_t result; - result = op1 << op2; - set_op(PARAM1, result); - env->cc_x = (op1 << (op2 - 1)) & 1; - FORCE_RET(); -} - -OP(shr32) -{ - uint32_t op2 = get_op(PARAM2); - uint32_t op3 = get_op(PARAM3); - uint32_t result; - result = op2 >> op3; - set_op(PARAM1, result); - FORCE_RET(); -} - -OP(shr_cc) -{ - uint32_t op1 = get_op(PARAM1); - uint32_t op2 = get_op(PARAM2); - uint32_t result; - result = op1 >> op2; - set_op(PARAM1, result); - env->cc_x = (op1 >> (op2 - 1)) & 1; - FORCE_RET(); -} - -OP(sar32) -{ - int32_t op2 = get_op(PARAM2); - uint32_t op3 = get_op(PARAM3); - uint32_t result; - result = op2 >> op3; - set_op(PARAM1, result); - FORCE_RET(); -} - -OP(sar_cc) -{ - int32_t op1 = get_op(PARAM1); - uint32_t op2 = get_op(PARAM2); - uint32_t result; - result = op1 >> op2; - set_op(PARAM1, result); - env->cc_x = (op1 >> (op2 - 1)) & 1; - FORCE_RET(); -} - -/* Value extend. */ - -OP(ext8u32) -{ - uint32_t op2 = get_op(PARAM2); - set_op(PARAM1, (uint8_t)op2); - FORCE_RET(); -} - -OP(ext8s32) -{ - uint32_t op2 = get_op(PARAM2); - set_op(PARAM1, (int8_t)op2); - FORCE_RET(); -} - -OP(ext16u32) -{ - uint32_t op2 = get_op(PARAM2); - set_op(PARAM1, (uint16_t)op2); - FORCE_RET(); -} - -OP(ext16s32) -{ - uint32_t op2 = get_op(PARAM2); - set_op(PARAM1, (int16_t)op2); - FORCE_RET(); -} - -OP(flush_flags) -{ - cpu_m68k_flush_flags(env, env->cc_op); - FORCE_RET(); -} - -OP(divu) -{ - uint32_t num; - uint32_t den; - uint32_t quot; - uint32_t rem; - uint32_t flags; - - num = env->div1; - den = env->div2; - /* ??? This needs to make sure the throwing location is accurate. */ - if (den == 0) - RAISE_EXCEPTION(EXCP_DIV0); - quot = num / den; - rem = num % den; - flags = 0; - /* Avoid using a PARAM1 of zero. This breaks dyngen because it uses - the address of a symbol, and gcc knows symbols can't have address - zero. */ - if (PARAM1 == 2 && quot > 0xffff) - flags |= CCF_V; - if (quot == 0) - flags |= CCF_Z; - else if ((int32_t)quot < 0) - flags |= CCF_N; - env->div1 = quot; - env->div2 = rem; - env->cc_dest = flags; - FORCE_RET(); -} - -OP(divs) -{ - int32_t num; - int32_t den; - int32_t quot; - int32_t rem; - int32_t flags; - - num = env->div1; - den = env->div2; - if (den == 0) - RAISE_EXCEPTION(EXCP_DIV0); - quot = num / den; - rem = num % den; - flags = 0; - if (PARAM1 == 2 && quot != (int16_t)quot) - flags |= CCF_V; - if (quot == 0) - flags |= CCF_Z; - else if (quot < 0) - flags |= CCF_N; - env->div1 = quot; - env->div2 = rem; - env->cc_dest = flags; - FORCE_RET(); -} - -/* Halt is special because it may be a semihosting call. */ -OP(halt) -{ - RAISE_EXCEPTION(EXCP_HALT_INSN); - FORCE_RET(); -} - -OP(stop) -{ - env->halted = 1; - RAISE_EXCEPTION(EXCP_HLT); - FORCE_RET(); -} - -OP(raise_exception) -{ - RAISE_EXCEPTION(PARAM1); - FORCE_RET(); -} - -/* Floating point comparison sets flags differently to other instructions. */ - -OP(sub_cmpf64) -{ - float64 src0; - float64 src1; - src0 = get_opf64(PARAM2); - src1 = get_opf64(PARAM3); - set_opf64(PARAM1, helper_sub_cmpf64(env, src0, src1)); - FORCE_RET(); -} - -OP(update_xflag_tst) -{ - uint32_t op1 = get_op(PARAM1); - env->cc_x = op1; - FORCE_RET(); -} - -OP(update_xflag_lt) -{ - uint32_t op1 = get_op(PARAM1); - uint32_t op2 = get_op(PARAM2); - env->cc_x = (op1 < op2); - FORCE_RET(); -} - -OP(get_xflag) -{ - set_op(PARAM1, env->cc_x); - FORCE_RET(); -} - -OP(logic_cc) -{ - uint32_t op1 = get_op(PARAM1); - env->cc_dest = op1; - FORCE_RET(); -} - -OP(update_cc_add) -{ - uint32_t op1 = get_op(PARAM1); - uint32_t op2 = get_op(PARAM2); - env->cc_dest = op1; - env->cc_src = op2; - FORCE_RET(); -} - -OP(fp_result) -{ - env->fp_result = get_opf64(PARAM1); - FORCE_RET(); -} - -OP(set_sr) -{ - env->sr = get_op(PARAM1) & 0xffff; - m68k_switch_sp(env); - FORCE_RET(); -} - -OP(jmp) -{ - GOTO_LABEL_PARAM(1); -} - -OP(set_T0_z32) -{ - uint32_t arg = get_op(PARAM1); - T0 = (arg == 0); - FORCE_RET(); -} - -OP(set_T0_nz32) -{ - uint32_t arg = get_op(PARAM1); - T0 = (arg != 0); - FORCE_RET(); -} - -OP(set_T0_s32) -{ - int32_t arg = get_op(PARAM1); - T0 = (arg > 0); - FORCE_RET(); -} - -OP(set_T0_ns32) -{ - int32_t arg = get_op(PARAM1); - T0 = (arg >= 0); - FORCE_RET(); -} - -OP(jmp_T0) -{ - if (T0) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO op_goto_tb0(void) -{ - GOTO_TB(op_goto_tb0, PARAM1, 0); -} - -void OPPROTO op_goto_tb1(void) -{ - GOTO_TB(op_goto_tb1, PARAM1, 1); -} - -OP(exit_tb) -{ - EXIT_TB(); -} - - -/* Floating point. */ -OP(f64_to_i32) -{ - set_op(PARAM1, float64_to_int32(get_opf64(PARAM2), &CPU_FP_STATUS)); - FORCE_RET(); -} - -OP(f64_to_f32) -{ - union { - float32 f; - uint32_t i; - } u; - u.f = float64_to_float32(get_opf64(PARAM2), &CPU_FP_STATUS); - set_op(PARAM1, u.i); - FORCE_RET(); -} - -OP(i32_to_f64) -{ - set_opf64(PARAM1, int32_to_float64(get_op(PARAM2), &CPU_FP_STATUS)); - FORCE_RET(); -} - -OP(f32_to_f64) -{ - union { - float32 f; - uint32_t i; - } u; - u.i = get_op(PARAM2); - set_opf64(PARAM1, float32_to_float64(u.f, &CPU_FP_STATUS)); - FORCE_RET(); -} - -OP(absf64) -{ - float64 op0 = get_opf64(PARAM2); - set_opf64(PARAM1, float64_abs(op0)); - FORCE_RET(); -} - -OP(chsf64) -{ - float64 op0 = get_opf64(PARAM2); - set_opf64(PARAM1, float64_chs(op0)); - FORCE_RET(); -} - -OP(sqrtf64) -{ - float64 op0 = get_opf64(PARAM2); - set_opf64(PARAM1, float64_sqrt(op0, &CPU_FP_STATUS)); - FORCE_RET(); -} - -OP(addf64) -{ - float64 op0 = get_opf64(PARAM2); - float64 op1 = get_opf64(PARAM3); - set_opf64(PARAM1, float64_add(op0, op1, &CPU_FP_STATUS)); - FORCE_RET(); -} - -OP(subf64) -{ - float64 op0 = get_opf64(PARAM2); - float64 op1 = get_opf64(PARAM3); - set_opf64(PARAM1, float64_sub(op0, op1, &CPU_FP_STATUS)); - FORCE_RET(); -} - -OP(mulf64) -{ - float64 op0 = get_opf64(PARAM2); - float64 op1 = get_opf64(PARAM3); - set_opf64(PARAM1, float64_mul(op0, op1, &CPU_FP_STATUS)); - FORCE_RET(); -} - -OP(divf64) -{ - float64 op0 = get_opf64(PARAM2); - float64 op1 = get_opf64(PARAM3); - set_opf64(PARAM1, float64_div(op0, op1, &CPU_FP_STATUS)); - FORCE_RET(); -} - -OP(iround_f64) -{ - float64 op0 = get_opf64(PARAM2); - set_opf64(PARAM1, float64_round_to_int(op0, &CPU_FP_STATUS)); - FORCE_RET(); -} - -OP(itrunc_f64) -{ - float64 op0 = get_opf64(PARAM2); - set_opf64(PARAM1, float64_trunc_to_int(op0, &CPU_FP_STATUS)); - FORCE_RET(); -} - -OP(compare_quietf64) -{ - float64 op0 = get_opf64(PARAM2); - float64 op1 = get_opf64(PARAM3); - set_op(PARAM1, float64_compare_quiet(op0, op1, &CPU_FP_STATUS)); - FORCE_RET(); -} - -OP(movec) -{ - int op1 = get_op(PARAM1); - uint32_t op2 = get_op(PARAM2); - helper_movec(env, op1, op2); -} - -/* Memory access. */ - -#define MEMSUFFIX _raw -#include "op_mem.h" - -#if !defined(CONFIG_USER_ONLY) -#define MEMSUFFIX _user -#include "op_mem.h" -#define MEMSUFFIX _kernel -#include "op_mem.h" -#endif - -/* MAC unit. */ -/* TODO: The MAC instructions use 64-bit arithmetic fairly extensively. - This results in fairly large ops (and sometimes other issues) on 32-bit - hosts. Maybe move most of them into helpers. */ -OP(macmuls) -{ - uint32_t op1 = get_op(PARAM1); - uint32_t op2 = get_op(PARAM2); - int64_t product; - int64_t res; - - product = (uint64_t)op1 * op2; - res = (product << 24) >> 24; - if (res != product) { - env->macsr |= MACSR_V; - if (env->macsr & MACSR_OMC) { - /* Make sure the accumulate operation overflows. */ - if (product < 0) - res = ~(1ll << 50); - else - res = 1ll << 50; - } - } - env->mactmp = res; - FORCE_RET(); -} - -OP(macmulu) -{ - uint32_t op1 = get_op(PARAM1); - uint32_t op2 = get_op(PARAM2); - uint64_t product; - - product = (uint64_t)op1 * op2; - if (product & (0xffffffull << 40)) { - env->macsr |= MACSR_V; - if (env->macsr & MACSR_OMC) { - /* Make sure the accumulate operation overflows. */ - product = 1ll << 50; - } else { - product &= ((1ull << 40) - 1); - } - } - env->mactmp = product; - FORCE_RET(); -} - -OP(macmulf) -{ - int32_t op1 = get_op(PARAM1); - int32_t op2 = get_op(PARAM2); - uint64_t product; - uint32_t remainder; - - product = (uint64_t)op1 * op2; - if (env->macsr & MACSR_RT) { - remainder = product & 0xffffff; - product >>= 24; - if (remainder > 0x800000) - product++; - else if (remainder == 0x800000) - product += (product & 1); - } else { - product >>= 24; - } - env->mactmp = product; - FORCE_RET(); -} - -OP(macshl) -{ - env->mactmp <<= 1; -} - -OP(macshr) -{ - env->mactmp >>= 1; -} - -OP(macadd) -{ - int acc = PARAM1; - env->macc[acc] += env->mactmp; - FORCE_RET(); -} - -OP(macsub) -{ - int acc = PARAM1; - env->macc[acc] -= env->mactmp; - FORCE_RET(); -} - -OP(macsats) -{ - int acc = PARAM1; - int64_t sum; - int64_t result; - - sum = env->macc[acc]; - result = (sum << 16) >> 16; - if (result != sum) { - env->macsr |= MACSR_V; - } - if (env->macsr & MACSR_V) { - env->macsr |= MACSR_PAV0 << acc; - if (env->macsr & MACSR_OMC) { - /* The result is saturated to 32 bits, despite overflow occuring - at 48 bits. Seems weird, but that's what the hardware docs - say. */ - result = (result >> 63) ^ 0x7fffffff; - } - } - env->macc[acc] = result; - FORCE_RET(); -} - -OP(macsatu) -{ - int acc = PARAM1; - uint64_t sum; - - sum = env->macc[acc]; - if (sum & (0xffffull << 48)) { - env->macsr |= MACSR_V; - } - if (env->macsr & MACSR_V) { - env->macsr |= MACSR_PAV0 << acc; - if (env->macsr & MACSR_OMC) { - if (sum > (1ull << 53)) - sum = 0; - else - sum = (1ull << 48) - 1; - } else { - sum &= ((1ull << 48) - 1); - } - } - FORCE_RET(); -} - -OP(macsatf) -{ - int acc = PARAM1; - int64_t sum; - int64_t result; - - sum = env->macc[acc]; - result = (sum << 16) >> 16; - if (result != sum) { - env->macsr |= MACSR_V; - } - if (env->macsr & MACSR_V) { - env->macsr |= MACSR_PAV0 << acc; - if (env->macsr & MACSR_OMC) { - result = (result >> 63) ^ 0x7fffffffffffll; - } - } - env->macc[acc] = result; - FORCE_RET(); -} - -OP(mac_clear_flags) -{ - env->macsr &= ~(MACSR_V | MACSR_Z | MACSR_N | MACSR_EV); -} - -OP(mac_set_flags) -{ - int acc = PARAM1; - uint64_t val; - val = env->macc[acc]; - if (val == 0) - env->macsr |= MACSR_Z; - else if (val & (1ull << 47)); - env->macsr |= MACSR_N; - if (env->macsr & (MACSR_PAV0 << acc)) { - env->macsr |= MACSR_V; - } - if (env->macsr & MACSR_FI) { - val = ((int64_t)val) >> 40; - if (val != 0 && val != -1) - env->macsr |= MACSR_EV; - } else if (env->macsr & MACSR_SU) { - val = ((int64_t)val) >> 32; - if (val != 0 && val != -1) - env->macsr |= MACSR_EV; - } else { - if ((val >> 32) != 0) - env->macsr |= MACSR_EV; - } - FORCE_RET(); -} - -OP(get_macf) -{ - int acc = PARAM2; - int64_t val; - int rem; - uint32_t result; - - val = env->macc[acc]; - if (env->macsr & MACSR_SU) { - /* 16-bit rounding. */ - rem = val & 0xffffff; - val = (val >> 24) & 0xffffu; - if (rem > 0x800000) - val++; - else if (rem == 0x800000) - val += (val & 1); - } else if (env->macsr & MACSR_RT) { - /* 32-bit rounding. */ - rem = val & 0xff; - val >>= 8; - if (rem > 0x80) - val++; - else if (rem == 0x80) - val += (val & 1); - } else { - /* No rounding. */ - val >>= 8; - } - if (env->macsr & MACSR_OMC) { - /* Saturate. */ - if (env->macsr & MACSR_SU) { - if (val != (uint16_t) val) { - result = ((val >> 63) ^ 0x7fff) & 0xffff; - } else { - result = val & 0xffff; - } - } else { - if (val != (uint32_t)val) { - result = ((uint32_t)(val >> 63) & 0x7fffffff); - } else { - result = (uint32_t)val; - } - } - } else { - /* No saturation. */ - if (env->macsr & MACSR_SU) { - result = val & 0xffff; - } else { - result = (uint32_t)val; - } - } - set_op(PARAM1, result); - FORCE_RET(); -} - -OP(get_maci) -{ - int acc = PARAM2; - set_op(PARAM1, (uint32_t)env->macc[acc]); - FORCE_RET(); -} - -OP(get_macs) -{ - int acc = PARAM2; - int64_t val = env->macc[acc]; - uint32_t result; - if (val == (int32_t)val) { - result = (int32_t)val; - } else { - result = (val >> 61) ^ 0x7fffffff; - } - set_op(PARAM1, result); - FORCE_RET(); -} - -OP(get_macu) -{ - int acc = PARAM2; - uint64_t val = env->macc[acc]; - uint32_t result; - if ((val >> 32) == 0) { - result = (uint32_t)val; - } else { - result = 0xffffffffu; - } - set_op(PARAM1, result); - FORCE_RET(); -} - -OP(clear_mac) -{ - int acc = PARAM1; - - env->macc[acc] = 0; - env->macsr &= ~(MACSR_PAV0 << acc); - FORCE_RET(); -} - -OP(move_mac) -{ - int dest = PARAM1; - int src = PARAM2; - uint32_t mask; - env->macc[dest] = env->macc[src]; - mask = MACSR_PAV0 << dest; - if (env->macsr & (MACSR_PAV0 << src)) - env->macsr |= mask; - else - env->macsr &= ~mask; - FORCE_RET(); -} - -OP(get_mac_extf) -{ - uint32_t val; - int acc = PARAM2; - val = env->macc[acc] & 0x00ff; - val = (env->macc[acc] >> 32) & 0xff00; - val |= (env->macc[acc + 1] << 16) & 0x00ff0000; - val |= (env->macc[acc + 1] >> 16) & 0xff000000; - set_op(PARAM1, val); - FORCE_RET(); -} - -OP(get_mac_exti) -{ - uint32_t val; - int acc = PARAM2; - val = (env->macc[acc] >> 32) & 0xffff; - val |= (env->macc[acc + 1] >> 16) & 0xffff0000; - set_op(PARAM1, val); - FORCE_RET(); -} - -OP(set_macf) -{ - int acc = PARAM2; - int32_t val = get_op(PARAM1); - env->macc[acc] = ((int64_t)val) << 8; - env->macsr &= ~(MACSR_PAV0 << acc); - FORCE_RET(); -} - -OP(set_macs) -{ - int acc = PARAM2; - int32_t val = get_op(PARAM1); - env->macc[acc] = val; - env->macsr &= ~(MACSR_PAV0 << acc); - FORCE_RET(); -} - -OP(set_macu) -{ - int acc = PARAM2; - uint32_t val = get_op(PARAM1); - env->macc[acc] = val; - env->macsr &= ~(MACSR_PAV0 << acc); - FORCE_RET(); -} - -OP(set_mac_extf) -{ - int acc = PARAM2; - int32_t val = get_op(PARAM1); - int64_t res; - int32_t tmp; - res = env->macc[acc] & 0xffffffff00ull; - tmp = (int16_t)(val & 0xff00); - res |= ((int64_t)tmp) << 32; - res |= val & 0xff; - env->macc[acc] = res; - res = env->macc[acc + 1] & 0xffffffff00ull; - tmp = (val & 0xff000000); - res |= ((int64_t)tmp) << 16; - res |= (val >> 16) & 0xff; - env->macc[acc + 1] = res; -} - -OP(set_mac_exts) -{ - int acc = PARAM2; - int32_t val = get_op(PARAM1); - int64_t res; - int32_t tmp; - res = (uint32_t)env->macc[acc]; - tmp = (int16_t)val; - res |= ((int64_t)tmp) << 32; - env->macc[acc] = res; - res = (uint32_t)env->macc[acc + 1]; - tmp = val & 0xffff0000; - res |= (int64_t)tmp << 16; - env->macc[acc + 1] = res; -} - -OP(set_mac_extu) -{ - int acc = PARAM2; - int32_t val = get_op(PARAM1); - uint64_t res; - res = (uint32_t)env->macc[acc]; - res |= ((uint64_t)(val & 0xffff)) << 32; - env->macc[acc] = res; - res = (uint32_t)env->macc[acc + 1]; - res |= (uint64_t)(val & 0xffff0000) << 16; - env->macc[acc + 1] = res; -} - -OP(set_macsr) -{ - m68k_set_macsr(env, get_op(PARAM1)); -} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-m68k/op-hacks.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-m68k/op-hacks.h --- qemu-0.9.1/target-m68k/op-hacks.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-m68k/op-hacks.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,130 +0,0 @@ -/* Various hacks to make code written for a dynamic code generator work - with regular QEMU. */ - -static int free_qreg; - -#define QMODE_I32 1 -#define QMODE_F32 1 -#define QMODE_F64 2 - -static inline int gen_new_qreg(int mode) -{ - int qreg; - - qreg = free_qreg; - free_qreg += mode; - if (free_qreg > MAX_QREGS) { - fprintf(stderr, "qreg overflow\n"); - abort(); - } - return qreg + TARGET_NUM_QREGS; -} - -static inline int gen_im32(uint32_t i) -{ - int qreg = gen_new_qreg(QMODE_I32); - gen_op_mov32_im(qreg, i); - return qreg; -} - -static inline void gen_op_ldf32_raw(int dest, int addr) -{ - gen_op_ld32_raw(dest, addr); -} - -static inline void gen_op_stf32_raw(int addr, int dest) -{ - gen_op_st32_raw(addr, dest); -} - -#if !defined(CONFIG_USER_ONLY) -static inline void gen_op_ldf32_user(int dest, int addr) -{ - gen_op_ld32_user(dest, addr); -} - -static inline void gen_op_stf32_user(int addr, int dest) -{ - gen_op_st32_user(addr, dest); -} - -static inline void gen_op_ldf32_kernel(int dest, int addr) -{ - gen_op_ld32_kernel(dest, addr); -} - -static inline void gen_op_stf32_kernel(int addr, int dest) -{ - gen_op_st32_kernel(addr, dest); -} -#endif - -static inline void gen_op_pack_32_f32(int dest, int src) -{ - gen_op_mov32(dest, src); -} - -static inline void gen_op_pack_f32_32(int dest, int src) -{ - gen_op_mov32(dest, src); -} - -static inline void gen_op_flags_set(void) -{ - /* Dummy op. */ -} - -static inline void gen_op_shl_im_cc(int val, int shift) -{ - gen_op_shl_cc(val, gen_im32(shift)); -} - -static inline void gen_op_shr_im_cc(int val, int shift) -{ - gen_op_shr_cc(val, gen_im32(shift)); -} - -static inline void gen_op_sar_im_cc(int val, int shift) -{ - gen_op_sar_cc(val, gen_im32(shift)); -} - -#ifdef USE_DIRECT_JUMP -#define TBPARAM(x) -#else -#define TBPARAM(x) (long)(x) -#endif - -static inline void gen_op_goto_tb(int dummy, int n, long tb) -{ - if (n == 0) { - gen_op_goto_tb0(TBPARAM(tb)); - } else { - gen_op_goto_tb1(TBPARAM(tb)); - } -} - -static inline void gen_op_jmp_z32(int val, int label) -{ - gen_op_set_T0_z32(val); - gen_op_jmp_T0(label); -} - -static inline void gen_op_jmp_nz32(int val, int label) -{ - gen_op_set_T0_nz32(val); - gen_op_jmp_T0(label); -} - -static inline void gen_op_jmp_s32(int val, int label) -{ - gen_op_set_T0_s32(val); - gen_op_jmp_T0(label); -} - -static inline void gen_op_jmp_ns32(int val, int label) -{ - gen_op_set_T0_ns32(val); - gen_op_jmp_T0(label); -} - diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-m68k/op_helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-m68k/op_helper.c --- qemu-0.9.1/target-m68k/op_helper.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-m68k/op_helper.c 2008-07-03 18:57:36.000000000 +0100 @@ -18,6 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "exec.h" +#include "helpers.h" #if defined(CONFIG_USER_ONLY) @@ -31,11 +32,6 @@ extern int semihosting_enabled; #define MMUSUFFIX _mmu -#ifdef __s390__ -# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) -#else -# define GETPC() (__builtin_return_address(0)) -#endif #define SHIFT 0 #include "softmmu_template.h" @@ -65,7 +61,7 @@ saved_env = env; env = cpu_single_env; ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); - if (__builtin_expect(ret, 0)) { + if (unlikely(ret)) { if (retaddr) { /* now we have a real cpu fault */ pc = (unsigned long)retaddr; @@ -161,3 +157,71 @@ } #endif + +static void raise_exception(int tt) +{ + env->exception_index = tt; + cpu_loop_exit(); +} + +void HELPER(raise_exception)(uint32_t tt) +{ + raise_exception(tt); +} + +void HELPER(divu)(CPUState *env, uint32_t word) +{ + uint32_t num; + uint32_t den; + uint32_t quot; + uint32_t rem; + uint32_t flags; + + num = env->div1; + den = env->div2; + /* ??? This needs to make sure the throwing location is accurate. */ + if (den == 0) + raise_exception(EXCP_DIV0); + quot = num / den; + rem = num % den; + flags = 0; + /* Avoid using a PARAM1 of zero. This breaks dyngen because it uses + the address of a symbol, and gcc knows symbols can't have address + zero. */ + if (word && quot > 0xffff) + flags |= CCF_V; + if (quot == 0) + flags |= CCF_Z; + else if ((int32_t)quot < 0) + flags |= CCF_N; + env->div1 = quot; + env->div2 = rem; + env->cc_dest = flags; +} + +void HELPER(divs)(CPUState *env, uint32_t word) +{ + int32_t num; + int32_t den; + int32_t quot; + int32_t rem; + int32_t flags; + + num = env->div1; + den = env->div2; + if (den == 0) + raise_exception(EXCP_DIV0); + quot = num / den; + rem = num % den; + flags = 0; + if (word && quot != (int16_t)quot) + flags |= CCF_V; + if (quot == 0) + flags |= CCF_Z; + else if (quot < 0) + flags |= CCF_N; + env->div1 = quot; + env->div2 = rem; + env->cc_dest = flags; +} + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-m68k/op_mem.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-m68k/op_mem.h --- qemu-0.9.1/target-m68k/op_mem.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-m68k/op_mem.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,46 +0,0 @@ -/* Load/store ops. */ -#define MEM_LD_OP(name,suffix) \ -OP(glue(glue(ld,name),MEMSUFFIX)) \ -{ \ - uint32_t addr = get_op(PARAM2); \ - set_op(PARAM1, glue(glue(ld,suffix),MEMSUFFIX)(addr)); \ - FORCE_RET(); \ -} - -MEM_LD_OP(8u32,ub) -MEM_LD_OP(8s32,sb) -MEM_LD_OP(16u32,uw) -MEM_LD_OP(16s32,sw) -MEM_LD_OP(32,l) - -#undef MEM_LD_OP - -#define MEM_ST_OP(name,suffix) \ -OP(glue(glue(st,name),MEMSUFFIX)) \ -{ \ - uint32_t addr = get_op(PARAM1); \ - glue(glue(st,suffix),MEMSUFFIX)(addr, get_op(PARAM2)); \ - FORCE_RET(); \ -} - -MEM_ST_OP(8,b) -MEM_ST_OP(16,w) -MEM_ST_OP(32,l) - -#undef MEM_ST_OP - -OP(glue(ldf64,MEMSUFFIX)) -{ - uint32_t addr = get_op(PARAM2); - set_opf64(PARAM1, glue(ldfq,MEMSUFFIX)(addr)); - FORCE_RET(); -} - -OP(glue(stf64,MEMSUFFIX)) -{ - uint32_t addr = get_op(PARAM1); - glue(stfq,MEMSUFFIX)(addr, get_opf64(PARAM2)); - FORCE_RET(); -} - -#undef MEMSUFFIX diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-m68k/qregs.def /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-m68k/qregs.def --- qemu-0.9.1/target-m68k/qregs.def 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-m68k/qregs.def 2008-05-24 23:29:16.000000000 +0100 @@ -1,37 +1,13 @@ -DEFO32(D0, dregs[0]) -DEFO32(D1, dregs[1]) -DEFO32(D2, dregs[2]) -DEFO32(D3, dregs[3]) -DEFO32(D4, dregs[4]) -DEFO32(D5, dregs[5]) -DEFO32(D6, dregs[6]) -DEFO32(D7, dregs[7]) -DEFO32(A0, aregs[0]) -DEFO32(A1, aregs[1]) -DEFO32(A2, aregs[2]) -DEFO32(A3, aregs[3]) -DEFO32(A4, aregs[4]) -DEFO32(A5, aregs[5]) -DEFO32(A6, aregs[6]) -DEFO32(SP, aregs[7]) /* A7 */ -DEFF64(F0, fregs[0]) -DEFF64(F1, fregs[1]) -DEFF64(F2, fregs[2]) -DEFF64(F3, fregs[3]) -DEFF64(F4, fregs[4]) -DEFF64(F5, fregs[5]) -DEFF64(F6, fregs[6]) -DEFF64(F7, fregs[7]) DEFF64(FP_RESULT, fp_result) DEFO32(PC, pc) DEFO32(SR, sr) DEFO32(CC_OP, cc_op) -DEFR(T0, AREG1, QMODE_I32) DEFO32(CC_DEST, cc_dest) DEFO32(CC_SRC, cc_src) DEFO32(CC_X, cc_x) DEFO32(DIV1, div1) DEFO32(DIV2, div2) DEFO32(EXCEPTION, exception_index) +DEFO32(HALTED, halted) DEFO32(MACSR, macsr) DEFO32(MAC_MASK, mac_mask) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-m68k/translate.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-m68k/translate.c --- qemu-0.9.1/target-m68k/translate.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-m68k/translate.c 2008-10-05 12:47:55.000000000 +0100 @@ -23,15 +23,105 @@ #include #include #include +#include #include "config.h" #include "cpu.h" #include "exec-all.h" #include "disas.h" -#include "m68k-qreg.h" +#include "tcg-op.h" +#include "qemu-log.h" + +#define GEN_HELPER 1 +#include "helpers.h" //#define DEBUG_DISPATCH 1 +/* Fake floating point. */ +#define TCG_TYPE_F32 TCG_TYPE_I32 +#define TCG_TYPE_F64 TCG_TYPE_I64 +#define tcg_gen_mov_f64 tcg_gen_mov_i64 +#define tcg_gen_qemu_ldf32 tcg_gen_qemu_ld32u +#define tcg_gen_qemu_ldf64 tcg_gen_qemu_ld64 +#define tcg_gen_qemu_stf32 tcg_gen_qemu_st32 +#define tcg_gen_qemu_stf64 tcg_gen_qemu_st64 +#define gen_helper_pack_32_f32 tcg_gen_mov_i32 +#define gen_helper_pack_f32_32 tcg_gen_mov_i32 + +#define DEFO32(name, offset) static TCGv QREG_##name; +#define DEFO64(name, offset) static TCGv QREG_##name; +#define DEFF64(name, offset) static TCGv QREG_##name; +#include "qregs.def" +#undef DEFO32 +#undef DEFO64 +#undef DEFF64 + +static TCGv cpu_env; + +static char cpu_reg_names[3*8*3 + 5*4]; +static TCGv cpu_dregs[8]; +static TCGv cpu_aregs[8]; +static TCGv cpu_fregs[8]; +static TCGv cpu_macc[4]; + +#define DREG(insn, pos) cpu_dregs[((insn) >> (pos)) & 7] +#define AREG(insn, pos) cpu_aregs[((insn) >> (pos)) & 7] +#define FREG(insn, pos) cpu_fregs[((insn) >> (pos)) & 7] +#define MACREG(acc) cpu_macc[acc] +#define QREG_SP cpu_aregs[7] + +static TCGv NULL_QREG; +#define IS_NULL_QREG(t) (GET_TCGV(t) == GET_TCGV(NULL_QREG)) +/* Used to distinguish stores from bad addressing modes. */ +static TCGv store_dummy; + +#include "gen-icount.h" + +void m68k_tcg_init(void) +{ + char *p; + int i; + +#define DEFO32(name, offset) QREG_##name = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, offsetof(CPUState, offset), #name); +#define DEFO64(name, offset) QREG_##name = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, offsetof(CPUState, offset), #name); +#define DEFF64(name, offset) DEFO64(name, offset) +#include "qregs.def" +#undef DEFO32 +#undef DEFO64 +#undef DEFF64 + + cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env"); + + p = cpu_reg_names; + for (i = 0; i < 8; i++) { + sprintf(p, "D%d", i); + cpu_dregs[i] = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUM68KState, dregs[i]), p); + p += 3; + sprintf(p, "A%d", i); + cpu_aregs[i] = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUM68KState, aregs[i]), p); + p += 3; + sprintf(p, "F%d", i); + cpu_fregs[i] = tcg_global_mem_new(TCG_TYPE_F64, TCG_AREG0, + offsetof(CPUM68KState, fregs[i]), p); + p += 3; + } + for (i = 0; i < 4; i++) { + sprintf(p, "ACC%d", i); + cpu_macc[i] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, + offsetof(CPUM68KState, macc[i]), p); + p += 5; + } + + NULL_QREG = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, -4, "NULL"); + store_dummy = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, -8, "NULL"); + +#define DEF_HELPER(name, ret, args) \ + tcg_register_helper(HELPER(name), #name); +#include "helpers.h" +} + static inline void qemu_assert(int cond, const char *msg) { if (!cond) { @@ -52,6 +142,7 @@ struct TranslationBlock *tb; int singlestep_enabled; int is_mem; + TCGv mactmp; } DisasContext; #define DISAS_JUMP_NEXT 4 @@ -67,50 +158,12 @@ static void *gen_throws_exception; #define gen_last_qop NULL -static uint16_t *gen_opc_ptr; -static uint32_t *gen_opparam_ptr; -extern FILE *logfile; -extern int loglevel; - -enum { -#define DEF(s, n, copy_size) INDEX_op_ ## s, -#include "opc.h" -#undef DEF - NB_OPS, -}; - -#include "gen-op.h" - -#if defined(CONFIG_USER_ONLY) -#define gen_st(s, name, addr, val) gen_op_st##name##_raw(addr, val) -#define gen_ld(s, name, val, addr) gen_op_ld##name##_raw(val, addr) -#else -#define gen_st(s, name, addr, val) do { \ - if (IS_USER(s)) \ - gen_op_st##name##_user(addr, val); \ - else \ - gen_op_st##name##_kernel(addr, val); \ - } while (0) -#define gen_ld(s, name, val, addr) do { \ - if (IS_USER(s)) \ - gen_op_ld##name##_user(val, addr); \ - else \ - gen_op_ld##name##_kernel(val, addr); \ - } while (0) -#endif - -#include "op-hacks.h" - #define OS_BYTE 0 #define OS_WORD 1 #define OS_LONG 2 #define OS_SINGLE 4 #define OS_DOUBLE 5 -#define DREG(insn, pos) (((insn >> pos) & 7) + QREG_D0) -#define AREG(insn, pos) (((insn >> pos) & 7) + QREG_A0) -#define FREG(insn, pos) (((insn >> pos) & 7) + QREG_F0) - typedef void (*disas_proc)(DisasContext *, uint16_t); #ifdef DEBUG_DISPATCH @@ -125,38 +178,51 @@ static void disas_##name (DisasContext *s, uint16_t insn) #endif +/* FIXME: Remove this. */ +#define gen_im32(val) tcg_const_i32(val) + +#define QMODE_I32 TCG_TYPE_I32 +#define QMODE_I64 TCG_TYPE_I64 +#define QMODE_F32 TCG_TYPE_F32 +#define QMODE_F64 TCG_TYPE_F64 +static inline TCGv gen_new_qreg(int mode) +{ + return tcg_temp_new(mode); +} + /* Generate a load from the specified address. Narrow values are sign extended to full register width. */ -static inline int gen_load(DisasContext * s, int opsize, int addr, int sign) +static inline TCGv gen_load(DisasContext * s, int opsize, TCGv addr, int sign) { - int tmp; + TCGv tmp; + int index = IS_USER(s); s->is_mem = 1; switch(opsize) { case OS_BYTE: tmp = gen_new_qreg(QMODE_I32); if (sign) - gen_ld(s, 8s32, tmp, addr); + tcg_gen_qemu_ld8s(tmp, addr, index); else - gen_ld(s, 8u32, tmp, addr); + tcg_gen_qemu_ld8u(tmp, addr, index); break; case OS_WORD: tmp = gen_new_qreg(QMODE_I32); if (sign) - gen_ld(s, 16s32, tmp, addr); + tcg_gen_qemu_ld16s(tmp, addr, index); else - gen_ld(s, 16u32, tmp, addr); + tcg_gen_qemu_ld16u(tmp, addr, index); break; case OS_LONG: tmp = gen_new_qreg(QMODE_I32); - gen_ld(s, 32, tmp, addr); + tcg_gen_qemu_ld32u(tmp, addr, index); break; case OS_SINGLE: tmp = gen_new_qreg(QMODE_F32); - gen_ld(s, f32, tmp, addr); + tcg_gen_qemu_ldf32(tmp, addr, index); break; case OS_DOUBLE: tmp = gen_new_qreg(QMODE_F64); - gen_ld(s, f64, tmp, addr); + tcg_gen_qemu_ldf64(tmp, addr, index); break; default: qemu_assert(0, "bad load size"); @@ -166,24 +232,25 @@ } /* Generate a store. */ -static inline void gen_store(DisasContext *s, int opsize, int addr, int val) +static inline void gen_store(DisasContext *s, int opsize, TCGv addr, TCGv val) { + int index = IS_USER(s); s->is_mem = 1; switch(opsize) { case OS_BYTE: - gen_st(s, 8, addr, val); + tcg_gen_qemu_st8(val, addr, index); break; case OS_WORD: - gen_st(s, 16, addr, val); + tcg_gen_qemu_st16(val, addr, index); break; case OS_LONG: - gen_st(s, 32, addr, val); + tcg_gen_qemu_st32(val, addr, index); break; case OS_SINGLE: - gen_st(s, f32, addr, val); + tcg_gen_qemu_stf32(val, addr, index); break; case OS_DOUBLE: - gen_st(s, f64, addr, val); + tcg_gen_qemu_stf64(val, addr, index); break; default: qemu_assert(0, "bad store size"); @@ -191,15 +258,22 @@ gen_throws_exception = gen_last_qop; } +typedef enum { + EA_STORE, + EA_LOADU, + EA_LOADS +} ea_what; + /* Generate an unsigned load if VAL is 0 a signed load if val is -1, otherwise generate a store. */ -static int gen_ldst(DisasContext *s, int opsize, int addr, int val) +static TCGv gen_ldst(DisasContext *s, int opsize, TCGv addr, TCGv val, + ea_what what) { - if (val > 0) { + if (what == EA_STORE) { gen_store(s, opsize, addr, val); - return 0; + return store_dummy; } else { - return gen_load(s, opsize, addr, val != 0); + return gen_load(s, opsize, addr, what == EA_LOADS); } } @@ -215,32 +289,32 @@ } /* Calculate and address index. */ -static int gen_addr_index(uint16_t ext, int tmp) +static TCGv gen_addr_index(uint16_t ext, TCGv tmp) { - int add; + TCGv add; int scale; add = (ext & 0x8000) ? AREG(ext, 12) : DREG(ext, 12); if ((ext & 0x800) == 0) { - gen_op_ext16s32(tmp, add); + tcg_gen_ext16s_i32(tmp, add); add = tmp; } scale = (ext >> 9) & 3; if (scale != 0) { - gen_op_shl32(tmp, add, gen_im32(scale)); + tcg_gen_shli_i32(tmp, add, scale); add = tmp; } return add; } -/* Handle a base + index + displacement effective addresss. A base of - -1 means pc-relative. */ -static int gen_lea_indexed(DisasContext *s, int opsize, int base) +/* Handle a base + index + displacement effective addresss. + A NULL_QREG base means pc-relative. */ +static TCGv gen_lea_indexed(DisasContext *s, int opsize, TCGv base) { uint32_t offset; uint16_t ext; - int add; - int tmp; + TCGv add; + TCGv tmp; uint32_t bd, od; offset = s->pc; @@ -248,12 +322,12 @@ s->pc += 2; if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX)) - return -1; + return NULL_QREG; if (ext & 0x100) { /* full extension word format */ if (!m68k_feature(s->env, M68K_FEATURE_EXT_FULL)) - return -1; + return NULL_QREG; if ((ext & 0x30) > 0x10) { /* base displacement */ @@ -271,24 +345,24 @@ /* pre-index */ add = gen_addr_index(ext, tmp); } else { - add = QREG_NULL; + add = NULL_QREG; } if ((ext & 0x80) == 0) { /* base not suppressed */ - if (base == -1) { + if (IS_NULL_QREG(base)) { base = gen_im32(offset + bd); bd = 0; } - if (add) { - gen_op_add32(tmp, add, base); + if (!IS_NULL_QREG(add)) { + tcg_gen_add_i32(tmp, add, base); add = tmp; } else { add = base; } } - if (add) { + if (!IS_NULL_QREG(add)) { if (bd != 0) { - gen_op_add32(tmp, add, gen_im32(bd)); + tcg_gen_addi_i32(tmp, add, bd); add = tmp; } } else { @@ -299,7 +373,7 @@ base = gen_load(s, OS_LONG, add, 0); if ((ext & 0x44) == 4) { add = gen_addr_index(ext, tmp); - gen_op_add32(tmp, add, base); + tcg_gen_add_i32(tmp, add, base); add = tmp; } else { add = base; @@ -316,7 +390,7 @@ od = 0; } if (od != 0) { - gen_op_add32(tmp, add, gen_im32(od)); + tcg_gen_addi_i32(tmp, add, od); add = tmp; } } @@ -324,12 +398,12 @@ /* brief extension word format */ tmp = gen_new_qreg(QMODE_I32); add = gen_addr_index(ext, tmp); - if (base != -1) { - gen_op_add32(tmp, add, base); + if (!IS_NULL_QREG(base)) { + tcg_gen_add_i32(tmp, add, base); if ((int8_t)ext) - gen_op_add32(tmp, tmp, gen_im32((int8_t)ext)); + tcg_gen_addi_i32(tmp, tmp, (int8_t)ext); } else { - gen_op_add32(tmp, add, gen_im32(offset + (int8_t)ext)); + tcg_gen_addi_i32(tmp, add, offset + (int8_t)ext); } add = tmp; } @@ -340,7 +414,7 @@ static inline void gen_flush_cc_op(DisasContext *s) { if (s->cc_op != CC_OP_DYNAMIC) - gen_op_mov32(QREG_CC_OP, gen_im32(s->cc_op)); + tcg_gen_movi_i32(QREG_CC_OP, s->cc_op); } /* Evaluate all the CC flags. */ @@ -349,10 +423,22 @@ if (s->cc_op == CC_OP_FLAGS) return; gen_flush_cc_op(s); - gen_op_flush_flags(); + gen_helper_flush_flags(cpu_env, QREG_CC_OP); s->cc_op = CC_OP_FLAGS; } +static void gen_logic_cc(DisasContext *s, TCGv val) +{ + tcg_gen_mov_i32(QREG_CC_DEST, val); + s->cc_op = CC_OP_LOGIC; +} + +static void gen_update_cc_add(TCGv dest, TCGv src) +{ + tcg_gen_mov_i32(QREG_CC_DEST, dest); + tcg_gen_mov_i32(QREG_CC_SRC, src); +} + static inline int opsize_bytes(int opsize) { switch (opsize) { @@ -363,32 +449,33 @@ case OS_DOUBLE: return 8; default: qemu_assert(0, "bad operand size"); + return 0; } } /* Assign value to a register. If the width is less than the register width only the low part of the register is set. */ -static void gen_partset_reg(int opsize, int reg, int val) +static void gen_partset_reg(int opsize, TCGv reg, TCGv val) { - int tmp; + TCGv tmp; switch (opsize) { case OS_BYTE: - gen_op_and32(reg, reg, gen_im32(0xffffff00)); + tcg_gen_andi_i32(reg, reg, 0xffffff00); tmp = gen_new_qreg(QMODE_I32); - gen_op_and32(tmp, val, gen_im32(0xff)); - gen_op_or32(reg, reg, tmp); + tcg_gen_ext8u_i32(tmp, val); + tcg_gen_or_i32(reg, reg, tmp); break; case OS_WORD: - gen_op_and32(reg, reg, gen_im32(0xffff0000)); + tcg_gen_andi_i32(reg, reg, 0xffff0000); tmp = gen_new_qreg(QMODE_I32); - gen_op_and32(tmp, val, gen_im32(0xffff)); - gen_op_or32(reg, reg, tmp); + tcg_gen_ext16u_i32(tmp, val); + tcg_gen_or_i32(reg, reg, tmp); break; case OS_LONG: - gen_op_mov32(reg, val); + tcg_gen_mov_i32(reg, val); break; case OS_SINGLE: - gen_op_pack_32_f32(reg, val); + gen_helper_pack_32_f32(reg, val); break; default: qemu_assert(0, "Bad operand size"); @@ -397,31 +484,31 @@ } /* Sign or zero extend a value. */ -static inline int gen_extend(int val, int opsize, int sign) +static inline TCGv gen_extend(TCGv val, int opsize, int sign) { - int tmp; + TCGv tmp; switch (opsize) { case OS_BYTE: tmp = gen_new_qreg(QMODE_I32); if (sign) - gen_op_ext8s32(tmp, val); + tcg_gen_ext8s_i32(tmp, val); else - gen_op_ext8u32(tmp, val); + tcg_gen_ext8u_i32(tmp, val); break; case OS_WORD: tmp = gen_new_qreg(QMODE_I32); if (sign) - gen_op_ext16s32(tmp, val); + tcg_gen_ext16s_i32(tmp, val); else - gen_op_ext16u32(tmp, val); + tcg_gen_ext16u_i32(tmp, val); break; case OS_LONG: tmp = val; break; case OS_SINGLE: tmp = gen_new_qreg(QMODE_F32); - gen_op_pack_f32_32(tmp, val); + gen_helper_pack_f32_32(tmp, val); break; default: qemu_assert(0, "Bad operand size"); @@ -431,39 +518,37 @@ /* Generate code for an "effective address". Does not adjust the base register for autoincrememnt addressing modes. */ -static int gen_lea(DisasContext *s, uint16_t insn, int opsize) +static TCGv gen_lea(DisasContext *s, uint16_t insn, int opsize) { - int reg; - int tmp; + TCGv reg; + TCGv tmp; uint16_t ext; uint32_t offset; - reg = insn & 7; switch ((insn >> 3) & 7) { case 0: /* Data register direct. */ case 1: /* Address register direct. */ - return -1; + return NULL_QREG; case 2: /* Indirect register */ case 3: /* Indirect postincrement. */ - reg += QREG_A0; - return reg; + return AREG(insn, 0); case 4: /* Indirect predecrememnt. */ - reg += QREG_A0; + reg = AREG(insn, 0); tmp = gen_new_qreg(QMODE_I32); - gen_op_sub32(tmp, reg, gen_im32(opsize_bytes(opsize))); + tcg_gen_subi_i32(tmp, reg, opsize_bytes(opsize)); return tmp; case 5: /* Indirect displacement. */ - reg += QREG_A0; + reg = AREG(insn, 0); tmp = gen_new_qreg(QMODE_I32); ext = lduw_code(s->pc); s->pc += 2; - gen_op_add32(tmp, reg, gen_im32((int16_t)ext)); + tcg_gen_addi_i32(tmp, reg, (int16_t)ext); return tmp; case 6: /* Indirect index + displacement. */ - reg += QREG_A0; + reg = AREG(insn, 0); return gen_lea_indexed(s, opsize, reg); case 7: /* Other */ - switch (reg) { + switch (insn & 7) { case 0: /* Absolute short. */ offset = ldsw_code(s->pc); s->pc += 2; @@ -478,117 +563,116 @@ s->pc += 2; return gen_im32(offset); case 3: /* pc index+displacement. */ - return gen_lea_indexed(s, opsize, -1); + return gen_lea_indexed(s, opsize, NULL_QREG); case 4: /* Immediate. */ default: - return -1; + return NULL_QREG; } } /* Should never happen. */ - return -1; + return NULL_QREG; } /* Helper function for gen_ea. Reuse the computed address between the for read/write operands. */ -static inline int gen_ea_once(DisasContext *s, uint16_t insn, int opsize, - int val, int *addrp) +static inline TCGv gen_ea_once(DisasContext *s, uint16_t insn, int opsize, + TCGv val, TCGv *addrp, ea_what what) { - int tmp; + TCGv tmp; - if (addrp && val > 0) { + if (addrp && what == EA_STORE) { tmp = *addrp; } else { tmp = gen_lea(s, insn, opsize); - if (tmp == -1) - return -1; + if (IS_NULL_QREG(tmp)) + return tmp; if (addrp) *addrp = tmp; } - return gen_ldst(s, opsize, tmp, val); + return gen_ldst(s, opsize, tmp, val, what); } /* Generate code to load/store a value ito/from an EA. If VAL > 0 this is a write otherwise it is a read (0 == sign extend, -1 == zero extend). ADDRP is non-null for readwrite operands. */ -static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val, - int *addrp) +static TCGv gen_ea(DisasContext *s, uint16_t insn, int opsize, TCGv val, + TCGv *addrp, ea_what what) { - int reg; - int result; + TCGv reg; + TCGv result; uint32_t offset; - reg = insn & 7; switch ((insn >> 3) & 7) { case 0: /* Data register direct. */ - reg += QREG_D0; - if (val > 0) { + reg = DREG(insn, 0); + if (what == EA_STORE) { gen_partset_reg(opsize, reg, val); - return 0; + return store_dummy; } else { - return gen_extend(reg, opsize, val); + return gen_extend(reg, opsize, what == EA_LOADS); } case 1: /* Address register direct. */ - reg += QREG_A0; - if (val > 0) { - gen_op_mov32(reg, val); - return 0; + reg = AREG(insn, 0); + if (what == EA_STORE) { + tcg_gen_mov_i32(reg, val); + return store_dummy; } else { - return gen_extend(reg, opsize, val); + return gen_extend(reg, opsize, what == EA_LOADS); } case 2: /* Indirect register */ - reg += QREG_A0; - return gen_ldst(s, opsize, reg, val); + reg = AREG(insn, 0); + return gen_ldst(s, opsize, reg, val, what); case 3: /* Indirect postincrement. */ - reg += QREG_A0; - result = gen_ldst(s, opsize, reg, val); + reg = AREG(insn, 0); + result = gen_ldst(s, opsize, reg, val, what); /* ??? This is not exception safe. The instruction may still fault after this point. */ - if (val > 0 || !addrp) - gen_op_add32(reg, reg, gen_im32(opsize_bytes(opsize))); + if (what == EA_STORE || !addrp) + tcg_gen_addi_i32(reg, reg, opsize_bytes(opsize)); return result; case 4: /* Indirect predecrememnt. */ { - int tmp; - if (addrp && val > 0) { + TCGv tmp; + if (addrp && what == EA_STORE) { tmp = *addrp; } else { tmp = gen_lea(s, insn, opsize); - if (tmp == -1) - return -1; + if (IS_NULL_QREG(tmp)) + return tmp; if (addrp) *addrp = tmp; } - result = gen_ldst(s, opsize, tmp, val); + result = gen_ldst(s, opsize, tmp, val, what); /* ??? This is not exception safe. The instruction may still fault after this point. */ - if (val > 0 || !addrp) { - reg += QREG_A0; - gen_op_mov32(reg, tmp); + if (what == EA_STORE || !addrp) { + reg = AREG(insn, 0); + tcg_gen_mov_i32(reg, tmp); } } return result; case 5: /* Indirect displacement. */ case 6: /* Indirect index + displacement. */ - return gen_ea_once(s, insn, opsize, val, addrp); + return gen_ea_once(s, insn, opsize, val, addrp, what); case 7: /* Other */ - switch (reg) { + switch (insn & 7) { case 0: /* Absolute short. */ case 1: /* Absolute long. */ case 2: /* pc displacement */ case 3: /* pc index+displacement. */ - return gen_ea_once(s, insn, opsize, val, addrp); + return gen_ea_once(s, insn, opsize, val, addrp, what); case 4: /* Immediate. */ /* Sign extend values for consistency. */ switch (opsize) { case OS_BYTE: - if (val) + if (what == EA_LOADS) offset = ldsb_code(s->pc + 1); else offset = ldub_code(s->pc + 1); s->pc += 2; break; case OS_WORD: - if (val) + if (what == EA_LOADS) offset = ldsw_code(s->pc); else offset = lduw_code(s->pc); @@ -600,121 +684,112 @@ default: qemu_assert(0, "Bad immediate operand"); } - return gen_im32(offset); + return tcg_const_i32(offset); default: - return -1; + return NULL_QREG; } } /* Should never happen. */ - return -1; -} - -static void gen_logic_cc(DisasContext *s, int val) -{ - gen_op_logic_cc(val); - s->cc_op = CC_OP_LOGIC; + return NULL_QREG; } +/* This generates a conditional branch, clobbering all temporaries. */ static void gen_jmpcc(DisasContext *s, int cond, int l1) { - int tmp; + TCGv tmp; + /* TODO: Optimize compare/branch pairs rather than always flushing + flag state to CC_OP_FLAGS. */ gen_flush_flags(s); switch (cond) { case 0: /* T */ - gen_op_jmp(l1); + tcg_gen_br(l1); break; case 1: /* F */ break; case 2: /* HI (!C && !Z) */ tmp = gen_new_qreg(QMODE_I32); - gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C | CCF_Z)); - gen_op_jmp_z32(tmp, l1); + tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_C | CCF_Z); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1); break; case 3: /* LS (C || Z) */ tmp = gen_new_qreg(QMODE_I32); - gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C | CCF_Z)); - gen_op_jmp_nz32(tmp, l1); + tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_C | CCF_Z); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1); break; case 4: /* CC (!C) */ tmp = gen_new_qreg(QMODE_I32); - gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C)); - gen_op_jmp_z32(tmp, l1); + tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_C); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1); break; case 5: /* CS (C) */ tmp = gen_new_qreg(QMODE_I32); - gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C)); - gen_op_jmp_nz32(tmp, l1); + tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_C); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1); break; case 6: /* NE (!Z) */ tmp = gen_new_qreg(QMODE_I32); - gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z)); - gen_op_jmp_z32(tmp, l1); + tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_Z); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1); break; case 7: /* EQ (Z) */ tmp = gen_new_qreg(QMODE_I32); - gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z)); - gen_op_jmp_nz32(tmp, l1); + tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_Z); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1); break; case 8: /* VC (!V) */ tmp = gen_new_qreg(QMODE_I32); - gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_V)); - gen_op_jmp_z32(tmp, l1); + tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_V); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1); break; case 9: /* VS (V) */ tmp = gen_new_qreg(QMODE_I32); - gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_V)); - gen_op_jmp_nz32(tmp, l1); + tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_V); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1); break; case 10: /* PL (!N) */ tmp = gen_new_qreg(QMODE_I32); - gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_N)); - gen_op_jmp_z32(tmp, l1); + tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_N); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1); break; case 11: /* MI (N) */ tmp = gen_new_qreg(QMODE_I32); - gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_N)); - gen_op_jmp_nz32(tmp, l1); + tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_N); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1); break; case 12: /* GE (!(N ^ V)) */ tmp = gen_new_qreg(QMODE_I32); - gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2)); - gen_op_xor32(tmp, tmp, QREG_CC_DEST); - gen_op_and32(tmp, tmp, gen_im32(CCF_V)); - gen_op_jmp_z32(tmp, l1); + assert(CCF_V == (CCF_N >> 2)); + tcg_gen_shri_i32(tmp, QREG_CC_DEST, 2); + tcg_gen_xor_i32(tmp, tmp, QREG_CC_DEST); + tcg_gen_andi_i32(tmp, tmp, CCF_V); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1); break; case 13: /* LT (N ^ V) */ tmp = gen_new_qreg(QMODE_I32); - gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2)); - gen_op_xor32(tmp, tmp, QREG_CC_DEST); - gen_op_and32(tmp, tmp, gen_im32(CCF_V)); - gen_op_jmp_nz32(tmp, l1); + assert(CCF_V == (CCF_N >> 2)); + tcg_gen_shri_i32(tmp, QREG_CC_DEST, 2); + tcg_gen_xor_i32(tmp, tmp, QREG_CC_DEST); + tcg_gen_andi_i32(tmp, tmp, CCF_V); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1); break; case 14: /* GT (!(Z || (N ^ V))) */ - { - int l2; - l2 = gen_new_label(); - tmp = gen_new_qreg(QMODE_I32); - gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z)); - gen_op_jmp_nz32(tmp, l2); - tmp = gen_new_qreg(QMODE_I32); - gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2)); - gen_op_xor32(tmp, tmp, QREG_CC_DEST); - gen_op_and32(tmp, tmp, gen_im32(CCF_V)); - gen_op_jmp_nz32(tmp, l2); - gen_op_jmp(l1); - gen_set_label(l2); - } + tmp = gen_new_qreg(QMODE_I32); + assert(CCF_V == (CCF_N >> 2)); + tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_N); + tcg_gen_shri_i32(tmp, tmp, 2); + tcg_gen_xor_i32(tmp, tmp, QREG_CC_DEST); + tcg_gen_andi_i32(tmp, tmp, CCF_V | CCF_Z); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1); break; case 15: /* LE (Z || (N ^ V)) */ tmp = gen_new_qreg(QMODE_I32); - gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z)); - gen_op_jmp_nz32(tmp, l1); - tmp = gen_new_qreg(QMODE_I32); - gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2)); - gen_op_xor32(tmp, tmp, QREG_CC_DEST); - gen_op_and32(tmp, tmp, gen_im32(CCF_V)); - gen_op_jmp_nz32(tmp, l1); + assert(CCF_V == (CCF_N >> 2)); + tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_N); + tcg_gen_shri_i32(tmp, tmp, 2); + tcg_gen_xor_i32(tmp, tmp, QREG_CC_DEST); + tcg_gen_andi_i32(tmp, tmp, CCF_V | CCF_Z); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1); break; default: /* Should ever happen. */ @@ -726,14 +801,16 @@ { int l1; int cond; - int reg; + TCGv reg; l1 = gen_new_label(); cond = (insn >> 8) & 0xf; reg = DREG(insn, 0); - gen_op_and32(reg, reg, gen_im32(0xffffff00)); + tcg_gen_andi_i32(reg, reg, 0xffffff00); + /* This is safe because we modify the reg directly, with no other values + live. */ gen_jmpcc(s, cond ^ 1, l1); - gen_op_or32(reg, reg, gen_im32(0xff)); + tcg_gen_ori_i32(reg, reg, 0xff); gen_set_label(l1); } @@ -741,23 +818,31 @@ static void gen_lookup_tb(DisasContext *s) { gen_flush_cc_op(s); - gen_op_mov32(QREG_PC, gen_im32(s->pc)); + tcg_gen_movi_i32(QREG_PC, s->pc); s->is_jmp = DISAS_UPDATE; } -/* Generate a jump to to the address in qreg DEST. */ -static void gen_jmp(DisasContext *s, int dest) +/* Generate a jump to an immediate address. */ +static void gen_jmp_im(DisasContext *s, uint32_t dest) +{ + gen_flush_cc_op(s); + tcg_gen_movi_i32(QREG_PC, dest); + s->is_jmp = DISAS_JUMP; +} + +/* Generate a jump to the address in qreg DEST. */ +static void gen_jmp(DisasContext *s, TCGv dest) { gen_flush_cc_op(s); - gen_op_mov32(QREG_PC, dest); + tcg_gen_mov_i32(QREG_PC, dest); s->is_jmp = DISAS_JUMP; } static void gen_exception(DisasContext *s, uint32_t where, int nr) { gen_flush_cc_op(s); - gen_jmp(s, gen_im32(where)); - gen_op_raise_exception(nr); + gen_jmp_im(s, where); + gen_helper_raise_exception(tcg_const_i32(nr)); } static inline void gen_addr_fault(DisasContext *s) @@ -765,17 +850,17 @@ gen_exception(s, s->insn_pc, EXCP_ADDRESS); } -#define SRC_EA(result, opsize, val, addrp) do { \ - result = gen_ea(s, insn, opsize, val, addrp); \ - if (result == -1) { \ +#define SRC_EA(result, opsize, op_sign, addrp) do { \ + result = gen_ea(s, insn, opsize, NULL_QREG, addrp, op_sign ? EA_LOADS : EA_LOADU); \ + if (IS_NULL_QREG(result)) { \ gen_addr_fault(s); \ return; \ } \ } while (0) #define DEST_EA(insn, opsize, val, addrp) do { \ - int ea_result = gen_ea(s, insn, opsize, val, addrp); \ - if (ea_result == -1) { \ + TCGv ea_result = gen_ea(s, insn, opsize, val, addrp, EA_STORE); \ + if (IS_NULL_QREG(ea_result)) { \ gen_addr_fault(s); \ return; \ } \ @@ -787,18 +872,16 @@ TranslationBlock *tb; tb = s->tb; - if (__builtin_expect (s->singlestep_enabled, 0)) { + if (unlikely(s->singlestep_enabled)) { gen_exception(s, dest, EXCP_DEBUG); } else if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) || (s->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { - gen_op_goto_tb(0, n, (long)tb); - gen_op_mov32(QREG_PC, gen_im32(dest)); - gen_op_mov32(QREG_T0, gen_im32((long)tb + n)); - gen_op_exit_tb(); - } else { - gen_jmp(s, gen_im32(dest)); - gen_op_mov32(QREG_T0, gen_im32(0)); - gen_op_exit_tb(); + tcg_gen_goto_tb(n); + tcg_gen_movi_i32(QREG_PC, dest); + tcg_gen_exit_tb((long)tb + n); + } else { + gen_jmp_im(s, dest); + tcg_gen_exit_tb(0); } s->is_jmp = DISAS_TB_JUMP; } @@ -822,61 +905,60 @@ DISAS_INSN(mulw) { - int reg; - int tmp; - int src; + TCGv reg; + TCGv tmp; + TCGv src; int sign; sign = (insn & 0x100) != 0; reg = DREG(insn, 9); tmp = gen_new_qreg(QMODE_I32); if (sign) - gen_op_ext16s32(tmp, reg); + tcg_gen_ext16s_i32(tmp, reg); else - gen_op_ext16u32(tmp, reg); - SRC_EA(src, OS_WORD, sign ? -1 : 0, NULL); - gen_op_mul32(tmp, tmp, src); - gen_op_mov32(reg, tmp); + tcg_gen_ext16u_i32(tmp, reg); + SRC_EA(src, OS_WORD, sign, NULL); + tcg_gen_mul_i32(tmp, tmp, src); + tcg_gen_mov_i32(reg, tmp); /* Unlike m68k, coldfire always clears the overflow bit. */ gen_logic_cc(s, tmp); } DISAS_INSN(divw) { - int reg; - int tmp; - int src; + TCGv reg; + TCGv tmp; + TCGv src; int sign; sign = (insn & 0x100) != 0; reg = DREG(insn, 9); if (sign) { - gen_op_ext16s32(QREG_DIV1, reg); + tcg_gen_ext16s_i32(QREG_DIV1, reg); } else { - gen_op_ext16u32(QREG_DIV1, reg); + tcg_gen_ext16u_i32(QREG_DIV1, reg); } - SRC_EA(src, OS_WORD, sign ? -1 : 0, NULL); - gen_op_mov32(QREG_DIV2, src); + SRC_EA(src, OS_WORD, sign, NULL); + tcg_gen_mov_i32(QREG_DIV2, src); if (sign) { - gen_op_divs(1); + gen_helper_divs(cpu_env, tcg_const_i32(1)); } else { - gen_op_divu(1); + gen_helper_divu(cpu_env, tcg_const_i32(1)); } tmp = gen_new_qreg(QMODE_I32); src = gen_new_qreg(QMODE_I32); - gen_op_ext16u32(tmp, QREG_DIV1); - gen_op_shl32(src, QREG_DIV2, gen_im32(16)); - gen_op_or32(reg, tmp, src); - gen_op_flags_set(); + tcg_gen_ext16u_i32(tmp, QREG_DIV1); + tcg_gen_shli_i32(src, QREG_DIV2, 16); + tcg_gen_or_i32(reg, tmp, src); s->cc_op = CC_OP_FLAGS; } DISAS_INSN(divl) { - int num; - int den; - int reg; + TCGv num; + TCGv den; + TCGv reg; uint16_t ext; ext = lduw_code(s->pc); @@ -887,32 +969,31 @@ } num = DREG(ext, 12); reg = DREG(ext, 0); - gen_op_mov32(QREG_DIV1, num); + tcg_gen_mov_i32(QREG_DIV1, num); SRC_EA(den, OS_LONG, 0, NULL); - gen_op_mov32(QREG_DIV2, den); + tcg_gen_mov_i32(QREG_DIV2, den); if (ext & 0x0800) { - gen_op_divs(2); + gen_helper_divs(cpu_env, tcg_const_i32(0)); } else { - gen_op_divu(2); + gen_helper_divu(cpu_env, tcg_const_i32(0)); } - if (num == reg) { + if ((ext & 7) == ((ext >> 12) & 7)) { /* div */ - gen_op_mov32 (reg, QREG_DIV1); + tcg_gen_mov_i32 (reg, QREG_DIV1); } else { /* rem */ - gen_op_mov32 (reg, QREG_DIV2); + tcg_gen_mov_i32 (reg, QREG_DIV2); } - gen_op_flags_set(); s->cc_op = CC_OP_FLAGS; } DISAS_INSN(addsub) { - int reg; - int dest; - int src; - int tmp; - int addr; + TCGv reg; + TCGv dest; + TCGv src; + TCGv tmp; + TCGv addr; int add; add = (insn & 0x4000) != 0; @@ -926,19 +1007,19 @@ SRC_EA(src, OS_LONG, 0, NULL); } if (add) { - gen_op_add32(dest, tmp, src); - gen_op_update_xflag_lt(dest, src); + tcg_gen_add_i32(dest, tmp, src); + gen_helper_xflag_lt(QREG_CC_X, dest, src); s->cc_op = CC_OP_ADD; } else { - gen_op_update_xflag_lt(tmp, src); - gen_op_sub32(dest, tmp, src); + gen_helper_xflag_lt(QREG_CC_X, tmp, src); + tcg_gen_sub_i32(dest, tmp, src); s->cc_op = CC_OP_SUB; } - gen_op_update_cc_add(dest, src); + gen_update_cc_add(dest, src); if (insn & 0x100) { DEST_EA(insn, OS_LONG, dest, &addr); } else { - gen_op_mov32(reg, dest); + tcg_gen_mov_i32(reg, dest); } } @@ -946,48 +1027,20 @@ /* Reverse the order of the bits in REG. */ DISAS_INSN(bitrev) { - int val; - int tmp1; - int tmp2; - int reg; - - val = gen_new_qreg(QMODE_I32); - tmp1 = gen_new_qreg(QMODE_I32); - tmp2 = gen_new_qreg(QMODE_I32); + TCGv reg; reg = DREG(insn, 0); - gen_op_mov32(val, reg); - /* Reverse bits within each nibble. */ - gen_op_shl32(tmp1, val, gen_im32(3)); - gen_op_and32(tmp1, tmp1, gen_im32(0x88888888)); - gen_op_shl32(tmp2, val, gen_im32(1)); - gen_op_and32(tmp2, tmp2, gen_im32(0x44444444)); - gen_op_or32(tmp1, tmp1, tmp2); - gen_op_shr32(tmp2, val, gen_im32(1)); - gen_op_and32(tmp2, tmp2, gen_im32(0x22222222)); - gen_op_or32(tmp1, tmp1, tmp2); - gen_op_shr32(tmp2, val, gen_im32(3)); - gen_op_and32(tmp2, tmp2, gen_im32(0x11111111)); - gen_op_or32(tmp1, tmp1, tmp2); - /* Reverse nibbles withing bytes. */ - gen_op_shl32(val, tmp1, gen_im32(4)); - gen_op_and32(val, val, gen_im32(0xf0f0f0f0)); - gen_op_shr32(tmp2, tmp1, gen_im32(4)); - gen_op_and32(tmp2, tmp2, gen_im32(0x0f0f0f0f)); - gen_op_or32(val, val, tmp2); - /* Reverse bytes. */ - gen_op_bswap32(reg, val); - gen_op_mov32(reg, val); + gen_helper_bitrev(reg, reg); } DISAS_INSN(bitop_reg) { int opsize; int op; - int src1; - int src2; - int tmp; - int addr; - int dest; + TCGv src1; + TCGv src2; + TCGv tmp; + TCGv addr; + TCGv dest; if ((insn & 0x38) != 0) opsize = OS_BYTE; @@ -1001,24 +1054,29 @@ gen_flush_flags(s); tmp = gen_new_qreg(QMODE_I32); if (opsize == OS_BYTE) - gen_op_and32(tmp, src2, gen_im32(7)); + tcg_gen_andi_i32(tmp, src2, 7); else - gen_op_and32(tmp, src2, gen_im32(31)); + tcg_gen_andi_i32(tmp, src2, 31); src2 = tmp; tmp = gen_new_qreg(QMODE_I32); - gen_op_shl32(tmp, gen_im32(1), src2); + tcg_gen_shr_i32(tmp, src1, src2); + tcg_gen_andi_i32(tmp, tmp, 1); + tcg_gen_shli_i32(tmp, tmp, 2); + /* Clear CCF_Z if bit set. */ + tcg_gen_ori_i32(QREG_CC_DEST, QREG_CC_DEST, CCF_Z); + tcg_gen_xor_i32(QREG_CC_DEST, QREG_CC_DEST, tmp); - gen_op_btest(src1, tmp); + tcg_gen_shl_i32(tmp, tcg_const_i32(1), src2); switch (op) { case 1: /* bchg */ - gen_op_xor32(dest, src1, tmp); + tcg_gen_xor_i32(dest, src1, tmp); break; case 2: /* bclr */ - gen_op_not32(tmp, tmp); - gen_op_and32(dest, src1, tmp); + tcg_gen_not_i32(tmp, tmp); + tcg_gen_and_i32(dest, src1, tmp); break; case 3: /* bset */ - gen_op_or32(dest, src1, tmp); + tcg_gen_or_i32(dest, src1, tmp); break; default: /* btst */ break; @@ -1029,52 +1087,41 @@ DISAS_INSN(sats) { - int reg; - int tmp; - int l1; - + TCGv reg; reg = DREG(insn, 0); - tmp = gen_new_qreg(QMODE_I32); gen_flush_flags(s); - gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_V)); - l1 = gen_new_label(); - gen_op_jmp_z32(tmp, l1); - tmp = gen_new_qreg(QMODE_I32); - gen_op_shr32(tmp, reg, gen_im32(31)); - gen_op_xor32(tmp, tmp, gen_im32(0x80000000)); - gen_op_mov32(reg, tmp); - gen_set_label(l1); - gen_logic_cc(s, tmp); + gen_helper_sats(reg, reg, QREG_CC_DEST); + gen_logic_cc(s, reg); } -static void gen_push(DisasContext *s, int val) +static void gen_push(DisasContext *s, TCGv val) { - int tmp; + TCGv tmp; tmp = gen_new_qreg(QMODE_I32); - gen_op_sub32(tmp, QREG_SP, gen_im32(4)); + tcg_gen_subi_i32(tmp, QREG_SP, 4); gen_store(s, OS_LONG, tmp, val); - gen_op_mov32(QREG_SP, tmp); + tcg_gen_mov_i32(QREG_SP, tmp); } DISAS_INSN(movem) { - int addr; + TCGv addr; int i; uint16_t mask; - int reg; - int tmp; + TCGv reg; + TCGv tmp; int is_load; mask = lduw_code(s->pc); s->pc += 2; tmp = gen_lea(s, insn, OS_LONG); - if (tmp == -1) { + if (IS_NULL_QREG(tmp)) { gen_addr_fault(s); return; } addr = gen_new_qreg(QMODE_I32); - gen_op_mov32(addr, tmp); + tcg_gen_mov_i32(addr, tmp); is_load = ((insn & 0x0400) != 0); for (i = 0; i < 16; i++, mask >>= 1) { if (mask & 1) { @@ -1084,12 +1131,12 @@ reg = AREG(i, 0); if (is_load) { tmp = gen_load(s, OS_LONG, addr, 0); - gen_op_mov32(reg, tmp); + tcg_gen_mov_i32(reg, tmp); } else { gen_store(s, OS_LONG, addr, reg); } if (mask != 1) - gen_op_add32(addr, addr, gen_im32(4)); + tcg_gen_addi_i32(addr, addr, 4); } } } @@ -1098,12 +1145,11 @@ { int opsize; int op; - int src1; + TCGv src1; uint32_t mask; int bitnum; - int tmp; - int addr; - int dest; + TCGv tmp; + TCGv addr; if ((insn & 0x38) != 0) opsize = OS_BYTE; @@ -1121,79 +1167,85 @@ SRC_EA(src1, opsize, 0, op ? &addr: NULL); gen_flush_flags(s); - tmp = gen_new_qreg(QMODE_I32); if (opsize == OS_BYTE) bitnum &= 7; else bitnum &= 31; mask = 1 << bitnum; - gen_op_btest(src1, gen_im32(mask)); - if (op) - dest = gen_new_qreg(QMODE_I32); + tmp = gen_new_qreg(QMODE_I32); + assert (CCF_Z == (1 << 2)); + if (bitnum > 2) + tcg_gen_shri_i32(tmp, src1, bitnum - 2); + else if (bitnum < 2) + tcg_gen_shli_i32(tmp, src1, 2 - bitnum); else - dest = -1; - - switch (op) { - case 1: /* bchg */ - gen_op_xor32(dest, src1, gen_im32(mask)); - break; - case 2: /* bclr */ - gen_op_and32(dest, src1, gen_im32(~mask)); - break; - case 3: /* bset */ - gen_op_or32(dest, src1, gen_im32(mask)); - break; - default: /* btst */ - break; + tcg_gen_mov_i32(tmp, src1); + tcg_gen_andi_i32(tmp, tmp, CCF_Z); + /* Clear CCF_Z if bit set. */ + tcg_gen_ori_i32(QREG_CC_DEST, QREG_CC_DEST, CCF_Z); + tcg_gen_xor_i32(QREG_CC_DEST, QREG_CC_DEST, tmp); + if (op) { + switch (op) { + case 1: /* bchg */ + tcg_gen_xori_i32(tmp, src1, mask); + break; + case 2: /* bclr */ + tcg_gen_andi_i32(tmp, src1, ~mask); + break; + case 3: /* bset */ + tcg_gen_ori_i32(tmp, src1, mask); + break; + default: /* btst */ + break; + } + DEST_EA(insn, opsize, tmp, &addr); } - if (op) - DEST_EA(insn, opsize, dest, &addr); } DISAS_INSN(arith_im) { int op; - int src1; - int dest; - int src2; - int addr; + uint32_t im; + TCGv src1; + TCGv dest; + TCGv addr; op = (insn >> 9) & 7; SRC_EA(src1, OS_LONG, 0, (op == 6) ? NULL : &addr); - src2 = gen_im32(read_im32(s)); + im = read_im32(s); dest = gen_new_qreg(QMODE_I32); switch (op) { case 0: /* ori */ - gen_op_or32(dest, src1, src2); + tcg_gen_ori_i32(dest, src1, im); gen_logic_cc(s, dest); break; case 1: /* andi */ - gen_op_and32(dest, src1, src2); + tcg_gen_andi_i32(dest, src1, im); gen_logic_cc(s, dest); break; case 2: /* subi */ - gen_op_mov32(dest, src1); - gen_op_update_xflag_lt(dest, src2); - gen_op_sub32(dest, dest, src2); - gen_op_update_cc_add(dest, src2); + tcg_gen_mov_i32(dest, src1); + gen_helper_xflag_lt(QREG_CC_X, dest, gen_im32(im)); + tcg_gen_subi_i32(dest, dest, im); + gen_update_cc_add(dest, gen_im32(im)); s->cc_op = CC_OP_SUB; break; case 3: /* addi */ - gen_op_mov32(dest, src1); - gen_op_add32(dest, dest, src2); - gen_op_update_cc_add(dest, src2); - gen_op_update_xflag_lt(dest, src2); + tcg_gen_mov_i32(dest, src1); + tcg_gen_addi_i32(dest, dest, im); + gen_update_cc_add(dest, gen_im32(im)); + gen_helper_xflag_lt(QREG_CC_X, dest, gen_im32(im)); s->cc_op = CC_OP_ADD; break; case 5: /* eori */ - gen_op_xor32(dest, src1, src2); + tcg_gen_xori_i32(dest, src1, im); gen_logic_cc(s, dest); break; case 6: /* cmpi */ - gen_op_mov32(dest, src1); - gen_op_sub32(dest, dest, src2); - gen_op_update_cc_add(dest, src2); + tcg_gen_mov_i32(dest, src1); + tcg_gen_subi_i32(dest, dest, im); + gen_update_cc_add(dest, gen_im32(im)); s->cc_op = CC_OP_SUB; break; default: @@ -1206,16 +1258,16 @@ DISAS_INSN(byterev) { - int reg; + TCGv reg; reg = DREG(insn, 0); - gen_op_bswap32(reg, reg); + tcg_gen_bswap_i32(reg, reg); } DISAS_INSN(move) { - int src; - int dest; + TCGv src; + TCGv dest; int op; int opsize; @@ -1232,13 +1284,13 @@ default: abort(); } - SRC_EA(src, opsize, -1, NULL); + SRC_EA(src, opsize, 1, NULL); op = (insn >> 6) & 7; if (op == 1) { /* movea */ /* The value will already have been sign extended. */ dest = AREG(insn, 9); - gen_op_mov32(dest, src); + tcg_gen_mov_i32(dest, src); } else { /* normal move */ uint16_t dest_ea; @@ -1251,39 +1303,25 @@ DISAS_INSN(negx) { - int reg; - int dest; - int tmp; + TCGv reg; gen_flush_flags(s); reg = DREG(insn, 0); - dest = gen_new_qreg(QMODE_I32); - gen_op_mov32 (dest, gen_im32(0)); - gen_op_subx_cc(dest, reg); - /* !Z is sticky. */ - tmp = gen_new_qreg(QMODE_I32); - gen_op_mov32 (tmp, QREG_CC_DEST); - gen_op_update_cc_add(dest, reg); - gen_op_mov32(reg, dest); - s->cc_op = CC_OP_DYNAMIC; - gen_flush_flags(s); - gen_op_or32(tmp, tmp, gen_im32(~CCF_Z)); - gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, tmp); - s->cc_op = CC_OP_FLAGS; + gen_helper_subx_cc(reg, cpu_env, tcg_const_i32(0), reg); } DISAS_INSN(lea) { - int reg; - int tmp; + TCGv reg; + TCGv tmp; reg = AREG(insn, 9); tmp = gen_lea(s, insn, OS_LONG); - if (tmp == -1) { + if (IS_NULL_QREG(tmp)) { gen_addr_fault(s); return; } - gen_op_mov32(reg, tmp); + tcg_gen_mov_i32(reg, tmp); } DISAS_INSN(clr) @@ -1307,22 +1345,21 @@ gen_logic_cc(s, gen_im32(0)); } -static int gen_get_ccr(DisasContext *s) +static TCGv gen_get_ccr(DisasContext *s) { - int dest; + TCGv dest; gen_flush_flags(s); dest = gen_new_qreg(QMODE_I32); - gen_op_get_xflag(dest); - gen_op_shl32(dest, dest, gen_im32(4)); - gen_op_or32(dest, dest, QREG_CC_DEST); + tcg_gen_shli_i32(dest, QREG_CC_X, 4); + tcg_gen_or_i32(dest, dest, QREG_CC_DEST); return dest; } DISAS_INSN(move_from_ccr) { - int reg; - int ccr; + TCGv reg; + TCGv ccr; ccr = gen_get_ccr(s); reg = DREG(insn, 0); @@ -1331,45 +1368,43 @@ DISAS_INSN(neg) { - int reg; - int src1; + TCGv reg; + TCGv src1; reg = DREG(insn, 0); src1 = gen_new_qreg(QMODE_I32); - gen_op_mov32(src1, reg); - gen_op_neg32(reg, src1); + tcg_gen_mov_i32(src1, reg); + tcg_gen_neg_i32(reg, src1); s->cc_op = CC_OP_SUB; - gen_op_update_cc_add(reg, src1); - gen_op_update_xflag_lt(gen_im32(0), src1); + gen_update_cc_add(reg, src1); + gen_helper_xflag_lt(QREG_CC_X, tcg_const_i32(0), src1); s->cc_op = CC_OP_SUB; } static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) { - gen_op_logic_cc(gen_im32(val & 0xf)); - gen_op_update_xflag_tst(gen_im32((val & 0x10) >> 4)); + tcg_gen_movi_i32(QREG_CC_DEST, val & 0xf); + tcg_gen_movi_i32(QREG_CC_X, (val & 0x10) >> 4); if (!ccr_only) { - gen_op_set_sr(gen_im32(val & 0xff00)); + gen_helper_set_sr(cpu_env, tcg_const_i32(val & 0xff00)); } } static void gen_set_sr(DisasContext *s, uint16_t insn, int ccr_only) { - int src1; - int reg; + TCGv tmp; + TCGv reg; s->cc_op = CC_OP_FLAGS; if ((insn & 0x38) == 0) { - src1 = gen_new_qreg(QMODE_I32); + tmp = gen_new_qreg(QMODE_I32); reg = DREG(insn, 0); - gen_op_and32(src1, reg, gen_im32(0xf)); - gen_op_logic_cc(src1); - gen_op_shr32(src1, reg, gen_im32(4)); - gen_op_and32(src1, src1, gen_im32(1)); - gen_op_update_xflag_tst(src1); + tcg_gen_andi_i32(QREG_CC_DEST, reg, 0xf); + tcg_gen_shri_i32(tmp, reg, 4); + tcg_gen_andi_i32(QREG_CC_X, tmp, 1); if (!ccr_only) { - gen_op_set_sr(reg); + gen_helper_set_sr(cpu_env, reg); } } else if ((insn & 0x3f) == 0x3c) @@ -1390,37 +1425,34 @@ DISAS_INSN(not) { - int reg; + TCGv reg; reg = DREG(insn, 0); - gen_op_not32(reg, reg); + tcg_gen_not_i32(reg, reg); gen_logic_cc(s, reg); } DISAS_INSN(swap) { - int dest; - int src1; - int src2; - int reg; + TCGv src1; + TCGv src2; + TCGv reg; - dest = gen_new_qreg(QMODE_I32); src1 = gen_new_qreg(QMODE_I32); src2 = gen_new_qreg(QMODE_I32); reg = DREG(insn, 0); - gen_op_shl32(src1, reg, gen_im32(16)); - gen_op_shr32(src2, reg, gen_im32(16)); - gen_op_or32(dest, src1, src2); - gen_op_mov32(reg, dest); - gen_logic_cc(s, dest); + tcg_gen_shli_i32(src1, reg, 16); + tcg_gen_shri_i32(src2, reg, 16); + tcg_gen_or_i32(reg, src1, src2); + gen_logic_cc(s, reg); } DISAS_INSN(pea) { - int tmp; + TCGv tmp; tmp = gen_lea(s, insn, OS_LONG); - if (tmp == -1) { + if (IS_NULL_QREG(tmp)) { gen_addr_fault(s); return; } @@ -1429,28 +1461,28 @@ DISAS_INSN(ext) { - int reg; int op; - int tmp; + TCGv reg; + TCGv tmp; reg = DREG(insn, 0); op = (insn >> 6) & 7; tmp = gen_new_qreg(QMODE_I32); if (op == 3) - gen_op_ext16s32(tmp, reg); + tcg_gen_ext16s_i32(tmp, reg); else - gen_op_ext8s32(tmp, reg); + tcg_gen_ext8s_i32(tmp, reg); if (op == 2) gen_partset_reg(OS_WORD, reg, tmp); else - gen_op_mov32(reg, tmp); + tcg_gen_mov_i32(reg, tmp); gen_logic_cc(s, tmp); } DISAS_INSN(tst) { int opsize; - int tmp; + TCGv tmp; switch ((insn >> 6) & 3) { case 0: /* tst.b */ @@ -1465,7 +1497,7 @@ default: abort(); } - SRC_EA(tmp, opsize, -1, NULL); + SRC_EA(tmp, opsize, 1, NULL); gen_logic_cc(s, tmp); } @@ -1482,23 +1514,23 @@ /* ??? This should be atomic. */ DISAS_INSN(tas) { - int dest; - int src1; - int addr; + TCGv dest; + TCGv src1; + TCGv addr; dest = gen_new_qreg(QMODE_I32); - SRC_EA(src1, OS_BYTE, -1, &addr); + SRC_EA(src1, OS_BYTE, 1, &addr); gen_logic_cc(s, src1); - gen_op_or32(dest, src1, gen_im32(0x80)); + tcg_gen_ori_i32(dest, src1, 0x80); DEST_EA(insn, OS_BYTE, dest, &addr); } DISAS_INSN(mull) { uint16_t ext; - int reg; - int src1; - int dest; + TCGv reg; + TCGv src1; + TCGv dest; /* The upper 32 bits of the product are discarded, so muls.l and mulu.l are functionally equivalent. */ @@ -1511,8 +1543,8 @@ reg = DREG(ext, 12); SRC_EA(src1, OS_LONG, 0, NULL); dest = gen_new_qreg(QMODE_I32); - gen_op_mul32(dest, src1, reg); - gen_op_mov32(reg, dest); + tcg_gen_mul_i32(dest, src1, reg); + tcg_gen_mov_i32(reg, dest); /* Unlike m68k, coldfire always clears the overflow bit. */ gen_logic_cc(s, dest); } @@ -1520,32 +1552,32 @@ DISAS_INSN(link) { int16_t offset; - int reg; - int tmp; + TCGv reg; + TCGv tmp; offset = ldsw_code(s->pc); s->pc += 2; reg = AREG(insn, 0); tmp = gen_new_qreg(QMODE_I32); - gen_op_sub32(tmp, QREG_SP, gen_im32(4)); + tcg_gen_subi_i32(tmp, QREG_SP, 4); gen_store(s, OS_LONG, tmp, reg); - if (reg != QREG_SP) - gen_op_mov32(reg, tmp); - gen_op_add32(QREG_SP, tmp, gen_im32(offset)); + if ((insn & 7) != 7) + tcg_gen_mov_i32(reg, tmp); + tcg_gen_addi_i32(QREG_SP, tmp, offset); } DISAS_INSN(unlk) { - int src; - int reg; - int tmp; + TCGv src; + TCGv reg; + TCGv tmp; src = gen_new_qreg(QMODE_I32); reg = AREG(insn, 0); - gen_op_mov32(src, reg); + tcg_gen_mov_i32(src, reg); tmp = gen_load(s, OS_LONG, src, 0); - gen_op_mov32(reg, tmp); - gen_op_add32(QREG_SP, src, gen_im32(4)); + tcg_gen_mov_i32(reg, tmp); + tcg_gen_addi_i32(QREG_SP, src, 4); } DISAS_INSN(nop) @@ -1554,21 +1586,21 @@ DISAS_INSN(rts) { - int tmp; + TCGv tmp; tmp = gen_load(s, OS_LONG, QREG_SP, 0); - gen_op_add32(QREG_SP, QREG_SP, gen_im32(4)); + tcg_gen_addi_i32(QREG_SP, QREG_SP, 4); gen_jmp(s, tmp); } DISAS_INSN(jump) { - int tmp; + TCGv tmp; /* Load the target address first to ensure correct exception behavior. */ tmp = gen_lea(s, insn, OS_LONG); - if (tmp == -1) { + if (IS_NULL_QREG(tmp)) { gen_addr_fault(s); return; } @@ -1581,38 +1613,38 @@ DISAS_INSN(addsubq) { - int src1; - int src2; - int dest; + TCGv src1; + TCGv src2; + TCGv dest; int val; - int addr; + TCGv addr; SRC_EA(src1, OS_LONG, 0, &addr); val = (insn >> 9) & 7; if (val == 0) val = 8; - src2 = gen_im32(val); dest = gen_new_qreg(QMODE_I32); - gen_op_mov32(dest, src1); + tcg_gen_mov_i32(dest, src1); if ((insn & 0x38) == 0x08) { /* Don't update condition codes if the destination is an address register. */ if (insn & 0x0100) { - gen_op_sub32(dest, dest, src2); + tcg_gen_subi_i32(dest, dest, val); } else { - gen_op_add32(dest, dest, src2); + tcg_gen_addi_i32(dest, dest, val); } } else { + src2 = gen_im32(val); if (insn & 0x0100) { - gen_op_update_xflag_lt(dest, src2); - gen_op_sub32(dest, dest, src2); + gen_helper_xflag_lt(QREG_CC_X, dest, src2); + tcg_gen_subi_i32(dest, dest, val); s->cc_op = CC_OP_SUB; } else { - gen_op_add32(dest, dest, src2); - gen_op_update_xflag_lt(dest, src2); + tcg_gen_addi_i32(dest, dest, val); + gen_helper_xflag_lt(QREG_CC_X, dest, src2); s->cc_op = CC_OP_ADD; } - gen_op_update_cc_add(dest, src2); + gen_update_cc_add(dest, src2); } DEST_EA(insn, OS_LONG, dest, &addr); } @@ -1669,88 +1701,74 @@ DISAS_INSN(moveq) { - int tmp; + uint32_t val; - tmp = gen_im32((int8_t)insn); - gen_op_mov32(DREG(insn, 9), tmp); - gen_logic_cc(s, tmp); + val = (int8_t)insn; + tcg_gen_movi_i32(DREG(insn, 9), val); + gen_logic_cc(s, tcg_const_i32(val)); } DISAS_INSN(mvzs) { int opsize; - int src; - int reg; + TCGv src; + TCGv reg; if (insn & 0x40) opsize = OS_WORD; else opsize = OS_BYTE; - SRC_EA(src, opsize, (insn & 0x80) ? 0 : -1, NULL); + SRC_EA(src, opsize, (insn & 0x80) == 0, NULL); reg = DREG(insn, 9); - gen_op_mov32(reg, src); + tcg_gen_mov_i32(reg, src); gen_logic_cc(s, src); } DISAS_INSN(or) { - int reg; - int dest; - int src; - int addr; + TCGv reg; + TCGv dest; + TCGv src; + TCGv addr; reg = DREG(insn, 9); dest = gen_new_qreg(QMODE_I32); if (insn & 0x100) { SRC_EA(src, OS_LONG, 0, &addr); - gen_op_or32(dest, src, reg); + tcg_gen_or_i32(dest, src, reg); DEST_EA(insn, OS_LONG, dest, &addr); } else { SRC_EA(src, OS_LONG, 0, NULL); - gen_op_or32(dest, src, reg); - gen_op_mov32(reg, dest); + tcg_gen_or_i32(dest, src, reg); + tcg_gen_mov_i32(reg, dest); } gen_logic_cc(s, dest); } DISAS_INSN(suba) { - int src; - int reg; + TCGv src; + TCGv reg; SRC_EA(src, OS_LONG, 0, NULL); reg = AREG(insn, 9); - gen_op_sub32(reg, reg, src); + tcg_gen_sub_i32(reg, reg, src); } DISAS_INSN(subx) { - int reg; - int src; - int dest; - int tmp; + TCGv reg; + TCGv src; gen_flush_flags(s); reg = DREG(insn, 9); src = DREG(insn, 0); - dest = gen_new_qreg(QMODE_I32); - gen_op_mov32 (dest, reg); - gen_op_subx_cc(dest, src); - /* !Z is sticky. */ - tmp = gen_new_qreg(QMODE_I32); - gen_op_mov32 (tmp, QREG_CC_DEST); - gen_op_update_cc_add(dest, src); - gen_op_mov32(reg, dest); - s->cc_op = CC_OP_DYNAMIC; - gen_flush_flags(s); - gen_op_or32(tmp, tmp, gen_im32(~CCF_Z)); - gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, tmp); - s->cc_op = CC_OP_FLAGS; + gen_helper_subx_cc(reg, cpu_env, reg, src); } DISAS_INSN(mov3q) { - int src; + TCGv src; int val; val = (insn >> 9) & 7; @@ -1764,9 +1782,9 @@ DISAS_INSN(cmp) { int op; - int src; - int reg; - int dest; + TCGv src; + TCGv reg; + TCGv dest; int opsize; op = (insn >> 6) & 3; @@ -1786,168 +1804,154 @@ default: abort(); } - SRC_EA(src, opsize, -1, NULL); + SRC_EA(src, opsize, 1, NULL); reg = DREG(insn, 9); dest = gen_new_qreg(QMODE_I32); - gen_op_sub32(dest, reg, src); - gen_op_update_cc_add(dest, src); + tcg_gen_sub_i32(dest, reg, src); + gen_update_cc_add(dest, src); } DISAS_INSN(cmpa) { int opsize; - int src; - int reg; - int dest; + TCGv src; + TCGv reg; + TCGv dest; if (insn & 0x100) { opsize = OS_LONG; } else { opsize = OS_WORD; } - SRC_EA(src, opsize, -1, NULL); + SRC_EA(src, opsize, 1, NULL); reg = AREG(insn, 9); dest = gen_new_qreg(QMODE_I32); - gen_op_sub32(dest, reg, src); - gen_op_update_cc_add(dest, src); + tcg_gen_sub_i32(dest, reg, src); + gen_update_cc_add(dest, src); s->cc_op = CC_OP_SUB; } DISAS_INSN(eor) { - int src; - int reg; - int dest; - int addr; + TCGv src; + TCGv reg; + TCGv dest; + TCGv addr; SRC_EA(src, OS_LONG, 0, &addr); reg = DREG(insn, 9); dest = gen_new_qreg(QMODE_I32); - gen_op_xor32(dest, src, reg); + tcg_gen_xor_i32(dest, src, reg); gen_logic_cc(s, dest); DEST_EA(insn, OS_LONG, dest, &addr); } DISAS_INSN(and) { - int src; - int reg; - int dest; - int addr; + TCGv src; + TCGv reg; + TCGv dest; + TCGv addr; reg = DREG(insn, 9); dest = gen_new_qreg(QMODE_I32); if (insn & 0x100) { SRC_EA(src, OS_LONG, 0, &addr); - gen_op_and32(dest, src, reg); + tcg_gen_and_i32(dest, src, reg); DEST_EA(insn, OS_LONG, dest, &addr); } else { SRC_EA(src, OS_LONG, 0, NULL); - gen_op_and32(dest, src, reg); - gen_op_mov32(reg, dest); + tcg_gen_and_i32(dest, src, reg); + tcg_gen_mov_i32(reg, dest); } gen_logic_cc(s, dest); } DISAS_INSN(adda) { - int src; - int reg; + TCGv src; + TCGv reg; SRC_EA(src, OS_LONG, 0, NULL); reg = AREG(insn, 9); - gen_op_add32(reg, reg, src); + tcg_gen_add_i32(reg, reg, src); } DISAS_INSN(addx) { - int reg; - int src; - int dest; - int tmp; + TCGv reg; + TCGv src; gen_flush_flags(s); reg = DREG(insn, 9); src = DREG(insn, 0); - dest = gen_new_qreg(QMODE_I32); - gen_op_mov32 (dest, reg); - gen_op_addx_cc(dest, src); - /* !Z is sticky. */ - tmp = gen_new_qreg(QMODE_I32); - gen_op_mov32 (tmp, QREG_CC_DEST); - gen_op_update_cc_add(dest, src); - gen_op_mov32(reg, dest); - s->cc_op = CC_OP_DYNAMIC; - gen_flush_flags(s); - gen_op_or32(tmp, tmp, gen_im32(~CCF_Z)); - gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, tmp); + gen_helper_addx_cc(reg, cpu_env, reg, src); s->cc_op = CC_OP_FLAGS; } +/* TODO: This could be implemented without helper functions. */ DISAS_INSN(shift_im) { - int reg; + TCGv reg; int tmp; + TCGv shift; reg = DREG(insn, 0); tmp = (insn >> 9) & 7; if (tmp == 0) - tmp = 8; + tmp = 8; + shift = gen_im32(tmp); + /* No need to flush flags becuse we know we will set C flag. */ if (insn & 0x100) { - gen_op_shl_im_cc(reg, tmp); - s->cc_op = CC_OP_SHL; + gen_helper_shl_cc(reg, cpu_env, reg, shift); } else { if (insn & 8) { - gen_op_shr_im_cc(reg, tmp); - s->cc_op = CC_OP_SHR; + gen_helper_shr_cc(reg, cpu_env, reg, shift); } else { - gen_op_sar_im_cc(reg, tmp); - s->cc_op = CC_OP_SAR; + gen_helper_sar_cc(reg, cpu_env, reg, shift); } } + s->cc_op = CC_OP_SHIFT; } DISAS_INSN(shift_reg) { - int reg; - int src; - int tmp; + TCGv reg; + TCGv shift; reg = DREG(insn, 0); - src = DREG(insn, 9); - tmp = gen_new_qreg(QMODE_I32); - gen_op_and32(tmp, src, gen_im32(63)); + shift = DREG(insn, 9); + /* Shift by zero leaves C flag unmodified. */ + gen_flush_flags(s); if (insn & 0x100) { - gen_op_shl_cc(reg, tmp); - s->cc_op = CC_OP_SHL; + gen_helper_shl_cc(reg, cpu_env, reg, shift); } else { if (insn & 8) { - gen_op_shr_cc(reg, tmp); - s->cc_op = CC_OP_SHR; + gen_helper_shr_cc(reg, cpu_env, reg, shift); } else { - gen_op_sar_cc(reg, tmp); - s->cc_op = CC_OP_SAR; + gen_helper_sar_cc(reg, cpu_env, reg, shift); } } + s->cc_op = CC_OP_SHIFT; } DISAS_INSN(ff1) { - int reg; + TCGv reg; reg = DREG(insn, 0); gen_logic_cc(s, reg); - gen_op_ff1(reg, reg); + gen_helper_ff1(reg, reg); } -static int gen_get_sr(DisasContext *s) +static TCGv gen_get_sr(DisasContext *s) { - int ccr; - int sr; + TCGv ccr; + TCGv sr; ccr = gen_get_ccr(s); sr = gen_new_qreg(QMODE_I32); - gen_op_and32(sr, QREG_SR, gen_im32(0xffe0)); - gen_op_or32(sr, sr, ccr); + tcg_gen_andi_i32(sr, QREG_SR, 0xffe0); + tcg_gen_or_i32(sr, sr, ccr); return sr; } @@ -1975,8 +1979,8 @@ DISAS_INSN(move_from_sr) { - int reg; - int sr; + TCGv reg; + TCGv sr; if (IS_USER(s)) { gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); @@ -2019,8 +2023,7 @@ DISAS_INSN(halt) { - gen_jmp(s, gen_im32(s->pc)); - gen_op_halt(); + gen_exception(s, s->pc, EXCP_HALT_INSN); } DISAS_INSN(stop) @@ -2036,8 +2039,8 @@ s->pc += 2; gen_set_sr_im(s, ext, 0); - gen_jmp(s, gen_im32(s->pc)); - gen_op_stop(); + tcg_gen_movi_i32(QREG_HALTED, 1); + gen_exception(s, s->pc, EXCP_HLT); } DISAS_INSN(rte) @@ -2052,7 +2055,7 @@ DISAS_INSN(movec) { uint16_t ext; - int reg; + TCGv reg; if (IS_USER(s)) { gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); @@ -2067,7 +2070,7 @@ } else { reg = DREG(ext, 12); } - gen_op_movec(gen_im32(ext & 0xfff), reg); + gen_helper_movec(cpu_env, tcg_const_i32(ext & 0xfff), reg); gen_lookup_tb(s); } @@ -2115,9 +2118,9 @@ { uint16_t ext; int opmode; - int src; - int dest; - int res; + TCGv src; + TCGv dest; + TCGv res; int round; int opsize; @@ -2137,17 +2140,17 @@ case 0: opsize = OS_LONG; res = gen_new_qreg(QMODE_I32); - gen_op_f64_to_i32(res, src); + gen_helper_f64_to_i32(res, cpu_env, src); break; case 1: opsize = OS_SINGLE; res = gen_new_qreg(QMODE_F32); - gen_op_f64_to_f32(res, src); + gen_helper_f64_to_f32(res, cpu_env, src); break; case 4: opsize = OS_WORD; res = gen_new_qreg(QMODE_I32); - gen_op_f64_to_i32(res, src); + gen_helper_f64_to_i32(res, cpu_env, src); break; case 5: opsize = OS_DOUBLE; @@ -2156,7 +2159,7 @@ case 6: opsize = OS_BYTE; res = gen_new_qreg(QMODE_I32); - gen_op_f64_to_i32(res, src); + gen_helper_f64_to_i32(res, cpu_env, src); break; default: goto undef; @@ -2193,40 +2196,40 @@ case 6: /* fmovem */ case 7: { - int addr; - uint16_t mask; - if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0) - goto undef; - src = gen_lea(s, insn, OS_LONG); - if (src == -1) { - gen_addr_fault(s); - return; - } - addr = gen_new_qreg(QMODE_I32); - gen_op_mov32(addr, src); - mask = 0x80; - dest = QREG_F0; - while (mask) { - if (ext & mask) { - s->is_mem = 1; - if (ext & (1 << 13)) { - /* store */ - gen_st(s, f64, addr, dest); - } else { - /* load */ - gen_ld(s, f64, dest, addr); + TCGv addr; + uint16_t mask; + int i; + if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0) + goto undef; + src = gen_lea(s, insn, OS_LONG); + if (IS_NULL_QREG(src)) { + gen_addr_fault(s); + return; + } + addr = gen_new_qreg(QMODE_I32); + tcg_gen_mov_i32(addr, src); + mask = 0x80; + for (i = 0; i < 8; i++) { + if (ext & mask) { + s->is_mem = 1; + dest = FREG(i, 0); + if (ext & (1 << 13)) { + /* store */ + tcg_gen_qemu_stf64(dest, addr, IS_USER(s)); + } else { + /* load */ + tcg_gen_qemu_ldf64(dest, addr, IS_USER(s)); + } + if (ext & (mask - 1)) + tcg_gen_addi_i32(addr, addr, 8); } - if (ext & (mask - 1)) - gen_op_add32(addr, addr, gen_im32(8)); + mask >>= 1; } - mask >>= 1; - dest++; - } } return; } if (ext & (1 << 14)) { - int tmp; + TCGv tmp; /* Source effective address. */ switch ((ext >> 10) & 7) { @@ -2238,7 +2241,7 @@ default: goto undef; } - SRC_EA(tmp, opsize, -1, NULL); + SRC_EA(tmp, opsize, 1, NULL); if (opsize == OS_DOUBLE) { src = tmp; } else { @@ -2247,10 +2250,10 @@ case OS_LONG: case OS_WORD: case OS_BYTE: - gen_op_i32_to_f64(src, tmp); + gen_helper_i32_to_f64(src, cpu_env, tmp); break; case OS_SINGLE: - gen_op_f32_to_f64(src, tmp); + gen_helper_f32_to_f64(src, cpu_env, tmp); break; } } @@ -2261,49 +2264,49 @@ dest = FREG(ext, 7); res = gen_new_qreg(QMODE_F64); if (opmode != 0x3a) - gen_op_movf64(res, dest); + tcg_gen_mov_f64(res, dest); round = 1; switch (opmode) { case 0: case 0x40: case 0x44: /* fmove */ - gen_op_movf64(res, src); + tcg_gen_mov_f64(res, src); break; case 1: /* fint */ - gen_op_iround_f64(res, src); + gen_helper_iround_f64(res, cpu_env, src); round = 0; break; case 3: /* fintrz */ - gen_op_itrunc_f64(res, src); + gen_helper_itrunc_f64(res, cpu_env, src); round = 0; break; case 4: case 0x41: case 0x45: /* fsqrt */ - gen_op_sqrtf64(res, src); + gen_helper_sqrt_f64(res, cpu_env, src); break; case 0x18: case 0x58: case 0x5c: /* fabs */ - gen_op_absf64(res, src); + gen_helper_abs_f64(res, src); break; case 0x1a: case 0x5a: case 0x5e: /* fneg */ - gen_op_chsf64(res, src); + gen_helper_chs_f64(res, src); break; case 0x20: case 0x60: case 0x64: /* fdiv */ - gen_op_divf64(res, res, src); + gen_helper_div_f64(res, cpu_env, res, src); break; case 0x22: case 0x62: case 0x66: /* fadd */ - gen_op_addf64(res, res, src); + gen_helper_add_f64(res, cpu_env, res, src); break; case 0x23: case 0x63: case 0x67: /* fmul */ - gen_op_mulf64(res, res, src); + gen_helper_mul_f64(res, cpu_env, res, src); break; case 0x28: case 0x68: case 0x6c: /* fsub */ - gen_op_subf64(res, res, src); + gen_helper_sub_f64(res, cpu_env, res, src); break; case 0x38: /* fcmp */ - gen_op_sub_cmpf64(res, res, src); - dest = 0; + gen_helper_sub_cmp_f64(res, cpu_env, res, src); + dest = NULL_QREG; round = 0; break; case 0x3a: /* ftst */ - gen_op_movf64(res, src); - dest = 0; + tcg_gen_mov_f64(res, src); + dest = NULL_QREG; round = 0; break; default: @@ -2318,15 +2321,15 @@ } } if (round) { - int tmp; + TCGv tmp; tmp = gen_new_qreg(QMODE_F32); - gen_op_f64_to_f32(tmp, res); - gen_op_f32_to_f64(res, tmp); + gen_helper_f64_to_f32(tmp, cpu_env, res); + gen_helper_f32_to_f64(res, cpu_env, tmp); } - gen_op_fp_result(res); - if (dest) { - gen_op_movf64(dest, res); + tcg_gen_mov_f64(QREG_FP_RESULT, res); + if (!IS_NULL_QREG(dest)) { + tcg_gen_mov_f64(dest, res); } return; undef: @@ -2338,8 +2341,7 @@ { uint32_t offset; uint32_t addr; - int flag; - int zero; + TCGv flag; int l1; addr = s->pc; @@ -2353,72 +2355,57 @@ l1 = gen_new_label(); /* TODO: Raise BSUN exception. */ flag = gen_new_qreg(QMODE_I32); - zero = gen_new_qreg(QMODE_F64); - gen_op_zerof64(zero); - gen_op_compare_quietf64(flag, QREG_FP_RESULT, zero); + gen_helper_compare_f64(flag, cpu_env, QREG_FP_RESULT); /* Jump to l1 if condition is true. */ switch (insn & 0xf) { case 0: /* f */ break; case 1: /* eq (=0) */ - gen_op_jmp_z32(flag, l1); + tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(0), l1); break; case 2: /* ogt (=1) */ - gen_op_sub32(flag, flag, gen_im32(1)); - gen_op_jmp_z32(flag, l1); + tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(1), l1); break; case 3: /* oge (=0 or =1) */ - gen_op_jmp_z32(flag, l1); - gen_op_sub32(flag, flag, gen_im32(1)); - gen_op_jmp_z32(flag, l1); + tcg_gen_brcond_i32(TCG_COND_LEU, flag, tcg_const_i32(1), l1); break; case 4: /* olt (=-1) */ - gen_op_jmp_s32(flag, l1); + tcg_gen_brcond_i32(TCG_COND_LT, flag, tcg_const_i32(0), l1); break; case 5: /* ole (=-1 or =0) */ - gen_op_jmp_s32(flag, l1); - gen_op_jmp_z32(flag, l1); + tcg_gen_brcond_i32(TCG_COND_LE, flag, tcg_const_i32(0), l1); break; case 6: /* ogl (=-1 or =1) */ - gen_op_jmp_s32(flag, l1); - gen_op_sub32(flag, flag, gen_im32(1)); - gen_op_jmp_z32(flag, l1); + tcg_gen_andi_i32(flag, flag, 1); + tcg_gen_brcond_i32(TCG_COND_NE, flag, tcg_const_i32(0), l1); break; case 7: /* or (=2) */ - gen_op_sub32(flag, flag, gen_im32(2)); - gen_op_jmp_z32(flag, l1); + tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(2), l1); break; case 8: /* un (<2) */ - gen_op_sub32(flag, flag, gen_im32(2)); - gen_op_jmp_s32(flag, l1); + tcg_gen_brcond_i32(TCG_COND_LT, flag, tcg_const_i32(2), l1); break; case 9: /* ueq (=0 or =2) */ - gen_op_jmp_z32(flag, l1); - gen_op_sub32(flag, flag, gen_im32(2)); - gen_op_jmp_z32(flag, l1); + tcg_gen_andi_i32(flag, flag, 1); + tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(0), l1); break; case 10: /* ugt (>0) */ - /* ??? Add jmp_gtu. */ - gen_op_sub32(flag, flag, gen_im32(1)); - gen_op_jmp_ns32(flag, l1); + tcg_gen_brcond_i32(TCG_COND_GT, flag, tcg_const_i32(0), l1); break; case 11: /* uge (>=0) */ - gen_op_jmp_ns32(flag, l1); + tcg_gen_brcond_i32(TCG_COND_GE, flag, tcg_const_i32(0), l1); break; case 12: /* ult (=-1 or =2) */ - gen_op_jmp_s32(flag, l1); - gen_op_sub32(flag, flag, gen_im32(2)); - gen_op_jmp_z32(flag, l1); + tcg_gen_brcond_i32(TCG_COND_GEU, flag, tcg_const_i32(2), l1); break; case 13: /* ule (!=1) */ - gen_op_sub32(flag, flag, gen_im32(1)); - gen_op_jmp_nz32(flag, l1); + tcg_gen_brcond_i32(TCG_COND_NE, flag, tcg_const_i32(1), l1); break; case 14: /* ne (!=0) */ - gen_op_jmp_nz32(flag, l1); + tcg_gen_brcond_i32(TCG_COND_NE, flag, tcg_const_i32(0), l1); break; case 15: /* t */ - gen_op_mov32(flag, gen_im32(1)); + tcg_gen_br(l1); break; } gen_jmp_tb(s, 0, s->pc); @@ -2438,40 +2425,48 @@ qemu_assert(0, "FSAVE not implemented"); } -static inline int gen_mac_extract_word(DisasContext *s, int val, int upper) +static inline TCGv gen_mac_extract_word(DisasContext *s, TCGv val, int upper) { - int tmp = gen_new_qreg(QMODE_I32); + TCGv tmp = gen_new_qreg(QMODE_I32); if (s->env->macsr & MACSR_FI) { if (upper) - gen_op_and32(tmp, val, gen_im32(0xffff0000)); + tcg_gen_andi_i32(tmp, val, 0xffff0000); else - gen_op_shl32(tmp, val, gen_im32(16)); + tcg_gen_shli_i32(tmp, val, 16); } else if (s->env->macsr & MACSR_SU) { if (upper) - gen_op_sar32(tmp, val, gen_im32(16)); + tcg_gen_sari_i32(tmp, val, 16); else - gen_op_ext16s32(tmp, val); + tcg_gen_ext16s_i32(tmp, val); } else { if (upper) - gen_op_shr32(tmp, val, gen_im32(16)); + tcg_gen_shri_i32(tmp, val, 16); else - gen_op_ext16u32(tmp, val); + tcg_gen_ext16u_i32(tmp, val); } return tmp; } +static void gen_mac_clear_flags(void) +{ + tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, + ~(MACSR_V | MACSR_Z | MACSR_N | MACSR_EV)); +} + DISAS_INSN(mac) { - int rx; - int ry; + TCGv rx; + TCGv ry; uint16_t ext; int acc; - int l1; - int tmp; - int addr; - int loadval; + TCGv tmp; + TCGv addr; + TCGv loadval; int dual; - int saved_flags = -1; + TCGv saved_flags; + + if (IS_NULL_QREG(s->mactmp)) + s->mactmp = tcg_temp_new(TCG_TYPE_I64); ext = lduw_code(s->pc); s->pc += 2; @@ -2486,7 +2481,7 @@ /* MAC with load. */ tmp = gen_lea(s, insn, OS_LONG); addr = gen_new_qreg(QMODE_I32); - gen_op_and32(addr, tmp, QREG_MAC_MASK); + tcg_gen_and_i32(addr, tmp, QREG_MAC_MASK); /* Load the value now to ensure correct exception behavior. Perform writeback after reading the MAC inputs. */ loadval = gen_load(s, OS_LONG, addr, 0); @@ -2495,20 +2490,23 @@ rx = (ext & 0x8000) ? AREG(ext, 12) : DREG(insn, 12); ry = (ext & 8) ? AREG(ext, 0) : DREG(ext, 0); } else { - loadval = addr = -1; + loadval = addr = NULL_QREG; rx = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9); ry = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); } - gen_op_mac_clear_flags(); + gen_mac_clear_flags(); +#if 0 l1 = -1; + /* Disabled because conditional branches clobber temporary vars. */ if ((s->env->macsr & MACSR_OMC) != 0 && !dual) { /* Skip the multiply if we know we will ignore it. */ l1 = gen_new_label(); tmp = gen_new_qreg(QMODE_I32); - gen_op_and32(tmp, QREG_MACSR, gen_im32(1 << (acc + 8))); + tcg_gen_andi_i32(tmp, QREG_MACSR, 1 << (acc + 8)); gen_op_jmp_nz32(tmp, l1); } +#endif if ((ext & 0x0800) == 0) { /* Word. */ @@ -2516,18 +2514,18 @@ ry = gen_mac_extract_word(s, ry, (ext & 0x40) != 0); } if (s->env->macsr & MACSR_FI) { - gen_op_macmulf(rx, ry); + gen_helper_macmulf(s->mactmp, cpu_env, rx, ry); } else { if (s->env->macsr & MACSR_SU) - gen_op_macmuls(rx, ry); + gen_helper_macmuls(s->mactmp, cpu_env, rx, ry); else - gen_op_macmulu(rx, ry); + gen_helper_macmulu(s->mactmp, cpu_env, rx, ry); switch ((ext >> 9) & 3) { case 1: - gen_op_macshl(); + tcg_gen_shli_i64(s->mactmp, s->mactmp, 1); break; case 3: - gen_op_macshr(); + tcg_gen_shri_i64(s->mactmp, s->mactmp, 1); break; } } @@ -2535,9 +2533,13 @@ if (dual) { /* Save the overflow flag from the multiply. */ saved_flags = gen_new_qreg(QMODE_I32); - gen_op_mov32(saved_flags, QREG_MACSR); + tcg_gen_mov_i32(saved_flags, QREG_MACSR); + } else { + saved_flags = NULL_QREG; } +#if 0 + /* Disabled because conditional branches clobber temporary vars. */ if ((s->env->macsr & MACSR_OMC) != 0 && dual) { /* Skip the accumulate if the value is already saturated. */ l1 = gen_new_label(); @@ -2545,27 +2547,33 @@ gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc)); gen_op_jmp_nz32(tmp, l1); } +#endif if (insn & 0x100) - gen_op_macsub(acc); + tcg_gen_sub_i64(MACREG(acc), MACREG(acc), s->mactmp); else - gen_op_macadd(acc); + tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp); if (s->env->macsr & MACSR_FI) - gen_op_macsatf(acc); + gen_helper_macsatf(cpu_env, tcg_const_i32(acc)); else if (s->env->macsr & MACSR_SU) - gen_op_macsats(acc); + gen_helper_macsats(cpu_env, tcg_const_i32(acc)); else - gen_op_macsatu(acc); + gen_helper_macsatu(cpu_env, tcg_const_i32(acc)); +#if 0 + /* Disabled because conditional branches clobber temporary vars. */ if (l1 != -1) gen_set_label(l1); +#endif if (dual) { /* Dual accumulate variant. */ acc = (ext >> 2) & 3; /* Restore the overflow flag from the multiplier. */ - gen_op_mov32(QREG_MACSR, saved_flags); + tcg_gen_mov_i32(QREG_MACSR, saved_flags); +#if 0 + /* Disabled because conditional branches clobber temporary vars. */ if ((s->env->macsr & MACSR_OMC) != 0) { /* Skip the accumulate if the value is already saturated. */ l1 = gen_new_label(); @@ -2573,146 +2581,159 @@ gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc)); gen_op_jmp_nz32(tmp, l1); } +#endif if (ext & 2) - gen_op_macsub(acc); + tcg_gen_sub_i64(MACREG(acc), MACREG(acc), s->mactmp); else - gen_op_macadd(acc); + tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp); if (s->env->macsr & MACSR_FI) - gen_op_macsatf(acc); + gen_helper_macsatf(cpu_env, tcg_const_i32(acc)); else if (s->env->macsr & MACSR_SU) - gen_op_macsats(acc); + gen_helper_macsats(cpu_env, tcg_const_i32(acc)); else - gen_op_macsatu(acc); + gen_helper_macsatu(cpu_env, tcg_const_i32(acc)); +#if 0 + /* Disabled because conditional branches clobber temporary vars. */ if (l1 != -1) gen_set_label(l1); +#endif } - gen_op_mac_set_flags(acc); + gen_helper_mac_set_flags(cpu_env, tcg_const_i32(acc)); if (insn & 0x30) { - int rw; + TCGv rw; rw = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9); - gen_op_mov32(rw, loadval); + tcg_gen_mov_i32(rw, loadval); /* FIXME: Should address writeback happen with the masked or unmasked value? */ switch ((insn >> 3) & 7) { case 3: /* Post-increment. */ - gen_op_add32(AREG(insn, 0), addr, gen_im32(4)); + tcg_gen_addi_i32(AREG(insn, 0), addr, 4); break; case 4: /* Pre-decrement. */ - gen_op_mov32(AREG(insn, 0), addr); + tcg_gen_mov_i32(AREG(insn, 0), addr); } } } DISAS_INSN(from_mac) { - int rx; - int acc; + TCGv rx; + TCGv acc; + int accnum; rx = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); - acc = (insn >> 9) & 3; + accnum = (insn >> 9) & 3; + acc = MACREG(accnum); if (s->env->macsr & MACSR_FI) { - gen_op_get_macf(rx, acc); + gen_helper_get_macf(cpu_env, rx, acc); } else if ((s->env->macsr & MACSR_OMC) == 0) { - gen_op_get_maci(rx, acc); + tcg_gen_trunc_i64_i32(rx, acc); } else if (s->env->macsr & MACSR_SU) { - gen_op_get_macs(rx, acc); + gen_helper_get_macs(rx, acc); } else { - gen_op_get_macu(rx, acc); + gen_helper_get_macu(rx, acc); + } + if (insn & 0x40) { + tcg_gen_movi_i64(acc, 0); + tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum)); } - if (insn & 0x40) - gen_op_clear_mac(acc); } DISAS_INSN(move_mac) { + /* FIXME: This can be done without a helper. */ int src; - int dest; + TCGv dest; src = insn & 3; - dest = (insn >> 9) & 3; - gen_op_move_mac(dest, src); - gen_op_mac_clear_flags(); - gen_op_mac_set_flags(dest); + dest = tcg_const_i32((insn >> 9) & 3); + gen_helper_mac_move(cpu_env, dest, tcg_const_i32(src)); + gen_mac_clear_flags(); + gen_helper_mac_set_flags(cpu_env, dest); } DISAS_INSN(from_macsr) { - int reg; + TCGv reg; reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); - gen_op_mov32(reg, QREG_MACSR); + tcg_gen_mov_i32(reg, QREG_MACSR); } DISAS_INSN(from_mask) { - int reg; + TCGv reg; reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); - gen_op_mov32(reg, QREG_MAC_MASK); + tcg_gen_mov_i32(reg, QREG_MAC_MASK); } DISAS_INSN(from_mext) { - int reg; - int acc; + TCGv reg; + TCGv acc; reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); - acc = (insn & 0x400) ? 2 : 0; + acc = tcg_const_i32((insn & 0x400) ? 2 : 0); if (s->env->macsr & MACSR_FI) - gen_op_get_mac_extf(reg, acc); + gen_helper_get_mac_extf(reg, cpu_env, acc); else - gen_op_get_mac_exti(reg, acc); + gen_helper_get_mac_exti(reg, cpu_env, acc); } DISAS_INSN(macsr_to_ccr) { - gen_op_mov32(QREG_CC_X, gen_im32(0)); - gen_op_and32(QREG_CC_DEST, QREG_MACSR, gen_im32(0xf)); + tcg_gen_movi_i32(QREG_CC_X, 0); + tcg_gen_andi_i32(QREG_CC_DEST, QREG_MACSR, 0xf); s->cc_op = CC_OP_FLAGS; } DISAS_INSN(to_mac) { - int acc; - int val; - acc = (insn >>9) & 3; + TCGv acc; + TCGv val; + int accnum; + accnum = (insn >> 9) & 3; + acc = MACREG(accnum); SRC_EA(val, OS_LONG, 0, NULL); if (s->env->macsr & MACSR_FI) { - gen_op_set_macf(val, acc); + tcg_gen_ext_i32_i64(acc, val); + tcg_gen_shli_i64(acc, acc, 8); } else if (s->env->macsr & MACSR_SU) { - gen_op_set_macs(val, acc); + tcg_gen_ext_i32_i64(acc, val); } else { - gen_op_set_macu(val, acc); + tcg_gen_extu_i32_i64(acc, val); } - gen_op_mac_clear_flags(); - gen_op_mac_set_flags(acc); + tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum)); + gen_mac_clear_flags(); + gen_helper_mac_set_flags(cpu_env, tcg_const_i32(accnum)); } DISAS_INSN(to_macsr) { - int val; + TCGv val; SRC_EA(val, OS_LONG, 0, NULL); - gen_op_set_macsr(val); + gen_helper_set_macsr(cpu_env, val); gen_lookup_tb(s); } DISAS_INSN(to_mask) { - int val; + TCGv val; SRC_EA(val, OS_LONG, 0, NULL); - gen_op_or32(QREG_MAC_MASK, val, gen_im32(0xffff0000)); + tcg_gen_ori_i32(QREG_MAC_MASK, val, 0xffff0000); } DISAS_INSN(to_mext) { - int val; - int acc; + TCGv val; + TCGv acc; SRC_EA(val, OS_LONG, 0, NULL); - acc = (insn & 0x400) ? 2 : 0; + acc = tcg_const_i32((insn & 0x400) ? 2 : 0); if (s->env->macsr & MACSR_FI) - gen_op_set_mac_extf(val, acc); + gen_helper_set_mac_extf(cpu_env, val, acc); else if (s->env->macsr & MACSR_SU) - gen_op_set_mac_exts(val, acc); + gen_helper_set_mac_exts(cpu_env, val, acc); else - gen_op_set_mac_extu(val, acc); + gen_helper_set_mac_extu(cpu_env, val, acc); } static disas_proc opcode_table[65536]; @@ -2888,265 +2909,8 @@ opcode_table[insn](s, insn); } -#if 0 -/* Save the result of a floating point operation. */ -static void expand_op_fp_result(qOP *qop) -{ - gen_op_movf64(QREG_FP_RESULT, qop->args[0]); -} - -/* Dummy op to indicate that the flags have been set. */ -static void expand_op_flags_set(qOP *qop) -{ -} - -/* Convert the confition codes into CC_OP_FLAGS format. */ -static void expand_op_flush_flags(qOP *qop) -{ - int cc_opreg; - - if (qop->args[0] == CC_OP_DYNAMIC) - cc_opreg = QREG_CC_OP; - else - cc_opreg = gen_im32(qop->args[0]); - gen_op_helper32(QREG_NULL, cc_opreg, HELPER_flush_flags); -} - -/* Set CC_DEST after a logical or direct flag setting operation. */ -static void expand_op_logic_cc(qOP *qop) -{ - gen_op_mov32(QREG_CC_DEST, qop->args[0]); -} - -/* Set CC_SRC and CC_DEST after an arithmetic operation. */ -static void expand_op_update_cc_add(qOP *qop) -{ - gen_op_mov32(QREG_CC_DEST, qop->args[0]); - gen_op_mov32(QREG_CC_SRC, qop->args[1]); -} - -/* Update the X flag. */ -static void expand_op_update_xflag(qOP *qop) -{ - int arg0; - int arg1; - - arg0 = qop->args[0]; - arg1 = qop->args[1]; - if (arg1 == QREG_NULL) { - /* CC_X = arg0. */ - gen_op_mov32(QREG_CC_X, arg0); - } else { - /* CC_X = arg0 < (unsigned)arg1. */ - gen_op_set_ltu32(QREG_CC_X, arg0, arg1); - } -} - -/* Set arg0 to the contents of the X flag. */ -static void expand_op_get_xflag(qOP *qop) -{ - gen_op_mov32(qop->args[0], QREG_CC_X); -} - -/* Expand a shift by immediate. The ISA only allows shifts by 1-8, so we - already know the shift is within range. */ -static inline void expand_shift_im(qOP *qop, int right, int arith) -{ - int val; - int reg; - int tmp; - int im; - - reg = qop->args[0]; - im = qop->args[1]; - tmp = gen_im32(im); - val = gen_new_qreg(QMODE_I32); - gen_op_mov32(val, reg); - gen_op_mov32(QREG_CC_DEST, val); - gen_op_mov32(QREG_CC_SRC, tmp); - if (right) { - if (arith) { - gen_op_sar32(reg, val, tmp); - } else { - gen_op_shr32(reg, val, tmp); - } - if (im == 1) - tmp = QREG_NULL; - else - tmp = gen_im32(im - 1); - } else { - gen_op_shl32(reg, val, tmp); - tmp = gen_im32(32 - im); - } - if (tmp != QREG_NULL) - gen_op_shr32(val, val, tmp); - gen_op_and32(QREG_CC_X, val, gen_im32(1)); -} - -static void expand_op_shl_im_cc(qOP *qop) -{ - expand_shift_im(qop, 0, 0); -} - -static void expand_op_shr_im_cc(qOP *qop) -{ - expand_shift_im(qop, 1, 0); -} - -static void expand_op_sar_im_cc(qOP *qop) -{ - expand_shift_im(qop, 1, 1); -} - -/* Expand a shift by register. */ -/* ??? This gives incorrect answers for shifts by 0 or >= 32 */ -static inline void expand_shift_reg(qOP *qop, int right, int arith) -{ - int val; - int reg; - int shift; - int tmp; - - reg = qop->args[0]; - shift = qop->args[1]; - val = gen_new_qreg(QMODE_I32); - gen_op_mov32(val, reg); - gen_op_mov32(QREG_CC_DEST, val); - gen_op_mov32(QREG_CC_SRC, shift); - tmp = gen_new_qreg(QMODE_I32); - if (right) { - if (arith) { - gen_op_sar32(reg, val, shift); - } else { - gen_op_shr32(reg, val, shift); - } - gen_op_sub32(tmp, shift, gen_im32(1)); - } else { - gen_op_shl32(reg, val, shift); - gen_op_sub32(tmp, gen_im32(31), shift); - } - gen_op_shl32(val, val, tmp); - gen_op_and32(QREG_CC_X, val, gen_im32(1)); -} - -static void expand_op_shl_cc(qOP *qop) -{ - expand_shift_reg(qop, 0, 0); -} - -static void expand_op_shr_cc(qOP *qop) -{ - expand_shift_reg(qop, 1, 0); -} - -static void expand_op_sar_cc(qOP *qop) -{ - expand_shift_reg(qop, 1, 1); -} - -/* Set the Z flag to (arg0 & arg1) == 0. */ -static void expand_op_btest(qOP *qop) -{ - int tmp; - int l1; - - l1 = gen_new_label(); - tmp = gen_new_qreg(QMODE_I32); - gen_op_and32(tmp, qop->args[0], qop->args[1]); - gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, gen_im32(~(uint32_t)CCF_Z)); - gen_op_jmp_nz32(tmp, l1); - gen_op_or32(QREG_CC_DEST, QREG_CC_DEST, gen_im32(CCF_Z)); - gen_op_label(l1); -} - -/* arg0 += arg1 + CC_X */ -static void expand_op_addx_cc(qOP *qop) -{ - int arg0 = qop->args[0]; - int arg1 = qop->args[1]; - int l1, l2; - - gen_op_add32 (arg0, arg0, arg1); - l1 = gen_new_label(); - l2 = gen_new_label(); - gen_op_jmp_z32(QREG_CC_X, l1); - gen_op_add32(arg0, arg0, gen_im32(1)); - gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_ADDX)); - gen_op_set_leu32(QREG_CC_X, arg0, arg1); - gen_op_jmp(l2); - gen_set_label(l1); - gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_ADD)); - gen_op_set_ltu32(QREG_CC_X, arg0, arg1); - gen_set_label(l2); -} - -/* arg0 -= arg1 + CC_X */ -static void expand_op_subx_cc(qOP *qop) -{ - int arg0 = qop->args[0]; - int arg1 = qop->args[1]; - int l1, l2; - - l1 = gen_new_label(); - l2 = gen_new_label(); - gen_op_jmp_z32(QREG_CC_X, l1); - gen_op_set_leu32(QREG_CC_X, arg0, arg1); - gen_op_sub32(arg0, arg0, gen_im32(1)); - gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_SUBX)); - gen_op_jmp(l2); - gen_set_label(l1); - gen_op_set_ltu32(QREG_CC_X, arg0, arg1); - gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_SUB)); - gen_set_label(l2); - gen_op_sub32 (arg0, arg0, arg1); -} - -/* Expand target specific ops to generic qops. */ -static void expand_target_qops(void) -{ - qOP *qop; - qOP *next; - int c; - - /* Copy the list of qops, expanding target specific ops as we go. */ - qop = gen_first_qop; - gen_first_qop = NULL; - gen_last_qop = NULL; - for (; qop; qop = next) { - c = qop->opcode; - next = qop->next; - if (c < FIRST_TARGET_OP) { - qop->prev = gen_last_qop; - qop->next = NULL; - if (gen_last_qop) - gen_last_qop->next = qop; - else - gen_first_qop = qop; - gen_last_qop = qop; - continue; - } - switch (c) { -#define DEF(name, nargs, barrier) \ - case INDEX_op_##name: \ - expand_op_##name(qop); \ - break; -#include "qop-target.def" -#undef DEF - default: - cpu_abort(NULL, "Unexpanded target qop"); - } - } -} - -/* ??? Implement this. */ -static void -optimize_flags(void) -{ -} -#endif - /* generate intermediate code for basic block 'tb'. */ -static inline int +static inline void gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, int search_pc) { @@ -3156,15 +2920,15 @@ target_ulong pc_start; int pc_offset; int last_cc_op; + int num_insns; + int max_insns; /* generate intermediate code */ pc_start = tb->pc; dc->tb = tb; - gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; - gen_opparam_ptr = gen_opparam_buf; dc->env = env; dc->is_jmp = DISAS_NEXT; @@ -3174,10 +2938,15 @@ dc->fpcr = env->fpcr; dc->user = (env->sr & SR_S) == 0; dc->is_mem = 0; - nb_gen_labels = 0; + dc->mactmp = NULL_QREG; lj = -1; + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + if (max_insns == 0) + max_insns = CF_COUNT_MASK; + + gen_icount_start(); do { - free_qreg = 0; pc_offset = dc->pc - pc_start; gen_throws_exception = NULL; if (env->nb_breakpoints > 0) { @@ -3200,27 +2969,34 @@ } gen_opc_pc[lj] = dc->pc; gen_opc_instr_start[lj] = 1; + gen_opc_icount[lj] = num_insns; } + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) + gen_io_start(); last_cc_op = dc->cc_op; dc->insn_pc = dc->pc; disas_m68k_insn(env, dc); + num_insns++; /* Terminate the TB on memory ops if watchpoints are present. */ - /* FIXME: This should be replacd by the deterministic execution + /* FIXME: This should be replaced by the deterministic execution * IRQ raising bits. */ if (dc->is_mem && env->nb_watchpoints) break; } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && !env->singlestep_enabled && - (pc_offset) < (TARGET_PAGE_SIZE - 32)); + (pc_offset) < (TARGET_PAGE_SIZE - 32) && + num_insns < max_insns); - if (__builtin_expect(env->singlestep_enabled, 0)) { + if (tb->cflags & CF_LAST_IO) + gen_io_end(); + if (unlikely(env->singlestep_enabled)) { /* Make sure the pc is updated, and raise a debug exception. */ if (!dc->is_jmp) { gen_flush_cc_op(dc); - gen_op_mov32(QREG_PC, gen_im32((long)dc->pc)); + tcg_gen_movi_i32(QREG_PC, dc->pc); } - gen_op_raise_exception(EXCP_DEBUG); + gen_helper_raise_exception(tcg_const_i32(EXCP_DEBUG)); } else { switch(dc->is_jmp) { case DISAS_NEXT: @@ -3232,14 +3008,14 @@ case DISAS_UPDATE: gen_flush_cc_op(dc); /* indicate that the hash table must be used to find the next TB */ - gen_op_mov32(QREG_T0, gen_im32(0)); - gen_op_exit_tb(); + tcg_gen_exit_tb(0); break; case DISAS_TB_JUMP: /* nothing more to generate */ break; } } + gen_icount_end(tb, num_insns); *gen_opc_ptr = INDEX_op_end; #ifdef DEBUG_DISAS @@ -3248,11 +3024,6 @@ fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); target_disas(logfile, pc_start, dc->pc - pc_start, 0); fprintf(logfile, "\n"); - if (loglevel & (CPU_LOG_TB_OP)) { - fprintf(logfile, "OP:\n"); - dump_ops(gen_opc_buf, gen_opparam_buf); - fprintf(logfile, "\n"); - } } #endif if (search_pc) { @@ -3262,21 +3033,21 @@ gen_opc_instr_start[lj++] = 0; } else { tb->size = dc->pc - pc_start; + tb->icount = num_insns; } //optimize_flags(); //expand_target_qops(); - return 0; } -int gen_intermediate_code(CPUState *env, TranslationBlock *tb) +void gen_intermediate_code(CPUState *env, TranslationBlock *tb) { - return gen_intermediate_code_internal(env, tb, 0); + gen_intermediate_code_internal(env, tb, 0); } -int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) +void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) { - return gen_intermediate_code_internal(env, tb, 1); + gen_intermediate_code_internal(env, tb, 1); } void cpu_dump_state(CPUState *env, FILE *f, @@ -3301,3 +3072,8 @@ cpu_fprintf (f, "FPRESULT = %12g\n", *(double *)&env->fp_result); } +void gen_pc_load(CPUState *env, TranslationBlock *tb, + unsigned long searched_pc, int pc_pos, void *puc) +{ + env->pc = gen_opc_pc[pc_pos]; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-mips/cpu.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-mips/cpu.h --- qemu-0.9.1/target-mips/cpu.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-mips/cpu.h 2008-11-11 11:39:33.000000000 +0000 @@ -70,11 +70,6 @@ struct CPUMIPSFPUContext { /* Floating point registers */ fpr_t fpr[32]; -#ifndef USE_HOST_FLOAT_REGS - fpr_t ft0; - fpr_t ft1; - fpr_t ft2; -#endif float_status fp_status; /* fpu implementation/revision register (fir) */ uint32_t fcr0; @@ -89,9 +84,9 @@ #define FCR0_REV 0 /* fcsr */ uint32_t fcr31; -#define SET_FP_COND(num,env) do { ((env)->fcr31) |= ((num) ? (1 << ((num) + 24)) : (1 << 23)); } while(0) -#define CLEAR_FP_COND(num,env) do { ((env)->fcr31) &= ~((num) ? (1 << ((num) + 24)) : (1 << 23)); } while(0) -#define GET_FP_COND(env) ((((env)->fcr31 >> 24) & 0xfe) | (((env)->fcr31 >> 23) & 0x1)) +#define SET_FP_COND(num,env) do { ((env).fcr31) |= ((num) ? (1 << ((num) + 24)) : (1 << 23)); } while(0) +#define CLEAR_FP_COND(num,env) do { ((env).fcr31) &= ~((num) ? (1 << ((num) + 24)) : (1 << 23)); } while(0) +#define GET_FP_COND(env) ((((env).fcr31 >> 24) & 0xfe) | (((env).fcr31 >> 23) & 0x1)) #define GET_FP_CAUSE(reg) (((reg) >> 12) & 0x3f) #define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f) #define GET_FP_FLAGS(reg) (((reg) >> 2) & 0x1f) @@ -137,32 +132,55 @@ #define MIPS_SHADOW_SET_MAX 16 #define MIPS_TC_MAX 5 +#define MIPS_FPU_MAX 1 #define MIPS_DSP_ACC 4 +typedef struct TCState TCState; +struct TCState { + target_ulong gpr[32]; + target_ulong PC; + target_ulong HI[MIPS_DSP_ACC]; + target_ulong LO[MIPS_DSP_ACC]; + target_ulong ACX[MIPS_DSP_ACC]; + target_ulong DSPControl; + int32_t CP0_TCStatus; +#define CP0TCSt_TCU3 31 +#define CP0TCSt_TCU2 30 +#define CP0TCSt_TCU1 29 +#define CP0TCSt_TCU0 28 +#define CP0TCSt_TMX 27 +#define CP0TCSt_RNST 23 +#define CP0TCSt_TDS 21 +#define CP0TCSt_DT 20 +#define CP0TCSt_DA 15 +#define CP0TCSt_A 13 +#define CP0TCSt_TKSU 11 +#define CP0TCSt_IXMT 10 +#define CP0TCSt_TASID 0 + int32_t CP0_TCBind; +#define CP0TCBd_CurTC 21 +#define CP0TCBd_TBE 17 +#define CP0TCBd_CurVPE 0 + target_ulong CP0_TCHalt; + target_ulong CP0_TCContext; + target_ulong CP0_TCSchedule; + target_ulong CP0_TCScheFBack; + int32_t CP0_Debug_tcstatus; +}; + typedef struct CPUMIPSState CPUMIPSState; struct CPUMIPSState { - /* General integer registers */ - target_ulong gpr[32][MIPS_SHADOW_SET_MAX]; - /* Special registers */ - target_ulong PC[MIPS_TC_MAX]; -#if TARGET_LONG_BITS > HOST_LONG_BITS - target_ulong t0; - target_ulong t1; - target_ulong t2; -#endif - target_ulong HI[MIPS_DSP_ACC][MIPS_TC_MAX]; - target_ulong LO[MIPS_DSP_ACC][MIPS_TC_MAX]; - target_ulong ACX[MIPS_DSP_ACC][MIPS_TC_MAX]; - target_ulong DSPControl[MIPS_TC_MAX]; + TCState active_tc; + CPUMIPSFPUContext active_fpu; CPUMIPSMVPContext *mvp; CPUMIPSTLBContext *tlb; - CPUMIPSFPUContext *fpu; uint32_t current_tc; + uint32_t current_fpu; uint32_t SEGBITS; - target_ulong SEGMask; uint32_t PABITS; + target_ulong SEGMask; target_ulong PAMask; int32_t CP0_Index; @@ -208,28 +226,6 @@ #define CP0VPEOpt_DWX1 1 #define CP0VPEOpt_DWX0 0 target_ulong CP0_EntryLo0; - int32_t CP0_TCStatus[MIPS_TC_MAX]; -#define CP0TCSt_TCU3 31 -#define CP0TCSt_TCU2 30 -#define CP0TCSt_TCU1 29 -#define CP0TCSt_TCU0 28 -#define CP0TCSt_TMX 27 -#define CP0TCSt_RNST 23 -#define CP0TCSt_TDS 21 -#define CP0TCSt_DT 20 -#define CP0TCSt_DA 15 -#define CP0TCSt_A 13 -#define CP0TCSt_TKSU 11 -#define CP0TCSt_IXMT 10 -#define CP0TCSt_TASID 0 - int32_t CP0_TCBind[MIPS_TC_MAX]; -#define CP0TCBd_CurTC 21 -#define CP0TCBd_TBE 17 -#define CP0TCBd_CurVPE 0 - target_ulong CP0_TCHalt[MIPS_TC_MAX]; - target_ulong CP0_TCContext[MIPS_TC_MAX]; - target_ulong CP0_TCSchedule[MIPS_TC_MAX]; - target_ulong CP0_TCScheFBack[MIPS_TC_MAX]; target_ulong CP0_EntryLo1; target_ulong CP0_Context; int32_t CP0_PageMask; @@ -400,7 +396,6 @@ #define CP0DB_DDBL 2 #define CP0DB_DBp 1 #define CP0DB_DSS 0 - int32_t CP0_Debug_tcstatus[MIPS_TC_MAX]; target_ulong CP0_DEPC; int32_t CP0_Performance0; int32_t CP0_TagLo; @@ -409,15 +404,14 @@ int32_t CP0_DataHi; target_ulong CP0_ErrorEPC; int32_t CP0_DESAVE; + /* We waste some space so we can handle shadow registers like TCs. */ + TCState tcs[MIPS_SHADOW_SET_MAX]; + CPUMIPSFPUContext fpus[MIPS_FPU_MAX]; /* Qemu */ - int interrupt_request; - jmp_buf jmp_env; - int exception_index; int error_code; - int user_mode_only; /* user mode only simulation */ uint32_t hflags; /* CPU State */ /* TMASK defines different execution modes */ -#define MIPS_HFLAG_TMASK 0x01FF +#define MIPS_HFLAG_TMASK 0x03FF #define MIPS_HFLAG_MODE 0x0007 /* execution modes */ /* The KSU flags must be the lowest bits in hflags. The flag order must be the same as defined for CP0 Status. This allows to use @@ -436,37 +430,31 @@ and RSQRT.D. */ #define MIPS_HFLAG_COP1X 0x0080 /* COP1X instructions enabled */ #define MIPS_HFLAG_RE 0x0100 /* Reversed endianness */ +#define MIPS_HFLAG_UX 0x0200 /* 64-bit user mode */ /* If translation is interrupted between the branch instruction and * the delay slot, record what type of branch it is so that we can * resume translation properly. It might be possible to reduce * this from three bits to two. */ -#define MIPS_HFLAG_BMASK 0x0e00 -#define MIPS_HFLAG_B 0x0200 /* Unconditional branch */ -#define MIPS_HFLAG_BC 0x0400 /* Conditional branch */ -#define MIPS_HFLAG_BL 0x0600 /* Likely branch */ -#define MIPS_HFLAG_BR 0x0800 /* branch to register (can't link TB) */ +#define MIPS_HFLAG_BMASK 0x1C00 +#define MIPS_HFLAG_B 0x0400 /* Unconditional branch */ +#define MIPS_HFLAG_BC 0x0800 /* Conditional branch */ +#define MIPS_HFLAG_BL 0x0C00 /* Likely branch */ +#define MIPS_HFLAG_BR 0x1000 /* branch to register (can't link TB) */ target_ulong btarget; /* Jump / branch target */ int bcond; /* Branch condition (if needed) */ - int halted; /* TRUE if the CPU is in suspend state */ - int SYNCI_Step; /* Address step size for SYNCI */ int CCRes; /* Cycle count resolution/divisor */ uint32_t CP0_Status_rw_bitmask; /* Read/write bits in CP0_Status */ uint32_t CP0_TCStatus_rw_bitmask; /* Read/write bits in CP0_TCStatus */ int insn_flags; /* Supported instruction set */ -#ifdef CONFIG_USER_ONLY - target_ulong tls_value; -#endif + target_ulong tls_value; /* For usermode emulation */ CPU_COMMON const mips_def_t *cpu_model; -#ifndef CONFIG_USER_ONLY void *irq[8]; -#endif - struct QEMUTimer *timer; /* Internal timer */ }; @@ -483,7 +471,7 @@ void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, - int unused); + int unused, int size); #define CPUState CPUMIPSState #define cpu_init cpu_mips_init @@ -492,6 +480,8 @@ #define cpu_signal_handler cpu_mips_signal_handler #define cpu_list mips_cpu_list +#define CPU_SAVE_VERSION 3 + /* MMU modes definitions. We carefully match the indices with our hflags layout. */ #define MMU_MODE0_SUFFIX _kernel @@ -503,6 +493,14 @@ return env->hflags & MIPS_HFLAG_KSU; } +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) +{ + if (newsp) + env->active_tc.gpr[29] = newsp; + env->active_tc.gpr[7] = 0; + env->active_tc.gpr[2] = 0; +} + #include "cpu-all.h" /* Memory access type : @@ -565,4 +563,10 @@ uint32_t cpu_mips_get_clock (void); int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc); +#define CPU_PC_FROM_TB(env, tb) do { \ + env->active_tc.PC = tb->pc; \ + env->hflags &= ~MIPS_HFLAG_BMASK; \ + env->hflags |= tb->flags & MIPS_HFLAG_BMASK; \ + } while (0) + #endif /* !defined (__MIPS_CPU_H__) */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-mips/exec.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-mips/exec.h --- qemu-0.9.1/target-mips/exec.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-mips/exec.h 2008-11-11 11:39:33.000000000 +0000 @@ -10,39 +10,6 @@ register struct CPUMIPSState *env asm(AREG0); -#if TARGET_LONG_BITS > HOST_LONG_BITS -#define T0 (env->t0) -#define T1 (env->t1) -#define T2 (env->t2) -#else -register target_ulong T0 asm(AREG1); -register target_ulong T1 asm(AREG2); -register target_ulong T2 asm(AREG3); -#endif - -#if defined (USE_HOST_FLOAT_REGS) -#error "implement me." -#else -#define FDT0 (env->fpu->ft0.fd) -#define FDT1 (env->fpu->ft1.fd) -#define FDT2 (env->fpu->ft2.fd) -#define FST0 (env->fpu->ft0.fs[FP_ENDIAN_IDX]) -#define FST1 (env->fpu->ft1.fs[FP_ENDIAN_IDX]) -#define FST2 (env->fpu->ft2.fs[FP_ENDIAN_IDX]) -#define FSTH0 (env->fpu->ft0.fs[!FP_ENDIAN_IDX]) -#define FSTH1 (env->fpu->ft1.fs[!FP_ENDIAN_IDX]) -#define FSTH2 (env->fpu->ft2.fs[!FP_ENDIAN_IDX]) -#define DT0 (env->fpu->ft0.d) -#define DT1 (env->fpu->ft1.d) -#define DT2 (env->fpu->ft2.d) -#define WT0 (env->fpu->ft0.w[FP_ENDIAN_IDX]) -#define WT1 (env->fpu->ft1.w[FP_ENDIAN_IDX]) -#define WT2 (env->fpu->ft2.w[FP_ENDIAN_IDX]) -#define WTH0 (env->fpu->ft0.w[!FP_ENDIAN_IDX]) -#define WTH1 (env->fpu->ft1.w[!FP_ENDIAN_IDX]) -#define WTH2 (env->fpu->ft2.w[!FP_ENDIAN_IDX]) -#endif - #include "cpu.h" #include "exec-all.h" @@ -50,69 +17,12 @@ #include "softmmu_exec.h" #endif /* !defined(CONFIG_USER_ONLY) */ -#if defined(TARGET_MIPS64) -#if TARGET_LONG_BITS > HOST_LONG_BITS -void do_dsll (void); -void do_dsll32 (void); -void do_dsra (void); -void do_dsra32 (void); -void do_dsrl (void); -void do_dsrl32 (void); -void do_drotr (void); -void do_drotr32 (void); -void do_dsllv (void); -void do_dsrav (void); -void do_dsrlv (void); -void do_drotrv (void); -void do_dclo (void); -void do_dclz (void); -#endif -#endif - -#if HOST_LONG_BITS < 64 -void do_div (void); -#endif -#if TARGET_LONG_BITS > HOST_LONG_BITS -void do_mult (void); -void do_multu (void); -void do_madd (void); -void do_maddu (void); -void do_msub (void); -void do_msubu (void); -void do_muls (void); -void do_mulsu (void); -void do_macc (void); -void do_macchi (void); -void do_maccu (void); -void do_macchiu (void); -void do_msac (void); -void do_msachi (void); -void do_msacu (void); -void do_msachiu (void); -void do_mulhi (void); -void do_mulhiu (void); -void do_mulshi (void); -void do_mulshiu (void); -#endif -#if defined(TARGET_MIPS64) -void do_ddiv (void); -#if TARGET_LONG_BITS > HOST_LONG_BITS -void do_ddivu (void); -#endif -#endif -void do_mfc0_random(void); -void do_mfc0_count(void); -void do_mtc0_entryhi(uint32_t in); void do_mtc0_status_debug(uint32_t old, uint32_t val); void do_mtc0_status_irqraise_debug(void); void dump_fpu(CPUState *env); void fpu_dump_state(CPUState *env, FILE *f, int (*fpu_fprintf)(FILE *f, const char *fmt, ...), int flags); -void dump_sc (void); -void do_pmon (int function); - -void dump_sc (void); int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int mmu_idx, int is_softmmu); @@ -122,13 +32,7 @@ void cpu_loop_exit(void); void do_raise_exception_err (uint32_t exception, int error_code); void do_raise_exception (uint32_t exception); -void do_raise_exception_direct_err (uint32_t exception, int error_code); -void do_raise_exception_direct (uint32_t exception); -void cpu_dump_state(CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), - int flags); -void cpu_mips_irqctrl_init (void); uint32_t cpu_mips_get_random (CPUState *env); uint32_t cpu_mips_get_count (CPUState *env); void cpu_mips_store_count (CPUState *env, uint32_t value); @@ -139,91 +43,15 @@ void cpu_mips_clock_init (CPUState *env); void cpu_mips_tlb_flush (CPUState *env, int flush_global); -void do_cfc1 (int reg); -void do_ctc1 (int reg); - -#define FOP_PROTO(op) \ -void do_float_ ## op ## _s(void); \ -void do_float_ ## op ## _d(void); -FOP_PROTO(roundl) -FOP_PROTO(roundw) -FOP_PROTO(truncl) -FOP_PROTO(truncw) -FOP_PROTO(ceill) -FOP_PROTO(ceilw) -FOP_PROTO(floorl) -FOP_PROTO(floorw) -FOP_PROTO(rsqrt) -FOP_PROTO(recip) -#undef FOP_PROTO - -#define FOP_PROTO(op) \ -void do_float_ ## op ## _s(void); \ -void do_float_ ## op ## _d(void); \ -void do_float_ ## op ## _ps(void); -FOP_PROTO(add) -FOP_PROTO(sub) -FOP_PROTO(mul) -FOP_PROTO(div) -FOP_PROTO(recip1) -FOP_PROTO(recip2) -FOP_PROTO(rsqrt1) -FOP_PROTO(rsqrt2) -#undef FOP_PROTO - -void do_float_cvtd_s(void); -void do_float_cvtd_w(void); -void do_float_cvtd_l(void); -void do_float_cvtl_d(void); -void do_float_cvtl_s(void); -void do_float_cvtps_pw(void); -void do_float_cvtpw_ps(void); -void do_float_cvts_d(void); -void do_float_cvts_w(void); -void do_float_cvts_l(void); -void do_float_cvts_pl(void); -void do_float_cvts_pu(void); -void do_float_cvtw_s(void); -void do_float_cvtw_d(void); - -void do_float_addr_ps(void); -void do_float_mulr_ps(void); - -#define FOP_PROTO(op) \ -void do_cmp_d_ ## op(long cc); \ -void do_cmpabs_d_ ## op(long cc); \ -void do_cmp_s_ ## op(long cc); \ -void do_cmpabs_s_ ## op(long cc); \ -void do_cmp_ps_ ## op(long cc); \ -void do_cmpabs_ps_ ## op(long cc); - -FOP_PROTO(f) -FOP_PROTO(un) -FOP_PROTO(eq) -FOP_PROTO(ueq) -FOP_PROTO(olt) -FOP_PROTO(ult) -FOP_PROTO(ole) -FOP_PROTO(ule) -FOP_PROTO(sf) -FOP_PROTO(ngle) -FOP_PROTO(seq) -FOP_PROTO(ngl) -FOP_PROTO(lt) -FOP_PROTO(nge) -FOP_PROTO(le) -FOP_PROTO(ngt) -#undef FOP_PROTO - -static always_inline void env_to_regs(void) +static inline void env_to_regs(void) { } -static always_inline void regs_to_env(void) +static inline void regs_to_env(void) { } -static always_inline int cpu_halted(CPUState *env) +static inline int cpu_halted(CPUState *env) { if (!env->halted) return 0; @@ -235,10 +63,11 @@ return EXCP_HALTED; } -static always_inline void compute_hflags(CPUState *env) +static inline void compute_hflags(CPUState *env) { env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | - MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU); + MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU | + MIPS_HFLAG_UX); if (!(env->CP0_Status & (1 << CP0St_EXL)) && !(env->CP0_Status & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM)) { @@ -249,6 +78,8 @@ (env->CP0_Status & (1 << CP0St_PX)) || (env->CP0_Status & (1 << CP0St_UX))) env->hflags |= MIPS_HFLAG_64; + if (env->CP0_Status & (1 << CP0St_UX)) + env->hflags |= MIPS_HFLAG_UX; #endif if ((env->CP0_Status & (1 << CP0St_CU0)) || !(env->hflags & MIPS_HFLAG_KSU)) @@ -258,7 +89,7 @@ if (env->CP0_Status & (1 << CP0St_FR)) env->hflags |= MIPS_HFLAG_F64; if (env->insn_flags & ISA_MIPS32R2) { - if (env->fpu->fcr0 & FCR0_F64) + if (env->active_fpu.fcr0 & (1 << FCR0_F64)) env->hflags |= MIPS_HFLAG_COP1X; } else if (env->insn_flags & ISA_MIPS32) { if (env->hflags & MIPS_HFLAG_64) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-mips/fop_template.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-mips/fop_template.c --- qemu-0.9.1/target-mips/fop_template.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-mips/fop_template.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,131 +0,0 @@ -/* - * MIPS emulation micro-operations templates for floating point reg - * load & store for qemu. - * - * Copyright (c) 2006 Marius Groeger - * - * 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 - */ - -#if defined(FREG) - -#define OP_WLOAD_FREG(treg, tregname, FREG) \ - void glue(glue(op_load_fpr_,tregname), FREG) (void) \ - { \ - treg = env->fpu->fpr[FREG].w[FP_ENDIAN_IDX]; \ - FORCE_RET(); \ - } - -#define OP_WSTORE_FREG(treg, tregname, FREG) \ - void glue(glue(op_store_fpr_,tregname), FREG) (void) \ - { \ - env->fpu->fpr[FREG].w[FP_ENDIAN_IDX] = treg; \ - FORCE_RET(); \ - } - -/* WT0 = FREG.w: op_load_fpr_WT0_fprFREG */ -OP_WLOAD_FREG(WT0, WT0_fpr, FREG) -/* FREG.w = WT0: op_store_fpr_WT0_fprFREG */ -OP_WSTORE_FREG(WT0, WT0_fpr, FREG) - -OP_WLOAD_FREG(WT1, WT1_fpr, FREG) -OP_WSTORE_FREG(WT1, WT1_fpr, FREG) - -OP_WLOAD_FREG(WT2, WT2_fpr, FREG) -OP_WSTORE_FREG(WT2, WT2_fpr, FREG) - -#define OP_DLOAD_FREG(treg, tregname, FREG) \ - void glue(glue(op_load_fpr_,tregname), FREG) (void) \ - { \ - if (env->hflags & MIPS_HFLAG_F64) \ - treg = env->fpu->fpr[FREG].d; \ - else \ - treg = (uint64_t)(env->fpu->fpr[FREG | 1].w[FP_ENDIAN_IDX]) << 32 | \ - env->fpu->fpr[FREG & ~1].w[FP_ENDIAN_IDX]; \ - FORCE_RET(); \ - } - -#define OP_DSTORE_FREG(treg, tregname, FREG) \ - void glue(glue(op_store_fpr_,tregname), FREG) (void) \ - { \ - if (env->hflags & MIPS_HFLAG_F64) \ - env->fpu->fpr[FREG].d = treg; \ - else { \ - env->fpu->fpr[FREG | 1].w[FP_ENDIAN_IDX] = treg >> 32; \ - env->fpu->fpr[FREG & ~1].w[FP_ENDIAN_IDX] = treg; \ - } \ - FORCE_RET(); \ - } - -OP_DLOAD_FREG(DT0, DT0_fpr, FREG) -OP_DSTORE_FREG(DT0, DT0_fpr, FREG) - -OP_DLOAD_FREG(DT1, DT1_fpr, FREG) -OP_DSTORE_FREG(DT1, DT1_fpr, FREG) - -OP_DLOAD_FREG(DT2, DT2_fpr, FREG) -OP_DSTORE_FREG(DT2, DT2_fpr, FREG) - -#define OP_PSLOAD_FREG(treg, tregname, FREG) \ - void glue(glue(op_load_fpr_,tregname), FREG) (void) \ - { \ - treg = env->fpu->fpr[FREG].w[!FP_ENDIAN_IDX]; \ - FORCE_RET(); \ - } - -#define OP_PSSTORE_FREG(treg, tregname, FREG) \ - void glue(glue(op_store_fpr_,tregname), FREG) (void) \ - { \ - env->fpu->fpr[FREG].w[!FP_ENDIAN_IDX] = treg; \ - FORCE_RET(); \ - } - -OP_PSLOAD_FREG(WTH0, WTH0_fpr, FREG) -OP_PSSTORE_FREG(WTH0, WTH0_fpr, FREG) - -OP_PSLOAD_FREG(WTH1, WTH1_fpr, FREG) -OP_PSSTORE_FREG(WTH1, WTH1_fpr, FREG) - -OP_PSLOAD_FREG(WTH2, WTH2_fpr, FREG) -OP_PSSTORE_FREG(WTH2, WTH2_fpr, FREG) - -#endif - -#if defined (FTN) - -#define SET_RESET(treg, tregname) \ - void glue(op_set, tregname)(void) \ - { \ - treg = PARAM1; \ - FORCE_RET(); \ - } \ - void glue(op_reset, tregname)(void) \ - { \ - treg = 0; \ - FORCE_RET(); \ - } - -SET_RESET(WT0, _WT0) -SET_RESET(WT1, _WT1) -SET_RESET(WT2, _WT2) -SET_RESET(DT0, _DT0) -SET_RESET(DT1, _DT1) -SET_RESET(DT2, _DT2) -SET_RESET(WTH0, _WTH0) -SET_RESET(WTH1, _WTH1) -SET_RESET(WTH2, _WTH2) - -#undef SET_RESET -#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-mips/helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-mips/helper.c --- qemu-0.9.1/target-mips/helper.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-mips/helper.c 2008-09-21 22:21:26.000000000 +0100 @@ -206,26 +206,23 @@ return ret; } -#if defined(CONFIG_USER_ONLY) target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { - return addr; -} -#else -target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) -{ - target_ulong phys_addr; - int prot; - - if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0) - return -1; - return phys_addr; + if (env->user_mode_only) + return addr; + else { + target_ulong phys_addr; + int prot; + + if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0) + return -1; + return phys_addr; + } } void cpu_mips_init_mmu (CPUState *env) { } -#endif /* !defined(CONFIG_USER_ONLY) */ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int mmu_idx, int is_softmmu) @@ -241,7 +238,7 @@ cpu_dump_state(env, logfile, fprintf, 0); #endif fprintf(logfile, "%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d mmu_idx %d smmu %d\n", - __func__, env->PC[env->current_tc], address, rw, mmu_idx, is_softmmu); + __func__, env->active_tc.PC, address, rw, mmu_idx, is_softmmu); } rw &= 1; @@ -307,7 +304,7 @@ #if defined(TARGET_MIPS64) env->CP0_EntryHi &= env->SEGMask; env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) | - ((address & 0xC00000000000ULL) >> (env->SEGBITS - 9)) | + ((address & 0xC00000000000ULL) >> (55 - env->SEGBITS)) | ((address & ((1ULL << env->SEGBITS) - 1) & 0xFFFFFFFFFFFFE000ULL) >> 9); #endif env->exception_index = exception; @@ -318,7 +315,6 @@ return ret; } -#if !defined(CONFIG_USER_ONLY) static const char * const excp_names[EXCP_LAST + 1] = { [EXCP_RESET] = "reset", [EXCP_SRESET] = "soft reset", @@ -354,232 +350,230 @@ [EXCP_C2E] = "precise coprocessor 2", [EXCP_CACHE] = "cache error", }; -#endif void do_interrupt (CPUState *env) { -#if !defined(CONFIG_USER_ONLY) - target_ulong offset; - int cause = -1; - const char *name; - - if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { - if (env->exception_index < 0 || env->exception_index > EXCP_LAST) - name = "unknown"; - else - name = excp_names[env->exception_index]; - - fprintf(logfile, "%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n", - __func__, env->PC[env->current_tc], env->CP0_EPC, name); - } - if (env->exception_index == EXCP_EXT_INTERRUPT && - (env->hflags & MIPS_HFLAG_DM)) - env->exception_index = EXCP_DINT; - offset = 0x180; - switch (env->exception_index) { - case EXCP_DSS: - env->CP0_Debug |= 1 << CP0DB_DSS; - /* Debug single step cannot be raised inside a delay slot and - * resume will always occur on the next instruction - * (but we assume the pc has always been updated during - * code translation). - */ - env->CP0_DEPC = env->PC[env->current_tc]; - goto enter_debug_mode; - case EXCP_DINT: - env->CP0_Debug |= 1 << CP0DB_DINT; - goto set_DEPC; - case EXCP_DIB: - env->CP0_Debug |= 1 << CP0DB_DIB; - goto set_DEPC; - case EXCP_DBp: - env->CP0_Debug |= 1 << CP0DB_DBp; - goto set_DEPC; - case EXCP_DDBS: - env->CP0_Debug |= 1 << CP0DB_DDBS; - goto set_DEPC; - case EXCP_DDBL: - env->CP0_Debug |= 1 << CP0DB_DDBL; - set_DEPC: - if (env->hflags & MIPS_HFLAG_BMASK) { - /* If the exception was raised from a delay slot, - come back to the jump. */ - env->CP0_DEPC = env->PC[env->current_tc] - 4; - env->hflags &= ~MIPS_HFLAG_BMASK; - } else { - env->CP0_DEPC = env->PC[env->current_tc]; - } - enter_debug_mode: - env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0; - env->hflags &= ~(MIPS_HFLAG_KSU); - /* EJTAG probe trap enable is not implemented... */ - if (!(env->CP0_Status & (1 << CP0St_EXL))) - env->CP0_Cause &= ~(1 << CP0Ca_BD); - env->PC[env->current_tc] = (int32_t)0xBFC00480; - break; - case EXCP_RESET: - cpu_reset(env); - break; - case EXCP_SRESET: - env->CP0_Status |= (1 << CP0St_SR); - memset(env->CP0_WatchLo, 0, sizeof(*env->CP0_WatchLo)); - goto set_error_EPC; - case EXCP_NMI: - env->CP0_Status |= (1 << CP0St_NMI); - set_error_EPC: - if (env->hflags & MIPS_HFLAG_BMASK) { - /* If the exception was raised from a delay slot, - come back to the jump. */ - env->CP0_ErrorEPC = env->PC[env->current_tc] - 4; - env->hflags &= ~MIPS_HFLAG_BMASK; - } else { - env->CP0_ErrorEPC = env->PC[env->current_tc]; - } - env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); - env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; - env->hflags &= ~(MIPS_HFLAG_KSU); - if (!(env->CP0_Status & (1 << CP0St_EXL))) - env->CP0_Cause &= ~(1 << CP0Ca_BD); - env->PC[env->current_tc] = (int32_t)0xBFC00000; - break; - case EXCP_EXT_INTERRUPT: - cause = 0; - if (env->CP0_Cause & (1 << CP0Ca_IV)) - offset = 0x200; - goto set_EPC; - case EXCP_LTLBL: - cause = 1; - goto set_EPC; - case EXCP_TLBL: - cause = 2; - if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { -#if defined(TARGET_MIPS64) - int R = env->CP0_BadVAddr >> 62; - int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; - int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; - int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; - - if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) - offset = 0x080; + if (!env->user_mode_only) { + target_ulong offset; + int cause = -1; + const char *name; + + if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { + if (env->exception_index < 0 || env->exception_index > EXCP_LAST) + name = "unknown"; else -#endif - offset = 0x000; - } - goto set_EPC; - case EXCP_TLBS: - cause = 3; - if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { -#if defined(TARGET_MIPS64) - int R = env->CP0_BadVAddr >> 62; - int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; - int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; - int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; + name = excp_names[env->exception_index]; - if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) - offset = 0x080; - else -#endif - offset = 0x000; - } - goto set_EPC; - case EXCP_AdEL: - cause = 4; - goto set_EPC; - case EXCP_AdES: - cause = 5; - goto set_EPC; - case EXCP_IBE: - cause = 6; - goto set_EPC; - case EXCP_DBE: - cause = 7; - goto set_EPC; - case EXCP_SYSCALL: - cause = 8; - goto set_EPC; - case EXCP_BREAK: - cause = 9; - goto set_EPC; - case EXCP_RI: - cause = 10; - goto set_EPC; - case EXCP_CpU: - cause = 11; - env->CP0_Cause = (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) | - (env->error_code << CP0Ca_CE); - goto set_EPC; - case EXCP_OVERFLOW: - cause = 12; - goto set_EPC; - case EXCP_TRAP: - cause = 13; - goto set_EPC; - case EXCP_FPE: - cause = 15; - goto set_EPC; - case EXCP_C2E: - cause = 18; - goto set_EPC; - case EXCP_MDMX: - cause = 22; - goto set_EPC; - case EXCP_DWATCH: - cause = 23; - /* XXX: TODO: manage defered watch exceptions */ - goto set_EPC; - case EXCP_MCHECK: - cause = 24; - goto set_EPC; - case EXCP_THREAD: - cause = 25; - goto set_EPC; - case EXCP_CACHE: - cause = 30; - if (env->CP0_Status & (1 << CP0St_BEV)) { - offset = 0x100; - } else { - offset = 0x20000100; + fprintf(logfile, "%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n", + __func__, env->active_tc.PC, env->CP0_EPC, name); } - set_EPC: - if (!(env->CP0_Status & (1 << CP0St_EXL))) { + if (env->exception_index == EXCP_EXT_INTERRUPT && + (env->hflags & MIPS_HFLAG_DM)) + env->exception_index = EXCP_DINT; + offset = 0x180; + switch (env->exception_index) { + case EXCP_DSS: + env->CP0_Debug |= 1 << CP0DB_DSS; + /* Debug single step cannot be raised inside a delay slot and + resume will always occur on the next instruction + (but we assume the pc has always been updated during + code translation). */ + env->CP0_DEPC = env->active_tc.PC; + goto enter_debug_mode; + case EXCP_DINT: + env->CP0_Debug |= 1 << CP0DB_DINT; + goto set_DEPC; + case EXCP_DIB: + env->CP0_Debug |= 1 << CP0DB_DIB; + goto set_DEPC; + case EXCP_DBp: + env->CP0_Debug |= 1 << CP0DB_DBp; + goto set_DEPC; + case EXCP_DDBS: + env->CP0_Debug |= 1 << CP0DB_DDBS; + goto set_DEPC; + case EXCP_DDBL: + env->CP0_Debug |= 1 << CP0DB_DDBL; + set_DEPC: if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, come back to the jump. */ - env->CP0_EPC = env->PC[env->current_tc] - 4; - env->CP0_Cause |= (1 << CP0Ca_BD); + env->CP0_DEPC = env->active_tc.PC - 4; + env->hflags &= ~MIPS_HFLAG_BMASK; } else { - env->CP0_EPC = env->PC[env->current_tc]; + env->CP0_DEPC = env->active_tc.PC; + } + enter_debug_mode: + env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0; + env->hflags &= ~(MIPS_HFLAG_KSU); + /* EJTAG probe trap enable is not implemented... */ + if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); + env->active_tc.PC = (int32_t)0xBFC00480; + break; + case EXCP_RESET: + cpu_reset(env); + break; + case EXCP_SRESET: + env->CP0_Status |= (1 << CP0St_SR); + memset(env->CP0_WatchLo, 0, sizeof(*env->CP0_WatchLo)); + goto set_error_EPC; + case EXCP_NMI: + env->CP0_Status |= (1 << CP0St_NMI); + set_error_EPC: + if (env->hflags & MIPS_HFLAG_BMASK) { + /* If the exception was raised from a delay slot, + come back to the jump. */ + env->CP0_ErrorEPC = env->active_tc.PC - 4; + env->hflags &= ~MIPS_HFLAG_BMASK; + } else { + env->CP0_ErrorEPC = env->active_tc.PC; } - env->CP0_Status |= (1 << CP0St_EXL); + env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; env->hflags &= ~(MIPS_HFLAG_KSU); + if (!(env->CP0_Status & (1 << CP0St_EXL))) + env->CP0_Cause &= ~(1 << CP0Ca_BD); + env->active_tc.PC = (int32_t)0xBFC00000; + break; + case EXCP_EXT_INTERRUPT: + cause = 0; + if (env->CP0_Cause & (1 << CP0Ca_IV)) + offset = 0x200; + goto set_EPC; + case EXCP_LTLBL: + cause = 1; + goto set_EPC; + case EXCP_TLBL: + cause = 2; + if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { +#if defined(TARGET_MIPS64) + int R = env->CP0_BadVAddr >> 62; + int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; + int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; + int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; + + if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) + offset = 0x080; + else +#endif + offset = 0x000; + } + goto set_EPC; + case EXCP_TLBS: + cause = 3; + if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { +#if defined(TARGET_MIPS64) + int R = env->CP0_BadVAddr >> 62; + int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; + int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; + int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; + + if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) + offset = 0x080; + else +#endif + offset = 0x000; + } + goto set_EPC; + case EXCP_AdEL: + cause = 4; + goto set_EPC; + case EXCP_AdES: + cause = 5; + goto set_EPC; + case EXCP_IBE: + cause = 6; + goto set_EPC; + case EXCP_DBE: + cause = 7; + goto set_EPC; + case EXCP_SYSCALL: + cause = 8; + goto set_EPC; + case EXCP_BREAK: + cause = 9; + goto set_EPC; + case EXCP_RI: + cause = 10; + goto set_EPC; + case EXCP_CpU: + cause = 11; + env->CP0_Cause = (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) | + (env->error_code << CP0Ca_CE); + goto set_EPC; + case EXCP_OVERFLOW: + cause = 12; + goto set_EPC; + case EXCP_TRAP: + cause = 13; + goto set_EPC; + case EXCP_FPE: + cause = 15; + goto set_EPC; + case EXCP_C2E: + cause = 18; + goto set_EPC; + case EXCP_MDMX: + cause = 22; + goto set_EPC; + case EXCP_DWATCH: + cause = 23; + /* XXX: TODO: manage defered watch exceptions */ + goto set_EPC; + case EXCP_MCHECK: + cause = 24; + goto set_EPC; + case EXCP_THREAD: + cause = 25; + goto set_EPC; + case EXCP_CACHE: + cause = 30; + if (env->CP0_Status & (1 << CP0St_BEV)) { + offset = 0x100; + } else { + offset = 0x20000100; + } + set_EPC: + if (!(env->CP0_Status & (1 << CP0St_EXL))) { + if (env->hflags & MIPS_HFLAG_BMASK) { + /* If the exception was raised from a delay slot, + come back to the jump. */ + env->CP0_EPC = env->active_tc.PC - 4; + env->CP0_Cause |= (1 << CP0Ca_BD); + } else { + env->CP0_EPC = env->active_tc.PC; + env->CP0_Cause &= ~(1 << CP0Ca_BD); + } + env->CP0_Status |= (1 << CP0St_EXL); + env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; + env->hflags &= ~(MIPS_HFLAG_KSU); + } + env->hflags &= ~MIPS_HFLAG_BMASK; + if (env->CP0_Status & (1 << CP0St_BEV)) { + env->active_tc.PC = (int32_t)0xBFC00200; + } else { + env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff); + } + env->active_tc.PC += offset; + env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC); + break; + default: + if (logfile) { + fprintf(logfile, "Invalid MIPS exception %d. Exiting\n", + env->exception_index); + } + printf("Invalid MIPS exception %d. Exiting\n", env->exception_index); + exit(1); } - env->hflags &= ~MIPS_HFLAG_BMASK; - if (env->CP0_Status & (1 << CP0St_BEV)) { - env->PC[env->current_tc] = (int32_t)0xBFC00200; - } else { - env->PC[env->current_tc] = (int32_t)(env->CP0_EBase & ~0x3ff); - } - env->PC[env->current_tc] += offset; - env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC); - break; - default: - if (logfile) { - fprintf(logfile, "Invalid MIPS exception %d. Exiting\n", - env->exception_index); + if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { + fprintf(logfile, "%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d\n" + " S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n", + __func__, env->active_tc.PC, env->CP0_EPC, cause, + env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr, + env->CP0_DEPC); } - printf("Invalid MIPS exception %d. Exiting\n", env->exception_index); - exit(1); - } - if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { - fprintf(logfile, "%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d\n" - " S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n", - __func__, env->PC[env->current_tc], env->CP0_EPC, cause, - env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr, - env->CP0_DEPC); } -#endif /* !defined(CONFIG_USER_ONLY) */ env->exception_index = EXCP_NONE; } @@ -630,7 +624,7 @@ } #endif end = addr | mask; - while (addr < end) { + while (addr - 1 < end) { tlb_flush_page (env, addr); addr += TARGET_PAGE_SIZE; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-mips/helper.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-mips/helper.h --- qemu-0.9.1/target-mips/helper.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-mips/helper.h 2008-11-11 11:47:06.000000000 +0000 @@ -0,0 +1,271 @@ +#ifndef DEF_HELPER +#define DEF_HELPER(ret, name, params) ret name params; +#endif + +DEF_HELPER(void, do_raise_exception_err, (int excp, int err)) +DEF_HELPER(void, do_raise_exception, (int excp)) +DEF_HELPER(void, do_interrupt_restart, (void)) + +#ifdef TARGET_MIPS64 +DEF_HELPER(target_ulong, do_ldl, (target_ulong t0, target_ulong t1, int mem_idx)) +DEF_HELPER(target_ulong, do_ldr, (target_ulong t0, target_ulong t1, int mem_idx)) +DEF_HELPER(void, do_sdl, (target_ulong t0, target_ulong t1, int mem_idx)) +DEF_HELPER(void, do_sdr, (target_ulong t0, target_ulong t1, int mem_idx)) +#endif +DEF_HELPER(target_ulong, do_lwl, (target_ulong t0, target_ulong t1, int mem_idx)) +DEF_HELPER(target_ulong, do_lwr, (target_ulong t0, target_ulong t1, int mem_idx)) +DEF_HELPER(void, do_swl, (target_ulong t0, target_ulong t1, int mem_idx)) +DEF_HELPER(void, do_swr, (target_ulong t0, target_ulong t1, int mem_idx)) + +DEF_HELPER(target_ulong, do_clo, (target_ulong t0)) +DEF_HELPER(target_ulong, do_clz, (target_ulong t0)) +#ifdef TARGET_MIPS64 +DEF_HELPER(target_ulong, do_dclo, (target_ulong t0)) +DEF_HELPER(target_ulong, do_dclz, (target_ulong t0)) +DEF_HELPER(void, do_dmult, (target_ulong t0, target_ulong t1)) +DEF_HELPER(void, do_dmultu, (target_ulong t0, target_ulong t1)) +#endif + +DEF_HELPER(target_ulong, do_muls, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, do_mulsu, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, do_macc, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, do_maccu, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, do_msac, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, do_msacu, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, do_mulhi, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, do_mulhiu, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, do_mulshi, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, do_mulshiu, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, do_macchi, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, do_macchiu, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, do_msachi, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, do_msachiu, (target_ulong t0, target_ulong t1)) + +#ifndef CONFIG_USER_ONLY +/* CP0 helpers */ +DEF_HELPER(target_ulong, do_mfc0_mvpcontrol, (void)) +DEF_HELPER(target_ulong, do_mfc0_mvpconf0, (void)) +DEF_HELPER(target_ulong, do_mfc0_mvpconf1, (void)) +DEF_HELPER(target_ulong, do_mfc0_random, (void)) +DEF_HELPER(target_ulong, do_mfc0_tcstatus, (void)) +DEF_HELPER(target_ulong, do_mftc0_tcstatus, (void)) +DEF_HELPER(target_ulong, do_mfc0_tcbind, (void)) +DEF_HELPER(target_ulong, do_mftc0_tcbind, (void)) +DEF_HELPER(target_ulong, do_mfc0_tcrestart, (void)) +DEF_HELPER(target_ulong, do_mftc0_tcrestart, (void)) +DEF_HELPER(target_ulong, do_mfc0_tchalt, (void)) +DEF_HELPER(target_ulong, do_mftc0_tchalt, (void)) +DEF_HELPER(target_ulong, do_mfc0_tccontext, (void)) +DEF_HELPER(target_ulong, do_mftc0_tccontext, (void)) +DEF_HELPER(target_ulong, do_mfc0_tcschedule, (void)) +DEF_HELPER(target_ulong, do_mftc0_tcschedule, (void)) +DEF_HELPER(target_ulong, do_mfc0_tcschefback, (void)) +DEF_HELPER(target_ulong, do_mftc0_tcschefback, (void)) +DEF_HELPER(target_ulong, do_mfc0_count, (void)) +DEF_HELPER(target_ulong, do_mftc0_entryhi, (void)) +DEF_HELPER(target_ulong, do_mftc0_status, (void)) +DEF_HELPER(target_ulong, do_mfc0_lladdr, (void)) +DEF_HELPER(target_ulong, do_mfc0_watchlo, (uint32_t sel)) +DEF_HELPER(target_ulong, do_mfc0_watchhi, (uint32_t sel)) +DEF_HELPER(target_ulong, do_mfc0_debug, (void)) +DEF_HELPER(target_ulong, do_mftc0_debug, (void)) +#ifdef TARGET_MIPS64 +DEF_HELPER(target_ulong, do_dmfc0_tcrestart, (void)) +DEF_HELPER(target_ulong, do_dmfc0_tchalt, (void)) +DEF_HELPER(target_ulong, do_dmfc0_tccontext, (void)) +DEF_HELPER(target_ulong, do_dmfc0_tcschedule, (void)) +DEF_HELPER(target_ulong, do_dmfc0_tcschefback, (void)) +DEF_HELPER(target_ulong, do_dmfc0_lladdr, (void)) +DEF_HELPER(target_ulong, do_dmfc0_watchlo, (uint32_t sel)) +#endif /* TARGET_MIPS64 */ + +DEF_HELPER(void, do_mtc0_index, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_mvpcontrol, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_vpecontrol, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_vpeconf0, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_vpeconf1, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_yqmask, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_vpeopt, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_entrylo0, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_tcstatus, (target_ulong t0)) +DEF_HELPER(void, do_mttc0_tcstatus, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_tcbind, (target_ulong t0)) +DEF_HELPER(void, do_mttc0_tcbind, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_tcrestart, (target_ulong t0)) +DEF_HELPER(void, do_mttc0_tcrestart, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_tchalt, (target_ulong t0)) +DEF_HELPER(void, do_mttc0_tchalt, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_tccontext, (target_ulong t0)) +DEF_HELPER(void, do_mttc0_tccontext, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_tcschedule, (target_ulong t0)) +DEF_HELPER(void, do_mttc0_tcschedule, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_tcschefback, (target_ulong t0)) +DEF_HELPER(void, do_mttc0_tcschefback, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_entrylo1, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_context, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_pagemask, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_pagegrain, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_wired, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_srsconf0, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_srsconf1, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_srsconf2, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_srsconf3, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_srsconf4, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_hwrena, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_count, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_entryhi, (target_ulong t0)) +DEF_HELPER(void, do_mttc0_entryhi, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_compare, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_status, (target_ulong t0)) +DEF_HELPER(void, do_mttc0_status, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_intctl, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_srsctl, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_cause, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_ebase, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_config0, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_config2, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_watchlo, (target_ulong t0, uint32_t sel)) +DEF_HELPER(void, do_mtc0_watchhi, (target_ulong t0, uint32_t sel)) +DEF_HELPER(void, do_mtc0_xcontext, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_framemask, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_debug, (target_ulong t0)) +DEF_HELPER(void, do_mttc0_debug, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_performance0, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_taglo, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_datalo, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_taghi, (target_ulong t0)) +DEF_HELPER(void, do_mtc0_datahi, (target_ulong t0)) + +/* MIPS MT functions */ +DEF_HELPER(target_ulong, do_mftgpr, (uint32_t sel)) +DEF_HELPER(target_ulong, do_mftlo, (uint32_t sel)) +DEF_HELPER(target_ulong, do_mfthi, (uint32_t sel)) +DEF_HELPER(target_ulong, do_mftacx, (uint32_t sel)) +DEF_HELPER(target_ulong, do_mftdsp, (void)) +DEF_HELPER(void, do_mttgpr, (target_ulong t0, uint32_t sel)) +DEF_HELPER(void, do_mttlo, (target_ulong t0, uint32_t sel)) +DEF_HELPER(void, do_mtthi, (target_ulong t0, uint32_t sel)) +DEF_HELPER(void, do_mttacx, (target_ulong t0, uint32_t sel)) +DEF_HELPER(void, do_mttdsp, (target_ulong t0)) +DEF_HELPER(target_ulong, do_dmt, (target_ulong t0)) +DEF_HELPER(target_ulong, do_emt, (target_ulong t0)) +DEF_HELPER(target_ulong, do_dvpe, (target_ulong t0)) +DEF_HELPER(target_ulong, do_evpe, (target_ulong t0)) +#endif /* !CONFIG_USER_ONLY */ +DEF_HELPER(void, do_fork, (target_ulong t0, target_ulong t1)) +DEF_HELPER(target_ulong, do_yield, (target_ulong t0)) + +/* CP1 functions */ +DEF_HELPER(target_ulong, do_cfc1, (uint32_t reg)) +DEF_HELPER(void, do_ctc1, (target_ulong t0, uint32_t reg)) + +DEF_HELPER(uint64_t, do_float_cvtd_s, (uint32_t fst0)) +DEF_HELPER(uint64_t, do_float_cvtd_w, (uint32_t wt0)) +DEF_HELPER(uint64_t, do_float_cvtd_l, (uint64_t dt0)) +DEF_HELPER(uint64_t, do_float_cvtl_d, (uint64_t fd0)) +DEF_HELPER(uint64_t, do_float_cvtl_s, (uint32_t fst0)) +DEF_HELPER(uint64_t, do_float_cvtps_pw, (uint64_t dt0)) +DEF_HELPER(uint64_t, do_float_cvtpw_ps, (uint64_t fdt0)) +DEF_HELPER(uint32_t, do_float_cvts_d, (uint64_t fd0)) +DEF_HELPER(uint32_t, do_float_cvts_w, (uint32_t wt0)) +DEF_HELPER(uint32_t, do_float_cvts_l, (uint64_t dt0)) +DEF_HELPER(uint32_t, do_float_cvts_pl, (uint32_t wt0)) +DEF_HELPER(uint32_t, do_float_cvts_pu, (uint32_t wth0)) +DEF_HELPER(uint32_t, do_float_cvtw_s, (uint32_t fst0)) +DEF_HELPER(uint32_t, do_float_cvtw_d, (uint64_t fd0)) + +DEF_HELPER(uint64_t, do_float_addr_ps, (uint64_t fdt0, uint64_t fdt1)) +DEF_HELPER(uint64_t, do_float_mulr_ps, (uint64_t fdt0, uint64_t fdt1)) + +#define FOP_PROTO(op) \ +DEF_HELPER(uint64_t, do_float_ ## op ## l_s, (uint32_t fst0)) \ +DEF_HELPER(uint64_t, do_float_ ## op ## l_d, (uint64_t fdt0)) \ +DEF_HELPER(uint32_t, do_float_ ## op ## w_s, (uint32_t fst0)) \ +DEF_HELPER(uint32_t, do_float_ ## op ## w_d, (uint64_t fdt0)) +FOP_PROTO(round) +FOP_PROTO(trunc) +FOP_PROTO(ceil) +FOP_PROTO(floor) +#undef FOP_PROTO + +#define FOP_PROTO(op) \ +DEF_HELPER(uint32_t, do_float_ ## op ## _s, (uint32_t fst0)) \ +DEF_HELPER(uint64_t, do_float_ ## op ## _d, (uint64_t fdt0)) +FOP_PROTO(sqrt) +FOP_PROTO(rsqrt) +FOP_PROTO(recip) +#undef FOP_PROTO + +#define FOP_PROTO(op) \ +DEF_HELPER(uint32_t, do_float_ ## op ## _s, (uint32_t fst0)) \ +DEF_HELPER(uint64_t, do_float_ ## op ## _d, (uint64_t fdt0)) \ +DEF_HELPER(uint64_t, do_float_ ## op ## _ps, (uint64_t fdt0)) +FOP_PROTO(abs) +FOP_PROTO(chs) +FOP_PROTO(recip1) +FOP_PROTO(rsqrt1) +#undef FOP_PROTO + +#define FOP_PROTO(op) \ +DEF_HELPER(uint32_t, do_float_ ## op ## _s, (uint32_t fst0, uint32_t fst2)) \ +DEF_HELPER(uint64_t, do_float_ ## op ## _d, (uint64_t fdt0, uint64_t fdt2)) \ +DEF_HELPER(uint64_t, do_float_ ## op ## _ps, (uint64_t fdt0, uint64_t fdt2)) +FOP_PROTO(add) +FOP_PROTO(sub) +FOP_PROTO(mul) +FOP_PROTO(div) +FOP_PROTO(recip2) +FOP_PROTO(rsqrt2) +#undef FOP_PROTO + +#define FOP_PROTO(op) \ +DEF_HELPER(uint32_t, do_float_ ## op ## _s, (uint32_t fst0, uint32_t fst1, \ + uint32_t fst2)) \ +DEF_HELPER(uint64_t, do_float_ ## op ## _d, (uint64_t fdt0, uint64_t fdt1, \ + uint64_t fdt2)) \ +DEF_HELPER(uint64_t, do_float_ ## op ## _ps, (uint64_t fdt0, uint64_t fdt1, \ + uint64_t fdt2)) +FOP_PROTO(muladd) +FOP_PROTO(mulsub) +FOP_PROTO(nmuladd) +FOP_PROTO(nmulsub) +#undef FOP_PROTO + +#define FOP_PROTO(op) \ +DEF_HELPER(void, do_cmp_d_ ## op, (uint64_t fdt0, uint64_t fdt1, int cc)) \ +DEF_HELPER(void, do_cmpabs_d_ ## op, (uint64_t fdt0, uint64_t fdt1, int cc)) \ +DEF_HELPER(void, do_cmp_s_ ## op, (uint32_t fst0, uint32_t fst1, int cc)) \ +DEF_HELPER(void, do_cmpabs_s_ ## op, (uint32_t fst0, uint32_t fst1, int cc)) \ +DEF_HELPER(void, do_cmp_ps_ ## op, (uint64_t fdt0, uint64_t fdt1, int cc)) \ +DEF_HELPER(void, do_cmpabs_ps_ ## op, (uint64_t fdt0, uint64_t fdt1, int cc)) +FOP_PROTO(f) +FOP_PROTO(un) +FOP_PROTO(eq) +FOP_PROTO(ueq) +FOP_PROTO(olt) +FOP_PROTO(ult) +FOP_PROTO(ole) +FOP_PROTO(ule) +FOP_PROTO(sf) +FOP_PROTO(ngle) +FOP_PROTO(seq) +FOP_PROTO(ngl) +FOP_PROTO(lt) +FOP_PROTO(nge) +FOP_PROTO(le) +FOP_PROTO(ngt) +#undef FOP_PROTO + +/* Special functions */ +#ifndef CONFIG_USER_ONLY +DEF_HELPER(target_ulong, do_di, (void)) +DEF_HELPER(target_ulong, do_ei, (void)) +DEF_HELPER(void, do_eret, (void)) +DEF_HELPER(void, do_deret, (void)) +#endif /* !CONFIG_USER_ONLY */ +DEF_HELPER(target_ulong, do_rdhwr_cpunum, (void)) +DEF_HELPER(target_ulong, do_rdhwr_synci_step, (void)) +DEF_HELPER(target_ulong, do_rdhwr_cc, (void)) +DEF_HELPER(target_ulong, do_rdhwr_ccres, (void)) +DEF_HELPER(void, do_pmon, (int function)) +DEF_HELPER(void, do_wait, (void)) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-mips/machine.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-mips/machine.c --- qemu-0.9.1/target-mips/machine.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-mips/machine.c 2008-07-05 22:51:47.000000000 +0100 @@ -0,0 +1,22 @@ +#include "hw/hw.h" +#include "hw/boards.h" + +void register_machines(void) +{ + qemu_register_machine(&mips_malta_machine); + qemu_register_machine(&mips_magnum_machine); + qemu_register_machine(&mips_pica61_machine); + qemu_register_machine(&mips_mipssim_machine); + qemu_register_machine(&mips_machine); +} + +void cpu_save(QEMUFile *f, void *opaque) +{ +} + +int cpu_load(QEMUFile *f, void *opaque, int version_id) +{ + return 0; +} + + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-mips/op.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-mips/op.c --- qemu-0.9.1/target-mips/op.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-mips/op.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,3338 +0,0 @@ -/* - * MIPS emulation micro-operations for qemu. - * - * Copyright (c) 2004-2005 Jocelyn Mayer - * Copyright (c) 2006 Marius Groeger (FPU operations) - * Copyright (c) 2007 Thiemo Seufer (64-bit FPU support) - * - * 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 "config.h" -#include "exec.h" -#include "host-utils.h" - -#ifndef CALL_FROM_TB0 -#define CALL_FROM_TB0(func) func() -#endif -#ifndef CALL_FROM_TB1 -#define CALL_FROM_TB1(func, arg0) func(arg0) -#endif -#ifndef CALL_FROM_TB1_CONST16 -#define CALL_FROM_TB1_CONST16(func, arg0) CALL_FROM_TB1(func, arg0) -#endif -#ifndef CALL_FROM_TB2 -#define CALL_FROM_TB2(func, arg0, arg1) func(arg0, arg1) -#endif -#ifndef CALL_FROM_TB2_CONST16 -#define CALL_FROM_TB2_CONST16(func, arg0, arg1) \ - CALL_FROM_TB2(func, arg0, arg1) -#endif -#ifndef CALL_FROM_TB3 -#define CALL_FROM_TB3(func, arg0, arg1, arg2) func(arg0, arg1, arg2) -#endif -#ifndef CALL_FROM_TB4 -#define CALL_FROM_TB4(func, arg0, arg1, arg2, arg3) \ - func(arg0, arg1, arg2, arg3) -#endif - -#define REG 1 -#include "op_template.c" -#undef REG -#define REG 2 -#include "op_template.c" -#undef REG -#define REG 3 -#include "op_template.c" -#undef REG -#define REG 4 -#include "op_template.c" -#undef REG -#define REG 5 -#include "op_template.c" -#undef REG -#define REG 6 -#include "op_template.c" -#undef REG -#define REG 7 -#include "op_template.c" -#undef REG -#define REG 8 -#include "op_template.c" -#undef REG -#define REG 9 -#include "op_template.c" -#undef REG -#define REG 10 -#include "op_template.c" -#undef REG -#define REG 11 -#include "op_template.c" -#undef REG -#define REG 12 -#include "op_template.c" -#undef REG -#define REG 13 -#include "op_template.c" -#undef REG -#define REG 14 -#include "op_template.c" -#undef REG -#define REG 15 -#include "op_template.c" -#undef REG -#define REG 16 -#include "op_template.c" -#undef REG -#define REG 17 -#include "op_template.c" -#undef REG -#define REG 18 -#include "op_template.c" -#undef REG -#define REG 19 -#include "op_template.c" -#undef REG -#define REG 20 -#include "op_template.c" -#undef REG -#define REG 21 -#include "op_template.c" -#undef REG -#define REG 22 -#include "op_template.c" -#undef REG -#define REG 23 -#include "op_template.c" -#undef REG -#define REG 24 -#include "op_template.c" -#undef REG -#define REG 25 -#include "op_template.c" -#undef REG -#define REG 26 -#include "op_template.c" -#undef REG -#define REG 27 -#include "op_template.c" -#undef REG -#define REG 28 -#include "op_template.c" -#undef REG -#define REG 29 -#include "op_template.c" -#undef REG -#define REG 30 -#include "op_template.c" -#undef REG -#define REG 31 -#include "op_template.c" -#undef REG - -#define TN -#include "op_template.c" -#undef TN - -#define FREG 0 -#include "fop_template.c" -#undef FREG -#define FREG 1 -#include "fop_template.c" -#undef FREG -#define FREG 2 -#include "fop_template.c" -#undef FREG -#define FREG 3 -#include "fop_template.c" -#undef FREG -#define FREG 4 -#include "fop_template.c" -#undef FREG -#define FREG 5 -#include "fop_template.c" -#undef FREG -#define FREG 6 -#include "fop_template.c" -#undef FREG -#define FREG 7 -#include "fop_template.c" -#undef FREG -#define FREG 8 -#include "fop_template.c" -#undef FREG -#define FREG 9 -#include "fop_template.c" -#undef FREG -#define FREG 10 -#include "fop_template.c" -#undef FREG -#define FREG 11 -#include "fop_template.c" -#undef FREG -#define FREG 12 -#include "fop_template.c" -#undef FREG -#define FREG 13 -#include "fop_template.c" -#undef FREG -#define FREG 14 -#include "fop_template.c" -#undef FREG -#define FREG 15 -#include "fop_template.c" -#undef FREG -#define FREG 16 -#include "fop_template.c" -#undef FREG -#define FREG 17 -#include "fop_template.c" -#undef FREG -#define FREG 18 -#include "fop_template.c" -#undef FREG -#define FREG 19 -#include "fop_template.c" -#undef FREG -#define FREG 20 -#include "fop_template.c" -#undef FREG -#define FREG 21 -#include "fop_template.c" -#undef FREG -#define FREG 22 -#include "fop_template.c" -#undef FREG -#define FREG 23 -#include "fop_template.c" -#undef FREG -#define FREG 24 -#include "fop_template.c" -#undef FREG -#define FREG 25 -#include "fop_template.c" -#undef FREG -#define FREG 26 -#include "fop_template.c" -#undef FREG -#define FREG 27 -#include "fop_template.c" -#undef FREG -#define FREG 28 -#include "fop_template.c" -#undef FREG -#define FREG 29 -#include "fop_template.c" -#undef FREG -#define FREG 30 -#include "fop_template.c" -#undef FREG -#define FREG 31 -#include "fop_template.c" -#undef FREG - -#define FTN -#include "fop_template.c" -#undef FTN - -void op_dup_T0 (void) -{ - T2 = T0; - FORCE_RET(); -} - -void op_load_HI (void) -{ - T0 = env->HI[PARAM1][env->current_tc]; - FORCE_RET(); -} - -void op_store_HI (void) -{ - env->HI[PARAM1][env->current_tc] = T0; - FORCE_RET(); -} - -void op_load_LO (void) -{ - T0 = env->LO[PARAM1][env->current_tc]; - FORCE_RET(); -} - -void op_store_LO (void) -{ - env->LO[PARAM1][env->current_tc] = T0; - FORCE_RET(); -} - -/* Load and store */ -#define MEMSUFFIX _raw -#include "op_mem.c" -#undef MEMSUFFIX -#if !defined(CONFIG_USER_ONLY) -#define MEMSUFFIX _user -#include "op_mem.c" -#undef MEMSUFFIX - -#define MEMSUFFIX _super -#include "op_mem.c" -#undef MEMSUFFIX - -#define MEMSUFFIX _kernel -#include "op_mem.c" -#undef MEMSUFFIX -#endif - -/* Addresses computation */ -void op_addr_add (void) -{ -/* For compatibility with 32-bit code, data reference in user mode - with Status_UX = 0 should be casted to 32-bit and sign extended. - See the MIPS64 PRA manual, section 4.10. */ -#if defined(TARGET_MIPS64) - if (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && - !(env->CP0_Status & (1 << CP0St_UX))) - T0 = (int64_t)(int32_t)(T0 + T1); - else -#endif - T0 += T1; - FORCE_RET(); -} - -/* Arithmetic */ -void op_add (void) -{ - T0 = (int32_t)((int32_t)T0 + (int32_t)T1); - FORCE_RET(); -} - -void op_addo (void) -{ - target_ulong tmp; - - tmp = (int32_t)T0; - T0 = (int32_t)T0 + (int32_t)T1; - if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 31) { - /* operands of same sign, result different sign */ - CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); - } - T0 = (int32_t)T0; - FORCE_RET(); -} - -void op_sub (void) -{ - T0 = (int32_t)((int32_t)T0 - (int32_t)T1); - FORCE_RET(); -} - -void op_subo (void) -{ - target_ulong tmp; - - tmp = (int32_t)T0; - T0 = (int32_t)T0 - (int32_t)T1; - if (((tmp ^ T1) & (tmp ^ T0)) >> 31) { - /* operands of different sign, first operand and result different sign */ - CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); - } - T0 = (int32_t)T0; - FORCE_RET(); -} - -void op_mul (void) -{ - T0 = (int32_t)((int32_t)T0 * (int32_t)T1); - FORCE_RET(); -} - -#if HOST_LONG_BITS < 64 -void op_div (void) -{ - CALL_FROM_TB0(do_div); - FORCE_RET(); -} -#else -void op_div (void) -{ - if (T1 != 0) { - env->LO[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1); - env->HI[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1); - } - FORCE_RET(); -} -#endif - -void op_divu (void) -{ - if (T1 != 0) { - env->LO[0][env->current_tc] = (int32_t)((uint32_t)T0 / (uint32_t)T1); - env->HI[0][env->current_tc] = (int32_t)((uint32_t)T0 % (uint32_t)T1); - } - FORCE_RET(); -} - -#if defined(TARGET_MIPS64) -/* Arithmetic */ -void op_dadd (void) -{ - T0 += T1; - FORCE_RET(); -} - -void op_daddo (void) -{ - target_long tmp; - - tmp = T0; - T0 += T1; - if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 63) { - /* operands of same sign, result different sign */ - CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); - } - FORCE_RET(); -} - -void op_dsub (void) -{ - T0 -= T1; - FORCE_RET(); -} - -void op_dsubo (void) -{ - target_long tmp; - - tmp = T0; - T0 = (int64_t)T0 - (int64_t)T1; - if (((tmp ^ T1) & (tmp ^ T0)) >> 63) { - /* operands of different sign, first operand and result different sign */ - CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); - } - FORCE_RET(); -} - -void op_dmul (void) -{ - T0 = (int64_t)T0 * (int64_t)T1; - FORCE_RET(); -} - -/* Those might call libgcc functions. */ -void op_ddiv (void) -{ - do_ddiv(); - FORCE_RET(); -} - -#if TARGET_LONG_BITS > HOST_LONG_BITS -void op_ddivu (void) -{ - do_ddivu(); - FORCE_RET(); -} -#else -void op_ddivu (void) -{ - if (T1 != 0) { - env->LO[0][env->current_tc] = T0 / T1; - env->HI[0][env->current_tc] = T0 % T1; - } - FORCE_RET(); -} -#endif -#endif /* TARGET_MIPS64 */ - -/* Logical */ -void op_and (void) -{ - T0 &= T1; - FORCE_RET(); -} - -void op_nor (void) -{ - T0 = ~(T0 | T1); - FORCE_RET(); -} - -void op_or (void) -{ - T0 |= T1; - FORCE_RET(); -} - -void op_xor (void) -{ - T0 ^= T1; - FORCE_RET(); -} - -void op_sll (void) -{ - T0 = (int32_t)((uint32_t)T0 << T1); - FORCE_RET(); -} - -void op_sra (void) -{ - T0 = (int32_t)((int32_t)T0 >> T1); - FORCE_RET(); -} - -void op_srl (void) -{ - T0 = (int32_t)((uint32_t)T0 >> T1); - FORCE_RET(); -} - -void op_rotr (void) -{ - target_ulong tmp; - - if (T1) { - tmp = (int32_t)((uint32_t)T0 << (0x20 - T1)); - T0 = (int32_t)((uint32_t)T0 >> T1) | tmp; - } - FORCE_RET(); -} - -void op_sllv (void) -{ - T0 = (int32_t)((uint32_t)T1 << ((uint32_t)T0 & 0x1F)); - FORCE_RET(); -} - -void op_srav (void) -{ - T0 = (int32_t)((int32_t)T1 >> (T0 & 0x1F)); - FORCE_RET(); -} - -void op_srlv (void) -{ - T0 = (int32_t)((uint32_t)T1 >> (T0 & 0x1F)); - FORCE_RET(); -} - -void op_rotrv (void) -{ - target_ulong tmp; - - T0 &= 0x1F; - if (T0) { - tmp = (int32_t)((uint32_t)T1 << (0x20 - T0)); - T0 = (int32_t)((uint32_t)T1 >> T0) | tmp; - } else - T0 = T1; - FORCE_RET(); -} - -void op_clo (void) -{ - T0 = clo32(T0); - FORCE_RET(); -} - -void op_clz (void) -{ - T0 = clz32(T0); - FORCE_RET(); -} - -#if defined(TARGET_MIPS64) - -#if TARGET_LONG_BITS > HOST_LONG_BITS -/* Those might call libgcc functions. */ -void op_dsll (void) -{ - CALL_FROM_TB0(do_dsll); - FORCE_RET(); -} - -void op_dsll32 (void) -{ - CALL_FROM_TB0(do_dsll32); - FORCE_RET(); -} - -void op_dsra (void) -{ - CALL_FROM_TB0(do_dsra); - FORCE_RET(); -} - -void op_dsra32 (void) -{ - CALL_FROM_TB0(do_dsra32); - FORCE_RET(); -} - -void op_dsrl (void) -{ - CALL_FROM_TB0(do_dsrl); - FORCE_RET(); -} - -void op_dsrl32 (void) -{ - CALL_FROM_TB0(do_dsrl32); - FORCE_RET(); -} - -void op_drotr (void) -{ - CALL_FROM_TB0(do_drotr); - FORCE_RET(); -} - -void op_drotr32 (void) -{ - CALL_FROM_TB0(do_drotr32); - FORCE_RET(); -} - -void op_dsllv (void) -{ - CALL_FROM_TB0(do_dsllv); - FORCE_RET(); -} - -void op_dsrav (void) -{ - CALL_FROM_TB0(do_dsrav); - FORCE_RET(); -} - -void op_dsrlv (void) -{ - CALL_FROM_TB0(do_dsrlv); - FORCE_RET(); -} - -void op_drotrv (void) -{ - CALL_FROM_TB0(do_drotrv); - FORCE_RET(); -} - -void op_dclo (void) -{ - CALL_FROM_TB0(do_dclo); - FORCE_RET(); -} - -void op_dclz (void) -{ - CALL_FROM_TB0(do_dclz); - FORCE_RET(); -} - -#else /* TARGET_LONG_BITS > HOST_LONG_BITS */ - -void op_dsll (void) -{ - T0 = T0 << T1; - FORCE_RET(); -} - -void op_dsll32 (void) -{ - T0 = T0 << (T1 + 32); - FORCE_RET(); -} - -void op_dsra (void) -{ - T0 = (int64_t)T0 >> T1; - FORCE_RET(); -} - -void op_dsra32 (void) -{ - T0 = (int64_t)T0 >> (T1 + 32); - FORCE_RET(); -} - -void op_dsrl (void) -{ - T0 = T0 >> T1; - FORCE_RET(); -} - -void op_dsrl32 (void) -{ - T0 = T0 >> (T1 + 32); - FORCE_RET(); -} - -void op_drotr (void) -{ - target_ulong tmp; - - if (T1) { - tmp = T0 << (0x40 - T1); - T0 = (T0 >> T1) | tmp; - } - FORCE_RET(); -} - -void op_drotr32 (void) -{ - target_ulong tmp; - - tmp = T0 << (0x40 - (32 + T1)); - T0 = (T0 >> (32 + T1)) | tmp; - FORCE_RET(); -} - -void op_dsllv (void) -{ - T0 = T1 << (T0 & 0x3F); - FORCE_RET(); -} - -void op_dsrav (void) -{ - T0 = (int64_t)T1 >> (T0 & 0x3F); - FORCE_RET(); -} - -void op_dsrlv (void) -{ - T0 = T1 >> (T0 & 0x3F); - FORCE_RET(); -} - -void op_drotrv (void) -{ - target_ulong tmp; - - T0 &= 0x3F; - if (T0) { - tmp = T1 << (0x40 - T0); - T0 = (T1 >> T0) | tmp; - } else - T0 = T1; - FORCE_RET(); -} - -void op_dclo (void) -{ - T0 = clo64(T0); - FORCE_RET(); -} - -void op_dclz (void) -{ - T0 = clz64(T0); - FORCE_RET(); -} -#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ -#endif /* TARGET_MIPS64 */ - -/* 64 bits arithmetic */ -#if TARGET_LONG_BITS > HOST_LONG_BITS -void op_mult (void) -{ - CALL_FROM_TB0(do_mult); - FORCE_RET(); -} - -void op_multu (void) -{ - CALL_FROM_TB0(do_multu); - FORCE_RET(); -} - -void op_madd (void) -{ - CALL_FROM_TB0(do_madd); - FORCE_RET(); -} - -void op_maddu (void) -{ - CALL_FROM_TB0(do_maddu); - FORCE_RET(); -} - -void op_msub (void) -{ - CALL_FROM_TB0(do_msub); - FORCE_RET(); -} - -void op_msubu (void) -{ - CALL_FROM_TB0(do_msubu); - FORCE_RET(); -} - -/* Multiplication variants of the vr54xx. */ -void op_muls (void) -{ - CALL_FROM_TB0(do_muls); - FORCE_RET(); -} - -void op_mulsu (void) -{ - CALL_FROM_TB0(do_mulsu); - FORCE_RET(); -} - -void op_macc (void) -{ - CALL_FROM_TB0(do_macc); - FORCE_RET(); -} - -void op_macchi (void) -{ - CALL_FROM_TB0(do_macchi); - FORCE_RET(); -} - -void op_maccu (void) -{ - CALL_FROM_TB0(do_maccu); - FORCE_RET(); -} -void op_macchiu (void) -{ - CALL_FROM_TB0(do_macchiu); - FORCE_RET(); -} - -void op_msac (void) -{ - CALL_FROM_TB0(do_msac); - FORCE_RET(); -} - -void op_msachi (void) -{ - CALL_FROM_TB0(do_msachi); - FORCE_RET(); -} - -void op_msacu (void) -{ - CALL_FROM_TB0(do_msacu); - FORCE_RET(); -} - -void op_msachiu (void) -{ - CALL_FROM_TB0(do_msachiu); - FORCE_RET(); -} - -void op_mulhi (void) -{ - CALL_FROM_TB0(do_mulhi); - FORCE_RET(); -} - -void op_mulhiu (void) -{ - CALL_FROM_TB0(do_mulhiu); - FORCE_RET(); -} - -void op_mulshi (void) -{ - CALL_FROM_TB0(do_mulshi); - FORCE_RET(); -} - -void op_mulshiu (void) -{ - CALL_FROM_TB0(do_mulshiu); - FORCE_RET(); -} - -#else /* TARGET_LONG_BITS > HOST_LONG_BITS */ - -static always_inline uint64_t get_HILO (void) -{ - return ((uint64_t)env->HI[0][env->current_tc] << 32) | - ((uint64_t)(uint32_t)env->LO[0][env->current_tc]); -} - -static always_inline void set_HILO (uint64_t HILO) -{ - env->LO[0][env->current_tc] = (int32_t)(HILO & 0xFFFFFFFF); - env->HI[0][env->current_tc] = (int32_t)(HILO >> 32); -} - -static always_inline void set_HIT0_LO (uint64_t HILO) -{ - env->LO[0][env->current_tc] = (int32_t)(HILO & 0xFFFFFFFF); - T0 = env->HI[0][env->current_tc] = (int32_t)(HILO >> 32); -} - -static always_inline void set_HI_LOT0 (uint64_t HILO) -{ - T0 = env->LO[0][env->current_tc] = (int32_t)(HILO & 0xFFFFFFFF); - env->HI[0][env->current_tc] = (int32_t)(HILO >> 32); -} - -void op_mult (void) -{ - set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); - FORCE_RET(); -} - -void op_multu (void) -{ - set_HILO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); - FORCE_RET(); -} - -void op_madd (void) -{ - int64_t tmp; - - tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); - set_HILO((int64_t)get_HILO() + tmp); - FORCE_RET(); -} - -void op_maddu (void) -{ - uint64_t tmp; - - tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); - set_HILO(get_HILO() + tmp); - FORCE_RET(); -} - -void op_msub (void) -{ - int64_t tmp; - - tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); - set_HILO((int64_t)get_HILO() - tmp); - FORCE_RET(); -} - -void op_msubu (void) -{ - uint64_t tmp; - - tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); - set_HILO(get_HILO() - tmp); - FORCE_RET(); -} - -/* Multiplication variants of the vr54xx. */ -void op_muls (void) -{ - set_HI_LOT0(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1)); - FORCE_RET(); -} - -void op_mulsu (void) -{ - set_HI_LOT0(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1)); - FORCE_RET(); -} - -void op_macc (void) -{ - set_HI_LOT0(get_HILO() + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1)); - FORCE_RET(); -} - -void op_macchi (void) -{ - set_HIT0_LO(get_HILO() + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1)); - FORCE_RET(); -} - -void op_maccu (void) -{ - set_HI_LOT0(get_HILO() + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1)); - FORCE_RET(); -} - -void op_macchiu (void) -{ - set_HIT0_LO(get_HILO() + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1)); - FORCE_RET(); -} - -void op_msac (void) -{ - set_HI_LOT0(get_HILO() - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1)); - FORCE_RET(); -} - -void op_msachi (void) -{ - set_HIT0_LO(get_HILO() - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1)); - FORCE_RET(); -} - -void op_msacu (void) -{ - set_HI_LOT0(get_HILO() - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1)); - FORCE_RET(); -} - -void op_msachiu (void) -{ - set_HIT0_LO(get_HILO() - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1)); - FORCE_RET(); -} - -void op_mulhi (void) -{ - set_HIT0_LO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); - FORCE_RET(); -} - -void op_mulhiu (void) -{ - set_HIT0_LO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); - FORCE_RET(); -} - -void op_mulshi (void) -{ - set_HIT0_LO(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1)); - FORCE_RET(); -} - -void op_mulshiu (void) -{ - set_HIT0_LO(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1)); - FORCE_RET(); -} - -#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ - -#if defined(TARGET_MIPS64) -void op_dmult (void) -{ - CALL_FROM_TB4(muls64, &(env->LO[0][env->current_tc]), &(env->HI[0][env->current_tc]), T0, T1); - FORCE_RET(); -} - -void op_dmultu (void) -{ - CALL_FROM_TB4(mulu64, &(env->LO[0][env->current_tc]), &(env->HI[0][env->current_tc]), T0, T1); - FORCE_RET(); -} -#endif - -/* Conditional moves */ -void op_movn (void) -{ - if (T1 != 0) - env->gpr[PARAM1][env->current_tc] = T0; - FORCE_RET(); -} - -void op_movz (void) -{ - if (T1 == 0) - env->gpr[PARAM1][env->current_tc] = T0; - FORCE_RET(); -} - -void op_movf (void) -{ - if (!(env->fpu->fcr31 & PARAM1)) - T0 = T1; - FORCE_RET(); -} - -void op_movt (void) -{ - if (env->fpu->fcr31 & PARAM1) - T0 = T1; - FORCE_RET(); -} - -/* Tests */ -#define OP_COND(name, cond) \ -void glue(op_, name) (void) \ -{ \ - if (cond) { \ - T0 = 1; \ - } else { \ - T0 = 0; \ - } \ - FORCE_RET(); \ -} - -OP_COND(eq, T0 == T1); -OP_COND(ne, T0 != T1); -OP_COND(ge, (target_long)T0 >= (target_long)T1); -OP_COND(geu, T0 >= T1); -OP_COND(lt, (target_long)T0 < (target_long)T1); -OP_COND(ltu, T0 < T1); -OP_COND(gez, (target_long)T0 >= 0); -OP_COND(gtz, (target_long)T0 > 0); -OP_COND(lez, (target_long)T0 <= 0); -OP_COND(ltz, (target_long)T0 < 0); - -/* Branches */ -void OPPROTO op_goto_tb0(void) -{ - GOTO_TB(op_goto_tb0, PARAM1, 0); - FORCE_RET(); -} - -void OPPROTO op_goto_tb1(void) -{ - GOTO_TB(op_goto_tb1, PARAM1, 1); - FORCE_RET(); -} - -/* Branch to register */ -void op_save_breg_target (void) -{ - env->btarget = T2; - FORCE_RET(); -} - -void op_restore_breg_target (void) -{ - T2 = env->btarget; - FORCE_RET(); -} - -void op_breg (void) -{ - env->PC[env->current_tc] = T2; - FORCE_RET(); -} - -void op_save_btarget (void) -{ - env->btarget = PARAM1; - FORCE_RET(); -} - -#if defined(TARGET_MIPS64) -void op_save_btarget64 (void) -{ - env->btarget = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2; - FORCE_RET(); -} -#endif - -/* Conditional branch */ -void op_set_bcond (void) -{ - T2 = T0; - FORCE_RET(); -} - -void op_save_bcond (void) -{ - env->bcond = T2; - FORCE_RET(); -} - -void op_restore_bcond (void) -{ - T2 = env->bcond; - FORCE_RET(); -} - -void op_jnz_T2 (void) -{ - if (T2) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -/* CP0 functions */ -void op_mfc0_index (void) -{ - T0 = env->CP0_Index; - FORCE_RET(); -} - -void op_mfc0_mvpcontrol (void) -{ - T0 = env->mvp->CP0_MVPControl; - FORCE_RET(); -} - -void op_mfc0_mvpconf0 (void) -{ - T0 = env->mvp->CP0_MVPConf0; - FORCE_RET(); -} - -void op_mfc0_mvpconf1 (void) -{ - T0 = env->mvp->CP0_MVPConf1; - FORCE_RET(); -} - -void op_mfc0_random (void) -{ - CALL_FROM_TB0(do_mfc0_random); - FORCE_RET(); -} - -void op_mfc0_vpecontrol (void) -{ - T0 = env->CP0_VPEControl; - FORCE_RET(); -} - -void op_mfc0_vpeconf0 (void) -{ - T0 = env->CP0_VPEConf0; - FORCE_RET(); -} - -void op_mfc0_vpeconf1 (void) -{ - T0 = env->CP0_VPEConf1; - FORCE_RET(); -} - -void op_mfc0_yqmask (void) -{ - T0 = env->CP0_YQMask; - FORCE_RET(); -} - -void op_mfc0_vpeschedule (void) -{ - T0 = env->CP0_VPESchedule; - FORCE_RET(); -} - -void op_mfc0_vpeschefback (void) -{ - T0 = env->CP0_VPEScheFBack; - FORCE_RET(); -} - -void op_mfc0_vpeopt (void) -{ - T0 = env->CP0_VPEOpt; - FORCE_RET(); -} - -void op_mfc0_entrylo0 (void) -{ - T0 = (int32_t)env->CP0_EntryLo0; - FORCE_RET(); -} - -void op_mfc0_tcstatus (void) -{ - T0 = env->CP0_TCStatus[env->current_tc]; - FORCE_RET(); -} - -void op_mftc0_tcstatus(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - T0 = env->CP0_TCStatus[other_tc]; - FORCE_RET(); -} - -void op_mfc0_tcbind (void) -{ - T0 = env->CP0_TCBind[env->current_tc]; - FORCE_RET(); -} - -void op_mftc0_tcbind(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - T0 = env->CP0_TCBind[other_tc]; - FORCE_RET(); -} - -void op_mfc0_tcrestart (void) -{ - T0 = env->PC[env->current_tc]; - FORCE_RET(); -} - -void op_mftc0_tcrestart(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - T0 = env->PC[other_tc]; - FORCE_RET(); -} - -void op_mfc0_tchalt (void) -{ - T0 = env->CP0_TCHalt[env->current_tc]; - FORCE_RET(); -} - -void op_mftc0_tchalt(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - T0 = env->CP0_TCHalt[other_tc]; - FORCE_RET(); -} - -void op_mfc0_tccontext (void) -{ - T0 = env->CP0_TCContext[env->current_tc]; - FORCE_RET(); -} - -void op_mftc0_tccontext(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - T0 = env->CP0_TCContext[other_tc]; - FORCE_RET(); -} - -void op_mfc0_tcschedule (void) -{ - T0 = env->CP0_TCSchedule[env->current_tc]; - FORCE_RET(); -} - -void op_mftc0_tcschedule(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - T0 = env->CP0_TCSchedule[other_tc]; - FORCE_RET(); -} - -void op_mfc0_tcschefback (void) -{ - T0 = env->CP0_TCScheFBack[env->current_tc]; - FORCE_RET(); -} - -void op_mftc0_tcschefback(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - T0 = env->CP0_TCScheFBack[other_tc]; - FORCE_RET(); -} - -void op_mfc0_entrylo1 (void) -{ - T0 = (int32_t)env->CP0_EntryLo1; - FORCE_RET(); -} - -void op_mfc0_context (void) -{ - T0 = (int32_t)env->CP0_Context; - FORCE_RET(); -} - -void op_mfc0_pagemask (void) -{ - T0 = env->CP0_PageMask; - FORCE_RET(); -} - -void op_mfc0_pagegrain (void) -{ - T0 = env->CP0_PageGrain; - FORCE_RET(); -} - -void op_mfc0_wired (void) -{ - T0 = env->CP0_Wired; - FORCE_RET(); -} - -void op_mfc0_srsconf0 (void) -{ - T0 = env->CP0_SRSConf0; - FORCE_RET(); -} - -void op_mfc0_srsconf1 (void) -{ - T0 = env->CP0_SRSConf1; - FORCE_RET(); -} - -void op_mfc0_srsconf2 (void) -{ - T0 = env->CP0_SRSConf2; - FORCE_RET(); -} - -void op_mfc0_srsconf3 (void) -{ - T0 = env->CP0_SRSConf3; - FORCE_RET(); -} - -void op_mfc0_srsconf4 (void) -{ - T0 = env->CP0_SRSConf4; - FORCE_RET(); -} - -void op_mfc0_hwrena (void) -{ - T0 = env->CP0_HWREna; - FORCE_RET(); -} - -void op_mfc0_badvaddr (void) -{ - T0 = (int32_t)env->CP0_BadVAddr; - FORCE_RET(); -} - -void op_mfc0_count (void) -{ - CALL_FROM_TB0(do_mfc0_count); - FORCE_RET(); -} - -void op_mfc0_entryhi (void) -{ - T0 = (int32_t)env->CP0_EntryHi; - FORCE_RET(); -} - -void op_mftc0_entryhi(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - T0 = (env->CP0_EntryHi & ~0xff) | (env->CP0_TCStatus[other_tc] & 0xff); - FORCE_RET(); -} - -void op_mfc0_compare (void) -{ - T0 = env->CP0_Compare; - FORCE_RET(); -} - -void op_mfc0_status (void) -{ - T0 = env->CP0_Status; - FORCE_RET(); -} - -void op_mftc0_status(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - uint32_t tcstatus = env->CP0_TCStatus[other_tc]; - - T0 = env->CP0_Status & ~0xf1000018; - T0 |= tcstatus & (0xf << CP0TCSt_TCU0); - T0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX); - T0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_KSU); - FORCE_RET(); -} - -void op_mfc0_intctl (void) -{ - T0 = env->CP0_IntCtl; - FORCE_RET(); -} - -void op_mfc0_srsctl (void) -{ - T0 = env->CP0_SRSCtl; - FORCE_RET(); -} - -void op_mfc0_srsmap (void) -{ - T0 = env->CP0_SRSMap; - FORCE_RET(); -} - -void op_mfc0_cause (void) -{ - T0 = env->CP0_Cause; - FORCE_RET(); -} - -void op_mfc0_epc (void) -{ - T0 = (int32_t)env->CP0_EPC; - FORCE_RET(); -} - -void op_mfc0_prid (void) -{ - T0 = env->CP0_PRid; - FORCE_RET(); -} - -void op_mfc0_ebase (void) -{ - T0 = env->CP0_EBase; - FORCE_RET(); -} - -void op_mfc0_config0 (void) -{ - T0 = env->CP0_Config0; - FORCE_RET(); -} - -void op_mfc0_config1 (void) -{ - T0 = env->CP0_Config1; - FORCE_RET(); -} - -void op_mfc0_config2 (void) -{ - T0 = env->CP0_Config2; - FORCE_RET(); -} - -void op_mfc0_config3 (void) -{ - T0 = env->CP0_Config3; - FORCE_RET(); -} - -void op_mfc0_config6 (void) -{ - T0 = env->CP0_Config6; - FORCE_RET(); -} - -void op_mfc0_config7 (void) -{ - T0 = env->CP0_Config7; - FORCE_RET(); -} - -void op_mfc0_lladdr (void) -{ - T0 = (int32_t)env->CP0_LLAddr >> 4; - FORCE_RET(); -} - -void op_mfc0_watchlo (void) -{ - T0 = (int32_t)env->CP0_WatchLo[PARAM1]; - FORCE_RET(); -} - -void op_mfc0_watchhi (void) -{ - T0 = env->CP0_WatchHi[PARAM1]; - FORCE_RET(); -} - -void op_mfc0_xcontext (void) -{ - T0 = (int32_t)env->CP0_XContext; - FORCE_RET(); -} - -void op_mfc0_framemask (void) -{ - T0 = env->CP0_Framemask; - FORCE_RET(); -} - -void op_mfc0_debug (void) -{ - T0 = env->CP0_Debug; - if (env->hflags & MIPS_HFLAG_DM) - T0 |= 1 << CP0DB_DM; - FORCE_RET(); -} - -void op_mftc0_debug(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - /* XXX: Might be wrong, check with EJTAG spec. */ - T0 = (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) | - (env->CP0_Debug_tcstatus[other_tc] & - ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))); - FORCE_RET(); -} - -void op_mfc0_depc (void) -{ - T0 = (int32_t)env->CP0_DEPC; - FORCE_RET(); -} - -void op_mfc0_performance0 (void) -{ - T0 = env->CP0_Performance0; - FORCE_RET(); -} - -void op_mfc0_taglo (void) -{ - T0 = env->CP0_TagLo; - FORCE_RET(); -} - -void op_mfc0_datalo (void) -{ - T0 = env->CP0_DataLo; - FORCE_RET(); -} - -void op_mfc0_taghi (void) -{ - T0 = env->CP0_TagHi; - FORCE_RET(); -} - -void op_mfc0_datahi (void) -{ - T0 = env->CP0_DataHi; - FORCE_RET(); -} - -void op_mfc0_errorepc (void) -{ - T0 = (int32_t)env->CP0_ErrorEPC; - FORCE_RET(); -} - -void op_mfc0_desave (void) -{ - T0 = env->CP0_DESAVE; - FORCE_RET(); -} - -void op_mtc0_index (void) -{ - int num = 1; - unsigned int tmp = env->tlb->nb_tlb; - - do { - tmp >>= 1; - num <<= 1; - } while (tmp); - env->CP0_Index = (env->CP0_Index & 0x80000000) | (T0 & (num - 1)); - FORCE_RET(); -} - -void op_mtc0_mvpcontrol (void) -{ - uint32_t mask = 0; - uint32_t newval; - - if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) - mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) | - (1 << CP0MVPCo_EVP); - if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) - mask |= (1 << CP0MVPCo_STLB); - newval = (env->mvp->CP0_MVPControl & ~mask) | (T0 & mask); - - // TODO: Enable/disable shared TLB, enable/disable VPEs. - - env->mvp->CP0_MVPControl = newval; - FORCE_RET(); -} - -void op_mtc0_vpecontrol (void) -{ - uint32_t mask; - uint32_t newval; - - mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) | - (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC); - newval = (env->CP0_VPEControl & ~mask) | (T0 & mask); - - /* Yield scheduler intercept not implemented. */ - /* Gating storage scheduler intercept not implemented. */ - - // TODO: Enable/disable TCs. - - env->CP0_VPEControl = newval; - FORCE_RET(); -} - -void op_mtc0_vpeconf0 (void) -{ - uint32_t mask = 0; - uint32_t newval; - - if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) { - if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA)) - mask |= (0xff << CP0VPEC0_XTC); - mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA); - } - newval = (env->CP0_VPEConf0 & ~mask) | (T0 & mask); - - // TODO: TC exclusive handling due to ERL/EXL. - - env->CP0_VPEConf0 = newval; - FORCE_RET(); -} - -void op_mtc0_vpeconf1 (void) -{ - uint32_t mask = 0; - uint32_t newval; - - if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) - mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) | - (0xff << CP0VPEC1_NCP1); - newval = (env->CP0_VPEConf1 & ~mask) | (T0 & mask); - - /* UDI not implemented. */ - /* CP2 not implemented. */ - - // TODO: Handle FPU (CP1) binding. - - env->CP0_VPEConf1 = newval; - FORCE_RET(); -} - -void op_mtc0_yqmask (void) -{ - /* Yield qualifier inputs not implemented. */ - env->CP0_YQMask = 0x00000000; - FORCE_RET(); -} - -void op_mtc0_vpeschedule (void) -{ - env->CP0_VPESchedule = T0; - FORCE_RET(); -} - -void op_mtc0_vpeschefback (void) -{ - env->CP0_VPEScheFBack = T0; - FORCE_RET(); -} - -void op_mtc0_vpeopt (void) -{ - env->CP0_VPEOpt = T0 & 0x0000ffff; - FORCE_RET(); -} - -void op_mtc0_entrylo0 (void) -{ - /* Large physaddr (PABITS) not implemented */ - /* 1k pages not implemented */ - env->CP0_EntryLo0 = T0 & 0x3FFFFFFF; - FORCE_RET(); -} - -void op_mtc0_tcstatus (void) -{ - uint32_t mask = env->CP0_TCStatus_rw_bitmask; - uint32_t newval; - - newval = (env->CP0_TCStatus[env->current_tc] & ~mask) | (T0 & mask); - - // TODO: Sync with CP0_Status. - - env->CP0_TCStatus[env->current_tc] = newval; - FORCE_RET(); -} - -void op_mttc0_tcstatus (void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - // TODO: Sync with CP0_Status. - - env->CP0_TCStatus[other_tc] = T0; - FORCE_RET(); -} - -void op_mtc0_tcbind (void) -{ - uint32_t mask = (1 << CP0TCBd_TBE); - uint32_t newval; - - if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) - mask |= (1 << CP0TCBd_CurVPE); - newval = (env->CP0_TCBind[env->current_tc] & ~mask) | (T0 & mask); - env->CP0_TCBind[env->current_tc] = newval; - FORCE_RET(); -} - -void op_mttc0_tcbind (void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - uint32_t mask = (1 << CP0TCBd_TBE); - uint32_t newval; - - if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) - mask |= (1 << CP0TCBd_CurVPE); - newval = (env->CP0_TCBind[other_tc] & ~mask) | (T0 & mask); - env->CP0_TCBind[other_tc] = newval; - FORCE_RET(); -} - -void op_mtc0_tcrestart (void) -{ - env->PC[env->current_tc] = T0; - env->CP0_TCStatus[env->current_tc] &= ~(1 << CP0TCSt_TDS); - env->CP0_LLAddr = 0ULL; - /* MIPS16 not implemented. */ - FORCE_RET(); -} - -void op_mttc0_tcrestart (void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - env->PC[other_tc] = T0; - env->CP0_TCStatus[other_tc] &= ~(1 << CP0TCSt_TDS); - env->CP0_LLAddr = 0ULL; - /* MIPS16 not implemented. */ - FORCE_RET(); -} - -void op_mtc0_tchalt (void) -{ - env->CP0_TCHalt[env->current_tc] = T0 & 0x1; - - // TODO: Halt TC / Restart (if allocated+active) TC. - - FORCE_RET(); -} - -void op_mttc0_tchalt (void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - // TODO: Halt TC / Restart (if allocated+active) TC. - - env->CP0_TCHalt[other_tc] = T0; - FORCE_RET(); -} - -void op_mtc0_tccontext (void) -{ - env->CP0_TCContext[env->current_tc] = T0; - FORCE_RET(); -} - -void op_mttc0_tccontext (void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - env->CP0_TCContext[other_tc] = T0; - FORCE_RET(); -} - -void op_mtc0_tcschedule (void) -{ - env->CP0_TCSchedule[env->current_tc] = T0; - FORCE_RET(); -} - -void op_mttc0_tcschedule (void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - env->CP0_TCSchedule[other_tc] = T0; - FORCE_RET(); -} - -void op_mtc0_tcschefback (void) -{ - env->CP0_TCScheFBack[env->current_tc] = T0; - FORCE_RET(); -} - -void op_mttc0_tcschefback (void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - env->CP0_TCScheFBack[other_tc] = T0; - FORCE_RET(); -} - -void op_mtc0_entrylo1 (void) -{ - /* Large physaddr (PABITS) not implemented */ - /* 1k pages not implemented */ - env->CP0_EntryLo1 = T0 & 0x3FFFFFFF; - FORCE_RET(); -} - -void op_mtc0_context (void) -{ - env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (T0 & ~0x007FFFFF); - FORCE_RET(); -} - -void op_mtc0_pagemask (void) -{ - /* 1k pages not implemented */ - env->CP0_PageMask = T0 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1)); - FORCE_RET(); -} - -void op_mtc0_pagegrain (void) -{ - /* SmartMIPS not implemented */ - /* Large physaddr (PABITS) not implemented */ - /* 1k pages not implemented */ - env->CP0_PageGrain = 0; - FORCE_RET(); -} - -void op_mtc0_wired (void) -{ - env->CP0_Wired = T0 % env->tlb->nb_tlb; - FORCE_RET(); -} - -void op_mtc0_srsconf0 (void) -{ - env->CP0_SRSConf0 |= T0 & env->CP0_SRSConf0_rw_bitmask; - FORCE_RET(); -} - -void op_mtc0_srsconf1 (void) -{ - env->CP0_SRSConf1 |= T0 & env->CP0_SRSConf1_rw_bitmask; - FORCE_RET(); -} - -void op_mtc0_srsconf2 (void) -{ - env->CP0_SRSConf2 |= T0 & env->CP0_SRSConf2_rw_bitmask; - FORCE_RET(); -} - -void op_mtc0_srsconf3 (void) -{ - env->CP0_SRSConf3 |= T0 & env->CP0_SRSConf3_rw_bitmask; - FORCE_RET(); -} - -void op_mtc0_srsconf4 (void) -{ - env->CP0_SRSConf4 |= T0 & env->CP0_SRSConf4_rw_bitmask; - FORCE_RET(); -} - -void op_mtc0_hwrena (void) -{ - env->CP0_HWREna = T0 & 0x0000000F; - FORCE_RET(); -} - -void op_mtc0_count (void) -{ - CALL_FROM_TB2(cpu_mips_store_count, env, T0); - FORCE_RET(); -} - -void op_mtc0_entryhi (void) -{ - target_ulong old, val; - - /* 1k pages not implemented */ - val = T0 & ((TARGET_PAGE_MASK << 1) | 0xFF); -#if defined(TARGET_MIPS64) - val &= env->SEGMask; -#endif - old = env->CP0_EntryHi; - env->CP0_EntryHi = val; - if (env->CP0_Config3 & (1 << CP0C3_MT)) { - uint32_t tcst = env->CP0_TCStatus[env->current_tc] & ~0xff; - env->CP0_TCStatus[env->current_tc] = tcst | (val & 0xff); - } - /* If the ASID changes, flush qemu's TLB. */ - if ((old & 0xFF) != (val & 0xFF)) - CALL_FROM_TB2(cpu_mips_tlb_flush, env, 1); - FORCE_RET(); -} - -void op_mttc0_entryhi(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (T0 & ~0xff); - env->CP0_TCStatus[other_tc] = (env->CP0_TCStatus[other_tc] & ~0xff) | (T0 & 0xff); - FORCE_RET(); -} - -void op_mtc0_compare (void) -{ - CALL_FROM_TB2(cpu_mips_store_compare, env, T0); - FORCE_RET(); -} - -void op_mtc0_status (void) -{ - uint32_t val, old; - uint32_t mask = env->CP0_Status_rw_bitmask; - - val = T0 & mask; - old = env->CP0_Status; - env->CP0_Status = (env->CP0_Status & ~mask) | val; - CALL_FROM_TB1(compute_hflags, env); - if (loglevel & CPU_LOG_EXEC) - CALL_FROM_TB2(do_mtc0_status_debug, old, val); - CALL_FROM_TB1(cpu_mips_update_irq, env); - FORCE_RET(); -} - -void op_mttc0_status(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - uint32_t tcstatus = env->CP0_TCStatus[other_tc]; - - env->CP0_Status = T0 & ~0xf1000018; - tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (T0 & (0xf << CP0St_CU0)); - tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((T0 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX)); - tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((T0 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU)); - env->CP0_TCStatus[other_tc] = tcstatus; - FORCE_RET(); -} - -void op_mtc0_intctl (void) -{ - /* vectored interrupts not implemented, no performance counters. */ - env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (T0 & 0x000002e0); - FORCE_RET(); -} - -void op_mtc0_srsctl (void) -{ - uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS); - env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (T0 & mask); - FORCE_RET(); -} - -void op_mtc0_srsmap (void) -{ - env->CP0_SRSMap = T0; - FORCE_RET(); -} - -void op_mtc0_cause (void) -{ - uint32_t mask = 0x00C00300; - uint32_t old = env->CP0_Cause; - - if (env->insn_flags & ISA_MIPS32R2) - mask |= 1 << CP0Ca_DC; - - env->CP0_Cause = (env->CP0_Cause & ~mask) | (T0 & mask); - - if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) { - if (env->CP0_Cause & (1 << CP0Ca_DC)) - CALL_FROM_TB1(cpu_mips_stop_count, env); - else - CALL_FROM_TB1(cpu_mips_start_count, env); - } - - /* Handle the software interrupt as an hardware one, as they - are very similar */ - if (T0 & CP0Ca_IP_mask) { - CALL_FROM_TB1(cpu_mips_update_irq, env); - } - FORCE_RET(); -} - -void op_mtc0_epc (void) -{ - env->CP0_EPC = T0; - FORCE_RET(); -} - -void op_mtc0_ebase (void) -{ - /* vectored interrupts not implemented */ - /* Multi-CPU not implemented */ - env->CP0_EBase = 0x80000000 | (T0 & 0x3FFFF000); - FORCE_RET(); -} - -void op_mtc0_config0 (void) -{ - env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (T0 & 0x00000007); - FORCE_RET(); -} - -void op_mtc0_config2 (void) -{ - /* tertiary/secondary caches not implemented */ - env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF); - FORCE_RET(); -} - -void op_mtc0_watchlo (void) -{ - /* Watch exceptions for instructions, data loads, data stores - not implemented. */ - env->CP0_WatchLo[PARAM1] = (T0 & ~0x7); - FORCE_RET(); -} - -void op_mtc0_watchhi (void) -{ - env->CP0_WatchHi[PARAM1] = (T0 & 0x40FF0FF8); - env->CP0_WatchHi[PARAM1] &= ~(env->CP0_WatchHi[PARAM1] & T0 & 0x7); - FORCE_RET(); -} - -void op_mtc0_xcontext (void) -{ - target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1; - env->CP0_XContext = (env->CP0_XContext & mask) | (T0 & ~mask); - FORCE_RET(); -} - -void op_mtc0_framemask (void) -{ - env->CP0_Framemask = T0; /* XXX */ - FORCE_RET(); -} - -void op_mtc0_debug (void) -{ - env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120); - if (T0 & (1 << CP0DB_DM)) - env->hflags |= MIPS_HFLAG_DM; - else - env->hflags &= ~MIPS_HFLAG_DM; - FORCE_RET(); -} - -void op_mttc0_debug(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - /* XXX: Might be wrong, check with EJTAG spec. */ - env->CP0_Debug_tcstatus[other_tc] = T0 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)); - env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) | - (T0 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))); - FORCE_RET(); -} - -void op_mtc0_depc (void) -{ - env->CP0_DEPC = T0; - FORCE_RET(); -} - -void op_mtc0_performance0 (void) -{ - env->CP0_Performance0 = T0 & 0x000007ff; - FORCE_RET(); -} - -void op_mtc0_taglo (void) -{ - env->CP0_TagLo = T0 & 0xFFFFFCF6; - FORCE_RET(); -} - -void op_mtc0_datalo (void) -{ - env->CP0_DataLo = T0; /* XXX */ - FORCE_RET(); -} - -void op_mtc0_taghi (void) -{ - env->CP0_TagHi = T0; /* XXX */ - FORCE_RET(); -} - -void op_mtc0_datahi (void) -{ - env->CP0_DataHi = T0; /* XXX */ - FORCE_RET(); -} - -void op_mtc0_errorepc (void) -{ - env->CP0_ErrorEPC = T0; - FORCE_RET(); -} - -void op_mtc0_desave (void) -{ - env->CP0_DESAVE = T0; - FORCE_RET(); -} - -#if defined(TARGET_MIPS64) -void op_dmfc0_yqmask (void) -{ - T0 = env->CP0_YQMask; - FORCE_RET(); -} - -void op_dmfc0_vpeschedule (void) -{ - T0 = env->CP0_VPESchedule; - FORCE_RET(); -} - -void op_dmfc0_vpeschefback (void) -{ - T0 = env->CP0_VPEScheFBack; - FORCE_RET(); -} - -void op_dmfc0_entrylo0 (void) -{ - T0 = env->CP0_EntryLo0; - FORCE_RET(); -} - -void op_dmfc0_tcrestart (void) -{ - T0 = env->PC[env->current_tc]; - FORCE_RET(); -} - -void op_dmfc0_tchalt (void) -{ - T0 = env->CP0_TCHalt[env->current_tc]; - FORCE_RET(); -} - -void op_dmfc0_tccontext (void) -{ - T0 = env->CP0_TCContext[env->current_tc]; - FORCE_RET(); -} - -void op_dmfc0_tcschedule (void) -{ - T0 = env->CP0_TCSchedule[env->current_tc]; - FORCE_RET(); -} - -void op_dmfc0_tcschefback (void) -{ - T0 = env->CP0_TCScheFBack[env->current_tc]; - FORCE_RET(); -} - -void op_dmfc0_entrylo1 (void) -{ - T0 = env->CP0_EntryLo1; - FORCE_RET(); -} - -void op_dmfc0_context (void) -{ - T0 = env->CP0_Context; - FORCE_RET(); -} - -void op_dmfc0_badvaddr (void) -{ - T0 = env->CP0_BadVAddr; - FORCE_RET(); -} - -void op_dmfc0_entryhi (void) -{ - T0 = env->CP0_EntryHi; - FORCE_RET(); -} - -void op_dmfc0_epc (void) -{ - T0 = env->CP0_EPC; - FORCE_RET(); -} - -void op_dmfc0_lladdr (void) -{ - T0 = env->CP0_LLAddr >> 4; - FORCE_RET(); -} - -void op_dmfc0_watchlo (void) -{ - T0 = env->CP0_WatchLo[PARAM1]; - FORCE_RET(); -} - -void op_dmfc0_xcontext (void) -{ - T0 = env->CP0_XContext; - FORCE_RET(); -} - -void op_dmfc0_depc (void) -{ - T0 = env->CP0_DEPC; - FORCE_RET(); -} - -void op_dmfc0_errorepc (void) -{ - T0 = env->CP0_ErrorEPC; - FORCE_RET(); -} -#endif /* TARGET_MIPS64 */ - -/* MIPS MT functions */ -void op_mftgpr(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - T0 = env->gpr[PARAM1][other_tc]; - FORCE_RET(); -} - -void op_mftlo(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - T0 = env->LO[PARAM1][other_tc]; - FORCE_RET(); -} - -void op_mfthi(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - T0 = env->HI[PARAM1][other_tc]; - FORCE_RET(); -} - -void op_mftacx(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - T0 = env->ACX[PARAM1][other_tc]; - FORCE_RET(); -} - -void op_mftdsp(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - T0 = env->DSPControl[other_tc]; - FORCE_RET(); -} - -void op_mttgpr(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - T0 = env->gpr[PARAM1][other_tc]; - FORCE_RET(); -} - -void op_mttlo(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - T0 = env->LO[PARAM1][other_tc]; - FORCE_RET(); -} - -void op_mtthi(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - T0 = env->HI[PARAM1][other_tc]; - FORCE_RET(); -} - -void op_mttacx(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - T0 = env->ACX[PARAM1][other_tc]; - FORCE_RET(); -} - -void op_mttdsp(void) -{ - int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - - T0 = env->DSPControl[other_tc]; - FORCE_RET(); -} - - -void op_dmt(void) -{ - // TODO - T0 = 0; - // rt = T0 - FORCE_RET(); -} - -void op_emt(void) -{ - // TODO - T0 = 0; - // rt = T0 - FORCE_RET(); -} - -void op_dvpe(void) -{ - // TODO - T0 = 0; - // rt = T0 - FORCE_RET(); -} - -void op_evpe(void) -{ - // TODO - T0 = 0; - // rt = T0 - FORCE_RET(); -} - -void op_fork(void) -{ - // T0 = rt, T1 = rs - T0 = 0; - // TODO: store to TC register - FORCE_RET(); -} - -void op_yield(void) -{ - if (T0 < 0) { - /* No scheduling policy implemented. */ - if (T0 != -2) { - if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) && - env->CP0_TCStatus[env->current_tc] & (1 << CP0TCSt_DT)) { - env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); - env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT; - CALL_FROM_TB1(do_raise_exception, EXCP_THREAD); - } - } - } else if (T0 == 0) { - if (0 /* TODO: TC underflow */) { - env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); - CALL_FROM_TB1(do_raise_exception, EXCP_THREAD); - } else { - // TODO: Deallocate TC - } - } else if (T0 > 0) { - /* Yield qualifier inputs not implemented. */ - env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); - env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT; - CALL_FROM_TB1(do_raise_exception, EXCP_THREAD); - } - T0 = env->CP0_YQMask; - FORCE_RET(); -} - -/* CP1 functions */ -#if 0 -# define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env) -#else -# define DEBUG_FPU_STATE() do { } while(0) -#endif - -void op_cfc1 (void) -{ - CALL_FROM_TB1(do_cfc1, PARAM1); - DEBUG_FPU_STATE(); - FORCE_RET(); -} - -void op_ctc1 (void) -{ - CALL_FROM_TB1(do_ctc1, PARAM1); - DEBUG_FPU_STATE(); - FORCE_RET(); -} - -void op_mfc1 (void) -{ - T0 = (int32_t)WT0; - DEBUG_FPU_STATE(); - FORCE_RET(); -} - -void op_mtc1 (void) -{ - WT0 = T0; - DEBUG_FPU_STATE(); - FORCE_RET(); -} - -void op_dmfc1 (void) -{ - T0 = DT0; - DEBUG_FPU_STATE(); - FORCE_RET(); -} - -void op_dmtc1 (void) -{ - DT0 = T0; - DEBUG_FPU_STATE(); - FORCE_RET(); -} - -void op_mfhc1 (void) -{ - T0 = (int32_t)WTH0; - DEBUG_FPU_STATE(); - FORCE_RET(); -} - -void op_mthc1 (void) -{ - WTH0 = T0; - DEBUG_FPU_STATE(); - FORCE_RET(); -} - -/* Float support. - Single precition routines have a "s" suffix, double precision a - "d" suffix, 32bit integer "w", 64bit integer "l", paired singe "ps", - paired single lowwer "pl", paired single upper "pu". */ - -#define FLOAT_OP(name, p) void OPPROTO op_float_##name##_##p(void) - -FLOAT_OP(cvtd, s) -{ - CALL_FROM_TB0(do_float_cvtd_s); - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(cvtd, w) -{ - CALL_FROM_TB0(do_float_cvtd_w); - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(cvtd, l) -{ - CALL_FROM_TB0(do_float_cvtd_l); - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(cvtl, d) -{ - CALL_FROM_TB0(do_float_cvtl_d); - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(cvtl, s) -{ - CALL_FROM_TB0(do_float_cvtl_s); - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(cvtps, s) -{ - WT2 = WT0; - WTH2 = WT1; - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(cvtps, pw) -{ - CALL_FROM_TB0(do_float_cvtps_pw); - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(cvtpw, ps) -{ - CALL_FROM_TB0(do_float_cvtpw_ps); - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(cvts, d) -{ - CALL_FROM_TB0(do_float_cvts_d); - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(cvts, w) -{ - CALL_FROM_TB0(do_float_cvts_w); - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(cvts, l) -{ - CALL_FROM_TB0(do_float_cvts_l); - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(cvts, pl) -{ - CALL_FROM_TB0(do_float_cvts_pl); - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(cvts, pu) -{ - CALL_FROM_TB0(do_float_cvts_pu); - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(cvtw, s) -{ - CALL_FROM_TB0(do_float_cvtw_s); - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(cvtw, d) -{ - CALL_FROM_TB0(do_float_cvtw_d); - DEBUG_FPU_STATE(); - FORCE_RET(); -} - -FLOAT_OP(pll, ps) -{ - DT2 = ((uint64_t)WT0 << 32) | WT1; - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(plu, ps) -{ - DT2 = ((uint64_t)WT0 << 32) | WTH1; - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(pul, ps) -{ - DT2 = ((uint64_t)WTH0 << 32) | WT1; - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(puu, ps) -{ - DT2 = ((uint64_t)WTH0 << 32) | WTH1; - DEBUG_FPU_STATE(); - FORCE_RET(); -} - -#define FLOAT_ROUNDOP(op, ttype, stype) \ -FLOAT_OP(op ## ttype, stype) \ -{ \ - CALL_FROM_TB0(do_float_ ## op ## ttype ## _ ## stype); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} - -FLOAT_ROUNDOP(round, l, d) -FLOAT_ROUNDOP(round, l, s) -FLOAT_ROUNDOP(round, w, d) -FLOAT_ROUNDOP(round, w, s) - -FLOAT_ROUNDOP(trunc, l, d) -FLOAT_ROUNDOP(trunc, l, s) -FLOAT_ROUNDOP(trunc, w, d) -FLOAT_ROUNDOP(trunc, w, s) - -FLOAT_ROUNDOP(ceil, l, d) -FLOAT_ROUNDOP(ceil, l, s) -FLOAT_ROUNDOP(ceil, w, d) -FLOAT_ROUNDOP(ceil, w, s) - -FLOAT_ROUNDOP(floor, l, d) -FLOAT_ROUNDOP(floor, l, s) -FLOAT_ROUNDOP(floor, w, d) -FLOAT_ROUNDOP(floor, w, s) -#undef FLOAR_ROUNDOP - -FLOAT_OP(movf, d) -{ - if (!(env->fpu->fcr31 & PARAM1)) - DT2 = DT0; - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(movf, s) -{ - if (!(env->fpu->fcr31 & PARAM1)) - WT2 = WT0; - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(movf, ps) -{ - if (!(env->fpu->fcr31 & PARAM1)) { - WT2 = WT0; - WTH2 = WTH0; - } - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(movt, d) -{ - if (env->fpu->fcr31 & PARAM1) - DT2 = DT0; - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(movt, s) -{ - if (env->fpu->fcr31 & PARAM1) - WT2 = WT0; - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(movt, ps) -{ - if (env->fpu->fcr31 & PARAM1) { - WT2 = WT0; - WTH2 = WTH0; - } - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(movz, d) -{ - if (!T0) - DT2 = DT0; - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(movz, s) -{ - if (!T0) - WT2 = WT0; - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(movz, ps) -{ - if (!T0) { - WT2 = WT0; - WTH2 = WTH0; - } - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(movn, d) -{ - if (T0) - DT2 = DT0; - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(movn, s) -{ - if (T0) - WT2 = WT0; - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(movn, ps) -{ - if (T0) { - WT2 = WT0; - WTH2 = WTH0; - } - DEBUG_FPU_STATE(); - FORCE_RET(); -} - -/* operations calling helpers, for s, d and ps */ -#define FLOAT_HOP(name) \ -FLOAT_OP(name, d) \ -{ \ - CALL_FROM_TB0(do_float_ ## name ## _d); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} \ -FLOAT_OP(name, s) \ -{ \ - CALL_FROM_TB0(do_float_ ## name ## _s); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} \ -FLOAT_OP(name, ps) \ -{ \ - CALL_FROM_TB0(do_float_ ## name ## _ps); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} -FLOAT_HOP(add) -FLOAT_HOP(sub) -FLOAT_HOP(mul) -FLOAT_HOP(div) -FLOAT_HOP(recip2) -FLOAT_HOP(rsqrt2) -FLOAT_HOP(rsqrt1) -FLOAT_HOP(recip1) -#undef FLOAT_HOP - -/* operations calling helpers, for s and d */ -#define FLOAT_HOP(name) \ -FLOAT_OP(name, d) \ -{ \ - CALL_FROM_TB0(do_float_ ## name ## _d); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} \ -FLOAT_OP(name, s) \ -{ \ - CALL_FROM_TB0(do_float_ ## name ## _s); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} -FLOAT_HOP(rsqrt) -FLOAT_HOP(recip) -#undef FLOAT_HOP - -/* operations calling helpers, for ps */ -#define FLOAT_HOP(name) \ -FLOAT_OP(name, ps) \ -{ \ - CALL_FROM_TB0(do_float_ ## name ## _ps); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} -FLOAT_HOP(addr) -FLOAT_HOP(mulr) -#undef FLOAT_HOP - -/* ternary operations */ -#define FLOAT_TERNOP(name1, name2) \ -FLOAT_OP(name1 ## name2, d) \ -{ \ - FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status); \ - FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} \ -FLOAT_OP(name1 ## name2, s) \ -{ \ - FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \ - FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} \ -FLOAT_OP(name1 ## name2, ps) \ -{ \ - FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \ - FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \ - FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ - FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} -FLOAT_TERNOP(mul, add) -FLOAT_TERNOP(mul, sub) -#undef FLOAT_TERNOP - -/* negated ternary operations */ -#define FLOAT_NTERNOP(name1, name2) \ -FLOAT_OP(n ## name1 ## name2, d) \ -{ \ - FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status); \ - FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status); \ - FDT2 = float64_chs(FDT2); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} \ -FLOAT_OP(n ## name1 ## name2, s) \ -{ \ - FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \ - FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ - FST2 = float32_chs(FST2); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} \ -FLOAT_OP(n ## name1 ## name2, ps) \ -{ \ - FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \ - FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \ - FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ - FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \ - FST2 = float32_chs(FST2); \ - FSTH2 = float32_chs(FSTH2); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} -FLOAT_NTERNOP(mul, add) -FLOAT_NTERNOP(mul, sub) -#undef FLOAT_NTERNOP - -/* unary operations, modifying fp status */ -#define FLOAT_UNOP(name) \ -FLOAT_OP(name, d) \ -{ \ - FDT2 = float64_ ## name(FDT0, &env->fpu->fp_status); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} \ -FLOAT_OP(name, s) \ -{ \ - FST2 = float32_ ## name(FST0, &env->fpu->fp_status); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} -FLOAT_UNOP(sqrt) -#undef FLOAT_UNOP - -/* unary operations, not modifying fp status */ -#define FLOAT_UNOP(name) \ -FLOAT_OP(name, d) \ -{ \ - FDT2 = float64_ ## name(FDT0); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} \ -FLOAT_OP(name, s) \ -{ \ - FST2 = float32_ ## name(FST0); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} \ -FLOAT_OP(name, ps) \ -{ \ - FST2 = float32_ ## name(FST0); \ - FSTH2 = float32_ ## name(FSTH0); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} -FLOAT_UNOP(abs) -FLOAT_UNOP(chs) -#undef FLOAT_UNOP - -FLOAT_OP(mov, d) -{ - FDT2 = FDT0; - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(mov, s) -{ - FST2 = FST0; - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(mov, ps) -{ - FST2 = FST0; - FSTH2 = FSTH0; - DEBUG_FPU_STATE(); - FORCE_RET(); -} -FLOAT_OP(alnv, ps) -{ - switch (T0 & 0x7) { - case 0: - FST2 = FST0; - FSTH2 = FSTH0; - break; - case 4: -#ifdef TARGET_WORDS_BIGENDIAN - FSTH2 = FST0; - FST2 = FSTH1; -#else - FSTH2 = FST1; - FST2 = FSTH0; -#endif - break; - default: /* unpredictable */ - break; - } - DEBUG_FPU_STATE(); - FORCE_RET(); -} - -#ifdef CONFIG_SOFTFLOAT -#define clear_invalid() do { \ - int flags = get_float_exception_flags(&env->fpu->fp_status); \ - flags &= ~float_flag_invalid; \ - set_float_exception_flags(flags, &env->fpu->fp_status); \ -} while(0) -#else -#define clear_invalid() do { } while(0) -#endif - -extern void dump_fpu_s(CPUState *env); - -#define CMP_OP(fmt, op) \ -void OPPROTO op_cmp ## _ ## fmt ## _ ## op(void) \ -{ \ - CALL_FROM_TB1(do_cmp ## _ ## fmt ## _ ## op, PARAM1); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} \ -void OPPROTO op_cmpabs ## _ ## fmt ## _ ## op(void) \ -{ \ - CALL_FROM_TB1(do_cmpabs ## _ ## fmt ## _ ## op, PARAM1); \ - DEBUG_FPU_STATE(); \ - FORCE_RET(); \ -} -#define CMP_OPS(op) \ -CMP_OP(d, op) \ -CMP_OP(s, op) \ -CMP_OP(ps, op) - -CMP_OPS(f) -CMP_OPS(un) -CMP_OPS(eq) -CMP_OPS(ueq) -CMP_OPS(olt) -CMP_OPS(ult) -CMP_OPS(ole) -CMP_OPS(ule) -CMP_OPS(sf) -CMP_OPS(ngle) -CMP_OPS(seq) -CMP_OPS(ngl) -CMP_OPS(lt) -CMP_OPS(nge) -CMP_OPS(le) -CMP_OPS(ngt) -#undef CMP_OPS -#undef CMP_OP - -void op_bc1f (void) -{ - T0 = !!(~GET_FP_COND(env->fpu) & (0x1 << PARAM1)); - DEBUG_FPU_STATE(); - FORCE_RET(); -} -void op_bc1any2f (void) -{ - T0 = !!(~GET_FP_COND(env->fpu) & (0x3 << PARAM1)); - DEBUG_FPU_STATE(); - FORCE_RET(); -} -void op_bc1any4f (void) -{ - T0 = !!(~GET_FP_COND(env->fpu) & (0xf << PARAM1)); - DEBUG_FPU_STATE(); - FORCE_RET(); -} - -void op_bc1t (void) -{ - T0 = !!(GET_FP_COND(env->fpu) & (0x1 << PARAM1)); - DEBUG_FPU_STATE(); - FORCE_RET(); -} -void op_bc1any2t (void) -{ - T0 = !!(GET_FP_COND(env->fpu) & (0x3 << PARAM1)); - DEBUG_FPU_STATE(); - FORCE_RET(); -} -void op_bc1any4t (void) -{ - T0 = !!(GET_FP_COND(env->fpu) & (0xf << PARAM1)); - DEBUG_FPU_STATE(); - FORCE_RET(); -} - -void op_tlbwi (void) -{ - CALL_FROM_TB0(env->tlb->do_tlbwi); - FORCE_RET(); -} - -void op_tlbwr (void) -{ - CALL_FROM_TB0(env->tlb->do_tlbwr); - FORCE_RET(); -} - -void op_tlbp (void) -{ - CALL_FROM_TB0(env->tlb->do_tlbp); - FORCE_RET(); -} - -void op_tlbr (void) -{ - CALL_FROM_TB0(env->tlb->do_tlbr); - FORCE_RET(); -} - -/* Specials */ -#if defined (CONFIG_USER_ONLY) -void op_tls_value (void) -{ - T0 = env->tls_value; -} -#endif - -void op_pmon (void) -{ - CALL_FROM_TB1(do_pmon, PARAM1); - FORCE_RET(); -} - -void op_di (void) -{ - T0 = env->CP0_Status; - env->CP0_Status = T0 & ~(1 << CP0St_IE); - CALL_FROM_TB1(cpu_mips_update_irq, env); - FORCE_RET(); -} - -void op_ei (void) -{ - T0 = env->CP0_Status; - env->CP0_Status = T0 | (1 << CP0St_IE); - CALL_FROM_TB1(cpu_mips_update_irq, env); - FORCE_RET(); -} - -void op_trap (void) -{ - if (T0) { - CALL_FROM_TB1(do_raise_exception, EXCP_TRAP); - } - FORCE_RET(); -} - -void op_debug (void) -{ - CALL_FROM_TB1(do_raise_exception, EXCP_DEBUG); - FORCE_RET(); -} - -void op_set_lladdr (void) -{ - env->CP0_LLAddr = T2; - FORCE_RET(); -} - -void debug_pre_eret (void); -void debug_post_eret (void); -void op_eret (void) -{ - if (loglevel & CPU_LOG_EXEC) - CALL_FROM_TB0(debug_pre_eret); - if (env->CP0_Status & (1 << CP0St_ERL)) { - env->PC[env->current_tc] = env->CP0_ErrorEPC; - env->CP0_Status &= ~(1 << CP0St_ERL); - } else { - env->PC[env->current_tc] = env->CP0_EPC; - env->CP0_Status &= ~(1 << CP0St_EXL); - } - CALL_FROM_TB1(compute_hflags, env); - if (loglevel & CPU_LOG_EXEC) - CALL_FROM_TB0(debug_post_eret); - env->CP0_LLAddr = 1; - FORCE_RET(); -} - -void op_deret (void) -{ - if (loglevel & CPU_LOG_EXEC) - CALL_FROM_TB0(debug_pre_eret); - env->PC[env->current_tc] = env->CP0_DEPC; - env->hflags &= MIPS_HFLAG_DM; - CALL_FROM_TB1(compute_hflags, env); - if (loglevel & CPU_LOG_EXEC) - CALL_FROM_TB0(debug_post_eret); - env->CP0_LLAddr = 1; - FORCE_RET(); -} - -void op_rdhwr_cpunum(void) -{ - if ((env->hflags & MIPS_HFLAG_CP0) || - (env->CP0_HWREna & (1 << 0))) - T0 = env->CP0_EBase & 0x3ff; - else - CALL_FROM_TB1(do_raise_exception, EXCP_RI); - FORCE_RET(); -} - -void op_rdhwr_synci_step(void) -{ - if ((env->hflags & MIPS_HFLAG_CP0) || - (env->CP0_HWREna & (1 << 1))) - T0 = env->SYNCI_Step; - else - CALL_FROM_TB1(do_raise_exception, EXCP_RI); - FORCE_RET(); -} - -void op_rdhwr_cc(void) -{ - if ((env->hflags & MIPS_HFLAG_CP0) || - (env->CP0_HWREna & (1 << 2))) - T0 = env->CP0_Count; - else - CALL_FROM_TB1(do_raise_exception, EXCP_RI); - FORCE_RET(); -} - -void op_rdhwr_ccres(void) -{ - if ((env->hflags & MIPS_HFLAG_CP0) || - (env->CP0_HWREna & (1 << 3))) - T0 = env->CCRes; - else - CALL_FROM_TB1(do_raise_exception, EXCP_RI); - FORCE_RET(); -} - -void op_save_state (void) -{ - env->hflags = PARAM1; - FORCE_RET(); -} - -void op_save_pc (void) -{ - env->PC[env->current_tc] = PARAM1; - FORCE_RET(); -} - -#if defined(TARGET_MIPS64) -void op_save_pc64 (void) -{ - env->PC[env->current_tc] = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2; - FORCE_RET(); -} -#endif - -void op_interrupt_restart (void) -{ - if (!(env->CP0_Status & (1 << CP0St_EXL)) && - !(env->CP0_Status & (1 << CP0St_ERL)) && - !(env->hflags & MIPS_HFLAG_DM) && - (env->CP0_Status & (1 << CP0St_IE)) && - (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) { - env->CP0_Cause &= ~(0x1f << CP0Ca_EC); - CALL_FROM_TB1(do_raise_exception, EXCP_EXT_INTERRUPT); - } - FORCE_RET(); -} - -void op_raise_exception (void) -{ - CALL_FROM_TB1(do_raise_exception, PARAM1); - FORCE_RET(); -} - -void op_raise_exception_err (void) -{ - CALL_FROM_TB2(do_raise_exception_err, PARAM1, PARAM2); - FORCE_RET(); -} - -void op_exit_tb (void) -{ - EXIT_TB(); - FORCE_RET(); -} - -void op_wait (void) -{ - env->halted = 1; - CALL_FROM_TB1(do_raise_exception, EXCP_HLT); - FORCE_RET(); -} - -/* Bitfield operations. */ -void op_ext(void) -{ - unsigned int pos = PARAM1; - unsigned int size = PARAM2; - - T0 = (int32_t)((T1 >> pos) & ((size < 32) ? ((1 << size) - 1) : ~0)); - FORCE_RET(); -} - -void op_ins(void) -{ - unsigned int pos = PARAM1; - unsigned int size = PARAM2; - target_ulong mask = ((size < 32) ? ((1 << size) - 1) : ~0) << pos; - - T0 = (int32_t)((T0 & ~mask) | ((T1 << pos) & mask)); - FORCE_RET(); -} - -void op_wsbh(void) -{ - T0 = (int32_t)(((T1 << 8) & ~0x00FF00FF) | ((T1 >> 8) & 0x00FF00FF)); - FORCE_RET(); -} - -#if defined(TARGET_MIPS64) -void op_dext(void) -{ - unsigned int pos = PARAM1; - unsigned int size = PARAM2; - - T0 = (T1 >> pos) & ((size < 64) ? ((1ULL << size) - 1) : ~0ULL); - FORCE_RET(); -} - -void op_dins(void) -{ - unsigned int pos = PARAM1; - unsigned int size = PARAM2; - target_ulong mask = ((size < 64) ? ((1ULL << size) - 1) : ~0ULL) << pos; - - T0 = (T0 & ~mask) | ((T1 << pos) & mask); - FORCE_RET(); -} - -void op_dsbh(void) -{ - T0 = ((T1 << 8) & ~0x00FF00FF00FF00FFULL) | ((T1 >> 8) & 0x00FF00FF00FF00FFULL); - FORCE_RET(); -} - -void op_dshd(void) -{ - T1 = ((T1 << 16) & ~0x0000FFFF0000FFFFULL) | ((T1 >> 16) & 0x0000FFFF0000FFFFULL); - T0 = (T1 << 32) | (T1 >> 32); - FORCE_RET(); -} -#endif - -void op_seb(void) -{ - T0 = ((T1 & 0xFF) ^ 0x80) - 0x80; - FORCE_RET(); -} - -void op_seh(void) -{ - T0 = ((T1 & 0xFFFF) ^ 0x8000) - 0x8000; - FORCE_RET(); -} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-mips/op_helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-mips/op_helper.c --- qemu-0.9.1/target-mips/op_helper.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-mips/op_helper.c 2008-11-11 11:47:06.000000000 +0000 @@ -22,12 +22,6 @@ #include "host-utils.h" -#ifdef __s390__ -# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) -#else -# define GETPC() (__builtin_return_address(0)) -#endif - /*****************************************************************************/ /* Exceptions processing helpers */ @@ -39,7 +33,6 @@ #endif env->exception_index = exception; env->error_code = error_code; - T0 = 0; cpu_loop_exit(); } @@ -48,415 +41,1496 @@ do_raise_exception_err(exception, 0); } -void do_restore_state (void *pc_ptr) +void do_interrupt_restart (void) { - TranslationBlock *tb; - unsigned long pc = (unsigned long) pc_ptr; + if (!(env->CP0_Status & (1 << CP0St_EXL)) && + !(env->CP0_Status & (1 << CP0St_ERL)) && + !(env->hflags & MIPS_HFLAG_DM) && + (env->CP0_Status & (1 << CP0St_IE)) && + (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) { + env->CP0_Cause &= ~(0x1f << CP0Ca_EC); + do_raise_exception(EXCP_EXT_INTERRUPT); + } +} - tb = tb_find_pc (pc); - cpu_restore_state (tb, env, pc, NULL); +void do_restore_state (void *pc_ptr) +{ + TranslationBlock *tb; + unsigned long pc = (unsigned long) pc_ptr; + + tb = tb_find_pc (pc); + if (tb) { + cpu_restore_state (tb, env, pc, NULL); + } } -void do_raise_exception_direct_err (uint32_t exception, int error_code) +target_ulong do_clo (target_ulong t0) { - do_restore_state (GETPC ()); - do_raise_exception_err (exception, error_code); + return clo32(t0); } -void do_raise_exception_direct (uint32_t exception) +target_ulong do_clz (target_ulong t0) { - do_raise_exception_direct_err (exception, 0); + return clz32(t0); } #if defined(TARGET_MIPS64) +target_ulong do_dclo (target_ulong t0) +{ + return clo64(t0); +} + +target_ulong do_dclz (target_ulong t0) +{ + return clz64(t0); +} +#endif /* TARGET_MIPS64 */ + +/* 64 bits arithmetic for 32 bits hosts */ +static inline uint64_t get_HILO (void) +{ + return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0]; +} + +static inline void set_HILO (uint64_t HILO) +{ + env->active_tc.LO[0] = (int32_t)HILO; + env->active_tc.HI[0] = (int32_t)(HILO >> 32); +} + +static inline void set_HIT0_LO (target_ulong t0, uint64_t HILO) +{ + env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF); + t0 = env->active_tc.HI[0] = (int32_t)(HILO >> 32); +} + +static inline void set_HI_LOT0 (target_ulong t0, uint64_t HILO) +{ + t0 = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF); + env->active_tc.HI[0] = (int32_t)(HILO >> 32); +} + #if TARGET_LONG_BITS > HOST_LONG_BITS -/* Those might call libgcc functions. */ -void do_dsll (void) +void do_madd (target_ulong t0, target_ulong t1) { - T0 = T0 << T1; + int64_t tmp; + + tmp = ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1); + set_HILO((int64_t)get_HILO() + tmp); +} + +void do_maddu (target_ulong t0, target_ulong t1) +{ + uint64_t tmp; + + tmp = ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1); + set_HILO(get_HILO() + tmp); +} + +void do_msub (target_ulong t0, target_ulong t1) +{ + int64_t tmp; + + tmp = ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1); + set_HILO((int64_t)get_HILO() - tmp); +} + +void do_msubu (target_ulong t0, target_ulong t1) +{ + uint64_t tmp; + + tmp = ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1); + set_HILO(get_HILO() - tmp); +} +#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ + +/* Multiplication variants of the vr54xx. */ +target_ulong do_muls (target_ulong t0, target_ulong t1) +{ + set_HI_LOT0(t0, 0 - ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1)); + + return t0; +} + +target_ulong do_mulsu (target_ulong t0, target_ulong t1) +{ + set_HI_LOT0(t0, 0 - ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1)); + + return t0; +} + +target_ulong do_macc (target_ulong t0, target_ulong t1) +{ + set_HI_LOT0(t0, ((int64_t)get_HILO()) + ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1)); + + return t0; +} + +target_ulong do_macchi (target_ulong t0, target_ulong t1) +{ + set_HIT0_LO(t0, ((int64_t)get_HILO()) + ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1)); + + return t0; +} + +target_ulong do_maccu (target_ulong t0, target_ulong t1) +{ + set_HI_LOT0(t0, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1)); + + return t0; +} + +target_ulong do_macchiu (target_ulong t0, target_ulong t1) +{ + set_HIT0_LO(t0, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1)); + + return t0; +} + +target_ulong do_msac (target_ulong t0, target_ulong t1) +{ + set_HI_LOT0(t0, ((int64_t)get_HILO()) - ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1)); + + return t0; +} + +target_ulong do_msachi (target_ulong t0, target_ulong t1) +{ + set_HIT0_LO(t0, ((int64_t)get_HILO()) - ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1)); + + return t0; +} + +target_ulong do_msacu (target_ulong t0, target_ulong t1) +{ + set_HI_LOT0(t0, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1)); + + return t0; +} + +target_ulong do_msachiu (target_ulong t0, target_ulong t1) +{ + set_HIT0_LO(t0, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1)); + + return t0; +} + +target_ulong do_mulhi (target_ulong t0, target_ulong t1) +{ + set_HIT0_LO(t0, (int64_t)(int32_t)t0 * (int64_t)(int32_t)t1); + + return t0; +} + +target_ulong do_mulhiu (target_ulong t0, target_ulong t1) +{ + set_HIT0_LO(t0, (uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1); + + return t0; +} + +target_ulong do_mulshi (target_ulong t0, target_ulong t1) +{ + set_HIT0_LO(t0, 0 - ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1)); + + return t0; +} + +target_ulong do_mulshiu (target_ulong t0, target_ulong t1) +{ + set_HIT0_LO(t0, 0 - ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1)); + + return t0; +} + +#ifdef TARGET_MIPS64 +void do_dmult (target_ulong t0, target_ulong t1) +{ + muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), t0, t1); +} + +void do_dmultu (target_ulong t0, target_ulong t1) +{ + mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), t0, t1); +} +#endif + +#ifdef TARGET_WORDS_BIGENDIAN +#define GET_LMASK(v) ((v) & 3) +#define GET_OFFSET(addr, offset) (addr + (offset)) +#else +#define GET_LMASK(v) (((v) & 3) ^ 3) +#define GET_OFFSET(addr, offset) (addr - (offset)) +#endif + +target_ulong do_lwl(target_ulong t0, target_ulong t1, int mem_idx) +{ + target_ulong tmp; + +#ifdef CONFIG_USER_ONLY +#define ldfun ldub_raw +#else + int (*ldfun)(target_ulong); + + switch (mem_idx) + { + case 0: ldfun = ldub_kernel; break; + case 1: ldfun = ldub_super; break; + default: + case 2: ldfun = ldub_user; break; + } +#endif + tmp = ldfun(t0); + t1 = (t1 & 0x00FFFFFF) | (tmp << 24); + + if (GET_LMASK(t0) <= 2) { + tmp = ldfun(GET_OFFSET(t0, 1)); + t1 = (t1 & 0xFF00FFFF) | (tmp << 16); + } + + if (GET_LMASK(t0) <= 1) { + tmp = ldfun(GET_OFFSET(t0, 2)); + t1 = (t1 & 0xFFFF00FF) | (tmp << 8); + } + + if (GET_LMASK(t0) == 0) { + tmp = ldfun(GET_OFFSET(t0, 3)); + t1 = (t1 & 0xFFFFFF00) | tmp; + } + return (int32_t)t1; +} + +target_ulong do_lwr(target_ulong t0, target_ulong t1, int mem_idx) +{ + target_ulong tmp; + +#ifdef CONFIG_USER_ONLY +#define ldfun ldub_raw +#else + int (*ldfun)(target_ulong); + + switch (mem_idx) + { + case 0: ldfun = ldub_kernel; break; + case 1: ldfun = ldub_super; break; + default: + case 2: ldfun = ldub_user; break; + } +#endif + tmp = ldfun(t0); + t1 = (t1 & 0xFFFFFF00) | tmp; + + if (GET_LMASK(t0) >= 1) { + tmp = ldfun(GET_OFFSET(t0, -1)); + t1 = (t1 & 0xFFFF00FF) | (tmp << 8); + } + + if (GET_LMASK(t0) >= 2) { + tmp = ldfun(GET_OFFSET(t0, -2)); + t1 = (t1 & 0xFF00FFFF) | (tmp << 16); + } + + if (GET_LMASK(t0) == 3) { + tmp = ldfun(GET_OFFSET(t0, -3)); + t1 = (t1 & 0x00FFFFFF) | (tmp << 24); + } + return (int32_t)t1; +} + +void do_swl(target_ulong t0, target_ulong t1, int mem_idx) +{ +#ifdef CONFIG_USER_ONLY +#define stfun stb_raw +#else + void (*stfun)(target_ulong, int); + + switch (mem_idx) + { + case 0: stfun = stb_kernel; break; + case 1: stfun = stb_super; break; + default: + case 2: stfun = stb_user; break; + } +#endif + stfun(t0, (uint8_t)(t1 >> 24)); + + if (GET_LMASK(t0) <= 2) + stfun(GET_OFFSET(t0, 1), (uint8_t)(t1 >> 16)); + + if (GET_LMASK(t0) <= 1) + stfun(GET_OFFSET(t0, 2), (uint8_t)(t1 >> 8)); + + if (GET_LMASK(t0) == 0) + stfun(GET_OFFSET(t0, 3), (uint8_t)t1); +} + +void do_swr(target_ulong t0, target_ulong t1, int mem_idx) +{ +#ifdef CONFIG_USER_ONLY +#define stfun stb_raw +#else + void (*stfun)(target_ulong, int); + + switch (mem_idx) + { + case 0: stfun = stb_kernel; break; + case 1: stfun = stb_super; break; + default: + case 2: stfun = stb_user; break; + } +#endif + stfun(t0, (uint8_t)t1); + + if (GET_LMASK(t0) >= 1) + stfun(GET_OFFSET(t0, -1), (uint8_t)(t1 >> 8)); + + if (GET_LMASK(t0) >= 2) + stfun(GET_OFFSET(t0, -2), (uint8_t)(t1 >> 16)); + + if (GET_LMASK(t0) == 3) + stfun(GET_OFFSET(t0, -3), (uint8_t)(t1 >> 24)); +} + +#if defined(TARGET_MIPS64) +/* "half" load and stores. We must do the memory access inline, + or fault handling won't work. */ + +#ifdef TARGET_WORDS_BIGENDIAN +#define GET_LMASK64(v) ((v) & 7) +#else +#define GET_LMASK64(v) (((v) & 7) ^ 7) +#endif + +target_ulong do_ldl(target_ulong t0, target_ulong t1, int mem_idx) +{ + uint64_t tmp; + +#ifdef CONFIG_USER_ONLY +#define ldfun ldub_raw +#else + int (*ldfun)(target_ulong); + + switch (mem_idx) + { + case 0: ldfun = ldub_kernel; break; + case 1: ldfun = ldub_super; break; + default: + case 2: ldfun = ldub_user; break; + } +#endif + tmp = ldfun(t0); + t1 = (t1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56); + + if (GET_LMASK64(t0) <= 6) { + tmp = ldfun(GET_OFFSET(t0, 1)); + t1 = (t1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48); + } + + if (GET_LMASK64(t0) <= 5) { + tmp = ldfun(GET_OFFSET(t0, 2)); + t1 = (t1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40); + } + + if (GET_LMASK64(t0) <= 4) { + tmp = ldfun(GET_OFFSET(t0, 3)); + t1 = (t1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32); + } + + if (GET_LMASK64(t0) <= 3) { + tmp = ldfun(GET_OFFSET(t0, 4)); + t1 = (t1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24); + } + + if (GET_LMASK64(t0) <= 2) { + tmp = ldfun(GET_OFFSET(t0, 5)); + t1 = (t1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16); + } + + if (GET_LMASK64(t0) <= 1) { + tmp = ldfun(GET_OFFSET(t0, 6)); + t1 = (t1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8); + } + + if (GET_LMASK64(t0) == 0) { + tmp = ldfun(GET_OFFSET(t0, 7)); + t1 = (t1 & 0xFFFFFFFFFFFFFF00ULL) | tmp; + } + + return t1; +} + +target_ulong do_ldr(target_ulong t0, target_ulong t1, int mem_idx) +{ + uint64_t tmp; + +#ifdef CONFIG_USER_ONLY +#define ldfun ldub_raw +#else + int (*ldfun)(target_ulong); + + switch (mem_idx) + { + case 0: ldfun = ldub_kernel; break; + case 1: ldfun = ldub_super; break; + default: + case 2: ldfun = ldub_user; break; + } +#endif + tmp = ldfun(t0); + t1 = (t1 & 0xFFFFFFFFFFFFFF00ULL) | tmp; + + if (GET_LMASK64(t0) >= 1) { + tmp = ldfun(GET_OFFSET(t0, -1)); + t1 = (t1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8); + } + + if (GET_LMASK64(t0) >= 2) { + tmp = ldfun(GET_OFFSET(t0, -2)); + t1 = (t1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16); + } + + if (GET_LMASK64(t0) >= 3) { + tmp = ldfun(GET_OFFSET(t0, -3)); + t1 = (t1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24); + } + + if (GET_LMASK64(t0) >= 4) { + tmp = ldfun(GET_OFFSET(t0, -4)); + t1 = (t1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32); + } + + if (GET_LMASK64(t0) >= 5) { + tmp = ldfun(GET_OFFSET(t0, -5)); + t1 = (t1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40); + } + + if (GET_LMASK64(t0) >= 6) { + tmp = ldfun(GET_OFFSET(t0, -6)); + t1 = (t1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48); + } + + if (GET_LMASK64(t0) == 7) { + tmp = ldfun(GET_OFFSET(t0, -7)); + t1 = (t1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56); + } + + return t1; +} + +void do_sdl(target_ulong t0, target_ulong t1, int mem_idx) +{ +#ifdef CONFIG_USER_ONLY +#define stfun stb_raw +#else + void (*stfun)(target_ulong, int); + + switch (mem_idx) + { + case 0: stfun = stb_kernel; break; + case 1: stfun = stb_super; break; + default: + case 2: stfun = stb_user; break; + } +#endif + stfun(t0, (uint8_t)(t1 >> 56)); + + if (GET_LMASK64(t0) <= 6) + stfun(GET_OFFSET(t0, 1), (uint8_t)(t1 >> 48)); + + if (GET_LMASK64(t0) <= 5) + stfun(GET_OFFSET(t0, 2), (uint8_t)(t1 >> 40)); + + if (GET_LMASK64(t0) <= 4) + stfun(GET_OFFSET(t0, 3), (uint8_t)(t1 >> 32)); + + if (GET_LMASK64(t0) <= 3) + stfun(GET_OFFSET(t0, 4), (uint8_t)(t1 >> 24)); + + if (GET_LMASK64(t0) <= 2) + stfun(GET_OFFSET(t0, 5), (uint8_t)(t1 >> 16)); + + if (GET_LMASK64(t0) <= 1) + stfun(GET_OFFSET(t0, 6), (uint8_t)(t1 >> 8)); + + if (GET_LMASK64(t0) <= 0) + stfun(GET_OFFSET(t0, 7), (uint8_t)t1); +} + +void do_sdr(target_ulong t0, target_ulong t1, int mem_idx) +{ +#ifdef CONFIG_USER_ONLY +#define stfun stb_raw +#else + void (*stfun)(target_ulong, int); + + switch (mem_idx) + { + case 0: stfun = stb_kernel; break; + case 1: stfun = stb_super; break; + default: + case 2: stfun = stb_user; break; + } +#endif + stfun(t0, (uint8_t)t1); + + if (GET_LMASK64(t0) >= 1) + stfun(GET_OFFSET(t0, -1), (uint8_t)(t1 >> 8)); + + if (GET_LMASK64(t0) >= 2) + stfun(GET_OFFSET(t0, -2), (uint8_t)(t1 >> 16)); + + if (GET_LMASK64(t0) >= 3) + stfun(GET_OFFSET(t0, -3), (uint8_t)(t1 >> 24)); + + if (GET_LMASK64(t0) >= 4) + stfun(GET_OFFSET(t0, -4), (uint8_t)(t1 >> 32)); + + if (GET_LMASK64(t0) >= 5) + stfun(GET_OFFSET(t0, -5), (uint8_t)(t1 >> 40)); + + if (GET_LMASK64(t0) >= 6) + stfun(GET_OFFSET(t0, -6), (uint8_t)(t1 >> 48)); + + if (GET_LMASK64(t0) == 7) + stfun(GET_OFFSET(t0, -7), (uint8_t)(t1 >> 56)); +} +#endif /* TARGET_MIPS64 */ + +#ifndef CONFIG_USER_ONLY +/* CP0 helpers */ +target_ulong do_mfc0_mvpcontrol (void) +{ + return env->mvp->CP0_MVPControl; +} + +target_ulong do_mfc0_mvpconf0 (void) +{ + return env->mvp->CP0_MVPConf0; +} + +target_ulong do_mfc0_mvpconf1 (void) +{ + return env->mvp->CP0_MVPConf1; +} + +target_ulong do_mfc0_random (void) +{ + return (int32_t)cpu_mips_get_random(env); +} + +target_ulong do_mfc0_tcstatus (void) +{ + return env->active_tc.CP0_TCStatus; +} + +target_ulong do_mftc0_tcstatus(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + return env->active_tc.CP0_TCStatus; + else + return env->tcs[other_tc].CP0_TCStatus; +} + +target_ulong do_mfc0_tcbind (void) +{ + return env->active_tc.CP0_TCBind; +} + +target_ulong do_mftc0_tcbind(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + return env->active_tc.CP0_TCBind; + else + return env->tcs[other_tc].CP0_TCBind; +} + +target_ulong do_mfc0_tcrestart (void) +{ + return env->active_tc.PC; +} + +target_ulong do_mftc0_tcrestart(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + return env->active_tc.PC; + else + return env->tcs[other_tc].PC; +} + +target_ulong do_mfc0_tchalt (void) +{ + return env->active_tc.CP0_TCHalt; +} + +target_ulong do_mftc0_tchalt(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + return env->active_tc.CP0_TCHalt; + else + return env->tcs[other_tc].CP0_TCHalt; +} + +target_ulong do_mfc0_tccontext (void) +{ + return env->active_tc.CP0_TCContext; +} + +target_ulong do_mftc0_tccontext(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + return env->active_tc.CP0_TCContext; + else + return env->tcs[other_tc].CP0_TCContext; +} + +target_ulong do_mfc0_tcschedule (void) +{ + return env->active_tc.CP0_TCSchedule; +} + +target_ulong do_mftc0_tcschedule(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + return env->active_tc.CP0_TCSchedule; + else + return env->tcs[other_tc].CP0_TCSchedule; +} + +target_ulong do_mfc0_tcschefback (void) +{ + return env->active_tc.CP0_TCScheFBack; +} + +target_ulong do_mftc0_tcschefback(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + return env->active_tc.CP0_TCScheFBack; + else + return env->tcs[other_tc].CP0_TCScheFBack; +} + +target_ulong do_mfc0_count (void) +{ + return (int32_t)cpu_mips_get_count(env); +} + +target_ulong do_mftc0_entryhi(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + int32_t tcstatus; + + if (other_tc == env->current_tc) + tcstatus = env->active_tc.CP0_TCStatus; + else + tcstatus = env->tcs[other_tc].CP0_TCStatus; + + return (env->CP0_EntryHi & ~0xff) | (tcstatus & 0xff); +} + +target_ulong do_mftc0_status(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + target_ulong t0; + int32_t tcstatus; + + if (other_tc == env->current_tc) + tcstatus = env->active_tc.CP0_TCStatus; + else + tcstatus = env->tcs[other_tc].CP0_TCStatus; + + t0 = env->CP0_Status & ~0xf1000018; + t0 |= tcstatus & (0xf << CP0TCSt_TCU0); + t0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX); + t0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_KSU); + + return t0; +} + +target_ulong do_mfc0_lladdr (void) +{ + return (int32_t)env->CP0_LLAddr >> 4; +} + +target_ulong do_mfc0_watchlo (uint32_t sel) +{ + return (int32_t)env->CP0_WatchLo[sel]; +} + +target_ulong do_mfc0_watchhi (uint32_t sel) +{ + return env->CP0_WatchHi[sel]; +} + +target_ulong do_mfc0_debug (void) +{ + target_ulong t0 = env->CP0_Debug; + if (env->hflags & MIPS_HFLAG_DM) + t0 |= 1 << CP0DB_DM; + + return t0; +} + +target_ulong do_mftc0_debug(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + int32_t tcstatus; + + if (other_tc == env->current_tc) + tcstatus = env->active_tc.CP0_Debug_tcstatus; + else + tcstatus = env->tcs[other_tc].CP0_Debug_tcstatus; + + /* XXX: Might be wrong, check with EJTAG spec. */ + return (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) | + (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))); +} + +#if defined(TARGET_MIPS64) +target_ulong do_dmfc0_tcrestart (void) +{ + return env->active_tc.PC; +} + +target_ulong do_dmfc0_tchalt (void) +{ + return env->active_tc.CP0_TCHalt; +} + +target_ulong do_dmfc0_tccontext (void) +{ + return env->active_tc.CP0_TCContext; +} + +target_ulong do_dmfc0_tcschedule (void) +{ + return env->active_tc.CP0_TCSchedule; +} + +target_ulong do_dmfc0_tcschefback (void) +{ + return env->active_tc.CP0_TCScheFBack; +} + +target_ulong do_dmfc0_lladdr (void) +{ + return env->CP0_LLAddr >> 4; +} + +target_ulong do_dmfc0_watchlo (uint32_t sel) +{ + return env->CP0_WatchLo[sel]; +} +#endif /* TARGET_MIPS64 */ + +void do_mtc0_index (target_ulong t0) +{ + int num = 1; + unsigned int tmp = env->tlb->nb_tlb; + + do { + tmp >>= 1; + num <<= 1; + } while (tmp); + env->CP0_Index = (env->CP0_Index & 0x80000000) | (t0 & (num - 1)); +} + +void do_mtc0_mvpcontrol (target_ulong t0) +{ + uint32_t mask = 0; + uint32_t newval; + + if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) + mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) | + (1 << CP0MVPCo_EVP); + if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) + mask |= (1 << CP0MVPCo_STLB); + newval = (env->mvp->CP0_MVPControl & ~mask) | (t0 & mask); + + // TODO: Enable/disable shared TLB, enable/disable VPEs. + + env->mvp->CP0_MVPControl = newval; +} + +void do_mtc0_vpecontrol (target_ulong t0) +{ + uint32_t mask; + uint32_t newval; + + mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) | + (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC); + newval = (env->CP0_VPEControl & ~mask) | (t0 & mask); + + /* Yield scheduler intercept not implemented. */ + /* Gating storage scheduler intercept not implemented. */ + + // TODO: Enable/disable TCs. + + env->CP0_VPEControl = newval; +} + +void do_mtc0_vpeconf0 (target_ulong t0) +{ + uint32_t mask = 0; + uint32_t newval; + + if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) { + if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA)) + mask |= (0xff << CP0VPEC0_XTC); + mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA); + } + newval = (env->CP0_VPEConf0 & ~mask) | (t0 & mask); + + // TODO: TC exclusive handling due to ERL/EXL. + + env->CP0_VPEConf0 = newval; +} + +void do_mtc0_vpeconf1 (target_ulong t0) +{ + uint32_t mask = 0; + uint32_t newval; + + if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) + mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) | + (0xff << CP0VPEC1_NCP1); + newval = (env->CP0_VPEConf1 & ~mask) | (t0 & mask); + + /* UDI not implemented. */ + /* CP2 not implemented. */ + + // TODO: Handle FPU (CP1) binding. + + env->CP0_VPEConf1 = newval; +} + +void do_mtc0_yqmask (target_ulong t0) +{ + /* Yield qualifier inputs not implemented. */ + env->CP0_YQMask = 0x00000000; +} + +void do_mtc0_vpeopt (target_ulong t0) +{ + env->CP0_VPEOpt = t0 & 0x0000ffff; +} + +void do_mtc0_entrylo0 (target_ulong t0) +{ + /* Large physaddr (PABITS) not implemented */ + /* 1k pages not implemented */ + env->CP0_EntryLo0 = t0 & 0x3FFFFFFF; +} + +void do_mtc0_tcstatus (target_ulong t0) +{ + uint32_t mask = env->CP0_TCStatus_rw_bitmask; + uint32_t newval; + + newval = (env->active_tc.CP0_TCStatus & ~mask) | (t0 & mask); + + // TODO: Sync with CP0_Status. + + env->active_tc.CP0_TCStatus = newval; +} + +void do_mttc0_tcstatus (target_ulong t0) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + // TODO: Sync with CP0_Status. + + if (other_tc == env->current_tc) + env->active_tc.CP0_TCStatus = t0; + else + env->tcs[other_tc].CP0_TCStatus = t0; +} + +void do_mtc0_tcbind (target_ulong t0) +{ + uint32_t mask = (1 << CP0TCBd_TBE); + uint32_t newval; + + if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) + mask |= (1 << CP0TCBd_CurVPE); + newval = (env->active_tc.CP0_TCBind & ~mask) | (t0 & mask); + env->active_tc.CP0_TCBind = newval; +} + +void do_mttc0_tcbind (target_ulong t0) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + uint32_t mask = (1 << CP0TCBd_TBE); + uint32_t newval; + + if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) + mask |= (1 << CP0TCBd_CurVPE); + if (other_tc == env->current_tc) { + newval = (env->active_tc.CP0_TCBind & ~mask) | (t0 & mask); + env->active_tc.CP0_TCBind = newval; + } else { + newval = (env->tcs[other_tc].CP0_TCBind & ~mask) | (t0 & mask); + env->tcs[other_tc].CP0_TCBind = newval; + } +} + +void do_mtc0_tcrestart (target_ulong t0) +{ + env->active_tc.PC = t0; + env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS); + env->CP0_LLAddr = 0ULL; + /* MIPS16 not implemented. */ +} + +void do_mttc0_tcrestart (target_ulong t0) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) { + env->active_tc.PC = t0; + env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS); + env->CP0_LLAddr = 0ULL; + /* MIPS16 not implemented. */ + } else { + env->tcs[other_tc].PC = t0; + env->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS); + env->CP0_LLAddr = 0ULL; + /* MIPS16 not implemented. */ + } +} + +void do_mtc0_tchalt (target_ulong t0) +{ + env->active_tc.CP0_TCHalt = t0 & 0x1; + + // TODO: Halt TC / Restart (if allocated+active) TC. +} + +void do_mttc0_tchalt (target_ulong t0) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + // TODO: Halt TC / Restart (if allocated+active) TC. + + if (other_tc == env->current_tc) + env->active_tc.CP0_TCHalt = t0; + else + env->tcs[other_tc].CP0_TCHalt = t0; } -void do_dsll32 (void) +void do_mtc0_tccontext (target_ulong t0) { - T0 = T0 << (T1 + 32); + env->active_tc.CP0_TCContext = t0; } -void do_dsra (void) +void do_mttc0_tccontext (target_ulong t0) { - T0 = (int64_t)T0 >> T1; + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + env->active_tc.CP0_TCContext = t0; + else + env->tcs[other_tc].CP0_TCContext = t0; } -void do_dsra32 (void) +void do_mtc0_tcschedule (target_ulong t0) { - T0 = (int64_t)T0 >> (T1 + 32); + env->active_tc.CP0_TCSchedule = t0; } -void do_dsrl (void) +void do_mttc0_tcschedule (target_ulong t0) { - T0 = T0 >> T1; + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + env->active_tc.CP0_TCSchedule = t0; + else + env->tcs[other_tc].CP0_TCSchedule = t0; } -void do_dsrl32 (void) +void do_mtc0_tcschefback (target_ulong t0) { - T0 = T0 >> (T1 + 32); + env->active_tc.CP0_TCScheFBack = t0; } -void do_drotr (void) +void do_mttc0_tcschefback (target_ulong t0) { - target_ulong tmp; + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - if (T1) { - tmp = T0 << (0x40 - T1); - T0 = (T0 >> T1) | tmp; - } + if (other_tc == env->current_tc) + env->active_tc.CP0_TCScheFBack = t0; + else + env->tcs[other_tc].CP0_TCScheFBack = t0; } -void do_drotr32 (void) +void do_mtc0_entrylo1 (target_ulong t0) { - target_ulong tmp; - - tmp = T0 << (0x40 - (32 + T1)); - T0 = (T0 >> (32 + T1)) | tmp; + /* Large physaddr (PABITS) not implemented */ + /* 1k pages not implemented */ + env->CP0_EntryLo1 = t0 & 0x3FFFFFFF; } -void do_dsllv (void) +void do_mtc0_context (target_ulong t0) { - T0 = T1 << (T0 & 0x3F); + env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (t0 & ~0x007FFFFF); } -void do_dsrav (void) +void do_mtc0_pagemask (target_ulong t0) { - T0 = (int64_t)T1 >> (T0 & 0x3F); + /* 1k pages not implemented */ + env->CP0_PageMask = t0 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1)); } -void do_dsrlv (void) +void do_mtc0_pagegrain (target_ulong t0) { - T0 = T1 >> (T0 & 0x3F); + /* SmartMIPS not implemented */ + /* Large physaddr (PABITS) not implemented */ + /* 1k pages not implemented */ + env->CP0_PageGrain = 0; } -void do_drotrv (void) +void do_mtc0_wired (target_ulong t0) { - target_ulong tmp; - - T0 &= 0x3F; - if (T0) { - tmp = T1 << (0x40 - T0); - T0 = (T1 >> T0) | tmp; - } else - T0 = T1; + env->CP0_Wired = t0 % env->tlb->nb_tlb; } -void do_dclo (void) +void do_mtc0_srsconf0 (target_ulong t0) { - T0 = clo64(T0); + env->CP0_SRSConf0 |= t0 & env->CP0_SRSConf0_rw_bitmask; } -void do_dclz (void) +void do_mtc0_srsconf1 (target_ulong t0) { - T0 = clz64(T0); + env->CP0_SRSConf1 |= t0 & env->CP0_SRSConf1_rw_bitmask; } -#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ -#endif /* TARGET_MIPS64 */ +void do_mtc0_srsconf2 (target_ulong t0) +{ + env->CP0_SRSConf2 |= t0 & env->CP0_SRSConf2_rw_bitmask; +} -/* 64 bits arithmetic for 32 bits hosts */ -#if TARGET_LONG_BITS > HOST_LONG_BITS -static always_inline uint64_t get_HILO (void) +void do_mtc0_srsconf3 (target_ulong t0) { - return (env->HI[0][env->current_tc] << 32) | (uint32_t)env->LO[0][env->current_tc]; + env->CP0_SRSConf3 |= t0 & env->CP0_SRSConf3_rw_bitmask; } -static always_inline void set_HILO (uint64_t HILO) +void do_mtc0_srsconf4 (target_ulong t0) { - env->LO[0][env->current_tc] = (int32_t)HILO; - env->HI[0][env->current_tc] = (int32_t)(HILO >> 32); + env->CP0_SRSConf4 |= t0 & env->CP0_SRSConf4_rw_bitmask; } -static always_inline void set_HIT0_LO (uint64_t HILO) +void do_mtc0_hwrena (target_ulong t0) { - env->LO[0][env->current_tc] = (int32_t)(HILO & 0xFFFFFFFF); - T0 = env->HI[0][env->current_tc] = (int32_t)(HILO >> 32); + env->CP0_HWREna = t0 & 0x0000000F; } -static always_inline void set_HI_LOT0 (uint64_t HILO) +void do_mtc0_count (target_ulong t0) { - T0 = env->LO[0][env->current_tc] = (int32_t)(HILO & 0xFFFFFFFF); - env->HI[0][env->current_tc] = (int32_t)(HILO >> 32); + cpu_mips_store_count(env, t0); } -void do_mult (void) +void do_mtc0_entryhi (target_ulong t0) { - set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); + target_ulong old, val; + + /* 1k pages not implemented */ + val = t0 & ((TARGET_PAGE_MASK << 1) | 0xFF); +#if defined(TARGET_MIPS64) + val &= env->SEGMask; +#endif + old = env->CP0_EntryHi; + env->CP0_EntryHi = val; + if (env->CP0_Config3 & (1 << CP0C3_MT)) { + uint32_t tcst = env->active_tc.CP0_TCStatus & ~0xff; + env->active_tc.CP0_TCStatus = tcst | (val & 0xff); + } + /* If the ASID changes, flush qemu's TLB. */ + if ((old & 0xFF) != (val & 0xFF)) + cpu_mips_tlb_flush(env, 1); +} + +void do_mttc0_entryhi(target_ulong t0) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + int32_t tcstatus; + + env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (t0 & ~0xff); + if (other_tc == env->current_tc) { + tcstatus = (env->active_tc.CP0_TCStatus & ~0xff) | (t0 & 0xff); + env->active_tc.CP0_TCStatus = tcstatus; + } else { + tcstatus = (env->tcs[other_tc].CP0_TCStatus & ~0xff) | (t0 & 0xff); + env->tcs[other_tc].CP0_TCStatus = tcstatus; + } } -void do_multu (void) +void do_mtc0_compare (target_ulong t0) { - set_HILO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); + cpu_mips_store_compare(env, t0); } -void do_madd (void) +void do_mtc0_status (target_ulong t0) { - int64_t tmp; + uint32_t val, old; + uint32_t mask = env->CP0_Status_rw_bitmask; - tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); - set_HILO((int64_t)get_HILO() + tmp); + val = t0 & mask; + old = env->CP0_Status; + env->CP0_Status = (env->CP0_Status & ~mask) | val; + compute_hflags(env); + if (loglevel & CPU_LOG_EXEC) + do_mtc0_status_debug(old, val); + cpu_mips_update_irq(env); } -void do_maddu (void) +void do_mttc0_status(target_ulong t0) { - uint64_t tmp; + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + int32_t tcstatus = env->tcs[other_tc].CP0_TCStatus; - tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); - set_HILO(get_HILO() + tmp); + env->CP0_Status = t0 & ~0xf1000018; + tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (t0 & (0xf << CP0St_CU0)); + tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((t0 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX)); + tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((t0 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU)); + if (other_tc == env->current_tc) + env->active_tc.CP0_TCStatus = tcstatus; + else + env->tcs[other_tc].CP0_TCStatus = tcstatus; } -void do_msub (void) +void do_mtc0_intctl (target_ulong t0) { - int64_t tmp; + /* vectored interrupts not implemented, no performance counters. */ + env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (t0 & 0x000002e0); +} - tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); - set_HILO((int64_t)get_HILO() - tmp); +void do_mtc0_srsctl (target_ulong t0) +{ + uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS); + env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (t0 & mask); } -void do_msubu (void) +void do_mtc0_cause (target_ulong t0) { - uint64_t tmp; + uint32_t mask = 0x00C00300; + uint32_t old = env->CP0_Cause; - tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); - set_HILO(get_HILO() - tmp); + if (env->insn_flags & ISA_MIPS32R2) + mask |= 1 << CP0Ca_DC; + + env->CP0_Cause = (env->CP0_Cause & ~mask) | (t0 & mask); + + if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) { + if (env->CP0_Cause & (1 << CP0Ca_DC)) + cpu_mips_stop_count(env); + else + cpu_mips_start_count(env); + } + + /* Handle the software interrupt as an hardware one, as they + are very similar */ + if (t0 & CP0Ca_IP_mask) { + cpu_mips_update_irq(env); + } } -/* Multiplication variants of the vr54xx. */ -void do_muls (void) +void do_mtc0_ebase (target_ulong t0) { - set_HI_LOT0(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1)); + /* vectored interrupts not implemented */ + /* Multi-CPU not implemented */ + env->CP0_EBase = 0x80000000 | (t0 & 0x3FFFF000); } -void do_mulsu (void) +void do_mtc0_config0 (target_ulong t0) { - set_HI_LOT0(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1)); + env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (t0 & 0x00000007); } -void do_macc (void) +void do_mtc0_config2 (target_ulong t0) { - set_HI_LOT0(((int64_t)get_HILO()) + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1)); + /* tertiary/secondary caches not implemented */ + env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF); } -void do_macchi (void) +void do_mtc0_watchlo (target_ulong t0, uint32_t sel) { - set_HIT0_LO(((int64_t)get_HILO()) + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1)); + /* Watch exceptions for instructions, data loads, data stores + not implemented. */ + env->CP0_WatchLo[sel] = (t0 & ~0x7); } -void do_maccu (void) +void do_mtc0_watchhi (target_ulong t0, uint32_t sel) { - set_HI_LOT0(((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1)); + env->CP0_WatchHi[sel] = (t0 & 0x40FF0FF8); + env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & t0 & 0x7); } -void do_macchiu (void) +void do_mtc0_xcontext (target_ulong t0) { - set_HIT0_LO(((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1)); + target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1; + env->CP0_XContext = (env->CP0_XContext & mask) | (t0 & ~mask); } -void do_msac (void) +void do_mtc0_framemask (target_ulong t0) { - set_HI_LOT0(((int64_t)get_HILO()) - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1)); + env->CP0_Framemask = t0; /* XXX */ } -void do_msachi (void) +void do_mtc0_debug (target_ulong t0) { - set_HIT0_LO(((int64_t)get_HILO()) - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1)); + env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (t0 & 0x13300120); + if (t0 & (1 << CP0DB_DM)) + env->hflags |= MIPS_HFLAG_DM; + else + env->hflags &= ~MIPS_HFLAG_DM; } -void do_msacu (void) +void do_mttc0_debug(target_ulong t0) { - set_HI_LOT0(((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1)); + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + uint32_t val = t0 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)); + + /* XXX: Might be wrong, check with EJTAG spec. */ + if (other_tc == env->current_tc) + env->active_tc.CP0_Debug_tcstatus = val; + else + env->tcs[other_tc].CP0_Debug_tcstatus = val; + env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) | + (t0 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))); } -void do_msachiu (void) +void do_mtc0_performance0 (target_ulong t0) { - set_HIT0_LO(((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1)); + env->CP0_Performance0 = t0 & 0x000007ff; } -void do_mulhi (void) +void do_mtc0_taglo (target_ulong t0) { - set_HIT0_LO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); + env->CP0_TagLo = t0 & 0xFFFFFCF6; } -void do_mulhiu (void) +void do_mtc0_datalo (target_ulong t0) { - set_HIT0_LO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); + env->CP0_DataLo = t0; /* XXX */ } -void do_mulshi (void) +void do_mtc0_taghi (target_ulong t0) { - set_HIT0_LO(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1)); + env->CP0_TagHi = t0; /* XXX */ } -void do_mulshiu (void) +void do_mtc0_datahi (target_ulong t0) { - set_HIT0_LO(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1)); + env->CP0_DataHi = t0; /* XXX */ } -#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ -#if HOST_LONG_BITS < 64 -void do_div (void) +void do_mtc0_status_debug(uint32_t old, uint32_t val) { - /* 64bit datatypes because we may see overflow/underflow. */ - if (T1 != 0) { - env->LO[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1); - env->HI[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1); + fprintf(logfile, "Status %08x (%08x) => %08x (%08x) Cause %08x", + old, old & env->CP0_Cause & CP0Ca_IP_mask, + val, val & env->CP0_Cause & CP0Ca_IP_mask, + env->CP0_Cause); + switch (env->hflags & MIPS_HFLAG_KSU) { + case MIPS_HFLAG_UM: fputs(", UM\n", logfile); break; + case MIPS_HFLAG_SM: fputs(", SM\n", logfile); break; + case MIPS_HFLAG_KM: fputs("\n", logfile); break; + default: cpu_abort(env, "Invalid MMU mode!\n"); break; } } -#endif -#if defined(TARGET_MIPS64) -void do_ddiv (void) +void do_mtc0_status_irqraise_debug(void) { - if (T1 != 0) { - int64_t arg0 = (int64_t)T0; - int64_t arg1 = (int64_t)T1; - if (arg0 == ((int64_t)-1 << 63) && arg1 == (int64_t)-1) { - env->LO[0][env->current_tc] = arg0; - env->HI[0][env->current_tc] = 0; - } else { - lldiv_t res = lldiv(arg0, arg1); - env->LO[0][env->current_tc] = res.quot; - env->HI[0][env->current_tc] = res.rem; - } - } + fprintf(logfile, "Raise pending IRQs\n"); } +#endif /* !CONFIG_USER_ONLY */ -#if TARGET_LONG_BITS > HOST_LONG_BITS -void do_ddivu (void) +/* MIPS MT functions */ +target_ulong do_mftgpr(uint32_t sel) { - if (T1 != 0) { - env->LO[0][env->current_tc] = T0 / T1; - env->HI[0][env->current_tc] = T0 % T1; - } + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + return env->active_tc.gpr[sel]; + else + return env->tcs[other_tc].gpr[sel]; } -#endif -#endif /* TARGET_MIPS64 */ -#if defined(CONFIG_USER_ONLY) -void do_mfc0_random (void) +target_ulong do_mftlo(uint32_t sel) { - cpu_abort(env, "mfc0 random\n"); + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + return env->active_tc.LO[sel]; + else + return env->tcs[other_tc].LO[sel]; } -void do_mfc0_count (void) +target_ulong do_mfthi(uint32_t sel) { - cpu_abort(env, "mfc0 count\n"); + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + return env->active_tc.HI[sel]; + else + return env->tcs[other_tc].HI[sel]; } -void cpu_mips_store_count(CPUState *env, uint32_t value) +target_ulong do_mftacx(uint32_t sel) { - cpu_abort(env, "mtc0 count\n"); + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + return env->active_tc.ACX[sel]; + else + return env->tcs[other_tc].ACX[sel]; } -void cpu_mips_store_compare(CPUState *env, uint32_t value) +target_ulong do_mftdsp(void) { - cpu_abort(env, "mtc0 compare\n"); + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + return env->active_tc.DSPControl; + else + return env->tcs[other_tc].DSPControl; } -void cpu_mips_start_count(CPUState *env) +void do_mttgpr(target_ulong t0, uint32_t sel) { - cpu_abort(env, "start count\n"); + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + env->active_tc.gpr[sel] = t0; + else + env->tcs[other_tc].gpr[sel] = t0; } -void cpu_mips_stop_count(CPUState *env) +void do_mttlo(target_ulong t0, uint32_t sel) { - cpu_abort(env, "stop count\n"); + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + env->active_tc.LO[sel] = t0; + else + env->tcs[other_tc].LO[sel] = t0; } -void cpu_mips_update_irq(CPUState *env) +void do_mtthi(target_ulong t0, uint32_t sel) { - cpu_abort(env, "mtc0 status / mtc0 cause\n"); + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + env->active_tc.HI[sel] = t0; + else + env->tcs[other_tc].HI[sel] = t0; } -void do_mtc0_status_debug(uint32_t old, uint32_t val) +void do_mttacx(target_ulong t0, uint32_t sel) { - cpu_abort(env, "mtc0 status debug\n"); + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + env->active_tc.ACX[sel] = t0; + else + env->tcs[other_tc].ACX[sel] = t0; } -void do_mtc0_status_irqraise_debug (void) +void do_mttdsp(target_ulong t0) { - cpu_abort(env, "mtc0 status irqraise debug\n"); + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if (other_tc == env->current_tc) + env->active_tc.DSPControl = t0; + else + env->tcs[other_tc].DSPControl = t0; } -void cpu_mips_tlb_flush (CPUState *env, int flush_global) +/* MIPS MT functions */ +target_ulong do_dmt(target_ulong t0) { - cpu_abort(env, "mips_tlb_flush\n"); -} + // TODO + t0 = 0; + // rt = t0 -#else + return t0; +} -/* CP0 helpers */ -void do_mfc0_random (void) +target_ulong do_emt(target_ulong t0) { - T0 = (int32_t)cpu_mips_get_random(env); + // TODO + t0 = 0; + // rt = t0 + + return t0; } -void do_mfc0_count (void) +target_ulong do_dvpe(target_ulong t0) { - T0 = (int32_t)cpu_mips_get_count(env); + // TODO + t0 = 0; + // rt = t0 + + return t0; } -void do_mtc0_status_debug(uint32_t old, uint32_t val) +target_ulong do_evpe(target_ulong t0) { - fprintf(logfile, "Status %08x (%08x) => %08x (%08x) Cause %08x", - old, old & env->CP0_Cause & CP0Ca_IP_mask, - val, val & env->CP0_Cause & CP0Ca_IP_mask, - env->CP0_Cause); - switch (env->hflags & MIPS_HFLAG_KSU) { - case MIPS_HFLAG_UM: fputs(", UM\n", logfile); break; - case MIPS_HFLAG_SM: fputs(", SM\n", logfile); break; - case MIPS_HFLAG_KM: fputs("\n", logfile); break; - default: cpu_abort(env, "Invalid MMU mode!\n"); break; - } + // TODO + t0 = 0; + // rt = t0 + + return t0; } -void do_mtc0_status_irqraise_debug(void) +void do_fork(target_ulong t0, target_ulong t1) { - fprintf(logfile, "Raise pending IRQs\n"); + // t0 = rt, t1 = rs + t0 = 0; + // TODO: store to TC register } -void fpu_handle_exception(void) +target_ulong do_yield(target_ulong t0) { -#ifdef CONFIG_SOFTFLOAT - int flags = get_float_exception_flags(&env->fpu->fp_status); - unsigned int cpuflags = 0, enable, cause = 0; - - enable = GET_FP_ENABLE(env->fpu->fcr31); - - /* determine current flags */ - if (flags & float_flag_invalid) { - cpuflags |= FP_INVALID; - cause |= FP_INVALID & enable; - } - if (flags & float_flag_divbyzero) { - cpuflags |= FP_DIV0; - cause |= FP_DIV0 & enable; - } - if (flags & float_flag_overflow) { - cpuflags |= FP_OVERFLOW; - cause |= FP_OVERFLOW & enable; - } - if (flags & float_flag_underflow) { - cpuflags |= FP_UNDERFLOW; - cause |= FP_UNDERFLOW & enable; - } - if (flags & float_flag_inexact) { - cpuflags |= FP_INEXACT; - cause |= FP_INEXACT & enable; + if (t0 < 0) { + /* No scheduling policy implemented. */ + if (t0 != -2) { + if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) && + env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) { + env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); + env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT; + do_raise_exception(EXCP_THREAD); + } + } + } else if (t0 == 0) { + if (0 /* TODO: TC underflow */) { + env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); + do_raise_exception(EXCP_THREAD); + } else { + // TODO: Deallocate TC + } + } else if (t0 > 0) { + /* Yield qualifier inputs not implemented. */ + env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); + env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT; + do_raise_exception(EXCP_THREAD); } - SET_FP_FLAGS(env->fpu->fcr31, cpuflags); - SET_FP_CAUSE(env->fpu->fcr31, cause); -#else - SET_FP_FLAGS(env->fpu->fcr31, 0); - SET_FP_CAUSE(env->fpu->fcr31, 0); -#endif + return env->CP0_YQMask; } +#ifndef CONFIG_USER_ONLY /* TLB management */ void cpu_mips_tlb_flush (CPUState *env, int flush_global) { @@ -498,13 +1572,17 @@ void r4k_do_tlbwi (void) { + int idx; + + idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb; + /* Discard cached TLB entries. We could avoid doing this if the tlbwi is just upgrading access permissions on the current entry; that might be a further win. */ r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb); - r4k_invalidate_tlb(env, env->CP0_Index % env->tlb->nb_tlb, 0); - r4k_fill_tlb(env->CP0_Index % env->tlb->nb_tlb); + r4k_invalidate_tlb(env, idx, 0); + r4k_fill_tlb(idx); } void r4k_do_tlbwr (void) @@ -561,9 +1639,11 @@ { r4k_tlb_t *tlb; uint8_t ASID; + int idx; ASID = env->CP0_EntryHi & 0xFF; - tlb = &env->tlb->mmu.r4k.tlb[env->CP0_Index % env->tlb->nb_tlb]; + idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb; + tlb = &env->tlb->mmu.r4k.tlb[idx]; /* If this will change the current ASID, flush qemu's TLB. */ if (ASID != tlb->ASID) @@ -579,26 +1659,31 @@ (tlb->C1 << 3) | (tlb->PFN[1] >> 6); } -#endif /* !CONFIG_USER_ONLY */ - -void dump_ldst (const unsigned char *func) +/* Specials */ +target_ulong do_di (void) { - if (loglevel) - fprintf(logfile, "%s => " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, T0, T1); + target_ulong t0 = env->CP0_Status; + + env->CP0_Status = t0 & ~(1 << CP0St_IE); + cpu_mips_update_irq(env); + + return t0; } -void dump_sc (void) +target_ulong do_ei (void) { - if (loglevel) { - fprintf(logfile, "%s " TARGET_FMT_lx " at " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", __func__, - T1, T0, env->CP0_LLAddr); - } + target_ulong t0 = env->CP0_Status; + + env->CP0_Status = t0 | (1 << CP0St_IE); + cpu_mips_update_irq(env); + + return t0; } void debug_pre_eret (void) { fprintf(logfile, "ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, - env->PC[env->current_tc], env->CP0_EPC); + env->active_tc.PC, env->CP0_EPC); if (env->CP0_Status & (1 << CP0St_ERL)) fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); if (env->hflags & MIPS_HFLAG_DM) @@ -609,7 +1694,7 @@ void debug_post_eret (void) { fprintf(logfile, " => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, - env->PC[env->current_tc], env->CP0_EPC); + env->active_tc.PC, env->CP0_EPC); if (env->CP0_Status & (1 << CP0St_ERL)) fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); if (env->hflags & MIPS_HFLAG_DM) @@ -622,32 +1707,112 @@ } } +void do_eret (void) +{ + if (loglevel & CPU_LOG_EXEC) + debug_pre_eret(); + if (env->CP0_Status & (1 << CP0St_ERL)) { + env->active_tc.PC = env->CP0_ErrorEPC; + env->CP0_Status &= ~(1 << CP0St_ERL); + } else { + env->active_tc.PC = env->CP0_EPC; + env->CP0_Status &= ~(1 << CP0St_EXL); + } + compute_hflags(env); + if (loglevel & CPU_LOG_EXEC) + debug_post_eret(); + env->CP0_LLAddr = 1; +} + +void do_deret (void) +{ + if (loglevel & CPU_LOG_EXEC) + debug_pre_eret(); + env->active_tc.PC = env->CP0_DEPC; + env->hflags &= MIPS_HFLAG_DM; + compute_hflags(env); + if (loglevel & CPU_LOG_EXEC) + debug_post_eret(); + env->CP0_LLAddr = 1; +} +#endif /* !CONFIG_USER_ONLY */ + +target_ulong do_rdhwr_cpunum(void) +{ + if ((env->hflags & MIPS_HFLAG_CP0) || + (env->CP0_HWREna & (1 << 0))) + return env->CP0_EBase & 0x3ff; + else + do_raise_exception(EXCP_RI); + + return 0; +} + +target_ulong do_rdhwr_synci_step(void) +{ + if ((env->hflags & MIPS_HFLAG_CP0) || + (env->CP0_HWREna & (1 << 1))) + return env->SYNCI_Step; + else + do_raise_exception(EXCP_RI); + + return 0; +} + +target_ulong do_rdhwr_cc(void) +{ + if ((env->hflags & MIPS_HFLAG_CP0) || + (env->CP0_HWREna & (1 << 2))) + return env->CP0_Count; + else + do_raise_exception(EXCP_RI); + + return 0; +} + +target_ulong do_rdhwr_ccres(void) +{ + if ((env->hflags & MIPS_HFLAG_CP0) || + (env->CP0_HWREna & (1 << 3))) + return env->CCRes; + else + do_raise_exception(EXCP_RI); + + return 0; +} + void do_pmon (int function) { function /= 2; switch (function) { case 2: /* TODO: char inbyte(int waitflag); */ - if (env->gpr[4][env->current_tc] == 0) - env->gpr[2][env->current_tc] = -1; + if (env->active_tc.gpr[4] == 0) + env->active_tc.gpr[2] = -1; /* Fall through */ case 11: /* TODO: char inbyte (void); */ - env->gpr[2][env->current_tc] = -1; + env->active_tc.gpr[2] = -1; break; case 3: case 12: - printf("%c", (char)(env->gpr[4][env->current_tc] & 0xFF)); + printf("%c", (char)(env->active_tc.gpr[4] & 0xFF)); break; case 17: break; case 158: { - unsigned char *fmt = (void *)(unsigned long)env->gpr[4][env->current_tc]; + unsigned char *fmt = (void *)(unsigned long)env->active_tc.gpr[4]; printf("%s", fmt); } break; } } +void do_wait (void) +{ + env->halted = 1; + do_raise_exception(EXCP_HLT); +} + #if !defined(CONFIG_USER_ONLY) static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr); @@ -703,14 +1868,14 @@ } void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, - int unused) + int unused, int size) { if (is_exec) do_raise_exception(EXCP_IBE); else do_raise_exception(EXCP_DBE); } -#endif +#endif /* !CONFIG_USER_ONLY */ /* Complex FPU operations which may need stack space. */ @@ -732,65 +1897,69 @@ }; #define RESTORE_ROUNDING_MODE \ - set_float_rounding_mode(ieee_rm[env->fpu->fcr31 & 3], &env->fpu->fp_status) + set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status) -void do_cfc1 (int reg) +target_ulong do_cfc1 (uint32_t reg) { + target_ulong t0; + switch (reg) { case 0: - T0 = (int32_t)env->fpu->fcr0; + t0 = (int32_t)env->active_fpu.fcr0; break; case 25: - T0 = ((env->fpu->fcr31 >> 24) & 0xfe) | ((env->fpu->fcr31 >> 23) & 0x1); + t0 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1); break; case 26: - T0 = env->fpu->fcr31 & 0x0003f07c; + t0 = env->active_fpu.fcr31 & 0x0003f07c; break; case 28: - T0 = (env->fpu->fcr31 & 0x00000f83) | ((env->fpu->fcr31 >> 22) & 0x4); + t0 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4); break; default: - T0 = (int32_t)env->fpu->fcr31; + t0 = (int32_t)env->active_fpu.fcr31; break; } + + return t0; } -void do_ctc1 (int reg) +void do_ctc1 (target_ulong t0, uint32_t reg) { switch(reg) { case 25: - if (T0 & 0xffffff00) + if (t0 & 0xffffff00) return; - env->fpu->fcr31 = (env->fpu->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) | - ((T0 & 0x1) << 23); + env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((t0 & 0xfe) << 24) | + ((t0 & 0x1) << 23); break; case 26: - if (T0 & 0x007c0000) + if (t0 & 0x007c0000) return; - env->fpu->fcr31 = (env->fpu->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c); + env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (t0 & 0x0003f07c); break; case 28: - if (T0 & 0x007c0000) + if (t0 & 0x007c0000) return; - env->fpu->fcr31 = (env->fpu->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) | - ((T0 & 0x4) << 22); + env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (t0 & 0x00000f83) | + ((t0 & 0x4) << 22); break; case 31: - if (T0 & 0x007c0000) + if (t0 & 0x007c0000) return; - env->fpu->fcr31 = T0; + env->active_fpu.fcr31 = t0; break; default: return; } /* set rounding mode */ RESTORE_ROUNDING_MODE; - set_float_exception_flags(0, &env->fpu->fp_status); - if ((GET_FP_ENABLE(env->fpu->fcr31) | 0x20) & GET_FP_CAUSE(env->fpu->fcr31)) + set_float_exception_flags(0, &env->active_fpu.fp_status); + if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31)) do_raise_exception(EXCP_FPE); } -static always_inline char ieee_ex_to_mips(char xcpt) +static inline char ieee_ex_to_mips(char xcpt) { return (xcpt & float_flag_inexact) >> 5 | (xcpt & float_flag_underflow) >> 3 | @@ -799,7 +1968,7 @@ (xcpt & float_flag_invalid) << 4; } -static always_inline char mips_ex_to_ieee(char xcpt) +static inline char mips_ex_to_ieee(char xcpt) { return (xcpt & FP_INEXACT) << 5 | (xcpt & FP_UNDERFLOW) << 3 | @@ -808,456 +1977,782 @@ (xcpt & FP_INVALID) >> 4; } -static always_inline void update_fcr31(void) +static inline void update_fcr31(void) { - int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fpu->fp_status)); + int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status)); - SET_FP_CAUSE(env->fpu->fcr31, tmp); - if (GET_FP_ENABLE(env->fpu->fcr31) & tmp) + SET_FP_CAUSE(env->active_fpu.fcr31, tmp); + if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) do_raise_exception(EXCP_FPE); else - UPDATE_FP_FLAGS(env->fpu->fcr31, tmp); + UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp); } -#define FLOAT_OP(name, p) void do_float_##name##_##p(void) +/* Float support. + Single precition routines have a "s" suffix, double precision a + "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps", + paired single lower "pl", paired single upper "pu". */ + +/* unary operations, modifying fp status */ +uint64_t do_float_sqrt_d(uint64_t fdt0) +{ + return float64_sqrt(fdt0, &env->active_fpu.fp_status); +} -FLOAT_OP(cvtd, s) +uint32_t do_float_sqrt_s(uint32_t fst0) { - set_float_exception_flags(0, &env->fpu->fp_status); - FDT2 = float32_to_float64(FST0, &env->fpu->fp_status); + return float32_sqrt(fst0, &env->active_fpu.fp_status); +} + +uint64_t do_float_cvtd_s(uint32_t fst0) +{ + uint64_t fdt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status); update_fcr31(); + return fdt2; } -FLOAT_OP(cvtd, w) + +uint64_t do_float_cvtd_w(uint32_t wt0) { - set_float_exception_flags(0, &env->fpu->fp_status); - FDT2 = int32_to_float64(WT0, &env->fpu->fp_status); + uint64_t fdt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status); update_fcr31(); + return fdt2; } -FLOAT_OP(cvtd, l) + +uint64_t do_float_cvtd_l(uint64_t dt0) { - set_float_exception_flags(0, &env->fpu->fp_status); - FDT2 = int64_to_float64(DT0, &env->fpu->fp_status); + uint64_t fdt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status); update_fcr31(); + return fdt2; } -FLOAT_OP(cvtl, d) + +uint64_t do_float_cvtl_d(uint64_t fdt0) { - set_float_exception_flags(0, &env->fpu->fp_status); - DT2 = float64_to_int64(FDT0, &env->fpu->fp_status); + uint64_t dt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = FLOAT_SNAN64; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; } -FLOAT_OP(cvtl, s) + +uint64_t do_float_cvtl_s(uint32_t fst0) { - set_float_exception_flags(0, &env->fpu->fp_status); - DT2 = float32_to_int64(FST0, &env->fpu->fp_status); + uint64_t dt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = FLOAT_SNAN64; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; } -FLOAT_OP(cvtps, pw) +uint64_t do_float_cvtps_pw(uint64_t dt0) { - set_float_exception_flags(0, &env->fpu->fp_status); - FST2 = int32_to_float32(WT0, &env->fpu->fp_status); - FSTH2 = int32_to_float32(WTH0, &env->fpu->fp_status); + uint32_t fst2; + uint32_t fsth2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status); + fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status); update_fcr31(); + return ((uint64_t)fsth2 << 32) | fst2; } -FLOAT_OP(cvtpw, ps) + +uint64_t do_float_cvtpw_ps(uint64_t fdt0) { - set_float_exception_flags(0, &env->fpu->fp_status); - WT2 = float32_to_int32(FST0, &env->fpu->fp_status); - WTH2 = float32_to_int32(FSTH0, &env->fpu->fp_status); + uint32_t wt2; + uint32_t wth2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status); + wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = FLOAT_SNAN32; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) { + wt2 = FLOAT_SNAN32; + wth2 = FLOAT_SNAN32; + } + return ((uint64_t)wth2 << 32) | wt2; } -FLOAT_OP(cvts, d) + +uint32_t do_float_cvts_d(uint64_t fdt0) { - set_float_exception_flags(0, &env->fpu->fp_status); - FST2 = float64_to_float32(FDT0, &env->fpu->fp_status); + uint32_t fst2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status); update_fcr31(); + return fst2; } -FLOAT_OP(cvts, w) + +uint32_t do_float_cvts_w(uint32_t wt0) { - set_float_exception_flags(0, &env->fpu->fp_status); - FST2 = int32_to_float32(WT0, &env->fpu->fp_status); + uint32_t fst2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status); update_fcr31(); + return fst2; } -FLOAT_OP(cvts, l) + +uint32_t do_float_cvts_l(uint64_t dt0) { - set_float_exception_flags(0, &env->fpu->fp_status); - FST2 = int64_to_float32(DT0, &env->fpu->fp_status); + uint32_t fst2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status); update_fcr31(); + return fst2; } -FLOAT_OP(cvts, pl) + +uint32_t do_float_cvts_pl(uint32_t wt0) { - set_float_exception_flags(0, &env->fpu->fp_status); - WT2 = WT0; + uint32_t wt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + wt2 = wt0; update_fcr31(); + return wt2; } -FLOAT_OP(cvts, pu) + +uint32_t do_float_cvts_pu(uint32_t wth0) { - set_float_exception_flags(0, &env->fpu->fp_status); - WT2 = WTH0; + uint32_t wt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + wt2 = wth0; update_fcr31(); + return wt2; } -FLOAT_OP(cvtw, s) + +uint32_t do_float_cvtw_s(uint32_t fst0) { - set_float_exception_flags(0, &env->fpu->fp_status); - WT2 = float32_to_int32(FST0, &env->fpu->fp_status); + uint32_t wt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = FLOAT_SNAN32; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; } -FLOAT_OP(cvtw, d) + +uint32_t do_float_cvtw_d(uint64_t fdt0) { - set_float_exception_flags(0, &env->fpu->fp_status); - WT2 = float64_to_int32(FDT0, &env->fpu->fp_status); + uint32_t wt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = FLOAT_SNAN32; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; } -FLOAT_OP(roundl, d) +uint64_t do_float_roundl_d(uint64_t fdt0) { - set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status); - DT2 = float64_to_int64(FDT0, &env->fpu->fp_status); + uint64_t dt2; + + set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); + dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = FLOAT_SNAN64; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; } -FLOAT_OP(roundl, s) + +uint64_t do_float_roundl_s(uint32_t fst0) { - set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status); - DT2 = float32_to_int64(FST0, &env->fpu->fp_status); + uint64_t dt2; + + set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); + dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = FLOAT_SNAN64; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; } -FLOAT_OP(roundw, d) + +uint32_t do_float_roundw_d(uint64_t fdt0) { - set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status); - WT2 = float64_to_int32(FDT0, &env->fpu->fp_status); + uint32_t wt2; + + set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); + wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = FLOAT_SNAN32; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; } -FLOAT_OP(roundw, s) + +uint32_t do_float_roundw_s(uint32_t fst0) { - set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status); - WT2 = float32_to_int32(FST0, &env->fpu->fp_status); + uint32_t wt2; + + set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); + wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = FLOAT_SNAN32; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; } -FLOAT_OP(truncl, d) +uint64_t do_float_truncl_d(uint64_t fdt0) { - DT2 = float64_to_int64_round_to_zero(FDT0, &env->fpu->fp_status); + uint64_t dt2; + + dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = FLOAT_SNAN64; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; } -FLOAT_OP(truncl, s) + +uint64_t do_float_truncl_s(uint32_t fst0) { - DT2 = float32_to_int64_round_to_zero(FST0, &env->fpu->fp_status); + uint64_t dt2; + + dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = FLOAT_SNAN64; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; } -FLOAT_OP(truncw, d) + +uint32_t do_float_truncw_d(uint64_t fdt0) { - WT2 = float64_to_int32_round_to_zero(FDT0, &env->fpu->fp_status); + uint32_t wt2; + + wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = FLOAT_SNAN32; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; } -FLOAT_OP(truncw, s) + +uint32_t do_float_truncw_s(uint32_t fst0) { - WT2 = float32_to_int32_round_to_zero(FST0, &env->fpu->fp_status); + uint32_t wt2; + + wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = FLOAT_SNAN32; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; } -FLOAT_OP(ceill, d) +uint64_t do_float_ceill_d(uint64_t fdt0) { - set_float_rounding_mode(float_round_up, &env->fpu->fp_status); - DT2 = float64_to_int64(FDT0, &env->fpu->fp_status); + uint64_t dt2; + + set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); + dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = FLOAT_SNAN64; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; } -FLOAT_OP(ceill, s) + +uint64_t do_float_ceill_s(uint32_t fst0) { - set_float_rounding_mode(float_round_up, &env->fpu->fp_status); - DT2 = float32_to_int64(FST0, &env->fpu->fp_status); + uint64_t dt2; + + set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); + dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = FLOAT_SNAN64; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; } -FLOAT_OP(ceilw, d) + +uint32_t do_float_ceilw_d(uint64_t fdt0) { - set_float_rounding_mode(float_round_up, &env->fpu->fp_status); - WT2 = float64_to_int32(FDT0, &env->fpu->fp_status); + uint32_t wt2; + + set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); + wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = FLOAT_SNAN32; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; } -FLOAT_OP(ceilw, s) + +uint32_t do_float_ceilw_s(uint32_t fst0) { - set_float_rounding_mode(float_round_up, &env->fpu->fp_status); - WT2 = float32_to_int32(FST0, &env->fpu->fp_status); + uint32_t wt2; + + set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); + wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = FLOAT_SNAN32; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; } -FLOAT_OP(floorl, d) +uint64_t do_float_floorl_d(uint64_t fdt0) { - set_float_rounding_mode(float_round_down, &env->fpu->fp_status); - DT2 = float64_to_int64(FDT0, &env->fpu->fp_status); + uint64_t dt2; + + set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); + dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = FLOAT_SNAN64; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; } -FLOAT_OP(floorl, s) + +uint64_t do_float_floorl_s(uint32_t fst0) { - set_float_rounding_mode(float_round_down, &env->fpu->fp_status); - DT2 = float32_to_int64(FST0, &env->fpu->fp_status); + uint64_t dt2; + + set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); + dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = FLOAT_SNAN64; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; } -FLOAT_OP(floorw, d) + +uint32_t do_float_floorw_d(uint64_t fdt0) { - set_float_rounding_mode(float_round_down, &env->fpu->fp_status); - WT2 = float64_to_int32(FDT0, &env->fpu->fp_status); + uint32_t wt2; + + set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); + wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = FLOAT_SNAN32; + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; } -FLOAT_OP(floorw, s) + +uint32_t do_float_floorw_s(uint32_t fst0) { - set_float_rounding_mode(float_round_down, &env->fpu->fp_status); - WT2 = float32_to_int32(FST0, &env->fpu->fp_status); + uint32_t wt2; + + set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); + wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = FLOAT_SNAN32; -} + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; +} + +/* unary operations, not modifying fp status */ +#define FLOAT_UNOP(name) \ +uint64_t do_float_ ## name ## _d(uint64_t fdt0) \ +{ \ + return float64_ ## name(fdt0); \ +} \ +uint32_t do_float_ ## name ## _s(uint32_t fst0) \ +{ \ + return float32_ ## name(fst0); \ +} \ +uint64_t do_float_ ## name ## _ps(uint64_t fdt0) \ +{ \ + uint32_t wt0; \ + uint32_t wth0; \ + \ + wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF); \ + wth0 = float32_ ## name(fdt0 >> 32); \ + return ((uint64_t)wth0 << 32) | wt0; \ +} +FLOAT_UNOP(abs) +FLOAT_UNOP(chs) +#undef FLOAT_UNOP /* MIPS specific unary operations */ -FLOAT_OP(recip, d) +uint64_t do_float_recip_d(uint64_t fdt0) { - set_float_exception_flags(0, &env->fpu->fp_status); - FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status); + uint64_t fdt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status); update_fcr31(); + return fdt2; } -FLOAT_OP(recip, s) + +uint32_t do_float_recip_s(uint32_t fst0) { - set_float_exception_flags(0, &env->fpu->fp_status); - FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status); + uint32_t fst2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status); update_fcr31(); + return fst2; } -FLOAT_OP(rsqrt, d) +uint64_t do_float_rsqrt_d(uint64_t fdt0) { - set_float_exception_flags(0, &env->fpu->fp_status); - FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status); - FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status); + uint64_t fdt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status); + fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status); update_fcr31(); + return fdt2; } -FLOAT_OP(rsqrt, s) + +uint32_t do_float_rsqrt_s(uint32_t fst0) { - set_float_exception_flags(0, &env->fpu->fp_status); - FST2 = float32_sqrt(FST0, &env->fpu->fp_status); - FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status); + uint32_t fst2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status); + fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status); update_fcr31(); + return fst2; } -FLOAT_OP(recip1, d) +uint64_t do_float_recip1_d(uint64_t fdt0) { - set_float_exception_flags(0, &env->fpu->fp_status); - FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status); + uint64_t fdt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status); update_fcr31(); + return fdt2; } -FLOAT_OP(recip1, s) + +uint32_t do_float_recip1_s(uint32_t fst0) { - set_float_exception_flags(0, &env->fpu->fp_status); - FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status); + uint32_t fst2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status); update_fcr31(); + return fst2; } -FLOAT_OP(recip1, ps) + +uint64_t do_float_recip1_ps(uint64_t fdt0) { - set_float_exception_flags(0, &env->fpu->fp_status); - FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status); - FSTH2 = float32_div(FLOAT_ONE32, FSTH0, &env->fpu->fp_status); + uint32_t fst2; + uint32_t fsth2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_div(FLOAT_ONE32, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status); + fsth2 = float32_div(FLOAT_ONE32, fdt0 >> 32, &env->active_fpu.fp_status); update_fcr31(); + return ((uint64_t)fsth2 << 32) | fst2; } -FLOAT_OP(rsqrt1, d) +uint64_t do_float_rsqrt1_d(uint64_t fdt0) { - set_float_exception_flags(0, &env->fpu->fp_status); - FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status); - FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status); + uint64_t fdt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status); + fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status); update_fcr31(); + return fdt2; } -FLOAT_OP(rsqrt1, s) + +uint32_t do_float_rsqrt1_s(uint32_t fst0) { - set_float_exception_flags(0, &env->fpu->fp_status); - FST2 = float32_sqrt(FST0, &env->fpu->fp_status); - FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status); + uint32_t fst2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status); + fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status); update_fcr31(); + return fst2; } -FLOAT_OP(rsqrt1, ps) + +uint64_t do_float_rsqrt1_ps(uint64_t fdt0) { - set_float_exception_flags(0, &env->fpu->fp_status); - FST2 = float32_sqrt(FST0, &env->fpu->fp_status); - FSTH2 = float32_sqrt(FSTH0, &env->fpu->fp_status); - FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status); - FSTH2 = float32_div(FLOAT_ONE32, FSTH2, &env->fpu->fp_status); + uint32_t fst2; + uint32_t fsth2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status); + fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status); + fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status); + fsth2 = float32_div(FLOAT_ONE32, fsth2, &env->active_fpu.fp_status); update_fcr31(); + return ((uint64_t)fsth2 << 32) | fst2; } +#define FLOAT_OP(name, p) void do_float_##name##_##p(void) + /* binary operations */ -#define FLOAT_BINOP(name) \ -FLOAT_OP(name, d) \ -{ \ - set_float_exception_flags(0, &env->fpu->fp_status); \ - FDT2 = float64_ ## name (FDT0, FDT1, &env->fpu->fp_status); \ +#define FLOAT_BINOP(name) \ +uint64_t do_float_ ## name ## _d(uint64_t fdt0, uint64_t fdt1) \ +{ \ + uint64_t dt2; \ + \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ + dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status); \ + update_fcr31(); \ + if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) \ + dt2 = FLOAT_QNAN64; \ + return dt2; \ +} \ + \ +uint32_t do_float_ ## name ## _s(uint32_t fst0, uint32_t fst1) \ +{ \ + uint32_t wt2; \ + \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ + wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \ update_fcr31(); \ - if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) \ - DT2 = FLOAT_QNAN64; \ -} \ -FLOAT_OP(name, s) \ -{ \ - set_float_exception_flags(0, &env->fpu->fp_status); \ - FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status); \ + if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) \ + wt2 = FLOAT_QNAN32; \ + return wt2; \ +} \ + \ +uint64_t do_float_ ## name ## _ps(uint64_t fdt0, uint64_t fdt1) \ +{ \ + uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ + uint32_t fsth0 = fdt0 >> 32; \ + uint32_t fst1 = fdt1 & 0XFFFFFFFF; \ + uint32_t fsth1 = fdt1 >> 32; \ + uint32_t wt2; \ + uint32_t wth2; \ + \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ + wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \ + wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status); \ update_fcr31(); \ - if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) \ - WT2 = FLOAT_QNAN32; \ -} \ -FLOAT_OP(name, ps) \ -{ \ - set_float_exception_flags(0, &env->fpu->fp_status); \ - FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status); \ - FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fpu->fp_status); \ - update_fcr31(); \ - if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) { \ - WT2 = FLOAT_QNAN32; \ - WTH2 = FLOAT_QNAN32; \ - } \ + if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) { \ + wt2 = FLOAT_QNAN32; \ + wth2 = FLOAT_QNAN32; \ + } \ + return ((uint64_t)wth2 << 32) | wt2; \ } + FLOAT_BINOP(add) FLOAT_BINOP(sub) FLOAT_BINOP(mul) FLOAT_BINOP(div) #undef FLOAT_BINOP +/* ternary operations */ +#define FLOAT_TERNOP(name1, name2) \ +uint64_t do_float_ ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \ + uint64_t fdt2) \ +{ \ + fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status); \ + return float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status); \ +} \ + \ +uint32_t do_float_ ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \ + uint32_t fst2) \ +{ \ + fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \ + return float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \ +} \ + \ +uint64_t do_float_ ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1, \ + uint64_t fdt2) \ +{ \ + uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ + uint32_t fsth0 = fdt0 >> 32; \ + uint32_t fst1 = fdt1 & 0XFFFFFFFF; \ + uint32_t fsth1 = fdt1 >> 32; \ + uint32_t fst2 = fdt2 & 0XFFFFFFFF; \ + uint32_t fsth2 = fdt2 >> 32; \ + \ + fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \ + fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status); \ + fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \ + fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status); \ + return ((uint64_t)fsth2 << 32) | fst2; \ +} + +FLOAT_TERNOP(mul, add) +FLOAT_TERNOP(mul, sub) +#undef FLOAT_TERNOP + +/* negated ternary operations */ +#define FLOAT_NTERNOP(name1, name2) \ +uint64_t do_float_n ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \ + uint64_t fdt2) \ +{ \ + fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status); \ + fdt2 = float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status); \ + return float64_chs(fdt2); \ +} \ + \ +uint32_t do_float_n ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \ + uint32_t fst2) \ +{ \ + fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \ + fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \ + return float32_chs(fst2); \ +} \ + \ +uint64_t do_float_n ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1,\ + uint64_t fdt2) \ +{ \ + uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ + uint32_t fsth0 = fdt0 >> 32; \ + uint32_t fst1 = fdt1 & 0XFFFFFFFF; \ + uint32_t fsth1 = fdt1 >> 32; \ + uint32_t fst2 = fdt2 & 0XFFFFFFFF; \ + uint32_t fsth2 = fdt2 >> 32; \ + \ + fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \ + fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status); \ + fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \ + fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status); \ + fst2 = float32_chs(fst2); \ + fsth2 = float32_chs(fsth2); \ + return ((uint64_t)fsth2 << 32) | fst2; \ +} + +FLOAT_NTERNOP(mul, add) +FLOAT_NTERNOP(mul, sub) +#undef FLOAT_NTERNOP + /* MIPS specific binary operations */ -FLOAT_OP(recip2, d) +uint64_t do_float_recip2_d(uint64_t fdt0, uint64_t fdt2) { - set_float_exception_flags(0, &env->fpu->fp_status); - FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status); - FDT2 = float64_chs(float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status)); + set_float_exception_flags(0, &env->active_fpu.fp_status); + fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status); + fdt2 = float64_chs(float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status)); update_fcr31(); + return fdt2; } -FLOAT_OP(recip2, s) + +uint32_t do_float_recip2_s(uint32_t fst0, uint32_t fst2) { - set_float_exception_flags(0, &env->fpu->fp_status); - FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status); - FST2 = float32_chs(float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status)); + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status); + fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status)); update_fcr31(); + return fst2; } -FLOAT_OP(recip2, ps) + +uint64_t do_float_recip2_ps(uint64_t fdt0, uint64_t fdt2) { - set_float_exception_flags(0, &env->fpu->fp_status); - FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status); - FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status); - FST2 = float32_chs(float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status)); - FSTH2 = float32_chs(float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status)); + uint32_t fst0 = fdt0 & 0XFFFFFFFF; + uint32_t fsth0 = fdt0 >> 32; + uint32_t fst2 = fdt2 & 0XFFFFFFFF; + uint32_t fsth2 = fdt2 >> 32; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status); + fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status); + fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status)); + fsth2 = float32_chs(float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status)); update_fcr31(); + return ((uint64_t)fsth2 << 32) | fst2; } -FLOAT_OP(rsqrt2, d) +uint64_t do_float_rsqrt2_d(uint64_t fdt0, uint64_t fdt2) { - set_float_exception_flags(0, &env->fpu->fp_status); - FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status); - FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status); - FDT2 = float64_chs(float64_div(FDT2, FLOAT_TWO64, &env->fpu->fp_status)); + set_float_exception_flags(0, &env->active_fpu.fp_status); + fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status); + fdt2 = float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status); + fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status)); update_fcr31(); + return fdt2; } -FLOAT_OP(rsqrt2, s) + +uint32_t do_float_rsqrt2_s(uint32_t fst0, uint32_t fst2) { - set_float_exception_flags(0, &env->fpu->fp_status); - FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status); - FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status); - FST2 = float32_chs(float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status)); + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status); + fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status); + fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status)); update_fcr31(); + return fst2; } -FLOAT_OP(rsqrt2, ps) + +uint64_t do_float_rsqrt2_ps(uint64_t fdt0, uint64_t fdt2) { - set_float_exception_flags(0, &env->fpu->fp_status); - FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status); - FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status); - FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status); - FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status); - FST2 = float32_chs(float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status)); - FSTH2 = float32_chs(float32_div(FSTH2, FLOAT_TWO32, &env->fpu->fp_status)); + uint32_t fst0 = fdt0 & 0XFFFFFFFF; + uint32_t fsth0 = fdt0 >> 32; + uint32_t fst2 = fdt2 & 0XFFFFFFFF; + uint32_t fsth2 = fdt2 >> 32; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status); + fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status); + fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status); + fsth2 = float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status); + fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status)); + fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status)); update_fcr31(); + return ((uint64_t)fsth2 << 32) | fst2; } -FLOAT_OP(addr, ps) +uint64_t do_float_addr_ps(uint64_t fdt0, uint64_t fdt1) { - set_float_exception_flags(0, &env->fpu->fp_status); - FST2 = float32_add (FST0, FSTH0, &env->fpu->fp_status); - FSTH2 = float32_add (FST1, FSTH1, &env->fpu->fp_status); + uint32_t fst0 = fdt0 & 0XFFFFFFFF; + uint32_t fsth0 = fdt0 >> 32; + uint32_t fst1 = fdt1 & 0XFFFFFFFF; + uint32_t fsth1 = fdt1 >> 32; + uint32_t fst2; + uint32_t fsth2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status); + fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status); update_fcr31(); + return ((uint64_t)fsth2 << 32) | fst2; } -FLOAT_OP(mulr, ps) +uint64_t do_float_mulr_ps(uint64_t fdt0, uint64_t fdt1) { - set_float_exception_flags(0, &env->fpu->fp_status); - FST2 = float32_mul (FST0, FSTH0, &env->fpu->fp_status); - FSTH2 = float32_mul (FST1, FSTH1, &env->fpu->fp_status); + uint32_t fst0 = fdt0 & 0XFFFFFFFF; + uint32_t fsth0 = fdt0 >> 32; + uint32_t fst1 = fdt1 & 0XFFFFFFFF; + uint32_t fsth1 = fdt1 >> 32; + uint32_t fst2; + uint32_t fsth2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status); + fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status); update_fcr31(); + return ((uint64_t)fsth2 << 32) | fst2; } /* compare operations */ -#define FOP_COND_D(op, cond) \ -void do_cmp_d_ ## op (long cc) \ -{ \ - int c = cond; \ - update_fcr31(); \ - if (c) \ - SET_FP_COND(cc, env->fpu); \ - else \ - CLEAR_FP_COND(cc, env->fpu); \ -} \ -void do_cmpabs_d_ ## op (long cc) \ -{ \ - int c; \ - FDT0 = float64_chs(FDT0); \ - FDT1 = float64_chs(FDT1); \ - c = cond; \ - update_fcr31(); \ - if (c) \ - SET_FP_COND(cc, env->fpu); \ - else \ - CLEAR_FP_COND(cc, env->fpu); \ +#define FOP_COND_D(op, cond) \ +void do_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ +{ \ + int c = cond; \ + update_fcr31(); \ + if (c) \ + SET_FP_COND(cc, env->active_fpu); \ + else \ + CLEAR_FP_COND(cc, env->active_fpu); \ +} \ +void do_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ +{ \ + int c; \ + fdt0 = float64_abs(fdt0); \ + fdt1 = float64_abs(fdt1); \ + c = cond; \ + update_fcr31(); \ + if (c) \ + SET_FP_COND(cc, env->active_fpu); \ + else \ + CLEAR_FP_COND(cc, env->active_fpu); \ } int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM) @@ -1276,46 +2771,46 @@ /* NOTE: the comma operator will make "cond" to eval to false, * but float*_is_unordered() is still called. */ -FOP_COND_D(f, (float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status), 0)) -FOP_COND_D(un, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status)) -FOP_COND_D(eq, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status)) -FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) || float64_eq(FDT0, FDT1, &env->fpu->fp_status)) -FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status)) -FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) || float64_lt(FDT0, FDT1, &env->fpu->fp_status)) -FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status)) -FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) || float64_le(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(f, (float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status), 0)) +FOP_COND_D(un, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)) +FOP_COND_D(eq, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ueq, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(olt, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ult, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ole, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ule, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, * but float*_is_unordered() is still called. */ -FOP_COND_D(sf, (float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status), 0)) -FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status)) -FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status)) -FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) || float64_eq(FDT0, FDT1, &env->fpu->fp_status)) -FOP_COND_D(lt, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status)) -FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) || float64_lt(FDT0, FDT1, &env->fpu->fp_status)) -FOP_COND_D(le, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status)) -FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) || float64_le(FDT0, FDT1, &env->fpu->fp_status)) - -#define FOP_COND_S(op, cond) \ -void do_cmp_s_ ## op (long cc) \ -{ \ - int c = cond; \ - update_fcr31(); \ - if (c) \ - SET_FP_COND(cc, env->fpu); \ - else \ - CLEAR_FP_COND(cc, env->fpu); \ -} \ -void do_cmpabs_s_ ## op (long cc) \ -{ \ - int c; \ - FST0 = float32_abs(FST0); \ - FST1 = float32_abs(FST1); \ - c = cond; \ - update_fcr31(); \ - if (c) \ - SET_FP_COND(cc, env->fpu); \ - else \ - CLEAR_FP_COND(cc, env->fpu); \ +FOP_COND_D(sf, (float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status), 0)) +FOP_COND_D(ngle,float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)) +FOP_COND_D(seq, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ngl, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(lt, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(nge, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(le, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ngt, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) + +#define FOP_COND_S(op, cond) \ +void do_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ +{ \ + int c = cond; \ + update_fcr31(); \ + if (c) \ + SET_FP_COND(cc, env->active_fpu); \ + else \ + CLEAR_FP_COND(cc, env->active_fpu); \ +} \ +void do_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ +{ \ + int c; \ + fst0 = float32_abs(fst0); \ + fst1 = float32_abs(fst1); \ + c = cond; \ + update_fcr31(); \ + if (c) \ + SET_FP_COND(cc, env->active_fpu); \ + else \ + CLEAR_FP_COND(cc, env->active_fpu); \ } flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM) @@ -1334,93 +2829,98 @@ /* NOTE: the comma operator will make "cond" to eval to false, * but float*_is_unordered() is still called. */ -FOP_COND_S(f, (float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), 0)) -FOP_COND_S(un, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)) -FOP_COND_S(eq, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status)) -FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status)) -FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status)) -FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status)) -FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status)) -FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(f, (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0)) +FOP_COND_S(un, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)) +FOP_COND_S(eq, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, * but float*_is_unordered() is still called. */ -FOP_COND_S(sf, (float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), 0)) -FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)) -FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status)) -FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status)) -FOP_COND_S(lt, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status)) -FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status)) -FOP_COND_S(le, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status)) -FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status)) - -#define FOP_COND_PS(op, condl, condh) \ -void do_cmp_ps_ ## op (long cc) \ -{ \ - int cl = condl; \ - int ch = condh; \ - update_fcr31(); \ - if (cl) \ - SET_FP_COND(cc, env->fpu); \ - else \ - CLEAR_FP_COND(cc, env->fpu); \ - if (ch) \ - SET_FP_COND(cc + 1, env->fpu); \ - else \ - CLEAR_FP_COND(cc + 1, env->fpu); \ -} \ -void do_cmpabs_ps_ ## op (long cc) \ -{ \ - int cl, ch; \ - FST0 = float32_abs(FST0); \ - FSTH0 = float32_abs(FSTH0); \ - FST1 = float32_abs(FST1); \ - FSTH1 = float32_abs(FSTH1); \ - cl = condl; \ - ch = condh; \ - update_fcr31(); \ - if (cl) \ - SET_FP_COND(cc, env->fpu); \ - else \ - CLEAR_FP_COND(cc, env->fpu); \ - if (ch) \ - SET_FP_COND(cc + 1, env->fpu); \ - else \ - CLEAR_FP_COND(cc + 1, env->fpu); \ +FOP_COND_S(sf, (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0)) +FOP_COND_S(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)) +FOP_COND_S(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(lt, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(le, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status)) + +#define FOP_COND_PS(op, condl, condh) \ +void do_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ +{ \ + uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \ + uint32_t fsth0 = float32_abs(fdt0 >> 32); \ + uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \ + uint32_t fsth1 = float32_abs(fdt1 >> 32); \ + int cl = condl; \ + int ch = condh; \ + \ + update_fcr31(); \ + if (cl) \ + SET_FP_COND(cc, env->active_fpu); \ + else \ + CLEAR_FP_COND(cc, env->active_fpu); \ + if (ch) \ + SET_FP_COND(cc + 1, env->active_fpu); \ + else \ + CLEAR_FP_COND(cc + 1, env->active_fpu); \ +} \ +void do_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ +{ \ + uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \ + uint32_t fsth0 = float32_abs(fdt0 >> 32); \ + uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \ + uint32_t fsth1 = float32_abs(fdt1 >> 32); \ + int cl = condl; \ + int ch = condh; \ + \ + update_fcr31(); \ + if (cl) \ + SET_FP_COND(cc, env->active_fpu); \ + else \ + CLEAR_FP_COND(cc, env->active_fpu); \ + if (ch) \ + SET_FP_COND(cc + 1, env->active_fpu); \ + else \ + CLEAR_FP_COND(cc + 1, env->active_fpu); \ } /* NOTE: the comma operator will make "cond" to eval to false, * but float*_is_unordered() is still called. */ -FOP_COND_PS(f, (float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), 0), - (float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status), 0)) -FOP_COND_PS(un, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status)) -FOP_COND_PS(eq, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status), - !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status)) -FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status)) -FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status), - !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status)) -FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status)) -FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status), - !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status)) -FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) || float32_le(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(f, (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0), + (float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status), 0)) +FOP_COND_PS(un, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), + float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)) +FOP_COND_PS(eq, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status), + !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status), + float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status), + !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status), + float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status), + !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status), + float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, * but float*_is_unordered() is still called. */ -FOP_COND_PS(sf, (float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), 0), - (float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status), 0)) -FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status)) -FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status), - !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status)) -FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status)) -FOP_COND_PS(lt, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status), - !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status)) -FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status)) -FOP_COND_PS(le, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status), - !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status)) -FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) || float32_le(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(sf, (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0), + (float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status), 0)) +FOP_COND_PS(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), + float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)) +FOP_COND_PS(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status), + !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status), + float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(lt, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status), + !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status), + float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(le, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status), + !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status), + float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-mips/op_mem.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-mips/op_mem.c --- qemu-0.9.1/target-mips/op_mem.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-mips/op_mem.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,415 +0,0 @@ -/* - * MIPS emulation memory micro-operations for qemu. - * - * Copyright (c) 2004-2005 Jocelyn Mayer - * - * 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 - */ - -/* Standard loads and stores */ -void glue(op_lb, MEMSUFFIX) (void) -{ - T0 = glue(ldsb, MEMSUFFIX)(T0); - FORCE_RET(); -} - -void glue(op_lbu, MEMSUFFIX) (void) -{ - T0 = glue(ldub, MEMSUFFIX)(T0); - FORCE_RET(); -} - -void glue(op_sb, MEMSUFFIX) (void) -{ - glue(stb, MEMSUFFIX)(T0, T1); - FORCE_RET(); -} - -void glue(op_lh, MEMSUFFIX) (void) -{ - T0 = glue(ldsw, MEMSUFFIX)(T0); - FORCE_RET(); -} - -void glue(op_lhu, MEMSUFFIX) (void) -{ - T0 = glue(lduw, MEMSUFFIX)(T0); - FORCE_RET(); -} - -void glue(op_sh, MEMSUFFIX) (void) -{ - glue(stw, MEMSUFFIX)(T0, T1); - FORCE_RET(); -} - -void glue(op_lw, MEMSUFFIX) (void) -{ - T0 = glue(ldl, MEMSUFFIX)(T0); - FORCE_RET(); -} - -void glue(op_lwu, MEMSUFFIX) (void) -{ - T0 = (uint32_t)glue(ldl, MEMSUFFIX)(T0); - FORCE_RET(); -} - -void glue(op_sw, MEMSUFFIX) (void) -{ - glue(stl, MEMSUFFIX)(T0, T1); - FORCE_RET(); -} - -/* "half" load and stores. We must do the memory access inline, - or fault handling won't work. */ - -#ifdef TARGET_WORDS_BIGENDIAN -#define GET_LMASK(v) ((v) & 3) -#define GET_OFFSET(addr, offset) (addr + (offset)) -#else -#define GET_LMASK(v) (((v) & 3) ^ 3) -#define GET_OFFSET(addr, offset) (addr - (offset)) -#endif - -void glue(op_lwl, MEMSUFFIX) (void) -{ - target_ulong tmp; - - tmp = glue(ldub, MEMSUFFIX)(T0); - T1 = (T1 & 0x00FFFFFF) | (tmp << 24); - - if (GET_LMASK(T0) <= 2) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 1)); - T1 = (T1 & 0xFF00FFFF) | (tmp << 16); - } - - if (GET_LMASK(T0) <= 1) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 2)); - T1 = (T1 & 0xFFFF00FF) | (tmp << 8); - } - - if (GET_LMASK(T0) == 0) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 3)); - T1 = (T1 & 0xFFFFFF00) | tmp; - } - T1 = (int32_t)T1; - FORCE_RET(); -} - -void glue(op_lwr, MEMSUFFIX) (void) -{ - target_ulong tmp; - - tmp = glue(ldub, MEMSUFFIX)(T0); - T1 = (T1 & 0xFFFFFF00) | tmp; - - if (GET_LMASK(T0) >= 1) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -1)); - T1 = (T1 & 0xFFFF00FF) | (tmp << 8); - } - - if (GET_LMASK(T0) >= 2) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -2)); - T1 = (T1 & 0xFF00FFFF) | (tmp << 16); - } - - if (GET_LMASK(T0) == 3) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -3)); - T1 = (T1 & 0x00FFFFFF) | (tmp << 24); - } - T1 = (int32_t)T1; - FORCE_RET(); -} - -void glue(op_swl, MEMSUFFIX) (void) -{ - glue(stb, MEMSUFFIX)(T0, (uint8_t)(T1 >> 24)); - - if (GET_LMASK(T0) <= 2) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 1), (uint8_t)(T1 >> 16)); - - if (GET_LMASK(T0) <= 1) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 2), (uint8_t)(T1 >> 8)); - - if (GET_LMASK(T0) == 0) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 3), (uint8_t)T1); - - FORCE_RET(); -} - -void glue(op_swr, MEMSUFFIX) (void) -{ - glue(stb, MEMSUFFIX)(T0, (uint8_t)T1); - - if (GET_LMASK(T0) >= 1) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -1), (uint8_t)(T1 >> 8)); - - if (GET_LMASK(T0) >= 2) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -2), (uint8_t)(T1 >> 16)); - - if (GET_LMASK(T0) == 3) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -3), (uint8_t)(T1 >> 24)); - - FORCE_RET(); -} - -void glue(op_ll, MEMSUFFIX) (void) -{ - T1 = T0; - T0 = glue(ldl, MEMSUFFIX)(T0); - env->CP0_LLAddr = T1; - FORCE_RET(); -} - -void glue(op_sc, MEMSUFFIX) (void) -{ - CALL_FROM_TB0(dump_sc); - if (T0 & 0x3) { - env->CP0_BadVAddr = T0; - CALL_FROM_TB1(do_raise_exception, EXCP_AdES); - } - if (T0 == env->CP0_LLAddr) { - glue(stl, MEMSUFFIX)(T0, T1); - T0 = 1; - } else { - T0 = 0; - } - FORCE_RET(); -} - -#if defined(TARGET_MIPS64) -void glue(op_ld, MEMSUFFIX) (void) -{ - T0 = glue(ldq, MEMSUFFIX)(T0); - FORCE_RET(); -} - -void glue(op_sd, MEMSUFFIX) (void) -{ - glue(stq, MEMSUFFIX)(T0, T1); - FORCE_RET(); -} - -/* "half" load and stores. We must do the memory access inline, - or fault handling won't work. */ - -#ifdef TARGET_WORDS_BIGENDIAN -#define GET_LMASK64(v) ((v) & 7) -#else -#define GET_LMASK64(v) (((v) & 7) ^ 7) -#endif - -void glue(op_ldl, MEMSUFFIX) (void) -{ - uint64_t tmp; - - tmp = glue(ldub, MEMSUFFIX)(T0); - T1 = (T1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56); - - if (GET_LMASK64(T0) <= 6) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 1)); - T1 = (T1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48); - } - - if (GET_LMASK64(T0) <= 5) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 2)); - T1 = (T1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40); - } - - if (GET_LMASK64(T0) <= 4) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 3)); - T1 = (T1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32); - } - - if (GET_LMASK64(T0) <= 3) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 4)); - T1 = (T1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24); - } - - if (GET_LMASK64(T0) <= 2) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 5)); - T1 = (T1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16); - } - - if (GET_LMASK64(T0) <= 1) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 6)); - T1 = (T1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8); - } - - if (GET_LMASK64(T0) == 0) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 7)); - T1 = (T1 & 0xFFFFFFFFFFFFFF00ULL) | tmp; - } - - FORCE_RET(); -} - -void glue(op_ldr, MEMSUFFIX) (void) -{ - uint64_t tmp; - - tmp = glue(ldub, MEMSUFFIX)(T0); - T1 = (T1 & 0xFFFFFFFFFFFFFF00ULL) | tmp; - - if (GET_LMASK64(T0) >= 1) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -1)); - T1 = (T1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8); - } - - if (GET_LMASK64(T0) >= 2) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -2)); - T1 = (T1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16); - } - - if (GET_LMASK64(T0) >= 3) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -3)); - T1 = (T1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24); - } - - if (GET_LMASK64(T0) >= 4) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -4)); - T1 = (T1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32); - } - - if (GET_LMASK64(T0) >= 5) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -5)); - T1 = (T1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40); - } - - if (GET_LMASK64(T0) >= 6) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -6)); - T1 = (T1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48); - } - - if (GET_LMASK64(T0) == 7) { - tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -7)); - T1 = (T1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56); - } - - FORCE_RET(); -} - -void glue(op_sdl, MEMSUFFIX) (void) -{ - glue(stb, MEMSUFFIX)(T0, (uint8_t)(T1 >> 56)); - - if (GET_LMASK64(T0) <= 6) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 1), (uint8_t)(T1 >> 48)); - - if (GET_LMASK64(T0) <= 5) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 2), (uint8_t)(T1 >> 40)); - - if (GET_LMASK64(T0) <= 4) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 3), (uint8_t)(T1 >> 32)); - - if (GET_LMASK64(T0) <= 3) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 4), (uint8_t)(T1 >> 24)); - - if (GET_LMASK64(T0) <= 2) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 5), (uint8_t)(T1 >> 16)); - - if (GET_LMASK64(T0) <= 1) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 6), (uint8_t)(T1 >> 8)); - - if (GET_LMASK64(T0) <= 0) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 7), (uint8_t)T1); - - FORCE_RET(); -} - -void glue(op_sdr, MEMSUFFIX) (void) -{ - glue(stb, MEMSUFFIX)(T0, (uint8_t)T1); - - if (GET_LMASK64(T0) >= 1) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -1), (uint8_t)(T1 >> 8)); - - if (GET_LMASK64(T0) >= 2) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -2), (uint8_t)(T1 >> 16)); - - if (GET_LMASK64(T0) >= 3) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -3), (uint8_t)(T1 >> 24)); - - if (GET_LMASK64(T0) >= 4) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -4), (uint8_t)(T1 >> 32)); - - if (GET_LMASK64(T0) >= 5) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -5), (uint8_t)(T1 >> 40)); - - if (GET_LMASK64(T0) >= 6) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -6), (uint8_t)(T1 >> 48)); - - if (GET_LMASK64(T0) == 7) - glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -7), (uint8_t)(T1 >> 56)); - - FORCE_RET(); -} - -void glue(op_lld, MEMSUFFIX) (void) -{ - T1 = T0; - T0 = glue(ldq, MEMSUFFIX)(T0); - env->CP0_LLAddr = T1; - FORCE_RET(); -} - -void glue(op_scd, MEMSUFFIX) (void) -{ - CALL_FROM_TB0(dump_sc); - if (T0 & 0x7) { - env->CP0_BadVAddr = T0; - CALL_FROM_TB1(do_raise_exception, EXCP_AdES); - } - if (T0 == env->CP0_LLAddr) { - glue(stq, MEMSUFFIX)(T0, T1); - T0 = 1; - } else { - T0 = 0; - } - FORCE_RET(); -} -#endif /* TARGET_MIPS64 */ - -void glue(op_lwc1, MEMSUFFIX) (void) -{ - WT0 = glue(ldl, MEMSUFFIX)(T0); - FORCE_RET(); -} -void glue(op_swc1, MEMSUFFIX) (void) -{ - glue(stl, MEMSUFFIX)(T0, WT0); - FORCE_RET(); -} -void glue(op_ldc1, MEMSUFFIX) (void) -{ - DT0 = glue(ldq, MEMSUFFIX)(T0); - FORCE_RET(); -} -void glue(op_sdc1, MEMSUFFIX) (void) -{ - glue(stq, MEMSUFFIX)(T0, DT0); - FORCE_RET(); -} -void glue(op_luxc1, MEMSUFFIX) (void) -{ - DT0 = glue(ldq, MEMSUFFIX)(T0 & ~0x7); - FORCE_RET(); -} -void glue(op_suxc1, MEMSUFFIX) (void) -{ - glue(stq, MEMSUFFIX)(T0 & ~0x7, DT0); - FORCE_RET(); -} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-mips/op_template.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-mips/op_template.c --- qemu-0.9.1/target-mips/op_template.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-mips/op_template.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,100 +0,0 @@ -/* - * MIPS emulation micro-operations templates for reg load & store for qemu. - * - * Copyright (c) 2004-2005 Jocelyn Mayer - * - * 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 - */ - -#if defined(REG) -void glue(op_load_gpr_T0_gpr, REG) (void) -{ - T0 = env->gpr[REG][env->current_tc]; - FORCE_RET(); -} - -void glue(op_store_T0_gpr_gpr, REG) (void) -{ - env->gpr[REG][env->current_tc] = T0; - FORCE_RET(); -} - -void glue(op_load_gpr_T1_gpr, REG) (void) -{ - T1 = env->gpr[REG][env->current_tc]; - FORCE_RET(); -} - -void glue(op_store_T1_gpr_gpr, REG) (void) -{ - env->gpr[REG][env->current_tc] = T1; - FORCE_RET(); -} - -void glue(op_load_gpr_T2_gpr, REG) (void) -{ - T2 = env->gpr[REG][env->current_tc]; - FORCE_RET(); -} - - -void glue(op_load_srsgpr_T0_gpr, REG) (void) -{ - T0 = env->gpr[REG][(env->CP0_SRSCtl >> CP0SRSCtl_PSS) & 0xf]; - FORCE_RET(); -} - -void glue(op_store_T0_srsgpr_gpr, REG) (void) -{ - env->gpr[REG][(env->CP0_SRSCtl >> CP0SRSCtl_PSS) & 0xf] = T0; - FORCE_RET(); -} -#endif - -#if defined (TN) -#define SET_RESET(treg, tregname) \ - void glue(op_set, tregname)(void) \ - { \ - treg = (int32_t)PARAM1; \ - FORCE_RET(); \ - } \ - void glue(op_reset, tregname)(void) \ - { \ - treg = 0; \ - FORCE_RET(); \ - } \ - -SET_RESET(T0, _T0) -SET_RESET(T1, _T1) -SET_RESET(T2, _T2) - -#undef SET_RESET - -#if defined(TARGET_MIPS64) -#define SET64(treg, tregname) \ - void glue(op_set64, tregname)(void) \ - { \ - treg = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2; \ - FORCE_RET(); \ - } - -SET64(T0, _T0) -SET64(T1, _T1) -SET64(T2, _T2) - -#undef SET64 - -#endif -#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-mips/TODO /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-mips/TODO --- qemu-0.9.1/target-mips/TODO 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-mips/TODO 2008-09-18 12:57:27.000000000 +0100 @@ -29,6 +29,7 @@ To cope with these differences, Qemu currently flushes the TLB at each ASID change. Using the MMU modes to implement ASIDs hinges on implementing the global bit efficiently. +- save/restore of the CPU state is not implemented (see machine.c). MIPS64 ------ @@ -36,7 +37,8 @@ "Generic" 4Kc system emulation ------------------------------ -- Doesn't correspond to any real hardware. +- Doesn't correspond to any real hardware. Should be removed some day, + U-Boot is the last remaining user. PICA 61 system emulation ------------------------ @@ -45,7 +47,7 @@ MALTA system emulation ---------------------- - We fake firmware support instead of doing the real thing -- Real firmware falls over when trying to init RAM, presumably due - to lacking system controller emulation. +- Real firmware (YAMON) falls over when trying to init RAM, presumably + due to lacking system controller emulation. - Bonito system controller not implemented - MSC1 system controller not implemented diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-mips/translate.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-mips/translate.c --- qemu-0.9.1/target-mips/translate.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-mips/translate.c 2008-11-11 13:41:01.000000000 +0000 @@ -29,29 +29,14 @@ #include "cpu.h" #include "exec-all.h" #include "disas.h" +#include "helper.h" +#include "tcg-op.h" +#include "qemu-common.h" //#define MIPS_DEBUG_DISAS //#define MIPS_DEBUG_SIGN_EXTENSIONS //#define MIPS_SINGLE_STEP -#ifdef USE_DIRECT_JUMP -#define TBPARAM(x) -#else -#define TBPARAM(x) (long)(x) -#endif - -enum { -#define DEF(s, n, copy_size) INDEX_op_ ## s, -#include "opc.h" -#undef DEF - NB_OPS, -}; - -static uint16_t *gen_opc_ptr; -static uint32_t *gen_opparam_ptr; - -#include "gen-op.h" - /* MIPS major opcodes */ #define MASK_OP_MAJOR(op) (op & (0x3F << 26)) @@ -437,145 +422,155 @@ OPC_NMSUB_PS= 0x3E | OPC_CP3, }; +/* global register indices */ +static TCGv cpu_env, cpu_gpr[32], cpu_PC; +static TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC], cpu_ACX[MIPS_DSP_ACC]; +static TCGv cpu_dspctrl, bcond, btarget; +static TCGv fpu_fpr32[32], fpu_fpr32h[32], fpu_fpr64[32], fpu_fcr0, fpu_fcr31; -const unsigned char *regnames[] = - { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", - "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", - "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", }; +#include "gen-icount.h" -/* Warning: no function for r0 register (hard wired to zero) */ -#define GEN32(func, NAME) \ -static GenOpFunc *NAME ## _table [32] = { \ -NULL, NAME ## 1, NAME ## 2, NAME ## 3, \ -NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ -NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ -NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ -NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ -NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ -NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ -NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ -}; \ -static always_inline void func(int n) \ -{ \ - NAME ## _table[n](); \ -} - -/* General purpose registers moves */ -GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr); -GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr); -GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr); - -GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr); -GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr); - -/* Moves to/from shadow registers */ -GEN32(gen_op_load_srsgpr_T0, gen_op_load_srsgpr_T0_gpr); -GEN32(gen_op_store_T0_srsgpr, gen_op_store_T0_srsgpr_gpr); +static inline void tcg_gen_helper_0_i(void *func, uint32_t arg) -static const char *fregnames[] = - { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", - "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", - "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", - "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", }; +{ + TCGv tmp = tcg_const_i32(arg); -#define FGEN32(func, NAME) \ -static GenOpFunc *NAME ## _table [32] = { \ -NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ -NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ -NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ -NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ -NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ -NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ -NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ -NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ -}; \ -static always_inline void func(int n) \ -{ \ - NAME ## _table[n](); \ -} - -FGEN32(gen_op_load_fpr_WT0, gen_op_load_fpr_WT0_fpr); -FGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr); - -FGEN32(gen_op_load_fpr_WT1, gen_op_load_fpr_WT1_fpr); -FGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr); - -FGEN32(gen_op_load_fpr_WT2, gen_op_load_fpr_WT2_fpr); -FGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr); - -FGEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fpr); -FGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr); - -FGEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fpr); -FGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr); - -FGEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fpr); -FGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr); - -FGEN32(gen_op_load_fpr_WTH0, gen_op_load_fpr_WTH0_fpr); -FGEN32(gen_op_store_fpr_WTH0, gen_op_store_fpr_WTH0_fpr); - -FGEN32(gen_op_load_fpr_WTH1, gen_op_load_fpr_WTH1_fpr); -FGEN32(gen_op_store_fpr_WTH1, gen_op_store_fpr_WTH1_fpr); - -FGEN32(gen_op_load_fpr_WTH2, gen_op_load_fpr_WTH2_fpr); -FGEN32(gen_op_store_fpr_WTH2, gen_op_store_fpr_WTH2_fpr); - -#define FOP_CONDS(type, fmt) \ -static GenOpFunc1 * gen_op_cmp ## type ## _ ## fmt ## _table[16] = { \ - gen_op_cmp ## type ## _ ## fmt ## _f, \ - gen_op_cmp ## type ## _ ## fmt ## _un, \ - gen_op_cmp ## type ## _ ## fmt ## _eq, \ - gen_op_cmp ## type ## _ ## fmt ## _ueq, \ - gen_op_cmp ## type ## _ ## fmt ## _olt, \ - gen_op_cmp ## type ## _ ## fmt ## _ult, \ - gen_op_cmp ## type ## _ ## fmt ## _ole, \ - gen_op_cmp ## type ## _ ## fmt ## _ule, \ - gen_op_cmp ## type ## _ ## fmt ## _sf, \ - gen_op_cmp ## type ## _ ## fmt ## _ngle, \ - gen_op_cmp ## type ## _ ## fmt ## _seq, \ - gen_op_cmp ## type ## _ ## fmt ## _ngl, \ - gen_op_cmp ## type ## _ ## fmt ## _lt, \ - gen_op_cmp ## type ## _ ## fmt ## _nge, \ - gen_op_cmp ## type ## _ ## fmt ## _le, \ - gen_op_cmp ## type ## _ ## fmt ## _ngt, \ -}; \ -static always_inline void gen_cmp ## type ## _ ## fmt(int n, long cc) \ -{ \ - gen_op_cmp ## type ## _ ## fmt ## _table[n](cc); \ + tcg_gen_helper_0_1(func, tmp); + tcg_temp_free(tmp); } -FOP_CONDS(, d) -FOP_CONDS(abs, d) -FOP_CONDS(, s) -FOP_CONDS(abs, s) -FOP_CONDS(, ps) -FOP_CONDS(abs, ps) +static inline void tcg_gen_helper_0_ii(void *func, uint32_t arg1, uint32_t arg2) +{ + TCGv tmp1 = tcg_const_i32(arg1); + TCGv tmp2 = tcg_const_i32(arg2); + + tcg_gen_helper_0_2(func, tmp1, tmp2); + tcg_temp_free(tmp1); + tcg_temp_free(tmp2); +} + +static inline void tcg_gen_helper_0_1i(void *func, TCGv arg1, uint32_t arg2) +{ + TCGv tmp = tcg_const_i32(arg2); + + tcg_gen_helper_0_2(func, arg1, tmp); + tcg_temp_free(tmp); +} + +static inline void tcg_gen_helper_0_2i(void *func, TCGv arg1, TCGv arg2, uint32_t arg3) +{ + TCGv tmp = tcg_const_i32(arg3); + + tcg_gen_helper_0_3(func, arg1, arg2, tmp); + tcg_temp_free(tmp); +} + +static inline void tcg_gen_helper_0_1ii(void *func, TCGv arg1, uint32_t arg2, uint32_t arg3) +{ + TCGv tmp1 = tcg_const_i32(arg2); + TCGv tmp2 = tcg_const_i32(arg3); + + tcg_gen_helper_0_3(func, arg1, tmp1, tmp2); + tcg_temp_free(tmp1); + tcg_temp_free(tmp2); +} + +static inline void tcg_gen_helper_1_i(void *func, TCGv ret, uint32_t arg) +{ + TCGv tmp = tcg_const_i32(arg); + + tcg_gen_helper_1_1(func, ret, tmp); + tcg_temp_free(tmp); +} + +static inline void tcg_gen_helper_1_1i(void *func, TCGv ret, TCGv arg1, uint32_t arg2) +{ + TCGv tmp = tcg_const_i32(arg2); + + tcg_gen_helper_1_2(func, ret, arg1, tmp); + tcg_temp_free(tmp); +} + +static inline void tcg_gen_helper_1_1ii(void *func, TCGv ret, TCGv arg1, uint32_t arg2, uint32_t arg3) +{ + TCGv tmp1 = tcg_const_i32(arg2); + TCGv tmp2 = tcg_const_i32(arg3); + + tcg_gen_helper_1_3(func, ret, arg1, tmp1, tmp2); + tcg_temp_free(tmp1); + tcg_temp_free(tmp2); +} + +static inline void tcg_gen_helper_1_2i(void *func, TCGv ret, TCGv arg1, TCGv arg2, uint32_t arg3) +{ + TCGv tmp = tcg_const_i32(arg3); + + tcg_gen_helper_1_3(func, ret, arg1, arg2, tmp); + tcg_temp_free(tmp); +} + +static inline void tcg_gen_helper_1_2ii(void *func, TCGv ret, TCGv arg1, TCGv arg2, uint32_t arg3, uint32_t arg4) +{ + TCGv tmp1 = tcg_const_i32(arg3); + TCGv tmp2 = tcg_const_i32(arg4); + + tcg_gen_helper_1_4(func, ret, arg1, arg2, tmp1, tmp2); + tcg_temp_free(tmp1); + tcg_temp_free(tmp2); +} typedef struct DisasContext { struct TranslationBlock *tb; target_ulong pc, saved_pc; uint32_t opcode; - uint32_t fp_status; /* Routine used to access memory */ int mem_idx; uint32_t hflags, saved_hflags; int bstate; target_ulong btarget; - void *last_T0_store; - int last_T0_gpr; } DisasContext; enum { BS_NONE = 0, /* We go out of the TB without reaching a branch or an - * exception condition - */ + * exception condition */ BS_STOP = 1, /* We want to stop translation for any reason */ BS_BRANCH = 2, /* We reached a branch condition */ BS_EXCP = 3, /* We reached an exception condition */ }; +static const char *regnames[] = + { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", }; + +static const char *regnames_HI[] = + { "HI0", "HI1", "HI2", "HI3", }; + +static const char *regnames_LO[] = + { "LO0", "LO1", "LO2", "LO3", }; + +static const char *regnames_ACX[] = + { "ACX0", "ACX1", "ACX2", "ACX3", }; + +static const char *fregnames[] = + { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", }; + +static const char *fregnames_64[] = + { "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", + "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", + "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23", + "F24", "F25", "F26", "F27", "F28", "F29", "F30", "F31", }; + +static const char *fregnames_h[] = + { "h0", "h1", "h2", "h3", "h4", "h5", "h6", "h7", + "h8", "h9", "h10", "h11", "h12", "h13", "h14", "h15", + "h16", "h17", "h18", "h19", "h20", "h21", "h22", "h23", + "h24", "h25", "h26", "h27", "h28", "h29", "h30", "h31", }; + #ifdef MIPS_DEBUG_DISAS #define MIPS_DEBUG(fmt, args...) \ do { \ @@ -594,126 +589,228 @@ ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); \ } while (0) -#define GEN_LOAD_REG_T0(Rn) \ -do { \ - if (Rn == 0) { \ - gen_op_reset_T0(); \ - } else { \ - if (ctx->glue(last_T0, _store) != gen_opc_ptr \ - || ctx->glue(last_T0, _gpr) != Rn) { \ - gen_op_load_gpr_T0(Rn); \ - } \ - } \ -} while (0) +/* General purpose registers moves. */ +static inline void gen_load_gpr (TCGv t, int reg) +{ + if (reg == 0) + tcg_gen_movi_tl(t, 0); + else + tcg_gen_mov_tl(t, cpu_gpr[reg]); +} -#define GEN_LOAD_REG_T1(Rn) \ -do { \ - if (Rn == 0) { \ - gen_op_reset_T1(); \ - } else { \ - gen_op_load_gpr_T1(Rn); \ - } \ -} while (0) +static inline void gen_store_gpr (TCGv t, int reg) +{ + if (reg != 0) + tcg_gen_mov_tl(cpu_gpr[reg], t); +} -#define GEN_LOAD_REG_T2(Rn) \ -do { \ - if (Rn == 0) { \ - gen_op_reset_T2(); \ - } else { \ - gen_op_load_gpr_T2(Rn); \ - } \ -} while (0) +/* Moves to/from ACX register. */ +static inline void gen_load_ACX (TCGv t, int reg) +{ + tcg_gen_mov_tl(t, cpu_ACX[reg]); +} -#define GEN_LOAD_SRSREG_TN(Tn, Rn) \ -do { \ - if (Rn == 0) { \ - glue(gen_op_reset_, Tn)(); \ - } else { \ - glue(gen_op_load_srsgpr_, Tn)(Rn); \ - } \ -} while (0) +static inline void gen_store_ACX (TCGv t, int reg) +{ + tcg_gen_mov_tl(cpu_ACX[reg], t); +} -#if defined(TARGET_MIPS64) -#define GEN_LOAD_IMM_TN(Tn, Imm) \ -do { \ - if (Imm == 0) { \ - glue(gen_op_reset_, Tn)(); \ - } else if ((int32_t)Imm == Imm) { \ - glue(gen_op_set_, Tn)(Imm); \ - } else { \ - glue(gen_op_set64_, Tn)(((uint64_t)Imm) >> 32, (uint32_t)Imm); \ - } \ -} while (0) -#else -#define GEN_LOAD_IMM_TN(Tn, Imm) \ -do { \ - if (Imm == 0) { \ - glue(gen_op_reset_, Tn)(); \ - } else { \ - glue(gen_op_set_, Tn)(Imm); \ - } \ -} while (0) -#endif +/* Moves to/from shadow registers. */ +static inline void gen_load_srsgpr (int from, int to) +{ + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_TL); -#define GEN_STORE_T0_REG(Rn) \ -do { \ - if (Rn != 0) { \ - glue(gen_op_store_T0,_gpr)(Rn); \ - ctx->glue(last_T0,_store) = gen_opc_ptr; \ - ctx->glue(last_T0,_gpr) = Rn; \ - } \ -} while (0) + if (from == 0) + tcg_gen_movi_tl(r_tmp1, 0); + else { + TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_I32); -#define GEN_STORE_T1_REG(Rn) \ -do { \ - if (Rn != 0) \ - glue(gen_op_store_T1,_gpr)(Rn); \ -} while (0) + tcg_gen_ld_i32(r_tmp2, cpu_env, offsetof(CPUState, CP0_SRSCtl)); + tcg_gen_shri_i32(r_tmp2, r_tmp2, CP0SRSCtl_PSS); + tcg_gen_andi_i32(r_tmp2, r_tmp2, 0xf); + tcg_gen_muli_i32(r_tmp2, r_tmp2, sizeof(target_ulong) * 32); + tcg_gen_add_i32(r_tmp2, cpu_env, r_tmp2); -#define GEN_STORE_TN_SRSREG(Rn, Tn) \ -do { \ - if (Rn != 0) { \ - glue(glue(gen_op_store_, Tn),_srsgpr)(Rn); \ - } \ -} while (0) + tcg_gen_ld_tl(r_tmp1, r_tmp2, sizeof(target_ulong) * from); + tcg_temp_free(r_tmp2); + } + gen_store_gpr(r_tmp1, to); + tcg_temp_free(r_tmp1); +} -#define GEN_LOAD_FREG_FTN(FTn, Fn) \ -do { \ - glue(gen_op_load_fpr_, FTn)(Fn); \ -} while (0) +static inline void gen_store_srsgpr (int from, int to) +{ + if (to != 0) { + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_TL); + TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_I32); -#define GEN_STORE_FTN_FREG(Fn, FTn) \ -do { \ - glue(gen_op_store_fpr_, FTn)(Fn); \ -} while (0) + gen_load_gpr(r_tmp1, from); + tcg_gen_ld_i32(r_tmp2, cpu_env, offsetof(CPUState, CP0_SRSCtl)); + tcg_gen_shri_i32(r_tmp2, r_tmp2, CP0SRSCtl_PSS); + tcg_gen_andi_i32(r_tmp2, r_tmp2, 0xf); + tcg_gen_muli_i32(r_tmp2, r_tmp2, sizeof(target_ulong) * 32); + tcg_gen_add_i32(r_tmp2, cpu_env, r_tmp2); -static always_inline void gen_save_pc(target_ulong pc) + tcg_gen_st_tl(r_tmp1, r_tmp2, sizeof(target_ulong) * to); + tcg_temp_free(r_tmp1); + tcg_temp_free(r_tmp2); + } +} + +/* Floating point register moves. */ +static inline void gen_load_fpr32 (TCGv t, int reg) { -#if defined(TARGET_MIPS64) - if (pc == (int32_t)pc) { - gen_op_save_pc(pc); - } else { - gen_op_save_pc64(pc >> 32, (uint32_t)pc); + tcg_gen_mov_i32(t, fpu_fpr32[reg]); +} + +static inline void gen_store_fpr32 (TCGv t, int reg) +{ + tcg_gen_mov_i32(fpu_fpr32[reg], t); +} + +static inline void gen_load_fpr64 (DisasContext *ctx, TCGv t, int reg) +{ + if (ctx->hflags & MIPS_HFLAG_F64) + tcg_gen_mov_i64(t, fpu_fpr64[reg]); + else { + tcg_gen_concat_i32_i64(t, fpu_fpr32[reg & ~1], fpu_fpr32[reg | 1]); } -#else - gen_op_save_pc(pc); -#endif } -static always_inline void gen_save_btarget(target_ulong btarget) +static inline void gen_store_fpr64 (DisasContext *ctx, TCGv t, int reg) { -#if defined(TARGET_MIPS64) - if (btarget == (int32_t)btarget) { - gen_op_save_btarget(btarget); - } else { - gen_op_save_btarget64(btarget >> 32, (uint32_t)btarget); + if (ctx->hflags & MIPS_HFLAG_F64) + tcg_gen_mov_i64(fpu_fpr64[reg], t); + else { + tcg_gen_trunc_i64_i32(fpu_fpr32[reg & ~1], t); + tcg_gen_shri_i64(t, t, 32); + tcg_gen_trunc_i64_i32(fpu_fpr32[reg | 1], t); } -#else - gen_op_save_btarget(btarget); -#endif } -static always_inline void save_cpu_state (DisasContext *ctx, int do_save_pc) +static inline void gen_load_fpr32h (TCGv t, int reg) +{ + tcg_gen_mov_i32(t, fpu_fpr32h[reg]); +} + +static inline void gen_store_fpr32h (TCGv t, int reg) +{ + tcg_gen_mov_i32(fpu_fpr32h[reg], t); +} + +static inline void get_fp_cond (TCGv t) +{ + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_I32); + TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_shri_i32(r_tmp2, fpu_fcr31, 24); + tcg_gen_andi_i32(r_tmp2, r_tmp2, 0xfe); + tcg_gen_shri_i32(r_tmp1, fpu_fcr31, 23); + tcg_gen_andi_i32(r_tmp1, r_tmp1, 0x1); + tcg_gen_or_i32(t, r_tmp1, r_tmp2); + tcg_temp_free(r_tmp1); + tcg_temp_free(r_tmp2); +} + +typedef void (fcmp_fun32)(uint32_t, uint32_t, int); +typedef void (fcmp_fun64)(uint64_t, uint64_t, int); + +#define FOP_CONDS(fcmp_fun, type, fmt) \ +static fcmp_fun * fcmp ## type ## _ ## fmt ## _table[16] = { \ + do_cmp ## type ## _ ## fmt ## _f, \ + do_cmp ## type ## _ ## fmt ## _un, \ + do_cmp ## type ## _ ## fmt ## _eq, \ + do_cmp ## type ## _ ## fmt ## _ueq, \ + do_cmp ## type ## _ ## fmt ## _olt, \ + do_cmp ## type ## _ ## fmt ## _ult, \ + do_cmp ## type ## _ ## fmt ## _ole, \ + do_cmp ## type ## _ ## fmt ## _ule, \ + do_cmp ## type ## _ ## fmt ## _sf, \ + do_cmp ## type ## _ ## fmt ## _ngle, \ + do_cmp ## type ## _ ## fmt ## _seq, \ + do_cmp ## type ## _ ## fmt ## _ngl, \ + do_cmp ## type ## _ ## fmt ## _lt, \ + do_cmp ## type ## _ ## fmt ## _nge, \ + do_cmp ## type ## _ ## fmt ## _le, \ + do_cmp ## type ## _ ## fmt ## _ngt, \ +}; \ +static inline void gen_cmp ## type ## _ ## fmt(int n, TCGv a, TCGv b, int cc) \ +{ \ + tcg_gen_helper_0_2i(fcmp ## type ## _ ## fmt ## _table[n], a, b, cc); \ +} + +FOP_CONDS(fcmp_fun64, , d) +FOP_CONDS(fcmp_fun64, abs, d) +FOP_CONDS(fcmp_fun32, , s) +FOP_CONDS(fcmp_fun32, abs, s) +FOP_CONDS(fcmp_fun64, , ps) +FOP_CONDS(fcmp_fun64, abs, ps) +#undef FOP_CONDS + +/* Tests */ +#define OP_COND(name, cond) \ +static inline void glue(gen_op_, name) (TCGv t0, TCGv t1) \ +{ \ + int l1 = gen_new_label(); \ + int l2 = gen_new_label(); \ + \ + tcg_gen_brcond_tl(cond, t0, t1, l1); \ + tcg_gen_movi_tl(t0, 0); \ + tcg_gen_br(l2); \ + gen_set_label(l1); \ + tcg_gen_movi_tl(t0, 1); \ + gen_set_label(l2); \ +} +OP_COND(eq, TCG_COND_EQ); +OP_COND(ne, TCG_COND_NE); +OP_COND(ge, TCG_COND_GE); +OP_COND(geu, TCG_COND_GEU); +OP_COND(lt, TCG_COND_LT); +OP_COND(ltu, TCG_COND_LTU); +#undef OP_COND + +#define OP_CONDI(name, cond) \ +static inline void glue(gen_op_, name) (TCGv t, target_ulong val) \ +{ \ + int l1 = gen_new_label(); \ + int l2 = gen_new_label(); \ + \ + tcg_gen_brcondi_tl(cond, t, val, l1); \ + tcg_gen_movi_tl(t, 0); \ + tcg_gen_br(l2); \ + gen_set_label(l1); \ + tcg_gen_movi_tl(t, 1); \ + gen_set_label(l2); \ +} +OP_CONDI(lti, TCG_COND_LT); +OP_CONDI(ltiu, TCG_COND_LTU); +#undef OP_CONDI + +#define OP_CONDZ(name, cond) \ +static inline void glue(gen_op_, name) (TCGv t) \ +{ \ + int l1 = gen_new_label(); \ + int l2 = gen_new_label(); \ + \ + tcg_gen_brcondi_tl(cond, t, 0, l1); \ + tcg_gen_movi_tl(t, 0); \ + tcg_gen_br(l2); \ + gen_set_label(l1); \ + tcg_gen_movi_tl(t, 1); \ + gen_set_label(l2); \ +} +OP_CONDZ(gez, TCG_COND_GE); +OP_CONDZ(gtz, TCG_COND_GT); +OP_CONDZ(lez, TCG_COND_LE); +OP_CONDZ(ltz, TCG_COND_LT); +#undef OP_CONDZ + +static inline void gen_save_pc(target_ulong pc) +{ + tcg_gen_movi_tl(cpu_PC, pc); +} + +static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) { #if defined MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { @@ -726,69 +823,79 @@ ctx->saved_pc = ctx->pc; } if (ctx->hflags != ctx->saved_hflags) { - gen_op_save_state(ctx->hflags); + TCGv r_tmp = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_movi_i32(r_tmp, ctx->hflags); + tcg_gen_st_i32(r_tmp, cpu_env, offsetof(CPUState, hflags)); + tcg_temp_free(r_tmp); ctx->saved_hflags = ctx->hflags; switch (ctx->hflags & MIPS_HFLAG_BMASK) { case MIPS_HFLAG_BR: - gen_op_save_breg_target(); break; case MIPS_HFLAG_BC: - gen_op_save_bcond(); - /* fall through */ case MIPS_HFLAG_BL: - /* bcond was already saved by the BL insn */ - /* fall through */ case MIPS_HFLAG_B: - gen_save_btarget(ctx->btarget); + tcg_gen_movi_tl(btarget, ctx->btarget); break; } } } -static always_inline void restore_cpu_state (CPUState *env, DisasContext *ctx) +static inline void restore_cpu_state (CPUState *env, DisasContext *ctx) { ctx->saved_hflags = ctx->hflags; switch (ctx->hflags & MIPS_HFLAG_BMASK) { case MIPS_HFLAG_BR: - gen_op_restore_breg_target(); - break; - case MIPS_HFLAG_B: - ctx->btarget = env->btarget; break; case MIPS_HFLAG_BC: case MIPS_HFLAG_BL: + case MIPS_HFLAG_B: ctx->btarget = env->btarget; - gen_op_restore_bcond(); break; } } -static always_inline void generate_exception_err (DisasContext *ctx, int excp, int err) +static inline void +generate_exception_err (DisasContext *ctx, int excp, int err) { -#if defined MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile, "%s: raise exception %d\n", __func__, excp); -#endif save_cpu_state(ctx, 1); - if (err == 0) - gen_op_raise_exception(excp); - else - gen_op_raise_exception_err(excp, err); - ctx->bstate = BS_EXCP; + tcg_gen_helper_0_ii(do_raise_exception_err, excp, err); + tcg_gen_helper_0_0(do_interrupt_restart); + tcg_gen_exit_tb(0); } -static always_inline void generate_exception (DisasContext *ctx, int excp) +static inline void +generate_exception (DisasContext *ctx, int excp) { - generate_exception_err (ctx, excp, 0); + save_cpu_state(ctx, 1); + tcg_gen_helper_0_i(do_raise_exception, excp); + tcg_gen_helper_0_0(do_interrupt_restart); + tcg_gen_exit_tb(0); +} + +/* Addresses computation */ +static inline void gen_op_addr_add (DisasContext *ctx, TCGv t0, TCGv t1) +{ + tcg_gen_add_tl(t0, t0, t1); + +#if defined(TARGET_MIPS64) + /* For compatibility with 32-bit code, data reference in user mode + with Status_UX = 0 should be casted to 32-bit and sign extended. + See the MIPS64 PRA manual, section 4.10. */ + if (((ctx->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && + !(ctx->hflags & MIPS_HFLAG_UX)) { + tcg_gen_ext32s_i64(t0, t0); + } +#endif } -static always_inline void check_cp0_enabled(DisasContext *ctx) +static inline void check_cp0_enabled(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0))) generate_exception_err(ctx, EXCP_CpU, 1); } -static always_inline void check_cp1_enabled(DisasContext *ctx) +static inline void check_cp1_enabled(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_FPU))) generate_exception_err(ctx, EXCP_CpU, 1); @@ -798,7 +905,7 @@ This is associated with the nabla symbol in the MIPS32 and MIPS64 opcode tables. */ -static always_inline void check_cop1x(DisasContext *ctx) +static inline void check_cop1x(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_COP1X))) generate_exception(ctx, EXCP_RI); @@ -807,7 +914,7 @@ /* Verify that the processor is running with 64-bit floating-point operations enabled. */ -static always_inline void check_cp1_64bitmode(DisasContext *ctx) +static inline void check_cp1_64bitmode(DisasContext *ctx) { if (unlikely(~ctx->hflags & (MIPS_HFLAG_F64 | MIPS_HFLAG_COP1X))) generate_exception(ctx, EXCP_RI); @@ -824,7 +931,7 @@ * Multiple 64 bit wide registers can be checked by calling * gen_op_cp1_registers(freg1 | freg2 | ... | fregN); */ -void check_cp1_registers(DisasContext *ctx, int regs) +static inline void check_cp1_registers(DisasContext *ctx, int regs) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_F64) && (regs & 1))) generate_exception(ctx, EXCP_RI); @@ -832,7 +939,7 @@ /* This code generates a "reserved instruction" exception if the CPU does not support the instruction set corresponding to flags. */ -static always_inline void check_insn(CPUState *env, DisasContext *ctx, int flags) +static inline void check_insn(CPUState *env, DisasContext *ctx, int flags) { if (unlikely(!(env->insn_flags & flags))) generate_exception(ctx, EXCP_RI); @@ -840,259 +947,318 @@ /* This code generates a "reserved instruction" exception if 64-bit instructions are not enabled. */ -static always_inline void check_mips_64(DisasContext *ctx) +static inline void check_mips_64(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_64))) generate_exception(ctx, EXCP_RI); } -#if defined(CONFIG_USER_ONLY) -#define op_ldst(name) gen_op_##name##_raw() -#define OP_LD_TABLE(width) -#define OP_ST_TABLE(width) -#else -#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])() -#define OP_LD_TABLE(width) \ -static GenOpFunc *gen_op_l##width[] = { \ - &gen_op_l##width##_kernel, \ - &gen_op_l##width##_super, \ - &gen_op_l##width##_user, \ -} -#define OP_ST_TABLE(width) \ -static GenOpFunc *gen_op_s##width[] = { \ - &gen_op_s##width##_kernel, \ - &gen_op_s##width##_super, \ - &gen_op_s##width##_user, \ +/* load/store instructions. */ +#define OP_LD(insn,fname) \ +static inline void op_ldst_##insn(TCGv t0, DisasContext *ctx) \ +{ \ + tcg_gen_qemu_##fname(t0, t0, ctx->mem_idx); \ +} +OP_LD(lb,ld8s); +OP_LD(lbu,ld8u); +OP_LD(lh,ld16s); +OP_LD(lhu,ld16u); +OP_LD(lw,ld32s); +#if defined(TARGET_MIPS64) +OP_LD(lwu,ld32u); +OP_LD(ld,ld64); +#endif +#undef OP_LD + +#define OP_ST(insn,fname) \ +static inline void op_ldst_##insn(TCGv t0, TCGv t1, DisasContext *ctx) \ +{ \ + tcg_gen_qemu_##fname(t1, t0, ctx->mem_idx); \ +} +OP_ST(sb,st8); +OP_ST(sh,st16); +OP_ST(sw,st32); +#if defined(TARGET_MIPS64) +OP_ST(sd,st64); +#endif +#undef OP_ST + +#define OP_LD_ATOMIC(insn,fname) \ +static inline void op_ldst_##insn(TCGv t0, TCGv t1, DisasContext *ctx) \ +{ \ + tcg_gen_mov_tl(t1, t0); \ + tcg_gen_qemu_##fname(t0, t0, ctx->mem_idx); \ + tcg_gen_st_tl(t1, cpu_env, offsetof(CPUState, CP0_LLAddr)); \ } +OP_LD_ATOMIC(ll,ld32s); +#if defined(TARGET_MIPS64) +OP_LD_ATOMIC(lld,ld64); #endif +#undef OP_LD_ATOMIC +#define OP_ST_ATOMIC(insn,fname,almask) \ +static inline void op_ldst_##insn(TCGv t0, TCGv t1, DisasContext *ctx) \ +{ \ + TCGv r_tmp = tcg_temp_local_new(TCG_TYPE_TL); \ + int l1 = gen_new_label(); \ + int l2 = gen_new_label(); \ + int l3 = gen_new_label(); \ + \ + tcg_gen_andi_tl(r_tmp, t0, almask); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, r_tmp, 0, l1); \ + tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, CP0_BadVAddr)); \ + generate_exception(ctx, EXCP_AdES); \ + gen_set_label(l1); \ + tcg_gen_ld_tl(r_tmp, cpu_env, offsetof(CPUState, CP0_LLAddr)); \ + tcg_gen_brcond_tl(TCG_COND_NE, t0, r_tmp, l2); \ + tcg_gen_qemu_##fname(t1, t0, ctx->mem_idx); \ + tcg_gen_movi_tl(t0, 1); \ + tcg_gen_br(l3); \ + gen_set_label(l2); \ + tcg_gen_movi_tl(t0, 0); \ + gen_set_label(l3); \ + tcg_temp_free(r_tmp); \ +} +OP_ST_ATOMIC(sc,st32,0x3); #if defined(TARGET_MIPS64) -OP_LD_TABLE(d); -OP_LD_TABLE(dl); -OP_LD_TABLE(dr); -OP_ST_TABLE(d); -OP_ST_TABLE(dl); -OP_ST_TABLE(dr); -OP_LD_TABLE(ld); -OP_ST_TABLE(cd); -OP_LD_TABLE(wu); -#endif -OP_LD_TABLE(w); -OP_LD_TABLE(wl); -OP_LD_TABLE(wr); -OP_ST_TABLE(w); -OP_ST_TABLE(wl); -OP_ST_TABLE(wr); -OP_LD_TABLE(h); -OP_LD_TABLE(hu); -OP_ST_TABLE(h); -OP_LD_TABLE(b); -OP_LD_TABLE(bu); -OP_ST_TABLE(b); -OP_LD_TABLE(l); -OP_ST_TABLE(c); -OP_LD_TABLE(wc1); -OP_ST_TABLE(wc1); -OP_LD_TABLE(dc1); -OP_ST_TABLE(dc1); -OP_LD_TABLE(uxc1); -OP_ST_TABLE(uxc1); +OP_ST_ATOMIC(scd,st64,0x7); +#endif +#undef OP_ST_ATOMIC /* Load and store */ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, int base, int16_t offset) { const char *opn = "ldst"; + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + TCGv t1 = tcg_temp_local_new(TCG_TYPE_TL); if (base == 0) { - GEN_LOAD_IMM_TN(T0, offset); + tcg_gen_movi_tl(t0, offset); } else if (offset == 0) { - gen_op_load_gpr_T0(base); + gen_load_gpr(t0, base); } else { - gen_op_load_gpr_T0(base); - gen_op_set_T1(offset); - gen_op_addr_add(); + gen_load_gpr(t0, base); + tcg_gen_movi_tl(t1, offset); + gen_op_addr_add(ctx, t0, t1); } /* Don't do NOP if destination is zero: we must perform the actual memory access. */ switch (opc) { #if defined(TARGET_MIPS64) case OPC_LWU: - op_ldst(lwu); - GEN_STORE_T0_REG(rt); + op_ldst_lwu(t0, ctx); + gen_store_gpr(t0, rt); opn = "lwu"; break; case OPC_LD: - op_ldst(ld); - GEN_STORE_T0_REG(rt); + op_ldst_ld(t0, ctx); + gen_store_gpr(t0, rt); opn = "ld"; break; case OPC_LLD: - op_ldst(lld); - GEN_STORE_T0_REG(rt); + op_ldst_lld(t0, t1, ctx); + gen_store_gpr(t0, rt); opn = "lld"; break; case OPC_SD: - GEN_LOAD_REG_T1(rt); - op_ldst(sd); + gen_load_gpr(t1, rt); + op_ldst_sd(t0, t1, ctx); opn = "sd"; break; case OPC_SCD: save_cpu_state(ctx, 1); - GEN_LOAD_REG_T1(rt); - op_ldst(scd); - GEN_STORE_T0_REG(rt); + gen_load_gpr(t1, rt); + op_ldst_scd(t0, t1, ctx); + gen_store_gpr(t0, rt); opn = "scd"; break; case OPC_LDL: - GEN_LOAD_REG_T1(rt); - op_ldst(ldl); - GEN_STORE_T1_REG(rt); + save_cpu_state(ctx, 1); + gen_load_gpr(t1, rt); + tcg_gen_helper_1_2i(do_ldl, t1, t0, t1, ctx->mem_idx); + gen_store_gpr(t1, rt); opn = "ldl"; break; case OPC_SDL: - GEN_LOAD_REG_T1(rt); - op_ldst(sdl); + save_cpu_state(ctx, 1); + gen_load_gpr(t1, rt); + tcg_gen_helper_0_2i(do_sdl, t0, t1, ctx->mem_idx); opn = "sdl"; break; case OPC_LDR: - GEN_LOAD_REG_T1(rt); - op_ldst(ldr); - GEN_STORE_T1_REG(rt); + save_cpu_state(ctx, 1); + gen_load_gpr(t1, rt); + tcg_gen_helper_1_2i(do_ldr, t1, t0, t1, ctx->mem_idx); + gen_store_gpr(t1, rt); opn = "ldr"; break; case OPC_SDR: - GEN_LOAD_REG_T1(rt); - op_ldst(sdr); + save_cpu_state(ctx, 1); + gen_load_gpr(t1, rt); + tcg_gen_helper_0_2i(do_sdr, t0, t1, ctx->mem_idx); opn = "sdr"; break; #endif case OPC_LW: - op_ldst(lw); - GEN_STORE_T0_REG(rt); + op_ldst_lw(t0, ctx); + gen_store_gpr(t0, rt); opn = "lw"; break; case OPC_SW: - GEN_LOAD_REG_T1(rt); - op_ldst(sw); + gen_load_gpr(t1, rt); + op_ldst_sw(t0, t1, ctx); opn = "sw"; break; case OPC_LH: - op_ldst(lh); - GEN_STORE_T0_REG(rt); + op_ldst_lh(t0, ctx); + gen_store_gpr(t0, rt); opn = "lh"; break; case OPC_SH: - GEN_LOAD_REG_T1(rt); - op_ldst(sh); + gen_load_gpr(t1, rt); + op_ldst_sh(t0, t1, ctx); opn = "sh"; break; case OPC_LHU: - op_ldst(lhu); - GEN_STORE_T0_REG(rt); + op_ldst_lhu(t0, ctx); + gen_store_gpr(t0, rt); opn = "lhu"; break; case OPC_LB: - op_ldst(lb); - GEN_STORE_T0_REG(rt); + op_ldst_lb(t0, ctx); + gen_store_gpr(t0, rt); opn = "lb"; break; case OPC_SB: - GEN_LOAD_REG_T1(rt); - op_ldst(sb); + gen_load_gpr(t1, rt); + op_ldst_sb(t0, t1, ctx); opn = "sb"; break; case OPC_LBU: - op_ldst(lbu); - GEN_STORE_T0_REG(rt); + op_ldst_lbu(t0, ctx); + gen_store_gpr(t0, rt); opn = "lbu"; break; case OPC_LWL: - GEN_LOAD_REG_T1(rt); - op_ldst(lwl); - GEN_STORE_T1_REG(rt); + save_cpu_state(ctx, 1); + gen_load_gpr(t1, rt); + tcg_gen_helper_1_2i(do_lwl, t1, t0, t1, ctx->mem_idx); + gen_store_gpr(t1, rt); opn = "lwl"; break; case OPC_SWL: - GEN_LOAD_REG_T1(rt); - op_ldst(swl); + save_cpu_state(ctx, 1); + gen_load_gpr(t1, rt); + tcg_gen_helper_0_2i(do_swl, t0, t1, ctx->mem_idx); opn = "swr"; break; case OPC_LWR: - GEN_LOAD_REG_T1(rt); - op_ldst(lwr); - GEN_STORE_T1_REG(rt); + save_cpu_state(ctx, 1); + gen_load_gpr(t1, rt); + tcg_gen_helper_1_2i(do_lwr, t1, t0, t1, ctx->mem_idx); + gen_store_gpr(t1, rt); opn = "lwr"; break; case OPC_SWR: - GEN_LOAD_REG_T1(rt); - op_ldst(swr); + save_cpu_state(ctx, 1); + gen_load_gpr(t1, rt); + tcg_gen_helper_0_2i(do_swr, t0, t1, ctx->mem_idx); opn = "swr"; break; case OPC_LL: - op_ldst(ll); - GEN_STORE_T0_REG(rt); + op_ldst_ll(t0, t1, ctx); + gen_store_gpr(t0, rt); opn = "ll"; break; case OPC_SC: save_cpu_state(ctx, 1); - GEN_LOAD_REG_T1(rt); - op_ldst(sc); - GEN_STORE_T0_REG(rt); + gen_load_gpr(t1, rt); + op_ldst_sc(t0, t1, ctx); + gen_store_gpr(t0, rt); opn = "sc"; break; default: MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); - return; + goto out; } MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]); + out: + tcg_temp_free(t0); + tcg_temp_free(t1); } /* Load and store */ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, - int base, int16_t offset) + int base, int16_t offset) { const char *opn = "flt_ldst"; + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); if (base == 0) { - GEN_LOAD_IMM_TN(T0, offset); + tcg_gen_movi_tl(t0, offset); } else if (offset == 0) { - gen_op_load_gpr_T0(base); + gen_load_gpr(t0, base); } else { - gen_op_load_gpr_T0(base); - gen_op_set_T1(offset); - gen_op_addr_add(); + TCGv t1 = tcg_temp_local_new(TCG_TYPE_TL); + + gen_load_gpr(t0, base); + tcg_gen_movi_tl(t1, offset); + gen_op_addr_add(ctx, t0, t1); + tcg_temp_free(t1); } /* Don't do NOP if destination is zero: we must perform the actual memory access. */ switch (opc) { case OPC_LWC1: - op_ldst(lwc1); - GEN_STORE_FTN_FREG(ft, WT0); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_qemu_ld32s(fp0, t0, ctx->mem_idx); + gen_store_fpr32(fp0, ft); + tcg_temp_free(fp0); + } opn = "lwc1"; break; case OPC_SWC1: - GEN_LOAD_FREG_FTN(WT0, ft); - op_ldst(swc1); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, ft); + tcg_gen_qemu_st32(fp0, t0, ctx->mem_idx); + tcg_temp_free(fp0); + } opn = "swc1"; break; case OPC_LDC1: - op_ldst(ldc1); - GEN_STORE_FTN_FREG(ft, DT0); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_qemu_ld64(fp0, t0, ctx->mem_idx); + gen_store_fpr64(ctx, fp0, ft); + tcg_temp_free(fp0); + } opn = "ldc1"; break; case OPC_SDC1: - GEN_LOAD_FREG_FTN(DT0, ft); - op_ldst(sdc1); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, ft); + tcg_gen_qemu_st64(fp0, t0, ctx->mem_idx); + tcg_temp_free(fp0); + } opn = "sdc1"; break; default: MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); - return; + goto out; } MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]); + out: + tcg_temp_free(t0); } /* Arithmetic with immediate operand */ @@ -1101,12 +1267,13 @@ { target_ulong uimm; const char *opn = "imm arith"; + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); if (rt == 0 && opc != OPC_ADDI && opc != OPC_DADDI) { /* If no destination, treat it as a NOP. For addi, we must generate the overflow exception when needed. */ MIPS_DEBUG("NOP"); - return; + goto out; } uimm = (uint16_t)imm; switch (opc) { @@ -1123,11 +1290,10 @@ case OPC_ANDI: case OPC_ORI: case OPC_XORI: - GEN_LOAD_REG_T0(rs); - GEN_LOAD_IMM_TN(T1, uimm); + gen_load_gpr(t0, rs); break; case OPC_LUI: - GEN_LOAD_IMM_TN(T0, imm << 16); + tcg_gen_movi_tl(t0, imm << 16); break; case OPC_SLL: case OPC_SRA: @@ -1141,75 +1307,130 @@ case OPC_DSRL32: #endif uimm &= 0x1f; - GEN_LOAD_REG_T0(rs); - GEN_LOAD_IMM_TN(T1, uimm); + gen_load_gpr(t0, rs); break; } switch (opc) { case OPC_ADDI: - save_cpu_state(ctx, 1); - gen_op_addo(); + { + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_TL); + TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_TL); + int l1 = gen_new_label(); + + save_cpu_state(ctx, 1); + tcg_gen_ext32s_tl(r_tmp1, t0); + tcg_gen_addi_tl(t0, r_tmp1, uimm); + + tcg_gen_xori_tl(r_tmp1, r_tmp1, ~uimm); + tcg_gen_xori_tl(r_tmp2, t0, uimm); + tcg_gen_and_tl(r_tmp1, r_tmp1, r_tmp2); + tcg_temp_free(r_tmp2); + tcg_gen_brcondi_tl(TCG_COND_GE, r_tmp1, 0, l1); + /* operands of same sign, result different sign */ + generate_exception(ctx, EXCP_OVERFLOW); + gen_set_label(l1); + tcg_temp_free(r_tmp1); + + tcg_gen_ext32s_tl(t0, t0); + } opn = "addi"; break; case OPC_ADDIU: - gen_op_add(); + tcg_gen_addi_tl(t0, t0, uimm); + tcg_gen_ext32s_tl(t0, t0); opn = "addiu"; break; #if defined(TARGET_MIPS64) case OPC_DADDI: - save_cpu_state(ctx, 1); - gen_op_daddo(); + { + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_TL); + TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_TL); + int l1 = gen_new_label(); + + save_cpu_state(ctx, 1); + tcg_gen_mov_tl(r_tmp1, t0); + tcg_gen_addi_tl(t0, t0, uimm); + + tcg_gen_xori_tl(r_tmp1, r_tmp1, ~uimm); + tcg_gen_xori_tl(r_tmp2, t0, uimm); + tcg_gen_and_tl(r_tmp1, r_tmp1, r_tmp2); + tcg_temp_free(r_tmp2); + tcg_gen_brcondi_tl(TCG_COND_GE, r_tmp1, 0, l1); + /* operands of same sign, result different sign */ + generate_exception(ctx, EXCP_OVERFLOW); + gen_set_label(l1); + tcg_temp_free(r_tmp1); + } opn = "daddi"; break; case OPC_DADDIU: - gen_op_dadd(); + tcg_gen_addi_tl(t0, t0, uimm); opn = "daddiu"; break; #endif case OPC_SLTI: - gen_op_lt(); + gen_op_lti(t0, uimm); opn = "slti"; break; case OPC_SLTIU: - gen_op_ltu(); + gen_op_ltiu(t0, uimm); opn = "sltiu"; break; case OPC_ANDI: - gen_op_and(); + tcg_gen_andi_tl(t0, t0, uimm); opn = "andi"; break; case OPC_ORI: - gen_op_or(); + tcg_gen_ori_tl(t0, t0, uimm); opn = "ori"; break; case OPC_XORI: - gen_op_xor(); + tcg_gen_xori_tl(t0, t0, uimm); opn = "xori"; break; case OPC_LUI: opn = "lui"; break; case OPC_SLL: - gen_op_sll(); + tcg_gen_shli_tl(t0, t0, uimm); + tcg_gen_ext32s_tl(t0, t0); opn = "sll"; break; case OPC_SRA: - gen_op_sra(); + tcg_gen_ext32s_tl(t0, t0); + tcg_gen_sari_tl(t0, t0, uimm); opn = "sra"; break; case OPC_SRL: switch ((ctx->opcode >> 21) & 0x1f) { case 0: - gen_op_srl(); + if (uimm != 0) { + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_shri_tl(t0, t0, uimm); + } else { + tcg_gen_ext32s_tl(t0, t0); + } opn = "srl"; break; case 1: /* rotr is decoded as srl on non-R2 CPUs */ if (env->insn_flags & ISA_MIPS32R2) { - gen_op_rotr(); + if (uimm != 0) { + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_trunc_tl_i32(r_tmp1, t0); + tcg_gen_rotri_i32(r_tmp1, r_tmp1, uimm); + tcg_gen_ext_i32_tl(t0, r_tmp1); + tcg_temp_free(r_tmp1); + } opn = "rotr"; } else { - gen_op_srl(); + if (uimm != 0) { + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_shri_tl(t0, t0, uimm); + } else { + tcg_gen_ext32s_tl(t0, t0); + } opn = "srl"; } break; @@ -1221,26 +1442,28 @@ break; #if defined(TARGET_MIPS64) case OPC_DSLL: - gen_op_dsll(); + tcg_gen_shli_tl(t0, t0, uimm); opn = "dsll"; break; case OPC_DSRA: - gen_op_dsra(); + tcg_gen_sari_tl(t0, t0, uimm); opn = "dsra"; break; case OPC_DSRL: switch ((ctx->opcode >> 21) & 0x1f) { case 0: - gen_op_dsrl(); + tcg_gen_shri_tl(t0, t0, uimm); opn = "dsrl"; break; case 1: /* drotr is decoded as dsrl on non-R2 CPUs */ if (env->insn_flags & ISA_MIPS32R2) { - gen_op_drotr(); + if (uimm != 0) { + tcg_gen_rotri_tl(t0, t0, uimm); + } opn = "drotr"; } else { - gen_op_dsrl(); + tcg_gen_shri_tl(t0, t0, uimm); opn = "dsrl"; } break; @@ -1251,26 +1474,26 @@ } break; case OPC_DSLL32: - gen_op_dsll32(); + tcg_gen_shli_tl(t0, t0, uimm + 32); opn = "dsll32"; break; case OPC_DSRA32: - gen_op_dsra32(); + tcg_gen_sari_tl(t0, t0, uimm + 32); opn = "dsra32"; break; case OPC_DSRL32: switch ((ctx->opcode >> 21) & 0x1f) { case 0: - gen_op_dsrl32(); + tcg_gen_shri_tl(t0, t0, uimm + 32); opn = "dsrl32"; break; case 1: /* drotr32 is decoded as dsrl32 on non-R2 CPUs */ if (env->insn_flags & ISA_MIPS32R2) { - gen_op_drotr32(); + tcg_gen_rotri_tl(t0, t0, uimm + 32); opn = "drotr32"; } else { - gen_op_dsrl32(); + tcg_gen_shri_tl(t0, t0, uimm + 32); opn = "dsrl32"; } break; @@ -1284,10 +1507,12 @@ default: MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); - return; + goto out; } - GEN_STORE_T0_REG(rt); + gen_store_gpr(t0, rt); MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm); + out: + tcg_temp_free(t0); } /* Arithmetic */ @@ -1295,118 +1520,240 @@ int rd, int rs, int rt) { const char *opn = "arith"; + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + TCGv t1 = tcg_temp_local_new(TCG_TYPE_TL); if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB && opc != OPC_DADD && opc != OPC_DSUB) { /* If no destination, treat it as a NOP. For add & sub, we must generate the overflow exception when needed. */ MIPS_DEBUG("NOP"); - return; + goto out; } - GEN_LOAD_REG_T0(rs); + gen_load_gpr(t0, rs); /* Specialcase the conventional move operation. */ if (rt == 0 && (opc == OPC_ADDU || opc == OPC_DADDU || opc == OPC_SUBU || opc == OPC_DSUBU)) { - GEN_STORE_T0_REG(rd); - return; + gen_store_gpr(t0, rd); + goto out; } - GEN_LOAD_REG_T1(rt); + gen_load_gpr(t1, rt); switch (opc) { case OPC_ADD: - save_cpu_state(ctx, 1); - gen_op_addo(); + { + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_TL); + TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_TL); + int l1 = gen_new_label(); + + save_cpu_state(ctx, 1); + tcg_gen_ext32s_tl(r_tmp1, t0); + tcg_gen_ext32s_tl(r_tmp2, t1); + tcg_gen_add_tl(t0, r_tmp1, r_tmp2); + + tcg_gen_xor_tl(r_tmp1, r_tmp1, t1); + tcg_gen_xori_tl(r_tmp1, r_tmp1, -1); + tcg_gen_xor_tl(r_tmp2, t0, t1); + tcg_gen_and_tl(r_tmp1, r_tmp1, r_tmp2); + tcg_temp_free(r_tmp2); + tcg_gen_brcondi_tl(TCG_COND_GE, r_tmp1, 0, l1); + /* operands of same sign, result different sign */ + generate_exception(ctx, EXCP_OVERFLOW); + gen_set_label(l1); + tcg_temp_free(r_tmp1); + + tcg_gen_ext32s_tl(t0, t0); + } opn = "add"; break; case OPC_ADDU: - gen_op_add(); + tcg_gen_add_tl(t0, t0, t1); + tcg_gen_ext32s_tl(t0, t0); opn = "addu"; break; case OPC_SUB: - save_cpu_state(ctx, 1); - gen_op_subo(); + { + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_TL); + TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_TL); + int l1 = gen_new_label(); + + save_cpu_state(ctx, 1); + tcg_gen_ext32s_tl(r_tmp1, t0); + tcg_gen_ext32s_tl(r_tmp2, t1); + tcg_gen_sub_tl(t0, r_tmp1, r_tmp2); + + tcg_gen_xor_tl(r_tmp2, r_tmp1, t1); + tcg_gen_xor_tl(r_tmp1, r_tmp1, t0); + tcg_gen_and_tl(r_tmp1, r_tmp1, r_tmp2); + tcg_temp_free(r_tmp2); + tcg_gen_brcondi_tl(TCG_COND_GE, r_tmp1, 0, l1); + /* operands of different sign, first operand and result different sign */ + generate_exception(ctx, EXCP_OVERFLOW); + gen_set_label(l1); + tcg_temp_free(r_tmp1); + + tcg_gen_ext32s_tl(t0, t0); + } opn = "sub"; break; case OPC_SUBU: - gen_op_sub(); + tcg_gen_sub_tl(t0, t0, t1); + tcg_gen_ext32s_tl(t0, t0); opn = "subu"; break; #if defined(TARGET_MIPS64) case OPC_DADD: - save_cpu_state(ctx, 1); - gen_op_daddo(); + { + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_TL); + TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_TL); + int l1 = gen_new_label(); + + save_cpu_state(ctx, 1); + tcg_gen_mov_tl(r_tmp1, t0); + tcg_gen_add_tl(t0, t0, t1); + + tcg_gen_xor_tl(r_tmp1, r_tmp1, t1); + tcg_gen_xori_tl(r_tmp1, r_tmp1, -1); + tcg_gen_xor_tl(r_tmp2, t0, t1); + tcg_gen_and_tl(r_tmp1, r_tmp1, r_tmp2); + tcg_temp_free(r_tmp2); + tcg_gen_brcondi_tl(TCG_COND_GE, r_tmp1, 0, l1); + /* operands of same sign, result different sign */ + generate_exception(ctx, EXCP_OVERFLOW); + gen_set_label(l1); + tcg_temp_free(r_tmp1); + } opn = "dadd"; break; case OPC_DADDU: - gen_op_dadd(); + tcg_gen_add_tl(t0, t0, t1); opn = "daddu"; break; case OPC_DSUB: - save_cpu_state(ctx, 1); - gen_op_dsubo(); + { + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_TL); + TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_TL); + int l1 = gen_new_label(); + + save_cpu_state(ctx, 1); + tcg_gen_mov_tl(r_tmp1, t0); + tcg_gen_sub_tl(t0, t0, t1); + + tcg_gen_xor_tl(r_tmp2, r_tmp1, t1); + tcg_gen_xor_tl(r_tmp1, r_tmp1, t0); + tcg_gen_and_tl(r_tmp1, r_tmp1, r_tmp2); + tcg_temp_free(r_tmp2); + tcg_gen_brcondi_tl(TCG_COND_GE, r_tmp1, 0, l1); + /* operands of different sign, first operand and result different sign */ + generate_exception(ctx, EXCP_OVERFLOW); + gen_set_label(l1); + tcg_temp_free(r_tmp1); + } opn = "dsub"; break; case OPC_DSUBU: - gen_op_dsub(); + tcg_gen_sub_tl(t0, t0, t1); opn = "dsubu"; break; #endif case OPC_SLT: - gen_op_lt(); + gen_op_lt(t0, t1); opn = "slt"; break; case OPC_SLTU: - gen_op_ltu(); + gen_op_ltu(t0, t1); opn = "sltu"; break; case OPC_AND: - gen_op_and(); + tcg_gen_and_tl(t0, t0, t1); opn = "and"; break; case OPC_NOR: - gen_op_nor(); + tcg_gen_or_tl(t0, t0, t1); + tcg_gen_not_tl(t0, t0); opn = "nor"; break; case OPC_OR: - gen_op_or(); + tcg_gen_or_tl(t0, t0, t1); opn = "or"; break; case OPC_XOR: - gen_op_xor(); + tcg_gen_xor_tl(t0, t0, t1); opn = "xor"; break; case OPC_MUL: - gen_op_mul(); + tcg_gen_mul_tl(t0, t0, t1); + tcg_gen_ext32s_tl(t0, t0); opn = "mul"; break; case OPC_MOVN: - gen_op_movn(rd); + { + int l1 = gen_new_label(); + + tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1); + gen_store_gpr(t0, rd); + gen_set_label(l1); + } opn = "movn"; goto print; case OPC_MOVZ: - gen_op_movz(rd); + { + int l1 = gen_new_label(); + + tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1); + gen_store_gpr(t0, rd); + gen_set_label(l1); + } opn = "movz"; goto print; case OPC_SLLV: - gen_op_sllv(); + tcg_gen_andi_tl(t0, t0, 0x1f); + tcg_gen_shl_tl(t0, t1, t0); + tcg_gen_ext32s_tl(t0, t0); opn = "sllv"; break; case OPC_SRAV: - gen_op_srav(); + tcg_gen_ext32s_tl(t1, t1); + tcg_gen_andi_tl(t0, t0, 0x1f); + tcg_gen_sar_tl(t0, t1, t0); opn = "srav"; break; case OPC_SRLV: switch ((ctx->opcode >> 6) & 0x1f) { case 0: - gen_op_srlv(); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_andi_tl(t0, t0, 0x1f); + tcg_gen_shr_tl(t0, t1, t0); + tcg_gen_ext32s_tl(t0, t0); opn = "srlv"; break; case 1: /* rotrv is decoded as srlv on non-R2 CPUs */ if (env->insn_flags & ISA_MIPS32R2) { - gen_op_rotrv(); + int l1 = gen_new_label(); + int l2 = gen_new_label(); + + tcg_gen_andi_tl(t0, t0, 0x1f); + tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); + { + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_I32); + TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_trunc_tl_i32(r_tmp1, t0); + tcg_gen_trunc_tl_i32(r_tmp2, t1); + tcg_gen_rotr_i32(r_tmp1, r_tmp1, r_tmp2); + tcg_temp_free(r_tmp1); + tcg_temp_free(r_tmp2); + tcg_gen_br(l2); + } + gen_set_label(l1); + tcg_gen_mov_tl(t0, t1); + gen_set_label(l2); opn = "rotrv"; } else { - gen_op_srlv(); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_andi_tl(t0, t0, 0x1f); + tcg_gen_shr_tl(t0, t1, t0); + tcg_gen_ext32s_tl(t0, t0); opn = "srlv"; } break; @@ -1418,26 +1765,41 @@ break; #if defined(TARGET_MIPS64) case OPC_DSLLV: - gen_op_dsllv(); + tcg_gen_andi_tl(t0, t0, 0x3f); + tcg_gen_shl_tl(t0, t1, t0); opn = "dsllv"; break; case OPC_DSRAV: - gen_op_dsrav(); + tcg_gen_andi_tl(t0, t0, 0x3f); + tcg_gen_sar_tl(t0, t1, t0); opn = "dsrav"; break; case OPC_DSRLV: switch ((ctx->opcode >> 6) & 0x1f) { case 0: - gen_op_dsrlv(); + tcg_gen_andi_tl(t0, t0, 0x3f); + tcg_gen_shr_tl(t0, t1, t0); opn = "dsrlv"; break; case 1: /* drotrv is decoded as dsrlv on non-R2 CPUs */ if (env->insn_flags & ISA_MIPS32R2) { - gen_op_drotrv(); + int l1 = gen_new_label(); + int l2 = gen_new_label(); + + tcg_gen_andi_tl(t0, t0, 0x3f); + tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); + { + tcg_gen_rotr_tl(t0, t1, t0); + tcg_gen_br(l2); + } + gen_set_label(l1); + tcg_gen_mov_tl(t0, t1); + gen_set_label(l2); opn = "drotrv"; } else { - gen_op_dsrlv(); + tcg_gen_andi_tl(t0, t0, 0x3f); + tcg_gen_shr_tl(t0, t1, t0); opn = "dsrlv"; } break; @@ -1451,228 +1813,420 @@ default: MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); - return; + goto out; } - GEN_STORE_T0_REG(rd); + gen_store_gpr(t0, rd); print: MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]); + out: + tcg_temp_free(t0); + tcg_temp_free(t1); } /* Arithmetic on HI/LO registers */ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg) { const char *opn = "hilo"; + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) { /* Treat as NOP. */ MIPS_DEBUG("NOP"); - return; + goto out; } switch (opc) { case OPC_MFHI: - gen_op_load_HI(0); - GEN_STORE_T0_REG(reg); + tcg_gen_mov_tl(t0, cpu_HI[0]); + gen_store_gpr(t0, reg); opn = "mfhi"; break; case OPC_MFLO: - gen_op_load_LO(0); - GEN_STORE_T0_REG(reg); + tcg_gen_mov_tl(t0, cpu_LO[0]); + gen_store_gpr(t0, reg); opn = "mflo"; break; case OPC_MTHI: - GEN_LOAD_REG_T0(reg); - gen_op_store_HI(0); + gen_load_gpr(t0, reg); + tcg_gen_mov_tl(cpu_HI[0], t0); opn = "mthi"; break; case OPC_MTLO: - GEN_LOAD_REG_T0(reg); - gen_op_store_LO(0); + gen_load_gpr(t0, reg); + tcg_gen_mov_tl(cpu_LO[0], t0); opn = "mtlo"; break; default: MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); - return; + goto out; } MIPS_DEBUG("%s %s", opn, regnames[reg]); + out: + tcg_temp_free(t0); } static void gen_muldiv (DisasContext *ctx, uint32_t opc, int rs, int rt) { const char *opn = "mul/div"; + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + TCGv t1 = tcg_temp_local_new(TCG_TYPE_TL); - GEN_LOAD_REG_T0(rs); - GEN_LOAD_REG_T1(rt); + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); switch (opc) { case OPC_DIV: - gen_op_div(); + { + int l1 = gen_new_label(); + + tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1); + { + int l2 = gen_new_label(); + TCGv r_tmp1 = tcg_temp_local_new(TCG_TYPE_I32); + TCGv r_tmp2 = tcg_temp_local_new(TCG_TYPE_I32); + TCGv r_tmp3 = tcg_temp_local_new(TCG_TYPE_I32); + + tcg_gen_trunc_tl_i32(r_tmp1, t0); + tcg_gen_trunc_tl_i32(r_tmp2, t1); + tcg_gen_brcondi_i32(TCG_COND_NE, r_tmp1, -1 << 31, l2); + tcg_gen_brcondi_i32(TCG_COND_NE, r_tmp2, -1, l2); + tcg_gen_ext32s_tl(cpu_LO[0], t0); + tcg_gen_movi_tl(cpu_HI[0], 0); + tcg_gen_br(l1); + gen_set_label(l2); + tcg_gen_div_i32(r_tmp3, r_tmp1, r_tmp2); + tcg_gen_rem_i32(r_tmp2, r_tmp1, r_tmp2); + tcg_gen_ext_i32_tl(cpu_LO[0], r_tmp3); + tcg_gen_ext_i32_tl(cpu_HI[0], r_tmp2); + tcg_temp_free(r_tmp1); + tcg_temp_free(r_tmp2); + tcg_temp_free(r_tmp3); + } + gen_set_label(l1); + } opn = "div"; break; case OPC_DIVU: - gen_op_divu(); + { + int l1 = gen_new_label(); + + tcg_gen_ext32s_tl(t1, t1); + tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1); + { + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_I32); + TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_I32); + TCGv r_tmp3 = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_trunc_tl_i32(r_tmp1, t0); + tcg_gen_trunc_tl_i32(r_tmp2, t1); + tcg_gen_divu_i32(r_tmp3, r_tmp1, r_tmp2); + tcg_gen_remu_i32(r_tmp1, r_tmp1, r_tmp2); + tcg_gen_ext_i32_tl(cpu_LO[0], r_tmp3); + tcg_gen_ext_i32_tl(cpu_HI[0], r_tmp1); + tcg_temp_free(r_tmp1); + tcg_temp_free(r_tmp2); + tcg_temp_free(r_tmp3); + } + gen_set_label(l1); + } opn = "divu"; break; case OPC_MULT: - gen_op_mult(); + { + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_ext_tl_i64(r_tmp1, t0); + tcg_gen_ext_tl_i64(r_tmp2, t1); + tcg_gen_mul_i64(r_tmp1, r_tmp1, r_tmp2); + tcg_temp_free(r_tmp2); + tcg_gen_trunc_i64_tl(t0, r_tmp1); + tcg_gen_shri_i64(r_tmp1, r_tmp1, 32); + tcg_gen_trunc_i64_tl(t1, r_tmp1); + tcg_temp_free(r_tmp1); + tcg_gen_ext32s_tl(cpu_LO[0], t0); + tcg_gen_ext32s_tl(cpu_HI[0], t1); + } opn = "mult"; break; case OPC_MULTU: - gen_op_multu(); + { + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_extu_tl_i64(r_tmp1, t0); + tcg_gen_extu_tl_i64(r_tmp2, t1); + tcg_gen_mul_i64(r_tmp1, r_tmp1, r_tmp2); + tcg_temp_free(r_tmp2); + tcg_gen_trunc_i64_tl(t0, r_tmp1); + tcg_gen_shri_i64(r_tmp1, r_tmp1, 32); + tcg_gen_trunc_i64_tl(t1, r_tmp1); + tcg_temp_free(r_tmp1); + tcg_gen_ext32s_tl(cpu_LO[0], t0); + tcg_gen_ext32s_tl(cpu_HI[0], t1); + } opn = "multu"; break; #if defined(TARGET_MIPS64) case OPC_DDIV: - gen_op_ddiv(); + { + int l1 = gen_new_label(); + + tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1); + { + int l2 = gen_new_label(); + + tcg_gen_brcondi_tl(TCG_COND_NE, t0, -1LL << 63, l2); + tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2); + tcg_gen_mov_tl(cpu_LO[0], t0); + tcg_gen_movi_tl(cpu_HI[0], 0); + tcg_gen_br(l1); + gen_set_label(l2); + tcg_gen_div_i64(cpu_LO[0], t0, t1); + tcg_gen_rem_i64(cpu_HI[0], t0, t1); + } + gen_set_label(l1); + } opn = "ddiv"; break; case OPC_DDIVU: - gen_op_ddivu(); + { + int l1 = gen_new_label(); + + tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1); + tcg_gen_divu_i64(cpu_LO[0], t0, t1); + tcg_gen_remu_i64(cpu_HI[0], t0, t1); + gen_set_label(l1); + } opn = "ddivu"; break; case OPC_DMULT: - gen_op_dmult(); + tcg_gen_helper_0_2(do_dmult, t0, t1); opn = "dmult"; break; case OPC_DMULTU: - gen_op_dmultu(); + tcg_gen_helper_0_2(do_dmultu, t0, t1); opn = "dmultu"; break; #endif case OPC_MADD: - gen_op_madd(); + { + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_ext_tl_i64(r_tmp1, t0); + tcg_gen_ext_tl_i64(r_tmp2, t1); + tcg_gen_mul_i64(r_tmp1, r_tmp1, r_tmp2); + tcg_gen_concat_tl_i64(r_tmp2, cpu_LO[0], cpu_HI[0]); + tcg_gen_add_i64(r_tmp1, r_tmp1, r_tmp2); + tcg_temp_free(r_tmp2); + tcg_gen_trunc_i64_tl(t0, r_tmp1); + tcg_gen_shri_i64(r_tmp1, r_tmp1, 32); + tcg_gen_trunc_i64_tl(t1, r_tmp1); + tcg_temp_free(r_tmp1); + tcg_gen_ext32s_tl(cpu_LO[0], t0); + tcg_gen_ext32s_tl(cpu_LO[1], t1); + } opn = "madd"; break; case OPC_MADDU: - gen_op_maddu(); + { + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_extu_tl_i64(r_tmp1, t0); + tcg_gen_extu_tl_i64(r_tmp2, t1); + tcg_gen_mul_i64(r_tmp1, r_tmp1, r_tmp2); + tcg_gen_concat_tl_i64(r_tmp2, cpu_LO[0], cpu_HI[0]); + tcg_gen_add_i64(r_tmp1, r_tmp1, r_tmp2); + tcg_temp_free(r_tmp2); + tcg_gen_trunc_i64_tl(t0, r_tmp1); + tcg_gen_shri_i64(r_tmp1, r_tmp1, 32); + tcg_gen_trunc_i64_tl(t1, r_tmp1); + tcg_temp_free(r_tmp1); + tcg_gen_ext32s_tl(cpu_LO[0], t0); + tcg_gen_ext32s_tl(cpu_HI[0], t1); + } opn = "maddu"; break; case OPC_MSUB: - gen_op_msub(); + { + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_ext_tl_i64(r_tmp1, t0); + tcg_gen_ext_tl_i64(r_tmp2, t1); + tcg_gen_mul_i64(r_tmp1, r_tmp1, r_tmp2); + tcg_gen_concat_tl_i64(r_tmp2, cpu_LO[0], cpu_HI[0]); + tcg_gen_sub_i64(r_tmp1, r_tmp1, r_tmp2); + tcg_temp_free(r_tmp2); + tcg_gen_trunc_i64_tl(t0, r_tmp1); + tcg_gen_shri_i64(r_tmp1, r_tmp1, 32); + tcg_gen_trunc_i64_tl(t1, r_tmp1); + tcg_temp_free(r_tmp1); + tcg_gen_ext32s_tl(cpu_LO[0], t0); + tcg_gen_ext32s_tl(cpu_HI[0], t1); + } opn = "msub"; break; case OPC_MSUBU: - gen_op_msubu(); + { + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_extu_tl_i64(r_tmp1, t0); + tcg_gen_extu_tl_i64(r_tmp2, t1); + tcg_gen_mul_i64(r_tmp1, r_tmp1, r_tmp2); + tcg_gen_concat_tl_i64(r_tmp2, cpu_LO[0], cpu_HI[0]); + tcg_gen_sub_i64(r_tmp1, r_tmp1, r_tmp2); + tcg_temp_free(r_tmp2); + tcg_gen_trunc_i64_tl(t0, r_tmp1); + tcg_gen_shri_i64(r_tmp1, r_tmp1, 32); + tcg_gen_trunc_i64_tl(t1, r_tmp1); + tcg_temp_free(r_tmp1); + tcg_gen_ext32s_tl(cpu_LO[0], t0); + tcg_gen_ext32s_tl(cpu_HI[0], t1); + } opn = "msubu"; break; default: MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); - return; + goto out; } MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]); + out: + tcg_temp_free(t0); + tcg_temp_free(t1); } static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc, int rd, int rs, int rt) { const char *opn = "mul vr54xx"; + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + TCGv t1 = tcg_temp_local_new(TCG_TYPE_TL); - GEN_LOAD_REG_T0(rs); - GEN_LOAD_REG_T1(rt); + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); switch (opc) { case OPC_VR54XX_MULS: - gen_op_muls(); + tcg_gen_helper_1_2(do_muls, t0, t0, t1); opn = "muls"; break; case OPC_VR54XX_MULSU: - gen_op_mulsu(); + tcg_gen_helper_1_2(do_mulsu, t0, t0, t1); opn = "mulsu"; break; case OPC_VR54XX_MACC: - gen_op_macc(); + tcg_gen_helper_1_2(do_macc, t0, t0, t1); opn = "macc"; break; case OPC_VR54XX_MACCU: - gen_op_maccu(); + tcg_gen_helper_1_2(do_maccu, t0, t0, t1); opn = "maccu"; break; case OPC_VR54XX_MSAC: - gen_op_msac(); + tcg_gen_helper_1_2(do_msac, t0, t0, t1); opn = "msac"; break; case OPC_VR54XX_MSACU: - gen_op_msacu(); + tcg_gen_helper_1_2(do_msacu, t0, t0, t1); opn = "msacu"; break; case OPC_VR54XX_MULHI: - gen_op_mulhi(); + tcg_gen_helper_1_2(do_mulhi, t0, t0, t1); opn = "mulhi"; break; case OPC_VR54XX_MULHIU: - gen_op_mulhiu(); + tcg_gen_helper_1_2(do_mulhiu, t0, t0, t1); opn = "mulhiu"; break; case OPC_VR54XX_MULSHI: - gen_op_mulshi(); + tcg_gen_helper_1_2(do_mulshi, t0, t0, t1); opn = "mulshi"; break; case OPC_VR54XX_MULSHIU: - gen_op_mulshiu(); + tcg_gen_helper_1_2(do_mulshiu, t0, t0, t1); opn = "mulshiu"; break; case OPC_VR54XX_MACCHI: - gen_op_macchi(); + tcg_gen_helper_1_2(do_macchi, t0, t0, t1); opn = "macchi"; break; case OPC_VR54XX_MACCHIU: - gen_op_macchiu(); + tcg_gen_helper_1_2(do_macchiu, t0, t0, t1); opn = "macchiu"; break; case OPC_VR54XX_MSACHI: - gen_op_msachi(); + tcg_gen_helper_1_2(do_msachi, t0, t0, t1); opn = "msachi"; break; case OPC_VR54XX_MSACHIU: - gen_op_msachiu(); + tcg_gen_helper_1_2(do_msachiu, t0, t0, t1); opn = "msachiu"; break; default: MIPS_INVAL("mul vr54xx"); generate_exception(ctx, EXCP_RI); - return; + goto out; } - GEN_STORE_T0_REG(rd); + gen_store_gpr(t0, rd); MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]); + + out: + tcg_temp_free(t0); + tcg_temp_free(t1); } static void gen_cl (DisasContext *ctx, uint32_t opc, int rd, int rs) { const char *opn = "CLx"; + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + if (rd == 0) { /* Treat as NOP. */ MIPS_DEBUG("NOP"); - return; + goto out; } - GEN_LOAD_REG_T0(rs); + gen_load_gpr(t0, rs); switch (opc) { case OPC_CLO: - gen_op_clo(); + tcg_gen_helper_1_1(do_clo, t0, t0); opn = "clo"; break; case OPC_CLZ: - gen_op_clz(); + tcg_gen_helper_1_1(do_clz, t0, t0); opn = "clz"; break; #if defined(TARGET_MIPS64) case OPC_DCLO: - gen_op_dclo(); + tcg_gen_helper_1_1(do_dclo, t0, t0); opn = "dclo"; break; case OPC_DCLZ: - gen_op_dclz(); + tcg_gen_helper_1_1(do_dclz, t0, t0); opn = "dclz"; break; #endif default: MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); - return; + goto out; } - gen_op_store_T0_gpr(rd); + gen_store_gpr(t0, rd); MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]); + + out: + tcg_temp_free(t0); } /* Traps */ @@ -1680,6 +2234,8 @@ int rs, int rt, int16_t imm) { int cond; + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + TCGv t1 = tcg_temp_local_new(TCG_TYPE_TL); cond = 0; /* Load needed operands */ @@ -1692,8 +2248,8 @@ case OPC_TNE: /* Compare two registers */ if (rs != rt) { - GEN_LOAD_REG_T0(rs); - GEN_LOAD_REG_T1(rt); + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); cond = 1; } break; @@ -1705,8 +2261,8 @@ case OPC_TNEI: /* Compare register to immediate */ if (rs != 0 || imm != 0) { - GEN_LOAD_REG_T0(rs); - GEN_LOAD_IMM_TN(T1, (int32_t)imm); + gen_load_gpr(t0, rs); + tcg_gen_movi_tl(t1, (int32_t)imm); cond = 1; } break; @@ -1720,7 +2276,7 @@ case OPC_TGEU: /* rs >= rs unsigned */ case OPC_TGEIU: /* r0 >= 0 unsigned */ /* Always trap */ - gen_op_set_T0(1); + tcg_gen_movi_tl(t0, 1); break; case OPC_TLT: /* rs < rs */ case OPC_TLTI: /* r0 < 0 */ @@ -1729,74 +2285,81 @@ case OPC_TNE: /* rs != rs */ case OPC_TNEI: /* r0 != 0 */ /* Never trap: treat as NOP. */ - return; + goto out; default: MIPS_INVAL("trap"); generate_exception(ctx, EXCP_RI); - return; + goto out; } } else { switch (opc) { case OPC_TEQ: case OPC_TEQI: - gen_op_eq(); + gen_op_eq(t0, t1); break; case OPC_TGE: case OPC_TGEI: - gen_op_ge(); + gen_op_ge(t0, t1); break; case OPC_TGEU: case OPC_TGEIU: - gen_op_geu(); + gen_op_geu(t0, t1); break; case OPC_TLT: case OPC_TLTI: - gen_op_lt(); + gen_op_lt(t0, t1); break; case OPC_TLTU: case OPC_TLTIU: - gen_op_ltu(); + gen_op_ltu(t0, t1); break; case OPC_TNE: case OPC_TNEI: - gen_op_ne(); + gen_op_ne(t0, t1); break; default: MIPS_INVAL("trap"); generate_exception(ctx, EXCP_RI); - return; + goto out; } } save_cpu_state(ctx, 1); - gen_op_trap(); + { + int l1 = gen_new_label(); + + tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); + tcg_gen_helper_0_i(do_raise_exception, EXCP_TRAP); + gen_set_label(l1); + } ctx->bstate = BS_STOP; + out: + tcg_temp_free(t0); + tcg_temp_free(t1); } -static always_inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) +static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) { TranslationBlock *tb; tb = ctx->tb; if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { - if (n == 0) - gen_op_goto_tb0(TBPARAM(tb)); - else - gen_op_goto_tb1(TBPARAM(tb)); + tcg_gen_goto_tb(n); gen_save_pc(dest); - gen_op_set_T0((long)tb + n); + tcg_gen_exit_tb((long)tb + n); } else { gen_save_pc(dest); - gen_op_reset_T0(); + tcg_gen_exit_tb(0); } - gen_op_exit_tb(); } /* Branches (before delay slot) */ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, int rs, int rt, int32_t offset) { - target_ulong btarget = -1; + target_ulong btgt = -1; int blink = 0; - int bcond = 0; + int bcond_compute = 0; + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + TCGv t1 = tcg_temp_local_new(TCG_TYPE_TL); if (ctx->hflags & MIPS_HFLAG_BMASK) { #ifdef MIPS_DEBUG_DISAS @@ -1807,7 +2370,7 @@ } #endif generate_exception(ctx, EXCP_RI); - return; + goto out; } /* Load needed operands */ @@ -1818,11 +2381,11 @@ case OPC_BNEL: /* Compare two registers */ if (rs != rt) { - GEN_LOAD_REG_T0(rs); - GEN_LOAD_REG_T1(rt); - bcond = 1; + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + bcond_compute = 1; } - btarget = ctx->pc + 4 + offset; + btgt = ctx->pc + 4 + offset; break; case OPC_BGEZ: case OPC_BGEZAL: @@ -1838,15 +2401,15 @@ case OPC_BLTZL: /* Compare to zero */ if (rs != 0) { - gen_op_load_gpr_T0(rs); - bcond = 1; + gen_load_gpr(t0, rs); + bcond_compute = 1; } - btarget = ctx->pc + 4 + offset; + btgt = ctx->pc + 4 + offset; break; case OPC_J: case OPC_JAL: /* Jump to immediate */ - btarget = ((ctx->pc + 4) & (int32_t)0xF0000000) | (uint32_t)offset; + btgt = ((ctx->pc + 4) & (int32_t)0xF0000000) | (uint32_t)offset; break; case OPC_JR: case OPC_JALR: @@ -1856,16 +2419,16 @@ others are reserved. */ MIPS_INVAL("jump hint"); generate_exception(ctx, EXCP_RI); - return; + goto out; } - GEN_LOAD_REG_T2(rs); + gen_load_gpr(btarget, rs); break; default: MIPS_INVAL("branch/jump"); generate_exception(ctx, EXCP_RI); - return; + goto out; } - if (bcond == 0) { + if (bcond_compute == 0) { /* No condition to be computed */ switch (opc) { case OPC_BEQ: /* rx == rx */ @@ -1890,34 +2453,34 @@ case OPC_BLTZ: /* 0 < 0 */ /* Treat as NOP. */ MIPS_DEBUG("bnever (NOP)"); - return; + goto out; case OPC_BLTZAL: /* 0 < 0 */ - GEN_LOAD_IMM_TN(T0, ctx->pc + 8); - gen_op_store_T0_gpr(31); + tcg_gen_movi_tl(t0, ctx->pc + 8); + gen_store_gpr(t0, 31); MIPS_DEBUG("bnever and link"); - return; + goto out; case OPC_BLTZALL: /* 0 < 0 likely */ - GEN_LOAD_IMM_TN(T0, ctx->pc + 8); - gen_op_store_T0_gpr(31); + tcg_gen_movi_tl(t0, ctx->pc + 8); + gen_store_gpr(t0, 31); /* Skip the instruction in the delay slot */ MIPS_DEBUG("bnever, link and skip"); ctx->pc += 4; - return; + goto out; case OPC_BNEL: /* rx != rx likely */ case OPC_BGTZL: /* 0 > 0 likely */ case OPC_BLTZL: /* 0 < 0 likely */ /* Skip the instruction in the delay slot */ MIPS_DEBUG("bnever and skip"); ctx->pc += 4; - return; + goto out; case OPC_J: ctx->hflags |= MIPS_HFLAG_B; - MIPS_DEBUG("j " TARGET_FMT_lx, btarget); + MIPS_DEBUG("j " TARGET_FMT_lx, btgt); break; case OPC_JAL: blink = 31; ctx->hflags |= MIPS_HFLAG_B; - MIPS_DEBUG("jal " TARGET_FMT_lx, btarget); + MIPS_DEBUG("jal " TARGET_FMT_lx, btgt); break; case OPC_JR: ctx->hflags |= MIPS_HFLAG_BR; @@ -1931,170 +2494,288 @@ default: MIPS_INVAL("branch/jump"); generate_exception(ctx, EXCP_RI); - return; + goto out; } } else { switch (opc) { case OPC_BEQ: - gen_op_eq(); + gen_op_eq(t0, t1); MIPS_DEBUG("beq %s, %s, " TARGET_FMT_lx, - regnames[rs], regnames[rt], btarget); + regnames[rs], regnames[rt], btgt); goto not_likely; case OPC_BEQL: - gen_op_eq(); + gen_op_eq(t0, t1); MIPS_DEBUG("beql %s, %s, " TARGET_FMT_lx, - regnames[rs], regnames[rt], btarget); + regnames[rs], regnames[rt], btgt); goto likely; case OPC_BNE: - gen_op_ne(); + gen_op_ne(t0, t1); MIPS_DEBUG("bne %s, %s, " TARGET_FMT_lx, - regnames[rs], regnames[rt], btarget); + regnames[rs], regnames[rt], btgt); goto not_likely; case OPC_BNEL: - gen_op_ne(); + gen_op_ne(t0, t1); MIPS_DEBUG("bnel %s, %s, " TARGET_FMT_lx, - regnames[rs], regnames[rt], btarget); + regnames[rs], regnames[rt], btgt); goto likely; case OPC_BGEZ: - gen_op_gez(); - MIPS_DEBUG("bgez %s, " TARGET_FMT_lx, regnames[rs], btarget); + gen_op_gez(t0); + MIPS_DEBUG("bgez %s, " TARGET_FMT_lx, regnames[rs], btgt); goto not_likely; case OPC_BGEZL: - gen_op_gez(); - MIPS_DEBUG("bgezl %s, " TARGET_FMT_lx, regnames[rs], btarget); + gen_op_gez(t0); + MIPS_DEBUG("bgezl %s, " TARGET_FMT_lx, regnames[rs], btgt); goto likely; case OPC_BGEZAL: - gen_op_gez(); - MIPS_DEBUG("bgezal %s, " TARGET_FMT_lx, regnames[rs], btarget); + gen_op_gez(t0); + MIPS_DEBUG("bgezal %s, " TARGET_FMT_lx, regnames[rs], btgt); blink = 31; goto not_likely; case OPC_BGEZALL: - gen_op_gez(); + gen_op_gez(t0); blink = 31; - MIPS_DEBUG("bgezall %s, " TARGET_FMT_lx, regnames[rs], btarget); + MIPS_DEBUG("bgezall %s, " TARGET_FMT_lx, regnames[rs], btgt); goto likely; case OPC_BGTZ: - gen_op_gtz(); - MIPS_DEBUG("bgtz %s, " TARGET_FMT_lx, regnames[rs], btarget); + gen_op_gtz(t0); + MIPS_DEBUG("bgtz %s, " TARGET_FMT_lx, regnames[rs], btgt); goto not_likely; case OPC_BGTZL: - gen_op_gtz(); - MIPS_DEBUG("bgtzl %s, " TARGET_FMT_lx, regnames[rs], btarget); + gen_op_gtz(t0); + MIPS_DEBUG("bgtzl %s, " TARGET_FMT_lx, regnames[rs], btgt); goto likely; case OPC_BLEZ: - gen_op_lez(); - MIPS_DEBUG("blez %s, " TARGET_FMT_lx, regnames[rs], btarget); + gen_op_lez(t0); + MIPS_DEBUG("blez %s, " TARGET_FMT_lx, regnames[rs], btgt); goto not_likely; case OPC_BLEZL: - gen_op_lez(); - MIPS_DEBUG("blezl %s, " TARGET_FMT_lx, regnames[rs], btarget); + gen_op_lez(t0); + MIPS_DEBUG("blezl %s, " TARGET_FMT_lx, regnames[rs], btgt); goto likely; case OPC_BLTZ: - gen_op_ltz(); - MIPS_DEBUG("bltz %s, " TARGET_FMT_lx, regnames[rs], btarget); + gen_op_ltz(t0); + MIPS_DEBUG("bltz %s, " TARGET_FMT_lx, regnames[rs], btgt); goto not_likely; case OPC_BLTZL: - gen_op_ltz(); - MIPS_DEBUG("bltzl %s, " TARGET_FMT_lx, regnames[rs], btarget); + gen_op_ltz(t0); + MIPS_DEBUG("bltzl %s, " TARGET_FMT_lx, regnames[rs], btgt); goto likely; case OPC_BLTZAL: - gen_op_ltz(); + gen_op_ltz(t0); blink = 31; - MIPS_DEBUG("bltzal %s, " TARGET_FMT_lx, regnames[rs], btarget); + MIPS_DEBUG("bltzal %s, " TARGET_FMT_lx, regnames[rs], btgt); not_likely: ctx->hflags |= MIPS_HFLAG_BC; - gen_op_set_bcond(); + tcg_gen_trunc_tl_i32(bcond, t0); break; case OPC_BLTZALL: - gen_op_ltz(); + gen_op_ltz(t0); blink = 31; - MIPS_DEBUG("bltzall %s, " TARGET_FMT_lx, regnames[rs], btarget); + MIPS_DEBUG("bltzall %s, " TARGET_FMT_lx, regnames[rs], btgt); likely: ctx->hflags |= MIPS_HFLAG_BL; - gen_op_set_bcond(); - gen_op_save_bcond(); + tcg_gen_trunc_tl_i32(bcond, t0); break; default: MIPS_INVAL("conditional branch/jump"); generate_exception(ctx, EXCP_RI); - return; + goto out; } } MIPS_DEBUG("enter ds: link %d cond %02x target " TARGET_FMT_lx, - blink, ctx->hflags, btarget); + blink, ctx->hflags, btgt); - ctx->btarget = btarget; + ctx->btarget = btgt; if (blink > 0) { - GEN_LOAD_IMM_TN(T0, ctx->pc + 8); - gen_op_store_T0_gpr(blink); + tcg_gen_movi_tl(t0, ctx->pc + 8); + gen_store_gpr(t0, blink); } + + out: + tcg_temp_free(t0); + tcg_temp_free(t1); } /* special3 bitfield operations */ static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt, - int rs, int lsb, int msb) + int rs, int lsb, int msb) { - GEN_LOAD_REG_T1(rs); + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + TCGv t1 = tcg_temp_new(TCG_TYPE_TL); + target_ulong mask; + + gen_load_gpr(t1, rs); switch (opc) { case OPC_EXT: if (lsb + msb > 31) goto fail; - gen_op_ext(lsb, msb + 1); + tcg_gen_shri_tl(t0, t1, lsb); + if (msb != 31) { + tcg_gen_andi_tl(t0, t0, (1 << (msb + 1)) - 1); + } else { + tcg_gen_ext32s_tl(t0, t0); + } break; #if defined(TARGET_MIPS64) case OPC_DEXTM: - if (lsb + msb > 63) - goto fail; - gen_op_dext(lsb, msb + 1 + 32); + tcg_gen_shri_tl(t0, t1, lsb); + if (msb != 31) { + tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1 + 32)) - 1); + } break; case OPC_DEXTU: - if (lsb + msb > 63) - goto fail; - gen_op_dext(lsb + 32, msb + 1); + tcg_gen_shri_tl(t0, t1, lsb + 32); + tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1); break; case OPC_DEXT: - if (lsb + msb > 63) - goto fail; - gen_op_dext(lsb, msb + 1); + tcg_gen_shri_tl(t0, t1, lsb); + tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1); break; #endif case OPC_INS: if (lsb > msb) goto fail; - GEN_LOAD_REG_T0(rt); - gen_op_ins(lsb, msb - lsb + 1); + mask = ((msb - lsb + 1 < 32) ? ((1 << (msb - lsb + 1)) - 1) : ~0) << lsb; + gen_load_gpr(t0, rt); + tcg_gen_andi_tl(t0, t0, ~mask); + tcg_gen_shli_tl(t1, t1, lsb); + tcg_gen_andi_tl(t1, t1, mask); + tcg_gen_or_tl(t0, t0, t1); + tcg_gen_ext32s_tl(t0, t0); break; #if defined(TARGET_MIPS64) case OPC_DINSM: if (lsb > msb) goto fail; - GEN_LOAD_REG_T0(rt); - gen_op_dins(lsb, msb - lsb + 1 + 32); + mask = ((msb - lsb + 1 + 32 < 64) ? ((1ULL << (msb - lsb + 1 + 32)) - 1) : ~0ULL) << lsb; + gen_load_gpr(t0, rt); + tcg_gen_andi_tl(t0, t0, ~mask); + tcg_gen_shli_tl(t1, t1, lsb); + tcg_gen_andi_tl(t1, t1, mask); + tcg_gen_or_tl(t0, t0, t1); break; case OPC_DINSU: if (lsb > msb) goto fail; - GEN_LOAD_REG_T0(rt); - gen_op_dins(lsb + 32, msb - lsb + 1); + mask = ((1ULL << (msb - lsb + 1)) - 1) << lsb; + gen_load_gpr(t0, rt); + tcg_gen_andi_tl(t0, t0, ~mask); + tcg_gen_shli_tl(t1, t1, lsb + 32); + tcg_gen_andi_tl(t1, t1, mask); + tcg_gen_or_tl(t0, t0, t1); break; case OPC_DINS: if (lsb > msb) goto fail; - GEN_LOAD_REG_T0(rt); - gen_op_dins(lsb, msb - lsb + 1); + gen_load_gpr(t0, rt); + mask = ((1ULL << (msb - lsb + 1)) - 1) << lsb; + gen_load_gpr(t0, rt); + tcg_gen_andi_tl(t0, t0, ~mask); + tcg_gen_shli_tl(t1, t1, lsb); + tcg_gen_andi_tl(t1, t1, mask); + tcg_gen_or_tl(t0, t0, t1); break; #endif default: fail: MIPS_INVAL("bitops"); generate_exception(ctx, EXCP_RI); + tcg_temp_free(t0); + tcg_temp_free(t1); + return; + } + gen_store_gpr(t0, rt); + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void gen_bshfl (DisasContext *ctx, uint32_t op2, int rt, int rd) +{ + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + TCGv t1 = tcg_temp_new(TCG_TYPE_TL); + + gen_load_gpr(t1, rt); + switch (op2) { + case OPC_WSBH: + tcg_gen_shri_tl(t0, t1, 8); + tcg_gen_andi_tl(t0, t0, 0x00FF00FF); + tcg_gen_shli_tl(t1, t1, 8); + tcg_gen_andi_tl(t1, t1, ~0x00FF00FF); + tcg_gen_or_tl(t0, t0, t1); + tcg_gen_ext32s_tl(t0, t0); + break; + case OPC_SEB: + tcg_gen_ext8s_tl(t0, t1); + break; + case OPC_SEH: + tcg_gen_ext16s_tl(t0, t1); + break; +#if defined(TARGET_MIPS64) + case OPC_DSBH: + gen_load_gpr(t1, rt); + tcg_gen_shri_tl(t0, t1, 8); + tcg_gen_andi_tl(t0, t0, 0x00FF00FF00FF00FFULL); + tcg_gen_shli_tl(t1, t1, 8); + tcg_gen_andi_tl(t1, t1, ~0x00FF00FF00FF00FFULL); + tcg_gen_or_tl(t0, t0, t1); + break; + case OPC_DSHD: + gen_load_gpr(t1, rt); + tcg_gen_shri_tl(t0, t1, 16); + tcg_gen_andi_tl(t0, t0, 0x0000FFFF0000FFFFULL); + tcg_gen_shli_tl(t1, t1, 16); + tcg_gen_andi_tl(t1, t1, ~0x0000FFFF0000FFFFULL); + tcg_gen_or_tl(t1, t0, t1); + tcg_gen_shri_tl(t0, t1, 32); + tcg_gen_shli_tl(t1, t1, 32); + tcg_gen_or_tl(t0, t0, t1); + break; +#endif + default: + MIPS_INVAL("bsfhl"); + generate_exception(ctx, EXCP_RI); + tcg_temp_free(t0); + tcg_temp_free(t1); return; } - GEN_STORE_T0_REG(rt); + gen_store_gpr(t0, rd); + tcg_temp_free(t0); + tcg_temp_free(t1); } +#ifndef CONFIG_USER_ONLY /* CP0 (MMU and control) */ -static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) +static inline void gen_mfc0_load32 (TCGv t, target_ulong off) +{ + TCGv r_tmp = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_ld_i32(r_tmp, cpu_env, off); + tcg_gen_ext_i32_tl(t, r_tmp); + tcg_temp_free(r_tmp); +} + +static inline void gen_mfc0_load64 (TCGv t, target_ulong off) +{ + tcg_gen_ld_tl(t, cpu_env, off); + tcg_gen_ext32s_tl(t, t); +} + +static inline void gen_mtc0_store32 (TCGv t, target_ulong off) +{ + TCGv r_tmp = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_trunc_tl_i32(r_tmp, t); + tcg_gen_st_i32(r_tmp, cpu_env, off); + tcg_temp_free(r_tmp); +} + +static inline void gen_mtc0_store64 (TCGv t, target_ulong off) +{ + tcg_gen_ext32s_tl(t, t); + tcg_gen_st_tl(t, cpu_env, off); +} + +static void gen_mfc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int sel) { const char *rn = "invalid"; @@ -2105,22 +2786,22 @@ case 0: switch (sel) { case 0: - gen_op_mfc0_index(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Index)); rn = "Index"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_mvpcontrol(); + tcg_gen_helper_1_0(do_mfc0_mvpcontrol, t0); rn = "MVPControl"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_mvpconf0(); + tcg_gen_helper_1_0(do_mfc0_mvpconf0, t0); rn = "MVPConf0"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_mvpconf1(); + tcg_gen_helper_1_0(do_mfc0_mvpconf1, t0); rn = "MVPConf1"; break; default: @@ -2130,42 +2811,42 @@ case 1: switch (sel) { case 0: - gen_op_mfc0_random(); + tcg_gen_helper_1_0(do_mfc0_random, t0); rn = "Random"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpecontrol(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_VPEControl)); rn = "VPEControl"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpeconf0(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_VPEConf0)); rn = "VPEConf0"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpeconf1(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_VPEConf1)); rn = "VPEConf1"; break; case 4: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_yqmask(); + gen_mfc0_load64(t0, offsetof(CPUState, CP0_YQMask)); rn = "YQMask"; break; case 5: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpeschedule(); + gen_mfc0_load64(t0, offsetof(CPUState, CP0_VPESchedule)); rn = "VPESchedule"; break; case 6: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpeschefback(); + gen_mfc0_load64(t0, offsetof(CPUState, CP0_VPEScheFBack)); rn = "VPEScheFBack"; break; case 7: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpeopt(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_VPEOpt)); rn = "VPEOpt"; break; default: @@ -2175,42 +2856,43 @@ case 2: switch (sel) { case 0: - gen_op_mfc0_entrylo0(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_EntryLo0)); + tcg_gen_ext32s_tl(t0, t0); rn = "EntryLo0"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_tcstatus(); + tcg_gen_helper_1_0(do_mfc0_tcstatus, t0); rn = "TCStatus"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_tcbind(); + tcg_gen_helper_1_0(do_mfc0_tcbind, t0); rn = "TCBind"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_tcrestart(); + tcg_gen_helper_1_0(do_mfc0_tcrestart, t0); rn = "TCRestart"; break; case 4: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_tchalt(); + tcg_gen_helper_1_0(do_mfc0_tchalt, t0); rn = "TCHalt"; break; case 5: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_tccontext(); + tcg_gen_helper_1_0(do_mfc0_tccontext, t0); rn = "TCContext"; break; case 6: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_tcschedule(); + tcg_gen_helper_1_0(do_mfc0_tcschedule, t0); rn = "TCSchedule"; break; case 7: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_tcschefback(); + tcg_gen_helper_1_0(do_mfc0_tcschefback, t0); rn = "TCScheFBack"; break; default: @@ -2220,7 +2902,8 @@ case 3: switch (sel) { case 0: - gen_op_mfc0_entrylo1(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_EntryLo1)); + tcg_gen_ext32s_tl(t0, t0); rn = "EntryLo1"; break; default: @@ -2230,11 +2913,12 @@ case 4: switch (sel) { case 0: - gen_op_mfc0_context(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_Context)); + tcg_gen_ext32s_tl(t0, t0); rn = "Context"; break; case 1: -// gen_op_mfc0_contextconfig(); /* SmartMIPS ASE */ +// tcg_gen_helper_1_0(do_mfc0_contextconfig, t0); /* SmartMIPS ASE */ rn = "ContextConfig"; // break; default: @@ -2244,12 +2928,12 @@ case 5: switch (sel) { case 0: - gen_op_mfc0_pagemask(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_PageMask)); rn = "PageMask"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_pagegrain(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_PageGrain)); rn = "PageGrain"; break; default: @@ -2259,32 +2943,32 @@ case 6: switch (sel) { case 0: - gen_op_mfc0_wired(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Wired)); rn = "Wired"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf0(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_SRSConf0)); rn = "SRSConf0"; break; case 2: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf1(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_SRSConf1)); rn = "SRSConf1"; break; case 3: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf2(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_SRSConf2)); rn = "SRSConf2"; break; case 4: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf3(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_SRSConf3)); rn = "SRSConf3"; break; case 5: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf4(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_SRSConf4)); rn = "SRSConf4"; break; default: @@ -2295,7 +2979,7 @@ switch (sel) { case 0: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_hwrena(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_HWREna)); rn = "HWREna"; break; default: @@ -2305,8 +2989,9 @@ case 8: switch (sel) { case 0: - gen_op_mfc0_badvaddr(); - rn = "BadVaddr"; + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_BadVAddr)); + tcg_gen_ext32s_tl(t0, t0); + rn = "BadVAddr"; break; default: goto die; @@ -2315,7 +3000,14 @@ case 9: switch (sel) { case 0: - gen_op_mfc0_count(); + /* Mark as an IO operation because we read the time. */ + if (use_icount) + gen_io_start(); + tcg_gen_helper_1_0(do_mfc0_count, t0); + if (use_icount) { + gen_io_end(); + ctx->bstate = BS_STOP; + } rn = "Count"; break; /* 6,7 are implementation dependent */ @@ -2326,7 +3018,8 @@ case 10: switch (sel) { case 0: - gen_op_mfc0_entryhi(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_EntryHi)); + tcg_gen_ext32s_tl(t0, t0); rn = "EntryHi"; break; default: @@ -2336,7 +3029,7 @@ case 11: switch (sel) { case 0: - gen_op_mfc0_compare(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Compare)); rn = "Compare"; break; /* 6,7 are implementation dependent */ @@ -2347,22 +3040,22 @@ case 12: switch (sel) { case 0: - gen_op_mfc0_status(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Status)); rn = "Status"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_intctl(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_IntCtl)); rn = "IntCtl"; break; case 2: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsctl(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_SRSCtl)); rn = "SRSCtl"; break; case 3: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsmap(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_SRSMap)); rn = "SRSMap"; break; default: @@ -2372,7 +3065,7 @@ case 13: switch (sel) { case 0: - gen_op_mfc0_cause(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Cause)); rn = "Cause"; break; default: @@ -2382,7 +3075,8 @@ case 14: switch (sel) { case 0: - gen_op_mfc0_epc(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_EPC)); + tcg_gen_ext32s_tl(t0, t0); rn = "EPC"; break; default: @@ -2392,12 +3086,12 @@ case 15: switch (sel) { case 0: - gen_op_mfc0_prid(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_PRid)); rn = "PRid"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_ebase(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_EBase)); rn = "EBase"; break; default: @@ -2407,29 +3101,29 @@ case 16: switch (sel) { case 0: - gen_op_mfc0_config0(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Config0)); rn = "Config"; break; case 1: - gen_op_mfc0_config1(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Config1)); rn = "Config1"; break; case 2: - gen_op_mfc0_config2(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Config2)); rn = "Config2"; break; case 3: - gen_op_mfc0_config3(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Config3)); rn = "Config3"; break; /* 4,5 are reserved */ /* 6,7 are implementation dependent */ case 6: - gen_op_mfc0_config6(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Config6)); rn = "Config6"; break; case 7: - gen_op_mfc0_config7(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Config7)); rn = "Config7"; break; default: @@ -2439,7 +3133,7 @@ case 17: switch (sel) { case 0: - gen_op_mfc0_lladdr(); + tcg_gen_helper_1_0(do_mfc0_lladdr, t0); rn = "LLAddr"; break; default: @@ -2449,7 +3143,7 @@ case 18: switch (sel) { case 0 ... 7: - gen_op_mfc0_watchlo(sel); + tcg_gen_helper_1_i(do_mfc0_watchlo, t0, sel); rn = "WatchLo"; break; default: @@ -2459,7 +3153,7 @@ case 19: switch (sel) { case 0 ...7: - gen_op_mfc0_watchhi(sel); + tcg_gen_helper_1_i(do_mfc0_watchhi, t0, sel); rn = "WatchHi"; break; default: @@ -2471,7 +3165,8 @@ case 0: #if defined(TARGET_MIPS64) check_insn(env, ctx, ISA_MIPS3); - gen_op_mfc0_xcontext(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_XContext)); + tcg_gen_ext32s_tl(t0, t0); rn = "XContext"; break; #endif @@ -2483,7 +3178,7 @@ /* Officially reserved, but sel 0 is used for R1x000 framemask */ switch (sel) { case 0: - gen_op_mfc0_framemask(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Framemask)); rn = "Framemask"; break; default: @@ -2497,23 +3192,23 @@ case 23: switch (sel) { case 0: - gen_op_mfc0_debug(); /* EJTAG support */ + tcg_gen_helper_1_0(do_mfc0_debug, t0); /* EJTAG support */ rn = "Debug"; break; case 1: -// gen_op_mfc0_tracecontrol(); /* PDtrace support */ +// tcg_gen_helper_1_0(do_mfc0_tracecontrol, t0); /* PDtrace support */ rn = "TraceControl"; // break; case 2: -// gen_op_mfc0_tracecontrol2(); /* PDtrace support */ +// tcg_gen_helper_1_0(do_mfc0_tracecontrol2, t0); /* PDtrace support */ rn = "TraceControl2"; // break; case 3: -// gen_op_mfc0_usertracedata(); /* PDtrace support */ +// tcg_gen_helper_1_0(do_mfc0_usertracedata, t0); /* PDtrace support */ rn = "UserTraceData"; // break; case 4: -// gen_op_mfc0_debug(); /* PDtrace support */ +// tcg_gen_helper_1_0(do_mfc0_tracebpc, t0); /* PDtrace support */ rn = "TraceBPC"; // break; default: @@ -2523,7 +3218,9 @@ case 24: switch (sel) { case 0: - gen_op_mfc0_depc(); /* EJTAG support */ + /* EJTAG support */ + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_DEPC)); + tcg_gen_ext32s_tl(t0, t0); rn = "DEPC"; break; default: @@ -2533,35 +3230,35 @@ case 25: switch (sel) { case 0: - gen_op_mfc0_performance0(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Performance0)); rn = "Performance0"; break; case 1: -// gen_op_mfc0_performance1(); +// tcg_gen_helper_1_0(do_mfc0_performance1, t0); rn = "Performance1"; // break; case 2: -// gen_op_mfc0_performance2(); +// tcg_gen_helper_1_0(do_mfc0_performance2, t0); rn = "Performance2"; // break; case 3: -// gen_op_mfc0_performance3(); +// tcg_gen_helper_1_0(do_mfc0_performance3, t0); rn = "Performance3"; // break; case 4: -// gen_op_mfc0_performance4(); +// tcg_gen_helper_1_0(do_mfc0_performance4, t0); rn = "Performance4"; // break; case 5: -// gen_op_mfc0_performance5(); +// tcg_gen_helper_1_0(do_mfc0_performance5, t0); rn = "Performance5"; // break; case 6: -// gen_op_mfc0_performance6(); +// tcg_gen_helper_1_0(do_mfc0_performance6, t0); rn = "Performance6"; // break; case 7: -// gen_op_mfc0_performance7(); +// tcg_gen_helper_1_0(do_mfc0_performance7, t0); rn = "Performance7"; // break; default: @@ -2587,14 +3284,14 @@ case 2: case 4: case 6: - gen_op_mfc0_taglo(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_TagLo)); rn = "TagLo"; break; case 1: case 3: case 5: case 7: - gen_op_mfc0_datalo(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_DataLo)); rn = "DataLo"; break; default: @@ -2607,14 +3304,14 @@ case 2: case 4: case 6: - gen_op_mfc0_taghi(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_TagHi)); rn = "TagHi"; break; case 1: case 3: case 5: case 7: - gen_op_mfc0_datahi(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_DataHi)); rn = "DataHi"; break; default: @@ -2624,7 +3321,8 @@ case 30: switch (sel) { case 0: - gen_op_mfc0_errorepc(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_ErrorEPC)); + tcg_gen_ext32s_tl(t0, t0); rn = "ErrorEPC"; break; default: @@ -2634,7 +3332,8 @@ case 31: switch (sel) { case 0: - gen_op_mfc0_desave(); /* EJTAG support */ + /* EJTAG support */ + gen_mfc0_load32(t0, offsetof(CPUState, CP0_DESAVE)); rn = "DESAVE"; break; default: @@ -2662,23 +3361,26 @@ generate_exception(ctx, EXCP_RI); } -static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) +static void gen_mtc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int sel) { const char *rn = "invalid"; if (sel != 0) check_insn(env, ctx, ISA_MIPS32); + if (use_icount) + gen_io_start(); + switch (reg) { case 0: switch (sel) { case 0: - gen_op_mtc0_index(); + tcg_gen_helper_0_1(do_mtc0_index, t0); rn = "Index"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_mvpcontrol(); + tcg_gen_helper_0_1(do_mtc0_mvpcontrol, t0); rn = "MVPControl"; break; case 2: @@ -2703,37 +3405,37 @@ break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpecontrol(); + tcg_gen_helper_0_1(do_mtc0_vpecontrol, t0); rn = "VPEControl"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeconf0(); + tcg_gen_helper_0_1(do_mtc0_vpeconf0, t0); rn = "VPEConf0"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeconf1(); + tcg_gen_helper_0_1(do_mtc0_vpeconf1, t0); rn = "VPEConf1"; break; case 4: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_yqmask(); + tcg_gen_helper_0_1(do_mtc0_yqmask, t0); rn = "YQMask"; break; case 5: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeschedule(); + gen_mtc0_store64(t0, offsetof(CPUState, CP0_VPESchedule)); rn = "VPESchedule"; break; case 6: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeschefback(); + gen_mtc0_store64(t0, offsetof(CPUState, CP0_VPEScheFBack)); rn = "VPEScheFBack"; break; case 7: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeopt(); + tcg_gen_helper_0_1(do_mtc0_vpeopt, t0); rn = "VPEOpt"; break; default: @@ -2743,42 +3445,42 @@ case 2: switch (sel) { case 0: - gen_op_mtc0_entrylo0(); + tcg_gen_helper_0_1(do_mtc0_entrylo0, t0); rn = "EntryLo0"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcstatus(); + tcg_gen_helper_0_1(do_mtc0_tcstatus, t0); rn = "TCStatus"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcbind(); + tcg_gen_helper_0_1(do_mtc0_tcbind, t0); rn = "TCBind"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcrestart(); + tcg_gen_helper_0_1(do_mtc0_tcrestart, t0); rn = "TCRestart"; break; case 4: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tchalt(); + tcg_gen_helper_0_1(do_mtc0_tchalt, t0); rn = "TCHalt"; break; case 5: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tccontext(); + tcg_gen_helper_0_1(do_mtc0_tccontext, t0); rn = "TCContext"; break; case 6: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcschedule(); + tcg_gen_helper_0_1(do_mtc0_tcschedule, t0); rn = "TCSchedule"; break; case 7: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcschefback(); + tcg_gen_helper_0_1(do_mtc0_tcschefback, t0); rn = "TCScheFBack"; break; default: @@ -2788,7 +3490,7 @@ case 3: switch (sel) { case 0: - gen_op_mtc0_entrylo1(); + tcg_gen_helper_0_1(do_mtc0_entrylo1, t0); rn = "EntryLo1"; break; default: @@ -2798,11 +3500,11 @@ case 4: switch (sel) { case 0: - gen_op_mtc0_context(); + tcg_gen_helper_0_1(do_mtc0_context, t0); rn = "Context"; break; case 1: -// gen_op_mtc0_contextconfig(); /* SmartMIPS ASE */ +// tcg_gen_helper_0_1(do_mtc0_contextconfig, t0); /* SmartMIPS ASE */ rn = "ContextConfig"; // break; default: @@ -2812,12 +3514,12 @@ case 5: switch (sel) { case 0: - gen_op_mtc0_pagemask(); + tcg_gen_helper_0_1(do_mtc0_pagemask, t0); rn = "PageMask"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_pagegrain(); + tcg_gen_helper_0_1(do_mtc0_pagegrain, t0); rn = "PageGrain"; break; default: @@ -2827,32 +3529,32 @@ case 6: switch (sel) { case 0: - gen_op_mtc0_wired(); + tcg_gen_helper_0_1(do_mtc0_wired, t0); rn = "Wired"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf0(); + tcg_gen_helper_0_1(do_mtc0_srsconf0, t0); rn = "SRSConf0"; break; case 2: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf1(); + tcg_gen_helper_0_1(do_mtc0_srsconf1, t0); rn = "SRSConf1"; break; case 3: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf2(); + tcg_gen_helper_0_1(do_mtc0_srsconf2, t0); rn = "SRSConf2"; break; case 4: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf3(); + tcg_gen_helper_0_1(do_mtc0_srsconf3, t0); rn = "SRSConf3"; break; case 5: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf4(); + tcg_gen_helper_0_1(do_mtc0_srsconf4, t0); rn = "SRSConf4"; break; default: @@ -2863,7 +3565,7 @@ switch (sel) { case 0: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_hwrena(); + tcg_gen_helper_0_1(do_mtc0_hwrena, t0); rn = "HWREna"; break; default: @@ -2872,12 +3574,12 @@ break; case 8: /* ignored */ - rn = "BadVaddr"; + rn = "BadVAddr"; break; case 9: switch (sel) { case 0: - gen_op_mtc0_count(); + tcg_gen_helper_0_1(do_mtc0_count, t0); rn = "Count"; break; /* 6,7 are implementation dependent */ @@ -2890,7 +3592,7 @@ case 10: switch (sel) { case 0: - gen_op_mtc0_entryhi(); + tcg_gen_helper_0_1(do_mtc0_entryhi, t0); rn = "EntryHi"; break; default: @@ -2900,7 +3602,7 @@ case 11: switch (sel) { case 0: - gen_op_mtc0_compare(); + tcg_gen_helper_0_1(do_mtc0_compare, t0); rn = "Compare"; break; /* 6,7 are implementation dependent */ @@ -2913,7 +3615,7 @@ case 12: switch (sel) { case 0: - gen_op_mtc0_status(); + tcg_gen_helper_0_1(do_mtc0_status, t0); /* BS_STOP isn't good enough here, hflags may have changed. */ gen_save_pc(ctx->pc + 4); ctx->bstate = BS_EXCP; @@ -2921,21 +3623,21 @@ break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_intctl(); + tcg_gen_helper_0_1(do_mtc0_intctl, t0); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "IntCtl"; break; case 2: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsctl(); + tcg_gen_helper_0_1(do_mtc0_srsctl, t0); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "SRSCtl"; break; case 3: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsmap(); + gen_mtc0_store32(t0, offsetof(CPUState, CP0_SRSMap)); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "SRSMap"; @@ -2947,7 +3649,7 @@ case 13: switch (sel) { case 0: - gen_op_mtc0_cause(); + tcg_gen_helper_0_1(do_mtc0_cause, t0); rn = "Cause"; break; default: @@ -2959,7 +3661,7 @@ case 14: switch (sel) { case 0: - gen_op_mtc0_epc(); + gen_mtc0_store64(t0, offsetof(CPUState, CP0_EPC)); rn = "EPC"; break; default: @@ -2974,7 +3676,7 @@ break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_ebase(); + tcg_gen_helper_0_1(do_mtc0_ebase, t0); rn = "EBase"; break; default: @@ -2984,7 +3686,7 @@ case 16: switch (sel) { case 0: - gen_op_mtc0_config0(); + tcg_gen_helper_0_1(do_mtc0_config0, t0); rn = "Config"; /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -2994,7 +3696,7 @@ rn = "Config1"; break; case 2: - gen_op_mtc0_config2(); + tcg_gen_helper_0_1(do_mtc0_config2, t0); rn = "Config2"; /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -3031,7 +3733,7 @@ case 18: switch (sel) { case 0 ... 7: - gen_op_mtc0_watchlo(sel); + tcg_gen_helper_0_1i(do_mtc0_watchlo, t0, sel); rn = "WatchLo"; break; default: @@ -3041,7 +3743,7 @@ case 19: switch (sel) { case 0 ... 7: - gen_op_mtc0_watchhi(sel); + tcg_gen_helper_0_1i(do_mtc0_watchhi, t0, sel); rn = "WatchHi"; break; default: @@ -3053,7 +3755,7 @@ case 0: #if defined(TARGET_MIPS64) check_insn(env, ctx, ISA_MIPS3); - gen_op_mtc0_xcontext(); + tcg_gen_helper_0_1(do_mtc0_xcontext, t0); rn = "XContext"; break; #endif @@ -3065,7 +3767,7 @@ /* Officially reserved, but sel 0 is used for R1x000 framemask */ switch (sel) { case 0: - gen_op_mtc0_framemask(); + tcg_gen_helper_0_1(do_mtc0_framemask, t0); rn = "Framemask"; break; default: @@ -3079,20 +3781,20 @@ case 23: switch (sel) { case 0: - gen_op_mtc0_debug(); /* EJTAG support */ + tcg_gen_helper_0_1(do_mtc0_debug, t0); /* EJTAG support */ /* BS_STOP isn't good enough here, hflags may have changed. */ gen_save_pc(ctx->pc + 4); ctx->bstate = BS_EXCP; rn = "Debug"; break; case 1: -// gen_op_mtc0_tracecontrol(); /* PDtrace support */ +// tcg_gen_helper_0_1(do_mtc0_tracecontrol, t0); /* PDtrace support */ rn = "TraceControl"; /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; // break; case 2: -// gen_op_mtc0_tracecontrol2(); /* PDtrace support */ +// tcg_gen_helper_0_1(do_mtc0_tracecontrol2, t0); /* PDtrace support */ rn = "TraceControl2"; /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -3100,13 +3802,13 @@ case 3: /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; -// gen_op_mtc0_usertracedata(); /* PDtrace support */ +// tcg_gen_helper_0_1(do_mtc0_usertracedata, t0); /* PDtrace support */ rn = "UserTraceData"; /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; // break; case 4: -// gen_op_mtc0_debug(); /* PDtrace support */ +// tcg_gen_helper_0_1(do_mtc0_tracebpc, t0); /* PDtrace support */ /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "TraceBPC"; @@ -3118,7 +3820,8 @@ case 24: switch (sel) { case 0: - gen_op_mtc0_depc(); /* EJTAG support */ + /* EJTAG support */ + gen_mtc0_store64(t0, offsetof(CPUState, CP0_DEPC)); rn = "DEPC"; break; default: @@ -3128,35 +3831,35 @@ case 25: switch (sel) { case 0: - gen_op_mtc0_performance0(); + tcg_gen_helper_0_1(do_mtc0_performance0, t0); rn = "Performance0"; break; case 1: -// gen_op_mtc0_performance1(); +// tcg_gen_helper_0_1(do_mtc0_performance1, t0); rn = "Performance1"; // break; case 2: -// gen_op_mtc0_performance2(); +// tcg_gen_helper_0_1(do_mtc0_performance2, t0); rn = "Performance2"; // break; case 3: -// gen_op_mtc0_performance3(); +// tcg_gen_helper_0_1(do_mtc0_performance3, t0); rn = "Performance3"; // break; case 4: -// gen_op_mtc0_performance4(); +// tcg_gen_helper_0_1(do_mtc0_performance4, t0); rn = "Performance4"; // break; case 5: -// gen_op_mtc0_performance5(); +// tcg_gen_helper_0_1(do_mtc0_performance5, t0); rn = "Performance5"; // break; case 6: -// gen_op_mtc0_performance6(); +// tcg_gen_helper_0_1(do_mtc0_performance6, t0); rn = "Performance6"; // break; case 7: -// gen_op_mtc0_performance7(); +// tcg_gen_helper_0_1(do_mtc0_performance7, t0); rn = "Performance7"; // break; default: @@ -3183,14 +3886,14 @@ case 2: case 4: case 6: - gen_op_mtc0_taglo(); + tcg_gen_helper_0_1(do_mtc0_taglo, t0); rn = "TagLo"; break; case 1: case 3: case 5: case 7: - gen_op_mtc0_datalo(); + tcg_gen_helper_0_1(do_mtc0_datalo, t0); rn = "DataLo"; break; default: @@ -3203,14 +3906,14 @@ case 2: case 4: case 6: - gen_op_mtc0_taghi(); + tcg_gen_helper_0_1(do_mtc0_taghi, t0); rn = "TagHi"; break; case 1: case 3: case 5: case 7: - gen_op_mtc0_datahi(); + tcg_gen_helper_0_1(do_mtc0_datahi, t0); rn = "DataHi"; break; default: @@ -3221,7 +3924,7 @@ case 30: switch (sel) { case 0: - gen_op_mtc0_errorepc(); + gen_mtc0_store64(t0, offsetof(CPUState, CP0_ErrorEPC)); rn = "ErrorEPC"; break; default: @@ -3231,7 +3934,8 @@ case 31: switch (sel) { case 0: - gen_op_mtc0_desave(); /* EJTAG support */ + /* EJTAG support */ + gen_mtc0_store32(t0, offsetof(CPUState, CP0_DESAVE)); rn = "DESAVE"; break; default: @@ -3249,6 +3953,11 @@ rn, reg, sel); } #endif + /* For simplicity assume that all writes can cause interrupts. */ + if (use_icount) { + gen_io_end(); + ctx->bstate = BS_STOP; + } return; die: @@ -3262,7 +3971,7 @@ } #if defined(TARGET_MIPS64) -static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) +static void gen_dmfc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int sel) { const char *rn = "invalid"; @@ -3273,22 +3982,22 @@ case 0: switch (sel) { case 0: - gen_op_mfc0_index(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Index)); rn = "Index"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_mvpcontrol(); + tcg_gen_helper_1_0(do_mfc0_mvpcontrol, t0); rn = "MVPControl"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_mvpconf0(); + tcg_gen_helper_1_0(do_mfc0_mvpconf0, t0); rn = "MVPConf0"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_mvpconf1(); + tcg_gen_helper_1_0(do_mfc0_mvpconf1, t0); rn = "MVPConf1"; break; default: @@ -3298,42 +4007,42 @@ case 1: switch (sel) { case 0: - gen_op_mfc0_random(); + tcg_gen_helper_1_0(do_mfc0_random, t0); rn = "Random"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpecontrol(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_VPEControl)); rn = "VPEControl"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpeconf0(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_VPEConf0)); rn = "VPEConf0"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpeconf1(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_VPEConf1)); rn = "VPEConf1"; break; case 4: check_insn(env, ctx, ASE_MT); - gen_op_dmfc0_yqmask(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_YQMask)); rn = "YQMask"; break; case 5: check_insn(env, ctx, ASE_MT); - gen_op_dmfc0_vpeschedule(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_VPESchedule)); rn = "VPESchedule"; break; case 6: check_insn(env, ctx, ASE_MT); - gen_op_dmfc0_vpeschefback(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_VPEScheFBack)); rn = "VPEScheFBack"; break; case 7: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpeopt(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_VPEOpt)); rn = "VPEOpt"; break; default: @@ -3343,42 +4052,42 @@ case 2: switch (sel) { case 0: - gen_op_dmfc0_entrylo0(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_EntryLo0)); rn = "EntryLo0"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_tcstatus(); + tcg_gen_helper_1_0(do_mfc0_tcstatus, t0); rn = "TCStatus"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_tcbind(); + tcg_gen_helper_1_0(do_mfc0_tcbind, t0); rn = "TCBind"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_dmfc0_tcrestart(); + tcg_gen_helper_1_0(do_dmfc0_tcrestart, t0); rn = "TCRestart"; break; case 4: check_insn(env, ctx, ASE_MT); - gen_op_dmfc0_tchalt(); + tcg_gen_helper_1_0(do_dmfc0_tchalt, t0); rn = "TCHalt"; break; case 5: check_insn(env, ctx, ASE_MT); - gen_op_dmfc0_tccontext(); + tcg_gen_helper_1_0(do_dmfc0_tccontext, t0); rn = "TCContext"; break; case 6: check_insn(env, ctx, ASE_MT); - gen_op_dmfc0_tcschedule(); + tcg_gen_helper_1_0(do_dmfc0_tcschedule, t0); rn = "TCSchedule"; break; case 7: check_insn(env, ctx, ASE_MT); - gen_op_dmfc0_tcschefback(); + tcg_gen_helper_1_0(do_dmfc0_tcschefback, t0); rn = "TCScheFBack"; break; default: @@ -3388,7 +4097,7 @@ case 3: switch (sel) { case 0: - gen_op_dmfc0_entrylo1(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_EntryLo1)); rn = "EntryLo1"; break; default: @@ -3398,11 +4107,11 @@ case 4: switch (sel) { case 0: - gen_op_dmfc0_context(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_Context)); rn = "Context"; break; case 1: -// gen_op_dmfc0_contextconfig(); /* SmartMIPS ASE */ +// tcg_gen_helper_1_0(do_dmfc0_contextconfig, t0); /* SmartMIPS ASE */ rn = "ContextConfig"; // break; default: @@ -3412,12 +4121,12 @@ case 5: switch (sel) { case 0: - gen_op_mfc0_pagemask(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_PageMask)); rn = "PageMask"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_pagegrain(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_PageGrain)); rn = "PageGrain"; break; default: @@ -3427,32 +4136,32 @@ case 6: switch (sel) { case 0: - gen_op_mfc0_wired(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Wired)); rn = "Wired"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf0(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_SRSConf0)); rn = "SRSConf0"; break; case 2: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf1(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_SRSConf1)); rn = "SRSConf1"; break; case 3: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf2(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_SRSConf2)); rn = "SRSConf2"; break; case 4: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf3(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_SRSConf3)); rn = "SRSConf3"; break; case 5: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf4(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_SRSConf4)); rn = "SRSConf4"; break; default: @@ -3463,7 +4172,7 @@ switch (sel) { case 0: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_hwrena(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_HWREna)); rn = "HWREna"; break; default: @@ -3473,8 +4182,8 @@ case 8: switch (sel) { case 0: - gen_op_dmfc0_badvaddr(); - rn = "BadVaddr"; + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_BadVAddr)); + rn = "BadVAddr"; break; default: goto die; @@ -3483,7 +4192,14 @@ case 9: switch (sel) { case 0: - gen_op_mfc0_count(); + /* Mark as an IO operation because we read the time. */ + if (use_icount) + gen_io_start(); + tcg_gen_helper_1_0(do_mfc0_count, t0); + if (use_icount) { + gen_io_end(); + ctx->bstate = BS_STOP; + } rn = "Count"; break; /* 6,7 are implementation dependent */ @@ -3494,7 +4210,7 @@ case 10: switch (sel) { case 0: - gen_op_dmfc0_entryhi(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_EntryHi)); rn = "EntryHi"; break; default: @@ -3504,7 +4220,7 @@ case 11: switch (sel) { case 0: - gen_op_mfc0_compare(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Compare)); rn = "Compare"; break; /* 6,7 are implementation dependent */ @@ -3515,22 +4231,22 @@ case 12: switch (sel) { case 0: - gen_op_mfc0_status(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Status)); rn = "Status"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_intctl(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_IntCtl)); rn = "IntCtl"; break; case 2: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsctl(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_SRSCtl)); rn = "SRSCtl"; break; case 3: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsmap(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_SRSMap)); rn = "SRSMap"; break; default: @@ -3540,7 +4256,7 @@ case 13: switch (sel) { case 0: - gen_op_mfc0_cause(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Cause)); rn = "Cause"; break; default: @@ -3550,7 +4266,7 @@ case 14: switch (sel) { case 0: - gen_op_dmfc0_epc(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_EPC)); rn = "EPC"; break; default: @@ -3560,12 +4276,12 @@ case 15: switch (sel) { case 0: - gen_op_mfc0_prid(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_PRid)); rn = "PRid"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_ebase(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_EBase)); rn = "EBase"; break; default: @@ -3575,22 +4291,30 @@ case 16: switch (sel) { case 0: - gen_op_mfc0_config0(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Config0)); rn = "Config"; break; case 1: - gen_op_mfc0_config1(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Config1)); rn = "Config1"; break; case 2: - gen_op_mfc0_config2(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Config2)); rn = "Config2"; break; case 3: - gen_op_mfc0_config3(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Config3)); rn = "Config3"; break; /* 6,7 are implementation dependent */ + case 6: + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Config6)); + rn = "Config6"; + break; + case 7: + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Config7)); + rn = "Config7"; + break; default: goto die; } @@ -3598,7 +4322,7 @@ case 17: switch (sel) { case 0: - gen_op_dmfc0_lladdr(); + tcg_gen_helper_1_0(do_dmfc0_lladdr, t0); rn = "LLAddr"; break; default: @@ -3608,7 +4332,7 @@ case 18: switch (sel) { case 0 ... 7: - gen_op_dmfc0_watchlo(sel); + tcg_gen_helper_1_i(do_dmfc0_watchlo, t0, sel); rn = "WatchLo"; break; default: @@ -3618,7 +4342,7 @@ case 19: switch (sel) { case 0 ... 7: - gen_op_mfc0_watchhi(sel); + tcg_gen_helper_1_i(do_mfc0_watchhi, t0, sel); rn = "WatchHi"; break; default: @@ -3629,7 +4353,7 @@ switch (sel) { case 0: check_insn(env, ctx, ISA_MIPS3); - gen_op_dmfc0_xcontext(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_XContext)); rn = "XContext"; break; default: @@ -3640,7 +4364,7 @@ /* Officially reserved, but sel 0 is used for R1x000 framemask */ switch (sel) { case 0: - gen_op_mfc0_framemask(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Framemask)); rn = "Framemask"; break; default: @@ -3654,23 +4378,23 @@ case 23: switch (sel) { case 0: - gen_op_mfc0_debug(); /* EJTAG support */ + tcg_gen_helper_1_0(do_mfc0_debug, t0); /* EJTAG support */ rn = "Debug"; break; case 1: -// gen_op_dmfc0_tracecontrol(); /* PDtrace support */ +// tcg_gen_helper_1_0(do_dmfc0_tracecontrol, t0); /* PDtrace support */ rn = "TraceControl"; // break; case 2: -// gen_op_dmfc0_tracecontrol2(); /* PDtrace support */ +// tcg_gen_helper_1_0(do_dmfc0_tracecontrol2, t0); /* PDtrace support */ rn = "TraceControl2"; // break; case 3: -// gen_op_dmfc0_usertracedata(); /* PDtrace support */ +// tcg_gen_helper_1_0(do_dmfc0_usertracedata, t0); /* PDtrace support */ rn = "UserTraceData"; // break; case 4: -// gen_op_dmfc0_debug(); /* PDtrace support */ +// tcg_gen_helper_1_0(do_dmfc0_tracebpc, t0); /* PDtrace support */ rn = "TraceBPC"; // break; default: @@ -3680,7 +4404,8 @@ case 24: switch (sel) { case 0: - gen_op_dmfc0_depc(); /* EJTAG support */ + /* EJTAG support */ + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_DEPC)); rn = "DEPC"; break; default: @@ -3690,35 +4415,35 @@ case 25: switch (sel) { case 0: - gen_op_mfc0_performance0(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_Performance0)); rn = "Performance0"; break; case 1: -// gen_op_dmfc0_performance1(); +// tcg_gen_helper_1_0(do_dmfc0_performance1, t0); rn = "Performance1"; // break; case 2: -// gen_op_dmfc0_performance2(); +// tcg_gen_helper_1_0(do_dmfc0_performance2, t0); rn = "Performance2"; // break; case 3: -// gen_op_dmfc0_performance3(); +// tcg_gen_helper_1_0(do_dmfc0_performance3, t0); rn = "Performance3"; // break; case 4: -// gen_op_dmfc0_performance4(); +// tcg_gen_helper_1_0(do_dmfc0_performance4, t0); rn = "Performance4"; // break; case 5: -// gen_op_dmfc0_performance5(); +// tcg_gen_helper_1_0(do_dmfc0_performance5, t0); rn = "Performance5"; // break; case 6: -// gen_op_dmfc0_performance6(); +// tcg_gen_helper_1_0(do_dmfc0_performance6, t0); rn = "Performance6"; // break; case 7: -// gen_op_dmfc0_performance7(); +// tcg_gen_helper_1_0(do_dmfc0_performance7, t0); rn = "Performance7"; // break; default: @@ -3744,14 +4469,14 @@ case 2: case 4: case 6: - gen_op_mfc0_taglo(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_TagLo)); rn = "TagLo"; break; case 1: case 3: case 5: case 7: - gen_op_mfc0_datalo(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_DataLo)); rn = "DataLo"; break; default: @@ -3764,14 +4489,14 @@ case 2: case 4: case 6: - gen_op_mfc0_taghi(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_TagHi)); rn = "TagHi"; break; case 1: case 3: case 5: case 7: - gen_op_mfc0_datahi(); + gen_mfc0_load32(t0, offsetof(CPUState, CP0_DataHi)); rn = "DataHi"; break; default: @@ -3781,7 +4506,7 @@ case 30: switch (sel) { case 0: - gen_op_dmfc0_errorepc(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_ErrorEPC)); rn = "ErrorEPC"; break; default: @@ -3791,7 +4516,8 @@ case 31: switch (sel) { case 0: - gen_op_mfc0_desave(); /* EJTAG support */ + /* EJTAG support */ + gen_mfc0_load32(t0, offsetof(CPUState, CP0_DESAVE)); rn = "DESAVE"; break; default: @@ -3819,23 +4545,26 @@ generate_exception(ctx, EXCP_RI); } -static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) +static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int sel) { const char *rn = "invalid"; if (sel != 0) check_insn(env, ctx, ISA_MIPS64); + if (use_icount) + gen_io_start(); + switch (reg) { case 0: switch (sel) { case 0: - gen_op_mtc0_index(); + tcg_gen_helper_0_1(do_mtc0_index, t0); rn = "Index"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_mvpcontrol(); + tcg_gen_helper_0_1(do_mtc0_mvpcontrol, t0); rn = "MVPControl"; break; case 2: @@ -3860,37 +4589,37 @@ break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpecontrol(); + tcg_gen_helper_0_1(do_mtc0_vpecontrol, t0); rn = "VPEControl"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeconf0(); + tcg_gen_helper_0_1(do_mtc0_vpeconf0, t0); rn = "VPEConf0"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeconf1(); + tcg_gen_helper_0_1(do_mtc0_vpeconf1, t0); rn = "VPEConf1"; break; case 4: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_yqmask(); + tcg_gen_helper_0_1(do_mtc0_yqmask, t0); rn = "YQMask"; break; case 5: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeschedule(); + tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, CP0_VPESchedule)); rn = "VPESchedule"; break; case 6: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeschefback(); + tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, CP0_VPEScheFBack)); rn = "VPEScheFBack"; break; case 7: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeopt(); + tcg_gen_helper_0_1(do_mtc0_vpeopt, t0); rn = "VPEOpt"; break; default: @@ -3900,42 +4629,42 @@ case 2: switch (sel) { case 0: - gen_op_mtc0_entrylo0(); + tcg_gen_helper_0_1(do_mtc0_entrylo0, t0); rn = "EntryLo0"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcstatus(); + tcg_gen_helper_0_1(do_mtc0_tcstatus, t0); rn = "TCStatus"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcbind(); + tcg_gen_helper_0_1(do_mtc0_tcbind, t0); rn = "TCBind"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcrestart(); + tcg_gen_helper_0_1(do_mtc0_tcrestart, t0); rn = "TCRestart"; break; case 4: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tchalt(); + tcg_gen_helper_0_1(do_mtc0_tchalt, t0); rn = "TCHalt"; break; case 5: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tccontext(); + tcg_gen_helper_0_1(do_mtc0_tccontext, t0); rn = "TCContext"; break; case 6: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcschedule(); + tcg_gen_helper_0_1(do_mtc0_tcschedule, t0); rn = "TCSchedule"; break; case 7: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcschefback(); + tcg_gen_helper_0_1(do_mtc0_tcschefback, t0); rn = "TCScheFBack"; break; default: @@ -3945,7 +4674,7 @@ case 3: switch (sel) { case 0: - gen_op_mtc0_entrylo1(); + tcg_gen_helper_0_1(do_mtc0_entrylo1, t0); rn = "EntryLo1"; break; default: @@ -3955,11 +4684,11 @@ case 4: switch (sel) { case 0: - gen_op_mtc0_context(); + tcg_gen_helper_0_1(do_mtc0_context, t0); rn = "Context"; break; case 1: -// gen_op_mtc0_contextconfig(); /* SmartMIPS ASE */ +// tcg_gen_helper_0_1(do_mtc0_contextconfig, t0); /* SmartMIPS ASE */ rn = "ContextConfig"; // break; default: @@ -3969,12 +4698,12 @@ case 5: switch (sel) { case 0: - gen_op_mtc0_pagemask(); + tcg_gen_helper_0_1(do_mtc0_pagemask, t0); rn = "PageMask"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_pagegrain(); + tcg_gen_helper_0_1(do_mtc0_pagegrain, t0); rn = "PageGrain"; break; default: @@ -3984,32 +4713,32 @@ case 6: switch (sel) { case 0: - gen_op_mtc0_wired(); + tcg_gen_helper_0_1(do_mtc0_wired, t0); rn = "Wired"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf0(); + tcg_gen_helper_0_1(do_mtc0_srsconf0, t0); rn = "SRSConf0"; break; case 2: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf1(); + tcg_gen_helper_0_1(do_mtc0_srsconf1, t0); rn = "SRSConf1"; break; case 3: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf2(); + tcg_gen_helper_0_1(do_mtc0_srsconf2, t0); rn = "SRSConf2"; break; case 4: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf3(); + tcg_gen_helper_0_1(do_mtc0_srsconf3, t0); rn = "SRSConf3"; break; case 5: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf4(); + tcg_gen_helper_0_1(do_mtc0_srsconf4, t0); rn = "SRSConf4"; break; default: @@ -4020,7 +4749,7 @@ switch (sel) { case 0: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_hwrena(); + tcg_gen_helper_0_1(do_mtc0_hwrena, t0); rn = "HWREna"; break; default: @@ -4029,12 +4758,12 @@ break; case 8: /* ignored */ - rn = "BadVaddr"; + rn = "BadVAddr"; break; case 9: switch (sel) { case 0: - gen_op_mtc0_count(); + tcg_gen_helper_0_1(do_mtc0_count, t0); rn = "Count"; break; /* 6,7 are implementation dependent */ @@ -4047,7 +4776,7 @@ case 10: switch (sel) { case 0: - gen_op_mtc0_entryhi(); + tcg_gen_helper_0_1(do_mtc0_entryhi, t0); rn = "EntryHi"; break; default: @@ -4057,7 +4786,7 @@ case 11: switch (sel) { case 0: - gen_op_mtc0_compare(); + tcg_gen_helper_0_1(do_mtc0_compare, t0); rn = "Compare"; break; /* 6,7 are implementation dependent */ @@ -4070,7 +4799,7 @@ case 12: switch (sel) { case 0: - gen_op_mtc0_status(); + tcg_gen_helper_0_1(do_mtc0_status, t0); /* BS_STOP isn't good enough here, hflags may have changed. */ gen_save_pc(ctx->pc + 4); ctx->bstate = BS_EXCP; @@ -4078,21 +4807,21 @@ break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_intctl(); + tcg_gen_helper_0_1(do_mtc0_intctl, t0); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "IntCtl"; break; case 2: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsctl(); + tcg_gen_helper_0_1(do_mtc0_srsctl, t0); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "SRSCtl"; break; case 3: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsmap(); + gen_mtc0_store32(t0, offsetof(CPUState, CP0_SRSMap)); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "SRSMap"; @@ -4104,7 +4833,7 @@ case 13: switch (sel) { case 0: - gen_op_mtc0_cause(); + tcg_gen_helper_0_1(do_mtc0_cause, t0); rn = "Cause"; break; default: @@ -4116,7 +4845,7 @@ case 14: switch (sel) { case 0: - gen_op_mtc0_epc(); + tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, CP0_EPC)); rn = "EPC"; break; default: @@ -4131,7 +4860,7 @@ break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_ebase(); + tcg_gen_helper_0_1(do_mtc0_ebase, t0); rn = "EBase"; break; default: @@ -4141,7 +4870,7 @@ case 16: switch (sel) { case 0: - gen_op_mtc0_config0(); + tcg_gen_helper_0_1(do_mtc0_config0, t0); rn = "Config"; /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -4151,7 +4880,7 @@ rn = "Config1"; break; case 2: - gen_op_mtc0_config2(); + tcg_gen_helper_0_1(do_mtc0_config2, t0); rn = "Config2"; /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -4179,7 +4908,7 @@ case 18: switch (sel) { case 0 ... 7: - gen_op_mtc0_watchlo(sel); + tcg_gen_helper_0_1i(do_mtc0_watchlo, t0, sel); rn = "WatchLo"; break; default: @@ -4189,7 +4918,7 @@ case 19: switch (sel) { case 0 ... 7: - gen_op_mtc0_watchhi(sel); + tcg_gen_helper_0_1i(do_mtc0_watchhi, t0, sel); rn = "WatchHi"; break; default: @@ -4200,7 +4929,7 @@ switch (sel) { case 0: check_insn(env, ctx, ISA_MIPS3); - gen_op_mtc0_xcontext(); + tcg_gen_helper_0_1(do_mtc0_xcontext, t0); rn = "XContext"; break; default: @@ -4211,7 +4940,7 @@ /* Officially reserved, but sel 0 is used for R1x000 framemask */ switch (sel) { case 0: - gen_op_mtc0_framemask(); + tcg_gen_helper_0_1(do_mtc0_framemask, t0); rn = "Framemask"; break; default: @@ -4225,32 +4954,32 @@ case 23: switch (sel) { case 0: - gen_op_mtc0_debug(); /* EJTAG support */ + tcg_gen_helper_0_1(do_mtc0_debug, t0); /* EJTAG support */ /* BS_STOP isn't good enough here, hflags may have changed. */ gen_save_pc(ctx->pc + 4); ctx->bstate = BS_EXCP; rn = "Debug"; break; case 1: -// gen_op_mtc0_tracecontrol(); /* PDtrace support */ +// tcg_gen_helper_0_1(do_mtc0_tracecontrol, t0); /* PDtrace support */ /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "TraceControl"; // break; case 2: -// gen_op_mtc0_tracecontrol2(); /* PDtrace support */ +// tcg_gen_helper_0_1(do_mtc0_tracecontrol2, t0); /* PDtrace support */ /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "TraceControl2"; // break; case 3: -// gen_op_mtc0_usertracedata(); /* PDtrace support */ +// tcg_gen_helper_0_1(do_mtc0_usertracedata, t0); /* PDtrace support */ /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "UserTraceData"; // break; case 4: -// gen_op_mtc0_debug(); /* PDtrace support */ +// tcg_gen_helper_0_1(do_mtc0_tracebpc, t0); /* PDtrace support */ /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "TraceBPC"; @@ -4262,7 +4991,8 @@ case 24: switch (sel) { case 0: - gen_op_mtc0_depc(); /* EJTAG support */ + /* EJTAG support */ + tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, CP0_DEPC)); rn = "DEPC"; break; default: @@ -4272,35 +5002,35 @@ case 25: switch (sel) { case 0: - gen_op_mtc0_performance0(); + tcg_gen_helper_0_1(do_mtc0_performance0, t0); rn = "Performance0"; break; case 1: -// gen_op_mtc0_performance1(); +// tcg_gen_helper_0_1(do_mtc0_performance1, t0); rn = "Performance1"; // break; case 2: -// gen_op_mtc0_performance2(); +// tcg_gen_helper_0_1(do_mtc0_performance2, t0); rn = "Performance2"; // break; case 3: -// gen_op_mtc0_performance3(); +// tcg_gen_helper_0_1(do_mtc0_performance3, t0); rn = "Performance3"; // break; case 4: -// gen_op_mtc0_performance4(); +// tcg_gen_helper_0_1(do_mtc0_performance4, t0); rn = "Performance4"; // break; case 5: -// gen_op_mtc0_performance5(); +// tcg_gen_helper_0_1(do_mtc0_performance5, t0); rn = "Performance5"; // break; case 6: -// gen_op_mtc0_performance6(); +// tcg_gen_helper_0_1(do_mtc0_performance6, t0); rn = "Performance6"; // break; case 7: -// gen_op_mtc0_performance7(); +// tcg_gen_helper_0_1(do_mtc0_performance7, t0); rn = "Performance7"; // break; default: @@ -4327,14 +5057,14 @@ case 2: case 4: case 6: - gen_op_mtc0_taglo(); + tcg_gen_helper_0_1(do_mtc0_taglo, t0); rn = "TagLo"; break; case 1: case 3: case 5: case 7: - gen_op_mtc0_datalo(); + tcg_gen_helper_0_1(do_mtc0_datalo, t0); rn = "DataLo"; break; default: @@ -4347,14 +5077,14 @@ case 2: case 4: case 6: - gen_op_mtc0_taghi(); + tcg_gen_helper_0_1(do_mtc0_taghi, t0); rn = "TagHi"; break; case 1: case 3: case 5: case 7: - gen_op_mtc0_datahi(); + tcg_gen_helper_0_1(do_mtc0_datahi, t0); rn = "DataHi"; break; default: @@ -4365,7 +5095,7 @@ case 30: switch (sel) { case 0: - gen_op_mtc0_errorepc(); + tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, CP0_ErrorEPC)); rn = "ErrorEPC"; break; default: @@ -4375,7 +5105,8 @@ case 31: switch (sel) { case 0: - gen_op_mtc0_desave(); /* EJTAG support */ + /* EJTAG support */ + gen_mtc0_store32(t0, offsetof(CPUState, CP0_DESAVE)); rn = "DESAVE"; break; default: @@ -4393,6 +5124,11 @@ rn, reg, sel); } #endif + /* For simplicity assume that all writes can cause interrupts. */ + if (use_icount) { + gen_io_end(); + ctx->bstate = BS_STOP; + } return; die: @@ -4406,125 +5142,126 @@ } #endif /* TARGET_MIPS64 */ -static void gen_mftr(CPUState *env, DisasContext *ctx, int rt, +static void gen_mftr(CPUState *env, DisasContext *ctx, int rt, int rd, int u, int sel, int h) { int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 && - ((env->CP0_TCBind[other_tc] & (0xf << CP0TCBd_CurVPE)) != - (env->CP0_TCBind[env->current_tc] & (0xf << CP0TCBd_CurVPE)))) - gen_op_set_T0(-1); + ((env->tcs[other_tc].CP0_TCBind & (0xf << CP0TCBd_CurVPE)) != + (env->active_tc.CP0_TCBind & (0xf << CP0TCBd_CurVPE)))) + tcg_gen_movi_tl(t0, -1); else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) > (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC))) - gen_op_set_T0(-1); + tcg_gen_movi_tl(t0, -1); else if (u == 0) { switch (rt) { case 2: switch (sel) { case 1: - gen_op_mftc0_tcstatus(); + tcg_gen_helper_1_0(do_mftc0_tcstatus, t0); break; case 2: - gen_op_mftc0_tcbind(); + tcg_gen_helper_1_0(do_mftc0_tcbind, t0); break; case 3: - gen_op_mftc0_tcrestart(); + tcg_gen_helper_1_0(do_mftc0_tcrestart, t0); break; case 4: - gen_op_mftc0_tchalt(); + tcg_gen_helper_1_0(do_mftc0_tchalt, t0); break; case 5: - gen_op_mftc0_tccontext(); + tcg_gen_helper_1_0(do_mftc0_tccontext, t0); break; case 6: - gen_op_mftc0_tcschedule(); + tcg_gen_helper_1_0(do_mftc0_tcschedule, t0); break; case 7: - gen_op_mftc0_tcschefback(); + tcg_gen_helper_1_0(do_mftc0_tcschefback, t0); break; default: - gen_mfc0(env, ctx, rt, sel); + gen_mfc0(env, ctx, t0, rt, sel); break; } break; case 10: switch (sel) { case 0: - gen_op_mftc0_entryhi(); + tcg_gen_helper_1_0(do_mftc0_entryhi, t0); break; default: - gen_mfc0(env, ctx, rt, sel); + gen_mfc0(env, ctx, t0, rt, sel); break; } case 12: switch (sel) { case 0: - gen_op_mftc0_status(); + tcg_gen_helper_1_0(do_mftc0_status, t0); break; default: - gen_mfc0(env, ctx, rt, sel); + gen_mfc0(env, ctx, t0, rt, sel); break; } case 23: switch (sel) { case 0: - gen_op_mftc0_debug(); + tcg_gen_helper_1_0(do_mftc0_debug, t0); break; default: - gen_mfc0(env, ctx, rt, sel); + gen_mfc0(env, ctx, t0, rt, sel); break; } break; default: - gen_mfc0(env, ctx, rt, sel); + gen_mfc0(env, ctx, t0, rt, sel); } } else switch (sel) { /* GPR registers. */ case 0: - gen_op_mftgpr(rt); + tcg_gen_helper_1_i(do_mftgpr, t0, rt); break; /* Auxiliary CPU registers */ case 1: switch (rt) { case 0: - gen_op_mftlo(0); + tcg_gen_helper_1_i(do_mftlo, t0, 0); break; case 1: - gen_op_mfthi(0); + tcg_gen_helper_1_i(do_mfthi, t0, 0); break; case 2: - gen_op_mftacx(0); + tcg_gen_helper_1_i(do_mftacx, t0, 0); break; case 4: - gen_op_mftlo(1); + tcg_gen_helper_1_i(do_mftlo, t0, 1); break; case 5: - gen_op_mfthi(1); + tcg_gen_helper_1_i(do_mfthi, t0, 1); break; case 6: - gen_op_mftacx(1); + tcg_gen_helper_1_i(do_mftacx, t0, 1); break; case 8: - gen_op_mftlo(2); + tcg_gen_helper_1_i(do_mftlo, t0, 2); break; case 9: - gen_op_mfthi(2); + tcg_gen_helper_1_i(do_mfthi, t0, 2); break; case 10: - gen_op_mftacx(2); + tcg_gen_helper_1_i(do_mftacx, t0, 2); break; case 12: - gen_op_mftlo(3); + tcg_gen_helper_1_i(do_mftlo, t0, 3); break; case 13: - gen_op_mfthi(3); + tcg_gen_helper_1_i(do_mfthi, t0, 3); break; case 14: - gen_op_mftacx(3); + tcg_gen_helper_1_i(do_mftacx, t0, 3); break; case 16: - gen_op_mftdsp(); + tcg_gen_helper_1_0(do_mftdsp, t0); break; default: goto die; @@ -4534,16 +5271,22 @@ case 2: /* XXX: For now we support only a single FPU context. */ if (h == 0) { - GEN_LOAD_FREG_FTN(WT0, rt); - gen_op_mfc1(); + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, rt); + tcg_gen_ext_i32_tl(t0, fp0); + tcg_temp_free(fp0); } else { - GEN_LOAD_FREG_FTN(WTH0, rt); - gen_op_mfhc1(); + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32h(fp0, rt); + tcg_gen_ext_i32_tl(t0, fp0); + tcg_temp_free(fp0); } break; case 3: /* XXX: For now we support only a single FPU context. */ - gen_op_cfc1(rt); + tcg_gen_helper_1_1i(do_cfc1, t0, t0, rt); break; /* COP2: Not implemented. */ case 4: @@ -4558,9 +5301,12 @@ rt, u, sel, h); } #endif + gen_store_gpr(t0, rd); + tcg_temp_free(t0); return; die: + tcg_temp_free(t0); #if defined MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "mftr (reg %d u %d sel %d h %d)\n", @@ -4570,14 +5316,16 @@ generate_exception(ctx, EXCP_RI); } -static void gen_mttr(CPUState *env, DisasContext *ctx, int rd, +static void gen_mttr(CPUState *env, DisasContext *ctx, int rd, int rt, int u, int sel, int h) { int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + gen_load_gpr(t0, rt); if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 && - ((env->CP0_TCBind[other_tc] & (0xf << CP0TCBd_CurVPE)) != - (env->CP0_TCBind[env->current_tc] & (0xf << CP0TCBd_CurVPE)))) + ((env->tcs[other_tc].CP0_TCBind & (0xf << CP0TCBd_CurVPE)) != + (env->active_tc.CP0_TCBind & (0xf << CP0TCBd_CurVPE)))) /* NOP */ ; else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) > (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC))) @@ -4587,108 +5335,108 @@ case 2: switch (sel) { case 1: - gen_op_mttc0_tcstatus(); + tcg_gen_helper_0_1(do_mttc0_tcstatus, t0); break; case 2: - gen_op_mttc0_tcbind(); + tcg_gen_helper_0_1(do_mttc0_tcbind, t0); break; case 3: - gen_op_mttc0_tcrestart(); + tcg_gen_helper_0_1(do_mttc0_tcrestart, t0); break; case 4: - gen_op_mttc0_tchalt(); + tcg_gen_helper_0_1(do_mttc0_tchalt, t0); break; case 5: - gen_op_mttc0_tccontext(); + tcg_gen_helper_0_1(do_mttc0_tccontext, t0); break; case 6: - gen_op_mttc0_tcschedule(); + tcg_gen_helper_0_1(do_mttc0_tcschedule, t0); break; case 7: - gen_op_mttc0_tcschefback(); + tcg_gen_helper_0_1(do_mttc0_tcschefback, t0); break; default: - gen_mtc0(env, ctx, rd, sel); + gen_mtc0(env, ctx, t0, rd, sel); break; } break; case 10: switch (sel) { case 0: - gen_op_mttc0_entryhi(); + tcg_gen_helper_0_1(do_mttc0_entryhi, t0); break; default: - gen_mtc0(env, ctx, rd, sel); + gen_mtc0(env, ctx, t0, rd, sel); break; } case 12: switch (sel) { case 0: - gen_op_mttc0_status(); + tcg_gen_helper_0_1(do_mttc0_status, t0); break; default: - gen_mtc0(env, ctx, rd, sel); + gen_mtc0(env, ctx, t0, rd, sel); break; } case 23: switch (sel) { case 0: - gen_op_mttc0_debug(); + tcg_gen_helper_0_1(do_mttc0_debug, t0); break; default: - gen_mtc0(env, ctx, rd, sel); + gen_mtc0(env, ctx, t0, rd, sel); break; } break; default: - gen_mtc0(env, ctx, rd, sel); + gen_mtc0(env, ctx, t0, rd, sel); } } else switch (sel) { /* GPR registers. */ case 0: - gen_op_mttgpr(rd); + tcg_gen_helper_0_1i(do_mttgpr, t0, rd); break; /* Auxiliary CPU registers */ case 1: switch (rd) { case 0: - gen_op_mttlo(0); + tcg_gen_helper_0_1i(do_mttlo, t0, 0); break; case 1: - gen_op_mtthi(0); + tcg_gen_helper_0_1i(do_mtthi, t0, 0); break; case 2: - gen_op_mttacx(0); + tcg_gen_helper_0_1i(do_mttacx, t0, 0); break; case 4: - gen_op_mttlo(1); + tcg_gen_helper_0_1i(do_mttlo, t0, 1); break; case 5: - gen_op_mtthi(1); + tcg_gen_helper_0_1i(do_mtthi, t0, 1); break; case 6: - gen_op_mttacx(1); + tcg_gen_helper_0_1i(do_mttacx, t0, 1); break; case 8: - gen_op_mttlo(2); + tcg_gen_helper_0_1i(do_mttlo, t0, 2); break; case 9: - gen_op_mtthi(2); + tcg_gen_helper_0_1i(do_mtthi, t0, 2); break; case 10: - gen_op_mttacx(2); + tcg_gen_helper_0_1i(do_mttacx, t0, 2); break; case 12: - gen_op_mttlo(3); + tcg_gen_helper_0_1i(do_mttlo, t0, 3); break; case 13: - gen_op_mtthi(3); + tcg_gen_helper_0_1i(do_mtthi, t0, 3); break; case 14: - gen_op_mttacx(3); + tcg_gen_helper_0_1i(do_mttacx, t0, 3); break; case 16: - gen_op_mttdsp(); + tcg_gen_helper_0_1(do_mttdsp, t0); break; default: goto die; @@ -4698,16 +5446,22 @@ case 2: /* XXX: For now we support only a single FPU context. */ if (h == 0) { - gen_op_mtc1(); - GEN_STORE_FTN_FREG(rd, WT0); + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_trunc_tl_i32(fp0, t0); + gen_store_fpr32(fp0, rd); + tcg_temp_free(fp0); } else { - gen_op_mthc1(); - GEN_STORE_FTN_FREG(rd, WTH0); + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_trunc_tl_i32(fp0, t0); + gen_store_fpr32h(fp0, rd); + tcg_temp_free(fp0); } break; case 3: /* XXX: For now we support only a single FPU context. */ - gen_op_ctc1(rd); + tcg_gen_helper_0_1i(do_ctc1, t0, rd); break; /* COP2: Not implemented. */ case 4: @@ -4722,9 +5476,11 @@ rd, u, sel, h); } #endif + tcg_temp_free(t0); return; die: + tcg_temp_free(t0); #if defined MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "mttr (reg %d u %d sel %d h %d)\n", @@ -4744,14 +5500,24 @@ /* Treat as NOP. */ return; } - gen_mfc0(env, ctx, rd, ctx->opcode & 0x7); - gen_op_store_T0_gpr(rt); + { + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + + gen_mfc0(env, ctx, t0, rd, ctx->opcode & 0x7); + gen_store_gpr(t0, rt); + tcg_temp_free(t0); + } opn = "mfc0"; break; case OPC_MTC0: - GEN_LOAD_REG_T0(rt); - save_cpu_state(ctx, 1); - gen_mtc0(env, ctx, rd, ctx->opcode & 0x7); + { + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + + gen_load_gpr(t0, rt); + save_cpu_state(ctx, 1); + gen_mtc0(env, ctx, t0, rd, ctx->opcode & 0x7); + tcg_temp_free(t0); + } opn = "mtc0"; break; #if defined(TARGET_MIPS64) @@ -4761,15 +5527,25 @@ /* Treat as NOP. */ return; } - gen_dmfc0(env, ctx, rd, ctx->opcode & 0x7); - gen_op_store_T0_gpr(rt); + { + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + + gen_dmfc0(env, ctx, t0, rd, ctx->opcode & 0x7); + gen_store_gpr(t0, rt); + tcg_temp_free(t0); + } opn = "dmfc0"; break; case OPC_DMTC0: check_insn(env, ctx, ISA_MIPS3); - GEN_LOAD_REG_T0(rt); - save_cpu_state(ctx, 1); - gen_dmtc0(env, ctx, rd, ctx->opcode & 0x7); + { + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + + gen_load_gpr(t0, rt); + save_cpu_state(ctx, 1); + gen_dmtc0(env, ctx, t0, rd, ctx->opcode & 0x7); + tcg_temp_free(t0); + } opn = "dmtc0"; break; #endif @@ -4779,15 +5555,13 @@ /* Treat as NOP. */ return; } - gen_mftr(env, ctx, rt, (ctx->opcode >> 5) & 1, + gen_mftr(env, ctx, rt, rd, (ctx->opcode >> 5) & 1, ctx->opcode & 0x7, (ctx->opcode >> 4) & 1); - gen_op_store_T0_gpr(rd); opn = "mftr"; break; case OPC_MTTR: check_insn(env, ctx, ASE_MT); - GEN_LOAD_REG_T0(rt); - gen_mttr(env, ctx, rd, (ctx->opcode >> 5) & 1, + gen_mttr(env, ctx, rd, rt, (ctx->opcode >> 5) & 1, ctx->opcode & 0x7, (ctx->opcode >> 4) & 1); opn = "mttr"; break; @@ -4795,31 +5569,31 @@ opn = "tlbwi"; if (!env->tlb->do_tlbwi) goto die; - gen_op_tlbwi(); + tcg_gen_helper_0_0(env->tlb->do_tlbwi); break; case OPC_TLBWR: opn = "tlbwr"; if (!env->tlb->do_tlbwr) goto die; - gen_op_tlbwr(); + tcg_gen_helper_0_0(env->tlb->do_tlbwr); break; case OPC_TLBP: opn = "tlbp"; if (!env->tlb->do_tlbp) goto die; - gen_op_tlbp(); + tcg_gen_helper_0_0(env->tlb->do_tlbp); break; case OPC_TLBR: opn = "tlbr"; if (!env->tlb->do_tlbr) goto die; - gen_op_tlbr(); + tcg_gen_helper_0_0(env->tlb->do_tlbr); break; case OPC_ERET: opn = "eret"; check_insn(env, ctx, ISA_MIPS2); save_cpu_state(ctx, 1); - gen_op_eret(); + tcg_gen_helper_0_0(do_eret); ctx->bstate = BS_EXCP; break; case OPC_DERET: @@ -4830,7 +5604,7 @@ generate_exception(ctx, EXCP_RI); } else { save_cpu_state(ctx, 1); - gen_op_deret(); + tcg_gen_helper_0_0(do_deret); ctx->bstate = BS_EXCP; } break; @@ -4841,7 +5615,7 @@ ctx->pc += 4; save_cpu_state(ctx, 1); ctx->pc -= 4; - gen_op_wait(); + tcg_gen_helper_0_0(do_wait); ctx->bstate = BS_EXCP; break; default: @@ -4852,6 +5626,7 @@ } MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd); } +#endif /* !CONFIG_USER_ONLY */ /* CP1 Branches (before delay slot) */ static void gen_compute_branch1 (CPUState *env, DisasContext *ctx, uint32_t op, @@ -4859,6 +5634,7 @@ { target_ulong btarget; const char *opn = "cp1 cond branch"; + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); if (cc != 0) check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32); @@ -4867,52 +5643,148 @@ switch (op) { case OPC_BC1F: - gen_op_bc1f(cc); + { + int l1 = gen_new_label(); + int l2 = gen_new_label(); + + get_fp_cond(t0); + tcg_gen_andi_i32(t0, t0, 0x1 << cc); + tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1); + tcg_gen_movi_i32(bcond, 0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i32(bcond, 1); + gen_set_label(l2); + } opn = "bc1f"; goto not_likely; case OPC_BC1FL: - gen_op_bc1f(cc); + { + int l1 = gen_new_label(); + int l2 = gen_new_label(); + + get_fp_cond(t0); + tcg_gen_andi_i32(t0, t0, 0x1 << cc); + tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1); + tcg_gen_movi_i32(bcond, 0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i32(bcond, 1); + gen_set_label(l2); + } opn = "bc1fl"; goto likely; case OPC_BC1T: - gen_op_bc1t(cc); + { + int l1 = gen_new_label(); + int l2 = gen_new_label(); + + get_fp_cond(t0); + tcg_gen_andi_i32(t0, t0, 0x1 << cc); + tcg_gen_brcondi_i32(TCG_COND_NE, t0, 0, l1); + tcg_gen_movi_i32(bcond, 0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i32(bcond, 1); + gen_set_label(l2); + } opn = "bc1t"; goto not_likely; case OPC_BC1TL: - gen_op_bc1t(cc); + { + int l1 = gen_new_label(); + int l2 = gen_new_label(); + + get_fp_cond(t0); + tcg_gen_andi_i32(t0, t0, 0x1 << cc); + tcg_gen_brcondi_i32(TCG_COND_NE, t0, 0, l1); + tcg_gen_movi_i32(bcond, 0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i32(bcond, 1); + gen_set_label(l2); + } opn = "bc1tl"; likely: ctx->hflags |= MIPS_HFLAG_BL; - gen_op_set_bcond(); - gen_op_save_bcond(); break; case OPC_BC1FANY2: - gen_op_bc1any2f(cc); + { + int l1 = gen_new_label(); + int l2 = gen_new_label(); + + get_fp_cond(t0); + tcg_gen_andi_i32(t0, t0, 0x3 << cc); + tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1); + tcg_gen_movi_i32(bcond, 0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i32(bcond, 1); + gen_set_label(l2); + } opn = "bc1any2f"; goto not_likely; case OPC_BC1TANY2: - gen_op_bc1any2t(cc); + { + int l1 = gen_new_label(); + int l2 = gen_new_label(); + + get_fp_cond(t0); + tcg_gen_andi_i32(t0, t0, 0x3 << cc); + tcg_gen_brcondi_i32(TCG_COND_NE, t0, 0, l1); + tcg_gen_movi_i32(bcond, 0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i32(bcond, 1); + gen_set_label(l2); + } opn = "bc1any2t"; goto not_likely; case OPC_BC1FANY4: - gen_op_bc1any4f(cc); + { + int l1 = gen_new_label(); + int l2 = gen_new_label(); + + get_fp_cond(t0); + tcg_gen_andi_i32(t0, t0, 0xf << cc); + tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1); + tcg_gen_movi_i32(bcond, 0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i32(bcond, 1); + gen_set_label(l2); + } opn = "bc1any4f"; goto not_likely; case OPC_BC1TANY4: - gen_op_bc1any4t(cc); + { + int l1 = gen_new_label(); + int l2 = gen_new_label(); + + get_fp_cond(t0); + tcg_gen_andi_i32(t0, t0, 0xf << cc); + tcg_gen_brcondi_i32(TCG_COND_NE, t0, 0, l1); + tcg_gen_movi_i32(bcond, 0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i32(bcond, 1); + gen_set_label(l2); + } opn = "bc1any4t"; not_likely: ctx->hflags |= MIPS_HFLAG_BC; - gen_op_set_bcond(); break; default: MIPS_INVAL(opn); generate_exception (ctx, EXCP_RI); - return; + goto out; } MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn, ctx->hflags, btarget); ctx->btarget = btarget; + + out: + tcg_temp_free(t0); } /* Coprocessor 1 (FPU) */ @@ -4922,97 +5794,216 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) { const char *opn = "cp1 move"; + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); switch (opc) { case OPC_MFC1: - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_mfc1(); - GEN_STORE_T0_REG(rt); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + tcg_gen_ext_i32_tl(t0, fp0); + tcg_temp_free(fp0); + } + gen_store_gpr(t0, rt); opn = "mfc1"; break; case OPC_MTC1: - GEN_LOAD_REG_T0(rt); - gen_op_mtc1(); - GEN_STORE_FTN_FREG(fs, WT0); + gen_load_gpr(t0, rt); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_trunc_tl_i32(fp0, t0); + gen_store_fpr32(fp0, fs); + tcg_temp_free(fp0); + } opn = "mtc1"; break; case OPC_CFC1: - gen_op_cfc1(fs); - GEN_STORE_T0_REG(rt); + tcg_gen_helper_1_i(do_cfc1, t0, fs); + gen_store_gpr(t0, rt); opn = "cfc1"; break; case OPC_CTC1: - GEN_LOAD_REG_T0(rt); - gen_op_ctc1(fs); + gen_load_gpr(t0, rt); + tcg_gen_helper_0_1i(do_ctc1, t0, fs); opn = "ctc1"; break; case OPC_DMFC1: - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_dmfc1(); - GEN_STORE_T0_REG(rt); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_mov_tl(t0, fp0); + tcg_temp_free(fp0); + } + gen_store_gpr(t0, rt); opn = "dmfc1"; break; case OPC_DMTC1: - GEN_LOAD_REG_T0(rt); - gen_op_dmtc1(); - GEN_STORE_FTN_FREG(fs, DT0); + gen_load_gpr(t0, rt); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_mov_tl(fp0, t0); + gen_store_fpr64(ctx, fp0, fs); + tcg_temp_free(fp0); + } opn = "dmtc1"; break; case OPC_MFHC1: - GEN_LOAD_FREG_FTN(WTH0, fs); - gen_op_mfhc1(); - GEN_STORE_T0_REG(rt); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32h(fp0, fs); + tcg_gen_ext_i32_tl(t0, fp0); + tcg_temp_free(fp0); + } + gen_store_gpr(t0, rt); opn = "mfhc1"; break; case OPC_MTHC1: - GEN_LOAD_REG_T0(rt); - gen_op_mthc1(); - GEN_STORE_FTN_FREG(fs, WTH0); + gen_load_gpr(t0, rt); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_trunc_tl_i32(fp0, t0); + gen_store_fpr32h(fp0, fs); + tcg_temp_free(fp0); + } opn = "mthc1"; break; default: MIPS_INVAL(opn); generate_exception (ctx, EXCP_RI); - return; + goto out; } MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]); + + out: + tcg_temp_free(t0); +} + +static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) +{ + int l1 = gen_new_label(); + uint32_t ccbit; + TCGCond cond; + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + TCGv r_tmp = tcg_temp_new(TCG_TYPE_I32); + + if (cc) + ccbit = 1 << (24 + cc); + else + ccbit = 1 << 23; + if (tf) + cond = TCG_COND_EQ; + else + cond = TCG_COND_NE; + + gen_load_gpr(t0, rd); + tcg_gen_andi_i32(r_tmp, fpu_fcr31, ccbit); + tcg_gen_brcondi_i32(cond, r_tmp, 0, l1); + gen_load_gpr(t0, rs); + gen_set_label(l1); + gen_store_gpr(t0, rd); + tcg_temp_free(t0); +} + +static inline void gen_movcf_s (int fs, int fd, int cc, int tf) +{ + uint32_t ccbit; + int cond; + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I32); + int l1 = gen_new_label(); + + if (cc) + ccbit = 1 << (24 + cc); + else + ccbit = 1 << 23; + + if (tf) + cond = TCG_COND_EQ; + else + cond = TCG_COND_NE; + + gen_load_fpr32(fp0, fd); + tcg_gen_andi_i32(r_tmp1, fpu_fcr31, ccbit); + tcg_gen_brcondi_i32(cond, r_tmp1, 0, l1); + gen_load_fpr32(fp0, fs); + gen_set_label(l1); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); +} + +static inline void gen_movcf_d (DisasContext *ctx, int fs, int fd, int cc, int tf) +{ + uint32_t ccbit; + int cond; + TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I64); + int l1 = gen_new_label(); + + if (cc) + ccbit = 1 << (24 + cc); + else + ccbit = 1 << 23; + + if (tf) + cond = TCG_COND_EQ; + else + cond = TCG_COND_NE; + + gen_load_fpr64(ctx, fp0, fd); + tcg_gen_andi_i32(r_tmp1, fpu_fcr31, ccbit); + tcg_gen_brcondi_i32(cond, r_tmp1, 0, l1); + gen_load_fpr64(ctx, fp0, fs); + gen_set_label(l1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); } -static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) +static inline void gen_movcf_ps (int fs, int fd, int cc, int tf) { - uint32_t ccbit; + uint32_t ccbit1, ccbit2; + int cond; + TCGv r_tmp1 = tcg_temp_local_new(TCG_TYPE_I32); + TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I32); + int l1 = gen_new_label(); + int l2 = gen_new_label(); - GEN_LOAD_REG_T0(rd); - GEN_LOAD_REG_T1(rs); if (cc) { - ccbit = 1 << (24 + cc); - } else - ccbit = 1 << 23; - if (!tf) - gen_op_movf(ccbit); + ccbit1 = 1 << (24 + cc); + ccbit2 = 1 << (25 + cc); + } else { + ccbit1 = 1 << 23; + ccbit2 = 1 << 25; + } + + if (tf) + cond = TCG_COND_EQ; else - gen_op_movt(ccbit); - GEN_STORE_T0_REG(rd); + cond = TCG_COND_NE; + + gen_load_fpr32(fp0, fd); + tcg_gen_andi_i32(r_tmp1, fpu_fcr31, ccbit1); + tcg_gen_brcondi_i32(cond, r_tmp1, 0, l1); + gen_load_fpr32(fp0, fs); + gen_set_label(l1); + gen_store_fpr32(fp0, fd); + + gen_load_fpr32h(fp0, fd); + tcg_gen_andi_i32(r_tmp1, fpu_fcr31, ccbit2); + tcg_gen_brcondi_i32(cond, r_tmp1, 0, l2); + gen_load_fpr32h(fp0, fs); + gen_set_label(l2); + gen_store_fpr32h(fp0, fd); + + tcg_temp_free(r_tmp1); + tcg_temp_free(fp0); } -#define GEN_MOVCF(fmt) \ -static void glue(gen_movcf_, fmt) (DisasContext *ctx, int cc, int tf) \ -{ \ - uint32_t ccbit; \ - \ - if (cc) { \ - ccbit = 1 << (24 + cc); \ - } else \ - ccbit = 1 << 23; \ - if (!tf) \ - glue(gen_op_float_movf_, fmt)(ccbit); \ - else \ - glue(gen_op_float_movt_, fmt)(ccbit); \ -} -GEN_MOVCF(d); -GEN_MOVCF(s); -GEN_MOVCF(ps); -#undef GEN_MOVCF static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd, int cc) @@ -5059,207 +6050,376 @@ switch (ctx->opcode & FOP(0x3f, 0x1f)) { case FOP(0, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - gen_op_float_add_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + tcg_gen_helper_1_2(do_float_add_s, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "add.s"; optype = BINOP; break; case FOP(1, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - gen_op_float_sub_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + tcg_gen_helper_1_2(do_float_sub_s, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "sub.s"; optype = BINOP; break; case FOP(2, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - gen_op_float_mul_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + tcg_gen_helper_1_2(do_float_mul_s, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "mul.s"; optype = BINOP; break; case FOP(3, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - gen_op_float_div_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + tcg_gen_helper_1_2(do_float_div_s, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "div.s"; optype = BINOP; break; case FOP(4, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_sqrt_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + tcg_gen_helper_1_1(do_float_sqrt_s, fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "sqrt.s"; break; case FOP(5, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_abs_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + tcg_gen_helper_1_1(do_float_abs_s, fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "abs.s"; break; case FOP(6, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_mov_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "mov.s"; break; case FOP(7, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_chs_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + tcg_gen_helper_1_1(do_float_chs_s, fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "neg.s"; break; case FOP(8, 16): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_roundl_s(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp32 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp64 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr32(fp32, fs); + tcg_gen_helper_1_1(do_float_roundl_s, fp64, fp32); + tcg_temp_free(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free(fp64); + } opn = "round.l.s"; break; case FOP(9, 16): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_truncl_s(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp32 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp64 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr32(fp32, fs); + tcg_gen_helper_1_1(do_float_truncl_s, fp64, fp32); + tcg_temp_free(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free(fp64); + } opn = "trunc.l.s"; break; case FOP(10, 16): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_ceill_s(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp32 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp64 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr32(fp32, fs); + tcg_gen_helper_1_1(do_float_ceill_s, fp64, fp32); + tcg_temp_free(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free(fp64); + } opn = "ceil.l.s"; break; case FOP(11, 16): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_floorl_s(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp32 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp64 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr32(fp32, fs); + tcg_gen_helper_1_1(do_float_floorl_s, fp64, fp32); + tcg_temp_free(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free(fp64); + } opn = "floor.l.s"; break; case FOP(12, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_roundw_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + tcg_gen_helper_1_1(do_float_roundw_s, fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "round.w.s"; break; case FOP(13, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_truncw_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + tcg_gen_helper_1_1(do_float_truncw_s, fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "trunc.w.s"; break; case FOP(14, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_ceilw_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + tcg_gen_helper_1_1(do_float_ceilw_s, fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "ceil.w.s"; break; case FOP(15, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_floorw_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + tcg_gen_helper_1_1(do_float_floorw_s, fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "floor.w.s"; break; case FOP(17, 16): - GEN_LOAD_REG_T0(ft); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT2, fd); - gen_movcf_s(ctx, (ft >> 2) & 0x7, ft & 0x1); - GEN_STORE_FTN_FREG(fd, WT2); + gen_movcf_s(fs, fd, (ft >> 2) & 0x7, ft & 0x1); opn = "movcf.s"; break; case FOP(18, 16): - GEN_LOAD_REG_T0(ft); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT2, fd); - gen_op_float_movz_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + int l1 = gen_new_label(); + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I32); + + gen_load_gpr(t0, ft); + tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0, l1); + gen_load_fpr32(fp0, fs); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + gen_set_label(l1); + tcg_temp_free(t0); + } opn = "movz.s"; break; case FOP(19, 16): - GEN_LOAD_REG_T0(ft); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT2, fd); - gen_op_float_movn_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + int l1 = gen_new_label(); + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I32); + + gen_load_gpr(t0, ft); + tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); + gen_load_fpr32(fp0, fs); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + gen_set_label(l1); + tcg_temp_free(t0); + } opn = "movn.s"; break; case FOP(21, 16): check_cop1x(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_recip_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + tcg_gen_helper_1_1(do_float_recip_s, fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "recip.s"; break; case FOP(22, 16): check_cop1x(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_rsqrt_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + tcg_gen_helper_1_1(do_float_rsqrt_s, fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "rsqrt.s"; break; case FOP(28, 16): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT2, fd); - gen_op_float_recip2_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, fd); + tcg_gen_helper_1_2(do_float_recip2_s, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "recip2.s"; break; case FOP(29, 16): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_recip1_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + tcg_gen_helper_1_1(do_float_recip1_s, fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "recip1.s"; break; case FOP(30, 16): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_rsqrt1_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + tcg_gen_helper_1_1(do_float_rsqrt1_s, fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "rsqrt1.s"; break; case FOP(31, 16): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT2, ft); - gen_op_float_rsqrt2_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + tcg_gen_helper_1_2(do_float_rsqrt2_s, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "rsqrt2.s"; break; case FOP(33, 16): check_cp1_registers(ctx, fd); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_cvtd_s(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp32 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp64 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr32(fp32, fs); + tcg_gen_helper_1_1(do_float_cvtd_s, fp64, fp32); + tcg_temp_free(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free(fp64); + } opn = "cvt.d.s"; break; case FOP(36, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_cvtw_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + tcg_gen_helper_1_1(do_float_cvtw_s, fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "cvt.w.s"; break; case FOP(37, 16): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_cvtl_s(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp32 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp64 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr32(fp32, fs); + tcg_gen_helper_1_1(do_float_cvtl_s, fp64, fp32); + tcg_temp_free(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free(fp64); + } opn = "cvt.l.s"; break; case FOP(38, 16): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT1, fs); - GEN_LOAD_FREG_FTN(WT0, ft); - gen_op_float_cvtps_s(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp64 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp32_0 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp32_1 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp32_0, fs); + gen_load_fpr32(fp32_1, ft); + tcg_gen_concat_i32_i64(fp64, fp32_0, fp32_1); + tcg_temp_free(fp32_1); + tcg_temp_free(fp32_0); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free(fp64); + } opn = "cvt.ps.s"; break; case FOP(48, 16): @@ -5278,203 +6438,351 @@ case FOP(61, 16): case FOP(62, 16): case FOP(63, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - if (ctx->opcode & (1 << 6)) { - check_cop1x(ctx); - gen_cmpabs_s(func-48, cc); - opn = condnames_abs[func-48]; - } else { - gen_cmp_s(func-48, cc); - opn = condnames[func-48]; + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + if (ctx->opcode & (1 << 6)) { + check_cop1x(ctx); + gen_cmpabs_s(func-48, fp0, fp1, cc); + opn = condnames_abs[func-48]; + } else { + gen_cmp_s(func-48, fp0, fp1, cc); + opn = condnames[func-48]; + } + tcg_temp_free(fp0); + tcg_temp_free(fp1); } break; case FOP(0, 17): check_cp1_registers(ctx, fs | ft | fd); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - gen_op_float_add_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + tcg_gen_helper_1_2(do_float_add_d, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "add.d"; optype = BINOP; break; case FOP(1, 17): check_cp1_registers(ctx, fs | ft | fd); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - gen_op_float_sub_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + tcg_gen_helper_1_2(do_float_sub_d, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "sub.d"; optype = BINOP; break; case FOP(2, 17): check_cp1_registers(ctx, fs | ft | fd); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - gen_op_float_mul_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + tcg_gen_helper_1_2(do_float_mul_d, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "mul.d"; optype = BINOP; break; case FOP(3, 17): check_cp1_registers(ctx, fs | ft | fd); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - gen_op_float_div_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + tcg_gen_helper_1_2(do_float_div_d, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "div.d"; optype = BINOP; break; case FOP(4, 17): check_cp1_registers(ctx, fs | fd); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_sqrt_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_sqrt_d, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "sqrt.d"; break; case FOP(5, 17): check_cp1_registers(ctx, fs | fd); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_abs_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_abs_d, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "abs.d"; break; case FOP(6, 17): check_cp1_registers(ctx, fs | fd); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_mov_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "mov.d"; break; case FOP(7, 17): check_cp1_registers(ctx, fs | fd); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_chs_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_chs_d, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "neg.d"; break; case FOP(8, 17): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_roundl_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_roundl_d, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "round.l.d"; break; case FOP(9, 17): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_truncl_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_truncl_d, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "trunc.l.d"; break; case FOP(10, 17): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_ceill_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_ceill_d, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "ceil.l.d"; break; case FOP(11, 17): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_floorl_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_floorl_d, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "floor.l.d"; break; case FOP(12, 17): check_cp1_registers(ctx, fs); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_roundw_d(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp32 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp64 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp64, fs); + tcg_gen_helper_1_1(do_float_roundw_d, fp32, fp64); + tcg_temp_free(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free(fp32); + } opn = "round.w.d"; break; case FOP(13, 17): check_cp1_registers(ctx, fs); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_truncw_d(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp32 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp64 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp64, fs); + tcg_gen_helper_1_1(do_float_truncw_d, fp32, fp64); + tcg_temp_free(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free(fp32); + } opn = "trunc.w.d"; break; case FOP(14, 17): check_cp1_registers(ctx, fs); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_ceilw_d(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp32 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp64 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp64, fs); + tcg_gen_helper_1_1(do_float_ceilw_d, fp32, fp64); + tcg_temp_free(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free(fp32); + } opn = "ceil.w.d"; break; case FOP(15, 17): check_cp1_registers(ctx, fs); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_floorw_d(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp32 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp64 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp64, fs); + tcg_gen_helper_1_1(do_float_floorw_d, fp32, fp64); + tcg_temp_free(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free(fp32); + } opn = "floor.w.d"; break; case FOP(17, 17): - GEN_LOAD_REG_T0(ft); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT2, fd); - gen_movcf_d(ctx, (ft >> 2) & 0x7, ft & 0x1); - GEN_STORE_FTN_FREG(fd, DT2); + gen_movcf_d(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1); opn = "movcf.d"; break; case FOP(18, 17): - GEN_LOAD_REG_T0(ft); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT2, fd); - gen_op_float_movz_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + int l1 = gen_new_label(); + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I64); + + gen_load_gpr(t0, ft); + tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0, l1); + gen_load_fpr64(ctx, fp0, fs); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + gen_set_label(l1); + tcg_temp_free(t0); + } opn = "movz.d"; break; case FOP(19, 17): - GEN_LOAD_REG_T0(ft); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT2, fd); - gen_op_float_movn_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + int l1 = gen_new_label(); + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I64); + + gen_load_gpr(t0, ft); + tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); + gen_load_fpr64(ctx, fp0, fs); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + gen_set_label(l1); + tcg_temp_free(t0); + } opn = "movn.d"; break; case FOP(21, 17): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_recip_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_recip_d, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "recip.d"; break; case FOP(22, 17): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_rsqrt_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_rsqrt_d, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "rsqrt.d"; break; case FOP(28, 17): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT2, ft); - gen_op_float_recip2_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + tcg_gen_helper_1_2(do_float_recip2_d, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "recip2.d"; break; case FOP(29, 17): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_recip1_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_recip1_d, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "recip1.d"; break; case FOP(30, 17): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_rsqrt1_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_rsqrt1_d, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "rsqrt1.d"; break; case FOP(31, 17): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT2, ft); - gen_op_float_rsqrt2_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + tcg_gen_helper_1_2(do_float_rsqrt2_d, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "rsqrt2.d"; break; case FOP(48, 17): @@ -5493,287 +6801,434 @@ case FOP(61, 17): case FOP(62, 17): case FOP(63, 17): - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - if (ctx->opcode & (1 << 6)) { - check_cop1x(ctx); - check_cp1_registers(ctx, fs | ft); - gen_cmpabs_d(func-48, cc); - opn = condnames_abs[func-48]; - } else { - check_cp1_registers(ctx, fs | ft); - gen_cmp_d(func-48, cc); - opn = condnames[func-48]; + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + if (ctx->opcode & (1 << 6)) { + check_cop1x(ctx); + check_cp1_registers(ctx, fs | ft); + gen_cmpabs_d(func-48, fp0, fp1, cc); + opn = condnames_abs[func-48]; + } else { + check_cp1_registers(ctx, fs | ft); + gen_cmp_d(func-48, fp0, fp1, cc); + opn = condnames[func-48]; + } + tcg_temp_free(fp0); + tcg_temp_free(fp1); } break; case FOP(32, 17): check_cp1_registers(ctx, fs); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_cvts_d(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp32 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp64 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp64, fs); + tcg_gen_helper_1_1(do_float_cvts_d, fp32, fp64); + tcg_temp_free(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free(fp32); + } opn = "cvt.s.d"; break; case FOP(36, 17): check_cp1_registers(ctx, fs); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_cvtw_d(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp32 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp64 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp64, fs); + tcg_gen_helper_1_1(do_float_cvtw_d, fp32, fp64); + tcg_temp_free(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free(fp32); + } opn = "cvt.w.d"; break; case FOP(37, 17): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_cvtl_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_cvtl_d, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "cvt.l.d"; break; case FOP(32, 20): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_cvts_w(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + tcg_gen_helper_1_1(do_float_cvts_w, fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "cvt.s.w"; break; case FOP(33, 20): check_cp1_registers(ctx, fd); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_cvtd_w(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp32 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp64 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr32(fp32, fs); + tcg_gen_helper_1_1(do_float_cvtd_w, fp64, fp32); + tcg_temp_free(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free(fp64); + } opn = "cvt.d.w"; break; case FOP(32, 21): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_cvts_l(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp32 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp64 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp64, fs); + tcg_gen_helper_1_1(do_float_cvts_l, fp32, fp64); + tcg_temp_free(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free(fp32); + } opn = "cvt.s.l"; break; case FOP(33, 21): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_cvtd_l(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_cvtd_l, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "cvt.d.l"; break; case FOP(38, 20): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - gen_op_float_cvtps_pw(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_cvtps_pw, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "cvt.ps.pw"; break; case FOP(0, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WTH1, ft); - gen_op_float_add_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + tcg_gen_helper_1_2(do_float_add_ps, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "add.ps"; break; case FOP(1, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WTH1, ft); - gen_op_float_sub_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + tcg_gen_helper_1_2(do_float_sub_ps, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "sub.ps"; break; case FOP(2, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WTH1, ft); - gen_op_float_mul_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + tcg_gen_helper_1_2(do_float_mul_ps, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "mul.ps"; break; case FOP(5, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - gen_op_float_abs_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_abs_ps, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "abs.ps"; break; case FOP(6, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - gen_op_float_mov_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "mov.ps"; break; case FOP(7, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - gen_op_float_chs_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_chs_ps, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "neg.ps"; break; case FOP(17, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_REG_T0(ft); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT2, fd); - GEN_LOAD_FREG_FTN(WTH2, fd); - gen_movcf_ps(ctx, (ft >> 2) & 0x7, ft & 0x1); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + gen_movcf_ps(fs, fd, (ft >> 2) & 0x7, ft & 0x1); opn = "movcf.ps"; break; case FOP(18, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_REG_T0(ft); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT2, fd); - GEN_LOAD_FREG_FTN(WTH2, fd); - gen_op_float_movz_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + int l1 = gen_new_label(); + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I32); + TCGv fph0 = tcg_temp_local_new(TCG_TYPE_I32); + + gen_load_gpr(t0, ft); + tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0, l1); + gen_load_fpr32(fp0, fs); + gen_load_fpr32h(fph0, fs); + gen_store_fpr32(fp0, fd); + gen_store_fpr32h(fph0, fd); + tcg_temp_free(fp0); + tcg_temp_free(fph0); + gen_set_label(l1); + tcg_temp_free(t0); + } opn = "movz.ps"; break; case FOP(19, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_REG_T0(ft); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT2, fd); - GEN_LOAD_FREG_FTN(WTH2, fd); - gen_op_float_movn_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + int l1 = gen_new_label(); + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I32); + TCGv fph0 = tcg_temp_local_new(TCG_TYPE_I32); + + gen_load_gpr(t0, ft); + tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); + gen_load_fpr32(fp0, fs); + gen_load_fpr32h(fph0, fs); + gen_store_fpr32(fp0, fd); + gen_store_fpr32h(fph0, fd); + tcg_temp_free(fp0); + tcg_temp_free(fph0); + gen_set_label(l1); + tcg_temp_free(t0); + } opn = "movn.ps"; break; case FOP(24, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, ft); - GEN_LOAD_FREG_FTN(WTH0, ft); - GEN_LOAD_FREG_FTN(WT1, fs); - GEN_LOAD_FREG_FTN(WTH1, fs); - gen_op_float_addr_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, ft); + gen_load_fpr64(ctx, fp1, fs); + tcg_gen_helper_1_2(do_float_addr_ps, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "addr.ps"; break; case FOP(26, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, ft); - GEN_LOAD_FREG_FTN(WTH0, ft); - GEN_LOAD_FREG_FTN(WT1, fs); - GEN_LOAD_FREG_FTN(WTH1, fs); - gen_op_float_mulr_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, ft); + gen_load_fpr64(ctx, fp1, fs); + tcg_gen_helper_1_2(do_float_mulr_ps, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "mulr.ps"; break; case FOP(28, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT2, fd); - GEN_LOAD_FREG_FTN(WTH2, fd); - gen_op_float_recip2_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, fd); + tcg_gen_helper_1_2(do_float_recip2_ps, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "recip2.ps"; break; case FOP(29, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - gen_op_float_recip1_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_recip1_ps, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "recip1.ps"; break; case FOP(30, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - gen_op_float_rsqrt1_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_rsqrt1_ps, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "rsqrt1.ps"; break; case FOP(31, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT2, ft); - GEN_LOAD_FREG_FTN(WTH2, ft); - gen_op_float_rsqrt2_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + tcg_gen_helper_1_2(do_float_rsqrt2_ps, fp0, fp0, fp1); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "rsqrt2.ps"; break; case FOP(32, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WTH0, fs); - gen_op_float_cvts_pu(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32h(fp0, fs); + tcg_gen_helper_1_1(do_float_cvts_pu, fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "cvt.s.pu"; break; case FOP(36, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - gen_op_float_cvtpw_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_helper_1_1(do_float_cvtpw_ps, fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "cvt.pw.ps"; break; case FOP(40, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_cvts_pl(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + tcg_gen_helper_1_1(do_float_cvts_pl, fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "cvt.s.pl"; break; case FOP(44, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - gen_op_float_pll_ps(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_store_fpr32h(fp0, fd); + gen_store_fpr32(fp1, fd); + tcg_temp_free(fp0); + tcg_temp_free(fp1); + } opn = "pll.ps"; break; case FOP(45, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH1, ft); - gen_op_float_plu_ps(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32h(fp1, ft); + gen_store_fpr32(fp1, fd); + gen_store_fpr32h(fp0, fd); + tcg_temp_free(fp0); + tcg_temp_free(fp1); + } opn = "plu.ps"; break; case FOP(46, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - gen_op_float_pul_ps(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32h(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_store_fpr32(fp1, fd); + gen_store_fpr32h(fp0, fd); + tcg_temp_free(fp0); + tcg_temp_free(fp1); + } opn = "pul.ps"; break; case FOP(47, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WTH1, ft); - gen_op_float_puu_ps(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32h(fp0, fs); + gen_load_fpr32h(fp1, ft); + gen_store_fpr32(fp1, fd); + gen_store_fpr32h(fp0, fd); + tcg_temp_free(fp0); + tcg_temp_free(fp1); + } opn = "puu.ps"; break; case FOP(48, 22): @@ -5793,16 +7248,21 @@ case FOP(62, 22): case FOP(63, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WTH1, ft); - if (ctx->opcode & (1 << 6)) { - gen_cmpabs_ps(func-48, cc); - opn = condnames_abs[func-48]; - } else { - gen_cmp_ps(func-48, cc); - opn = condnames[func-48]; + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + if (ctx->opcode & (1 << 6)) { + gen_cmpabs_ps(func-48, fp0, fp1, cc); + opn = condnames_abs[func-48]; + } else { + gen_cmp_ps(func-48, fp0, fp1, cc); + opn = condnames[func-48]; + } + tcg_temp_free(fp0); + tcg_temp_free(fp1); } break; default: @@ -5829,68 +7289,103 @@ { const char *opn = "extended float load/store"; int store = 0; + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + TCGv t1 = tcg_temp_local_new(TCG_TYPE_TL); if (base == 0) { - if (index == 0) - gen_op_reset_T0(); - else - GEN_LOAD_REG_T0(index); + gen_load_gpr(t0, index); } else if (index == 0) { - GEN_LOAD_REG_T0(base); + gen_load_gpr(t0, base); } else { - GEN_LOAD_REG_T0(base); - GEN_LOAD_REG_T1(index); - gen_op_addr_add(); + gen_load_gpr(t0, base); + gen_load_gpr(t1, index); + gen_op_addr_add(ctx, t0, t1); } /* Don't do NOP if destination is zero: we must perform the actual memory access. */ switch (opc) { case OPC_LWXC1: check_cop1x(ctx); - op_ldst(lwc1); - GEN_STORE_FTN_FREG(fd, WT0); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_qemu_ld32s(fp0, t0, ctx->mem_idx); + gen_store_fpr32(fp0, fd); + tcg_temp_free(fp0); + } opn = "lwxc1"; break; case OPC_LDXC1: check_cop1x(ctx); check_cp1_registers(ctx, fd); - op_ldst(ldc1); - GEN_STORE_FTN_FREG(fd, DT0); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_qemu_ld64(fp0, t0, ctx->mem_idx); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "ldxc1"; break; case OPC_LUXC1: check_cp1_64bitmode(ctx); - op_ldst(luxc1); - GEN_STORE_FTN_FREG(fd, DT0); + tcg_gen_andi_tl(t0, t0, ~0x7); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_qemu_ld64(fp0, t0, ctx->mem_idx); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free(fp0); + } opn = "luxc1"; break; case OPC_SWXC1: check_cop1x(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - op_ldst(swc1); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + tcg_gen_qemu_st32(fp0, t0, ctx->mem_idx); + tcg_temp_free(fp0); + } opn = "swxc1"; store = 1; break; case OPC_SDXC1: check_cop1x(ctx); check_cp1_registers(ctx, fs); - GEN_LOAD_FREG_FTN(DT0, fs); - op_ldst(sdc1); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_qemu_st64(fp0, t0, ctx->mem_idx); + tcg_temp_free(fp0); + } opn = "sdxc1"; store = 1; break; case OPC_SUXC1: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - op_ldst(suxc1); + tcg_gen_andi_tl(t0, t0, ~0x7); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_qemu_st64(fp0, t0, ctx->mem_idx); + tcg_temp_free(fp0); + } opn = "suxc1"; store = 1; break; default: MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); + tcg_temp_free(t0); + tcg_temp_free(t1); return; } + tcg_temp_free(t0); + tcg_temp_free(t1); MIPS_DEBUG("%s %s, %s(%s)", opn, fregnames[store ? fs : fd], regnames[index], regnames[base]); } @@ -5903,139 +7398,262 @@ switch (opc) { case OPC_ALNV_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_REG_T0(fr); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - gen_op_float_alnv_ps(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I32); + TCGv fph0 = tcg_temp_local_new(TCG_TYPE_I32); + TCGv fp1 = tcg_temp_local_new(TCG_TYPE_I32); + TCGv fph1 = tcg_temp_local_new(TCG_TYPE_I32); + int l1 = gen_new_label(); + int l2 = gen_new_label(); + + gen_load_gpr(t0, fr); + tcg_gen_andi_tl(t0, t0, 0x7); + gen_load_fpr32(fp0, fs); + gen_load_fpr32h(fph0, fs); + gen_load_fpr32(fp1, ft); + gen_load_fpr32h(fph1, ft); + + tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0, l1); + gen_store_fpr32(fp0, fd); + gen_store_fpr32h(fph0, fd); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_brcondi_tl(TCG_COND_NE, t0, 4, l2); + tcg_temp_free(t0); +#ifdef TARGET_WORDS_BIGENDIAN + gen_store_fpr32(fph1, fd); + gen_store_fpr32h(fp0, fd); +#else + gen_store_fpr32(fph0, fd); + gen_store_fpr32h(fp1, fd); +#endif + gen_set_label(l2); + tcg_temp_free(fp0); + tcg_temp_free(fph0); + tcg_temp_free(fp1); + tcg_temp_free(fph1); + } opn = "alnv.ps"; break; case OPC_MADD_S: check_cop1x(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WT2, fr); - gen_op_float_muladd_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp2 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_load_fpr32(fp2, fr); + tcg_gen_helper_1_3(do_float_muladd_s, fp2, fp0, fp1, fp2); + tcg_temp_free(fp0); + tcg_temp_free(fp1); + gen_store_fpr32(fp2, fd); + tcg_temp_free(fp2); + } opn = "madd.s"; break; case OPC_MADD_D: check_cop1x(ctx); check_cp1_registers(ctx, fd | fs | ft | fr); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - GEN_LOAD_FREG_FTN(DT2, fr); - gen_op_float_muladd_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp2 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); + tcg_gen_helper_1_3(do_float_muladd_d, fp2, fp0, fp1, fp2); + tcg_temp_free(fp0); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free(fp2); + } opn = "madd.d"; break; case OPC_MADD_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WTH1, ft); - GEN_LOAD_FREG_FTN(WT2, fr); - GEN_LOAD_FREG_FTN(WTH2, fr); - gen_op_float_muladd_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp2 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); + tcg_gen_helper_1_3(do_float_muladd_ps, fp2, fp0, fp1, fp2); + tcg_temp_free(fp0); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free(fp2); + } opn = "madd.ps"; break; case OPC_MSUB_S: check_cop1x(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WT2, fr); - gen_op_float_mulsub_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp2 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_load_fpr32(fp2, fr); + tcg_gen_helper_1_3(do_float_mulsub_s, fp2, fp0, fp1, fp2); + tcg_temp_free(fp0); + tcg_temp_free(fp1); + gen_store_fpr32(fp2, fd); + tcg_temp_free(fp2); + } opn = "msub.s"; break; case OPC_MSUB_D: check_cop1x(ctx); check_cp1_registers(ctx, fd | fs | ft | fr); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - GEN_LOAD_FREG_FTN(DT2, fr); - gen_op_float_mulsub_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp2 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); + tcg_gen_helper_1_3(do_float_mulsub_d, fp2, fp0, fp1, fp2); + tcg_temp_free(fp0); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free(fp2); + } opn = "msub.d"; break; case OPC_MSUB_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WTH1, ft); - GEN_LOAD_FREG_FTN(WT2, fr); - GEN_LOAD_FREG_FTN(WTH2, fr); - gen_op_float_mulsub_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp2 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); + tcg_gen_helper_1_3(do_float_mulsub_ps, fp2, fp0, fp1, fp2); + tcg_temp_free(fp0); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free(fp2); + } opn = "msub.ps"; break; case OPC_NMADD_S: check_cop1x(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WT2, fr); - gen_op_float_nmuladd_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp2 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_load_fpr32(fp2, fr); + tcg_gen_helper_1_3(do_float_nmuladd_s, fp2, fp0, fp1, fp2); + tcg_temp_free(fp0); + tcg_temp_free(fp1); + gen_store_fpr32(fp2, fd); + tcg_temp_free(fp2); + } opn = "nmadd.s"; break; case OPC_NMADD_D: check_cop1x(ctx); check_cp1_registers(ctx, fd | fs | ft | fr); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - GEN_LOAD_FREG_FTN(DT2, fr); - gen_op_float_nmuladd_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp2 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); + tcg_gen_helper_1_3(do_float_nmuladd_d, fp2, fp0, fp1, fp2); + tcg_temp_free(fp0); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free(fp2); + } opn = "nmadd.d"; break; case OPC_NMADD_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WTH1, ft); - GEN_LOAD_FREG_FTN(WT2, fr); - GEN_LOAD_FREG_FTN(WTH2, fr); - gen_op_float_nmuladd_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp2 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); + tcg_gen_helper_1_3(do_float_nmuladd_ps, fp2, fp0, fp1, fp2); + tcg_temp_free(fp0); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free(fp2); + } opn = "nmadd.ps"; break; case OPC_NMSUB_S: check_cop1x(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WT2, fr); - gen_op_float_nmulsub_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I32); + TCGv fp2 = tcg_temp_new(TCG_TYPE_I32); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_load_fpr32(fp2, fr); + tcg_gen_helper_1_3(do_float_nmulsub_s, fp2, fp0, fp1, fp2); + tcg_temp_free(fp0); + tcg_temp_free(fp1); + gen_store_fpr32(fp2, fd); + tcg_temp_free(fp2); + } opn = "nmsub.s"; break; case OPC_NMSUB_D: check_cop1x(ctx); check_cp1_registers(ctx, fd | fs | ft | fr); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - GEN_LOAD_FREG_FTN(DT2, fr); - gen_op_float_nmulsub_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp2 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); + tcg_gen_helper_1_3(do_float_nmulsub_d, fp2, fp0, fp1, fp2); + tcg_temp_free(fp0); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free(fp2); + } opn = "nmsub.d"; break; case OPC_NMSUB_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WTH1, ft); - GEN_LOAD_FREG_FTN(WT2, fr); - GEN_LOAD_FREG_FTN(WTH2, fr); - gen_op_float_nmulsub_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv fp0 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv fp2 = tcg_temp_new(TCG_TYPE_I64); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); + tcg_gen_helper_1_3(do_float_nmulsub_ps, fp2, fp0, fp1, fp2); + tcg_temp_free(fp0); + tcg_temp_free(fp1); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free(fp2); + } opn = "nmsub.ps"; break; default: @@ -6071,13 +7689,19 @@ return; } + /* Handle blikely not taken case */ if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) { - int l1; - /* Handle blikely not taken case */ + int l1 = gen_new_label(); + MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4); - l1 = gen_new_label(); - gen_op_jnz_T2(l1); - gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK); + tcg_gen_brcondi_i32(TCG_COND_NE, bcond, 0, l1); + { + TCGv r_tmp = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_movi_i32(r_tmp, ctx->hflags & ~MIPS_HFLAG_BMASK); + tcg_gen_st_i32(r_tmp, cpu_env, offsetof(CPUState, hflags)); + tcg_temp_free(r_tmp); + } gen_goto_tb(ctx, 1, ctx->pc + 4); gen_set_label(l1); } @@ -6131,7 +7755,7 @@ MIPS_INVAL("PMON / selsl"); generate_exception(ctx, EXCP_RI); #else - gen_op_pmon(sa); + tcg_gen_helper_0_i(do_pmon, sa); #endif break; case OPC_SYSCALL: @@ -6236,78 +7860,80 @@ } break; case OPC_SPECIAL3: - op1 = MASK_SPECIAL3(ctx->opcode); - switch (op1) { - case OPC_EXT: - case OPC_INS: - check_insn(env, ctx, ISA_MIPS32R2); - gen_bitops(ctx, op1, rt, rs, sa, rd); - break; - case OPC_BSHFL: - check_insn(env, ctx, ISA_MIPS32R2); - op2 = MASK_BSHFL(ctx->opcode); - switch (op2) { - case OPC_WSBH: - GEN_LOAD_REG_T1(rt); - gen_op_wsbh(); - break; - case OPC_SEB: - GEN_LOAD_REG_T1(rt); - gen_op_seb(); - break; - case OPC_SEH: - GEN_LOAD_REG_T1(rt); - gen_op_seh(); - break; - default: /* Invalid */ - MIPS_INVAL("bshfl"); - generate_exception(ctx, EXCP_RI); - break; - } - GEN_STORE_T0_REG(rd); + op1 = MASK_SPECIAL3(ctx->opcode); + switch (op1) { + case OPC_EXT: + case OPC_INS: + check_insn(env, ctx, ISA_MIPS32R2); + gen_bitops(ctx, op1, rt, rs, sa, rd); + break; + case OPC_BSHFL: + check_insn(env, ctx, ISA_MIPS32R2); + op2 = MASK_BSHFL(ctx->opcode); + gen_bshfl(ctx, op2, rt, rd); break; case OPC_RDHWR: check_insn(env, ctx, ISA_MIPS32R2); - switch (rd) { - case 0: - save_cpu_state(ctx, 1); - gen_op_rdhwr_cpunum(); - break; - case 1: - save_cpu_state(ctx, 1); - gen_op_rdhwr_synci_step(); - break; - case 2: - save_cpu_state(ctx, 1); - gen_op_rdhwr_cc(); - break; - case 3: - save_cpu_state(ctx, 1); - gen_op_rdhwr_ccres(); - break; - case 29: -#if defined (CONFIG_USER_ONLY) - gen_op_tls_value(); - break; -#endif - default: /* Invalid */ - MIPS_INVAL("rdhwr"); - generate_exception(ctx, EXCP_RI); - break; + { + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + + switch (rd) { + case 0: + save_cpu_state(ctx, 1); + tcg_gen_helper_1_0(do_rdhwr_cpunum, t0); + break; + case 1: + save_cpu_state(ctx, 1); + tcg_gen_helper_1_0(do_rdhwr_synci_step, t0); + break; + case 2: + save_cpu_state(ctx, 1); + tcg_gen_helper_1_0(do_rdhwr_cc, t0); + break; + case 3: + save_cpu_state(ctx, 1); + tcg_gen_helper_1_0(do_rdhwr_ccres, t0); + break; + case 29: + if (env->user_mode_only) { + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, tls_value)); + break; + } else { + /* XXX: Some CPUs implement this in hardware. + Not supported yet. */ + } + default: /* Invalid */ + MIPS_INVAL("rdhwr"); + generate_exception(ctx, EXCP_RI); + break; + } + gen_store_gpr(t0, rt); + tcg_temp_free(t0); } - GEN_STORE_T0_REG(rt); break; case OPC_FORK: check_insn(env, ctx, ASE_MT); - GEN_LOAD_REG_T0(rt); - GEN_LOAD_REG_T1(rs); - gen_op_fork(); + { + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + TCGv t1 = tcg_temp_local_new(TCG_TYPE_TL); + + gen_load_gpr(t0, rt); + gen_load_gpr(t1, rs); + tcg_gen_helper_0_2(do_fork, t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); + } break; case OPC_YIELD: check_insn(env, ctx, ASE_MT); - GEN_LOAD_REG_T0(rs); - gen_op_yield(); - GEN_STORE_T0_REG(rd); + { + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + + gen_load_gpr(t0, rs); + tcg_gen_helper_1_1(do_yield, t0, t0); + gen_store_gpr(t0, rd); + tcg_temp_free(t0); + } break; #if defined(TARGET_MIPS64) case OPC_DEXTM ... OPC_DEXT: @@ -6320,21 +7946,7 @@ check_insn(env, ctx, ISA_MIPS64R2); check_mips_64(ctx); op2 = MASK_DBSHFL(ctx->opcode); - switch (op2) { - case OPC_DSBH: - GEN_LOAD_REG_T1(rt); - gen_op_dsbh(); - break; - case OPC_DSHD: - GEN_LOAD_REG_T1(rt); - gen_op_dshd(); - break; - default: /* Invalid */ - MIPS_INVAL("dbshfl"); - generate_exception(ctx, EXCP_RI); - break; - } - GEN_STORE_T0_REG(rd); + gen_bshfl(ctx, op2, rt, rd); break; #endif default: /* Invalid */ @@ -6376,60 +7988,71 @@ case OPC_DMFC0: case OPC_DMTC0: #endif - gen_cp0(env, ctx, op1, rt, rd); +#ifndef CONFIG_USER_ONLY + if (!env->user_mode_only) + gen_cp0(env, ctx, op1, rt, rd); +#endif /* !CONFIG_USER_ONLY */ break; case OPC_C0_FIRST ... OPC_C0_LAST: - gen_cp0(env, ctx, MASK_C0(ctx->opcode), rt, rd); +#ifndef CONFIG_USER_ONLY + if (!env->user_mode_only) + gen_cp0(env, ctx, MASK_C0(ctx->opcode), rt, rd); +#endif /* !CONFIG_USER_ONLY */ break; case OPC_MFMC0: - op2 = MASK_MFMC0(ctx->opcode); - switch (op2) { - case OPC_DMT: - check_insn(env, ctx, ASE_MT); - gen_op_dmt(); - break; - case OPC_EMT: - check_insn(env, ctx, ASE_MT); - gen_op_emt(); - break; - case OPC_DVPE: - check_insn(env, ctx, ASE_MT); - gen_op_dvpe(); - break; - case OPC_EVPE: - check_insn(env, ctx, ASE_MT); - gen_op_evpe(); - break; - case OPC_DI: - check_insn(env, ctx, ISA_MIPS32R2); - save_cpu_state(ctx, 1); - gen_op_di(); - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; - break; - case OPC_EI: - check_insn(env, ctx, ISA_MIPS32R2); - save_cpu_state(ctx, 1); - gen_op_ei(); - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; - break; - default: /* Invalid */ - MIPS_INVAL("mfmc0"); - generate_exception(ctx, EXCP_RI); - break; +#ifndef CONFIG_USER_ONLY + if (!env->user_mode_only) { + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + + op2 = MASK_MFMC0(ctx->opcode); + switch (op2) { + case OPC_DMT: + check_insn(env, ctx, ASE_MT); + tcg_gen_helper_1_1(do_dmt, t0, t0); + break; + case OPC_EMT: + check_insn(env, ctx, ASE_MT); + tcg_gen_helper_1_1(do_emt, t0, t0); + break; + case OPC_DVPE: + check_insn(env, ctx, ASE_MT); + tcg_gen_helper_1_1(do_dvpe, t0, t0); + break; + case OPC_EVPE: + check_insn(env, ctx, ASE_MT); + tcg_gen_helper_1_1(do_evpe, t0, t0); + break; + case OPC_DI: + check_insn(env, ctx, ISA_MIPS32R2); + save_cpu_state(ctx, 1); + tcg_gen_helper_1_0(do_di, t0); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + break; + case OPC_EI: + check_insn(env, ctx, ISA_MIPS32R2); + save_cpu_state(ctx, 1); + tcg_gen_helper_1_0(do_ei, t0); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + break; + default: /* Invalid */ + MIPS_INVAL("mfmc0"); + generate_exception(ctx, EXCP_RI); + break; + } + gen_store_gpr(t0, rt); + tcg_temp_free(t0); } - GEN_STORE_T0_REG(rt); +#endif /* !CONFIG_USER_ONLY */ break; case OPC_RDPGPR: check_insn(env, ctx, ISA_MIPS32R2); - GEN_LOAD_SRSREG_TN(T0, rt); - GEN_STORE_T0_REG(rd); + gen_load_srsgpr(rt, rd); break; case OPC_WRPGPR: check_insn(env, ctx, ISA_MIPS32R2); - GEN_LOAD_REG_T0(rt); - GEN_STORE_TN_SRSREG(rd, T0); + gen_store_srsgpr(rt, rd); break; default: MIPS_INVAL("cp0"); @@ -6615,6 +8238,7 @@ ctx->hflags &= ~MIPS_HFLAG_BMASK; ctx->bstate = BS_BRANCH; save_cpu_state(ctx, 0); + /* FIXME: Need to clear can_do_io. */ switch (hflags) { case MIPS_HFLAG_B: /* unconditional branch */ @@ -6630,20 +8254,19 @@ /* Conditional branch */ MIPS_DEBUG("conditional branch"); { - int l1; - l1 = gen_new_label(); - gen_op_jnz_T2(l1); - gen_goto_tb(ctx, 1, ctx->pc + 4); - gen_set_label(l1); - gen_goto_tb(ctx, 0, ctx->btarget); + int l1 = gen_new_label(); + + tcg_gen_brcondi_i32(TCG_COND_NE, bcond, 0, l1); + gen_goto_tb(ctx, 1, ctx->pc + 4); + gen_set_label(l1); + gen_goto_tb(ctx, 0, ctx->btarget); } break; case MIPS_HFLAG_BR: /* unconditional branch to register */ MIPS_DEBUG("branch to register"); - gen_op_breg(); - gen_op_reset_T0(); - gen_op_exit_tb(); + tcg_gen_mov_tl(cpu_PC, btarget); + tcg_gen_exit_tb(0); break; default: MIPS_DEBUG("unknown branch"); @@ -6652,7 +8275,7 @@ } } -static always_inline int +static inline void gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, int search_pc) { @@ -6660,15 +8283,15 @@ target_ulong pc_start; uint16_t *gen_opc_end; int j, lj = -1; + int num_insns; + int max_insns; if (search_pc && loglevel) fprintf (logfile, "search pc %d\n", search_pc); pc_start = tb->pc; - gen_opc_ptr = gen_opc_buf; - gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; - gen_opparam_ptr = gen_opparam_buf; - nb_gen_labels = 0; + /* Leave some spare opc slots for branch handling. */ + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE - 16; ctx.pc = pc_start; ctx.saved_pc = -1; ctx.tb = tb; @@ -6676,11 +8299,14 @@ /* Restore delay slot state from the tb context. */ ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */ restore_cpu_state(env, &ctx); -#if defined(CONFIG_USER_ONLY) - ctx.mem_idx = MIPS_HFLAG_UM; -#else - ctx.mem_idx = ctx.hflags & MIPS_HFLAG_KSU; -#endif + if (env->user_mode_only) + ctx.mem_idx = MIPS_HFLAG_UM; + else + ctx.mem_idx = ctx.hflags & MIPS_HFLAG_KSU; + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + if (max_insns == 0) + max_insns = CF_COUNT_MASK; #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_CPU) { fprintf(logfile, "------------------------------------------------\n"); @@ -6693,13 +8319,14 @@ fprintf(logfile, "\ntb %p idx %d hflags %04x\n", tb, ctx.mem_idx, ctx.hflags); #endif - while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) { + gen_icount_start(); + while (ctx.bstate == BS_NONE) { if (env->nb_breakpoints > 0) { for(j = 0; j < env->nb_breakpoints; j++) { if (env->breakpoints[j] == ctx.pc) { save_cpu_state(&ctx, 1); ctx.bstate = BS_BRANCH; - gen_op_debug(); + tcg_gen_helper_0_i(do_raise_exception, EXCP_DEBUG); /* Include the breakpoint location or the tb won't * be flushed when it must be. */ ctx.pc += 4; @@ -6718,10 +8345,14 @@ gen_opc_pc[lj] = ctx.pc; gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK; gen_opc_instr_start[lj] = 1; + gen_opc_icount[lj] = num_insns; } + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) + gen_io_start(); ctx.opcode = ldl_code(ctx.pc); decode_opc(env, &ctx); ctx.pc += 4; + num_insns++; if (env->singlestep_enabled) break; @@ -6729,17 +8360,24 @@ if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) break; + if (gen_opc_ptr >= gen_opc_end) + break; + + if (num_insns >= max_insns) + break; #if defined (MIPS_SINGLE_STEP) break; #endif } + if (tb->cflags & CF_LAST_IO) + gen_io_end(); if (env->singlestep_enabled) { save_cpu_state(&ctx, ctx.bstate == BS_NONE); - gen_op_debug(); + tcg_gen_helper_0_i(do_raise_exception, EXCP_DEBUG); } else { switch (ctx.bstate) { case BS_STOP: - gen_op_interrupt_restart(); + tcg_gen_helper_0_0(do_interrupt_restart); gen_goto_tb(&ctx, 0, ctx.pc); break; case BS_NONE: @@ -6747,9 +8385,8 @@ gen_goto_tb(&ctx, 0, ctx.pc); break; case BS_EXCP: - gen_op_interrupt_restart(); - gen_op_reset_T0(); - gen_op_exit_tb(); + tcg_gen_helper_0_0(do_interrupt_restart); + tcg_gen_exit_tb(0); break; case BS_BRANCH: default: @@ -6757,7 +8394,7 @@ } } done_generating: - ctx.last_T0_store = NULL; + gen_icount_end(tb, num_insns); *gen_opc_ptr = INDEX_op_end; if (search_pc) { j = gen_opc_ptr - gen_opc_buf; @@ -6766,6 +8403,7 @@ gen_opc_instr_start[lj++] = 0; } else { tb->size = ctx.pc - pc_start; + tb->icount = num_insns; } #ifdef DEBUG_DISAS #if defined MIPS_DEBUG_DISAS @@ -6777,32 +8415,25 @@ target_disas(logfile, pc_start, ctx.pc - pc_start, 0); fprintf(logfile, "\n"); } - if (loglevel & CPU_LOG_TB_OP) { - fprintf(logfile, "OP:\n"); - dump_ops(gen_opc_buf, gen_opparam_buf); - fprintf(logfile, "\n"); - } if (loglevel & CPU_LOG_TB_CPU) { fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags); } #endif - - return 0; } -int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) +void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) { - return gen_intermediate_code_internal(env, tb, 0); + gen_intermediate_code_internal(env, tb, 0); } -int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) +void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) { - return gen_intermediate_code_internal(env, tb, 1); + gen_intermediate_code_internal(env, tb, 1); } -void fpu_dump_state(CPUState *env, FILE *f, - int (*fpu_fprintf)(FILE *f, const char *fmt, ...), - int flags) +static void fpu_dump_state(CPUState *env, FILE *f, + int (*fpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) { int i; int is_fpu64 = !!(env->hflags & MIPS_HFLAG_F64); @@ -6825,52 +8456,41 @@ fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%08x(0x%02x)\n", - env->fpu->fcr0, env->fpu->fcr31, is_fpu64, env->fpu->fp_status, - get_float_exception_flags(&env->fpu->fp_status)); - fpu_fprintf(f, "FT0: "); printfpr(&env->fpu->ft0); - fpu_fprintf(f, "FT1: "); printfpr(&env->fpu->ft1); - fpu_fprintf(f, "FT2: "); printfpr(&env->fpu->ft2); + env->active_fpu.fcr0, env->active_fpu.fcr31, is_fpu64, env->active_fpu.fp_status, + get_float_exception_flags(&env->active_fpu.fp_status)); for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) { fpu_fprintf(f, "%3s: ", fregnames[i]); - printfpr(&env->fpu->fpr[i]); + printfpr(&env->active_fpu.fpr[i]); } #undef printfpr } -void dump_fpu (CPUState *env) -{ - if (loglevel) { - fprintf(logfile, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n", - env->PC[env->current_tc], env->HI[0][env->current_tc], env->LO[0][env->current_tc], env->hflags, env->btarget, env->bcond); - fpu_dump_state(env, logfile, fprintf, 0); - } -} - #if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) /* Debug help: The architecture requires 32bit code to maintain proper - sign-extened values on 64bit machines. */ + sign-extended values on 64bit machines. */ #define SIGN_EXT_P(val) ((((val) & ~0x7fffffff) == 0) || (((val) & ~0x7fffffff) == ~0x7fffffff)) -void cpu_mips_check_sign_extensions (CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), - int flags) +static void +cpu_mips_check_sign_extensions (CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) { int i; - if (!SIGN_EXT_P(env->PC[env->current_tc])) - cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->PC[env->current_tc]); - if (!SIGN_EXT_P(env->HI[0][env->current_tc])) - cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->HI[0][env->current_tc]); - if (!SIGN_EXT_P(env->LO[0][env->current_tc])) - cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->LO[0][env->current_tc]); + if (!SIGN_EXT_P(env->active_tc.PC)) + cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->active_tc.PC); + if (!SIGN_EXT_P(env->active_tc.HI[0])) + cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->active_tc.HI[0]); + if (!SIGN_EXT_P(env->active_tc.LO[0])) + cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->active_tc.LO[0]); if (!SIGN_EXT_P(env->btarget)) cpu_fprintf(f, "BROKEN: btarget=0x" TARGET_FMT_lx "\n", env->btarget); for (i = 0; i < 32; i++) { - if (!SIGN_EXT_P(env->gpr[i][env->current_tc])) - cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->gpr[i][env->current_tc]); + if (!SIGN_EXT_P(env->active_tc.gpr[i])) + cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->active_tc.gpr[i]); } if (!SIGN_EXT_P(env->CP0_EPC)) @@ -6887,11 +8507,12 @@ int i; cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n", - env->PC[env->current_tc], env->HI[env->current_tc], env->LO[env->current_tc], env->hflags, env->btarget, env->bcond); + env->active_tc.PC, env->active_tc.HI[0], env->active_tc.LO[0], + env->hflags, env->btarget, env->bcond); for (i = 0; i < 32; i++) { if ((i & 3) == 0) cpu_fprintf(f, "GPR%02d:", i); - cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->gpr[i][env->current_tc]); + cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->active_tc.gpr[i]); if ((i & 3) == 3) cpu_fprintf(f, "\n"); } @@ -6907,6 +8528,67 @@ #endif } +static void mips_tcg_init(void) +{ + int i; + static int inited; + + /* Initialize various static tables. */ + if (inited) + return; + + cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env"); + for (i = 0; i < 32; i++) + cpu_gpr[i] = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, active_tc.gpr[i]), + regnames[i]); + cpu_PC = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, active_tc.PC), "PC"); + for (i = 0; i < MIPS_DSP_ACC; i++) { + cpu_HI[i] = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, active_tc.HI[i]), + regnames_HI[i]); + cpu_LO[i] = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, active_tc.LO[i]), + regnames_LO[i]); + cpu_ACX[i] = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, active_tc.ACX[i]), + regnames_ACX[i]); + } + cpu_dspctrl = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, active_tc.DSPControl), + "DSPControl"); + bcond = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, bcond), "bcond"); + btarget = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, btarget), "btarget"); + for (i = 0; i < 32; i++) + fpu_fpr32[i] = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, active_fpu.fpr[i].w[FP_ENDIAN_IDX]), + fregnames[i]); + for (i = 0; i < 32; i++) + fpu_fpr64[i] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, + offsetof(CPUState, active_fpu.fpr[i]), + fregnames_64[i]); + for (i = 0; i < 32; i++) + fpu_fpr32h[i] = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, active_fpu.fpr[i].w[!FP_ENDIAN_IDX]), + fregnames_h[i]); + fpu_fcr0 = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, active_fpu.fcr0), + "fcr0"); + fpu_fcr31 = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, active_fpu.fcr31), + "fcr31"); + + /* register helpers */ +#undef DEF_HELPER +#define DEF_HELPER(ret, name, params) tcg_register_helper(name, #name); +#include "helper.h" + + inited = 1; +} + #include "translate_init.c" CPUMIPSState *cpu_mips_init (const char *cpu_model) @@ -6924,6 +8606,7 @@ cpu_exec_init(env); env->cpu_model_str = cpu_model; + mips_tcg_init(); cpu_reset(env); return env; } @@ -6935,41 +8618,49 @@ tlb_flush(env, 1); /* Minimal init */ -#if !defined(CONFIG_USER_ONLY) - if (env->hflags & MIPS_HFLAG_BMASK) { - /* If the exception was raised from a delay slot, - * come back to the jump. */ - env->CP0_ErrorEPC = env->PC[env->current_tc] - 4; +#if defined(CONFIG_USER_ONLY) + env->user_mode_only = 1; +#endif + if (env->user_mode_only) { + env->hflags = MIPS_HFLAG_UM; } else { - env->CP0_ErrorEPC = env->PC[env->current_tc]; - } - env->PC[env->current_tc] = (int32_t)0xBFC00000; - env->CP0_Wired = 0; - /* SMP not implemented */ - env->CP0_EBase = 0x80000000; - env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); - /* vectored interrupts not implemented, timer on int 7, - no performance counters. */ - env->CP0_IntCtl = 0xe0000000; - { - int i; - - for (i = 0; i < 7; i++) { - env->CP0_WatchLo[i] = 0; - env->CP0_WatchHi[i] = 0x80000000; + if (env->hflags & MIPS_HFLAG_BMASK) { + /* If the exception was raised from a delay slot, + come back to the jump. */ + env->CP0_ErrorEPC = env->active_tc.PC - 4; + } else { + env->CP0_ErrorEPC = env->active_tc.PC; + } + env->active_tc.PC = (int32_t)0xBFC00000; + env->CP0_Wired = 0; + /* SMP not implemented */ + env->CP0_EBase = 0x80000000; + env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); + /* vectored interrupts not implemented, timer on int 7, + no performance counters. */ + env->CP0_IntCtl = 0xe0000000; + { + int i; + + for (i = 0; i < 7; i++) { + env->CP0_WatchLo[i] = 0; + env->CP0_WatchHi[i] = 0x80000000; + } + env->CP0_WatchLo[7] = 0; + env->CP0_WatchHi[7] = 0; } - env->CP0_WatchLo[7] = 0; - env->CP0_WatchHi[7] = 0; + /* Count register increments in debug mode, EJTAG version 1 */ + env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); + env->hflags = MIPS_HFLAG_CP0; } - /* Count register increments in debug mode, EJTAG version 1 */ - env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); -#endif env->exception_index = EXCP_NONE; -#if defined(CONFIG_USER_ONLY) - env->hflags = MIPS_HFLAG_UM; - env->user_mode_only = 1; -#else - env->hflags = MIPS_HFLAG_CP0; -#endif cpu_mips_register(env, env->cpu_model); } + +void gen_pc_load(CPUState *env, TranslationBlock *tb, + unsigned long searched_pc, int pc_pos, void *puc) +{ + env->active_tc.PC = gen_opc_pc[pc_pos]; + env->hflags &= ~MIPS_HFLAG_BMASK; + env->hflags |= gen_opc_hflags[pc_pos]; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-mips/translate_init.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-mips/translate_init.c --- qemu-0.9.1/target-mips/translate_init.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-mips/translate_init.c 2008-09-18 12:57:27.000000000 +0100 @@ -63,7 +63,7 @@ }; struct mips_def_t { - const unsigned char *name; + const char *name; int32_t CP0_PRid; int32_t CP0_Config0; int32_t CP0_Config1; @@ -95,7 +95,7 @@ /*****************************************************************************/ /* MIPS CPU definitions */ -static mips_def_t mips_defs[] = +static const mips_def_t mips_defs[] = { { .name = "4Kc", @@ -417,7 +417,7 @@ #endif }; -static const mips_def_t *cpu_mips_find_by_name (const unsigned char *name) +static const mips_def_t *cpu_mips_find_by_name (const char *name) { int i; @@ -489,15 +489,20 @@ static void fpu_init (CPUMIPSState *env, const mips_def_t *def) { - env->fpu = qemu_mallocz(sizeof(CPUMIPSFPUContext)); + int i; + + for (i = 0; i < MIPS_FPU_MAX; i++) + env->fpus[i].fcr0 = def->CP1_fcr0; - env->fpu->fcr0 = def->CP1_fcr0; -#ifdef CONFIG_USER_ONLY - if (env->CP0_Config1 & (1 << CP0C1_FP)) - env->hflags |= MIPS_HFLAG_FPU; - if (env->fpu->fcr0 & (1 << FCR0_F64)) - env->hflags |= MIPS_HFLAG_F64; + memcpy(&env->active_fpu, &env->fpus[0], sizeof(env->active_fpu)); + if (env->user_mode_only) { + if (env->CP0_Config1 & (1 << CP0C1_FP)) + env->hflags |= MIPS_HFLAG_FPU; +#ifdef TARGET_MIPS64 + if (env->active_fpu.fcr0 & (1 << FCR0_F64)) + env->hflags |= MIPS_HFLAG_F64; #endif + } } static void mvp_init (CPUMIPSState *env, const mips_def_t *def) @@ -510,15 +515,15 @@ implemented, 5 TCs implemented. */ env->mvp->CP0_MVPConf0 = (1 << CP0MVPC0_M) | (1 << CP0MVPC0_TLBS) | (0 << CP0MVPC0_GS) | (1 << CP0MVPC0_PCP) | -#ifndef CONFIG_USER_ONLY - /* Usermode has no TLB support */ - (env->tlb->nb_tlb << CP0MVPC0_PTLBE) | -#endif // TODO: actually do 2 VPEs. // (1 << CP0MVPC0_TCA) | (0x1 << CP0MVPC0_PVPE) | // (0x04 << CP0MVPC0_PTC); (1 << CP0MVPC0_TCA) | (0x0 << CP0MVPC0_PVPE) | (0x04 << CP0MVPC0_PTC); + /* Usermode has no TLB support */ + if (!env->user_mode_only) + env->mvp->CP0_MVPConf0 |= (env->tlb->nb_tlb << CP0MVPC0_PTLBE); + /* Allocatable CP1 have media extensions, allocatable CP1 have FP support, no UDI implemented, no CP2 implemented, 1 CP1 implemented. */ env->mvp->CP0_MVPConf1 = (1 << CP0MVPC1_CIM) | (1 << CP0MVPC1_CIF) | @@ -543,6 +548,7 @@ env->CP0_Status_rw_bitmask = def->CP0_Status_rw_bitmask; env->CP0_TCStatus_rw_bitmask = def->CP0_TCStatus_rw_bitmask; env->CP0_SRSCtl = def->CP0_SRSCtl; + env->current_tc = 0; env->SEGBITS = def->SEGBITS; env->SEGMask = (target_ulong)((1ULL << def->SEGBITS) - 1); #if defined(TARGET_MIPS64) @@ -566,7 +572,8 @@ env->insn_flags = def->insn_flags; #ifndef CONFIG_USER_ONLY - mmu_init(env, def); + if (!env->user_mode_only) + mmu_init(env, def); #endif fpu_init(env, def); mvp_init(env, def); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-ppc/cpu.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-ppc/cpu.h --- qemu-0.9.1/target-ppc/cpu.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-ppc/cpu.h 2008-11-10 11:10:23.000000000 +0000 @@ -27,23 +27,11 @@ #if defined (TARGET_PPC64) /* PowerPC 64 definitions */ -typedef uint64_t ppc_gpr_t; #define TARGET_LONG_BITS 64 #define TARGET_PAGE_BITS 12 #else /* defined (TARGET_PPC64) */ /* PowerPC 32 definitions */ -#if (HOST_LONG_BITS >= 64) -/* When using 64 bits temporary registers, - * we can use 64 bits GPR with no extra cost - * It's even an optimization as this will prevent - * the compiler to do unuseful masking in the micro-ops. - */ -typedef uint64_t ppc_gpr_t; -#else /* (HOST_LONG_BITS >= 64) */ -typedef uint32_t ppc_gpr_t; -#endif /* (HOST_LONG_BITS >= 64) */ - #define TARGET_LONG_BITS 32 #if defined(TARGET_PPCEMB) @@ -315,7 +303,7 @@ void (*hea_read)(void *opaque, int spr_num); void (*hea_write)(void *opaque, int spr_num); #endif - const unsigned char *name; + const char *name; }; /* Altivec registers (128 bits) */ @@ -397,7 +385,7 @@ #define msr_thv ((env->msr >> MSR_THV) & 1) #define msr_ucle ((env->msr >> MSR_UCLE) & 1) #define msr_vr ((env->msr >> MSR_VR) & 1) -#define msr_spe ((env->msr >> MSR_SE) & 1) +#define msr_spe ((env->msr >> MSR_SPE) & 1) #define msr_ap ((env->msr >> MSR_AP) & 1) #define msr_sa ((env->msr >> MSR_SA) & 1) #define msr_key ((env->msr >> MSR_KEY) & 1) @@ -541,29 +529,35 @@ /* First are the most commonly used resources * during translated code execution */ -#if (HOST_LONG_BITS == 32) +#if TARGET_LONG_BITS > HOST_LONG_BITS + target_ulong t0, t1; +#endif + /* XXX: this is a temporary workaround for i386. cf translate.c comment */ +#if (TARGET_LONG_BITS > HOST_LONG_BITS) || defined(HOST_I386) + target_ulong t2; +#endif +#if !defined(TARGET_PPC64) /* temporary fixed-point registers - * used to emulate 64 bits registers on 32 bits hosts + * used to emulate 64 bits registers on 32 bits targets */ - uint64_t t0, t1, t2; + uint64_t t0_64, t1_64, t2_64; #endif ppc_avr_t avr0, avr1, avr2; /* general purpose registers */ - ppc_gpr_t gpr[32]; + target_ulong gpr[32]; #if !defined(TARGET_PPC64) /* Storage for GPR MSB, used by the SPE extension */ - ppc_gpr_t gprh[32]; + target_ulong gprh[32]; #endif /* LR */ target_ulong lr; /* CTR */ target_ulong ctr; /* condition register */ - uint8_t crf[8]; + uint32_t crf[8]; /* XER */ - /* XXX: We use only 5 fields, but we want to keep the structure aligned */ - uint8_t xer[8]; + target_ulong xer; /* Reservation address */ target_ulong reserve; @@ -571,7 +565,7 @@ /* machine state register */ target_ulong msr; /* temporary general purpose registers */ - ppc_gpr_t tgpr[4]; /* Used to speed-up TLB assist handlers */ + target_ulong tgpr[4]; /* Used to speed-up TLB assist handlers */ /* Floating point execution context */ /* temporary float registers */ @@ -586,8 +580,6 @@ CPU_COMMON - int halted; /* TRUE if the CPU is in suspend state */ - int access_type; /* when a memory exception occurs, the access type is stored here */ @@ -626,7 +618,7 @@ ppc_avr_t avr[32]; uint32_t vscr; /* SPE registers */ - ppc_gpr_t spe_acc; + target_ulong spe_acc; float_status spe_status; uint32_t spe_fscr; @@ -648,9 +640,7 @@ int bfd_mach; uint32_t flags; - int exception_index; int error_code; - int interrupt_request; uint32_t pending_interrupts; #if !defined(CONFIG_USER_ONLY) /* This is the IRQ controller, which is implementation dependant @@ -674,8 +664,6 @@ opc_handler_t *opcodes[0x40]; /* Those resources are used only in Qemu core */ - jmp_buf jmp_env; - int user_mode_only; /* user mode only simulation */ target_ulong hflags; /* hflags is a MSR & HFLAGS_MASK */ target_ulong hflags_nmsr; /* specific hflags, not comming from MSR */ int mmu_idx; /* precomputed MMU index to speed up mem accesses */ @@ -701,6 +689,7 @@ /*****************************************************************************/ CPUPPCState *cpu_ppc_init (const char *cpu_model); +void ppc_translate_init(void); int cpu_ppc_exec (CPUPPCState *s); void cpu_ppc_close (CPUPPCState *s); /* you can call this signal handler from your SIGBUS and SIGSEGV @@ -739,15 +728,13 @@ #endif void do_store_sr (CPUPPCState *env, int srnum, target_ulong value); #endif /* !defined(CONFIG_USER_ONLY) */ -target_ulong ppc_load_xer (CPUPPCState *env); -void ppc_store_xer (CPUPPCState *env, target_ulong value); void ppc_store_msr (CPUPPCState *env, target_ulong value); void cpu_ppc_reset (void *opaque); void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); -const ppc_def_t *cpu_ppc_find_by_name (const unsigned char *name); +const ppc_def_t *cpu_ppc_find_by_name (const char *name); int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def); /* Time-base and decrementer management */ @@ -816,6 +803,8 @@ #define cpu_signal_handler cpu_ppc_signal_handler #define cpu_list ppc_cpu_list +#define CPU_SAVE_VERSION 3 + /* MMU modes definitions */ #define MMU_MODE0_SUFFIX _user #define MMU_MODE1_SUFFIX _kernel @@ -826,20 +815,43 @@ return env->mmu_idx; } +#if defined(CONFIG_USER_ONLY) +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) +{ + int i; + if (newsp) + env->gpr[1] = newsp; + for (i = 7; i < 32; i++) + env->gpr[i] = 0; +} +#endif + +#define CPU_PC_FROM_TB(env, tb) env->nip = tb->pc + #include "cpu-all.h" /*****************************************************************************/ -/* Registers definitions */ -#define XER_SO 31 -#define XER_OV 30 -#define XER_CA 29 -#define XER_CMP 8 -#define XER_BC 0 -#define xer_so env->xer[4] -#define xer_ov env->xer[6] -#define xer_ca env->xer[2] -#define xer_cmp env->xer[1] -#define xer_bc env->xer[0] +/* CRF definitions */ +#define CRF_LT 3 +#define CRF_GT 2 +#define CRF_EQ 1 +#define CRF_SO 0 +#define CRF_CH (1 << 4) +#define CRF_CL (1 << 3) +#define CRF_CH_OR_CL (1 << 2) +#define CRF_CH_AND_CL (1 << 1) + +/* XER definitions */ +#define XER_SO 31 +#define XER_OV 30 +#define XER_CA 29 +#define XER_CMP 8 +#define XER_BC 0 +#define xer_so ((env->xer >> XER_SO) & 1) +#define xer_ov ((env->xer >> XER_OV) & 1) +#define xer_ca ((env->xer >> XER_CA) & 1) +#define xer_cmp ((env->xer >> XER_CMP) & 0xFF) +#define xer_bc ((env->xer >> XER_BC) & 0x7F) /* SPR definitions */ #define SPR_MQ (0x000) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-ppc/exec.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-ppc/exec.h --- qemu-0.9.1/target-ppc/exec.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-ppc/exec.h 2008-09-04 06:26:09.000000000 +0100 @@ -39,17 +39,16 @@ #define T2 (env->t2) #define TDX "%016" PRIx64 #else -register unsigned long T0 asm(AREG1); -register unsigned long T1 asm(AREG2); -register unsigned long T2 asm(AREG3); +register target_ulong T0 asm(AREG1); +register target_ulong T1 asm(AREG2); +register target_ulong T2 asm(AREG3); #define TDX "%016lx" #endif /* We may, sometime, need 64 bits registers on 32 bits targets */ -#if (HOST_LONG_BITS == 32) -/* no registers can be used */ -#define T0_64 (env->t0) -#define T1_64 (env->t1) -#define T2_64 (env->t2) +#if !defined(TARGET_PPC64) +#define T0_64 (env->t0_64) +#define T1_64 (env->t1_64) +#define T2_64 (env->t2_64) #else #define T0_64 T0 #define T1_64 T1 diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-ppc/helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-ppc/helper.c --- qemu-0.9.1/target-ppc/helper.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-ppc/helper.c 2008-10-21 12:28:46.000000000 +0100 @@ -28,6 +28,7 @@ #include "cpu.h" #include "exec-all.h" #include "helper_regs.h" +#include "qemu-common.h" //#define DEBUG_MMU //#define DEBUG_BATS @@ -2123,16 +2124,6 @@ } #endif /* !defined (CONFIG_USER_ONLY) */ -target_ulong ppc_load_xer (CPUPPCState *env) -{ - return hreg_load_xer(env); -} - -void ppc_store_xer (CPUPPCState *env, target_ulong value) -{ - hreg_store_xer(env, value); -} - /* GDBstub can read and write MSR... */ void ppc_store_msr (CPUPPCState *env, target_ulong value) { @@ -2898,19 +2889,6 @@ } #endif /* !CONFIG_USER_ONLY */ -void cpu_dump_EA (target_ulong EA) -{ - FILE *f; - - if (logfile) { - f = logfile; - } else { - f = stdout; - return; - } - fprintf(f, "Memory access at address " ADDRX "\n", EA); -} - void cpu_dump_rfi (target_ulong RA, target_ulong msr) { FILE *f; @@ -2976,6 +2954,7 @@ if (!env) return NULL; cpu_exec_init(env); + ppc_translate_init(); env->cpu_model_str = cpu_model; cpu_ppc_register_internal(env, def); cpu_ppc_reset(env); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-ppc/helper.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-ppc/helper.h --- qemu-0.9.1/target-ppc/helper.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-ppc/helper.h 2008-11-10 11:10:23.000000000 +0000 @@ -0,0 +1,28 @@ +#ifndef DEF_HELPER +#define DEF_HELPER(ret, name, params) ret name params; +#endif + +DEF_HELPER(uint32_t, helper_fcmpo, (void)) +DEF_HELPER(uint32_t, helper_fcmpu, (void)) + +DEF_HELPER(uint32_t, helper_load_cr, (void)) +DEF_HELPER(void, helper_store_cr, (target_ulong, uint32_t)) + +#if defined(TARGET_PPC64) +DEF_HELPER(uint64_t, helper_mulhd, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_mulhdu, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_mulldo, (uint64_t, uint64_t)) +#endif + +DEF_HELPER(target_ulong, helper_cntlzw, (target_ulong t)) +DEF_HELPER(target_ulong, helper_popcntb, (target_ulong val)) +DEF_HELPER(target_ulong, helper_sraw, (target_ulong, target_ulong)) +#if defined(TARGET_PPC64) +DEF_HELPER(target_ulong, helper_cntlzd, (target_ulong t)) +DEF_HELPER(target_ulong, helper_popcntb_64, (target_ulong val)) +DEF_HELPER(target_ulong, helper_srad, (target_ulong, target_ulong)) +#endif + +DEF_HELPER(uint32_t, helper_cntlsw32, (uint32_t)) +DEF_HELPER(uint32_t, helper_cntlzw32, (uint32_t)) +DEF_HELPER(uint32_t, helper_brinc, (uint32_t, uint32_t)) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-ppc/helper_regs.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-ppc/helper_regs.h --- qemu-0.9.1/target-ppc/helper_regs.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-ppc/helper_regs.h 2008-10-21 12:28:46.000000000 +0100 @@ -21,28 +21,10 @@ #if !defined(__HELPER_REGS_H__) #define __HELPER_REGS_H__ -static always_inline target_ulong hreg_load_xer (CPUPPCState *env) -{ - return (xer_so << XER_SO) | - (xer_ov << XER_OV) | - (xer_ca << XER_CA) | - (xer_bc << XER_BC) | - (xer_cmp << XER_CMP); -} - -static always_inline void hreg_store_xer (CPUPPCState *env, target_ulong value) -{ - xer_so = (value >> XER_SO) & 0x01; - xer_ov = (value >> XER_OV) & 0x01; - xer_ca = (value >> XER_CA) & 0x01; - xer_cmp = (value >> XER_CMP) & 0xFF; - xer_bc = (value >> XER_BC) & 0x7F; -} - /* Swap temporary saved registers with GPRs */ static always_inline void hreg_swap_gpr_tgpr (CPUPPCState *env) { - ppc_gpr_t tmp; + target_ulong tmp; tmp = env->gpr[0]; env->gpr[0] = env->tgpr[0]; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-ppc/machine.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-ppc/machine.c --- qemu-0.9.1/target-ppc/machine.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-ppc/machine.c 2008-05-04 14:11:44.000000000 +0100 @@ -0,0 +1,20 @@ +#include "hw/hw.h" +#include "hw/boards.h" + +void register_machines(void) +{ + qemu_register_machine(&heathrow_machine); + qemu_register_machine(&core99_machine); + qemu_register_machine(&prep_machine); + qemu_register_machine(&ref405ep_machine); + qemu_register_machine(&taihu_machine); +} + +void cpu_save(QEMUFile *f, void *opaque) +{ +} + +int cpu_load(QEMUFile *f, void *opaque, int version_id) +{ + return 0; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-ppc/op.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-ppc/op.c --- qemu-0.9.1/target-ppc/op.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-ppc/op.c 2008-11-10 11:10:23.000000000 +0000 @@ -26,283 +26,17 @@ #include "helper_regs.h" #include "op_helper.h" -#define REG 0 -#include "op_template.h" - -#define REG 1 -#include "op_template.h" - -#define REG 2 -#include "op_template.h" - -#define REG 3 -#include "op_template.h" - -#define REG 4 -#include "op_template.h" - -#define REG 5 -#include "op_template.h" - -#define REG 6 -#include "op_template.h" - -#define REG 7 -#include "op_template.h" - -#define REG 8 -#include "op_template.h" - -#define REG 9 -#include "op_template.h" - -#define REG 10 -#include "op_template.h" - -#define REG 11 -#include "op_template.h" - -#define REG 12 -#include "op_template.h" - -#define REG 13 -#include "op_template.h" - -#define REG 14 -#include "op_template.h" - -#define REG 15 -#include "op_template.h" - -#define REG 16 -#include "op_template.h" - -#define REG 17 -#include "op_template.h" - -#define REG 18 -#include "op_template.h" - -#define REG 19 -#include "op_template.h" - -#define REG 20 -#include "op_template.h" - -#define REG 21 -#include "op_template.h" - -#define REG 22 -#include "op_template.h" - -#define REG 23 -#include "op_template.h" - -#define REG 24 -#include "op_template.h" - -#define REG 25 -#include "op_template.h" - -#define REG 26 -#include "op_template.h" - -#define REG 27 -#include "op_template.h" - -#define REG 28 -#include "op_template.h" - -#define REG 29 -#include "op_template.h" - -#define REG 30 -#include "op_template.h" - -#define REG 31 -#include "op_template.h" - -void OPPROTO op_print_mem_EA (void) -{ - do_print_mem_EA(T0); - RETURN(); -} - -/* PowerPC state maintenance operations */ -/* set_Rc0 */ -void OPPROTO op_set_Rc0 (void) -{ - env->crf[0] = T0 | xer_so; - RETURN(); -} - -/* Constants load */ -void OPPROTO op_reset_T0 (void) -{ - T0 = 0; - RETURN(); -} - -void OPPROTO op_set_T0 (void) -{ - T0 = (uint32_t)PARAM1; - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_set_T0_64 (void) -{ - T0 = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2; - RETURN(); -} -#endif - -void OPPROTO op_set_T1 (void) -{ - T1 = (uint32_t)PARAM1; - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_set_T1_64 (void) -{ - T1 = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2; - RETURN(); -} -#endif - -#if 0 // unused -void OPPROTO op_set_T2 (void) -{ - T2 = (uint32_t)PARAM1; - RETURN(); -} -#endif - -void OPPROTO op_move_T1_T0 (void) -{ - T1 = T0; - RETURN(); -} - -void OPPROTO op_move_T2_T0 (void) -{ - T2 = T0; - RETURN(); -} - -void OPPROTO op_moven_T2_T0 (void) -{ - T2 = ~T0; - RETURN(); -} - /* Generate exceptions */ void OPPROTO op_raise_exception_err (void) { do_raise_exception_err(PARAM1, PARAM2); } -void OPPROTO op_update_nip (void) -{ - env->nip = (uint32_t)PARAM1; - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_update_nip_64 (void) -{ - env->nip = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2; - RETURN(); -} -#endif - void OPPROTO op_debug (void) { do_raise_exception(EXCP_DEBUG); } -void OPPROTO op_exit_tb (void) -{ - EXIT_TB(); -} - -/* Load/store special registers */ -void OPPROTO op_load_cr (void) -{ - do_load_cr(); - RETURN(); -} - -void OPPROTO op_store_cr (void) -{ - do_store_cr(PARAM1); - RETURN(); -} - -void OPPROTO op_load_cro (void) -{ - T0 = env->crf[PARAM1]; - RETURN(); -} - -void OPPROTO op_store_cro (void) -{ - env->crf[PARAM1] = T0; - RETURN(); -} - -void OPPROTO op_load_xer_cr (void) -{ - T0 = (xer_so << 3) | (xer_ov << 2) | (xer_ca << 1); - RETURN(); -} - -void OPPROTO op_clear_xer_ov (void) -{ - xer_so = 0; - xer_ov = 0; - RETURN(); -} - -void OPPROTO op_clear_xer_ca (void) -{ - xer_ca = 0; - RETURN(); -} - -void OPPROTO op_load_xer_bc (void) -{ - T1 = xer_bc; - RETURN(); -} - -void OPPROTO op_store_xer_bc (void) -{ - xer_bc = T0; - RETURN(); -} - -void OPPROTO op_load_xer (void) -{ - T0 = hreg_load_xer(env); - RETURN(); -} - -void OPPROTO op_store_xer (void) -{ - hreg_store_xer(env, T0); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_store_pri (void) -{ - do_store_pri(PARAM1); - RETURN(); -} -#endif - #if !defined(CONFIG_USER_ONLY) /* Segment registers load and store */ void OPPROTO op_load_sr (void) @@ -421,30 +155,6 @@ RETURN(); } -void OPPROTO op_load_lr (void) -{ - T0 = env->lr; - RETURN(); -} - -void OPPROTO op_store_lr (void) -{ - env->lr = T0; - RETURN(); -} - -void OPPROTO op_load_ctr (void) -{ - T0 = env->ctr; - RETURN(); -} - -void OPPROTO op_store_ctr (void) -{ - env->ctr = T0; - RETURN(); -} - void OPPROTO op_load_tbl (void) { T0 = cpu_ppc_load_tbl(env); @@ -524,1228 +234,105 @@ env->IBAT[1][PARAM1] = T0; #else do_store_ibatl(env, PARAM1, T0); -#endif - RETURN(); -} - -void OPPROTO op_load_dbat (void) -{ - T0 = env->DBAT[PARAM1][PARAM2]; - RETURN(); -} - -void OPPROTO op_store_dbatu (void) -{ - do_store_dbatu(env, PARAM1, T0); - RETURN(); -} - -void OPPROTO op_store_dbatl (void) -{ -#if 1 - env->DBAT[1][PARAM1] = T0; -#else - do_store_dbatl(env, PARAM1, T0); -#endif - RETURN(); -} -#endif /* !defined(CONFIG_USER_ONLY) */ - -/* FPSCR */ -#ifdef CONFIG_SOFTFLOAT -void OPPROTO op_reset_fpstatus (void) -{ - env->fp_status.float_exception_flags = 0; - RETURN(); -} -#endif - -void OPPROTO op_compute_fprf (void) -{ - do_compute_fprf(PARAM1); - RETURN(); -} - -#ifdef CONFIG_SOFTFLOAT -void OPPROTO op_float_check_status (void) -{ - do_float_check_status(); - RETURN(); -} -#else -void OPPROTO op_float_check_status (void) -{ - if (env->exception_index == POWERPC_EXCP_PROGRAM && - (env->error_code & POWERPC_EXCP_FP)) { - /* Differred floating-point exception after target FPR update */ - if (msr_fe0 != 0 || msr_fe1 != 0) - do_raise_exception_err(env->exception_index, env->error_code); - } - RETURN(); -} -#endif - -#if defined(WORDS_BIGENDIAN) -#define WORD0 0 -#define WORD1 1 -#else -#define WORD0 1 -#define WORD1 0 -#endif -void OPPROTO op_load_fpscr_FT0 (void) -{ - /* The 32 MSB of the target fpr are undefined. - * They'll be zero... - */ - union { - float64 d; - struct { - uint32_t u[2]; - } s; - } u; - - u.s.u[WORD0] = 0; - u.s.u[WORD1] = env->fpscr; - FT0 = u.d; - RETURN(); -} - -void OPPROTO op_set_FT0 (void) -{ - union { - float64 d; - struct { - uint32_t u[2]; - } s; - } u; - - u.s.u[WORD0] = 0; - u.s.u[WORD1] = PARAM1; - FT0 = u.d; - RETURN(); -} -#undef WORD0 -#undef WORD1 - -void OPPROTO op_load_fpscr_T0 (void) -{ - T0 = (env->fpscr >> PARAM1) & 0xF; - RETURN(); -} - -void OPPROTO op_load_fpcc (void) -{ - T0 = fpscr_fpcc; - RETURN(); -} - -void OPPROTO op_fpscr_resetbit (void) -{ - env->fpscr &= PARAM1; - RETURN(); -} - -void OPPROTO op_fpscr_setbit (void) -{ - do_fpscr_setbit(PARAM1); - RETURN(); -} - -void OPPROTO op_store_fpscr (void) -{ - do_store_fpscr(PARAM1); - RETURN(); -} - -/* Branch */ -#define EIP env->nip - -void OPPROTO op_setlr (void) -{ - env->lr = (uint32_t)PARAM1; - RETURN(); -} - -#if defined (TARGET_PPC64) -void OPPROTO op_setlr_64 (void) -{ - env->lr = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2; - RETURN(); -} -#endif - -void OPPROTO op_goto_tb0 (void) -{ - GOTO_TB(op_goto_tb0, PARAM1, 0); -} - -void OPPROTO op_goto_tb1 (void) -{ - GOTO_TB(op_goto_tb1, PARAM1, 1); -} - -void OPPROTO op_b_T1 (void) -{ - env->nip = (uint32_t)(T1 & ~3); - RETURN(); -} - -#if defined (TARGET_PPC64) -void OPPROTO op_b_T1_64 (void) -{ - env->nip = (uint64_t)(T1 & ~3); - RETURN(); -} -#endif - -void OPPROTO op_jz_T0 (void) -{ - if (!T0) - GOTO_LABEL_PARAM(1); - RETURN(); -} - -void OPPROTO op_btest_T1 (void) -{ - if (T0) { - env->nip = (uint32_t)(T1 & ~3); - } else { - env->nip = (uint32_t)PARAM1; - } - RETURN(); -} - -#if defined (TARGET_PPC64) -void OPPROTO op_btest_T1_64 (void) -{ - if (T0) { - env->nip = (uint64_t)(T1 & ~3); - } else { - env->nip = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2; - } - RETURN(); -} -#endif - -void OPPROTO op_movl_T1_ctr (void) -{ - T1 = env->ctr; - RETURN(); -} - -void OPPROTO op_movl_T1_lr (void) -{ - T1 = env->lr; - RETURN(); -} - -/* tests with result in T0 */ -void OPPROTO op_test_ctr (void) -{ - T0 = (uint32_t)env->ctr; - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_test_ctr_64 (void) -{ - T0 = (uint64_t)env->ctr; - RETURN(); -} -#endif - -void OPPROTO op_test_ctr_true (void) -{ - T0 = ((uint32_t)env->ctr != 0 && (T0 & PARAM1) != 0); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_test_ctr_true_64 (void) -{ - T0 = ((uint64_t)env->ctr != 0 && (T0 & PARAM1) != 0); - RETURN(); -} -#endif - -void OPPROTO op_test_ctr_false (void) -{ - T0 = ((uint32_t)env->ctr != 0 && (T0 & PARAM1) == 0); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_test_ctr_false_64 (void) -{ - T0 = ((uint64_t)env->ctr != 0 && (T0 & PARAM1) == 0); - RETURN(); -} -#endif - -void OPPROTO op_test_ctrz (void) -{ - T0 = ((uint32_t)env->ctr == 0); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_test_ctrz_64 (void) -{ - T0 = ((uint64_t)env->ctr == 0); - RETURN(); -} -#endif - -void OPPROTO op_test_ctrz_true (void) -{ - T0 = ((uint32_t)env->ctr == 0 && (T0 & PARAM1) != 0); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_test_ctrz_true_64 (void) -{ - T0 = ((uint64_t)env->ctr == 0 && (T0 & PARAM1) != 0); - RETURN(); -} -#endif - -void OPPROTO op_test_ctrz_false (void) -{ - T0 = ((uint32_t)env->ctr == 0 && (T0 & PARAM1) == 0); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_test_ctrz_false_64 (void) -{ - T0 = ((uint64_t)env->ctr == 0 && (T0 & PARAM1) == 0); - RETURN(); -} -#endif - -void OPPROTO op_test_true (void) -{ - T0 = (T0 & PARAM1); - RETURN(); -} - -void OPPROTO op_test_false (void) -{ - T0 = ((T0 & PARAM1) == 0); - RETURN(); -} - -/* CTR maintenance */ -void OPPROTO op_dec_ctr (void) -{ - env->ctr--; - RETURN(); -} - -/*** Integer arithmetic ***/ -/* add */ -void OPPROTO op_add (void) -{ - T0 += T1; - RETURN(); -} - -void OPPROTO op_check_addo (void) -{ - xer_ov = (((uint32_t)T2 ^ (uint32_t)T1 ^ UINT32_MAX) & - ((uint32_t)T2 ^ (uint32_t)T0)) >> 31; - xer_so |= xer_ov; - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_check_addo_64 (void) -{ - xer_ov = (((uint64_t)T2 ^ (uint64_t)T1 ^ UINT64_MAX) & - ((uint64_t)T2 ^ (uint64_t)T0)) >> 63; - xer_so |= xer_ov; - RETURN(); -} -#endif - -/* add carrying */ -void OPPROTO op_check_addc (void) -{ - if (likely((uint32_t)T0 >= (uint32_t)T2)) { - xer_ca = 0; - } else { - xer_ca = 1; - } - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_check_addc_64 (void) -{ - if (likely((uint64_t)T0 >= (uint64_t)T2)) { - xer_ca = 0; - } else { - xer_ca = 1; - } - RETURN(); -} -#endif - -/* add extended */ -void OPPROTO op_adde (void) -{ - do_adde(); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_adde_64 (void) -{ - do_adde_64(); - RETURN(); -} -#endif - -/* add immediate */ -void OPPROTO op_addi (void) -{ - T0 += (int32_t)PARAM1; - RETURN(); -} - -/* add to minus one extended */ -void OPPROTO op_add_me (void) -{ - T0 += xer_ca + (-1); - if (likely((uint32_t)T1 != 0)) - xer_ca = 1; - else - xer_ca = 0; - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_add_me_64 (void) -{ - T0 += xer_ca + (-1); - if (likely((uint64_t)T1 != 0)) - xer_ca = 1; - else - xer_ca = 0; - RETURN(); -} -#endif - -void OPPROTO op_addmeo (void) -{ - do_addmeo(); - RETURN(); -} - -void OPPROTO op_addmeo_64 (void) -{ - do_addmeo(); - RETURN(); -} - -/* add to zero extended */ -void OPPROTO op_add_ze (void) -{ - T0 += xer_ca; - RETURN(); -} - -/* divide word */ -void OPPROTO op_divw (void) -{ - if (unlikely(((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) || - (int32_t)T1 == 0)) { - T0 = (int32_t)(UINT32_MAX * ((uint32_t)T0 >> 31)); - } else { - T0 = (int32_t)T0 / (int32_t)T1; - } - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_divd (void) -{ - if (unlikely(((int64_t)T0 == INT64_MIN && (int64_t)T1 == (int64_t)-1LL) || - (int64_t)T1 == 0)) { - T0 = (int64_t)(UINT64_MAX * ((uint64_t)T0 >> 63)); - } else { - T0 = (int64_t)T0 / (int64_t)T1; - } - RETURN(); -} -#endif - -void OPPROTO op_divwo (void) -{ - do_divwo(); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_divdo (void) -{ - do_divdo(); - RETURN(); -} -#endif - -/* divide word unsigned */ -void OPPROTO op_divwu (void) -{ - if (unlikely(T1 == 0)) { - T0 = 0; - } else { - T0 = (uint32_t)T0 / (uint32_t)T1; - } - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_divdu (void) -{ - if (unlikely(T1 == 0)) { - T0 = 0; - } else { - T0 /= T1; - } - RETURN(); -} -#endif - -void OPPROTO op_divwuo (void) -{ - do_divwuo(); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_divduo (void) -{ - do_divduo(); - RETURN(); -} -#endif - -/* multiply high word */ -void OPPROTO op_mulhw (void) -{ - T0 = ((int64_t)((int32_t)T0) * (int64_t)((int32_t)T1)) >> 32; - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_mulhd (void) -{ - uint64_t tl, th; - - muls64(&tl, &th, T0, T1); - T0 = th; - RETURN(); -} -#endif - -/* multiply high word unsigned */ -void OPPROTO op_mulhwu (void) -{ - T0 = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1) >> 32; - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_mulhdu (void) -{ - uint64_t tl, th; - - mulu64(&tl, &th, T0, T1); - T0 = th; - RETURN(); -} -#endif - -/* multiply low immediate */ -void OPPROTO op_mulli (void) -{ - T0 = ((int32_t)T0 * (int32_t)PARAM1); - RETURN(); -} - -/* multiply low word */ -void OPPROTO op_mullw (void) -{ - T0 = (int32_t)(T0 * T1); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_mulld (void) -{ - T0 *= T1; - RETURN(); -} -#endif - -void OPPROTO op_mullwo (void) -{ - do_mullwo(); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_mulldo (void) -{ - do_mulldo(); - RETURN(); -} -#endif - -/* negate */ -void OPPROTO op_neg (void) -{ - if (likely(T0 != INT32_MIN)) { - T0 = -(int32_t)T0; - } - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_neg_64 (void) -{ - if (likely(T0 != INT64_MIN)) { - T0 = -(int64_t)T0; - } - RETURN(); -} -#endif - -void OPPROTO op_nego (void) -{ - do_nego(); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_nego_64 (void) -{ - do_nego_64(); - RETURN(); -} -#endif - -/* subtract from */ -void OPPROTO op_subf (void) -{ - T0 = T1 - T0; - RETURN(); -} - -/* subtract from carrying */ -void OPPROTO op_check_subfc (void) -{ - if (likely((uint32_t)T0 > (uint32_t)T1)) { - xer_ca = 0; - } else { - xer_ca = 1; - } - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_check_subfc_64 (void) -{ - if (likely((uint64_t)T0 > (uint64_t)T1)) { - xer_ca = 0; - } else { - xer_ca = 1; - } - RETURN(); -} -#endif - -/* subtract from extended */ -void OPPROTO op_subfe (void) -{ - do_subfe(); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_subfe_64 (void) -{ - do_subfe_64(); - RETURN(); -} -#endif - -/* subtract from immediate carrying */ -void OPPROTO op_subfic (void) -{ - T0 = (int32_t)PARAM1 + ~T0 + 1; - if ((uint32_t)T0 <= (uint32_t)PARAM1) { - xer_ca = 1; - } else { - xer_ca = 0; - } - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_subfic_64 (void) -{ - T0 = (int64_t)PARAM1 + ~T0 + 1; - if ((uint64_t)T0 <= (uint64_t)PARAM1) { - xer_ca = 1; - } else { - xer_ca = 0; - } - RETURN(); -} -#endif - -/* subtract from minus one extended */ -void OPPROTO op_subfme (void) -{ - T0 = ~T0 + xer_ca - 1; - if (likely((uint32_t)T0 != UINT32_MAX)) - xer_ca = 1; - else - xer_ca = 0; - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_subfme_64 (void) -{ - T0 = ~T0 + xer_ca - 1; - if (likely((uint64_t)T0 != UINT64_MAX)) - xer_ca = 1; - else - xer_ca = 0; - RETURN(); -} -#endif - -void OPPROTO op_subfmeo (void) -{ - do_subfmeo(); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_subfmeo_64 (void) -{ - do_subfmeo_64(); - RETURN(); -} -#endif - -/* subtract from zero extended */ -void OPPROTO op_subfze (void) -{ - T1 = ~T0; - T0 = T1 + xer_ca; - if ((uint32_t)T0 < (uint32_t)T1) { - xer_ca = 1; - } else { - xer_ca = 0; - } - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_subfze_64 (void) -{ - T1 = ~T0; - T0 = T1 + xer_ca; - if ((uint64_t)T0 < (uint64_t)T1) { - xer_ca = 1; - } else { - xer_ca = 0; - } - RETURN(); -} -#endif - -void OPPROTO op_subfzeo (void) -{ - do_subfzeo(); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_subfzeo_64 (void) -{ - do_subfzeo_64(); - RETURN(); -} -#endif - -/*** Integer comparison ***/ -/* compare */ -void OPPROTO op_cmp (void) -{ - if ((int32_t)T0 < (int32_t)T1) { - T0 = 0x08; - } else if ((int32_t)T0 > (int32_t)T1) { - T0 = 0x04; - } else { - T0 = 0x02; - } - T0 |= xer_so; - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_cmp_64 (void) -{ - if ((int64_t)T0 < (int64_t)T1) { - T0 = 0x08; - } else if ((int64_t)T0 > (int64_t)T1) { - T0 = 0x04; - } else { - T0 = 0x02; - } - T0 |= xer_so; - RETURN(); -} -#endif - -/* compare immediate */ -void OPPROTO op_cmpi (void) -{ - if ((int32_t)T0 < (int32_t)PARAM1) { - T0 = 0x08; - } else if ((int32_t)T0 > (int32_t)PARAM1) { - T0 = 0x04; - } else { - T0 = 0x02; - } - T0 |= xer_so; - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_cmpi_64 (void) -{ - if ((int64_t)T0 < (int64_t)((int32_t)PARAM1)) { - T0 = 0x08; - } else if ((int64_t)T0 > (int64_t)((int32_t)PARAM1)) { - T0 = 0x04; - } else { - T0 = 0x02; - } - T0 |= xer_so; - RETURN(); -} -#endif - -/* compare logical */ -void OPPROTO op_cmpl (void) -{ - if ((uint32_t)T0 < (uint32_t)T1) { - T0 = 0x08; - } else if ((uint32_t)T0 > (uint32_t)T1) { - T0 = 0x04; - } else { - T0 = 0x02; - } - T0 |= xer_so; - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_cmpl_64 (void) -{ - if ((uint64_t)T0 < (uint64_t)T1) { - T0 = 0x08; - } else if ((uint64_t)T0 > (uint64_t)T1) { - T0 = 0x04; - } else { - T0 = 0x02; - } - T0 |= xer_so; - RETURN(); -} -#endif - -/* compare logical immediate */ -void OPPROTO op_cmpli (void) -{ - if ((uint32_t)T0 < (uint32_t)PARAM1) { - T0 = 0x08; - } else if ((uint32_t)T0 > (uint32_t)PARAM1) { - T0 = 0x04; - } else { - T0 = 0x02; - } - T0 |= xer_so; - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_cmpli_64 (void) -{ - if ((uint64_t)T0 < (uint64_t)PARAM1) { - T0 = 0x08; - } else if ((uint64_t)T0 > (uint64_t)PARAM1) { - T0 = 0x04; - } else { - T0 = 0x02; - } - T0 |= xer_so; - RETURN(); -} -#endif - -void OPPROTO op_isel (void) -{ - if (T0) - T0 = T1; - else - T0 = T2; - RETURN(); -} - -void OPPROTO op_popcntb (void) -{ - do_popcntb(); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_popcntb_64 (void) -{ - do_popcntb_64(); - RETURN(); -} -#endif - -/*** Integer logical ***/ -/* and */ -void OPPROTO op_and (void) -{ - T0 &= T1; - RETURN(); -} - -/* andc */ -void OPPROTO op_andc (void) -{ - T0 &= ~T1; - RETURN(); -} - -/* andi. */ -void OPPROTO op_andi_T0 (void) -{ - T0 &= (uint32_t)PARAM1; - RETURN(); -} - -void OPPROTO op_andi_T1 (void) -{ - T1 &= (uint32_t)PARAM1; - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_andi_T0_64 (void) -{ - T0 &= ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2; - RETURN(); -} - -void OPPROTO op_andi_T1_64 (void) -{ - T1 &= ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2; - RETURN(); -} -#endif - -/* count leading zero */ -void OPPROTO op_cntlzw (void) -{ - do_cntlzw(); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_cntlzd (void) -{ - do_cntlzd(); - RETURN(); -} -#endif - -/* eqv */ -void OPPROTO op_eqv (void) -{ - T0 = ~(T0 ^ T1); - RETURN(); -} - -/* extend sign byte */ -void OPPROTO op_extsb (void) -{ -#if defined (TARGET_PPC64) - T0 = (int64_t)((int8_t)T0); -#else - T0 = (int32_t)((int8_t)T0); -#endif - RETURN(); -} - -/* extend sign half word */ -void OPPROTO op_extsh (void) -{ -#if defined (TARGET_PPC64) - T0 = (int64_t)((int16_t)T0); -#else - T0 = (int32_t)((int16_t)T0); -#endif - RETURN(); -} - -#if defined (TARGET_PPC64) -void OPPROTO op_extsw (void) -{ - T0 = (int64_t)((int32_t)T0); - RETURN(); -} -#endif - -/* nand */ -void OPPROTO op_nand (void) -{ - T0 = ~(T0 & T1); - RETURN(); -} - -/* nor */ -void OPPROTO op_nor (void) -{ - T0 = ~(T0 | T1); - RETURN(); -} - -/* or */ -void OPPROTO op_or (void) -{ - T0 |= T1; - RETURN(); -} - -/* orc */ -void OPPROTO op_orc (void) -{ - T0 |= ~T1; - RETURN(); -} - -/* ori */ -void OPPROTO op_ori (void) -{ - T0 |= (uint32_t)PARAM1; - RETURN(); -} - -/* xor */ -void OPPROTO op_xor (void) -{ - T0 ^= T1; - RETURN(); -} - -/* xori */ -void OPPROTO op_xori (void) -{ - T0 ^= (uint32_t)PARAM1; - RETURN(); -} - -/*** Integer rotate ***/ -void OPPROTO op_rotl32_T0_T1 (void) -{ - T0 = rotl32(T0, T1 & 0x1F); - RETURN(); -} - -void OPPROTO op_rotli32_T0 (void) -{ - T0 = rotl32(T0, PARAM1); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_rotl64_T0_T1 (void) -{ - T0 = rotl64(T0, T1 & 0x3F); - RETURN(); -} - -void OPPROTO op_rotli64_T0 (void) -{ - T0 = rotl64(T0, PARAM1); - RETURN(); -} -#endif - -/*** Integer shift ***/ -/* shift left word */ -void OPPROTO op_slw (void) -{ - if (T1 & 0x20) { - T0 = 0; - } else { - T0 = (uint32_t)(T0 << T1); - } - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_sld (void) -{ - if (T1 & 0x40) { - T0 = 0; - } else { - T0 = T0 << T1; - } - RETURN(); -} -#endif - -/* shift right algebraic word */ -void OPPROTO op_sraw (void) -{ - do_sraw(); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_srad (void) -{ - do_srad(); +#endif RETURN(); } -#endif -/* shift right algebraic word immediate */ -void OPPROTO op_srawi (void) +void OPPROTO op_load_dbat (void) { - uint32_t mask = (uint32_t)PARAM2; - - T0 = (int32_t)T0 >> PARAM1; - if ((int32_t)T1 < 0 && (T1 & mask) != 0) { - xer_ca = 1; - } else { - xer_ca = 0; - } + T0 = env->DBAT[PARAM1][PARAM2]; RETURN(); } -#if defined(TARGET_PPC64) -void OPPROTO op_sradi (void) +void OPPROTO op_store_dbatu (void) { - uint64_t mask = ((uint64_t)PARAM2 << 32) | (uint64_t)PARAM3; - - T0 = (int64_t)T0 >> PARAM1; - if ((int64_t)T1 < 0 && ((uint64_t)T1 & mask) != 0) { - xer_ca = 1; - } else { - xer_ca = 0; - } + do_store_dbatu(env, PARAM1, T0); RETURN(); } -#endif -/* shift right word */ -void OPPROTO op_srw (void) +void OPPROTO op_store_dbatl (void) { - if (T1 & 0x20) { - T0 = 0; - } else { - T0 = (uint32_t)T0 >> T1; - } +#if 1 + env->DBAT[1][PARAM1] = T0; +#else + do_store_dbatl(env, PARAM1, T0); +#endif RETURN(); } +#endif /* !defined(CONFIG_USER_ONLY) */ -#if defined(TARGET_PPC64) -void OPPROTO op_srd (void) +/* FPSCR */ +#ifdef CONFIG_SOFTFLOAT +void OPPROTO op_reset_fpstatus (void) { - if (T1 & 0x40) { - T0 = 0; - } else { - T0 = (uint64_t)T0 >> T1; - } + env->fp_status.float_exception_flags = 0; RETURN(); } #endif -void OPPROTO op_sl_T0_T1 (void) +void OPPROTO op_compute_fprf (void) { - T0 = T0 << T1; + do_compute_fprf(PARAM1); RETURN(); } -void OPPROTO op_sli_T0 (void) +#ifdef CONFIG_SOFTFLOAT +void OPPROTO op_float_check_status (void) { - T0 = T0 << PARAM1; + do_float_check_status(); RETURN(); } - -void OPPROTO op_sli_T1 (void) +#else +void OPPROTO op_float_check_status (void) { - T1 = T1 << PARAM1; + if (env->exception_index == POWERPC_EXCP_PROGRAM && + (env->error_code & POWERPC_EXCP_FP)) { + /* Differred floating-point exception after target FPR update */ + if (msr_fe0 != 0 || msr_fe1 != 0) + do_raise_exception_err(env->exception_index, env->error_code); + } RETURN(); } +#endif -void OPPROTO op_srl_T0_T1 (void) +void OPPROTO op_load_fpscr_FT0 (void) { - T0 = (uint32_t)T0 >> T1; + /* The 32 MSB of the target fpr are undefined. + * They'll be zero... + */ + CPU_DoubleU u; + + u.l.upper = 0; + u.l.lower = env->fpscr; + FT0 = u.d; RETURN(); } -#if defined(TARGET_PPC64) -void OPPROTO op_srl_T0_T1_64 (void) +void OPPROTO op_fpscr_resetbit (void) { - T0 = (uint32_t)T0 >> T1; + env->fpscr &= PARAM1; RETURN(); } -#endif -void OPPROTO op_srli_T0 (void) +void OPPROTO op_fpscr_setbit (void) { - T0 = (uint32_t)T0 >> PARAM1; + do_fpscr_setbit(PARAM1); RETURN(); } -#if defined(TARGET_PPC64) -void OPPROTO op_srli_T0_64 (void) +void OPPROTO op_store_fpscr (void) { - T0 = (uint64_t)T0 >> PARAM1; + do_store_fpscr(PARAM1); RETURN(); } -#endif +/*** Integer shift ***/ void OPPROTO op_srli_T1 (void) { T1 = (uint32_t)T1 >> PARAM1; RETURN(); } -#if defined(TARGET_PPC64) -void OPPROTO op_srli_T1_64 (void) -{ - T1 = (uint64_t)T1 >> PARAM1; - RETURN(); -} -#endif - /*** Floating-Point arithmetic ***/ /* fadd - fadd. */ void OPPROTO op_fadd (void) @@ -1938,21 +525,6 @@ RETURN(); } -/*** Floating-Point compare ***/ -/* fcmpu */ -void OPPROTO op_fcmpu (void) -{ - do_fcmpu(); - RETURN(); -} - -/* fcmpo */ -void OPPROTO op_fcmpo (void) -{ - do_fcmpo(); - RETURN(); -} - /*** Floating-point move ***/ /* fabs */ void OPPROTO op_fabs (void) @@ -2299,7 +871,7 @@ /* nabs never overflows */ if (T0 > 0) T0 = -T0; - xer_ov = 0; + env->xer &= ~(1 << XER_OV); RETURN(); } @@ -2462,74 +1034,6 @@ #endif /* PowerPC 4xx specific micro-ops */ -void OPPROTO op_405_add_T0_T2 (void) -{ - T0 = (int32_t)T0 + (int32_t)T2; - RETURN(); -} - -void OPPROTO op_405_mulchw (void) -{ - T0 = ((int16_t)T0) * ((int16_t)(T1 >> 16)); - RETURN(); -} - -void OPPROTO op_405_mulchwu (void) -{ - T0 = ((uint16_t)T0) * ((uint16_t)(T1 >> 16)); - RETURN(); -} - -void OPPROTO op_405_mulhhw (void) -{ - T0 = ((int16_t)(T0 >> 16)) * ((int16_t)(T1 >> 16)); - RETURN(); -} - -void OPPROTO op_405_mulhhwu (void) -{ - T0 = ((uint16_t)(T0 >> 16)) * ((uint16_t)(T1 >> 16)); - RETURN(); -} - -void OPPROTO op_405_mullhw (void) -{ - T0 = ((int16_t)T0) * ((int16_t)T1); - RETURN(); -} - -void OPPROTO op_405_mullhwu (void) -{ - T0 = ((uint16_t)T0) * ((uint16_t)T1); - RETURN(); -} - -void OPPROTO op_405_check_sat (void) -{ - do_405_check_sat(); - RETURN(); -} - -void OPPROTO op_405_check_ovu (void) -{ - if (likely(T0 >= T2)) { - xer_ov = 0; - } else { - xer_ov = 1; - xer_so = 1; - } - RETURN(); -} - -void OPPROTO op_405_check_satu (void) -{ - if (unlikely(T0 < T2)) { - /* Saturate result */ - T0 = UINT32_MAX; - } - RETURN(); -} - void OPPROTO op_load_dcr (void) { do_load_dcr(); @@ -2723,22 +1227,6 @@ RETURN(); } -void OPPROTO op_splatwi_T0_64 (void) -{ - uint64_t tmp = PARAM1; - - T0_64 = (tmp << 32) | tmp; - RETURN(); -} - -void OPPROTO op_splatwi_T1_64 (void) -{ - uint64_t tmp = PARAM1; - - T1_64 = (tmp << 32) | tmp; - RETURN(); -} - void OPPROTO op_extsh_T1_64 (void) { T1_64 = (int32_t)((int16_t)T1_64); @@ -2763,200 +1251,6 @@ RETURN(); } -void OPPROTO op_evsel (void) -{ - do_evsel(); - RETURN(); -} - -void OPPROTO op_evaddw (void) -{ - do_evaddw(); - RETURN(); -} - -void OPPROTO op_evsubfw (void) -{ - do_evsubfw(); - RETURN(); -} - -void OPPROTO op_evneg (void) -{ - do_evneg(); - RETURN(); -} - -void OPPROTO op_evabs (void) -{ - do_evabs(); - RETURN(); -} - -void OPPROTO op_evextsh (void) -{ - T0_64 = ((uint64_t)((int32_t)(int16_t)(T0_64 >> 32)) << 32) | - (uint64_t)((int32_t)(int16_t)T0_64); - RETURN(); -} - -void OPPROTO op_evextsb (void) -{ - T0_64 = ((uint64_t)((int32_t)(int8_t)(T0_64 >> 32)) << 32) | - (uint64_t)((int32_t)(int8_t)T0_64); - RETURN(); -} - -void OPPROTO op_evcntlzw (void) -{ - do_evcntlzw(); - RETURN(); -} - -void OPPROTO op_evrndw (void) -{ - do_evrndw(); - RETURN(); -} - -void OPPROTO op_brinc (void) -{ - do_brinc(); - RETURN(); -} - -void OPPROTO op_evcntlsw (void) -{ - do_evcntlsw(); - RETURN(); -} - -void OPPROTO op_evand (void) -{ - T0_64 &= T1_64; - RETURN(); -} - -void OPPROTO op_evandc (void) -{ - T0_64 &= ~T1_64; - RETURN(); -} - -void OPPROTO op_evor (void) -{ - T0_64 |= T1_64; - RETURN(); -} - -void OPPROTO op_evxor (void) -{ - T0_64 ^= T1_64; - RETURN(); -} - -void OPPROTO op_eveqv (void) -{ - T0_64 = ~(T0_64 ^ T1_64); - RETURN(); -} - -void OPPROTO op_evnor (void) -{ - T0_64 = ~(T0_64 | T1_64); - RETURN(); -} - -void OPPROTO op_evorc (void) -{ - T0_64 |= ~T1_64; - RETURN(); -} - -void OPPROTO op_evnand (void) -{ - T0_64 = ~(T0_64 & T1_64); - RETURN(); -} - -void OPPROTO op_evsrws (void) -{ - do_evsrws(); - RETURN(); -} - -void OPPROTO op_evsrwu (void) -{ - do_evsrwu(); - RETURN(); -} - -void OPPROTO op_evslw (void) -{ - do_evslw(); - RETURN(); -} - -void OPPROTO op_evrlw (void) -{ - do_evrlw(); - RETURN(); -} - -void OPPROTO op_evmergelo (void) -{ - T0_64 = (T0_64 << 32) | (T1_64 & 0x00000000FFFFFFFFULL); - RETURN(); -} - -void OPPROTO op_evmergehi (void) -{ - T0_64 = (T0_64 & 0xFFFFFFFF00000000ULL) | (T1_64 >> 32); - RETURN(); -} - -void OPPROTO op_evmergelohi (void) -{ - T0_64 = (T0_64 << 32) | (T1_64 >> 32); - RETURN(); -} - -void OPPROTO op_evmergehilo (void) -{ - T0_64 = (T0_64 & 0xFFFFFFFF00000000ULL) | (T1_64 & 0x00000000FFFFFFFFULL); - RETURN(); -} - -void OPPROTO op_evcmpgts (void) -{ - do_evcmpgts(); - RETURN(); -} - -void OPPROTO op_evcmpgtu (void) -{ - do_evcmpgtu(); - RETURN(); -} - -void OPPROTO op_evcmplts (void) -{ - do_evcmplts(); - RETURN(); -} - -void OPPROTO op_evcmpltu (void) -{ - do_evcmpltu(); - RETURN(); -} - -void OPPROTO op_evcmpeq (void) -{ - do_evcmpeq(); - RETURN(); -} - void OPPROTO op_evfssub (void) { do_evfssub(); @@ -3241,27 +1535,21 @@ void OPPROTO op_efdsub (void) { - union { - uint64_t u; - float64 f; - } u1, u2; - u1.u = T0_64; - u2.u = T1_64; - u1.f = float64_sub(u1.f, u2.f, &env->spe_status); - T0_64 = u1.u; + CPU_DoubleU u1, u2; + u1.ll = T0_64; + u2.ll = T1_64; + u1.d = float64_sub(u1.d, u2.d, &env->spe_status); + T0_64 = u1.ll; RETURN(); } void OPPROTO op_efdadd (void) { - union { - uint64_t u; - float64 f; - } u1, u2; - u1.u = T0_64; - u2.u = T1_64; - u1.f = float64_add(u1.f, u2.f, &env->spe_status); - T0_64 = u1.u; + CPU_DoubleU u1, u2; + u1.ll = T0_64; + u2.ll = T1_64; + u1.d = float64_add(u1.d, u2.d, &env->spe_status); + T0_64 = u1.ll; RETURN(); } @@ -3297,27 +1585,21 @@ void OPPROTO op_efddiv (void) { - union { - uint64_t u; - float64 f; - } u1, u2; - u1.u = T0_64; - u2.u = T1_64; - u1.f = float64_div(u1.f, u2.f, &env->spe_status); - T0_64 = u1.u; + CPU_DoubleU u1, u2; + u1.ll = T0_64; + u2.ll = T1_64; + u1.d = float64_div(u1.d, u2.d, &env->spe_status); + T0_64 = u1.ll; RETURN(); } void OPPROTO op_efdmul (void) { - union { - uint64_t u; - float64 f; - } u1, u2; - u1.u = T0_64; - u2.u = T1_64; - u1.f = float64_mul(u1.f, u2.f, &env->spe_status); - T0_64 = u1.u; + CPU_DoubleU u1, u2; + u1.ll = T0_64; + u2.ll = T1_64; + u1.d = float64_mul(u1.d, u2.d, &env->spe_status); + T0_64 = u1.ll; RETURN(); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-ppc/op_helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-ppc/op_helper.c --- qemu-0.9.1/target-ppc/op_helper.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-ppc/op_helper.c 2008-11-10 11:10:23.000000000 +0000 @@ -60,33 +60,27 @@ do_raise_exception_err(exception, 0); } -void cpu_dump_EA (target_ulong EA); -void do_print_mem_EA (target_ulong EA) -{ - cpu_dump_EA(EA); -} - /*****************************************************************************/ /* Registers load and stores */ -void do_load_cr (void) +uint32_t helper_load_cr (void) { - T0 = (env->crf[0] << 28) | - (env->crf[1] << 24) | - (env->crf[2] << 20) | - (env->crf[3] << 16) | - (env->crf[4] << 12) | - (env->crf[5] << 8) | - (env->crf[6] << 4) | - (env->crf[7] << 0); + return (env->crf[0] << 28) | + (env->crf[1] << 24) | + (env->crf[2] << 20) | + (env->crf[3] << 16) | + (env->crf[4] << 12) | + (env->crf[5] << 8) | + (env->crf[6] << 4) | + (env->crf[7] << 0); } -void do_store_cr (uint32_t mask) +void helper_store_cr (target_ulong val, uint32_t mask) { int i, sh; for (i = 0, sh = 7; i < 8; i++, sh--) { if (mask & (1 << sh)) - env->crf[i] = (T0 >> (sh * 4)) & 0xFUL; + env->crf[i] = (val >> (sh * 4)) & 0xFUL; } } @@ -119,391 +113,191 @@ /*****************************************************************************/ /* Fixed point operations helpers */ -void do_adde (void) -{ - T2 = T0; - T0 += T1 + xer_ca; - if (likely(!((uint32_t)T0 < (uint32_t)T2 || - (xer_ca == 1 && (uint32_t)T0 == (uint32_t)T2)))) { - xer_ca = 0; - } else { - xer_ca = 1; - } -} - -#if defined(TARGET_PPC64) -void do_adde_64 (void) -{ - T2 = T0; - T0 += T1 + xer_ca; - if (likely(!((uint64_t)T0 < (uint64_t)T2 || - (xer_ca == 1 && (uint64_t)T0 == (uint64_t)T2)))) { - xer_ca = 0; - } else { - xer_ca = 1; - } -} -#endif - -void do_addmeo (void) -{ - T1 = T0; - T0 += xer_ca + (-1); - xer_ov = ((uint32_t)T1 & ((uint32_t)T1 ^ (uint32_t)T0)) >> 31; - xer_so |= xer_ov; - if (likely(T1 != 0)) - xer_ca = 1; - else - xer_ca = 0; -} - -#if defined(TARGET_PPC64) -void do_addmeo_64 (void) -{ - T1 = T0; - T0 += xer_ca + (-1); - xer_ov = ((uint64_t)T1 & ((uint64_t)T1 ^ (uint64_t)T0)) >> 63; - xer_so |= xer_ov; - if (likely(T1 != 0)) - xer_ca = 1; - else - xer_ca = 0; -} -#endif - -void do_divwo (void) -{ - if (likely(!(((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) || - (int32_t)T1 == 0))) { - xer_ov = 0; - T0 = (int32_t)T0 / (int32_t)T1; - } else { - xer_ov = 1; - T0 = UINT32_MAX * ((uint32_t)T0 >> 31); - } - xer_so |= xer_ov; -} - #if defined(TARGET_PPC64) -void do_divdo (void) -{ - if (likely(!(((int64_t)T0 == INT64_MIN && (int64_t)T1 == (int64_t)-1LL) || - (int64_t)T1 == 0))) { - xer_ov = 0; - T0 = (int64_t)T0 / (int64_t)T1; - } else { - xer_ov = 1; - T0 = UINT64_MAX * ((uint64_t)T0 >> 63); - } - xer_so |= xer_ov; -} -#endif -void do_divwuo (void) +/* multiply high word */ +uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2) { - if (likely((uint32_t)T1 != 0)) { - xer_ov = 0; - T0 = (uint32_t)T0 / (uint32_t)T1; - } else { - xer_ov = 1; - xer_so = 1; - T0 = 0; - } -} + uint64_t tl, th; -#if defined(TARGET_PPC64) -void do_divduo (void) -{ - if (likely((uint64_t)T1 != 0)) { - xer_ov = 0; - T0 = (uint64_t)T0 / (uint64_t)T1; - } else { - xer_ov = 1; - xer_so = 1; - T0 = 0; - } + muls64(&tl, &th, arg1, arg2); + return th; } -#endif -void do_mullwo (void) +/* multiply high word unsigned */ +uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2) { - int64_t res = (int64_t)T0 * (int64_t)T1; + uint64_t tl, th; - if (likely((int32_t)res == res)) { - xer_ov = 0; - } else { - xer_ov = 1; - xer_so = 1; - } - T0 = (int32_t)res; + mulu64(&tl, &th, arg1, arg2); + return th; } -#if defined(TARGET_PPC64) -void do_mulldo (void) +uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2) { int64_t th; uint64_t tl; - muls64(&tl, &th, T0, T1); - T0 = (int64_t)tl; + muls64(&tl, (uint64_t *)&th, arg1, arg2); /* If th != 0 && th != -1, then we had an overflow */ if (likely((uint64_t)(th + 1) <= 1)) { - xer_ov = 0; + env->xer &= ~(1 << XER_OV); } else { - xer_ov = 1; + env->xer |= (1 << XER_OV) | (1 << XER_SO); } - xer_so |= xer_ov; + return (int64_t)tl; } #endif -void do_nego (void) +target_ulong helper_cntlzw (target_ulong t) { - if (likely((int32_t)T0 != INT32_MIN)) { - xer_ov = 0; - T0 = -(int32_t)T0; - } else { - xer_ov = 1; - xer_so = 1; - } + return clz32(t); } #if defined(TARGET_PPC64) -void do_nego_64 (void) +target_ulong helper_cntlzd (target_ulong t) { - if (likely((int64_t)T0 != INT64_MIN)) { - xer_ov = 0; - T0 = -(int64_t)T0; - } else { - xer_ov = 1; - xer_so = 1; - } -} -#endif - -void do_subfe (void) -{ - T0 = T1 + ~T0 + xer_ca; - if (likely((uint32_t)T0 >= (uint32_t)T1 && - (xer_ca == 0 || (uint32_t)T0 != (uint32_t)T1))) { - xer_ca = 0; - } else { - xer_ca = 1; - } -} - -#if defined(TARGET_PPC64) -void do_subfe_64 (void) -{ - T0 = T1 + ~T0 + xer_ca; - if (likely((uint64_t)T0 >= (uint64_t)T1 && - (xer_ca == 0 || (uint64_t)T0 != (uint64_t)T1))) { - xer_ca = 0; - } else { - xer_ca = 1; - } -} -#endif - -void do_subfmeo (void) -{ - T1 = T0; - T0 = ~T0 + xer_ca - 1; - xer_ov = ((uint32_t)~T1 & ((uint32_t)~T1 ^ (uint32_t)T0)) >> 31; - xer_so |= xer_ov; - if (likely((uint32_t)T1 != UINT32_MAX)) - xer_ca = 1; - else - xer_ca = 0; -} - -#if defined(TARGET_PPC64) -void do_subfmeo_64 (void) -{ - T1 = T0; - T0 = ~T0 + xer_ca - 1; - xer_ov = ((uint64_t)~T1 & ((uint64_t)~T1 ^ (uint64_t)T0)) >> 63; - xer_so |= xer_ov; - if (likely((uint64_t)T1 != UINT64_MAX)) - xer_ca = 1; - else - xer_ca = 0; -} -#endif - -void do_subfzeo (void) -{ - T1 = T0; - T0 = ~T0 + xer_ca; - xer_ov = (((uint32_t)~T1 ^ UINT32_MAX) & - ((uint32_t)(~T1) ^ (uint32_t)T0)) >> 31; - xer_so |= xer_ov; - if (likely((uint32_t)T0 >= (uint32_t)~T1)) { - xer_ca = 0; - } else { - xer_ca = 1; - } -} - -#if defined(TARGET_PPC64) -void do_subfzeo_64 (void) -{ - T1 = T0; - T0 = ~T0 + xer_ca; - xer_ov = (((uint64_t)~T1 ^ UINT64_MAX) & - ((uint64_t)(~T1) ^ (uint64_t)T0)) >> 63; - xer_so |= xer_ov; - if (likely((uint64_t)T0 >= (uint64_t)~T1)) { - xer_ca = 0; - } else { - xer_ca = 1; - } -} -#endif - -void do_cntlzw (void) -{ - T0 = clz32(T0); -} - -#if defined(TARGET_PPC64) -void do_cntlzd (void) -{ - T0 = clz64(T0); + return clz64(t); } #endif /* shift right arithmetic helper */ -void do_sraw (void) +target_ulong helper_sraw (target_ulong value, target_ulong shift) { int32_t ret; - if (likely(!(T1 & 0x20UL))) { - if (likely((uint32_t)T1 != 0)) { - ret = (int32_t)T0 >> (T1 & 0x1fUL); - if (likely(ret >= 0 || ((int32_t)T0 & ((1 << T1) - 1)) == 0)) { - xer_ca = 0; + if (likely(!(shift & 0x20))) { + if (likely((uint32_t)shift != 0)) { + shift &= 0x1f; + ret = (int32_t)value >> shift; + if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) { + env->xer &= ~(1 << XER_CA); } else { - xer_ca = 1; + env->xer |= (1 << XER_CA); } } else { - ret = T0; - xer_ca = 0; + ret = (int32_t)value; + env->xer &= ~(1 << XER_CA); } } else { - ret = UINT32_MAX * ((uint32_t)T0 >> 31); - if (likely(ret >= 0 || ((uint32_t)T0 & ~0x80000000UL) == 0)) { - xer_ca = 0; + ret = (int32_t)value >> 31; + if (ret) { + env->xer |= (1 << XER_CA); } else { - xer_ca = 1; + env->xer &= ~(1 << XER_CA); } } - T0 = ret; + return (target_long)ret; } #if defined(TARGET_PPC64) -void do_srad (void) +target_ulong helper_srad (target_ulong value, target_ulong shift) { int64_t ret; - if (likely(!(T1 & 0x40UL))) { - if (likely((uint64_t)T1 != 0)) { - ret = (int64_t)T0 >> (T1 & 0x3FUL); - if (likely(ret >= 0 || ((int64_t)T0 & ((1 << T1) - 1)) == 0)) { - xer_ca = 0; + if (likely(!(shift & 0x40))) { + if (likely((uint64_t)shift != 0)) { + shift &= 0x3f; + ret = (int64_t)value >> shift; + if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) { + env->xer &= ~(1 << XER_CA); } else { - xer_ca = 1; + env->xer |= (1 << XER_CA); } } else { - ret = T0; - xer_ca = 0; + ret = (int64_t)value; + env->xer &= ~(1 << XER_CA); } } else { - ret = UINT64_MAX * ((uint64_t)T0 >> 63); - if (likely(ret >= 0 || ((uint64_t)T0 & ~0x8000000000000000ULL) == 0)) { - xer_ca = 0; + ret = (int64_t)value >> 63; + if (ret) { + env->xer |= (1 << XER_CA); } else { - xer_ca = 1; + env->xer &= ~(1 << XER_CA); } } - T0 = ret; + return ret; } #endif -void do_popcntb (void) +target_ulong helper_popcntb (target_ulong val) { - uint32_t ret; - int i; - - ret = 0; - for (i = 0; i < 32; i += 8) - ret |= ctpop8((T0 >> i) & 0xFF) << i; - T0 = ret; + val = (val & 0x55555555) + ((val >> 1) & 0x55555555); + val = (val & 0x33333333) + ((val >> 2) & 0x33333333); + val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f); + return val; } #if defined(TARGET_PPC64) -void do_popcntb_64 (void) +target_ulong helper_popcntb_64 (target_ulong val) { - uint64_t ret; - int i; - - ret = 0; - for (i = 0; i < 64; i += 8) - ret |= ctpop8((T0 >> i) & 0xFF) << i; - T0 = ret; + val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL); + val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL); + val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & 0x0f0f0f0f0f0f0f0fULL); + return val; } #endif /*****************************************************************************/ /* Floating point operations helpers */ -static always_inline int fpisneg (float64 f) +static always_inline int fpisneg (float64 d) { - union { - float64 f; - uint64_t u; - } u; + CPU_DoubleU u; - u.f = f; + u.d = d; - return u.u >> 63 != 0; + return u.ll >> 63 != 0; } -static always_inline int isden (float f) +static always_inline int isden (float64 d) { - union { - float64 f; - uint64_t u; - } u; + CPU_DoubleU u; - u.f = f; + u.d = d; - return ((u.u >> 52) & 0x7FF) == 0; + return ((u.ll >> 52) & 0x7FF) == 0; } -static always_inline int iszero (float64 f) +static always_inline int iszero (float64 d) { - union { - float64 f; - uint64_t u; - } u; + CPU_DoubleU u; - u.f = f; + u.d = d; - return (u.u & ~0x8000000000000000ULL) == 0; + return (u.ll & ~0x8000000000000000ULL) == 0; } -static always_inline int isinfinity (float64 f) +static always_inline int isinfinity (float64 d) { - union { - float64 f; - uint64_t u; - } u; + CPU_DoubleU u; - u.f = f; + u.d = d; - return ((u.u >> 52) & 0x7FF) == 0x7FF && - (u.u & 0x000FFFFFFFFFFFFFULL) == 0; + return ((u.ll >> 52) & 0x7FF) == 0x7FF && + (u.ll & 0x000FFFFFFFFFFFFFULL) == 0; } +#ifdef CONFIG_SOFTFLOAT +static always_inline int isfinite (float64 d) +{ + CPU_DoubleU u; + + u.d = d; + + return (((u.ll >> 52) & 0x7FF) != 0x7FF); +} + +static always_inline int isnormal (float64 d) +{ + CPU_DoubleU u; + + u.d = d; + + uint32_t exp = (u.ll >> 52) & 0x7FF; + return ((0 < exp) && (exp < 0x7FF)); +} +#endif + void do_compute_fprf (int set_fprf) { int isneg; @@ -638,10 +432,7 @@ static always_inline void float_zero_divide_excp (void) { - union { - float64 f; - uint64_t u; - } u0, u1; + CPU_DoubleU u0, u1; env->fpscr |= 1 << FPSCR_ZX; env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); @@ -656,11 +447,11 @@ } } else { /* Set the result to infinity */ - u0.f = FT0; - u1.f = FT1; - u0.u = ((u0.u ^ u1.u) & 0x8000000000000000ULL); - u0.u |= 0x7FFULL << 52; - FT0 = u0.f; + u0.d = FT0; + u1.d = FT1; + u0.ll = ((u0.ll ^ u1.ll) & 0x8000000000000000ULL); + u0.ll |= 0x7FFULL << 52; + FT0 = u0.d; } } @@ -865,18 +656,13 @@ /* * We use only the 32 LSB of the incoming fpr */ - union { - double d; - struct { - uint32_t u[2]; - } s; - } u; + CPU_DoubleU u; uint32_t prev, new; int i; u.d = FT0; prev = env->fpscr; - new = u.s.u[WORD1]; + new = u.l.lower; new &= ~0x90000000; new |= prev & 0x90000000; for (i = 0; i < 7; i++) { @@ -888,12 +674,16 @@ /* Update VX and FEX */ if (fpscr_ix != 0) env->fpscr |= 1 << FPSCR_VX; + else + env->fpscr &= ~(1 << FPSCR_VX); if ((fpscr_ex & fpscr_eex) != 0) { env->fpscr |= 1 << FPSCR_FEX; env->exception_index = POWERPC_EXCP_PROGRAM; /* XXX: we should compute it properly */ env->error_code = POWERPC_EXCP_FP; } + else + env->fpscr &= ~(1 << FPSCR_FEX); fpscr_set_rounding_mode(); } #undef WORD0 @@ -988,10 +778,7 @@ void do_fctiw (void) { - union { - double d; - uint64_t i; - } p; + CPU_DoubleU p; if (unlikely(float64_is_signaling_nan(FT0))) { /* sNaN conversion */ @@ -1000,12 +787,12 @@ /* qNan / infinity conversion */ fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); } else { - p.i = float64_to_int32(FT0, &env->fp_status); + p.ll = float64_to_int32(FT0, &env->fp_status); #if USE_PRECISE_EMULATION /* XXX: higher bits are not supposed to be significant. * to make tests easier, return the same as a real PowerPC 750 */ - p.i |= 0xFFF80000ULL << 32; + p.ll |= 0xFFF80000ULL << 32; #endif FT0 = p.d; } @@ -1013,10 +800,7 @@ void do_fctiwz (void) { - union { - double d; - uint64_t i; - } p; + CPU_DoubleU p; if (unlikely(float64_is_signaling_nan(FT0))) { /* sNaN conversion */ @@ -1025,12 +809,12 @@ /* qNan / infinity conversion */ fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); } else { - p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status); + p.ll = float64_to_int32_round_to_zero(FT0, &env->fp_status); #if USE_PRECISE_EMULATION /* XXX: higher bits are not supposed to be significant. * to make tests easier, return the same as a real PowerPC 750 */ - p.i |= 0xFFF80000ULL << 32; + p.ll |= 0xFFF80000ULL << 32; #endif FT0 = p.d; } @@ -1039,21 +823,15 @@ #if defined(TARGET_PPC64) void do_fcfid (void) { - union { - double d; - uint64_t i; - } p; + CPU_DoubleU p; p.d = FT0; - FT0 = int64_to_float64(p.i, &env->fp_status); + FT0 = int64_to_float64(p.ll, &env->fp_status); } void do_fctid (void) { - union { - double d; - uint64_t i; - } p; + CPU_DoubleU p; if (unlikely(float64_is_signaling_nan(FT0))) { /* sNaN conversion */ @@ -1062,17 +840,14 @@ /* qNan / infinity conversion */ fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); } else { - p.i = float64_to_int64(FT0, &env->fp_status); + p.ll = float64_to_int64(FT0, &env->fp_status); FT0 = p.d; } } void do_fctidz (void) { - union { - double d; - uint64_t i; - } p; + CPU_DoubleU p; if (unlikely(float64_is_signaling_nan(FT0))) { /* sNaN conversion */ @@ -1081,7 +856,7 @@ /* qNan / infinity conversion */ fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); } else { - p.i = float64_to_int64_round_to_zero(FT0, &env->fp_status); + p.ll = float64_to_int64_round_to_zero(FT0, &env->fp_status); FT0 = p.d; } } @@ -1267,10 +1042,7 @@ void do_fre (void) { - union { - double d; - uint64_t i; - } p; + CPU_DoubleU p; if (unlikely(float64_is_signaling_nan(FT0))) { /* sNaN reciprocal */ @@ -1282,16 +1054,16 @@ FT0 = float64_div(1.0, FT0, &env->fp_status); } else { p.d = FT0; - if (p.i == 0x8000000000000000ULL) { - p.i = 0xFFF0000000000000ULL; - } else if (p.i == 0x0000000000000000ULL) { - p.i = 0x7FF0000000000000ULL; + if (p.ll == 0x8000000000000000ULL) { + p.ll = 0xFFF0000000000000ULL; + } else if (p.ll == 0x0000000000000000ULL) { + p.ll = 0x7FF0000000000000ULL; } else if (isnan(FT0)) { - p.i = 0x7FF8000000000000ULL; + p.ll = 0x7FF8000000000000ULL; } else if (fpisneg(FT0)) { - p.i = 0x8000000000000000ULL; + p.ll = 0x8000000000000000ULL; } else { - p.i = 0x0000000000000000ULL; + p.ll = 0x0000000000000000ULL; } FT0 = p.d; } @@ -1299,10 +1071,7 @@ void do_fres (void) { - union { - double d; - uint64_t i; - } p; + CPU_DoubleU p; if (unlikely(float64_is_signaling_nan(FT0))) { /* sNaN reciprocal */ @@ -1319,16 +1088,16 @@ #endif } else { p.d = FT0; - if (p.i == 0x8000000000000000ULL) { - p.i = 0xFFF0000000000000ULL; - } else if (p.i == 0x0000000000000000ULL) { - p.i = 0x7FF0000000000000ULL; + if (p.ll == 0x8000000000000000ULL) { + p.ll = 0xFFF0000000000000ULL; + } else if (p.ll == 0x0000000000000000ULL) { + p.ll = 0x7FF0000000000000ULL; } else if (isnan(FT0)) { - p.i = 0x7FF8000000000000ULL; + p.ll = 0x7FF8000000000000ULL; } else if (fpisneg(FT0)) { - p.i = 0x8000000000000000ULL; + p.ll = 0x8000000000000000ULL; } else { - p.i = 0x0000000000000000ULL; + p.ll = 0x0000000000000000ULL; } FT0 = p.d; } @@ -1336,10 +1105,7 @@ void do_frsqrte (void) { - union { - double d; - uint64_t i; - } p; + CPU_DoubleU p; if (unlikely(float64_is_signaling_nan(FT0))) { /* sNaN reciprocal square root */ @@ -1352,16 +1118,16 @@ FT0 = float32_div(1.0, FT0, &env->fp_status); } else { p.d = FT0; - if (p.i == 0x8000000000000000ULL) { - p.i = 0xFFF0000000000000ULL; - } else if (p.i == 0x0000000000000000ULL) { - p.i = 0x7FF0000000000000ULL; + if (p.ll == 0x8000000000000000ULL) { + p.ll = 0xFFF0000000000000ULL; + } else if (p.ll == 0x0000000000000000ULL) { + p.ll = 0x7FF0000000000000ULL; } else if (isnan(FT0)) { - p.i |= 0x000FFFFFFFFFFFFFULL; + p.ll |= 0x000FFFFFFFFFFFFFULL; } else if (fpisneg(FT0)) { - p.i = 0x7FF8000000000000ULL; + p.ll = 0x7FF8000000000000ULL; } else { - p.i = 0x0000000000000000ULL; + p.ll = 0x0000000000000000ULL; } FT0 = p.d; } @@ -1375,27 +1141,32 @@ FT0 = FT2; } -void do_fcmpu (void) +uint32_t helper_fcmpu (void) { + uint32_t ret = 0; + if (unlikely(float64_is_signaling_nan(FT0) || float64_is_signaling_nan(FT1))) { /* sNaN comparison */ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); } else { if (float64_lt(FT0, FT1, &env->fp_status)) { - T0 = 0x08UL; + ret = 0x08UL; } else if (!float64_le(FT0, FT1, &env->fp_status)) { - T0 = 0x04UL; + ret = 0x04UL; } else { - T0 = 0x02UL; + ret = 0x02UL; } } env->fpscr &= ~(0x0F << FPSCR_FPRF); - env->fpscr |= T0 << FPSCR_FPRF; + env->fpscr |= ret << FPSCR_FPRF; + return ret; } -void do_fcmpo (void) +uint32_t helper_fcmpo (void) { + uint32_t ret = 0; + if (unlikely(float64_is_nan(FT0) || float64_is_nan(FT1))) { if (float64_is_signaling_nan(FT0) || @@ -1409,15 +1180,16 @@ } } else { if (float64_lt(FT0, FT1, &env->fp_status)) { - T0 = 0x08UL; + ret = 0x08UL; } else if (!float64_le(FT0, FT1, &env->fp_status)) { - T0 = 0x04UL; + ret = 0x04UL; } else { - T0 = 0x02UL; + ret = 0x02UL; } } env->fpscr &= ~(0x0F << FPSCR_FPRF); - env->fpscr |= T0 << FPSCR_FPRF; + env->fpscr |= ret << FPSCR_FPRF; + return ret; } #if !defined (CONFIG_USER_ONLY) @@ -1511,14 +1283,13 @@ { if ((int32_t)T0 == INT32_MIN) { T0 = INT32_MAX; - xer_ov = 1; + env->xer |= (1 << XER_OV) | (1 << XER_SO); } else if ((int32_t)T0 < 0) { T0 = -T0; - xer_ov = 0; + env->xer &= ~(1 << XER_OV); } else { - xer_ov = 0; + env->xer &= ~(1 << XER_OV); } - xer_so |= xer_ov; } void do_POWER_clcs (void) @@ -1571,19 +1342,18 @@ (int32_t)T1 == 0) { T0 = UINT32_MAX * ((uint32_t)T0 >> 31); env->spr[SPR_MQ] = 0; - xer_ov = 1; + env->xer |= (1 << XER_OV) | (1 << XER_SO); } else { tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ]; env->spr[SPR_MQ] = tmp % T1; tmp /= (int32_t)T1; if (tmp > (int64_t)INT32_MAX || tmp < (int64_t)INT32_MIN) { - xer_ov = 1; + env->xer |= (1 << XER_OV) | (1 << XER_SO); } else { - xer_ov = 0; + env->xer &= ~(1 << XER_OV); } T0 = tmp; } - xer_so |= xer_ov; } void do_POWER_divs (void) @@ -1604,13 +1374,12 @@ (int32_t)T1 == 0) { T0 = UINT32_MAX * ((uint32_t)T0 >> 31); env->spr[SPR_MQ] = 0; - xer_ov = 1; + env->xer |= (1 << XER_OV) | (1 << XER_SO); } else { T0 = (int32_t)T0 / (int32_t)T1; env->spr[SPR_MQ] = (int32_t)T0 % (int32_t)T1; - xer_ov = 0; + env->xer &= ~(1 << XER_OV); } - xer_so |= xer_ov; } void do_POWER_dozo (void) @@ -1620,14 +1389,13 @@ T0 = T1 - T0; if (((uint32_t)(~T2) ^ (uint32_t)T1 ^ UINT32_MAX) & ((uint32_t)(~T2) ^ (uint32_t)T0) & (1UL << 31)) { - xer_ov = 1; - xer_so = 1; + env->xer |= (1 << XER_OV) | (1 << XER_SO); } else { - xer_ov = 0; + env->xer &= ~(1 << XER_OV); } } else { T0 = 0; - xer_ov = 0; + env->xer &= ~(1 << XER_OV); } } @@ -1654,10 +1422,9 @@ env->spr[SPR_MQ] = tmp >> 32; T0 = tmp; if (tmp >> 32 != ((uint64_t)T0 >> 16) * ((uint64_t)T1 >> 16)) { - xer_ov = 1; - xer_so = 1; + env->xer |= (1 << XER_OV) | (1 << XER_SO); } else { - xer_ov = 0; + env->xer &= ~(1 << XER_OV); } } @@ -1737,18 +1504,6 @@ /*****************************************************************************/ /* Embedded PowerPC specific helpers */ -void do_405_check_sat (void) -{ - if (!likely((((uint32_t)T1 ^ (uint32_t)T2) >> 31) || - !(((uint32_t)T0 ^ (uint32_t)T2) >> 31))) { - /* Saturate result */ - if (T2 >> 31) { - T0 = INT32_MIN; - } else { - T0 = INT32_MAX; - } - } -} /* XXX: to be improved to check access rights when in user-mode */ void do_load_dcr (void) @@ -1869,46 +1624,18 @@ } #define MASKBITS 16 // Random value - to be fixed (implementation dependant) -void do_brinc (void) +target_ulong helper_brinc (target_ulong arg1, target_ulong arg2) { uint32_t a, b, d, mask; mask = UINT32_MAX >> (32 - MASKBITS); - a = T0 & mask; - b = T1 & mask; + a = arg1 & mask; + b = arg2 & mask; d = word_reverse(1 + word_reverse(a | ~b)); - T0 = (T0 & ~mask) | (d & b); + return (arg1 & ~mask) | (d & b); } -#define DO_SPE_OP2(name) \ -void do_ev##name (void) \ -{ \ - T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32, T1_64 >> 32) << 32) | \ - (uint64_t)_do_e##name(T0_64, T1_64); \ -} - -#define DO_SPE_OP1(name) \ -void do_ev##name (void) \ -{ \ - T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32) << 32) | \ - (uint64_t)_do_e##name(T0_64); \ -} - -/* Fixed-point vector arithmetic */ -static always_inline uint32_t _do_eabs (uint32_t val) -{ - if ((val & 0x80000000) && val != 0x80000000) - val -= val; - - return val; -} - -static always_inline uint32_t _do_eaddw (uint32_t op1, uint32_t op2) -{ - return op1 + op2; -} - -static always_inline int _do_ecntlsw (uint32_t val) +uint32_t helper_cntlsw32 (uint32_t val) { if (val & 0x80000000) return clz32(~val); @@ -1916,88 +1643,23 @@ return clz32(val); } -static always_inline int _do_ecntlzw (uint32_t val) +uint32_t helper_cntlzw32 (uint32_t val) { return clz32(val); } -static always_inline uint32_t _do_eneg (uint32_t val) -{ - if (val != 0x80000000) - val -= val; - - return val; -} - -static always_inline uint32_t _do_erlw (uint32_t op1, uint32_t op2) -{ - return rotl32(op1, op2); -} - -static always_inline uint32_t _do_erndw (uint32_t val) -{ - return (val + 0x000080000000) & 0xFFFF0000; -} - -static always_inline uint32_t _do_eslw (uint32_t op1, uint32_t op2) -{ - /* No error here: 6 bits are used */ - return op1 << (op2 & 0x3F); -} - -static always_inline int32_t _do_esrws (int32_t op1, uint32_t op2) -{ - /* No error here: 6 bits are used */ - return op1 >> (op2 & 0x3F); -} - -static always_inline uint32_t _do_esrwu (uint32_t op1, uint32_t op2) -{ - /* No error here: 6 bits are used */ - return op1 >> (op2 & 0x3F); -} - -static always_inline uint32_t _do_esubfw (uint32_t op1, uint32_t op2) -{ - return op2 - op1; -} - -/* evabs */ -DO_SPE_OP1(abs); -/* evaddw */ -DO_SPE_OP2(addw); -/* evcntlsw */ -DO_SPE_OP1(cntlsw); -/* evcntlzw */ -DO_SPE_OP1(cntlzw); -/* evneg */ -DO_SPE_OP1(neg); -/* evrlw */ -DO_SPE_OP2(rlw); -/* evrnd */ -DO_SPE_OP1(rndw); -/* evslw */ -DO_SPE_OP2(slw); -/* evsrws */ -DO_SPE_OP2(srws); -/* evsrwu */ -DO_SPE_OP2(srwu); -/* evsubfw */ -DO_SPE_OP2(subfw); - -/* evsel is a little bit more complicated... */ -static always_inline uint32_t _do_esel (uint32_t op1, uint32_t op2, int n) -{ - if (n) - return op1; - else - return op2; +#define DO_SPE_OP1(name) \ +void do_ev##name (void) \ +{ \ + T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32) << 32) | \ + (uint64_t)_do_e##name(T0_64); \ } -void do_evsel (void) -{ - T0_64 = ((uint64_t)_do_esel(T0_64 >> 32, T1_64 >> 32, T0 >> 3) << 32) | - (uint64_t)_do_esel(T0_64, T1_64, (T0 >> 2) & 1); +#define DO_SPE_OP2(name) \ +void do_ev##name (void) \ +{ \ + T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32, T1_64 >> 32) << 32) | \ + (uint64_t)_do_e##name(T0_64, T1_64); \ } /* Fixed-point vector comparisons */ @@ -2013,75 +1675,31 @@ { return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1); } -static always_inline int _do_ecmpeq (uint32_t op1, uint32_t op2) -{ - return op1 == op2 ? 1 : 0; -} - -static always_inline int _do_ecmpgts (int32_t op1, int32_t op2) -{ - return op1 > op2 ? 1 : 0; -} - -static always_inline int _do_ecmpgtu (uint32_t op1, uint32_t op2) -{ - return op1 > op2 ? 1 : 0; -} - -static always_inline int _do_ecmplts (int32_t op1, int32_t op2) -{ - return op1 < op2 ? 1 : 0; -} - -static always_inline int _do_ecmpltu (uint32_t op1, uint32_t op2) -{ - return op1 < op2 ? 1 : 0; -} - -/* evcmpeq */ -DO_SPE_CMP(cmpeq); -/* evcmpgts */ -DO_SPE_CMP(cmpgts); -/* evcmpgtu */ -DO_SPE_CMP(cmpgtu); -/* evcmplts */ -DO_SPE_CMP(cmplts); -/* evcmpltu */ -DO_SPE_CMP(cmpltu); /* Single precision floating-point conversions from/to integer */ static always_inline uint32_t _do_efscfsi (int32_t val) { - union { - uint32_t u; - float32 f; - } u; + CPU_FloatU u; u.f = int32_to_float32(val, &env->spe_status); - return u.u; + return u.l; } static always_inline uint32_t _do_efscfui (uint32_t val) { - union { - uint32_t u; - float32 f; - } u; + CPU_FloatU u; u.f = uint32_to_float32(val, &env->spe_status); - return u.u; + return u.l; } static always_inline int32_t _do_efsctsi (uint32_t val) { - union { - int32_t u; - float32 f; - } u; + CPU_FloatU u; - u.u = val; + u.l = val; /* NaN are not treated the same way IEEE 754 does */ if (unlikely(isnan(u.f))) return 0; @@ -2091,12 +1709,9 @@ static always_inline uint32_t _do_efsctui (uint32_t val) { - union { - int32_t u; - float32 f; - } u; + CPU_FloatU u; - u.u = val; + u.l = val; /* NaN are not treated the same way IEEE 754 does */ if (unlikely(isnan(u.f))) return 0; @@ -2106,12 +1721,9 @@ static always_inline int32_t _do_efsctsiz (uint32_t val) { - union { - int32_t u; - float32 f; - } u; + CPU_FloatU u; - u.u = val; + u.l = val; /* NaN are not treated the same way IEEE 754 does */ if (unlikely(isnan(u.f))) return 0; @@ -2121,12 +1733,9 @@ static always_inline uint32_t _do_efsctuiz (uint32_t val) { - union { - int32_t u; - float32 f; - } u; + CPU_FloatU u; - u.u = val; + u.l = val; /* NaN are not treated the same way IEEE 754 does */ if (unlikely(isnan(u.f))) return 0; @@ -2167,43 +1776,34 @@ /* Single precision floating-point conversion to/from fractional */ static always_inline uint32_t _do_efscfsf (uint32_t val) { - union { - uint32_t u; - float32 f; - } u; + CPU_FloatU u; float32 tmp; u.f = int32_to_float32(val, &env->spe_status); tmp = int64_to_float32(1ULL << 32, &env->spe_status); u.f = float32_div(u.f, tmp, &env->spe_status); - return u.u; + return u.l; } static always_inline uint32_t _do_efscfuf (uint32_t val) { - union { - uint32_t u; - float32 f; - } u; + CPU_FloatU u; float32 tmp; u.f = uint32_to_float32(val, &env->spe_status); tmp = uint64_to_float32(1ULL << 32, &env->spe_status); u.f = float32_div(u.f, tmp, &env->spe_status); - return u.u; + return u.l; } static always_inline int32_t _do_efsctsf (uint32_t val) { - union { - int32_t u; - float32 f; - } u; + CPU_FloatU u; float32 tmp; - u.u = val; + u.l = val; /* NaN are not treated the same way IEEE 754 does */ if (unlikely(isnan(u.f))) return 0; @@ -2215,13 +1815,10 @@ static always_inline uint32_t _do_efsctuf (uint32_t val) { - union { - int32_t u; - float32 f; - } u; + CPU_FloatU u; float32 tmp; - u.u = val; + u.l = val; /* NaN are not treated the same way IEEE 754 does */ if (unlikely(isnan(u.f))) return 0; @@ -2233,13 +1830,10 @@ static always_inline int32_t _do_efsctsfz (uint32_t val) { - union { - int32_t u; - float32 f; - } u; + CPU_FloatU u; float32 tmp; - u.u = val; + u.l = val; /* NaN are not treated the same way IEEE 754 does */ if (unlikely(isnan(u.f))) return 0; @@ -2251,13 +1845,10 @@ static always_inline uint32_t _do_efsctufz (uint32_t val) { - union { - int32_t u; - float32 f; - } u; + CPU_FloatU u; float32 tmp; - u.u = val; + u.l = val; /* NaN are not treated the same way IEEE 754 does */ if (unlikely(isnan(u.f))) return 0; @@ -2334,86 +1925,68 @@ /* Double precision floating-point conversion to/from integer */ static always_inline uint64_t _do_efdcfsi (int64_t val) { - union { - uint64_t u; - float64 f; - } u; + CPU_DoubleU u; - u.f = int64_to_float64(val, &env->spe_status); + u.d = int64_to_float64(val, &env->spe_status); - return u.u; + return u.ll; } static always_inline uint64_t _do_efdcfui (uint64_t val) { - union { - uint64_t u; - float64 f; - } u; + CPU_DoubleU u; - u.f = uint64_to_float64(val, &env->spe_status); + u.d = uint64_to_float64(val, &env->spe_status); - return u.u; + return u.ll; } static always_inline int64_t _do_efdctsi (uint64_t val) { - union { - int64_t u; - float64 f; - } u; + CPU_DoubleU u; - u.u = val; + u.ll = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(isnan(u.f))) + if (unlikely(isnan(u.d))) return 0; - return float64_to_int64(u.f, &env->spe_status); + return float64_to_int64(u.d, &env->spe_status); } static always_inline uint64_t _do_efdctui (uint64_t val) { - union { - int64_t u; - float64 f; - } u; + CPU_DoubleU u; - u.u = val; + u.ll = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(isnan(u.f))) + if (unlikely(isnan(u.d))) return 0; - return float64_to_uint64(u.f, &env->spe_status); + return float64_to_uint64(u.d, &env->spe_status); } static always_inline int64_t _do_efdctsiz (uint64_t val) { - union { - int64_t u; - float64 f; - } u; + CPU_DoubleU u; - u.u = val; + u.ll = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(isnan(u.f))) + if (unlikely(isnan(u.d))) return 0; - return float64_to_int64_round_to_zero(u.f, &env->spe_status); + return float64_to_int64_round_to_zero(u.d, &env->spe_status); } static always_inline uint64_t _do_efdctuiz (uint64_t val) { - union { - int64_t u; - float64 f; - } u; + CPU_DoubleU u; - u.u = val; + u.ll = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(isnan(u.f))) + if (unlikely(isnan(u.d))) return 0; - return float64_to_uint64_round_to_zero(u.f, &env->spe_status); + return float64_to_uint64_round_to_zero(u.d, &env->spe_status); } void do_efdcfsi (void) @@ -2449,104 +2022,86 @@ /* Double precision floating-point conversion to/from fractional */ static always_inline uint64_t _do_efdcfsf (int64_t val) { - union { - uint64_t u; - float64 f; - } u; + CPU_DoubleU u; float64 tmp; - u.f = int32_to_float64(val, &env->spe_status); + u.d = int32_to_float64(val, &env->spe_status); tmp = int64_to_float64(1ULL << 32, &env->spe_status); - u.f = float64_div(u.f, tmp, &env->spe_status); + u.d = float64_div(u.d, tmp, &env->spe_status); - return u.u; + return u.ll; } static always_inline uint64_t _do_efdcfuf (uint64_t val) { - union { - uint64_t u; - float64 f; - } u; + CPU_DoubleU u; float64 tmp; - u.f = uint32_to_float64(val, &env->spe_status); + u.d = uint32_to_float64(val, &env->spe_status); tmp = int64_to_float64(1ULL << 32, &env->spe_status); - u.f = float64_div(u.f, tmp, &env->spe_status); + u.d = float64_div(u.d, tmp, &env->spe_status); - return u.u; + return u.ll; } static always_inline int64_t _do_efdctsf (uint64_t val) { - union { - int64_t u; - float64 f; - } u; + CPU_DoubleU u; float64 tmp; - u.u = val; + u.ll = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(isnan(u.f))) + if (unlikely(isnan(u.d))) return 0; tmp = uint64_to_float64(1ULL << 32, &env->spe_status); - u.f = float64_mul(u.f, tmp, &env->spe_status); + u.d = float64_mul(u.d, tmp, &env->spe_status); - return float64_to_int32(u.f, &env->spe_status); + return float64_to_int32(u.d, &env->spe_status); } static always_inline uint64_t _do_efdctuf (uint64_t val) { - union { - int64_t u; - float64 f; - } u; + CPU_DoubleU u; float64 tmp; - u.u = val; + u.ll = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(isnan(u.f))) + if (unlikely(isnan(u.d))) return 0; tmp = uint64_to_float64(1ULL << 32, &env->spe_status); - u.f = float64_mul(u.f, tmp, &env->spe_status); + u.d = float64_mul(u.d, tmp, &env->spe_status); - return float64_to_uint32(u.f, &env->spe_status); + return float64_to_uint32(u.d, &env->spe_status); } static always_inline int64_t _do_efdctsfz (uint64_t val) { - union { - int64_t u; - float64 f; - } u; + CPU_DoubleU u; float64 tmp; - u.u = val; + u.ll = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(isnan(u.f))) + if (unlikely(isnan(u.d))) return 0; tmp = uint64_to_float64(1ULL << 32, &env->spe_status); - u.f = float64_mul(u.f, tmp, &env->spe_status); + u.d = float64_mul(u.d, tmp, &env->spe_status); - return float64_to_int32_round_to_zero(u.f, &env->spe_status); + return float64_to_int32_round_to_zero(u.d, &env->spe_status); } static always_inline uint64_t _do_efdctufz (uint64_t val) { - union { - int64_t u; - float64 f; - } u; + CPU_DoubleU u; float64 tmp; - u.u = val; + u.ll = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(isnan(u.f))) + if (unlikely(isnan(u.d))) return 0; tmp = uint64_to_float64(1ULL << 32, &env->spe_status); - u.f = float64_mul(u.f, tmp, &env->spe_status); + u.d = float64_mul(u.d, tmp, &env->spe_status); - return float64_to_uint32_round_to_zero(u.f, &env->spe_status); + return float64_to_uint32_round_to_zero(u.d, &env->spe_status); } void do_efdcfsf (void) @@ -2582,36 +2137,24 @@ /* Floating point conversion between single and double precision */ static always_inline uint32_t _do_efscfd (uint64_t val) { - union { - uint64_t u; - float64 f; - } u1; - union { - uint32_t u; - float32 f; - } u2; + CPU_DoubleU u1; + CPU_FloatU u2; - u1.u = val; - u2.f = float64_to_float32(u1.f, &env->spe_status); + u1.ll = val; + u2.f = float64_to_float32(u1.d, &env->spe_status); - return u2.u; + return u2.l; } static always_inline uint64_t _do_efdcfs (uint32_t val) { - union { - uint64_t u; - float64 f; - } u2; - union { - uint32_t u; - float32 f; - } u1; + CPU_DoubleU u2; + CPU_FloatU u1; - u1.u = val; - u2.f = float32_to_float64(u1.f, &env->spe_status); + u1.l = val; + u2.d = float32_to_float64(u1.f, &env->spe_status); - return u2.u; + return u2.ll; } void do_efscfd (void) @@ -2715,11 +2258,6 @@ #if !defined (CONFIG_USER_ONLY) #define MMUSUFFIX _mmu -#ifdef __s390__ -# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) -#else -# define GETPC() (__builtin_return_address(0)) -#endif #define SHIFT 0 #include "softmmu_template.h" diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-ppc/op_helper.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-ppc/op_helper.h --- qemu-0.9.1/target-ppc/op_helper.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-ppc/op_helper.h 2008-11-01 00:54:23.000000000 +0000 @@ -61,38 +61,6 @@ target_ulong ppc_load_dump_spr (int sprn); void ppc_store_dump_spr (int sprn, target_ulong val); -/* Integer arithmetic helpers */ -void do_adde (void); -void do_addmeo (void); -void do_divwo (void); -void do_divwuo (void); -void do_mullwo (void); -void do_nego (void); -void do_subfe (void); -void do_subfmeo (void); -void do_subfzeo (void); -void do_cntlzw (void); -#if defined(TARGET_PPC64) -void do_cntlzd (void); -#endif -void do_sraw (void); -#if defined(TARGET_PPC64) -void do_adde_64 (void); -void do_addmeo_64 (void); -void do_divdo (void); -void do_divduo (void); -void do_mulldo (void); -void do_nego_64 (void); -void do_subfe_64 (void); -void do_subfmeo_64 (void); -void do_subfzeo_64 (void); -void do_srad (void); -#endif -void do_popcntb (void); -#if defined(TARGET_PPC64) -void do_popcntb_64 (void); -#endif - /* Floating-point arithmetic helpers */ void do_compute_fprf (int set_class); #ifdef CONFIG_SOFTFLOAT @@ -176,7 +144,6 @@ #endif /* PowerPC 4xx specific helpers */ -void do_405_check_sat (void); void do_load_dcr (void); void do_store_dcr (void); #if !defined(CONFIG_USER_ONLY) @@ -296,108 +263,78 @@ } static always_inline uint32_t _do_efsadd (uint32_t op1, uint32_t op2) { - union { - uint32_t u; - float32 f; - } u1, u2; - u1.u = op1; - u2.u = op2; + CPU_FloatU u1, u2; + u1.l = op1; + u2.l = op2; u1.f = float32_add(u1.f, u2.f, &env->spe_status); - return u1.u; + return u1.l; } static always_inline uint32_t _do_efssub (uint32_t op1, uint32_t op2) { - union { - uint32_t u; - float32 f; - } u1, u2; - u1.u = op1; - u2.u = op2; + CPU_FloatU u1, u2; + u1.l = op1; + u2.l = op2; u1.f = float32_sub(u1.f, u2.f, &env->spe_status); - return u1.u; + return u1.l; } static always_inline uint32_t _do_efsmul (uint32_t op1, uint32_t op2) { - union { - uint32_t u; - float32 f; - } u1, u2; - u1.u = op1; - u2.u = op2; + CPU_FloatU u1, u2; + u1.l = op1; + u2.l = op2; u1.f = float32_mul(u1.f, u2.f, &env->spe_status); - return u1.u; + return u1.l; } static always_inline uint32_t _do_efsdiv (uint32_t op1, uint32_t op2) { - union { - uint32_t u; - float32 f; - } u1, u2; - u1.u = op1; - u2.u = op2; + CPU_FloatU u1, u2; + u1.l = op1; + u2.l = op2; u1.f = float32_div(u1.f, u2.f, &env->spe_status); - return u1.u; + return u1.l; } static always_inline int _do_efststlt (uint32_t op1, uint32_t op2) { - union { - uint32_t u; - float32 f; - } u1, u2; - u1.u = op1; - u2.u = op2; - return float32_lt(u1.f, u2.f, &env->spe_status) ? 1 : 0; + CPU_FloatU u1, u2; + u1.l = op1; + u2.l = op2; + return float32_lt(u1.f, u2.f, &env->spe_status) ? 4 : 0; } static always_inline int _do_efststgt (uint32_t op1, uint32_t op2) { - union { - uint32_t u; - float32 f; - } u1, u2; - u1.u = op1; - u2.u = op2; - return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 1; + CPU_FloatU u1, u2; + u1.l = op1; + u2.l = op2; + return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 4; } static always_inline int _do_efststeq (uint32_t op1, uint32_t op2) { - union { - uint32_t u; - float32 f; - } u1, u2; - u1.u = op1; - u2.u = op2; - return float32_eq(u1.f, u2.f, &env->spe_status) ? 1 : 0; + CPU_FloatU u1, u2; + u1.l = op1; + u2.l = op2; + return float32_eq(u1.f, u2.f, &env->spe_status) ? 4 : 0; } /* Double precision floating-point helpers */ static always_inline int _do_efdtstlt (uint64_t op1, uint64_t op2) { - union { - uint64_t u; - float64 f; - } u1, u2; - u1.u = op1; - u2.u = op2; - return float64_lt(u1.f, u2.f, &env->spe_status) ? 1 : 0; + CPU_DoubleU u1, u2; + u1.ll = op1; + u2.ll = op2; + return float64_lt(u1.d, u2.d, &env->spe_status) ? 4 : 0; } static always_inline int _do_efdtstgt (uint64_t op1, uint64_t op2) { - union { - uint64_t u; - float64 f; - } u1, u2; - u1.u = op1; - u2.u = op2; - return float64_le(u1.f, u2.f, &env->spe_status) ? 0 : 1; + CPU_DoubleU u1, u2; + u1.ll = op1; + u2.ll = op2; + return float64_le(u1.d, u2.d, &env->spe_status) ? 0 : 4; } static always_inline int _do_efdtsteq (uint64_t op1, uint64_t op2) { - union { - uint64_t u; - float64 f; - } u1, u2; - u1.u = op1; - u2.u = op2; - return float64_eq(u1.f, u2.f, &env->spe_status) ? 1 : 0; + CPU_DoubleU u1, u2; + u1.ll = op1; + u2.ll = op2; + return float64_eq(u1.d, u2.d, &env->spe_status) ? 4 : 0; } #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-ppc/op_helper_mem.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-ppc/op_helper_mem.h --- qemu-0.9.1/target-ppc/op_helper_mem.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-ppc/op_helper_mem.h 2008-03-13 19:19:16.000000000 +0000 @@ -316,15 +316,12 @@ FT1 = glue(ldfq, MEMSUFFIX)((uint32_t)(T0 + 4)); } -static always_inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA) +static always_inline float64 glue(ldfqr, MEMSUFFIX) (target_ulong EA) { - union { - double d; - uint64_t u; - } u; + CPU_DoubleU u; u.d = glue(ldfq, MEMSUFFIX)(EA); - u.u = bswap64(u.u); + u.ll = bswap64(u.ll); return u.d; } @@ -341,15 +338,12 @@ glue(stfq, MEMSUFFIX)((uint32_t)(T0 + 4), FT1); } -static always_inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d) +static always_inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, float64 d) { - union { - double d; - uint64_t u; - } u; + CPU_DoubleU u; u.d = d; - u.u = bswap64(u.u); + u.ll = bswap64(u.ll); glue(stfq, MEMSUFFIX)(EA, u.d); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-ppc/op_mem.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-ppc/op_mem.h --- qemu-0.9.1/target-ppc/op_mem.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-ppc/op_mem.h 2008-10-15 18:00:37.000000000 +0100 @@ -20,111 +20,6 @@ #include "op_mem_access.h" -/*** Integer load ***/ -#define PPC_LD_OP(name, op) \ -void OPPROTO glue(glue(op_l, name), MEMSUFFIX) (void) \ -{ \ - T1 = glue(op, MEMSUFFIX)((uint32_t)T0); \ - RETURN(); \ -} - -#if defined(TARGET_PPC64) -#define PPC_LD_OP_64(name, op) \ -void OPPROTO glue(glue(glue(op_l, name), _64), MEMSUFFIX) (void) \ -{ \ - T1 = glue(op, MEMSUFFIX)((uint64_t)T0); \ - RETURN(); \ -} -#endif - -#define PPC_ST_OP(name, op) \ -void OPPROTO glue(glue(op_st, name), MEMSUFFIX) (void) \ -{ \ - glue(op, MEMSUFFIX)((uint32_t)T0, T1); \ - RETURN(); \ -} - -#if defined(TARGET_PPC64) -#define PPC_ST_OP_64(name, op) \ -void OPPROTO glue(glue(glue(op_st, name), _64), MEMSUFFIX) (void) \ -{ \ - glue(op, MEMSUFFIX)((uint64_t)T0, T1); \ - RETURN(); \ -} -#endif - -PPC_LD_OP(bz, ldu8); -PPC_LD_OP(ha, lds16); -PPC_LD_OP(hz, ldu16); -PPC_LD_OP(wz, ldu32); -#if defined(TARGET_PPC64) -PPC_LD_OP(wa, lds32); -PPC_LD_OP(d, ldu64); -PPC_LD_OP_64(bz, ldu8); -PPC_LD_OP_64(ha, lds16); -PPC_LD_OP_64(hz, ldu16); -PPC_LD_OP_64(wz, ldu32); -PPC_LD_OP_64(wa, lds32); -PPC_LD_OP_64(d, ldu64); -#endif - -PPC_LD_OP(ha_le, lds16r); -PPC_LD_OP(hz_le, ldu16r); -PPC_LD_OP(wz_le, ldu32r); -#if defined(TARGET_PPC64) -PPC_LD_OP(wa_le, lds32r); -PPC_LD_OP(d_le, ldu64r); -PPC_LD_OP_64(ha_le, lds16r); -PPC_LD_OP_64(hz_le, ldu16r); -PPC_LD_OP_64(wz_le, ldu32r); -PPC_LD_OP_64(wa_le, lds32r); -PPC_LD_OP_64(d_le, ldu64r); -#endif - -/*** Integer store ***/ -PPC_ST_OP(b, st8); -PPC_ST_OP(h, st16); -PPC_ST_OP(w, st32); -#if defined(TARGET_PPC64) -PPC_ST_OP(d, st64); -PPC_ST_OP_64(b, st8); -PPC_ST_OP_64(h, st16); -PPC_ST_OP_64(w, st32); -PPC_ST_OP_64(d, st64); -#endif - -PPC_ST_OP(h_le, st16r); -PPC_ST_OP(w_le, st32r); -#if defined(TARGET_PPC64) -PPC_ST_OP(d_le, st64r); -PPC_ST_OP_64(h_le, st16r); -PPC_ST_OP_64(w_le, st32r); -PPC_ST_OP_64(d_le, st64r); -#endif - -/*** Integer load and store with byte reverse ***/ -PPC_LD_OP(hbr, ldu16r); -PPC_LD_OP(wbr, ldu32r); -PPC_ST_OP(hbr, st16r); -PPC_ST_OP(wbr, st32r); -#if defined(TARGET_PPC64) -PPC_LD_OP_64(hbr, ldu16r); -PPC_LD_OP_64(wbr, ldu32r); -PPC_ST_OP_64(hbr, st16r); -PPC_ST_OP_64(wbr, st32r); -#endif - -PPC_LD_OP(hbr_le, ldu16); -PPC_LD_OP(wbr_le, ldu32); -PPC_ST_OP(hbr_le, st16); -PPC_ST_OP(wbr_le, st32); -#if defined(TARGET_PPC64) -PPC_LD_OP_64(hbr_le, ldu16); -PPC_LD_OP_64(wbr_le, ldu32); -PPC_ST_OP_64(hbr_le, st16); -PPC_ST_OP_64(wbr_le, st32); -#endif - /*** Integer load and store multiple ***/ void OPPROTO glue(op_lmw, MEMSUFFIX) (void) { @@ -267,31 +162,19 @@ } #endif -static always_inline void glue(stfs, MEMSUFFIX) (target_ulong EA, double d) +static always_inline void glue(stfs, MEMSUFFIX) (target_ulong EA, float64 d) { glue(stfl, MEMSUFFIX)(EA, float64_to_float32(d, &env->fp_status)); } -#if defined(WORDS_BIGENDIAN) -#define WORD0 0 -#define WORD1 1 -#else -#define WORD0 1 -#define WORD1 0 -#endif -static always_inline void glue(stfiw, MEMSUFFIX) (target_ulong EA, double d) +static always_inline void glue(stfiw, MEMSUFFIX) (target_ulong EA, float64 d) { - union { - double d; - uint32_t u[2]; - } u; + CPU_DoubleU u; /* Store the low order 32 bits without any conversion */ u.d = d; - glue(st32, MEMSUFFIX)(EA, u.u[WORD0]); + glue(st32, MEMSUFFIX)(EA, u.l.lower); } -#undef WORD0 -#undef WORD1 PPC_STF_OP(fd, stfq); PPC_STF_OP(fs, stfs); @@ -302,41 +185,32 @@ PPC_STF_OP_64(fiw, stfiw); #endif -static always_inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d) +static always_inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, float64 d) { - union { - double d; - uint64_t u; - } u; + CPU_DoubleU u; u.d = d; - u.u = bswap64(u.u); + u.ll = bswap64(u.ll); glue(stfq, MEMSUFFIX)(EA, u.d); } -static always_inline void glue(stfsr, MEMSUFFIX) (target_ulong EA, double d) +static always_inline void glue(stfsr, MEMSUFFIX) (target_ulong EA, float64 d) { - union { - float f; - uint32_t u; - } u; + CPU_FloatU u; u.f = float64_to_float32(d, &env->fp_status); - u.u = bswap32(u.u); + u.l = bswap32(u.l); glue(stfl, MEMSUFFIX)(EA, u.f); } -static always_inline void glue(stfiwr, MEMSUFFIX) (target_ulong EA, double d) +static always_inline void glue(stfiwr, MEMSUFFIX) (target_ulong EA, float64 d) { - union { - double d; - uint64_t u; - } u; + CPU_DoubleU u; /* Store the low order 32 bits without any conversion */ u.d = d; - u.u = bswap32(u.u); - glue(st32, MEMSUFFIX)(EA, u.u); + u.l.lower = bswap32(u.l.lower); + glue(st32, MEMSUFFIX)(EA, u.l.lower); } PPC_STF_OP(fd_le, stfqr); @@ -365,7 +239,7 @@ } #endif -static always_inline double glue(ldfs, MEMSUFFIX) (target_ulong EA) +static always_inline float64 glue(ldfs, MEMSUFFIX) (target_ulong EA) { return float32_to_float64(glue(ldfl, MEMSUFFIX)(EA), &env->fp_status); } @@ -377,28 +251,22 @@ PPC_LDF_OP_64(fs, ldfs); #endif -static always_inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA) +static always_inline float64 glue(ldfqr, MEMSUFFIX) (target_ulong EA) { - union { - double d; - uint64_t u; - } u; + CPU_DoubleU u; u.d = glue(ldfq, MEMSUFFIX)(EA); - u.u = bswap64(u.u); + u.ll = bswap64(u.ll); return u.d; } -static always_inline double glue(ldfsr, MEMSUFFIX) (target_ulong EA) +static always_inline float64 glue(ldfsr, MEMSUFFIX) (target_ulong EA) { - union { - float f; - uint32_t u; - } u; + CPU_FloatU u; u.f = glue(ldfl, MEMSUFFIX)(EA); - u.u = bswap32(u.u); + u.l = bswap32(u.l); return float32_to_float64(u.f, &env->fp_status); } @@ -1012,12 +880,10 @@ _PPC_SPE_ST_OP(name, op) #endif -#if !defined(TARGET_PPC64) PPC_SPE_LD_OP(dd, ldu64); PPC_SPE_ST_OP(dd, st64); PPC_SPE_LD_OP(dd_le, ldu64r); PPC_SPE_ST_OP(dd_le, st64r); -#endif static always_inline uint64_t glue(spe_ldw, MEMSUFFIX) (target_ulong EA) { uint64_t ret; @@ -1162,7 +1028,6 @@ glue(st16r, MEMSUFFIX)(EA + 2, data); } PPC_SPE_ST_OP(who_le, spe_stwho_le); -#if !defined(TARGET_PPC64) static always_inline void glue(spe_stwwo, MEMSUFFIX) (target_ulong EA, uint64_t data) { @@ -1175,7 +1040,6 @@ glue(st32r, MEMSUFFIX)(EA, data); } PPC_SPE_ST_OP(wwo_le, spe_stwwo_le); -#endif static always_inline uint64_t glue(spe_lh, MEMSUFFIX) (target_ulong EA) { uint16_t tmp; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-ppc/op_template.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-ppc/op_template.h --- qemu-0.9.1/target-ppc/op_template.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-ppc/op_template.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,214 +0,0 @@ -/* - * PowerPC emulation micro-operations for qemu. - * - * Copyright (c) 2003-2007 Jocelyn Mayer - * - * 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 - */ - -/* General purpose registers moves */ -void OPPROTO glue(op_load_gpr_T0_gpr, REG) (void) -{ - T0 = env->gpr[REG]; - RETURN(); -} - -void OPPROTO glue(op_load_gpr_T1_gpr, REG) (void) -{ - T1 = env->gpr[REG]; - RETURN(); -} - -void OPPROTO glue(op_load_gpr_T2_gpr, REG) (void) -{ - T2 = env->gpr[REG]; - RETURN(); -} - -void OPPROTO glue(op_store_T0_gpr_gpr, REG) (void) -{ - env->gpr[REG] = T0; - RETURN(); -} - -void OPPROTO glue(op_store_T1_gpr_gpr, REG) (void) -{ - env->gpr[REG] = T1; - RETURN(); -} - -#if 0 // unused -void OPPROTO glue(op_store_T2_gpr_gpr, REG) (void) -{ - env->gpr[REG] = T2; - RETURN(); -} -#endif - -/* General purpose registers containing vector operands moves */ -#if !defined(TARGET_PPC64) -void OPPROTO glue(op_load_gpr64_T0_gpr, REG) (void) -{ - T0_64 = (uint64_t)env->gpr[REG] | ((uint64_t)env->gprh[REG] << 32); - RETURN(); -} - -void OPPROTO glue(op_load_gpr64_T1_gpr, REG) (void) -{ - T1_64 = (uint64_t)env->gpr[REG] | ((uint64_t)env->gprh[REG] << 32); - RETURN(); -} - -#if 0 // unused -void OPPROTO glue(op_load_gpr64_T2_gpr, REG) (void) -{ - T2_64 = (uint64_t)env->gpr[REG] | ((uint64_t)env->gprh[REG] << 32); - RETURN(); -} -#endif - -void OPPROTO glue(op_store_T0_gpr64_gpr, REG) (void) -{ - env->gpr[REG] = T0_64; - env->gprh[REG] = T0_64 >> 32; - RETURN(); -} - -void OPPROTO glue(op_store_T1_gpr64_gpr, REG) (void) -{ - env->gpr[REG] = T1_64; - env->gprh[REG] = T1_64 >> 32; - RETURN(); -} - -#if 0 // unused -void OPPROTO glue(op_store_T2_gpr64_gpr, REG) (void) -{ - env->gpr[REG] = T2_64; - env->gprh[REG] = T2_64 >> 32; - RETURN(); -} -#endif -#endif /* !defined(TARGET_PPC64) */ - -/* Altivec registers moves */ -void OPPROTO glue(op_load_avr_A0_avr, REG) (void) -{ - AVR0 = env->avr[REG]; - RETURN(); -} - -void OPPROTO glue(op_load_avr_A1_avr, REG) (void) -{ - AVR1 = env->avr[REG]; - RETURN(); -} - -void OPPROTO glue(op_load_avr_A2_avr, REG) (void) -{ - AVR2 = env->avr[REG]; - RETURN(); -} - -void OPPROTO glue(op_store_A0_avr_avr, REG) (void) -{ - env->avr[REG] = AVR0; - RETURN(); -} - -void OPPROTO glue(op_store_A1_avr_avr, REG) (void) -{ - env->avr[REG] = AVR1; - RETURN(); -} - -#if 0 // unused -void OPPROTO glue(op_store_A2_avr_avr, REG) (void) -{ - env->avr[REG] = AVR2; - RETURN(); -} -#endif - -#if REG <= 7 -/* Condition register moves */ -void OPPROTO glue(op_load_crf_T0_crf, REG) (void) -{ - T0 = env->crf[REG]; - RETURN(); -} - -void OPPROTO glue(op_load_crf_T1_crf, REG) (void) -{ - T1 = env->crf[REG]; - RETURN(); -} - -void OPPROTO glue(op_store_T0_crf_crf, REG) (void) -{ - env->crf[REG] = T0; - RETURN(); -} - -#if 0 // Unused -void OPPROTO glue(op_store_T1_crf_crf, REG) (void) -{ - env->crf[REG] = T1; - RETURN(); -} -#endif - -#endif /* REG <= 7 */ - -/* floating point registers moves */ -void OPPROTO glue(op_load_fpr_FT0_fpr, REG) (void) -{ - FT0 = env->fpr[REG]; - RETURN(); -} - -void OPPROTO glue(op_store_FT0_fpr_fpr, REG) (void) -{ - env->fpr[REG] = FT0; - RETURN(); -} - -void OPPROTO glue(op_load_fpr_FT1_fpr, REG) (void) -{ - FT1 = env->fpr[REG]; - RETURN(); -} - -void OPPROTO glue(op_store_FT1_fpr_fpr, REG) (void) -{ - env->fpr[REG] = FT1; - RETURN(); -} - -void OPPROTO glue(op_load_fpr_FT2_fpr, REG) (void) -{ - FT2 = env->fpr[REG]; - RETURN(); -} - -#if 0 // unused -void OPPROTO glue(op_store_FT2_fpr_fpr, REG) (void) -{ - env->fpr[REG] = FT2; - RETURN(); -} -#endif - -#undef REG diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-ppc/translate.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-ppc/translate.c --- qemu-0.9.1/target-ppc/translate.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-ppc/translate.c 2008-11-10 11:10:23.000000000 +0000 @@ -26,123 +26,183 @@ #include "cpu.h" #include "exec-all.h" #include "disas.h" +#include "helper.h" +#include "tcg-op.h" +#include "qemu-common.h" + +#define CPU_SINGLE_STEP 0x1 +#define CPU_BRANCH_STEP 0x2 +#define GDBSTUB_SINGLE_STEP 0x4 /* Include definitions for instructions classes and implementations flags */ //#define DO_SINGLE_STEP //#define PPC_DEBUG_DISAS -//#define DEBUG_MEMORY_ACCESSES //#define DO_PPC_STATISTICS //#define OPTIMIZE_FPRF_UPDATE /*****************************************************************************/ /* Code translation helpers */ -#if defined(USE_DIRECT_JUMP) -#define TBPARAM(x) -#else -#define TBPARAM(x) (long)(x) -#endif -enum { -#define DEF(s, n, copy_size) INDEX_op_ ## s, -#include "opc.h" -#undef DEF - NB_OPS, -}; +/* global register indexes */ +static TCGv cpu_env; +static char cpu_reg_names[10*3 + 22*4 /* GPR */ +#if !defined(TARGET_PPC64) + + 10*4 + 22*5 /* SPE GPRh */ +#endif + + 10*4 + 22*5 /* FPR */ + + 2*(10*6 + 22*7) /* AVRh, AVRl */ + + 8*5 /* CRF */]; +static TCGv cpu_gpr[32]; +#if !defined(TARGET_PPC64) +static TCGv cpu_gprh[32]; +#endif +static TCGv cpu_fpr[32]; +static TCGv cpu_avrh[32], cpu_avrl[32]; +static TCGv cpu_crf[8]; +static TCGv cpu_nip; +static TCGv cpu_ctr; +static TCGv cpu_lr; +static TCGv cpu_xer; +static TCGv cpu_fpscr; -static uint16_t *gen_opc_ptr; -static uint32_t *gen_opparam_ptr; -#if defined(OPTIMIZE_FPRF_UPDATE) -static uint16_t *gen_fprf_buf[OPC_BUF_SIZE]; -static uint16_t **gen_fprf_ptr; +/* dyngen register indexes */ +static TCGv cpu_T[3]; +#if defined(TARGET_PPC64) +#define cpu_T64 cpu_T +#else +static TCGv cpu_T64[3]; #endif +static TCGv cpu_FT[3]; +static TCGv cpu_AVRh[3], cpu_AVRl[3]; -#include "gen-op.h" +#include "gen-icount.h" -static always_inline void gen_set_T0 (target_ulong val) +void ppc_translate_init(void) { -#if defined(TARGET_PPC64) - if (val >> 32) - gen_op_set_T0_64(val >> 32, val); - else + int i; + char* p; + static int done_init = 0; + + if (done_init) + return; + + cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env"); +#if TARGET_LONG_BITS > HOST_LONG_BITS + cpu_T[0] = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, offsetof(CPUState, t0), "T0"); + cpu_T[1] = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, offsetof(CPUState, t1), "T1"); + cpu_T[2] = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, offsetof(CPUState, t2), "T2"); +#else + cpu_T[0] = tcg_global_reg_new(TCG_TYPE_TL, TCG_AREG1, "T0"); + cpu_T[1] = tcg_global_reg_new(TCG_TYPE_TL, TCG_AREG2, "T1"); +#ifdef HOST_I386 + /* XXX: This is a temporary workaround for i386. + * On i386 qemu_st32 runs out of registers. + * The proper fix is to remove cpu_T. + */ + cpu_T[2] = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, offsetof(CPUState, t2), "T2"); +#else + cpu_T[2] = tcg_global_reg_new(TCG_TYPE_TL, TCG_AREG3, "T2"); #endif - gen_op_set_T0(val); -} +#endif +#if !defined(TARGET_PPC64) + cpu_T64[0] = tcg_global_mem_new(TCG_TYPE_I64, + TCG_AREG0, offsetof(CPUState, t0_64), + "T0_64"); + cpu_T64[1] = tcg_global_mem_new(TCG_TYPE_I64, + TCG_AREG0, offsetof(CPUState, t1_64), + "T1_64"); + cpu_T64[2] = tcg_global_mem_new(TCG_TYPE_I64, + TCG_AREG0, offsetof(CPUState, t2_64), + "T2_64"); +#endif + + cpu_FT[0] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, + offsetof(CPUState, ft0), "FT0"); + cpu_FT[1] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, + offsetof(CPUState, ft1), "FT1"); + cpu_FT[2] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, + offsetof(CPUState, ft2), "FT2"); + + cpu_AVRh[0] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, + offsetof(CPUState, avr0.u64[0]), "AVR0H"); + cpu_AVRl[0] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, + offsetof(CPUState, avr0.u64[1]), "AVR0L"); + cpu_AVRh[1] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, + offsetof(CPUState, avr1.u64[0]), "AVR1H"); + cpu_AVRl[1] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, + offsetof(CPUState, avr1.u64[1]), "AVR1L"); + cpu_AVRh[2] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, + offsetof(CPUState, avr2.u64[0]), "AVR2H"); + cpu_AVRl[2] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, + offsetof(CPUState, avr2.u64[1]), "AVR2L"); -static always_inline void gen_set_T1 (target_ulong val) -{ -#if defined(TARGET_PPC64) - if (val >> 32) - gen_op_set_T1_64(val >> 32, val); - else + p = cpu_reg_names; + + for (i = 0; i < 8; i++) { + sprintf(p, "crf%d", i); + cpu_crf[i] = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, crf[i]), p); + p += 5; + } + + for (i = 0; i < 32; i++) { + sprintf(p, "r%d", i); + cpu_gpr[i] = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, gpr[i]), p); + p += (i < 10) ? 3 : 4; +#if !defined(TARGET_PPC64) + sprintf(p, "r%dH", i); + cpu_gprh[i] = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, gprh[i]), p); + p += (i < 10) ? 4 : 5; #endif - gen_op_set_T1(val); + + sprintf(p, "fp%d", i); + cpu_fpr[i] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, + offsetof(CPUState, fpr[i]), p); + p += (i < 10) ? 4 : 5; + + sprintf(p, "avr%dH", i); + cpu_avrh[i] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, + offsetof(CPUState, avr[i].u64[0]), p); + p += (i < 10) ? 6 : 7; + + sprintf(p, "avr%dL", i); + cpu_avrl[i] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, + offsetof(CPUState, avr[i].u64[1]), p); + p += (i < 10) ? 6 : 7; + } + + cpu_nip = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, nip), "nip"); + + cpu_ctr = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, ctr), "ctr"); + + cpu_lr = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, lr), "lr"); + + cpu_xer = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, xer), "xer"); + + cpu_fpscr = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, fpscr), "fpscr"); + + /* register helpers */ +#undef DEF_HELPER +#define DEF_HELPER(ret, name, params) tcg_register_helper(name, #name); +#include "helper.h" + + done_init = 1; } -#define GEN8(func, NAME) \ -static GenOpFunc *NAME ## _table [8] = { \ -NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ -NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ -}; \ -static always_inline void func (int n) \ -{ \ - NAME ## _table[n](); \ -} - -#define GEN16(func, NAME) \ -static GenOpFunc *NAME ## _table [16] = { \ -NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ -NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ -NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ -NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ -}; \ -static always_inline void func (int n) \ -{ \ - NAME ## _table[n](); \ -} - -#define GEN32(func, NAME) \ -static GenOpFunc *NAME ## _table [32] = { \ -NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ -NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ -NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ -NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ -NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ -NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ -NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ -NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ -}; \ -static always_inline void func (int n) \ -{ \ - NAME ## _table[n](); \ -} - -/* Condition register moves */ -GEN8(gen_op_load_crf_T0, gen_op_load_crf_T0_crf); -GEN8(gen_op_load_crf_T1, gen_op_load_crf_T1_crf); -GEN8(gen_op_store_T0_crf, gen_op_store_T0_crf_crf); -#if 0 // Unused -GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf); -#endif - -/* General purpose registers moves */ -GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr); -GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr); -GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr); - -GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr); -GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr); -#if 0 // unused -GEN32(gen_op_store_T2_gpr, gen_op_store_T2_gpr_gpr); -#endif - -/* floating point registers moves */ -GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fpr); -GEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fpr); -GEN32(gen_op_load_fpr_FT2, gen_op_load_fpr_FT2_fpr); -GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fpr); -GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fpr); -#if 0 // unused -GEN32(gen_op_store_FT2_fpr, gen_op_store_FT2_fpr_fpr); +#if defined(OPTIMIZE_FPRF_UPDATE) +static uint16_t *gen_fprf_buf[OPC_BUF_SIZE]; +static uint16_t **gen_fprf_ptr; #endif /* internal defines */ @@ -176,24 +236,13 @@ /* handler */ void (*handler)(DisasContext *ctx); #if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU) - const unsigned char *oname; + const char *oname; #endif #if defined(DO_PPC_STATISTICS) uint64_t count; #endif }; -static always_inline void gen_set_Rc0 (DisasContext *ctx) -{ -#if defined(TARGET_PPC64) - if (ctx->sf_mode) - gen_op_cmpi_64(0); - else -#endif - gen_op_cmpi(0); - gen_op_set_Rc0(); -} - static always_inline void gen_reset_fpstatus (void) { #ifdef CONFIG_SOFTFLOAT @@ -210,12 +259,12 @@ #endif gen_op_compute_fprf(1); if (unlikely(set_rc)) - gen_op_store_T0_crf(1); + tcg_gen_andi_i32(cpu_crf[1], cpu_T[0], 0xf); gen_op_float_check_status(); } else if (unlikely(set_rc)) { /* We always need to compute fpcc */ gen_op_compute_fprf(0); - gen_op_store_T0_crf(1); + tcg_gen_andi_i32(cpu_crf[1], cpu_T[0], 0xf); if (set_fprf) gen_op_float_check_status(); } @@ -236,10 +285,10 @@ { #if defined(TARGET_PPC64) if (ctx->sf_mode) - gen_op_update_nip_64(nip >> 32, nip); + tcg_gen_movi_tl(cpu_nip, nip); else #endif - gen_op_update_nip(nip); + tcg_gen_movi_tl(cpu_nip, (uint32_t)nip); } #define GEN_EXCP(ctx, excp, error) \ @@ -297,13 +346,13 @@ typedef struct opcode_t { unsigned char opc1, opc2, opc3; -#if HOST_LONG_BITS == 64 /* Explicitely align to 64 bits */ +#if HOST_LONG_BITS == 64 /* Explicitly align to 64 bits */ unsigned char pad[5]; #else unsigned char pad[1]; #endif opc_handler_t handler; - const unsigned char *oname; + const char *oname; } opcode_t; /*****************************************************************************/ @@ -372,7 +421,7 @@ EXTRACT_HELPER(CRM, 12, 8); EXTRACT_HELPER(FM, 17, 8); EXTRACT_HELPER(SR, 16, 4); -EXTRACT_HELPER(FPIMM, 20, 4); +EXTRACT_HELPER(FPIMM, 12, 4); /*** Jump target decoding ***/ /* Displacement */ @@ -661,320 +710,312 @@ .handler = gen_invalid, }; -/*** Integer arithmetic ***/ -#define __GEN_INT_ARITH2(name, opc1, opc2, opc3, inval, type) \ -GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ -{ \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_##name(); \ - gen_op_store_T0_gpr(rD(ctx->opcode)); \ - if (unlikely(Rc(ctx->opcode) != 0)) \ - gen_set_Rc0(ctx); \ -} +/*** Integer comparison ***/ -#define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval, type) \ -GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ -{ \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_##name(); \ - gen_op_store_T0_gpr(rD(ctx->opcode)); \ - if (unlikely(Rc(ctx->opcode) != 0)) \ - gen_set_Rc0(ctx); \ -} +static always_inline void gen_op_cmp(TCGv arg0, TCGv arg1, int s, int crf) +{ + int l1, l2, l3; -#define __GEN_INT_ARITH1(name, opc1, opc2, opc3, type) \ -GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type) \ -{ \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_##name(); \ - gen_op_store_T0_gpr(rD(ctx->opcode)); \ - if (unlikely(Rc(ctx->opcode) != 0)) \ - gen_set_Rc0(ctx); \ -} -#define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3, type) \ -GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type) \ -{ \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_##name(); \ - gen_op_store_T0_gpr(rD(ctx->opcode)); \ - if (unlikely(Rc(ctx->opcode) != 0)) \ - gen_set_Rc0(ctx); \ + tcg_gen_trunc_tl_i32(cpu_crf[crf], cpu_xer); + tcg_gen_shri_i32(cpu_crf[crf], cpu_crf[crf], XER_SO); + tcg_gen_andi_i32(cpu_crf[crf], cpu_crf[crf], 1); + + l1 = gen_new_label(); + l2 = gen_new_label(); + l3 = gen_new_label(); + if (s) { + tcg_gen_brcond_tl(TCG_COND_LT, arg0, arg1, l1); + tcg_gen_brcond_tl(TCG_COND_GT, arg0, arg1, l2); + } else { + tcg_gen_brcond_tl(TCG_COND_LTU, arg0, arg1, l1); + tcg_gen_brcond_tl(TCG_COND_GTU, arg0, arg1, l2); + } + tcg_gen_ori_i32(cpu_crf[crf], cpu_crf[crf], 1 << CRF_EQ); + tcg_gen_br(l3); + gen_set_label(l1); + tcg_gen_ori_i32(cpu_crf[crf], cpu_crf[crf], 1 << CRF_LT); + tcg_gen_br(l3); + gen_set_label(l2); + tcg_gen_ori_i32(cpu_crf[crf], cpu_crf[crf], 1 << CRF_GT); + gen_set_label(l3); } -/* Two operands arithmetic functions */ -#define GEN_INT_ARITH2(name, opc1, opc2, opc3, type) \ -__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000000, type) \ -__GEN_INT_ARITH2_O(name##o, opc1, opc2, opc3 | 0x10, 0x00000000, type) - -/* Two operands arithmetic functions with no overflow allowed */ -#define GEN_INT_ARITHN(name, opc1, opc2, opc3, type) \ -__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000400, type) - -/* One operand arithmetic functions */ -#define GEN_INT_ARITH1(name, opc1, opc2, opc3, type) \ -__GEN_INT_ARITH1(name, opc1, opc2, opc3, type) \ -__GEN_INT_ARITH1_O(name##o, opc1, opc2, opc3 | 0x10, type) - -#if defined(TARGET_PPC64) -#define __GEN_INT_ARITH2_64(name, opc1, opc2, opc3, inval, type) \ -GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ -{ \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - if (ctx->sf_mode) \ - gen_op_##name##_64(); \ - else \ - gen_op_##name(); \ - gen_op_store_T0_gpr(rD(ctx->opcode)); \ - if (unlikely(Rc(ctx->opcode) != 0)) \ - gen_set_Rc0(ctx); \ +static always_inline void gen_op_cmpi(TCGv arg0, target_ulong arg1, int s, int crf) +{ + TCGv t0 = tcg_const_local_tl(arg1); + gen_op_cmp(arg0, t0, s, crf); + tcg_temp_free(t0); } -#define __GEN_INT_ARITH2_O_64(name, opc1, opc2, opc3, inval, type) \ -GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ -{ \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - if (ctx->sf_mode) \ - gen_op_##name##_64(); \ - else \ - gen_op_##name(); \ - gen_op_store_T0_gpr(rD(ctx->opcode)); \ - if (unlikely(Rc(ctx->opcode) != 0)) \ - gen_set_Rc0(ctx); \ +#if defined(TARGET_PPC64) +static always_inline void gen_op_cmp32(TCGv arg0, TCGv arg1, int s, int crf) +{ + TCGv t0, t1; + t0 = tcg_temp_local_new(TCG_TYPE_TL); + t1 = tcg_temp_local_new(TCG_TYPE_TL); + if (s) { + tcg_gen_ext32s_tl(t0, arg0); + tcg_gen_ext32s_tl(t1, arg1); + } else { + tcg_gen_ext32u_tl(t0, arg0); + tcg_gen_ext32u_tl(t1, arg1); + } + gen_op_cmp(t0, t1, s, crf); + tcg_temp_free(t1); + tcg_temp_free(t0); } -#define __GEN_INT_ARITH1_64(name, opc1, opc2, opc3, type) \ -GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type) \ -{ \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - if (ctx->sf_mode) \ - gen_op_##name##_64(); \ - else \ - gen_op_##name(); \ - gen_op_store_T0_gpr(rD(ctx->opcode)); \ - if (unlikely(Rc(ctx->opcode) != 0)) \ - gen_set_Rc0(ctx); \ -} -#define __GEN_INT_ARITH1_O_64(name, opc1, opc2, opc3, type) \ -GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type) \ -{ \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - if (ctx->sf_mode) \ - gen_op_##name##_64(); \ - else \ - gen_op_##name(); \ - gen_op_store_T0_gpr(rD(ctx->opcode)); \ - if (unlikely(Rc(ctx->opcode) != 0)) \ - gen_set_Rc0(ctx); \ +static always_inline void gen_op_cmpi32(TCGv arg0, target_ulong arg1, int s, int crf) +{ + TCGv t0 = tcg_const_local_tl(arg1); + gen_op_cmp32(arg0, t0, s, crf); + tcg_temp_free(t0); } - -/* Two operands arithmetic functions */ -#define GEN_INT_ARITH2_64(name, opc1, opc2, opc3, type) \ -__GEN_INT_ARITH2_64(name, opc1, opc2, opc3, 0x00000000, type) \ -__GEN_INT_ARITH2_O_64(name##o, opc1, opc2, opc3 | 0x10, 0x00000000, type) - -/* Two operands arithmetic functions with no overflow allowed */ -#define GEN_INT_ARITHN_64(name, opc1, opc2, opc3, type) \ -__GEN_INT_ARITH2_64(name, opc1, opc2, opc3, 0x00000400, type) - -/* One operand arithmetic functions */ -#define GEN_INT_ARITH1_64(name, opc1, opc2, opc3, type) \ -__GEN_INT_ARITH1_64(name, opc1, opc2, opc3, type) \ -__GEN_INT_ARITH1_O_64(name##o, opc1, opc2, opc3 | 0x10, type) -#else -#define GEN_INT_ARITH2_64 GEN_INT_ARITH2 -#define GEN_INT_ARITHN_64 GEN_INT_ARITHN -#define GEN_INT_ARITH1_64 GEN_INT_ARITH1 #endif -/* add add. addo addo. */ -static always_inline void gen_op_addo (void) +static always_inline void gen_set_Rc0 (DisasContext *ctx, TCGv reg) { - gen_op_move_T2_T0(); - gen_op_add(); - gen_op_check_addo(); -} #if defined(TARGET_PPC64) -#define gen_op_add_64 gen_op_add -static always_inline void gen_op_addo_64 (void) -{ - gen_op_move_T2_T0(); - gen_op_add(); - gen_op_check_addo_64(); -} + if (!(ctx->sf_mode)) + gen_op_cmpi32(reg, 0, 1, 0); + else #endif -GEN_INT_ARITH2_64 (add, 0x1F, 0x0A, 0x08, PPC_INTEGER); -/* addc addc. addco addco. */ -static always_inline void gen_op_addc (void) -{ - gen_op_move_T2_T0(); - gen_op_add(); - gen_op_check_addc(); + gen_op_cmpi(reg, 0, 1, 0); } -static always_inline void gen_op_addco (void) + +/* cmp */ +GEN_HANDLER(cmp, 0x1F, 0x00, 0x00, 0x00400000, PPC_INTEGER) { - gen_op_move_T2_T0(); - gen_op_add(); - gen_op_check_addc(); - gen_op_check_addo(); -} #if defined(TARGET_PPC64) -static always_inline void gen_op_addc_64 (void) -{ - gen_op_move_T2_T0(); - gen_op_add(); - gen_op_check_addc_64(); -} -static always_inline void gen_op_addco_64 (void) -{ - gen_op_move_T2_T0(); - gen_op_add(); - gen_op_check_addc_64(); - gen_op_check_addo_64(); -} + if (!(ctx->sf_mode && (ctx->opcode & 0x00200000))) + gen_op_cmp32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], + 1, crfD(ctx->opcode)); + else #endif -GEN_INT_ARITH2_64 (addc, 0x1F, 0x0A, 0x00, PPC_INTEGER); -/* adde adde. addeo addeo. */ -static always_inline void gen_op_addeo (void) -{ - gen_op_move_T2_T0(); - gen_op_adde(); - gen_op_check_addo(); + gen_op_cmp(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], + 1, crfD(ctx->opcode)); } -#if defined(TARGET_PPC64) -static always_inline void gen_op_addeo_64 (void) + +/* cmpi */ +GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER) { - gen_op_move_T2_T0(); - gen_op_adde_64(); - gen_op_check_addo_64(); -} +#if defined(TARGET_PPC64) + if (!(ctx->sf_mode && (ctx->opcode & 0x00200000))) + gen_op_cmpi32(cpu_gpr[rA(ctx->opcode)], SIMM(ctx->opcode), + 1, crfD(ctx->opcode)); + else #endif -GEN_INT_ARITH2_64 (adde, 0x1F, 0x0A, 0x04, PPC_INTEGER); -/* addme addme. addmeo addmeo. */ -static always_inline void gen_op_addme (void) -{ - gen_op_move_T1_T0(); - gen_op_add_me(); + gen_op_cmpi(cpu_gpr[rA(ctx->opcode)], SIMM(ctx->opcode), + 1, crfD(ctx->opcode)); } -#if defined(TARGET_PPC64) -static always_inline void gen_op_addme_64 (void) + +/* cmpl */ +GEN_HANDLER(cmpl, 0x1F, 0x00, 0x01, 0x00400000, PPC_INTEGER) { - gen_op_move_T1_T0(); - gen_op_add_me_64(); -} +#if defined(TARGET_PPC64) + if (!(ctx->sf_mode && (ctx->opcode & 0x00200000))) + gen_op_cmp32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], + 0, crfD(ctx->opcode)); + else #endif -GEN_INT_ARITH1_64 (addme, 0x1F, 0x0A, 0x07, PPC_INTEGER); -/* addze addze. addzeo addzeo. */ -static always_inline void gen_op_addze (void) -{ - gen_op_move_T2_T0(); - gen_op_add_ze(); - gen_op_check_addc(); + gen_op_cmp(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], + 0, crfD(ctx->opcode)); } -static always_inline void gen_op_addzeo (void) + +/* cmpli */ +GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER) { - gen_op_move_T2_T0(); - gen_op_add_ze(); - gen_op_check_addc(); - gen_op_check_addo(); -} #if defined(TARGET_PPC64) -static always_inline void gen_op_addze_64 (void) -{ - gen_op_move_T2_T0(); - gen_op_add_ze(); - gen_op_check_addc_64(); + if (!(ctx->sf_mode && (ctx->opcode & 0x00200000))) + gen_op_cmpi32(cpu_gpr[rA(ctx->opcode)], UIMM(ctx->opcode), + 0, crfD(ctx->opcode)); + else +#endif + gen_op_cmpi(cpu_gpr[rA(ctx->opcode)], UIMM(ctx->opcode), + 0, crfD(ctx->opcode)); } -static always_inline void gen_op_addzeo_64 (void) + +/* isel (PowerPC 2.03 specification) */ +GEN_HANDLER(isel, 0x1F, 0x0F, 0xFF, 0x00000001, PPC_ISEL) { - gen_op_move_T2_T0(); - gen_op_add_ze(); - gen_op_check_addc_64(); - gen_op_check_addo_64(); + int l1, l2; + uint32_t bi = rC(ctx->opcode); + uint32_t mask; + TCGv t0; + + l1 = gen_new_label(); + l2 = gen_new_label(); + + mask = 1 << (3 - (bi & 0x03)); + t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_andi_i32(t0, cpu_crf[bi >> 2], mask); + tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1); + if (rA(ctx->opcode) == 0) + tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0); + else + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + gen_set_label(l2); + tcg_temp_free(t0); } -#endif -GEN_INT_ARITH1_64 (addze, 0x1F, 0x0A, 0x06, PPC_INTEGER); -/* divw divw. divwo divwo. */ -GEN_INT_ARITH2 (divw, 0x1F, 0x0B, 0x0F, PPC_INTEGER); -/* divwu divwu. divwuo divwuo. */ -GEN_INT_ARITH2 (divwu, 0x1F, 0x0B, 0x0E, PPC_INTEGER); -/* mulhw mulhw. */ -GEN_INT_ARITHN (mulhw, 0x1F, 0x0B, 0x02, PPC_INTEGER); -/* mulhwu mulhwu. */ -GEN_INT_ARITHN (mulhwu, 0x1F, 0x0B, 0x00, PPC_INTEGER); -/* mullw mullw. mullwo mullwo. */ -GEN_INT_ARITH2 (mullw, 0x1F, 0x0B, 0x07, PPC_INTEGER); -/* neg neg. nego nego. */ -GEN_INT_ARITH1_64 (neg, 0x1F, 0x08, 0x03, PPC_INTEGER); -/* subf subf. subfo subfo. */ -static always_inline void gen_op_subfo (void) + +/*** Integer arithmetic ***/ + +static always_inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0, TCGv arg1, TCGv arg2, int sub) { - gen_op_moven_T2_T0(); - gen_op_subf(); - gen_op_check_addo(); -} + int l1; + TCGv t0; + + l1 = gen_new_label(); + /* Start with XER OV disabled, the most likely case */ + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + t0 = tcg_temp_local_new(TCG_TYPE_TL); + tcg_gen_xor_tl(t0, arg0, arg1); #if defined(TARGET_PPC64) -#define gen_op_subf_64 gen_op_subf -static always_inline void gen_op_subfo_64 (void) -{ - gen_op_moven_T2_T0(); - gen_op_subf(); - gen_op_check_addo_64(); -} + if (!ctx->sf_mode) + tcg_gen_ext32s_tl(t0, t0); #endif -GEN_INT_ARITH2_64 (subf, 0x1F, 0x08, 0x01, PPC_INTEGER); -/* subfc subfc. subfco subfco. */ -static always_inline void gen_op_subfc (void) -{ - gen_op_subf(); - gen_op_check_subfc(); + if (sub) + tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0, l1); + else + tcg_gen_brcondi_tl(TCG_COND_GE, t0, 0, l1); + tcg_gen_xor_tl(t0, arg1, arg2); +#if defined(TARGET_PPC64) + if (!ctx->sf_mode) + tcg_gen_ext32s_tl(t0, t0); +#endif + if (sub) + tcg_gen_brcondi_tl(TCG_COND_GE, t0, 0, l1); + else + tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0, l1); + tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + gen_set_label(l1); + tcg_temp_free(t0); } -static always_inline void gen_op_subfco (void) + +static always_inline void gen_op_arith_compute_ca(DisasContext *ctx, TCGv arg1, TCGv arg2, int sub) { - gen_op_moven_T2_T0(); - gen_op_subf(); - gen_op_check_subfc(); - gen_op_check_addo(); -} + int l1 = gen_new_label(); + #if defined(TARGET_PPC64) -static always_inline void gen_op_subfc_64 (void) -{ - gen_op_subf(); - gen_op_check_subfc_64(); + if (!(ctx->sf_mode)) { + TCGv t0, t1; + t0 = tcg_temp_new(TCG_TYPE_TL); + t1 = tcg_temp_new(TCG_TYPE_TL); + + tcg_gen_ext32u_tl(t0, arg1); + tcg_gen_ext32u_tl(t1, arg2); + if (sub) { + tcg_gen_brcond_tl(TCG_COND_GTU, t0, t1, l1); + } else { + tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1); + } + tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA); + gen_set_label(l1); + tcg_temp_free(t0); + tcg_temp_free(t1); + } else +#endif + { + if (sub) { + tcg_gen_brcond_tl(TCG_COND_GTU, arg1, arg2, l1); + } else { + tcg_gen_brcond_tl(TCG_COND_GEU, arg1, arg2, l1); + } + tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA); + gen_set_label(l1); + } } -static always_inline void gen_op_subfco_64 (void) -{ - gen_op_moven_T2_T0(); - gen_op_subf(); - gen_op_check_subfc_64(); - gen_op_check_addo_64(); + +/* Common add function */ +static always_inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1, TCGv arg2, + int add_ca, int compute_ca, int compute_ov) +{ + TCGv t0, t1; + + if ((!compute_ca && !compute_ov) || + (GET_TCGV(ret) != GET_TCGV(arg1) && GET_TCGV(ret) != GET_TCGV(arg2))) { + t0 = ret; + } else { + t0 = tcg_temp_local_new(TCG_TYPE_TL); + } + + if (add_ca) { + t1 = tcg_temp_local_new(TCG_TYPE_TL); + tcg_gen_andi_tl(t1, cpu_xer, (1 << XER_CA)); + tcg_gen_shri_tl(t1, t1, XER_CA); + } + + if (compute_ca && compute_ov) { + /* Start with XER CA and OV disabled, the most likely case */ + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~((1 << XER_CA) | (1 << XER_OV))); + } else if (compute_ca) { + /* Start with XER CA disabled, the most likely case */ + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA)); + } else if (compute_ov) { + /* Start with XER OV disabled, the most likely case */ + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + } + + tcg_gen_add_tl(t0, arg1, arg2); + + if (compute_ca) { + gen_op_arith_compute_ca(ctx, t0, arg1, 0); + } + if (add_ca) { + tcg_gen_add_tl(t0, t0, t1); + gen_op_arith_compute_ca(ctx, t0, t1, 0); + tcg_temp_free(t1); + } + if (compute_ov) { + gen_op_arith_compute_ov(ctx, t0, arg1, arg2, 0); + } + + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, t0); + + if (GET_TCGV(t0) != GET_TCGV(ret)) { + tcg_gen_mov_tl(ret, t0); + tcg_temp_free(t0); + } } -#endif -GEN_INT_ARITH2_64 (subfc, 0x1F, 0x08, 0x00, PPC_INTEGER); -/* subfe subfe. subfeo subfeo. */ -static always_inline void gen_op_subfeo (void) -{ - gen_op_moven_T2_T0(); - gen_op_subfe(); - gen_op_check_addo(); +/* Add functions with two operands */ +#define GEN_INT_ARITH_ADD(name, opc3, add_ca, compute_ca, compute_ov) \ +GEN_HANDLER(name, 0x1F, 0x0A, opc3, 0x00000000, PPC_INTEGER) \ +{ \ + gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)], \ + cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \ + add_ca, compute_ca, compute_ov); \ } -#if defined(TARGET_PPC64) -#define gen_op_subfe_64 gen_op_subfe -static always_inline void gen_op_subfeo_64 (void) -{ - gen_op_moven_T2_T0(); - gen_op_subfe_64(); - gen_op_check_addo_64(); +/* Add functions with one operand and one immediate */ +#define GEN_INT_ARITH_ADD_CONST(name, opc3, const_val, \ + add_ca, compute_ca, compute_ov) \ +GEN_HANDLER(name, 0x1F, 0x0A, opc3, 0x0000F800, PPC_INTEGER) \ +{ \ + TCGv t0 = tcg_const_local_tl(const_val); \ + gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)], \ + cpu_gpr[rA(ctx->opcode)], t0, \ + add_ca, compute_ca, compute_ov); \ + tcg_temp_free(t0); \ } -#endif -GEN_INT_ARITH2_64 (subfe, 0x1F, 0x08, 0x04, PPC_INTEGER); -/* subfme subfme. subfmeo subfmeo. */ -GEN_INT_ARITH1_64 (subfme, 0x1F, 0x08, 0x07, PPC_INTEGER); -/* subfze subfze. subfzeo subfzeo. */ -GEN_INT_ARITH1_64 (subfze, 0x1F, 0x08, 0x06, PPC_INTEGER); + +/* add add. addo addo. */ +GEN_INT_ARITH_ADD(add, 0x08, 0, 0, 0) +GEN_INT_ARITH_ADD(addo, 0x18, 0, 0, 1) +/* addc addc. addco addco. */ +GEN_INT_ARITH_ADD(addc, 0x00, 0, 1, 0) +GEN_INT_ARITH_ADD(addco, 0x10, 0, 1, 1) +/* adde adde. addeo addeo. */ +GEN_INT_ARITH_ADD(adde, 0x04, 1, 1, 0) +GEN_INT_ARITH_ADD(addeo, 0x14, 1, 1, 1) +/* addme addme. addmeo addmeo. */ +GEN_INT_ARITH_ADD_CONST(addme, 0x07, -1LL, 1, 1, 0) +GEN_INT_ARITH_ADD_CONST(addmeo, 0x17, -1LL, 1, 1, 1) +/* addze addze. addzeo addzeo.*/ +GEN_INT_ARITH_ADD_CONST(addze, 0x06, 0, 1, 1, 0) +GEN_INT_ARITH_ADD_CONST(addzeo, 0x16, 0, 1, 1, 1) /* addi */ GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { @@ -982,54 +1023,40 @@ if (rA(ctx->opcode) == 0) { /* li case */ - gen_set_T0(simm); + tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], simm); } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - if (likely(simm != 0)) - gen_op_addi(simm); + tcg_gen_addi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], simm); } - gen_op_store_T0_gpr(rD(ctx->opcode)); } -/* addic */ -GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +/* addic addic.*/ +static always_inline void gen_op_addic (DisasContext *ctx, TCGv ret, TCGv arg1, + int compute_Rc0) { target_long simm = SIMM(ctx->opcode); - gen_op_load_gpr_T0(rA(ctx->opcode)); + /* Start with XER CA and OV disabled, the most likely case */ + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA)); + if (likely(simm != 0)) { - gen_op_move_T2_T0(); - gen_op_addi(simm); -#if defined(TARGET_PPC64) - if (ctx->sf_mode) - gen_op_check_addc_64(); - else -#endif - gen_op_check_addc(); + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + tcg_gen_addi_tl(t0, arg1, simm); + gen_op_arith_compute_ca(ctx, t0, arg1, 0); + tcg_gen_mov_tl(ret, t0); + tcg_temp_free(t0); } else { - gen_op_clear_xer_ca(); + tcg_gen_mov_tl(ret, arg1); } - gen_op_store_T0_gpr(rD(ctx->opcode)); + if (compute_Rc0) { + gen_set_Rc0(ctx, ret); + } +} +GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + gen_op_addic(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0); } -/* addic. */ GEN_HANDLER2(addic_, "addic.", 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - target_long simm = SIMM(ctx->opcode); - - gen_op_load_gpr_T0(rA(ctx->opcode)); - if (likely(simm != 0)) { - gen_op_move_T2_T0(); - gen_op_addi(simm); -#if defined(TARGET_PPC64) - if (ctx->sf_mode) - gen_op_check_addc_64(); - else -#endif - gen_op_check_addc(); - } else { - gen_op_clear_xer_ca(); - } - gen_op_store_T0_gpr(rD(ctx->opcode)); - gen_set_Rc0(ctx); + gen_op_addic(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 1); } /* addis */ GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -1038,177 +1065,431 @@ if (rA(ctx->opcode) == 0) { /* lis case */ - gen_set_T0(simm << 16); + tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], simm << 16); } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - if (likely(simm != 0)) - gen_op_addi(simm << 16); + tcg_gen_addi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], simm << 16); } - gen_op_store_T0_gpr(rD(ctx->opcode)); } -/* mulli */ -GEN_HANDLER(mulli, 0x07, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) + +static always_inline void gen_op_arith_divw (DisasContext *ctx, TCGv ret, TCGv arg1, TCGv arg2, + int sign, int compute_ov) { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_mulli(SIMM(ctx->opcode)); - gen_op_store_T0_gpr(rD(ctx->opcode)); + int l1 = gen_new_label(); + int l2 = gen_new_label(); + TCGv t0 = tcg_temp_local_new(TCG_TYPE_I32); + TCGv t1 = tcg_temp_local_new(TCG_TYPE_I32); + + tcg_gen_trunc_tl_i32(t0, arg1); + tcg_gen_trunc_tl_i32(t1, arg2); + tcg_gen_brcondi_i32(TCG_COND_EQ, t1, 0, l1); + if (sign) { + int l3 = gen_new_label(); + tcg_gen_brcondi_i32(TCG_COND_NE, t1, -1, l3); + tcg_gen_brcondi_i32(TCG_COND_EQ, t0, INT32_MIN, l1); + gen_set_label(l3); + tcg_gen_div_i32(t0, t0, t1); + } else { + tcg_gen_divu_i32(t0, t0, t1); + } + if (compute_ov) { + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + } + tcg_gen_br(l2); + gen_set_label(l1); + if (sign) { + tcg_gen_sari_i32(t0, t0, 31); + } else { + tcg_gen_movi_i32(t0, 0); + } + if (compute_ov) { + tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + } + gen_set_label(l2); + tcg_gen_extu_i32_tl(ret, t0); + tcg_temp_free(t0); + tcg_temp_free(t1); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, ret); +} +/* Div functions */ +#define GEN_INT_ARITH_DIVW(name, opc3, sign, compute_ov) \ +GEN_HANDLER(name, 0x1F, 0x0B, opc3, 0x00000000, PPC_INTEGER) \ +{ \ + gen_op_arith_divw(ctx, cpu_gpr[rD(ctx->opcode)], \ + cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \ + sign, compute_ov); \ +} +/* divwu divwu. divwuo divwuo. */ +GEN_INT_ARITH_DIVW(divwu, 0x0E, 0, 0); +GEN_INT_ARITH_DIVW(divwuo, 0x1E, 0, 1); +/* divw divw. divwo divwo. */ +GEN_INT_ARITH_DIVW(divw, 0x0F, 1, 0); +GEN_INT_ARITH_DIVW(divwo, 0x1F, 1, 1); +#if defined(TARGET_PPC64) +static always_inline void gen_op_arith_divd (DisasContext *ctx, TCGv ret, TCGv arg1, TCGv arg2, + int sign, int compute_ov) +{ + int l1 = gen_new_label(); + int l2 = gen_new_label(); + + tcg_gen_brcondi_i64(TCG_COND_EQ, arg2, 0, l1); + if (sign) { + int l3 = gen_new_label(); + tcg_gen_brcondi_i64(TCG_COND_NE, arg2, -1, l3); + tcg_gen_brcondi_i64(TCG_COND_EQ, arg1, INT64_MIN, l1); + gen_set_label(l3); + tcg_gen_div_i64(ret, arg1, arg2); + } else { + tcg_gen_divu_i64(ret, arg1, arg2); + } + if (compute_ov) { + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + } + tcg_gen_br(l2); + gen_set_label(l1); + if (sign) { + tcg_gen_sari_i64(ret, arg1, 63); + } else { + tcg_gen_movi_i64(ret, 0); + } + if (compute_ov) { + tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + } + gen_set_label(l2); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, ret); } -/* subfic */ -GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +#define GEN_INT_ARITH_DIVD(name, opc3, sign, compute_ov) \ +GEN_HANDLER(name, 0x1F, 0x09, opc3, 0x00000000, PPC_64B) \ +{ \ + gen_op_arith_divd(ctx, cpu_gpr[rD(ctx->opcode)], \ + cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \ + sign, compute_ov); \ +} +/* divwu divwu. divwuo divwuo. */ +GEN_INT_ARITH_DIVD(divdu, 0x0E, 0, 0); +GEN_INT_ARITH_DIVD(divduo, 0x1E, 0, 1); +/* divw divw. divwo divwo. */ +GEN_INT_ARITH_DIVD(divd, 0x0F, 1, 0); +GEN_INT_ARITH_DIVD(divdo, 0x1F, 1, 1); +#endif + +/* mulhw mulhw. */ +GEN_HANDLER(mulhw, 0x1F, 0x0B, 0x02, 0x00000400, PPC_INTEGER) { - gen_op_load_gpr_T0(rA(ctx->opcode)); + TCGv t0, t1; + + t0 = tcg_temp_new(TCG_TYPE_I64); + t1 = tcg_temp_new(TCG_TYPE_I64); #if defined(TARGET_PPC64) - if (ctx->sf_mode) - gen_op_subfic_64(SIMM(ctx->opcode)); - else + tcg_gen_ext32s_tl(t0, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_ext32s_tl(t1, cpu_gpr[rB(ctx->opcode)]); + tcg_gen_mul_i64(t0, t0, t1); + tcg_gen_shri_i64(cpu_gpr[rD(ctx->opcode)], t0, 32); +#else + tcg_gen_ext_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_ext_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]); + tcg_gen_mul_i64(t0, t0, t1); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t0); #endif - gen_op_subfic(SIMM(ctx->opcode)); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_temp_free(t0); + tcg_temp_free(t1); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } +/* mulhwu mulhwu. */ +GEN_HANDLER(mulhwu, 0x1F, 0x0B, 0x00, 0x00000400, PPC_INTEGER) +{ + TCGv t0, t1; + t0 = tcg_temp_new(TCG_TYPE_I64); + t1 = tcg_temp_new(TCG_TYPE_I64); #if defined(TARGET_PPC64) -/* mulhd mulhd. */ -GEN_INT_ARITHN (mulhd, 0x1F, 0x09, 0x02, PPC_64B); -/* mulhdu mulhdu. */ -GEN_INT_ARITHN (mulhdu, 0x1F, 0x09, 0x00, PPC_64B); -/* mulld mulld. mulldo mulldo. */ -GEN_INT_ARITH2 (mulld, 0x1F, 0x09, 0x07, PPC_64B); -/* divd divd. divdo divdo. */ -GEN_INT_ARITH2 (divd, 0x1F, 0x09, 0x0F, PPC_64B); -/* divdu divdu. divduo divduo. */ -GEN_INT_ARITH2 (divdu, 0x1F, 0x09, 0x0E, PPC_64B); + tcg_gen_ext32u_i64(t0, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_ext32u_i64(t1, cpu_gpr[rB(ctx->opcode)]); + tcg_gen_mul_i64(t0, t0, t1); + tcg_gen_shri_i64(cpu_gpr[rD(ctx->opcode)], t0, 32); +#else + tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]); + tcg_gen_mul_i64(t0, t0, t1); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t0); #endif + tcg_temp_free(t0); + tcg_temp_free(t1); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); +} +/* mullw mullw. */ +GEN_HANDLER(mullw, 0x1F, 0x0B, 0x07, 0x00000000, PPC_INTEGER) +{ + tcg_gen_mul_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], + cpu_gpr[rB(ctx->opcode)]); + tcg_gen_ext32s_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)]); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); +} +/* mullwo mullwo. */ +GEN_HANDLER(mullwo, 0x1F, 0x0B, 0x17, 0x00000000, PPC_INTEGER) +{ + int l1; + TCGv t0, t1; -/*** Integer comparison ***/ + t0 = tcg_temp_new(TCG_TYPE_I64); + t1 = tcg_temp_new(TCG_TYPE_I64); + l1 = gen_new_label(); + /* Start with XER OV disabled, the most likely case */ + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); #if defined(TARGET_PPC64) -#define GEN_CMP(name, opc, type) \ -GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, type) \ -{ \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - if (ctx->sf_mode && (ctx->opcode & 0x00200000)) \ - gen_op_##name##_64(); \ - else \ - gen_op_##name(); \ - gen_op_store_T0_crf(crfD(ctx->opcode)); \ -} + tcg_gen_ext32s_i64(t0, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_ext32s_i64(t1, cpu_gpr[rB(ctx->opcode)]); #else -#define GEN_CMP(name, opc, type) \ -GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, type) \ + tcg_gen_ext_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_ext_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]); +#endif + tcg_gen_mul_i64(t0, t0, t1); +#if defined(TARGET_PPC64) + tcg_gen_ext32s_i64(cpu_gpr[rD(ctx->opcode)], t0); + tcg_gen_brcond_i64(TCG_COND_EQ, t0, cpu_gpr[rD(ctx->opcode)], l1); +#else + tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t0); + tcg_gen_ext32s_i64(t1, t0); + tcg_gen_brcond_i64(TCG_COND_EQ, t0, t1, l1); +#endif + tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + gen_set_label(l1); + tcg_temp_free(t0); + tcg_temp_free(t1); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); +} +/* mulli */ +GEN_HANDLER(mulli, 0x07, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + tcg_gen_muli_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], + SIMM(ctx->opcode)); +} +#if defined(TARGET_PPC64) +#define GEN_INT_ARITH_MUL_HELPER(name, opc3) \ +GEN_HANDLER(name, 0x1F, 0x09, opc3, 0x00000000, PPC_64B) \ { \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_##name(); \ - gen_op_store_T0_crf(crfD(ctx->opcode)); \ + tcg_gen_helper_1_2(helper_##name, cpu_gpr[rD(ctx->opcode)], \ + cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \ + if (unlikely(Rc(ctx->opcode) != 0)) \ + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); \ } +/* mulhd mulhd. */ +GEN_INT_ARITH_MUL_HELPER(mulhdu, 0x00); +/* mulhdu mulhdu. */ +GEN_INT_ARITH_MUL_HELPER(mulhd, 0x02); +/* mulld mulld. */ +GEN_HANDLER(mulld, 0x1F, 0x09, 0x07, 0x00000000, PPC_64B) +{ + tcg_gen_mul_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], + cpu_gpr[rB(ctx->opcode)]); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); +} +/* mulldo mulldo. */ +GEN_INT_ARITH_MUL_HELPER(mulldo, 0x17); #endif -/* cmp */ -GEN_CMP(cmp, 0x00, PPC_INTEGER); -/* cmpi */ -GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER) +/* neg neg. nego nego. */ +static always_inline void gen_op_arith_neg (DisasContext *ctx, TCGv ret, TCGv arg1, int ov_check) { - gen_op_load_gpr_T0(rA(ctx->opcode)); + int l1 = gen_new_label(); + int l2 = gen_new_label(); + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); #if defined(TARGET_PPC64) - if (ctx->sf_mode && (ctx->opcode & 0x00200000)) - gen_op_cmpi_64(SIMM(ctx->opcode)); - else + if (ctx->sf_mode) { + tcg_gen_mov_tl(t0, arg1); + tcg_gen_brcondi_tl(TCG_COND_EQ, t0, INT64_MIN, l1); + } else #endif - gen_op_cmpi(SIMM(ctx->opcode)); - gen_op_store_T0_crf(crfD(ctx->opcode)); + { + tcg_gen_ext32s_tl(t0, arg1); + tcg_gen_brcondi_tl(TCG_COND_EQ, t0, INT32_MIN, l1); + } + tcg_gen_neg_tl(ret, arg1); + if (ov_check) { + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + } + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_mov_tl(ret, t0); + if (ov_check) { + tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + } + gen_set_label(l2); + tcg_temp_free(t0); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, ret); } -/* cmpl */ -GEN_CMP(cmpl, 0x01, PPC_INTEGER); -/* cmpli */ -GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER) +GEN_HANDLER(neg, 0x1F, 0x08, 0x03, 0x0000F800, PPC_INTEGER) { - gen_op_load_gpr_T0(rA(ctx->opcode)); -#if defined(TARGET_PPC64) - if (ctx->sf_mode && (ctx->opcode & 0x00200000)) - gen_op_cmpli_64(UIMM(ctx->opcode)); - else -#endif - gen_op_cmpli(UIMM(ctx->opcode)); - gen_op_store_T0_crf(crfD(ctx->opcode)); + gen_op_arith_neg(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0); +} +GEN_HANDLER(nego, 0x1F, 0x08, 0x13, 0x0000F800, PPC_INTEGER) +{ + gen_op_arith_neg(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 1); } -/* isel (PowerPC 2.03 specification) */ -GEN_HANDLER(isel, 0x1F, 0x0F, 0x00, 0x00000001, PPC_ISEL) +/* Common subf function */ +static always_inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1, TCGv arg2, + int add_ca, int compute_ca, int compute_ov) { - uint32_t bi = rC(ctx->opcode); - uint32_t mask; + TCGv t0, t1; - if (rA(ctx->opcode) == 0) { - gen_set_T0(0); + if ((!compute_ca && !compute_ov) || + (GET_TCGV(ret) != GET_TCGV(arg1) && GET_TCGV(ret) != GET_TCGV(arg2))) { + t0 = ret; } else { - gen_op_load_gpr_T1(rA(ctx->opcode)); + t0 = tcg_temp_local_new(TCG_TYPE_TL); } - gen_op_load_gpr_T2(rB(ctx->opcode)); - mask = 1 << (3 - (bi & 0x03)); - gen_op_load_crf_T0(bi >> 2); - gen_op_test_true(mask); - gen_op_isel(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + + if (add_ca) { + t1 = tcg_temp_local_new(TCG_TYPE_TL); + tcg_gen_andi_tl(t1, cpu_xer, (1 << XER_CA)); + tcg_gen_shri_tl(t1, t1, XER_CA); + } + + if (compute_ca && compute_ov) { + /* Start with XER CA and OV disabled, the most likely case */ + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~((1 << XER_CA) | (1 << XER_OV))); + } else if (compute_ca) { + /* Start with XER CA disabled, the most likely case */ + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA)); + } else if (compute_ov) { + /* Start with XER OV disabled, the most likely case */ + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + } + + if (add_ca) { + tcg_gen_not_tl(t0, arg1); + tcg_gen_add_tl(t0, t0, arg2); + gen_op_arith_compute_ca(ctx, t0, arg2, 0); + tcg_gen_add_tl(t0, t0, t1); + gen_op_arith_compute_ca(ctx, t0, t1, 0); + tcg_temp_free(t1); + } else { + tcg_gen_sub_tl(t0, arg2, arg1); + if (compute_ca) { + gen_op_arith_compute_ca(ctx, t0, arg2, 1); + } + } + if (compute_ov) { + gen_op_arith_compute_ov(ctx, t0, arg1, arg2, 1); + } + + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, t0); + + if (GET_TCGV(t0) != GET_TCGV(ret)) { + tcg_gen_mov_tl(ret, t0); + tcg_temp_free(t0); + } +} +/* Sub functions with Two operands functions */ +#define GEN_INT_ARITH_SUBF(name, opc3, add_ca, compute_ca, compute_ov) \ +GEN_HANDLER(name, 0x1F, 0x08, opc3, 0x00000000, PPC_INTEGER) \ +{ \ + gen_op_arith_subf(ctx, cpu_gpr[rD(ctx->opcode)], \ + cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \ + add_ca, compute_ca, compute_ov); \ +} +/* Sub functions with one operand and one immediate */ +#define GEN_INT_ARITH_SUBF_CONST(name, opc3, const_val, \ + add_ca, compute_ca, compute_ov) \ +GEN_HANDLER(name, 0x1F, 0x08, opc3, 0x0000F800, PPC_INTEGER) \ +{ \ + TCGv t0 = tcg_const_local_tl(const_val); \ + gen_op_arith_subf(ctx, cpu_gpr[rD(ctx->opcode)], \ + cpu_gpr[rA(ctx->opcode)], t0, \ + add_ca, compute_ca, compute_ov); \ + tcg_temp_free(t0); \ +} +/* subf subf. subfo subfo. */ +GEN_INT_ARITH_SUBF(subf, 0x01, 0, 0, 0) +GEN_INT_ARITH_SUBF(subfo, 0x11, 0, 0, 1) +/* subfc subfc. subfco subfco. */ +GEN_INT_ARITH_SUBF(subfc, 0x00, 0, 1, 0) +GEN_INT_ARITH_SUBF(subfco, 0x10, 0, 1, 1) +/* subfe subfe. subfeo subfo. */ +GEN_INT_ARITH_SUBF(subfe, 0x04, 1, 1, 0) +GEN_INT_ARITH_SUBF(subfeo, 0x14, 1, 1, 1) +/* subfme subfme. subfmeo subfmeo. */ +GEN_INT_ARITH_SUBF_CONST(subfme, 0x07, -1LL, 1, 1, 0) +GEN_INT_ARITH_SUBF_CONST(subfmeo, 0x17, -1LL, 1, 1, 1) +/* subfze subfze. subfzeo subfzeo.*/ +GEN_INT_ARITH_SUBF_CONST(subfze, 0x06, 0, 1, 1, 0) +GEN_INT_ARITH_SUBF_CONST(subfzeo, 0x16, 0, 1, 1, 1) +/* subfic */ +GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + /* Start with XER CA and OV disabled, the most likely case */ + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA)); + TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL); + TCGv t1 = tcg_const_local_tl(SIMM(ctx->opcode)); + tcg_gen_sub_tl(t0, t1, cpu_gpr[rA(ctx->opcode)]); + gen_op_arith_compute_ca(ctx, t0, t1, 1); + tcg_temp_free(t1); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); + tcg_temp_free(t0); } /*** Integer logical ***/ -#define __GEN_LOGICAL2(name, opc2, opc3, type) \ -GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, type) \ +#define GEN_LOGICAL2(name, tcg_op, opc, type) \ +GEN_HANDLER(name, 0x1F, 0x1C, opc, 0x00000000, type) \ { \ - gen_op_load_gpr_T0(rS(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_##name(); \ - gen_op_store_T0_gpr(rA(ctx->opcode)); \ + tcg_op(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], \ + cpu_gpr[rB(ctx->opcode)]); \ if (unlikely(Rc(ctx->opcode) != 0)) \ - gen_set_Rc0(ctx); \ + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); \ } -#define GEN_LOGICAL2(name, opc, type) \ -__GEN_LOGICAL2(name, 0x1C, opc, type) -#define GEN_LOGICAL1(name, opc, type) \ +#define GEN_LOGICAL1(name, tcg_op, opc, type) \ GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, type) \ { \ - gen_op_load_gpr_T0(rS(ctx->opcode)); \ - gen_op_##name(); \ - gen_op_store_T0_gpr(rA(ctx->opcode)); \ + tcg_op(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); \ if (unlikely(Rc(ctx->opcode) != 0)) \ - gen_set_Rc0(ctx); \ + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); \ } /* and & and. */ -GEN_LOGICAL2(and, 0x00, PPC_INTEGER); +GEN_LOGICAL2(and, tcg_gen_and_tl, 0x00, PPC_INTEGER); /* andc & andc. */ -GEN_LOGICAL2(andc, 0x01, PPC_INTEGER); +GEN_LOGICAL2(andc, tcg_gen_andc_tl, 0x01, PPC_INTEGER); /* andi. */ GEN_HANDLER2(andi_, "andi.", 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_andi_T0(UIMM(ctx->opcode)); - gen_op_store_T0_gpr(rA(ctx->opcode)); - gen_set_Rc0(ctx); + tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], UIMM(ctx->opcode)); + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } /* andis. */ GEN_HANDLER2(andis_, "andis.", 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_andi_T0(UIMM(ctx->opcode) << 16); - gen_op_store_T0_gpr(rA(ctx->opcode)); - gen_set_Rc0(ctx); + tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], UIMM(ctx->opcode) << 16); + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } - /* cntlzw */ -GEN_LOGICAL1(cntlzw, 0x00, PPC_INTEGER); +GEN_HANDLER(cntlzw, 0x1F, 0x1A, 0x00, 0x00000000, PPC_INTEGER) +{ + tcg_gen_helper_1_1(helper_cntlzw, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); +} /* eqv & eqv. */ -GEN_LOGICAL2(eqv, 0x08, PPC_INTEGER); +GEN_LOGICAL2(eqv, tcg_gen_eqv_tl, 0x08, PPC_INTEGER); /* extsb & extsb. */ -GEN_LOGICAL1(extsb, 0x1D, PPC_INTEGER); +GEN_LOGICAL1(extsb, tcg_gen_ext8s_tl, 0x1D, PPC_INTEGER); /* extsh & extsh. */ -GEN_LOGICAL1(extsh, 0x1C, PPC_INTEGER); +GEN_LOGICAL1(extsh, tcg_gen_ext16s_tl, 0x1C, PPC_INTEGER); /* nand & nand. */ -GEN_LOGICAL2(nand, 0x0E, PPC_INTEGER); +GEN_LOGICAL2(nand, tcg_gen_nand_tl, 0x0E, PPC_INTEGER); /* nor & nor. */ -GEN_LOGICAL2(nor, 0x03, PPC_INTEGER); - +GEN_LOGICAL2(nor, tcg_gen_nor_tl, 0x03, PPC_INTEGER); /* or & or. */ GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER) { @@ -1219,55 +1500,54 @@ rb = rB(ctx->opcode); /* Optimisation for mr. ri case */ if (rs != ra || rs != rb) { - gen_op_load_gpr_T0(rs); - if (rs != rb) { - gen_op_load_gpr_T1(rb); - gen_op_or(); - } - gen_op_store_T0_gpr(ra); + if (rs != rb) + tcg_gen_or_tl(cpu_gpr[ra], cpu_gpr[rs], cpu_gpr[rb]); + else + tcg_gen_mov_tl(cpu_gpr[ra], cpu_gpr[rs]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_gpr[ra]); } else if (unlikely(Rc(ctx->opcode) != 0)) { - gen_op_load_gpr_T0(rs); - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_gpr[rs]); #if defined(TARGET_PPC64) } else { + int prio = 0; + switch (rs) { case 1: /* Set process priority to low */ - gen_op_store_pri(2); + prio = 2; break; case 6: /* Set process priority to medium-low */ - gen_op_store_pri(3); + prio = 3; break; case 2: /* Set process priority to normal */ - gen_op_store_pri(4); + prio = 4; break; #if !defined(CONFIG_USER_ONLY) case 31: if (ctx->supervisor > 0) { /* Set process priority to very low */ - gen_op_store_pri(1); + prio = 1; } break; case 5: if (ctx->supervisor > 0) { /* Set process priority to medium-hight */ - gen_op_store_pri(5); + prio = 5; } break; case 3: if (ctx->supervisor > 0) { /* Set process priority to high */ - gen_op_store_pri(6); + prio = 6; } break; case 7: if (ctx->supervisor > 1) { /* Set process priority to very high */ - gen_op_store_pri(7); + prio = 7; } break; #endif @@ -1275,26 +1555,29 @@ /* nop */ break; } + if (prio) { + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, spr[SPR_PPR])); + tcg_gen_andi_tl(t0, t0, ~0x001C000000000000ULL); + tcg_gen_ori_tl(t0, t0, ((uint64_t)prio) << 50); + tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, spr[SPR_PPR])); + tcg_temp_free(t0); + } #endif } } - /* orc & orc. */ -GEN_LOGICAL2(orc, 0x0C, PPC_INTEGER); +GEN_LOGICAL2(orc, tcg_gen_orc_tl, 0x0C, PPC_INTEGER); /* xor & xor. */ GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER) { - gen_op_load_gpr_T0(rS(ctx->opcode)); /* Optimisation for "set to zero" case */ - if (rS(ctx->opcode) != rB(ctx->opcode)) { - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_xor(); - } else { - gen_op_reset_T0(); - } - gen_op_store_T0_gpr(rA(ctx->opcode)); + if (rS(ctx->opcode) != rB(ctx->opcode)) + tcg_gen_xor_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + else + tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } /* ori */ GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -1306,10 +1589,7 @@ /* XXX: should handle special NOPs for POWER series */ return; } - gen_op_load_gpr_T0(rS(ctx->opcode)); - if (likely(uimm != 0)) - gen_op_ori(uimm); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm); } /* oris */ GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -1320,10 +1600,7 @@ /* NOP */ return; } - gen_op_load_gpr_T0(rS(ctx->opcode)); - if (likely(uimm != 0)) - gen_op_ori(uimm << 16); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm << 16); } /* xori */ GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -1334,12 +1611,8 @@ /* NOP */ return; } - gen_op_load_gpr_T0(rS(ctx->opcode)); - if (likely(uimm != 0)) - gen_op_xori(uimm); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm); } - /* xoris */ GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { @@ -1349,70 +1622,70 @@ /* NOP */ return; } - gen_op_load_gpr_T0(rS(ctx->opcode)); - if (likely(uimm != 0)) - gen_op_xori(uimm << 16); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm << 16); } - /* popcntb : PowerPC 2.03 specification */ GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_POPCNTB) { - gen_op_load_gpr_T0(rS(ctx->opcode)); #if defined(TARGET_PPC64) if (ctx->sf_mode) - gen_op_popcntb_64(); + tcg_gen_helper_1_1(helper_popcntb_64, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); else #endif - gen_op_popcntb(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_helper_1_1(helper_popcntb, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); } #if defined(TARGET_PPC64) /* extsw & extsw. */ -GEN_LOGICAL1(extsw, 0x1E, PPC_64B); +GEN_LOGICAL1(extsw, tcg_gen_ext32s_tl, 0x1E, PPC_64B); /* cntlzd */ -GEN_LOGICAL1(cntlzd, 0x01, PPC_64B); +GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B) +{ + tcg_gen_helper_1_1(helper_cntlzd, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); +} #endif /*** Integer rotate ***/ /* rlwimi & rlwimi. */ GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - target_ulong mask; uint32_t mb, me, sh; mb = MB(ctx->opcode); me = ME(ctx->opcode); sh = SH(ctx->opcode); - if (likely(sh == 0)) { - if (likely(mb == 0 && me == 31)) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - goto do_store; - } else if (likely(mb == 31 && me == 0)) { - gen_op_load_gpr_T0(rA(ctx->opcode)); - goto do_store; - } - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rA(ctx->opcode)); - goto do_mask; - } - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rA(ctx->opcode)); - gen_op_rotli32_T0(SH(ctx->opcode)); - do_mask: -#if defined(TARGET_PPC64) - mb += 32; - me += 32; -#endif - mask = MASK(mb, me); - gen_op_andi_T0(mask); - gen_op_andi_T1(~mask); - gen_op_or(); - do_store: - gen_op_store_T0_gpr(rA(ctx->opcode)); + if (likely(sh == 0 && mb == 0 && me == 31)) { + tcg_gen_ext32u_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); + } else { + TCGv t0, t1; + target_ulong mask; + + t0 = tcg_temp_new(TCG_TYPE_TL); +#if defined(TARGET_PPC64) + t1 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_trunc_i64_i32(t1, cpu_gpr[rS(ctx->opcode)]); + tcg_gen_rotli_i32(t1, t1, sh); + tcg_gen_extu_i32_i64(t0, t1); + tcg_temp_free(t1); +#else + tcg_gen_rotli_i32(t0, cpu_gpr[rS(ctx->opcode)], sh); +#endif +#if defined(TARGET_PPC64) + mb += 32; + me += 32; +#endif + mask = MASK(mb, me); + t1 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_andi_tl(t0, t0, mask); + tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], ~mask); + tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); + } if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } /* rlwinm & rlwinm. */ GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -1422,56 +1695,81 @@ sh = SH(ctx->opcode); mb = MB(ctx->opcode); me = ME(ctx->opcode); - gen_op_load_gpr_T0(rS(ctx->opcode)); - if (likely(sh == 0)) { - goto do_mask; - } - if (likely(mb == 0)) { - if (likely(me == 31)) { - gen_op_rotli32_T0(sh); - goto do_store; - } else if (likely(me == (31 - sh))) { - gen_op_sli_T0(sh); - goto do_store; - } - } else if (likely(me == 31)) { - if (likely(sh == (32 - mb))) { - gen_op_srli_T0(mb); - goto do_store; + + if (likely(mb == 0 && me == (31 - sh))) { + if (likely(sh == 0)) { + tcg_gen_ext32u_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); + } else { + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_ext32u_tl(t0, cpu_gpr[rS(ctx->opcode)]); + tcg_gen_shli_tl(t0, t0, sh); + tcg_gen_ext32u_tl(cpu_gpr[rA(ctx->opcode)], t0); + tcg_temp_free(t0); } - } - gen_op_rotli32_T0(sh); - do_mask: + } else if (likely(sh != 0 && me == 31 && sh == (32 - mb))) { + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_ext32u_tl(t0, cpu_gpr[rS(ctx->opcode)]); + tcg_gen_shri_tl(t0, t0, mb); + tcg_gen_ext32u_tl(cpu_gpr[rA(ctx->opcode)], t0); + tcg_temp_free(t0); + } else { + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); #if defined(TARGET_PPC64) - mb += 32; - me += 32; + TCGv t1 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_trunc_i64_i32(t1, cpu_gpr[rS(ctx->opcode)]); + tcg_gen_rotli_i32(t1, t1, sh); + tcg_gen_extu_i32_i64(t0, t1); + tcg_temp_free(t1); +#else + tcg_gen_rotli_i32(t0, cpu_gpr[rS(ctx->opcode)], sh); +#endif +#if defined(TARGET_PPC64) + mb += 32; + me += 32; #endif - gen_op_andi_T0(MASK(mb, me)); - do_store: - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], t0, MASK(mb, me)); + tcg_temp_free(t0); + } if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } /* rlwnm & rlwnm. */ GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { uint32_t mb, me; + TCGv t0; +#if defined(TARGET_PPC64) + TCGv t1, t2; +#endif mb = MB(ctx->opcode); me = ME(ctx->opcode); - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_rotl32_T0_T1(); + t0 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1f); +#if defined(TARGET_PPC64) + t1 = tcg_temp_new(TCG_TYPE_I32); + t2 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_trunc_i64_i32(t1, cpu_gpr[rS(ctx->opcode)]); + tcg_gen_trunc_i64_i32(t2, t0); + tcg_gen_rotl_i32(t1, t1, t2); + tcg_gen_extu_i32_i64(t0, t1); + tcg_temp_free(t1); + tcg_temp_free(t2); +#else + tcg_gen_rotl_i32(t0, cpu_gpr[rS(ctx->opcode)], t0); +#endif if (unlikely(mb != 0 || me != 31)) { #if defined(TARGET_PPC64) mb += 32; me += 32; #endif - gen_op_andi_T0(MASK(mb, me)); + tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], t0, MASK(mb, me)); + } else { + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0); } - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_temp_free(t0); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } #if defined(TARGET_PPC64) @@ -1506,50 +1804,25 @@ gen_##name(ctx, 1, 1); \ } -static always_inline void gen_andi_T0_64 (DisasContext *ctx, uint64_t mask) -{ - if (mask >> 32) - gen_op_andi_T0_64(mask >> 32, mask & 0xFFFFFFFF); - else - gen_op_andi_T0(mask); -} - -static always_inline void gen_andi_T1_64 (DisasContext *ctx, uint64_t mask) -{ - if (mask >> 32) - gen_op_andi_T1_64(mask >> 32, mask & 0xFFFFFFFF); - else - gen_op_andi_T1(mask); -} - static always_inline void gen_rldinm (DisasContext *ctx, uint32_t mb, uint32_t me, uint32_t sh) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - if (likely(sh == 0)) { - goto do_mask; - } - if (likely(mb == 0)) { - if (likely(me == 63)) { - gen_op_rotli64_T0(sh); - goto do_store; - } else if (likely(me == (63 - sh))) { - gen_op_sli_T0(sh); - goto do_store; - } - } else if (likely(me == 63)) { - if (likely(sh == (64 - mb))) { - gen_op_srli_T0_64(mb); - goto do_store; + if (likely(sh != 0 && mb == 0 && me == (63 - sh))) { + tcg_gen_shli_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], sh); + } else if (likely(sh != 0 && me == 63 && sh == (64 - mb))) { + tcg_gen_shri_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], mb); + } else { + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_rotli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh); + if (likely(mb == 0 && me == 63)) { + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0); + } else { + tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], t0, MASK(mb, me)); } + tcg_temp_free(t0); } - gen_op_rotli64_T0(sh); - do_mask: - gen_andi_T0_64(ctx, MASK(mb, me)); - do_store: - gen_op_store_T0_gpr(rA(ctx->opcode)); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } /* rldicl - rldicl. */ static always_inline void gen_rldicl (DisasContext *ctx, int mbn, int shn) @@ -1585,15 +1858,21 @@ static always_inline void gen_rldnm (DisasContext *ctx, uint32_t mb, uint32_t me) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_rotl64_T0_T1(); + TCGv t0; + + mb = MB(ctx->opcode); + me = ME(ctx->opcode); + t0 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x3f); + tcg_gen_rotl_tl(t0, cpu_gpr[rS(ctx->opcode)], t0); if (unlikely(mb != 0 || me != 63)) { - gen_andi_T0_64(ctx, MASK(mb, me)); + tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], t0, MASK(mb, me)); + } else { + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0); } - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_temp_free(t0); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } /* rldcl - rldcl. */ @@ -1617,87 +1896,170 @@ /* rldimi - rldimi. */ static always_inline void gen_rldimi (DisasContext *ctx, int mbn, int shn) { - uint64_t mask; uint32_t sh, mb, me; sh = SH(ctx->opcode) | (shn << 5); mb = MB(ctx->opcode) | (mbn << 5); me = 63 - sh; - if (likely(sh == 0)) { - if (likely(mb == 0)) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - goto do_store; - } - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rA(ctx->opcode)); - goto do_mask; - } - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rA(ctx->opcode)); - gen_op_rotli64_T0(sh); - do_mask: - mask = MASK(mb, me); - gen_andi_T0_64(ctx, mask); - gen_andi_T1_64(ctx, ~mask); - gen_op_or(); - do_store: - gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(sh == 0 && mb == 0)) { + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); + } else { + TCGv t0, t1; + target_ulong mask; + + t0 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_rotli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh); + t1 = tcg_temp_new(TCG_TYPE_TL); + mask = MASK(mb, me); + tcg_gen_andi_tl(t0, t0, mask); + tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], ~mask); + tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); + } if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } GEN_PPC64_R4(rldimi, 0x1E, 0x06); #endif /*** Integer shift ***/ /* slw & slw. */ -__GEN_LOGICAL2(slw, 0x18, 0x00, PPC_INTEGER); +GEN_HANDLER(slw, 0x1F, 0x18, 0x00, 0x00000000, PPC_INTEGER) +{ + TCGv t0; + int l1, l2; + l1 = gen_new_label(); + l2 = gen_new_label(); + + t0 = tcg_temp_local_new(TCG_TYPE_TL); + tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x3f); + tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0x20, l1); + tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_shl_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], t0); + tcg_gen_ext32u_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + gen_set_label(l2); + tcg_temp_free(t0); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); +} /* sraw & sraw. */ -__GEN_LOGICAL2(sraw, 0x18, 0x18, PPC_INTEGER); +GEN_HANDLER(sraw, 0x1F, 0x18, 0x18, 0x00000000, PPC_INTEGER) +{ + tcg_gen_helper_1_2(helper_sraw, cpu_gpr[rA(ctx->opcode)], + cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); +} /* srawi & srawi. */ GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER) { - int mb, me; - gen_op_load_gpr_T0(rS(ctx->opcode)); - if (SH(ctx->opcode) != 0) { - gen_op_move_T1_T0(); - mb = 32 - SH(ctx->opcode); - me = 31; -#if defined(TARGET_PPC64) - mb += 32; - me += 32; -#endif - gen_op_srawi(SH(ctx->opcode), MASK(mb, me)); + int sh = SH(ctx->opcode); + if (sh != 0) { + int l1, l2; + TCGv t0; + l1 = gen_new_label(); + l2 = gen_new_label(); + t0 = tcg_temp_local_new(TCG_TYPE_TL); + tcg_gen_ext32s_tl(t0, cpu_gpr[rS(ctx->opcode)]); + tcg_gen_brcondi_tl(TCG_COND_GE, t0, 0, l1); + tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1ULL << sh) - 1); + tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); + tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA)); + gen_set_label(l2); + tcg_gen_ext32s_tl(t0, cpu_gpr[rS(ctx->opcode)]); + tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], t0, sh); + tcg_temp_free(t0); + } else { + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA)); } - gen_op_store_T0_gpr(rA(ctx->opcode)); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } /* srw & srw. */ -__GEN_LOGICAL2(srw, 0x18, 0x10, PPC_INTEGER); - +GEN_HANDLER(srw, 0x1F, 0x18, 0x10, 0x00000000, PPC_INTEGER) +{ + TCGv t0, t1; + int l1, l2; + l1 = gen_new_label(); + l2 = gen_new_label(); + + t0 = tcg_temp_local_new(TCG_TYPE_TL); + tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x3f); + tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0x20, l1); + tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0); + tcg_gen_br(l2); + gen_set_label(l1); + t1 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_ext32u_tl(t1, cpu_gpr[rS(ctx->opcode)]); + tcg_gen_shr_tl(cpu_gpr[rA(ctx->opcode)], t1, t0); + tcg_temp_free(t1); + gen_set_label(l2); + tcg_temp_free(t0); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); +} #if defined(TARGET_PPC64) /* sld & sld. */ -__GEN_LOGICAL2(sld, 0x1B, 0x00, PPC_64B); +GEN_HANDLER(sld, 0x1F, 0x1B, 0x00, 0x00000000, PPC_64B) +{ + TCGv t0; + int l1, l2; + l1 = gen_new_label(); + l2 = gen_new_label(); + + t0 = tcg_temp_local_new(TCG_TYPE_TL); + tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x7f); + tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0x40, l1); + tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_shl_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], t0); + gen_set_label(l2); + tcg_temp_free(t0); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); +} /* srad & srad. */ -__GEN_LOGICAL2(srad, 0x1A, 0x18, PPC_64B); +GEN_HANDLER(srad, 0x1F, 0x1A, 0x18, 0x00000000, PPC_64B) +{ + tcg_gen_helper_1_2(helper_srad, cpu_gpr[rA(ctx->opcode)], + cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); +} /* sradi & sradi. */ static always_inline void gen_sradi (DisasContext *ctx, int n) { - uint64_t mask; - int sh, mb, me; - - gen_op_load_gpr_T0(rS(ctx->opcode)); - sh = SH(ctx->opcode) + (n << 5); + int sh = SH(ctx->opcode) + (n << 5); if (sh != 0) { - gen_op_move_T1_T0(); - mb = 64 - SH(ctx->opcode); - me = 63; - mask = MASK(mb, me); - gen_op_sradi(sh, mask >> 32, mask); + int l1, l2; + TCGv t0; + l1 = gen_new_label(); + l2 = gen_new_label(); + t0 = tcg_temp_local_new(TCG_TYPE_TL); + tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rS(ctx->opcode)], 0, l1); + tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1ULL << sh) - 1); + tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); + tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA)); + gen_set_label(l2); + tcg_temp_free(t0); + tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], sh); + } else { + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA)); } - gen_op_store_T0_gpr(rA(ctx->opcode)); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } GEN_HANDLER2(sradi0, "sradi", 0x1F, 0x1A, 0x19, 0x00000000, PPC_64B) { @@ -1708,7 +2070,25 @@ gen_sradi(ctx, 1); } /* srd & srd. */ -__GEN_LOGICAL2(srd, 0x1B, 0x10, PPC_64B); +GEN_HANDLER(srd, 0x1F, 0x1B, 0x10, 0x00000000, PPC_64B) +{ + TCGv t0; + int l1, l2; + l1 = gen_new_label(); + l2 = gen_new_label(); + + t0 = tcg_temp_local_new(TCG_TYPE_TL); + tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x7f); + tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0x40, l1); + tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_shr_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], t0); + gen_set_label(l2); + tcg_temp_free(t0); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); +} #endif /*** Floating-Point arithmetic ***/ @@ -1719,15 +2099,15 @@ GEN_EXCP_NO_FP(ctx); \ return; \ } \ - gen_op_load_fpr_FT0(rA(ctx->opcode)); \ - gen_op_load_fpr_FT1(rC(ctx->opcode)); \ - gen_op_load_fpr_FT2(rB(ctx->opcode)); \ + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rA(ctx->opcode)]); \ + tcg_gen_mov_i64(cpu_FT[1], cpu_fpr[rC(ctx->opcode)]); \ + tcg_gen_mov_i64(cpu_FT[2], cpu_fpr[rB(ctx->opcode)]); \ gen_reset_fpstatus(); \ gen_op_f##op(); \ if (isfloat) { \ gen_op_frsp(); \ } \ - gen_op_store_FT0_fpr(rD(ctx->opcode)); \ + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]); \ gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \ } @@ -1742,14 +2122,14 @@ GEN_EXCP_NO_FP(ctx); \ return; \ } \ - gen_op_load_fpr_FT0(rA(ctx->opcode)); \ - gen_op_load_fpr_FT1(rB(ctx->opcode)); \ + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rA(ctx->opcode)]); \ + tcg_gen_mov_i64(cpu_FT[1], cpu_fpr[rB(ctx->opcode)]); \ gen_reset_fpstatus(); \ gen_op_f##op(); \ if (isfloat) { \ gen_op_frsp(); \ } \ - gen_op_store_FT0_fpr(rD(ctx->opcode)); \ + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]); \ gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \ } #define GEN_FLOAT_AB(name, op2, inval, set_fprf, type) \ @@ -1763,14 +2143,14 @@ GEN_EXCP_NO_FP(ctx); \ return; \ } \ - gen_op_load_fpr_FT0(rA(ctx->opcode)); \ - gen_op_load_fpr_FT1(rC(ctx->opcode)); \ + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rA(ctx->opcode)]); \ + tcg_gen_mov_i64(cpu_FT[1], cpu_fpr[rC(ctx->opcode)]); \ gen_reset_fpstatus(); \ gen_op_f##op(); \ if (isfloat) { \ gen_op_frsp(); \ } \ - gen_op_store_FT0_fpr(rD(ctx->opcode)); \ + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]); \ gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \ } #define GEN_FLOAT_AC(name, op2, inval, set_fprf, type) \ @@ -1784,10 +2164,10 @@ GEN_EXCP_NO_FP(ctx); \ return; \ } \ - gen_op_load_fpr_FT0(rB(ctx->opcode)); \ + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rB(ctx->opcode)]); \ gen_reset_fpstatus(); \ gen_op_f##name(); \ - gen_op_store_FT0_fpr(rD(ctx->opcode)); \ + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]); \ gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \ } @@ -1798,10 +2178,10 @@ GEN_EXCP_NO_FP(ctx); \ return; \ } \ - gen_op_load_fpr_FT0(rB(ctx->opcode)); \ + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rB(ctx->opcode)]); \ gen_reset_fpstatus(); \ gen_op_f##name(); \ - gen_op_store_FT0_fpr(rD(ctx->opcode)); \ + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]); \ gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \ } @@ -1841,10 +2221,10 @@ GEN_EXCP_NO_FP(ctx); return; } - gen_op_load_fpr_FT0(rB(ctx->opcode)); + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rB(ctx->opcode)]); gen_reset_fpstatus(); gen_op_fsqrt(); - gen_op_store_FT0_fpr(rD(ctx->opcode)); + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]); gen_compute_fprf(1, Rc(ctx->opcode) != 0); } @@ -1854,11 +2234,11 @@ GEN_EXCP_NO_FP(ctx); return; } - gen_op_load_fpr_FT0(rB(ctx->opcode)); + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rB(ctx->opcode)]); gen_reset_fpstatus(); gen_op_fsqrt(); gen_op_frsp(); - gen_op_store_FT0_fpr(rD(ctx->opcode)); + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]); gen_compute_fprf(1, Rc(ctx->opcode) != 0); } @@ -1905,11 +2285,10 @@ GEN_EXCP_NO_FP(ctx); return; } - gen_op_load_fpr_FT0(rA(ctx->opcode)); - gen_op_load_fpr_FT1(rB(ctx->opcode)); + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rA(ctx->opcode)]); + tcg_gen_mov_i64(cpu_FT[1], cpu_fpr[rB(ctx->opcode)]); gen_reset_fpstatus(); - gen_op_fcmpo(); - gen_op_store_T0_crf(crfD(ctx->opcode)); + tcg_gen_helper_1_0(helper_fcmpo, cpu_crf[crfD(ctx->opcode)]); gen_op_float_check_status(); } @@ -1920,11 +2299,10 @@ GEN_EXCP_NO_FP(ctx); return; } - gen_op_load_fpr_FT0(rA(ctx->opcode)); - gen_op_load_fpr_FT1(rB(ctx->opcode)); + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rA(ctx->opcode)]); + tcg_gen_mov_i64(cpu_FT[1], cpu_fpr[rB(ctx->opcode)]); gen_reset_fpstatus(); - gen_op_fcmpu(); - gen_op_store_T0_crf(crfD(ctx->opcode)); + tcg_gen_helper_1_0(helper_fcmpu, cpu_crf[crfD(ctx->opcode)]); gen_op_float_check_status(); } @@ -1941,8 +2319,8 @@ GEN_EXCP_NO_FP(ctx); return; } - gen_op_load_fpr_FT0(rB(ctx->opcode)); - gen_op_store_FT0_fpr(rD(ctx->opcode)); + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rB(ctx->opcode)]); + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]); gen_compute_fprf(0, Rc(ctx->opcode) != 0); } @@ -1965,8 +2343,8 @@ } gen_optimize_fprf(); bfa = 4 * (7 - crfS(ctx->opcode)); - gen_op_load_fpscr_T0(bfa); - gen_op_store_T0_crf(crfD(ctx->opcode)); + tcg_gen_shri_i32(cpu_crf[crfD(ctx->opcode)], cpu_fpscr, bfa); + tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], 0xf); gen_op_fpscr_resetbit(~(0xF << bfa)); } @@ -1980,7 +2358,7 @@ gen_optimize_fprf(); gen_reset_fpstatus(); gen_op_load_fpscr_FT0(); - gen_op_store_FT0_fpr(rD(ctx->opcode)); + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]); gen_compute_fprf(0, Rc(ctx->opcode) != 0); } @@ -1999,8 +2377,7 @@ if (likely(crb != 30 && crb != 29)) gen_op_fpscr_resetbit(~(1 << crb)); if (unlikely(Rc(ctx->opcode) != 0)) { - gen_op_load_fpcc(); - gen_op_set_Rc0(); + tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX); } } @@ -2020,8 +2397,7 @@ if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) gen_op_fpscr_setbit(crb); if (unlikely(Rc(ctx->opcode) != 0)) { - gen_op_load_fpcc(); - gen_op_set_Rc0(); + tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX); } /* We can raise a differed exception */ gen_op_float_check_status(); @@ -2035,12 +2411,11 @@ return; } gen_optimize_fprf(); - gen_op_load_fpr_FT0(rB(ctx->opcode)); + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rB(ctx->opcode)]); gen_reset_fpstatus(); gen_op_store_fpscr(FM(ctx->opcode)); if (unlikely(Rc(ctx->opcode) != 0)) { - gen_op_load_fpcc(); - gen_op_set_Rc0(); + tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX); } /* We can raise a differed exception */ gen_op_float_check_status(); @@ -2058,12 +2433,11 @@ bf = crbD(ctx->opcode) >> 2; sh = 7 - bf; gen_optimize_fprf(); - gen_op_set_FT0(FPIMM(ctx->opcode) << (4 * sh)); + tcg_gen_movi_i64(cpu_FT[0], FPIMM(ctx->opcode) << (4 * sh)); gen_reset_fpstatus(); gen_op_store_fpscr(1 << sh); if (unlikely(Rc(ctx->opcode) != 0)) { - gen_op_load_fpcc(); - gen_op_set_Rc0(); + tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX); } /* We can raise a differed exception */ gen_op_float_check_status(); @@ -2071,48 +2445,37 @@ /*** Addressing modes ***/ /* Register indirect with immediate index : EA = (rA|0) + SIMM */ -static always_inline void gen_addr_imm_index (DisasContext *ctx, +static always_inline void gen_addr_imm_index (TCGv EA, + DisasContext *ctx, target_long maskl) { target_long simm = SIMM(ctx->opcode); simm &= ~maskl; - if (rA(ctx->opcode) == 0) { - gen_set_T0(simm); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - if (likely(simm != 0)) - gen_op_addi(simm); - } -#ifdef DEBUG_MEMORY_ACCESSES - gen_op_print_mem_EA(); -#endif + if (rA(ctx->opcode) == 0) + tcg_gen_movi_tl(EA, simm); + else if (likely(simm != 0)) + tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], simm); + else + tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]); } -static always_inline void gen_addr_reg_index (DisasContext *ctx) +static always_inline void gen_addr_reg_index (TCGv EA, + DisasContext *ctx) { - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); - } -#ifdef DEBUG_MEMORY_ACCESSES - gen_op_print_mem_EA(); -#endif + if (rA(ctx->opcode) == 0) + tcg_gen_mov_tl(EA, cpu_gpr[rB(ctx->opcode)]); + else + tcg_gen_add_tl(EA, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); } -static always_inline void gen_addr_register (DisasContext *ctx) +static always_inline void gen_addr_register (TCGv EA, + DisasContext *ctx) { - if (rA(ctx->opcode) == 0) { - gen_op_reset_T0(); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - } -#ifdef DEBUG_MEMORY_ACCESSES - gen_op_print_mem_EA(); -#endif + if (rA(ctx->opcode) == 0) + tcg_gen_movi_tl(EA, 0); + else + tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]); } #if defined(TARGET_PPC64) @@ -2148,23 +2511,6 @@ /*** Integer load ***/ #define op_ldst(name) (*gen_op_##name[ctx->mem_idx])() -/* Byte access routine are endian safe */ -#define gen_op_lbz_le_raw gen_op_lbz_raw -#define gen_op_lbz_le_user gen_op_lbz_user -#define gen_op_lbz_le_kernel gen_op_lbz_kernel -#define gen_op_lbz_le_hypv gen_op_lbz_hypv -#define gen_op_lbz_le_64_raw gen_op_lbz_64_raw -#define gen_op_lbz_le_64_user gen_op_lbz_64_user -#define gen_op_lbz_le_64_kernel gen_op_lbz_64_kernel -#define gen_op_lbz_le_64_hypv gen_op_lbz_64_hypv -#define gen_op_stb_le_raw gen_op_stb_raw -#define gen_op_stb_le_user gen_op_stb_user -#define gen_op_stb_le_kernel gen_op_stb_kernel -#define gen_op_stb_le_hypv gen_op_stb_hypv -#define gen_op_stb_le_64_raw gen_op_stb_64_raw -#define gen_op_stb_le_64_user gen_op_stb_64_user -#define gen_op_stb_le_64_kernel gen_op_stb_64_kernel -#define gen_op_stb_le_64_hypv gen_op_stb_64_hypv #define OP_LD_TABLE(width) \ static GenOpFunc *gen_op_l##width[NB_MEM_FUNCS] = { \ GEN_MEM_FUNCS(l##width), \ @@ -2174,81 +2520,354 @@ GEN_MEM_FUNCS(st##width), \ }; + +#if defined(TARGET_PPC64) +#define GEN_QEMU_LD_PPC64(width) \ +static always_inline void gen_qemu_ld##width##_ppc64(TCGv t0, TCGv t1, int flags)\ +{ \ + if (likely(flags & 2)) \ + tcg_gen_qemu_ld##width(t0, t1, flags >> 2); \ + else { \ + TCGv addr = tcg_temp_new(TCG_TYPE_TL); \ + tcg_gen_ext32u_tl(addr, t1); \ + tcg_gen_qemu_ld##width(t0, addr, flags >> 2); \ + tcg_temp_free(addr); \ + } \ +} +GEN_QEMU_LD_PPC64(8u) +GEN_QEMU_LD_PPC64(8s) +GEN_QEMU_LD_PPC64(16u) +GEN_QEMU_LD_PPC64(16s) +GEN_QEMU_LD_PPC64(32u) +GEN_QEMU_LD_PPC64(32s) +GEN_QEMU_LD_PPC64(64) + +#define GEN_QEMU_ST_PPC64(width) \ +static always_inline void gen_qemu_st##width##_ppc64(TCGv t0, TCGv t1, int flags)\ +{ \ + if (likely(flags & 2)) \ + tcg_gen_qemu_st##width(t0, t1, flags >> 2); \ + else { \ + TCGv addr = tcg_temp_new(TCG_TYPE_TL); \ + tcg_gen_ext32u_tl(addr, t1); \ + tcg_gen_qemu_st##width(t0, addr, flags >> 2); \ + tcg_temp_free(addr); \ + } \ +} +GEN_QEMU_ST_PPC64(8) +GEN_QEMU_ST_PPC64(16) +GEN_QEMU_ST_PPC64(32) +GEN_QEMU_ST_PPC64(64) + +static always_inline void gen_qemu_ld8u(TCGv arg0, TCGv arg1, int flags) +{ + gen_qemu_ld8u_ppc64(arg0, arg1, flags); +} + +static always_inline void gen_qemu_ld8s(TCGv arg0, TCGv arg1, int flags) +{ + gen_qemu_ld8s_ppc64(arg0, arg1, flags); +} + +static always_inline void gen_qemu_ld16u(TCGv arg0, TCGv arg1, int flags) +{ + if (unlikely(flags & 1)) { + TCGv t0; + gen_qemu_ld16u_ppc64(arg0, arg1, flags); + t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_trunc_tl_i32(t0, arg0); + tcg_gen_bswap16_i32(t0, t0); + tcg_gen_extu_i32_tl(arg0, t0); + tcg_temp_free(t0); + } else + gen_qemu_ld16u_ppc64(arg0, arg1, flags); +} + +static always_inline void gen_qemu_ld16s(TCGv arg0, TCGv arg1, int flags) +{ + if (unlikely(flags & 1)) { + TCGv t0; + gen_qemu_ld16u_ppc64(arg0, arg1, flags); + t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_trunc_tl_i32(t0, arg0); + tcg_gen_bswap16_i32(t0, t0); + tcg_gen_extu_i32_tl(arg0, t0); + tcg_gen_ext16s_tl(arg0, arg0); + tcg_temp_free(t0); + } else + gen_qemu_ld16s_ppc64(arg0, arg1, flags); +} + +static always_inline void gen_qemu_ld32u(TCGv arg0, TCGv arg1, int flags) +{ + if (unlikely(flags & 1)) { + TCGv t0; + gen_qemu_ld32u_ppc64(arg0, arg1, flags); + t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_trunc_tl_i32(t0, arg0); + tcg_gen_bswap_i32(t0, t0); + tcg_gen_extu_i32_tl(arg0, t0); + tcg_temp_free(t0); + } else + gen_qemu_ld32u_ppc64(arg0, arg1, flags); +} + +static always_inline void gen_qemu_ld32s(TCGv arg0, TCGv arg1, int flags) +{ + if (unlikely(flags & 1)) { + TCGv t0; + gen_qemu_ld32u_ppc64(arg0, arg1, flags); + t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_trunc_tl_i32(t0, arg0); + tcg_gen_bswap_i32(t0, t0); + tcg_gen_ext_i32_tl(arg0, t0); + tcg_temp_free(t0); + } else + gen_qemu_ld32s_ppc64(arg0, arg1, flags); +} + +static always_inline void gen_qemu_ld64(TCGv arg0, TCGv arg1, int flags) +{ + gen_qemu_ld64_ppc64(arg0, arg1, flags); + if (unlikely(flags & 1)) + tcg_gen_bswap_i64(arg0, arg0); +} + +static always_inline void gen_qemu_st8(TCGv arg0, TCGv arg1, int flags) +{ + gen_qemu_st8_ppc64(arg0, arg1, flags); +} + +static always_inline void gen_qemu_st16(TCGv arg0, TCGv arg1, int flags) +{ + if (unlikely(flags & 1)) { + TCGv t0, t1; + t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_trunc_tl_i32(t0, arg0); + tcg_gen_ext16u_i32(t0, t0); + tcg_gen_bswap16_i32(t0, t0); + t1 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_extu_i32_tl(t1, t0); + tcg_temp_free(t0); + gen_qemu_st16_ppc64(t1, arg1, flags); + tcg_temp_free(t1); + } else + gen_qemu_st16_ppc64(arg0, arg1, flags); +} + +static always_inline void gen_qemu_st32(TCGv arg0, TCGv arg1, int flags) +{ + if (unlikely(flags & 1)) { + TCGv t0, t1; + t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_trunc_tl_i32(t0, arg0); + tcg_gen_bswap_i32(t0, t0); + t1 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_extu_i32_tl(t1, t0); + tcg_temp_free(t0); + gen_qemu_st32_ppc64(t1, arg1, flags); + tcg_temp_free(t1); + } else + gen_qemu_st32_ppc64(arg0, arg1, flags); +} + +static always_inline void gen_qemu_st64(TCGv arg0, TCGv arg1, int flags) +{ + if (unlikely(flags & 1)) { + TCGv t0 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_bswap_i64(t0, arg0); + gen_qemu_st64_ppc64(t0, arg1, flags); + tcg_temp_free(t0); + } else + gen_qemu_st64_ppc64(arg0, arg1, flags); +} + + +#else /* defined(TARGET_PPC64) */ +#define GEN_QEMU_LD_PPC32(width) \ +static always_inline void gen_qemu_ld##width##_ppc32(TCGv arg0, TCGv arg1, int flags)\ +{ \ + tcg_gen_qemu_ld##width(arg0, arg1, flags >> 1); \ +} +GEN_QEMU_LD_PPC32(8u) +GEN_QEMU_LD_PPC32(8s) +GEN_QEMU_LD_PPC32(16u) +GEN_QEMU_LD_PPC32(16s) +GEN_QEMU_LD_PPC32(32u) +GEN_QEMU_LD_PPC32(32s) +GEN_QEMU_LD_PPC32(64) + +#define GEN_QEMU_ST_PPC32(width) \ +static always_inline void gen_qemu_st##width##_ppc32(TCGv arg0, TCGv arg1, int flags)\ +{ \ + tcg_gen_qemu_st##width(arg0, arg1, flags >> 1); \ +} +GEN_QEMU_ST_PPC32(8) +GEN_QEMU_ST_PPC32(16) +GEN_QEMU_ST_PPC32(32) +GEN_QEMU_ST_PPC32(64) + +static always_inline void gen_qemu_ld8u(TCGv arg0, TCGv arg1, int flags) +{ + gen_qemu_ld8u_ppc32(arg0, arg1, flags >> 1); +} + +static always_inline void gen_qemu_ld8s(TCGv arg0, TCGv arg1, int flags) +{ + gen_qemu_ld8s_ppc32(arg0, arg1, flags >> 1); +} + +static always_inline void gen_qemu_ld16u(TCGv arg0, TCGv arg1, int flags) +{ + gen_qemu_ld16u_ppc32(arg0, arg1, flags >> 1); + if (unlikely(flags & 1)) + tcg_gen_bswap16_i32(arg0, arg0); +} + +static always_inline void gen_qemu_ld16s(TCGv arg0, TCGv arg1, int flags) +{ + if (unlikely(flags & 1)) { + gen_qemu_ld16u_ppc32(arg0, arg1, flags); + tcg_gen_bswap16_i32(arg0, arg0); + tcg_gen_ext16s_i32(arg0, arg0); + } else + gen_qemu_ld16s_ppc32(arg0, arg1, flags); +} + +static always_inline void gen_qemu_ld32u(TCGv arg0, TCGv arg1, int flags) +{ + gen_qemu_ld32u_ppc32(arg0, arg1, flags); + if (unlikely(flags & 1)) + tcg_gen_bswap_i32(arg0, arg0); +} + +static always_inline void gen_qemu_ld64(TCGv arg0, TCGv arg1, int flags) +{ + gen_qemu_ld64_ppc32(arg0, arg1, flags); + if (unlikely(flags & 1)) + tcg_gen_bswap_i64(arg0, arg0); +} + +static always_inline void gen_qemu_st8(TCGv arg0, TCGv arg1, int flags) +{ + gen_qemu_st8_ppc32(arg0, arg1, flags); +} + +static always_inline void gen_qemu_st16(TCGv arg0, TCGv arg1, int flags) +{ + if (unlikely(flags & 1)) { + TCGv temp = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_ext16u_i32(temp, arg0); + tcg_gen_bswap16_i32(temp, temp); + gen_qemu_st16_ppc32(temp, arg1, flags); + tcg_temp_free(temp); + } else + gen_qemu_st16_ppc32(arg0, arg1, flags); +} + +static always_inline void gen_qemu_st32(TCGv arg0, TCGv arg1, int flags) +{ + if (unlikely(flags & 1)) { + TCGv temp = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_bswap_i32(temp, arg0); + gen_qemu_st32_ppc32(temp, arg1, flags); + tcg_temp_free(temp); + } else + gen_qemu_st32_ppc32(arg0, arg1, flags); +} + +static always_inline void gen_qemu_st64(TCGv arg0, TCGv arg1, int flags) +{ + if (unlikely(flags & 1)) { + TCGv temp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_bswap_i64(temp, arg0); + gen_qemu_st64_ppc32(temp, arg1, flags); + tcg_temp_free(temp); + } else + gen_qemu_st64_ppc32(arg0, arg1, flags); +} + +#endif + #define GEN_LD(width, opc, type) \ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, type) \ { \ - gen_addr_imm_index(ctx, 0); \ - op_ldst(l##width); \ - gen_op_store_T1_gpr(rD(ctx->opcode)); \ + TCGv EA = tcg_temp_new(TCG_TYPE_TL); \ + gen_addr_imm_index(EA, ctx, 0); \ + gen_qemu_ld##width(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx); \ + tcg_temp_free(EA); \ } #define GEN_LDU(width, opc, type) \ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \ { \ + TCGv EA; \ if (unlikely(rA(ctx->opcode) == 0 || \ rA(ctx->opcode) == rD(ctx->opcode))) { \ GEN_EXCP_INVAL(ctx); \ return; \ } \ + EA = tcg_temp_new(TCG_TYPE_TL); \ if (type == PPC_64B) \ - gen_addr_imm_index(ctx, 0x03); \ + gen_addr_imm_index(EA, ctx, 0x03); \ else \ - gen_addr_imm_index(ctx, 0); \ - op_ldst(l##width); \ - gen_op_store_T1_gpr(rD(ctx->opcode)); \ - gen_op_store_T0_gpr(rA(ctx->opcode)); \ + gen_addr_imm_index(EA, ctx, 0); \ + gen_qemu_ld##width(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx); \ + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ + tcg_temp_free(EA); \ } #define GEN_LDUX(width, opc2, opc3, type) \ GEN_HANDLER(l##width##ux, 0x1F, opc2, opc3, 0x00000001, type) \ { \ + TCGv EA; \ if (unlikely(rA(ctx->opcode) == 0 || \ rA(ctx->opcode) == rD(ctx->opcode))) { \ GEN_EXCP_INVAL(ctx); \ return; \ } \ - gen_addr_reg_index(ctx); \ - op_ldst(l##width); \ - gen_op_store_T1_gpr(rD(ctx->opcode)); \ - gen_op_store_T0_gpr(rA(ctx->opcode)); \ + EA = tcg_temp_new(TCG_TYPE_TL); \ + gen_addr_reg_index(EA, ctx); \ + gen_qemu_ld##width(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx); \ + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ + tcg_temp_free(EA); \ } #define GEN_LDX(width, opc2, opc3, type) \ GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, type) \ { \ - gen_addr_reg_index(ctx); \ - op_ldst(l##width); \ - gen_op_store_T1_gpr(rD(ctx->opcode)); \ + TCGv EA = tcg_temp_new(TCG_TYPE_TL); \ + gen_addr_reg_index(EA, ctx); \ + gen_qemu_ld##width(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx); \ + tcg_temp_free(EA); \ } #define GEN_LDS(width, op, type) \ -OP_LD_TABLE(width); \ GEN_LD(width, op | 0x20, type); \ GEN_LDU(width, op | 0x21, type); \ GEN_LDUX(width, 0x17, op | 0x01, type); \ GEN_LDX(width, 0x17, op | 0x00, type) /* lbz lbzu lbzux lbzx */ -GEN_LDS(bz, 0x02, PPC_INTEGER); +GEN_LDS(8u, 0x02, PPC_INTEGER); /* lha lhau lhaux lhax */ -GEN_LDS(ha, 0x0A, PPC_INTEGER); +GEN_LDS(16s, 0x0A, PPC_INTEGER); /* lhz lhzu lhzux lhzx */ -GEN_LDS(hz, 0x08, PPC_INTEGER); +GEN_LDS(16u, 0x08, PPC_INTEGER); /* lwz lwzu lwzux lwzx */ -GEN_LDS(wz, 0x00, PPC_INTEGER); +GEN_LDS(32u, 0x00, PPC_INTEGER); #if defined(TARGET_PPC64) -OP_LD_TABLE(wa); -OP_LD_TABLE(d); /* lwaux */ -GEN_LDUX(wa, 0x15, 0x0B, PPC_64B); +GEN_LDUX(32s, 0x15, 0x0B, PPC_64B); /* lwax */ -GEN_LDX(wa, 0x15, 0x0A, PPC_64B); +GEN_LDX(32s, 0x15, 0x0A, PPC_64B); /* ldux */ -GEN_LDUX(d, 0x15, 0x01, PPC_64B); +GEN_LDUX(64, 0x15, 0x01, PPC_64B); /* ldx */ -GEN_LDX(d, 0x15, 0x00, PPC_64B); +GEN_LDX(64, 0x15, 0x00, PPC_64B); GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B) { + TCGv EA; if (Rc(ctx->opcode)) { if (unlikely(rA(ctx->opcode) == 0 || rA(ctx->opcode) == rD(ctx->opcode))) { @@ -2256,17 +2875,18 @@ return; } } - gen_addr_imm_index(ctx, 0x03); + EA = tcg_temp_new(TCG_TYPE_TL); + gen_addr_imm_index(EA, ctx, 0x03); if (ctx->opcode & 0x02) { /* lwa (lwau is undefined) */ - op_ldst(lwa); + gen_qemu_ld32s(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx); } else { /* ld - ldu */ - op_ldst(ld); + gen_qemu_ld64(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx); } - gen_op_store_T1_gpr(rD(ctx->opcode)); if (Rc(ctx->opcode)) - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); + tcg_temp_free(EA); } /* lq */ GEN_HANDLER(lq, 0x38, 0xFF, 0xFF, 0x00000000, PPC_64BX) @@ -2275,6 +2895,7 @@ GEN_EXCP_PRIVOPC(ctx); #else int ra, rd; + TCGv EA; /* Restore CPU state */ if (unlikely(ctx->supervisor == 0)) { @@ -2292,12 +2913,12 @@ GEN_EXCP(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE); return; } - gen_addr_imm_index(ctx, 0x0F); - op_ldst(ld); - gen_op_store_T1_gpr(rd); - gen_op_addi(8); - op_ldst(ld); - gen_op_store_T1_gpr(rd + 1); + EA = tcg_temp_new(TCG_TYPE_TL); + gen_addr_imm_index(EA, ctx, 0x0F); + gen_qemu_ld64(cpu_gpr[rd], EA, ctx->mem_idx); + tcg_gen_addi_tl(EA, EA, 8); + gen_qemu_ld64(cpu_gpr[rd+1], EA, ctx->mem_idx); + tcg_temp_free(EA); #endif } #endif @@ -2306,68 +2927,73 @@ #define GEN_ST(width, opc, type) \ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, type) \ { \ - gen_addr_imm_index(ctx, 0); \ - gen_op_load_gpr_T1(rS(ctx->opcode)); \ - op_ldst(st##width); \ + TCGv EA = tcg_temp_new(TCG_TYPE_TL); \ + gen_addr_imm_index(EA, ctx, 0); \ + gen_qemu_st##width(cpu_gpr[rS(ctx->opcode)], EA, ctx->mem_idx); \ + tcg_temp_free(EA); \ } #define GEN_STU(width, opc, type) \ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \ { \ + TCGv EA; \ if (unlikely(rA(ctx->opcode) == 0)) { \ GEN_EXCP_INVAL(ctx); \ return; \ } \ + EA = tcg_temp_new(TCG_TYPE_TL); \ if (type == PPC_64B) \ - gen_addr_imm_index(ctx, 0x03); \ + gen_addr_imm_index(EA, ctx, 0x03); \ else \ - gen_addr_imm_index(ctx, 0); \ - gen_op_load_gpr_T1(rS(ctx->opcode)); \ - op_ldst(st##width); \ - gen_op_store_T0_gpr(rA(ctx->opcode)); \ + gen_addr_imm_index(EA, ctx, 0); \ + gen_qemu_st##width(cpu_gpr[rS(ctx->opcode)], EA, ctx->mem_idx); \ + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ + tcg_temp_free(EA); \ } #define GEN_STUX(width, opc2, opc3, type) \ GEN_HANDLER(st##width##ux, 0x1F, opc2, opc3, 0x00000001, type) \ { \ + TCGv EA; \ if (unlikely(rA(ctx->opcode) == 0)) { \ GEN_EXCP_INVAL(ctx); \ return; \ } \ - gen_addr_reg_index(ctx); \ - gen_op_load_gpr_T1(rS(ctx->opcode)); \ - op_ldst(st##width); \ - gen_op_store_T0_gpr(rA(ctx->opcode)); \ + EA = tcg_temp_new(TCG_TYPE_TL); \ + gen_addr_reg_index(EA, ctx); \ + gen_qemu_st##width(cpu_gpr[rS(ctx->opcode)], EA, ctx->mem_idx); \ + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ + tcg_temp_free(EA); \ } #define GEN_STX(width, opc2, opc3, type) \ GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, type) \ { \ - gen_addr_reg_index(ctx); \ - gen_op_load_gpr_T1(rS(ctx->opcode)); \ - op_ldst(st##width); \ + TCGv EA = tcg_temp_new(TCG_TYPE_TL); \ + gen_addr_reg_index(EA, ctx); \ + gen_qemu_st##width(cpu_gpr[rS(ctx->opcode)], EA, ctx->mem_idx); \ + tcg_temp_free(EA); \ } #define GEN_STS(width, op, type) \ -OP_ST_TABLE(width); \ GEN_ST(width, op | 0x20, type); \ GEN_STU(width, op | 0x21, type); \ GEN_STUX(width, 0x17, op | 0x01, type); \ GEN_STX(width, 0x17, op | 0x00, type) /* stb stbu stbux stbx */ -GEN_STS(b, 0x06, PPC_INTEGER); +GEN_STS(8, 0x06, PPC_INTEGER); /* sth sthu sthux sthx */ -GEN_STS(h, 0x0C, PPC_INTEGER); +GEN_STS(16, 0x0C, PPC_INTEGER); /* stw stwu stwux stwx */ -GEN_STS(w, 0x04, PPC_INTEGER); +GEN_STS(32, 0x04, PPC_INTEGER); #if defined(TARGET_PPC64) -OP_ST_TABLE(d); -GEN_STUX(d, 0x15, 0x05, PPC_64B); -GEN_STX(d, 0x15, 0x04, PPC_64B); +GEN_STUX(64, 0x15, 0x05, PPC_64B); +GEN_STX(64, 0x15, 0x04, PPC_64B); GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000000, PPC_64B) { int rs; + TCGv EA; rs = rS(ctx->opcode); if ((ctx->opcode & 0x3) == 0x2) { @@ -2388,12 +3014,12 @@ GEN_EXCP(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE); return; } - gen_addr_imm_index(ctx, 0x03); - gen_op_load_gpr_T1(rs); - op_ldst(std); - gen_op_addi(8); - gen_op_load_gpr_T1(rs + 1); - op_ldst(std); + EA = tcg_temp_new(TCG_TYPE_TL); + gen_addr_imm_index(EA, ctx, 0x03); + gen_qemu_st64(cpu_gpr[rs], EA, ctx->mem_idx); + tcg_gen_addi_tl(EA, EA, 8); + gen_qemu_st64(cpu_gpr[rs+1], EA, ctx->mem_idx); + tcg_temp_free(EA); #endif } else { /* std / stdu */ @@ -2403,27 +3029,60 @@ return; } } - gen_addr_imm_index(ctx, 0x03); - gen_op_load_gpr_T1(rs); - op_ldst(std); + EA = tcg_temp_new(TCG_TYPE_TL); + gen_addr_imm_index(EA, ctx, 0x03); + gen_qemu_st64(cpu_gpr[rs], EA, ctx->mem_idx); if (Rc(ctx->opcode)) - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); + tcg_temp_free(EA); } } #endif /*** Integer load and store with byte reverse ***/ /* lhbrx */ -OP_LD_TABLE(hbr); -GEN_LDX(hbr, 0x16, 0x18, PPC_INTEGER); +void always_inline gen_qemu_ld16ur(TCGv t0, TCGv t1, int flags) +{ + TCGv temp = tcg_temp_new(TCG_TYPE_I32); + gen_qemu_ld16u(temp, t1, flags); + tcg_gen_bswap16_i32(temp, temp); + tcg_gen_extu_i32_tl(t0, temp); + tcg_temp_free(temp); +} +GEN_LDX(16ur, 0x16, 0x18, PPC_INTEGER); + /* lwbrx */ -OP_LD_TABLE(wbr); -GEN_LDX(wbr, 0x16, 0x10, PPC_INTEGER); +void always_inline gen_qemu_ld32ur(TCGv t0, TCGv t1, int flags) +{ + TCGv temp = tcg_temp_new(TCG_TYPE_I32); + gen_qemu_ld32u(temp, t1, flags); + tcg_gen_bswap_i32(temp, temp); + tcg_gen_extu_i32_tl(t0, temp); + tcg_temp_free(temp); +} +GEN_LDX(32ur, 0x16, 0x10, PPC_INTEGER); + /* sthbrx */ -OP_ST_TABLE(hbr); -GEN_STX(hbr, 0x16, 0x1C, PPC_INTEGER); +void always_inline gen_qemu_st16r(TCGv t0, TCGv t1, int flags) +{ + TCGv temp = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_trunc_tl_i32(temp, t0); + tcg_gen_ext16u_i32(temp, temp); + tcg_gen_bswap16_i32(temp, temp); + gen_qemu_st16(temp, t1, flags); + tcg_temp_free(temp); +} +GEN_STX(16r, 0x16, 0x1C, PPC_INTEGER); + /* stwbrx */ -OP_ST_TABLE(wbr); -GEN_STX(wbr, 0x16, 0x14, PPC_INTEGER); +void always_inline gen_qemu_st32r(TCGv t0, TCGv t1, int flags) +{ + TCGv temp = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_trunc_tl_i32(temp, t0); + tcg_gen_bswap_i32(temp, temp); + gen_qemu_st32(temp, t1, flags); + tcg_temp_free(temp); +} +GEN_STX(32r, 0x16, 0x14, PPC_INTEGER); /*** Integer load and store multiple ***/ #define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg) @@ -2439,7 +3098,7 @@ { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_imm_index(ctx, 0); + gen_addr_imm_index(cpu_T[0], ctx, 0); op_ldstm(lmw, rD(ctx->opcode)); } @@ -2448,7 +3107,7 @@ { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_imm_index(ctx, 0); + gen_addr_imm_index(cpu_T[0], ctx, 0); op_ldstm(stmw, rS(ctx->opcode)); } @@ -2515,8 +3174,8 @@ } /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_register(ctx); - gen_op_set_T1(nb); + gen_addr_register(cpu_T[0], ctx); + tcg_gen_movi_tl(cpu_T[1], nb); op_ldsts(lswi, start); } @@ -2528,11 +3187,11 @@ /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_reg_index(ctx); + gen_addr_reg_index(cpu_T[0], ctx); if (ra == 0) { ra = rb; } - gen_op_load_xer_bc(); + tcg_gen_andi_tl(cpu_T[1], cpu_xer, 0x7F); op_ldstsx(lswx, rD(ctx->opcode), ra, rb); } @@ -2543,10 +3202,10 @@ /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_register(ctx); + gen_addr_register(cpu_T[0], ctx); if (nb == 0) nb = 32; - gen_op_set_T1(nb); + tcg_gen_movi_tl(cpu_T[1], nb); op_ldsts(stsw, rS(ctx->opcode)); } @@ -2555,8 +3214,8 @@ { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_reg_index(ctx); - gen_op_load_xer_bc(); + gen_addr_reg_index(cpu_T[0], ctx); + tcg_gen_andi_tl(cpu_T[1], cpu_xer, 0x7F); op_ldsts(stsw, rS(ctx->opcode)); } @@ -2586,9 +3245,9 @@ { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_reg_index(ctx); + gen_addr_reg_index(cpu_T[0], ctx); op_lwarx(); - gen_op_store_T1_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[1]); } /* stwcx. */ @@ -2596,8 +3255,8 @@ { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_reg_index(ctx); - gen_op_load_gpr_T1(rS(ctx->opcode)); + gen_addr_reg_index(cpu_T[0], ctx); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]); op_stwcx(); } @@ -2616,9 +3275,9 @@ { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_reg_index(ctx); + gen_addr_reg_index(cpu_T[0], ctx); op_ldarx(); - gen_op_store_T1_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[1]); } /* stdcx. */ @@ -2626,8 +3285,8 @@ { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_reg_index(ctx); - gen_op_load_gpr_T1(rS(ctx->opcode)); + gen_addr_reg_index(cpu_T[0], ctx); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]); op_stdcx(); } #endif /* defined(TARGET_PPC64) */ @@ -2653,9 +3312,9 @@ GEN_EXCP_NO_FP(ctx); \ return; \ } \ - gen_addr_imm_index(ctx, 0); \ + gen_addr_imm_index(cpu_T[0], ctx, 0); \ op_ldst(l##width); \ - gen_op_store_FT0_fpr(rD(ctx->opcode)); \ + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]); \ } #define GEN_LDUF(width, opc, type) \ @@ -2669,10 +3328,10 @@ GEN_EXCP_INVAL(ctx); \ return; \ } \ - gen_addr_imm_index(ctx, 0); \ + gen_addr_imm_index(cpu_T[0], ctx, 0); \ op_ldst(l##width); \ - gen_op_store_FT0_fpr(rD(ctx->opcode)); \ - gen_op_store_T0_gpr(rA(ctx->opcode)); \ + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]); \ + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); \ } #define GEN_LDUXF(width, opc, type) \ @@ -2686,10 +3345,10 @@ GEN_EXCP_INVAL(ctx); \ return; \ } \ - gen_addr_reg_index(ctx); \ + gen_addr_reg_index(cpu_T[0], ctx); \ op_ldst(l##width); \ - gen_op_store_FT0_fpr(rD(ctx->opcode)); \ - gen_op_store_T0_gpr(rA(ctx->opcode)); \ + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]); \ + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); \ } #define GEN_LDXF(width, opc2, opc3, type) \ @@ -2699,9 +3358,9 @@ GEN_EXCP_NO_FP(ctx); \ return; \ } \ - gen_addr_reg_index(ctx); \ + gen_addr_reg_index(cpu_T[0], ctx); \ op_ldst(l##width); \ - gen_op_store_FT0_fpr(rD(ctx->opcode)); \ + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]); \ } #define GEN_LDFS(width, op, type) \ @@ -2724,8 +3383,8 @@ GEN_EXCP_NO_FP(ctx); \ return; \ } \ - gen_addr_imm_index(ctx, 0); \ - gen_op_load_fpr_FT0(rS(ctx->opcode)); \ + gen_addr_imm_index(cpu_T[0], ctx, 0); \ + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rS(ctx->opcode)]); \ op_ldst(st##width); \ } @@ -2740,10 +3399,10 @@ GEN_EXCP_INVAL(ctx); \ return; \ } \ - gen_addr_imm_index(ctx, 0); \ - gen_op_load_fpr_FT0(rS(ctx->opcode)); \ + gen_addr_imm_index(cpu_T[0], ctx, 0); \ + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rS(ctx->opcode)]); \ op_ldst(st##width); \ - gen_op_store_T0_gpr(rA(ctx->opcode)); \ + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); \ } #define GEN_STUXF(width, opc, type) \ @@ -2757,10 +3416,10 @@ GEN_EXCP_INVAL(ctx); \ return; \ } \ - gen_addr_reg_index(ctx); \ - gen_op_load_fpr_FT0(rS(ctx->opcode)); \ + gen_addr_reg_index(cpu_T[0], ctx); \ + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rS(ctx->opcode)]); \ op_ldst(st##width); \ - gen_op_store_T0_gpr(rA(ctx->opcode)); \ + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); \ } #define GEN_STXF(width, opc2, opc3, type) \ @@ -2770,8 +3429,8 @@ GEN_EXCP_NO_FP(ctx); \ return; \ } \ - gen_addr_reg_index(ctx); \ - gen_op_load_fpr_FT0(rS(ctx->opcode)); \ + gen_addr_reg_index(cpu_T[0], ctx); \ + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rS(ctx->opcode)]); \ op_ldst(st##width); \ } @@ -2798,45 +3457,43 @@ { TranslationBlock *tb; tb = ctx->tb; - if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { - if (n == 0) - gen_op_goto_tb0(TBPARAM(tb)); - else - gen_op_goto_tb1(TBPARAM(tb)); - gen_set_T1(dest); #if defined(TARGET_PPC64) - if (ctx->sf_mode) - gen_op_b_T1_64(); - else + if (!ctx->sf_mode) + dest = (uint32_t) dest; #endif - gen_op_b_T1(); - gen_op_set_T0((long)tb + n); - if (ctx->singlestep_enabled) - gen_op_debug(); - gen_op_exit_tb(); + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) && + likely(!ctx->singlestep_enabled)) { + tcg_gen_goto_tb(n); + tcg_gen_movi_tl(cpu_nip, dest & ~3); + tcg_gen_exit_tb((long)tb + n); } else { - gen_set_T1(dest); -#if defined(TARGET_PPC64) - if (ctx->sf_mode) - gen_op_b_T1_64(); - else -#endif - gen_op_b_T1(); - gen_op_reset_T0(); - if (ctx->singlestep_enabled) - gen_op_debug(); - gen_op_exit_tb(); + tcg_gen_movi_tl(cpu_nip, dest & ~3); + if (unlikely(ctx->singlestep_enabled)) { + if ((ctx->singlestep_enabled & + (CPU_BRANCH_STEP | CPU_SINGLE_STEP)) && + ctx->exception == POWERPC_EXCP_BRANCH) { + target_ulong tmp = ctx->nip; + ctx->nip = dest; + GEN_EXCP(ctx, POWERPC_EXCP_TRACE, 0); + ctx->nip = tmp; + } + if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) { + gen_update_nip(ctx, dest); + gen_op_debug(); + } + } + tcg_gen_exit_tb(0); } } static always_inline void gen_setlr (DisasContext *ctx, target_ulong nip) { #if defined(TARGET_PPC64) - if (ctx->sf_mode != 0 && (nip >> 32)) - gen_op_setlr_64(ctx->nip >> 32, ctx->nip); + if (ctx->sf_mode == 0) + tcg_gen_movi_tl(cpu_lr, (uint32_t)nip); else #endif - gen_op_setlr(ctx->nip); + tcg_gen_movi_tl(cpu_lr, nip); } /* b ba bl bla */ @@ -2844,6 +3501,7 @@ { target_ulong li, target; + ctx->exception = POWERPC_EXCP_BRANCH; /* sign extend LI */ #if defined(TARGET_PPC64) if (ctx->sf_mode) @@ -2855,14 +3513,9 @@ target = ctx->nip + li - 4; else target = li; -#if defined(TARGET_PPC64) - if (!ctx->sf_mode) - target = (uint32_t)target; -#endif if (LK(ctx->opcode)) gen_setlr(ctx, ctx->nip); gen_goto_tb(ctx, 0, target); - ctx->exception = POWERPC_EXCP_BRANCH; } #define BCOND_IM 0 @@ -2871,148 +3524,81 @@ static always_inline void gen_bcond (DisasContext *ctx, int type) { - target_ulong target = 0; - target_ulong li; uint32_t bo = BO(ctx->opcode); - uint32_t bi = BI(ctx->opcode); - uint32_t mask; + int l1 = gen_new_label(); + TCGv target; - if ((bo & 0x4) == 0) - gen_op_dec_ctr(); - switch(type) { - case BCOND_IM: - li = (target_long)((int16_t)(BD(ctx->opcode))); - if (likely(AA(ctx->opcode) == 0)) { - target = ctx->nip + li - 4; - } else { - target = li; - } -#if defined(TARGET_PPC64) - if (!ctx->sf_mode) - target = (uint32_t)target; -#endif - break; - case BCOND_CTR: - gen_op_movl_T1_ctr(); - break; - default: - case BCOND_LR: - gen_op_movl_T1_lr(); - break; + ctx->exception = POWERPC_EXCP_BRANCH; + if (type == BCOND_LR || type == BCOND_CTR) { + target = tcg_temp_local_new(TCG_TYPE_TL); + if (type == BCOND_CTR) + tcg_gen_mov_tl(target, cpu_ctr); + else + tcg_gen_mov_tl(target, cpu_lr); } if (LK(ctx->opcode)) gen_setlr(ctx, ctx->nip); - if (bo & 0x10) { - /* No CR condition */ - switch (bo & 0x6) { - case 0: -#if defined(TARGET_PPC64) - if (ctx->sf_mode) - gen_op_test_ctr_64(); - else -#endif - gen_op_test_ctr(); - break; - case 2: + l1 = gen_new_label(); + if ((bo & 0x4) == 0) { + /* Decrement and test CTR */ + TCGv temp = tcg_temp_new(TCG_TYPE_TL); + if (unlikely(type == BCOND_CTR)) { + GEN_EXCP_INVAL(ctx); + return; + } + tcg_gen_subi_tl(cpu_ctr, cpu_ctr, 1); #if defined(TARGET_PPC64) - if (ctx->sf_mode) - gen_op_test_ctrz_64(); - else + if (!ctx->sf_mode) + tcg_gen_ext32u_tl(temp, cpu_ctr); + else #endif - gen_op_test_ctrz(); - break; - default: - case 4: - case 6: - if (type == BCOND_IM) { - gen_goto_tb(ctx, 0, target); - goto out; - } else { -#if defined(TARGET_PPC64) - if (ctx->sf_mode) - gen_op_b_T1_64(); - else -#endif - gen_op_b_T1(); - gen_op_reset_T0(); - goto no_test; - } - break; + tcg_gen_mov_tl(temp, cpu_ctr); + if (bo & 0x2) { + tcg_gen_brcondi_tl(TCG_COND_NE, temp, 0, l1); + } else { + tcg_gen_brcondi_tl(TCG_COND_EQ, temp, 0, l1); } - } else { - mask = 1 << (3 - (bi & 0x03)); - gen_op_load_crf_T0(bi >> 2); + } + if ((bo & 0x10) == 0) { + /* Test CR */ + uint32_t bi = BI(ctx->opcode); + uint32_t mask = 1 << (3 - (bi & 0x03)); + TCGv temp = tcg_temp_new(TCG_TYPE_I32); + if (bo & 0x8) { - switch (bo & 0x6) { - case 0: -#if defined(TARGET_PPC64) - if (ctx->sf_mode) - gen_op_test_ctr_true_64(mask); - else -#endif - gen_op_test_ctr_true(mask); - break; - case 2: -#if defined(TARGET_PPC64) - if (ctx->sf_mode) - gen_op_test_ctrz_true_64(mask); - else -#endif - gen_op_test_ctrz_true(mask); - break; - default: - case 4: - case 6: - gen_op_test_true(mask); - break; - } + tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask); + tcg_gen_brcondi_i32(TCG_COND_EQ, temp, 0, l1); } else { - switch (bo & 0x6) { - case 0: -#if defined(TARGET_PPC64) - if (ctx->sf_mode) - gen_op_test_ctr_false_64(mask); - else -#endif - gen_op_test_ctr_false(mask); - break; - case 2: -#if defined(TARGET_PPC64) - if (ctx->sf_mode) - gen_op_test_ctrz_false_64(mask); - else -#endif - gen_op_test_ctrz_false(mask); - break; - default: - case 4: - case 6: - gen_op_test_false(mask); - break; - } + tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask); + tcg_gen_brcondi_i32(TCG_COND_NE, temp, 0, l1); } } if (type == BCOND_IM) { - int l1 = gen_new_label(); - gen_op_jz_T0(l1); - gen_goto_tb(ctx, 0, target); + target_ulong li = (target_long)((int16_t)(BD(ctx->opcode))); + if (likely(AA(ctx->opcode) == 0)) { + gen_goto_tb(ctx, 0, ctx->nip + li - 4); + } else { + gen_goto_tb(ctx, 0, li); + } gen_set_label(l1); gen_goto_tb(ctx, 1, ctx->nip); } else { #if defined(TARGET_PPC64) - if (ctx->sf_mode) - gen_op_btest_T1_64(ctx->nip >> 32, ctx->nip); + if (!(ctx->sf_mode)) + tcg_gen_andi_tl(cpu_nip, target, (uint32_t)~3); else #endif - gen_op_btest_T1(ctx->nip); - gen_op_reset_T0(); - no_test: - if (ctx->singlestep_enabled) - gen_op_debug(); - gen_op_exit_tb(); + tcg_gen_andi_tl(cpu_nip, target, ~3); + tcg_gen_exit_tb(0); + gen_set_label(l1); +#if defined(TARGET_PPC64) + if (!(ctx->sf_mode)) + tcg_gen_movi_tl(cpu_nip, (uint32_t)ctx->nip); + else +#endif + tcg_gen_movi_tl(cpu_nip, ctx->nip); + tcg_gen_exit_tb(0); } - out: - ctx->exception = POWERPC_EXCP_BRANCH; } GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW) @@ -3031,53 +3617,57 @@ } /*** Condition register logical ***/ -#define GEN_CRLOGIC(op, opc) \ -GEN_HANDLER(cr##op, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER) \ +#define GEN_CRLOGIC(name, tcg_op, opc) \ +GEN_HANDLER(name, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER) \ { \ uint8_t bitmask; \ int sh; \ - gen_op_load_crf_T0(crbA(ctx->opcode) >> 2); \ + TCGv t0, t1; \ sh = (crbD(ctx->opcode) & 0x03) - (crbA(ctx->opcode) & 0x03); \ + t0 = tcg_temp_new(TCG_TYPE_I32); \ if (sh > 0) \ - gen_op_srli_T0(sh); \ + tcg_gen_shri_i32(t0, cpu_crf[crbA(ctx->opcode) >> 2], sh); \ else if (sh < 0) \ - gen_op_sli_T0(-sh); \ - gen_op_load_crf_T1(crbB(ctx->opcode) >> 2); \ + tcg_gen_shli_i32(t0, cpu_crf[crbA(ctx->opcode) >> 2], -sh); \ + else \ + tcg_gen_mov_i32(t0, cpu_crf[crbA(ctx->opcode) >> 2]); \ + t1 = tcg_temp_new(TCG_TYPE_I32); \ sh = (crbD(ctx->opcode) & 0x03) - (crbB(ctx->opcode) & 0x03); \ if (sh > 0) \ - gen_op_srli_T1(sh); \ + tcg_gen_shri_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2], sh); \ else if (sh < 0) \ - gen_op_sli_T1(-sh); \ - gen_op_##op(); \ + tcg_gen_shli_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2], -sh); \ + else \ + tcg_gen_mov_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2]); \ + tcg_op(t0, t0, t1); \ bitmask = 1 << (3 - (crbD(ctx->opcode) & 0x03)); \ - gen_op_andi_T0(bitmask); \ - gen_op_load_crf_T1(crbD(ctx->opcode) >> 2); \ - gen_op_andi_T1(~bitmask); \ - gen_op_or(); \ - gen_op_store_T0_crf(crbD(ctx->opcode) >> 2); \ + tcg_gen_andi_i32(t0, t0, bitmask); \ + tcg_gen_andi_i32(t1, cpu_crf[crbD(ctx->opcode) >> 2], ~bitmask); \ + tcg_gen_or_i32(cpu_crf[crbD(ctx->opcode) >> 2], t0, t1); \ + tcg_temp_free(t0); \ + tcg_temp_free(t1); \ } /* crand */ -GEN_CRLOGIC(and, 0x08); +GEN_CRLOGIC(crand, tcg_gen_and_i32, 0x08); /* crandc */ -GEN_CRLOGIC(andc, 0x04); +GEN_CRLOGIC(crandc, tcg_gen_andc_i32, 0x04); /* creqv */ -GEN_CRLOGIC(eqv, 0x09); +GEN_CRLOGIC(creqv, tcg_gen_eqv_i32, 0x09); /* crnand */ -GEN_CRLOGIC(nand, 0x07); +GEN_CRLOGIC(crnand, tcg_gen_nand_i32, 0x07); /* crnor */ -GEN_CRLOGIC(nor, 0x01); +GEN_CRLOGIC(crnor, tcg_gen_nor_i32, 0x01); /* cror */ -GEN_CRLOGIC(or, 0x0E); +GEN_CRLOGIC(cror, tcg_gen_or_i32, 0x0E); /* crorc */ -GEN_CRLOGIC(orc, 0x0D); +GEN_CRLOGIC(crorc, tcg_gen_orc_i32, 0x0D); /* crxor */ -GEN_CRLOGIC(xor, 0x06); +GEN_CRLOGIC(crxor, tcg_gen_xor_i32, 0x06); /* mcrf */ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER) { - gen_op_load_crf_T0(crfS(ctx->opcode)); - gen_op_store_T0_crf(crfD(ctx->opcode)); + tcg_gen_mov_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfS(ctx->opcode)]); } /*** System linkage ***/ @@ -3147,8 +3737,8 @@ /* tw */ GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW) { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); /* Update the nip since this might generate a trap exception */ gen_update_nip(ctx, ctx->nip); gen_op_tw(TO(ctx->opcode)); @@ -3157,8 +3747,8 @@ /* twi */ GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW) { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_set_T1(SIMM(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_movi_tl(cpu_T[1], SIMM(ctx->opcode)); /* Update the nip since this might generate a trap exception */ gen_update_nip(ctx, ctx->nip); gen_op_tw(TO(ctx->opcode)); @@ -3168,8 +3758,8 @@ /* td */ GEN_HANDLER(td, 0x1F, 0x04, 0x02, 0x00000001, PPC_64B) { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); /* Update the nip since this might generate a trap exception */ gen_update_nip(ctx, ctx->nip); gen_op_td(TO(ctx->opcode)); @@ -3178,8 +3768,8 @@ /* tdi */ GEN_HANDLER(tdi, 0x02, 0xFF, 0xFF, 0x00000000, PPC_64B) { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_set_T1(SIMM(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_movi_tl(cpu_T[1], SIMM(ctx->opcode)); /* Update the nip since this might generate a trap exception */ gen_update_nip(ctx, ctx->nip); gen_op_td(TO(ctx->opcode)); @@ -3190,10 +3780,9 @@ /* mcrxr */ GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC) { - gen_op_load_xer_cr(); - gen_op_store_T0_crf(crfD(ctx->opcode)); - gen_op_clear_xer_ov(); - gen_op_clear_xer_ca(); + tcg_gen_trunc_tl_i32(cpu_crf[crfD(ctx->opcode)], cpu_xer); + tcg_gen_shri_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], XER_CA); + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_SO | 1 << XER_OV | 1 << XER_CA)); } /* mfcr */ @@ -3205,12 +3794,11 @@ crm = CRM(ctx->opcode); if (likely((crm ^ (crm - 1)) == 0)) { crn = ffs(crm); - gen_op_load_cro(7 - crn); + tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], cpu_crf[7 - crn]); } } else { - gen_op_load_cr(); + tcg_gen_helper_1_0(helper_load_cr, cpu_gpr[rD(ctx->opcode)]); } - gen_op_store_T0_gpr(rD(ctx->opcode)); } /* mfmsr */ @@ -3224,7 +3812,7 @@ return; } gen_op_load_msr(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); #endif } @@ -3256,7 +3844,7 @@ if (likely(read_cb != NULL)) { if (likely(read_cb != SPR_NOACCESS)) { (*read_cb)(ctx, sprn); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); } else { /* Privilege exception */ /* This is a hack to avoid warnings when running Linux: @@ -3302,15 +3890,15 @@ { uint32_t crm, crn; - gen_op_load_gpr_T0(rS(ctx->opcode)); crm = CRM(ctx->opcode); if (likely((ctx->opcode & 0x00100000) || (crm ^ (crm - 1)) == 0)) { crn = ffs(crm); - gen_op_srli_T0(crn * 4); - gen_op_andi_T0(0xF); - gen_op_store_cro(7 - crn); + tcg_gen_shri_i32(cpu_crf[7 - crn], cpu_gpr[rS(ctx->opcode)], crn * 4); + tcg_gen_andi_i32(cpu_crf[7 - crn], cpu_crf[7 - crn], 0xf); } else { - gen_op_store_cr(crm); + TCGv t0 = tcg_const_tl(crm); + tcg_gen_helper_0_2(helper_store_cr, cpu_gpr[rS(ctx->opcode)], t0); + tcg_temp_free(t0); } } @@ -3325,7 +3913,7 @@ GEN_EXCP_PRIVREG(ctx); return; } - gen_op_load_gpr_T0(rS(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); if (ctx->opcode & 0x00010000) { /* Special form that does not need any synchronisation */ gen_op_update_riee(); @@ -3353,7 +3941,7 @@ GEN_EXCP_PRIVREG(ctx); return; } - gen_op_load_gpr_T0(rS(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); if (ctx->opcode & 0x00010000) { /* Special form that does not need any synchronisation */ gen_op_update_riee(); @@ -3392,7 +3980,7 @@ write_cb = ctx->spr_cb[sprn].uea_write; if (likely(write_cb != NULL)) { if (likely(write_cb != SPR_NOACCESS)) { - gen_op_load_gpr_T0(rS(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); (*write_cb)(ctx, sprn); } else { /* Privilege exception */ @@ -3422,8 +4010,10 @@ GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03C00001, PPC_CACHE) { /* XXX: specification says this is treated as a load by the MMU */ - gen_addr_reg_index(ctx); - op_ldst(lbz); + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + gen_addr_reg_index(t0, ctx); + gen_qemu_ld8u(t0, t0, ctx->mem_idx); + tcg_temp_free(t0); } /* dcbi (Supervisor only) */ @@ -3432,14 +4022,19 @@ #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); #else + TCGv EA, val; if (unlikely(!ctx->supervisor)) { GEN_EXCP_PRIVOPC(ctx); return; } - gen_addr_reg_index(ctx); + EA = tcg_temp_new(TCG_TYPE_TL); + gen_addr_reg_index(EA, ctx); + val = tcg_temp_new(TCG_TYPE_TL); /* XXX: specification says this should be treated as a store by the MMU */ - op_ldst(lbz); - op_ldst(stb); + gen_qemu_ld8u(val, EA, ctx->mem_idx); + gen_qemu_st8(val, EA, ctx->mem_idx); + tcg_temp_free(val); + tcg_temp_free(EA); #endif } @@ -3447,8 +4042,10 @@ GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE) { /* XXX: specification say this is treated as a load by the MMU */ - gen_addr_reg_index(ctx); - op_ldst(lbz); + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + gen_addr_reg_index(t0, ctx); + gen_qemu_ld8u(t0, t0, ctx->mem_idx); + tcg_temp_free(t0); } /* dcbt */ @@ -3546,14 +4143,14 @@ GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE_DCBZ) { - gen_addr_reg_index(ctx); + gen_addr_reg_index(cpu_T[0], ctx); handler_dcbz(ctx, ctx->dcache_line_size); gen_op_check_reservation(); } GEN_HANDLER2(dcbz_970, "dcbz", 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZT) { - gen_addr_reg_index(ctx); + gen_addr_reg_index(cpu_T[0], ctx); if (ctx->opcode & 0x00200000) handler_dcbz(ctx, ctx->dcache_line_size); else @@ -3579,7 +4176,7 @@ { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_reg_index(ctx); + gen_addr_reg_index(cpu_T[0], ctx); op_icbi(); } @@ -3605,9 +4202,9 @@ GEN_EXCP_PRIVREG(ctx); return; } - gen_op_set_T1(SR(ctx->opcode)); + tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode)); gen_op_load_sr(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); #endif } @@ -3621,10 +4218,10 @@ GEN_EXCP_PRIVREG(ctx); return; } - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_srli_T1(28); gen_op_load_sr(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); #endif } @@ -3638,8 +4235,8 @@ GEN_EXCP_PRIVREG(ctx); return; } - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_set_T1(SR(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode)); gen_op_store_sr(); #endif } @@ -3654,8 +4251,8 @@ GEN_EXCP_PRIVREG(ctx); return; } - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_srli_T1(28); gen_op_store_sr(); #endif @@ -3673,9 +4270,9 @@ GEN_EXCP_PRIVREG(ctx); return; } - gen_op_set_T1(SR(ctx->opcode)); + tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode)); gen_op_load_slb(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); #endif } @@ -3690,10 +4287,10 @@ GEN_EXCP_PRIVREG(ctx); return; } - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_srli_T1(28); gen_op_load_slb(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); #endif } @@ -3707,8 +4304,8 @@ GEN_EXCP_PRIVREG(ctx); return; } - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_set_T1(SR(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode)); gen_op_store_slb(); #endif } @@ -3724,8 +4321,8 @@ GEN_EXCP_PRIVREG(ctx); return; } - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_srli_T1(28); gen_op_store_slb(); #endif @@ -3758,7 +4355,7 @@ GEN_EXCP_PRIVOPC(ctx); return; } - gen_op_load_gpr_T0(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rB(ctx->opcode)]); #if defined(TARGET_PPC64) if (ctx->sf_mode) gen_op_tlbie_64(); @@ -3810,7 +4407,7 @@ GEN_EXCP_PRIVOPC(ctx); return; } - gen_op_load_gpr_T0(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rB(ctx->opcode)]); gen_op_slbie(); #endif } @@ -3831,17 +4428,17 @@ GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN) { /* Should check EAR[E] & alignment ! */ - gen_addr_reg_index(ctx); + gen_addr_reg_index(cpu_T[0], ctx); op_eciwx(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); } /* ecowx */ GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN) { /* Should check EAR[E] & alignment ! */ - gen_addr_reg_index(ctx); - gen_op_load_gpr_T1(rS(ctx->opcode)); + gen_addr_reg_index(cpu_T[0], ctx); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]); op_ecowx(); } @@ -3849,105 +4446,105 @@ /* abs - abs. */ GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR) { - gen_op_load_gpr_T0(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); gen_op_POWER_abs(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* abso - abso. */ GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR) { - gen_op_load_gpr_T0(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); gen_op_POWER_abso(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* clcs */ GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR) { - gen_op_load_gpr_T0(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); gen_op_POWER_clcs(); /* Rc=1 sets CR0 to an undefined state */ - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); } /* div - div. */ GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_div(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* divo - divo. */ GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_divo(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* divs - divs. */ GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_divs(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* divso - divso. */ GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_divso(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* doz - doz. */ GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_doz(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* dozo - dozo. */ GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_dozo(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* dozi */ GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_set_T1(SIMM(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_movi_tl(cpu_T[1], SIMM(ctx->opcode)); gen_op_POWER_doz(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); } /* As lscbx load from memory byte after byte, it's always endian safe. @@ -3977,83 +4574,85 @@ int ra = rA(ctx->opcode); int rb = rB(ctx->opcode); - gen_addr_reg_index(ctx); + gen_addr_reg_index(cpu_T[0], ctx); if (ra == 0) { ra = rb; } /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_op_load_xer_bc(); - gen_op_load_xer_cmp(); + tcg_gen_andi_tl(cpu_T[1], cpu_xer, 0x7F); + tcg_gen_shri_tl(cpu_T[2], cpu_xer, XER_CMP); + tcg_gen_andi_tl(cpu_T[2], cpu_T[2], 0xFF); op_POWER_lscbx(rD(ctx->opcode), ra, rb); - gen_op_store_xer_bc(); + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~0x7F); + tcg_gen_or_tl(cpu_xer, cpu_xer, cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* maskg - maskg. */ GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_maskg(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* maskir - maskir. */ GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rS(ctx->opcode)); - gen_op_load_gpr_T2(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[2], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_maskir(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* mul - mul. */ GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_mul(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* mulo - mulo. */ GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_mulo(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* nabs - nabs. */ GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); gen_op_POWER_nabs(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* nabso - nabso. */ GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); gen_op_POWER_nabso(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* rlmi - rlmi. */ @@ -4063,191 +4662,191 @@ mb = MB(ctx->opcode); me = ME(ctx->opcode); - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rA(ctx->opcode)); - gen_op_load_gpr_T2(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[2], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_rlmi(MASK(mb, me), ~MASK(mb, me)); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* rrib - rrib. */ GEN_HANDLER(rrib, 0x1F, 0x19, 0x10, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rA(ctx->opcode)); - gen_op_load_gpr_T2(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[2], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_rrib(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* sle - sle. */ GEN_HANDLER(sle, 0x1F, 0x19, 0x04, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_sle(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* sleq - sleq. */ GEN_HANDLER(sleq, 0x1F, 0x19, 0x06, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_sleq(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* sliq - sliq. */ GEN_HANDLER(sliq, 0x1F, 0x18, 0x05, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_set_T1(SH(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_movi_tl(cpu_T[1], SH(ctx->opcode)); gen_op_POWER_sle(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* slliq - slliq. */ GEN_HANDLER(slliq, 0x1F, 0x18, 0x07, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_set_T1(SH(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_movi_tl(cpu_T[1], SH(ctx->opcode)); gen_op_POWER_sleq(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* sllq - sllq. */ GEN_HANDLER(sllq, 0x1F, 0x18, 0x06, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_sllq(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* slq - slq. */ GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_slq(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* sraiq - sraiq. */ GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_set_T1(SH(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_movi_tl(cpu_T[1], SH(ctx->opcode)); gen_op_POWER_sraq(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* sraq - sraq. */ GEN_HANDLER(sraq, 0x1F, 0x18, 0x1C, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_sraq(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* sre - sre. */ GEN_HANDLER(sre, 0x1F, 0x19, 0x14, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_sre(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* srea - srea. */ GEN_HANDLER(srea, 0x1F, 0x19, 0x1C, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_srea(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* sreq */ GEN_HANDLER(sreq, 0x1F, 0x19, 0x16, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_sreq(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* sriq */ GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_set_T1(SH(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_movi_tl(cpu_T[1], SH(ctx->opcode)); gen_op_POWER_srq(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* srliq */ GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_set_T1(SH(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); + tcg_gen_movi_tl(cpu_T[1], SH(ctx->opcode)); gen_op_POWER_srlq(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* srlq */ GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_srlq(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* srq */ GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_POWER_srq(); - gen_op_store_T0_gpr(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_T[0]); } /* PowerPC 602 specific instructions */ @@ -4275,9 +4874,9 @@ GEN_EXCP_PRIVOPC(ctx); return; } - gen_op_load_gpr_T0(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); gen_op_602_mfrom(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); #endif } @@ -4292,7 +4891,7 @@ GEN_EXCP_PRIVOPC(ctx); return; } - gen_op_load_gpr_T0(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rB(ctx->opcode)]); gen_op_6xx_tlbld(); #endif } @@ -4307,7 +4906,7 @@ GEN_EXCP_PRIVOPC(ctx); return; } - gen_op_load_gpr_T0(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rB(ctx->opcode)]); gen_op_6xx_tlbli(); #endif } @@ -4323,7 +4922,7 @@ GEN_EXCP_PRIVOPC(ctx); return; } - gen_op_load_gpr_T0(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rB(ctx->opcode)]); gen_op_74xx_tlbld(); #endif } @@ -4338,7 +4937,7 @@ GEN_EXCP_PRIVOPC(ctx); return; } - gen_op_load_gpr_T0(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rB(ctx->opcode)]); gen_op_74xx_tlbli(); #endif } @@ -4382,11 +4981,11 @@ int ra = rA(ctx->opcode); int rd = rD(ctx->opcode); - gen_addr_reg_index(ctx); + gen_addr_reg_index(cpu_T[0], ctx); gen_op_POWER_mfsri(); - gen_op_store_T0_gpr(rd); + tcg_gen_mov_tl(cpu_gpr[rd], cpu_T[0]); if (ra != 0 && ra != rd) - gen_op_store_T1_gpr(ra); + tcg_gen_mov_tl(cpu_gpr[ra], cpu_T[1]); #endif } @@ -4399,9 +4998,9 @@ GEN_EXCP_PRIVOPC(ctx); return; } - gen_addr_reg_index(ctx); + gen_addr_reg_index(cpu_T[0], ctx); gen_op_POWER_rac(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); #endif } @@ -4454,10 +5053,10 @@ { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_imm_index(ctx, 0); + gen_addr_imm_index(cpu_T[0], ctx, 0); op_POWER2_lfq(); - gen_op_store_FT0_fpr(rD(ctx->opcode)); - gen_op_store_FT1_fpr(rD(ctx->opcode) + 1); + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]); + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode) + 1], cpu_FT[1]); } /* lfqu */ @@ -4467,12 +5066,12 @@ /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_imm_index(ctx, 0); + gen_addr_imm_index(cpu_T[0], ctx, 0); op_POWER2_lfq(); - gen_op_store_FT0_fpr(rD(ctx->opcode)); - gen_op_store_FT1_fpr(rD(ctx->opcode) + 1); + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]); + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode) + 1], cpu_FT[1]); if (ra != 0) - gen_op_store_T0_gpr(ra); + tcg_gen_mov_tl(cpu_gpr[ra], cpu_T[0]); } /* lfqux */ @@ -4482,12 +5081,12 @@ /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_reg_index(ctx); + gen_addr_reg_index(cpu_T[0], ctx); op_POWER2_lfq(); - gen_op_store_FT0_fpr(rD(ctx->opcode)); - gen_op_store_FT1_fpr(rD(ctx->opcode) + 1); + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]); + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode) + 1], cpu_FT[1]); if (ra != 0) - gen_op_store_T0_gpr(ra); + tcg_gen_mov_tl(cpu_gpr[ra], cpu_T[0]); } /* lfqx */ @@ -4495,10 +5094,10 @@ { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_reg_index(ctx); + gen_addr_reg_index(cpu_T[0], ctx); op_POWER2_lfq(); - gen_op_store_FT0_fpr(rD(ctx->opcode)); - gen_op_store_FT1_fpr(rD(ctx->opcode) + 1); + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]); + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode) + 1], cpu_FT[1]); } /* stfq */ @@ -4506,9 +5105,9 @@ { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_imm_index(ctx, 0); - gen_op_load_fpr_FT0(rS(ctx->opcode)); - gen_op_load_fpr_FT1(rS(ctx->opcode) + 1); + gen_addr_imm_index(cpu_T[0], ctx, 0); + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rS(ctx->opcode)]); + tcg_gen_mov_i64(cpu_FT[1], cpu_fpr[rS(ctx->opcode) + 1]); op_POWER2_stfq(); } @@ -4519,12 +5118,12 @@ /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_imm_index(ctx, 0); - gen_op_load_fpr_FT0(rS(ctx->opcode)); - gen_op_load_fpr_FT1(rS(ctx->opcode) + 1); + gen_addr_imm_index(cpu_T[0], ctx, 0); + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rS(ctx->opcode)]); + tcg_gen_mov_i64(cpu_FT[1], cpu_fpr[rS(ctx->opcode) + 1]); op_POWER2_stfq(); if (ra != 0) - gen_op_store_T0_gpr(ra); + tcg_gen_mov_tl(cpu_gpr[ra], cpu_T[0]); } /* stfqux */ @@ -4534,12 +5133,12 @@ /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_reg_index(ctx); - gen_op_load_fpr_FT0(rS(ctx->opcode)); - gen_op_load_fpr_FT1(rS(ctx->opcode) + 1); + gen_addr_reg_index(cpu_T[0], ctx); + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rS(ctx->opcode)]); + tcg_gen_mov_i64(cpu_FT[1], cpu_fpr[rS(ctx->opcode) + 1]); op_POWER2_stfq(); if (ra != 0) - gen_op_store_T0_gpr(ra); + tcg_gen_mov_tl(cpu_gpr[ra], cpu_T[0]); } /* stfqx */ @@ -4547,9 +5146,9 @@ { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_reg_index(ctx); - gen_op_load_fpr_FT0(rS(ctx->opcode)); - gen_op_load_fpr_FT1(rS(ctx->opcode) + 1); + gen_addr_reg_index(cpu_T[0], ctx); + tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rS(ctx->opcode)]); + tcg_gen_mov_i64(cpu_FT[1], cpu_fpr[rS(ctx->opcode) + 1]); op_POWER2_stfq(); } @@ -4571,7 +5170,7 @@ GEN_EXCP_PRIVOPC(ctx); return; } - gen_addr_reg_index(ctx); + gen_addr_reg_index(cpu_T[0], ctx); /* Use the same micro-ops as for tlbie */ #if defined(TARGET_PPC64) if (ctx->sf_mode) @@ -4587,8 +5186,11 @@ int opc2, int opc3, int ra, int rb, int rt, int Rc) { - gen_op_load_gpr_T0(ra); - gen_op_load_gpr_T1(rb); + TCGv t0, t1; + + t0 = tcg_temp_local_new(TCG_TYPE_TL); + t1 = tcg_temp_local_new(TCG_TYPE_TL); + switch (opc3 & 0x0D) { case 0x05: /* macchw - macchw. - macchwo - macchwo. */ @@ -4596,13 +5198,17 @@ /* nmacchw - nmacchw. - nmacchwo - nmacchwo. */ /* nmacchws - nmacchws. - nmacchwso - nmacchwso. */ /* mulchw - mulchw. */ - gen_op_405_mulchw(); + tcg_gen_ext16s_tl(t0, cpu_gpr[ra]); + tcg_gen_sari_tl(t1, cpu_gpr[rb], 16); + tcg_gen_ext16s_tl(t1, t1); break; case 0x04: /* macchwu - macchwu. - macchwuo - macchwuo. */ /* macchwsu - macchwsu. - macchwsuo - macchwsuo. */ /* mulchwu - mulchwu. */ - gen_op_405_mulchwu(); + tcg_gen_ext16u_tl(t0, cpu_gpr[ra]); + tcg_gen_shri_tl(t1, cpu_gpr[rb], 16); + tcg_gen_ext16u_tl(t1, t1); break; case 0x01: /* machhw - machhw. - machhwo - machhwo. */ @@ -4610,13 +5216,19 @@ /* nmachhw - nmachhw. - nmachhwo - nmachhwo. */ /* nmachhws - nmachhws. - nmachhwso - nmachhwso. */ /* mulhhw - mulhhw. */ - gen_op_405_mulhhw(); + tcg_gen_sari_tl(t0, cpu_gpr[ra], 16); + tcg_gen_ext16s_tl(t0, t0); + tcg_gen_sari_tl(t1, cpu_gpr[rb], 16); + tcg_gen_ext16s_tl(t1, t1); break; case 0x00: /* machhwu - machhwu. - machhwuo - machhwuo. */ /* machhwsu - machhwsu. - machhwsuo - machhwsuo. */ /* mulhhwu - mulhhwu. */ - gen_op_405_mulhhwu(); + tcg_gen_shri_tl(t0, cpu_gpr[ra], 16); + tcg_gen_ext16u_tl(t0, t0); + tcg_gen_shri_tl(t1, cpu_gpr[rb], 16); + tcg_gen_ext16u_tl(t1, t1); break; case 0x0D: /* maclhw - maclhw. - maclhwo - maclhwo. */ @@ -4624,43 +5236,70 @@ /* nmaclhw - nmaclhw. - nmaclhwo - nmaclhwo. */ /* nmaclhws - nmaclhws. - nmaclhwso - nmaclhwso. */ /* mullhw - mullhw. */ - gen_op_405_mullhw(); + tcg_gen_ext16s_tl(t0, cpu_gpr[ra]); + tcg_gen_ext16s_tl(t1, cpu_gpr[rb]); break; case 0x0C: /* maclhwu - maclhwu. - maclhwuo - maclhwuo. */ /* maclhwsu - maclhwsu. - maclhwsuo - maclhwsuo. */ /* mullhwu - mullhwu. */ - gen_op_405_mullhwu(); + tcg_gen_ext16u_tl(t0, cpu_gpr[ra]); + tcg_gen_ext16u_tl(t1, cpu_gpr[rb]); break; } - if (opc2 & 0x02) { - /* nmultiply-and-accumulate (0x0E) */ - gen_op_neg(); - } if (opc2 & 0x04) { - /* (n)multiply-and-accumulate (0x0C - 0x0E) */ - gen_op_load_gpr_T2(rt); - gen_op_move_T1_T0(); - gen_op_405_add_T0_T2(); - } - if (opc3 & 0x10) { - /* Check overflow */ - if (opc3 & 0x01) - gen_op_check_addo(); - else - gen_op_405_check_ovu(); - } - if (opc3 & 0x02) { - /* Saturate */ - if (opc3 & 0x01) - gen_op_405_check_sat(); - else - gen_op_405_check_satu(); + /* (n)multiply-and-accumulate (0x0C / 0x0E) */ + tcg_gen_mul_tl(t1, t0, t1); + if (opc2 & 0x02) { + /* nmultiply-and-accumulate (0x0E) */ + tcg_gen_sub_tl(t0, cpu_gpr[rt], t1); + } else { + /* multiply-and-accumulate (0x0C) */ + tcg_gen_add_tl(t0, cpu_gpr[rt], t1); + } + + if (opc3 & 0x12) { + /* Check overflow and/or saturate */ + int l1 = gen_new_label(); + + if (opc3 & 0x10) { + /* Start with XER OV disabled, the most likely case */ + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + } + if (opc3 & 0x01) { + /* Signed */ + tcg_gen_xor_tl(t1, cpu_gpr[rt], t1); + tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1); + tcg_gen_xor_tl(t1, cpu_gpr[rt], t0); + tcg_gen_brcondi_tl(TCG_COND_LT, t1, 0, l1); + if (opc3 & 0x02) { + /* Saturate */ + tcg_gen_sari_tl(t0, cpu_gpr[rt], 31); + tcg_gen_xori_tl(t0, t0, 0x7fffffff); + } + } else { + /* Unsigned */ + tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1); + if (opc3 & 0x02) { + /* Saturate */ + tcg_gen_movi_tl(t0, UINT32_MAX); + } + } + if (opc3 & 0x10) { + /* Check overflow */ + tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + } + gen_set_label(l1); + tcg_gen_mov_tl(cpu_gpr[rt], t0); + } + } else { + tcg_gen_mul_tl(cpu_gpr[rt], t0, t1); } - gen_op_store_T0_gpr(rt); + tcg_temp_free(t0); + tcg_temp_free(t1); if (unlikely(Rc) != 0) { /* Update Rc0 */ - gen_set_Rc0(ctx); + gen_set_Rc0(ctx, cpu_gpr[rt]); } } @@ -4769,9 +5408,9 @@ GEN_EXCP_PRIVREG(ctx); return; } - gen_op_set_T0(dcrn); + tcg_gen_movi_tl(cpu_T[0], dcrn); gen_op_load_dcr(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); #endif } @@ -4787,8 +5426,8 @@ GEN_EXCP_PRIVREG(ctx); return; } - gen_op_set_T0(dcrn); - gen_op_load_gpr_T1(rS(ctx->opcode)); + tcg_gen_movi_tl(cpu_T[0], dcrn); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]); gen_op_store_dcr(); #endif } @@ -4804,9 +5443,9 @@ GEN_EXCP_PRIVREG(ctx); return; } - gen_op_load_gpr_T0(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); gen_op_load_dcr(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); /* Note: Rc update flag set leads to undefined state of Rc0 */ #endif } @@ -4822,8 +5461,8 @@ GEN_EXCP_PRIVREG(ctx); return; } - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rS(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]); gen_op_store_dcr(); /* Note: Rc update flag set leads to undefined state of Rc0 */ #endif @@ -4832,17 +5471,17 @@ /* mfdcrux (PPC 460) : user-mode access to DCR */ GEN_HANDLER(mfdcrux, 0x1F, 0x03, 0x09, 0x00000000, PPC_DCRUX) { - gen_op_load_gpr_T0(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); gen_op_load_dcr(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); /* Note: Rc update flag set leads to undefined state of Rc0 */ } /* mtdcrux (PPC 460) : user-mode access to DCR */ GEN_HANDLER(mtdcrux, 0x1F, 0x03, 0x0D, 0x00000000, PPC_DCRUX) { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rS(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]); gen_op_store_dcr(); /* Note: Rc update flag set leads to undefined state of Rc0 */ } @@ -4867,13 +5506,18 @@ #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); #else + TCGv EA, val; if (unlikely(!ctx->supervisor)) { GEN_EXCP_PRIVOPC(ctx); return; } - gen_addr_reg_index(ctx); - op_ldst(lwz); - gen_op_store_T0_gpr(rD(ctx->opcode)); + EA = tcg_temp_new(TCG_TYPE_TL); + gen_addr_reg_index(EA, ctx); + val = tcg_temp_new(TCG_TYPE_TL); + gen_qemu_ld32u(val, EA, ctx->mem_idx); + tcg_temp_free(val); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], EA); + tcg_temp_free(EA); #endif } @@ -4991,14 +5635,14 @@ } switch (rB(ctx->opcode)) { case 0: - gen_op_load_gpr_T0(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); gen_op_4xx_tlbre_hi(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); break; case 1: - gen_op_load_gpr_T0(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); gen_op_4xx_tlbre_lo(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); break; default: GEN_EXCP_INVAL(ctx); @@ -5017,11 +5661,11 @@ GEN_EXCP_PRIVOPC(ctx); return; } - gen_addr_reg_index(ctx); + gen_addr_reg_index(cpu_T[0], ctx); gen_op_4xx_tlbsx(); if (Rc(ctx->opcode)) gen_op_4xx_tlbsx_check(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); #endif } @@ -5037,13 +5681,13 @@ } switch (rB(ctx->opcode)) { case 0: - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rS(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]); gen_op_4xx_tlbwe_hi(); break; case 1: - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rS(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]); gen_op_4xx_tlbwe_lo(); break; default: @@ -5068,9 +5712,9 @@ case 0: case 1: case 2: - gen_op_load_gpr_T0(rA(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); gen_op_440_tlbre(rB(ctx->opcode)); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); break; default: GEN_EXCP_INVAL(ctx); @@ -5089,11 +5733,11 @@ GEN_EXCP_PRIVOPC(ctx); return; } - gen_addr_reg_index(ctx); + gen_addr_reg_index(cpu_T[0], ctx); gen_op_440_tlbsx(); if (Rc(ctx->opcode)) gen_op_4xx_tlbsx_check(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); #endif } @@ -5111,8 +5755,8 @@ case 0: case 1: case 2: - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rS(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]); gen_op_440_tlbwe(rB(ctx->opcode)); break; default: @@ -5132,7 +5776,7 @@ GEN_EXCP_PRIVOPC(ctx); return; } - gen_op_load_gpr_T0(rD(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rD(ctx->opcode)]); gen_op_wrte(); /* Stop translation to have a chance to raise an exception * if we just set msr_ee to 1 @@ -5151,7 +5795,7 @@ GEN_EXCP_PRIVOPC(ctx); return; } - gen_op_set_T0(ctx->opcode & 0x00010000); + tcg_gen_movi_tl(cpu_T[0], ctx->opcode & 0x00010000); gen_op_wrte(); /* Stop translation to have a chance to raise an exception * if we just set msr_ee to 1 @@ -5164,14 +5808,15 @@ /* dlmzb */ GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); + tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); + tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); gen_op_440_dlmzb(); - gen_op_store_T0_gpr(rA(ctx->opcode)); - gen_op_store_xer_bc(); + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~0x7F); + tcg_gen_or_tl(cpu_xer, cpu_xer, cpu_T[0]); if (Rc(ctx->opcode)) { gen_op_440_dlmzb_update_Rc(); - gen_op_store_T0_crf(0); + tcg_gen_andi_i32(cpu_crf[0], cpu_T[0], 0xf); } } @@ -5198,15 +5843,16 @@ /*** Altivec vector extension ***/ /* Altivec registers moves */ -GEN32(gen_op_load_avr_A0, gen_op_load_avr_A0_avr); -GEN32(gen_op_load_avr_A1, gen_op_load_avr_A1_avr); -GEN32(gen_op_load_avr_A2, gen_op_load_avr_A2_avr); - -GEN32(gen_op_store_A0_avr, gen_op_store_A0_avr_avr); -GEN32(gen_op_store_A1_avr, gen_op_store_A1_avr_avr); -#if 0 // unused -GEN32(gen_op_store_A2_avr, gen_op_store_A2_avr_avr); -#endif + +static always_inline void gen_load_avr(int t, int reg) { + tcg_gen_mov_i64(cpu_AVRh[t], cpu_avrh[reg]); + tcg_gen_mov_i64(cpu_AVRl[t], cpu_avrl[reg]); +} + +static always_inline void gen_store_avr(int reg, int t) { + tcg_gen_mov_i64(cpu_avrh[reg], cpu_AVRh[t]); + tcg_gen_mov_i64(cpu_avrl[reg], cpu_AVRl[t]); +} #define op_vr_ldst(name) (*gen_op_##name[ctx->mem_idx])() #define OP_VR_LD_TABLE(name) \ @@ -5225,9 +5871,9 @@ GEN_EXCP_NO_VR(ctx); \ return; \ } \ - gen_addr_reg_index(ctx); \ + gen_addr_reg_index(cpu_T[0], ctx); \ op_vr_ldst(vr_l##name); \ - gen_op_store_A0_avr(rD(ctx->opcode)); \ + gen_store_avr(rD(ctx->opcode), 0); \ } #define GEN_VR_STX(name, opc2, opc3) \ @@ -5237,8 +5883,8 @@ GEN_EXCP_NO_VR(ctx); \ return; \ } \ - gen_addr_reg_index(ctx); \ - gen_op_load_avr_A0(rS(ctx->opcode)); \ + gen_addr_reg_index(cpu_T[0], ctx); \ + gen_load_avr(0, rS(ctx->opcode)); \ op_vr_ldst(vr_st##name); \ } @@ -5255,37 +5901,27 @@ GEN_VR_STX(vxl, 0x07, 0x0F); /*** SPE extension ***/ -/* Register moves */ -#if !defined(TARGET_PPC64) - -GEN32(gen_op_load_gpr64_T0, gen_op_load_gpr64_T0_gpr); -GEN32(gen_op_load_gpr64_T1, gen_op_load_gpr64_T1_gpr); -#if 0 // unused -GEN32(gen_op_load_gpr64_T2, gen_op_load_gpr64_T2_gpr); -#endif - -GEN32(gen_op_store_T0_gpr64, gen_op_store_T0_gpr64_gpr); -GEN32(gen_op_store_T1_gpr64, gen_op_store_T1_gpr64_gpr); -#if 0 // unused -GEN32(gen_op_store_T2_gpr64, gen_op_store_T2_gpr64_gpr); -#endif - -#else /* !defined(TARGET_PPC64) */ +/* Register moves */ -/* No specific load/store functions: GPRs are already 64 bits */ -#define gen_op_load_gpr64_T0 gen_op_load_gpr_T0 -#define gen_op_load_gpr64_T1 gen_op_load_gpr_T1 -#if 0 // unused -#define gen_op_load_gpr64_T2 gen_op_load_gpr_T2 +static always_inline void gen_load_gpr64(TCGv t, int reg) { +#if defined(TARGET_PPC64) + tcg_gen_mov_i64(t, cpu_gpr[reg]); +#else + tcg_gen_concat_i32_i64(t, cpu_gpr[reg], cpu_gprh[reg]); #endif +} -#define gen_op_store_T0_gpr64 gen_op_store_T0_gpr -#define gen_op_store_T1_gpr64 gen_op_store_T1_gpr -#if 0 // unused -#define gen_op_store_T2_gpr64 gen_op_store_T2_gpr +static always_inline void gen_store_gpr64(int reg, TCGv t) { +#if defined(TARGET_PPC64) + tcg_gen_mov_i64(cpu_gpr[reg], t); +#else + tcg_gen_trunc_i64_i32(cpu_gpr[reg], t); + TCGv tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_shri_i64(tmp, t, 32); + tcg_gen_trunc_i64_i32(cpu_gprh[reg], tmp); + tcg_temp_free(tmp); #endif - -#endif /* !defined(TARGET_PPC64) */ +} #define GEN_SPE(name0, name1, opc2, opc3, inval, type) \ GEN_HANDLER(name0##_##name1, 0x04, opc2, opc3, inval, type) \ @@ -5303,17 +5939,16 @@ } /* SPE load and stores */ -static always_inline void gen_addr_spe_imm_index (DisasContext *ctx, int sh) +static always_inline void gen_addr_spe_imm_index (TCGv EA, DisasContext *ctx, int sh) { target_long simm = rB(ctx->opcode); - if (rA(ctx->opcode) == 0) { - gen_set_T0(simm << sh); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - if (likely(simm != 0)) - gen_op_addi(simm << sh); - } + if (rA(ctx->opcode) == 0) + tcg_gen_movi_tl(EA, simm << sh); + else if (likely(simm != 0)) + tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], simm << sh); + else + tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]); } #define op_spe_ldst(name) (*gen_op_##name[ctx->mem_idx])() @@ -5333,9 +5968,9 @@ GEN_EXCP_NO_AP(ctx); \ return; \ } \ - gen_addr_spe_imm_index(ctx, sh); \ + gen_addr_spe_imm_index(cpu_T[0], ctx, sh); \ op_spe_ldst(spe_l##name); \ - gen_op_store_T1_gpr64(rD(ctx->opcode)); \ + gen_store_gpr64(rD(ctx->opcode), cpu_T64[1]); \ } #define GEN_SPE_LDX(name) \ @@ -5345,9 +5980,9 @@ GEN_EXCP_NO_AP(ctx); \ return; \ } \ - gen_addr_reg_index(ctx); \ + gen_addr_reg_index(cpu_T[0], ctx); \ op_spe_ldst(spe_l##name); \ - gen_op_store_T1_gpr64(rD(ctx->opcode)); \ + gen_store_gpr64(rD(ctx->opcode), cpu_T64[1]); \ } #define GEN_SPEOP_LD(name, sh) \ @@ -5362,8 +5997,8 @@ GEN_EXCP_NO_AP(ctx); \ return; \ } \ - gen_addr_spe_imm_index(ctx, sh); \ - gen_op_load_gpr64_T1(rS(ctx->opcode)); \ + gen_addr_spe_imm_index(cpu_T[0], ctx, sh); \ + gen_load_gpr64(cpu_T64[1], rS(ctx->opcode)); \ op_spe_ldst(spe_st##name); \ } @@ -5374,8 +6009,8 @@ GEN_EXCP_NO_AP(ctx); \ return; \ } \ - gen_addr_reg_index(ctx); \ - gen_op_load_gpr64_T1(rS(ctx->opcode)); \ + gen_addr_reg_index(cpu_T[0], ctx); \ + gen_load_gpr64(cpu_T64[1], rS(ctx->opcode)); \ op_spe_ldst(spe_st##name); \ } @@ -5388,141 +6023,564 @@ GEN_SPEOP_LD(name, sh); \ GEN_SPEOP_ST(name, sh) -/* SPE arithmetic and logic */ -#define GEN_SPEOP_ARITH2(name) \ +/* SPE logic */ +#if defined(TARGET_PPC64) +#define GEN_SPEOP_LOGIC2(name, tcg_op) \ static always_inline void gen_##name (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ GEN_EXCP_NO_AP(ctx); \ return; \ } \ - gen_op_load_gpr64_T0(rA(ctx->opcode)); \ - gen_op_load_gpr64_T1(rB(ctx->opcode)); \ - gen_op_##name(); \ - gen_op_store_T0_gpr64(rD(ctx->opcode)); \ + tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], \ + cpu_gpr[rB(ctx->opcode)]); \ +} +#else +#define GEN_SPEOP_LOGIC2(name, tcg_op) \ +static always_inline void gen_##name (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + GEN_EXCP_NO_AP(ctx); \ + return; \ + } \ + tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], \ + cpu_gpr[rB(ctx->opcode)]); \ + tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], \ + cpu_gprh[rB(ctx->opcode)]); \ } +#endif + +GEN_SPEOP_LOGIC2(evand, tcg_gen_and_tl); +GEN_SPEOP_LOGIC2(evandc, tcg_gen_andc_tl); +GEN_SPEOP_LOGIC2(evxor, tcg_gen_xor_tl); +GEN_SPEOP_LOGIC2(evor, tcg_gen_or_tl); +GEN_SPEOP_LOGIC2(evnor, tcg_gen_nor_tl); +GEN_SPEOP_LOGIC2(eveqv, tcg_gen_eqv_tl); +GEN_SPEOP_LOGIC2(evorc, tcg_gen_orc_tl); +GEN_SPEOP_LOGIC2(evnand, tcg_gen_nand_tl); -#define GEN_SPEOP_ARITH1(name) \ +/* SPE logic immediate */ +#if defined(TARGET_PPC64) +#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi) \ static always_inline void gen_##name (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ GEN_EXCP_NO_AP(ctx); \ return; \ } \ - gen_op_load_gpr64_T0(rA(ctx->opcode)); \ - gen_op_##name(); \ - gen_op_store_T0_gpr64(rD(ctx->opcode)); \ + TCGv t0 = tcg_temp_local_new(TCG_TYPE_I32); \ + TCGv t1 = tcg_temp_local_new(TCG_TYPE_I32); \ + TCGv t2 = tcg_temp_local_new(TCG_TYPE_I64); \ + tcg_gen_trunc_i64_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ + tcg_opi(t0, t0, rB(ctx->opcode)); \ + tcg_gen_shri_i64(t2, cpu_gpr[rA(ctx->opcode)], 32); \ + tcg_gen_trunc_i64_i32(t1, t2); \ + tcg_temp_free(t2); \ + tcg_opi(t1, t1, rB(ctx->opcode)); \ + tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1); \ + tcg_temp_free(t0); \ + tcg_temp_free(t1); \ +} +#else +#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi) \ +static always_inline void gen_##name (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + GEN_EXCP_NO_AP(ctx); \ + return; \ + } \ + tcg_opi(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], \ + rB(ctx->opcode)); \ + tcg_opi(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], \ + rB(ctx->opcode)); \ } +#endif +GEN_SPEOP_TCG_LOGIC_IMM2(evslwi, tcg_gen_shli_i32); +GEN_SPEOP_TCG_LOGIC_IMM2(evsrwiu, tcg_gen_shri_i32); +GEN_SPEOP_TCG_LOGIC_IMM2(evsrwis, tcg_gen_sari_i32); +GEN_SPEOP_TCG_LOGIC_IMM2(evrlwi, tcg_gen_rotli_i32); -#define GEN_SPEOP_COMP(name) \ +/* SPE arithmetic */ +#if defined(TARGET_PPC64) +#define GEN_SPEOP_ARITH1(name, tcg_op) \ static always_inline void gen_##name (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ GEN_EXCP_NO_AP(ctx); \ return; \ } \ - gen_op_load_gpr64_T0(rA(ctx->opcode)); \ - gen_op_load_gpr64_T1(rB(ctx->opcode)); \ - gen_op_##name(); \ - gen_op_store_T0_crf(crfD(ctx->opcode)); \ + TCGv t0 = tcg_temp_local_new(TCG_TYPE_I32); \ + TCGv t1 = tcg_temp_local_new(TCG_TYPE_I32); \ + TCGv t2 = tcg_temp_local_new(TCG_TYPE_I64); \ + tcg_gen_trunc_i64_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ + tcg_op(t0, t0); \ + tcg_gen_shri_i64(t2, cpu_gpr[rA(ctx->opcode)], 32); \ + tcg_gen_trunc_i64_i32(t1, t2); \ + tcg_temp_free(t2); \ + tcg_op(t1, t1); \ + tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1); \ + tcg_temp_free(t0); \ + tcg_temp_free(t1); \ +} +#else +#define GEN_SPEOP_ARITH1(name, tcg_op) \ +static always_inline void gen_##name (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + GEN_EXCP_NO_AP(ctx); \ + return; \ + } \ + tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); \ + tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); \ } +#endif -/* Logical */ -GEN_SPEOP_ARITH2(evand); -GEN_SPEOP_ARITH2(evandc); -GEN_SPEOP_ARITH2(evxor); -GEN_SPEOP_ARITH2(evor); -GEN_SPEOP_ARITH2(evnor); -GEN_SPEOP_ARITH2(eveqv); -GEN_SPEOP_ARITH2(evorc); -GEN_SPEOP_ARITH2(evnand); -GEN_SPEOP_ARITH2(evsrwu); -GEN_SPEOP_ARITH2(evsrws); -GEN_SPEOP_ARITH2(evslw); -GEN_SPEOP_ARITH2(evrlw); -GEN_SPEOP_ARITH2(evmergehi); -GEN_SPEOP_ARITH2(evmergelo); -GEN_SPEOP_ARITH2(evmergehilo); -GEN_SPEOP_ARITH2(evmergelohi); +static always_inline void gen_op_evabs (TCGv ret, TCGv arg1) +{ + int l1 = gen_new_label(); + int l2 = gen_new_label(); -/* Arithmetic */ -GEN_SPEOP_ARITH2(evaddw); -GEN_SPEOP_ARITH2(evsubfw); -GEN_SPEOP_ARITH1(evabs); -GEN_SPEOP_ARITH1(evneg); -GEN_SPEOP_ARITH1(evextsb); -GEN_SPEOP_ARITH1(evextsh); -GEN_SPEOP_ARITH1(evrndw); -GEN_SPEOP_ARITH1(evcntlzw); -GEN_SPEOP_ARITH1(evcntlsw); -static always_inline void gen_brinc (DisasContext *ctx) + tcg_gen_brcondi_i32(TCG_COND_GE, arg1, 0, l1); + tcg_gen_neg_i32(ret, arg1); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_mov_tl(ret, arg1); + gen_set_label(l2); +} +GEN_SPEOP_ARITH1(evabs, gen_op_evabs); +GEN_SPEOP_ARITH1(evneg, tcg_gen_neg_i32); +GEN_SPEOP_ARITH1(evextsb, tcg_gen_ext8s_i32); +GEN_SPEOP_ARITH1(evextsh, tcg_gen_ext16s_i32); +static always_inline void gen_op_evrndw (TCGv ret, TCGv arg1) { - /* Note: brinc is usable even if SPE is disabled */ - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_brinc(); - gen_op_store_T0_gpr(rD(ctx->opcode)); + tcg_gen_addi_i32(ret, arg1, 0x8000); + tcg_gen_ext16u_i32(ret, ret); +} +GEN_SPEOP_ARITH1(evrndw, gen_op_evrndw); +static always_inline void gen_op_cntlsw (TCGv ret, TCGv arg1) +{ + tcg_gen_helper_1_1(helper_cntlsw32, ret, arg1); +} +GEN_SPEOP_ARITH1(evcntlsw, gen_op_cntlsw); +static always_inline void gen_op_cntlzw (TCGv ret, TCGv arg1) +{ + tcg_gen_helper_1_1(helper_cntlzw32, ret, arg1); } +GEN_SPEOP_ARITH1(evcntlzw, gen_op_cntlzw); -#define GEN_SPEOP_ARITH_IMM2(name) \ -static always_inline void gen_##name##i (DisasContext *ctx) \ +#if defined(TARGET_PPC64) +#define GEN_SPEOP_ARITH2(name, tcg_op) \ +static always_inline void gen_##name (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ GEN_EXCP_NO_AP(ctx); \ return; \ } \ - gen_op_load_gpr64_T0(rB(ctx->opcode)); \ - gen_op_splatwi_T1_64(rA(ctx->opcode)); \ - gen_op_##name(); \ - gen_op_store_T0_gpr64(rD(ctx->opcode)); \ + TCGv t0 = tcg_temp_local_new(TCG_TYPE_I32); \ + TCGv t1 = tcg_temp_local_new(TCG_TYPE_I32); \ + TCGv t2 = tcg_temp_local_new(TCG_TYPE_I32); \ + TCGv t3 = tcg_temp_local_new(TCG_TYPE_I64); \ + tcg_gen_trunc_i64_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ + tcg_gen_trunc_i64_i32(t2, cpu_gpr[rB(ctx->opcode)]); \ + tcg_op(t0, t0, t2); \ + tcg_gen_shri_i64(t3, cpu_gpr[rA(ctx->opcode)], 32); \ + tcg_gen_trunc_i64_i32(t1, t3); \ + tcg_gen_shri_i64(t3, cpu_gpr[rB(ctx->opcode)], 32); \ + tcg_gen_trunc_i64_i32(t2, t3); \ + tcg_temp_free(t3); \ + tcg_op(t1, t1, t2); \ + tcg_temp_free(t2); \ + tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1); \ + tcg_temp_free(t0); \ + tcg_temp_free(t1); \ +} +#else +#define GEN_SPEOP_ARITH2(name, tcg_op) \ +static always_inline void gen_##name (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + GEN_EXCP_NO_AP(ctx); \ + return; \ + } \ + tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], \ + cpu_gpr[rB(ctx->opcode)]); \ + tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], \ + cpu_gprh[rB(ctx->opcode)]); \ +} +#endif + +static always_inline void gen_op_evsrwu (TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + int l1, l2; + + l1 = gen_new_label(); + l2 = gen_new_label(); + t0 = tcg_temp_local_new(TCG_TYPE_I32); + /* No error here: 6 bits are used */ + tcg_gen_andi_i32(t0, arg2, 0x3F); + tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1); + tcg_gen_shr_i32(ret, arg1, t0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i32(ret, 0); + tcg_gen_br(l2); + tcg_temp_free(t0); +} +GEN_SPEOP_ARITH2(evsrwu, gen_op_evsrwu); +static always_inline void gen_op_evsrws (TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + int l1, l2; + + l1 = gen_new_label(); + l2 = gen_new_label(); + t0 = tcg_temp_local_new(TCG_TYPE_I32); + /* No error here: 6 bits are used */ + tcg_gen_andi_i32(t0, arg2, 0x3F); + tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1); + tcg_gen_sar_i32(ret, arg1, t0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i32(ret, 0); + tcg_gen_br(l2); + tcg_temp_free(t0); +} +GEN_SPEOP_ARITH2(evsrws, gen_op_evsrws); +static always_inline void gen_op_evslw (TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + int l1, l2; + + l1 = gen_new_label(); + l2 = gen_new_label(); + t0 = tcg_temp_local_new(TCG_TYPE_I32); + /* No error here: 6 bits are used */ + tcg_gen_andi_i32(t0, arg2, 0x3F); + tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1); + tcg_gen_shl_i32(ret, arg1, t0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i32(ret, 0); + tcg_gen_br(l2); + tcg_temp_free(t0); +} +GEN_SPEOP_ARITH2(evslw, gen_op_evslw); +static always_inline void gen_op_evrlw (TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_andi_i32(t0, arg2, 0x1F); + tcg_gen_rotl_i32(ret, arg1, t0); + tcg_temp_free(t0); +} +GEN_SPEOP_ARITH2(evrlw, gen_op_evrlw); +static always_inline void gen_evmergehi (DisasContext *ctx) +{ + if (unlikely(!ctx->spe_enabled)) { + GEN_EXCP_NO_AP(ctx); + return; + } +#if defined(TARGET_PPC64) + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + TCGv t1 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 32); + tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], 0xFFFFFFFF0000000ULL); + tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); +#else + tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); + tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); +#endif +} +GEN_SPEOP_ARITH2(evaddw, tcg_gen_add_i32); +static always_inline void gen_op_evsubf (TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_sub_i32(ret, arg2, arg1); } +GEN_SPEOP_ARITH2(evsubfw, gen_op_evsubf); -#define GEN_SPEOP_LOGIC_IMM2(name) \ -static always_inline void gen_##name##i (DisasContext *ctx) \ +/* SPE arithmetic immediate */ +#if defined(TARGET_PPC64) +#define GEN_SPEOP_ARITH_IMM2(name, tcg_op) \ +static always_inline void gen_##name (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ GEN_EXCP_NO_AP(ctx); \ return; \ } \ - gen_op_load_gpr64_T0(rA(ctx->opcode)); \ - gen_op_splatwi_T1_64(rB(ctx->opcode)); \ - gen_op_##name(); \ - gen_op_store_T0_gpr64(rD(ctx->opcode)); \ + TCGv t0 = tcg_temp_local_new(TCG_TYPE_I32); \ + TCGv t1 = tcg_temp_local_new(TCG_TYPE_I32); \ + TCGv t2 = tcg_temp_local_new(TCG_TYPE_I64); \ + tcg_gen_trunc_i64_i32(t0, cpu_gpr[rB(ctx->opcode)]); \ + tcg_op(t0, t0, rA(ctx->opcode)); \ + tcg_gen_shri_i64(t2, cpu_gpr[rB(ctx->opcode)], 32); \ + tcg_gen_trunc_i64_i32(t1, t2); \ + tcg_temp_free(t2); \ + tcg_op(t1, t1, rA(ctx->opcode)); \ + tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1); \ + tcg_temp_free(t0); \ + tcg_temp_free(t1); \ } +#else +#define GEN_SPEOP_ARITH_IMM2(name, tcg_op) \ +static always_inline void gen_##name (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + GEN_EXCP_NO_AP(ctx); \ + return; \ + } \ + tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \ + rA(ctx->opcode)); \ + tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)], \ + rA(ctx->opcode)); \ +} +#endif +GEN_SPEOP_ARITH_IMM2(evaddiw, tcg_gen_addi_i32); +GEN_SPEOP_ARITH_IMM2(evsubifw, tcg_gen_subi_i32); -GEN_SPEOP_ARITH_IMM2(evaddw); -#define gen_evaddiw gen_evaddwi -GEN_SPEOP_ARITH_IMM2(evsubfw); -#define gen_evsubifw gen_evsubfwi -GEN_SPEOP_LOGIC_IMM2(evslw); -GEN_SPEOP_LOGIC_IMM2(evsrwu); -#define gen_evsrwis gen_evsrwsi -GEN_SPEOP_LOGIC_IMM2(evsrws); -#define gen_evsrwiu gen_evsrwui -GEN_SPEOP_LOGIC_IMM2(evrlw); +/* SPE comparison */ +#if defined(TARGET_PPC64) +#define GEN_SPEOP_COMP(name, tcg_cond) \ +static always_inline void gen_##name (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + GEN_EXCP_NO_AP(ctx); \ + return; \ + } \ + int l1 = gen_new_label(); \ + int l2 = gen_new_label(); \ + int l3 = gen_new_label(); \ + int l4 = gen_new_label(); \ + TCGv t0 = tcg_temp_local_new(TCG_TYPE_I32); \ + TCGv t1 = tcg_temp_local_new(TCG_TYPE_I32); \ + TCGv t2 = tcg_temp_local_new(TCG_TYPE_I64); \ + tcg_gen_trunc_i64_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ + tcg_gen_trunc_i64_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ + tcg_gen_brcond_i32(tcg_cond, t0, t1, l1); \ + tcg_gen_movi_tl(cpu_crf[crfD(ctx->opcode)], 0); \ + tcg_gen_br(l2); \ + gen_set_label(l1); \ + tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], \ + CRF_CL | CRF_CH_OR_CL | CRF_CH_AND_CL); \ + gen_set_label(l2); \ + tcg_gen_shri_i64(t2, cpu_gpr[rA(ctx->opcode)], 32); \ + tcg_gen_trunc_i64_i32(t0, t2); \ + tcg_gen_shri_i64(t2, cpu_gpr[rB(ctx->opcode)], 32); \ + tcg_gen_trunc_i64_i32(t1, t2); \ + tcg_temp_free(t2); \ + tcg_gen_brcond_i32(tcg_cond, t0, t1, l3); \ + tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], \ + ~(CRF_CH | CRF_CH_AND_CL)); \ + tcg_gen_br(l4); \ + gen_set_label(l3); \ + tcg_gen_ori_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], \ + CRF_CH | CRF_CH_OR_CL); \ + gen_set_label(l4); \ + tcg_temp_free(t0); \ + tcg_temp_free(t1); \ +} +#else +#define GEN_SPEOP_COMP(name, tcg_cond) \ +static always_inline void gen_##name (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + GEN_EXCP_NO_AP(ctx); \ + return; \ + } \ + int l1 = gen_new_label(); \ + int l2 = gen_new_label(); \ + int l3 = gen_new_label(); \ + int l4 = gen_new_label(); \ + \ + tcg_gen_brcond_i32(tcg_cond, cpu_gpr[rA(ctx->opcode)], \ + cpu_gpr[rB(ctx->opcode)], l1); \ + tcg_gen_movi_tl(cpu_crf[crfD(ctx->opcode)], 0); \ + tcg_gen_br(l2); \ + gen_set_label(l1); \ + tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], \ + CRF_CL | CRF_CH_OR_CL | CRF_CH_AND_CL); \ + gen_set_label(l2); \ + tcg_gen_brcond_i32(tcg_cond, cpu_gprh[rA(ctx->opcode)], \ + cpu_gprh[rB(ctx->opcode)], l3); \ + tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], \ + ~(CRF_CH | CRF_CH_AND_CL)); \ + tcg_gen_br(l4); \ + gen_set_label(l3); \ + tcg_gen_ori_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], \ + CRF_CH | CRF_CH_OR_CL); \ + gen_set_label(l4); \ +} +#endif +GEN_SPEOP_COMP(evcmpgtu, TCG_COND_GTU); +GEN_SPEOP_COMP(evcmpgts, TCG_COND_GT); +GEN_SPEOP_COMP(evcmpltu, TCG_COND_LTU); +GEN_SPEOP_COMP(evcmplts, TCG_COND_LT); +GEN_SPEOP_COMP(evcmpeq, TCG_COND_EQ); +/* SPE misc */ +static always_inline void gen_brinc (DisasContext *ctx) +{ + /* Note: brinc is usable even if SPE is disabled */ + tcg_gen_helper_1_2(helper_brinc, cpu_gpr[rD(ctx->opcode)], + cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); +} +static always_inline void gen_evmergelo (DisasContext *ctx) +{ + if (unlikely(!ctx->spe_enabled)) { + GEN_EXCP_NO_AP(ctx); + return; + } +#if defined(TARGET_PPC64) + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + TCGv t1 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x00000000FFFFFFFFLL); + tcg_gen_shli_tl(t1, cpu_gpr[rA(ctx->opcode)], 32); + tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); +#else + tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); +#endif +} +static always_inline void gen_evmergehilo (DisasContext *ctx) +{ + if (unlikely(!ctx->spe_enabled)) { + GEN_EXCP_NO_AP(ctx); + return; + } +#if defined(TARGET_PPC64) + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + TCGv t1 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x00000000FFFFFFFFLL); + tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], 0xFFFFFFFF0000000ULL); + tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); +#else + tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); +#endif +} +static always_inline void gen_evmergelohi (DisasContext *ctx) +{ + if (unlikely(!ctx->spe_enabled)) { + GEN_EXCP_NO_AP(ctx); + return; + } +#if defined(TARGET_PPC64) + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + TCGv t1 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 32); + tcg_gen_shli_tl(t1, cpu_gpr[rA(ctx->opcode)], 32); + tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); +#else + tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); + tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); +#endif +} static always_inline void gen_evsplati (DisasContext *ctx) { - int32_t imm = (int32_t)(rA(ctx->opcode) << 27) >> 27; + int32_t imm = (int32_t)(rA(ctx->opcode) << 11) >> 27; - gen_op_splatwi_T0_64(imm); - gen_op_store_T0_gpr64(rD(ctx->opcode)); +#if defined(TARGET_PPC64) + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + TCGv t1 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_movi_tl(t0, imm); + tcg_gen_shri_tl(t1, t0, 32); + tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); +#else + tcg_gen_movi_i32(cpu_gpr[rD(ctx->opcode)], imm); + tcg_gen_movi_i32(cpu_gprh[rD(ctx->opcode)], imm); +#endif } - static always_inline void gen_evsplatfi (DisasContext *ctx) { - uint32_t imm = rA(ctx->opcode) << 27; + uint32_t imm = rA(ctx->opcode) << 11; - gen_op_splatwi_T0_64(imm); - gen_op_store_T0_gpr64(rD(ctx->opcode)); +#if defined(TARGET_PPC64) + TCGv t0 = tcg_temp_new(TCG_TYPE_TL); + TCGv t1 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_movi_tl(t0, imm); + tcg_gen_shri_tl(t1, t0, 32); + tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); +#else + tcg_gen_movi_i32(cpu_gpr[rD(ctx->opcode)], imm); + tcg_gen_movi_i32(cpu_gprh[rD(ctx->opcode)], imm); +#endif } -/* Comparison */ -GEN_SPEOP_COMP(evcmpgtu); -GEN_SPEOP_COMP(evcmpgts); -GEN_SPEOP_COMP(evcmpltu); -GEN_SPEOP_COMP(evcmplts); -GEN_SPEOP_COMP(evcmpeq); +static always_inline void gen_evsel (DisasContext *ctx) +{ + int l1 = gen_new_label(); + int l2 = gen_new_label(); + int l3 = gen_new_label(); + int l4 = gen_new_label(); + TCGv t0 = tcg_temp_local_new(TCG_TYPE_I32); +#if defined(TARGET_PPC64) + TCGv t1 = tcg_temp_local_new(TCG_TYPE_TL); + TCGv t2 = tcg_temp_local_new(TCG_TYPE_TL); +#endif + tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 3); + tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1); +#if defined(TARGET_PPC64) + tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], 0xFFFFFFFF00000000ULL); +#else + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); +#endif + tcg_gen_br(l2); + gen_set_label(l1); +#if defined(TARGET_PPC64) + tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0xFFFFFFFF00000000ULL); +#else + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); +#endif + gen_set_label(l2); + tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 2); + tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l3); +#if defined(TARGET_PPC64) + tcg_gen_andi_tl(t2, cpu_gpr[rA(ctx->opcode)], 0x00000000FFFFFFFFULL); +#else + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); +#endif + tcg_gen_br(l4); + gen_set_label(l3); +#if defined(TARGET_PPC64) + tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x00000000FFFFFFFFULL); +#else + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); +#endif + gen_set_label(l4); + tcg_temp_free(t0); +#if defined(TARGET_PPC64) + tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t1, t2); + tcg_temp_free(t1); + tcg_temp_free(t2); +#endif +} +GEN_HANDLER2(evsel0, "evsel", 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE) +{ + gen_evsel(ctx); +} +GEN_HANDLER2(evsel1, "evsel", 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE) +{ + gen_evsel(ctx); +} +GEN_HANDLER2(evsel2, "evsel", 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE) +{ + gen_evsel(ctx); +} +GEN_HANDLER2(evsel3, "evsel", 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE) +{ + gen_evsel(ctx); +} GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, PPC_SPE); //// GEN_SPE(evaddiw, speundef, 0x01, 0x08, 0x00000000, PPC_SPE); @@ -5550,74 +6608,7 @@ GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, PPC_SPE); //// GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, PPC_SPE); //// -static always_inline void gen_evsel (DisasContext *ctx) -{ - if (unlikely(!ctx->spe_enabled)) { - GEN_EXCP_NO_AP(ctx); - return; - } - gen_op_load_crf_T0(ctx->opcode & 0x7); - gen_op_load_gpr64_T0(rA(ctx->opcode)); - gen_op_load_gpr64_T1(rB(ctx->opcode)); - gen_op_evsel(); - gen_op_store_T0_gpr64(rD(ctx->opcode)); -} - -GEN_HANDLER2(evsel0, "evsel", 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE) -{ - gen_evsel(ctx); -} -GEN_HANDLER2(evsel1, "evsel", 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE) -{ - gen_evsel(ctx); -} -GEN_HANDLER2(evsel2, "evsel", 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE) -{ - gen_evsel(ctx); -} -GEN_HANDLER2(evsel3, "evsel", 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE) -{ - gen_evsel(ctx); -} - /* Load and stores */ -#if defined(TARGET_PPC64) -/* In that case, we already have 64 bits load & stores - * so, spe_ldd is equivalent to ld and spe_std is equivalent to std - */ -#define gen_op_spe_ldd_raw gen_op_ld_raw -#define gen_op_spe_ldd_user gen_op_ld_user -#define gen_op_spe_ldd_kernel gen_op_ld_kernel -#define gen_op_spe_ldd_hypv gen_op_ld_hypv -#define gen_op_spe_ldd_64_raw gen_op_ld_64_raw -#define gen_op_spe_ldd_64_user gen_op_ld_64_user -#define gen_op_spe_ldd_64_kernel gen_op_ld_64_kernel -#define gen_op_spe_ldd_64_hypv gen_op_ld_64_hypv -#define gen_op_spe_ldd_le_raw gen_op_ld_le_raw -#define gen_op_spe_ldd_le_user gen_op_ld_le_user -#define gen_op_spe_ldd_le_kernel gen_op_ld_le_kernel -#define gen_op_spe_ldd_le_hypv gen_op_ld_le_hypv -#define gen_op_spe_ldd_le_64_raw gen_op_ld_le_64_raw -#define gen_op_spe_ldd_le_64_user gen_op_ld_le_64_user -#define gen_op_spe_ldd_le_64_kernel gen_op_ld_le_64_kernel -#define gen_op_spe_ldd_le_64_hypv gen_op_ld_le_64_hypv -#define gen_op_spe_stdd_raw gen_op_std_raw -#define gen_op_spe_stdd_user gen_op_std_user -#define gen_op_spe_stdd_kernel gen_op_std_kernel -#define gen_op_spe_stdd_hypv gen_op_std_hypv -#define gen_op_spe_stdd_64_raw gen_op_std_64_raw -#define gen_op_spe_stdd_64_user gen_op_std_64_user -#define gen_op_spe_stdd_64_kernel gen_op_std_64_kernel -#define gen_op_spe_stdd_64_hypv gen_op_std_64_hypv -#define gen_op_spe_stdd_le_raw gen_op_std_le_raw -#define gen_op_spe_stdd_le_user gen_op_std_le_user -#define gen_op_spe_stdd_le_kernel gen_op_std_le_kernel -#define gen_op_spe_stdd_le_hypv gen_op_std_le_hypv -#define gen_op_spe_stdd_le_64_raw gen_op_std_le_64_raw -#define gen_op_spe_stdd_le_64_user gen_op_std_le_64_user -#define gen_op_spe_stdd_le_64_kernel gen_op_std_le_64_kernel -#define gen_op_spe_stdd_le_64_hypv gen_op_std_le_64_hypv -#endif /* defined(TARGET_PPC64) */ GEN_SPEOP_LDST(dd, 3); GEN_SPEOP_LDST(dw, 3); GEN_SPEOP_LDST(dh, 3); @@ -5626,25 +6617,6 @@ GEN_SPEOP_LD(whos, 2); GEN_SPEOP_ST(who, 2); -#if defined(TARGET_PPC64) -/* In that case, spe_stwwo is equivalent to stw */ -#define gen_op_spe_stwwo_raw gen_op_stw_raw -#define gen_op_spe_stwwo_user gen_op_stw_user -#define gen_op_spe_stwwo_kernel gen_op_stw_kernel -#define gen_op_spe_stwwo_hypv gen_op_stw_hypv -#define gen_op_spe_stwwo_le_raw gen_op_stw_le_raw -#define gen_op_spe_stwwo_le_user gen_op_stw_le_user -#define gen_op_spe_stwwo_le_kernel gen_op_stw_le_kernel -#define gen_op_spe_stwwo_le_hypv gen_op_stw_le_hypv -#define gen_op_spe_stwwo_64_raw gen_op_stw_64_raw -#define gen_op_spe_stwwo_64_user gen_op_stw_64_user -#define gen_op_spe_stwwo_64_kernel gen_op_stw_64_kernel -#define gen_op_spe_stwwo_64_hypv gen_op_stw_64_hypv -#define gen_op_spe_stwwo_le_64_raw gen_op_stw_le_64_raw -#define gen_op_spe_stwwo_le_64_user gen_op_stw_le_64_user -#define gen_op_spe_stwwo_le_64_kernel gen_op_stw_le_64_kernel -#define gen_op_spe_stwwo_le_64_hypv gen_op_stw_le_64_hypv -#endif #define _GEN_OP_SPE_STWWE(suffix) \ static always_inline void gen_op_spe_stwwe_##suffix (void) \ { \ @@ -5899,20 +6871,58 @@ #define GEN_SPEFPUOP_CONV(name) \ static always_inline void gen_##name (DisasContext *ctx) \ { \ - gen_op_load_gpr64_T0(rB(ctx->opcode)); \ + gen_load_gpr64(cpu_T64[0], rB(ctx->opcode)); \ + gen_op_##name(); \ + gen_store_gpr64(rD(ctx->opcode), cpu_T64[0]); \ +} + +#define GEN_SPEFPUOP_ARITH1(name) \ +static always_inline void gen_##name (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + GEN_EXCP_NO_AP(ctx); \ + return; \ + } \ + gen_load_gpr64(cpu_T64[0], rA(ctx->opcode)); \ + gen_op_##name(); \ + gen_store_gpr64(rD(ctx->opcode), cpu_T64[0]); \ +} + +#define GEN_SPEFPUOP_ARITH2(name) \ +static always_inline void gen_##name (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + GEN_EXCP_NO_AP(ctx); \ + return; \ + } \ + gen_load_gpr64(cpu_T64[0], rA(ctx->opcode)); \ + gen_load_gpr64(cpu_T64[1], rB(ctx->opcode)); \ + gen_op_##name(); \ + gen_store_gpr64(rD(ctx->opcode), cpu_T64[0]); \ +} + +#define GEN_SPEFPUOP_COMP(name) \ +static always_inline void gen_##name (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + GEN_EXCP_NO_AP(ctx); \ + return; \ + } \ + gen_load_gpr64(cpu_T64[0], rA(ctx->opcode)); \ + gen_load_gpr64(cpu_T64[1], rB(ctx->opcode)); \ gen_op_##name(); \ - gen_op_store_T0_gpr64(rD(ctx->opcode)); \ + tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_T[0], 0xf); \ } /* Single precision floating-point vectors operations */ /* Arithmetic */ -GEN_SPEOP_ARITH2(evfsadd); -GEN_SPEOP_ARITH2(evfssub); -GEN_SPEOP_ARITH2(evfsmul); -GEN_SPEOP_ARITH2(evfsdiv); -GEN_SPEOP_ARITH1(evfsabs); -GEN_SPEOP_ARITH1(evfsnabs); -GEN_SPEOP_ARITH1(evfsneg); +GEN_SPEFPUOP_ARITH2(evfsadd); +GEN_SPEFPUOP_ARITH2(evfssub); +GEN_SPEFPUOP_ARITH2(evfsmul); +GEN_SPEFPUOP_ARITH2(evfsdiv); +GEN_SPEFPUOP_ARITH1(evfsabs); +GEN_SPEFPUOP_ARITH1(evfsnabs); +GEN_SPEFPUOP_ARITH1(evfsneg); /* Conversion */ GEN_SPEFPUOP_CONV(evfscfui); GEN_SPEFPUOP_CONV(evfscfsi); @@ -5925,12 +6935,12 @@ GEN_SPEFPUOP_CONV(evfsctuiz); GEN_SPEFPUOP_CONV(evfsctsiz); /* Comparison */ -GEN_SPEOP_COMP(evfscmpgt); -GEN_SPEOP_COMP(evfscmplt); -GEN_SPEOP_COMP(evfscmpeq); -GEN_SPEOP_COMP(evfststgt); -GEN_SPEOP_COMP(evfststlt); -GEN_SPEOP_COMP(evfststeq); +GEN_SPEFPUOP_COMP(evfscmpgt); +GEN_SPEFPUOP_COMP(evfscmplt); +GEN_SPEFPUOP_COMP(evfscmpeq); +GEN_SPEFPUOP_COMP(evfststgt); +GEN_SPEFPUOP_COMP(evfststlt); +GEN_SPEFPUOP_COMP(evfststeq); /* Opcodes definitions */ GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, PPC_SPEFPU); // @@ -5950,13 +6960,13 @@ /* Single precision floating-point operations */ /* Arithmetic */ -GEN_SPEOP_ARITH2(efsadd); -GEN_SPEOP_ARITH2(efssub); -GEN_SPEOP_ARITH2(efsmul); -GEN_SPEOP_ARITH2(efsdiv); -GEN_SPEOP_ARITH1(efsabs); -GEN_SPEOP_ARITH1(efsnabs); -GEN_SPEOP_ARITH1(efsneg); +GEN_SPEFPUOP_ARITH2(efsadd); +GEN_SPEFPUOP_ARITH2(efssub); +GEN_SPEFPUOP_ARITH2(efsmul); +GEN_SPEFPUOP_ARITH2(efsdiv); +GEN_SPEFPUOP_ARITH1(efsabs); +GEN_SPEFPUOP_ARITH1(efsnabs); +GEN_SPEFPUOP_ARITH1(efsneg); /* Conversion */ GEN_SPEFPUOP_CONV(efscfui); GEN_SPEFPUOP_CONV(efscfsi); @@ -5970,12 +6980,12 @@ GEN_SPEFPUOP_CONV(efsctsiz); GEN_SPEFPUOP_CONV(efscfd); /* Comparison */ -GEN_SPEOP_COMP(efscmpgt); -GEN_SPEOP_COMP(efscmplt); -GEN_SPEOP_COMP(efscmpeq); -GEN_SPEOP_COMP(efststgt); -GEN_SPEOP_COMP(efststlt); -GEN_SPEOP_COMP(efststeq); +GEN_SPEFPUOP_COMP(efscmpgt); +GEN_SPEFPUOP_COMP(efscmplt); +GEN_SPEFPUOP_COMP(efscmpeq); +GEN_SPEFPUOP_COMP(efststgt); +GEN_SPEFPUOP_COMP(efststlt); +GEN_SPEFPUOP_COMP(efststeq); /* Opcodes definitions */ GEN_SPE(efsadd, efssub, 0x00, 0x0B, 0x00000000, PPC_SPEFPU); // @@ -5988,19 +6998,20 @@ GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, PPC_SPEFPU); // GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, PPC_SPEFPU); // GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, PPC_SPEFPU); // -GEN_SPE(efsctuiz, efsctsiz, 0x0C, 0x0B, 0x00180000, PPC_SPEFPU); // +GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, PPC_SPEFPU); // +GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, PPC_SPEFPU); // GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, PPC_SPEFPU); // GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, PPC_SPEFPU); // /* Double precision floating-point operations */ /* Arithmetic */ -GEN_SPEOP_ARITH2(efdadd); -GEN_SPEOP_ARITH2(efdsub); -GEN_SPEOP_ARITH2(efdmul); -GEN_SPEOP_ARITH2(efddiv); -GEN_SPEOP_ARITH1(efdabs); -GEN_SPEOP_ARITH1(efdnabs); -GEN_SPEOP_ARITH1(efdneg); +GEN_SPEFPUOP_ARITH2(efdadd); +GEN_SPEFPUOP_ARITH2(efdsub); +GEN_SPEFPUOP_ARITH2(efdmul); +GEN_SPEFPUOP_ARITH2(efddiv); +GEN_SPEFPUOP_ARITH1(efdabs); +GEN_SPEFPUOP_ARITH1(efdnabs); +GEN_SPEFPUOP_ARITH1(efdneg); /* Conversion */ GEN_SPEFPUOP_CONV(efdcfui); @@ -6019,12 +7030,12 @@ GEN_SPEFPUOP_CONV(efdctuidz); GEN_SPEFPUOP_CONV(efdctsidz); /* Comparison */ -GEN_SPEOP_COMP(efdcmpgt); -GEN_SPEOP_COMP(efdcmplt); -GEN_SPEOP_COMP(efdcmpeq); -GEN_SPEOP_COMP(efdtstgt); -GEN_SPEOP_COMP(efdtstlt); -GEN_SPEOP_COMP(efdtsteq); +GEN_SPEFPUOP_COMP(efdcmpgt); +GEN_SPEFPUOP_COMP(efdcmplt); +GEN_SPEFPUOP_COMP(efdcmpeq); +GEN_SPEFPUOP_COMP(efdtstgt); +GEN_SPEFPUOP_COMP(efdtstlt); +GEN_SPEFPUOP_COMP(efdtsteq); /* Opcodes definitions */ GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, PPC_SPEFPU); // @@ -6062,7 +7073,7 @@ int i; cpu_fprintf(f, "NIP " ADDRX " LR " ADDRX " CTR " ADDRX " XER %08x\n", - env->nip, env->lr, env->ctr, hreg_load_xer(env)); + env->nip, env->lr, env->ctr, env->xer); cpu_fprintf(f, "MSR " ADDRX " HID0 " ADDRX " HF " ADDRX " idx %d\n", env->msr, env->spr[SPR_HID0], env->hflags, env->mmu_idx); #if !defined(NO_TIMER_DUMP) @@ -6163,26 +7174,24 @@ } /*****************************************************************************/ -static always_inline int gen_intermediate_code_internal (CPUState *env, - TranslationBlock *tb, - int search_pc) +static always_inline void gen_intermediate_code_internal (CPUState *env, + TranslationBlock *tb, + int search_pc) { DisasContext ctx, *ctxp = &ctx; opc_handler_t **table, *handler; target_ulong pc_start; uint16_t *gen_opc_end; int supervisor, little_endian; - int single_step, branch_step; int j, lj = -1; + int num_insns; + int max_insns; pc_start = tb->pc; - gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; - gen_opparam_ptr = gen_opparam_buf; #if defined(OPTIMIZE_FPRF_UPDATE) gen_fprf_ptr = gen_fprf_buf; #endif - nb_gen_labels = 0; ctx.nip = pc_start; ctx.tb = tb; ctx.exception = POWERPC_EXCP_NONE; @@ -6209,18 +7218,23 @@ else ctx.altivec_enabled = 0; if ((env->flags & POWERPC_FLAG_SE) && msr_se) - single_step = 1; + ctx.singlestep_enabled = CPU_SINGLE_STEP; else - single_step = 0; + ctx.singlestep_enabled = 0; if ((env->flags & POWERPC_FLAG_BE) && msr_be) - branch_step = 1; - else - branch_step = 0; - ctx.singlestep_enabled = env->singlestep_enabled || single_step == 1; + ctx.singlestep_enabled |= CPU_BRANCH_STEP; + if (unlikely(env->singlestep_enabled)) + ctx.singlestep_enabled |= GDBSTUB_SINGLE_STEP; #if defined (DO_SINGLE_STEP) && 0 /* Single step trace mode */ msr_se = 1; #endif + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + if (max_insns == 0) + max_insns = CF_COUNT_MASK; + + gen_icount_start(); /* Set env in case of segfault during code fetch */ while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) { if (unlikely(env->nb_breakpoints > 0)) { @@ -6240,6 +7254,7 @@ gen_opc_instr_start[lj++] = 0; gen_opc_pc[lj] = ctx.nip; gen_opc_instr_start[lj] = 1; + gen_opc_icount[lj] = num_insns; } } #if defined PPC_DEBUG_DISAS @@ -6249,6 +7264,8 @@ ctx.nip, supervisor, (int)msr_ir); } #endif + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) + gen_io_start(); if (unlikely(little_endian)) { ctx.opcode = bswap32(ldl_code(ctx.nip)); } else { @@ -6263,6 +7280,7 @@ #endif ctx.nip += 4; table = env->opcodes; + num_insns++; handler = table[opc1(ctx.opcode)]; if (is_indirect_opcode(handler)) { table = ind_table(handler); @@ -6309,17 +7327,15 @@ handler->count++; #endif /* Check trace mode exceptions */ - if (unlikely(branch_step != 0 && - ctx.exception == POWERPC_EXCP_BRANCH)) { - GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0); - } else if (unlikely(single_step != 0 && - (ctx.nip <= 0x100 || ctx.nip > 0xF00 || - (ctx.nip & 0xFC) != 0x04) && - ctx.exception != POWERPC_SYSCALL && - ctx.exception != POWERPC_EXCP_TRAP)) { + if (unlikely(ctx.singlestep_enabled & CPU_SINGLE_STEP && + (ctx.nip <= 0x100 || ctx.nip > 0xF00) && + ctx.exception != POWERPC_SYSCALL && + ctx.exception != POWERPC_EXCP_TRAP && + ctx.exception != POWERPC_EXCP_BRANCH)) { GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0); } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) || - (env->singlestep_enabled))) { + (env->singlestep_enabled) || + num_insns >= max_insns)) { /* if we reach a page boundary or are single stepping, stop * generation */ @@ -6329,13 +7345,19 @@ break; #endif } + if (tb->cflags & CF_LAST_IO) + gen_io_end(); if (ctx.exception == POWERPC_EXCP_NONE) { gen_goto_tb(&ctx, 0, ctx.nip); } else if (ctx.exception != POWERPC_EXCP_BRANCH) { - gen_op_reset_T0(); + if (unlikely(env->singlestep_enabled)) { + gen_update_nip(&ctx, ctx.nip); + gen_op_debug(); + } /* Generate the return instruction */ - gen_op_exit_tb(); + tcg_gen_exit_tb(0); } + gen_icount_end(tb, num_insns); *gen_opc_ptr = INDEX_op_end; if (unlikely(search_pc)) { j = gen_opc_ptr - gen_opc_buf; @@ -6344,6 +7366,7 @@ gen_opc_instr_start[lj++] = 0; } else { tb->size = ctx.nip - pc_start; + tb->icount = num_insns; } #if defined(DEBUG_DISAS) if (loglevel & CPU_LOG_TB_CPU) { @@ -6358,21 +7381,57 @@ target_disas(logfile, pc_start, ctx.nip - pc_start, flags); fprintf(logfile, "\n"); } - if (loglevel & CPU_LOG_TB_OP) { - fprintf(logfile, "OP:\n"); - dump_ops(gen_opc_buf, gen_opparam_buf); - fprintf(logfile, "\n"); - } #endif - return 0; } -int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) +void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) +{ + gen_intermediate_code_internal(env, tb, 0); +} + +void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) { - return gen_intermediate_code_internal(env, tb, 0); + gen_intermediate_code_internal(env, tb, 1); } -int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) +void gen_pc_load(CPUState *env, TranslationBlock *tb, + unsigned long searched_pc, int pc_pos, void *puc) { - return gen_intermediate_code_internal(env, tb, 1); + int type, c; + /* for PPC, we need to look at the micro operation to get the + * access type */ + env->nip = gen_opc_pc[pc_pos]; + c = gen_opc_buf[pc_pos]; + switch(c) { +#if defined(CONFIG_USER_ONLY) +#define CASE3(op)\ + case INDEX_op_ ## op ## _raw +#else +#define CASE3(op)\ + case INDEX_op_ ## op ## _user:\ + case INDEX_op_ ## op ## _kernel:\ + case INDEX_op_ ## op ## _hypv +#endif + + CASE3(stfd): + CASE3(stfs): + CASE3(lfd): + CASE3(lfs): + type = ACCESS_FLOAT; + break; + CASE3(lwarx): + type = ACCESS_RES; + break; + CASE3(stwcx): + type = ACCESS_RES; + break; + CASE3(eciwx): + CASE3(ecowx): + type = ACCESS_EXT; + break; + default: + type = ACCESS_INT; + break; + } + env->access_type = type; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-ppc/translate_init.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-ppc/translate_init.c --- qemu-0.9.1/target-ppc/translate_init.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-ppc/translate_init.c 2008-10-21 12:28:46.000000000 +0100 @@ -34,7 +34,7 @@ #endif struct ppc_def_t { - const unsigned char *name; + const char *name; uint32_t pvr; uint32_t svr; uint64_t insns_flags; @@ -99,34 +99,34 @@ /* XER */ static void spr_read_xer (void *opaque, int sprn) { - gen_op_load_xer(); + tcg_gen_mov_tl(cpu_T[0], cpu_xer); } static void spr_write_xer (void *opaque, int sprn) { - gen_op_store_xer(); + tcg_gen_mov_tl(cpu_xer, cpu_T[0]); } /* LR */ static void spr_read_lr (void *opaque, int sprn) { - gen_op_load_lr(); + tcg_gen_mov_tl(cpu_T[0], cpu_lr); } static void spr_write_lr (void *opaque, int sprn) { - gen_op_store_lr(); + tcg_gen_mov_tl(cpu_lr, cpu_T[0]); } /* CTR */ static void spr_read_ctr (void *opaque, int sprn) { - gen_op_load_ctr(); + tcg_gen_mov_tl(cpu_T[0], cpu_ctr); } static void spr_write_ctr (void *opaque, int sprn) { - gen_op_store_ctr(); + tcg_gen_mov_tl(cpu_ctr, cpu_T[0]); } /* User read access to SPR */ @@ -433,13 +433,13 @@ _spr_register(env, num, name, uea_read, uea_write, initial_value); \ } while (0) static inline void _spr_register (CPUPPCState *env, int num, - const unsigned char *name, + const char *name, void (*uea_read)(void *opaque, int sprn), void (*uea_write)(void *opaque, int sprn), target_ulong initial_value) #else static inline void spr_register (CPUPPCState *env, int num, - const unsigned char *name, + const char *name, void (*uea_read)(void *opaque, int sprn), void (*uea_write)(void *opaque, int sprn), void (*oea_read)(void *opaque, int sprn), @@ -1245,7 +1245,7 @@ /* PowerPC BookE SPR */ static void gen_spr_BookE (CPUPPCState *env, uint64_t ivor_mask) { - const unsigned char *ivor_names[64] = { + const char *ivor_names[64] = { "IVOR0", "IVOR1", "IVOR2", "IVOR3", "IVOR4", "IVOR5", "IVOR6", "IVOR7", "IVOR8", "IVOR9", "IVOR10", "IVOR11", @@ -1407,7 +1407,7 @@ static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask) { #if !defined(CONFIG_USER_ONLY) - const unsigned char *mas_names[8] = { + const char *mas_names[8] = { "MAS0", "MAS1", "MAS2", "MAS3", "MAS4", "MAS5", "MAS6", "MAS7", }; int mas_sprn[8] = { @@ -8941,8 +8941,6 @@ #include #include -int fflush (FILE *stream); - /* Opcode types */ enum { PPC_DIRECT = 0, /* Opcode routine */ @@ -9159,7 +9157,7 @@ static void dump_ppc_insns (CPUPPCState *env) { opc_handler_t **table, *handler; - const unsigned char *p, *q; + const char *p, *q; uint8_t opc1, opc2, opc3; printf("Instructions set:\n"); @@ -9242,7 +9240,7 @@ init_ppc_proc(env, def); #if defined(PPC_DUMP_CPU) { - const unsigned char *mmu_model, *excp_model, *bus_model; + const char *mmu_model, *excp_model, *bus_model; switch (env->mmu_model) { case POWERPC_MMU_32B: mmu_model = "PowerPC 32"; @@ -9445,10 +9443,10 @@ #include -const ppc_def_t *cpu_ppc_find_by_name (const unsigned char *name) +const ppc_def_t *cpu_ppc_find_by_name (const char *name) { const ppc_def_t *ret; - const unsigned char *p; + const char *p; int i, max, len; /* Check if the given name is a PVR */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sh4/cpu.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sh4/cpu.h --- qemu-0.9.1/target-sh4/cpu.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-sh4/cpu.h 2008-09-15 08:43:43.000000000 +0100 @@ -27,6 +27,15 @@ #define ELF_MACHINE EM_SH +/* CPU Subtypes */ +#define SH_CPU_SH7750 (1 << 0) +#define SH_CPU_SH7750S (1 << 1) +#define SH_CPU_SH7750R (1 << 2) +#define SH_CPU_SH7751 (1 << 3) +#define SH_CPU_SH7751R (1 << 4) +#define SH_CPU_SH7750_ALL (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7750R) +#define SH_CPU_SH7751_ALL (SH_CPU_SH7751 | SH_CPU_SH7751R) + #include "cpu-defs.h" #include "softfloat.h" @@ -80,6 +89,8 @@ #define NB_MMU_MODES 2 typedef struct CPUSH4State { + int id; /* CPU model */ + uint32_t flags; /* general execution flags */ uint32_t gregs[24]; /* general registers */ float32 fregs[32]; /* floating point registers */ @@ -98,9 +109,7 @@ uint32_t fpscr; /* floating point status/control register */ uint32_t fpul; /* floating point communication register */ - /* temporary float registers */ - float32 ft0, ft1; - float64 dt0, dt1; + /* float point status register */ float_status fp_status; /* Those belong to the specific unit (SH7750) but are handled here */ @@ -114,20 +123,28 @@ uint32_t expevt; /* exception event register */ uint32_t intevt; /* interrupt event register */ - jmp_buf jmp_env; - int user_mode_only; - int interrupt_request; - int halted; - int exception_index; + uint32_t pvr; /* Processor Version Register */ + uint32_t prr; /* Processor Revision Register */ + uint32_t cvr; /* Cache Version Register */ + CPU_COMMON tlb_t utlb[UTLB_SIZE]; /* unified translation table */ tlb_t itlb[ITLB_SIZE]; /* instruction translation table */ void *intc_handle; + int intr_at_halt; /* SR_BL ignored during sleep */ } CPUSH4State; CPUSH4State *cpu_sh4_init(const char *cpu_model); int cpu_sh4_exec(CPUSH4State * s); int cpu_sh4_signal_handler(int host_signum, void *pinfo, void *puc); +void sh4_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr, + uint32_t mem_value); + +static inline void cpu_set_tls(CPUSH4State *env, target_ulong newtls) +{ + env->gbr = newtls; +} #include "softfloat.h" @@ -136,6 +153,7 @@ #define cpu_exec cpu_sh4_exec #define cpu_gen_code cpu_sh4_gen_code #define cpu_signal_handler cpu_sh4_signal_handler +#define cpu_list sh4_cpu_list /* MMU modes definitions */ #define MMU_MODE0_SUFFIX _kernel @@ -146,6 +164,20 @@ return (env->sr & SR_MD) == 0 ? 1 : 0; } +#if defined(CONFIG_USER_ONLY) +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) +{ + if (newsp) + env->gregs[15] = newsp; + env->gregs[0] = 0; +} +#endif + +#define CPU_PC_FROM_TB(env, tb) do { \ + env->pc = tb->pc; \ + env->flags = tb->flags; \ + } while (0) + #include "cpu-all.h" /* Memory access type */ @@ -163,5 +195,78 @@ #define MMUCR 0x1F000010 #define MMUCR_AT (1<<0) #define MMUCR_SV (1<<8) +#define MMUCR_URC_BITS (6) +#define MMUCR_URC_OFFSET (10) +#define MMUCR_URC_SIZE (1 << MMUCR_URC_BITS) +#define MMUCR_URC_MASK (((MMUCR_URC_SIZE) - 1) << MMUCR_URC_OFFSET) +static inline int cpu_mmucr_urc (uint32_t mmucr) +{ + return ((mmucr & MMUCR_URC_MASK) >> MMUCR_URC_OFFSET); +} + +/* PTEH : Page Translation Entry High register */ +#define PTEH_ASID_BITS (8) +#define PTEH_ASID_SIZE (1 << PTEH_ASID_BITS) +#define PTEH_ASID_MASK (PTEH_ASID_SIZE - 1) +#define cpu_pteh_asid(pteh) ((pteh) & PTEH_ASID_MASK) +#define PTEH_VPN_BITS (22) +#define PTEH_VPN_OFFSET (10) +#define PTEH_VPN_SIZE (1 << PTEH_VPN_BITS) +#define PTEH_VPN_MASK (((PTEH_VPN_SIZE) - 1) << PTEH_VPN_OFFSET) +static inline int cpu_pteh_vpn (uint32_t pteh) +{ + return ((pteh & PTEH_VPN_MASK) >> PTEH_VPN_OFFSET); +} + +/* PTEL : Page Translation Entry Low register */ +#define PTEL_V (1 << 8) +#define cpu_ptel_v(ptel) (((ptel) & PTEL_V) >> 8) +#define PTEL_C (1 << 3) +#define cpu_ptel_c(ptel) (((ptel) & PTEL_C) >> 3) +#define PTEL_D (1 << 2) +#define cpu_ptel_d(ptel) (((ptel) & PTEL_D) >> 2) +#define PTEL_SH (1 << 1) +#define cpu_ptel_sh(ptel)(((ptel) & PTEL_SH) >> 1) +#define PTEL_WT (1 << 0) +#define cpu_ptel_wt(ptel) ((ptel) & PTEL_WT) + +#define PTEL_SZ_HIGH_OFFSET (7) +#define PTEL_SZ_HIGH (1 << PTEL_SZ_HIGH_OFFSET) +#define PTEL_SZ_LOW_OFFSET (4) +#define PTEL_SZ_LOW (1 << PTEL_SZ_LOW_OFFSET) +static inline int cpu_ptel_sz (uint32_t ptel) +{ + int sz; + sz = (ptel & PTEL_SZ_HIGH) >> PTEL_SZ_HIGH_OFFSET; + sz <<= 1; + sz |= (ptel & PTEL_SZ_LOW) >> PTEL_SZ_LOW_OFFSET; + return sz; +} + +#define PTEL_PPN_BITS (19) +#define PTEL_PPN_OFFSET (10) +#define PTEL_PPN_SIZE (1 << PTEL_PPN_BITS) +#define PTEL_PPN_MASK (((PTEL_PPN_SIZE) - 1) << PTEL_PPN_OFFSET) +static inline int cpu_ptel_ppn (uint32_t ptel) +{ + return ((ptel & PTEL_PPN_MASK) >> PTEL_PPN_OFFSET); +} + +#define PTEL_PR_BITS (2) +#define PTEL_PR_OFFSET (5) +#define PTEL_PR_SIZE (1 << PTEL_PR_BITS) +#define PTEL_PR_MASK (((PTEL_PR_SIZE) - 1) << PTEL_PR_OFFSET) +static inline int cpu_ptel_pr (uint32_t ptel) +{ + return ((ptel & PTEL_PR_MASK) >> PTEL_PR_OFFSET); +} + +/* PTEA : Page Translation Entry Assistance register */ +#define PTEA_SA_BITS (3) +#define PTEA_SA_SIZE (1 << PTEA_SA_BITS) +#define PTEA_SA_MASK (PTEA_SA_SIZE - 1) +#define cpu_ptea_sa(ptea) ((ptea) & PTEA_SA_MASK) +#define PTEA_TC (1 << 3) +#define cpu_ptea_tc(ptea) (((ptea) & PTEA_TC) >> 3) #endif /* _CPU_SH4_H */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sh4/exec.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sh4/exec.h --- qemu-0.9.1/target-sh4/exec.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-sh4/exec.h 2008-09-01 23:12:14.000000000 +0100 @@ -24,14 +24,6 @@ #include "dyngen-exec.h" register struct CPUSH4State *env asm(AREG0); -register uint32_t T0 asm(AREG1); -register uint32_t T1 asm(AREG2); -//register uint32_t T2 asm(AREG3); - -#define FT0 (env->ft0) -#define FT1 (env->ft1) -#define DT0 (env->dt0) -#define DT1 (env->dt1) #include "cpu.h" #include "exec-all.h" @@ -41,6 +33,7 @@ return 0; if (env->interrupt_request & CPU_INTERRUPT_HARD) { env->halted = 0; + env->intr_at_halt = 1; return 0; } return EXCP_HALTED; @@ -64,27 +57,14 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, int mmu_idx, int is_softmmu); +void cpu_load_tlb(CPUState * env); int find_itlb_entry(CPUState * env, target_ulong address, int use_asid, int update); int find_utlb_entry(CPUState * env, target_ulong address, int use_asid); -void helper_addc_T0_T1(void); -void helper_addv_T0_T1(void); -void helper_div1_T0_T1(void); -void helper_dmulsl_T0_T1(void); -void helper_dmulul_T0_T1(void); -void helper_macl_T0_T1(void); -void helper_macw_T0_T1(void); -void helper_negc_T0(void); -void helper_subc_T0_T1(void); -void helper_subv_T0_T1(void); -void helper_rotcl(uint32_t * addr); -void helper_rotcr(uint32_t * addr); - void do_interrupt(CPUState * env); void cpu_loop_exit(void); -void do_raise_exception(void); #endif /* _EXEC_SH4_H */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sh4/helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sh4/helper.c --- qemu-0.9.1/target-sh4/helper.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-sh4/helper.c 2008-08-22 09:57:52.000000000 +0100 @@ -87,9 +87,10 @@ if (do_exp && env->exception_index != 0x1e0) { env->exception_index = 0x000; /* masked exception -> reset */ } - if (do_irq) { + if (do_irq && !env->intr_at_halt) { return; /* masked */ } + env->intr_at_halt = 0; } if (do_irq) { @@ -156,6 +157,15 @@ env->sgr = env->gregs[15]; env->sr |= SR_BL | SR_MD | SR_RB; + if (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { + /* Branch instruction should be executed again before delay slot. */ + env->spc -= 2; + /* Clear flags for exception/interrupt routine. */ + env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL | DELAY_SLOT_TRUE); + } + if (env->flags & DELAY_SLOT_CLEARME) + env->flags = 0; + if (do_exp) { env->expevt = env->exception_index; switch (env->exception_index) { @@ -193,7 +203,7 @@ switch (itlbnb) { case 0: - and_mask = 0x7f; + and_mask = 0x1f; break; case 1: and_mask = 0xe7; @@ -208,7 +218,7 @@ break; } - env->mmucr &= (and_mask << 24); + env->mmucr &= (and_mask << 24) | 0x00ffffff; env->mmucr |= (or_mask << 24); } @@ -216,7 +226,7 @@ { if ((env->mmucr & 0xe0000000) == 0xe0000000) return 0; - if ((env->mmucr & 0x98000000) == 0x08000000) + if ((env->mmucr & 0x98000000) == 0x18000000) return 1; if ((env->mmucr & 0x54000000) == 0x04000000) return 2; @@ -241,7 +251,7 @@ for (i = 0; i < nbtlb; i++) { if (!entries[i].v) continue; /* Invalid entry */ - if (use_asid && entries[i].asid != asid && !entries[i].sh) + if (use_asid && entries[i].asid != asid) continue; /* Bad ASID */ #if 0 switch (entries[i].sz) { @@ -264,7 +274,7 @@ start = (entries[i].vpn << 10) & ~(entries[i].size - 1); end = start + entries[i].size - 1; if (address >= start && address <= end) { /* Match */ - if (match != -1) + if (match != MMU_DTLB_MISS) return MMU_DTLB_MULTIPLE; /* Multiple match */ match = i; } @@ -272,6 +282,29 @@ return match; } +static int same_tlb_entry_exists(const tlb_t * haystack, uint8_t nbtlb, + const tlb_t * needle) +{ + int i; + for (i = 0; i < nbtlb; i++) + if (!memcmp(&haystack[i], needle, sizeof(tlb_t))) + return 1; + return 0; +} + +static void increment_urc(CPUState * env) +{ + uint8_t urb, urc; + + /* Increment URC */ + urb = ((env->mmucr) >> 18) & 0x3f; + urc = ((env->mmucr) >> 10) & 0x3f; + urc++; + if (urc == urb || urc == UTLB_SIZE - 1) + urc = 0; + env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10); +} + /* Find itlb entry - update itlb from utlb if necessary and asked for Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE Update the itlb from utlb if update is not 0 @@ -287,11 +320,19 @@ else if (e == MMU_DTLB_MISS && update) { e = find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid); if (e >= 0) { + tlb_t * ientry; n = itlb_replacement(env); - env->itlb[n] = env->utlb[e]; + ientry = &env->itlb[n]; + if (ientry->v) { + if (!same_tlb_entry_exists(env->utlb, UTLB_SIZE, ientry)) + tlb_flush_page(env, ientry->vpn << 10); + } + *ientry = env->utlb[e]; e = n; - } - } + } else if (e == MMU_DTLB_MISS) + e = MMU_ITLB_MISS; + } else if (e == MMU_DTLB_MISS) + e = MMU_ITLB_MISS; if (e >= 0) update_itlb_use(env, e); return e; @@ -301,15 +342,8 @@ Return entry, MMU_DTLB_MISS, MMU_DTLB_MULTIPLE */ int find_utlb_entry(CPUState * env, target_ulong address, int use_asid) { - uint8_t urb, urc; - - /* Increment URC */ - urb = ((env->mmucr) >> 18) & 0x3f; - urc = ((env->mmucr) >> 10) & 0x3f; - urc++; - if (urc == urb || urc == UTLB_SIZE - 1) - urc = 0; - env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10); + /* per utlb access */ + increment_urc(env); /* Return entry */ return find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid); @@ -328,7 +362,7 @@ int use_asid, is_code, n; tlb_t *matching = NULL; - use_asid = (env->mmucr & MMUCR_SV) == 0 && (env->sr & SR_MD) == 0; + use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0; is_code = env->pc == address; /* Hack */ /* Use a hack to find if this is an instruction or data access */ @@ -395,8 +429,21 @@ return (rw & PAGE_WRITE) ? MMU_DTLB_MISS_WRITE : MMU_DTLB_MISS_READ; } - /* Mask upper 3 bits */ - *physical = address & 0x1FFFFFFF; + if (address >= 0x80000000 && address < 0xc0000000) { + /* Mask upper 3 bits for P1 and P2 areas */ + *physical = address & 0x1fffffff; + } else if (address >= 0xfc000000) { + /* + * Mask upper 3 bits for control registers in P4 area, + * to unify access to control registers via P0-P3 area. + * The addresses for cache store queue, TLB address array + * are not masked. + */ + *physical = address & 0x1fffffff; + } else { + /* access to cache store queue, or TLB address array. */ + *physical = address; + } *prot = PAGE_READ | PAGE_WRITE; return MMU_OK; } @@ -418,6 +465,21 @@ target_ulong physical, page_offset, page_size; int prot, ret, access_type; + switch (rw) { + case 0: + rw = PAGE_READ; + break; + case 1: + rw = PAGE_WRITE; + break; + case 2: /* READ_ACCESS_TYPE == 2 defined in softmmu_template.h */ + rw = PAGE_READ; + break; + default: + /* fatal error */ + assert(0); + } + /* XXXXX */ #if 0 fprintf(stderr, "%s pc %08x ad %08x rw %d mmu_idx %d smmu %d\n", @@ -479,4 +541,123 @@ return physical; } +void cpu_load_tlb(CPUState * env) +{ + int n = cpu_mmucr_urc(env->mmucr); + tlb_t * entry = &env->utlb[n]; + + if (entry->v) { + /* Overwriting valid entry in utlb. */ + target_ulong address = entry->vpn << 10; + if (!same_tlb_entry_exists(env->itlb, ITLB_SIZE, entry)) { + tlb_flush_page(env, address); + } + } + + /* per utlb access cannot implemented. */ + increment_urc(env); + + /* Take values into cpu status from registers. */ + entry->asid = (uint8_t)cpu_pteh_asid(env->pteh); + entry->vpn = cpu_pteh_vpn(env->pteh); + entry->v = (uint8_t)cpu_ptel_v(env->ptel); + entry->ppn = cpu_ptel_ppn(env->ptel); + entry->sz = (uint8_t)cpu_ptel_sz(env->ptel); + switch (entry->sz) { + case 0: /* 00 */ + entry->size = 1024; /* 1K */ + break; + case 1: /* 01 */ + entry->size = 1024 * 4; /* 4K */ + break; + case 2: /* 10 */ + entry->size = 1024 * 64; /* 64K */ + break; + case 3: /* 11 */ + entry->size = 1024 * 1024; /* 1M */ + break; + default: + assert(0); + break; + } + entry->sh = (uint8_t)cpu_ptel_sh(env->ptel); + entry->c = (uint8_t)cpu_ptel_c(env->ptel); + entry->pr = (uint8_t)cpu_ptel_pr(env->ptel); + entry->d = (uint8_t)cpu_ptel_d(env->ptel); + entry->wt = (uint8_t)cpu_ptel_wt(env->ptel); + entry->sa = (uint8_t)cpu_ptea_sa(env->ptea); + entry->tc = (uint8_t)cpu_ptea_tc(env->ptea); +} + +void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr, + uint32_t mem_value) +{ + int associate = addr & 0x0000080; + uint32_t vpn = (mem_value & 0xfffffc00) >> 10; + uint8_t d = (uint8_t)((mem_value & 0x00000200) >> 9); + uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8); + uint8_t asid = (uint8_t)(mem_value & 0x000000ff); + + if (associate) { + int i; + tlb_t * utlb_match_entry = NULL; + int needs_tlb_flush = 0; + + /* search UTLB */ + for (i = 0; i < UTLB_SIZE; i++) { + tlb_t * entry = &s->utlb[i]; + if (!entry->v) + continue; + + if (entry->vpn == vpn && entry->asid == asid) { + if (utlb_match_entry) { + /* Multiple TLB Exception */ + s->exception_index = 0x140; + s->tea = addr; + break; + } + if (entry->v && !v) + needs_tlb_flush = 1; + entry->v = v; + entry->d = d; + utlb_match_entry = entry; + } + increment_urc(s); /* per utlb access */ + } + + /* search ITLB */ + for (i = 0; i < ITLB_SIZE; i++) { + tlb_t * entry = &s->itlb[i]; + if (entry->vpn == vpn && entry->asid == asid) { + if (entry->v && !v) + needs_tlb_flush = 1; + if (utlb_match_entry) + *entry = *utlb_match_entry; + else + entry->v = v; + break; + } + } + + if (needs_tlb_flush) + tlb_flush_page(s, vpn << 10); + + } else { + int index = (addr & 0x00003f00) >> 8; + tlb_t * entry = &s->utlb[index]; + if (entry->v) { + /* Overwriting valid entry in utlb. */ + target_ulong address = entry->vpn << 10; + if (!same_tlb_entry_exists(s->itlb, ITLB_SIZE, entry)) { + tlb_flush_page(s, address); + } + } + entry->asid = asid; + entry->vpn = vpn; + entry->d = d; + entry->v = v; + increment_urc(s); + } +} + #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sh4/helper.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sh4/helper.h --- qemu-0.9.1/target-sh4/helper.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-sh4/helper.h 2008-09-15 07:42:30.000000000 +0100 @@ -0,0 +1,46 @@ +#ifndef DEF_HELPER +#define DEF_HELPER(ret, name, params) ret name params; +#endif + +DEF_HELPER(void, helper_ldtlb, (void)) +DEF_HELPER(void, helper_raise_illegal_instruction, (void)) +DEF_HELPER(void, helper_raise_slot_illegal_instruction, (void)) +DEF_HELPER(void, helper_debug, (void)) +DEF_HELPER(void, helper_sleep, (uint32_t)) +DEF_HELPER(void, helper_trapa, (uint32_t)) + +DEF_HELPER(uint32_t, helper_addv, (uint32_t, uint32_t)) +DEF_HELPER(uint32_t, helper_addc, (uint32_t, uint32_t)) +DEF_HELPER(uint32_t, helper_subv, (uint32_t, uint32_t)) +DEF_HELPER(uint32_t, helper_subc, (uint32_t, uint32_t)) +DEF_HELPER(uint32_t, helper_negc, (uint32_t)) +DEF_HELPER(uint32_t, helper_div1, (uint32_t, uint32_t)) +DEF_HELPER(void, helper_macl, (uint32_t, uint32_t)) +DEF_HELPER(void, helper_macw, (uint32_t, uint32_t)) + +DEF_HELPER(void, helper_ld_fpscr, (uint32_t)) + +DEF_HELPER(uint32_t, helper_fabs_FT, (uint32_t)) +DEF_HELPER(uint64_t, helper_fabs_DT, (uint64_t)) +DEF_HELPER(uint32_t, helper_fadd_FT, (uint32_t, uint32_t)) +DEF_HELPER(uint64_t, helper_fadd_DT, (uint64_t, uint64_t)) +DEF_HELPER(uint64_t, helper_fcnvsd_FT_DT, (uint32_t)) +DEF_HELPER(uint32_t, helper_fcnvds_DT_FT, (uint64_t)) + +DEF_HELPER(void, helper_fcmp_eq_FT, (uint32_t, uint32_t)) +DEF_HELPER(void, helper_fcmp_eq_DT, (uint64_t, uint64_t)) +DEF_HELPER(void, helper_fcmp_gt_FT, (uint32_t, uint32_t)) +DEF_HELPER(void, helper_fcmp_gt_DT, (uint64_t, uint64_t)) +DEF_HELPER(uint32_t, helper_fdiv_FT, (uint32_t, uint32_t)) +DEF_HELPER(uint64_t, helper_fdiv_DT, (uint64_t, uint64_t)) +DEF_HELPER(uint32_t, helper_float_FT, (uint32_t)) +DEF_HELPER(uint64_t, helper_float_DT, (uint32_t)) +DEF_HELPER(uint32_t, helper_fmul_FT, (uint32_t, uint32_t)) +DEF_HELPER(uint64_t, helper_fmul_DT, (uint64_t, uint64_t)) +DEF_HELPER(uint32_t, helper_fneg_T, (uint32_t)) +DEF_HELPER(uint32_t, helper_fsub_FT, (uint32_t, uint32_t)) +DEF_HELPER(uint64_t, helper_fsub_DT, (uint64_t, uint64_t)) +DEF_HELPER(uint32_t, helper_fsqrt_FT, (uint32_t)) +DEF_HELPER(uint64_t, helper_fsqrt_DT, (uint64_t)) +DEF_HELPER(uint32_t, helper_ftrc_FT, (uint32_t)) +DEF_HELPER(uint32_t, helper_ftrc_DT, (uint64_t)) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sh4/machine.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sh4/machine.c --- qemu-0.9.1/target-sh4/machine.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-sh4/machine.c 2008-05-04 14:11:44.000000000 +0100 @@ -0,0 +1,8 @@ +#include "hw/hw.h" +#include "hw/boards.h" + +void register_machines(void) +{ + qemu_register_machine(&shix_machine); + qemu_register_machine(&r2d_machine); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sh4/op.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sh4/op.c --- qemu-0.9.1/target-sh4/op.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-sh4/op.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,1052 +0,0 @@ -/* - * SH4 emulation - * - * Copyright (c) 2005 Samuel Tardieu - * - * 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 "exec.h" - -static inline void set_t(void) -{ - env->sr |= SR_T; -} - -static inline void clr_t(void) -{ - env->sr &= ~SR_T; -} - -static inline void cond_t(int cond) -{ - if (cond) - set_t(); - else - clr_t(); -} - -void OPPROTO op_movl_imm_T0(void) -{ - T0 = (uint32_t) PARAM1; - RETURN(); -} - -void OPPROTO op_movl_imm_T1(void) -{ - T0 = (uint32_t) PARAM1; - RETURN(); -} - -void OPPROTO op_movl_imm_T2(void) -{ - T0 = (uint32_t) PARAM1; - RETURN(); -} - -void OPPROTO op_cmp_eq_imm_T0(void) -{ - cond_t((int32_t) T0 == (int32_t) PARAM1); - RETURN(); -} - -void OPPROTO op_cmd_eq_T0_T1(void) -{ - cond_t(T0 == T1); - RETURN(); -} - -void OPPROTO op_cmd_hs_T0_T1(void) -{ - cond_t((uint32_t) T0 <= (uint32_t) T1); - RETURN(); -} - -void OPPROTO op_cmd_ge_T0_T1(void) -{ - cond_t((int32_t) T0 <= (int32_t) T1); - RETURN(); -} - -void OPPROTO op_cmd_hi_T0_T1(void) -{ - cond_t((uint32_t) T0 < (uint32_t) T1); - RETURN(); -} - -void OPPROTO op_cmd_gt_T0_T1(void) -{ - cond_t((int32_t) T0 < (int32_t) T1); - RETURN(); -} - -void OPPROTO op_not_T0(void) -{ - T0 = ~T0; - RETURN(); -} - -void OPPROTO op_bf_s(void) -{ - env->delayed_pc = PARAM1; - if (!(env->sr & SR_T)) { - env->flags |= DELAY_SLOT_TRUE; - } - RETURN(); -} - -void OPPROTO op_bt_s(void) -{ - env->delayed_pc = PARAM1; - if (env->sr & SR_T) { - env->flags |= DELAY_SLOT_TRUE; - } - RETURN(); -} - -void OPPROTO op_store_flags(void) -{ - env->flags &= DELAY_SLOT_TRUE; - env->flags |= PARAM1; - RETURN(); -} - -void OPPROTO op_bra(void) -{ - env->delayed_pc = PARAM1; - RETURN(); -} - -void OPPROTO op_braf_T0(void) -{ - env->delayed_pc = PARAM1 + T0; - RETURN(); -} - -void OPPROTO op_bsr(void) -{ - env->pr = PARAM1; - env->delayed_pc = PARAM2; - RETURN(); -} - -void OPPROTO op_bsrf_T0(void) -{ - env->pr = PARAM1; - env->delayed_pc = PARAM1 + T0; - RETURN(); -} - -void OPPROTO op_jsr_T0(void) -{ - env->pr = PARAM1; - env->delayed_pc = T0; - RETURN(); -} - -void OPPROTO op_rts(void) -{ - env->delayed_pc = env->pr; - RETURN(); -} - -void OPPROTO op_exit_tb(void) -{ - EXIT_TB(); - RETURN(); -} - -void OPPROTO op_addl_imm_T0(void) -{ - T0 += PARAM1; - RETURN(); -} - -void OPPROTO op_addl_imm_T1(void) -{ - T1 += PARAM1; - RETURN(); -} - -void OPPROTO op_clrmac(void) -{ - env->mach = env->macl = 0; - RETURN(); -} - -void OPPROTO op_clrs(void) -{ - env->sr &= ~SR_S; - RETURN(); -} - -void OPPROTO op_clrt(void) -{ - env->sr &= ~SR_T; - RETURN(); -} - -void OPPROTO op_sets(void) -{ - env->sr |= SR_S; - RETURN(); -} - -void OPPROTO op_sett(void) -{ - env->sr |= SR_T; - RETURN(); -} - -void OPPROTO op_frchg(void) -{ - env->fpscr ^= FPSCR_FR; - RETURN(); -} - -void OPPROTO op_fschg(void) -{ - env->fpscr ^= FPSCR_SZ; - RETURN(); -} - -void OPPROTO op_rte(void) -{ - env->sr = env->ssr; - env->delayed_pc = env->spc; - RETURN(); -} - -void OPPROTO op_swapb_T0(void) -{ - T0 = (T0 & 0xffff0000) | ((T0 & 0xff) << 8) | ((T0 >> 8) & 0xff); - RETURN(); -} - -void OPPROTO op_swapw_T0(void) -{ - T0 = ((T0 & 0xffff) << 16) | ((T0 >> 16) & 0xffff); - RETURN(); -} - -void OPPROTO op_xtrct_T0_T1(void) -{ - T1 = ((T0 & 0xffff) << 16) | ((T1 >> 16) & 0xffff); - RETURN(); -} - -void OPPROTO op_addc_T0_T1(void) -{ - helper_addc_T0_T1(); - RETURN(); -} - -void OPPROTO op_addv_T0_T1(void) -{ - helper_addv_T0_T1(); - RETURN(); -} - -void OPPROTO op_cmp_eq_T0_T1(void) -{ - cond_t(T1 == T0); - RETURN(); -} - -void OPPROTO op_cmp_ge_T0_T1(void) -{ - cond_t((int32_t) T1 >= (int32_t) T0); - RETURN(); -} - -void OPPROTO op_cmp_gt_T0_T1(void) -{ - cond_t((int32_t) T1 > (int32_t) T0); - RETURN(); -} - -void OPPROTO op_cmp_hi_T0_T1(void) -{ - cond_t((uint32_t) T1 > (uint32_t) T0); - RETURN(); -} - -void OPPROTO op_cmp_hs_T0_T1(void) -{ - cond_t((uint32_t) T1 >= (uint32_t) T0); - RETURN(); -} - -void OPPROTO op_cmp_str_T0_T1(void) -{ - cond_t((T0 & 0x000000ff) == (T1 & 0x000000ff) || - (T0 & 0x0000ff00) == (T1 & 0x0000ff00) || - (T0 & 0x00ff0000) == (T1 & 0x00ff0000) || - (T0 & 0xff000000) == (T1 & 0xff000000)); - RETURN(); -} - -void OPPROTO op_tst_T0_T1(void) -{ - cond_t((T1 & T0) == 0); - RETURN(); -} - -void OPPROTO op_div0s_T0_T1(void) -{ - if (T1 & 0x80000000) - env->sr |= SR_Q; - else - env->sr &= ~SR_Q; - if (T0 & 0x80000000) - env->sr |= SR_M; - else - env->sr &= ~SR_M; - cond_t((T1 ^ T0) & 0x80000000); - RETURN(); -} - -void OPPROTO op_div0u(void) -{ - env->sr &= ~(SR_M | SR_Q | SR_T); - RETURN(); -} - -void OPPROTO op_div1_T0_T1(void) -{ - helper_div1_T0_T1(); - RETURN(); -} - -void OPPROTO op_dmulsl_T0_T1(void) -{ - helper_dmulsl_T0_T1(); - RETURN(); -} - -void OPPROTO op_dmulul_T0_T1(void) -{ - helper_dmulul_T0_T1(); - RETURN(); -} - -void OPPROTO op_macl_T0_T1(void) -{ - helper_macl_T0_T1(); - RETURN(); -} - -void OPPROTO op_macw_T0_T1(void) -{ - helper_macw_T0_T1(); - RETURN(); -} - -void OPPROTO op_mull_T0_T1(void) -{ - env->macl = (T0 * T1) & 0xffffffff; - RETURN(); -} - -void OPPROTO op_mulsw_T0_T1(void) -{ - env->macl = (int32_t) T0 *(int32_t) T1; - RETURN(); -} - -void OPPROTO op_muluw_T0_T1(void) -{ - env->macl = (uint32_t) T0 *(uint32_t) T1; - RETURN(); -} - -void OPPROTO op_neg_T0(void) -{ - T0 = -T0; - RETURN(); -} - -void OPPROTO op_negc_T0(void) -{ - helper_negc_T0(); - RETURN(); -} - -void OPPROTO op_shad_T0_T1(void) -{ - if ((T0 & 0x80000000) == 0) - T1 <<= (T0 & 0x1f); - else if ((T0 & 0x1f) == 0) - T1 = 0; - else - T1 = ((int32_t) T1) >> ((~T0 & 0x1f) + 1); - RETURN(); -} - -void OPPROTO op_shld_T0_T1(void) -{ - if ((T0 & 0x80000000) == 0) - T1 <<= (T0 & 0x1f); - else if ((T0 & 0x1f) == 0) - T1 = 0; - else - T1 = ((uint32_t) T1) >> ((~T0 & 0x1f) + 1); - RETURN(); -} - -void OPPROTO op_subc_T0_T1(void) -{ - helper_subc_T0_T1(); - RETURN(); -} - -void OPPROTO op_subv_T0_T1(void) -{ - helper_subv_T0_T1(); - RETURN(); -} - -void OPPROTO op_trapa(void) -{ - env->tra = PARAM1 << 2; - env->exception_index = 0x160; - do_raise_exception(); - RETURN(); -} - -void OPPROTO op_cmp_pl_T0(void) -{ - cond_t((int32_t) T0 > 0); - RETURN(); -} - -void OPPROTO op_cmp_pz_T0(void) -{ - cond_t((int32_t) T0 >= 0); - RETURN(); -} - -void OPPROTO op_jmp_T0(void) -{ - env->delayed_pc = T0; - RETURN(); -} - -void OPPROTO op_movl_rN_rN(void) -{ - env->gregs[PARAM2] = env->gregs[PARAM1]; - RETURN(); -} - -void OPPROTO op_ldcl_rMplus_rN_bank(void) -{ - env->gregs[PARAM2] = env->gregs[PARAM1]; - env->gregs[PARAM1] += 4; - RETURN(); -} - -void OPPROTO op_ldc_T0_sr(void) -{ - env->sr = T0 & 0x700083f3; - RETURN(); -} - -void OPPROTO op_stc_sr_T0(void) -{ - T0 = env->sr; - RETURN(); -} - -#define LDSTOPS(target,load,store) \ -void OPPROTO op_##load##_T0_##target (void) \ -{ env ->target = T0; RETURN(); \ -} \ -void OPPROTO op_##store##_##target##_T0 (void) \ -{ T0 = env->target; RETURN(); \ -} \ - - LDSTOPS(gbr, ldc, stc) - LDSTOPS(vbr, ldc, stc) - LDSTOPS(ssr, ldc, stc) - LDSTOPS(spc, ldc, stc) - LDSTOPS(sgr, ldc, stc) - LDSTOPS(dbr, ldc, stc) - LDSTOPS(mach, lds, sts) - LDSTOPS(macl, lds, sts) - LDSTOPS(pr, lds, sts) - LDSTOPS(fpul, lds, sts) - -void OPPROTO op_lds_T0_fpscr(void) -{ - env->fpscr = T0 & 0x003fffff; - env->fp_status.float_rounding_mode = T0 & 0x01 ? - float_round_to_zero : float_round_nearest_even; - - RETURN(); -} - -void OPPROTO op_sts_fpscr_T0(void) -{ - T0 = env->fpscr & 0x003fffff; - RETURN(); -} - -void OPPROTO op_movt_rN(void) -{ - env->gregs[PARAM1] = env->sr & SR_T; - RETURN(); -} - -void OPPROTO op_rotcl_Rn(void) -{ - helper_rotcl(&env->gregs[PARAM1]); - RETURN(); -} - -void OPPROTO op_rotcr_Rn(void) -{ - helper_rotcr(&env->gregs[PARAM1]); - RETURN(); -} - -void OPPROTO op_rotl_Rn(void) -{ - cond_t(env->gregs[PARAM1] & 0x80000000); - env->gregs[PARAM1] = (env->gregs[PARAM1] << 1) | (env->sr & SR_T); - RETURN(); -} - -void OPPROTO op_rotr_Rn(void) -{ - cond_t(env->gregs[PARAM1] & 1); - env->gregs[PARAM1] = (env->gregs[PARAM1] >> 1) | - ((env->sr & SR_T) ? 0x80000000 : 0); - RETURN(); -} - -void OPPROTO op_shal_Rn(void) -{ - cond_t(env->gregs[PARAM1] & 0x80000000); - env->gregs[PARAM1] <<= 1; - RETURN(); -} - -void OPPROTO op_shar_Rn(void) -{ - cond_t(env->gregs[PARAM1] & 1); - env->gregs[PARAM1] >>= 1; - RETURN(); -} - -void OPPROTO op_shlr_Rn(void) -{ - cond_t(env->gregs[PARAM1] & 1); - env->gregs[PARAM1] >>= 1; - RETURN(); -} - -void OPPROTO op_shll2_Rn(void) -{ - env->gregs[PARAM1] <<= 2; - RETURN(); -} - -void OPPROTO op_shll8_Rn(void) -{ - env->gregs[PARAM1] <<= 8; - RETURN(); -} - -void OPPROTO op_shll16_Rn(void) -{ - env->gregs[PARAM1] <<= 16; - RETURN(); -} - -void OPPROTO op_shlr2_Rn(void) -{ - env->gregs[PARAM1] >>= 2; - RETURN(); -} - -void OPPROTO op_shlr8_Rn(void) -{ - env->gregs[PARAM1] >>= 8; - RETURN(); -} - -void OPPROTO op_shlr16_Rn(void) -{ - env->gregs[PARAM1] >>= 16; - RETURN(); -} - -void OPPROTO op_tasb_rN(void) -{ - cond_t(*(int8_t *) env->gregs[PARAM1] == 0); - *(int8_t *) env->gregs[PARAM1] |= 0x80; - RETURN(); -} - -void OPPROTO op_movl_T0_rN(void) -{ - env->gregs[PARAM1] = T0; - RETURN(); -} - -void OPPROTO op_movl_T1_rN(void) -{ - env->gregs[PARAM1] = T1; - RETURN(); -} - -void OPPROTO op_movb_rN_T0(void) -{ - T0 = (int32_t) (int8_t) (env->gregs[PARAM1] & 0xff); - RETURN(); -} - -void OPPROTO op_movub_rN_T0(void) -{ - T0 = env->gregs[PARAM1] & 0xff; - RETURN(); -} - -void OPPROTO op_movw_rN_T0(void) -{ - T0 = (int32_t) (int16_t) (env->gregs[PARAM1] & 0xffff); - RETURN(); -} - -void OPPROTO op_movuw_rN_T0(void) -{ - T0 = env->gregs[PARAM1] & 0xffff; - RETURN(); -} - -void OPPROTO op_movl_rN_T0(void) -{ - T0 = env->gregs[PARAM1]; - RETURN(); -} - -void OPPROTO op_movb_rN_T1(void) -{ - T1 = (int32_t) (int8_t) (env->gregs[PARAM1] & 0xff); - RETURN(); -} - -void OPPROTO op_movub_rN_T1(void) -{ - T1 = env->gregs[PARAM1] & 0xff; - RETURN(); -} - -void OPPROTO op_movw_rN_T1(void) -{ - T1 = (int32_t) (int16_t) (env->gregs[PARAM1] & 0xffff); - RETURN(); -} - -void OPPROTO op_movuw_rN_T1(void) -{ - T1 = env->gregs[PARAM1] & 0xffff; - RETURN(); -} - -void OPPROTO op_movl_rN_T1(void) -{ - T1 = env->gregs[PARAM1]; - RETURN(); -} - -void OPPROTO op_movl_imm_rN(void) -{ - env->gregs[PARAM2] = PARAM1; - RETURN(); -} - -void OPPROTO op_fmov_frN_FT0(void) -{ - FT0 = env->fregs[PARAM1]; - RETURN(); -} - -void OPPROTO op_fmov_drN_DT0(void) -{ - CPU_DoubleU d; - - d.l.upper = *(uint32_t *)&env->fregs[PARAM1]; - d.l.lower = *(uint32_t *)&env->fregs[PARAM1 + 1]; - DT0 = d.d; - RETURN(); -} - -void OPPROTO op_fmov_frN_FT1(void) -{ - FT1 = env->fregs[PARAM1]; - RETURN(); -} - -void OPPROTO op_fmov_drN_DT1(void) -{ - CPU_DoubleU d; - - d.l.upper = *(uint32_t *)&env->fregs[PARAM1]; - d.l.lower = *(uint32_t *)&env->fregs[PARAM1 + 1]; - DT1 = d.d; - RETURN(); -} - -void OPPROTO op_fmov_FT0_frN(void) -{ - env->fregs[PARAM1] = FT0; - RETURN(); -} - -void OPPROTO op_fmov_DT0_drN(void) -{ - CPU_DoubleU d; - - d.d = DT0; - *(uint32_t *)&env->fregs[PARAM1] = d.l.upper; - *(uint32_t *)&env->fregs[PARAM1 + 1] = d.l.lower; - RETURN(); -} - -void OPPROTO op_fadd_FT(void) -{ - FT0 = float32_add(FT0, FT1, &env->fp_status); - RETURN(); -} - -void OPPROTO op_fadd_DT(void) -{ - DT0 = float64_add(DT0, DT1, &env->fp_status); - RETURN(); -} - -void OPPROTO op_fsub_FT(void) -{ - FT0 = float32_sub(FT0, FT1, &env->fp_status); - RETURN(); -} - -void OPPROTO op_fsub_DT(void) -{ - DT0 = float64_sub(DT0, DT1, &env->fp_status); - RETURN(); -} - -void OPPROTO op_fmul_FT(void) -{ - FT0 = float32_mul(FT0, FT1, &env->fp_status); - RETURN(); -} - -void OPPROTO op_fmul_DT(void) -{ - DT0 = float64_mul(DT0, DT1, &env->fp_status); - RETURN(); -} - -void OPPROTO op_fdiv_FT(void) -{ - FT0 = float32_div(FT0, FT1, &env->fp_status); - RETURN(); -} - -void OPPROTO op_fdiv_DT(void) -{ - DT0 = float64_div(DT0, DT1, &env->fp_status); - RETURN(); -} - -void OPPROTO op_float_FT(void) -{ - FT0 = int32_to_float32(env->fpul, &env->fp_status); - RETURN(); -} - -void OPPROTO op_float_DT(void) -{ - DT0 = int32_to_float64(env->fpul, &env->fp_status); - RETURN(); -} - -void OPPROTO op_ftrc_FT(void) -{ - env->fpul = float32_to_int32_round_to_zero(FT0, &env->fp_status); - RETURN(); -} - -void OPPROTO op_ftrc_DT(void) -{ - env->fpul = float64_to_int32_round_to_zero(DT0, &env->fp_status); - RETURN(); -} - -void OPPROTO op_fmov_T0_frN(void) -{ - *(unsigned int *)&env->fregs[PARAM1] = T0; - RETURN(); -} - -void OPPROTO op_dec1_rN(void) -{ - env->gregs[PARAM1] -= 1; - RETURN(); -} - -void OPPROTO op_dec2_rN(void) -{ - env->gregs[PARAM1] -= 2; - RETURN(); -} - -void OPPROTO op_dec4_rN(void) -{ - env->gregs[PARAM1] -= 4; - RETURN(); -} - -void OPPROTO op_dec8_rN(void) -{ - env->gregs[PARAM1] -= 8; - RETURN(); -} - -void OPPROTO op_inc1_rN(void) -{ - env->gregs[PARAM1] += 1; - RETURN(); -} - -void OPPROTO op_inc2_rN(void) -{ - env->gregs[PARAM1] += 2; - RETURN(); -} - -void OPPROTO op_inc4_rN(void) -{ - env->gregs[PARAM1] += 4; - RETURN(); -} - -void OPPROTO op_inc8_rN(void) -{ - env->gregs[PARAM1] += 8; - RETURN(); -} - -void OPPROTO op_add_T0_rN(void) -{ - env->gregs[PARAM1] += T0; - RETURN(); -} - -void OPPROTO op_sub_T0_rN(void) -{ - env->gregs[PARAM1] -= T0; - RETURN(); -} - -void OPPROTO op_and_T0_rN(void) -{ - env->gregs[PARAM1] &= T0; - RETURN(); -} - -void OPPROTO op_or_T0_rN(void) -{ - env->gregs[PARAM1] |= T0; - RETURN(); -} - -void OPPROTO op_xor_T0_rN(void) -{ - env->gregs[PARAM1] ^= T0; - RETURN(); -} - -void OPPROTO op_add_rN_T0(void) -{ - T0 += env->gregs[PARAM1]; - RETURN(); -} - -void OPPROTO op_add_rN_T1(void) -{ - T1 += env->gregs[PARAM1]; - RETURN(); -} - -void OPPROTO op_add_imm_rN(void) -{ - env->gregs[PARAM2] += PARAM1; - RETURN(); -} - -void OPPROTO op_and_imm_rN(void) -{ - env->gregs[PARAM2] &= PARAM1; - RETURN(); -} - -void OPPROTO op_or_imm_rN(void) -{ - env->gregs[PARAM2] |= PARAM1; - RETURN(); -} - -void OPPROTO op_xor_imm_rN(void) -{ - env->gregs[PARAM2] ^= PARAM1; - RETURN(); -} - -void OPPROTO op_dt_rN(void) -{ - cond_t((--env->gregs[PARAM1]) == 0); - RETURN(); -} - -void OPPROTO op_tst_imm_rN(void) -{ - cond_t((env->gregs[PARAM2] & PARAM1) == 0); - RETURN(); -} - -void OPPROTO op_movl_T0_T1(void) -{ - T1 = T0; - RETURN(); -} - -void OPPROTO op_movl_fpul_FT0(void) -{ - FT0 = *(float32 *)&env->fpul; - RETURN(); -} - -void OPPROTO op_movl_FT0_fpul(void) -{ - *(float32 *)&env->fpul = FT0; - RETURN(); -} - -void OPPROTO op_goto_tb0(void) -{ - GOTO_TB(op_goto_tb0, PARAM1, 0); - RETURN(); -} - -void OPPROTO op_goto_tb1(void) -{ - GOTO_TB(op_goto_tb1, PARAM1, 1); - RETURN(); -} - -void OPPROTO op_movl_imm_PC(void) -{ - env->pc = PARAM1; - RETURN(); -} - -void OPPROTO op_jT(void) -{ - if (env->sr & SR_T) - GOTO_LABEL_PARAM(1); - RETURN(); -} - -void OPPROTO op_jdelayed(void) -{ - if (env->flags & DELAY_SLOT_TRUE) { - env->flags &= ~DELAY_SLOT_TRUE; - GOTO_LABEL_PARAM(1); - } - RETURN(); -} - -void OPPROTO op_movl_delayed_pc_PC(void) -{ - env->pc = env->delayed_pc; - RETURN(); -} - -void OPPROTO op_addl_GBR_T0(void) -{ - T0 += env->gbr; - RETURN(); -} - -void OPPROTO op_and_imm_T0(void) -{ - T0 &= PARAM1; - RETURN(); -} - -void OPPROTO op_or_imm_T0(void) -{ - T0 |= PARAM1; - RETURN(); -} - -void OPPROTO op_xor_imm_T0(void) -{ - T0 ^= PARAM1; - RETURN(); -} - -void OPPROTO op_tst_imm_T0(void) -{ - cond_t((T0 & PARAM1) == 0); - RETURN(); -} - -void OPPROTO op_raise_illegal_instruction(void) -{ - env->exception_index = 0x180; - do_raise_exception(); - RETURN(); -} - -void OPPROTO op_raise_slot_illegal_instruction(void) -{ - env->exception_index = 0x1a0; - do_raise_exception(); - RETURN(); -} - -void OPPROTO op_debug(void) -{ - env->exception_index = EXCP_DEBUG; - cpu_loop_exit(); -} - -/* Load and store */ -#define MEMSUFFIX _raw -#include "op_mem.c" -#undef MEMSUFFIX -#if !defined(CONFIG_USER_ONLY) -#define MEMSUFFIX _user -#include "op_mem.c" -#undef MEMSUFFIX - -#define MEMSUFFIX _kernel -#include "op_mem.c" -#undef MEMSUFFIX -#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sh4/op_helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sh4/op_helper.c --- qemu-0.9.1/target-sh4/op_helper.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-sh4/op_helper.c 2008-09-15 07:42:30.000000000 +0100 @@ -20,19 +20,9 @@ #include #include "exec.h" -void do_raise_exception(void) -{ - cpu_loop_exit(); -} - #ifndef CONFIG_USER_ONLY #define MMUSUFFIX _mmu -#ifdef __s390__ -# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) -#else -# define GETPC() (__builtin_return_address(0)) -#endif #define SHIFT 0 #include "softmmu_template.h" @@ -69,43 +59,87 @@ cpu_restore_state(tb, env, pc, NULL); } } - do_raise_exception(); + cpu_loop_exit(); } env = saved_env; } #endif -void helper_addc_T0_T1(void) +void helper_ldtlb(void) +{ +#ifdef CONFIG_USER_ONLY + /* XXXXX */ + assert(0); +#else + cpu_load_tlb(env); +#endif +} + +void helper_raise_illegal_instruction(void) +{ + env->exception_index = 0x180; + cpu_loop_exit(); +} + +void helper_raise_slot_illegal_instruction(void) +{ + env->exception_index = 0x1a0; + cpu_loop_exit(); +} + +void helper_debug(void) +{ + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(); +} + +void helper_sleep(uint32_t next_pc) +{ + env->halted = 1; + env->exception_index = EXCP_HLT; + env->pc = next_pc; + cpu_loop_exit(); +} + +void helper_trapa(uint32_t tra) +{ + env->tra = tra << 2; + env->exception_index = 0x160; + cpu_loop_exit(); +} + +uint32_t helper_addc(uint32_t arg0, uint32_t arg1) { uint32_t tmp0, tmp1; - tmp1 = T0 + T1; - tmp0 = T1; - T1 = tmp1 + (env->sr & 1); + tmp1 = arg0 + arg1; + tmp0 = arg1; + arg1 = tmp1 + (env->sr & 1); if (tmp0 > tmp1) env->sr |= SR_T; else env->sr &= ~SR_T; - if (tmp1 > T1) + if (tmp1 > arg1) env->sr |= SR_T; + return arg1; } -void helper_addv_T0_T1(void) +uint32_t helper_addv(uint32_t arg0, uint32_t arg1) { uint32_t dest, src, ans; - if ((int32_t) T1 >= 0) + if ((int32_t) arg1 >= 0) dest = 0; else dest = 1; - if ((int32_t) T0 >= 0) + if ((int32_t) arg0 >= 0) src = 0; else src = 1; src += dest; - T1 += T0; - if ((int32_t) T1 >= 0) + arg1 += arg0; + if ((int32_t) arg1 >= 0) ans = 0; else ans = 1; @@ -117,6 +151,7 @@ env->sr &= ~SR_T; } else env->sr &= ~SR_T; + return arg1; } #define T (env->sr & SR_T) @@ -129,27 +164,27 @@ #define SETM env->sr |= SR_M #define CLRM env->sr &= ~SR_M -void helper_div1_T0_T1(void) +uint32_t helper_div1(uint32_t arg0, uint32_t arg1) { uint32_t tmp0, tmp2; uint8_t old_q, tmp1 = 0xff; - //printf("div1 T0=0x%08x T1=0x%08x M=%d Q=%d T=%d\n", T0, T1, M, Q, T); + //printf("div1 arg0=0x%08x arg1=0x%08x M=%d Q=%d T=%d\n", arg0, arg1, M, Q, T); old_q = Q; - if ((0x80000000 & T1) != 0) + if ((0x80000000 & arg1) != 0) SETQ; else CLRQ; - tmp2 = T0; - T1 <<= 1; - T1 |= T; + tmp2 = arg0; + arg1 <<= 1; + arg1 |= T; switch (old_q) { case 0: switch (M) { case 0: - tmp0 = T1; - T1 -= tmp2; - tmp1 = T1 > tmp0; + tmp0 = arg1; + arg1 -= tmp2; + tmp1 = arg1 > tmp0; switch (Q) { case 0: if (tmp1) @@ -166,9 +201,9 @@ } break; case 1: - tmp0 = T1; - T1 += tmp2; - tmp1 = T1 < tmp0; + tmp0 = arg1; + arg1 += tmp2; + tmp1 = arg1 < tmp0; switch (Q) { case 0: if (tmp1 == 0) @@ -189,9 +224,9 @@ case 1: switch (M) { case 0: - tmp0 = T1; - T1 += tmp2; - tmp1 = T1 < tmp0; + tmp0 = arg1; + arg1 += tmp2; + tmp1 = arg1 < tmp0; switch (Q) { case 0: if (tmp1) @@ -208,9 +243,9 @@ } break; case 1: - tmp0 = T1; - T1 -= tmp2; - tmp1 = T1 > tmp0; + tmp0 = arg1; + arg1 -= tmp2; + tmp1 = arg1 > tmp0; switch (Q) { case 0: if (tmp1 == 0) @@ -233,33 +268,16 @@ SETT; else CLRT; - //printf("Output: T1=0x%08x M=%d Q=%d T=%d\n", T1, M, Q, T); + //printf("Output: arg1=0x%08x M=%d Q=%d T=%d\n", arg1, M, Q, T); + return arg1; } -void helper_dmulsl_T0_T1() -{ - int64_t res; - - res = (int64_t) (int32_t) T0 *(int64_t) (int32_t) T1; - env->mach = (res >> 32) & 0xffffffff; - env->macl = res & 0xffffffff; -} - -void helper_dmulul_T0_T1() -{ - uint64_t res; - - res = (uint64_t) (uint32_t) T0 *(uint64_t) (uint32_t) T1; - env->mach = (res >> 32) & 0xffffffff; - env->macl = res & 0xffffffff; -} - -void helper_macl_T0_T1() +void helper_macl(uint32_t arg0, uint32_t arg1) { int64_t res; res = ((uint64_t) env->mach << 32) | env->macl; - res += (int64_t) (int32_t) T0 *(int64_t) (int32_t) T1; + res += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1; env->mach = (res >> 32) & 0xffffffff; env->macl = res & 0xffffffff; if (env->sr & SR_S) { @@ -270,12 +288,12 @@ } } -void helper_macw_T0_T1() +void helper_macw(uint32_t arg0, uint32_t arg1) { int64_t res; res = ((uint64_t) env->mach << 32) | env->macl; - res += (int64_t) (int16_t) T0 *(int64_t) (int16_t) T1; + res += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1; env->mach = (res >> 32) & 0xffffffff; env->macl = res & 0xffffffff; if (env->sr & SR_S) { @@ -289,50 +307,52 @@ } } -void helper_negc_T0() +uint32_t helper_negc(uint32_t arg) { uint32_t temp; - temp = -T0; - T0 = temp - (env->sr & SR_T); + temp = -arg; + arg = temp - (env->sr & SR_T); if (0 < temp) env->sr |= SR_T; else env->sr &= ~SR_T; - if (temp < T0) + if (temp < arg) env->sr |= SR_T; + return arg; } -void helper_subc_T0_T1() +uint32_t helper_subc(uint32_t arg0, uint32_t arg1) { uint32_t tmp0, tmp1; - tmp1 = T1 - T0; - tmp0 = T1; - T1 = tmp1 - (env->sr & SR_T); + tmp1 = arg1 - arg0; + tmp0 = arg1; + arg1 = tmp1 - (env->sr & SR_T); if (tmp0 < tmp1) env->sr |= SR_T; else env->sr &= ~SR_T; - if (tmp1 < T1) + if (tmp1 < arg1) env->sr |= SR_T; + return arg1; } -void helper_subv_T0_T1() +uint32_t helper_subv(uint32_t arg0, uint32_t arg1) { int32_t dest, src, ans; - if ((int32_t) T1 >= 0) + if ((int32_t) arg1 >= 0) dest = 0; else dest = 1; - if ((int32_t) T0 >= 0) + if ((int32_t) arg0 >= 0) src = 0; else src = 1; src += dest; - T1 -= T0; - if ((int32_t) T1 >= 0) + arg1 -= arg0; + if ((int32_t) arg1 >= 0) ans = 0; else ans = 1; @@ -344,28 +364,168 @@ env->sr &= ~SR_T; } else env->sr &= ~SR_T; + return arg1; } -void helper_rotcl(uint32_t * addr) +static inline void set_t(void) { - uint32_t new; + env->sr |= SR_T; +} - new = (*addr << 1) | (env->sr & SR_T); - if (*addr & 0x80000000) - env->sr |= SR_T; +static inline void clr_t(void) +{ + env->sr &= ~SR_T; +} + +void helper_ld_fpscr(uint32_t val) +{ + env->fpscr = val & 0x003fffff; + if (val & 0x01) + set_float_rounding_mode(float_round_to_zero, &env->fp_status); else - env->sr &= ~SR_T; - *addr = new; + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); } -void helper_rotcr(uint32_t * addr) +uint32_t helper_fabs_FT(uint32_t t0) { - uint32_t new; + float32 ret = float32_abs(*(float32*)&t0); + return *(uint32_t*)(&ret); +} - new = (*addr >> 1) | ((env->sr & SR_T) ? 0x80000000 : 0); - if (*addr & 1) - env->sr |= SR_T; +uint64_t helper_fabs_DT(uint64_t t0) +{ + float64 ret = float64_abs(*(float64*)&t0); + return *(uint64_t*)(&ret); +} + +uint32_t helper_fadd_FT(uint32_t t0, uint32_t t1) +{ + float32 ret = float32_add(*(float32*)&t0, *(float32*)&t1, &env->fp_status); + return *(uint32_t*)(&ret); +} + +uint64_t helper_fadd_DT(uint64_t t0, uint64_t t1) +{ + float64 ret = float64_add(*(float64*)&t0, *(float64*)&t1, &env->fp_status); + return *(uint64_t*)(&ret); +} + +void helper_fcmp_eq_FT(uint32_t t0, uint32_t t1) +{ + if (float32_compare(*(float32*)&t0, *(float32*)&t1, &env->fp_status) == 0) + set_t(); else - env->sr &= ~SR_T; - *addr = new; + clr_t(); +} + +void helper_fcmp_eq_DT(uint64_t t0, uint64_t t1) +{ + if (float64_compare(*(float64*)&t0, *(float64*)&t1, &env->fp_status) == 0) + set_t(); + else + clr_t(); +} + +void helper_fcmp_gt_FT(uint32_t t0, uint32_t t1) +{ + if (float32_compare(*(float32*)&t0, *(float32*)&t1, &env->fp_status) == 1) + set_t(); + else + clr_t(); +} + +void helper_fcmp_gt_DT(uint64_t t0, uint64_t t1) +{ + if (float64_compare(*(float64*)&t0, *(float64*)&t1, &env->fp_status) == 1) + set_t(); + else + clr_t(); +} + +uint64_t helper_fcnvsd_FT_DT(uint32_t t0) +{ + float64 ret = float32_to_float64(*(float32*)&t0, &env->fp_status); + return *(uint64_t*)(&ret); +} + +uint32_t helper_fcnvds_DT_FT(uint64_t t0) +{ + float32 ret = float64_to_float32(*(float64*)&t0, &env->fp_status); + return *(uint32_t*)(&ret); +} + +uint32_t helper_fdiv_FT(uint32_t t0, uint32_t t1) +{ + float32 ret = float32_div(*(float32*)&t0, *(float32*)&t1, &env->fp_status); + return *(uint32_t*)(&ret); +} + +uint64_t helper_fdiv_DT(uint64_t t0, uint64_t t1) +{ + float64 ret = float64_div(*(float64*)&t0, *(float64*)&t1, &env->fp_status); + return *(uint64_t*)(&ret); +} + +uint32_t helper_float_FT(uint32_t t0) +{ + float32 ret = int32_to_float32(t0, &env->fp_status); + return *(uint32_t*)(&ret); +} + +uint64_t helper_float_DT(uint32_t t0) +{ + float64 ret = int32_to_float64(t0, &env->fp_status); + return *(uint64_t*)(&ret); +} + +uint32_t helper_fmul_FT(uint32_t t0, uint32_t t1) +{ + float32 ret = float32_mul(*(float32*)&t0, *(float32*)&t1, &env->fp_status); + return *(uint32_t*)(&ret); +} + +uint64_t helper_fmul_DT(uint64_t t0, uint64_t t1) +{ + float64 ret = float64_mul(*(float64*)&t0, *(float64*)&t1, &env->fp_status); + return *(uint64_t*)(&ret); +} + +uint32_t helper_fneg_T(uint32_t t0) +{ + float32 ret = float32_chs(*(float32*)&t0); + return *(uint32_t*)(&ret); +} + +uint32_t helper_fsqrt_FT(uint32_t t0) +{ + float32 ret = float32_sqrt(*(float32*)&t0, &env->fp_status); + return *(uint32_t*)(&ret); +} + +uint64_t helper_fsqrt_DT(uint64_t t0) +{ + float64 ret = float64_sqrt(*(float64*)&t0, &env->fp_status); + return *(uint64_t*)(&ret); +} + +uint32_t helper_fsub_FT(uint32_t t0, uint32_t t1) +{ + float32 ret = float32_sub(*(float32*)&t0, *(float32*)&t1, &env->fp_status); + return *(uint32_t*)(&ret); +} + +uint64_t helper_fsub_DT(uint64_t t0, uint64_t t1) +{ + float64 ret = float64_sub(*(float64*)&t0, *(float64*)&t1, &env->fp_status); + return *(uint64_t*)(&ret); +} + +uint32_t helper_ftrc_FT(uint32_t t0) +{ + return float32_to_int32_round_to_zero(*(float32*)&t0, &env->fp_status); +} + +uint32_t helper_ftrc_DT(uint64_t t0) +{ + return float64_to_int32_round_to_zero(*(float64*)&t0, &env->fp_status); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sh4/op_mem.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sh4/op_mem.c --- qemu-0.9.1/target-sh4/op_mem.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-sh4/op_mem.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,78 +0,0 @@ -/* - * SH4 emulation - * - * Copyright (c) 2005 Samuel Tardieu - * - * 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 - */ -void glue(op_ldb_T0_T0, MEMSUFFIX) (void) { - T0 = glue(ldsb, MEMSUFFIX) (T0); - RETURN(); -} - -void glue(op_ldub_T0_T0, MEMSUFFIX) (void) { - T0 = glue(ldub, MEMSUFFIX) (T0); - RETURN(); -} - -void glue(op_stb_T0_T1, MEMSUFFIX) (void) { - glue(stb, MEMSUFFIX) (T1, T0); - RETURN(); -} - -void glue(op_ldw_T0_T0, MEMSUFFIX) (void) { - T0 = glue(ldsw, MEMSUFFIX) (T0); - RETURN(); -} - -void glue(op_lduw_T0_T0, MEMSUFFIX) (void) { - T0 = glue(lduw, MEMSUFFIX) (T0); - RETURN(); -} - -void glue(op_stw_T0_T1, MEMSUFFIX) (void) { - glue(stw, MEMSUFFIX) (T1, T0); - RETURN(); -} - -void glue(op_ldl_T0_T0, MEMSUFFIX) (void) { - T0 = glue(ldl, MEMSUFFIX) (T0); - RETURN(); -} - -void glue(op_stl_T0_T1, MEMSUFFIX) (void) { - glue(stl, MEMSUFFIX) (T1, T0); - RETURN(); -} - -void glue(op_ldfl_T0_FT0, MEMSUFFIX) (void) { - FT0 = glue(ldfl, MEMSUFFIX) (T0); - RETURN(); -} - -void glue(op_stfl_FT0_T1, MEMSUFFIX) (void) { - glue(stfl, MEMSUFFIX) (T1, FT0); - RETURN(); -} - -void glue(op_ldfq_T0_DT0, MEMSUFFIX) (void) { - DT0 = glue(ldfq, MEMSUFFIX) (T0); - RETURN(); -} - -void glue(op_stfq_DT0_T1, MEMSUFFIX) (void) { - glue(stfq, MEMSUFFIX) (T1, DT0); - RETURN(); -} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sh4/translate.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sh4/translate.c --- qemu-0.9.1/target-sh4/translate.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-sh4/translate.c 2008-10-26 13:43:07.000000000 +0000 @@ -31,24 +31,9 @@ #include "cpu.h" #include "exec-all.h" #include "disas.h" - -enum { -#define DEF(s, n, copy_size) INDEX_op_ ## s, -#include "opc.h" -#undef DEF - NB_OPS, -}; - -#ifdef USE_DIRECT_JUMP -#define TBPARAM(x) -#else -#define TBPARAM(x) ((long)(x)) -#endif - -static uint16_t *gen_opc_ptr; -static uint32_t *gen_opparam_ptr; - -#include "gen-op.h" +#include "helper.h" +#include "tcg-op.h" +#include "qemu-common.h" typedef struct DisasContext { struct TranslationBlock *tb; @@ -63,6 +48,12 @@ int singlestep_enabled; } DisasContext; +#if defined(CONFIG_USER_ONLY) +#define IS_USER(ctx) 1 +#else +#define IS_USER(ctx) (!(ctx->sr & SR_MD)) +#endif + enum { BS_NONE = 0, /* We go out of the TB without reaching a branch or an * exception condition @@ -72,44 +63,80 @@ BS_EXCP = 3, /* We reached an exception condition */ }; -#ifdef CONFIG_USER_ONLY +/* global register indexes */ +static TCGv cpu_env; +static TCGv cpu_gregs[24]; +static TCGv cpu_pc, cpu_sr, cpu_ssr, cpu_spc, cpu_gbr; +static TCGv cpu_vbr, cpu_sgr, cpu_dbr, cpu_mach, cpu_macl; +static TCGv cpu_pr, cpu_fpscr, cpu_fpul, cpu_flags; -#define GEN_OP_LD(width, reg) \ - void gen_op_ld##width##_T0_##reg (DisasContext *ctx) { \ - gen_op_ld##width##_T0_##reg##_raw(); \ - } -#define GEN_OP_ST(width, reg) \ - void gen_op_st##width##_##reg##_T1 (DisasContext *ctx) { \ - gen_op_st##width##_##reg##_T1_raw(); \ - } +/* internal register indexes */ +static TCGv cpu_flags, cpu_delayed_pc; -#else - -#define GEN_OP_LD(width, reg) \ - void gen_op_ld##width##_T0_##reg (DisasContext *ctx) { \ - if (ctx->memidx) gen_op_ld##width##_T0_##reg##_kernel(); \ - else gen_op_ld##width##_T0_##reg##_user();\ - } -#define GEN_OP_ST(width, reg) \ - void gen_op_st##width##_##reg##_T1 (DisasContext *ctx) { \ - if (ctx->memidx) gen_op_st##width##_##reg##_T1_kernel(); \ - else gen_op_st##width##_##reg##_T1_user();\ - } +#include "gen-icount.h" -#endif +static void sh4_translate_init(void) +{ + int i; + static int done_init = 0; + static const char * const gregnames[24] = { + "R0_BANK0", "R1_BANK0", "R2_BANK0", "R3_BANK0", + "R4_BANK0", "R5_BANK0", "R6_BANK0", "R7_BANK0", + "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", + "R0_BANK1", "R1_BANK1", "R2_BANK1", "R3_BANK1", + "R4_BANK1", "R5_BANK1", "R6_BANK1", "R7_BANK1" + }; + + if (done_init) + return; + + cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env"); + + for (i = 0; i < 24; i++) + cpu_gregs[i] = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, gregs[i]), + gregnames[i]); + + cpu_pc = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, pc), "PC"); + cpu_sr = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, sr), "SR"); + cpu_ssr = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, ssr), "SSR"); + cpu_spc = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, spc), "SPC"); + cpu_gbr = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, gbr), "GBR"); + cpu_vbr = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, vbr), "VBR"); + cpu_sgr = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, sgr), "SGR"); + cpu_dbr = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, dbr), "DBR"); + cpu_mach = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, mach), "MACH"); + cpu_macl = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, macl), "MACL"); + cpu_pr = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, pr), "PR"); + cpu_fpscr = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, fpscr), "FPSCR"); + cpu_fpul = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, fpul), "FPUL"); + + cpu_flags = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, flags), "_flags_"); + cpu_delayed_pc = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, delayed_pc), + "_delayed_pc_"); + + /* register helpers */ +#undef DEF_HELPER +#define DEF_HELPER(ret, name, params) tcg_register_helper(name, #name); +#include "helper.h" -GEN_OP_LD(ub, T0) -GEN_OP_LD(b, T0) -GEN_OP_ST(b, T0) -GEN_OP_LD(uw, T0) -GEN_OP_LD(w, T0) -GEN_OP_ST(w, T0) -GEN_OP_LD(l, T0) -GEN_OP_ST(l, T0) -GEN_OP_LD(fl, FT0) -GEN_OP_ST(fl, FT0) -GEN_OP_LD(fq, DT0) -GEN_OP_ST(fq, DT0) + done_init = 1; +} void cpu_dump_state(CPUState * env, FILE * f, int (*cpu_fprintf) (FILE * f, const char *fmt, ...), @@ -118,6 +145,10 @@ int i; cpu_fprintf(f, "pc=0x%08x sr=0x%08x pr=0x%08x fpscr=0x%08x\n", env->pc, env->sr, env->pr, env->fpscr); + cpu_fprintf(f, "spc=0x%08x ssr=0x%08x gbr=0x%08x vbr=0x%08x\n", + env->spc, env->ssr, env->gbr, env->vbr); + cpu_fprintf(f, "sgr=0x%08x dbr=0x%08x delayed_pc=0x%08x fpul=0x%08x\n", + env->sgr, env->dbr, env->delayed_pc, env->fpul); for (i = 0; i < 24; i += 4) { cpu_fprintf(f, "r%d=0x%08x r%d=0x%08x r%d=0x%08x r%d=0x%08x\n", i, env->gregs[i], i + 1, env->gregs[i + 1], @@ -151,15 +182,76 @@ env->mmucr = 0; } +typedef struct { + const char *name; + int id; + uint32_t pvr; + uint32_t prr; + uint32_t cvr; +} sh4_def_t; + +static sh4_def_t sh4_defs[] = { + { + .name = "SH7750R", + .id = SH_CPU_SH7750R, + .pvr = 0x00050000, + .prr = 0x00000100, + .cvr = 0x00110000, + }, { + .name = "SH7751R", + .id = SH_CPU_SH7751R, + .pvr = 0x04050005, + .prr = 0x00000113, + .cvr = 0x00110000, /* Neutered caches, should be 0x20480000 */ + }, +}; + +static const sh4_def_t *cpu_sh4_find_by_name(const char *name) +{ + int i; + + if (strcasecmp(name, "any") == 0) + return &sh4_defs[0]; + + for (i = 0; i < sizeof(sh4_defs) / sizeof(*sh4_defs); i++) + if (strcasecmp(name, sh4_defs[i].name) == 0) + return &sh4_defs[i]; + + return NULL; +} + +void sh4_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + int i; + + for (i = 0; i < sizeof(sh4_defs) / sizeof(*sh4_defs); i++) + (*cpu_fprintf)(f, "%s\n", sh4_defs[i].name); +} + +static void cpu_sh4_register(CPUSH4State *env, const sh4_def_t *def) +{ + env->pvr = def->pvr; + env->prr = def->prr; + env->cvr = def->cvr; + env->id = def->id; +} + CPUSH4State *cpu_sh4_init(const char *cpu_model) { CPUSH4State *env; + const sh4_def_t *def; + def = cpu_sh4_find_by_name(cpu_model); + if (!def) + return NULL; env = qemu_mallocz(sizeof(CPUSH4State)); if (!env) return NULL; cpu_exec_init(env); + sh4_translate_init(); + env->cpu_model_str = cpu_model; cpu_sh4_reset(env); + cpu_sh4_register(env, def); tlb_flush(env, 1); return env; } @@ -172,18 +264,15 @@ if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) && !ctx->singlestep_enabled) { /* Use a direct jump if in same page and singlestep not enabled */ - if (n == 0) - gen_op_goto_tb0(TBPARAM(tb)); - else - gen_op_goto_tb1(TBPARAM(tb)); - gen_op_movl_imm_T0((long) tb + n); + tcg_gen_goto_tb(n); + tcg_gen_movi_i32(cpu_pc, dest); + tcg_gen_exit_tb((long) tb + n); } else { - gen_op_movl_imm_T0(0); + tcg_gen_movi_i32(cpu_pc, dest); + if (ctx->singlestep_enabled) + tcg_gen_helper_0_0(helper_debug); + tcg_gen_exit_tb(0); } - gen_op_movl_imm_PC(dest); - if (ctx->singlestep_enabled) - gen_op_debug(); - gen_op_exit_tb(); } static void gen_jump(DisasContext * ctx) @@ -191,24 +280,38 @@ if (ctx->delayed_pc == (uint32_t) - 1) { /* Target is not statically known, it comes necessarily from a delayed jump as immediate jump are conditinal jumps */ - gen_op_movl_delayed_pc_PC(); - gen_op_movl_imm_T0(0); + tcg_gen_mov_i32(cpu_pc, cpu_delayed_pc); if (ctx->singlestep_enabled) - gen_op_debug(); - gen_op_exit_tb(); + tcg_gen_helper_0_0(helper_debug); + tcg_gen_exit_tb(0); } else { gen_goto_tb(ctx, 0, ctx->delayed_pc); } } +static inline void gen_branch_slot(uint32_t delayed_pc, int t) +{ + TCGv sr; + int label = gen_new_label(); + tcg_gen_movi_i32(cpu_delayed_pc, delayed_pc); + sr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_andi_i32(sr, cpu_sr, SR_T); + tcg_gen_brcondi_i32(TCG_COND_NE, sr, t ? SR_T : 0, label); + tcg_gen_ori_i32(cpu_flags, cpu_flags, DELAY_SLOT_TRUE); + gen_set_label(label); +} + /* Immediate conditional jump (bt or bf) */ static void gen_conditional_jump(DisasContext * ctx, target_ulong ift, target_ulong ifnott) { int l1; + TCGv sr; l1 = gen_new_label(); - gen_op_jT(l1); + sr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_andi_i32(sr, cpu_sr, SR_T); + tcg_gen_brcondi_i32(TCG_COND_EQ, sr, SR_T, l1); gen_goto_tb(ctx, 0, ifnott); gen_set_label(l1); gen_goto_tb(ctx, 1, ift); @@ -218,14 +321,111 @@ static void gen_delayed_conditional_jump(DisasContext * ctx) { int l1; + TCGv ds; l1 = gen_new_label(); - gen_op_jdelayed(l1); + ds = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_andi_i32(ds, cpu_flags, DELAY_SLOT_TRUE); + tcg_gen_brcondi_i32(TCG_COND_EQ, ds, DELAY_SLOT_TRUE, l1); gen_goto_tb(ctx, 1, ctx->pc + 2); gen_set_label(l1); + tcg_gen_andi_i32(cpu_flags, cpu_flags, ~DELAY_SLOT_TRUE); gen_jump(ctx); } +static inline void gen_set_t(void) +{ + tcg_gen_ori_i32(cpu_sr, cpu_sr, SR_T); +} + +static inline void gen_clr_t(void) +{ + tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T); +} + +static inline void gen_cmp(int cond, TCGv t0, TCGv t1) +{ + int label1 = gen_new_label(); + int label2 = gen_new_label(); + tcg_gen_brcond_i32(cond, t1, t0, label1); + gen_clr_t(); + tcg_gen_br(label2); + gen_set_label(label1); + gen_set_t(); + gen_set_label(label2); +} + +static inline void gen_cmp_imm(int cond, TCGv t0, int32_t imm) +{ + int label1 = gen_new_label(); + int label2 = gen_new_label(); + tcg_gen_brcondi_i32(cond, t0, imm, label1); + gen_clr_t(); + tcg_gen_br(label2); + gen_set_label(label1); + gen_set_t(); + gen_set_label(label2); +} + +static inline void gen_store_flags(uint32_t flags) +{ + tcg_gen_andi_i32(cpu_flags, cpu_flags, DELAY_SLOT_TRUE); + tcg_gen_ori_i32(cpu_flags, cpu_flags, flags); +} + +static inline void gen_copy_bit_i32(TCGv t0, int p0, TCGv t1, int p1) +{ + TCGv tmp = tcg_temp_new(TCG_TYPE_I32); + + p0 &= 0x1f; + p1 &= 0x1f; + + tcg_gen_andi_i32(tmp, t1, (1 << p1)); + tcg_gen_andi_i32(t0, t0, ~(1 << p0)); + if (p0 < p1) + tcg_gen_shri_i32(tmp, tmp, p1 - p0); + else if (p0 > p1) + tcg_gen_shli_i32(tmp, tmp, p0 - p1); + tcg_gen_or_i32(t0, t0, tmp); + + tcg_temp_free(tmp); +} + + +static inline void gen_load_fpr32(TCGv t, int reg) +{ + tcg_gen_ld_i32(t, cpu_env, offsetof(CPUState, fregs[reg])); +} + +static inline void gen_load_fpr64(TCGv t, int reg) +{ + TCGv tmp1 = tcg_temp_new(TCG_TYPE_I32); + TCGv tmp2 = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_ld_i32(tmp1, cpu_env, offsetof(CPUState, fregs[reg])); + tcg_gen_ld_i32(tmp2, cpu_env, offsetof(CPUState, fregs[reg + 1])); + tcg_gen_concat_i32_i64(t, tmp2, tmp1); + tcg_temp_free(tmp1); + tcg_temp_free(tmp2); +} + +static inline void gen_store_fpr32(TCGv t, int reg) +{ + tcg_gen_st_i32(t, cpu_env, offsetof(CPUState, fregs[reg])); +} + +static inline void gen_store_fpr64 (TCGv t, int reg) +{ + TCGv tmp = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_trunc_i64_i32(tmp, t); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, fregs[reg + 1])); + tcg_gen_shri_i64(t, t, 32); + tcg_gen_trunc_i64_i32(tmp, t); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, fregs[reg])); + tcg_temp_free(tmp); +} + #define B3_0 (ctx->opcode & 0xf) #define B6_4 ((ctx->opcode >> 4) & 0x7) #define B7_4 ((ctx->opcode >> 4) & 0xf) @@ -237,10 +437,10 @@ #define B15_12 ((ctx->opcode >> 12) & 0xf) #define REG(x) ((x) < 8 && (ctx->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB) ? \ - (x) + 16 : (x)) + (cpu_gregs[x + 16]) : (cpu_gregs[x])) #define ALTREG(x) ((x) < 8 && (ctx->sr & (SR_MD | SR_RB)) != (SR_MD | SR_RB) \ - ? (x) + 16 : (x)) + ? (cpu_gregs[x + 16]) : (cpu_gregs[x])) #define FREG(x) (ctx->fpscr & FPSCR_FR ? (x) ^ 0x10 : (x)) #define XHACK(x) ((((x) & 1 ) << 4) | ((x) & 0xe)) @@ -249,500 +449,648 @@ #define CHECK_NOT_DELAY_SLOT \ if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \ - {gen_op_raise_slot_illegal_instruction (); ctx->bstate = BS_EXCP; \ + {tcg_gen_helper_0_0(helper_raise_slot_illegal_instruction); ctx->bstate = BS_EXCP; \ return;} -void _decode_opc(DisasContext * ctx) +#define CHECK_PRIVILEGED \ + if (IS_USER(ctx)) { \ + tcg_gen_helper_0_0(helper_raise_illegal_instruction); \ + ctx->bstate = BS_EXCP; \ + return; \ + } + +static void _decode_opc(DisasContext * ctx) { #if 0 fprintf(stderr, "Translating opcode 0x%04x\n", ctx->opcode); #endif switch (ctx->opcode) { case 0x0019: /* div0u */ - gen_op_div0u(); + tcg_gen_andi_i32(cpu_sr, cpu_sr, ~(SR_M | SR_Q | SR_T)); return; case 0x000b: /* rts */ - CHECK_NOT_DELAY_SLOT gen_op_rts(); + CHECK_NOT_DELAY_SLOT + tcg_gen_mov_i32(cpu_delayed_pc, cpu_pr); ctx->flags |= DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; return; case 0x0028: /* clrmac */ - gen_op_clrmac(); + tcg_gen_movi_i32(cpu_mach, 0); + tcg_gen_movi_i32(cpu_macl, 0); return; case 0x0048: /* clrs */ - gen_op_clrs(); + tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_S); return; case 0x0008: /* clrt */ - gen_op_clrt(); + gen_clr_t(); return; case 0x0038: /* ldtlb */ - assert(0); /* XXXXX */ + CHECK_PRIVILEGED + tcg_gen_helper_0_0(helper_ldtlb); return; case 0x002b: /* rte */ - CHECK_NOT_DELAY_SLOT gen_op_rte(); + CHECK_PRIVILEGED + CHECK_NOT_DELAY_SLOT + tcg_gen_mov_i32(cpu_sr, cpu_ssr); + tcg_gen_mov_i32(cpu_delayed_pc, cpu_spc); ctx->flags |= DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; return; case 0x0058: /* sets */ - gen_op_sets(); + tcg_gen_ori_i32(cpu_sr, cpu_sr, SR_S); return; case 0x0018: /* sett */ - gen_op_sett(); + gen_set_t(); return; - case 0xfbfb: /* frchg */ - gen_op_frchg(); + case 0xfbfd: /* frchg */ + tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_FR); ctx->bstate = BS_STOP; return; - case 0xf3fb: /* fschg */ - gen_op_fschg(); + case 0xf3fd: /* fschg */ + tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_SZ); ctx->bstate = BS_STOP; return; case 0x0009: /* nop */ return; case 0x001b: /* sleep */ - assert(0); /* XXXXX */ + CHECK_PRIVILEGED + tcg_gen_helper_0_1(helper_sleep, tcg_const_i32(ctx->pc + 2)); return; } switch (ctx->opcode & 0xf000) { case 0x1000: /* mov.l Rm,@(disp,Rn) */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_addl_imm_T1(B3_0 * 4); - gen_op_stl_T0_T1(ctx); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_addi_i32(addr, REG(B11_8), B3_0 * 4); + tcg_gen_qemu_st32(REG(B7_4), addr, ctx->memidx); + tcg_temp_free(addr); + } return; case 0x5000: /* mov.l @(disp,Rm),Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_addl_imm_T0(B3_0 * 4); - gen_op_ldl_T0_T0(ctx); - gen_op_movl_T0_rN(REG(B11_8)); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 4); + tcg_gen_qemu_ld32s(REG(B11_8), addr, ctx->memidx); + tcg_temp_free(addr); + } return; - case 0xe000: /* mov.l #imm,Rn */ - gen_op_movl_imm_rN(B7_0s, REG(B11_8)); + case 0xe000: /* mov #imm,Rn */ + tcg_gen_movi_i32(REG(B11_8), B7_0s); return; case 0x9000: /* mov.w @(disp,PC),Rn */ - gen_op_movl_imm_T0(ctx->pc + 4 + B7_0 * 2); - gen_op_ldw_T0_T0(ctx); - gen_op_movl_T0_rN(REG(B11_8)); + { + TCGv addr = tcg_const_i32(ctx->pc + 4 + B7_0 * 2); + tcg_gen_qemu_ld16s(REG(B11_8), addr, ctx->memidx); + tcg_temp_free(addr); + } return; case 0xd000: /* mov.l @(disp,PC),Rn */ - gen_op_movl_imm_T0((ctx->pc + 4 + B7_0 * 4) & ~3); - gen_op_ldl_T0_T0(ctx); - gen_op_movl_T0_rN(REG(B11_8)); + { + TCGv addr = tcg_const_i32((ctx->pc + 4 + B7_0 * 4) & ~3); + tcg_gen_qemu_ld32s(REG(B11_8), addr, ctx->memidx); + tcg_temp_free(addr); + } return; - case 0x7000: /* add.l #imm,Rn */ - gen_op_add_imm_rN(B7_0s, REG(B11_8)); + case 0x7000: /* add #imm,Rn */ + tcg_gen_addi_i32(REG(B11_8), REG(B11_8), B7_0s); return; case 0xa000: /* bra disp */ CHECK_NOT_DELAY_SLOT - gen_op_bra(ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2); + ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2; + tcg_gen_movi_i32(cpu_delayed_pc, ctx->delayed_pc); ctx->flags |= DELAY_SLOT; return; case 0xb000: /* bsr disp */ CHECK_NOT_DELAY_SLOT - gen_op_bsr(ctx->pc + 4, ctx->delayed_pc = - ctx->pc + 4 + B11_0s * 2); + tcg_gen_movi_i32(cpu_pr, ctx->pc + 4); + ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2; + tcg_gen_movi_i32(cpu_delayed_pc, ctx->delayed_pc); ctx->flags |= DELAY_SLOT; return; } switch (ctx->opcode & 0xf00f) { case 0x6003: /* mov Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_T0_rN(REG(B11_8)); + tcg_gen_mov_i32(REG(B11_8), REG(B7_4)); return; case 0x2000: /* mov.b Rm,@Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_stb_T0_T1(ctx); + tcg_gen_qemu_st8(REG(B7_4), REG(B11_8), ctx->memidx); return; case 0x2001: /* mov.w Rm,@Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_stw_T0_T1(ctx); + tcg_gen_qemu_st16(REG(B7_4), REG(B11_8), ctx->memidx); return; case 0x2002: /* mov.l Rm,@Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_stl_T0_T1(ctx); + tcg_gen_qemu_st32(REG(B7_4), REG(B11_8), ctx->memidx); return; case 0x6000: /* mov.b @Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_ldb_T0_T0(ctx); - gen_op_movl_T0_rN(REG(B11_8)); + tcg_gen_qemu_ld8s(REG(B11_8), REG(B7_4), ctx->memidx); return; case 0x6001: /* mov.w @Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_ldw_T0_T0(ctx); - gen_op_movl_T0_rN(REG(B11_8)); + tcg_gen_qemu_ld16s(REG(B11_8), REG(B7_4), ctx->memidx); return; case 0x6002: /* mov.l @Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_ldl_T0_T0(ctx); - gen_op_movl_T0_rN(REG(B11_8)); + tcg_gen_qemu_ld32s(REG(B11_8), REG(B7_4), ctx->memidx); return; case 0x2004: /* mov.b Rm,@-Rn */ - gen_op_dec1_rN(REG(B11_8)); - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_stb_T0_T1(ctx); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_subi_i32(addr, REG(B11_8), 1); + tcg_gen_qemu_st8(REG(B7_4), addr, ctx->memidx); /* might cause re-execution */ + tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 1); /* modify register status */ + tcg_temp_free(addr); + } return; case 0x2005: /* mov.w Rm,@-Rn */ - gen_op_dec2_rN(REG(B11_8)); - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_stw_T0_T1(ctx); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_subi_i32(addr, REG(B11_8), 2); + tcg_gen_qemu_st16(REG(B7_4), addr, ctx->memidx); + tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 2); + tcg_temp_free(addr); + } return; case 0x2006: /* mov.l Rm,@-Rn */ - gen_op_dec4_rN(REG(B11_8)); - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_stl_T0_T1(ctx); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_subi_i32(addr, REG(B11_8), 4); + tcg_gen_qemu_st32(REG(B7_4), addr, ctx->memidx); + tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4); + } return; case 0x6004: /* mov.b @Rm+,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_ldb_T0_T0(ctx); - gen_op_movl_T0_rN(REG(B11_8)); - gen_op_inc1_rN(REG(B7_4)); + tcg_gen_qemu_ld8s(REG(B11_8), REG(B7_4), ctx->memidx); + if ( B11_8 != B7_4 ) + tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 1); return; case 0x6005: /* mov.w @Rm+,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_ldw_T0_T0(ctx); - gen_op_movl_T0_rN(REG(B11_8)); - gen_op_inc2_rN(REG(B7_4)); + tcg_gen_qemu_ld16s(REG(B11_8), REG(B7_4), ctx->memidx); + if ( B11_8 != B7_4 ) + tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 2); return; case 0x6006: /* mov.l @Rm+,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_ldl_T0_T0(ctx); - gen_op_movl_T0_rN(REG(B11_8)); - gen_op_inc4_rN(REG(B7_4)); + tcg_gen_qemu_ld32s(REG(B11_8), REG(B7_4), ctx->memidx); + if ( B11_8 != B7_4 ) + tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4); return; case 0x0004: /* mov.b Rm,@(R0,Rn) */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_add_rN_T1(REG(0)); - gen_op_stb_T0_T1(ctx); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_add_i32(addr, REG(B11_8), REG(0)); + tcg_gen_qemu_st8(REG(B7_4), addr, ctx->memidx); + tcg_temp_free(addr); + } return; case 0x0005: /* mov.w Rm,@(R0,Rn) */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_add_rN_T1(REG(0)); - gen_op_stw_T0_T1(ctx); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_add_i32(addr, REG(B11_8), REG(0)); + tcg_gen_qemu_st16(REG(B7_4), addr, ctx->memidx); + tcg_temp_free(addr); + } return; case 0x0006: /* mov.l Rm,@(R0,Rn) */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_add_rN_T1(REG(0)); - gen_op_stl_T0_T1(ctx); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_add_i32(addr, REG(B11_8), REG(0)); + tcg_gen_qemu_st32(REG(B7_4), addr, ctx->memidx); + tcg_temp_free(addr); + } return; case 0x000c: /* mov.b @(R0,Rm),Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_add_rN_T0(REG(0)); - gen_op_ldb_T0_T0(ctx); - gen_op_movl_T0_rN(REG(B11_8)); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_add_i32(addr, REG(B7_4), REG(0)); + tcg_gen_qemu_ld8s(REG(B11_8), addr, ctx->memidx); + tcg_temp_free(addr); + } return; case 0x000d: /* mov.w @(R0,Rm),Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_add_rN_T0(REG(0)); - gen_op_ldw_T0_T0(ctx); - gen_op_movl_T0_rN(REG(B11_8)); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_add_i32(addr, REG(B7_4), REG(0)); + tcg_gen_qemu_ld16s(REG(B11_8), addr, ctx->memidx); + tcg_temp_free(addr); + } return; case 0x000e: /* mov.l @(R0,Rm),Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_add_rN_T0(REG(0)); - gen_op_ldl_T0_T0(ctx); - gen_op_movl_T0_rN(REG(B11_8)); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_add_i32(addr, REG(B7_4), REG(0)); + tcg_gen_qemu_ld32s(REG(B11_8), addr, ctx->memidx); + tcg_temp_free(addr); + } return; case 0x6008: /* swap.b Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_swapb_T0(); - gen_op_movl_T0_rN(REG(B11_8)); + { + TCGv highw, high, low; + highw = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_andi_i32(highw, REG(B7_4), 0xffff0000); + high = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_ext8u_i32(high, REG(B7_4)); + tcg_gen_shli_i32(high, high, 8); + low = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_shri_i32(low, REG(B7_4), 8); + tcg_gen_ext8u_i32(low, low); + tcg_gen_or_i32(REG(B11_8), high, low); + tcg_gen_or_i32(REG(B11_8), REG(B11_8), highw); + tcg_temp_free(low); + tcg_temp_free(high); + } return; case 0x6009: /* swap.w Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_swapw_T0(); - gen_op_movl_T0_rN(REG(B11_8)); + { + TCGv high, low; + high = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_ext16u_i32(high, REG(B7_4)); + tcg_gen_shli_i32(high, high, 16); + low = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_shri_i32(low, REG(B7_4), 16); + tcg_gen_ext16u_i32(low, low); + tcg_gen_or_i32(REG(B11_8), high, low); + tcg_temp_free(low); + tcg_temp_free(high); + } return; case 0x200d: /* xtrct Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_xtrct_T0_T1(); - gen_op_movl_T1_rN(REG(B11_8)); + { + TCGv high, low; + high = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_ext16u_i32(high, REG(B7_4)); + tcg_gen_shli_i32(high, high, 16); + low = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_shri_i32(low, REG(B11_8), 16); + tcg_gen_ext16u_i32(low, low); + tcg_gen_or_i32(REG(B11_8), high, low); + tcg_temp_free(low); + tcg_temp_free(high); + } return; case 0x300c: /* add Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_add_T0_rN(REG(B11_8)); + tcg_gen_add_i32(REG(B11_8), REG(B11_8), REG(B7_4)); return; case 0x300e: /* addc Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_addc_T0_T1(); - gen_op_movl_T1_rN(REG(B11_8)); + tcg_gen_helper_1_2(helper_addc, REG(B11_8), REG(B7_4), REG(B11_8)); return; case 0x300f: /* addv Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_addv_T0_T1(); - gen_op_movl_T1_rN(REG(B11_8)); + tcg_gen_helper_1_2(helper_addv, REG(B11_8), REG(B7_4), REG(B11_8)); return; case 0x2009: /* and Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_and_T0_rN(REG(B11_8)); + tcg_gen_and_i32(REG(B11_8), REG(B11_8), REG(B7_4)); return; case 0x3000: /* cmp/eq Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_cmp_eq_T0_T1(); + gen_cmp(TCG_COND_EQ, REG(B7_4), REG(B11_8)); return; case 0x3003: /* cmp/ge Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_cmp_ge_T0_T1(); + gen_cmp(TCG_COND_GE, REG(B7_4), REG(B11_8)); return; case 0x3007: /* cmp/gt Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_cmp_gt_T0_T1(); + gen_cmp(TCG_COND_GT, REG(B7_4), REG(B11_8)); return; case 0x3006: /* cmp/hi Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_cmp_hi_T0_T1(); + gen_cmp(TCG_COND_GTU, REG(B7_4), REG(B11_8)); return; case 0x3002: /* cmp/hs Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_cmp_hs_T0_T1(); + gen_cmp(TCG_COND_GEU, REG(B7_4), REG(B11_8)); return; case 0x200c: /* cmp/str Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_cmp_str_T0_T1(); + { + int label1 = gen_new_label(); + int label2 = gen_new_label(); + TCGv cmp1 = tcg_temp_local_new(TCG_TYPE_I32); + TCGv cmp2 = tcg_temp_local_new(TCG_TYPE_I32); + tcg_gen_xor_i32(cmp1, REG(B7_4), REG(B11_8)); + tcg_gen_andi_i32(cmp2, cmp1, 0xff000000); + tcg_gen_brcondi_i32(TCG_COND_EQ, cmp2, 0, label1); + tcg_gen_andi_i32(cmp2, cmp1, 0x00ff0000); + tcg_gen_brcondi_i32(TCG_COND_EQ, cmp2, 0, label1); + tcg_gen_andi_i32(cmp2, cmp1, 0x0000ff00); + tcg_gen_brcondi_i32(TCG_COND_EQ, cmp2, 0, label1); + tcg_gen_andi_i32(cmp2, cmp1, 0x000000ff); + tcg_gen_brcondi_i32(TCG_COND_EQ, cmp2, 0, label1); + tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T); + tcg_gen_br(label2); + gen_set_label(label1); + tcg_gen_ori_i32(cpu_sr, cpu_sr, SR_T); + gen_set_label(label2); + tcg_temp_free(cmp2); + tcg_temp_free(cmp1); + } return; case 0x2007: /* div0s Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_div0s_T0_T1(); - gen_op_movl_T1_rN(REG(B11_8)); + { + gen_copy_bit_i32(cpu_sr, 8, REG(B11_8), 31); /* SR_Q */ + gen_copy_bit_i32(cpu_sr, 9, REG(B7_4), 31); /* SR_M */ + TCGv val = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_xor_i32(val, REG(B7_4), REG(B11_8)); + gen_copy_bit_i32(cpu_sr, 0, val, 31); /* SR_T */ + tcg_temp_free(val); + } return; case 0x3004: /* div1 Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_div1_T0_T1(); - gen_op_movl_T1_rN(REG(B11_8)); + tcg_gen_helper_1_2(helper_div1, REG(B11_8), REG(B7_4), REG(B11_8)); return; case 0x300d: /* dmuls.l Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_dmulsl_T0_T1(); + { + TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_ext_i32_i64(tmp1, REG(B7_4)); + tcg_gen_ext_i32_i64(tmp2, REG(B11_8)); + tcg_gen_mul_i64(tmp1, tmp1, tmp2); + tcg_gen_trunc_i64_i32(cpu_macl, tmp1); + tcg_gen_shri_i64(tmp1, tmp1, 32); + tcg_gen_trunc_i64_i32(cpu_mach, tmp1); + + tcg_temp_free(tmp2); + tcg_temp_free(tmp1); + } return; case 0x3005: /* dmulu.l Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_dmulul_T0_T1(); + { + TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64); + TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_extu_i32_i64(tmp1, REG(B7_4)); + tcg_gen_extu_i32_i64(tmp2, REG(B11_8)); + tcg_gen_mul_i64(tmp1, tmp1, tmp2); + tcg_gen_trunc_i64_i32(cpu_macl, tmp1); + tcg_gen_shri_i64(tmp1, tmp1, 32); + tcg_gen_trunc_i64_i32(cpu_mach, tmp1); + + tcg_temp_free(tmp2); + tcg_temp_free(tmp1); + } return; case 0x600e: /* exts.b Rm,Rn */ - gen_op_movb_rN_T0(REG(B7_4)); - gen_op_movl_T0_rN(REG(B11_8)); + tcg_gen_ext8s_i32(REG(B11_8), REG(B7_4)); return; case 0x600f: /* exts.w Rm,Rn */ - gen_op_movw_rN_T0(REG(B7_4)); - gen_op_movl_T0_rN(REG(B11_8)); + tcg_gen_ext16s_i32(REG(B11_8), REG(B7_4)); return; case 0x600c: /* extu.b Rm,Rn */ - gen_op_movub_rN_T0(REG(B7_4)); - gen_op_movl_T0_rN(REG(B11_8)); + tcg_gen_ext8u_i32(REG(B11_8), REG(B7_4)); return; case 0x600d: /* extu.w Rm,Rn */ - gen_op_movuw_rN_T0(REG(B7_4)); - gen_op_movl_T0_rN(REG(B11_8)); + tcg_gen_ext16u_i32(REG(B11_8), REG(B7_4)); return; - case 0x000f: /* mac.l @Rm+,@Rn- */ - gen_op_movl_rN_T0(REG(B11_8)); - gen_op_ldl_T0_T0(ctx); - gen_op_movl_T0_T1(); - gen_op_movl_rN_T1(REG(B7_4)); - gen_op_ldl_T0_T0(ctx); - gen_op_macl_T0_T1(); - gen_op_inc4_rN(REG(B7_4)); - gen_op_inc4_rN(REG(B11_8)); + case 0x000f: /* mac.l @Rm+,@Rn+ */ + { + TCGv arg0, arg1; + arg0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_qemu_ld32s(arg0, REG(B7_4), ctx->memidx); + arg1 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_qemu_ld32s(arg1, REG(B11_8), ctx->memidx); + tcg_gen_helper_0_2(helper_macl, arg0, arg1); + tcg_temp_free(arg1); + tcg_temp_free(arg0); + tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4); + tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); + } return; case 0x400f: /* mac.w @Rm+,@Rn+ */ - gen_op_movl_rN_T0(REG(B11_8)); - gen_op_ldl_T0_T0(ctx); - gen_op_movl_T0_T1(); - gen_op_movl_rN_T1(REG(B7_4)); - gen_op_ldl_T0_T0(ctx); - gen_op_macw_T0_T1(); - gen_op_inc2_rN(REG(B7_4)); - gen_op_inc2_rN(REG(B11_8)); + { + TCGv arg0, arg1; + arg0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_qemu_ld32s(arg0, REG(B7_4), ctx->memidx); + arg1 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_qemu_ld32s(arg1, REG(B11_8), ctx->memidx); + tcg_gen_helper_0_2(helper_macw, arg0, arg1); + tcg_temp_free(arg1); + tcg_temp_free(arg0); + tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 2); + tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 2); + } return; case 0x0007: /* mul.l Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_mull_T0_T1(); + tcg_gen_mul_i32(cpu_macl, REG(B7_4), REG(B11_8)); return; case 0x200f: /* muls.w Rm,Rn */ - gen_op_movw_rN_T0(REG(B7_4)); - gen_op_movw_rN_T1(REG(B11_8)); - gen_op_mulsw_T0_T1(); + { + TCGv arg0, arg1; + arg0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_ext16s_i32(arg0, REG(B7_4)); + arg1 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_ext16s_i32(arg1, REG(B11_8)); + tcg_gen_mul_i32(cpu_macl, arg0, arg1); + tcg_temp_free(arg1); + tcg_temp_free(arg0); + } return; case 0x200e: /* mulu.w Rm,Rn */ - gen_op_movuw_rN_T0(REG(B7_4)); - gen_op_movuw_rN_T1(REG(B11_8)); - gen_op_muluw_T0_T1(); + { + TCGv arg0, arg1; + arg0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_ext16u_i32(arg0, REG(B7_4)); + arg1 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_ext16u_i32(arg1, REG(B11_8)); + tcg_gen_mul_i32(cpu_macl, arg0, arg1); + tcg_temp_free(arg1); + tcg_temp_free(arg0); + } return; case 0x600b: /* neg Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_neg_T0(); - gen_op_movl_T0_rN(REG(B11_8)); + tcg_gen_neg_i32(REG(B11_8), REG(B7_4)); return; case 0x600a: /* negc Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_negc_T0(); - gen_op_movl_T0_rN(REG(B11_8)); + tcg_gen_helper_1_1(helper_negc, REG(B11_8), REG(B7_4)); return; case 0x6007: /* not Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_not_T0(); - gen_op_movl_T0_rN(REG(B11_8)); + tcg_gen_not_i32(REG(B11_8), REG(B7_4)); return; case 0x200b: /* or Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_or_T0_rN(REG(B11_8)); + tcg_gen_or_i32(REG(B11_8), REG(B11_8), REG(B7_4)); return; case 0x400c: /* shad Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_shad_T0_T1(); - gen_op_movl_T1_rN(REG(B11_8)); + { + int label1 = gen_new_label(); + int label2 = gen_new_label(); + int label3 = gen_new_label(); + int label4 = gen_new_label(); + TCGv shift = tcg_temp_local_new(TCG_TYPE_I32); + tcg_gen_brcondi_i32(TCG_COND_LT, REG(B7_4), 0, label1); + /* Rm positive, shift to the left */ + tcg_gen_andi_i32(shift, REG(B7_4), 0x1f); + tcg_gen_shl_i32(REG(B11_8), REG(B11_8), shift); + tcg_gen_br(label4); + /* Rm negative, shift to the right */ + gen_set_label(label1); + tcg_gen_andi_i32(shift, REG(B7_4), 0x1f); + tcg_gen_brcondi_i32(TCG_COND_EQ, shift, 0, label2); + tcg_gen_not_i32(shift, REG(B7_4)); + tcg_gen_andi_i32(shift, shift, 0x1f); + tcg_gen_addi_i32(shift, shift, 1); + tcg_gen_sar_i32(REG(B11_8), REG(B11_8), shift); + tcg_gen_br(label4); + /* Rm = -32 */ + gen_set_label(label2); + tcg_gen_brcondi_i32(TCG_COND_LT, REG(B11_8), 0, label3); + tcg_gen_movi_i32(REG(B11_8), 0); + tcg_gen_br(label4); + gen_set_label(label3); + tcg_gen_movi_i32(REG(B11_8), 0xffffffff); + gen_set_label(label4); + tcg_temp_free(shift); + } return; case 0x400d: /* shld Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_shld_T0_T1(); - gen_op_movl_T1_rN(REG(B11_8)); + { + int label1 = gen_new_label(); + int label2 = gen_new_label(); + int label3 = gen_new_label(); + TCGv shift = tcg_temp_local_new(TCG_TYPE_I32); + tcg_gen_brcondi_i32(TCG_COND_LT, REG(B7_4), 0, label1); + /* Rm positive, shift to the left */ + tcg_gen_andi_i32(shift, REG(B7_4), 0x1f); + tcg_gen_shl_i32(REG(B11_8), REG(B11_8), shift); + tcg_gen_br(label3); + /* Rm negative, shift to the right */ + gen_set_label(label1); + tcg_gen_andi_i32(shift, REG(B7_4), 0x1f); + tcg_gen_brcondi_i32(TCG_COND_EQ, shift, 0, label2); + tcg_gen_not_i32(shift, REG(B7_4)); + tcg_gen_andi_i32(shift, shift, 0x1f); + tcg_gen_addi_i32(shift, shift, 1); + tcg_gen_shr_i32(REG(B11_8), REG(B11_8), shift); + tcg_gen_br(label3); + /* Rm = -32 */ + gen_set_label(label2); + tcg_gen_movi_i32(REG(B11_8), 0); + gen_set_label(label3); + tcg_temp_free(shift); + } return; case 0x3008: /* sub Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_sub_T0_rN(REG(B11_8)); + tcg_gen_sub_i32(REG(B11_8), REG(B11_8), REG(B7_4)); return; case 0x300a: /* subc Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_subc_T0_T1(); - gen_op_movl_T1_rN(REG(B11_8)); + tcg_gen_helper_1_2(helper_subc, REG(B11_8), REG(B7_4), REG(B11_8)); return; case 0x300b: /* subv Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_subv_T0_T1(); - gen_op_movl_T1_rN(REG(B11_8)); + tcg_gen_helper_1_2(helper_subv, REG(B11_8), REG(B7_4), REG(B11_8)); return; case 0x2008: /* tst Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_tst_T0_T1(); + { + TCGv val = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_and_i32(val, REG(B7_4), REG(B11_8)); + gen_cmp_imm(TCG_COND_EQ, val, 0); + tcg_temp_free(val); + } return; case 0x200a: /* xor Rm,Rn */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_xor_T0_rN(REG(B11_8)); + tcg_gen_xor_i32(REG(B11_8), REG(B11_8), REG(B7_4)); return; case 0xf00c: /* fmov {F,D,X}Rm,{F,D,X}Rn - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_SZ) { - if (ctx->opcode & 0x0110) - break; /* illegal instruction */ - gen_op_fmov_drN_DT0(DREG(B7_4)); - gen_op_fmov_DT0_drN(DREG(B11_8)); + TCGv fp = tcg_temp_new(TCG_TYPE_I64); + gen_load_fpr64(fp, XREG(B7_4)); + gen_store_fpr64(fp, XREG(B11_8)); + tcg_temp_free(fp); } else { - gen_op_fmov_frN_FT0(FREG(B7_4)); - gen_op_fmov_FT0_frN(FREG(B11_8)); + TCGv fp = tcg_temp_new(TCG_TYPE_I32); + gen_load_fpr32(fp, FREG(B7_4)); + gen_store_fpr32(fp, FREG(B11_8)); + tcg_temp_free(fp); } return; case 0xf00a: /* fmov {F,D,X}Rm,@Rn - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_SZ) { - if (ctx->opcode & 0x0010) - break; /* illegal instruction */ - gen_op_fmov_drN_DT0(DREG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_stfq_DT0_T1(ctx); + TCGv fp = tcg_temp_new(TCG_TYPE_I64); + gen_load_fpr64(fp, XREG(B7_4)); + tcg_gen_qemu_st64(fp, REG(B11_8), ctx->memidx); + tcg_temp_free(fp); } else { - gen_op_fmov_frN_FT0(FREG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_stfl_FT0_T1(ctx); + TCGv fp = tcg_temp_new(TCG_TYPE_I32); + gen_load_fpr32(fp, FREG(B7_4)); + tcg_gen_qemu_st32(fp, REG(B11_8), ctx->memidx); + tcg_temp_free(fp); } return; case 0xf008: /* fmov @Rm,{F,D,X}Rn - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_SZ) { - if (ctx->opcode & 0x0100) - break; /* illegal instruction */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_ldfq_T0_DT0(ctx); - gen_op_fmov_DT0_drN(DREG(B11_8)); + TCGv fp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_qemu_ld64(fp, REG(B7_4), ctx->memidx); + gen_store_fpr64(fp, XREG(B11_8)); + tcg_temp_free(fp); } else { - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_ldfl_T0_FT0(ctx); - gen_op_fmov_FT0_frN(FREG(B11_8)); + TCGv fp = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_qemu_ld32u(fp, REG(B7_4), ctx->memidx); + gen_store_fpr32(fp, FREG(B11_8)); + tcg_temp_free(fp); } return; case 0xf009: /* fmov @Rm+,{F,D,X}Rn - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_SZ) { - if (ctx->opcode & 0x0100) - break; /* illegal instruction */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_ldfq_T0_DT0(ctx); - gen_op_fmov_DT0_drN(DREG(B11_8)); - gen_op_inc8_rN(REG(B7_4)); + TCGv fp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_qemu_ld64(fp, REG(B7_4), ctx->memidx); + gen_store_fpr64(fp, XREG(B11_8)); + tcg_temp_free(fp); + tcg_gen_addi_i32(REG(B7_4),REG(B7_4), 8); } else { - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_ldfl_T0_FT0(ctx); - gen_op_fmov_FT0_frN(FREG(B11_8)); - gen_op_inc4_rN(REG(B7_4)); + TCGv fp = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_qemu_ld32u(fp, REG(B7_4), ctx->memidx); + gen_store_fpr32(fp, FREG(B11_8)); + tcg_temp_free(fp); + tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4); } return; case 0xf00b: /* fmov {F,D,X}Rm,@-Rn - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_SZ) { - if (ctx->opcode & 0x0100) - break; /* illegal instruction */ - gen_op_dec8_rN(REG(B11_8)); - gen_op_fmov_drN_DT0(DREG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_stfq_DT0_T1(ctx); + TCGv addr, fp; + addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_subi_i32(addr, REG(B11_8), 8); + fp = tcg_temp_new(TCG_TYPE_I64); + gen_load_fpr64(fp, XREG(B7_4)); + tcg_gen_qemu_st64(fp, addr, ctx->memidx); + tcg_temp_free(fp); + tcg_temp_free(addr); + tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 8); } else { - gen_op_dec4_rN(REG(B11_8)); - gen_op_fmov_frN_FT0(FREG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_stfl_FT0_T1(ctx); + TCGv addr, fp; + addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_subi_i32(addr, REG(B11_8), 4); + fp = tcg_temp_new(TCG_TYPE_I32); + gen_load_fpr32(fp, FREG(B7_4)); + tcg_gen_qemu_st32(fp, addr, ctx->memidx); + tcg_temp_free(fp); + tcg_temp_free(addr); + tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4); } return; case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm - FPSCR: Nothing */ - if (ctx->fpscr & FPSCR_SZ) { - if (ctx->opcode & 0x0100) - break; /* illegal instruction */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_add_rN_T0(REG(0)); - gen_op_ldfq_T0_DT0(ctx); - gen_op_fmov_DT0_drN(DREG(B11_8)); - } else { - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_add_rN_T0(REG(0)); - gen_op_ldfl_T0_FT0(ctx); - gen_op_fmov_FT0_frN(FREG(B11_8)); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_add_i32(addr, REG(B7_4), REG(0)); + if (ctx->fpscr & FPSCR_SZ) { + TCGv fp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_qemu_ld64(fp, addr, ctx->memidx); + gen_store_fpr64(fp, XREG(B11_8)); + tcg_temp_free(fp); + } else { + TCGv fp = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_qemu_ld32u(fp, addr, ctx->memidx); + gen_store_fpr32(fp, FREG(B11_8)); + tcg_temp_free(fp); + } + tcg_temp_free(addr); } return; case 0xf007: /* fmov {F,D,X}Rn,@(R0,Rn) - FPSCR: Nothing */ - if (ctx->fpscr & FPSCR_SZ) { - if (ctx->opcode & 0x0010) - break; /* illegal instruction */ - gen_op_fmov_drN_DT0(DREG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_add_rN_T1(REG(0)); - gen_op_stfq_DT0_T1(ctx); - } else { - gen_op_fmov_frN_FT0(FREG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_add_rN_T1(REG(0)); - gen_op_stfl_FT0_T1(ctx); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_add_i32(addr, REG(B11_8), REG(0)); + if (ctx->fpscr & FPSCR_SZ) { + TCGv fp = tcg_temp_new(TCG_TYPE_I64); + gen_load_fpr64(fp, XREG(B7_4)); + tcg_gen_qemu_st64(fp, addr, ctx->memidx); + tcg_temp_free(fp); + } else { + TCGv fp = tcg_temp_new(TCG_TYPE_I32); + gen_load_fpr32(fp, FREG(B7_4)); + tcg_gen_qemu_st32(fp, addr, ctx->memidx); + tcg_temp_free(fp); + } + tcg_temp_free(addr); } return; case 0xf000: /* fadd Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */ @@ -751,56 +1099,91 @@ case 0xf003: /* fdiv Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */ case 0xf004: /* fcmp/eq Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */ case 0xf005: /* fcmp/gt Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */ - if (ctx->fpscr & FPSCR_PR) { - if (ctx->opcode & 0x0110) - break; /* illegal instruction */ - gen_op_fmov_drN_DT1(DREG(B7_4)); - gen_op_fmov_drN_DT0(DREG(B11_8)); - } - else { - gen_op_fmov_frN_FT1(FREG(B7_4)); - gen_op_fmov_frN_FT0(FREG(B11_8)); - } + { + TCGv fp0, fp1; - switch (ctx->opcode & 0xf00f) { - case 0xf000: /* fadd Rm,Rn */ - ctx->fpscr & FPSCR_PR ? gen_op_fadd_DT() : gen_op_fadd_FT(); - break; - case 0xf001: /* fsub Rm,Rn */ - ctx->fpscr & FPSCR_PR ? gen_op_fsub_DT() : gen_op_fsub_FT(); - break; - case 0xf002: /* fmul Rm,Rn */ - ctx->fpscr & FPSCR_PR ? gen_op_fmul_DT() : gen_op_fmul_FT(); - break; - case 0xf003: /* fdiv Rm,Rn */ - ctx->fpscr & FPSCR_PR ? gen_op_fdiv_DT() : gen_op_fdiv_FT(); - break; - case 0xf004: /* fcmp/eq Rm,Rn */ - return; - case 0xf005: /* fcmp/gt Rm,Rn */ - return; - } + if (ctx->fpscr & FPSCR_PR) { + if (ctx->opcode & 0x0110) + break; /* illegal instruction */ + fp0 = tcg_temp_new(TCG_TYPE_I64); + fp1 = tcg_temp_new(TCG_TYPE_I64); + gen_load_fpr64(fp0, DREG(B11_8)); + gen_load_fpr64(fp1, DREG(B7_4)); + } + else { + fp0 = tcg_temp_new(TCG_TYPE_I32); + fp1 = tcg_temp_new(TCG_TYPE_I32); + gen_load_fpr32(fp0, FREG(B11_8)); + gen_load_fpr32(fp1, FREG(B7_4)); + } - if (ctx->fpscr & FPSCR_PR) { - gen_op_fmov_DT0_drN(DREG(B11_8)); - } - else { - gen_op_fmov_FT0_frN(FREG(B11_8)); + switch (ctx->opcode & 0xf00f) { + case 0xf000: /* fadd Rm,Rn */ + if (ctx->fpscr & FPSCR_PR) + tcg_gen_helper_1_2(helper_fadd_DT, fp0, fp0, fp1); + else + tcg_gen_helper_1_2(helper_fadd_FT, fp0, fp0, fp1); + break; + case 0xf001: /* fsub Rm,Rn */ + if (ctx->fpscr & FPSCR_PR) + tcg_gen_helper_1_2(helper_fsub_DT, fp0, fp0, fp1); + else + tcg_gen_helper_1_2(helper_fsub_FT, fp0, fp0, fp1); + break; + case 0xf002: /* fmul Rm,Rn */ + if (ctx->fpscr & FPSCR_PR) + tcg_gen_helper_1_2(helper_fmul_DT, fp0, fp0, fp1); + else + tcg_gen_helper_1_2(helper_fmul_FT, fp0, fp0, fp1); + break; + case 0xf003: /* fdiv Rm,Rn */ + if (ctx->fpscr & FPSCR_PR) + tcg_gen_helper_1_2(helper_fdiv_DT, fp0, fp0, fp1); + else + tcg_gen_helper_1_2(helper_fdiv_FT, fp0, fp0, fp1); + break; + case 0xf004: /* fcmp/eq Rm,Rn */ + if (ctx->fpscr & FPSCR_PR) + tcg_gen_helper_0_2(helper_fcmp_eq_DT, fp0, fp1); + else + tcg_gen_helper_0_2(helper_fcmp_eq_FT, fp0, fp1); + return; + case 0xf005: /* fcmp/gt Rm,Rn */ + if (ctx->fpscr & FPSCR_PR) + tcg_gen_helper_0_2(helper_fcmp_gt_DT, fp0, fp1); + else + tcg_gen_helper_0_2(helper_fcmp_gt_FT, fp0, fp1); + return; + } + + if (ctx->fpscr & FPSCR_PR) { + gen_store_fpr64(fp0, DREG(B11_8)); + } + else { + gen_store_fpr32(fp0, FREG(B11_8)); + } + tcg_temp_free(fp1); + tcg_temp_free(fp0); } return; } switch (ctx->opcode & 0xff00) { case 0xc900: /* and #imm,R0 */ - gen_op_and_imm_rN(B7_0, REG(0)); + tcg_gen_andi_i32(REG(0), REG(0), B7_0); return; - case 0xcd00: /* and.b #imm,@(R0+GBR) */ - gen_op_movl_rN_T0(REG(0)); - gen_op_addl_GBR_T0(); - gen_op_movl_T0_T1(); - gen_op_ldb_T0_T0(ctx); - gen_op_and_imm_T0(B7_0); - gen_op_stb_T0_T1(ctx); + case 0xcd00: /* and.b #imm,@(R0,GBR) */ + { + TCGv addr, val; + addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_add_i32(addr, REG(0), cpu_gbr); + val = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_qemu_ld8u(val, addr, ctx->memidx); + tcg_gen_andi_i32(val, val, B7_0); + tcg_gen_qemu_st8(val, addr, ctx->memidx); + tcg_temp_free(val); + tcg_temp_free(addr); + } return; case 0x8b00: /* bf label */ CHECK_NOT_DELAY_SLOT @@ -810,7 +1193,7 @@ return; case 0x8f00: /* bf/s label */ CHECK_NOT_DELAY_SLOT - gen_op_bf_s(ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2); + gen_branch_slot(ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2, 0); ctx->flags |= DELAY_SLOT_CONDITIONAL; return; case 0x8900: /* bt label */ @@ -821,331 +1204,565 @@ return; case 0x8d00: /* bt/s label */ CHECK_NOT_DELAY_SLOT - gen_op_bt_s(ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2); + gen_branch_slot(ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2, 1); ctx->flags |= DELAY_SLOT_CONDITIONAL; return; case 0x8800: /* cmp/eq #imm,R0 */ - gen_op_movl_rN_T0(REG(0)); - gen_op_cmp_eq_imm_T0(B7_0s); + gen_cmp_imm(TCG_COND_EQ, REG(0), B7_0s); return; case 0xc400: /* mov.b @(disp,GBR),R0 */ - gen_op_stc_gbr_T0(); - gen_op_addl_imm_T0(B7_0); - gen_op_ldb_T0_T0(ctx); - gen_op_movl_T0_rN(REG(0)); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_addi_i32(addr, cpu_gbr, B7_0); + tcg_gen_qemu_ld8s(REG(0), addr, ctx->memidx); + tcg_temp_free(addr); + } return; case 0xc500: /* mov.w @(disp,GBR),R0 */ - gen_op_stc_gbr_T0(); - gen_op_addl_imm_T0(B7_0); - gen_op_ldw_T0_T0(ctx); - gen_op_movl_T0_rN(REG(0)); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 2); + tcg_gen_qemu_ld16s(REG(0), addr, ctx->memidx); + tcg_temp_free(addr); + } return; case 0xc600: /* mov.l @(disp,GBR),R0 */ - gen_op_stc_gbr_T0(); - gen_op_addl_imm_T0(B7_0); - gen_op_ldl_T0_T0(ctx); - gen_op_movl_T0_rN(REG(0)); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 4); + tcg_gen_qemu_ld32s(REG(0), addr, ctx->memidx); + tcg_temp_free(addr); + } return; case 0xc000: /* mov.b R0,@(disp,GBR) */ - gen_op_stc_gbr_T0(); - gen_op_addl_imm_T0(B7_0); - gen_op_movl_T0_T1(); - gen_op_movl_rN_T0(REG(0)); - gen_op_stb_T0_T1(ctx); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_addi_i32(addr, cpu_gbr, B7_0); + tcg_gen_qemu_st8(REG(0), addr, ctx->memidx); + tcg_temp_free(addr); + } return; case 0xc100: /* mov.w R0,@(disp,GBR) */ - gen_op_stc_gbr_T0(); - gen_op_addl_imm_T0(B7_0); - gen_op_movl_T0_T1(); - gen_op_movl_rN_T0(REG(0)); - gen_op_stw_T0_T1(ctx); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 2); + tcg_gen_qemu_st16(REG(0), addr, ctx->memidx); + tcg_temp_free(addr); + } return; case 0xc200: /* mov.l R0,@(disp,GBR) */ - gen_op_stc_gbr_T0(); - gen_op_addl_imm_T0(B7_0); - gen_op_movl_T0_T1(); - gen_op_movl_rN_T0(REG(0)); - gen_op_stl_T0_T1(ctx); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 4); + tcg_gen_qemu_st32(REG(0), addr, ctx->memidx); + tcg_temp_free(addr); + } return; case 0x8000: /* mov.b R0,@(disp,Rn) */ - gen_op_movl_rN_T0(REG(0)); - gen_op_movl_rN_T1(REG(B7_4)); - gen_op_addl_imm_T1(B3_0); - gen_op_stb_T0_T1(ctx); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_addi_i32(addr, REG(B7_4), B3_0); + tcg_gen_qemu_st8(REG(0), addr, ctx->memidx); + tcg_temp_free(addr); + } return; case 0x8100: /* mov.w R0,@(disp,Rn) */ - gen_op_movl_rN_T0(REG(0)); - gen_op_movl_rN_T1(REG(B7_4)); - gen_op_addl_imm_T1(B3_0 * 2); - gen_op_stw_T0_T1(ctx); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 2); + tcg_gen_qemu_st16(REG(0), addr, ctx->memidx); + tcg_temp_free(addr); + } return; case 0x8400: /* mov.b @(disp,Rn),R0 */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_addl_imm_T0(B3_0); - gen_op_ldb_T0_T0(ctx); - gen_op_movl_T0_rN(REG(0)); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_addi_i32(addr, REG(B7_4), B3_0); + tcg_gen_qemu_ld8s(REG(0), addr, ctx->memidx); + tcg_temp_free(addr); + } return; case 0x8500: /* mov.w @(disp,Rn),R0 */ - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_addl_imm_T0(B3_0 * 2); - gen_op_ldw_T0_T0(ctx); - gen_op_movl_T0_rN(REG(0)); + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 2); + tcg_gen_qemu_ld16s(REG(0), addr, ctx->memidx); + tcg_temp_free(addr); + } return; case 0xc700: /* mova @(disp,PC),R0 */ - gen_op_movl_imm_rN(((ctx->pc & 0xfffffffc) + 4 + B7_0 * 4) & ~3, - REG(0)); + tcg_gen_movi_i32(REG(0), ((ctx->pc & 0xfffffffc) + 4 + B7_0 * 4) & ~3); return; case 0xcb00: /* or #imm,R0 */ - gen_op_or_imm_rN(B7_0, REG(0)); + tcg_gen_ori_i32(REG(0), REG(0), B7_0); return; - case 0xcf00: /* or.b #imm,@(R0+GBR) */ - gen_op_movl_rN_T0(REG(0)); - gen_op_addl_GBR_T0(); - gen_op_movl_T0_T1(); - gen_op_ldb_T0_T0(ctx); - gen_op_or_imm_T0(B7_0); - gen_op_stb_T0_T1(ctx); + case 0xcf00: /* or.b #imm,@(R0,GBR) */ + { + TCGv addr, val; + addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_add_i32(addr, REG(0), cpu_gbr); + val = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_qemu_ld8u(val, addr, ctx->memidx); + tcg_gen_ori_i32(val, val, B7_0); + tcg_gen_qemu_st8(val, addr, ctx->memidx); + tcg_temp_free(val); + tcg_temp_free(addr); + } return; case 0xc300: /* trapa #imm */ - CHECK_NOT_DELAY_SLOT gen_op_movl_imm_PC(ctx->pc); - gen_op_trapa(B7_0); - ctx->bstate = BS_BRANCH; + { + TCGv imm; + CHECK_NOT_DELAY_SLOT + tcg_gen_movi_i32(cpu_pc, ctx->pc); + imm = tcg_const_i32(B7_0); + tcg_gen_helper_0_1(helper_trapa, imm); + tcg_temp_free(imm); + ctx->bstate = BS_BRANCH; + } return; case 0xc800: /* tst #imm,R0 */ - gen_op_tst_imm_rN(B7_0, REG(0)); + { + TCGv val = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_andi_i32(val, REG(0), B7_0); + gen_cmp_imm(TCG_COND_EQ, val, 0); + tcg_temp_free(val); + } return; - case 0xcc00: /* tst #imm,@(R0+GBR) */ - gen_op_movl_rN_T0(REG(0)); - gen_op_addl_GBR_T0(); - gen_op_ldb_T0_T0(ctx); - gen_op_tst_imm_T0(B7_0); + case 0xcc00: /* tst.b #imm,@(R0,GBR) */ + { + TCGv val = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_add_i32(val, REG(0), cpu_gbr); + tcg_gen_qemu_ld8u(val, val, ctx->memidx); + tcg_gen_andi_i32(val, val, B7_0); + gen_cmp_imm(TCG_COND_EQ, val, 0); + tcg_temp_free(val); + } return; case 0xca00: /* xor #imm,R0 */ - gen_op_xor_imm_rN(B7_0, REG(0)); + tcg_gen_xori_i32(REG(0), REG(0), B7_0); return; - case 0xce00: /* xor.b #imm,@(R0+GBR) */ - gen_op_movl_rN_T0(REG(0)); - gen_op_addl_GBR_T0(); - gen_op_movl_T0_T1(); - gen_op_ldb_T0_T0(ctx); - gen_op_xor_imm_T0(B7_0); - gen_op_stb_T0_T1(ctx); + case 0xce00: /* xor.b #imm,@(R0,GBR) */ + { + TCGv addr, val; + addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_add_i32(addr, REG(0), cpu_gbr); + val = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_qemu_ld8u(val, addr, ctx->memidx); + tcg_gen_xori_i32(val, val, B7_0); + tcg_gen_qemu_st8(val, addr, ctx->memidx); + tcg_temp_free(val); + tcg_temp_free(addr); + } return; } switch (ctx->opcode & 0xf08f) { case 0x408e: /* ldc Rm,Rn_BANK */ - gen_op_movl_rN_rN(REG(B11_8), ALTREG(B6_4)); + CHECK_PRIVILEGED + tcg_gen_mov_i32(ALTREG(B6_4), REG(B11_8)); return; case 0x4087: /* ldc.l @Rm+,Rn_BANK */ - gen_op_movl_rN_T0(REG(B11_8)); - gen_op_ldl_T0_T0(ctx); - gen_op_movl_T0_rN(ALTREG(B6_4)); - gen_op_inc4_rN(REG(B11_8)); + CHECK_PRIVILEGED + tcg_gen_qemu_ld32s(ALTREG(B6_4), REG(B11_8), ctx->memidx); + tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); return; case 0x0082: /* stc Rm_BANK,Rn */ - gen_op_movl_rN_rN(ALTREG(B6_4), REG(B11_8)); + CHECK_PRIVILEGED + tcg_gen_mov_i32(REG(B11_8), ALTREG(B6_4)); return; case 0x4083: /* stc.l Rm_BANK,@-Rn */ - gen_op_dec4_rN(REG(B11_8)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_movl_rN_T0(ALTREG(B6_4)); - gen_op_stl_T0_T1(ctx); + CHECK_PRIVILEGED + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_subi_i32(addr, REG(B11_8), 4); + tcg_gen_qemu_st32(ALTREG(B6_4), addr, ctx->memidx); + tcg_temp_free(addr); + tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4); + } return; } switch (ctx->opcode & 0xf0ff) { case 0x0023: /* braf Rn */ - CHECK_NOT_DELAY_SLOT gen_op_movl_rN_T0(REG(B11_8)); - gen_op_braf_T0(ctx->pc + 4); + CHECK_NOT_DELAY_SLOT + tcg_gen_addi_i32(cpu_delayed_pc, REG(B11_8), ctx->pc + 4); ctx->flags |= DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; return; case 0x0003: /* bsrf Rn */ - CHECK_NOT_DELAY_SLOT gen_op_movl_rN_T0(REG(B11_8)); - gen_op_bsrf_T0(ctx->pc + 4); + CHECK_NOT_DELAY_SLOT + tcg_gen_movi_i32(cpu_pr, ctx->pc + 4); + tcg_gen_add_i32(cpu_delayed_pc, REG(B11_8), cpu_pr); ctx->flags |= DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; return; case 0x4015: /* cmp/pl Rn */ - gen_op_movl_rN_T0(REG(B11_8)); - gen_op_cmp_pl_T0(); + gen_cmp_imm(TCG_COND_GT, REG(B11_8), 0); return; case 0x4011: /* cmp/pz Rn */ - gen_op_movl_rN_T0(REG(B11_8)); - gen_op_cmp_pz_T0(); + gen_cmp_imm(TCG_COND_GE, REG(B11_8), 0); return; case 0x4010: /* dt Rn */ - gen_op_dt_rN(REG(B11_8)); + tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 1); + gen_cmp_imm(TCG_COND_EQ, REG(B11_8), 0); return; case 0x402b: /* jmp @Rn */ - CHECK_NOT_DELAY_SLOT gen_op_movl_rN_T0(REG(B11_8)); - gen_op_jmp_T0(); + CHECK_NOT_DELAY_SLOT + tcg_gen_mov_i32(cpu_delayed_pc, REG(B11_8)); ctx->flags |= DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; return; case 0x400b: /* jsr @Rn */ - CHECK_NOT_DELAY_SLOT gen_op_movl_rN_T0(REG(B11_8)); - gen_op_jsr_T0(ctx->pc + 4); + CHECK_NOT_DELAY_SLOT + tcg_gen_movi_i32(cpu_pr, ctx->pc + 4); + tcg_gen_mov_i32(cpu_delayed_pc, REG(B11_8)); ctx->flags |= DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; return; -#define LDST(reg,ldnum,ldpnum,ldop,stnum,stpnum,stop,extrald) \ + case 0x400e: /* ldc Rm,SR */ + CHECK_PRIVILEGED + tcg_gen_andi_i32(cpu_sr, REG(B11_8), 0x700083f3); + ctx->bstate = BS_STOP; + return; + case 0x4007: /* ldc.l @Rm+,SR */ + CHECK_PRIVILEGED + { + TCGv val = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_qemu_ld32s(val, REG(B11_8), ctx->memidx); + tcg_gen_andi_i32(cpu_sr, val, 0x700083f3); + tcg_temp_free(val); + tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); + ctx->bstate = BS_STOP; + } + return; + case 0x0002: /* stc SR,Rn */ + CHECK_PRIVILEGED + tcg_gen_mov_i32(REG(B11_8), cpu_sr); + return; + case 0x4003: /* stc SR,@-Rn */ + CHECK_PRIVILEGED + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_subi_i32(addr, REG(B11_8), 4); + tcg_gen_qemu_st32(cpu_sr, addr, ctx->memidx); + tcg_temp_free(addr); + tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4); + } + return; +#define LDST(reg,ldnum,ldpnum,stnum,stpnum,prechk) \ case ldnum: \ - gen_op_movl_rN_T0 (REG(B11_8)); \ - gen_op_##ldop##_T0_##reg (); \ - extrald \ + prechk \ + tcg_gen_mov_i32 (cpu_##reg, REG(B11_8)); \ return; \ case ldpnum: \ - gen_op_movl_rN_T0 (REG(B11_8)); \ - gen_op_ldl_T0_T0 (ctx); \ - gen_op_inc4_rN (REG(B11_8)); \ - gen_op_##ldop##_T0_##reg (); \ - extrald \ + prechk \ + tcg_gen_qemu_ld32s (cpu_##reg, REG(B11_8), ctx->memidx); \ + tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); \ return; \ case stnum: \ - gen_op_##stop##_##reg##_T0 (); \ - gen_op_movl_T0_rN (REG(B11_8)); \ + prechk \ + tcg_gen_mov_i32 (REG(B11_8), cpu_##reg); \ return; \ case stpnum: \ - gen_op_##stop##_##reg##_T0 (); \ - gen_op_dec4_rN (REG(B11_8)); \ - gen_op_movl_rN_T1 (REG(B11_8)); \ - gen_op_stl_T0_T1 (ctx); \ + prechk \ + { \ + TCGv addr = tcg_temp_new(TCG_TYPE_I32); \ + tcg_gen_subi_i32(addr, REG(B11_8), 4); \ + tcg_gen_qemu_st32 (cpu_##reg, addr, ctx->memidx); \ + tcg_temp_free(addr); \ + tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4); \ + } \ return; - LDST(sr, 0x400e, 0x4007, ldc, 0x0002, 0x4003, stc, ctx->bstate = - BS_STOP;) - LDST(gbr, 0x401e, 0x4017, ldc, 0x0012, 0x4013, stc,) - LDST(vbr, 0x402e, 0x4027, ldc, 0x0022, 0x4023, stc,) - LDST(ssr, 0x403e, 0x4037, ldc, 0x0032, 0x4033, stc,) - LDST(spc, 0x404e, 0x4047, ldc, 0x0042, 0x4043, stc,) - LDST(dbr, 0x40fa, 0x40f6, ldc, 0x00fa, 0x40f2, stc,) - LDST(mach, 0x400a, 0x4006, lds, 0x000a, 0x4002, sts,) - LDST(macl, 0x401a, 0x4016, lds, 0x001a, 0x4012, sts,) - LDST(pr, 0x402a, 0x4026, lds, 0x002a, 0x4022, sts,) - LDST(fpul, 0x405a, 0x4056, lds, 0x005a, 0x4052, sts,) - LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x4062, sts, ctx->bstate = - BS_STOP;) + LDST(gbr, 0x401e, 0x4017, 0x0012, 0x4013, {}) + LDST(vbr, 0x402e, 0x4027, 0x0022, 0x4023, CHECK_PRIVILEGED) + LDST(ssr, 0x403e, 0x4037, 0x0032, 0x4033, CHECK_PRIVILEGED) + LDST(spc, 0x404e, 0x4047, 0x0042, 0x4043, CHECK_PRIVILEGED) + LDST(dbr, 0x40fa, 0x40f6, 0x00fa, 0x40f2, CHECK_PRIVILEGED) + LDST(mach, 0x400a, 0x4006, 0x000a, 0x4002, {}) + LDST(macl, 0x401a, 0x4016, 0x001a, 0x4012, {}) + LDST(pr, 0x402a, 0x4026, 0x002a, 0x4022, {}) + LDST(fpul, 0x405a, 0x4056, 0x005a, 0x4052, {}) + case 0x406a: /* lds Rm,FPSCR */ + tcg_gen_helper_0_1(helper_ld_fpscr, REG(B11_8)); + ctx->bstate = BS_STOP; + return; + case 0x4066: /* lds.l @Rm+,FPSCR */ + { + TCGv addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_qemu_ld32s(addr, REG(B11_8), ctx->memidx); + tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); + tcg_gen_helper_0_1(helper_ld_fpscr, addr); + tcg_temp_free(addr); + ctx->bstate = BS_STOP; + } + return; + case 0x006a: /* sts FPSCR,Rn */ + tcg_gen_andi_i32(REG(B11_8), cpu_fpscr, 0x003fffff); + return; + case 0x4062: /* sts FPSCR,@-Rn */ + { + TCGv addr, val; + val = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_andi_i32(val, cpu_fpscr, 0x003fffff); + addr = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_subi_i32(addr, REG(B11_8), 4); + tcg_gen_qemu_st32(val, addr, ctx->memidx); + tcg_temp_free(addr); + tcg_temp_free(val); + tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4); + } + return; case 0x00c3: /* movca.l R0,@Rm */ - gen_op_movl_rN_T0(REG(0)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_stl_T0_T1(ctx); + tcg_gen_qemu_st32(REG(0), REG(B11_8), ctx->memidx); + return; + case 0x40a9: + /* MOVUA.L @Rm,R0 (Rm) -> R0 + Load non-boundary-aligned data */ + tcg_gen_qemu_ld32u(REG(0), REG(B11_8), ctx->memidx); + return; + case 0x40e9: + /* MOVUA.L @Rm+,R0 (Rm) -> R0, Rm + 4 -> Rm + Load non-boundary-aligned data */ + tcg_gen_qemu_ld32u(REG(0), REG(B11_8), ctx->memidx); + tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); return; case 0x0029: /* movt Rn */ - gen_op_movt_rN(REG(B11_8)); + tcg_gen_andi_i32(REG(B11_8), cpu_sr, SR_T); return; case 0x0093: /* ocbi @Rn */ - gen_op_movl_rN_T0(REG(B11_8)); - gen_op_ldl_T0_T0(ctx); + { + TCGv dummy = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_qemu_ld32s(dummy, REG(B11_8), ctx->memidx); + tcg_temp_free(dummy); + } return; - case 0x00a2: /* ocbp @Rn */ - gen_op_movl_rN_T0(REG(B11_8)); - gen_op_ldl_T0_T0(ctx); + case 0x00a3: /* ocbp @Rn */ + { + TCGv dummy = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_qemu_ld32s(dummy, REG(B11_8), ctx->memidx); + tcg_temp_free(dummy); + } return; case 0x00b3: /* ocbwb @Rn */ - gen_op_movl_rN_T0(REG(B11_8)); - gen_op_ldl_T0_T0(ctx); + { + TCGv dummy = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_qemu_ld32s(dummy, REG(B11_8), ctx->memidx); + tcg_temp_free(dummy); + } return; case 0x0083: /* pref @Rn */ return; case 0x4024: /* rotcl Rn */ - gen_op_rotcl_Rn(REG(B11_8)); + { + TCGv tmp = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_mov_i32(tmp, cpu_sr); + gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 31); + tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 1); + gen_copy_bit_i32(REG(B11_8), 0, tmp, 0); + tcg_temp_free(tmp); + } return; case 0x4025: /* rotcr Rn */ - gen_op_rotcr_Rn(REG(B11_8)); + { + TCGv tmp = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_mov_i32(tmp, cpu_sr); + gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 0); + tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 1); + gen_copy_bit_i32(REG(B11_8), 31, tmp, 0); + tcg_temp_free(tmp); + } return; case 0x4004: /* rotl Rn */ - gen_op_rotl_Rn(REG(B11_8)); + gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 31); + tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 1); + gen_copy_bit_i32(REG(B11_8), 0, cpu_sr, 0); return; case 0x4005: /* rotr Rn */ - gen_op_rotr_Rn(REG(B11_8)); + gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 0); + tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 1); + gen_copy_bit_i32(REG(B11_8), 31, cpu_sr, 0); return; case 0x4000: /* shll Rn */ case 0x4020: /* shal Rn */ - gen_op_shal_Rn(REG(B11_8)); + gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 31); + tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 1); return; case 0x4021: /* shar Rn */ - gen_op_shar_Rn(REG(B11_8)); + gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 0); + tcg_gen_sari_i32(REG(B11_8), REG(B11_8), 1); return; case 0x4001: /* shlr Rn */ - gen_op_shlr_Rn(REG(B11_8)); + gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 0); + tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 1); return; case 0x4008: /* shll2 Rn */ - gen_op_shll2_Rn(REG(B11_8)); + tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 2); return; case 0x4018: /* shll8 Rn */ - gen_op_shll8_Rn(REG(B11_8)); + tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 8); return; case 0x4028: /* shll16 Rn */ - gen_op_shll16_Rn(REG(B11_8)); + tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 16); return; case 0x4009: /* shlr2 Rn */ - gen_op_shlr2_Rn(REG(B11_8)); + tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 2); return; case 0x4019: /* shlr8 Rn */ - gen_op_shlr8_Rn(REG(B11_8)); + tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 8); return; case 0x4029: /* shlr16 Rn */ - gen_op_shlr16_Rn(REG(B11_8)); + tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 16); return; case 0x401b: /* tas.b @Rn */ - gen_op_tasb_rN(REG(B11_8)); + { + TCGv addr, val; + addr = tcg_temp_local_new(TCG_TYPE_I32); + tcg_gen_mov_i32(addr, REG(B11_8)); + val = tcg_temp_local_new(TCG_TYPE_I32); + tcg_gen_qemu_ld8u(val, addr, ctx->memidx); + gen_cmp_imm(TCG_COND_EQ, val, 0); + tcg_gen_ori_i32(val, val, 0x80); + tcg_gen_qemu_st8(val, addr, ctx->memidx); + tcg_temp_free(val); + tcg_temp_free(addr); + } return; case 0xf00d: /* fsts FPUL,FRn - FPSCR: Nothing */ - gen_op_movl_fpul_FT0(); - gen_op_fmov_FT0_frN(FREG(B11_8)); + { + TCGv fp = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_mov_i32(fp, cpu_fpul); + gen_store_fpr32(fp, FREG(B11_8)); + tcg_temp_free(fp); + } return; case 0xf01d: /* flds FRm,FPUL - FPSCR: Nothing */ - gen_op_fmov_frN_FT0(FREG(B11_8)); - gen_op_movl_FT0_fpul(); + { + TCGv fp = tcg_temp_new(TCG_TYPE_I32); + gen_load_fpr32(fp, FREG(B11_8)); + tcg_gen_mov_i32(cpu_fpul, fp); + tcg_temp_free(fp); + } return; case 0xf02d: /* float FPUL,FRn/DRn - FPSCR: R[PR,Enable.I]/W[Cause,Flag] */ if (ctx->fpscr & FPSCR_PR) { + TCGv fp; if (ctx->opcode & 0x0100) break; /* illegal instruction */ - gen_op_float_DT(); - gen_op_fmov_DT0_drN(DREG(B11_8)); + fp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_helper_1_1(helper_float_DT, fp, cpu_fpul); + gen_store_fpr64(fp, DREG(B11_8)); + tcg_temp_free(fp); } else { - gen_op_float_FT(); - gen_op_fmov_FT0_frN(FREG(B11_8)); + TCGv fp = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_helper_1_1(helper_float_FT, fp, cpu_fpul); + gen_store_fpr32(fp, FREG(B11_8)); + tcg_temp_free(fp); } return; case 0xf03d: /* ftrc FRm/DRm,FPUL - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */ if (ctx->fpscr & FPSCR_PR) { + TCGv fp; if (ctx->opcode & 0x0100) break; /* illegal instruction */ - gen_op_fmov_drN_DT0(DREG(B11_8)); - gen_op_ftrc_DT(); + fp = tcg_temp_new(TCG_TYPE_I64); + gen_load_fpr64(fp, DREG(B11_8)); + tcg_gen_helper_1_1(helper_ftrc_DT, cpu_fpul, fp); + tcg_temp_free(fp); } else { - gen_op_fmov_frN_FT0(FREG(B11_8)); - gen_op_ftrc_FT(); + TCGv fp = tcg_temp_new(TCG_TYPE_I32); + gen_load_fpr32(fp, FREG(B11_8)); + tcg_gen_helper_1_1(helper_ftrc_FT, cpu_fpul, fp); + tcg_temp_free(fp); + } + return; + case 0xf04d: /* fneg FRn/DRn - FPSCR: Nothing */ + { + TCGv fp = tcg_temp_new(TCG_TYPE_I32); + gen_load_fpr32(fp, FREG(B11_8)); + tcg_gen_helper_1_1(helper_fneg_T, fp, fp); + gen_store_fpr32(fp, FREG(B11_8)); + tcg_temp_free(fp); + } + return; + case 0xf05d: /* fabs FRn/DRn */ + if (ctx->fpscr & FPSCR_PR) { + if (ctx->opcode & 0x0100) + break; /* illegal instruction */ + TCGv fp = tcg_temp_new(TCG_TYPE_I64); + gen_load_fpr64(fp, DREG(B11_8)); + tcg_gen_helper_1_1(helper_fabs_DT, fp, fp); + gen_store_fpr64(fp, DREG(B11_8)); + tcg_temp_free(fp); + } else { + TCGv fp = tcg_temp_new(TCG_TYPE_I32); + gen_load_fpr32(fp, FREG(B11_8)); + tcg_gen_helper_1_1(helper_fabs_FT, fp, fp); + gen_store_fpr32(fp, FREG(B11_8)); + tcg_temp_free(fp); + } + return; + case 0xf06d: /* fsqrt FRn */ + if (ctx->fpscr & FPSCR_PR) { + if (ctx->opcode & 0x0100) + break; /* illegal instruction */ + TCGv fp = tcg_temp_new(TCG_TYPE_I64); + gen_load_fpr64(fp, DREG(B11_8)); + tcg_gen_helper_1_1(helper_fsqrt_DT, fp, fp); + gen_store_fpr64(fp, DREG(B11_8)); + tcg_temp_free(fp); + } else { + TCGv fp = tcg_temp_new(TCG_TYPE_I32); + gen_load_fpr32(fp, FREG(B11_8)); + tcg_gen_helper_1_1(helper_fsqrt_FT, fp, fp); + gen_store_fpr32(fp, FREG(B11_8)); + tcg_temp_free(fp); } return; + case 0xf07d: /* fsrra FRn */ + break; case 0xf08d: /* fldi0 FRn - FPSCR: R[PR] */ if (!(ctx->fpscr & FPSCR_PR)) { - gen_op_movl_imm_T0(0); - gen_op_fmov_T0_frN(FREG(B11_8)); + TCGv val = tcg_const_i32(0); + gen_load_fpr32(val, FREG(B11_8)); + tcg_temp_free(val); return; } break; case 0xf09d: /* fldi1 FRn - FPSCR: R[PR] */ if (!(ctx->fpscr & FPSCR_PR)) { - gen_op_movl_imm_T0(0x3f800000); - gen_op_fmov_T0_frN(FREG(B11_8)); + TCGv val = tcg_const_i32(0x3f800000); + gen_load_fpr32(val, FREG(B11_8)); + tcg_temp_free(val); return; } break; + case 0xf0ad: /* fcnvsd FPUL,DRn */ + { + TCGv fp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_helper_1_1(helper_fcnvsd_FT_DT, fp, cpu_fpul); + gen_store_fpr64(fp, DREG(B11_8)); + tcg_temp_free(fp); + } + return; + case 0xf0bd: /* fcnvds DRn,FPUL */ + { + TCGv fp = tcg_temp_new(TCG_TYPE_I64); + gen_load_fpr64(fp, DREG(B11_8)); + tcg_gen_helper_1_1(helper_fcnvds_DT_FT, cpu_fpul, fp); + tcg_temp_free(fp); + } + return; } fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n", ctx->opcode, ctx->pc); - gen_op_raise_illegal_instruction(); + tcg_gen_helper_0_0(helper_raise_illegal_instruction); ctx->bstate = BS_EXCP; } -void decode_opc(DisasContext * ctx) +static void decode_opc(DisasContext * ctx) { uint32_t old_flags = ctx->flags; @@ -1153,7 +1770,12 @@ if (old_flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { if (ctx->flags & DELAY_SLOT_CLEARME) { - gen_op_store_flags(0); + gen_store_flags(0); + } else { + /* go out of the delay slot */ + uint32_t new_flags = ctx->flags; + new_flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL); + gen_store_flags(new_flags); } ctx->flags = 0; ctx->bstate = BS_BRANCH; @@ -1164,9 +1786,13 @@ } } + + /* go into a delay slot */ + if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) + gen_store_flags(ctx->flags); } -static inline int +static inline void gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, int search_pc) { @@ -1174,11 +1800,11 @@ target_ulong pc_start; static uint16_t *gen_opc_end; int i, ii; + int num_insns; + int max_insns; pc_start = tb->pc; - gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; - gen_opparam_ptr = gen_opparam_buf; ctx.pc = pc_start; ctx.flags = (uint32_t)tb->flags; ctx.bstate = BS_NONE; @@ -1190,7 +1816,6 @@ ctx.delayed_pc = -1; /* use delayed pc from env pointer */ ctx.tb = tb; ctx.singlestep_enabled = env->singlestep_enabled; - nb_gen_labels = 0; #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_CPU) { @@ -1201,13 +1826,18 @@ #endif ii = -1; + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + if (max_insns == 0) + max_insns = CF_COUNT_MASK; + gen_icount_start(); while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) { if (env->nb_breakpoints > 0) { for (i = 0; i < env->nb_breakpoints; i++) { if (ctx.pc == env->breakpoints[i]) { /* We have hit a breakpoint - make sure PC is up-to-date */ - gen_op_movl_imm_PC(ctx.pc); - gen_op_debug(); + tcg_gen_movi_i32(cpu_pc, ctx.pc); + tcg_gen_helper_0_0(helper_debug); ctx.bstate = BS_EXCP; break; } @@ -1223,24 +1853,33 @@ gen_opc_pc[ii] = ctx.pc; gen_opc_hflags[ii] = ctx.flags; gen_opc_instr_start[ii] = 1; + gen_opc_icount[ii] = num_insns; } + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) + gen_io_start(); #if 0 fprintf(stderr, "Loading opcode at address 0x%08x\n", ctx.pc); fflush(stderr); #endif ctx.opcode = lduw_code(ctx.pc); decode_opc(&ctx); + num_insns++; ctx.pc += 2; if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) break; if (env->singlestep_enabled) break; + if (num_insns >= max_insns) + break; #ifdef SH4_SINGLE_STEP break; #endif } + if (tb->cflags & CF_LAST_IO) + gen_io_end(); if (env->singlestep_enabled) { - gen_op_debug(); + tcg_gen_movi_i32(cpu_pc, ctx.pc); + tcg_gen_helper_0_0(helper_debug); } else { switch (ctx.bstate) { case BS_STOP: @@ -1248,14 +1887,13 @@ /* fall through */ case BS_NONE: if (ctx.flags) { - gen_op_store_flags(ctx.flags | DELAY_SLOT_CLEARME); + gen_store_flags(ctx.flags | DELAY_SLOT_CLEARME); } gen_goto_tb(&ctx, 0, ctx.pc); break; case BS_EXCP: /* gen_op_interrupt_restart(); */ - gen_op_movl_imm_T0(0); - gen_op_exit_tb(); + tcg_gen_exit_tb(0); break; case BS_BRANCH: default: @@ -1263,6 +1901,7 @@ } } + gen_icount_end(tb, num_insns); *gen_opc_ptr = INDEX_op_end; if (search_pc) { i = gen_opc_ptr - gen_opc_buf; @@ -1271,6 +1910,7 @@ gen_opc_instr_start[ii++] = 0; } else { tb->size = ctx.pc - pc_start; + tb->icount = num_insns; } #ifdef DEBUG_DISAS @@ -1283,21 +1923,22 @@ target_disas(logfile, pc_start, ctx.pc - pc_start, 0); fprintf(logfile, "\n"); } - if (loglevel & CPU_LOG_TB_OP) { - fprintf(logfile, "OP:\n"); - dump_ops(gen_opc_buf, gen_opparam_buf); - fprintf(logfile, "\n"); - } #endif - return 0; } -int gen_intermediate_code(CPUState * env, struct TranslationBlock *tb) +void gen_intermediate_code(CPUState * env, struct TranslationBlock *tb) +{ + gen_intermediate_code_internal(env, tb, 0); +} + +void gen_intermediate_code_pc(CPUState * env, struct TranslationBlock *tb) { - return gen_intermediate_code_internal(env, tb, 0); + gen_intermediate_code_internal(env, tb, 1); } -int gen_intermediate_code_pc(CPUState * env, struct TranslationBlock *tb) +void gen_pc_load(CPUState *env, TranslationBlock *tb, + unsigned long searched_pc, int pc_pos, void *puc) { - return gen_intermediate_code_internal(env, tb, 1); + env->pc = gen_opc_pc[pc_pos]; + env->flags = gen_opc_hflags[pc_pos]; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sparc/cpu.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sparc/cpu.h --- qemu-0.9.1/target-sparc/cpu.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-sparc/cpu.h 2008-10-06 19:46:28.000000000 +0100 @@ -43,15 +43,16 @@ #define TT_TOVF 0x0a #define TT_EXTINT 0x10 #define TT_CODE_ACCESS 0x21 +#define TT_UNIMP_FLUSH 0x25 #define TT_DATA_ACCESS 0x29 #define TT_DIV_ZERO 0x2a #define TT_NCP_INSN 0x24 #define TT_TRAP 0x80 #else #define TT_TFAULT 0x08 -#define TT_TMISS 0x09 #define TT_CODE_ACCESS 0x0a #define TT_ILL_INSN 0x10 +#define TT_UNIMP_FLUSH TT_ILL_INSN #define TT_PRIV_INSN 0x11 #define TT_NFPU_INSN 0x20 #define TT_FP_EXCP 0x21 @@ -59,22 +60,28 @@ #define TT_CLRWIN 0x24 #define TT_DIV_ZERO 0x28 #define TT_DFAULT 0x30 -#define TT_DMISS 0x31 #define TT_DATA_ACCESS 0x32 -#define TT_DPROT 0x33 #define TT_UNALIGNED 0x34 #define TT_PRIV_ACT 0x37 #define TT_EXTINT 0x40 +#define TT_IVEC 0x60 +#define TT_TMISS 0x64 +#define TT_DMISS 0x68 +#define TT_DPROT 0x6c #define TT_SPILL 0x80 #define TT_FILL 0xc0 #define TT_WOTHER 0x10 #define TT_TRAP 0x100 #endif -#define PSR_NEG (1<<23) -#define PSR_ZERO (1<<22) -#define PSR_OVF (1<<21) -#define PSR_CARRY (1<<20) +#define PSR_NEG_SHIFT 23 +#define PSR_NEG (1 << PSR_NEG_SHIFT) +#define PSR_ZERO_SHIFT 22 +#define PSR_ZERO (1 << PSR_ZERO_SHIFT) +#define PSR_OVF_SHIFT 21 +#define PSR_OVF (1 << PSR_OVF_SHIFT) +#define PSR_CARRY_SHIFT 20 +#define PSR_CARRY (1 << PSR_CARRY_SHIFT) #define PSR_ICC (PSR_NEG|PSR_ZERO|PSR_OVF|PSR_CARRY) #define PSR_EF (1<<12) #define PSR_PIL 0xf00 @@ -103,46 +110,61 @@ #endif /* Fcc */ -#define FSR_RD1 (1<<31) -#define FSR_RD0 (1<<30) +#define FSR_RD1 (1ULL << 31) +#define FSR_RD0 (1ULL << 30) #define FSR_RD_MASK (FSR_RD1 | FSR_RD0) #define FSR_RD_NEAREST 0 #define FSR_RD_ZERO FSR_RD0 #define FSR_RD_POS FSR_RD1 #define FSR_RD_NEG (FSR_RD1 | FSR_RD0) -#define FSR_NVM (1<<27) -#define FSR_OFM (1<<26) -#define FSR_UFM (1<<25) -#define FSR_DZM (1<<24) -#define FSR_NXM (1<<23) +#define FSR_NVM (1ULL << 27) +#define FSR_OFM (1ULL << 26) +#define FSR_UFM (1ULL << 25) +#define FSR_DZM (1ULL << 24) +#define FSR_NXM (1ULL << 23) #define FSR_TEM_MASK (FSR_NVM | FSR_OFM | FSR_UFM | FSR_DZM | FSR_NXM) -#define FSR_NVA (1<<9) -#define FSR_OFA (1<<8) -#define FSR_UFA (1<<7) -#define FSR_DZA (1<<6) -#define FSR_NXA (1<<5) +#define FSR_NVA (1ULL << 9) +#define FSR_OFA (1ULL << 8) +#define FSR_UFA (1ULL << 7) +#define FSR_DZA (1ULL << 6) +#define FSR_NXA (1ULL << 5) #define FSR_AEXC_MASK (FSR_NVA | FSR_OFA | FSR_UFA | FSR_DZA | FSR_NXA) -#define FSR_NVC (1<<4) -#define FSR_OFC (1<<3) -#define FSR_UFC (1<<2) -#define FSR_DZC (1<<1) -#define FSR_NXC (1<<0) +#define FSR_NVC (1ULL << 4) +#define FSR_OFC (1ULL << 3) +#define FSR_UFC (1ULL << 2) +#define FSR_DZC (1ULL << 1) +#define FSR_NXC (1ULL << 0) #define FSR_CEXC_MASK (FSR_NVC | FSR_OFC | FSR_UFC | FSR_DZC | FSR_NXC) -#define FSR_FTT2 (1<<16) -#define FSR_FTT1 (1<<15) -#define FSR_FTT0 (1<<14) -#define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0) -#define FSR_FTT_IEEE_EXCP (1 << 14) -#define FSR_FTT_UNIMPFPOP (3 << 14) -#define FSR_FTT_SEQ_ERROR (4 << 14) -#define FSR_FTT_INVAL_FPR (6 << 14) - -#define FSR_FCC1 (1<<11) -#define FSR_FCC0 (1<<10) +#define FSR_FTT2 (1ULL << 16) +#define FSR_FTT1 (1ULL << 15) +#define FSR_FTT0 (1ULL << 14) +//gcc warns about constant overflow for ~FSR_FTT_MASK +//#define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0) +#ifdef TARGET_SPARC64 +#define FSR_FTT_NMASK 0xfffffffffffe3fffULL +#define FSR_FTT_CEXC_NMASK 0xfffffffffffe3fe0ULL +#define FSR_LDFSR_OLDMASK 0x0000003f000fc000ULL +#define FSR_LDXFSR_MASK 0x0000003fcfc00fffULL +#define FSR_LDXFSR_OLDMASK 0x00000000000fc000ULL +#else +#define FSR_FTT_NMASK 0xfffe3fffULL +#define FSR_FTT_CEXC_NMASK 0xfffe3fe0ULL +#define FSR_LDFSR_OLDMASK 0x000fc000ULL +#endif +#define FSR_LDFSR_MASK 0xcfc00fffULL +#define FSR_FTT_IEEE_EXCP (1ULL << 14) +#define FSR_FTT_UNIMPFPOP (3ULL << 14) +#define FSR_FTT_SEQ_ERROR (4ULL << 14) +#define FSR_FTT_INVAL_FPR (6ULL << 14) + +#define FSR_FCC1_SHIFT 11 +#define FSR_FCC1 (1ULL << FSR_FCC1_SHIFT) +#define FSR_FCC0_SHIFT 10 +#define FSR_FCC0 (1ULL << FSR_FCC0_SHIFT) /* MMU */ #define MMU_E (1<<0) @@ -162,24 +184,88 @@ #define PG_MODIFIED_MASK (1 << PG_MODIFIED_BIT) #define PG_CACHE_MASK (1 << PG_CACHE_BIT) -/* 2 <= NWINDOWS <= 32. In QEMU it must also be a power of two. */ -#define NWINDOWS 8 +/* 3 <= NWINDOWS <= 32. */ +#define MIN_NWINDOWS 3 +#define MAX_NWINDOWS 32 #if !defined(TARGET_SPARC64) #define NB_MMU_MODES 2 #else #define NB_MMU_MODES 3 +typedef struct trap_state { + uint64_t tpc; + uint64_t tnpc; + uint64_t tstate; + uint32_t tt; +} trap_state; +#endif + +typedef struct sparc_def_t { + const char *name; + target_ulong iu_version; + uint32_t fpu_version; + uint32_t mmu_version; + uint32_t mmu_bm; + uint32_t mmu_ctpr_mask; + uint32_t mmu_cxr_mask; + uint32_t mmu_sfsr_mask; + uint32_t mmu_trcr_mask; + uint32_t features; + uint32_t nwindows; + uint32_t maxtl; +} sparc_def_t; + +#define CPU_FEATURE_FLOAT (1 << 0) +#define CPU_FEATURE_FLOAT128 (1 << 1) +#define CPU_FEATURE_SWAP (1 << 2) +#define CPU_FEATURE_MUL (1 << 3) +#define CPU_FEATURE_DIV (1 << 4) +#define CPU_FEATURE_FLUSH (1 << 5) +#define CPU_FEATURE_FSQRT (1 << 6) +#define CPU_FEATURE_FMUL (1 << 7) +#define CPU_FEATURE_VIS1 (1 << 8) +#define CPU_FEATURE_VIS2 (1 << 9) +#define CPU_FEATURE_FSMULD (1 << 10) +#define CPU_FEATURE_HYPV (1 << 11) +#define CPU_FEATURE_CMT (1 << 12) +#define CPU_FEATURE_GL (1 << 13) +#ifndef TARGET_SPARC64 +#define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | \ + CPU_FEATURE_MUL | CPU_FEATURE_DIV | \ + CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT | \ + CPU_FEATURE_FMUL | CPU_FEATURE_FSMULD) +#else +#define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | \ + CPU_FEATURE_MUL | CPU_FEATURE_DIV | \ + CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT | \ + CPU_FEATURE_FMUL | CPU_FEATURE_VIS1 | \ + CPU_FEATURE_VIS2 | CPU_FEATURE_FSMULD) +enum { + mmu_us_12, // Ultrasparc < III (64 entry TLB) + mmu_us_3, // Ultrasparc III (512 entry TLB) + mmu_us_4, // Ultrasparc IV (several TLBs, 32 and 256MB pages) + mmu_sun4v, // T1, T2 +}; #endif typedef struct CPUSPARCState { target_ulong gregs[8]; /* general registers */ target_ulong *regwptr; /* pointer to current register window */ - float32 fpr[TARGET_FPREGS]; /* floating point registers */ target_ulong pc; /* program counter */ target_ulong npc; /* next program counter */ target_ulong y; /* multiply/divide register */ + + /* emulator internal flags handling */ + target_ulong cc_src, cc_src2; + target_ulong cc_dst; + + target_ulong t0, t1; /* temporaries live across basic blocks */ + target_ulong cond; /* conditional branch result (XXX: save it in a + temporary register when possible) */ + uint32_t psr; /* processor state register */ target_ulong fsr; /* FPU state register */ + float32 fpr[TARGET_FPREGS]; /* floating point registers */ uint32_t cwp; /* index of current register window (extracted from PSR) */ uint32_t wim; /* window invalid mask */ @@ -191,15 +277,10 @@ uint32_t pil_in; /* incoming interrupt level bitmap */ int psref; /* enable fpu */ target_ulong version; - jmp_buf jmp_env; - int user_mode_only; - int exception_index; int interrupt_index; - int interrupt_request; - int halted; - uint32_t mmu_bm; + uint32_t nwindows; /* NOTE: we allow 8 more registers to handle wrapping */ - target_ulong regbase[NWINDOWS * 16 + 8]; + target_ulong regbase[MAX_NWINDOWS * 16 + 8]; CPU_COMMON @@ -214,6 +295,7 @@ uint64_t itlb_tte[64]; uint64_t dtlb_tag[64]; uint64_t dtlb_tte[64]; + uint32_t mmu_version; #else uint32_t mmuregs[32]; uint64_t mxccdata[4]; @@ -221,23 +303,19 @@ uint64_t prom_addr; #endif /* temporary float registers */ - float32 ft0, ft1; float64 dt0, dt1; -#if defined(CONFIG_USER_ONLY) float128 qt0, qt1; -#endif float_status fp_status; #if defined(TARGET_SPARC64) -#define MAXTL 4 - uint64_t t0, t1, t2; - uint64_t tpc[MAXTL]; - uint64_t tnpc[MAXTL]; - uint64_t tstate[MAXTL]; - uint32_t tt[MAXTL]; +#define MAXTL_MAX 8 +#define MAXTL_MASK (MAXTL_MAX - 1) + trap_state *tsptr; + trap_state ts[MAXTL_MAX]; uint32_t xcc; /* Extended integer condition codes */ uint32_t asi; uint32_t pstate; uint32_t tl; + uint32_t maxtl; uint32_t cansave, canrestore, otherwin, wstate, cleanwin; uint64_t agregs[8]; /* alternate general registers */ uint64_t bgregs[8]; /* backup for normal global registers */ @@ -249,35 +327,31 @@ uint64_t gsr; uint32_t gl; // UA2005 /* UA 2005 hyperprivileged registers */ - uint64_t hpstate, htstate[MAXTL], hintp, htba, hver, hstick_cmpr, ssr; + uint64_t hpstate, htstate[MAXTL_MAX], hintp, htba, hver, hstick_cmpr, ssr; void *hstick; // UA 2005 + uint32_t softint; +#define SOFTINT_TIMER 1 #endif -#if !defined(TARGET_SPARC64) && !defined(reg_T2) - target_ulong t2; -#endif + sparc_def_t *def; } CPUSPARCState; -#if defined(TARGET_SPARC64) -#define GET_FSR32(env) (env->fsr & 0xcfc1ffff) -#define PUT_FSR32(env, val) do { uint32_t _tmp = val; \ - env->fsr = (_tmp & 0xcfc1c3ff) | (env->fsr & 0x3f00000000ULL); \ - } while (0) -#define GET_FSR64(env) (env->fsr & 0x3fcfc1ffffULL) -#define PUT_FSR64(env, val) do { uint64_t _tmp = val; \ - env->fsr = _tmp & 0x3fcfc1c3ffULL; \ - } while (0) -#else -#define GET_FSR32(env) (env->fsr) -#define PUT_FSR32(env, val) do { uint32_t _tmp = val; \ - env->fsr = (_tmp & 0xcfc1dfff) | (env->fsr & 0x000e0000); \ - } while (0) -#endif +/* helper.c */ CPUSPARCState *cpu_sparc_init(const char *cpu_model); -int cpu_sparc_exec(CPUSPARCState *s); -int cpu_sparc_close(CPUSPARCState *s); +void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu); void sparc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); -void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu); +void cpu_lock(void); +void cpu_unlock(void); +int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw, + int mmu_idx, int is_softmmu); +target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev); +void dump_mmu(CPUSPARCState *env); + +/* translate.c */ +void gen_intermediate_code_init(CPUSPARCState *env); + +/* cpu-exec.c */ +int cpu_sparc_exec(CPUSPARCState *s); #define GET_PSR(env) (env->version | (env->psr & PSR_ICC) | \ (env->psref? PSR_EF : 0) | \ @@ -287,7 +361,43 @@ (env->psret? PSR_ET : 0) | env->cwp) #ifndef NO_CPU_IO_DEFS -void cpu_set_cwp(CPUSPARCState *env1, int new_cwp); +static inline void memcpy32(target_ulong *dst, const target_ulong *src) +{ + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; +} + +static inline void cpu_set_cwp(CPUSPARCState *env1, int new_cwp) +{ + /* put the modified wrap registers at their proper location */ + if (env1->cwp == env1->nwindows - 1) + memcpy32(env1->regbase, env1->regbase + env1->nwindows * 16); + env1->cwp = new_cwp; + /* put the wrap registers at their temporary location */ + if (new_cwp == env1->nwindows - 1) + memcpy32(env1->regbase + env1->nwindows * 16, env1->regbase); + env1->regwptr = env1->regbase + (new_cwp * 16); +} + +static inline int cpu_cwp_inc(CPUSPARCState *env1, int cwp) +{ + if (unlikely(cwp >= env1->nwindows)) + cwp -= env1->nwindows; + return cwp; +} + +static inline int cpu_cwp_dec(CPUSPARCState *env1, int cwp) +{ + if (unlikely(cwp < 0)) + cwp += env1->nwindows; + return cwp; +} #endif #define PUT_PSR(env, val) do { int _tmp = val; \ @@ -303,23 +413,25 @@ #ifdef TARGET_SPARC64 #define GET_CCR(env) (((env->xcc >> 20) << 4) | ((env->psr & PSR_ICC) >> 20)) #define PUT_CCR(env, val) do { int _tmp = val; \ - env->xcc = (_tmp >> 4) << 20; \ + env->xcc = (_tmp >> 4) << 20; \ env->psr = (_tmp & 0xf) << 20; \ } while (0) -#define GET_CWP64(env) (NWINDOWS - 1 - (env)->cwp) -#define PUT_CWP64(env, val) \ - cpu_set_cwp(env, NWINDOWS - 1 - ((val) & (NWINDOWS - 1))) +#define GET_CWP64(env) (env->nwindows - 1 - (env)->cwp) +#ifndef NO_CPU_IO_DEFS +static inline void PUT_CWP64(CPUSPARCState *env1, int cwp) +{ + if (unlikely(cwp >= env1->nwindows || cwp < 0)) + cwp = 0; + cpu_set_cwp(env1, env1->nwindows - 1 - cwp); +} +#endif #endif -int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); -void raise_exception(int tt); +/* cpu-exec.c */ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, - int is_asi); -void do_tick_set_count(void *opaque, uint64_t count); -uint64_t do_tick_get_count(void *opaque); -void do_tick_set_limit(void *opaque, uint64_t limit); -void cpu_check_irqs(CPUSPARCState *env); + int is_asi, int size); +int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); #define CPUState CPUSPARCState #define cpu_init cpu_sparc_init @@ -328,40 +440,72 @@ #define cpu_signal_handler cpu_sparc_signal_handler #define cpu_list sparc_cpu_list +#define CPU_SAVE_VERSION 5 + /* MMU modes definitions */ #define MMU_MODE0_SUFFIX _user #define MMU_MODE1_SUFFIX _kernel #ifdef TARGET_SPARC64 #define MMU_MODE2_SUFFIX _hypv #endif -#define MMU_USER_IDX 0 -static inline int cpu_mmu_index (CPUState *env) +#define MMU_USER_IDX 0 +#define MMU_KERNEL_IDX 1 +#define MMU_HYPV_IDX 2 + +static inline int cpu_mmu_index(CPUState *env1) { #if defined(CONFIG_USER_ONLY) - return 0; + return MMU_USER_IDX; #elif !defined(TARGET_SPARC64) - return env->psrs; + return env1->psrs; #else - if (!env->psrs) - return 0; - else if ((env->hpstate & HS_PRIV) == 0) - return 1; + if (!env1->psrs) + return MMU_USER_IDX; + else if ((env1->hpstate & HS_PRIV) == 0) + return MMU_KERNEL_IDX; else - return 2; + return MMU_HYPV_IDX; #endif } -static inline int cpu_fpu_enabled(CPUState *env) +static inline int cpu_fpu_enabled(CPUState *env1) { #if defined(CONFIG_USER_ONLY) return 1; #elif !defined(TARGET_SPARC64) - return env->psref; + return env1->psref; #else - return ((env->pstate & PS_PEF) != 0) && ((env->fprs & FPRS_FEF) != 0); + return ((env1->pstate & PS_PEF) != 0) && ((env1->fprs & FPRS_FEF) != 0); #endif } +#if defined(CONFIG_USER_ONLY) +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) +{ + if (newsp) + env->regwptr[22] = newsp; + env->regwptr[0] = 0; + /* FIXME: Do we also need to clear CF? */ + /* XXXXX */ + printf ("HELPME: %s:%d\n", __FILE__, __LINE__); +} +#endif + +#define CPU_PC_FROM_TB(env, tb) do { \ + env->pc = tb->pc; \ + env->npc = tb->cs_base; \ + } while(0) + #include "cpu-all.h" +/* sum4m.c, sun4u.c */ +void cpu_check_irqs(CPUSPARCState *env); + +#ifdef TARGET_SPARC64 +/* sun4u.c */ +void cpu_tick_set_count(void *opaque, uint64_t count); +uint64_t cpu_tick_get_count(void *opaque); +void cpu_tick_set_limit(void *opaque, uint64_t limit); +#endif + #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sparc/exec.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sparc/exec.h --- qemu-0.9.1/target-sparc/exec.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-sparc/exec.h 2008-10-03 20:02:42.000000000 +0100 @@ -5,145 +5,33 @@ register struct CPUSPARCState *env asm(AREG0); -#ifdef TARGET_SPARC64 -#define T0 (env->t0) -#define T1 (env->t1) -#define T2 (env->t2) -#define REGWPTR env->regwptr -#else -register uint32_t T0 asm(AREG1); -register uint32_t T1 asm(AREG2); - -#undef REG_REGWPTR // Broken -#ifdef REG_REGWPTR -#if defined(__sparc__) -register uint32_t *REGWPTR asm(AREG4); -#else -register uint32_t *REGWPTR asm(AREG3); -#endif -#define reg_REGWPTR - -#ifdef AREG4 -register uint32_t T2 asm(AREG4); -#define reg_T2 -#else -#define T2 (env->t2) -#endif - -#else -#define REGWPTR env->regwptr -register uint32_t T2 asm(AREG3); -#endif -#define reg_T2 -#endif - -#define FT0 (env->ft0) -#define FT1 (env->ft1) #define DT0 (env->dt0) #define DT1 (env->dt1) -#if defined(CONFIG_USER_ONLY) #define QT0 (env->qt0) #define QT1 (env->qt1) -#endif #include "cpu.h" #include "exec-all.h" -void cpu_lock(void); -void cpu_unlock(void); -void cpu_loop_exit(void); -void helper_flush(target_ulong addr); -void helper_ld_asi(int asi, int size, int sign); -void helper_st_asi(int asi, int size); -void helper_ldf_asi(int asi, int size, int rd); -void helper_stf_asi(int asi, int size, int rd); -void helper_rett(void); -void helper_ldfsr(void); -void set_cwp(int new_cwp); -void do_fitos(void); -void do_fitod(void); -void do_fabss(void); -void do_fsqrts(void); -void do_fsqrtd(void); -void do_fcmps(void); -void do_fcmpd(void); -void do_fcmpes(void); -void do_fcmped(void); -#if defined(CONFIG_USER_ONLY) -void do_fitoq(void); -void do_fsqrtq(void); -void do_fcmpq(void); -void do_fcmpeq(void); -#endif -#ifdef TARGET_SPARC64 -void do_fabsd(void); -void do_fxtos(void); -void do_fxtod(void); -void do_fcmps_fcc1(void); -void do_fcmpd_fcc1(void); -void do_fcmps_fcc2(void); -void do_fcmpd_fcc2(void); -void do_fcmps_fcc3(void); -void do_fcmpd_fcc3(void); -void do_fcmpes_fcc1(void); -void do_fcmped_fcc1(void); -void do_fcmpes_fcc2(void); -void do_fcmped_fcc2(void); -void do_fcmpes_fcc3(void); -void do_fcmped_fcc3(void); -#if defined(CONFIG_USER_ONLY) -void do_fabsq(void); -void do_fxtoq(void); -void do_fcmpq_fcc1(void); -void do_fcmpq_fcc2(void); -void do_fcmpq_fcc3(void); -void do_fcmpeq_fcc1(void); -void do_fcmpeq_fcc2(void); -void do_fcmpeq_fcc3(void); -#endif -void do_popc(); -void do_wrpstate(); -void do_done(); -void do_retry(); -#endif -void do_ldd_kernel(target_ulong addr); -void do_ldd_user(target_ulong addr); -void do_ldd_raw(target_ulong addr); -void do_interrupt(int intno); -void raise_exception(int tt); -void check_ieee_exceptions(); -void memcpy32(target_ulong *dst, const target_ulong *src); -target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev); -void dump_mmu(CPUState *env); -void helper_debug(); -void do_wrpsr(); -void do_rdpsr(); - -/* XXX: move that to a generic header */ -#if !defined(CONFIG_USER_ONLY) -#include "softmmu_exec.h" -#endif /* !defined(CONFIG_USER_ONLY) */ - static inline void env_to_regs(void) { -#if defined(reg_REGWPTR) - REGWPTR = env->regbase + (env->cwp * 16); - env->regwptr = REGWPTR; -#endif } static inline void regs_to_env(void) { } -int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw, - int mmu_idx, int is_softmmu); +/* op_helper.c */ +void do_interrupt(CPUState *env); + +/* cpu-exec.c */ +void cpu_loop_exit(void); -static inline int cpu_halted(CPUState *env) { - if (!env->halted) +static inline int cpu_halted(CPUState *env1) { + if (!env1->halted) return 0; - if ((env->interrupt_request & CPU_INTERRUPT_HARD) && (env->psret != 0)) { - env->halted = 0; + if ((env1->interrupt_request & CPU_INTERRUPT_HARD) && (env1->psret != 0)) { + env1->halted = 0; return 0; } return EXCP_HALTED; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sparc/fbranch_template.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sparc/fbranch_template.h --- qemu-0.9.1/target-sparc/fbranch_template.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-sparc/fbranch_template.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,89 +0,0 @@ -/* FCC1:FCC0: 0 =, 1 <, 2 >, 3 u */ - -void OPPROTO glue(op_eval_fbne, FCC)(void) -{ -// !0 - T2 = FFLAG_SET(FSR_FCC0) | FFLAG_SET(FSR_FCC1); /* L or G or U */ -} - -void OPPROTO glue(op_eval_fblg, FCC)(void) -{ -// 1 or 2 - T2 = FFLAG_SET(FSR_FCC0) ^ FFLAG_SET(FSR_FCC1); -} - -void OPPROTO glue(op_eval_fbul, FCC)(void) -{ -// 1 or 3 - T2 = FFLAG_SET(FSR_FCC0); -} - -void OPPROTO glue(op_eval_fbl, FCC)(void) -{ -// 1 - T2 = FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1); -} - -void OPPROTO glue(op_eval_fbug, FCC)(void) -{ -// 2 or 3 - T2 = FFLAG_SET(FSR_FCC1); -} - -void OPPROTO glue(op_eval_fbg, FCC)(void) -{ -// 2 - T2 = !FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1); -} - -void OPPROTO glue(op_eval_fbu, FCC)(void) -{ -// 3 - T2 = FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1); -} - -void OPPROTO glue(op_eval_fbe, FCC)(void) -{ -// 0 - T2 = !FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1); -} - -void OPPROTO glue(op_eval_fbue, FCC)(void) -{ -// 0 or 3 - T2 = !(FFLAG_SET(FSR_FCC1) ^ FFLAG_SET(FSR_FCC0)); - FORCE_RET(); -} - -void OPPROTO glue(op_eval_fbge, FCC)(void) -{ -// 0 or 2 - T2 = !FFLAG_SET(FSR_FCC0); -} - -void OPPROTO glue(op_eval_fbuge, FCC)(void) -{ -// !1 - T2 = !(FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1)); -} - -void OPPROTO glue(op_eval_fble, FCC)(void) -{ -// 0 or 1 - T2 = !FFLAG_SET(FSR_FCC1); -} - -void OPPROTO glue(op_eval_fbule, FCC)(void) -{ -// !2 - T2 = !(!FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1)); -} - -void OPPROTO glue(op_eval_fbo, FCC)(void) -{ -// !3 - T2 = !(FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1)); -} - -#undef FCC -#undef FFLAG_SET diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sparc/fop_template.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sparc/fop_template.h --- qemu-0.9.1/target-sparc/fop_template.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-sparc/fop_template.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,128 +0,0 @@ -/* - * SPARC micro operations (templates for various register related - * operations) - * - * Copyright (c) 2003 Fabrice Bellard - * - * 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 - */ - -/* floating point registers moves */ -void OPPROTO glue(op_load_fpr_FT0_fpr, REGNAME)(void) -{ - FT0 = REG; -} - -void OPPROTO glue(op_store_FT0_fpr_fpr, REGNAME)(void) -{ - REG = FT0; -} - -void OPPROTO glue(op_load_fpr_FT1_fpr, REGNAME)(void) -{ - FT1 = REG; -} - -void OPPROTO glue(op_store_FT1_fpr_fpr, REGNAME)(void) -{ - REG = FT1; -} - -/* double floating point registers moves */ -void OPPROTO glue(op_load_fpr_DT0_fpr, REGNAME)(void) -{ - CPU_DoubleU u; - uint32_t *p = (uint32_t *)® - u.l.lower = *(p +1); - u.l.upper = *p; - DT0 = u.d; -} - -void OPPROTO glue(op_store_DT0_fpr_fpr, REGNAME)(void) -{ - CPU_DoubleU u; - uint32_t *p = (uint32_t *)® - u.d = DT0; - *(p +1) = u.l.lower; - *p = u.l.upper; -} - -void OPPROTO glue(op_load_fpr_DT1_fpr, REGNAME)(void) -{ - CPU_DoubleU u; - uint32_t *p = (uint32_t *)® - u.l.lower = *(p +1); - u.l.upper = *p; - DT1 = u.d; -} - -void OPPROTO glue(op_store_DT1_fpr_fpr, REGNAME)(void) -{ - CPU_DoubleU u; - uint32_t *p = (uint32_t *)® - u.d = DT1; - *(p +1) = u.l.lower; - *p = u.l.upper; -} - -#if defined(CONFIG_USER_ONLY) -/* quad floating point registers moves */ -void OPPROTO glue(op_load_fpr_QT0_fpr, REGNAME)(void) -{ - CPU_QuadU u; - uint32_t *p = (uint32_t *)® - u.l.lowest = *(p + 3); - u.l.lower = *(p + 2); - u.l.upper = *(p + 1); - u.l.upmost = *p; - QT0 = u.q; -} - -void OPPROTO glue(op_store_QT0_fpr_fpr, REGNAME)(void) -{ - CPU_QuadU u; - uint32_t *p = (uint32_t *)® - u.q = QT0; - *(p + 3) = u.l.lowest; - *(p + 2) = u.l.lower; - *(p + 1) = u.l.upper; - *p = u.l.upmost; -} - -void OPPROTO glue(op_load_fpr_QT1_fpr, REGNAME)(void) -{ - CPU_QuadU u; - uint32_t *p = (uint32_t *)® - u.l.lowest = *(p + 3); - u.l.lower = *(p + 2); - u.l.upper = *(p + 1); - u.l.upmost = *p; - QT1 = u.q; -} - -void OPPROTO glue(op_store_QT1_fpr_fpr, REGNAME)(void) -{ - CPU_QuadU u; - uint32_t *p = (uint32_t *)® - u.q = QT1; - *(p + 3) = u.l.lowest; - *(p + 2) = u.l.lower; - *(p + 1) = u.l.upper; - *p = u.l.upmost; -} -#endif - -#undef REG -#undef REGNAME diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sparc/helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sparc/helper.c --- qemu-0.9.1/target-sparc/helper.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-sparc/helper.c 2008-10-07 20:12:13.000000000 +0100 @@ -27,14 +27,18 @@ #include "cpu.h" #include "exec-all.h" +#include "qemu-common.h" //#define DEBUG_MMU +//#define DEBUG_FEATURES + +static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model); /* Sparc MMU emulation */ /* thread support */ -spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; void cpu_lock(void) { @@ -48,13 +52,13 @@ #if defined(CONFIG_USER_ONLY) -int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw, +int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw, int mmu_idx, int is_softmmu) { if (rw & 2) - env->exception_index = TT_TFAULT; + env1->exception_index = TT_TFAULT; else - env->exception_index = TT_DFAULT; + env1->exception_index = TT_DFAULT; return 1; } @@ -65,14 +69,14 @@ * Sparc V8 Reference MMU (SRMMU) */ static const int access_table[8][8] = { - { 0, 0, 0, 0, 2, 0, 3, 3 }, - { 0, 0, 0, 0, 2, 0, 0, 0 }, - { 2, 2, 0, 0, 0, 2, 3, 3 }, - { 2, 2, 0, 0, 0, 2, 0, 0 }, - { 2, 0, 2, 0, 2, 2, 3, 3 }, - { 2, 0, 2, 0, 2, 0, 2, 0 }, - { 2, 2, 2, 0, 2, 2, 3, 3 }, - { 2, 2, 2, 0, 2, 2, 2, 0 } + { 0, 0, 0, 0, 8, 0, 12, 12 }, + { 0, 0, 0, 0, 8, 0, 0, 0 }, + { 8, 8, 0, 0, 0, 8, 12, 12 }, + { 8, 8, 0, 0, 0, 8, 0, 0 }, + { 8, 0, 8, 0, 8, 8, 12, 12 }, + { 8, 0, 8, 0, 8, 0, 8, 0 }, + { 8, 8, 8, 0, 8, 8, 12, 12 }, + { 8, 8, 8, 0, 8, 8, 8, 0 } }; static const int perm_table[2][8] = { @@ -98,9 +102,9 @@ } }; -int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot, - int *access_index, target_ulong address, int rw, - int mmu_idx) +static int get_physical_address(CPUState *env, target_phys_addr_t *physical, + int *prot, int *access_index, + target_ulong address, int rw, int mmu_idx) { int access_perms = 0; target_phys_addr_t pde_ptr; @@ -114,7 +118,7 @@ if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ // Boot mode: instruction fetches are taken from PROM - if (rw == 2 && (env->mmuregs[0] & env->mmu_bm)) { + if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) { *physical = env->prom_addr | (address & 0x7ffffULL); *prot = PAGE_READ | PAGE_EXEC; return 0; @@ -129,7 +133,7 @@ /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ /* Context base + context number */ - pde_ptr = ((env->mmuregs[1] & ~63)<< 4) + (env->mmuregs[2] << 2); + pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); pde = ldl_phys(pde_ptr); /* Ctx pde */ @@ -173,7 +177,8 @@ return (3 << 8) | (4 << 2); case 2: /* L3 PTE */ virt_addr = address & TARGET_PAGE_MASK; - page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1); + page_offset = (address & TARGET_PAGE_MASK) & + (TARGET_PAGE_SIZE - 1); } break; case 2: /* L2 PTE */ @@ -223,7 +228,8 @@ target_ulong vaddr; int error_code = 0, prot, ret = 0, access_index; - error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, mmu_idx); + error_code = get_physical_address(env, &paddr, &prot, &access_index, + address, rw, mmu_idx); if (error_code == 0) { vaddr = address & TARGET_PAGE_MASK; paddr &= TARGET_PAGE_MASK; @@ -367,9 +373,9 @@ /* * UltraSparc IIi I/DMMUs */ -static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical, int *prot, - int *access_index, target_ulong address, int rw, - int is_user) +static int get_physical_address_data(CPUState *env, + target_phys_addr_t *physical, int *prot, + target_ulong address, int rw, int is_user) { target_ulong mask; unsigned int i; @@ -404,7 +410,8 @@ ((env->dtlb_tte[i] & 0x4) && is_user) || (!(env->dtlb_tte[i] & 0x2) && (rw == 1))) { if (env->dmmuregs[3]) /* Fault status register */ - env->dmmuregs[3] = 2; /* overflow (not read before another fault) */ + env->dmmuregs[3] = 2; /* overflow (not read before + another fault) */ env->dmmuregs[3] |= (is_user << 3) | ((rw == 1) << 2) | 1; env->dmmuregs[4] = address; /* Fault address register */ env->exception_index = TT_DFAULT; @@ -413,7 +420,8 @@ #endif return 1; } - *physical = (env->dtlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL); + *physical = (env->dtlb_tte[i] & mask & 0x1fffffff000ULL) + + (address & ~mask & 0x1fffffff000ULL); *prot = PAGE_READ; if (env->dtlb_tte[i] & 0x2) *prot |= PAGE_WRITE; @@ -423,13 +431,14 @@ #ifdef DEBUG_MMU printf("DMISS at 0x%" PRIx64 "\n", address); #endif + env->dmmuregs[6] = (address & ~0x1fffULL) | (env->dmmuregs[1] & 0x1fff); env->exception_index = TT_DMISS; return 1; } -static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical, int *prot, - int *access_index, target_ulong address, int rw, - int is_user) +static int get_physical_address_code(CPUState *env, + target_phys_addr_t *physical, int *prot, + target_ulong address, int is_user) { target_ulong mask; unsigned int i; @@ -463,7 +472,8 @@ if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0 || ((env->itlb_tte[i] & 0x4) && is_user)) { if (env->immuregs[3]) /* Fault status register */ - env->immuregs[3] = 2; /* overflow (not read before another fault) */ + env->immuregs[3] = 2; /* overflow (not read before + another fault) */ env->immuregs[3] |= (is_user << 3) | 1; env->exception_index = TT_TFAULT; #ifdef DEBUG_MMU @@ -471,7 +481,8 @@ #endif return 1; } - *physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL); + *physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + + (address & ~mask & 0x1fffffff000ULL); *prot = PAGE_EXEC; return 0; } @@ -479,20 +490,23 @@ #ifdef DEBUG_MMU printf("TMISS at 0x%" PRIx64 "\n", address); #endif + env->immuregs[6] = (address & ~0x1fffULL) | (env->dmmuregs[1] & 0x1fff); env->exception_index = TT_TMISS; return 1; } -int get_physical_address(CPUState *env, target_phys_addr_t *physical, int *prot, - int *access_index, target_ulong address, int rw, - int mmu_idx) +static int get_physical_address(CPUState *env, target_phys_addr_t *physical, + int *prot, int *access_index, + target_ulong address, int rw, int mmu_idx) { int is_user = mmu_idx == MMU_USER_IDX; if (rw == 2) - return get_physical_address_code(env, physical, prot, access_index, address, rw, is_user); + return get_physical_address_code(env, physical, prot, address, + is_user); else - return get_physical_address_data(env, physical, prot, access_index, address, rw, is_user); + return get_physical_address_data(env, physical, prot, address, rw, + is_user); } /* Perform address translation */ @@ -503,12 +517,15 @@ target_phys_addr_t paddr; int error_code = 0, prot, ret = 0, access_index; - error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, mmu_idx); + error_code = get_physical_address(env, &paddr, &prot, &access_index, + address, rw, mmu_idx); if (error_code == 0) { virt_addr = address & TARGET_PAGE_MASK; - vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1)); + vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & + (TARGET_PAGE_SIZE - 1)); #ifdef DEBUG_MMU - printf("Translate at 0x%" PRIx64 " -> 0x%" PRIx64 ", vaddr 0x%" PRIx64 "\n", address, paddr, vaddr); + printf("Translate at 0x%" PRIx64 " -> 0x%" PRIx64 ", vaddr 0x%" PRIx64 + "\n", address, paddr, vaddr); #endif ret = tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu); return ret; @@ -523,7 +540,8 @@ unsigned int i; const char *mask; - printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" PRId64 "\n", env->dmmuregs[1], env->dmmuregs[2]); + printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" PRId64 "\n", + env->dmmuregs[1], env->dmmuregs[2]); if ((env->lsu & DMMU_E) == 0) { printf("DMMU disabled\n"); } else { @@ -545,7 +563,8 @@ break; } if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) { - printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, %s, ctx %" PRId64 "\n", + printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx + ", %s, %s, %s, %s, ctx %" PRId64 "\n", env->dtlb_tag[i] & ~0x1fffULL, env->dtlb_tte[i] & 0x1ffffffe000ULL, mask, @@ -577,7 +596,8 @@ break; } if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) { - printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, ctx %" PRId64 "\n", + printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx + ", %s, %s, %s, ctx %" PRId64 "\n", env->itlb_tag[i] & ~0x1fffULL, env->itlb_tte[i] & 0x1ffffffe000ULL, mask, @@ -593,45 +613,802 @@ #endif /* TARGET_SPARC64 */ #endif /* !CONFIG_USER_ONLY */ -void memcpy32(target_ulong *dst, const target_ulong *src) + +#if defined(CONFIG_USER_ONLY) +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - dst[3] = src[3]; - dst[4] = src[4]; - dst[5] = src[5]; - dst[6] = src[6]; - dst[7] = src[7]; + return addr; } -#ifdef TARGET_SPARC64 -#if !defined(CONFIG_USER_ONLY) -#include "qemu-common.h" -#include "hw/irq.h" -#include "qemu-timer.h" +#else +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + target_phys_addr_t phys_addr; + int prot, access_index; + + if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2, + MMU_KERNEL_IDX) != 0) + if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, + 0, MMU_KERNEL_IDX) != 0) + return -1; + if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) + return -1; + return phys_addr; +} #endif -void do_tick_set_count(void *opaque, uint64_t count) +void cpu_reset(CPUSPARCState *env) { -#if !defined(CONFIG_USER_ONLY) - ptimer_set_count(opaque, -count); + tlb_flush(env, 1); + env->cwp = 0; + env->wim = 1; + env->regwptr = env->regbase + (env->cwp * 16); +#if defined(CONFIG_USER_ONLY) + env->user_mode_only = 1; +#ifdef TARGET_SPARC64 + env->cleanwin = env->nwindows - 2; + env->cansave = env->nwindows - 2; + env->pstate = PS_RMO | PS_PEF | PS_IE; + env->asi = 0x82; // Primary no-fault +#endif +#else + env->psret = 0; + env->psrs = 1; + env->psrps = 1; +#ifdef TARGET_SPARC64 + env->pstate = PS_PRIV; + env->hpstate = HS_PRIV; + env->tsptr = &env->ts[env->tl & MAXTL_MASK]; +#else + env->mmuregs[0] &= ~(MMU_E | MMU_NF); + env->mmuregs[0] |= env->def->mmu_bm; +#endif + env->pc = 0; + env->npc = env->pc + 4; #endif } -uint64_t do_tick_get_count(void *opaque) +static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model) { -#if !defined(CONFIG_USER_ONLY) - return -ptimer_get_count(opaque); + sparc_def_t def1, *def = &def1; + + if (cpu_sparc_find_by_name(def, cpu_model) < 0) + return -1; + + env->def = qemu_mallocz(sizeof(*def)); + memcpy(env->def, def, sizeof(*def)); +#if defined(CONFIG_USER_ONLY) + if ((env->def->features & CPU_FEATURE_FLOAT)) + env->def->features |= CPU_FEATURE_FLOAT128; +#endif + env->cpu_model_str = cpu_model; + env->version = def->iu_version; + env->fsr = def->fpu_version; + env->nwindows = def->nwindows; +#if !defined(TARGET_SPARC64) + env->mmuregs[0] |= def->mmu_version; + cpu_sparc_set_id(env, 0); #else + env->mmu_version = def->mmu_version; + env->maxtl = def->maxtl; + env->version |= def->maxtl << 8; + env->version |= def->nwindows - 1; +#endif return 0; +} + +static void cpu_sparc_close(CPUSPARCState *env) +{ + free(env->def); + free(env); +} + +CPUSPARCState *cpu_sparc_init(const char *cpu_model) +{ + CPUSPARCState *env; + + env = qemu_mallocz(sizeof(CPUSPARCState)); + if (!env) + return NULL; + cpu_exec_init(env); + + gen_intermediate_code_init(env); + + if (cpu_sparc_register(env, cpu_model) < 0) { + cpu_sparc_close(env); + return NULL; + } + cpu_reset(env); + + return env; +} + +void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu) +{ +#if !defined(TARGET_SPARC64) + env->mxccregs[7] = ((cpu + 8) & 0xf) << 24; +#endif +} + +static const sparc_def_t sparc_defs[] = { +#ifdef TARGET_SPARC64 + { + .name = "Fujitsu Sparc64", + .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 4, + .maxtl = 4, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Fujitsu Sparc64 III", + .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 5, + .maxtl = 4, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Fujitsu Sparc64 IV", + .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Fujitsu Sparc64 V", + .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI UltraSparc I", + .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI UltraSparc II", + .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI UltraSparc IIi", + .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI UltraSparc IIe", + .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Sun UltraSparc III", + .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Sun UltraSparc III Cu", + .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_3, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Sun UltraSparc IIIi", + .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Sun UltraSparc IV", + .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_4, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Sun UltraSparc IV+", + .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT, + }, + { + .name = "Sun UltraSparc IIIi+", + .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_3, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Sun UltraSparc T1", + // defined in sparc_ifu_fdp.v and ctu.h + .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_sun4v, + .nwindows = 8, + .maxtl = 6, + .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT + | CPU_FEATURE_GL, + }, + { + .name = "Sun UltraSparc T2", + // defined in tlu_asi_ctl.v and n2_revid_cust.v + .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_sun4v, + .nwindows = 8, + .maxtl = 6, + .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT + | CPU_FEATURE_GL, + }, + { + .name = "NEC UltraSparc I", + .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)), + .fpu_version = 0x00000000, + .mmu_version = mmu_us_12, + .nwindows = 8, + .maxtl = 5, + .features = CPU_DEFAULT_FEATURES, + }, +#else + { + .name = "Fujitsu MB86900", + .iu_version = 0x00 << 24, /* Impl 0, ver 0 */ + .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ + .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */ + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 7, + .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD, + }, + { + .name = "Fujitsu MB86904", + .iu_version = 0x04 << 24, /* Impl 0, ver 4 */ + .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ + .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */ + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x00ffffc0, + .mmu_cxr_mask = 0x000000ff, + .mmu_sfsr_mask = 0x00016fff, + .mmu_trcr_mask = 0x00ffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Fujitsu MB86907", + .iu_version = 0x05 << 24, /* Impl 0, ver 5 */ + .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ + .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */ + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0xffffffc0, + .mmu_cxr_mask = 0x000000ff, + .mmu_sfsr_mask = 0x00016fff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "LSI L64811", + .iu_version = 0x10 << 24, /* Impl 1, ver 0 */ + .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */ + .mmu_version = 0x10 << 24, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT | + CPU_FEATURE_FSMULD, + }, + { + .name = "Cypress CY7C601", + .iu_version = 0x11 << 24, /* Impl 1, ver 1 */ + .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */ + .mmu_version = 0x10 << 24, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT | + CPU_FEATURE_FSMULD, + }, + { + .name = "Cypress CY7C611", + .iu_version = 0x13 << 24, /* Impl 1, ver 3 */ + .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */ + .mmu_version = 0x10 << 24, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT | + CPU_FEATURE_FSMULD, + }, + { + .name = "TI SuperSparc II", + .iu_version = 0x40000000, + .fpu_version = 0 << 17, + .mmu_version = 0x04000000, + .mmu_bm = 0x00002000, + .mmu_ctpr_mask = 0xffffffc0, + .mmu_cxr_mask = 0x0000ffff, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI MicroSparc I", + .iu_version = 0x41000000, + .fpu_version = 4 << 17, + .mmu_version = 0x41000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0x00016fff, + .mmu_trcr_mask = 0x0000003f, + .nwindows = 7, + .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL | + CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT | + CPU_FEATURE_FMUL, + }, + { + .name = "TI MicroSparc II", + .iu_version = 0x42000000, + .fpu_version = 4 << 17, + .mmu_version = 0x02000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x00ffffc0, + .mmu_cxr_mask = 0x000000ff, + .mmu_sfsr_mask = 0x00016fff, + .mmu_trcr_mask = 0x00ffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI MicroSparc IIep", + .iu_version = 0x42000000, + .fpu_version = 4 << 17, + .mmu_version = 0x04000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x00ffffc0, + .mmu_cxr_mask = 0x000000ff, + .mmu_sfsr_mask = 0x00016bff, + .mmu_trcr_mask = 0x00ffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI SuperSparc 40", // STP1020NPGA + .iu_version = 0x41000000, + .fpu_version = 0 << 17, + .mmu_version = 0x00000000, + .mmu_bm = 0x00002000, + .mmu_ctpr_mask = 0xffffffc0, + .mmu_cxr_mask = 0x0000ffff, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI SuperSparc 50", // STP1020PGA + .iu_version = 0x40000000, + .fpu_version = 0 << 17, + .mmu_version = 0x04000000, + .mmu_bm = 0x00002000, + .mmu_ctpr_mask = 0xffffffc0, + .mmu_cxr_mask = 0x0000ffff, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI SuperSparc 51", + .iu_version = 0x43000000, + .fpu_version = 0 << 17, + .mmu_version = 0x04000000, + .mmu_bm = 0x00002000, + .mmu_ctpr_mask = 0xffffffc0, + .mmu_cxr_mask = 0x0000ffff, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI SuperSparc 60", // STP1020APGA + .iu_version = 0x40000000, + .fpu_version = 0 << 17, + .mmu_version = 0x03000000, + .mmu_bm = 0x00002000, + .mmu_ctpr_mask = 0xffffffc0, + .mmu_cxr_mask = 0x0000ffff, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "TI SuperSparc 61", + .iu_version = 0x44000000, + .fpu_version = 0 << 17, + .mmu_version = 0x04000000, + .mmu_bm = 0x00002000, + .mmu_ctpr_mask = 0xffffffc0, + .mmu_cxr_mask = 0x0000ffff, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Ross RT625", + .iu_version = 0x1e000000, + .fpu_version = 1 << 17, + .mmu_version = 0x1e000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "Ross RT620", + .iu_version = 0x1f000000, + .fpu_version = 1 << 17, + .mmu_version = 0x1f000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "BIT B5010", + .iu_version = 0x20000000, + .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */ + .mmu_version = 0x20000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT | + CPU_FEATURE_FSMULD, + }, + { + .name = "Matsushita MN10501", + .iu_version = 0x50000000, + .fpu_version = 0 << 17, + .mmu_version = 0x50000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT | + CPU_FEATURE_FSMULD, + }, + { + .name = "Weitek W8601", + .iu_version = 0x90 << 24, /* Impl 9, ver 0 */ + .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */ + .mmu_version = 0x10 << 24, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "LEON2", + .iu_version = 0xf2000000, + .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ + .mmu_version = 0xf2000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, + { + .name = "LEON3", + .iu_version = 0xf3000000, + .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ + .mmu_version = 0xf3000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + .nwindows = 8, + .features = CPU_DEFAULT_FEATURES, + }, #endif +}; + +static const char * const feature_name[] = { + "float", + "float128", + "swap", + "mul", + "div", + "flush", + "fsqrt", + "fmul", + "vis1", + "vis2", + "fsmuld", + "hypv", + "cmt", + "gl", +}; + +static void print_features(FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + uint32_t features, const char *prefix) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(feature_name); i++) + if (feature_name[i] && (features & (1 << i))) { + if (prefix) + (*cpu_fprintf)(f, "%s", prefix); + (*cpu_fprintf)(f, "%s ", feature_name[i]); + } } -void do_tick_set_limit(void *opaque, uint64_t limit) +static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features) { -#if !defined(CONFIG_USER_ONLY) - ptimer_set_limit(opaque, -limit, 0); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(feature_name); i++) + if (feature_name[i] && !strcmp(flagname, feature_name[i])) { + *features |= 1 << i; + return; + } + fprintf(stderr, "CPU feature %s not found\n", flagname); +} + +static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model) +{ + unsigned int i; + const sparc_def_t *def = NULL; + char *s = strdup(cpu_model); + char *featurestr, *name = strtok(s, ","); + uint32_t plus_features = 0; + uint32_t minus_features = 0; + long long iu_version; + uint32_t fpu_version, mmu_version, nwindows; + + for (i = 0; i < sizeof(sparc_defs) / sizeof(sparc_def_t); i++) { + if (strcasecmp(name, sparc_defs[i].name) == 0) { + def = &sparc_defs[i]; + } + } + if (!def) + goto error; + memcpy(cpu_def, def, sizeof(*def)); + + featurestr = strtok(NULL, ","); + while (featurestr) { + char *val; + + if (featurestr[0] == '+') { + add_flagname_to_bitmaps(featurestr + 1, &plus_features); + } else if (featurestr[0] == '-') { + add_flagname_to_bitmaps(featurestr + 1, &minus_features); + } else if ((val = strchr(featurestr, '='))) { + *val = 0; val++; + if (!strcmp(featurestr, "iu_version")) { + char *err; + + iu_version = strtoll(val, &err, 0); + if (!*val || *err) { + fprintf(stderr, "bad numerical value %s\n", val); + goto error; + } + cpu_def->iu_version = iu_version; +#ifdef DEBUG_FEATURES + fprintf(stderr, "iu_version %llx\n", iu_version); #endif + } else if (!strcmp(featurestr, "fpu_version")) { + char *err; + + fpu_version = strtol(val, &err, 0); + if (!*val || *err) { + fprintf(stderr, "bad numerical value %s\n", val); + goto error; + } + cpu_def->fpu_version = fpu_version; +#ifdef DEBUG_FEATURES + fprintf(stderr, "fpu_version %llx\n", fpu_version); +#endif + } else if (!strcmp(featurestr, "mmu_version")) { + char *err; + + mmu_version = strtol(val, &err, 0); + if (!*val || *err) { + fprintf(stderr, "bad numerical value %s\n", val); + goto error; + } + cpu_def->mmu_version = mmu_version; +#ifdef DEBUG_FEATURES + fprintf(stderr, "mmu_version %llx\n", mmu_version); +#endif + } else if (!strcmp(featurestr, "nwindows")) { + char *err; + + nwindows = strtol(val, &err, 0); + if (!*val || *err || nwindows > MAX_NWINDOWS || + nwindows < MIN_NWINDOWS) { + fprintf(stderr, "bad numerical value %s\n", val); + goto error; + } + cpu_def->nwindows = nwindows; +#ifdef DEBUG_FEATURES + fprintf(stderr, "nwindows %d\n", nwindows); +#endif + } else { + fprintf(stderr, "unrecognized feature %s\n", featurestr); + goto error; + } + } else { + fprintf(stderr, "feature string `%s' not in format " + "(+feature|-feature|feature=xyz)\n", featurestr); + goto error; + } + featurestr = strtok(NULL, ","); + } + cpu_def->features |= plus_features; + cpu_def->features &= ~minus_features; +#ifdef DEBUG_FEATURES + print_features(stderr, fprintf, cpu_def->features, NULL); +#endif + free(s); + return 0; + + error: + free(s); + return -1; +} + +void sparc_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + unsigned int i; + + for (i = 0; i < sizeof(sparc_defs) / sizeof(sparc_def_t); i++) { + (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x NWINS %d ", + sparc_defs[i].name, + sparc_defs[i].iu_version, + sparc_defs[i].fpu_version, + sparc_defs[i].mmu_version, + sparc_defs[i].nwindows); + print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES & + ~sparc_defs[i].features, "-"); + print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES & + sparc_defs[i].features, "+"); + (*cpu_fprintf)(f, "\n"); + } + (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): "); + print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL); + (*cpu_fprintf)(f, "\n"); + (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): "); + print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL); + (*cpu_fprintf)(f, "\n"); + (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version " + "fpu_version mmu_version nwindows\n"); } + +#define GET_FLAG(a,b) ((env->psr & a)?b:'-') + +void cpu_dump_state(CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) +{ + int i, x; + + cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc, + env->npc); + cpu_fprintf(f, "General Registers:\n"); + for (i = 0; i < 4; i++) + cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]); + cpu_fprintf(f, "\n"); + for (; i < 8; i++) + cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]); + cpu_fprintf(f, "\nCurrent Register Window:\n"); + for (x = 0; x < 3; x++) { + for (i = 0; i < 4; i++) + cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t", + (x == 0 ? 'o' : (x == 1 ? 'l' : 'i')), i, + env->regwptr[i + x * 8]); + cpu_fprintf(f, "\n"); + for (; i < 8; i++) + cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t", + (x == 0 ? 'o' : x == 1 ? 'l' : 'i'), i, + env->regwptr[i + x * 8]); + cpu_fprintf(f, "\n"); + } + cpu_fprintf(f, "\nFloating Point Registers:\n"); + for (i = 0; i < 32; i++) { + if ((i & 3) == 0) + cpu_fprintf(f, "%%f%02d:", i); + cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]); + if ((i & 3) == 3) + cpu_fprintf(f, "\n"); + } +#ifdef TARGET_SPARC64 + cpu_fprintf(f, "pstate: 0x%08x ccr: 0x%02x asi: 0x%02x tl: %d fprs: %d\n", + env->pstate, GET_CCR(env), env->asi, env->tl, env->fprs); + cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate %d " + "cleanwin %d cwp %d\n", + env->cansave, env->canrestore, env->otherwin, env->wstate, + env->cleanwin, env->nwindows - 1 - env->cwp); +#else + cpu_fprintf(f, "psr: 0x%08x -> %c%c%c%c %c%c%c wim: 0x%08x\n", + GET_PSR(env), GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'), + GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'), + env->psrs?'S':'-', env->psrps?'P':'-', + env->psret?'E':'-', env->wim); #endif + cpu_fprintf(f, "fsr: 0x%08x\n", env->fsr); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sparc/helper.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sparc/helper.h --- qemu-0.9.1/target-sparc/helper.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-sparc/helper.h 2008-09-26 19:05:23.000000000 +0100 @@ -0,0 +1,168 @@ +#ifndef DEF_HELPER +#define DEF_HELPER(ret, name, params) ret name params; +#endif + +#ifndef TARGET_SPARC64 +DEF_HELPER(void, helper_rett, (void)) +DEF_HELPER(void, helper_wrpsr, (target_ulong new_psr)) +DEF_HELPER(target_ulong, helper_rdpsr, (void)) +#else +DEF_HELPER(void, helper_wrpstate, (target_ulong new_state)) +DEF_HELPER(void, helper_done, (void)) +DEF_HELPER(void, helper_retry, (void)) +DEF_HELPER(void, helper_flushw, (void)) +DEF_HELPER(void, helper_saved, (void)) +DEF_HELPER(void, helper_restored, (void)) +DEF_HELPER(target_ulong, helper_rdccr, (void)) +DEF_HELPER(void, helper_wrccr, (target_ulong new_ccr)) +DEF_HELPER(target_ulong, helper_rdcwp, (void)) +DEF_HELPER(void, helper_wrcwp, (target_ulong new_cwp)) +DEF_HELPER(target_ulong, helper_array8, (target_ulong pixel_addr, \ + target_ulong cubesize)) +DEF_HELPER(target_ulong, helper_alignaddr, (target_ulong addr, \ + target_ulong offset)) +DEF_HELPER(target_ulong, helper_popc, (target_ulong val)) +DEF_HELPER(void, helper_ldda_asi, (target_ulong addr, int asi, int rd)) +DEF_HELPER(void, helper_ldf_asi, (target_ulong addr, int asi, int size, int rd)) +DEF_HELPER(void, helper_stf_asi, (target_ulong addr, int asi, int size, int rd)) +DEF_HELPER(target_ulong, helper_cas_asi, (target_ulong addr, \ + target_ulong val1, \ + target_ulong val2, uint32_t asi)) +DEF_HELPER(target_ulong, helper_casx_asi, (target_ulong addr, \ + target_ulong val1, \ + target_ulong val2, uint32_t asi)) +DEF_HELPER(void, helper_set_softint, (uint64_t value)) +DEF_HELPER(void, helper_clear_softint, (uint64_t value)) +DEF_HELPER(void, helper_write_softint, (uint64_t value)) +DEF_HELPER(void, helper_tick_set_count, (void *opaque, uint64_t count)) +DEF_HELPER(uint64_t, helper_tick_get_count, (void *opaque)) +DEF_HELPER(void, helper_tick_set_limit, (void *opaque, uint64_t limit)) +#endif +DEF_HELPER(void, helper_check_align, (target_ulong addr, uint32_t align)) +DEF_HELPER(void, helper_debug, (void)) +DEF_HELPER(void, helper_save, (void)) +DEF_HELPER(void, helper_restore, (void)) +DEF_HELPER(void, helper_flush, (target_ulong addr)) +DEF_HELPER(target_ulong, helper_udiv, (target_ulong a, target_ulong b)) +DEF_HELPER(target_ulong, helper_sdiv, (target_ulong a, target_ulong b)) +DEF_HELPER(void, helper_stdf, (target_ulong addr, int mem_idx)) +DEF_HELPER(void, helper_lddf, (target_ulong addr, int mem_idx)) +DEF_HELPER(void, helper_ldqf, (target_ulong addr, int mem_idx)) +DEF_HELPER(void, helper_stqf, (target_ulong addr, int mem_idx)) +#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) +DEF_HELPER(uint64_t, helper_ld_asi, (target_ulong addr, int asi, int size, \ + int sign)) +DEF_HELPER(void, helper_st_asi, (target_ulong addr, uint64_t val, int asi, \ + int size)) +#endif +DEF_HELPER(void, helper_ldfsr, (uint32_t new_fsr)) +DEF_HELPER(void, helper_check_ieee_exceptions, (void)) +DEF_HELPER(void, helper_clear_float_exceptions, (void)) +DEF_HELPER(float32, helper_fabss, (float32 src)) +DEF_HELPER(float32, helper_fsqrts, (float32 src)) +DEF_HELPER(void, helper_fsqrtd, (void)) +DEF_HELPER(void, helper_fcmps, (float32 src1, float32 src2)) +DEF_HELPER(void, helper_fcmpd, (void)) +DEF_HELPER(void, helper_fcmpes, (float32 src1, float32 src2)) +DEF_HELPER(void, helper_fcmped, (void)) +DEF_HELPER(void, helper_fsqrtq, (void)) +DEF_HELPER(void, helper_fcmpq, (void)) +DEF_HELPER(void, helper_fcmpeq, (void)) +#ifdef TARGET_SPARC64 +DEF_HELPER(void, helper_ldxfsr, (uint64_t new_fsr)) +DEF_HELPER(void, helper_fabsd, (void)) +DEF_HELPER(void, helper_fcmps_fcc1, (float32 src1, float32 src2)) +DEF_HELPER(void, helper_fcmps_fcc2, (float32 src1, float32 src2)) +DEF_HELPER(void, helper_fcmps_fcc3, (float32 src1, float32 src2)) +DEF_HELPER(void, helper_fcmpd_fcc1, (void)) +DEF_HELPER(void, helper_fcmpd_fcc2, (void)) +DEF_HELPER(void, helper_fcmpd_fcc3, (void)) +DEF_HELPER(void, helper_fcmpes_fcc1, (float32 src1, float32 src2)) +DEF_HELPER(void, helper_fcmpes_fcc2, (float32 src1, float32 src2)) +DEF_HELPER(void, helper_fcmpes_fcc3, (float32 src1, float32 src2)) +DEF_HELPER(void, helper_fcmped_fcc1, (void)) +DEF_HELPER(void, helper_fcmped_fcc2, (void)) +DEF_HELPER(void, helper_fcmped_fcc3, (void)) +DEF_HELPER(void, helper_fabsq, (void)) +DEF_HELPER(void, helper_fcmpq_fcc1, (void)) +DEF_HELPER(void, helper_fcmpq_fcc2, (void)) +DEF_HELPER(void, helper_fcmpq_fcc3, (void)) +DEF_HELPER(void, helper_fcmpeq_fcc1, (void)) +DEF_HELPER(void, helper_fcmpeq_fcc2, (void)) +DEF_HELPER(void, helper_fcmpeq_fcc3, (void)) +#endif +DEF_HELPER(void, raise_exception, (int tt)) +#define F_HELPER_0_0(name) DEF_HELPER(void, helper_f ## name, (void)) +#define F_HELPER_DQ_0_0(name) \ + F_HELPER_0_0(name ## d); \ + F_HELPER_0_0(name ## q) + +F_HELPER_DQ_0_0(add); +F_HELPER_DQ_0_0(sub); +F_HELPER_DQ_0_0(mul); +F_HELPER_DQ_0_0(div); + +DEF_HELPER(float32, helper_fadds, (float32 src1, float32 src2)) +DEF_HELPER(float32, helper_fsubs, (float32 src1, float32 src2)) +DEF_HELPER(float32, helper_fmuls, (float32 src1, float32 src2)) +DEF_HELPER(float32, helper_fdivs, (float32 src1, float32 src2)) + +DEF_HELPER(void, helper_fsmuld, (float32 src1, float32 src2)) +F_HELPER_0_0(dmulq); + +DEF_HELPER(float32, helper_fnegs, (float32 src)) +DEF_HELPER(void, helper_fitod, (int32_t src)) +DEF_HELPER(void, helper_fitoq, (int32_t src)) + +DEF_HELPER(float32, helper_fitos, (int32_t src)) + +#ifdef TARGET_SPARC64 +DEF_HELPER(void, helper_fnegd, (void)) +DEF_HELPER(void, helper_fnegq, (void)) +DEF_HELPER(uint32_t, helper_fxtos, (void)) +F_HELPER_DQ_0_0(xto); +#endif +DEF_HELPER(float32, helper_fdtos, (void)) +DEF_HELPER(void, helper_fstod, (float32 src)) +DEF_HELPER(float32, helper_fqtos, (void)) +DEF_HELPER(void, helper_fstoq, (float32 src)) +F_HELPER_0_0(qtod); +F_HELPER_0_0(dtoq); +DEF_HELPER(int32_t, helper_fstoi, (float32 src)) +DEF_HELPER(int32_t, helper_fdtoi, (void)) +DEF_HELPER(int32_t, helper_fqtoi, (void)) +#ifdef TARGET_SPARC64 +DEF_HELPER(void, helper_fstox, (uint32_t src)) +F_HELPER_0_0(dtox); +F_HELPER_0_0(qtox); +F_HELPER_0_0(aligndata); + +F_HELPER_0_0(pmerge); +F_HELPER_0_0(mul8x16); +F_HELPER_0_0(mul8x16al); +F_HELPER_0_0(mul8x16au); +F_HELPER_0_0(mul8sux16); +F_HELPER_0_0(mul8ulx16); +F_HELPER_0_0(muld8sux16); +F_HELPER_0_0(muld8ulx16); +F_HELPER_0_0(expand); +#define VIS_HELPER(name) \ + F_HELPER_0_0(name##16); \ + DEF_HELPER(uint32_t, helper_f ## name ## 16s, (uint32_t src1, uint32_t src2))\ + F_HELPER_0_0(name##32); \ + DEF_HELPER(uint32_t, helper_f ## name ## 32s, (uint32_t src1, uint32_t src2)) + +VIS_HELPER(padd); +VIS_HELPER(psub); +#define VIS_CMPHELPER(name) \ + F_HELPER_0_0(name##16); \ + F_HELPER_0_0(name##32) +VIS_CMPHELPER(cmpgt); +VIS_CMPHELPER(cmpeq); +VIS_CMPHELPER(cmple); +VIS_CMPHELPER(cmpne); +#endif +#undef F_HELPER_0_0 +#undef F_HELPER_DQ_0_0 +#undef VIS_HELPER +#undef VIS_CMPHELPER diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sparc/machine.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sparc/machine.c --- qemu-0.9.1/target-sparc/machine.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-sparc/machine.c 2008-09-26 20:48:58.000000000 +0100 @@ -0,0 +1,224 @@ +#include "hw/hw.h" +#include "hw/boards.h" +#include "qemu-timer.h" + +#include "exec-all.h" + +void register_machines(void) +{ +#ifdef TARGET_SPARC64 + qemu_register_machine(&sun4u_machine); + qemu_register_machine(&sun4v_machine); + qemu_register_machine(&niagara_machine); +#else + qemu_register_machine(&ss5_machine); + qemu_register_machine(&ss10_machine); + qemu_register_machine(&ss600mp_machine); + qemu_register_machine(&ss20_machine); + qemu_register_machine(&ss2_machine); + qemu_register_machine(&voyager_machine); + qemu_register_machine(&ss_lx_machine); + qemu_register_machine(&ss4_machine); + qemu_register_machine(&scls_machine); + qemu_register_machine(&sbook_machine); + qemu_register_machine(&ss1000_machine); + qemu_register_machine(&ss2000_machine); +#endif +} + +void cpu_save(QEMUFile *f, void *opaque) +{ + CPUState *env = opaque; + int i; + uint32_t tmp; + + // if env->cwp == env->nwindows - 1, this will set the ins of the last + // window as the outs of the first window + cpu_set_cwp(env, env->cwp); + + for(i = 0; i < 8; i++) + qemu_put_betls(f, &env->gregs[i]); + qemu_put_be32s(f, &env->nwindows); + for(i = 0; i < env->nwindows * 16; i++) + qemu_put_betls(f, &env->regbase[i]); + + /* FPU */ + for(i = 0; i < TARGET_FPREGS; i++) { + union { + float32 f; + uint32_t i; + } u; + u.f = env->fpr[i]; + qemu_put_be32(f, u.i); + } + + qemu_put_betls(f, &env->pc); + qemu_put_betls(f, &env->npc); + qemu_put_betls(f, &env->y); + tmp = GET_PSR(env); + qemu_put_be32(f, tmp); + qemu_put_betls(f, &env->fsr); + qemu_put_betls(f, &env->tbr); + tmp = env->interrupt_index; + qemu_put_be32(f, tmp); + qemu_put_be32s(f, &env->pil_in); +#ifndef TARGET_SPARC64 + qemu_put_be32s(f, &env->wim); + /* MMU */ + for (i = 0; i < 32; i++) + qemu_put_be32s(f, &env->mmuregs[i]); +#else + qemu_put_be64s(f, &env->lsu); + for (i = 0; i < 16; i++) { + qemu_put_be64s(f, &env->immuregs[i]); + qemu_put_be64s(f, &env->dmmuregs[i]); + } + for (i = 0; i < 64; i++) { + qemu_put_be64s(f, &env->itlb_tag[i]); + qemu_put_be64s(f, &env->itlb_tte[i]); + qemu_put_be64s(f, &env->dtlb_tag[i]); + qemu_put_be64s(f, &env->dtlb_tte[i]); + } + qemu_put_be32s(f, &env->mmu_version); + for (i = 0; i < MAXTL_MAX; i++) { + qemu_put_be64s(f, &env->ts[i].tpc); + qemu_put_be64s(f, &env->ts[i].tnpc); + qemu_put_be64s(f, &env->ts[i].tstate); + qemu_put_be32s(f, &env->ts[i].tt); + } + qemu_put_be32s(f, &env->xcc); + qemu_put_be32s(f, &env->asi); + qemu_put_be32s(f, &env->pstate); + qemu_put_be32s(f, &env->tl); + qemu_put_be32s(f, &env->cansave); + qemu_put_be32s(f, &env->canrestore); + qemu_put_be32s(f, &env->otherwin); + qemu_put_be32s(f, &env->wstate); + qemu_put_be32s(f, &env->cleanwin); + for (i = 0; i < 8; i++) + qemu_put_be64s(f, &env->agregs[i]); + for (i = 0; i < 8; i++) + qemu_put_be64s(f, &env->bgregs[i]); + for (i = 0; i < 8; i++) + qemu_put_be64s(f, &env->igregs[i]); + for (i = 0; i < 8; i++) + qemu_put_be64s(f, &env->mgregs[i]); + qemu_put_be64s(f, &env->fprs); + qemu_put_be64s(f, &env->tick_cmpr); + qemu_put_be64s(f, &env->stick_cmpr); + qemu_put_ptimer(f, env->tick); + qemu_put_ptimer(f, env->stick); + qemu_put_be64s(f, &env->gsr); + qemu_put_be32s(f, &env->gl); + qemu_put_be64s(f, &env->hpstate); + for (i = 0; i < MAXTL_MAX; i++) + qemu_put_be64s(f, &env->htstate[i]); + qemu_put_be64s(f, &env->hintp); + qemu_put_be64s(f, &env->htba); + qemu_put_be64s(f, &env->hver); + qemu_put_be64s(f, &env->hstick_cmpr); + qemu_put_be64s(f, &env->ssr); + qemu_put_ptimer(f, env->hstick); +#endif +} + +int cpu_load(QEMUFile *f, void *opaque, int version_id) +{ + CPUState *env = opaque; + int i; + uint32_t tmp; + + if (version_id != 5) + return -EINVAL; + for(i = 0; i < 8; i++) + qemu_get_betls(f, &env->gregs[i]); + qemu_get_be32s(f, &env->nwindows); + for(i = 0; i < env->nwindows * 16; i++) + qemu_get_betls(f, &env->regbase[i]); + + /* FPU */ + for(i = 0; i < TARGET_FPREGS; i++) { + union { + float32 f; + uint32_t i; + } u; + u.i = qemu_get_be32(f); + env->fpr[i] = u.f; + } + + qemu_get_betls(f, &env->pc); + qemu_get_betls(f, &env->npc); + qemu_get_betls(f, &env->y); + tmp = qemu_get_be32(f); + env->cwp = 0; /* needed to ensure that the wrapping registers are + correctly updated */ + PUT_PSR(env, tmp); + qemu_get_betls(f, &env->fsr); + qemu_get_betls(f, &env->tbr); + tmp = qemu_get_be32(f); + env->interrupt_index = tmp; + qemu_get_be32s(f, &env->pil_in); +#ifndef TARGET_SPARC64 + qemu_get_be32s(f, &env->wim); + /* MMU */ + for (i = 0; i < 32; i++) + qemu_get_be32s(f, &env->mmuregs[i]); +#else + qemu_get_be64s(f, &env->lsu); + for (i = 0; i < 16; i++) { + qemu_get_be64s(f, &env->immuregs[i]); + qemu_get_be64s(f, &env->dmmuregs[i]); + } + for (i = 0; i < 64; i++) { + qemu_get_be64s(f, &env->itlb_tag[i]); + qemu_get_be64s(f, &env->itlb_tte[i]); + qemu_get_be64s(f, &env->dtlb_tag[i]); + qemu_get_be64s(f, &env->dtlb_tte[i]); + } + qemu_get_be32s(f, &env->mmu_version); + for (i = 0; i < MAXTL_MAX; i++) { + qemu_get_be64s(f, &env->ts[i].tpc); + qemu_get_be64s(f, &env->ts[i].tnpc); + qemu_get_be64s(f, &env->ts[i].tstate); + qemu_get_be32s(f, &env->ts[i].tt); + } + qemu_get_be32s(f, &env->xcc); + qemu_get_be32s(f, &env->asi); + qemu_get_be32s(f, &env->pstate); + qemu_get_be32s(f, &env->tl); + env->tsptr = &env->ts[env->tl & MAXTL_MASK]; + qemu_get_be32s(f, &env->cansave); + qemu_get_be32s(f, &env->canrestore); + qemu_get_be32s(f, &env->otherwin); + qemu_get_be32s(f, &env->wstate); + qemu_get_be32s(f, &env->cleanwin); + for (i = 0; i < 8; i++) + qemu_get_be64s(f, &env->agregs[i]); + for (i = 0; i < 8; i++) + qemu_get_be64s(f, &env->bgregs[i]); + for (i = 0; i < 8; i++) + qemu_get_be64s(f, &env->igregs[i]); + for (i = 0; i < 8; i++) + qemu_get_be64s(f, &env->mgregs[i]); + qemu_get_be64s(f, &env->fprs); + qemu_get_be64s(f, &env->tick_cmpr); + qemu_get_be64s(f, &env->stick_cmpr); + qemu_get_ptimer(f, env->tick); + qemu_get_ptimer(f, env->stick); + qemu_get_be64s(f, &env->gsr); + qemu_get_be32s(f, &env->gl); + qemu_get_be64s(f, &env->hpstate); + for (i = 0; i < MAXTL_MAX; i++) + qemu_get_be64s(f, &env->htstate[i]); + qemu_get_be64s(f, &env->hintp); + qemu_get_be64s(f, &env->htba); + qemu_get_be64s(f, &env->hver); + qemu_get_be64s(f, &env->hstick_cmpr); + qemu_get_be64s(f, &env->ssr); + qemu_get_ptimer(f, env->hstick); +#endif + tlb_flush(env, 1); + return 0; +} + + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sparc/op.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sparc/op.c --- qemu-0.9.1/target-sparc/op.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-sparc/op.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,2720 +0,0 @@ -/* - SPARC micro operations - - Copyright (C) 2003 Thomas M. Ogrisegg - - 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 "exec.h" - - /*XXX*/ -#define REGNAME g0 -#define REG (env->gregs[0]) -#include "op_template.h" -#define REGNAME g1 -#define REG (env->gregs[1]) -#include "op_template.h" -#define REGNAME g2 -#define REG (env->gregs[2]) -#include "op_template.h" -#define REGNAME g3 -#define REG (env->gregs[3]) -#include "op_template.h" -#define REGNAME g4 -#define REG (env->gregs[4]) -#include "op_template.h" -#define REGNAME g5 -#define REG (env->gregs[5]) -#include "op_template.h" -#define REGNAME g6 -#define REG (env->gregs[6]) -#include "op_template.h" -#define REGNAME g7 -#define REG (env->gregs[7]) -#include "op_template.h" -#define REGNAME i0 -#define REG (REGWPTR[16]) -#include "op_template.h" -#define REGNAME i1 -#define REG (REGWPTR[17]) -#include "op_template.h" -#define REGNAME i2 -#define REG (REGWPTR[18]) -#include "op_template.h" -#define REGNAME i3 -#define REG (REGWPTR[19]) -#include "op_template.h" -#define REGNAME i4 -#define REG (REGWPTR[20]) -#include "op_template.h" -#define REGNAME i5 -#define REG (REGWPTR[21]) -#include "op_template.h" -#define REGNAME i6 -#define REG (REGWPTR[22]) -#include "op_template.h" -#define REGNAME i7 -#define REG (REGWPTR[23]) -#include "op_template.h" -#define REGNAME l0 -#define REG (REGWPTR[8]) -#include "op_template.h" -#define REGNAME l1 -#define REG (REGWPTR[9]) -#include "op_template.h" -#define REGNAME l2 -#define REG (REGWPTR[10]) -#include "op_template.h" -#define REGNAME l3 -#define REG (REGWPTR[11]) -#include "op_template.h" -#define REGNAME l4 -#define REG (REGWPTR[12]) -#include "op_template.h" -#define REGNAME l5 -#define REG (REGWPTR[13]) -#include "op_template.h" -#define REGNAME l6 -#define REG (REGWPTR[14]) -#include "op_template.h" -#define REGNAME l7 -#define REG (REGWPTR[15]) -#include "op_template.h" -#define REGNAME o0 -#define REG (REGWPTR[0]) -#include "op_template.h" -#define REGNAME o1 -#define REG (REGWPTR[1]) -#include "op_template.h" -#define REGNAME o2 -#define REG (REGWPTR[2]) -#include "op_template.h" -#define REGNAME o3 -#define REG (REGWPTR[3]) -#include "op_template.h" -#define REGNAME o4 -#define REG (REGWPTR[4]) -#include "op_template.h" -#define REGNAME o5 -#define REG (REGWPTR[5]) -#include "op_template.h" -#define REGNAME o6 -#define REG (REGWPTR[6]) -#include "op_template.h" -#define REGNAME o7 -#define REG (REGWPTR[7]) -#include "op_template.h" - -#define REGNAME f0 -#define REG (env->fpr[0]) -#include "fop_template.h" -#define REGNAME f1 -#define REG (env->fpr[1]) -#include "fop_template.h" -#define REGNAME f2 -#define REG (env->fpr[2]) -#include "fop_template.h" -#define REGNAME f3 -#define REG (env->fpr[3]) -#include "fop_template.h" -#define REGNAME f4 -#define REG (env->fpr[4]) -#include "fop_template.h" -#define REGNAME f5 -#define REG (env->fpr[5]) -#include "fop_template.h" -#define REGNAME f6 -#define REG (env->fpr[6]) -#include "fop_template.h" -#define REGNAME f7 -#define REG (env->fpr[7]) -#include "fop_template.h" -#define REGNAME f8 -#define REG (env->fpr[8]) -#include "fop_template.h" -#define REGNAME f9 -#define REG (env->fpr[9]) -#include "fop_template.h" -#define REGNAME f10 -#define REG (env->fpr[10]) -#include "fop_template.h" -#define REGNAME f11 -#define REG (env->fpr[11]) -#include "fop_template.h" -#define REGNAME f12 -#define REG (env->fpr[12]) -#include "fop_template.h" -#define REGNAME f13 -#define REG (env->fpr[13]) -#include "fop_template.h" -#define REGNAME f14 -#define REG (env->fpr[14]) -#include "fop_template.h" -#define REGNAME f15 -#define REG (env->fpr[15]) -#include "fop_template.h" -#define REGNAME f16 -#define REG (env->fpr[16]) -#include "fop_template.h" -#define REGNAME f17 -#define REG (env->fpr[17]) -#include "fop_template.h" -#define REGNAME f18 -#define REG (env->fpr[18]) -#include "fop_template.h" -#define REGNAME f19 -#define REG (env->fpr[19]) -#include "fop_template.h" -#define REGNAME f20 -#define REG (env->fpr[20]) -#include "fop_template.h" -#define REGNAME f21 -#define REG (env->fpr[21]) -#include "fop_template.h" -#define REGNAME f22 -#define REG (env->fpr[22]) -#include "fop_template.h" -#define REGNAME f23 -#define REG (env->fpr[23]) -#include "fop_template.h" -#define REGNAME f24 -#define REG (env->fpr[24]) -#include "fop_template.h" -#define REGNAME f25 -#define REG (env->fpr[25]) -#include "fop_template.h" -#define REGNAME f26 -#define REG (env->fpr[26]) -#include "fop_template.h" -#define REGNAME f27 -#define REG (env->fpr[27]) -#include "fop_template.h" -#define REGNAME f28 -#define REG (env->fpr[28]) -#include "fop_template.h" -#define REGNAME f29 -#define REG (env->fpr[29]) -#include "fop_template.h" -#define REGNAME f30 -#define REG (env->fpr[30]) -#include "fop_template.h" -#define REGNAME f31 -#define REG (env->fpr[31]) -#include "fop_template.h" - -#ifdef TARGET_SPARC64 -#define REGNAME f32 -#define REG (env->fpr[32]) -#include "fop_template.h" -#define REGNAME f34 -#define REG (env->fpr[34]) -#include "fop_template.h" -#define REGNAME f36 -#define REG (env->fpr[36]) -#include "fop_template.h" -#define REGNAME f38 -#define REG (env->fpr[38]) -#include "fop_template.h" -#define REGNAME f40 -#define REG (env->fpr[40]) -#include "fop_template.h" -#define REGNAME f42 -#define REG (env->fpr[42]) -#include "fop_template.h" -#define REGNAME f44 -#define REG (env->fpr[44]) -#include "fop_template.h" -#define REGNAME f46 -#define REG (env->fpr[46]) -#include "fop_template.h" -#define REGNAME f48 -#define REG (env->fpr[47]) -#include "fop_template.h" -#define REGNAME f50 -#define REG (env->fpr[50]) -#include "fop_template.h" -#define REGNAME f52 -#define REG (env->fpr[52]) -#include "fop_template.h" -#define REGNAME f54 -#define REG (env->fpr[54]) -#include "fop_template.h" -#define REGNAME f56 -#define REG (env->fpr[56]) -#include "fop_template.h" -#define REGNAME f58 -#define REG (env->fpr[58]) -#include "fop_template.h" -#define REGNAME f60 -#define REG (env->fpr[60]) -#include "fop_template.h" -#define REGNAME f62 -#define REG (env->fpr[62]) -#include "fop_template.h" -#endif - -#ifdef TARGET_SPARC64 -#ifdef WORDS_BIGENDIAN -typedef union UREG64 { - struct { uint16_t v3, v2, v1, v0; } w; - struct { uint32_t v1, v0; } l; - uint64_t q; -} UREG64; -#else -typedef union UREG64 { - struct { uint16_t v0, v1, v2, v3; } w; - struct { uint32_t v0, v1; } l; - uint64_t q; -} UREG64; -#endif - -#define PARAMQ1 \ -({\ - UREG64 __p;\ - __p.l.v1 = PARAM1;\ - __p.l.v0 = PARAM2;\ - __p.q;\ -}) - -void OPPROTO op_movq_T0_im64(void) -{ - T0 = PARAMQ1; -} - -void OPPROTO op_movq_T1_im64(void) -{ - T1 = PARAMQ1; -} - -#define XFLAG_SET(x) ((env->xcc&x)?1:0) - -#else -#define EIP (env->pc) -#endif - -#define FLAG_SET(x) ((env->psr&x)?1:0) - -void OPPROTO op_movl_T0_0(void) -{ - T0 = 0; -} - -void OPPROTO op_movl_T0_im(void) -{ - T0 = (uint32_t)PARAM1; -} - -void OPPROTO op_movl_T1_im(void) -{ - T1 = (uint32_t)PARAM1; -} - -void OPPROTO op_movl_T2_im(void) -{ - T2 = (uint32_t)PARAM1; -} - -void OPPROTO op_movl_T0_sim(void) -{ - T0 = (int32_t)PARAM1; -} - -void OPPROTO op_movl_T1_sim(void) -{ - T1 = (int32_t)PARAM1; -} - -void OPPROTO op_movl_T2_sim(void) -{ - T2 = (int32_t)PARAM1; -} - -void OPPROTO op_movl_T0_env(void) -{ - T0 = *(uint32_t *)((char *)env + PARAM1); -} - -void OPPROTO op_movl_env_T0(void) -{ - *(uint32_t *)((char *)env + PARAM1) = T0; -} - -void OPPROTO op_movtl_T0_env(void) -{ - T0 = *(target_ulong *)((char *)env + PARAM1); -} - -void OPPROTO op_movtl_env_T0(void) -{ - *(target_ulong *)((char *)env + PARAM1) = T0; -} - -void OPPROTO op_add_T1_T0(void) -{ - T0 += T1; -} - -void OPPROTO op_add_T1_T0_cc(void) -{ - target_ulong src1; - - src1 = T0; - T0 += T1; - env->psr = 0; -#ifdef TARGET_SPARC64 - if (!(T0 & 0xffffffff)) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) - env->psr |= PSR_CARRY; - if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & - ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) - env->psr |= PSR_OVF; - - env->xcc = 0; - if (!T0) - env->xcc |= PSR_ZERO; - if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; - if (T0 < src1) - env->xcc |= PSR_CARRY; - if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1ULL << 63)) - env->xcc |= PSR_OVF; -#else - if (!T0) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if (T0 < src1) - env->psr |= PSR_CARRY; - if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) - env->psr |= PSR_OVF; -#endif - FORCE_RET(); -} - -void OPPROTO op_addx_T1_T0(void) -{ - T0 += T1 + FLAG_SET(PSR_CARRY); -} - -void OPPROTO op_addx_T1_T0_cc(void) -{ - target_ulong src1; - src1 = T0; - if (FLAG_SET(PSR_CARRY)) - { - T0 += T1 + 1; - env->psr = 0; -#ifdef TARGET_SPARC64 - if ((T0 & 0xffffffff) <= (src1 & 0xffffffff)) - env->psr |= PSR_CARRY; - env->xcc = 0; - if (T0 <= src1) - env->xcc |= PSR_CARRY; -#else - if (T0 <= src1) - env->psr |= PSR_CARRY; -#endif - } - else - { - T0 += T1; - env->psr = 0; -#ifdef TARGET_SPARC64 - if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) - env->psr |= PSR_CARRY; - env->xcc = 0; - if (T0 < src1) - env->xcc |= PSR_CARRY; -#else - if (T0 < src1) - env->psr |= PSR_CARRY; -#endif - } -#ifdef TARGET_SPARC64 - if (!(T0 & 0xffffffff)) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & - ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) - env->psr |= PSR_OVF; - - if (!T0) - env->xcc |= PSR_ZERO; - if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; - if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1ULL << 63)) - env->xcc |= PSR_OVF; -#else - if (!T0) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) - env->psr |= PSR_OVF; -#endif - FORCE_RET(); -} - -void OPPROTO op_tadd_T1_T0_cc(void) -{ - target_ulong src1; - - src1 = T0; - T0 += T1; - env->psr = 0; -#ifdef TARGET_SPARC64 - if (!(T0 & 0xffffffff)) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) - env->psr |= PSR_CARRY; - if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & - ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) - env->psr |= PSR_OVF; - if ((src1 & 0x03) || (T1 & 0x03)) - env->psr |= PSR_OVF; - - env->xcc = 0; - if (!T0) - env->xcc |= PSR_ZERO; - if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; - if (T0 < src1) - env->xcc |= PSR_CARRY; - if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1ULL << 63)) - env->xcc |= PSR_OVF; -#else - if (!T0) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if (T0 < src1) - env->psr |= PSR_CARRY; - if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) - env->psr |= PSR_OVF; - if ((src1 & 0x03) || (T1 & 0x03)) - env->psr |= PSR_OVF; -#endif - FORCE_RET(); -} - -void OPPROTO op_tadd_T1_T0_ccTV(void) -{ - target_ulong src1; - - if ((T0 & 0x03) || (T1 & 0x03)) { - raise_exception(TT_TOVF); - FORCE_RET(); - return; - } - - src1 = T0; - T0 += T1; - -#ifdef TARGET_SPARC64 - if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & - ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) - raise_exception(TT_TOVF); -#else - if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) - raise_exception(TT_TOVF); -#endif - - env->psr = 0; -#ifdef TARGET_SPARC64 - if (!(T0 & 0xffffffff)) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) - env->psr |= PSR_CARRY; - - env->xcc = 0; - if (!T0) - env->xcc |= PSR_ZERO; - if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; - if (T0 < src1) - env->xcc |= PSR_CARRY; -#else - if (!T0) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if (T0 < src1) - env->psr |= PSR_CARRY; -#endif - FORCE_RET(); -} - -void OPPROTO op_sub_T1_T0(void) -{ - T0 -= T1; -} - -void OPPROTO op_sub_T1_T0_cc(void) -{ - target_ulong src1; - - src1 = T0; - T0 -= T1; - env->psr = 0; -#ifdef TARGET_SPARC64 - if (!(T0 & 0xffffffff)) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) - env->psr |= PSR_CARRY; - if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) & - ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) - env->psr |= PSR_OVF; - - env->xcc = 0; - if (!T0) - env->xcc |= PSR_ZERO; - if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; - if (src1 < T1) - env->xcc |= PSR_CARRY; - if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63)) - env->xcc |= PSR_OVF; -#else - if (!T0) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if (src1 < T1) - env->psr |= PSR_CARRY; - if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) - env->psr |= PSR_OVF; -#endif - FORCE_RET(); -} - -void OPPROTO op_subx_T1_T0(void) -{ - T0 -= T1 + FLAG_SET(PSR_CARRY); -} - -void OPPROTO op_subx_T1_T0_cc(void) -{ - target_ulong src1; - src1 = T0; - if (FLAG_SET(PSR_CARRY)) - { - T0 -= T1 + 1; - env->psr = 0; -#ifdef TARGET_SPARC64 - if ((src1 & 0xffffffff) <= (T1 & 0xffffffff)) - env->psr |= PSR_CARRY; - env->xcc = 0; - if (src1 <= T1) - env->xcc |= PSR_CARRY; -#else - if (src1 <= T1) - env->psr |= PSR_CARRY; -#endif - } - else - { - T0 -= T1; - env->psr = 0; -#ifdef TARGET_SPARC64 - if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) - env->psr |= PSR_CARRY; - env->xcc = 0; - if (src1 < T1) - env->xcc |= PSR_CARRY; -#else - if (src1 < T1) - env->psr |= PSR_CARRY; -#endif - } -#ifdef TARGET_SPARC64 - if (!(T0 & 0xffffffff)) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) & - ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) - env->psr |= PSR_OVF; - - if (!T0) - env->xcc |= PSR_ZERO; - if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; - if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63)) - env->xcc |= PSR_OVF; -#else - if (!T0) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) - env->psr |= PSR_OVF; -#endif - FORCE_RET(); -} - -void OPPROTO op_tsub_T1_T0_cc(void) -{ - target_ulong src1; - - src1 = T0; - T0 -= T1; - env->psr = 0; -#ifdef TARGET_SPARC64 - if (!(T0 & 0xffffffff)) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) - env->psr |= PSR_CARRY; - if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) & - ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) - env->psr |= PSR_OVF; - if ((src1 & 0x03) || (T1 & 0x03)) - env->psr |= PSR_OVF; - - env->xcc = 0; - if (!T0) - env->xcc |= PSR_ZERO; - if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; - if (src1 < T1) - env->xcc |= PSR_CARRY; - if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63)) - env->xcc |= PSR_OVF; -#else - if (!T0) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if (src1 < T1) - env->psr |= PSR_CARRY; - if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) - env->psr |= PSR_OVF; - if ((src1 & 0x03) || (T1 & 0x03)) - env->psr |= PSR_OVF; -#endif - FORCE_RET(); -} - -void OPPROTO op_tsub_T1_T0_ccTV(void) -{ - target_ulong src1; - - if ((T0 & 0x03) || (T1 & 0x03)) - raise_exception(TT_TOVF); - - src1 = T0; - T0 -= T1; - -#ifdef TARGET_SPARC64 - if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) & - ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) - raise_exception(TT_TOVF); -#else - if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) - raise_exception(TT_TOVF); -#endif - - env->psr = 0; -#ifdef TARGET_SPARC64 - if (!(T0 & 0xffffffff)) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) - env->psr |= PSR_CARRY; - - env->xcc = 0; - if (!T0) - env->xcc |= PSR_ZERO; - if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; - if (src1 < T1) - env->xcc |= PSR_CARRY; -#else - if (!T0) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if (src1 < T1) - env->psr |= PSR_CARRY; -#endif - FORCE_RET(); -} - -void OPPROTO op_and_T1_T0(void) -{ - T0 &= T1; -} - -void OPPROTO op_or_T1_T0(void) -{ - T0 |= T1; -} - -void OPPROTO op_xor_T1_T0(void) -{ - T0 ^= T1; -} - -void OPPROTO op_andn_T1_T0(void) -{ - T0 &= ~T1; -} - -void OPPROTO op_orn_T1_T0(void) -{ - T0 |= ~T1; -} - -void OPPROTO op_xnor_T1_T0(void) -{ - T0 ^= ~T1; -} - -void OPPROTO op_umul_T1_T0(void) -{ - uint64_t res; - res = (uint64_t) T0 * (uint64_t) T1; -#ifdef TARGET_SPARC64 - T0 = res; -#else - T0 = res & 0xffffffff; -#endif - env->y = res >> 32; -} - -void OPPROTO op_smul_T1_T0(void) -{ - uint64_t res; - res = (int64_t) ((int32_t) T0) * (int64_t) ((int32_t) T1); -#ifdef TARGET_SPARC64 - T0 = res; -#else - T0 = res & 0xffffffff; -#endif - env->y = res >> 32; -} - -void OPPROTO op_mulscc_T1_T0(void) -{ - unsigned int b1, N, V, b2; - target_ulong src1; - - N = FLAG_SET(PSR_NEG); - V = FLAG_SET(PSR_OVF); - b1 = N ^ V; - b2 = T0 & 1; - T0 = (b1 << 31) | (T0 >> 1); - if (!(env->y & 1)) - T1 = 0; - /* do addition and update flags */ - src1 = T0; - T0 += T1; - env->psr = 0; - if (!T0) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if (T0 < src1) - env->psr |= PSR_CARRY; - if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) - env->psr |= PSR_OVF; - env->y = (b2 << 31) | (env->y >> 1); - FORCE_RET(); -} - -void OPPROTO op_udiv_T1_T0(void) -{ - uint64_t x0; - uint32_t x1; - - x0 = T0 | ((uint64_t) (env->y) << 32); - x1 = T1; - - if (x1 == 0) { - raise_exception(TT_DIV_ZERO); - } - - x0 = x0 / x1; - if (x0 > 0xffffffff) { - T0 = 0xffffffff; - T1 = 1; - } else { - T0 = x0; - T1 = 0; - } - FORCE_RET(); -} - -void OPPROTO op_sdiv_T1_T0(void) -{ - int64_t x0; - int32_t x1; - - x0 = T0 | ((int64_t) (env->y) << 32); - x1 = T1; - - if (x1 == 0) { - raise_exception(TT_DIV_ZERO); - } - - x0 = x0 / x1; - if ((int32_t) x0 != x0) { - T0 = x0 < 0? 0x80000000: 0x7fffffff; - T1 = 1; - } else { - T0 = x0; - T1 = 0; - } - FORCE_RET(); -} - -void OPPROTO op_div_cc(void) -{ - env->psr = 0; -#ifdef TARGET_SPARC64 - if (!T0) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if (T1) - env->psr |= PSR_OVF; - - env->xcc = 0; - if (!T0) - env->xcc |= PSR_ZERO; - if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; -#else - if (!T0) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - if (T1) - env->psr |= PSR_OVF; -#endif - FORCE_RET(); -} - -#ifdef TARGET_SPARC64 -void OPPROTO op_mulx_T1_T0(void) -{ - T0 *= T1; - FORCE_RET(); -} - -void OPPROTO op_udivx_T1_T0(void) -{ - if (T1 == 0) { - raise_exception(TT_DIV_ZERO); - } - T0 /= T1; - FORCE_RET(); -} - -void OPPROTO op_sdivx_T1_T0(void) -{ - if (T1 == 0) { - raise_exception(TT_DIV_ZERO); - } - if (T0 == INT64_MIN && T1 == -1) - T0 = INT64_MIN; - else - T0 /= (target_long) T1; - FORCE_RET(); -} -#endif - -void OPPROTO op_logic_T0_cc(void) -{ - env->psr = 0; -#ifdef TARGET_SPARC64 - if (!(T0 & 0xffffffff)) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; - - env->xcc = 0; - if (!T0) - env->xcc |= PSR_ZERO; - if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; -#else - if (!T0) - env->psr |= PSR_ZERO; - if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; -#endif - FORCE_RET(); -} - -void OPPROTO op_sll(void) -{ - T0 <<= (T1 & 0x1f); -} - -#ifdef TARGET_SPARC64 -void OPPROTO op_sllx(void) -{ - T0 <<= (T1 & 0x3f); -} - -void OPPROTO op_srl(void) -{ - T0 = (T0 & 0xffffffff) >> (T1 & 0x1f); -} - -void OPPROTO op_srlx(void) -{ - T0 >>= (T1 & 0x3f); -} - -void OPPROTO op_sra(void) -{ - T0 = ((int32_t) (T0 & 0xffffffff)) >> (T1 & 0x1f); -} - -void OPPROTO op_srax(void) -{ - T0 = ((int64_t) T0) >> (T1 & 0x3f); -} -#else -void OPPROTO op_srl(void) -{ - T0 >>= (T1 & 0x1f); -} - -void OPPROTO op_sra(void) -{ - T0 = ((int32_t) T0) >> (T1 & 0x1f); -} -#endif - -/* Load and store */ -#define MEMSUFFIX _raw -#include "op_mem.h" -#if !defined(CONFIG_USER_ONLY) -#define MEMSUFFIX _user -#include "op_mem.h" - -#define MEMSUFFIX _kernel -#include "op_mem.h" - -#ifdef TARGET_SPARC64 -#define MEMSUFFIX _hypv -#include "op_mem.h" -#endif -#endif - -void OPPROTO op_ldfsr(void) -{ - PUT_FSR32(env, *((uint32_t *) &FT0)); - helper_ldfsr(); -} - -void OPPROTO op_stfsr(void) -{ - *((uint32_t *) &FT0) = GET_FSR32(env); -} - -#ifndef TARGET_SPARC64 -void OPPROTO op_rdpsr(void) -{ - do_rdpsr(); -} - -void OPPROTO op_wrpsr(void) -{ - do_wrpsr(); - FORCE_RET(); -} - -void OPPROTO op_wrwim(void) -{ -#if NWINDOWS == 32 - env->wim = T0; -#else - env->wim = T0 & ((1 << NWINDOWS) - 1); -#endif -} - -void OPPROTO op_rett(void) -{ - helper_rett(); - FORCE_RET(); -} - -/* XXX: use another pointer for %iN registers to avoid slow wrapping - handling ? */ -void OPPROTO op_save(void) -{ - uint32_t cwp; - cwp = (env->cwp - 1) & (NWINDOWS - 1); - if (env->wim & (1 << cwp)) { - raise_exception(TT_WIN_OVF); - } - set_cwp(cwp); - FORCE_RET(); -} - -void OPPROTO op_restore(void) -{ - uint32_t cwp; - cwp = (env->cwp + 1) & (NWINDOWS - 1); - if (env->wim & (1 << cwp)) { - raise_exception(TT_WIN_UNF); - } - set_cwp(cwp); - FORCE_RET(); -} -#else -void OPPROTO op_rdccr(void) -{ - T0 = GET_CCR(env); -} - -void OPPROTO op_wrccr(void) -{ - PUT_CCR(env, T0); -} - -void OPPROTO op_rdtick(void) -{ - T0 = do_tick_get_count(env->tick); -} - -void OPPROTO op_wrtick(void) -{ - do_tick_set_count(env->tick, T0); -} - -void OPPROTO op_wrtick_cmpr(void) -{ - do_tick_set_limit(env->tick, T0); -} - -void OPPROTO op_rdstick(void) -{ - T0 = do_tick_get_count(env->stick); -} - -void OPPROTO op_wrstick(void) -{ - do_tick_set_count(env->stick, T0); - do_tick_set_count(env->hstick, T0); -} - -void OPPROTO op_wrstick_cmpr(void) -{ - do_tick_set_limit(env->stick, T0); -} - -void OPPROTO op_wrhstick_cmpr(void) -{ - do_tick_set_limit(env->hstick, T0); -} - -void OPPROTO op_rdtpc(void) -{ - T0 = env->tpc[env->tl]; -} - -void OPPROTO op_wrtpc(void) -{ - env->tpc[env->tl] = T0; -} - -void OPPROTO op_rdtnpc(void) -{ - T0 = env->tnpc[env->tl]; -} - -void OPPROTO op_wrtnpc(void) -{ - env->tnpc[env->tl] = T0; -} - -void OPPROTO op_rdtstate(void) -{ - T0 = env->tstate[env->tl]; -} - -void OPPROTO op_wrtstate(void) -{ - env->tstate[env->tl] = T0; -} - -void OPPROTO op_rdtt(void) -{ - T0 = env->tt[env->tl]; -} - -void OPPROTO op_wrtt(void) -{ - env->tt[env->tl] = T0; -} - -void OPPROTO op_rdpstate(void) -{ - T0 = env->pstate; -} - -void OPPROTO op_wrpstate(void) -{ - do_wrpstate(); -} - -// CWP handling is reversed in V9, but we still use the V8 register -// order. -void OPPROTO op_rdcwp(void) -{ - T0 = GET_CWP64(env); -} - -void OPPROTO op_wrcwp(void) -{ - PUT_CWP64(env, T0); -} - -/* XXX: use another pointer for %iN registers to avoid slow wrapping - handling ? */ -void OPPROTO op_save(void) -{ - uint32_t cwp; - cwp = (env->cwp - 1) & (NWINDOWS - 1); - if (env->cansave == 0) { - raise_exception(TT_SPILL | (env->otherwin != 0 ? - (TT_WOTHER | ((env->wstate & 0x38) >> 1)): - ((env->wstate & 0x7) << 2))); - } else { - if (env->cleanwin - env->canrestore == 0) { - // XXX Clean windows without trap - raise_exception(TT_CLRWIN); - } else { - env->cansave--; - env->canrestore++; - set_cwp(cwp); - } - } - FORCE_RET(); -} - -void OPPROTO op_restore(void) -{ - uint32_t cwp; - cwp = (env->cwp + 1) & (NWINDOWS - 1); - if (env->canrestore == 0) { - raise_exception(TT_FILL | (env->otherwin != 0 ? - (TT_WOTHER | ((env->wstate & 0x38) >> 1)): - ((env->wstate & 0x7) << 2))); - } else { - env->cansave++; - env->canrestore--; - set_cwp(cwp); - } - FORCE_RET(); -} -#endif - -void OPPROTO op_exception(void) -{ - env->exception_index = PARAM1; - cpu_loop_exit(); - FORCE_RET(); -} - -void OPPROTO op_trap_T0(void) -{ - env->exception_index = TT_TRAP + (T0 & 0x7f); - cpu_loop_exit(); - FORCE_RET(); -} - -void OPPROTO op_trapcc_T0(void) -{ - if (T2) { - env->exception_index = TT_TRAP + (T0 & 0x7f); - cpu_loop_exit(); - } - FORCE_RET(); -} - -void OPPROTO op_fpexception_im(void) -{ - env->exception_index = TT_FP_EXCP; - env->fsr &= ~FSR_FTT_MASK; - env->fsr |= PARAM1; - cpu_loop_exit(); - FORCE_RET(); -} - -void OPPROTO op_debug(void) -{ - helper_debug(); -} - -void OPPROTO op_exit_tb(void) -{ - EXIT_TB(); -} - -void OPPROTO op_eval_ba(void) -{ - T2 = 1; -} - -void OPPROTO op_eval_be(void) -{ - T2 = FLAG_SET(PSR_ZERO); -} - -void OPPROTO op_eval_ble(void) -{ - target_ulong Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF); - - T2 = Z | (N ^ V); -} - -void OPPROTO op_eval_bl(void) -{ - target_ulong N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF); - - T2 = N ^ V; -} - -void OPPROTO op_eval_bleu(void) -{ - target_ulong Z = FLAG_SET(PSR_ZERO), C = FLAG_SET(PSR_CARRY); - - T2 = C | Z; -} - -void OPPROTO op_eval_bcs(void) -{ - T2 = FLAG_SET(PSR_CARRY); -} - -void OPPROTO op_eval_bvs(void) -{ - T2 = FLAG_SET(PSR_OVF); -} - -void OPPROTO op_eval_bn(void) -{ - T2 = 0; -} - -void OPPROTO op_eval_bneg(void) -{ - T2 = FLAG_SET(PSR_NEG); -} - -void OPPROTO op_eval_bne(void) -{ - T2 = !FLAG_SET(PSR_ZERO); -} - -void OPPROTO op_eval_bg(void) -{ - target_ulong Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF); - - T2 = !(Z | (N ^ V)); -} - -void OPPROTO op_eval_bge(void) -{ - target_ulong N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF); - - T2 = !(N ^ V); -} - -void OPPROTO op_eval_bgu(void) -{ - target_ulong Z = FLAG_SET(PSR_ZERO), C = FLAG_SET(PSR_CARRY); - - T2 = !(C | Z); -} - -void OPPROTO op_eval_bcc(void) -{ - T2 = !FLAG_SET(PSR_CARRY); -} - -void OPPROTO op_eval_bpos(void) -{ - T2 = !FLAG_SET(PSR_NEG); -} - -void OPPROTO op_eval_bvc(void) -{ - T2 = !FLAG_SET(PSR_OVF); -} - -#ifdef TARGET_SPARC64 -void OPPROTO op_eval_xbe(void) -{ - T2 = XFLAG_SET(PSR_ZERO); -} - -void OPPROTO op_eval_xble(void) -{ - target_ulong Z = XFLAG_SET(PSR_ZERO), N = XFLAG_SET(PSR_NEG), V = XFLAG_SET(PSR_OVF); - - T2 = Z | (N ^ V); -} - -void OPPROTO op_eval_xbl(void) -{ - target_ulong N = XFLAG_SET(PSR_NEG), V = XFLAG_SET(PSR_OVF); - - T2 = N ^ V; -} - -void OPPROTO op_eval_xbleu(void) -{ - target_ulong Z = XFLAG_SET(PSR_ZERO), C = XFLAG_SET(PSR_CARRY); - - T2 = C | Z; -} - -void OPPROTO op_eval_xbcs(void) -{ - T2 = XFLAG_SET(PSR_CARRY); -} - -void OPPROTO op_eval_xbvs(void) -{ - T2 = XFLAG_SET(PSR_OVF); -} - -void OPPROTO op_eval_xbneg(void) -{ - T2 = XFLAG_SET(PSR_NEG); -} - -void OPPROTO op_eval_xbne(void) -{ - T2 = !XFLAG_SET(PSR_ZERO); -} - -void OPPROTO op_eval_xbg(void) -{ - target_ulong Z = XFLAG_SET(PSR_ZERO), N = XFLAG_SET(PSR_NEG), V = XFLAG_SET(PSR_OVF); - - T2 = !(Z | (N ^ V)); -} - -void OPPROTO op_eval_xbge(void) -{ - target_ulong N = XFLAG_SET(PSR_NEG), V = XFLAG_SET(PSR_OVF); - - T2 = !(N ^ V); -} - -void OPPROTO op_eval_xbgu(void) -{ - target_ulong Z = XFLAG_SET(PSR_ZERO), C = XFLAG_SET(PSR_CARRY); - - T2 = !(C | Z); -} - -void OPPROTO op_eval_xbcc(void) -{ - T2 = !XFLAG_SET(PSR_CARRY); -} - -void OPPROTO op_eval_xbpos(void) -{ - T2 = !XFLAG_SET(PSR_NEG); -} - -void OPPROTO op_eval_xbvc(void) -{ - T2 = !XFLAG_SET(PSR_OVF); -} -#endif - -#define FCC -#define FFLAG_SET(x) (env->fsr & x? 1: 0) -#include "fbranch_template.h" - -#ifdef TARGET_SPARC64 -#define FCC _fcc1 -#define FFLAG_SET(x) ((env->fsr & ((uint64_t)x >> 32))? 1: 0) -#include "fbranch_template.h" -#define FCC _fcc2 -#define FFLAG_SET(x) ((env->fsr & ((uint64_t)x >> 34))? 1: 0) -#include "fbranch_template.h" -#define FCC _fcc3 -#define FFLAG_SET(x) ((env->fsr & ((uint64_t)x >> 36))? 1: 0) -#include "fbranch_template.h" -#endif - -#ifdef TARGET_SPARC64 -void OPPROTO op_eval_brz(void) -{ - T2 = (T0 == 0); -} - -void OPPROTO op_eval_brnz(void) -{ - T2 = (T0 != 0); -} - -void OPPROTO op_eval_brlz(void) -{ - T2 = ((int64_t)T0 < 0); -} - -void OPPROTO op_eval_brlez(void) -{ - T2 = ((int64_t)T0 <= 0); -} - -void OPPROTO op_eval_brgz(void) -{ - T2 = ((int64_t)T0 > 0); -} - -void OPPROTO op_eval_brgez(void) -{ - T2 = ((int64_t)T0 >= 0); -} - -void OPPROTO op_jmp_im64(void) -{ - env->pc = PARAMQ1; -} - -void OPPROTO op_movq_npc_im64(void) -{ - env->npc = PARAMQ1; -} -#endif - -void OPPROTO op_jmp_im(void) -{ - env->pc = (uint32_t)PARAM1; -} - -void OPPROTO op_movl_npc_im(void) -{ - env->npc = (uint32_t)PARAM1; -} - -void OPPROTO op_movl_npc_T0(void) -{ - env->npc = T0; -} - -void OPPROTO op_mov_pc_npc(void) -{ - env->pc = env->npc; -} - -void OPPROTO op_next_insn(void) -{ - env->pc = env->npc; - env->npc = env->npc + 4; -} - -void OPPROTO op_goto_tb0(void) -{ - GOTO_TB(op_goto_tb0, PARAM1, 0); -} - -void OPPROTO op_goto_tb1(void) -{ - GOTO_TB(op_goto_tb1, PARAM1, 1); -} - -void OPPROTO op_jmp_label(void) -{ - GOTO_LABEL_PARAM(1); -} - -void OPPROTO op_jnz_T2_label(void) -{ - if (T2) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO op_jz_T2_label(void) -{ - if (!T2) - GOTO_LABEL_PARAM(1); - FORCE_RET(); -} - -void OPPROTO op_flush_T0(void) -{ - helper_flush(T0); -} - -void OPPROTO op_clear_ieee_excp_and_FTT(void) -{ - env->fsr &= ~(FSR_FTT_MASK | FSR_CEXC_MASK);; -} - -#define F_OP(name, p) void OPPROTO op_f##name##p(void) - -#if defined(CONFIG_USER_ONLY) -#define F_BINOP(name) \ - F_OP(name, s) \ - { \ - set_float_exception_flags(0, &env->fp_status); \ - FT0 = float32_ ## name (FT0, FT1, &env->fp_status); \ - check_ieee_exceptions(); \ - } \ - F_OP(name, d) \ - { \ - set_float_exception_flags(0, &env->fp_status); \ - DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \ - check_ieee_exceptions(); \ - } \ - F_OP(name, q) \ - { \ - set_float_exception_flags(0, &env->fp_status); \ - QT0 = float128_ ## name (QT0, QT1, &env->fp_status); \ - check_ieee_exceptions(); \ - } -#else -#define F_BINOP(name) \ - F_OP(name, s) \ - { \ - set_float_exception_flags(0, &env->fp_status); \ - FT0 = float32_ ## name (FT0, FT1, &env->fp_status); \ - check_ieee_exceptions(); \ - } \ - F_OP(name, d) \ - { \ - set_float_exception_flags(0, &env->fp_status); \ - DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \ - check_ieee_exceptions(); \ - } -#endif - -F_BINOP(add); -F_BINOP(sub); -F_BINOP(mul); -F_BINOP(div); -#undef F_BINOP - -void OPPROTO op_fsmuld(void) -{ - set_float_exception_flags(0, &env->fp_status); - DT0 = float64_mul(float32_to_float64(FT0, &env->fp_status), - float32_to_float64(FT1, &env->fp_status), - &env->fp_status); - check_ieee_exceptions(); -} - -#if defined(CONFIG_USER_ONLY) -void OPPROTO op_fdmulq(void) -{ - set_float_exception_flags(0, &env->fp_status); - QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status), - float64_to_float128(DT1, &env->fp_status), - &env->fp_status); - check_ieee_exceptions(); -} -#endif - -#if defined(CONFIG_USER_ONLY) -#define F_HELPER(name) \ - F_OP(name, s) \ - { \ - do_f##name##s(); \ - } \ - F_OP(name, d) \ - { \ - do_f##name##d(); \ - } \ - F_OP(name, q) \ - { \ - do_f##name##q(); \ - } -#else -#define F_HELPER(name) \ - F_OP(name, s) \ - { \ - do_f##name##s(); \ - } \ - F_OP(name, d) \ - { \ - do_f##name##d(); \ - } -#endif - -F_HELPER(sqrt); - -F_OP(neg, s) -{ - FT0 = float32_chs(FT1); -} - -F_OP(abs, s) -{ - do_fabss(); -} - -F_HELPER(cmp); -F_HELPER(cmpe); - -#ifdef TARGET_SPARC64 -F_OP(neg, d) -{ - DT0 = float64_chs(DT1); -} - -F_OP(abs, d) -{ - do_fabsd(); -} - -#if defined(CONFIG_USER_ONLY) -F_OP(neg, q) -{ - QT0 = float128_chs(QT1); -} - -F_OP(abs, q) -{ - do_fabsd(); -} -#endif - -void OPPROTO op_fcmps_fcc1(void) -{ - do_fcmps_fcc1(); -} - -void OPPROTO op_fcmpd_fcc1(void) -{ - do_fcmpd_fcc1(); -} - -void OPPROTO op_fcmps_fcc2(void) -{ - do_fcmps_fcc2(); -} - -void OPPROTO op_fcmpd_fcc2(void) -{ - do_fcmpd_fcc2(); -} - -void OPPROTO op_fcmps_fcc3(void) -{ - do_fcmps_fcc3(); -} - -void OPPROTO op_fcmpd_fcc3(void) -{ - do_fcmpd_fcc3(); -} - -void OPPROTO op_fcmpes_fcc1(void) -{ - do_fcmpes_fcc1(); -} - -void OPPROTO op_fcmped_fcc1(void) -{ - do_fcmped_fcc1(); -} - -void OPPROTO op_fcmpes_fcc2(void) -{ - do_fcmpes_fcc2(); -} - -void OPPROTO op_fcmped_fcc2(void) -{ - do_fcmped_fcc2(); -} - -void OPPROTO op_fcmpes_fcc3(void) -{ - do_fcmpes_fcc3(); -} - -void OPPROTO op_fcmped_fcc3(void) -{ - do_fcmped_fcc3(); -} - -#if defined(CONFIG_USER_ONLY) -void OPPROTO op_fcmpq_fcc1(void) -{ - do_fcmpq_fcc1(); -} - -void OPPROTO op_fcmpq_fcc2(void) -{ - do_fcmpq_fcc2(); -} - -void OPPROTO op_fcmpq_fcc3(void) -{ - do_fcmpq_fcc3(); -} - -void OPPROTO op_fcmpeq_fcc1(void) -{ - do_fcmpeq_fcc1(); -} - -void OPPROTO op_fcmpeq_fcc2(void) -{ - do_fcmpeq_fcc2(); -} - -void OPPROTO op_fcmpeq_fcc3(void) -{ - do_fcmpeq_fcc3(); -} -#endif - -#endif - -/* Integer to float conversion. */ -#ifdef USE_INT_TO_FLOAT_HELPERS -F_HELPER(ito); -#ifdef TARGET_SPARC64 -F_HELPER(xto); -#endif -#else -F_OP(ito, s) -{ - set_float_exception_flags(0, &env->fp_status); - FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status); - check_ieee_exceptions(); -} - -F_OP(ito, d) -{ - set_float_exception_flags(0, &env->fp_status); - DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status); - check_ieee_exceptions(); -} - -#if defined(CONFIG_USER_ONLY) -F_OP(ito, q) -{ - set_float_exception_flags(0, &env->fp_status); - QT0 = int32_to_float128(*((int32_t *)&FT1), &env->fp_status); - check_ieee_exceptions(); -} -#endif - -#ifdef TARGET_SPARC64 -F_OP(xto, s) -{ - set_float_exception_flags(0, &env->fp_status); - FT0 = int64_to_float32(*((int64_t *)&DT1), &env->fp_status); - check_ieee_exceptions(); -} - -F_OP(xto, d) -{ - set_float_exception_flags(0, &env->fp_status); - DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status); - check_ieee_exceptions(); -} -#if defined(CONFIG_USER_ONLY) -F_OP(xto, q) -{ - set_float_exception_flags(0, &env->fp_status); - QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status); - check_ieee_exceptions(); -} -#endif -#endif -#endif -#undef F_HELPER - -/* floating point conversion */ -void OPPROTO op_fdtos(void) -{ - set_float_exception_flags(0, &env->fp_status); - FT0 = float64_to_float32(DT1, &env->fp_status); - check_ieee_exceptions(); -} - -void OPPROTO op_fstod(void) -{ - set_float_exception_flags(0, &env->fp_status); - DT0 = float32_to_float64(FT1, &env->fp_status); - check_ieee_exceptions(); -} - -#if defined(CONFIG_USER_ONLY) -void OPPROTO op_fqtos(void) -{ - set_float_exception_flags(0, &env->fp_status); - FT0 = float128_to_float32(QT1, &env->fp_status); - check_ieee_exceptions(); -} - -void OPPROTO op_fstoq(void) -{ - set_float_exception_flags(0, &env->fp_status); - QT0 = float32_to_float128(FT1, &env->fp_status); - check_ieee_exceptions(); -} - -void OPPROTO op_fqtod(void) -{ - set_float_exception_flags(0, &env->fp_status); - DT0 = float128_to_float64(QT1, &env->fp_status); - check_ieee_exceptions(); -} - -void OPPROTO op_fdtoq(void) -{ - set_float_exception_flags(0, &env->fp_status); - QT0 = float64_to_float128(DT1, &env->fp_status); - check_ieee_exceptions(); -} -#endif - -/* Float to integer conversion. */ -void OPPROTO op_fstoi(void) -{ - set_float_exception_flags(0, &env->fp_status); - *((int32_t *)&FT0) = float32_to_int32_round_to_zero(FT1, &env->fp_status); - check_ieee_exceptions(); -} - -void OPPROTO op_fdtoi(void) -{ - set_float_exception_flags(0, &env->fp_status); - *((int32_t *)&FT0) = float64_to_int32_round_to_zero(DT1, &env->fp_status); - check_ieee_exceptions(); -} - -#if defined(CONFIG_USER_ONLY) -void OPPROTO op_fqtoi(void) -{ - set_float_exception_flags(0, &env->fp_status); - *((int32_t *)&FT0) = float128_to_int32_round_to_zero(QT1, &env->fp_status); - check_ieee_exceptions(); -} -#endif - -#ifdef TARGET_SPARC64 -void OPPROTO op_fstox(void) -{ - set_float_exception_flags(0, &env->fp_status); - *((int64_t *)&DT0) = float32_to_int64_round_to_zero(FT1, &env->fp_status); - check_ieee_exceptions(); -} - -void OPPROTO op_fdtox(void) -{ - set_float_exception_flags(0, &env->fp_status); - *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status); - check_ieee_exceptions(); -} - -#if defined(CONFIG_USER_ONLY) -void OPPROTO op_fqtox(void) -{ - set_float_exception_flags(0, &env->fp_status); - *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status); - check_ieee_exceptions(); -} -#endif - -void OPPROTO op_fmovs_cc(void) -{ - if (T2) - FT0 = FT1; -} - -void OPPROTO op_fmovd_cc(void) -{ - if (T2) - DT0 = DT1; -} - -#if defined(CONFIG_USER_ONLY) -void OPPROTO op_fmovq_cc(void) -{ - if (T2) - QT0 = QT1; -} -#endif - -void OPPROTO op_mov_cc(void) -{ - if (T2) - T0 = T1; -} - -void OPPROTO op_flushw(void) -{ - if (env->cansave != NWINDOWS - 2) { - raise_exception(TT_SPILL | (env->otherwin != 0 ? - (TT_WOTHER | ((env->wstate & 0x38) >> 1)): - ((env->wstate & 0x7) << 2))); - } -} - -void OPPROTO op_saved(void) -{ - env->cansave++; - if (env->otherwin == 0) - env->canrestore--; - else - env->otherwin--; - FORCE_RET(); -} - -void OPPROTO op_restored(void) -{ - env->canrestore++; - if (env->cleanwin < NWINDOWS - 1) - env->cleanwin++; - if (env->otherwin == 0) - env->cansave--; - else - env->otherwin--; - FORCE_RET(); -} - -void OPPROTO op_popc(void) -{ - do_popc(); -} - -void OPPROTO op_done(void) -{ - do_done(); -} - -void OPPROTO op_retry(void) -{ - do_retry(); -} - -void OPPROTO op_sir(void) -{ - T0 = 0; // XXX -} - -void OPPROTO op_ld_asi_reg() -{ - T0 += PARAM1; - helper_ld_asi(env->asi, PARAM2, PARAM3); -} - -void OPPROTO op_st_asi_reg() -{ - T0 += PARAM1; - helper_st_asi(env->asi, PARAM2); -} - -void OPPROTO op_ldf_asi_reg() -{ - T0 += PARAM1; - helper_ldf_asi(env->asi, PARAM2, PARAM3); -} - -void OPPROTO op_stf_asi_reg() -{ - T0 += PARAM1; - helper_stf_asi(env->asi, PARAM2, PARAM3); -} - -void OPPROTO op_ldf_asi() -{ - helper_ldf_asi(PARAM1, PARAM2, PARAM3); -} - -void OPPROTO op_stf_asi() -{ - helper_stf_asi(PARAM1, PARAM2, PARAM3); -} - -void OPPROTO op_ldstub_asi_reg() /* XXX: should be atomically */ -{ - target_ulong tmp; - - T0 += PARAM1; - helper_ld_asi(env->asi, 1, 0); - tmp = T1; - T1 = 0xff; - helper_st_asi(env->asi, 1); - T1 = tmp; -} - -void OPPROTO op_swap_asi_reg() /* XXX: should be atomically */ -{ - target_ulong tmp1, tmp2; - - T0 += PARAM1; - tmp1 = T1; - helper_ld_asi(env->asi, 4, 0); - tmp2 = T1; - T1 = tmp1; - helper_st_asi(env->asi, 4); - T1 = tmp2; -} - -void OPPROTO op_ldda_asi() -{ - helper_ld_asi(PARAM1, 8, 0); - T0 = T1 & 0xffffffffUL; - T1 >>= 32; -} - -void OPPROTO op_ldda_asi_reg() -{ - T0 += PARAM1; - helper_ld_asi(env->asi, 8, 0); - T0 = T1 & 0xffffffffUL; - T1 >>= 32; -} - -void OPPROTO op_stda_asi() -{ - T1 <<= 32; - T1 += T2 & 0xffffffffUL; - helper_st_asi(PARAM1, 8); -} - -void OPPROTO op_stda_asi_reg() -{ - T0 += PARAM1; - T1 <<= 32; - T1 += T2 & 0xffffffffUL; - helper_st_asi(env->asi, 8); -} - -void OPPROTO op_cas_asi() /* XXX: should be atomically */ -{ - target_ulong tmp; - - tmp = T1 & 0xffffffffUL; - helper_ld_asi(PARAM1, 4, 0); - if (tmp == T1) { - tmp = T1; - T1 = T2 & 0xffffffffUL; - helper_st_asi(PARAM1, 4); - T1 = tmp; - } - T1 &= 0xffffffffUL; -} - -void OPPROTO op_cas_asi_reg() /* XXX: should be atomically */ -{ - target_ulong tmp; - - T0 += PARAM1; - tmp = T1 & 0xffffffffUL; - helper_ld_asi(env->asi, 4, 0); - if (tmp == T1) { - tmp = T1; - T1 = T2 & 0xffffffffUL; - helper_st_asi(env->asi, 4); - T1 = tmp; - } - T1 &= 0xffffffffUL; -} - -void OPPROTO op_casx_asi() /* XXX: should be atomically */ -{ - target_ulong tmp; - - tmp = T1; - helper_ld_asi(PARAM1, 8, 0); - if (tmp == T1) { - tmp = T1; - T1 = T2; - helper_st_asi(PARAM1, 8); - T1 = tmp; - } -} - -void OPPROTO op_casx_asi_reg() /* XXX: should be atomically */ -{ - target_ulong tmp; - - T0 += PARAM1; - tmp = T1; - helper_ld_asi(env->asi, 8, 0); - if (tmp == T1) { - tmp = T1; - T1 = T2; - helper_st_asi(env->asi, 8); - T1 = tmp; - } -} -#endif - -#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) -void OPPROTO op_ld_asi() -{ - helper_ld_asi(PARAM1, PARAM2, PARAM3); -} - -void OPPROTO op_st_asi() -{ - helper_st_asi(PARAM1, PARAM2); -} - -void OPPROTO op_ldstub_asi() /* XXX: should be atomically */ -{ - target_ulong tmp; - - helper_ld_asi(PARAM1, 1, 0); - tmp = T1; - T1 = 0xff; - helper_st_asi(PARAM1, 1); - T1 = tmp; -} - -void OPPROTO op_swap_asi() /* XXX: should be atomically */ -{ - target_ulong tmp1, tmp2; - - tmp1 = T1; - helper_ld_asi(PARAM1, 4, 0); - tmp2 = T1; - T1 = tmp1; - helper_st_asi(PARAM1, 4); - T1 = tmp2; -} -#endif - -#ifdef TARGET_SPARC64 -// This function uses non-native bit order -#define GET_FIELD(X, FROM, TO) \ - ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1)) - -// This function uses the order in the manuals, i.e. bit 0 is 2^0 -#define GET_FIELD_SP(X, FROM, TO) \ - GET_FIELD(X, 63 - (TO), 63 - (FROM)) - -void OPPROTO op_array8() -{ - T0 = (GET_FIELD_SP(T0, 60, 63) << (17 + 2 * T1)) | - (GET_FIELD_SP(T0, 39, 39 + T1 - 1) << (17 + T1)) | - (GET_FIELD_SP(T0, 17 + T1 - 1, 17) << 17) | - (GET_FIELD_SP(T0, 56, 59) << 13) | (GET_FIELD_SP(T0, 35, 38) << 9) | - (GET_FIELD_SP(T0, 13, 16) << 5) | (((T0 >> 55) & 1) << 4) | - (GET_FIELD_SP(T0, 33, 34) << 2) | GET_FIELD_SP(T0, 11, 12); -} - -void OPPROTO op_array16() -{ - T0 = ((GET_FIELD_SP(T0, 60, 63) << (17 + 2 * T1)) | - (GET_FIELD_SP(T0, 39, 39 + T1 - 1) << (17 + T1)) | - (GET_FIELD_SP(T0, 17 + T1 - 1, 17) << 17) | - (GET_FIELD_SP(T0, 56, 59) << 13) | (GET_FIELD_SP(T0, 35, 38) << 9) | - (GET_FIELD_SP(T0, 13, 16) << 5) | (((T0 >> 55) & 1) << 4) | - (GET_FIELD_SP(T0, 33, 34) << 2) | GET_FIELD_SP(T0, 11, 12)) << 1; -} - -void OPPROTO op_array32() -{ - T0 = ((GET_FIELD_SP(T0, 60, 63) << (17 + 2 * T1)) | - (GET_FIELD_SP(T0, 39, 39 + T1 - 1) << (17 + T1)) | - (GET_FIELD_SP(T0, 17 + T1 - 1, 17) << 17) | - (GET_FIELD_SP(T0, 56, 59) << 13) | (GET_FIELD_SP(T0, 35, 38) << 9) | - (GET_FIELD_SP(T0, 13, 16) << 5) | (((T0 >> 55) & 1) << 4) | - (GET_FIELD_SP(T0, 33, 34) << 2) | GET_FIELD_SP(T0, 11, 12)) << 2; -} - -void OPPROTO op_alignaddr() -{ - uint64_t tmp; - - tmp = T0 + T1; - env->gsr &= ~7ULL; - env->gsr |= tmp & 7ULL; - T0 = tmp & ~7ULL; -} - -void OPPROTO op_faligndata() -{ - uint64_t tmp; - - tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8); - tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8); - *((uint64_t *)&DT0) = tmp; -} - -void OPPROTO op_movl_FT0_0(void) -{ - *((uint32_t *)&FT0) = 0; -} - -void OPPROTO op_movl_DT0_0(void) -{ - *((uint64_t *)&DT0) = 0; -} - -void OPPROTO op_movl_FT0_1(void) -{ - *((uint32_t *)&FT0) = 0xffffffff; -} - -void OPPROTO op_movl_DT0_1(void) -{ - *((uint64_t *)&DT0) = 0xffffffffffffffffULL; -} - -void OPPROTO op_fnot(void) -{ - *(uint64_t *)&DT0 = ~*(uint64_t *)&DT1; -} - -void OPPROTO op_fnots(void) -{ - *(uint32_t *)&FT0 = ~*(uint32_t *)&FT1; -} - -void OPPROTO op_fnor(void) -{ - *(uint64_t *)&DT0 = ~(*(uint64_t *)&DT0 | *(uint64_t *)&DT1); -} - -void OPPROTO op_fnors(void) -{ - *(uint32_t *)&FT0 = ~(*(uint32_t *)&FT0 | *(uint32_t *)&FT1); -} - -void OPPROTO op_for(void) -{ - *(uint64_t *)&DT0 |= *(uint64_t *)&DT1; -} - -void OPPROTO op_fors(void) -{ - *(uint32_t *)&FT0 |= *(uint32_t *)&FT1; -} - -void OPPROTO op_fxor(void) -{ - *(uint64_t *)&DT0 ^= *(uint64_t *)&DT1; -} - -void OPPROTO op_fxors(void) -{ - *(uint32_t *)&FT0 ^= *(uint32_t *)&FT1; -} - -void OPPROTO op_fand(void) -{ - *(uint64_t *)&DT0 &= *(uint64_t *)&DT1; -} - -void OPPROTO op_fands(void) -{ - *(uint32_t *)&FT0 &= *(uint32_t *)&FT1; -} - -void OPPROTO op_fornot(void) -{ - *(uint64_t *)&DT0 = *(uint64_t *)&DT0 | ~*(uint64_t *)&DT1; -} - -void OPPROTO op_fornots(void) -{ - *(uint32_t *)&FT0 = *(uint32_t *)&FT0 | ~*(uint32_t *)&FT1; -} - -void OPPROTO op_fandnot(void) -{ - *(uint64_t *)&DT0 = *(uint64_t *)&DT0 & ~*(uint64_t *)&DT1; -} - -void OPPROTO op_fandnots(void) -{ - *(uint32_t *)&FT0 = *(uint32_t *)&FT0 & ~*(uint32_t *)&FT1; -} - -void OPPROTO op_fnand(void) -{ - *(uint64_t *)&DT0 = ~(*(uint64_t *)&DT0 & *(uint64_t *)&DT1); -} - -void OPPROTO op_fnands(void) -{ - *(uint32_t *)&FT0 = ~(*(uint32_t *)&FT0 & *(uint32_t *)&FT1); -} - -void OPPROTO op_fxnor(void) -{ - *(uint64_t *)&DT0 ^= ~*(uint64_t *)&DT1; -} - -void OPPROTO op_fxnors(void) -{ - *(uint32_t *)&FT0 ^= ~*(uint32_t *)&FT1; -} - -#ifdef WORDS_BIGENDIAN -#define VIS_B64(n) b[7 - (n)] -#define VIS_W64(n) w[3 - (n)] -#define VIS_SW64(n) sw[3 - (n)] -#define VIS_L64(n) l[1 - (n)] -#define VIS_B32(n) b[3 - (n)] -#define VIS_W32(n) w[1 - (n)] -#else -#define VIS_B64(n) b[n] -#define VIS_W64(n) w[n] -#define VIS_SW64(n) sw[n] -#define VIS_L64(n) l[n] -#define VIS_B32(n) b[n] -#define VIS_W32(n) w[n] -#endif - -typedef union { - uint8_t b[8]; - uint16_t w[4]; - int16_t sw[4]; - uint32_t l[2]; - float64 d; -} vis64; - -typedef union { - uint8_t b[4]; - uint16_t w[2]; - uint32_t l; - float32 f; -} vis32; - -void OPPROTO op_fpmerge(void) -{ - vis64 s, d; - - s.d = DT0; - d.d = DT1; - - // Reverse calculation order to handle overlap - d.VIS_B64(7) = s.VIS_B64(3); - d.VIS_B64(6) = d.VIS_B64(3); - d.VIS_B64(5) = s.VIS_B64(2); - d.VIS_B64(4) = d.VIS_B64(2); - d.VIS_B64(3) = s.VIS_B64(1); - d.VIS_B64(2) = d.VIS_B64(1); - d.VIS_B64(1) = s.VIS_B64(0); - //d.VIS_B64(0) = d.VIS_B64(0); - - DT0 = d.d; -} - -void OPPROTO op_fmul8x16(void) -{ - vis64 s, d; - uint32_t tmp; - - s.d = DT0; - d.d = DT1; - -#define PMUL(r) \ - tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r); \ - if ((tmp & 0xff) > 0x7f) \ - tmp += 0x100; \ - d.VIS_W64(r) = tmp >> 8; - - PMUL(0); - PMUL(1); - PMUL(2); - PMUL(3); -#undef PMUL - - DT0 = d.d; -} - -void OPPROTO op_fmul8x16al(void) -{ - vis64 s, d; - uint32_t tmp; - - s.d = DT0; - d.d = DT1; - -#define PMUL(r) \ - tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r); \ - if ((tmp & 0xff) > 0x7f) \ - tmp += 0x100; \ - d.VIS_W64(r) = tmp >> 8; - - PMUL(0); - PMUL(1); - PMUL(2); - PMUL(3); -#undef PMUL - - DT0 = d.d; -} - -void OPPROTO op_fmul8x16au(void) -{ - vis64 s, d; - uint32_t tmp; - - s.d = DT0; - d.d = DT1; - -#define PMUL(r) \ - tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r); \ - if ((tmp & 0xff) > 0x7f) \ - tmp += 0x100; \ - d.VIS_W64(r) = tmp >> 8; - - PMUL(0); - PMUL(1); - PMUL(2); - PMUL(3); -#undef PMUL - - DT0 = d.d; -} - -void OPPROTO op_fmul8sux16(void) -{ - vis64 s, d; - uint32_t tmp; - - s.d = DT0; - d.d = DT1; - -#define PMUL(r) \ - tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \ - if ((tmp & 0xff) > 0x7f) \ - tmp += 0x100; \ - d.VIS_W64(r) = tmp >> 8; - - PMUL(0); - PMUL(1); - PMUL(2); - PMUL(3); -#undef PMUL - - DT0 = d.d; -} - -void OPPROTO op_fmul8ulx16(void) -{ - vis64 s, d; - uint32_t tmp; - - s.d = DT0; - d.d = DT1; - -#define PMUL(r) \ - tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \ - if ((tmp & 0xff) > 0x7f) \ - tmp += 0x100; \ - d.VIS_W64(r) = tmp >> 8; - - PMUL(0); - PMUL(1); - PMUL(2); - PMUL(3); -#undef PMUL - - DT0 = d.d; -} - -void OPPROTO op_fmuld8sux16(void) -{ - vis64 s, d; - uint32_t tmp; - - s.d = DT0; - d.d = DT1; - -#define PMUL(r) \ - tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \ - if ((tmp & 0xff) > 0x7f) \ - tmp += 0x100; \ - d.VIS_L64(r) = tmp; - - // Reverse calculation order to handle overlap - PMUL(1); - PMUL(0); -#undef PMUL - - DT0 = d.d; -} - -void OPPROTO op_fmuld8ulx16(void) -{ - vis64 s, d; - uint32_t tmp; - - s.d = DT0; - d.d = DT1; - -#define PMUL(r) \ - tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \ - if ((tmp & 0xff) > 0x7f) \ - tmp += 0x100; \ - d.VIS_L64(r) = tmp; - - // Reverse calculation order to handle overlap - PMUL(1); - PMUL(0); -#undef PMUL - - DT0 = d.d; -} - -void OPPROTO op_fexpand(void) -{ - vis32 s; - vis64 d; - - s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff); - d.d = DT1; - d.VIS_L64(0) = s.VIS_W32(0) << 4; - d.VIS_L64(1) = s.VIS_W32(1) << 4; - d.VIS_L64(2) = s.VIS_W32(2) << 4; - d.VIS_L64(3) = s.VIS_W32(3) << 4; - - DT0 = d.d; -} - -#define VIS_OP(name, F) \ - void OPPROTO name##16(void) \ - { \ - vis64 s, d; \ - \ - s.d = DT0; \ - d.d = DT1; \ - \ - d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0)); \ - d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1)); \ - d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2)); \ - d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3)); \ - \ - DT0 = d.d; \ - } \ - \ - void OPPROTO name##16s(void) \ - { \ - vis32 s, d; \ - \ - s.f = FT0; \ - d.f = FT1; \ - \ - d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0)); \ - d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1)); \ - \ - FT0 = d.f; \ - } \ - \ - void OPPROTO name##32(void) \ - { \ - vis64 s, d; \ - \ - s.d = DT0; \ - d.d = DT1; \ - \ - d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0)); \ - d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1)); \ - \ - DT0 = d.d; \ - } \ - \ - void OPPROTO name##32s(void) \ - { \ - vis32 s, d; \ - \ - s.f = FT0; \ - d.f = FT1; \ - \ - d.l = F(d.l, s.l); \ - \ - FT0 = d.f; \ - } - -#define FADD(a, b) ((a) + (b)) -#define FSUB(a, b) ((a) - (b)) -VIS_OP(op_fpadd, FADD) -VIS_OP(op_fpsub, FSUB) - -#define VIS_CMPOP(name, F) \ - void OPPROTO name##16(void) \ - { \ - vis64 s, d; \ - \ - s.d = DT0; \ - d.d = DT1; \ - \ - d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0))? 1: 0; \ - d.VIS_W64(0) |= F(d.VIS_W64(1), s.VIS_W64(1))? 2: 0; \ - d.VIS_W64(0) |= F(d.VIS_W64(2), s.VIS_W64(2))? 4: 0; \ - d.VIS_W64(0) |= F(d.VIS_W64(3), s.VIS_W64(3))? 8: 0; \ - \ - DT0 = d.d; \ - } \ - \ - void OPPROTO name##32(void) \ - { \ - vis64 s, d; \ - \ - s.d = DT0; \ - d.d = DT1; \ - \ - d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0))? 1: 0; \ - d.VIS_L64(0) |= F(d.VIS_L64(1), s.VIS_L64(1))? 2: 0; \ - \ - DT0 = d.d; \ - } - -#define FCMPGT(a, b) ((a) > (b)) -#define FCMPEQ(a, b) ((a) == (b)) -#define FCMPLE(a, b) ((a) <= (b)) -#define FCMPNE(a, b) ((a) != (b)) - -VIS_CMPOP(op_fcmpgt, FCMPGT) -VIS_CMPOP(op_fcmpeq, FCMPEQ) -VIS_CMPOP(op_fcmple, FCMPLE) -VIS_CMPOP(op_fcmpne, FCMPNE) - -#endif - -#define CHECK_ALIGN_OP(align) \ - void OPPROTO op_check_align_T0_ ## align (void) \ - { \ - if (T0 & align) \ - raise_exception(TT_UNALIGNED); \ - FORCE_RET(); \ - } - -CHECK_ALIGN_OP(1) -CHECK_ALIGN_OP(3) -CHECK_ALIGN_OP(7) diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sparc/op_helper.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sparc/op_helper.c --- qemu-0.9.1/target-sparc/op_helper.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-sparc/op_helper.c 2008-10-07 19:54:35.000000000 +0100 @@ -1,168 +1,669 @@ #include "exec.h" #include "host-utils.h" +#include "helper.h" +#if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" +#endif /* !defined(CONFIG_USER_ONLY) */ -//#define DEBUG_PCALL //#define DEBUG_MMU //#define DEBUG_MXCC //#define DEBUG_UNALIGNED //#define DEBUG_UNASSIGNED //#define DEBUG_ASI +//#define DEBUG_PCALL #ifdef DEBUG_MMU #define DPRINTF_MMU(fmt, args...) \ do { printf("MMU: " fmt , ##args); } while (0) #else -#define DPRINTF_MMU(fmt, args...) +#define DPRINTF_MMU(fmt, args...) do {} while (0) #endif #ifdef DEBUG_MXCC #define DPRINTF_MXCC(fmt, args...) \ do { printf("MXCC: " fmt , ##args); } while (0) #else -#define DPRINTF_MXCC(fmt, args...) +#define DPRINTF_MXCC(fmt, args...) do {} while (0) #endif #ifdef DEBUG_ASI #define DPRINTF_ASI(fmt, args...) \ do { printf("ASI: " fmt , ##args); } while (0) #else -#define DPRINTF_ASI(fmt, args...) +#define DPRINTF_ASI(fmt, args...) do {} while (0) +#endif + +#ifdef TARGET_SPARC64 +#ifndef TARGET_ABI32 +#define AM_CHECK(env1) ((env1)->pstate & PS_AM) +#else +#define AM_CHECK(env1) (1) +#endif #endif +static inline void address_mask(CPUState *env1, target_ulong *addr) +{ +#ifdef TARGET_SPARC64 + if (AM_CHECK(env1)) + *addr &= 0xffffffffULL; +#endif +} + void raise_exception(int tt) { env->exception_index = tt; cpu_loop_exit(); } -void check_ieee_exceptions() +static inline void set_cwp(int new_cwp) { - T0 = get_float_exception_flags(&env->fp_status); - if (T0) - { - /* Copy IEEE 754 flags into FSR */ - if (T0 & float_flag_invalid) - env->fsr |= FSR_NVC; - if (T0 & float_flag_overflow) - env->fsr |= FSR_OFC; - if (T0 & float_flag_underflow) - env->fsr |= FSR_UFC; - if (T0 & float_flag_divbyzero) - env->fsr |= FSR_DZC; - if (T0 & float_flag_inexact) - env->fsr |= FSR_NXC; + cpu_set_cwp(env, new_cwp); +} - if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) - { - /* Unmasked exception, generate a trap */ - env->fsr |= FSR_FTT_IEEE_EXCP; - raise_exception(TT_FP_EXCP); - } - else - { - /* Accumulate exceptions */ - env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5; - } - } +void helper_check_align(target_ulong addr, uint32_t align) +{ + if (addr & align) { +#ifdef DEBUG_UNALIGNED + printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx + "\n", addr, env->pc); +#endif + raise_exception(TT_UNALIGNED); + } } -#ifdef USE_INT_TO_FLOAT_HELPERS -void do_fitos(void) +#define F_HELPER(name, p) void helper_f##name##p(void) + +#define F_BINOP(name) \ + float32 helper_f ## name ## s (float32 src1, float32 src2) \ + { \ + return float32_ ## name (src1, src2, &env->fp_status); \ + } \ + F_HELPER(name, d) \ + { \ + DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \ + } \ + F_HELPER(name, q) \ + { \ + QT0 = float128_ ## name (QT0, QT1, &env->fp_status); \ + } + +F_BINOP(add); +F_BINOP(sub); +F_BINOP(mul); +F_BINOP(div); +#undef F_BINOP + +void helper_fsmuld(float32 src1, float32 src2) { - set_float_exception_flags(0, &env->fp_status); - FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status); - check_ieee_exceptions(); + DT0 = float64_mul(float32_to_float64(src1, &env->fp_status), + float32_to_float64(src2, &env->fp_status), + &env->fp_status); +} + +void helper_fdmulq(void) +{ + QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status), + float64_to_float128(DT1, &env->fp_status), + &env->fp_status); +} + +float32 helper_fnegs(float32 src) +{ + return float32_chs(src); } -void do_fitod(void) +#ifdef TARGET_SPARC64 +F_HELPER(neg, d) { - DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status); + DT0 = float64_chs(DT1); } -#if defined(CONFIG_USER_ONLY) -void do_fitoq(void) +F_HELPER(neg, q) { - QT0 = int32_to_float128(*((int32_t *)&FT1), &env->fp_status); + QT0 = float128_chs(QT1); } #endif +/* Integer to float conversion. */ +float32 helper_fitos(int32_t src) +{ + return int32_to_float32(src, &env->fp_status); +} + +void helper_fitod(int32_t src) +{ + DT0 = int32_to_float64(src, &env->fp_status); +} + +void helper_fitoq(int32_t src) +{ + QT0 = int32_to_float128(src, &env->fp_status); +} + #ifdef TARGET_SPARC64 -void do_fxtos(void) +float32 helper_fxtos(void) { - set_float_exception_flags(0, &env->fp_status); - FT0 = int64_to_float32(*((int64_t *)&DT1), &env->fp_status); - check_ieee_exceptions(); + return int64_to_float32(*((int64_t *)&DT1), &env->fp_status); } -void do_fxtod(void) +F_HELPER(xto, d) { - set_float_exception_flags(0, &env->fp_status); DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status); - check_ieee_exceptions(); } -#if defined(CONFIG_USER_ONLY) -void do_fxtoq(void) +F_HELPER(xto, q) { - set_float_exception_flags(0, &env->fp_status); - QT0 = int64_to_float128(*((int32_t *)&DT1), &env->fp_status); - check_ieee_exceptions(); + QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status); } #endif +#undef F_HELPER + +/* floating point conversion */ +float32 helper_fdtos(void) +{ + return float64_to_float32(DT1, &env->fp_status); +} + +void helper_fstod(float32 src) +{ + DT0 = float32_to_float64(src, &env->fp_status); +} + +float32 helper_fqtos(void) +{ + return float128_to_float32(QT1, &env->fp_status); +} + +void helper_fstoq(float32 src) +{ + QT0 = float32_to_float128(src, &env->fp_status); +} + +void helper_fqtod(void) +{ + DT0 = float128_to_float64(QT1, &env->fp_status); +} + +void helper_fdtoq(void) +{ + QT0 = float64_to_float128(DT1, &env->fp_status); +} + +/* Float to integer conversion. */ +int32_t helper_fstoi(float32 src) +{ + return float32_to_int32_round_to_zero(src, &env->fp_status); +} + +int32_t helper_fdtoi(void) +{ + return float64_to_int32_round_to_zero(DT1, &env->fp_status); +} + +int32_t helper_fqtoi(void) +{ + return float128_to_int32_round_to_zero(QT1, &env->fp_status); +} + +#ifdef TARGET_SPARC64 +void helper_fstox(float32 src) +{ + *((int64_t *)&DT0) = float32_to_int64_round_to_zero(src, &env->fp_status); +} + +void helper_fdtox(void) +{ + *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status); +} + +void helper_fqtox(void) +{ + *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status); +} + +void helper_faligndata(void) +{ + uint64_t tmp; + + tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8); + /* on many architectures a shift of 64 does nothing */ + if ((env->gsr & 7) != 0) { + tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8); + } + *((uint64_t *)&DT0) = tmp; +} + +#ifdef WORDS_BIGENDIAN +#define VIS_B64(n) b[7 - (n)] +#define VIS_W64(n) w[3 - (n)] +#define VIS_SW64(n) sw[3 - (n)] +#define VIS_L64(n) l[1 - (n)] +#define VIS_B32(n) b[3 - (n)] +#define VIS_W32(n) w[1 - (n)] +#else +#define VIS_B64(n) b[n] +#define VIS_W64(n) w[n] +#define VIS_SW64(n) sw[n] +#define VIS_L64(n) l[n] +#define VIS_B32(n) b[n] +#define VIS_W32(n) w[n] +#endif + +typedef union { + uint8_t b[8]; + uint16_t w[4]; + int16_t sw[4]; + uint32_t l[2]; + float64 d; +} vis64; + +typedef union { + uint8_t b[4]; + uint16_t w[2]; + uint32_t l; + float32 f; +} vis32; + +void helper_fpmerge(void) +{ + vis64 s, d; + + s.d = DT0; + d.d = DT1; + + // Reverse calculation order to handle overlap + d.VIS_B64(7) = s.VIS_B64(3); + d.VIS_B64(6) = d.VIS_B64(3); + d.VIS_B64(5) = s.VIS_B64(2); + d.VIS_B64(4) = d.VIS_B64(2); + d.VIS_B64(3) = s.VIS_B64(1); + d.VIS_B64(2) = d.VIS_B64(1); + d.VIS_B64(1) = s.VIS_B64(0); + //d.VIS_B64(0) = d.VIS_B64(0); + + DT0 = d.d; +} + +void helper_fmul8x16(void) +{ + vis64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r); \ + if ((tmp & 0xff) > 0x7f) \ + tmp += 0x100; \ + d.VIS_W64(r) = tmp >> 8; + + PMUL(0); + PMUL(1); + PMUL(2); + PMUL(3); +#undef PMUL + + DT0 = d.d; +} + +void helper_fmul8x16al(void) +{ + vis64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r); \ + if ((tmp & 0xff) > 0x7f) \ + tmp += 0x100; \ + d.VIS_W64(r) = tmp >> 8; + + PMUL(0); + PMUL(1); + PMUL(2); + PMUL(3); +#undef PMUL + + DT0 = d.d; +} + +void helper_fmul8x16au(void) +{ + vis64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r); \ + if ((tmp & 0xff) > 0x7f) \ + tmp += 0x100; \ + d.VIS_W64(r) = tmp >> 8; + + PMUL(0); + PMUL(1); + PMUL(2); + PMUL(3); +#undef PMUL + + DT0 = d.d; +} + +void helper_fmul8sux16(void) +{ + vis64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \ + if ((tmp & 0xff) > 0x7f) \ + tmp += 0x100; \ + d.VIS_W64(r) = tmp >> 8; + + PMUL(0); + PMUL(1); + PMUL(2); + PMUL(3); +#undef PMUL + + DT0 = d.d; +} + +void helper_fmul8ulx16(void) +{ + vis64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \ + if ((tmp & 0xff) > 0x7f) \ + tmp += 0x100; \ + d.VIS_W64(r) = tmp >> 8; + + PMUL(0); + PMUL(1); + PMUL(2); + PMUL(3); +#undef PMUL + + DT0 = d.d; +} + +void helper_fmuld8sux16(void) +{ + vis64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \ + if ((tmp & 0xff) > 0x7f) \ + tmp += 0x100; \ + d.VIS_L64(r) = tmp; + + // Reverse calculation order to handle overlap + PMUL(1); + PMUL(0); +#undef PMUL + + DT0 = d.d; +} + +void helper_fmuld8ulx16(void) +{ + vis64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \ + if ((tmp & 0xff) > 0x7f) \ + tmp += 0x100; \ + d.VIS_L64(r) = tmp; + + // Reverse calculation order to handle overlap + PMUL(1); + PMUL(0); +#undef PMUL + + DT0 = d.d; +} + +void helper_fexpand(void) +{ + vis32 s; + vis64 d; + + s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff); + d.d = DT1; + d.VIS_W64(0) = s.VIS_B32(0) << 4; + d.VIS_W64(1) = s.VIS_B32(1) << 4; + d.VIS_W64(2) = s.VIS_B32(2) << 4; + d.VIS_W64(3) = s.VIS_B32(3) << 4; + + DT0 = d.d; +} + +#define VIS_HELPER(name, F) \ + void name##16(void) \ + { \ + vis64 s, d; \ + \ + s.d = DT0; \ + d.d = DT1; \ + \ + d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0)); \ + d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1)); \ + d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2)); \ + d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3)); \ + \ + DT0 = d.d; \ + } \ + \ + uint32_t name##16s(uint32_t src1, uint32_t src2) \ + { \ + vis32 s, d; \ + \ + s.l = src1; \ + d.l = src2; \ + \ + d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0)); \ + d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1)); \ + \ + return d.l; \ + } \ + \ + void name##32(void) \ + { \ + vis64 s, d; \ + \ + s.d = DT0; \ + d.d = DT1; \ + \ + d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0)); \ + d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1)); \ + \ + DT0 = d.d; \ + } \ + \ + uint32_t name##32s(uint32_t src1, uint32_t src2) \ + { \ + vis32 s, d; \ + \ + s.l = src1; \ + d.l = src2; \ + \ + d.l = F(d.l, s.l); \ + \ + return d.l; \ + } + +#define FADD(a, b) ((a) + (b)) +#define FSUB(a, b) ((a) - (b)) +VIS_HELPER(helper_fpadd, FADD) +VIS_HELPER(helper_fpsub, FSUB) + +#define VIS_CMPHELPER(name, F) \ + void name##16(void) \ + { \ + vis64 s, d; \ + \ + s.d = DT0; \ + d.d = DT1; \ + \ + d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0))? 1: 0; \ + d.VIS_W64(0) |= F(d.VIS_W64(1), s.VIS_W64(1))? 2: 0; \ + d.VIS_W64(0) |= F(d.VIS_W64(2), s.VIS_W64(2))? 4: 0; \ + d.VIS_W64(0) |= F(d.VIS_W64(3), s.VIS_W64(3))? 8: 0; \ + \ + DT0 = d.d; \ + } \ + \ + void name##32(void) \ + { \ + vis64 s, d; \ + \ + s.d = DT0; \ + d.d = DT1; \ + \ + d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0))? 1: 0; \ + d.VIS_L64(0) |= F(d.VIS_L64(1), s.VIS_L64(1))? 2: 0; \ + \ + DT0 = d.d; \ + } + +#define FCMPGT(a, b) ((a) > (b)) +#define FCMPEQ(a, b) ((a) == (b)) +#define FCMPLE(a, b) ((a) <= (b)) +#define FCMPNE(a, b) ((a) != (b)) + +VIS_CMPHELPER(helper_fcmpgt, FCMPGT) +VIS_CMPHELPER(helper_fcmpeq, FCMPEQ) +VIS_CMPHELPER(helper_fcmple, FCMPLE) +VIS_CMPHELPER(helper_fcmpne, FCMPNE) #endif -#endif -void do_fabss(void) +void helper_check_ieee_exceptions(void) +{ + target_ulong status; + + status = get_float_exception_flags(&env->fp_status); + if (status) { + /* Copy IEEE 754 flags into FSR */ + if (status & float_flag_invalid) + env->fsr |= FSR_NVC; + if (status & float_flag_overflow) + env->fsr |= FSR_OFC; + if (status & float_flag_underflow) + env->fsr |= FSR_UFC; + if (status & float_flag_divbyzero) + env->fsr |= FSR_DZC; + if (status & float_flag_inexact) + env->fsr |= FSR_NXC; + + if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) { + /* Unmasked exception, generate a trap */ + env->fsr |= FSR_FTT_IEEE_EXCP; + raise_exception(TT_FP_EXCP); + } else { + /* Accumulate exceptions */ + env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5; + } + } +} + +void helper_clear_float_exceptions(void) +{ + set_float_exception_flags(0, &env->fp_status); +} + +float32 helper_fabss(float32 src) { - FT0 = float32_abs(FT1); + return float32_abs(src); } #ifdef TARGET_SPARC64 -void do_fabsd(void) +void helper_fabsd(void) { DT0 = float64_abs(DT1); } -#if defined(CONFIG_USER_ONLY) -void do_fabsq(void) +void helper_fabsq(void) { QT0 = float128_abs(QT1); } #endif -#endif -void do_fsqrts(void) +float32 helper_fsqrts(float32 src) { - set_float_exception_flags(0, &env->fp_status); - FT0 = float32_sqrt(FT1, &env->fp_status); - check_ieee_exceptions(); + return float32_sqrt(src, &env->fp_status); } -void do_fsqrtd(void) +void helper_fsqrtd(void) { - set_float_exception_flags(0, &env->fp_status); DT0 = float64_sqrt(DT1, &env->fp_status); - check_ieee_exceptions(); } -#if defined(CONFIG_USER_ONLY) -void do_fsqrtq(void) +void helper_fsqrtq(void) { - set_float_exception_flags(0, &env->fp_status); QT0 = float128_sqrt(QT1, &env->fp_status); - check_ieee_exceptions(); } -#endif #define GEN_FCMP(name, size, reg1, reg2, FS, TRAP) \ - void glue(do_, name) (void) \ + void glue(helper_, name) (void) \ { \ + target_ulong new_fsr; \ + \ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \ case float_relation_unordered: \ - T0 = (FSR_FCC1 | FSR_FCC0) << FS; \ + new_fsr = (FSR_FCC1 | FSR_FCC0) << FS; \ + if ((env->fsr & FSR_NVM) || TRAP) { \ + env->fsr |= new_fsr; \ + env->fsr |= FSR_NVC; \ + env->fsr |= FSR_FTT_IEEE_EXCP; \ + raise_exception(TT_FP_EXCP); \ + } else { \ + env->fsr |= FSR_NVA; \ + } \ + break; \ + case float_relation_less: \ + new_fsr = FSR_FCC0 << FS; \ + break; \ + case float_relation_greater: \ + new_fsr = FSR_FCC1 << FS; \ + break; \ + default: \ + new_fsr = 0; \ + break; \ + } \ + env->fsr |= new_fsr; \ + } +#define GEN_FCMPS(name, size, FS, TRAP) \ + void glue(helper_, name)(float32 src1, float32 src2) \ + { \ + target_ulong new_fsr; \ + \ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + switch (glue(size, _compare) (src1, src2, &env->fp_status)) { \ + case float_relation_unordered: \ + new_fsr = (FSR_FCC1 | FSR_FCC0) << FS; \ if ((env->fsr & FSR_NVM) || TRAP) { \ - env->fsr |= T0; \ + env->fsr |= new_fsr; \ env->fsr |= FSR_NVC; \ env->fsr |= FSR_FTT_IEEE_EXCP; \ raise_exception(TT_FP_EXCP); \ @@ -171,140 +672,147 @@ } \ break; \ case float_relation_less: \ - T0 = FSR_FCC0 << FS; \ + new_fsr = FSR_FCC0 << FS; \ break; \ case float_relation_greater: \ - T0 = FSR_FCC1 << FS; \ + new_fsr = FSR_FCC1 << FS; \ break; \ default: \ - T0 = 0; \ + new_fsr = 0; \ break; \ } \ - env->fsr |= T0; \ + env->fsr |= new_fsr; \ } -GEN_FCMP(fcmps, float32, FT0, FT1, 0, 0); +GEN_FCMPS(fcmps, float32, 0, 0); GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0); -GEN_FCMP(fcmpes, float32, FT0, FT1, 0, 1); +GEN_FCMPS(fcmpes, float32, 0, 1); GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1); -#ifdef CONFIG_USER_ONLY GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0); GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1); -#endif #ifdef TARGET_SPARC64 -GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22, 0); +GEN_FCMPS(fcmps_fcc1, float32, 22, 0); GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0); +GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0); -GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24, 0); +GEN_FCMPS(fcmps_fcc2, float32, 24, 0); GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0); +GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0); -GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26, 0); +GEN_FCMPS(fcmps_fcc3, float32, 26, 0); GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0); +GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0); -GEN_FCMP(fcmpes_fcc1, float32, FT0, FT1, 22, 1); +GEN_FCMPS(fcmpes_fcc1, float32, 22, 1); GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1); +GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1); -GEN_FCMP(fcmpes_fcc2, float32, FT0, FT1, 24, 1); +GEN_FCMPS(fcmpes_fcc2, float32, 24, 1); GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1); +GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1); -GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1); +GEN_FCMPS(fcmpes_fcc3, float32, 26, 1); GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1); -#ifdef CONFIG_USER_ONLY -GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0); -GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0); -GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0); -GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1); -GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1); GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1); #endif -#endif +#undef GEN_FCMPS -#ifndef TARGET_SPARC64 -#ifndef CONFIG_USER_ONLY - -#ifdef DEBUG_MXCC +#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && \ + defined(DEBUG_MXCC) static void dump_mxcc(CPUState *env) { printf("mxccdata: %016llx %016llx %016llx %016llx\n", - env->mxccdata[0], env->mxccdata[1], env->mxccdata[2], env->mxccdata[3]); + env->mxccdata[0], env->mxccdata[1], + env->mxccdata[2], env->mxccdata[3]); printf("mxccregs: %016llx %016llx %016llx %016llx\n" " %016llx %016llx %016llx %016llx\n", - env->mxccregs[0], env->mxccregs[1], env->mxccregs[2], env->mxccregs[3], - env->mxccregs[4], env->mxccregs[5], env->mxccregs[6], env->mxccregs[7]); + env->mxccregs[0], env->mxccregs[1], + env->mxccregs[2], env->mxccregs[3], + env->mxccregs[4], env->mxccregs[5], + env->mxccregs[6], env->mxccregs[7]); } #endif -#ifdef DEBUG_ASI -static void dump_asi(const char * txt, uint32_t addr, int asi, int size, - uint32_t r1, uint32_t r2) +#if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)) \ + && defined(DEBUG_ASI) +static void dump_asi(const char *txt, target_ulong addr, int asi, int size, + uint64_t r1) { switch (size) { case 1: - DPRINTF_ASI("%s %08x asi 0x%02x = %02x\n", txt, addr, asi, r1 & 0xff); + DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt, + addr, asi, r1 & 0xff); break; case 2: - DPRINTF_ASI("%s %08x asi 0x%02x = %04x\n", txt, addr, asi, r1 & 0xffff); + DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %04" PRIx64 "\n", txt, + addr, asi, r1 & 0xffff); break; case 4: - DPRINTF_ASI("%s %08x asi 0x%02x = %08x\n", txt, addr, asi, r1); + DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %08" PRIx64 "\n", txt, + addr, asi, r1 & 0xffffffff); break; case 8: - DPRINTF_ASI("%s %08x asi 0x%02x = %016llx\n", txt, addr, asi, - r2 | ((uint64_t)r1 << 32)); + DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %016" PRIx64 "\n", txt, + addr, asi, r1); break; } } #endif -void helper_ld_asi(int asi, int size, int sign) +#ifndef TARGET_SPARC64 +#ifndef CONFIG_USER_ONLY +uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) { - uint32_t ret = 0; - uint64_t tmp; + uint64_t ret = 0; #if defined(DEBUG_MXCC) || defined(DEBUG_ASI) - uint32_t last_T0 = T0; + uint32_t last_addr = addr; #endif + helper_check_align(addr, size - 1); switch (asi) { case 2: /* SuperSparc MXCC registers */ - switch (T0) { + switch (addr) { case 0x01c00a00: /* MXCC control register */ - if (size == 8) { - ret = env->mxccregs[3] >> 32; - T0 = env->mxccregs[3]; - } else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + if (size == 8) + ret = env->mxccregs[3]; + else + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); break; case 0x01c00a04: /* MXCC control register */ if (size == 4) ret = env->mxccregs[3]; else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); break; case 0x01c00c00: /* Module reset register */ if (size == 8) { - ret = env->mxccregs[5] >> 32; - T0 = env->mxccregs[5]; + ret = env->mxccregs[5]; // should we do something here? } else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); break; case 0x01c00f00: /* MBus port address register */ - if (size == 8) { - ret = env->mxccregs[7] >> 32; - T0 = env->mxccregs[7]; - } else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + if (size == 8) + ret = env->mxccregs[7]; + else + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); break; default: - DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", T0, size); + DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr, + size); break; } - DPRINTF_MXCC("asi = %d, size = %d, sign = %d, T0 = %08x -> ret = %08x," - "T0 = %08x\n", asi, size, sign, last_T0, ret, T0); + DPRINTF_MXCC("asi = %d, size = %d, sign = %d, " + "addr = %08x -> ret = %" PRIx64 "," + "addr = %08x\n", asi, size, sign, last_addr, ret, addr); #ifdef DEBUG_MXCC dump_mxcc(env); #endif @@ -313,19 +821,18 @@ { int mmulev; - mmulev = (T0 >> 8) & 15; + mmulev = (addr >> 8) & 15; if (mmulev > 4) ret = 0; - else { - ret = mmu_probe(env, T0, mmulev); - //bswap32s(&ret); - } - DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret); + else + ret = mmu_probe(env, addr, mmulev); + DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n", + addr, mmulev, ret); } break; case 4: /* read MMU regs */ { - int reg = (T0 >> 8) & 0x1f; + int reg = (addr >> 8) & 0x1f; ret = env->mmuregs[reg]; if (reg == 3) /* Fault status cleared on read */ @@ -334,7 +841,7 @@ ret = env->mmuregs[3]; else if (reg == 0x14) /* Fault address read */ ret = env->mmuregs[4]; - DPRINTF_MMU("mmu_read: reg[%d] = 0x%08x\n", reg, ret); + DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret); } break; case 5: // Turbosparc ITLB Diagnostic @@ -344,57 +851,51 @@ case 9: /* Supervisor code access */ switch(size) { case 1: - ret = ldub_code(T0); + ret = ldub_code(addr); break; case 2: - ret = lduw_code(T0 & ~1); + ret = lduw_code(addr); break; default: case 4: - ret = ldl_code(T0 & ~3); + ret = ldl_code(addr); break; case 8: - tmp = ldq_code(T0 & ~7); - ret = tmp >> 32; - T0 = tmp; + ret = ldq_code(addr); break; } break; case 0xa: /* User data access */ switch(size) { case 1: - ret = ldub_user(T0); + ret = ldub_user(addr); break; case 2: - ret = lduw_user(T0 & ~1); + ret = lduw_user(addr); break; default: case 4: - ret = ldl_user(T0 & ~3); + ret = ldl_user(addr); break; case 8: - tmp = ldq_user(T0 & ~7); - ret = tmp >> 32; - T0 = tmp; + ret = ldq_user(addr); break; } break; case 0xb: /* Supervisor data access */ switch(size) { case 1: - ret = ldub_kernel(T0); + ret = ldub_kernel(addr); break; case 2: - ret = lduw_kernel(T0 & ~1); + ret = lduw_kernel(addr); break; default: case 4: - ret = ldl_kernel(T0 & ~3); + ret = ldl_kernel(addr); break; case 8: - tmp = ldq_kernel(T0 & ~7); - ret = tmp >> 32; - T0 = tmp; + ret = ldq_kernel(addr); break; } break; @@ -406,42 +907,38 @@ case 0x20: /* MMU passthrough */ switch(size) { case 1: - ret = ldub_phys(T0); + ret = ldub_phys(addr); break; case 2: - ret = lduw_phys(T0 & ~1); + ret = lduw_phys(addr); break; default: case 4: - ret = ldl_phys(T0 & ~3); + ret = ldl_phys(addr); break; case 8: - tmp = ldq_phys(T0 & ~7); - ret = tmp >> 32; - T0 = tmp; + ret = ldq_phys(addr); break; } break; case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */ switch(size) { case 1: - ret = ldub_phys((target_phys_addr_t)T0 + ret = ldub_phys((target_phys_addr_t)addr | ((target_phys_addr_t)(asi & 0xf) << 32)); break; case 2: - ret = lduw_phys((target_phys_addr_t)(T0 & ~1) + ret = lduw_phys((target_phys_addr_t)addr | ((target_phys_addr_t)(asi & 0xf) << 32)); break; default: case 4: - ret = ldl_phys((target_phys_addr_t)(T0 & ~3) + ret = ldl_phys((target_phys_addr_t)addr | ((target_phys_addr_t)(asi & 0xf) << 32)); break; case 8: - tmp = ldq_phys((target_phys_addr_t)(T0 & ~7) + ret = ldq_phys((target_phys_addr_t)addr | ((target_phys_addr_t)(asi & 0xf) << 32)); - ret = tmp >> 32; - T0 = tmp; break; } break; @@ -453,109 +950,132 @@ break; case 8: /* User code access, XXX */ default: - do_unassigned_access(T0, 0, 0, asi); + do_unassigned_access(addr, 0, 0, asi, size); ret = 0; break; } if (sign) { switch(size) { case 1: - T1 = (int8_t) ret; + ret = (int8_t) ret; break; case 2: - T1 = (int16_t) ret; + ret = (int16_t) ret; + break; + case 4: + ret = (int32_t) ret; break; default: - T1 = ret; break; } } - else - T1 = ret; #ifdef DEBUG_ASI - dump_asi("read ", last_T0, asi, size, T1, T0); + dump_asi("read ", last_addr, asi, size, ret); #endif + return ret; } -void helper_st_asi(int asi, int size) +void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) { + helper_check_align(addr, size - 1); switch(asi) { case 2: /* SuperSparc MXCC registers */ - switch (T0) { + switch (addr) { case 0x01c00000: /* MXCC stream data register 0 */ if (size == 8) - env->mxccdata[0] = ((uint64_t)T1 << 32) | T2; + env->mxccdata[0] = val; else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); break; case 0x01c00008: /* MXCC stream data register 1 */ if (size == 8) - env->mxccdata[1] = ((uint64_t)T1 << 32) | T2; + env->mxccdata[1] = val; else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); break; case 0x01c00010: /* MXCC stream data register 2 */ if (size == 8) - env->mxccdata[2] = ((uint64_t)T1 << 32) | T2; + env->mxccdata[2] = val; else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); break; case 0x01c00018: /* MXCC stream data register 3 */ if (size == 8) - env->mxccdata[3] = ((uint64_t)T1 << 32) | T2; + env->mxccdata[3] = val; else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); break; case 0x01c00100: /* MXCC stream source */ if (size == 8) - env->mxccregs[0] = ((uint64_t)T1 << 32) | T2; + env->mxccregs[0] = val; else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); - env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + 0); - env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + 8); - env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + 16); - env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + 24); + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); + env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + + 0); + env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + + 8); + env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + + 16); + env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + + 24); break; case 0x01c00200: /* MXCC stream destination */ if (size == 8) - env->mxccregs[1] = ((uint64_t)T1 << 32) | T2; + env->mxccregs[1] = val; else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); - stq_phys((env->mxccregs[1] & 0xffffffffULL) + 0, env->mxccdata[0]); - stq_phys((env->mxccregs[1] & 0xffffffffULL) + 8, env->mxccdata[1]); - stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16, env->mxccdata[2]); - stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24, env->mxccdata[3]); + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); + stq_phys((env->mxccregs[1] & 0xffffffffULL) + 0, + env->mxccdata[0]); + stq_phys((env->mxccregs[1] & 0xffffffffULL) + 8, + env->mxccdata[1]); + stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16, + env->mxccdata[2]); + stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24, + env->mxccdata[3]); break; case 0x01c00a00: /* MXCC control register */ if (size == 8) - env->mxccregs[3] = ((uint64_t)T1 << 32) | T2; + env->mxccregs[3] = val; else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); break; case 0x01c00a04: /* MXCC control register */ if (size == 4) - env->mxccregs[3] = (env->mxccregs[0xa] & 0xffffffff00000000ULL) | T1; + env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL) + | val; else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); break; case 0x01c00e00: /* MXCC error register */ // writing a 1 bit clears the error if (size == 8) - env->mxccregs[6] &= ~(((uint64_t)T1 << 32) | T2); + env->mxccregs[6] &= ~val; else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); break; case 0x01c00f00: /* MBus port address register */ if (size == 8) - env->mxccregs[7] = ((uint64_t)T1 << 32) | T2; + env->mxccregs[7] = val; else - DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, + size); break; default: - DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", T0, size); + DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr, + size); break; } - DPRINTF_MXCC("asi = %d, size = %d, T0 = %08x, T1 = %08x\n", asi, size, T0, T1); + DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %" PRIx64 "\n", + asi, size, addr, val); #ifdef DEBUG_MXCC dump_mxcc(env); #endif @@ -564,11 +1084,11 @@ { int mmulev; - mmulev = (T0 >> 8) & 15; + mmulev = (addr >> 8) & 15; DPRINTF_MMU("mmu flush level %d\n", mmulev); switch (mmulev) { case 0: // flush page - tlb_flush_page(env, T0 & 0xfffff000); + tlb_flush_page(env, addr & 0xfffff000); break; case 1: // flush segment (256k) case 2: // flush region (16M) @@ -586,43 +1106,50 @@ break; case 4: /* write MMU regs */ { - int reg = (T0 >> 8) & 0x1f; + int reg = (addr >> 8) & 0x1f; uint32_t oldreg; oldreg = env->mmuregs[reg]; switch(reg) { - case 0: + case 0: // Control Register env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) | - (T1 & 0x00ffffff); + (val & 0x00ffffff); // Mappings generated during no-fault mode or MMU // disabled mode are invalid in normal mode - if ((oldreg & (MMU_E | MMU_NF | env->mmu_bm)) != - (env->mmuregs[reg] & (MMU_E | MMU_NF | env->mmu_bm))) + if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) != + (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm))) tlb_flush(env, 1); break; - case 2: - env->mmuregs[reg] = T1; + case 1: // Context Table Pointer Register + env->mmuregs[reg] = val & env->def->mmu_ctpr_mask; + break; + case 2: // Context Register + env->mmuregs[reg] = val & env->def->mmu_cxr_mask; if (oldreg != env->mmuregs[reg]) { /* we flush when the MMU context changes because QEMU has no MMU context support */ tlb_flush(env, 1); } break; - case 3: - case 4: + case 3: // Synchronous Fault Status Register with Clear + case 4: // Synchronous Fault Address Register + break; + case 0x10: // TLB Replacement Control Register + env->mmuregs[reg] = val & env->def->mmu_trcr_mask; break; - case 0x13: - env->mmuregs[3] = T1; + case 0x13: // Synchronous Fault Status Register with Read and Clear + env->mmuregs[3] = val & env->def->mmu_sfsr_mask; break; - case 0x14: - env->mmuregs[4] = T1; + case 0x14: // Synchronous Fault Address Register + env->mmuregs[4] = val; break; default: - env->mmuregs[reg] = T1; + env->mmuregs[reg] = val; break; } if (oldreg != env->mmuregs[reg]) { - DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->mmuregs[reg]); + DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n", + reg, oldreg, env->mmuregs[reg]); } #ifdef DEBUG_MMU dump_mmu(env); @@ -636,34 +1163,34 @@ case 0xa: /* User data access */ switch(size) { case 1: - stb_user(T0, T1); + stb_user(addr, val); break; case 2: - stw_user(T0 & ~1, T1); + stw_user(addr, val); break; default: case 4: - stl_user(T0 & ~3, T1); + stl_user(addr, val); break; case 8: - stq_user(T0 & ~7, ((uint64_t)T1 << 32) | T2); + stq_user(addr, val); break; } break; case 0xb: /* Supervisor data access */ switch(size) { case 1: - stb_kernel(T0, T1); + stb_kernel(addr, val); break; case 2: - stw_kernel(T0 & ~1, T1); + stw_kernel(addr, val); break; default: case 4: - stl_kernel(T0 & ~3, T1); + stl_kernel(addr, val); break; case 8: - stq_kernel(T0 & ~7, ((uint64_t)T1 << 32) | T2); + stq_kernel(addr, val); break; } break; @@ -679,11 +1206,11 @@ break; case 0x17: /* Block copy, sta access */ { - // value (T1) = src - // address (T0) = dst + // val = src + // addr = dst // copy 32 bytes unsigned int i; - uint32_t src = T1 & ~3, dst = T0 & ~3, temp; + uint32_t src = val & ~3, dst = addr & ~3, temp; for (i = 0; i < 32; i += 4, src += 4, dst += 4) { temp = ldl_kernel(src); @@ -693,14 +1220,10 @@ break; case 0x1f: /* Block fill, stda access */ { - // value (T1, T2) - // address (T0) = dst - // fill 32 bytes + // addr = dst + // fill 32 bytes with val unsigned int i; - uint32_t dst = T0 & 7; - uint64_t val; - - val = (((uint64_t)T1) << 32) | T2; + uint32_t dst = addr & 7; for (i = 0; i < 32; i += 8, dst += 8) stq_kernel(dst, val); @@ -710,17 +1233,17 @@ { switch(size) { case 1: - stb_phys(T0, T1); + stb_phys(addr, val); break; case 2: - stw_phys(T0 & ~1, T1); + stw_phys(addr, val); break; case 4: default: - stl_phys(T0 & ~3, T1); + stl_phys(addr, val); break; case 8: - stq_phys(T0 & ~7, ((uint64_t)T1 << 32) | T2); + stq_phys(addr, val); break; } } @@ -729,22 +1252,21 @@ { switch(size) { case 1: - stb_phys((target_phys_addr_t)T0 - | ((target_phys_addr_t)(asi & 0xf) << 32), T1); + stb_phys((target_phys_addr_t)addr + | ((target_phys_addr_t)(asi & 0xf) << 32), val); break; case 2: - stw_phys((target_phys_addr_t)(T0 & ~1) - | ((target_phys_addr_t)(asi & 0xf) << 32), T1); + stw_phys((target_phys_addr_t)addr + | ((target_phys_addr_t)(asi & 0xf) << 32), val); break; case 4: default: - stl_phys((target_phys_addr_t)(T0 & ~3) - | ((target_phys_addr_t)(asi & 0xf) << 32), T1); + stl_phys((target_phys_addr_t)addr + | ((target_phys_addr_t)(asi & 0xf) << 32), val); break; case 8: - stq_phys((target_phys_addr_t)(T0 & ~7) - | ((target_phys_addr_t)(asi & 0xf) << 32), - ((uint64_t)T1 << 32) | T2); + stq_phys((target_phys_addr_t)addr + | ((target_phys_addr_t)(asi & 0xf) << 32), val); break; } } @@ -752,7 +1274,8 @@ case 0x30: // store buffer tags or Turbosparc secondary cache diagnostic case 0x31: // store buffer data, Ross RT620 I-cache flush or // Turbosparc snoop RAM - case 0x32: // store buffer control or Turbosparc page table descriptor diagnostic + case 0x32: // store buffer control or Turbosparc page table + // descriptor diagnostic case 0x36: /* I-cache flash clear */ case 0x37: /* D-cache flash clear */ case 0x38: /* breakpoint diagnostics */ @@ -761,11 +1284,11 @@ case 8: /* User code access, XXX */ case 9: /* Supervisor code access, XXX */ default: - do_unassigned_access(T0, 1, 0, asi); + do_unassigned_access(addr, 1, 0, asi, size); break; } #ifdef DEBUG_ASI - dump_asi("write", T0, asi, size, T1, T2); + dump_asi("write", addr, asi, size, val); #endif } @@ -773,40 +1296,60 @@ #else /* TARGET_SPARC64 */ #ifdef CONFIG_USER_ONLY -void helper_ld_asi(int asi, int size, int sign) +uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) { uint64_t ret = 0; +#if defined(DEBUG_ASI) + target_ulong last_addr = addr; +#endif if (asi < 0x80) raise_exception(TT_PRIV_ACT); + helper_check_align(addr, size - 1); + address_mask(env, &addr); + switch (asi) { - case 0x80: // Primary case 0x82: // Primary no-fault - case 0x88: // Primary LE case 0x8a: // Primary no-fault LE + if (page_check_range(addr, size, PAGE_READ) == -1) { +#ifdef DEBUG_ASI + dump_asi("read ", last_addr, asi, size, ret); +#endif + return 0; + } + // Fall through + case 0x80: // Primary + case 0x88: // Primary LE { switch(size) { case 1: - ret = ldub_raw(T0); + ret = ldub_raw(addr); break; case 2: - ret = lduw_raw(T0 & ~1); + ret = lduw_raw(addr); break; case 4: - ret = ldl_raw(T0 & ~3); + ret = ldl_raw(addr); break; default: case 8: - ret = ldq_raw(T0 & ~7); + ret = ldq_raw(addr); break; } } break; - case 0x81: // Secondary case 0x83: // Secondary no-fault - case 0x89: // Secondary LE case 0x8b: // Secondary no-fault LE + if (page_check_range(addr, size, PAGE_READ) == -1) { +#ifdef DEBUG_ASI + dump_asi("read ", last_addr, asi, size, ret); +#endif + return 0; + } + // Fall through + case 0x81: // Secondary + case 0x89: // Secondary LE // XXX break; default: @@ -852,27 +1395,36 @@ break; } } - T1 = ret; +#ifdef DEBUG_ASI + dump_asi("read ", last_addr, asi, size, ret); +#endif + return ret; } -void helper_st_asi(int asi, int size) +void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) { +#ifdef DEBUG_ASI + dump_asi("write", addr, asi, size, val); +#endif if (asi < 0x80) raise_exception(TT_PRIV_ACT); + helper_check_align(addr, size - 1); + address_mask(env, &addr); + /* Convert to little endian */ switch (asi) { case 0x88: // Primary LE case 0x89: // Secondary LE switch(size) { case 2: - T0 = bswap16(T0); + addr = bswap16(addr); break; case 4: - T0 = bswap32(T0); + addr = bswap32(addr); break; case 8: - T0 = bswap64(T0); + addr = bswap64(addr); break; default: break; @@ -887,17 +1439,17 @@ { switch(size) { case 1: - stb_raw(T0, T1); + stb_raw(addr, val); break; case 2: - stw_raw(T0 & ~1, T1); + stw_raw(addr, val); break; case 4: - stl_raw(T0 & ~3, T1); + stl_raw(addr, val); break; case 8: default: - stq_raw(T0 & ~7, T1); + stq_raw(addr, val); break; } } @@ -912,76 +1464,92 @@ case 0x8a: // Primary no-fault LE, RO case 0x8b: // Secondary no-fault LE, RO default: - do_unassigned_access(T0, 1, 0, 1); + do_unassigned_access(addr, 1, 0, 1, size); return; } } #else /* CONFIG_USER_ONLY */ -void helper_ld_asi(int asi, int size, int sign) +uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) { uint64_t ret = 0; +#if defined(DEBUG_ASI) + target_ulong last_addr = addr; +#endif if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) - || (asi >= 0x30 && asi < 0x80 && !(env->hpstate & HS_PRIV))) + || ((env->def->features & CPU_FEATURE_HYPV) + && asi >= 0x30 && asi < 0x80 + && !(env->hpstate & HS_PRIV))) raise_exception(TT_PRIV_ACT); + helper_check_align(addr, size - 1); switch (asi) { + case 0x82: // Primary no-fault + case 0x8a: // Primary no-fault LE + if (cpu_get_phys_page_debug(env, addr) == -1ULL) { +#ifdef DEBUG_ASI + dump_asi("read ", last_addr, asi, size, ret); +#endif + return 0; + } + // Fall through case 0x10: // As if user primary case 0x18: // As if user primary LE case 0x80: // Primary - case 0x82: // Primary no-fault case 0x88: // Primary LE - case 0x8a: // Primary no-fault LE + case 0xe2: // UA2007 Primary block init + case 0xe3: // UA2007 Secondary block init if ((asi & 0x80) && (env->pstate & PS_PRIV)) { - if (env->hpstate & HS_PRIV) { + if ((env->def->features & CPU_FEATURE_HYPV) + && env->hpstate & HS_PRIV) { switch(size) { case 1: - ret = ldub_hypv(T0); + ret = ldub_hypv(addr); break; case 2: - ret = lduw_hypv(T0 & ~1); + ret = lduw_hypv(addr); break; case 4: - ret = ldl_hypv(T0 & ~3); + ret = ldl_hypv(addr); break; default: case 8: - ret = ldq_hypv(T0 & ~7); + ret = ldq_hypv(addr); break; } } else { switch(size) { case 1: - ret = ldub_kernel(T0); + ret = ldub_kernel(addr); break; case 2: - ret = lduw_kernel(T0 & ~1); + ret = lduw_kernel(addr); break; case 4: - ret = ldl_kernel(T0 & ~3); + ret = ldl_kernel(addr); break; default: case 8: - ret = ldq_kernel(T0 & ~7); + ret = ldq_kernel(addr); break; } } } else { switch(size) { case 1: - ret = ldub_user(T0); + ret = ldub_user(addr); break; case 2: - ret = lduw_user(T0 & ~1); + ret = lduw_user(addr); break; case 4: - ret = ldl_user(T0 & ~3); + ret = ldl_user(addr); break; default: case 8: - ret = ldq_user(T0 & ~7); + ret = ldq_user(addr); break; } } @@ -993,32 +1561,42 @@ { switch(size) { case 1: - ret = ldub_phys(T0); + ret = ldub_phys(addr); break; case 2: - ret = lduw_phys(T0 & ~1); + ret = lduw_phys(addr); break; case 4: - ret = ldl_phys(T0 & ~3); + ret = ldl_phys(addr); break; default: case 8: - ret = ldq_phys(T0 & ~7); + ret = ldq_phys(addr); break; } break; } + case 0x24: // Nucleus quad LDD 128 bit atomic + case 0x2c: // Nucleus quad LDD 128 bit atomic LE + // Only ldda allowed + raise_exception(TT_ILL_INSN); + return 0; + case 0x83: // Secondary no-fault + case 0x8b: // Secondary no-fault LE + if (cpu_get_phys_page_debug(env, addr) == -1ULL) { +#ifdef DEBUG_ASI + dump_asi("read ", last_addr, asi, size, ret); +#endif + return 0; + } + // Fall through case 0x04: // Nucleus case 0x0c: // Nucleus Little Endian (LE) case 0x11: // As if user secondary case 0x19: // As if user secondary LE - case 0x24: // Nucleus quad LDD 128 bit atomic - case 0x2c: // Nucleus quad LDD 128 bit atomic case 0x4a: // UPA config case 0x81: // Secondary - case 0x83: // Secondary no-fault case 0x89: // Secondary LE - case 0x8b: // Secondary no-fault LE // XXX break; case 0x45: // LSU @@ -1026,55 +1604,66 @@ break; case 0x50: // I-MMU regs { - int reg = (T0 >> 3) & 0xf; + int reg = (addr >> 3) & 0xf; ret = env->immuregs[reg]; break; } case 0x51: // I-MMU 8k TSB pointer case 0x52: // I-MMU 64k TSB pointer - case 0x55: // I-MMU data access // XXX break; + case 0x55: // I-MMU data access + { + int reg = (addr >> 3) & 0x3f; + + ret = env->itlb_tte[reg]; + break; + } case 0x56: // I-MMU tag read { - unsigned int i; + int reg = (addr >> 3) & 0x3f; - for (i = 0; i < 64; i++) { - // Valid, ctx match, vaddr match - if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0 && - env->itlb_tag[i] == T0) { - ret = env->itlb_tag[i]; - break; - } - } + ret = env->itlb_tag[reg]; break; } case 0x58: // D-MMU regs { - int reg = (T0 >> 3) & 0xf; + int reg = (addr >> 3) & 0xf; ret = env->dmmuregs[reg]; break; } + case 0x5d: // D-MMU data access + { + int reg = (addr >> 3) & 0x3f; + + ret = env->dtlb_tte[reg]; + break; + } case 0x5e: // D-MMU tag read { - unsigned int i; + int reg = (addr >> 3) & 0x3f; - for (i = 0; i < 64; i++) { - // Valid, ctx match, vaddr match - if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0 && - env->dtlb_tag[i] == T0) { - ret = env->dtlb_tag[i]; - break; - } - } + ret = env->dtlb_tag[reg]; break; } + case 0x46: // D-cache data + case 0x47: // D-cache tag access + case 0x4b: // E-cache error enable + case 0x4c: // E-cache asynchronous fault status + case 0x4d: // E-cache asynchronous fault address + case 0x4e: // E-cache tag data + case 0x66: // I-cache instruction access + case 0x67: // I-cache tag access + case 0x6e: // I-cache predecode + case 0x6f: // I-cache LRU etc. + case 0x76: // E-cache tag + case 0x7e: // E-cache tag + break; case 0x59: // D-MMU 8k TSB pointer case 0x5a: // D-MMU 64k TSB pointer case 0x5b: // D-MMU data pointer - case 0x5d: // D-MMU data access case 0x48: // Interrupt dispatch, RO case 0x49: // Interrupt data receive case 0x7f: // Incoming interrupt vector, RO @@ -1086,7 +1675,7 @@ case 0x5f: // D-MMU demap, WO case 0x77: // Interrupt vector, WO default: - do_unassigned_access(T0, 0, 0, 1); + do_unassigned_access(addr, 0, 0, 1, size); ret = 0; break; } @@ -1135,15 +1724,24 @@ break; } } - T1 = ret; +#ifdef DEBUG_ASI + dump_asi("read ", last_addr, asi, size, ret); +#endif + return ret; } -void helper_st_asi(int asi, int size) +void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) { +#ifdef DEBUG_ASI + dump_asi("write", addr, asi, size, val); +#endif if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) - || (asi >= 0x30 && asi < 0x80 && !(env->hpstate & HS_PRIV))) + || ((env->def->features & CPU_FEATURE_HYPV) + && asi >= 0x30 && asi < 0x80 + && !(env->hpstate & HS_PRIV))) raise_exception(TT_PRIV_ACT); + helper_check_align(addr, size - 1); /* Convert to little endian */ switch (asi) { case 0x0c: // Nucleus Little Endian (LE) @@ -1155,13 +1753,13 @@ case 0x89: // Secondary LE switch(size) { case 2: - T0 = bswap16(T0); + addr = bswap16(addr); break; case 4: - T0 = bswap32(T0); + addr = bswap32(addr); break; case 8: - T0 = bswap64(T0); + addr = bswap64(addr); break; default: break; @@ -1175,54 +1773,57 @@ case 0x18: // As if user primary LE case 0x80: // Primary case 0x88: // Primary LE + case 0xe2: // UA2007 Primary block init + case 0xe3: // UA2007 Secondary block init if ((asi & 0x80) && (env->pstate & PS_PRIV)) { - if (env->hpstate & HS_PRIV) { + if ((env->def->features & CPU_FEATURE_HYPV) + && env->hpstate & HS_PRIV) { switch(size) { case 1: - stb_hypv(T0, T1); + stb_hypv(addr, val); break; case 2: - stw_hypv(T0 & ~1, T1); + stw_hypv(addr, val); break; case 4: - stl_hypv(T0 & ~3, T1); + stl_hypv(addr, val); break; case 8: default: - stq_hypv(T0 & ~7, T1); + stq_hypv(addr, val); break; } } else { switch(size) { case 1: - stb_kernel(T0, T1); + stb_kernel(addr, val); break; case 2: - stw_kernel(T0 & ~1, T1); + stw_kernel(addr, val); break; case 4: - stl_kernel(T0 & ~3, T1); + stl_kernel(addr, val); break; case 8: default: - stq_kernel(T0 & ~7, T1); + stq_kernel(addr, val); break; } } } else { switch(size) { case 1: - stb_user(T0, T1); + stb_user(addr, val); break; case 2: - stw_user(T0 & ~1, T1); + stw_user(addr, val); break; case 4: - stl_user(T0 & ~3, T1); + stl_user(addr, val); break; case 8: default: - stq_user(T0 & ~7, T1); + stq_user(addr, val); break; } } @@ -1234,27 +1835,30 @@ { switch(size) { case 1: - stb_phys(T0, T1); + stb_phys(addr, val); break; case 2: - stw_phys(T0 & ~1, T1); + stw_phys(addr, val); break; case 4: - stl_phys(T0 & ~3, T1); + stl_phys(addr, val); break; case 8: default: - stq_phys(T0 & ~7, T1); + stq_phys(addr, val); break; } } return; + case 0x24: // Nucleus quad LDD 128 bit atomic + case 0x2c: // Nucleus quad LDD 128 bit atomic LE + // Only ldda allowed + raise_exception(TT_ILL_INSN); + return; case 0x04: // Nucleus case 0x0c: // Nucleus Little Endian (LE) case 0x11: // As if user secondary case 0x19: // As if user secondary LE - case 0x24: // Nucleus quad LDD 128 bit atomic - case 0x2c: // Nucleus quad LDD 128 bit atomic case 0x4a: // UPA config case 0x81: // Secondary case 0x89: // Secondary LE @@ -1265,11 +1869,12 @@ uint64_t oldreg; oldreg = env->lsu; - env->lsu = T1 & (DMMU_E | IMMU_E); + env->lsu = val & (DMMU_E | IMMU_E); // Mappings generated during D/I MMU disabled mode are // invalid in normal mode if (oldreg != env->lsu) { - DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", oldreg, env->lsu); + DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", + oldreg, env->lsu); #ifdef DEBUG_MMU dump_mmu(env); #endif @@ -1279,7 +1884,7 @@ } case 0x50: // I-MMU regs { - int reg = (T0 >> 3) & 0xf; + int reg = (addr >> 3) & 0xf; uint64_t oldreg; oldreg = env->immuregs[reg]; @@ -1293,17 +1898,18 @@ case 8: return; case 3: // SFSR - if ((T1 & 1) == 0) - T1 = 0; // Clear SFSR + if ((val & 1) == 0) + val = 0; // Clear SFSR break; case 5: // TSB access case 6: // Tag access default: break; } - env->immuregs[reg] = T1; + env->immuregs[reg] = val; if (oldreg != env->immuregs[reg]) { - DPRINTF_MMU("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->immuregs[reg]); + DPRINTF_MMU("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" + PRIx64 "\n", reg, oldreg, env->immuregs[reg]); } #ifdef DEBUG_MMU dump_mmu(env); @@ -1318,7 +1924,7 @@ for (i = 0; i < 64; i++) { if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0) { env->itlb_tag[i] = env->immuregs[6]; - env->itlb_tte[i] = T1; + env->itlb_tte[i] = val; return; } } @@ -1326,7 +1932,7 @@ for (i = 0; i < 64; i++) { if ((env->itlb_tte[i] & 0x40) == 0) { env->itlb_tag[i] = env->immuregs[6]; - env->itlb_tte[i] = T1; + env->itlb_tte[i] = val; return; } } @@ -1335,18 +1941,35 @@ } case 0x55: // I-MMU data access { - unsigned int i = (T0 >> 3) & 0x3f; + // TODO: auto demap + + unsigned int i = (addr >> 3) & 0x3f; env->itlb_tag[i] = env->immuregs[6]; - env->itlb_tte[i] = T1; + env->itlb_tte[i] = val; return; } case 0x57: // I-MMU demap - // XXX + { + unsigned int i; + + for (i = 0; i < 64; i++) { + if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) { + target_ulong mask = 0xffffffffffffe000ULL; + + mask <<= 3 * ((env->itlb_tte[i] >> 61) & 3); + if ((val & mask) == (env->itlb_tag[i] & mask)) { + env->itlb_tag[i] = 0; + env->itlb_tte[i] = 0; + } + return; + } + } + } return; case 0x58: // D-MMU regs { - int reg = (T0 >> 3) & 0xf; + int reg = (addr >> 3) & 0xf; uint64_t oldreg; oldreg = env->dmmuregs[reg]; @@ -1355,11 +1978,11 @@ case 4: return; case 3: // SFSR - if ((T1 & 1) == 0) { - T1 = 0; // Clear SFSR, Fault address + if ((val & 1) == 0) { + val = 0; // Clear SFSR, Fault address env->dmmuregs[4] = 0; } - env->dmmuregs[reg] = T1; + env->dmmuregs[reg] = val; break; case 1: // Primary context case 2: // Secondary context @@ -1370,9 +1993,10 @@ default: break; } - env->dmmuregs[reg] = T1; + env->dmmuregs[reg] = val; if (oldreg != env->dmmuregs[reg]) { - DPRINTF_MMU("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]); + DPRINTF_MMU("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" + PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]); } #ifdef DEBUG_MMU dump_mmu(env); @@ -1387,7 +2011,7 @@ for (i = 0; i < 64; i++) { if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0) { env->dtlb_tag[i] = env->dmmuregs[6]; - env->dtlb_tte[i] = T1; + env->dtlb_tte[i] = val; return; } } @@ -1395,7 +2019,7 @@ for (i = 0; i < 64; i++) { if ((env->dtlb_tte[i] & 0x40) == 0) { env->dtlb_tag[i] = env->dmmuregs[6]; - env->dtlb_tte[i] = T1; + env->dtlb_tte[i] = val; return; } } @@ -1404,16 +2028,46 @@ } case 0x5d: // D-MMU data access { - unsigned int i = (T0 >> 3) & 0x3f; + unsigned int i = (addr >> 3) & 0x3f; env->dtlb_tag[i] = env->dmmuregs[6]; - env->dtlb_tte[i] = T1; + env->dtlb_tte[i] = val; return; } case 0x5f: // D-MMU demap + { + unsigned int i; + + for (i = 0; i < 64; i++) { + if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) { + target_ulong mask = 0xffffffffffffe000ULL; + + mask <<= 3 * ((env->dtlb_tte[i] >> 61) & 3); + if ((val & mask) == (env->dtlb_tag[i] & mask)) { + env->dtlb_tag[i] = 0; + env->dtlb_tte[i] = 0; + } + return; + } + } + } + return; case 0x49: // Interrupt data receive // XXX return; + case 0x46: // D-cache data + case 0x47: // D-cache tag access + case 0x4b: // E-cache error enable + case 0x4c: // E-cache asynchronous fault status + case 0x4d: // E-cache asynchronous fault address + case 0x4e: // E-cache tag data + case 0x66: // I-cache instruction access + case 0x67: // I-cache tag access + case 0x6e: // I-cache predecode + case 0x6f: // I-cache LRU etc. + case 0x76: // E-cache tag + case 0x7e: // E-cache tag + return; case 0x51: // I-MMU 8k TSB pointer, RO case 0x52: // I-MMU 64k TSB pointer, RO case 0x56: // I-MMU tag read, RO @@ -1428,17 +2082,65 @@ case 0x8a: // Primary no-fault LE, RO case 0x8b: // Secondary no-fault LE, RO default: - do_unassigned_access(T0, 1, 0, 1); + do_unassigned_access(addr, 1, 0, 1, size); return; } } #endif /* CONFIG_USER_ONLY */ -void helper_ldf_asi(int asi, int size, int rd) +void helper_ldda_asi(target_ulong addr, int asi, int rd) +{ + if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) + || ((env->def->features & CPU_FEATURE_HYPV) + && asi >= 0x30 && asi < 0x80 + && !(env->hpstate & HS_PRIV))) + raise_exception(TT_PRIV_ACT); + + switch (asi) { + case 0x24: // Nucleus quad LDD 128 bit atomic + case 0x2c: // Nucleus quad LDD 128 bit atomic LE + helper_check_align(addr, 0xf); + if (rd == 0) { + env->gregs[1] = ldq_kernel(addr + 8); + if (asi == 0x2c) + bswap64s(&env->gregs[1]); + } else if (rd < 8) { + env->gregs[rd] = ldq_kernel(addr); + env->gregs[rd + 1] = ldq_kernel(addr + 8); + if (asi == 0x2c) { + bswap64s(&env->gregs[rd]); + bswap64s(&env->gregs[rd + 1]); + } + } else { + env->regwptr[rd] = ldq_kernel(addr); + env->regwptr[rd + 1] = ldq_kernel(addr + 8); + if (asi == 0x2c) { + bswap64s(&env->regwptr[rd]); + bswap64s(&env->regwptr[rd + 1]); + } + } + break; + default: + helper_check_align(addr, 0x3); + if (rd == 0) + env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0); + else if (rd < 8) { + env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0); + env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0); + } else { + env->regwptr[rd] = helper_ld_asi(addr, asi, 4, 0); + env->regwptr[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0); + } + break; + } +} + +void helper_ldf_asi(target_ulong addr, int asi, int size, int rd) { - target_ulong tmp_T0 = T0, tmp_T1 = T1; unsigned int i; + target_ulong val; + helper_check_align(addr, 3); switch (asi) { case 0xf0: // Block load primary case 0xf1: // Block load secondary @@ -1448,47 +2150,42 @@ raise_exception(TT_ILL_INSN); return; } - if (T0 & 0x3f) { - raise_exception(TT_UNALIGNED); - return; - } + helper_check_align(addr, 0x3f); for (i = 0; i < 16; i++) { - helper_ld_asi(asi & 0x8f, 4, 0); - *(uint32_t *)&env->fpr[rd++] = T1; - T0 += 4; + *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x8f, 4, + 0); + addr += 4; } - T0 = tmp_T0; - T1 = tmp_T1; return; default: break; } - helper_ld_asi(asi, size, 0); + val = helper_ld_asi(addr, asi, size, 0); switch(size) { default: case 4: - *((uint32_t *)&FT0) = T1; + *((uint32_t *)&env->fpr[rd]) = val; break; case 8: - *((int64_t *)&DT0) = T1; + *((int64_t *)&DT0) = val; break; -#if defined(CONFIG_USER_ONLY) case 16: // XXX break; -#endif } - T1 = tmp_T1; } -void helper_stf_asi(int asi, int size, int rd) +void helper_stf_asi(target_ulong addr, int asi, int size, int rd) { - target_ulong tmp_T0 = T0, tmp_T1 = T1; unsigned int i; + target_ulong val = 0; + helper_check_align(addr, 3); switch (asi) { + case 0xe0: // UA2007 Block commit store primary (cache flush) + case 0xe1: // UA2007 Block commit store secondary (cache flush) case 0xf0: // Block store primary case 0xf1: // Block store secondary case 0xf8: // Block store primary LE @@ -1497,17 +2194,12 @@ raise_exception(TT_ILL_INSN); return; } - if (T0 & 0x3f) { - raise_exception(TT_UNALIGNED); - return; - } + helper_check_align(addr, 0x3f); for (i = 0; i < 16; i++) { - T1 = *(uint32_t *)&env->fpr[rd++]; - helper_st_asi(asi & 0x8f, 4); - T0 += 4; + val = *(uint32_t *)&env->fpr[rd++]; + helper_st_asi(addr, val, asi & 0x8f, 4); + addr += 4; } - T0 = tmp_T0; - T1 = tmp_T1; return; default: @@ -1517,25 +2209,45 @@ switch(size) { default: case 4: - T1 = *((uint32_t *)&FT0); + val = *((uint32_t *)&env->fpr[rd]); break; case 8: - T1 = *((int64_t *)&DT0); + val = *((int64_t *)&DT0); break; -#if defined(CONFIG_USER_ONLY) case 16: // XXX break; -#endif } - helper_st_asi(asi, size); - T1 = tmp_T1; + helper_st_asi(addr, val, asi, size); } +target_ulong helper_cas_asi(target_ulong addr, target_ulong val1, + target_ulong val2, uint32_t asi) +{ + target_ulong ret; + + val2 &= 0xffffffffUL; + ret = helper_ld_asi(addr, asi, 4, 0); + ret &= 0xffffffffUL; + if (val2 == ret) + helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4); + return ret; +} + +target_ulong helper_casx_asi(target_ulong addr, target_ulong val1, + target_ulong val2, uint32_t asi) +{ + target_ulong ret; + + ret = helper_ld_asi(addr, asi, 8, 0); + if (val2 == ret) + helper_st_asi(addr, val1, asi, 8); + return ret; +} #endif /* TARGET_SPARC64 */ #ifndef TARGET_SPARC64 -void helper_rett() +void helper_rett(void) { unsigned int cwp; @@ -1543,7 +2255,7 @@ raise_exception(TT_ILL_INSN); env->psret = 1; - cwp = (env->cwp + 1) & (NWINDOWS - 1); + cwp = cpu_cwp_inc(env, env->cwp + 1) ; if (env->wim & (1 << cwp)) { raise_exception(TT_WIN_UNF); } @@ -1552,9 +2264,176 @@ } #endif -void helper_ldfsr(void) +target_ulong helper_udiv(target_ulong a, target_ulong b) +{ + uint64_t x0; + uint32_t x1; + + x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32); + x1 = b; + + if (x1 == 0) { + raise_exception(TT_DIV_ZERO); + } + + x0 = x0 / x1; + if (x0 > 0xffffffff) { + env->cc_src2 = 1; + return 0xffffffff; + } else { + env->cc_src2 = 0; + return x0; + } +} + +target_ulong helper_sdiv(target_ulong a, target_ulong b) +{ + int64_t x0; + int32_t x1; + + x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32); + x1 = b; + + if (x1 == 0) { + raise_exception(TT_DIV_ZERO); + } + + x0 = x0 / x1; + if ((int32_t) x0 != x0) { + env->cc_src2 = 1; + return x0 < 0? 0x80000000: 0x7fffffff; + } else { + env->cc_src2 = 0; + return x0; + } +} + +void helper_stdf(target_ulong addr, int mem_idx) +{ + helper_check_align(addr, 7); +#if !defined(CONFIG_USER_ONLY) + switch (mem_idx) { + case 0: + stfq_user(addr, DT0); + break; + case 1: + stfq_kernel(addr, DT0); + break; +#ifdef TARGET_SPARC64 + case 2: + stfq_hypv(addr, DT0); + break; +#endif + default: + break; + } +#else + address_mask(env, &addr); + stfq_raw(addr, DT0); +#endif +} + +void helper_lddf(target_ulong addr, int mem_idx) +{ + helper_check_align(addr, 7); +#if !defined(CONFIG_USER_ONLY) + switch (mem_idx) { + case 0: + DT0 = ldfq_user(addr); + break; + case 1: + DT0 = ldfq_kernel(addr); + break; +#ifdef TARGET_SPARC64 + case 2: + DT0 = ldfq_hypv(addr); + break; +#endif + default: + break; + } +#else + address_mask(env, &addr); + DT0 = ldfq_raw(addr); +#endif +} + +void helper_ldqf(target_ulong addr, int mem_idx) +{ + // XXX add 128 bit load + CPU_QuadU u; + + helper_check_align(addr, 7); +#if !defined(CONFIG_USER_ONLY) + switch (mem_idx) { + case 0: + u.ll.upper = ldq_user(addr); + u.ll.lower = ldq_user(addr + 8); + QT0 = u.q; + break; + case 1: + u.ll.upper = ldq_kernel(addr); + u.ll.lower = ldq_kernel(addr + 8); + QT0 = u.q; + break; +#ifdef TARGET_SPARC64 + case 2: + u.ll.upper = ldq_hypv(addr); + u.ll.lower = ldq_hypv(addr + 8); + QT0 = u.q; + break; +#endif + default: + break; + } +#else + address_mask(env, &addr); + u.ll.upper = ldq_raw(addr); + u.ll.lower = ldq_raw((addr + 8) & 0xffffffffULL); + QT0 = u.q; +#endif +} + +void helper_stqf(target_ulong addr, int mem_idx) +{ + // XXX add 128 bit store + CPU_QuadU u; + + helper_check_align(addr, 7); +#if !defined(CONFIG_USER_ONLY) + switch (mem_idx) { + case 0: + u.q = QT0; + stq_user(addr, u.ll.upper); + stq_user(addr + 8, u.ll.lower); + break; + case 1: + u.q = QT0; + stq_kernel(addr, u.ll.upper); + stq_kernel(addr + 8, u.ll.lower); + break; +#ifdef TARGET_SPARC64 + case 2: + u.q = QT0; + stq_hypv(addr, u.ll.upper); + stq_hypv(addr + 8, u.ll.lower); + break; +#endif + default: + break; + } +#else + u.q = QT0; + address_mask(env, &addr); + stq_raw(addr, u.ll.upper); + stq_raw((addr + 8) & 0xffffffffULL, u.ll.lower); +#endif +} + +static inline void set_fsr(void) { int rnd_mode; + switch (env->fsr & FSR_RD_MASK) { case FSR_RD_NEAREST: rnd_mode = float_round_nearest_even; @@ -1573,31 +2452,189 @@ set_float_rounding_mode(rnd_mode, &env->fp_status); } -void helper_debug() +void helper_ldfsr(uint32_t new_fsr) +{ + env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK); + set_fsr(); +} + +#ifdef TARGET_SPARC64 +void helper_ldxfsr(uint64_t new_fsr) +{ + env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK); + set_fsr(); +} +#endif + +void helper_debug(void) { env->exception_index = EXCP_DEBUG; cpu_loop_exit(); } #ifndef TARGET_SPARC64 -void do_wrpsr() +/* XXX: use another pointer for %iN registers to avoid slow wrapping + handling ? */ +void helper_save(void) { - if ((T0 & PSR_CWP) >= NWINDOWS) + uint32_t cwp; + + cwp = cpu_cwp_dec(env, env->cwp - 1); + if (env->wim & (1 << cwp)) { + raise_exception(TT_WIN_OVF); + } + set_cwp(cwp); +} + +void helper_restore(void) +{ + uint32_t cwp; + + cwp = cpu_cwp_inc(env, env->cwp + 1); + if (env->wim & (1 << cwp)) { + raise_exception(TT_WIN_UNF); + } + set_cwp(cwp); +} + +void helper_wrpsr(target_ulong new_psr) +{ + if ((new_psr & PSR_CWP) >= env->nwindows) raise_exception(TT_ILL_INSN); else - PUT_PSR(env, T0); + PUT_PSR(env, new_psr); } -void do_rdpsr() +target_ulong helper_rdpsr(void) { - T0 = GET_PSR(env); + return GET_PSR(env); } #else +/* XXX: use another pointer for %iN registers to avoid slow wrapping + handling ? */ +void helper_save(void) +{ + uint32_t cwp; + + cwp = cpu_cwp_dec(env, env->cwp - 1); + if (env->cansave == 0) { + raise_exception(TT_SPILL | (env->otherwin != 0 ? + (TT_WOTHER | ((env->wstate & 0x38) >> 1)): + ((env->wstate & 0x7) << 2))); + } else { + if (env->cleanwin - env->canrestore == 0) { + // XXX Clean windows without trap + raise_exception(TT_CLRWIN); + } else { + env->cansave--; + env->canrestore++; + set_cwp(cwp); + } + } +} + +void helper_restore(void) +{ + uint32_t cwp; + + cwp = cpu_cwp_inc(env, env->cwp + 1); + if (env->canrestore == 0) { + raise_exception(TT_FILL | (env->otherwin != 0 ? + (TT_WOTHER | ((env->wstate & 0x38) >> 1)): + ((env->wstate & 0x7) << 2))); + } else { + env->cansave++; + env->canrestore--; + set_cwp(cwp); + } +} + +void helper_flushw(void) +{ + if (env->cansave != env->nwindows - 2) { + raise_exception(TT_SPILL | (env->otherwin != 0 ? + (TT_WOTHER | ((env->wstate & 0x38) >> 1)): + ((env->wstate & 0x7) << 2))); + } +} + +void helper_saved(void) +{ + env->cansave++; + if (env->otherwin == 0) + env->canrestore--; + else + env->otherwin--; +} + +void helper_restored(void) +{ + env->canrestore++; + if (env->cleanwin < env->nwindows - 1) + env->cleanwin++; + if (env->otherwin == 0) + env->cansave--; + else + env->otherwin--; +} + +target_ulong helper_rdccr(void) +{ + return GET_CCR(env); +} + +void helper_wrccr(target_ulong new_ccr) +{ + PUT_CCR(env, new_ccr); +} + +// CWP handling is reversed in V9, but we still use the V8 register +// order. +target_ulong helper_rdcwp(void) +{ + return GET_CWP64(env); +} + +void helper_wrcwp(target_ulong new_cwp) +{ + PUT_CWP64(env, new_cwp); +} + +// This function uses non-native bit order +#define GET_FIELD(X, FROM, TO) \ + ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1)) -void do_popc() +// This function uses the order in the manuals, i.e. bit 0 is 2^0 +#define GET_FIELD_SP(X, FROM, TO) \ + GET_FIELD(X, 63 - (TO), 63 - (FROM)) + +target_ulong helper_array8(target_ulong pixel_addr, target_ulong cubesize) +{ + return (GET_FIELD_SP(pixel_addr, 60, 63) << (17 + 2 * cubesize)) | + (GET_FIELD_SP(pixel_addr, 39, 39 + cubesize - 1) << (17 + cubesize)) | + (GET_FIELD_SP(pixel_addr, 17 + cubesize - 1, 17) << 17) | + (GET_FIELD_SP(pixel_addr, 56, 59) << 13) | + (GET_FIELD_SP(pixel_addr, 35, 38) << 9) | + (GET_FIELD_SP(pixel_addr, 13, 16) << 5) | + (((pixel_addr >> 55) & 1) << 4) | + (GET_FIELD_SP(pixel_addr, 33, 34) << 2) | + GET_FIELD_SP(pixel_addr, 11, 12); +} + +target_ulong helper_alignaddr(target_ulong addr, target_ulong offset) +{ + uint64_t tmp; + + tmp = addr + offset; + env->gsr &= ~7ULL; + env->gsr |= tmp & 7ULL; + return tmp & ~7ULL; +} + +target_ulong helper_popc(target_ulong val) { - T0 = ctpop64(T1); + return ctpop64(val); } static inline uint64_t *get_gregset(uint64_t pstate) @@ -1632,69 +2669,61 @@ env->pstate = new_pstate; } -void do_wrpstate(void) +void helper_wrpstate(target_ulong new_state) { - change_pstate(T0 & 0xf3f); + if (!(env->def->features & CPU_FEATURE_GL)) + change_pstate(new_state & 0xf3f); } -void do_done(void) +void helper_done(void) { + env->pc = env->tsptr->tpc; + env->npc = env->tsptr->tnpc + 4; + PUT_CCR(env, env->tsptr->tstate >> 32); + env->asi = (env->tsptr->tstate >> 24) & 0xff; + change_pstate((env->tsptr->tstate >> 8) & 0xf3f); + PUT_CWP64(env, env->tsptr->tstate & 0xff); env->tl--; - env->pc = env->tnpc[env->tl]; - env->npc = env->tnpc[env->tl] + 4; - PUT_CCR(env, env->tstate[env->tl] >> 32); - env->asi = (env->tstate[env->tl] >> 24) & 0xff; - change_pstate((env->tstate[env->tl] >> 8) & 0xf3f); - PUT_CWP64(env, env->tstate[env->tl] & 0xff); + env->tsptr = &env->ts[env->tl & MAXTL_MASK]; } -void do_retry(void) +void helper_retry(void) { + env->pc = env->tsptr->tpc; + env->npc = env->tsptr->tnpc; + PUT_CCR(env, env->tsptr->tstate >> 32); + env->asi = (env->tsptr->tstate >> 24) & 0xff; + change_pstate((env->tsptr->tstate >> 8) & 0xf3f); + PUT_CWP64(env, env->tsptr->tstate & 0xff); env->tl--; - env->pc = env->tpc[env->tl]; - env->npc = env->tnpc[env->tl]; - PUT_CCR(env, env->tstate[env->tl] >> 32); - env->asi = (env->tstate[env->tl] >> 24) & 0xff; - change_pstate((env->tstate[env->tl] >> 8) & 0xf3f); - PUT_CWP64(env, env->tstate[env->tl] & 0xff); + env->tsptr = &env->ts[env->tl & MAXTL_MASK]; } -#endif -void set_cwp(int new_cwp) +void helper_set_softint(uint64_t value) { - /* put the modified wrap registers at their proper location */ - if (env->cwp == (NWINDOWS - 1)) - memcpy32(env->regbase, env->regbase + NWINDOWS * 16); - env->cwp = new_cwp; - /* put the wrap registers at their temporary location */ - if (new_cwp == (NWINDOWS - 1)) - memcpy32(env->regbase + NWINDOWS * 16, env->regbase); - env->regwptr = env->regbase + (new_cwp * 16); - REGWPTR = env->regwptr; + env->softint |= (uint32_t)value; } -void cpu_set_cwp(CPUState *env1, int new_cwp) +void helper_clear_softint(uint64_t value) { - CPUState *saved_env; -#ifdef reg_REGWPTR - target_ulong *saved_regwptr; -#endif + env->softint &= (uint32_t)~value; +} - saved_env = env; -#ifdef reg_REGWPTR - saved_regwptr = REGWPTR; -#endif - env = env1; - set_cwp(new_cwp); - env = saved_env; -#ifdef reg_REGWPTR - REGWPTR = saved_regwptr; +void helper_write_softint(uint64_t value) +{ + env->softint = (uint32_t)value; +} #endif + +void helper_flush(target_ulong addr) +{ + addr &= ~7; + tb_invalidate_page_range(addr, addr + 8); } #ifdef TARGET_SPARC64 #ifdef DEBUG_PCALL -static const char * const excp_names[0x50] = { +static const char * const excp_names[0x80] = { [TT_TFAULT] = "Instruction Access Fault", [TT_TMISS] = "Instruction Access MMU Miss", [TT_CODE_ACCESS] = "Instruction Access Error", @@ -1729,14 +2758,16 @@ }; #endif -void do_interrupt(int intno) +void do_interrupt(CPUState *env) { + int intno = env->exception_index; + #ifdef DEBUG_PCALL if (loglevel & CPU_LOG_INT) { static int count; const char *name; - if (intno < 0 || intno >= 0x180 || (intno > 0x4f && intno < 0x80)) + if (intno < 0 || intno >= 0x180) name = "Unknown"; else if (intno >= 0x100) name = "Trap Instruction"; @@ -1773,33 +2804,51 @@ } #endif #if !defined(CONFIG_USER_ONLY) - if (env->tl == MAXTL) { - cpu_abort(env, "Trap 0x%04x while trap level is MAXTL, Error state", env->exception_index); + if (env->tl >= env->maxtl) { + cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d)," + " Error state", env->exception_index, env->tl, env->maxtl); return; } #endif - env->tstate[env->tl] = ((uint64_t)GET_CCR(env) << 32) | ((env->asi & 0xff) << 24) | - ((env->pstate & 0xf3f) << 8) | GET_CWP64(env); - env->tpc[env->tl] = env->pc; - env->tnpc[env->tl] = env->npc; - env->tt[env->tl] = intno; - change_pstate(PS_PEF | PS_PRIV | PS_AG); - - if (intno == TT_CLRWIN) - set_cwp((env->cwp - 1) & (NWINDOWS - 1)); - else if ((intno & 0x1c0) == TT_SPILL) - set_cwp((env->cwp - env->cansave - 2) & (NWINDOWS - 1)); - else if ((intno & 0x1c0) == TT_FILL) - set_cwp((env->cwp + 1) & (NWINDOWS - 1)); - env->tbr &= ~0x7fffULL; - env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5); - if (env->tl < MAXTL - 1) { + if (env->tl < env->maxtl - 1) { env->tl++; } else { env->pstate |= PS_RED; - if (env->tl != MAXTL) + if (env->tl < env->maxtl) env->tl++; } + env->tsptr = &env->ts[env->tl & MAXTL_MASK]; + env->tsptr->tstate = ((uint64_t)GET_CCR(env) << 32) | + ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) | + GET_CWP64(env); + env->tsptr->tpc = env->pc; + env->tsptr->tnpc = env->npc; + env->tsptr->tt = intno; + if (!(env->def->features & CPU_FEATURE_GL)) { + switch (intno) { + case TT_IVEC: + change_pstate(PS_PEF | PS_PRIV | PS_IG); + break; + case TT_TFAULT: + case TT_TMISS: + case TT_DFAULT: + case TT_DMISS: + case TT_DPROT: + change_pstate(PS_PEF | PS_PRIV | PS_MG); + break; + default: + change_pstate(PS_PEF | PS_PRIV | PS_AG); + break; + } + } + if (intno == TT_CLRWIN) + cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1)); + else if ((intno & 0x1c0) == TT_SPILL) + cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2)); + else if ((intno & 0x1c0) == TT_FILL) + cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1)); + env->tbr &= ~0x7fffULL; + env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5); env->pc = env->tbr; env->npc = env->pc + 4; env->exception_index = 0; @@ -1840,9 +2889,9 @@ }; #endif -void do_interrupt(int intno) +void do_interrupt(CPUState *env) { - int cwp; + int cwp, intno = env->exception_index; #ifdef DEBUG_PCALL if (loglevel & CPU_LOG_INT) { @@ -1882,13 +2931,14 @@ #endif #if !defined(CONFIG_USER_ONLY) if (env->psret == 0) { - cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index); + cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state", + env->exception_index); return; } #endif env->psret = 0; - cwp = (env->cwp - 1) & (NWINDOWS - 1); - set_cwp(cwp); + cwp = cpu_cwp_dec(env, env->cwp - 1); + cpu_set_cwp(env, cwp); env->regwptr[9] = env->pc; env->regwptr[10] = env->npc; env->psrps = env->psrs; @@ -1907,11 +2957,6 @@ #define MMUSUFFIX _mmu #define ALIGNED_ONLY -#ifdef __s390__ -# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) -#else -# define GETPC() (__builtin_return_address(0)) -#endif #define SHIFT 0 #include "softmmu_template.h" @@ -1925,12 +2970,32 @@ #define SHIFT 3 #include "softmmu_template.h" +/* XXX: make it generic ? */ +static void cpu_restore_state2(void *retaddr) +{ + TranslationBlock *tb; + unsigned long pc; + + if (retaddr) { + /* now we have a real cpu fault */ + pc = (unsigned long)retaddr; + tb = tb_find_pc(pc); + if (tb) { + /* the PC is inside the translated code. It means that we have + a virtual CPU fault */ + cpu_restore_state(tb, env, pc, (void *)(long)env->cond); + } + } +} + static void do_unaligned_access(target_ulong addr, int is_write, int is_user, void *retaddr) { #ifdef DEBUG_UNALIGNED - printf("Unaligned access to 0x%x from 0x%x\n", addr, env->pc); + printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx + "\n", addr, env->pc); #endif + cpu_restore_state2(retaddr); raise_exception(TT_UNALIGNED); } @@ -1940,9 +3005,7 @@ /* XXX: fix it to restore all registers */ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) { - TranslationBlock *tb; int ret; - unsigned long pc; CPUState *saved_env; /* XXX: hack to restore env in all cases, even if not called from @@ -1952,16 +3015,7 @@ ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); if (ret) { - if (retaddr) { - /* now we have a real cpu fault */ - pc = (unsigned long)retaddr; - tb = tb_find_pc(pc); - if (tb) { - /* the PC is inside the translated code. It means that we have - a virtual CPU fault */ - cpu_restore_state(tb, env, pc, (void *)T2); - } - } + cpu_restore_state2(retaddr); cpu_loop_exit(); } env = saved_env; @@ -1971,7 +3025,7 @@ #ifndef TARGET_SPARC64 void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, - int is_asi) + int is_asi, int size) { CPUState *saved_env; @@ -1981,14 +3035,15 @@ env = cpu_single_env; #ifdef DEBUG_UNASSIGNED if (is_asi) - printf("Unassigned mem %s access to " TARGET_FMT_plx " asi 0x%02x from " - TARGET_FMT_lx "\n", - is_exec ? "exec" : is_write ? "write" : "read", addr, is_asi, - env->pc); + printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx + " asi 0x%02x from " TARGET_FMT_lx "\n", + is_exec ? "exec" : is_write ? "write" : "read", size, + size == 1 ? "" : "s", addr, is_asi, env->pc); else - printf("Unassigned mem %s access to " TARGET_FMT_plx " from " - TARGET_FMT_lx "\n", - is_exec ? "exec" : is_write ? "write" : "read", addr, env->pc); + printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx + " from " TARGET_FMT_lx "\n", + is_exec ? "exec" : is_write ? "write" : "read", size, + size == 1 ? "" : "s", addr, env->pc); #endif if (env->mmuregs[3]) /* Fault status register */ env->mmuregs[3] = 1; /* overflow (not read before another fault) */ @@ -2012,7 +3067,7 @@ } #else void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, - int is_asi) + int is_asi, int size) { #ifdef DEBUG_UNASSIGNED CPUState *saved_env; @@ -2021,8 +3076,8 @@ generated code */ saved_env = env; env = cpu_single_env; - printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx "\n", - addr, env->pc); + printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx + "\n", addr, env->pc); env = saved_env; #endif if (is_exec) @@ -2032,3 +3087,27 @@ } #endif +#ifdef TARGET_SPARC64 +void helper_tick_set_count(void *opaque, uint64_t count) +{ +#if !defined(CONFIG_USER_ONLY) + cpu_tick_set_count(opaque, count); +#endif +} + +uint64_t helper_tick_get_count(void *opaque) +{ +#if !defined(CONFIG_USER_ONLY) + return cpu_tick_get_count(opaque); +#else + return 0; +#endif +} + +void helper_tick_set_limit(void *opaque, uint64_t limit) +{ +#if !defined(CONFIG_USER_ONLY) + cpu_tick_set_limit(opaque, limit); +#endif +} +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sparc/op_mem.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sparc/op_mem.h --- qemu-0.9.1/target-sparc/op_mem.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-sparc/op_mem.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,124 +0,0 @@ -#ifdef TARGET_ABI32 -#define ADDR(x) ((x) & 0xffffffff) -#else -#define ADDR(x) (x) -#endif - -/*** Integer load ***/ -#define SPARC_LD_OP(name, qp) \ -void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ -{ \ - T1 = (target_ulong)glue(qp, MEMSUFFIX)(ADDR(T0)); \ -} - -#define SPARC_LD_OP_S(name, qp) \ - void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ - { \ - T1 = (target_long)glue(qp, MEMSUFFIX)(ADDR(T0)); \ - } - -#define SPARC_ST_OP(name, op) \ -void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ -{ \ - glue(op, MEMSUFFIX)(ADDR(T0), T1); \ -} - -SPARC_LD_OP(ld, ldl); -SPARC_LD_OP(ldub, ldub); -SPARC_LD_OP(lduh, lduw); -SPARC_LD_OP_S(ldsb, ldsb); -SPARC_LD_OP_S(ldsh, ldsw); - -/*** Integer store ***/ -SPARC_ST_OP(st, stl); -SPARC_ST_OP(stb, stb); -SPARC_ST_OP(sth, stw); - -void OPPROTO glue(op_std, MEMSUFFIX)(void) -{ - uint64_t tmp = ((uint64_t)T1 << 32) | (uint64_t)(T2 & 0xffffffff); - - glue(stq, MEMSUFFIX)(ADDR(T0), tmp); -} - -void OPPROTO glue(op_ldstub, MEMSUFFIX)(void) -{ - T1 = glue(ldub, MEMSUFFIX)(ADDR(T0)); - glue(stb, MEMSUFFIX)(ADDR(T0), 0xff); /* XXX: Should be Atomically */ -} - -void OPPROTO glue(op_swap, MEMSUFFIX)(void) -{ - target_ulong tmp = glue(ldl, MEMSUFFIX)(ADDR(T0)); - glue(stl, MEMSUFFIX)(ADDR(T0), T1); /* XXX: Should be Atomically */ - T1 = tmp; -} - -void OPPROTO glue(op_ldd, MEMSUFFIX)(void) -{ - uint64_t tmp; - - tmp = glue(ldq, MEMSUFFIX)(ADDR(T0)); - T1 = tmp >> 32; - T0 = tmp & 0xffffffff; -} - -/*** Floating-point store ***/ -void OPPROTO glue(op_stf, MEMSUFFIX) (void) -{ - glue(stfl, MEMSUFFIX)(ADDR(T0), FT0); -} - -void OPPROTO glue(op_stdf, MEMSUFFIX) (void) -{ - glue(stfq, MEMSUFFIX)(ADDR(T0), DT0); -} - -/*** Floating-point load ***/ -void OPPROTO glue(op_ldf, MEMSUFFIX) (void) -{ - FT0 = glue(ldfl, MEMSUFFIX)(ADDR(T0)); -} - -void OPPROTO glue(op_lddf, MEMSUFFIX) (void) -{ - DT0 = glue(ldfq, MEMSUFFIX)(ADDR(T0)); -} - -#if defined(CONFIG_USER_ONLY) -void OPPROTO glue(op_ldqf, MEMSUFFIX) (void) -{ - // XXX add 128 bit load - CPU_QuadU u; - - u.ll.upper = glue(ldq, MEMSUFFIX)(ADDR(T0)); - u.ll.lower = glue(ldq, MEMSUFFIX)(ADDR(T0 + 8)); - QT0 = u.q; -} - -void OPPROTO glue(op_stqf, MEMSUFFIX) (void) -{ - // XXX add 128 bit store - CPU_QuadU u; - - u.q = QT0; - glue(stq, MEMSUFFIX)(ADDR(T0), u.ll.upper); - glue(stq, MEMSUFFIX)(ADDR(T0 + 8), u.ll.lower); -} -#endif - -#ifdef TARGET_SPARC64 -void OPPROTO glue(op_lduw, MEMSUFFIX)(void) -{ - T1 = (uint64_t)(glue(ldl, MEMSUFFIX)(ADDR(T0)) & 0xffffffff); -} - -void OPPROTO glue(op_ldsw, MEMSUFFIX)(void) -{ - T1 = (int64_t)(glue(ldl, MEMSUFFIX)(ADDR(T0)) & 0xffffffff); -} - -SPARC_LD_OP(ldx, ldq); -SPARC_ST_OP(stx, stq); -#endif -#undef MEMSUFFIX diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sparc/op_template.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sparc/op_template.h --- qemu-0.9.1/target-sparc/op_template.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-sparc/op_template.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,48 +0,0 @@ -/* - * SPARC micro operations (templates for various register related - * operations) - * - * Copyright (c) 2003 Fabrice Bellard - * - * 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 - */ - -void OPPROTO glue(op_movl_T0_, REGNAME)(void) -{ - T0 = REG; -} - -void OPPROTO glue(op_movl_T1_, REGNAME)(void) -{ - T1 = REG; -} - -void OPPROTO glue(op_movl_T2_, REGNAME)(void) -{ - T2 = REG; -} - -void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void) -{ - REG = T0; -} - -void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void) -{ - REG = T1; -} - -#undef REG -#undef REGNAME diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sparc/TODO /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sparc/TODO --- qemu-0.9.1/target-sparc/TODO 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/target-sparc/TODO 2008-09-10 20:57:35.000000000 +0100 @@ -0,0 +1,89 @@ +TODO-list: + +CPU common: +- Unimplemented features/bugs: + - Delay slot handling may fail sometimes (branch end of page, delay + slot next page) + - Atomical instructions + - CPU features should match real CPUs (also ASI selection) +- Optimizations/improvements: + - Condition code/branch handling like x86, also for FPU? + - Remove remaining explicit alignment checks + - Global register for regwptr, so that windowed registers can be + accessed directly + - Improve Sparc32plus addressing + - NPC/PC static optimisations (use JUMP_TB when possible)? (Is this + obsolete?) + - Synthetic instructions + - MMU model dependant on CPU model + - Select ASI helper at translation time (on V9 only if known) + - KQemu/KVM support for VM only + - Hardware breakpoint/watchpoint support + - Cache emulation mode + - Reverse-endian pages + - Faster FPU emulation + - Busy loop detection + +Sparc32 CPUs: +- Unimplemented features/bugs: + - Sun4/Sun4c MMUs + - Some V8 ASIs + +Sparc64 CPUs: +- Unimplemented features/bugs: + - Interrupt handling + - Secondary address space, other MMU functions + - Many V9/UA2005/UA2007 ASIs + - Rest of V9 instructions, missing VIS instructions + - IG/MG/AG vs. UA2007 globals + - Full hypervisor support + - SMP/CMT + - Sun4v CPUs + +Sun4: +- To be added + +Sun4c: +- A lot of unimplemented features +- Maybe split from Sun4m + +Sun4m: +- Unimplemented features/bugs: + - Hardware devices do not match real boards + - Floppy does not work + - CS4231: merge with cs4231a, add DMA + - Add cg6, bwtwo + - Arbitrary resolution support + - PCI for MicroSparc-IIe + - JavaStation machines + - SBus slot probing, FCode ROM support + - SMP probing support + - Interrupt routing does not match real HW + - SuSE 7.3 keyboard sometimes unresponsive + - Gentoo 2004.1 SMP does not work + - SS600MP ledma -> lebuffer + - Type 5 keyboard + - Less fixed hardware choices + - DBRI audio (Am7930) + - BPP parallel + - Diagnostic switch + - ESP PIO mode + +Sun4d: +- A lot of unimplemented features: + - SBI + - IO-unit +- Maybe split from Sun4m + +Sun4u: +- Unimplemented features/bugs: + - Interrupt controller + - PCI/IOMMU support (Simba, JIO, Tomatillo, Psycho, Schizo, Safari...) + - SMP + - Happy Meal Ethernet, flash, I2C, GPIO + - A lot of real machine types + +Sun4v: +- A lot of unimplemented features + - A lot of real machine types + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/target-sparc/translate.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/target-sparc/translate.c --- qemu-0.9.1/target-sparc/translate.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/target-sparc/translate.c 2008-11-09 19:52:36.000000000 +0000 @@ -19,14 +19,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* - TODO-list: - - Rest of V9 instructions, VIS instructions - NPC/PC static optimisations (use JUMP_TB when possible) - Optimize synthetic instructions -*/ - #include #include #include @@ -36,6 +28,8 @@ #include "cpu.h" #include "exec-all.h" #include "disas.h" +#include "helper.h" +#include "tcg-op.h" #define DEBUG_DISAS @@ -43,6 +37,29 @@ #define JUMP_PC 2 /* dynamic pc value which takes only two values according to jump_pc[T2] */ +/* global register indexes */ +static TCGv cpu_env, cpu_regwptr; +static TCGv cpu_cc_src, cpu_cc_src2, cpu_cc_dst; +static TCGv cpu_psr, cpu_fsr, cpu_pc, cpu_npc, cpu_gregs[8]; +static TCGv cpu_y; +#ifndef CONFIG_USER_ONLY +static TCGv cpu_tbr; +#endif +static TCGv cpu_cond, cpu_src1, cpu_src2, cpu_dst, cpu_addr, cpu_val; +#ifdef TARGET_SPARC64 +static TCGv cpu_xcc, cpu_asi, cpu_fprs, cpu_gsr; +static TCGv cpu_tick_cmpr, cpu_stick_cmpr, cpu_hstick_cmpr; +static TCGv cpu_hintp, cpu_htba, cpu_hver, cpu_ssr, cpu_ver, cpu_softint; +#else +static TCGv cpu_wim; +#endif +/* local register indexes (only used inside old micro ops) */ +static TCGv cpu_tmp0, cpu_tmp32, cpu_tmp64; +/* Floating point registers */ +static TCGv cpu_fpr[TARGET_FPREGS]; + +#include "gen-icount.h" + typedef struct DisasContext { target_ulong pc; /* current Program Counter: integer or DYNAMIC_PC */ target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */ @@ -50,35 +67,11 @@ int is_br; int mem_idx; int fpu_enabled; + int address_mask_32bit; struct TranslationBlock *tb; + sparc_def_t *def; } DisasContext; -typedef struct sparc_def_t sparc_def_t; - -struct sparc_def_t { - const unsigned char *name; - target_ulong iu_version; - uint32_t fpu_version; - uint32_t mmu_version; - uint32_t mmu_bm; -}; - -static const sparc_def_t *cpu_sparc_find_by_name(const unsigned char *name); - -static uint16_t *gen_opc_ptr; -static uint32_t *gen_opparam_ptr; -extern FILE *logfile; -extern int loglevel; - -enum { -#define DEF(s,n,copy_size) INDEX_op_ ## s, -#include "opc.h" -#undef DEF - NB_OPS -}; - -#include "gen-op.h" - // This function uses non-native bit order #define GET_FIELD(X, FROM, TO) \ ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) @@ -91,18 +84,17 @@ #define GET_FIELD_SPs(x,a,b) sign_extend (GET_FIELD_SP(x,a,b), ((b) - (a) + 1)) #ifdef TARGET_SPARC64 +#define FFPREG(r) (r) #define DFPREG(r) (((r & 1) << 5) | (r & 0x1e)) #define QFPREG(r) (((r & 1) << 5) | (r & 0x1c)) #else +#define FFPREG(r) (r) #define DFPREG(r) (r & 0x1e) #define QFPREG(r) (r & 0x1c) #endif -#ifdef USE_DIRECT_JUMP -#define TBPARAM(x) -#else -#define TBPARAM(x) (long)(x) -#endif +#define UA2005_HTRAP_MASK 0xff +#define V8_TRAP_MASK 0x7f static int sign_extend(int x, int len) { @@ -112,252 +104,66 @@ #define IS_IMM (insn & (1<<13)) -static void disas_sparc_insn(DisasContext * dc); - -static GenOpFunc * const gen_op_movl_TN_reg[2][32] = { - { - gen_op_movl_g0_T0, - gen_op_movl_g1_T0, - gen_op_movl_g2_T0, - gen_op_movl_g3_T0, - gen_op_movl_g4_T0, - gen_op_movl_g5_T0, - gen_op_movl_g6_T0, - gen_op_movl_g7_T0, - gen_op_movl_o0_T0, - gen_op_movl_o1_T0, - gen_op_movl_o2_T0, - gen_op_movl_o3_T0, - gen_op_movl_o4_T0, - gen_op_movl_o5_T0, - gen_op_movl_o6_T0, - gen_op_movl_o7_T0, - gen_op_movl_l0_T0, - gen_op_movl_l1_T0, - gen_op_movl_l2_T0, - gen_op_movl_l3_T0, - gen_op_movl_l4_T0, - gen_op_movl_l5_T0, - gen_op_movl_l6_T0, - gen_op_movl_l7_T0, - gen_op_movl_i0_T0, - gen_op_movl_i1_T0, - gen_op_movl_i2_T0, - gen_op_movl_i3_T0, - gen_op_movl_i4_T0, - gen_op_movl_i5_T0, - gen_op_movl_i6_T0, - gen_op_movl_i7_T0, - }, - { - gen_op_movl_g0_T1, - gen_op_movl_g1_T1, - gen_op_movl_g2_T1, - gen_op_movl_g3_T1, - gen_op_movl_g4_T1, - gen_op_movl_g5_T1, - gen_op_movl_g6_T1, - gen_op_movl_g7_T1, - gen_op_movl_o0_T1, - gen_op_movl_o1_T1, - gen_op_movl_o2_T1, - gen_op_movl_o3_T1, - gen_op_movl_o4_T1, - gen_op_movl_o5_T1, - gen_op_movl_o6_T1, - gen_op_movl_o7_T1, - gen_op_movl_l0_T1, - gen_op_movl_l1_T1, - gen_op_movl_l2_T1, - gen_op_movl_l3_T1, - gen_op_movl_l4_T1, - gen_op_movl_l5_T1, - gen_op_movl_l6_T1, - gen_op_movl_l7_T1, - gen_op_movl_i0_T1, - gen_op_movl_i1_T1, - gen_op_movl_i2_T1, - gen_op_movl_i3_T1, - gen_op_movl_i4_T1, - gen_op_movl_i5_T1, - gen_op_movl_i6_T1, - gen_op_movl_i7_T1, - } -}; - -static GenOpFunc * const gen_op_movl_reg_TN[3][32] = { - { - gen_op_movl_T0_g0, - gen_op_movl_T0_g1, - gen_op_movl_T0_g2, - gen_op_movl_T0_g3, - gen_op_movl_T0_g4, - gen_op_movl_T0_g5, - gen_op_movl_T0_g6, - gen_op_movl_T0_g7, - gen_op_movl_T0_o0, - gen_op_movl_T0_o1, - gen_op_movl_T0_o2, - gen_op_movl_T0_o3, - gen_op_movl_T0_o4, - gen_op_movl_T0_o5, - gen_op_movl_T0_o6, - gen_op_movl_T0_o7, - gen_op_movl_T0_l0, - gen_op_movl_T0_l1, - gen_op_movl_T0_l2, - gen_op_movl_T0_l3, - gen_op_movl_T0_l4, - gen_op_movl_T0_l5, - gen_op_movl_T0_l6, - gen_op_movl_T0_l7, - gen_op_movl_T0_i0, - gen_op_movl_T0_i1, - gen_op_movl_T0_i2, - gen_op_movl_T0_i3, - gen_op_movl_T0_i4, - gen_op_movl_T0_i5, - gen_op_movl_T0_i6, - gen_op_movl_T0_i7, - }, - { - gen_op_movl_T1_g0, - gen_op_movl_T1_g1, - gen_op_movl_T1_g2, - gen_op_movl_T1_g3, - gen_op_movl_T1_g4, - gen_op_movl_T1_g5, - gen_op_movl_T1_g6, - gen_op_movl_T1_g7, - gen_op_movl_T1_o0, - gen_op_movl_T1_o1, - gen_op_movl_T1_o2, - gen_op_movl_T1_o3, - gen_op_movl_T1_o4, - gen_op_movl_T1_o5, - gen_op_movl_T1_o6, - gen_op_movl_T1_o7, - gen_op_movl_T1_l0, - gen_op_movl_T1_l1, - gen_op_movl_T1_l2, - gen_op_movl_T1_l3, - gen_op_movl_T1_l4, - gen_op_movl_T1_l5, - gen_op_movl_T1_l6, - gen_op_movl_T1_l7, - gen_op_movl_T1_i0, - gen_op_movl_T1_i1, - gen_op_movl_T1_i2, - gen_op_movl_T1_i3, - gen_op_movl_T1_i4, - gen_op_movl_T1_i5, - gen_op_movl_T1_i6, - gen_op_movl_T1_i7, - }, - { - gen_op_movl_T2_g0, - gen_op_movl_T2_g1, - gen_op_movl_T2_g2, - gen_op_movl_T2_g3, - gen_op_movl_T2_g4, - gen_op_movl_T2_g5, - gen_op_movl_T2_g6, - gen_op_movl_T2_g7, - gen_op_movl_T2_o0, - gen_op_movl_T2_o1, - gen_op_movl_T2_o2, - gen_op_movl_T2_o3, - gen_op_movl_T2_o4, - gen_op_movl_T2_o5, - gen_op_movl_T2_o6, - gen_op_movl_T2_o7, - gen_op_movl_T2_l0, - gen_op_movl_T2_l1, - gen_op_movl_T2_l2, - gen_op_movl_T2_l3, - gen_op_movl_T2_l4, - gen_op_movl_T2_l5, - gen_op_movl_T2_l6, - gen_op_movl_T2_l7, - gen_op_movl_T2_i0, - gen_op_movl_T2_i1, - gen_op_movl_T2_i2, - gen_op_movl_T2_i3, - gen_op_movl_T2_i4, - gen_op_movl_T2_i5, - gen_op_movl_T2_i6, - gen_op_movl_T2_i7, - } -}; - -static GenOpFunc1 * const gen_op_movl_TN_im[3] = { - gen_op_movl_T0_im, - gen_op_movl_T1_im, - gen_op_movl_T2_im -}; +/* floating point registers moves */ +static void gen_op_load_fpr_DT0(unsigned int src) +{ + tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, dt0) + + offsetof(CPU_DoubleU, l.upper)); + tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, dt0) + + offsetof(CPU_DoubleU, l.lower)); +} -// Sign extending version -static GenOpFunc1 * const gen_op_movl_TN_sim[3] = { - gen_op_movl_T0_sim, - gen_op_movl_T1_sim, - gen_op_movl_T2_sim -}; +static void gen_op_load_fpr_DT1(unsigned int src) +{ + tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, dt1) + + offsetof(CPU_DoubleU, l.upper)); + tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, dt1) + + offsetof(CPU_DoubleU, l.lower)); +} -#ifdef TARGET_SPARC64 -#define GEN32(func, NAME) \ -static GenOpFunc * const NAME ## _table [64] = { \ -NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ -NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ -NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ -NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ -NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ -NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ -NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ -NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ -NAME ## 32, 0, NAME ## 34, 0, NAME ## 36, 0, NAME ## 38, 0, \ -NAME ## 40, 0, NAME ## 42, 0, NAME ## 44, 0, NAME ## 46, 0, \ -NAME ## 48, 0, NAME ## 50, 0, NAME ## 52, 0, NAME ## 54, 0, \ -NAME ## 56, 0, NAME ## 58, 0, NAME ## 60, 0, NAME ## 62, 0, \ -}; \ -static inline void func(int n) \ -{ \ - NAME ## _table[n](); \ +static void gen_op_store_DT0_fpr(unsigned int dst) +{ + tcg_gen_ld_i32(cpu_fpr[dst], cpu_env, offsetof(CPUSPARCState, dt0) + + offsetof(CPU_DoubleU, l.upper)); + tcg_gen_ld_i32(cpu_fpr[dst + 1], cpu_env, offsetof(CPUSPARCState, dt0) + + offsetof(CPU_DoubleU, l.lower)); } -#else -#define GEN32(func, NAME) \ -static GenOpFunc *const NAME ## _table [32] = { \ -NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ -NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ -NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ -NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ -NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ -NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ -NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ -NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ -}; \ -static inline void func(int n) \ -{ \ - NAME ## _table[n](); \ + +static void gen_op_load_fpr_QT0(unsigned int src) +{ + tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, qt0) + + offsetof(CPU_QuadU, l.upmost)); + tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, qt0) + + offsetof(CPU_QuadU, l.upper)); + tcg_gen_st_i32(cpu_fpr[src + 2], cpu_env, offsetof(CPUSPARCState, qt0) + + offsetof(CPU_QuadU, l.lower)); + tcg_gen_st_i32(cpu_fpr[src + 3], cpu_env, offsetof(CPUSPARCState, qt0) + + offsetof(CPU_QuadU, l.lowest)); } -#endif -/* floating point registers moves */ -GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fprf); -GEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fprf); -GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fprf); -GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fprf); - -GEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fprf); -GEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fprf); -GEN32(gen_op_store_DT0_fpr, gen_op_store_DT0_fpr_fprf); -GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); +static void gen_op_load_fpr_QT1(unsigned int src) +{ + tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, qt1) + + offsetof(CPU_QuadU, l.upmost)); + tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, qt1) + + offsetof(CPU_QuadU, l.upper)); + tcg_gen_st_i32(cpu_fpr[src + 2], cpu_env, offsetof(CPUSPARCState, qt1) + + offsetof(CPU_QuadU, l.lower)); + tcg_gen_st_i32(cpu_fpr[src + 3], cpu_env, offsetof(CPUSPARCState, qt1) + + offsetof(CPU_QuadU, l.lowest)); +} -#if defined(CONFIG_USER_ONLY) -GEN32(gen_op_load_fpr_QT0, gen_op_load_fpr_QT0_fprf); -GEN32(gen_op_load_fpr_QT1, gen_op_load_fpr_QT1_fprf); -GEN32(gen_op_store_QT0_fpr, gen_op_store_QT0_fpr_fprf); -GEN32(gen_op_store_QT1_fpr, gen_op_store_QT1_fpr_fprf); -#endif +static void gen_op_store_QT0_fpr(unsigned int dst) +{ + tcg_gen_ld_i32(cpu_fpr[dst], cpu_env, offsetof(CPUSPARCState, qt0) + + offsetof(CPU_QuadU, l.upmost)); + tcg_gen_ld_i32(cpu_fpr[dst + 1], cpu_env, offsetof(CPUSPARCState, qt0) + + offsetof(CPU_QuadU, l.upper)); + tcg_gen_ld_i32(cpu_fpr[dst + 2], cpu_env, offsetof(CPUSPARCState, qt0) + + offsetof(CPU_QuadU, l.lower)); + tcg_gen_ld_i32(cpu_fpr[dst + 3], cpu_env, offsetof(CPUSPARCState, qt0) + + offsetof(CPU_QuadU, l.lowest)); +} /* moves */ #ifdef CONFIG_USER_ONLY @@ -365,597 +171,1204 @@ #ifdef TARGET_SPARC64 #define hypervisor(dc) 0 #endif -#define gen_op_ldst(name) gen_op_##name##_raw() #else #define supervisor(dc) (dc->mem_idx >= 1) #ifdef TARGET_SPARC64 #define hypervisor(dc) (dc->mem_idx == 2) -#define OP_LD_TABLE(width) \ - static GenOpFunc * const gen_op_##width[] = { \ - &gen_op_##width##_user, \ - &gen_op_##width##_kernel, \ - &gen_op_##width##_hypv, \ - }; #else -#define OP_LD_TABLE(width) \ - static GenOpFunc * const gen_op_##width[] = { \ - &gen_op_##width##_user, \ - &gen_op_##width##_kernel, \ - }; #endif -#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() #endif -#ifndef CONFIG_USER_ONLY -OP_LD_TABLE(ld); -OP_LD_TABLE(st); -OP_LD_TABLE(ldub); -OP_LD_TABLE(lduh); -OP_LD_TABLE(ldsb); -OP_LD_TABLE(ldsh); -OP_LD_TABLE(stb); -OP_LD_TABLE(sth); -OP_LD_TABLE(std); -OP_LD_TABLE(ldstub); -OP_LD_TABLE(swap); -OP_LD_TABLE(ldd); -OP_LD_TABLE(stf); -OP_LD_TABLE(stdf); -OP_LD_TABLE(ldf); -OP_LD_TABLE(lddf); - -#ifdef TARGET_SPARC64 -OP_LD_TABLE(lduw); -OP_LD_TABLE(ldsw); -OP_LD_TABLE(ldx); -OP_LD_TABLE(stx); +#ifdef TARGET_SPARC64 +#ifndef TARGET_ABI32 +#define AM_CHECK(dc) ((dc)->address_mask_32bit) +#else +#define AM_CHECK(dc) (1) #endif #endif -/* asi moves */ -#ifdef TARGET_SPARC64 -static inline void gen_ld_asi(int insn, int size, int sign) +static inline void gen_address_mask(DisasContext *dc, TCGv addr) { - int asi, offset; - - if (IS_IMM) { - offset = GET_FIELD(insn, 25, 31); - gen_op_ld_asi_reg(offset, size, sign); - } else { - asi = GET_FIELD(insn, 19, 26); - gen_op_ld_asi(asi, size, sign); - } +#ifdef TARGET_SPARC64 + if (AM_CHECK(dc)) + tcg_gen_andi_tl(addr, addr, 0xffffffffULL); +#endif } -static inline void gen_st_asi(int insn, int size) +static inline void gen_movl_reg_TN(int reg, TCGv tn) { - int asi, offset; - - if (IS_IMM) { - offset = GET_FIELD(insn, 25, 31); - gen_op_st_asi_reg(offset, size); - } else { - asi = GET_FIELD(insn, 19, 26); - gen_op_st_asi(asi, size); + if (reg == 0) + tcg_gen_movi_tl(tn, 0); + else if (reg < 8) + tcg_gen_mov_tl(tn, cpu_gregs[reg]); + else { + tcg_gen_ld_tl(tn, cpu_regwptr, (reg - 8) * sizeof(target_ulong)); } } -static inline void gen_ldf_asi(int insn, int size, int rd) +static inline void gen_movl_TN_reg(int reg, TCGv tn) { - int asi, offset; - - if (IS_IMM) { - offset = GET_FIELD(insn, 25, 31); - gen_op_ldf_asi_reg(offset, size, rd); - } else { - asi = GET_FIELD(insn, 19, 26); - gen_op_ldf_asi(asi, size, rd); + if (reg == 0) + return; + else if (reg < 8) + tcg_gen_mov_tl(cpu_gregs[reg], tn); + else { + tcg_gen_st_tl(tn, cpu_regwptr, (reg - 8) * sizeof(target_ulong)); } } -static inline void gen_stf_asi(int insn, int size, int rd) +static inline void gen_goto_tb(DisasContext *s, int tb_num, + target_ulong pc, target_ulong npc) { - int asi, offset; + TranslationBlock *tb; - if (IS_IMM) { - offset = GET_FIELD(insn, 25, 31); - gen_op_stf_asi_reg(offset, size, rd); + tb = s->tb; + if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) && + (npc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK)) { + /* jump to same page: we can use a direct jump */ + tcg_gen_goto_tb(tb_num); + tcg_gen_movi_tl(cpu_pc, pc); + tcg_gen_movi_tl(cpu_npc, npc); + tcg_gen_exit_tb((long)tb + tb_num); } else { - asi = GET_FIELD(insn, 19, 26); - gen_op_stf_asi(asi, size, rd); + /* jump to another page: currently not optimized */ + tcg_gen_movi_tl(cpu_pc, pc); + tcg_gen_movi_tl(cpu_npc, npc); + tcg_gen_exit_tb(0); } } -static inline void gen_swap_asi(int insn) +// XXX suboptimal +static inline void gen_mov_reg_N(TCGv reg, TCGv src) { - int asi, offset; - - if (IS_IMM) { - offset = GET_FIELD(insn, 25, 31); - gen_op_swap_asi_reg(offset); - } else { - asi = GET_FIELD(insn, 19, 26); - gen_op_swap_asi(asi); - } + tcg_gen_extu_i32_tl(reg, src); + tcg_gen_shri_tl(reg, reg, PSR_NEG_SHIFT); + tcg_gen_andi_tl(reg, reg, 0x1); } -static inline void gen_ldstub_asi(int insn) +static inline void gen_mov_reg_Z(TCGv reg, TCGv src) { - int asi, offset; - - if (IS_IMM) { - offset = GET_FIELD(insn, 25, 31); - gen_op_ldstub_asi_reg(offset); - } else { - asi = GET_FIELD(insn, 19, 26); - gen_op_ldstub_asi(asi); - } + tcg_gen_extu_i32_tl(reg, src); + tcg_gen_shri_tl(reg, reg, PSR_ZERO_SHIFT); + tcg_gen_andi_tl(reg, reg, 0x1); } -static inline void gen_ldda_asi(int insn) +static inline void gen_mov_reg_V(TCGv reg, TCGv src) { - int asi, offset; - - if (IS_IMM) { - offset = GET_FIELD(insn, 25, 31); - gen_op_ldda_asi_reg(offset); - } else { - asi = GET_FIELD(insn, 19, 26); - gen_op_ldda_asi(asi); - } + tcg_gen_extu_i32_tl(reg, src); + tcg_gen_shri_tl(reg, reg, PSR_OVF_SHIFT); + tcg_gen_andi_tl(reg, reg, 0x1); } -static inline void gen_stda_asi(int insn) +static inline void gen_mov_reg_C(TCGv reg, TCGv src) { - int asi, offset; - - if (IS_IMM) { - offset = GET_FIELD(insn, 25, 31); - gen_op_stda_asi_reg(offset); - } else { - asi = GET_FIELD(insn, 19, 26); - gen_op_stda_asi(asi); - } + tcg_gen_extu_i32_tl(reg, src); + tcg_gen_shri_tl(reg, reg, PSR_CARRY_SHIFT); + tcg_gen_andi_tl(reg, reg, 0x1); } -static inline void gen_cas_asi(int insn) +static inline void gen_cc_clear_icc(void) { - int asi, offset; - - if (IS_IMM) { - offset = GET_FIELD(insn, 25, 31); - gen_op_cas_asi_reg(offset); - } else { - asi = GET_FIELD(insn, 19, 26); - gen_op_cas_asi(asi); - } + tcg_gen_movi_i32(cpu_psr, 0); } -static inline void gen_casx_asi(int insn) +#ifdef TARGET_SPARC64 +static inline void gen_cc_clear_xcc(void) { - int asi, offset; - - if (IS_IMM) { - offset = GET_FIELD(insn, 25, 31); - gen_op_casx_asi_reg(offset); - } else { - asi = GET_FIELD(insn, 19, 26); - gen_op_casx_asi(asi); - } + tcg_gen_movi_i32(cpu_xcc, 0); } +#endif -#elif !defined(CONFIG_USER_ONLY) - -static inline void gen_ld_asi(int insn, int size, int sign) +/* old op: + if (!T0) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; +*/ +static inline void gen_cc_NZ_icc(TCGv dst) { - int asi; + TCGv r_temp; + int l1, l2; - asi = GET_FIELD(insn, 19, 26); - gen_op_ld_asi(asi, size, sign); + l1 = gen_new_label(); + l2 = gen_new_label(); + r_temp = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_andi_tl(r_temp, dst, 0xffffffffULL); + tcg_gen_brcondi_tl(TCG_COND_NE, r_temp, 0, l1); + tcg_gen_ori_i32(cpu_psr, cpu_psr, PSR_ZERO); + gen_set_label(l1); + tcg_gen_ext32s_tl(r_temp, dst); + tcg_gen_brcondi_tl(TCG_COND_GE, r_temp, 0, l2); + tcg_gen_ori_i32(cpu_psr, cpu_psr, PSR_NEG); + gen_set_label(l2); + tcg_temp_free(r_temp); } -static inline void gen_st_asi(int insn, int size) +#ifdef TARGET_SPARC64 +static inline void gen_cc_NZ_xcc(TCGv dst) { - int asi; + int l1, l2; - asi = GET_FIELD(insn, 19, 26); - gen_op_st_asi(asi, size); + l1 = gen_new_label(); + l2 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_NE, dst, 0, l1); + tcg_gen_ori_i32(cpu_xcc, cpu_xcc, PSR_ZERO); + gen_set_label(l1); + tcg_gen_brcondi_tl(TCG_COND_GE, dst, 0, l2); + tcg_gen_ori_i32(cpu_xcc, cpu_xcc, PSR_NEG); + gen_set_label(l2); } +#endif -static inline void gen_ldstub_asi(int insn) +/* old op: + if (T0 < src1) + env->psr |= PSR_CARRY; +*/ +static inline void gen_cc_C_add_icc(TCGv dst, TCGv src1) { - int asi; + TCGv r_temp1, r_temp2; + int l1; - asi = GET_FIELD(insn, 19, 26); - gen_op_ldstub_asi(asi); + l1 = gen_new_label(); + r_temp1 = tcg_temp_new(TCG_TYPE_TL); + r_temp2 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_andi_tl(r_temp1, dst, 0xffffffffULL); + tcg_gen_andi_tl(r_temp2, src1, 0xffffffffULL); + tcg_gen_brcond_tl(TCG_COND_GEU, r_temp1, r_temp2, l1); + tcg_gen_ori_i32(cpu_psr, cpu_psr, PSR_CARRY); + gen_set_label(l1); + tcg_temp_free(r_temp1); + tcg_temp_free(r_temp2); } -static inline void gen_swap_asi(int insn) +#ifdef TARGET_SPARC64 +static inline void gen_cc_C_add_xcc(TCGv dst, TCGv src1) { - int asi; + int l1; - asi = GET_FIELD(insn, 19, 26); - gen_op_swap_asi(asi); + l1 = gen_new_label(); + tcg_gen_brcond_tl(TCG_COND_GEU, dst, src1, l1); + tcg_gen_ori_i32(cpu_xcc, cpu_xcc, PSR_CARRY); + gen_set_label(l1); } +#endif -static inline void gen_ldda_asi(int insn) +/* old op: + if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) + env->psr |= PSR_OVF; +*/ +static inline void gen_cc_V_add_icc(TCGv dst, TCGv src1, TCGv src2) { - int asi; + TCGv r_temp; - asi = GET_FIELD(insn, 19, 26); - gen_op_ld_asi(asi, 8, 0); + r_temp = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_xor_tl(r_temp, src1, src2); + tcg_gen_not_tl(r_temp, r_temp); + tcg_gen_xor_tl(cpu_tmp0, src1, dst); + tcg_gen_and_tl(r_temp, r_temp, cpu_tmp0); + tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31)); + tcg_gen_shri_tl(r_temp, r_temp, 31 - PSR_OVF_SHIFT); + tcg_gen_trunc_tl_i32(cpu_tmp32, r_temp); + tcg_temp_free(r_temp); + tcg_gen_or_i32(cpu_psr, cpu_psr, cpu_tmp32); } -static inline void gen_stda_asi(int insn) +#ifdef TARGET_SPARC64 +static inline void gen_cc_V_add_xcc(TCGv dst, TCGv src1, TCGv src2) { - int asi; + TCGv r_temp; - asi = GET_FIELD(insn, 19, 26); - gen_op_st_asi(asi, 8); + r_temp = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_xor_tl(r_temp, src1, src2); + tcg_gen_not_tl(r_temp, r_temp); + tcg_gen_xor_tl(cpu_tmp0, src1, dst); + tcg_gen_and_tl(r_temp, r_temp, cpu_tmp0); + tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 63)); + tcg_gen_shri_tl(r_temp, r_temp, 63 - PSR_OVF_SHIFT); + tcg_gen_trunc_tl_i32(cpu_tmp32, r_temp); + tcg_temp_free(r_temp); + tcg_gen_or_i32(cpu_xcc, cpu_xcc, cpu_tmp32); } #endif -static inline void gen_movl_imm_TN(int reg, uint32_t imm) +static inline void gen_add_tv(TCGv dst, TCGv src1, TCGv src2) { - gen_op_movl_TN_im[reg](imm); + TCGv r_temp, r_const; + int l1; + + l1 = gen_new_label(); + + r_temp = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_xor_tl(r_temp, src1, src2); + tcg_gen_not_tl(r_temp, r_temp); + tcg_gen_xor_tl(cpu_tmp0, src1, dst); + tcg_gen_and_tl(r_temp, r_temp, cpu_tmp0); + tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31)); + tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1); + r_const = tcg_const_i32(TT_TOVF); + tcg_gen_helper_0_1(raise_exception, r_const); + tcg_temp_free(r_const); + gen_set_label(l1); + tcg_temp_free(r_temp); } -static inline void gen_movl_imm_T1(uint32_t val) +static inline void gen_cc_V_tag(TCGv src1, TCGv src2) { - gen_movl_imm_TN(1, val); + int l1; + + l1 = gen_new_label(); + tcg_gen_or_tl(cpu_tmp0, src1, src2); + tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0x3); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, l1); + tcg_gen_ori_i32(cpu_psr, cpu_psr, PSR_OVF); + gen_set_label(l1); } -static inline void gen_movl_imm_T0(uint32_t val) +static inline void gen_tag_tv(TCGv src1, TCGv src2) { - gen_movl_imm_TN(0, val); + int l1; + TCGv r_const; + + l1 = gen_new_label(); + tcg_gen_or_tl(cpu_tmp0, src1, src2); + tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0x3); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, l1); + r_const = tcg_const_i32(TT_TOVF); + tcg_gen_helper_0_1(raise_exception, r_const); + tcg_temp_free(r_const); + gen_set_label(l1); } -static inline void gen_movl_simm_TN(int reg, int32_t imm) +static inline void gen_op_add_cc(TCGv dst, TCGv src1, TCGv src2) { - gen_op_movl_TN_sim[reg](imm); + tcg_gen_mov_tl(cpu_cc_src, src1); + tcg_gen_mov_tl(cpu_cc_src2, src2); + tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); + gen_cc_clear_icc(); + gen_cc_NZ_icc(cpu_cc_dst); + gen_cc_C_add_icc(cpu_cc_dst, cpu_cc_src); + gen_cc_V_add_icc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); +#ifdef TARGET_SPARC64 + gen_cc_clear_xcc(); + gen_cc_NZ_xcc(cpu_cc_dst); + gen_cc_C_add_xcc(cpu_cc_dst, cpu_cc_src); + gen_cc_V_add_xcc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); +#endif + tcg_gen_mov_tl(dst, cpu_cc_dst); } -static inline void gen_movl_simm_T1(int32_t val) +static inline void gen_op_addx_cc(TCGv dst, TCGv src1, TCGv src2) { - gen_movl_simm_TN(1, val); + tcg_gen_mov_tl(cpu_cc_src, src1); + tcg_gen_mov_tl(cpu_cc_src2, src2); + gen_mov_reg_C(cpu_tmp0, cpu_psr); + tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_tmp0); + gen_cc_clear_icc(); + gen_cc_C_add_icc(cpu_cc_dst, cpu_cc_src); +#ifdef TARGET_SPARC64 + gen_cc_clear_xcc(); + gen_cc_C_add_xcc(cpu_cc_dst, cpu_cc_src); +#endif + tcg_gen_add_tl(cpu_cc_dst, cpu_cc_dst, cpu_cc_src2); + gen_cc_NZ_icc(cpu_cc_dst); + gen_cc_C_add_icc(cpu_cc_dst, cpu_cc_src); + gen_cc_V_add_icc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); +#ifdef TARGET_SPARC64 + gen_cc_NZ_xcc(cpu_cc_dst); + gen_cc_C_add_xcc(cpu_cc_dst, cpu_cc_src); + gen_cc_V_add_xcc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); +#endif + tcg_gen_mov_tl(dst, cpu_cc_dst); } -static inline void gen_movl_simm_T0(int32_t val) +static inline void gen_op_tadd_cc(TCGv dst, TCGv src1, TCGv src2) { - gen_movl_simm_TN(0, val); + tcg_gen_mov_tl(cpu_cc_src, src1); + tcg_gen_mov_tl(cpu_cc_src2, src2); + tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); + gen_cc_clear_icc(); + gen_cc_NZ_icc(cpu_cc_dst); + gen_cc_C_add_icc(cpu_cc_dst, cpu_cc_src); + gen_cc_V_add_icc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); + gen_cc_V_tag(cpu_cc_src, cpu_cc_src2); +#ifdef TARGET_SPARC64 + gen_cc_clear_xcc(); + gen_cc_NZ_xcc(cpu_cc_dst); + gen_cc_C_add_xcc(cpu_cc_dst, cpu_cc_src); + gen_cc_V_add_xcc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); +#endif + tcg_gen_mov_tl(dst, cpu_cc_dst); } -static inline void gen_movl_reg_TN(int reg, int t) +static inline void gen_op_tadd_ccTV(TCGv dst, TCGv src1, TCGv src2) { - if (reg) - gen_op_movl_reg_TN[t][reg] (); - else - gen_movl_imm_TN(t, 0); + tcg_gen_mov_tl(cpu_cc_src, src1); + tcg_gen_mov_tl(cpu_cc_src2, src2); + gen_tag_tv(cpu_cc_src, cpu_cc_src2); + tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); + gen_add_tv(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); + gen_cc_clear_icc(); + gen_cc_NZ_icc(cpu_cc_dst); + gen_cc_C_add_icc(cpu_cc_dst, cpu_cc_src); +#ifdef TARGET_SPARC64 + gen_cc_clear_xcc(); + gen_cc_NZ_xcc(cpu_cc_dst); + gen_cc_C_add_xcc(cpu_cc_dst, cpu_cc_src); + gen_cc_V_add_xcc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); +#endif + tcg_gen_mov_tl(dst, cpu_cc_dst); } -static inline void gen_movl_reg_T0(int reg) +/* old op: + if (src1 < T1) + env->psr |= PSR_CARRY; +*/ +static inline void gen_cc_C_sub_icc(TCGv src1, TCGv src2) { - gen_movl_reg_TN(reg, 0); + TCGv r_temp1, r_temp2; + int l1; + + l1 = gen_new_label(); + r_temp1 = tcg_temp_new(TCG_TYPE_TL); + r_temp2 = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_andi_tl(r_temp1, src1, 0xffffffffULL); + tcg_gen_andi_tl(r_temp2, src2, 0xffffffffULL); + tcg_gen_brcond_tl(TCG_COND_GEU, r_temp1, r_temp2, l1); + tcg_gen_ori_i32(cpu_psr, cpu_psr, PSR_CARRY); + gen_set_label(l1); + tcg_temp_free(r_temp1); + tcg_temp_free(r_temp2); } -static inline void gen_movl_reg_T1(int reg) +#ifdef TARGET_SPARC64 +static inline void gen_cc_C_sub_xcc(TCGv src1, TCGv src2) { - gen_movl_reg_TN(reg, 1); + int l1; + + l1 = gen_new_label(); + tcg_gen_brcond_tl(TCG_COND_GEU, src1, src2, l1); + tcg_gen_ori_i32(cpu_xcc, cpu_xcc, PSR_CARRY); + gen_set_label(l1); } +#endif -static inline void gen_movl_reg_T2(int reg) +/* old op: + if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) + env->psr |= PSR_OVF; +*/ +static inline void gen_cc_V_sub_icc(TCGv dst, TCGv src1, TCGv src2) { - gen_movl_reg_TN(reg, 2); + TCGv r_temp; + + r_temp = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_xor_tl(r_temp, src1, src2); + tcg_gen_xor_tl(cpu_tmp0, src1, dst); + tcg_gen_and_tl(r_temp, r_temp, cpu_tmp0); + tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31)); + tcg_gen_shri_tl(r_temp, r_temp, 31 - PSR_OVF_SHIFT); + tcg_gen_trunc_tl_i32(cpu_tmp32, r_temp); + tcg_gen_or_i32(cpu_psr, cpu_psr, cpu_tmp32); + tcg_temp_free(r_temp); } -static inline void gen_movl_TN_reg(int reg, int t) +#ifdef TARGET_SPARC64 +static inline void gen_cc_V_sub_xcc(TCGv dst, TCGv src1, TCGv src2) { - if (reg) - gen_op_movl_TN_reg[t][reg] (); + TCGv r_temp; + + r_temp = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_xor_tl(r_temp, src1, src2); + tcg_gen_xor_tl(cpu_tmp0, src1, dst); + tcg_gen_and_tl(r_temp, r_temp, cpu_tmp0); + tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 63)); + tcg_gen_shri_tl(r_temp, r_temp, 63 - PSR_OVF_SHIFT); + tcg_gen_trunc_tl_i32(cpu_tmp32, r_temp); + tcg_gen_or_i32(cpu_xcc, cpu_xcc, cpu_tmp32); + tcg_temp_free(r_temp); } +#endif -static inline void gen_movl_T0_reg(int reg) +static inline void gen_sub_tv(TCGv dst, TCGv src1, TCGv src2) { - gen_movl_TN_reg(reg, 0); + TCGv r_temp, r_const; + int l1; + + l1 = gen_new_label(); + + r_temp = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_xor_tl(r_temp, src1, src2); + tcg_gen_xor_tl(cpu_tmp0, src1, dst); + tcg_gen_and_tl(r_temp, r_temp, cpu_tmp0); + tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31)); + tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1); + r_const = tcg_const_i32(TT_TOVF); + tcg_gen_helper_0_1(raise_exception, r_const); + tcg_temp_free(r_const); + gen_set_label(l1); + tcg_temp_free(r_temp); } -static inline void gen_movl_T1_reg(int reg) +static inline void gen_op_sub_cc(TCGv dst, TCGv src1, TCGv src2) { - gen_movl_TN_reg(reg, 1); + tcg_gen_mov_tl(cpu_cc_src, src1); + tcg_gen_mov_tl(cpu_cc_src2, src2); + tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); + gen_cc_clear_icc(); + gen_cc_NZ_icc(cpu_cc_dst); + gen_cc_C_sub_icc(cpu_cc_src, cpu_cc_src2); + gen_cc_V_sub_icc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); +#ifdef TARGET_SPARC64 + gen_cc_clear_xcc(); + gen_cc_NZ_xcc(cpu_cc_dst); + gen_cc_C_sub_xcc(cpu_cc_src, cpu_cc_src2); + gen_cc_V_sub_xcc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); +#endif + tcg_gen_mov_tl(dst, cpu_cc_dst); } -static inline void gen_jmp_im(target_ulong pc) +static inline void gen_op_subx_cc(TCGv dst, TCGv src1, TCGv src2) { + tcg_gen_mov_tl(cpu_cc_src, src1); + tcg_gen_mov_tl(cpu_cc_src2, src2); + gen_mov_reg_C(cpu_tmp0, cpu_psr); + tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_tmp0); + gen_cc_clear_icc(); + gen_cc_C_sub_icc(cpu_cc_dst, cpu_cc_src); #ifdef TARGET_SPARC64 - if (pc == (uint32_t)pc) { - gen_op_jmp_im(pc); - } else { - gen_op_jmp_im64(pc >> 32, pc); - } -#else - gen_op_jmp_im(pc); + gen_cc_clear_xcc(); + gen_cc_C_sub_xcc(cpu_cc_dst, cpu_cc_src); #endif + tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_dst, cpu_cc_src2); + gen_cc_NZ_icc(cpu_cc_dst); + gen_cc_C_sub_icc(cpu_cc_dst, cpu_cc_src); + gen_cc_V_sub_icc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); +#ifdef TARGET_SPARC64 + gen_cc_NZ_xcc(cpu_cc_dst); + gen_cc_C_sub_xcc(cpu_cc_dst, cpu_cc_src); + gen_cc_V_sub_xcc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); +#endif + tcg_gen_mov_tl(dst, cpu_cc_dst); } -static inline void gen_movl_npc_im(target_ulong npc) +static inline void gen_op_tsub_cc(TCGv dst, TCGv src1, TCGv src2) { + tcg_gen_mov_tl(cpu_cc_src, src1); + tcg_gen_mov_tl(cpu_cc_src2, src2); + tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); + gen_cc_clear_icc(); + gen_cc_NZ_icc(cpu_cc_dst); + gen_cc_C_sub_icc(cpu_cc_src, cpu_cc_src2); + gen_cc_V_sub_icc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); + gen_cc_V_tag(cpu_cc_src, cpu_cc_src2); #ifdef TARGET_SPARC64 - if (npc == (uint32_t)npc) { - gen_op_movl_npc_im(npc); - } else { - gen_op_movq_npc_im64(npc >> 32, npc); - } -#else - gen_op_movl_npc_im(npc); + gen_cc_clear_xcc(); + gen_cc_NZ_xcc(cpu_cc_dst); + gen_cc_C_sub_xcc(cpu_cc_src, cpu_cc_src2); + gen_cc_V_sub_xcc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); #endif + tcg_gen_mov_tl(dst, cpu_cc_dst); } -static inline void gen_goto_tb(DisasContext *s, int tb_num, - target_ulong pc, target_ulong npc) +static inline void gen_op_tsub_ccTV(TCGv dst, TCGv src1, TCGv src2) { - TranslationBlock *tb; - - tb = s->tb; - if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) && - (npc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK)) { - /* jump to same page: we can use a direct jump */ - if (tb_num == 0) - gen_op_goto_tb0(TBPARAM(tb)); - else - gen_op_goto_tb1(TBPARAM(tb)); - gen_jmp_im(pc); - gen_movl_npc_im(npc); - gen_op_movl_T0_im((long)tb + tb_num); - gen_op_exit_tb(); - } else { - /* jump to another page: currently not optimized */ - gen_jmp_im(pc); - gen_movl_npc_im(npc); - gen_op_movl_T0_0(); - gen_op_exit_tb(); - } + tcg_gen_mov_tl(cpu_cc_src, src1); + tcg_gen_mov_tl(cpu_cc_src2, src2); + gen_tag_tv(cpu_cc_src, cpu_cc_src2); + tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); + gen_sub_tv(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); + gen_cc_clear_icc(); + gen_cc_NZ_icc(cpu_cc_dst); + gen_cc_C_sub_icc(cpu_cc_src, cpu_cc_src2); +#ifdef TARGET_SPARC64 + gen_cc_clear_xcc(); + gen_cc_NZ_xcc(cpu_cc_dst); + gen_cc_C_sub_xcc(cpu_cc_src, cpu_cc_src2); + gen_cc_V_sub_xcc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); +#endif + tcg_gen_mov_tl(dst, cpu_cc_dst); } -static inline void gen_branch2(DisasContext *dc, target_ulong pc1, - target_ulong pc2) +static inline void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2) { + TCGv r_temp; int l1; l1 = gen_new_label(); + r_temp = tcg_temp_new(TCG_TYPE_TL); - gen_op_jz_T2_label(l1); + /* old op: + if (!(env->y & 1)) + T1 = 0; + */ + tcg_gen_andi_tl(cpu_cc_src, src1, 0xffffffff); + tcg_gen_andi_tl(r_temp, cpu_y, 0x1); + tcg_gen_andi_tl(cpu_cc_src2, src2, 0xffffffff); + tcg_gen_brcondi_tl(TCG_COND_NE, r_temp, 0, l1); + tcg_gen_movi_tl(cpu_cc_src2, 0); + gen_set_label(l1); - gen_goto_tb(dc, 0, pc1, pc1 + 4); + // b2 = T0 & 1; + // env->y = (b2 << 31) | (env->y >> 1); + tcg_gen_andi_tl(r_temp, cpu_cc_src, 0x1); + tcg_gen_shli_tl(r_temp, r_temp, 31); + tcg_gen_shri_tl(cpu_tmp0, cpu_y, 1); + tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0x7fffffff); + tcg_gen_or_tl(cpu_tmp0, cpu_tmp0, r_temp); + tcg_gen_andi_tl(cpu_y, cpu_tmp0, 0xffffffff); - gen_set_label(l1); - gen_goto_tb(dc, 1, pc2, pc2 + 4); + // b1 = N ^ V; + gen_mov_reg_N(cpu_tmp0, cpu_psr); + gen_mov_reg_V(r_temp, cpu_psr); + tcg_gen_xor_tl(cpu_tmp0, cpu_tmp0, r_temp); + tcg_temp_free(r_temp); + + // T0 = (b1 << 31) | (T0 >> 1); + // src1 = T0; + tcg_gen_shli_tl(cpu_tmp0, cpu_tmp0, 31); + tcg_gen_shri_tl(cpu_cc_src, cpu_cc_src, 1); + tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_tmp0); + + /* do addition and update flags */ + tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); + + gen_cc_clear_icc(); + gen_cc_NZ_icc(cpu_cc_dst); + gen_cc_V_add_icc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); + gen_cc_C_add_icc(cpu_cc_dst, cpu_cc_src); + tcg_gen_mov_tl(dst, cpu_cc_dst); } -static inline void gen_branch_a(DisasContext *dc, target_ulong pc1, - target_ulong pc2) +static inline void gen_op_umul(TCGv dst, TCGv src1, TCGv src2) { - int l1; + TCGv r_temp, r_temp2; - l1 = gen_new_label(); + r_temp = tcg_temp_new(TCG_TYPE_I64); + r_temp2 = tcg_temp_new(TCG_TYPE_I64); - gen_op_jz_T2_label(l1); + tcg_gen_extu_tl_i64(r_temp, src2); + tcg_gen_extu_tl_i64(r_temp2, src1); + tcg_gen_mul_i64(r_temp2, r_temp, r_temp2); - gen_goto_tb(dc, 0, pc2, pc1); + tcg_gen_shri_i64(r_temp, r_temp2, 32); + tcg_gen_trunc_i64_tl(cpu_tmp0, r_temp); + tcg_temp_free(r_temp); + tcg_gen_andi_tl(cpu_y, cpu_tmp0, 0xffffffff); +#ifdef TARGET_SPARC64 + tcg_gen_mov_i64(dst, r_temp2); +#else + tcg_gen_trunc_i64_tl(dst, r_temp2); +#endif + tcg_temp_free(r_temp2); +} - gen_set_label(l1); - gen_goto_tb(dc, 1, pc2 + 4, pc2 + 8); +static inline void gen_op_smul(TCGv dst, TCGv src1, TCGv src2) +{ + TCGv r_temp, r_temp2; + + r_temp = tcg_temp_new(TCG_TYPE_I64); + r_temp2 = tcg_temp_new(TCG_TYPE_I64); + + tcg_gen_ext_tl_i64(r_temp, src2); + tcg_gen_ext_tl_i64(r_temp2, src1); + tcg_gen_mul_i64(r_temp2, r_temp, r_temp2); + + tcg_gen_shri_i64(r_temp, r_temp2, 32); + tcg_gen_trunc_i64_tl(cpu_tmp0, r_temp); + tcg_temp_free(r_temp); + tcg_gen_andi_tl(cpu_y, cpu_tmp0, 0xffffffff); +#ifdef TARGET_SPARC64 + tcg_gen_mov_i64(dst, r_temp2); +#else + tcg_gen_trunc_i64_tl(dst, r_temp2); +#endif + tcg_temp_free(r_temp2); } -static inline void gen_branch(DisasContext *dc, target_ulong pc, - target_ulong npc) +#ifdef TARGET_SPARC64 +static inline void gen_trap_ifdivzero_tl(TCGv divisor) { - gen_goto_tb(dc, 0, pc, npc); + TCGv r_const; + int l1; + + l1 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_NE, divisor, 0, l1); + r_const = tcg_const_i32(TT_DIV_ZERO); + tcg_gen_helper_0_1(raise_exception, r_const); + tcg_temp_free(r_const); + gen_set_label(l1); } -static inline void gen_generic_branch(target_ulong npc1, target_ulong npc2) +static inline void gen_op_sdivx(TCGv dst, TCGv src1, TCGv src2) { int l1, l2; l1 = gen_new_label(); l2 = gen_new_label(); - gen_op_jz_T2_label(l1); - - gen_movl_npc_im(npc1); - gen_op_jmp_label(l2); - + tcg_gen_mov_tl(cpu_cc_src, src1); + tcg_gen_mov_tl(cpu_cc_src2, src2); + gen_trap_ifdivzero_tl(cpu_cc_src2); + tcg_gen_brcondi_tl(TCG_COND_NE, cpu_cc_src, INT64_MIN, l1); + tcg_gen_brcondi_tl(TCG_COND_NE, cpu_cc_src2, -1, l1); + tcg_gen_movi_i64(dst, INT64_MIN); + tcg_gen_br(l2); gen_set_label(l1); - gen_movl_npc_im(npc2); + tcg_gen_div_i64(dst, cpu_cc_src, cpu_cc_src2); gen_set_label(l2); } +#endif -/* call this function before using T2 as it may have been set for a jump */ -static inline void flush_T2(DisasContext * dc) +static inline void gen_op_div_cc(TCGv dst) { - if (dc->npc == JUMP_PC) { - gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1]); - dc->npc = DYNAMIC_PC; - } + int l1; + + tcg_gen_mov_tl(cpu_cc_dst, dst); + gen_cc_clear_icc(); + gen_cc_NZ_icc(cpu_cc_dst); + l1 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_cc_src2, 0, l1); + tcg_gen_ori_i32(cpu_psr, cpu_psr, PSR_OVF); + gen_set_label(l1); } -static inline void save_npc(DisasContext * dc) +static inline void gen_op_logic_cc(TCGv dst) { - if (dc->npc == JUMP_PC) { - gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1]); + tcg_gen_mov_tl(cpu_cc_dst, dst); + + gen_cc_clear_icc(); + gen_cc_NZ_icc(cpu_cc_dst); +#ifdef TARGET_SPARC64 + gen_cc_clear_xcc(); + gen_cc_NZ_xcc(cpu_cc_dst); +#endif +} + +// 1 +static inline void gen_op_eval_ba(TCGv dst) +{ + tcg_gen_movi_tl(dst, 1); +} + +// Z +static inline void gen_op_eval_be(TCGv dst, TCGv src) +{ + gen_mov_reg_Z(dst, src); +} + +// Z | (N ^ V) +static inline void gen_op_eval_ble(TCGv dst, TCGv src) +{ + gen_mov_reg_N(cpu_tmp0, src); + gen_mov_reg_V(dst, src); + tcg_gen_xor_tl(dst, dst, cpu_tmp0); + gen_mov_reg_Z(cpu_tmp0, src); + tcg_gen_or_tl(dst, dst, cpu_tmp0); +} + +// N ^ V +static inline void gen_op_eval_bl(TCGv dst, TCGv src) +{ + gen_mov_reg_V(cpu_tmp0, src); + gen_mov_reg_N(dst, src); + tcg_gen_xor_tl(dst, dst, cpu_tmp0); +} + +// C | Z +static inline void gen_op_eval_bleu(TCGv dst, TCGv src) +{ + gen_mov_reg_Z(cpu_tmp0, src); + gen_mov_reg_C(dst, src); + tcg_gen_or_tl(dst, dst, cpu_tmp0); +} + +// C +static inline void gen_op_eval_bcs(TCGv dst, TCGv src) +{ + gen_mov_reg_C(dst, src); +} + +// V +static inline void gen_op_eval_bvs(TCGv dst, TCGv src) +{ + gen_mov_reg_V(dst, src); +} + +// 0 +static inline void gen_op_eval_bn(TCGv dst) +{ + tcg_gen_movi_tl(dst, 0); +} + +// N +static inline void gen_op_eval_bneg(TCGv dst, TCGv src) +{ + gen_mov_reg_N(dst, src); +} + +// !Z +static inline void gen_op_eval_bne(TCGv dst, TCGv src) +{ + gen_mov_reg_Z(dst, src); + tcg_gen_xori_tl(dst, dst, 0x1); +} + +// !(Z | (N ^ V)) +static inline void gen_op_eval_bg(TCGv dst, TCGv src) +{ + gen_mov_reg_N(cpu_tmp0, src); + gen_mov_reg_V(dst, src); + tcg_gen_xor_tl(dst, dst, cpu_tmp0); + gen_mov_reg_Z(cpu_tmp0, src); + tcg_gen_or_tl(dst, dst, cpu_tmp0); + tcg_gen_xori_tl(dst, dst, 0x1); +} + +// !(N ^ V) +static inline void gen_op_eval_bge(TCGv dst, TCGv src) +{ + gen_mov_reg_V(cpu_tmp0, src); + gen_mov_reg_N(dst, src); + tcg_gen_xor_tl(dst, dst, cpu_tmp0); + tcg_gen_xori_tl(dst, dst, 0x1); +} + +// !(C | Z) +static inline void gen_op_eval_bgu(TCGv dst, TCGv src) +{ + gen_mov_reg_Z(cpu_tmp0, src); + gen_mov_reg_C(dst, src); + tcg_gen_or_tl(dst, dst, cpu_tmp0); + tcg_gen_xori_tl(dst, dst, 0x1); +} + +// !C +static inline void gen_op_eval_bcc(TCGv dst, TCGv src) +{ + gen_mov_reg_C(dst, src); + tcg_gen_xori_tl(dst, dst, 0x1); +} + +// !N +static inline void gen_op_eval_bpos(TCGv dst, TCGv src) +{ + gen_mov_reg_N(dst, src); + tcg_gen_xori_tl(dst, dst, 0x1); +} + +// !V +static inline void gen_op_eval_bvc(TCGv dst, TCGv src) +{ + gen_mov_reg_V(dst, src); + tcg_gen_xori_tl(dst, dst, 0x1); +} + +/* + FPSR bit field FCC1 | FCC0: + 0 = + 1 < + 2 > + 3 unordered +*/ +static inline void gen_mov_reg_FCC0(TCGv reg, TCGv src, + unsigned int fcc_offset) +{ + tcg_gen_shri_tl(reg, src, FSR_FCC0_SHIFT + fcc_offset); + tcg_gen_andi_tl(reg, reg, 0x1); +} + +static inline void gen_mov_reg_FCC1(TCGv reg, TCGv src, + unsigned int fcc_offset) +{ + tcg_gen_shri_tl(reg, src, FSR_FCC1_SHIFT + fcc_offset); + tcg_gen_andi_tl(reg, reg, 0x1); +} + +// !0: FCC0 | FCC1 +static inline void gen_op_eval_fbne(TCGv dst, TCGv src, + unsigned int fcc_offset) +{ + gen_mov_reg_FCC0(dst, src, fcc_offset); + gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); + tcg_gen_or_tl(dst, dst, cpu_tmp0); +} + +// 1 or 2: FCC0 ^ FCC1 +static inline void gen_op_eval_fblg(TCGv dst, TCGv src, + unsigned int fcc_offset) +{ + gen_mov_reg_FCC0(dst, src, fcc_offset); + gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); + tcg_gen_xor_tl(dst, dst, cpu_tmp0); +} + +// 1 or 3: FCC0 +static inline void gen_op_eval_fbul(TCGv dst, TCGv src, + unsigned int fcc_offset) +{ + gen_mov_reg_FCC0(dst, src, fcc_offset); +} + +// 1: FCC0 & !FCC1 +static inline void gen_op_eval_fbl(TCGv dst, TCGv src, + unsigned int fcc_offset) +{ + gen_mov_reg_FCC0(dst, src, fcc_offset); + gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); + tcg_gen_xori_tl(cpu_tmp0, cpu_tmp0, 0x1); + tcg_gen_and_tl(dst, dst, cpu_tmp0); +} + +// 2 or 3: FCC1 +static inline void gen_op_eval_fbug(TCGv dst, TCGv src, + unsigned int fcc_offset) +{ + gen_mov_reg_FCC1(dst, src, fcc_offset); +} + +// 2: !FCC0 & FCC1 +static inline void gen_op_eval_fbg(TCGv dst, TCGv src, + unsigned int fcc_offset) +{ + gen_mov_reg_FCC0(dst, src, fcc_offset); + tcg_gen_xori_tl(dst, dst, 0x1); + gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); + tcg_gen_and_tl(dst, dst, cpu_tmp0); +} + +// 3: FCC0 & FCC1 +static inline void gen_op_eval_fbu(TCGv dst, TCGv src, + unsigned int fcc_offset) +{ + gen_mov_reg_FCC0(dst, src, fcc_offset); + gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); + tcg_gen_and_tl(dst, dst, cpu_tmp0); +} + +// 0: !(FCC0 | FCC1) +static inline void gen_op_eval_fbe(TCGv dst, TCGv src, + unsigned int fcc_offset) +{ + gen_mov_reg_FCC0(dst, src, fcc_offset); + gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); + tcg_gen_or_tl(dst, dst, cpu_tmp0); + tcg_gen_xori_tl(dst, dst, 0x1); +} + +// 0 or 3: !(FCC0 ^ FCC1) +static inline void gen_op_eval_fbue(TCGv dst, TCGv src, + unsigned int fcc_offset) +{ + gen_mov_reg_FCC0(dst, src, fcc_offset); + gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); + tcg_gen_xor_tl(dst, dst, cpu_tmp0); + tcg_gen_xori_tl(dst, dst, 0x1); +} + +// 0 or 2: !FCC0 +static inline void gen_op_eval_fbge(TCGv dst, TCGv src, + unsigned int fcc_offset) +{ + gen_mov_reg_FCC0(dst, src, fcc_offset); + tcg_gen_xori_tl(dst, dst, 0x1); +} + +// !1: !(FCC0 & !FCC1) +static inline void gen_op_eval_fbuge(TCGv dst, TCGv src, + unsigned int fcc_offset) +{ + gen_mov_reg_FCC0(dst, src, fcc_offset); + gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); + tcg_gen_xori_tl(cpu_tmp0, cpu_tmp0, 0x1); + tcg_gen_and_tl(dst, dst, cpu_tmp0); + tcg_gen_xori_tl(dst, dst, 0x1); +} + +// 0 or 1: !FCC1 +static inline void gen_op_eval_fble(TCGv dst, TCGv src, + unsigned int fcc_offset) +{ + gen_mov_reg_FCC1(dst, src, fcc_offset); + tcg_gen_xori_tl(dst, dst, 0x1); +} + +// !2: !(!FCC0 & FCC1) +static inline void gen_op_eval_fbule(TCGv dst, TCGv src, + unsigned int fcc_offset) +{ + gen_mov_reg_FCC0(dst, src, fcc_offset); + tcg_gen_xori_tl(dst, dst, 0x1); + gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); + tcg_gen_and_tl(dst, dst, cpu_tmp0); + tcg_gen_xori_tl(dst, dst, 0x1); +} + +// !3: !(FCC0 & FCC1) +static inline void gen_op_eval_fbo(TCGv dst, TCGv src, + unsigned int fcc_offset) +{ + gen_mov_reg_FCC0(dst, src, fcc_offset); + gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); + tcg_gen_and_tl(dst, dst, cpu_tmp0); + tcg_gen_xori_tl(dst, dst, 0x1); +} + +static inline void gen_branch2(DisasContext *dc, target_ulong pc1, + target_ulong pc2, TCGv r_cond) +{ + int l1; + + l1 = gen_new_label(); + + tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1); + + gen_goto_tb(dc, 0, pc1, pc1 + 4); + + gen_set_label(l1); + gen_goto_tb(dc, 1, pc2, pc2 + 4); +} + +static inline void gen_branch_a(DisasContext *dc, target_ulong pc1, + target_ulong pc2, TCGv r_cond) +{ + int l1; + + l1 = gen_new_label(); + + tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1); + + gen_goto_tb(dc, 0, pc2, pc1); + + gen_set_label(l1); + gen_goto_tb(dc, 1, pc2 + 4, pc2 + 8); +} + +static inline void gen_generic_branch(target_ulong npc1, target_ulong npc2, + TCGv r_cond) +{ + int l1, l2; + + l1 = gen_new_label(); + l2 = gen_new_label(); + + tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1); + + tcg_gen_movi_tl(cpu_npc, npc1); + tcg_gen_br(l2); + + gen_set_label(l1); + tcg_gen_movi_tl(cpu_npc, npc2); + gen_set_label(l2); +} + +/* call this function before using the condition register as it may + have been set for a jump */ +static inline void flush_cond(DisasContext *dc, TCGv cond) +{ + if (dc->npc == JUMP_PC) { + gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1], cond); + dc->npc = DYNAMIC_PC; + } +} + +static inline void save_npc(DisasContext *dc, TCGv cond) +{ + if (dc->npc == JUMP_PC) { + gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1], cond); dc->npc = DYNAMIC_PC; } else if (dc->npc != DYNAMIC_PC) { - gen_movl_npc_im(dc->npc); + tcg_gen_movi_tl(cpu_npc, dc->npc); } } -static inline void save_state(DisasContext * dc) +static inline void save_state(DisasContext *dc, TCGv cond) { - gen_jmp_im(dc->pc); - save_npc(dc); + tcg_gen_movi_tl(cpu_pc, dc->pc); + save_npc(dc, cond); } -static inline void gen_mov_pc_npc(DisasContext * dc) +static inline void gen_mov_pc_npc(DisasContext *dc, TCGv cond) { if (dc->npc == JUMP_PC) { - gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1]); - gen_op_mov_pc_npc(); + gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1], cond); + tcg_gen_mov_tl(cpu_pc, cpu_npc); dc->pc = DYNAMIC_PC; } else if (dc->npc == DYNAMIC_PC) { - gen_op_mov_pc_npc(); + tcg_gen_mov_tl(cpu_pc, cpu_npc); dc->pc = DYNAMIC_PC; } else { dc->pc = dc->npc; } } -static GenOpFunc * const gen_cond[2][16] = { - { - gen_op_eval_bn, - gen_op_eval_be, - gen_op_eval_ble, - gen_op_eval_bl, - gen_op_eval_bleu, - gen_op_eval_bcs, - gen_op_eval_bneg, - gen_op_eval_bvs, - gen_op_eval_ba, - gen_op_eval_bne, - gen_op_eval_bg, - gen_op_eval_bge, - gen_op_eval_bgu, - gen_op_eval_bcc, - gen_op_eval_bpos, - gen_op_eval_bvc, - }, - { -#ifdef TARGET_SPARC64 - gen_op_eval_bn, - gen_op_eval_xbe, - gen_op_eval_xble, - gen_op_eval_xbl, - gen_op_eval_xbleu, - gen_op_eval_xbcs, - gen_op_eval_xbneg, - gen_op_eval_xbvs, - gen_op_eval_ba, - gen_op_eval_xbne, - gen_op_eval_xbg, - gen_op_eval_xbge, - gen_op_eval_xbgu, - gen_op_eval_xbcc, - gen_op_eval_xbpos, - gen_op_eval_xbvc, -#endif - }, -}; +static inline void gen_op_next_insn(void) +{ + tcg_gen_mov_tl(cpu_pc, cpu_npc); + tcg_gen_addi_tl(cpu_npc, cpu_npc, 4); +} + +static inline void gen_cond(TCGv r_dst, unsigned int cc, unsigned int cond) +{ + TCGv r_src; -static GenOpFunc * const gen_fcond[4][16] = { - { - gen_op_eval_bn, - gen_op_eval_fbne, - gen_op_eval_fblg, - gen_op_eval_fbul, - gen_op_eval_fbl, - gen_op_eval_fbug, - gen_op_eval_fbg, - gen_op_eval_fbu, - gen_op_eval_ba, - gen_op_eval_fbe, - gen_op_eval_fbue, - gen_op_eval_fbge, - gen_op_eval_fbuge, - gen_op_eval_fble, - gen_op_eval_fbule, - gen_op_eval_fbo, - }, #ifdef TARGET_SPARC64 - { - gen_op_eval_bn, - gen_op_eval_fbne_fcc1, - gen_op_eval_fblg_fcc1, - gen_op_eval_fbul_fcc1, - gen_op_eval_fbl_fcc1, - gen_op_eval_fbug_fcc1, - gen_op_eval_fbg_fcc1, - gen_op_eval_fbu_fcc1, - gen_op_eval_ba, - gen_op_eval_fbe_fcc1, - gen_op_eval_fbue_fcc1, - gen_op_eval_fbge_fcc1, - gen_op_eval_fbuge_fcc1, - gen_op_eval_fble_fcc1, - gen_op_eval_fbule_fcc1, - gen_op_eval_fbo_fcc1, - }, - { - gen_op_eval_bn, - gen_op_eval_fbne_fcc2, - gen_op_eval_fblg_fcc2, - gen_op_eval_fbul_fcc2, - gen_op_eval_fbl_fcc2, - gen_op_eval_fbug_fcc2, - gen_op_eval_fbg_fcc2, - gen_op_eval_fbu_fcc2, - gen_op_eval_ba, - gen_op_eval_fbe_fcc2, - gen_op_eval_fbue_fcc2, - gen_op_eval_fbge_fcc2, - gen_op_eval_fbuge_fcc2, - gen_op_eval_fble_fcc2, - gen_op_eval_fbule_fcc2, - gen_op_eval_fbo_fcc2, - }, - { - gen_op_eval_bn, - gen_op_eval_fbne_fcc3, - gen_op_eval_fblg_fcc3, - gen_op_eval_fbul_fcc3, - gen_op_eval_fbl_fcc3, - gen_op_eval_fbug_fcc3, - gen_op_eval_fbg_fcc3, - gen_op_eval_fbu_fcc3, - gen_op_eval_ba, - gen_op_eval_fbe_fcc3, - gen_op_eval_fbue_fcc3, - gen_op_eval_fbge_fcc3, - gen_op_eval_fbuge_fcc3, - gen_op_eval_fble_fcc3, - gen_op_eval_fbule_fcc3, - gen_op_eval_fbo_fcc3, - }, + if (cc) + r_src = cpu_xcc; + else + r_src = cpu_psr; #else - {}, {}, {}, + r_src = cpu_psr; #endif -}; + switch (cond) { + case 0x0: + gen_op_eval_bn(r_dst); + break; + case 0x1: + gen_op_eval_be(r_dst, r_src); + break; + case 0x2: + gen_op_eval_ble(r_dst, r_src); + break; + case 0x3: + gen_op_eval_bl(r_dst, r_src); + break; + case 0x4: + gen_op_eval_bleu(r_dst, r_src); + break; + case 0x5: + gen_op_eval_bcs(r_dst, r_src); + break; + case 0x6: + gen_op_eval_bneg(r_dst, r_src); + break; + case 0x7: + gen_op_eval_bvs(r_dst, r_src); + break; + case 0x8: + gen_op_eval_ba(r_dst); + break; + case 0x9: + gen_op_eval_bne(r_dst, r_src); + break; + case 0xa: + gen_op_eval_bg(r_dst, r_src); + break; + case 0xb: + gen_op_eval_bge(r_dst, r_src); + break; + case 0xc: + gen_op_eval_bgu(r_dst, r_src); + break; + case 0xd: + gen_op_eval_bcc(r_dst, r_src); + break; + case 0xe: + gen_op_eval_bpos(r_dst, r_src); + break; + case 0xf: + gen_op_eval_bvc(r_dst, r_src); + break; + } +} + +static inline void gen_fcond(TCGv r_dst, unsigned int cc, unsigned int cond) +{ + unsigned int offset; + + switch (cc) { + default: + case 0x0: + offset = 0; + break; + case 0x1: + offset = 32 - 10; + break; + case 0x2: + offset = 34 - 10; + break; + case 0x3: + offset = 36 - 10; + break; + } + + switch (cond) { + case 0x0: + gen_op_eval_bn(r_dst); + break; + case 0x1: + gen_op_eval_fbne(r_dst, cpu_fsr, offset); + break; + case 0x2: + gen_op_eval_fblg(r_dst, cpu_fsr, offset); + break; + case 0x3: + gen_op_eval_fbul(r_dst, cpu_fsr, offset); + break; + case 0x4: + gen_op_eval_fbl(r_dst, cpu_fsr, offset); + break; + case 0x5: + gen_op_eval_fbug(r_dst, cpu_fsr, offset); + break; + case 0x6: + gen_op_eval_fbg(r_dst, cpu_fsr, offset); + break; + case 0x7: + gen_op_eval_fbu(r_dst, cpu_fsr, offset); + break; + case 0x8: + gen_op_eval_ba(r_dst); + break; + case 0x9: + gen_op_eval_fbe(r_dst, cpu_fsr, offset); + break; + case 0xa: + gen_op_eval_fbue(r_dst, cpu_fsr, offset); + break; + case 0xb: + gen_op_eval_fbge(r_dst, cpu_fsr, offset); + break; + case 0xc: + gen_op_eval_fbuge(r_dst, cpu_fsr, offset); + break; + case 0xd: + gen_op_eval_fble(r_dst, cpu_fsr, offset); + break; + case 0xe: + gen_op_eval_fbule(r_dst, cpu_fsr, offset); + break; + case 0xf: + gen_op_eval_fbo(r_dst, cpu_fsr, offset); + break; + } +} #ifdef TARGET_SPARC64 -static void gen_cond_reg(int cond) +// Inverted logic +static const int gen_tcg_cond_reg[8] = { + -1, + TCG_COND_NE, + TCG_COND_GT, + TCG_COND_GE, + -1, + TCG_COND_EQ, + TCG_COND_LE, + TCG_COND_LT, +}; + +static inline void gen_cond_reg(TCGv r_dst, int cond, TCGv r_src) { - switch (cond) { - case 0x1: - gen_op_eval_brz(); - break; - case 0x2: - gen_op_eval_brlez(); - break; - case 0x3: - gen_op_eval_brlz(); - break; - case 0x5: - gen_op_eval_brnz(); - break; - case 0x6: - gen_op_eval_brgz(); - break; - default: - case 0x7: - gen_op_eval_brgez(); - break; - } + int l1; + + l1 = gen_new_label(); + tcg_gen_movi_tl(r_dst, 0); + tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], r_src, 0, l1); + tcg_gen_movi_tl(r_dst, 1); + gen_set_label(l1); } #endif /* XXX: potentially incorrect if dynamic npc */ -static void do_branch(DisasContext * dc, int32_t offset, uint32_t insn, int cc) +static void do_branch(DisasContext *dc, int32_t offset, uint32_t insn, int cc, + TCGv r_cond) { unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); target_ulong target = dc->pc + offset; @@ -979,10 +1392,10 @@ dc->npc = target; } } else { - flush_T2(dc); - gen_cond[cc][cond](); + flush_cond(dc, r_cond); + gen_cond(r_cond, cc, cond); if (a) { - gen_branch_a(dc, target, dc->npc); + gen_branch_a(dc, target, dc->npc, r_cond); dc->is_br = 1; } else { dc->pc = dc->npc; @@ -994,7 +1407,8 @@ } /* XXX: potentially incorrect if dynamic npc */ -static void do_fbranch(DisasContext * dc, int32_t offset, uint32_t insn, int cc) +static void do_fbranch(DisasContext *dc, int32_t offset, uint32_t insn, int cc, + TCGv r_cond) { unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); target_ulong target = dc->pc + offset; @@ -1018,10 +1432,10 @@ dc->npc = target; } } else { - flush_T2(dc); - gen_fcond[cc][cond](); + flush_cond(dc, r_cond); + gen_fcond(r_cond, cc, cond); if (a) { - gen_branch_a(dc, target, dc->npc); + gen_branch_a(dc, target, dc->npc, r_cond); dc->is_br = 1; } else { dc->pc = dc->npc; @@ -1034,15 +1448,16 @@ #ifdef TARGET_SPARC64 /* XXX: potentially incorrect if dynamic npc */ -static void do_branch_reg(DisasContext * dc, int32_t offset, uint32_t insn) +static void do_branch_reg(DisasContext *dc, int32_t offset, uint32_t insn, + TCGv r_cond, TCGv r_reg) { unsigned int cond = GET_FIELD_SP(insn, 25, 27), a = (insn & (1 << 29)); target_ulong target = dc->pc + offset; - flush_T2(dc); - gen_cond_reg(cond); + flush_cond(dc, r_cond); + gen_cond_reg(r_cond, cond, r_reg); if (a) { - gen_branch_a(dc, target, dc->npc); + gen_branch_a(dc, target, dc->npc, r_cond); dc->is_br = 1; } else { dc->pc = dc->npc; @@ -1052,59 +1467,144 @@ } } -static GenOpFunc * const gen_fcmps[4] = { - gen_op_fcmps, - gen_op_fcmps_fcc1, - gen_op_fcmps_fcc2, - gen_op_fcmps_fcc3, -}; - static GenOpFunc * const gen_fcmpd[4] = { - gen_op_fcmpd, - gen_op_fcmpd_fcc1, - gen_op_fcmpd_fcc2, - gen_op_fcmpd_fcc3, + helper_fcmpd, + helper_fcmpd_fcc1, + helper_fcmpd_fcc2, + helper_fcmpd_fcc3, }; -#if defined(CONFIG_USER_ONLY) static GenOpFunc * const gen_fcmpq[4] = { - gen_op_fcmpq, - gen_op_fcmpq_fcc1, - gen_op_fcmpq_fcc2, - gen_op_fcmpq_fcc3, -}; -#endif - -static GenOpFunc * const gen_fcmpes[4] = { - gen_op_fcmpes, - gen_op_fcmpes_fcc1, - gen_op_fcmpes_fcc2, - gen_op_fcmpes_fcc3, + helper_fcmpq, + helper_fcmpq_fcc1, + helper_fcmpq_fcc2, + helper_fcmpq_fcc3, }; static GenOpFunc * const gen_fcmped[4] = { - gen_op_fcmped, - gen_op_fcmped_fcc1, - gen_op_fcmped_fcc2, - gen_op_fcmped_fcc3, + helper_fcmped, + helper_fcmped_fcc1, + helper_fcmped_fcc2, + helper_fcmped_fcc3, }; -#if defined(CONFIG_USER_ONLY) static GenOpFunc * const gen_fcmpeq[4] = { - gen_op_fcmpeq, - gen_op_fcmpeq_fcc1, - gen_op_fcmpeq_fcc2, - gen_op_fcmpeq_fcc3, + helper_fcmpeq, + helper_fcmpeq_fcc1, + helper_fcmpeq_fcc2, + helper_fcmpeq_fcc3, }; -#endif + +static inline void gen_op_fcmps(int fccno, TCGv r_rs1, TCGv r_rs2) +{ + switch (fccno) { + case 0: + tcg_gen_helper_0_2(helper_fcmps, r_rs1, r_rs2); + break; + case 1: + tcg_gen_helper_0_2(helper_fcmps_fcc1, r_rs1, r_rs2); + break; + case 2: + tcg_gen_helper_0_2(helper_fcmps_fcc2, r_rs1, r_rs2); + break; + case 3: + tcg_gen_helper_0_2(helper_fcmps_fcc3, r_rs1, r_rs2); + break; + } +} + +static inline void gen_op_fcmpd(int fccno) +{ + tcg_gen_helper_0_0(gen_fcmpd[fccno]); +} + +static inline void gen_op_fcmpq(int fccno) +{ + tcg_gen_helper_0_0(gen_fcmpq[fccno]); +} + +static inline void gen_op_fcmpes(int fccno, TCGv r_rs1, TCGv r_rs2) +{ + switch (fccno) { + case 0: + tcg_gen_helper_0_2(helper_fcmpes, r_rs1, r_rs2); + break; + case 1: + tcg_gen_helper_0_2(helper_fcmpes_fcc1, r_rs1, r_rs2); + break; + case 2: + tcg_gen_helper_0_2(helper_fcmpes_fcc2, r_rs1, r_rs2); + break; + case 3: + tcg_gen_helper_0_2(helper_fcmpes_fcc3, r_rs1, r_rs2); + break; + } +} + +static inline void gen_op_fcmped(int fccno) +{ + tcg_gen_helper_0_0(gen_fcmped[fccno]); +} + +static inline void gen_op_fcmpeq(int fccno) +{ + tcg_gen_helper_0_0(gen_fcmpeq[fccno]); +} + +#else + +static inline void gen_op_fcmps(int fccno, TCGv r_rs1, TCGv r_rs2) +{ + tcg_gen_helper_0_2(helper_fcmps, r_rs1, r_rs2); +} + +static inline void gen_op_fcmpd(int fccno) +{ + tcg_gen_helper_0_0(helper_fcmpd); +} + +static inline void gen_op_fcmpq(int fccno) +{ + tcg_gen_helper_0_0(helper_fcmpq); +} + +static inline void gen_op_fcmpes(int fccno, TCGv r_rs1, TCGv r_rs2) +{ + tcg_gen_helper_0_2(helper_fcmpes, r_rs1, r_rs2); +} + +static inline void gen_op_fcmped(int fccno) +{ + tcg_gen_helper_0_0(helper_fcmped); +} + +static inline void gen_op_fcmpeq(int fccno) +{ + tcg_gen_helper_0_0(helper_fcmpeq); +} #endif -static int gen_trap_ifnofpu(DisasContext * dc) +static inline void gen_op_fpexception_im(int fsr_flags) +{ + TCGv r_const; + + tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_NMASK); + tcg_gen_ori_tl(cpu_fsr, cpu_fsr, fsr_flags); + r_const = tcg_const_i32(TT_FP_EXCP); + tcg_gen_helper_0_1(raise_exception, r_const); + tcg_temp_free(r_const); +} + +static int gen_trap_ifnofpu(DisasContext *dc, TCGv r_cond) { #if !defined(CONFIG_USER_ONLY) if (!dc->fpu_enabled) { - save_state(dc); - gen_op_exception(TT_NFPU_INSN); + TCGv r_const; + + save_state(dc, r_cond); + r_const = tcg_const_i32(TT_NFPU_INSN); + tcg_gen_helper_0_1(raise_exception, r_const); + tcg_temp_free(r_const); dc->is_br = 1; return 1; } @@ -1112,15 +1612,297 @@ return 0; } +static inline void gen_op_clear_ieee_excp_and_FTT(void) +{ + tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_CEXC_NMASK); +} + +static inline void gen_clear_float_exceptions(void) +{ + tcg_gen_helper_0_0(helper_clear_float_exceptions); +} + +/* asi moves */ +#ifdef TARGET_SPARC64 +static inline TCGv gen_get_asi(int insn, TCGv r_addr) +{ + int asi; + TCGv r_asi; + + if (IS_IMM) { + r_asi = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_mov_i32(r_asi, cpu_asi); + } else { + asi = GET_FIELD(insn, 19, 26); + r_asi = tcg_const_i32(asi); + } + return r_asi; +} + +static inline void gen_ld_asi(TCGv dst, TCGv addr, int insn, int size, + int sign) +{ + TCGv r_asi, r_size, r_sign; + + r_asi = gen_get_asi(insn, addr); + r_size = tcg_const_i32(size); + r_sign = tcg_const_i32(sign); + tcg_gen_helper_1_4(helper_ld_asi, dst, addr, r_asi, r_size, r_sign); + tcg_temp_free(r_sign); + tcg_temp_free(r_size); + tcg_temp_free(r_asi); +} + +static inline void gen_st_asi(TCGv src, TCGv addr, int insn, int size) +{ + TCGv r_asi, r_size; + + r_asi = gen_get_asi(insn, addr); + r_size = tcg_const_i32(size); + tcg_gen_helper_0_4(helper_st_asi, addr, src, r_asi, r_size); + tcg_temp_free(r_size); + tcg_temp_free(r_asi); +} + +static inline void gen_ldf_asi(TCGv addr, int insn, int size, int rd) +{ + TCGv r_asi, r_size, r_rd; + + r_asi = gen_get_asi(insn, addr); + r_size = tcg_const_i32(size); + r_rd = tcg_const_i32(rd); + tcg_gen_helper_0_4(helper_ldf_asi, addr, r_asi, r_size, r_rd); + tcg_temp_free(r_rd); + tcg_temp_free(r_size); + tcg_temp_free(r_asi); +} + +static inline void gen_stf_asi(TCGv addr, int insn, int size, int rd) +{ + TCGv r_asi, r_size, r_rd; + + r_asi = gen_get_asi(insn, addr); + r_size = tcg_const_i32(size); + r_rd = tcg_const_i32(rd); + tcg_gen_helper_0_4(helper_stf_asi, addr, r_asi, r_size, r_rd); + tcg_temp_free(r_rd); + tcg_temp_free(r_size); + tcg_temp_free(r_asi); +} + +static inline void gen_swap_asi(TCGv dst, TCGv addr, int insn) +{ + TCGv r_asi, r_size, r_sign; + + r_asi = gen_get_asi(insn, addr); + r_size = tcg_const_i32(4); + r_sign = tcg_const_i32(0); + tcg_gen_helper_1_4(helper_ld_asi, cpu_tmp64, addr, r_asi, r_size, r_sign); + tcg_temp_free(r_sign); + tcg_gen_helper_0_4(helper_st_asi, addr, dst, r_asi, r_size); + tcg_temp_free(r_size); + tcg_temp_free(r_asi); + tcg_gen_trunc_i64_tl(dst, cpu_tmp64); +} + +static inline void gen_ldda_asi(TCGv hi, TCGv addr, int insn, int rd) +{ + TCGv r_asi, r_rd; + + r_asi = gen_get_asi(insn, addr); + r_rd = tcg_const_i32(rd); + tcg_gen_helper_0_3(helper_ldda_asi, addr, r_asi, r_rd); + tcg_temp_free(r_rd); + tcg_temp_free(r_asi); +} + +static inline void gen_stda_asi(TCGv hi, TCGv addr, int insn, int rd) +{ + TCGv r_asi, r_size; + + gen_movl_reg_TN(rd + 1, cpu_tmp0); + tcg_gen_concat_tl_i64(cpu_tmp64, cpu_tmp0, hi); + r_asi = gen_get_asi(insn, addr); + r_size = tcg_const_i32(8); + tcg_gen_helper_0_4(helper_st_asi, addr, cpu_tmp64, r_asi, r_size); + tcg_temp_free(r_size); + tcg_temp_free(r_asi); +} + +static inline void gen_cas_asi(TCGv dst, TCGv addr, TCGv val2, int insn, + int rd) +{ + TCGv r_val1, r_asi; + + r_val1 = tcg_temp_new(TCG_TYPE_TL); + gen_movl_reg_TN(rd, r_val1); + r_asi = gen_get_asi(insn, addr); + tcg_gen_helper_1_4(helper_cas_asi, dst, addr, r_val1, val2, r_asi); + tcg_temp_free(r_asi); + tcg_temp_free(r_val1); +} + +static inline void gen_casx_asi(TCGv dst, TCGv addr, TCGv val2, int insn, + int rd) +{ + TCGv r_asi; + + gen_movl_reg_TN(rd, cpu_tmp64); + r_asi = gen_get_asi(insn, addr); + tcg_gen_helper_1_4(helper_casx_asi, dst, addr, cpu_tmp64, val2, r_asi); + tcg_temp_free(r_asi); +} + +#elif !defined(CONFIG_USER_ONLY) + +static inline void gen_ld_asi(TCGv dst, TCGv addr, int insn, int size, + int sign) +{ + TCGv r_asi, r_size, r_sign; + + r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); + r_size = tcg_const_i32(size); + r_sign = tcg_const_i32(sign); + tcg_gen_helper_1_4(helper_ld_asi, cpu_tmp64, addr, r_asi, r_size, r_sign); + tcg_temp_free(r_sign); + tcg_temp_free(r_size); + tcg_temp_free(r_asi); + tcg_gen_trunc_i64_tl(dst, cpu_tmp64); +} + +static inline void gen_st_asi(TCGv src, TCGv addr, int insn, int size) +{ + TCGv r_asi, r_size; + + tcg_gen_extu_tl_i64(cpu_tmp64, src); + r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); + r_size = tcg_const_i32(size); + tcg_gen_helper_0_4(helper_st_asi, addr, cpu_tmp64, r_asi, r_size); + tcg_temp_free(r_size); + tcg_temp_free(r_asi); +} + +static inline void gen_swap_asi(TCGv dst, TCGv addr, int insn) +{ + TCGv r_asi, r_size, r_sign; + + r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); + r_size = tcg_const_i32(4); + r_sign = tcg_const_i32(0); + tcg_gen_helper_1_4(helper_ld_asi, cpu_tmp64, addr, r_asi, r_size, r_sign); + tcg_temp_free(r_sign); + tcg_gen_helper_0_4(helper_st_asi, addr, dst, r_asi, r_size); + tcg_temp_free(r_size); + tcg_temp_free(r_asi); + tcg_gen_trunc_i64_tl(dst, cpu_tmp64); +} + +static inline void gen_ldda_asi(TCGv hi, TCGv addr, int insn, int rd) +{ + TCGv r_asi, r_size, r_sign; + + r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); + r_size = tcg_const_i32(8); + r_sign = tcg_const_i32(0); + tcg_gen_helper_1_4(helper_ld_asi, cpu_tmp64, addr, r_asi, r_size, r_sign); + tcg_temp_free(r_sign); + tcg_temp_free(r_size); + tcg_temp_free(r_asi); + tcg_gen_trunc_i64_tl(cpu_tmp0, cpu_tmp64); + gen_movl_TN_reg(rd + 1, cpu_tmp0); + tcg_gen_shri_i64(cpu_tmp64, cpu_tmp64, 32); + tcg_gen_trunc_i64_tl(hi, cpu_tmp64); + gen_movl_TN_reg(rd, hi); +} + +static inline void gen_stda_asi(TCGv hi, TCGv addr, int insn, int rd) +{ + TCGv r_asi, r_size; + + gen_movl_reg_TN(rd + 1, cpu_tmp0); + tcg_gen_concat_tl_i64(cpu_tmp64, cpu_tmp0, hi); + r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); + r_size = tcg_const_i32(8); + tcg_gen_helper_0_4(helper_st_asi, addr, cpu_tmp64, r_asi, r_size); + tcg_temp_free(r_size); + tcg_temp_free(r_asi); +} +#endif + +#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) +static inline void gen_ldstub_asi(TCGv dst, TCGv addr, int insn) +{ + TCGv r_val, r_asi, r_size; + + gen_ld_asi(dst, addr, insn, 1, 0); + + r_val = tcg_const_i64(0xffULL); + r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); + r_size = tcg_const_i32(1); + tcg_gen_helper_0_4(helper_st_asi, addr, r_val, r_asi, r_size); + tcg_temp_free(r_size); + tcg_temp_free(r_asi); + tcg_temp_free(r_val); +} +#endif + +static inline TCGv get_src1(unsigned int insn, TCGv def) +{ + TCGv r_rs1 = def; + unsigned int rs1; + + rs1 = GET_FIELD(insn, 13, 17); + if (rs1 == 0) + r_rs1 = tcg_const_tl(0); // XXX how to free? + else if (rs1 < 8) + r_rs1 = cpu_gregs[rs1]; + else + tcg_gen_ld_tl(def, cpu_regwptr, (rs1 - 8) * sizeof(target_ulong)); + return r_rs1; +} + +static inline TCGv get_src2(unsigned int insn, TCGv def) +{ + TCGv r_rs2 = def; + unsigned int rs2; + + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs(insn, 19, 31); + r_rs2 = tcg_const_tl((int)rs2); // XXX how to free? + } else { /* register */ + rs2 = GET_FIELD(insn, 27, 31); + if (rs2 == 0) + r_rs2 = tcg_const_tl(0); // XXX how to free? + else if (rs2 < 8) + r_rs2 = cpu_gregs[rs2]; + else + tcg_gen_ld_tl(def, cpu_regwptr, (rs2 - 8) * sizeof(target_ulong)); + } + return r_rs2; +} + +#define CHECK_IU_FEATURE(dc, FEATURE) \ + if (!((dc)->def->features & CPU_FEATURE_ ## FEATURE)) \ + goto illegal_insn; +#define CHECK_FPU_FEATURE(dc, FEATURE) \ + if (!((dc)->def->features & CPU_FEATURE_ ## FEATURE)) \ + goto nfpu_insn; + /* before an instruction, dc->pc must be static */ static void disas_sparc_insn(DisasContext * dc) { unsigned int insn, opc, rs1, rs2, rd; + if (unlikely(loglevel & CPU_LOG_TB_OP)) + tcg_gen_debug_insn_start(dc->pc); insn = ldl_code(dc->pc); opc = GET_FIELD(insn, 0, 1); rd = GET_FIELD(insn, 2, 6); + + cpu_src1 = tcg_temp_new(TCG_TYPE_TL); // const + cpu_src2 = tcg_temp_new(TCG_TYPE_TL); // const + switch (opc) { case 0: /* branches/sethi */ { @@ -1137,9 +1919,9 @@ target <<= 2; cc = GET_FIELD_SP(insn, 20, 21); if (cc == 0) - do_branch(dc, target, insn, 0); + do_branch(dc, target, insn, 0, cpu_cond); else if (cc == 2) - do_branch(dc, target, insn, 1); + do_branch(dc, target, insn, 1, cpu_cond); else goto illegal_insn; goto jmp_insn; @@ -1150,20 +1932,19 @@ (GET_FIELD_SP(insn, 20, 21) << 14); target = sign_extend(target, 16); target <<= 2; - rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); - do_branch_reg(dc, target, insn); + cpu_src1 = get_src1(insn, cpu_src1); + do_branch_reg(dc, target, insn, cpu_cond, cpu_src1); goto jmp_insn; } case 0x5: /* V9 FBPcc */ { int cc = GET_FIELD_SP(insn, 20, 21); - if (gen_trap_ifnofpu(dc)) + if (gen_trap_ifnofpu(dc, cpu_cond)) goto jmp_insn; target = GET_FIELD_SP(insn, 0, 18); target = sign_extend(target, 19); target <<= 2; - do_fbranch(dc, target, insn, cc); + do_fbranch(dc, target, insn, cc, cpu_cond); goto jmp_insn; } #else @@ -1177,30 +1958,28 @@ target = GET_FIELD(insn, 10, 31); target = sign_extend(target, 22); target <<= 2; - do_branch(dc, target, insn, 0); + do_branch(dc, target, insn, 0, cpu_cond); goto jmp_insn; } case 0x6: /* FBN+x */ { - if (gen_trap_ifnofpu(dc)) + if (gen_trap_ifnofpu(dc, cpu_cond)) goto jmp_insn; target = GET_FIELD(insn, 10, 31); target = sign_extend(target, 22); target <<= 2; - do_fbranch(dc, target, insn, 0); + do_fbranch(dc, target, insn, 0, cpu_cond); goto jmp_insn; } case 0x4: /* SETHI */ -#define OPTIM -#if defined(OPTIM) if (rd) { // nop -#endif uint32_t value = GET_FIELD(insn, 10, 31); - gen_movl_imm_T0(value << 10); - gen_movl_T0_reg(rd); -#if defined(OPTIM) + TCGv r_const; + + r_const = tcg_const_tl(value << 10); + gen_movl_TN_reg(rd, r_const); + tcg_temp_free(r_const); } -#endif break; case 0x0: /* UNIMPL */ default: @@ -1212,19 +1991,13 @@ case 1: /*CALL*/ { target_long target = GET_FIELDs(insn, 2, 31) << 2; + TCGv r_const; -#ifdef TARGET_SPARC64 - if (dc->pc == (uint32_t)dc->pc) { - gen_op_movl_T0_im(dc->pc); - } else { - gen_op_movq_T0_im64(dc->pc >> 32, dc->pc); - } -#else - gen_op_movl_T0_im(dc->pc); -#endif - gen_movl_T0_reg(15); + r_const = tcg_const_tl(dc->pc); + gen_movl_TN_reg(15, r_const); + tcg_temp_free(r_const); target += dc->pc; - gen_mov_pc_npc(dc); + gen_mov_pc_npc(dc, cpu_cond); dc->npc = target; } goto jmp_insn; @@ -1234,55 +2007,62 @@ if (xop == 0x3a) { /* generate trap */ int cond; - rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); + cpu_src1 = get_src1(insn, cpu_src1); if (IS_IMM) { rs2 = GET_FIELD(insn, 25, 31); -#if defined(OPTIM) - if (rs2 != 0) { -#endif - gen_movl_simm_T1(rs2); - gen_op_add_T1_T0(); -#if defined(OPTIM) - } -#endif + tcg_gen_addi_tl(cpu_dst, cpu_src1, rs2); } else { rs2 = GET_FIELD(insn, 27, 31); -#if defined(OPTIM) if (rs2 != 0) { -#endif - gen_movl_reg_T1(rs2); - gen_op_add_T1_T0(); -#if defined(OPTIM) - } -#endif + gen_movl_reg_TN(rs2, cpu_src2); + tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2); + } else + tcg_gen_mov_tl(cpu_dst, cpu_src1); } cond = GET_FIELD(insn, 3, 6); if (cond == 0x8) { - save_state(dc); - gen_op_trap_T0(); + save_state(dc, cpu_cond); + if ((dc->def->features & CPU_FEATURE_HYPV) && + supervisor(dc)) + tcg_gen_andi_tl(cpu_dst, cpu_dst, UA2005_HTRAP_MASK); + else + tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK); + tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP); + tcg_gen_helper_0_1(raise_exception, cpu_dst); } else if (cond != 0) { + TCGv r_cond = tcg_temp_new(TCG_TYPE_TL); + int l1; #ifdef TARGET_SPARC64 /* V9 icc/xcc */ int cc = GET_FIELD_SP(insn, 11, 12); - flush_T2(dc); - save_state(dc); + + save_state(dc, cpu_cond); if (cc == 0) - gen_cond[0][cond](); + gen_cond(r_cond, 0, cond); else if (cc == 2) - gen_cond[1][cond](); + gen_cond(r_cond, 1, cond); else goto illegal_insn; #else - flush_T2(dc); - save_state(dc); - gen_cond[0][cond](); + save_state(dc, cpu_cond); + gen_cond(r_cond, 0, cond); #endif - gen_op_trapcc_T0(); + l1 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1); + + if ((dc->def->features & CPU_FEATURE_HYPV) && + supervisor(dc)) + tcg_gen_andi_tl(cpu_dst, cpu_dst, UA2005_HTRAP_MASK); + else + tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK); + tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP); + tcg_gen_helper_0_1(raise_exception, cpu_dst); + + gen_set_label(l1); + tcg_temp_free(r_cond); } gen_op_next_insn(); - gen_op_movl_T0_0(); - gen_op_exit_tb(); + tcg_gen_exit_tb(0); dc->is_br = 1; goto jmp_insn; } else if (xop == 0x28) { @@ -1299,60 +2079,78 @@ SPARCv8 manual, rdy on the microSPARC II */ #endif - gen_op_movtl_T0_env(offsetof(CPUSPARCState, y)); - gen_movl_T0_reg(rd); + gen_movl_TN_reg(rd, cpu_y); break; #ifdef TARGET_SPARC64 case 0x2: /* V9 rdccr */ - gen_op_rdccr(); - gen_movl_T0_reg(rd); + tcg_gen_helper_1_0(helper_rdccr, cpu_dst); + gen_movl_TN_reg(rd, cpu_dst); break; case 0x3: /* V9 rdasi */ - gen_op_movl_T0_env(offsetof(CPUSPARCState, asi)); - gen_movl_T0_reg(rd); + tcg_gen_ext_i32_tl(cpu_dst, cpu_asi); + gen_movl_TN_reg(rd, cpu_dst); break; case 0x4: /* V9 rdtick */ - gen_op_rdtick(); - gen_movl_T0_reg(rd); + { + TCGv r_tickptr; + + r_tickptr = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_ld_ptr(r_tickptr, cpu_env, + offsetof(CPUState, tick)); + tcg_gen_helper_1_1(helper_tick_get_count, cpu_dst, + r_tickptr); + tcg_temp_free(r_tickptr); + gen_movl_TN_reg(rd, cpu_dst); + } break; case 0x5: /* V9 rdpc */ - if (dc->pc == (uint32_t)dc->pc) { - gen_op_movl_T0_im(dc->pc); - } else { - gen_op_movq_T0_im64(dc->pc >> 32, dc->pc); + { + TCGv r_const; + + r_const = tcg_const_tl(dc->pc); + gen_movl_TN_reg(rd, r_const); + tcg_temp_free(r_const); } - gen_movl_T0_reg(rd); break; case 0x6: /* V9 rdfprs */ - gen_op_movl_T0_env(offsetof(CPUSPARCState, fprs)); - gen_movl_T0_reg(rd); + tcg_gen_ext_i32_tl(cpu_dst, cpu_fprs); + gen_movl_TN_reg(rd, cpu_dst); break; case 0xf: /* V9 membar */ break; /* no effect */ case 0x13: /* Graphics Status */ - if (gen_trap_ifnofpu(dc)) + if (gen_trap_ifnofpu(dc, cpu_cond)) goto jmp_insn; - gen_op_movtl_T0_env(offsetof(CPUSPARCState, gsr)); - gen_movl_T0_reg(rd); + gen_movl_TN_reg(rd, cpu_gsr); + break; + case 0x16: /* Softint */ + tcg_gen_ext_i32_tl(cpu_dst, cpu_softint); + gen_movl_TN_reg(rd, cpu_dst); break; case 0x17: /* Tick compare */ - gen_op_movtl_T0_env(offsetof(CPUSPARCState, tick_cmpr)); - gen_movl_T0_reg(rd); + gen_movl_TN_reg(rd, cpu_tick_cmpr); break; case 0x18: /* System tick */ - gen_op_rdstick(); - gen_movl_T0_reg(rd); + { + TCGv r_tickptr; + + r_tickptr = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_ld_ptr(r_tickptr, cpu_env, + offsetof(CPUState, stick)); + tcg_gen_helper_1_1(helper_tick_get_count, cpu_dst, + r_tickptr); + tcg_temp_free(r_tickptr); + gen_movl_TN_reg(rd, cpu_dst); + } break; case 0x19: /* System tick compare */ - gen_op_movtl_T0_env(offsetof(CPUSPARCState, stick_cmpr)); - gen_movl_T0_reg(rd); + gen_movl_TN_reg(rd, cpu_stick_cmpr); break; case 0x10: /* Performance Control */ case 0x11: /* Performance Instrumentation Counter */ case 0x12: /* Dispatch Control */ case 0x14: /* Softint set, WO */ case 0x15: /* Softint clear, WO */ - case 0x16: /* Softint write */ #endif default: goto illegal_insn; @@ -1362,8 +2160,9 @@ #ifndef TARGET_SPARC64 if (!supervisor(dc)) goto priv_insn; - gen_op_rdpsr(); + tcg_gen_helper_1_0(helper_rdpsr, cpu_dst); #else + CHECK_IU_FEATURE(dc, HYPV); if (!hypervisor(dc)) goto priv_insn; rs1 = GET_FIELD(insn, 13, 17); @@ -1375,22 +2174,22 @@ // gen_op_rdhtstate(); break; case 3: // hintp - gen_op_movl_T0_env(offsetof(CPUSPARCState, hintp)); + tcg_gen_mov_tl(cpu_dst, cpu_hintp); break; case 5: // htba - gen_op_movl_T0_env(offsetof(CPUSPARCState, htba)); + tcg_gen_mov_tl(cpu_dst, cpu_htba); break; case 6: // hver - gen_op_movl_T0_env(offsetof(CPUSPARCState, hver)); + tcg_gen_mov_tl(cpu_dst, cpu_hver); break; case 31: // hstick_cmpr - gen_op_movl_env_T0(offsetof(CPUSPARCState, hstick_cmpr)); + tcg_gen_mov_tl(cpu_dst, cpu_hstick_cmpr); break; default: goto illegal_insn; } #endif - gen_movl_T0_reg(rd); + gen_movl_TN_reg(rd, cpu_dst); break; } else if (xop == 0x2a) { /* rdwim / V9 rdpr */ if (!supervisor(dc)) @@ -1399,83 +2198,150 @@ rs1 = GET_FIELD(insn, 13, 17); switch (rs1) { case 0: // tpc - gen_op_rdtpc(); + { + TCGv r_tsptr; + + r_tsptr = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_ld_ptr(r_tsptr, cpu_env, + offsetof(CPUState, tsptr)); + tcg_gen_ld_tl(cpu_tmp32, r_tsptr, + offsetof(trap_state, tpc)); + tcg_temp_free(r_tsptr); + tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); + } break; case 1: // tnpc - gen_op_rdtnpc(); + { + TCGv r_tsptr; + + r_tsptr = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_ld_ptr(r_tsptr, cpu_env, + offsetof(CPUState, tsptr)); + tcg_gen_ld_tl(cpu_tmp0, r_tsptr, + offsetof(trap_state, tnpc)); + tcg_temp_free(r_tsptr); + } break; case 2: // tstate - gen_op_rdtstate(); + { + TCGv r_tsptr; + + r_tsptr = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_ld_ptr(r_tsptr, cpu_env, + offsetof(CPUState, tsptr)); + tcg_gen_ld_tl(cpu_tmp0, r_tsptr, + offsetof(trap_state, tstate)); + tcg_temp_free(r_tsptr); + } break; case 3: // tt - gen_op_rdtt(); + { + TCGv r_tsptr; + + r_tsptr = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_ld_ptr(r_tsptr, cpu_env, + offsetof(CPUState, tsptr)); + tcg_gen_ld_i32(cpu_tmp0, r_tsptr, + offsetof(trap_state, tt)); + tcg_temp_free(r_tsptr); + } break; case 4: // tick - gen_op_rdtick(); + { + TCGv r_tickptr; + + r_tickptr = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_ld_ptr(r_tickptr, cpu_env, + offsetof(CPUState, tick)); + tcg_gen_helper_1_1(helper_tick_get_count, cpu_tmp0, + r_tickptr); + gen_movl_TN_reg(rd, cpu_tmp0); + tcg_temp_free(r_tickptr); + } break; case 5: // tba - gen_op_movtl_T0_env(offsetof(CPUSPARCState, tbr)); + tcg_gen_mov_tl(cpu_tmp0, cpu_tbr); break; case 6: // pstate - gen_op_rdpstate(); + tcg_gen_ld_i32(cpu_tmp32, cpu_env, + offsetof(CPUSPARCState, pstate)); + tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); break; case 7: // tl - gen_op_movl_T0_env(offsetof(CPUSPARCState, tl)); + tcg_gen_ld_i32(cpu_tmp32, cpu_env, + offsetof(CPUSPARCState, tl)); + tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); break; case 8: // pil - gen_op_movl_T0_env(offsetof(CPUSPARCState, psrpil)); + tcg_gen_ld_i32(cpu_tmp32, cpu_env, + offsetof(CPUSPARCState, psrpil)); + tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); break; case 9: // cwp - gen_op_rdcwp(); + tcg_gen_helper_1_0(helper_rdcwp, cpu_tmp0); break; case 10: // cansave - gen_op_movl_T0_env(offsetof(CPUSPARCState, cansave)); + tcg_gen_ld_i32(cpu_tmp32, cpu_env, + offsetof(CPUSPARCState, cansave)); + tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); break; case 11: // canrestore - gen_op_movl_T0_env(offsetof(CPUSPARCState, canrestore)); + tcg_gen_ld_i32(cpu_tmp32, cpu_env, + offsetof(CPUSPARCState, canrestore)); + tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); break; case 12: // cleanwin - gen_op_movl_T0_env(offsetof(CPUSPARCState, cleanwin)); + tcg_gen_ld_i32(cpu_tmp32, cpu_env, + offsetof(CPUSPARCState, cleanwin)); + tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); break; case 13: // otherwin - gen_op_movl_T0_env(offsetof(CPUSPARCState, otherwin)); + tcg_gen_ld_i32(cpu_tmp32, cpu_env, + offsetof(CPUSPARCState, otherwin)); + tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); break; case 14: // wstate - gen_op_movl_T0_env(offsetof(CPUSPARCState, wstate)); + tcg_gen_ld_i32(cpu_tmp32, cpu_env, + offsetof(CPUSPARCState, wstate)); + tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); break; case 16: // UA2005 gl - gen_op_movl_T0_env(offsetof(CPUSPARCState, gl)); + CHECK_IU_FEATURE(dc, GL); + tcg_gen_ld_i32(cpu_tmp32, cpu_env, + offsetof(CPUSPARCState, gl)); + tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); break; case 26: // UA2005 strand status + CHECK_IU_FEATURE(dc, HYPV); if (!hypervisor(dc)) goto priv_insn; - gen_op_movl_T0_env(offsetof(CPUSPARCState, ssr)); + tcg_gen_mov_tl(cpu_tmp0, cpu_ssr); break; case 31: // ver - gen_op_movtl_T0_env(offsetof(CPUSPARCState, version)); + tcg_gen_mov_tl(cpu_tmp0, cpu_ver); break; case 15: // fq default: goto illegal_insn; } #else - gen_op_movl_T0_env(offsetof(CPUSPARCState, wim)); + tcg_gen_ext_i32_tl(cpu_tmp0, cpu_wim); #endif - gen_movl_T0_reg(rd); + gen_movl_TN_reg(rd, cpu_tmp0); break; } else if (xop == 0x2b) { /* rdtbr / V9 flushw */ #ifdef TARGET_SPARC64 - gen_op_flushw(); + save_state(dc, cpu_cond); + tcg_gen_helper_0_0(helper_flushw); #else if (!supervisor(dc)) goto priv_insn; - gen_op_movtl_T0_env(offsetof(CPUSPARCState, tbr)); - gen_movl_T0_reg(rd); + gen_movl_TN_reg(rd, cpu_tbr); #endif break; #endif } else if (xop == 0x34) { /* FPU Operations */ - if (gen_trap_ifnofpu(dc)) + if (gen_trap_ifnofpu(dc, cpu_cond)) goto jmp_insn; gen_op_clear_ieee_excp_and_FTT(); rs1 = GET_FIELD(insn, 13, 17); @@ -1483,305 +2349,315 @@ xop = GET_FIELD(insn, 18, 26); switch (xop) { case 0x1: /* fmovs */ - gen_op_load_fpr_FT0(rs2); - gen_op_store_FT0_fpr(rd); + tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]); break; case 0x5: /* fnegs */ - gen_op_load_fpr_FT1(rs2); - gen_op_fnegs(); - gen_op_store_FT0_fpr(rd); + tcg_gen_helper_1_1(helper_fnegs, cpu_fpr[rd], + cpu_fpr[rs2]); break; case 0x9: /* fabss */ - gen_op_load_fpr_FT1(rs2); - gen_op_fabss(); - gen_op_store_FT0_fpr(rd); + tcg_gen_helper_1_1(helper_fabss, cpu_fpr[rd], + cpu_fpr[rs2]); break; case 0x29: /* fsqrts */ - gen_op_load_fpr_FT1(rs2); - gen_op_fsqrts(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, FSQRT); + gen_clear_float_exceptions(); + tcg_gen_helper_1_1(helper_fsqrts, cpu_tmp32, + cpu_fpr[rs2]); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); + tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); break; case 0x2a: /* fsqrtd */ + CHECK_FPU_FEATURE(dc, FSQRT); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fsqrtd(); + gen_clear_float_exceptions(); + tcg_gen_helper_0_0(helper_fsqrtd); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x2b: /* fsqrtq */ -#if defined(CONFIG_USER_ONLY) + CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT1(QFPREG(rs2)); - gen_op_fsqrtq(); + gen_clear_float_exceptions(); + tcg_gen_helper_0_0(helper_fsqrtq); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); gen_op_store_QT0_fpr(QFPREG(rd)); break; -#else - goto nfpu_insn; -#endif - case 0x41: - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fadds(); - gen_op_store_FT0_fpr(rd); + case 0x41: /* fadds */ + gen_clear_float_exceptions(); + tcg_gen_helper_1_2(helper_fadds, cpu_tmp32, + cpu_fpr[rs1], cpu_fpr[rs2]); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); + tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); break; case 0x42: gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_faddd(); + gen_clear_float_exceptions(); + tcg_gen_helper_0_0(helper_faddd); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x43: /* faddq */ -#if defined(CONFIG_USER_ONLY) + CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT0(QFPREG(rs1)); gen_op_load_fpr_QT1(QFPREG(rs2)); - gen_op_faddq(); + gen_clear_float_exceptions(); + tcg_gen_helper_0_0(helper_faddq); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); gen_op_store_QT0_fpr(QFPREG(rd)); break; -#else - goto nfpu_insn; -#endif - case 0x45: - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fsubs(); - gen_op_store_FT0_fpr(rd); + case 0x45: /* fsubs */ + gen_clear_float_exceptions(); + tcg_gen_helper_1_2(helper_fsubs, cpu_tmp32, + cpu_fpr[rs1], cpu_fpr[rs2]); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); + tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); break; case 0x46: gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fsubd(); + gen_clear_float_exceptions(); + tcg_gen_helper_0_0(helper_fsubd); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x47: /* fsubq */ -#if defined(CONFIG_USER_ONLY) + CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT0(QFPREG(rs1)); gen_op_load_fpr_QT1(QFPREG(rs2)); - gen_op_fsubq(); + gen_clear_float_exceptions(); + tcg_gen_helper_0_0(helper_fsubq); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); gen_op_store_QT0_fpr(QFPREG(rd)); break; -#else - goto nfpu_insn; -#endif - case 0x49: - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fmuls(); - gen_op_store_FT0_fpr(rd); + case 0x49: /* fmuls */ + CHECK_FPU_FEATURE(dc, FMUL); + gen_clear_float_exceptions(); + tcg_gen_helper_1_2(helper_fmuls, cpu_tmp32, + cpu_fpr[rs1], cpu_fpr[rs2]); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); + tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); break; - case 0x4a: + case 0x4a: /* fmuld */ + CHECK_FPU_FEATURE(dc, FMUL); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fmuld(); + gen_clear_float_exceptions(); + tcg_gen_helper_0_0(helper_fmuld); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x4b: /* fmulq */ -#if defined(CONFIG_USER_ONLY) + CHECK_FPU_FEATURE(dc, FLOAT128); + CHECK_FPU_FEATURE(dc, FMUL); gen_op_load_fpr_QT0(QFPREG(rs1)); gen_op_load_fpr_QT1(QFPREG(rs2)); - gen_op_fmulq(); + gen_clear_float_exceptions(); + tcg_gen_helper_0_0(helper_fmulq); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); gen_op_store_QT0_fpr(QFPREG(rd)); break; -#else - goto nfpu_insn; -#endif - case 0x4d: - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fdivs(); - gen_op_store_FT0_fpr(rd); + case 0x4d: /* fdivs */ + gen_clear_float_exceptions(); + tcg_gen_helper_1_2(helper_fdivs, cpu_tmp32, + cpu_fpr[rs1], cpu_fpr[rs2]); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); + tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); break; case 0x4e: gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fdivd(); + gen_clear_float_exceptions(); + tcg_gen_helper_0_0(helper_fdivd); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x4f: /* fdivq */ -#if defined(CONFIG_USER_ONLY) + CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT0(QFPREG(rs1)); gen_op_load_fpr_QT1(QFPREG(rs2)); - gen_op_fdivq(); + gen_clear_float_exceptions(); + tcg_gen_helper_0_0(helper_fdivq); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); gen_op_store_QT0_fpr(QFPREG(rd)); break; -#else - goto nfpu_insn; -#endif - case 0x69: - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fsmuld(); + case 0x69: /* fsmuld */ + CHECK_FPU_FEATURE(dc, FSMULD); + gen_clear_float_exceptions(); + tcg_gen_helper_0_2(helper_fsmuld, cpu_fpr[rs1], + cpu_fpr[rs2]); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x6e: /* fdmulq */ -#if defined(CONFIG_USER_ONLY) + CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fdmulq(); + gen_clear_float_exceptions(); + tcg_gen_helper_0_0(helper_fdmulq); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); gen_op_store_QT0_fpr(QFPREG(rd)); break; -#else - goto nfpu_insn; -#endif - case 0xc4: - gen_op_load_fpr_FT1(rs2); - gen_op_fitos(); - gen_op_store_FT0_fpr(rd); + case 0xc4: /* fitos */ + gen_clear_float_exceptions(); + tcg_gen_helper_1_1(helper_fitos, cpu_tmp32, + cpu_fpr[rs2]); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); + tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); break; - case 0xc6: + case 0xc6: /* fdtos */ gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fdtos(); - gen_op_store_FT0_fpr(rd); + gen_clear_float_exceptions(); + tcg_gen_helper_1_0(helper_fdtos, cpu_tmp32); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); + tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); break; case 0xc7: /* fqtos */ -#if defined(CONFIG_USER_ONLY) + CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT1(QFPREG(rs2)); - gen_op_fqtos(); - gen_op_store_FT0_fpr(rd); + gen_clear_float_exceptions(); + tcg_gen_helper_1_0(helper_fqtos, cpu_tmp32); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); + tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); break; -#else - goto nfpu_insn; -#endif - case 0xc8: - gen_op_load_fpr_FT1(rs2); - gen_op_fitod(); + case 0xc8: /* fitod */ + tcg_gen_helper_0_1(helper_fitod, cpu_fpr[rs2]); gen_op_store_DT0_fpr(DFPREG(rd)); break; - case 0xc9: - gen_op_load_fpr_FT1(rs2); - gen_op_fstod(); + case 0xc9: /* fstod */ + tcg_gen_helper_0_1(helper_fstod, cpu_fpr[rs2]); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0xcb: /* fqtod */ -#if defined(CONFIG_USER_ONLY) + CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT1(QFPREG(rs2)); - gen_op_fqtod(); + gen_clear_float_exceptions(); + tcg_gen_helper_0_0(helper_fqtod); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); gen_op_store_DT0_fpr(DFPREG(rd)); break; -#else - goto nfpu_insn; -#endif case 0xcc: /* fitoq */ -#if defined(CONFIG_USER_ONLY) - gen_op_load_fpr_FT1(rs2); - gen_op_fitoq(); + CHECK_FPU_FEATURE(dc, FLOAT128); + tcg_gen_helper_0_1(helper_fitoq, cpu_fpr[rs2]); gen_op_store_QT0_fpr(QFPREG(rd)); break; -#else - goto nfpu_insn; -#endif case 0xcd: /* fstoq */ -#if defined(CONFIG_USER_ONLY) - gen_op_load_fpr_FT1(rs2); - gen_op_fstoq(); + CHECK_FPU_FEATURE(dc, FLOAT128); + tcg_gen_helper_0_1(helper_fstoq, cpu_fpr[rs2]); gen_op_store_QT0_fpr(QFPREG(rd)); break; -#else - goto nfpu_insn; -#endif case 0xce: /* fdtoq */ -#if defined(CONFIG_USER_ONLY) + CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fdtoq(); + tcg_gen_helper_0_0(helper_fdtoq); gen_op_store_QT0_fpr(QFPREG(rd)); break; -#else - goto nfpu_insn; -#endif - case 0xd1: - gen_op_load_fpr_FT1(rs2); - gen_op_fstoi(); - gen_op_store_FT0_fpr(rd); + case 0xd1: /* fstoi */ + gen_clear_float_exceptions(); + tcg_gen_helper_1_1(helper_fstoi, cpu_tmp32, + cpu_fpr[rs2]); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); + tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); break; - case 0xd2: + case 0xd2: /* fdtoi */ gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fdtoi(); - gen_op_store_FT0_fpr(rd); + gen_clear_float_exceptions(); + tcg_gen_helper_1_0(helper_fdtoi, cpu_tmp32); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); + tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); break; case 0xd3: /* fqtoi */ -#if defined(CONFIG_USER_ONLY) + CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT1(QFPREG(rs2)); - gen_op_fqtoi(); - gen_op_store_FT0_fpr(rd); + gen_clear_float_exceptions(); + tcg_gen_helper_1_0(helper_fqtoi, cpu_tmp32); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); + tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); break; -#else - goto nfpu_insn; -#endif #ifdef TARGET_SPARC64 case 0x2: /* V9 fmovd */ - gen_op_load_fpr_DT0(DFPREG(rs2)); - gen_op_store_DT0_fpr(DFPREG(rd)); + tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)], + cpu_fpr[DFPREG(rs2)]); + tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1], + cpu_fpr[DFPREG(rs2) + 1]); break; case 0x3: /* V9 fmovq */ -#if defined(CONFIG_USER_ONLY) - gen_op_load_fpr_QT0(QFPREG(rs2)); - gen_op_store_QT0_fpr(QFPREG(rd)); + CHECK_FPU_FEATURE(dc, FLOAT128); + tcg_gen_mov_i32(cpu_fpr[QFPREG(rd)], + cpu_fpr[QFPREG(rs2)]); + tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1], + cpu_fpr[QFPREG(rs2) + 1]); + tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2], + cpu_fpr[QFPREG(rs2) + 2]); + tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3], + cpu_fpr[QFPREG(rs2) + 3]); break; -#else - goto nfpu_insn; -#endif case 0x6: /* V9 fnegd */ gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fnegd(); + tcg_gen_helper_0_0(helper_fnegd); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x7: /* V9 fnegq */ -#if defined(CONFIG_USER_ONLY) + CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT1(QFPREG(rs2)); - gen_op_fnegq(); + tcg_gen_helper_0_0(helper_fnegq); gen_op_store_QT0_fpr(QFPREG(rd)); break; -#else - goto nfpu_insn; -#endif case 0xa: /* V9 fabsd */ gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fabsd(); + tcg_gen_helper_0_0(helper_fabsd); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0xb: /* V9 fabsq */ -#if defined(CONFIG_USER_ONLY) + CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT1(QFPREG(rs2)); - gen_op_fabsq(); + tcg_gen_helper_0_0(helper_fabsq); gen_op_store_QT0_fpr(QFPREG(rd)); break; -#else - goto nfpu_insn; -#endif case 0x81: /* V9 fstox */ - gen_op_load_fpr_FT1(rs2); - gen_op_fstox(); + gen_clear_float_exceptions(); + tcg_gen_helper_0_1(helper_fstox, cpu_fpr[rs2]); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x82: /* V9 fdtox */ gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fdtox(); + gen_clear_float_exceptions(); + tcg_gen_helper_0_0(helper_fdtox); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x83: /* V9 fqtox */ -#if defined(CONFIG_USER_ONLY) + CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT1(QFPREG(rs2)); - gen_op_fqtox(); + gen_clear_float_exceptions(); + tcg_gen_helper_0_0(helper_fqtox); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); gen_op_store_DT0_fpr(DFPREG(rd)); break; -#else - goto nfpu_insn; -#endif case 0x84: /* V9 fxtos */ gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fxtos(); - gen_op_store_FT0_fpr(rd); + gen_clear_float_exceptions(); + tcg_gen_helper_1_0(helper_fxtos, cpu_tmp32); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); + tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32); break; case 0x88: /* V9 fxtod */ gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fxtod(); + gen_clear_float_exceptions(); + tcg_gen_helper_0_0(helper_fxtod); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x8c: /* V9 fxtoq */ -#if defined(CONFIG_USER_ONLY) + CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fxtoq(); + gen_clear_float_exceptions(); + tcg_gen_helper_0_0(helper_fxtoq); + tcg_gen_helper_0_0(helper_check_ieee_exceptions); gen_op_store_QT0_fpr(QFPREG(rd)); break; -#else - goto nfpu_insn; -#endif #endif default: goto illegal_insn; @@ -1790,7 +2666,7 @@ #ifdef TARGET_SPARC64 int cond; #endif - if (gen_trap_ifnofpu(dc)) + if (gen_trap_ifnofpu(dc, cpu_cond)) goto jmp_insn; gen_op_clear_ieee_excp_and_FTT(); rs1 = GET_FIELD(insn, 13, 17); @@ -1798,524 +2674,549 @@ xop = GET_FIELD(insn, 18, 26); #ifdef TARGET_SPARC64 if ((xop & 0x11f) == 0x005) { // V9 fmovsr + int l1; + + l1 = gen_new_label(); cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_FT0(rd); - gen_op_load_fpr_FT1(rs2); - rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); - flush_T2(dc); - gen_cond_reg(cond); - gen_op_fmovs_cc(); - gen_op_store_FT0_fpr(rd); + cpu_src1 = get_src1(insn, cpu_src1); + tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1, + 0, l1); + tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]); + gen_set_label(l1); break; } else if ((xop & 0x11f) == 0x006) { // V9 fmovdr + int l1; + + l1 = gen_new_label(); cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(DFPREG(rd)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - flush_T2(dc); - rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); - gen_cond_reg(cond); - gen_op_fmovs_cc(); - gen_op_store_DT0_fpr(DFPREG(rd)); + cpu_src1 = get_src1(insn, cpu_src1); + tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1, + 0, l1); + tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)]); + tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1], cpu_fpr[DFPREG(rs2) + 1]); + gen_set_label(l1); break; } else if ((xop & 0x11f) == 0x007) { // V9 fmovqr -#if defined(CONFIG_USER_ONLY) + int l1; + + CHECK_FPU_FEATURE(dc, FLOAT128); + l1 = gen_new_label(); cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_QT0(QFPREG(rd)); - gen_op_load_fpr_QT1(QFPREG(rs2)); - flush_T2(dc); - rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); - gen_cond_reg(cond); - gen_op_fmovq_cc(); - gen_op_store_QT0_fpr(QFPREG(rd)); + cpu_src1 = get_src1(insn, cpu_src1); + tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1, + 0, l1); + tcg_gen_mov_i32(cpu_fpr[QFPREG(rd)], cpu_fpr[QFPREG(rs2)]); + tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1], cpu_fpr[QFPREG(rs2) + 1]); + tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2], cpu_fpr[QFPREG(rs2) + 2]); + tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3], cpu_fpr[QFPREG(rs2) + 3]); + gen_set_label(l1); break; -#else - goto nfpu_insn; -#endif } #endif switch (xop) { #ifdef TARGET_SPARC64 +#define FMOVSCC(fcc) \ + { \ + TCGv r_cond; \ + int l1; \ + \ + l1 = gen_new_label(); \ + r_cond = tcg_temp_new(TCG_TYPE_TL); \ + cond = GET_FIELD_SP(insn, 14, 17); \ + gen_fcond(r_cond, fcc, cond); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ + 0, l1); \ + tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]); \ + gen_set_label(l1); \ + tcg_temp_free(r_cond); \ + } +#define FMOVDCC(fcc) \ + { \ + TCGv r_cond; \ + int l1; \ + \ + l1 = gen_new_label(); \ + r_cond = tcg_temp_new(TCG_TYPE_TL); \ + cond = GET_FIELD_SP(insn, 14, 17); \ + gen_fcond(r_cond, fcc, cond); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ + 0, l1); \ + tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)], \ + cpu_fpr[DFPREG(rs2)]); \ + tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1], \ + cpu_fpr[DFPREG(rs2) + 1]); \ + gen_set_label(l1); \ + tcg_temp_free(r_cond); \ + } +#define FMOVQCC(fcc) \ + { \ + TCGv r_cond; \ + int l1; \ + \ + l1 = gen_new_label(); \ + r_cond = tcg_temp_new(TCG_TYPE_TL); \ + cond = GET_FIELD_SP(insn, 14, 17); \ + gen_fcond(r_cond, fcc, cond); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ + 0, l1); \ + tcg_gen_mov_i32(cpu_fpr[QFPREG(rd)], \ + cpu_fpr[QFPREG(rs2)]); \ + tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1], \ + cpu_fpr[QFPREG(rs2) + 1]); \ + tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2], \ + cpu_fpr[QFPREG(rs2) + 2]); \ + tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3], \ + cpu_fpr[QFPREG(rs2) + 3]); \ + gen_set_label(l1); \ + tcg_temp_free(r_cond); \ + } case 0x001: /* V9 fmovscc %fcc0 */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_FT0(rd); - gen_op_load_fpr_FT1(rs2); - flush_T2(dc); - gen_fcond[0][cond](); - gen_op_fmovs_cc(); - gen_op_store_FT0_fpr(rd); + FMOVSCC(0); break; case 0x002: /* V9 fmovdcc %fcc0 */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(DFPREG(rd)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - flush_T2(dc); - gen_fcond[0][cond](); - gen_op_fmovd_cc(); - gen_op_store_DT0_fpr(DFPREG(rd)); + FMOVDCC(0); break; case 0x003: /* V9 fmovqcc %fcc0 */ -#if defined(CONFIG_USER_ONLY) - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_QT0(QFPREG(rd)); - gen_op_load_fpr_QT1(QFPREG(rs2)); - flush_T2(dc); - gen_fcond[0][cond](); - gen_op_fmovq_cc(); - gen_op_store_QT0_fpr(QFPREG(rd)); + CHECK_FPU_FEATURE(dc, FLOAT128); + FMOVQCC(0); break; -#else - goto nfpu_insn; -#endif case 0x041: /* V9 fmovscc %fcc1 */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_FT0(rd); - gen_op_load_fpr_FT1(rs2); - flush_T2(dc); - gen_fcond[1][cond](); - gen_op_fmovs_cc(); - gen_op_store_FT0_fpr(rd); + FMOVSCC(1); break; case 0x042: /* V9 fmovdcc %fcc1 */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(DFPREG(rd)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - flush_T2(dc); - gen_fcond[1][cond](); - gen_op_fmovd_cc(); - gen_op_store_DT0_fpr(DFPREG(rd)); + FMOVDCC(1); break; case 0x043: /* V9 fmovqcc %fcc1 */ -#if defined(CONFIG_USER_ONLY) - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_QT0(QFPREG(rd)); - gen_op_load_fpr_QT1(QFPREG(rs2)); - flush_T2(dc); - gen_fcond[1][cond](); - gen_op_fmovq_cc(); - gen_op_store_QT0_fpr(QFPREG(rd)); + CHECK_FPU_FEATURE(dc, FLOAT128); + FMOVQCC(1); break; -#else - goto nfpu_insn; -#endif case 0x081: /* V9 fmovscc %fcc2 */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_FT0(rd); - gen_op_load_fpr_FT1(rs2); - flush_T2(dc); - gen_fcond[2][cond](); - gen_op_fmovs_cc(); - gen_op_store_FT0_fpr(rd); + FMOVSCC(2); break; case 0x082: /* V9 fmovdcc %fcc2 */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(DFPREG(rd)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - flush_T2(dc); - gen_fcond[2][cond](); - gen_op_fmovd_cc(); - gen_op_store_DT0_fpr(DFPREG(rd)); + FMOVDCC(2); break; case 0x083: /* V9 fmovqcc %fcc2 */ -#if defined(CONFIG_USER_ONLY) - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_QT0(rd); - gen_op_load_fpr_QT1(rs2); - flush_T2(dc); - gen_fcond[2][cond](); - gen_op_fmovq_cc(); - gen_op_store_QT0_fpr(rd); + CHECK_FPU_FEATURE(dc, FLOAT128); + FMOVQCC(2); break; -#else - goto nfpu_insn; -#endif case 0x0c1: /* V9 fmovscc %fcc3 */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_FT0(rd); - gen_op_load_fpr_FT1(rs2); - flush_T2(dc); - gen_fcond[3][cond](); - gen_op_fmovs_cc(); - gen_op_store_FT0_fpr(rd); + FMOVSCC(3); break; case 0x0c2: /* V9 fmovdcc %fcc3 */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(DFPREG(rd)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - flush_T2(dc); - gen_fcond[3][cond](); - gen_op_fmovd_cc(); - gen_op_store_DT0_fpr(DFPREG(rd)); + FMOVDCC(3); break; case 0x0c3: /* V9 fmovqcc %fcc3 */ -#if defined(CONFIG_USER_ONLY) - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_QT0(QFPREG(rd)); - gen_op_load_fpr_QT1(QFPREG(rs2)); - flush_T2(dc); - gen_fcond[3][cond](); - gen_op_fmovq_cc(); - gen_op_store_QT0_fpr(QFPREG(rd)); + CHECK_FPU_FEATURE(dc, FLOAT128); + FMOVQCC(3); break; -#else - goto nfpu_insn; -#endif +#undef FMOVSCC +#undef FMOVDCC +#undef FMOVQCC +#define FMOVCC(size_FDQ, icc) \ + { \ + TCGv r_cond; \ + int l1; \ + \ + l1 = gen_new_label(); \ + r_cond = tcg_temp_new(TCG_TYPE_TL); \ + cond = GET_FIELD_SP(insn, 14, 17); \ + gen_cond(r_cond, icc, cond); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ + 0, l1); \ + glue(glue(gen_op_load_fpr_, size_FDQ), T0) \ + (glue(size_FDQ, FPREG(rs2))); \ + glue(glue(gen_op_store_, size_FDQ), T0_fpr) \ + (glue(size_FDQ, FPREG(rd))); \ + gen_set_label(l1); \ + tcg_temp_free(r_cond); \ + } +#define FMOVSCC(icc) \ + { \ + TCGv r_cond; \ + int l1; \ + \ + l1 = gen_new_label(); \ + r_cond = tcg_temp_new(TCG_TYPE_TL); \ + cond = GET_FIELD_SP(insn, 14, 17); \ + gen_cond(r_cond, icc, cond); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ + 0, l1); \ + tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]); \ + gen_set_label(l1); \ + tcg_temp_free(r_cond); \ + } +#define FMOVDCC(icc) \ + { \ + TCGv r_cond; \ + int l1; \ + \ + l1 = gen_new_label(); \ + r_cond = tcg_temp_new(TCG_TYPE_TL); \ + cond = GET_FIELD_SP(insn, 14, 17); \ + gen_cond(r_cond, icc, cond); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ + 0, l1); \ + tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)], \ + cpu_fpr[DFPREG(rs2)]); \ + tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1], \ + cpu_fpr[DFPREG(rs2) + 1]); \ + gen_set_label(l1); \ + tcg_temp_free(r_cond); \ + } +#define FMOVQCC(icc) \ + { \ + TCGv r_cond; \ + int l1; \ + \ + l1 = gen_new_label(); \ + r_cond = tcg_temp_new(TCG_TYPE_TL); \ + cond = GET_FIELD_SP(insn, 14, 17); \ + gen_cond(r_cond, icc, cond); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ + 0, l1); \ + tcg_gen_mov_i32(cpu_fpr[QFPREG(rd)], \ + cpu_fpr[QFPREG(rs2)]); \ + tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1], \ + cpu_fpr[QFPREG(rs2) + 1]); \ + tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2], \ + cpu_fpr[QFPREG(rs2) + 2]); \ + tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3], \ + cpu_fpr[QFPREG(rs2) + 3]); \ + gen_set_label(l1); \ + tcg_temp_free(r_cond); \ + } + case 0x101: /* V9 fmovscc %icc */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_FT0(rd); - gen_op_load_fpr_FT1(rs2); - flush_T2(dc); - gen_cond[0][cond](); - gen_op_fmovs_cc(); - gen_op_store_FT0_fpr(rd); + FMOVSCC(0); break; case 0x102: /* V9 fmovdcc %icc */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(DFPREG(rd)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - flush_T2(dc); - gen_cond[0][cond](); - gen_op_fmovd_cc(); - gen_op_store_DT0_fpr(DFPREG(rd)); - break; + FMOVDCC(0); case 0x103: /* V9 fmovqcc %icc */ -#if defined(CONFIG_USER_ONLY) - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_QT0(rd); - gen_op_load_fpr_QT1(rs2); - flush_T2(dc); - gen_cond[0][cond](); - gen_op_fmovq_cc(); - gen_op_store_QT0_fpr(rd); + CHECK_FPU_FEATURE(dc, FLOAT128); + FMOVQCC(0); break; -#else - goto nfpu_insn; -#endif case 0x181: /* V9 fmovscc %xcc */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_FT0(rd); - gen_op_load_fpr_FT1(rs2); - flush_T2(dc); - gen_cond[1][cond](); - gen_op_fmovs_cc(); - gen_op_store_FT0_fpr(rd); + FMOVSCC(1); break; case 0x182: /* V9 fmovdcc %xcc */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(DFPREG(rd)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - flush_T2(dc); - gen_cond[1][cond](); - gen_op_fmovd_cc(); - gen_op_store_DT0_fpr(DFPREG(rd)); + FMOVDCC(1); break; case 0x183: /* V9 fmovqcc %xcc */ -#if defined(CONFIG_USER_ONLY) - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_QT0(rd); - gen_op_load_fpr_QT1(rs2); - flush_T2(dc); - gen_cond[1][cond](); - gen_op_fmovq_cc(); - gen_op_store_QT0_fpr(rd); + CHECK_FPU_FEATURE(dc, FLOAT128); + FMOVQCC(1); break; -#else - goto nfpu_insn; -#endif +#undef FMOVSCC +#undef FMOVDCC +#undef FMOVQCC #endif case 0x51: /* fcmps, V9 %fcc */ - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); -#ifdef TARGET_SPARC64 - gen_fcmps[rd & 3](); -#else - gen_op_fcmps(); -#endif + gen_op_fcmps(rd & 3, cpu_fpr[rs1], cpu_fpr[rs2]); break; case 0x52: /* fcmpd, V9 %fcc */ gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); -#ifdef TARGET_SPARC64 - gen_fcmpd[rd & 3](); -#else - gen_op_fcmpd(); -#endif + gen_op_fcmpd(rd & 3); break; case 0x53: /* fcmpq, V9 %fcc */ -#if defined(CONFIG_USER_ONLY) + CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT0(QFPREG(rs1)); gen_op_load_fpr_QT1(QFPREG(rs2)); -#ifdef TARGET_SPARC64 - gen_fcmpq[rd & 3](); -#else - gen_op_fcmpq(); -#endif + gen_op_fcmpq(rd & 3); break; -#else /* !defined(CONFIG_USER_ONLY) */ - goto nfpu_insn; -#endif case 0x55: /* fcmpes, V9 %fcc */ - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); -#ifdef TARGET_SPARC64 - gen_fcmpes[rd & 3](); -#else - gen_op_fcmpes(); -#endif + gen_op_fcmpes(rd & 3, cpu_fpr[rs1], cpu_fpr[rs2]); break; case 0x56: /* fcmped, V9 %fcc */ gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); -#ifdef TARGET_SPARC64 - gen_fcmped[rd & 3](); -#else - gen_op_fcmped(); -#endif + gen_op_fcmped(rd & 3); break; case 0x57: /* fcmpeq, V9 %fcc */ -#if defined(CONFIG_USER_ONLY) + CHECK_FPU_FEATURE(dc, FLOAT128); gen_op_load_fpr_QT0(QFPREG(rs1)); gen_op_load_fpr_QT1(QFPREG(rs2)); -#ifdef TARGET_SPARC64 - gen_fcmpeq[rd & 3](); -#else - gen_op_fcmpeq(); -#endif + gen_op_fcmpeq(rd & 3); break; -#else/* !defined(CONFIG_USER_ONLY) */ - goto nfpu_insn; -#endif default: goto illegal_insn; } -#if defined(OPTIM) } else if (xop == 0x2) { // clr/mov shortcut rs1 = GET_FIELD(insn, 13, 17); if (rs1 == 0) { - // or %g0, x, y -> mov T1, x; mov y, T1 + // or %g0, x, y -> mov T0, x; mov y, T0 if (IS_IMM) { /* immediate */ + TCGv r_const; + rs2 = GET_FIELDs(insn, 19, 31); - gen_movl_simm_T1(rs2); + r_const = tcg_const_tl((int)rs2); + gen_movl_TN_reg(rd, r_const); + tcg_temp_free(r_const); } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); - gen_movl_reg_T1(rs2); + gen_movl_reg_TN(rs2, cpu_dst); + gen_movl_TN_reg(rd, cpu_dst); } - gen_movl_T1_reg(rd); } else { - gen_movl_reg_T0(rs1); + cpu_src1 = get_src1(insn, cpu_src1); if (IS_IMM) { /* immediate */ - // or x, #0, y -> mov T1, x; mov y, T1 rs2 = GET_FIELDs(insn, 19, 31); - if (rs2 != 0) { - gen_movl_simm_T1(rs2); - gen_op_or_T1_T0(); - } + tcg_gen_ori_tl(cpu_dst, cpu_src1, (int)rs2); + gen_movl_TN_reg(rd, cpu_dst); } else { /* register */ // or x, %g0, y -> mov T1, x; mov y, T1 rs2 = GET_FIELD(insn, 27, 31); if (rs2 != 0) { - gen_movl_reg_T1(rs2); - gen_op_or_T1_T0(); - } + gen_movl_reg_TN(rs2, cpu_src2); + tcg_gen_or_tl(cpu_dst, cpu_src1, cpu_src2); + gen_movl_TN_reg(rd, cpu_dst); + } else + gen_movl_TN_reg(rd, cpu_src1); } - gen_movl_T0_reg(rd); } -#endif #ifdef TARGET_SPARC64 } else if (xop == 0x25) { /* sll, V9 sllx */ - rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); + cpu_src1 = get_src1(insn, cpu_src1); if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 20, 31); - gen_movl_simm_T1(rs2); + if (insn & (1 << 12)) { + tcg_gen_shli_i64(cpu_dst, cpu_src1, rs2 & 0x3f); + } else { + tcg_gen_shli_i64(cpu_dst, cpu_src1, rs2 & 0x1f); + } } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); - gen_movl_reg_T1(rs2); + gen_movl_reg_TN(rs2, cpu_src2); + if (insn & (1 << 12)) { + tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x3f); + } else { + tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x1f); + } + tcg_gen_shl_i64(cpu_dst, cpu_src1, cpu_tmp0); } - if (insn & (1 << 12)) - gen_op_sllx(); - else - gen_op_sll(); - gen_movl_T0_reg(rd); + gen_movl_TN_reg(rd, cpu_dst); } else if (xop == 0x26) { /* srl, V9 srlx */ - rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); + cpu_src1 = get_src1(insn, cpu_src1); if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 20, 31); - gen_movl_simm_T1(rs2); + if (insn & (1 << 12)) { + tcg_gen_shri_i64(cpu_dst, cpu_src1, rs2 & 0x3f); + } else { + tcg_gen_andi_i64(cpu_dst, cpu_src1, 0xffffffffULL); + tcg_gen_shri_i64(cpu_dst, cpu_dst, rs2 & 0x1f); + } } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); - gen_movl_reg_T1(rs2); + gen_movl_reg_TN(rs2, cpu_src2); + if (insn & (1 << 12)) { + tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x3f); + tcg_gen_shr_i64(cpu_dst, cpu_src1, cpu_tmp0); + } else { + tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x1f); + tcg_gen_andi_i64(cpu_dst, cpu_src1, 0xffffffffULL); + tcg_gen_shr_i64(cpu_dst, cpu_dst, cpu_tmp0); + } } - if (insn & (1 << 12)) - gen_op_srlx(); - else - gen_op_srl(); - gen_movl_T0_reg(rd); + gen_movl_TN_reg(rd, cpu_dst); } else if (xop == 0x27) { /* sra, V9 srax */ - rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); + cpu_src1 = get_src1(insn, cpu_src1); if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 20, 31); - gen_movl_simm_T1(rs2); + if (insn & (1 << 12)) { + tcg_gen_sari_i64(cpu_dst, cpu_src1, rs2 & 0x3f); + } else { + tcg_gen_andi_i64(cpu_dst, cpu_src1, 0xffffffffULL); + tcg_gen_ext32s_i64(cpu_dst, cpu_dst); + tcg_gen_sari_i64(cpu_dst, cpu_dst, rs2 & 0x1f); + } } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); - gen_movl_reg_T1(rs2); + gen_movl_reg_TN(rs2, cpu_src2); + if (insn & (1 << 12)) { + tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x3f); + tcg_gen_sar_i64(cpu_dst, cpu_src1, cpu_tmp0); + } else { + tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x1f); + tcg_gen_andi_i64(cpu_dst, cpu_src1, 0xffffffffULL); + tcg_gen_ext32s_i64(cpu_dst, cpu_dst); + tcg_gen_sar_i64(cpu_dst, cpu_dst, cpu_tmp0); + } } - if (insn & (1 << 12)) - gen_op_srax(); - else - gen_op_sra(); - gen_movl_T0_reg(rd); + gen_movl_TN_reg(rd, cpu_dst); #endif } else if (xop < 0x36) { - rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); - if (IS_IMM) { /* immediate */ - rs2 = GET_FIELDs(insn, 19, 31); - gen_movl_simm_T1(rs2); - } else { /* register */ - rs2 = GET_FIELD(insn, 27, 31); - gen_movl_reg_T1(rs2); - } + cpu_src1 = get_src1(insn, cpu_src1); + cpu_src2 = get_src2(insn, cpu_src2); if (xop < 0x20) { switch (xop & ~0x10) { case 0x0: if (xop & 0x10) - gen_op_add_T1_T0_cc(); + gen_op_add_cc(cpu_dst, cpu_src1, cpu_src2); else - gen_op_add_T1_T0(); + tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2); break; case 0x1: - gen_op_and_T1_T0(); + tcg_gen_and_tl(cpu_dst, cpu_src1, cpu_src2); if (xop & 0x10) - gen_op_logic_T0_cc(); + gen_op_logic_cc(cpu_dst); break; case 0x2: - gen_op_or_T1_T0(); + tcg_gen_or_tl(cpu_dst, cpu_src1, cpu_src2); if (xop & 0x10) - gen_op_logic_T0_cc(); + gen_op_logic_cc(cpu_dst); break; case 0x3: - gen_op_xor_T1_T0(); + tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2); if (xop & 0x10) - gen_op_logic_T0_cc(); + gen_op_logic_cc(cpu_dst); break; case 0x4: if (xop & 0x10) - gen_op_sub_T1_T0_cc(); + gen_op_sub_cc(cpu_dst, cpu_src1, cpu_src2); else - gen_op_sub_T1_T0(); + tcg_gen_sub_tl(cpu_dst, cpu_src1, cpu_src2); break; case 0x5: - gen_op_andn_T1_T0(); + tcg_gen_andc_tl(cpu_dst, cpu_src1, cpu_src2); if (xop & 0x10) - gen_op_logic_T0_cc(); + gen_op_logic_cc(cpu_dst); break; case 0x6: - gen_op_orn_T1_T0(); + tcg_gen_orc_tl(cpu_dst, cpu_src1, cpu_src2); if (xop & 0x10) - gen_op_logic_T0_cc(); + gen_op_logic_cc(cpu_dst); break; case 0x7: - gen_op_xnor_T1_T0(); + tcg_gen_not_tl(cpu_tmp0, cpu_src2); + tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_tmp0); if (xop & 0x10) - gen_op_logic_T0_cc(); + gen_op_logic_cc(cpu_dst); break; case 0x8: if (xop & 0x10) - gen_op_addx_T1_T0_cc(); - else - gen_op_addx_T1_T0(); + gen_op_addx_cc(cpu_dst, cpu_src1, cpu_src2); + else { + gen_mov_reg_C(cpu_tmp0, cpu_psr); + tcg_gen_add_tl(cpu_tmp0, cpu_src2, cpu_tmp0); + tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_tmp0); + } break; #ifdef TARGET_SPARC64 case 0x9: /* V9 mulx */ - gen_op_mulx_T1_T0(); + tcg_gen_mul_i64(cpu_dst, cpu_src1, cpu_src2); break; #endif case 0xa: - gen_op_umul_T1_T0(); + CHECK_IU_FEATURE(dc, MUL); + gen_op_umul(cpu_dst, cpu_src1, cpu_src2); if (xop & 0x10) - gen_op_logic_T0_cc(); + gen_op_logic_cc(cpu_dst); break; case 0xb: - gen_op_smul_T1_T0(); + CHECK_IU_FEATURE(dc, MUL); + gen_op_smul(cpu_dst, cpu_src1, cpu_src2); if (xop & 0x10) - gen_op_logic_T0_cc(); + gen_op_logic_cc(cpu_dst); break; case 0xc: if (xop & 0x10) - gen_op_subx_T1_T0_cc(); - else - gen_op_subx_T1_T0(); + gen_op_subx_cc(cpu_dst, cpu_src1, cpu_src2); + else { + gen_mov_reg_C(cpu_tmp0, cpu_psr); + tcg_gen_add_tl(cpu_tmp0, cpu_src2, cpu_tmp0); + tcg_gen_sub_tl(cpu_dst, cpu_src1, cpu_tmp0); + } break; #ifdef TARGET_SPARC64 case 0xd: /* V9 udivx */ - gen_op_udivx_T1_T0(); + tcg_gen_mov_tl(cpu_cc_src, cpu_src1); + tcg_gen_mov_tl(cpu_cc_src2, cpu_src2); + gen_trap_ifdivzero_tl(cpu_cc_src2); + tcg_gen_divu_i64(cpu_dst, cpu_cc_src, cpu_cc_src2); break; #endif case 0xe: - gen_op_udiv_T1_T0(); + CHECK_IU_FEATURE(dc, DIV); + tcg_gen_helper_1_2(helper_udiv, cpu_dst, cpu_src1, + cpu_src2); if (xop & 0x10) - gen_op_div_cc(); + gen_op_div_cc(cpu_dst); break; case 0xf: - gen_op_sdiv_T1_T0(); + CHECK_IU_FEATURE(dc, DIV); + tcg_gen_helper_1_2(helper_sdiv, cpu_dst, cpu_src1, + cpu_src2); if (xop & 0x10) - gen_op_div_cc(); + gen_op_div_cc(cpu_dst); break; default: goto illegal_insn; } - gen_movl_T0_reg(rd); + gen_movl_TN_reg(rd, cpu_dst); } else { switch (xop) { case 0x20: /* taddcc */ - gen_op_tadd_T1_T0_cc(); - gen_movl_T0_reg(rd); + gen_op_tadd_cc(cpu_dst, cpu_src1, cpu_src2); + gen_movl_TN_reg(rd, cpu_dst); break; case 0x21: /* tsubcc */ - gen_op_tsub_T1_T0_cc(); - gen_movl_T0_reg(rd); + gen_op_tsub_cc(cpu_dst, cpu_src1, cpu_src2); + gen_movl_TN_reg(rd, cpu_dst); break; case 0x22: /* taddcctv */ - save_state(dc); - gen_op_tadd_T1_T0_ccTV(); - gen_movl_T0_reg(rd); + save_state(dc, cpu_cond); + gen_op_tadd_ccTV(cpu_dst, cpu_src1, cpu_src2); + gen_movl_TN_reg(rd, cpu_dst); break; case 0x23: /* tsubcctv */ - save_state(dc); - gen_op_tsub_T1_T0_ccTV(); - gen_movl_T0_reg(rd); + save_state(dc, cpu_cond); + gen_op_tsub_ccTV(cpu_dst, cpu_src1, cpu_src2); + gen_movl_TN_reg(rd, cpu_dst); break; case 0x24: /* mulscc */ - gen_op_mulscc_T1_T0(); - gen_movl_T0_reg(rd); + gen_op_mulscc(cpu_dst, cpu_src1, cpu_src2); + gen_movl_TN_reg(rd, cpu_dst); break; #ifndef TARGET_SPARC64 case 0x25: /* sll */ - gen_op_sll(); - gen_movl_T0_reg(rd); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs(insn, 20, 31); + tcg_gen_shli_tl(cpu_dst, cpu_src1, rs2 & 0x1f); + } else { /* register */ + tcg_gen_andi_tl(cpu_tmp0, cpu_src2, 0x1f); + tcg_gen_shl_tl(cpu_dst, cpu_src1, cpu_tmp0); + } + gen_movl_TN_reg(rd, cpu_dst); break; case 0x26: /* srl */ - gen_op_srl(); - gen_movl_T0_reg(rd); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs(insn, 20, 31); + tcg_gen_shri_tl(cpu_dst, cpu_src1, rs2 & 0x1f); + } else { /* register */ + tcg_gen_andi_tl(cpu_tmp0, cpu_src2, 0x1f); + tcg_gen_shr_tl(cpu_dst, cpu_src1, cpu_tmp0); + } + gen_movl_TN_reg(rd, cpu_dst); break; case 0x27: /* sra */ - gen_op_sra(); - gen_movl_T0_reg(rd); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs(insn, 20, 31); + tcg_gen_sari_tl(cpu_dst, cpu_src1, rs2 & 0x1f); + } else { /* register */ + tcg_gen_andi_tl(cpu_tmp0, cpu_src2, 0x1f); + tcg_gen_sar_tl(cpu_dst, cpu_src1, cpu_tmp0); + } + gen_movl_TN_reg(rd, cpu_dst); break; #endif case 0x30: { switch(rd) { case 0: /* wry */ - gen_op_xor_T1_T0(); - gen_op_movtl_env_T0(offsetof(CPUSPARCState, y)); + tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); + tcg_gen_andi_tl(cpu_y, cpu_tmp0, 0xffffffff); break; #ifndef TARGET_SPARC64 case 0x01 ... 0x0f: /* undefined in the @@ -2329,67 +3230,112 @@ break; #else case 0x2: /* V9 wrccr */ - gen_op_xor_T1_T0(); - gen_op_wrccr(); + tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2); + tcg_gen_helper_0_1(helper_wrccr, cpu_dst); break; case 0x3: /* V9 wrasi */ - gen_op_xor_T1_T0(); - gen_op_movl_env_T0(offsetof(CPUSPARCState, asi)); + tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2); + tcg_gen_trunc_tl_i32(cpu_asi, cpu_dst); break; case 0x6: /* V9 wrfprs */ - gen_op_xor_T1_T0(); - gen_op_movl_env_T0(offsetof(CPUSPARCState, fprs)); - save_state(dc); + tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2); + tcg_gen_trunc_tl_i32(cpu_fprs, cpu_dst); + save_state(dc, cpu_cond); gen_op_next_insn(); - gen_op_movl_T0_0(); - gen_op_exit_tb(); + tcg_gen_exit_tb(0); dc->is_br = 1; break; case 0xf: /* V9 sir, nop if user */ #if !defined(CONFIG_USER_ONLY) if (supervisor(dc)) - gen_op_sir(); + ; // XXX #endif break; case 0x13: /* Graphics Status */ - if (gen_trap_ifnofpu(dc)) + if (gen_trap_ifnofpu(dc, cpu_cond)) goto jmp_insn; - gen_op_xor_T1_T0(); - gen_op_movtl_env_T0(offsetof(CPUSPARCState, gsr)); + tcg_gen_xor_tl(cpu_gsr, cpu_src1, cpu_src2); + break; + case 0x14: /* Softint set */ + if (!supervisor(dc)) + goto illegal_insn; + tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2); + tcg_gen_helper_0_1(helper_set_softint, + cpu_tmp64); + break; + case 0x15: /* Softint clear */ + if (!supervisor(dc)) + goto illegal_insn; + tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2); + tcg_gen_helper_0_1(helper_clear_softint, + cpu_tmp64); + break; + case 0x16: /* Softint write */ + if (!supervisor(dc)) + goto illegal_insn; + tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2); + tcg_gen_helper_0_1(helper_write_softint, + cpu_tmp64); break; case 0x17: /* Tick compare */ #if !defined(CONFIG_USER_ONLY) if (!supervisor(dc)) goto illegal_insn; #endif - gen_op_xor_T1_T0(); - gen_op_movtl_env_T0(offsetof(CPUSPARCState, tick_cmpr)); - gen_op_wrtick_cmpr(); + { + TCGv r_tickptr; + + tcg_gen_xor_tl(cpu_tick_cmpr, cpu_src1, + cpu_src2); + r_tickptr = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_ld_ptr(r_tickptr, cpu_env, + offsetof(CPUState, tick)); + tcg_gen_helper_0_2(helper_tick_set_limit, + r_tickptr, cpu_tick_cmpr); + tcg_temp_free(r_tickptr); + } break; case 0x18: /* System tick */ #if !defined(CONFIG_USER_ONLY) if (!supervisor(dc)) goto illegal_insn; #endif - gen_op_xor_T1_T0(); - gen_op_wrstick(); + { + TCGv r_tickptr; + + tcg_gen_xor_tl(cpu_dst, cpu_src1, + cpu_src2); + r_tickptr = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_ld_ptr(r_tickptr, cpu_env, + offsetof(CPUState, stick)); + tcg_gen_helper_0_2(helper_tick_set_count, + r_tickptr, cpu_dst); + tcg_temp_free(r_tickptr); + } break; case 0x19: /* System tick compare */ #if !defined(CONFIG_USER_ONLY) if (!supervisor(dc)) goto illegal_insn; #endif - gen_op_xor_T1_T0(); - gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr)); - gen_op_wrstick_cmpr(); + { + TCGv r_tickptr; + + tcg_gen_xor_tl(cpu_stick_cmpr, cpu_src1, + cpu_src2); + r_tickptr = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_ld_ptr(r_tickptr, cpu_env, + offsetof(CPUState, stick)); + tcg_gen_helper_0_2(helper_tick_set_limit, + r_tickptr, cpu_stick_cmpr); + tcg_temp_free(r_tickptr); + } break; case 0x10: /* Performance Control */ - case 0x11: /* Performance Instrumentation Counter */ + case 0x11: /* Performance Instrumentation + Counter */ case 0x12: /* Dispatch Control */ - case 0x14: /* Softint set */ - case 0x15: /* Softint clear */ - case 0x16: /* Softint write */ #endif default: goto illegal_insn; @@ -2404,10 +3350,10 @@ #ifdef TARGET_SPARC64 switch (rd) { case 0: - gen_op_saved(); + tcg_gen_helper_0_0(helper_saved); break; case 1: - gen_op_restored(); + tcg_gen_helper_0_0(helper_restored); break; case 2: /* UA2005 allclean */ case 3: /* UA2005 otherw */ @@ -2418,12 +3364,11 @@ goto illegal_insn; } #else - gen_op_xor_T1_T0(); - gen_op_wrpsr(); - save_state(dc); + tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2); + tcg_gen_helper_0_1(helper_wrpsr, cpu_dst); + save_state(dc, cpu_cond); gen_op_next_insn(); - gen_op_movl_T0_0(); - gen_op_exit_tb(); + tcg_gen_exit_tb(0); dc->is_br = 1; #endif } @@ -2432,72 +3377,146 @@ { if (!supervisor(dc)) goto priv_insn; - gen_op_xor_T1_T0(); + tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); #ifdef TARGET_SPARC64 switch (rd) { case 0: // tpc - gen_op_wrtpc(); + { + TCGv r_tsptr; + + r_tsptr = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_ld_ptr(r_tsptr, cpu_env, + offsetof(CPUState, tsptr)); + tcg_gen_st_tl(cpu_tmp0, r_tsptr, + offsetof(trap_state, tpc)); + tcg_temp_free(r_tsptr); + } break; case 1: // tnpc - gen_op_wrtnpc(); + { + TCGv r_tsptr; + + r_tsptr = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_ld_ptr(r_tsptr, cpu_env, + offsetof(CPUState, tsptr)); + tcg_gen_st_tl(cpu_tmp0, r_tsptr, + offsetof(trap_state, tnpc)); + tcg_temp_free(r_tsptr); + } break; case 2: // tstate - gen_op_wrtstate(); + { + TCGv r_tsptr; + + r_tsptr = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_ld_ptr(r_tsptr, cpu_env, + offsetof(CPUState, tsptr)); + tcg_gen_st_tl(cpu_tmp0, r_tsptr, + offsetof(trap_state, + tstate)); + tcg_temp_free(r_tsptr); + } break; case 3: // tt - gen_op_wrtt(); + { + TCGv r_tsptr; + + r_tsptr = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_ld_ptr(r_tsptr, cpu_env, + offsetof(CPUState, tsptr)); + tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); + tcg_gen_st_i32(cpu_tmp32, r_tsptr, + offsetof(trap_state, tt)); + tcg_temp_free(r_tsptr); + } break; case 4: // tick - gen_op_wrtick(); + { + TCGv r_tickptr; + + r_tickptr = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_ld_ptr(r_tickptr, cpu_env, + offsetof(CPUState, tick)); + tcg_gen_helper_0_2(helper_tick_set_count, + r_tickptr, cpu_tmp0); + tcg_temp_free(r_tickptr); + } break; case 5: // tba - gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr)); + tcg_gen_mov_tl(cpu_tbr, cpu_tmp0); break; case 6: // pstate - gen_op_wrpstate(); - save_state(dc); + save_state(dc, cpu_cond); + tcg_gen_helper_0_1(helper_wrpstate, cpu_tmp0); gen_op_next_insn(); - gen_op_movl_T0_0(); - gen_op_exit_tb(); + tcg_gen_exit_tb(0); dc->is_br = 1; break; case 7: // tl - gen_op_movl_env_T0(offsetof(CPUSPARCState, tl)); + tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); + tcg_gen_st_i32(cpu_tmp32, cpu_env, + offsetof(CPUSPARCState, tl)); break; case 8: // pil - gen_op_movl_env_T0(offsetof(CPUSPARCState, psrpil)); + tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); + tcg_gen_st_i32(cpu_tmp32, cpu_env, + offsetof(CPUSPARCState, + psrpil)); break; case 9: // cwp - gen_op_wrcwp(); + tcg_gen_helper_0_1(helper_wrcwp, cpu_tmp0); break; case 10: // cansave - gen_op_movl_env_T0(offsetof(CPUSPARCState, cansave)); + tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); + tcg_gen_st_i32(cpu_tmp32, cpu_env, + offsetof(CPUSPARCState, + cansave)); break; case 11: // canrestore - gen_op_movl_env_T0(offsetof(CPUSPARCState, canrestore)); + tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); + tcg_gen_st_i32(cpu_tmp32, cpu_env, + offsetof(CPUSPARCState, + canrestore)); break; case 12: // cleanwin - gen_op_movl_env_T0(offsetof(CPUSPARCState, cleanwin)); + tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); + tcg_gen_st_i32(cpu_tmp32, cpu_env, + offsetof(CPUSPARCState, + cleanwin)); break; case 13: // otherwin - gen_op_movl_env_T0(offsetof(CPUSPARCState, otherwin)); + tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); + tcg_gen_st_i32(cpu_tmp32, cpu_env, + offsetof(CPUSPARCState, + otherwin)); break; case 14: // wstate - gen_op_movl_env_T0(offsetof(CPUSPARCState, wstate)); + tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); + tcg_gen_st_i32(cpu_tmp32, cpu_env, + offsetof(CPUSPARCState, + wstate)); break; case 16: // UA2005 gl - gen_op_movl_env_T0(offsetof(CPUSPARCState, gl)); + CHECK_IU_FEATURE(dc, GL); + tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); + tcg_gen_st_i32(cpu_tmp32, cpu_env, + offsetof(CPUSPARCState, gl)); break; case 26: // UA2005 strand status + CHECK_IU_FEATURE(dc, HYPV); if (!hypervisor(dc)) goto priv_insn; - gen_op_movl_env_T0(offsetof(CPUSPARCState, ssr)); + tcg_gen_mov_tl(cpu_ssr, cpu_tmp0); break; default: goto illegal_insn; } #else - gen_op_wrwim(); + tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); + if (dc->def->nwindows != 32) + tcg_gen_andi_tl(cpu_tmp32, cpu_tmp32, + (1 << dc->def->nwindows) - 1); + tcg_gen_mov_i32(cpu_wim, cpu_tmp32); #endif } break; @@ -2506,33 +3525,41 @@ #ifndef TARGET_SPARC64 if (!supervisor(dc)) goto priv_insn; - gen_op_xor_T1_T0(); - gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr)); + tcg_gen_xor_tl(cpu_tbr, cpu_src1, cpu_src2); #else + CHECK_IU_FEATURE(dc, HYPV); if (!hypervisor(dc)) goto priv_insn; - gen_op_xor_T1_T0(); + tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); switch (rd) { case 0: // hpstate // XXX gen_op_wrhpstate(); - save_state(dc); + save_state(dc, cpu_cond); gen_op_next_insn(); - gen_op_movl_T0_0(); - gen_op_exit_tb(); + tcg_gen_exit_tb(0); dc->is_br = 1; break; case 1: // htstate // XXX gen_op_wrhtstate(); break; case 3: // hintp - gen_op_movl_env_T0(offsetof(CPUSPARCState, hintp)); + tcg_gen_mov_tl(cpu_hintp, cpu_tmp0); break; case 5: // htba - gen_op_movl_env_T0(offsetof(CPUSPARCState, htba)); + tcg_gen_mov_tl(cpu_htba, cpu_tmp0); break; case 31: // hstick_cmpr - gen_op_movtl_env_T0(offsetof(CPUSPARCState, hstick_cmpr)); - gen_op_wrhstick_cmpr(); + { + TCGv r_tickptr; + + tcg_gen_mov_tl(cpu_hstick_cmpr, cpu_tmp0); + r_tickptr = tcg_temp_new(TCG_TYPE_PTR); + tcg_gen_ld_ptr(r_tickptr, cpu_env, + offsetof(CPUState, hstick)); + tcg_gen_helper_0_2(helper_tick_set_limit, + r_tickptr, cpu_hstick_cmpr); + tcg_temp_free(r_tickptr); + } break; case 6: // hver readonly default: @@ -2547,66 +3574,75 @@ { int cc = GET_FIELD_SP(insn, 11, 12); int cond = GET_FIELD_SP(insn, 14, 17); - if (IS_IMM) { /* immediate */ - rs2 = GET_FIELD_SPs(insn, 0, 10); - gen_movl_simm_T1(rs2); - } - else { - rs2 = GET_FIELD_SP(insn, 0, 4); - gen_movl_reg_T1(rs2); - } - gen_movl_reg_T0(rd); - flush_T2(dc); + TCGv r_cond; + int l1; + + r_cond = tcg_temp_new(TCG_TYPE_TL); if (insn & (1 << 18)) { if (cc == 0) - gen_cond[0][cond](); + gen_cond(r_cond, 0, cond); else if (cc == 2) - gen_cond[1][cond](); + gen_cond(r_cond, 1, cond); else goto illegal_insn; } else { - gen_fcond[cc][cond](); + gen_fcond(r_cond, cc, cond); + } + + l1 = gen_new_label(); + + tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1); + if (IS_IMM) { /* immediate */ + TCGv r_const; + + rs2 = GET_FIELD_SPs(insn, 0, 10); + r_const = tcg_const_tl((int)rs2); + gen_movl_TN_reg(rd, r_const); + tcg_temp_free(r_const); + } else { + rs2 = GET_FIELD_SP(insn, 0, 4); + gen_movl_reg_TN(rs2, cpu_tmp0); + gen_movl_TN_reg(rd, cpu_tmp0); } - gen_op_mov_cc(); - gen_movl_T0_reg(rd); + gen_set_label(l1); + tcg_temp_free(r_cond); break; } case 0x2d: /* V9 sdivx */ - gen_op_sdivx_T1_T0(); - gen_movl_T0_reg(rd); + gen_op_sdivx(cpu_dst, cpu_src1, cpu_src2); + gen_movl_TN_reg(rd, cpu_dst); break; case 0x2e: /* V9 popc */ { - if (IS_IMM) { /* immediate */ - rs2 = GET_FIELD_SPs(insn, 0, 12); - gen_movl_simm_T1(rs2); - // XXX optimize: popc(constant) - } - else { - rs2 = GET_FIELD_SP(insn, 0, 4); - gen_movl_reg_T1(rs2); - } - gen_op_popc(); - gen_movl_T0_reg(rd); + cpu_src2 = get_src2(insn, cpu_src2); + tcg_gen_helper_1_1(helper_popc, cpu_dst, + cpu_src2); + gen_movl_TN_reg(rd, cpu_dst); } case 0x2f: /* V9 movr */ { int cond = GET_FIELD_SP(insn, 10, 12); - rs1 = GET_FIELD(insn, 13, 17); - flush_T2(dc); - gen_movl_reg_T0(rs1); - gen_cond_reg(cond); + int l1; + + cpu_src1 = get_src1(insn, cpu_src1); + + l1 = gen_new_label(); + + tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], + cpu_src1, 0, l1); if (IS_IMM) { /* immediate */ + TCGv r_const; + rs2 = GET_FIELD_SPs(insn, 0, 9); - gen_movl_simm_T1(rs2); - } - else { + r_const = tcg_const_tl((int)rs2); + gen_movl_TN_reg(rd, r_const); + tcg_temp_free(r_const); + } else { rs2 = GET_FIELD_SP(insn, 0, 4); - gen_movl_reg_T1(rs2); + gen_movl_reg_TN(rs2, cpu_tmp0); + gen_movl_TN_reg(rd, cpu_tmp0); } - gen_movl_reg_T0(rd); - gen_op_mov_cc(); - gen_movl_T0_reg(rd); + gen_set_label(l1); break; } #endif @@ -2619,7 +3655,7 @@ int opf = GET_FIELD_SP(insn, 5, 13); rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); - if (gen_trap_ifnofpu(dc)) + if (gen_trap_ifnofpu(dc, cpu_cond)) goto jmp_insn; switch (opf) { @@ -2638,121 +3674,146 @@ // XXX goto illegal_insn; case 0x010: /* VIS I array8 */ - gen_movl_reg_T0(rs1); - gen_movl_reg_T1(rs2); - gen_op_array8(); - gen_movl_T0_reg(rd); + CHECK_FPU_FEATURE(dc, VIS1); + cpu_src1 = get_src1(insn, cpu_src1); + gen_movl_reg_TN(rs2, cpu_src2); + tcg_gen_helper_1_2(helper_array8, cpu_dst, cpu_src1, + cpu_src2); + gen_movl_TN_reg(rd, cpu_dst); break; case 0x012: /* VIS I array16 */ - gen_movl_reg_T0(rs1); - gen_movl_reg_T1(rs2); - gen_op_array16(); - gen_movl_T0_reg(rd); + CHECK_FPU_FEATURE(dc, VIS1); + cpu_src1 = get_src1(insn, cpu_src1); + gen_movl_reg_TN(rs2, cpu_src2); + tcg_gen_helper_1_2(helper_array8, cpu_dst, cpu_src1, + cpu_src2); + tcg_gen_shli_i64(cpu_dst, cpu_dst, 1); + gen_movl_TN_reg(rd, cpu_dst); break; case 0x014: /* VIS I array32 */ - gen_movl_reg_T0(rs1); - gen_movl_reg_T1(rs2); - gen_op_array32(); - gen_movl_T0_reg(rd); + CHECK_FPU_FEATURE(dc, VIS1); + cpu_src1 = get_src1(insn, cpu_src1); + gen_movl_reg_TN(rs2, cpu_src2); + tcg_gen_helper_1_2(helper_array8, cpu_dst, cpu_src1, + cpu_src2); + tcg_gen_shli_i64(cpu_dst, cpu_dst, 2); + gen_movl_TN_reg(rd, cpu_dst); break; case 0x018: /* VIS I alignaddr */ - gen_movl_reg_T0(rs1); - gen_movl_reg_T1(rs2); - gen_op_alignaddr(); - gen_movl_T0_reg(rd); + CHECK_FPU_FEATURE(dc, VIS1); + cpu_src1 = get_src1(insn, cpu_src1); + gen_movl_reg_TN(rs2, cpu_src2); + tcg_gen_helper_1_2(helper_alignaddr, cpu_dst, cpu_src1, + cpu_src2); + gen_movl_TN_reg(rd, cpu_dst); break; case 0x019: /* VIS II bmask */ case 0x01a: /* VIS I alignaddrl */ // XXX goto illegal_insn; case 0x020: /* VIS I fcmple16 */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fcmple16(); + tcg_gen_helper_0_0(helper_fcmple16); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x022: /* VIS I fcmpne16 */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fcmpne16(); + tcg_gen_helper_0_0(helper_fcmpne16); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x024: /* VIS I fcmple32 */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fcmple32(); + tcg_gen_helper_0_0(helper_fcmple32); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x026: /* VIS I fcmpne32 */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fcmpne32(); + tcg_gen_helper_0_0(helper_fcmpne32); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x028: /* VIS I fcmpgt16 */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fcmpgt16(); + tcg_gen_helper_0_0(helper_fcmpgt16); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x02a: /* VIS I fcmpeq16 */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fcmpeq16(); + tcg_gen_helper_0_0(helper_fcmpeq16); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x02c: /* VIS I fcmpgt32 */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fcmpgt32(); + tcg_gen_helper_0_0(helper_fcmpgt32); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x02e: /* VIS I fcmpeq32 */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fcmpeq32(); + tcg_gen_helper_0_0(helper_fcmpeq32); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x031: /* VIS I fmul8x16 */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fmul8x16(); + tcg_gen_helper_0_0(helper_fmul8x16); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x033: /* VIS I fmul8x16au */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fmul8x16au(); + tcg_gen_helper_0_0(helper_fmul8x16au); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x035: /* VIS I fmul8x16al */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fmul8x16al(); + tcg_gen_helper_0_0(helper_fmul8x16al); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x036: /* VIS I fmul8sux16 */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fmul8sux16(); + tcg_gen_helper_0_0(helper_fmul8sux16); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x037: /* VIS I fmul8ulx16 */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fmul8ulx16(); + tcg_gen_helper_0_0(helper_fmul8ulx16); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x038: /* VIS I fmuld8sux16 */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fmuld8sux16(); + tcg_gen_helper_0_0(helper_fmuld8sux16); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x039: /* VIS I fmuld8ulx16 */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fmuld8ulx16(); + tcg_gen_helper_0_0(helper_fmuld8ulx16); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x03a: /* VIS I fpack32 */ @@ -2762,245 +3823,253 @@ // XXX goto illegal_insn; case 0x048: /* VIS I faligndata */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_faligndata(); + tcg_gen_helper_0_0(helper_faligndata); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x04b: /* VIS I fpmerge */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fpmerge(); + tcg_gen_helper_0_0(helper_fpmerge); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x04c: /* VIS II bshuffle */ // XXX goto illegal_insn; case 0x04d: /* VIS I fexpand */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fexpand(); + tcg_gen_helper_0_0(helper_fexpand); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x050: /* VIS I fpadd16 */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fpadd16(); + tcg_gen_helper_0_0(helper_fpadd16); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x051: /* VIS I fpadd16s */ - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fpadd16s(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_helper_1_2(helper_fpadd16s, cpu_fpr[rd], + cpu_fpr[rs1], cpu_fpr[rs2]); break; case 0x052: /* VIS I fpadd32 */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fpadd32(); + tcg_gen_helper_0_0(helper_fpadd32); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x053: /* VIS I fpadd32s */ - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fpadd32s(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_helper_1_2(helper_fpadd32s, cpu_fpr[rd], + cpu_fpr[rs1], cpu_fpr[rs2]); break; case 0x054: /* VIS I fpsub16 */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fpsub16(); + tcg_gen_helper_0_0(helper_fpsub16); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x055: /* VIS I fpsub16s */ - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fpsub16s(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_helper_1_2(helper_fpsub16s, cpu_fpr[rd], + cpu_fpr[rs1], cpu_fpr[rs2]); break; case 0x056: /* VIS I fpsub32 */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fpadd32(); + tcg_gen_helper_0_0(helper_fpsub32); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x057: /* VIS I fpsub32s */ - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fpsub32s(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_helper_1_2(helper_fpsub32s, cpu_fpr[rd], + cpu_fpr[rs1], cpu_fpr[rs2]); break; case 0x060: /* VIS I fzero */ - gen_op_movl_DT0_0(); - gen_op_store_DT0_fpr(DFPREG(rd)); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_movi_i32(cpu_fpr[DFPREG(rd)], 0); + tcg_gen_movi_i32(cpu_fpr[DFPREG(rd) + 1], 0); break; case 0x061: /* VIS I fzeros */ - gen_op_movl_FT0_0(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_movi_i32(cpu_fpr[rd], 0); break; case 0x062: /* VIS I fnor */ - gen_op_load_fpr_DT0(DFPREG(rs1)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fnor(); - gen_op_store_DT0_fpr(DFPREG(rd)); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_nor_i32(cpu_tmp32, cpu_fpr[DFPREG(rs1)], + cpu_fpr[DFPREG(rs2)]); + tcg_gen_nor_i32(cpu_tmp32, cpu_fpr[DFPREG(rs1) + 1], + cpu_fpr[DFPREG(rs2) + 1]); break; case 0x063: /* VIS I fnors */ - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fnors(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_nor_i32(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]); break; case 0x064: /* VIS I fandnot2 */ - gen_op_load_fpr_DT1(DFPREG(rs1)); - gen_op_load_fpr_DT0(DFPREG(rs2)); - gen_op_fandnot(); - gen_op_store_DT0_fpr(DFPREG(rd)); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_andc_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)], + cpu_fpr[DFPREG(rs2)]); + tcg_gen_andc_i32(cpu_fpr[DFPREG(rd) + 1], + cpu_fpr[DFPREG(rs1) + 1], + cpu_fpr[DFPREG(rs2) + 1]); break; case 0x065: /* VIS I fandnot2s */ - gen_op_load_fpr_FT1(rs1); - gen_op_load_fpr_FT0(rs2); - gen_op_fandnots(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_andc_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]); break; case 0x066: /* VIS I fnot2 */ - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fnot(); - gen_op_store_DT0_fpr(DFPREG(rd)); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_not_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)]); + tcg_gen_not_i32(cpu_fpr[DFPREG(rd) + 1], + cpu_fpr[DFPREG(rs2) + 1]); break; case 0x067: /* VIS I fnot2s */ - gen_op_load_fpr_FT1(rs2); - gen_op_fnot(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_not_i32(cpu_fpr[rd], cpu_fpr[rs2]); break; case 0x068: /* VIS I fandnot1 */ - gen_op_load_fpr_DT0(DFPREG(rs1)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fandnot(); - gen_op_store_DT0_fpr(DFPREG(rd)); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_andc_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)], + cpu_fpr[DFPREG(rs1)]); + tcg_gen_andc_i32(cpu_fpr[DFPREG(rd) + 1], + cpu_fpr[DFPREG(rs2) + 1], + cpu_fpr[DFPREG(rs1) + 1]); break; case 0x069: /* VIS I fandnot1s */ - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fandnots(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_andc_i32(cpu_fpr[rd], cpu_fpr[rs2], cpu_fpr[rs1]); break; case 0x06a: /* VIS I fnot1 */ - gen_op_load_fpr_DT1(DFPREG(rs1)); - gen_op_fnot(); - gen_op_store_DT0_fpr(DFPREG(rd)); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_not_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)]); + tcg_gen_not_i32(cpu_fpr[DFPREG(rd) + 1], + cpu_fpr[DFPREG(rs1) + 1]); break; case 0x06b: /* VIS I fnot1s */ - gen_op_load_fpr_FT1(rs1); - gen_op_fnot(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_not_i32(cpu_fpr[rd], cpu_fpr[rs1]); break; case 0x06c: /* VIS I fxor */ - gen_op_load_fpr_DT0(DFPREG(rs1)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fxor(); - gen_op_store_DT0_fpr(DFPREG(rd)); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_xor_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)], + cpu_fpr[DFPREG(rs2)]); + tcg_gen_xor_i32(cpu_fpr[DFPREG(rd) + 1], + cpu_fpr[DFPREG(rs1) + 1], + cpu_fpr[DFPREG(rs2) + 1]); break; case 0x06d: /* VIS I fxors */ - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fxors(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_xor_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]); break; case 0x06e: /* VIS I fnand */ - gen_op_load_fpr_DT0(DFPREG(rs1)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fnand(); - gen_op_store_DT0_fpr(DFPREG(rd)); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_nand_i32(cpu_tmp32, cpu_fpr[DFPREG(rs1)], + cpu_fpr[DFPREG(rs2)]); + tcg_gen_nand_i32(cpu_tmp32, cpu_fpr[DFPREG(rs1) + 1], + cpu_fpr[DFPREG(rs2) + 1]); break; case 0x06f: /* VIS I fnands */ - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fnands(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_nand_i32(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]); break; case 0x070: /* VIS I fand */ - gen_op_load_fpr_DT0(DFPREG(rs1)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fand(); - gen_op_store_DT0_fpr(DFPREG(rd)); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_and_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)], + cpu_fpr[DFPREG(rs2)]); + tcg_gen_and_i32(cpu_fpr[DFPREG(rd) + 1], + cpu_fpr[DFPREG(rs1) + 1], + cpu_fpr[DFPREG(rs2) + 1]); break; case 0x071: /* VIS I fands */ - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fands(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_and_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]); break; case 0x072: /* VIS I fxnor */ - gen_op_load_fpr_DT0(DFPREG(rs1)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fxnor(); - gen_op_store_DT0_fpr(DFPREG(rd)); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_xori_i32(cpu_tmp32, cpu_fpr[DFPREG(rs2)], -1); + tcg_gen_xor_i32(cpu_fpr[DFPREG(rd)], cpu_tmp32, + cpu_fpr[DFPREG(rs1)]); + tcg_gen_xori_i32(cpu_tmp32, cpu_fpr[DFPREG(rs2) + 1], -1); + tcg_gen_xor_i32(cpu_fpr[DFPREG(rd) + 1], cpu_tmp32, + cpu_fpr[DFPREG(rs1) + 1]); break; case 0x073: /* VIS I fxnors */ - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fxnors(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_xori_i32(cpu_tmp32, cpu_fpr[rs2], -1); + tcg_gen_xor_i32(cpu_fpr[rd], cpu_tmp32, cpu_fpr[rs1]); break; case 0x074: /* VIS I fsrc1 */ - gen_op_load_fpr_DT0(DFPREG(rs1)); - gen_op_store_DT0_fpr(DFPREG(rd)); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)]); + tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1], + cpu_fpr[DFPREG(rs1) + 1]); break; case 0x075: /* VIS I fsrc1s */ - gen_op_load_fpr_FT0(rs1); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs1]); break; case 0x076: /* VIS I fornot2 */ - gen_op_load_fpr_DT1(DFPREG(rs1)); - gen_op_load_fpr_DT0(DFPREG(rs2)); - gen_op_fornot(); - gen_op_store_DT0_fpr(DFPREG(rd)); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_orc_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)], + cpu_fpr[DFPREG(rs2)]); + tcg_gen_orc_i32(cpu_fpr[DFPREG(rd) + 1], + cpu_fpr[DFPREG(rs1) + 1], + cpu_fpr[DFPREG(rs2) + 1]); break; case 0x077: /* VIS I fornot2s */ - gen_op_load_fpr_FT1(rs1); - gen_op_load_fpr_FT0(rs2); - gen_op_fornots(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_orc_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]); break; case 0x078: /* VIS I fsrc2 */ + CHECK_FPU_FEATURE(dc, VIS1); gen_op_load_fpr_DT0(DFPREG(rs2)); gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x079: /* VIS I fsrc2s */ - gen_op_load_fpr_FT0(rs2); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]); break; case 0x07a: /* VIS I fornot1 */ - gen_op_load_fpr_DT0(DFPREG(rs1)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fornot(); - gen_op_store_DT0_fpr(DFPREG(rd)); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_orc_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)], + cpu_fpr[DFPREG(rs1)]); + tcg_gen_orc_i32(cpu_fpr[DFPREG(rd) + 1], + cpu_fpr[DFPREG(rs2) + 1], + cpu_fpr[DFPREG(rs1) + 1]); break; case 0x07b: /* VIS I fornot1s */ - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fornots(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_orc_i32(cpu_fpr[rd], cpu_fpr[rs2], cpu_fpr[rs1]); break; case 0x07c: /* VIS I for */ - gen_op_load_fpr_DT0(DFPREG(rs1)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_for(); - gen_op_store_DT0_fpr(DFPREG(rd)); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_or_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)], + cpu_fpr[DFPREG(rs2)]); + tcg_gen_or_i32(cpu_fpr[DFPREG(rd) + 1], + cpu_fpr[DFPREG(rs1) + 1], + cpu_fpr[DFPREG(rs2) + 1]); break; case 0x07d: /* VIS I fors */ - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fors(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_or_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]); break; case 0x07e: /* VIS I fone */ - gen_op_movl_DT0_1(); - gen_op_store_DT0_fpr(DFPREG(rd)); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_movi_i32(cpu_fpr[DFPREG(rd)], -1); + tcg_gen_movi_i32(cpu_fpr[DFPREG(rd) + 1], -1); break; case 0x07f: /* VIS I fones */ - gen_op_movl_FT0_1(); - gen_op_store_FT0_fpr(rd); + CHECK_FPU_FEATURE(dc, VIS1); + tcg_gen_movi_i32(cpu_fpr[rd], -1); break; case 0x080: /* VIS I shutdown */ case 0x081: /* VIS II siam */ @@ -3020,107 +4089,92 @@ #endif #ifdef TARGET_SPARC64 } else if (xop == 0x39) { /* V9 return */ - rs1 = GET_FIELD(insn, 13, 17); - save_state(dc); - gen_movl_reg_T0(rs1); + TCGv r_const; + + save_state(dc, cpu_cond); + cpu_src1 = get_src1(insn, cpu_src1); if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 19, 31); -#if defined(OPTIM) - if (rs2) { -#endif - gen_movl_simm_T1(rs2); - gen_op_add_T1_T0(); -#if defined(OPTIM) - } -#endif + tcg_gen_addi_tl(cpu_dst, cpu_src1, (int)rs2); } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); -#if defined(OPTIM) if (rs2) { -#endif - gen_movl_reg_T1(rs2); - gen_op_add_T1_T0(); -#if defined(OPTIM) - } -#endif + gen_movl_reg_TN(rs2, cpu_src2); + tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2); + } else + tcg_gen_mov_tl(cpu_dst, cpu_src1); } - gen_op_restore(); - gen_mov_pc_npc(dc); - gen_op_check_align_T0_3(); - gen_op_movl_npc_T0(); + tcg_gen_helper_0_0(helper_restore); + gen_mov_pc_npc(dc, cpu_cond); + r_const = tcg_const_i32(3); + tcg_gen_helper_0_2(helper_check_align, cpu_dst, r_const); + tcg_temp_free(r_const); + tcg_gen_mov_tl(cpu_npc, cpu_dst); dc->npc = DYNAMIC_PC; goto jmp_insn; #endif } else { - rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); + cpu_src1 = get_src1(insn, cpu_src1); if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 19, 31); -#if defined(OPTIM) - if (rs2) { -#endif - gen_movl_simm_T1(rs2); - gen_op_add_T1_T0(); -#if defined(OPTIM) - } -#endif + tcg_gen_addi_tl(cpu_dst, cpu_src1, (int)rs2); } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); -#if defined(OPTIM) if (rs2) { -#endif - gen_movl_reg_T1(rs2); - gen_op_add_T1_T0(); -#if defined(OPTIM) - } -#endif + gen_movl_reg_TN(rs2, cpu_src2); + tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2); + } else + tcg_gen_mov_tl(cpu_dst, cpu_src1); } switch (xop) { case 0x38: /* jmpl */ { - if (rd != 0) { -#ifdef TARGET_SPARC64 - if (dc->pc == (uint32_t)dc->pc) { - gen_op_movl_T1_im(dc->pc); - } else { - gen_op_movq_T1_im64(dc->pc >> 32, dc->pc); - } -#else - gen_op_movl_T1_im(dc->pc); -#endif - gen_movl_T1_reg(rd); - } - gen_mov_pc_npc(dc); - gen_op_check_align_T0_3(); - gen_op_movl_npc_T0(); + TCGv r_const; + + r_const = tcg_const_tl(dc->pc); + gen_movl_TN_reg(rd, r_const); + tcg_temp_free(r_const); + gen_mov_pc_npc(dc, cpu_cond); + r_const = tcg_const_i32(3); + tcg_gen_helper_0_2(helper_check_align, cpu_dst, + r_const); + tcg_temp_free(r_const); + tcg_gen_mov_tl(cpu_npc, cpu_dst); dc->npc = DYNAMIC_PC; } goto jmp_insn; #if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64) case 0x39: /* rett, V9 return */ { + TCGv r_const; + if (!supervisor(dc)) goto priv_insn; - gen_mov_pc_npc(dc); - gen_op_check_align_T0_3(); - gen_op_movl_npc_T0(); + gen_mov_pc_npc(dc, cpu_cond); + r_const = tcg_const_i32(3); + tcg_gen_helper_0_2(helper_check_align, cpu_dst, + r_const); + tcg_temp_free(r_const); + tcg_gen_mov_tl(cpu_npc, cpu_dst); dc->npc = DYNAMIC_PC; - gen_op_rett(); + tcg_gen_helper_0_0(helper_rett); } goto jmp_insn; #endif case 0x3b: /* flush */ - gen_op_flush_T0(); + if (!((dc)->def->features & CPU_FEATURE_FLUSH)) + goto unimp_flush; + tcg_gen_helper_0_1(helper_flush, cpu_dst); break; case 0x3c: /* save */ - save_state(dc); - gen_op_save(); - gen_movl_T0_reg(rd); + save_state(dc, cpu_cond); + tcg_gen_helper_0_0(helper_save); + gen_movl_TN_reg(rd, cpu_dst); break; case 0x3d: /* restore */ - save_state(dc); - gen_op_restore(); - gen_movl_T0_reg(rd); + save_state(dc, cpu_cond); + tcg_gen_helper_0_0(helper_restore); + gen_movl_TN_reg(rd, cpu_dst); break; #if !defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64) case 0x3e: /* V9 done/retry */ @@ -3131,14 +4185,14 @@ goto priv_insn; dc->npc = DYNAMIC_PC; dc->pc = DYNAMIC_PC; - gen_op_done(); + tcg_gen_helper_0_0(helper_done); goto jmp_insn; case 1: if (!supervisor(dc)) goto priv_insn; dc->npc = DYNAMIC_PC; dc->pc = DYNAMIC_PC; - gen_op_retry(); + tcg_gen_helper_0_0(helper_retry); goto jmp_insn; default: goto illegal_insn; @@ -3156,75 +4210,87 @@ case 3: /* load/store instructions */ { unsigned int xop = GET_FIELD(insn, 7, 12); - rs1 = GET_FIELD(insn, 13, 17); - save_state(dc); - gen_movl_reg_T0(rs1); - if (xop == 0x3c || xop == 0x3e) - { + + cpu_src1 = get_src1(insn, cpu_src1); + if (xop == 0x3c || xop == 0x3e) { // V9 casa/casxa rs2 = GET_FIELD(insn, 27, 31); - gen_movl_reg_T1(rs2); - } - else if (IS_IMM) { /* immediate */ + gen_movl_reg_TN(rs2, cpu_src2); + tcg_gen_mov_tl(cpu_addr, cpu_src1); + } else if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 19, 31); -#if defined(OPTIM) - if (rs2 != 0) { -#endif - gen_movl_simm_T1(rs2); - gen_op_add_T1_T0(); -#if defined(OPTIM) - } -#endif + tcg_gen_addi_tl(cpu_addr, cpu_src1, (int)rs2); } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); -#if defined(OPTIM) if (rs2 != 0) { -#endif - gen_movl_reg_T1(rs2); - gen_op_add_T1_T0(); -#if defined(OPTIM) - } -#endif + gen_movl_reg_TN(rs2, cpu_src2); + tcg_gen_add_tl(cpu_addr, cpu_src1, cpu_src2); + } else + tcg_gen_mov_tl(cpu_addr, cpu_src1); } if (xop < 4 || (xop > 7 && xop < 0x14 && xop != 0x0e) || (xop > 0x17 && xop <= 0x1d ) || (xop > 0x2c && xop <= 0x33) || xop == 0x1f || xop == 0x3d) { switch (xop) { - case 0x0: /* load word */ - gen_op_check_align_T0_3(); -#ifndef TARGET_SPARC64 - gen_op_ldst(ld); -#else - gen_op_ldst(lduw); -#endif + case 0x0: /* load unsigned word */ + gen_address_mask(dc, cpu_addr); + tcg_gen_qemu_ld32u(cpu_val, cpu_addr, dc->mem_idx); break; case 0x1: /* load unsigned byte */ - gen_op_ldst(ldub); + gen_address_mask(dc, cpu_addr); + tcg_gen_qemu_ld8u(cpu_val, cpu_addr, dc->mem_idx); break; case 0x2: /* load unsigned halfword */ - gen_op_check_align_T0_1(); - gen_op_ldst(lduh); + gen_address_mask(dc, cpu_addr); + tcg_gen_qemu_ld16u(cpu_val, cpu_addr, dc->mem_idx); break; case 0x3: /* load double word */ if (rd & 1) goto illegal_insn; - gen_op_check_align_T0_7(); - gen_op_ldst(ldd); - gen_movl_T0_reg(rd + 1); + else { + TCGv r_const; + + save_state(dc, cpu_cond); + r_const = tcg_const_i32(7); + tcg_gen_helper_0_2(helper_check_align, cpu_addr, + r_const); // XXX remove + tcg_temp_free(r_const); + gen_address_mask(dc, cpu_addr); + tcg_gen_qemu_ld64(cpu_tmp64, cpu_addr, dc->mem_idx); + tcg_gen_trunc_i64_tl(cpu_tmp0, cpu_tmp64); + tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0xffffffffULL); + gen_movl_TN_reg(rd + 1, cpu_tmp0); + tcg_gen_shri_i64(cpu_tmp64, cpu_tmp64, 32); + tcg_gen_trunc_i64_tl(cpu_val, cpu_tmp64); + tcg_gen_andi_tl(cpu_val, cpu_val, 0xffffffffULL); + } break; case 0x9: /* load signed byte */ - gen_op_ldst(ldsb); + gen_address_mask(dc, cpu_addr); + tcg_gen_qemu_ld8s(cpu_val, cpu_addr, dc->mem_idx); break; case 0xa: /* load signed halfword */ - gen_op_check_align_T0_1(); - gen_op_ldst(ldsh); + gen_address_mask(dc, cpu_addr); + tcg_gen_qemu_ld16s(cpu_val, cpu_addr, dc->mem_idx); break; case 0xd: /* ldstub -- XXX: should be atomically */ - gen_op_ldst(ldstub); + { + TCGv r_const; + + gen_address_mask(dc, cpu_addr); + tcg_gen_qemu_ld8s(cpu_val, cpu_addr, dc->mem_idx); + r_const = tcg_const_tl(0xff); + tcg_gen_qemu_st8(r_const, cpu_addr, dc->mem_idx); + tcg_temp_free(r_const); + } break; - case 0x0f: /* swap register with memory. Also atomically */ - gen_op_check_align_T0_3(); - gen_movl_reg_T1(rd); - gen_op_ldst(swap); + case 0x0f: /* swap register with memory. Also + atomically */ + CHECK_IU_FEATURE(dc, SWAP); + gen_movl_reg_TN(rd, cpu_val); + gen_address_mask(dc, cpu_addr); + tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx); + tcg_gen_qemu_st32(cpu_val, cpu_addr, dc->mem_idx); + tcg_gen_mov_tl(cpu_val, cpu_tmp0); break; #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) case 0x10: /* load word alternate */ @@ -3234,8 +4300,8 @@ if (!supervisor(dc)) goto priv_insn; #endif - gen_op_check_align_T0_3(); - gen_ld_asi(insn, 4, 0); + save_state(dc, cpu_cond); + gen_ld_asi(cpu_val, cpu_addr, insn, 4, 0); break; case 0x11: /* load unsigned byte alternate */ #ifndef TARGET_SPARC64 @@ -3244,7 +4310,8 @@ if (!supervisor(dc)) goto priv_insn; #endif - gen_ld_asi(insn, 1, 0); + save_state(dc, cpu_cond); + gen_ld_asi(cpu_val, cpu_addr, insn, 1, 0); break; case 0x12: /* load unsigned halfword alternate */ #ifndef TARGET_SPARC64 @@ -3253,8 +4320,8 @@ if (!supervisor(dc)) goto priv_insn; #endif - gen_op_check_align_T0_1(); - gen_ld_asi(insn, 2, 0); + save_state(dc, cpu_cond); + gen_ld_asi(cpu_val, cpu_addr, insn, 2, 0); break; case 0x13: /* load double word alternate */ #ifndef TARGET_SPARC64 @@ -3265,10 +4332,9 @@ #endif if (rd & 1) goto illegal_insn; - gen_op_check_align_T0_7(); - gen_ldda_asi(insn); - gen_movl_T0_reg(rd + 1); - break; + save_state(dc, cpu_cond); + gen_ldda_asi(cpu_val, cpu_addr, insn, rd); + goto skip_move; case 0x19: /* load signed byte alternate */ #ifndef TARGET_SPARC64 if (IS_IMM) @@ -3276,7 +4342,8 @@ if (!supervisor(dc)) goto priv_insn; #endif - gen_ld_asi(insn, 1, 1); + save_state(dc, cpu_cond); + gen_ld_asi(cpu_val, cpu_addr, insn, 1, 1); break; case 0x1a: /* load signed halfword alternate */ #ifndef TARGET_SPARC64 @@ -3285,8 +4352,8 @@ if (!supervisor(dc)) goto priv_insn; #endif - gen_op_check_align_T0_1(); - gen_ld_asi(insn, 2, 1); + save_state(dc, cpu_cond); + gen_ld_asi(cpu_val, cpu_addr, insn, 2, 1); break; case 0x1d: /* ldstuba -- XXX: should be atomically */ #ifndef TARGET_SPARC64 @@ -3295,18 +4362,21 @@ if (!supervisor(dc)) goto priv_insn; #endif - gen_ldstub_asi(insn); + save_state(dc, cpu_cond); + gen_ldstub_asi(cpu_val, cpu_addr, insn); break; - case 0x1f: /* swap reg with alt. memory. Also atomically */ + case 0x1f: /* swap reg with alt. memory. Also + atomically */ + CHECK_IU_FEATURE(dc, SWAP); #ifndef TARGET_SPARC64 if (IS_IMM) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; #endif - gen_op_check_align_T0_3(); - gen_movl_reg_T1(rd); - gen_swap_asi(insn); + save_state(dc, cpu_cond); + gen_movl_reg_TN(rd, cpu_val); + gen_swap_asi(cpu_val, cpu_addr, insn); break; #ifndef TARGET_SPARC64 @@ -3318,134 +4388,159 @@ #endif #ifdef TARGET_SPARC64 case 0x08: /* V9 ldsw */ - gen_op_check_align_T0_3(); - gen_op_ldst(ldsw); + gen_address_mask(dc, cpu_addr); + tcg_gen_qemu_ld32s(cpu_val, cpu_addr, dc->mem_idx); break; case 0x0b: /* V9 ldx */ - gen_op_check_align_T0_7(); - gen_op_ldst(ldx); + gen_address_mask(dc, cpu_addr); + tcg_gen_qemu_ld64(cpu_val, cpu_addr, dc->mem_idx); break; case 0x18: /* V9 ldswa */ - gen_op_check_align_T0_3(); - gen_ld_asi(insn, 4, 1); + save_state(dc, cpu_cond); + gen_ld_asi(cpu_val, cpu_addr, insn, 4, 1); break; case 0x1b: /* V9 ldxa */ - gen_op_check_align_T0_7(); - gen_ld_asi(insn, 8, 0); + save_state(dc, cpu_cond); + gen_ld_asi(cpu_val, cpu_addr, insn, 8, 0); break; case 0x2d: /* V9 prefetch, no effect */ goto skip_move; case 0x30: /* V9 ldfa */ - gen_op_check_align_T0_3(); - gen_ldf_asi(insn, 4, rd); + save_state(dc, cpu_cond); + gen_ldf_asi(cpu_addr, insn, 4, rd); goto skip_move; case 0x33: /* V9 lddfa */ - gen_op_check_align_T0_3(); - gen_ldf_asi(insn, 8, DFPREG(rd)); + save_state(dc, cpu_cond); + gen_ldf_asi(cpu_addr, insn, 8, DFPREG(rd)); goto skip_move; case 0x3d: /* V9 prefetcha, no effect */ goto skip_move; case 0x32: /* V9 ldqfa */ -#if defined(CONFIG_USER_ONLY) - gen_op_check_align_T0_3(); - gen_ldf_asi(insn, 16, QFPREG(rd)); + CHECK_FPU_FEATURE(dc, FLOAT128); + save_state(dc, cpu_cond); + gen_ldf_asi(cpu_addr, insn, 16, QFPREG(rd)); goto skip_move; -#else - goto nfpu_insn; -#endif #endif default: goto illegal_insn; } - gen_movl_T1_reg(rd); -#ifdef TARGET_SPARC64 + gen_movl_TN_reg(rd, cpu_val); +#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) skip_move: ; #endif } else if (xop >= 0x20 && xop < 0x24) { - if (gen_trap_ifnofpu(dc)) + if (gen_trap_ifnofpu(dc, cpu_cond)) goto jmp_insn; + save_state(dc, cpu_cond); switch (xop) { case 0x20: /* load fpreg */ - gen_op_check_align_T0_3(); - gen_op_ldst(ldf); - gen_op_store_FT0_fpr(rd); - break; - case 0x21: /* load fsr */ - gen_op_check_align_T0_3(); - gen_op_ldst(ldf); - gen_op_ldfsr(); + gen_address_mask(dc, cpu_addr); + tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx); + tcg_gen_trunc_tl_i32(cpu_fpr[rd], cpu_tmp0); + break; + case 0x21: /* ldfsr, V9 ldxfsr */ +#ifdef TARGET_SPARC64 + gen_address_mask(dc, cpu_addr); + if (rd == 1) { + tcg_gen_qemu_ld64(cpu_tmp64, cpu_addr, dc->mem_idx); + tcg_gen_helper_0_1(helper_ldxfsr, cpu_tmp64); + } else +#else + { + tcg_gen_qemu_ld32u(cpu_tmp32, cpu_addr, dc->mem_idx); + tcg_gen_helper_0_1(helper_ldfsr, cpu_tmp32); + } +#endif break; case 0x22: /* load quad fpreg */ -#if defined(CONFIG_USER_ONLY) - gen_op_check_align_T0_7(); - gen_op_ldst(ldqf); - gen_op_store_QT0_fpr(QFPREG(rd)); + { + TCGv r_const; + + CHECK_FPU_FEATURE(dc, FLOAT128); + r_const = tcg_const_i32(dc->mem_idx); + tcg_gen_helper_0_2(helper_ldqf, cpu_addr, r_const); + tcg_temp_free(r_const); + gen_op_store_QT0_fpr(QFPREG(rd)); + } break; -#else - goto nfpu_insn; -#endif case 0x23: /* load double fpreg */ - gen_op_check_align_T0_7(); - gen_op_ldst(lddf); - gen_op_store_DT0_fpr(DFPREG(rd)); + { + TCGv r_const; + + r_const = tcg_const_i32(dc->mem_idx); + tcg_gen_helper_0_2(helper_lddf, cpu_addr, r_const); + tcg_temp_free(r_const); + gen_op_store_DT0_fpr(DFPREG(rd)); + } break; default: goto illegal_insn; } } else if (xop < 8 || (xop >= 0x14 && xop < 0x18) || \ xop == 0xe || xop == 0x1e) { - gen_movl_reg_T1(rd); + gen_movl_reg_TN(rd, cpu_val); switch (xop) { - case 0x4: - gen_op_check_align_T0_3(); - gen_op_ldst(st); - break; - case 0x5: - gen_op_ldst(stb); - break; - case 0x6: - gen_op_check_align_T0_1(); - gen_op_ldst(sth); + case 0x4: /* store word */ + gen_address_mask(dc, cpu_addr); + tcg_gen_qemu_st32(cpu_val, cpu_addr, dc->mem_idx); + break; + case 0x5: /* store byte */ + gen_address_mask(dc, cpu_addr); + tcg_gen_qemu_st8(cpu_val, cpu_addr, dc->mem_idx); + break; + case 0x6: /* store halfword */ + gen_address_mask(dc, cpu_addr); + tcg_gen_qemu_st16(cpu_val, cpu_addr, dc->mem_idx); break; - case 0x7: + case 0x7: /* store double word */ if (rd & 1) goto illegal_insn; - gen_op_check_align_T0_7(); - flush_T2(dc); - gen_movl_reg_T2(rd + 1); - gen_op_ldst(std); + else { + TCGv r_const; + + save_state(dc, cpu_cond); + gen_address_mask(dc, cpu_addr); + r_const = tcg_const_i32(7); + tcg_gen_helper_0_2(helper_check_align, cpu_addr, + r_const); // XXX remove + tcg_temp_free(r_const); + gen_movl_reg_TN(rd + 1, cpu_tmp0); + tcg_gen_concat_tl_i64(cpu_tmp64, cpu_tmp0, cpu_val); + tcg_gen_qemu_st64(cpu_tmp64, cpu_addr, dc->mem_idx); + } break; #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) - case 0x14: + case 0x14: /* store word alternate */ #ifndef TARGET_SPARC64 if (IS_IMM) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; #endif - gen_op_check_align_T0_3(); - gen_st_asi(insn, 4); + save_state(dc, cpu_cond); + gen_st_asi(cpu_val, cpu_addr, insn, 4); break; - case 0x15: + case 0x15: /* store byte alternate */ #ifndef TARGET_SPARC64 if (IS_IMM) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; #endif - gen_st_asi(insn, 1); + save_state(dc, cpu_cond); + gen_st_asi(cpu_val, cpu_addr, insn, 1); break; - case 0x16: + case 0x16: /* store halfword alternate */ #ifndef TARGET_SPARC64 if (IS_IMM) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; #endif - gen_op_check_align_T0_1(); - gen_st_asi(insn, 2); + save_state(dc, cpu_cond); + gen_st_asi(cpu_val, cpu_addr, insn, 2); break; - case 0x17: + case 0x17: /* store double word alternate */ #ifndef TARGET_SPARC64 if (IS_IMM) goto illegal_insn; @@ -3454,52 +4549,61 @@ #endif if (rd & 1) goto illegal_insn; - gen_op_check_align_T0_7(); - flush_T2(dc); - gen_movl_reg_T2(rd + 1); - gen_stda_asi(insn); + else { + save_state(dc, cpu_cond); + gen_stda_asi(cpu_val, cpu_addr, insn, rd); + } break; #endif #ifdef TARGET_SPARC64 case 0x0e: /* V9 stx */ - gen_op_check_align_T0_7(); - gen_op_ldst(stx); + gen_address_mask(dc, cpu_addr); + tcg_gen_qemu_st64(cpu_val, cpu_addr, dc->mem_idx); break; case 0x1e: /* V9 stxa */ - gen_op_check_align_T0_7(); - gen_st_asi(insn, 8); + save_state(dc, cpu_cond); + gen_st_asi(cpu_val, cpu_addr, insn, 8); break; #endif default: goto illegal_insn; } } else if (xop > 0x23 && xop < 0x28) { - if (gen_trap_ifnofpu(dc)) + if (gen_trap_ifnofpu(dc, cpu_cond)) goto jmp_insn; + save_state(dc, cpu_cond); switch (xop) { - case 0x24: - gen_op_check_align_T0_3(); - gen_op_load_fpr_FT0(rd); - gen_op_ldst(stf); + case 0x24: /* store fpreg */ + gen_address_mask(dc, cpu_addr); + tcg_gen_ext_i32_tl(cpu_tmp0, cpu_fpr[rd]); + tcg_gen_qemu_st32(cpu_tmp0, cpu_addr, dc->mem_idx); break; case 0x25: /* stfsr, V9 stxfsr */ -#ifdef CONFIG_USER_ONLY - gen_op_check_align_T0_3(); +#ifdef TARGET_SPARC64 + gen_address_mask(dc, cpu_addr); + tcg_gen_ld_i64(cpu_tmp64, cpu_env, offsetof(CPUState, fsr)); + if (rd == 1) + tcg_gen_qemu_st64(cpu_tmp64, cpu_addr, dc->mem_idx); + else + tcg_gen_qemu_st32(cpu_tmp64, cpu_addr, dc->mem_idx); +#else + tcg_gen_ld_i32(cpu_tmp32, cpu_env, offsetof(CPUState, fsr)); + tcg_gen_qemu_st32(cpu_tmp32, cpu_addr, dc->mem_idx); #endif - gen_op_stfsr(); - gen_op_ldst(stf); break; case 0x26: #ifdef TARGET_SPARC64 -#if defined(CONFIG_USER_ONLY) /* V9 stqf, store quad fpreg */ - gen_op_check_align_T0_7(); - gen_op_load_fpr_QT0(QFPREG(rd)); - gen_op_ldst(stqf); + { + TCGv r_const; + + CHECK_FPU_FEATURE(dc, FLOAT128); + gen_op_load_fpr_QT0(QFPREG(rd)); + r_const = tcg_const_i32(dc->mem_idx); + tcg_gen_helper_0_2(helper_stqf, cpu_addr, r_const); + tcg_temp_free(r_const); + } break; -#else - goto nfpu_insn; -#endif #else /* !TARGET_SPARC64 */ /* stdfq, store floating point queue */ #if defined(CONFIG_USER_ONLY) @@ -3507,54 +4611,55 @@ #else if (!supervisor(dc)) goto priv_insn; - if (gen_trap_ifnofpu(dc)) + if (gen_trap_ifnofpu(dc, cpu_cond)) goto jmp_insn; goto nfq_insn; #endif #endif - case 0x27: - gen_op_check_align_T0_7(); - gen_op_load_fpr_DT0(DFPREG(rd)); - gen_op_ldst(stdf); + case 0x27: /* store double fpreg */ + { + TCGv r_const; + + gen_op_load_fpr_DT0(DFPREG(rd)); + r_const = tcg_const_i32(dc->mem_idx); + tcg_gen_helper_0_2(helper_stdf, cpu_addr, r_const); + tcg_temp_free(r_const); + } break; default: goto illegal_insn; } } else if (xop > 0x33 && xop < 0x3f) { + save_state(dc, cpu_cond); switch (xop) { #ifdef TARGET_SPARC64 case 0x34: /* V9 stfa */ - gen_op_check_align_T0_3(); - gen_op_load_fpr_FT0(rd); - gen_stf_asi(insn, 4, rd); + gen_stf_asi(cpu_addr, insn, 4, rd); break; case 0x36: /* V9 stqfa */ -#if defined(CONFIG_USER_ONLY) - gen_op_check_align_T0_7(); - gen_op_load_fpr_QT0(QFPREG(rd)); - gen_stf_asi(insn, 16, QFPREG(rd)); + { + TCGv r_const; + + CHECK_FPU_FEATURE(dc, FLOAT128); + r_const = tcg_const_i32(7); + tcg_gen_helper_0_2(helper_check_align, cpu_addr, + r_const); + tcg_temp_free(r_const); + gen_op_load_fpr_QT0(QFPREG(rd)); + gen_stf_asi(cpu_addr, insn, 16, QFPREG(rd)); + } break; -#else - goto nfpu_insn; -#endif case 0x37: /* V9 stdfa */ - gen_op_check_align_T0_3(); gen_op_load_fpr_DT0(DFPREG(rd)); - gen_stf_asi(insn, 8, DFPREG(rd)); + gen_stf_asi(cpu_addr, insn, 8, DFPREG(rd)); break; case 0x3c: /* V9 casa */ - gen_op_check_align_T0_3(); - flush_T2(dc); - gen_movl_reg_T2(rd); - gen_cas_asi(insn); - gen_movl_T1_reg(rd); + gen_cas_asi(cpu_val, cpu_addr, cpu_src2, insn, rd); + gen_movl_TN_reg(rd, cpu_val); break; case 0x3e: /* V9 casxa */ - gen_op_check_align_T0_7(); - flush_T2(dc); - gen_movl_reg_T2(rd); - gen_casx_asi(insn); - gen_movl_T1_reg(rd); + gen_casx_asi(cpu_val, cpu_addr, cpu_src2, insn, rd); + gen_movl_TN_reg(rd, cpu_val); break; #else case 0x34: /* stc */ @@ -3578,7 +4683,7 @@ gen_op_next_insn(); } else if (dc->npc == JUMP_PC) { /* we can do a static jump */ - gen_branch2(dc, dc->jump_pc[0], dc->jump_pc[1]); + gen_branch2(dc, dc->jump_pc[0], dc->jump_pc[1], cpu_cond); dc->is_br = 1; } else { dc->pc = dc->npc; @@ -3587,45 +4692,76 @@ jmp_insn: return; illegal_insn: - save_state(dc); - gen_op_exception(TT_ILL_INSN); - dc->is_br = 1; + { + TCGv r_const; + + save_state(dc, cpu_cond); + r_const = tcg_const_i32(TT_ILL_INSN); + tcg_gen_helper_0_1(raise_exception, r_const); + tcg_temp_free(r_const); + dc->is_br = 1; + } + return; + unimp_flush: + { + TCGv r_const; + + save_state(dc, cpu_cond); + r_const = tcg_const_i32(TT_UNIMP_FLUSH); + tcg_gen_helper_0_1(raise_exception, r_const); + tcg_temp_free(r_const); + dc->is_br = 1; + } return; #if !defined(CONFIG_USER_ONLY) priv_insn: - save_state(dc); - gen_op_exception(TT_PRIV_INSN); - dc->is_br = 1; + { + TCGv r_const; + + save_state(dc, cpu_cond); + r_const = tcg_const_i32(TT_PRIV_INSN); + tcg_gen_helper_0_1(raise_exception, r_const); + tcg_temp_free(r_const); + dc->is_br = 1; + } return; +#endif nfpu_insn: - save_state(dc); + save_state(dc, cpu_cond); gen_op_fpexception_im(FSR_FTT_UNIMPFPOP); dc->is_br = 1; return; -#ifndef TARGET_SPARC64 +#if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64) nfq_insn: - save_state(dc); + save_state(dc, cpu_cond); gen_op_fpexception_im(FSR_FTT_SEQ_ERROR); dc->is_br = 1; return; #endif -#endif #ifndef TARGET_SPARC64 ncp_insn: - save_state(dc); - gen_op_exception(TT_NCP_INSN); - dc->is_br = 1; + { + TCGv r_const; + + save_state(dc, cpu_cond); + r_const = tcg_const_i32(TT_NCP_INSN); + tcg_gen_helper_0_1(raise_exception, r_const); + tcg_temp_free(r_const); + dc->is_br = 1; + } return; #endif } -static inline int gen_intermediate_code_internal(TranslationBlock * tb, - int spc, CPUSPARCState *env) +static inline void gen_intermediate_code_internal(TranslationBlock * tb, + int spc, CPUSPARCState *env) { target_ulong pc_start, last_pc; uint16_t *gen_opc_end; DisasContext dc1, *dc = &dc1; int j, lj = -1; + int num_insns; + int max_insns; memset(dc, 0, sizeof(DisasContext)); dc->tb = tb; @@ -3634,21 +4770,39 @@ last_pc = dc->pc; dc->npc = (target_ulong) tb->cs_base; dc->mem_idx = cpu_mmu_index(env); - dc->fpu_enabled = cpu_fpu_enabled(env); - gen_opc_ptr = gen_opc_buf; + dc->def = env->def; + if ((dc->def->features & CPU_FEATURE_FLOAT)) + dc->fpu_enabled = cpu_fpu_enabled(env); + else + dc->fpu_enabled = 0; +#ifdef TARGET_SPARC64 + dc->address_mask_32bit = env->pstate & PS_AM; +#endif gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; - gen_opparam_ptr = gen_opparam_buf; - nb_gen_labels = 0; + cpu_tmp0 = tcg_temp_new(TCG_TYPE_TL); + cpu_tmp32 = tcg_temp_new(TCG_TYPE_I32); + cpu_tmp64 = tcg_temp_new(TCG_TYPE_I64); + + cpu_dst = tcg_temp_local_new(TCG_TYPE_TL); + + // loads and stores + cpu_val = tcg_temp_local_new(TCG_TYPE_TL); + cpu_addr = tcg_temp_local_new(TCG_TYPE_TL); + + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + if (max_insns == 0) + max_insns = CF_COUNT_MASK; + gen_icount_start(); do { if (env->nb_breakpoints > 0) { for(j = 0; j < env->nb_breakpoints; j++) { if (env->breakpoints[j] == dc->pc) { if (dc->pc != pc_start) - save_state(dc); - gen_op_debug(); - gen_op_movl_T0_0(); - gen_op_exit_tb(); + save_state(dc, cpu_cond); + tcg_gen_helper_0_0(helper_debug); + tcg_gen_exit_tb(0); dc->is_br = 1; goto exit_gen_loop; } @@ -3665,10 +4819,14 @@ gen_opc_pc[lj] = dc->pc; gen_opc_npc[lj] = dc->npc; gen_opc_instr_start[lj] = 1; + gen_opc_icount[lj] = num_insns; } } + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) + gen_io_start(); last_pc = dc->pc; disas_sparc_insn(dc); + num_insns++; if (dc->is_br) break; @@ -3682,28 +4840,36 @@ /* if single step mode, we generate only one instruction and generate an exception */ if (env->singlestep_enabled) { - gen_jmp_im(dc->pc); - gen_op_movl_T0_0(); - gen_op_exit_tb(); + tcg_gen_movi_tl(cpu_pc, dc->pc); + tcg_gen_exit_tb(0); break; } } while ((gen_opc_ptr < gen_opc_end) && - (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); + (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32) && + num_insns < max_insns); exit_gen_loop: + tcg_temp_free(cpu_addr); + tcg_temp_free(cpu_val); + tcg_temp_free(cpu_dst); + tcg_temp_free(cpu_tmp64); + tcg_temp_free(cpu_tmp32); + tcg_temp_free(cpu_tmp0); + if (tb->cflags & CF_LAST_IO) + gen_io_end(); if (!dc->is_br) { if (dc->pc != DYNAMIC_PC && (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) { /* static PC and NPC: we can use direct chaining */ - gen_branch(dc, dc->pc, dc->npc); + gen_goto_tb(dc, 0, dc->pc, dc->npc); } else { if (dc->pc != DYNAMIC_PC) - gen_jmp_im(dc->pc); - save_npc(dc); - gen_op_movl_T0_0(); - gen_op_exit_tb(); + tcg_gen_movi_tl(cpu_pc, dc->pc); + save_npc(dc, cpu_cond); + tcg_gen_exit_tb(0); } } + gen_icount_end(tb, num_insns); *gen_opc_ptr = INDEX_op_end; if (spc) { j = gen_opc_ptr - gen_opc_buf; @@ -3719,6 +4885,7 @@ gen_opc_jump_pc[1] = dc->jump_pc[1]; } else { tb->size = last_pc + 4 - pc_start; + tb->icount = num_insns; } #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { @@ -3726,440 +4893,163 @@ fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); target_disas(logfile, pc_start, last_pc + 4 - pc_start, 0); fprintf(logfile, "\n"); - if (loglevel & CPU_LOG_TB_OP) { - fprintf(logfile, "OP:\n"); - dump_ops(gen_opc_buf, gen_opparam_buf); - fprintf(logfile, "\n"); - } } #endif - return 0; -} - -int gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb) -{ - return gen_intermediate_code_internal(tb, 0, env); -} - -int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb) -{ - return gen_intermediate_code_internal(tb, 1, env); -} - -extern int ram_size; - -void cpu_reset(CPUSPARCState *env) -{ - tlb_flush(env, 1); - env->cwp = 0; - env->wim = 1; - env->regwptr = env->regbase + (env->cwp * 16); -#if defined(CONFIG_USER_ONLY) - env->user_mode_only = 1; -#ifdef TARGET_SPARC64 - env->cleanwin = NWINDOWS - 2; - env->cansave = NWINDOWS - 2; - env->pstate = PS_RMO | PS_PEF | PS_IE; - env->asi = 0x82; // Primary no-fault -#endif -#else - env->psret = 0; - env->psrs = 1; - env->psrps = 1; -#ifdef TARGET_SPARC64 - env->pstate = PS_PRIV; - env->hpstate = HS_PRIV; - env->pc = 0x1fff0000000ULL; -#else - env->pc = 0; - env->mmuregs[0] &= ~(MMU_E | MMU_NF); - env->mmuregs[0] |= env->mmu_bm; -#endif - env->npc = env->pc + 4; -#endif } -CPUSPARCState *cpu_sparc_init(const char *cpu_model) +void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb) { - CPUSPARCState *env; - const sparc_def_t *def; - - def = cpu_sparc_find_by_name(cpu_model); - if (!def) - return NULL; - - env = qemu_mallocz(sizeof(CPUSPARCState)); - if (!env) - return NULL; - cpu_exec_init(env); - env->cpu_model_str = cpu_model; - env->version = def->iu_version; - env->fsr = def->fpu_version; -#if !defined(TARGET_SPARC64) - env->mmu_bm = def->mmu_bm; - env->mmuregs[0] |= def->mmu_version; - cpu_sparc_set_id(env, 0); -#endif - cpu_reset(env); - - return env; + gen_intermediate_code_internal(tb, 0, env); } -void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu) +void gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb) { -#if !defined(TARGET_SPARC64) - env->mxccregs[7] = ((cpu + 8) & 0xf) << 24; -#endif + gen_intermediate_code_internal(tb, 1, env); } -static const sparc_def_t sparc_defs[] = { -#ifdef TARGET_SPARC64 - { - .name = "Fujitsu Sparc64", - .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24) - | (MAXTL << 8) | (NWINDOWS - 1)), - .fpu_version = 0x00000000, - .mmu_version = 0, - }, - { - .name = "Fujitsu Sparc64 III", - .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24) - | (MAXTL << 8) | (NWINDOWS - 1)), - .fpu_version = 0x00000000, - .mmu_version = 0, - }, - { - .name = "Fujitsu Sparc64 IV", - .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24) - | (MAXTL << 8) | (NWINDOWS - 1)), - .fpu_version = 0x00000000, - .mmu_version = 0, - }, - { - .name = "Fujitsu Sparc64 V", - .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24) - | (MAXTL << 8) | (NWINDOWS - 1)), - .fpu_version = 0x00000000, - .mmu_version = 0, - }, - { - .name = "TI UltraSparc I", - .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24) - | (MAXTL << 8) | (NWINDOWS - 1)), - .fpu_version = 0x00000000, - .mmu_version = 0, - }, - { - .name = "TI UltraSparc II", - .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24) - | (MAXTL << 8) | (NWINDOWS - 1)), - .fpu_version = 0x00000000, - .mmu_version = 0, - }, - { - .name = "TI UltraSparc IIi", - .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24) - | (MAXTL << 8) | (NWINDOWS - 1)), - .fpu_version = 0x00000000, - .mmu_version = 0, - }, - { - .name = "TI UltraSparc IIe", - .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24) - | (MAXTL << 8) | (NWINDOWS - 1)), - .fpu_version = 0x00000000, - .mmu_version = 0, - }, - { - .name = "Sun UltraSparc III", - .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24) - | (MAXTL << 8) | (NWINDOWS - 1)), - .fpu_version = 0x00000000, - .mmu_version = 0, - }, - { - .name = "Sun UltraSparc III Cu", - .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24) - | (MAXTL << 8) | (NWINDOWS - 1)), - .fpu_version = 0x00000000, - .mmu_version = 0, - }, - { - .name = "Sun UltraSparc IIIi", - .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24) - | (MAXTL << 8) | (NWINDOWS - 1)), - .fpu_version = 0x00000000, - .mmu_version = 0, - }, - { - .name = "Sun UltraSparc IV", - .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24) - | (MAXTL << 8) | (NWINDOWS - 1)), - .fpu_version = 0x00000000, - .mmu_version = 0, - }, - { - .name = "Sun UltraSparc IV+", - .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24) - | (MAXTL << 8) | (NWINDOWS - 1)), - .fpu_version = 0x00000000, - .mmu_version = 0, - }, - { - .name = "Sun UltraSparc IIIi+", - .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24) - | (MAXTL << 8) | (NWINDOWS - 1)), - .fpu_version = 0x00000000, - .mmu_version = 0, - }, - { - .name = "NEC UltraSparc I", - .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24) - | (MAXTL << 8) | (NWINDOWS - 1)), - .fpu_version = 0x00000000, - .mmu_version = 0, - }, -#else - { - .name = "Fujitsu MB86900", - .iu_version = 0x00 << 24, /* Impl 0, ver 0 */ - .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ - .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */ - .mmu_bm = 0x00004000, - }, - { - .name = "Fujitsu MB86904", - .iu_version = 0x04 << 24, /* Impl 0, ver 4 */ - .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ - .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */ - .mmu_bm = 0x00004000, - }, - { - .name = "Fujitsu MB86907", - .iu_version = 0x05 << 24, /* Impl 0, ver 5 */ - .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ - .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */ - .mmu_bm = 0x00004000, - }, - { - .name = "LSI L64811", - .iu_version = 0x10 << 24, /* Impl 1, ver 0 */ - .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */ - .mmu_version = 0x10 << 24, - .mmu_bm = 0x00004000, - }, - { - .name = "Cypress CY7C601", - .iu_version = 0x11 << 24, /* Impl 1, ver 1 */ - .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */ - .mmu_version = 0x10 << 24, - .mmu_bm = 0x00004000, - }, - { - .name = "Cypress CY7C611", - .iu_version = 0x13 << 24, /* Impl 1, ver 3 */ - .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */ - .mmu_version = 0x10 << 24, - .mmu_bm = 0x00004000, - }, - { - .name = "TI SuperSparc II", - .iu_version = 0x40000000, - .fpu_version = 0 << 17, - .mmu_version = 0x04000000, - .mmu_bm = 0x00002000, - }, - { - .name = "TI MicroSparc I", - .iu_version = 0x41000000, - .fpu_version = 4 << 17, - .mmu_version = 0x41000000, - .mmu_bm = 0x00004000, - }, - { - .name = "TI MicroSparc II", - .iu_version = 0x42000000, - .fpu_version = 4 << 17, - .mmu_version = 0x02000000, - .mmu_bm = 0x00004000, - }, - { - .name = "TI MicroSparc IIep", - .iu_version = 0x42000000, - .fpu_version = 4 << 17, - .mmu_version = 0x04000000, - .mmu_bm = 0x00004000, - }, - { - .name = "TI SuperSparc 51", - .iu_version = 0x43000000, - .fpu_version = 0 << 17, - .mmu_version = 0x04000000, - .mmu_bm = 0x00002000, - }, - { - .name = "TI SuperSparc 61", - .iu_version = 0x44000000, - .fpu_version = 0 << 17, - .mmu_version = 0x04000000, - .mmu_bm = 0x00002000, - }, - { - .name = "Ross RT625", - .iu_version = 0x1e000000, - .fpu_version = 1 << 17, - .mmu_version = 0x1e000000, - .mmu_bm = 0x00004000, - }, - { - .name = "Ross RT620", - .iu_version = 0x1f000000, - .fpu_version = 1 << 17, - .mmu_version = 0x1f000000, - .mmu_bm = 0x00004000, - }, - { - .name = "BIT B5010", - .iu_version = 0x20000000, - .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */ - .mmu_version = 0x20000000, - .mmu_bm = 0x00004000, - }, - { - .name = "Matsushita MN10501", - .iu_version = 0x50000000, - .fpu_version = 0 << 17, - .mmu_version = 0x50000000, - .mmu_bm = 0x00004000, - }, - { - .name = "Weitek W8601", - .iu_version = 0x90 << 24, /* Impl 9, ver 0 */ - .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */ - .mmu_version = 0x10 << 24, - .mmu_bm = 0x00004000, - }, - { - .name = "LEON2", - .iu_version = 0xf2000000, - .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ - .mmu_version = 0xf2000000, - .mmu_bm = 0x00004000, - }, - { - .name = "LEON3", - .iu_version = 0xf3000000, - .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ - .mmu_version = 0xf3000000, - .mmu_bm = 0x00004000, - }, -#endif -}; - -static const sparc_def_t *cpu_sparc_find_by_name(const unsigned char *name) +void gen_intermediate_code_init(CPUSPARCState *env) { unsigned int i; + static int inited; + static const char * const gregnames[8] = { + NULL, // g0 not used + "g1", + "g2", + "g3", + "g4", + "g5", + "g6", + "g7", + }; + static const char * const fregnames[64] = { + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", + "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39", + "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", + "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55", + "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63", + }; - for (i = 0; i < sizeof(sparc_defs) / sizeof(sparc_def_t); i++) { - if (strcasecmp(name, sparc_defs[i].name) == 0) { - return &sparc_defs[i]; - } + /* init various static tables */ + if (!inited) { + inited = 1; + + cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env"); + cpu_regwptr = tcg_global_mem_new(TCG_TYPE_PTR, TCG_AREG0, + offsetof(CPUState, regwptr), + "regwptr"); +#ifdef TARGET_SPARC64 + cpu_xcc = tcg_global_mem_new(TCG_TYPE_I32, + TCG_AREG0, offsetof(CPUState, xcc), + "xcc"); + cpu_asi = tcg_global_mem_new(TCG_TYPE_I32, + TCG_AREG0, offsetof(CPUState, asi), + "asi"); + cpu_fprs = tcg_global_mem_new(TCG_TYPE_I32, + TCG_AREG0, offsetof(CPUState, fprs), + "fprs"); + cpu_gsr = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, offsetof(CPUState, gsr), + "gsr"); + cpu_tick_cmpr = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, + offsetof(CPUState, tick_cmpr), + "tick_cmpr"); + cpu_stick_cmpr = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, + offsetof(CPUState, stick_cmpr), + "stick_cmpr"); + cpu_hstick_cmpr = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, + offsetof(CPUState, hstick_cmpr), + "hstick_cmpr"); + cpu_hintp = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, hintp), + "hintp"); + cpu_htba = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, htba), + "htba"); + cpu_hver = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, hver), + "hver"); + cpu_ssr = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, ssr), "ssr"); + cpu_ver = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, version), "ver"); + cpu_softint = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, softint), + "softint"); +#else + cpu_wim = tcg_global_mem_new(TCG_TYPE_I32, + TCG_AREG0, offsetof(CPUState, wim), + "wim"); +#endif + cpu_cond = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, offsetof(CPUState, cond), + "cond"); + cpu_cc_src = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, offsetof(CPUState, cc_src), + "cc_src"); + cpu_cc_src2 = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, cc_src2), + "cc_src2"); + cpu_cc_dst = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, offsetof(CPUState, cc_dst), + "cc_dst"); + cpu_psr = tcg_global_mem_new(TCG_TYPE_I32, + TCG_AREG0, offsetof(CPUState, psr), + "psr"); + cpu_fsr = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, offsetof(CPUState, fsr), + "fsr"); + cpu_pc = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, offsetof(CPUState, pc), + "pc"); + cpu_npc = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, offsetof(CPUState, npc), + "npc"); + cpu_y = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, offsetof(CPUState, y), "y"); +#ifndef CONFIG_USER_ONLY + cpu_tbr = tcg_global_mem_new(TCG_TYPE_TL, + TCG_AREG0, offsetof(CPUState, tbr), + "tbr"); +#endif + for (i = 1; i < 8; i++) + cpu_gregs[i] = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, + offsetof(CPUState, gregs[i]), + gregnames[i]); + for (i = 0; i < TARGET_FPREGS; i++) + cpu_fpr[i] = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, fpr[i]), + fregnames[i]); + + /* register helpers */ + +#undef DEF_HELPER +#define DEF_HELPER(ret, name, params) tcg_register_helper(name, #name); +#include "helper.h" } - return NULL; } -void sparc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +void gen_pc_load(CPUState *env, TranslationBlock *tb, + unsigned long searched_pc, int pc_pos, void *puc) { - unsigned int i; - - for (i = 0; i < sizeof(sparc_defs) / sizeof(sparc_def_t); i++) { - (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x\n", - sparc_defs[i].name, - sparc_defs[i].iu_version, - sparc_defs[i].fpu_version, - sparc_defs[i].mmu_version); - } -} - -#define GET_FLAG(a,b) ((env->psr & a)?b:'-') - -void cpu_dump_state(CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), - int flags) -{ - int i, x; - - cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc, env->npc); - cpu_fprintf(f, "General Registers:\n"); - for (i = 0; i < 4; i++) - cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]); - cpu_fprintf(f, "\n"); - for (; i < 8; i++) - cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]); - cpu_fprintf(f, "\nCurrent Register Window:\n"); - for (x = 0; x < 3; x++) { - for (i = 0; i < 4; i++) - cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t", - (x == 0 ? 'o' : (x == 1 ? 'l' : 'i')), i, - env->regwptr[i + x * 8]); - cpu_fprintf(f, "\n"); - for (; i < 8; i++) - cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t", - (x == 0 ? 'o' : x == 1 ? 'l' : 'i'), i, - env->regwptr[i + x * 8]); - cpu_fprintf(f, "\n"); - } - cpu_fprintf(f, "\nFloating Point Registers:\n"); - for (i = 0; i < 32; i++) { - if ((i & 3) == 0) - cpu_fprintf(f, "%%f%02d:", i); - cpu_fprintf(f, " %016lf", env->fpr[i]); - if ((i & 3) == 3) - cpu_fprintf(f, "\n"); + target_ulong npc; + env->pc = gen_opc_pc[pc_pos]; + npc = gen_opc_npc[pc_pos]; + if (npc == 1) { + /* dynamic NPC: already stored */ + } else if (npc == 2) { + target_ulong t2 = (target_ulong)(unsigned long)puc; + /* jump PC: use T2 and the jump targets of the translation */ + if (t2) + env->npc = gen_opc_jump_pc[0]; + else + env->npc = gen_opc_jump_pc[1]; + } else { + env->npc = npc; } -#ifdef TARGET_SPARC64 - cpu_fprintf(f, "pstate: 0x%08x ccr: 0x%02x asi: 0x%02x tl: %d fprs: %d\n", - env->pstate, GET_CCR(env), env->asi, env->tl, env->fprs); - cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate %d cleanwin %d cwp %d\n", - env->cansave, env->canrestore, env->otherwin, env->wstate, - env->cleanwin, NWINDOWS - 1 - env->cwp); -#else - cpu_fprintf(f, "psr: 0x%08x -> %c%c%c%c %c%c%c wim: 0x%08x\n", GET_PSR(env), - GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'), - GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'), - env->psrs?'S':'-', env->psrps?'P':'-', - env->psret?'E':'-', env->wim); -#endif - cpu_fprintf(f, "fsr: 0x%08x\n", GET_FSR32(env)); -} - -#if defined(CONFIG_USER_ONLY) -target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) -{ - return addr; -} - -#else -extern int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot, - int *access_index, target_ulong address, int rw, - int mmu_idx); - -target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) -{ - target_phys_addr_t phys_addr; - int prot, access_index; - - if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2, 0) != 0) - if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 0, 0) != 0) - return -1; - if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) - return -1; - return phys_addr; -} -#endif - -void helper_flush(target_ulong addr) -{ - addr &= ~7; - tb_invalidate_page_range(addr, addr + 8); } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/arm/tcg-target.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/arm/tcg-target.c --- qemu-0.9.1/tcg/arm/tcg-target.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/arm/tcg-target.c 2008-10-05 10:59:14.000000000 +0100 @@ -0,0 +1,1587 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Andrzej Zaborowski + * + * 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. + */ + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "%r0", + "%r1", + "%r2", + "%r3", + "%r4", + "%r5", + "%r6", + "%r7", + "%r8", + "%r9", + "%r10", + "%r11", + "%r12", + "%r13", + "%r14", +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_R0, + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, +}; + +static const int tcg_target_call_iarg_regs[4] = { + TCG_REG_R0, TCG_REG_R1, TCG_REG_R2, TCG_REG_R3 +}; +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_R0, TCG_REG_R1 +}; + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + switch (type) { + case R_ARM_ABS32: + *(uint32_t *) code_ptr = value; + break; + + case R_ARM_CALL: + case R_ARM_JUMP24: + default: + tcg_abort(); + + case R_ARM_PC24: + *(uint32_t *) code_ptr = ((*(uint32_t *) code_ptr) & 0xff000000) | + (((value - ((tcg_target_long) code_ptr + 8)) >> 2) & 0xffffff); + break; + } +} + +/* maximum number of register used for input function arguments */ +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + return 4; +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch (ct_str[0]) { + case 'r': +#ifndef CONFIG_SOFTMMU + case 'd': + case 'D': + case 'x': + case 'X': +#endif + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + break; + +#ifdef CONFIG_SOFTMMU + /* qemu_ld/st inputs (unless 'X', 'd' or 'D') */ + case 'x': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); + break; + + /* qemu_ld64 data_reg */ + case 'd': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + /* r1 is still needed to load data_reg2, so don't use it. */ + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); + break; + + /* qemu_ld/st64 data_reg2 */ + case 'D': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + /* r0, r1 and optionally r2 will be overwritten by the address + * and the low word of data, so don't use these. */ + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); +# if TARGET_LONG_BITS == 64 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2); +# endif + break; + +# if TARGET_LONG_BITS == 64 + /* qemu_ld/st addr_reg2 */ + case 'X': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + /* r0 will be overwritten by the low word of base, so don't use it. */ + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); + break; +# endif +#endif + + case '1': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); + break; + + case '2': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); + break; + + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + + return 0; +} + +/* Test if a constant matches the constraint. + * TODO: define constraints for: + * + * ldr/str offset: between -0xfff and 0xfff + * ldrh/strh offset: between -0xff and 0xff + * mov operand2: values represented with x << (2 * y), x < 0x100 + * add, sub, eor...: ditto + */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + else + return 0; +} + +enum arm_data_opc_e { + ARITH_AND = 0x0, + ARITH_EOR = 0x1, + ARITH_SUB = 0x2, + ARITH_RSB = 0x3, + ARITH_ADD = 0x4, + ARITH_ADC = 0x5, + ARITH_SBC = 0x6, + ARITH_RSC = 0x7, + ARITH_TST = 0x8, + ARITH_CMP = 0xa, + ARITH_CMN = 0xb, + ARITH_ORR = 0xc, + ARITH_MOV = 0xd, + ARITH_BIC = 0xe, + ARITH_MVN = 0xf, +}; + +#define TO_CPSR(opc) \ + ((opc == ARITH_CMP || opc == ARITH_CMN || opc == ARITH_TST) << 20) + +#define SHIFT_IMM_LSL(im) (((im) << 7) | 0x00) +#define SHIFT_IMM_LSR(im) (((im) << 7) | 0x20) +#define SHIFT_IMM_ASR(im) (((im) << 7) | 0x40) +#define SHIFT_IMM_ROR(im) (((im) << 7) | 0x60) +#define SHIFT_REG_LSL(rs) (((rs) << 8) | 0x10) +#define SHIFT_REG_LSR(rs) (((rs) << 8) | 0x30) +#define SHIFT_REG_ASR(rs) (((rs) << 8) | 0x50) +#define SHIFT_REG_ROR(rs) (((rs) << 8) | 0x70) + +enum arm_cond_code_e { + COND_EQ = 0x0, + COND_NE = 0x1, + COND_CS = 0x2, /* Unsigned greater or equal */ + COND_CC = 0x3, /* Unsigned less than */ + COND_MI = 0x4, /* Negative */ + COND_PL = 0x5, /* Zero or greater */ + COND_VS = 0x6, /* Overflow */ + COND_VC = 0x7, /* No overflow */ + COND_HI = 0x8, /* Unsigned greater than */ + COND_LS = 0x9, /* Unsigned less or equal */ + COND_GE = 0xa, + COND_LT = 0xb, + COND_GT = 0xc, + COND_LE = 0xd, + COND_AL = 0xe, +}; + +static const uint8_t tcg_cond_to_arm_cond[10] = { + [TCG_COND_EQ] = COND_EQ, + [TCG_COND_NE] = COND_NE, + [TCG_COND_LT] = COND_LT, + [TCG_COND_GE] = COND_GE, + [TCG_COND_LE] = COND_LE, + [TCG_COND_GT] = COND_GT, + /* unsigned */ + [TCG_COND_LTU] = COND_CC, + [TCG_COND_GEU] = COND_CS, + [TCG_COND_LEU] = COND_LS, + [TCG_COND_GTU] = COND_HI, +}; + +static inline void tcg_out_bx(TCGContext *s, int cond, int rn) +{ + tcg_out32(s, (cond << 28) | 0x012fff10 | rn); +} + +static inline void tcg_out_b(TCGContext *s, int cond, int32_t offset) +{ + tcg_out32(s, (cond << 28) | 0x0a000000 | + (((offset - 8) >> 2) & 0x00ffffff)); +} + +static inline void tcg_out_b_noaddr(TCGContext *s, int cond) +{ +#ifdef WORDS_BIGENDIAN + tcg_out8(s, (cond << 4) | 0x0a); + s->code_ptr += 3; +#else + s->code_ptr += 3; + tcg_out8(s, (cond << 4) | 0x0a); +#endif +} + +static inline void tcg_out_bl(TCGContext *s, int cond, int32_t offset) +{ + tcg_out32(s, (cond << 28) | 0x0b000000 | + (((offset - 8) >> 2) & 0x00ffffff)); +} + +static inline void tcg_out_dat_reg(TCGContext *s, + int cond, int opc, int rd, int rn, int rm, int shift) +{ + tcg_out32(s, (cond << 28) | (0 << 25) | (opc << 21) | TO_CPSR(opc) | + (rn << 16) | (rd << 12) | shift | rm); +} + +static inline void tcg_out_dat_reg2(TCGContext *s, + int cond, int opc0, int opc1, int rd0, int rd1, + int rn0, int rn1, int rm0, int rm1, int shift) +{ + tcg_out32(s, (cond << 28) | (0 << 25) | (opc0 << 21) | (1 << 20) | + (rn0 << 16) | (rd0 << 12) | shift | rm0); + tcg_out32(s, (cond << 28) | (0 << 25) | (opc1 << 21) | + (rn1 << 16) | (rd1 << 12) | shift | rm1); +} + +static inline void tcg_out_dat_imm(TCGContext *s, + int cond, int opc, int rd, int rn, int im) +{ + tcg_out32(s, (cond << 28) | (1 << 25) | (opc << 21) | TO_CPSR(opc) | + (rn << 16) | (rd << 12) | im); +} + +static inline void tcg_out_movi32(TCGContext *s, + int cond, int rd, int32_t arg) +{ + int offset = (uint32_t) arg - ((uint32_t) s->code_ptr + 8); + + /* TODO: This is very suboptimal, we can easily have a constant + * pool somewhere after all the instructions. */ + + if (arg < 0 && arg > -0x100) + return tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0, (~arg) & 0xff); + + if (offset < 0x100 && offset > -0x100) + return offset >= 0 ? + tcg_out_dat_imm(s, cond, ARITH_ADD, rd, 15, offset) : + tcg_out_dat_imm(s, cond, ARITH_SUB, rd, 15, -offset); + + tcg_out_dat_imm(s, cond, ARITH_MOV, rd, 0, arg & 0xff); + if (arg & 0x0000ff00) + tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd, + ((arg >> 8) & 0xff) | 0xc00); + if (arg & 0x00ff0000) + tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd, + ((arg >> 16) & 0xff) | 0x800); + if (arg & 0xff000000) + tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd, + ((arg >> 24) & 0xff) | 0x400); +} + +static inline void tcg_out_mul32(TCGContext *s, + int cond, int rd, int rs, int rm) +{ + if (rd != rm) + tcg_out32(s, (cond << 28) | (rd << 16) | (0 << 12) | + (rs << 8) | 0x90 | rm); + else if (rd != rs) + tcg_out32(s, (cond << 28) | (rd << 16) | (0 << 12) | + (rm << 8) | 0x90 | rs); + else { + tcg_out32(s, (cond << 28) | ( 8 << 16) | (0 << 12) | + (rs << 8) | 0x90 | rm); + tcg_out_dat_reg(s, cond, ARITH_MOV, + rd, 0, 8, SHIFT_IMM_LSL(0)); + } +} + +static inline void tcg_out_umull32(TCGContext *s, + int cond, int rd0, int rd1, int rs, int rm) +{ + if (rd0 != rm && rd1 != rm) + tcg_out32(s, (cond << 28) | 0x800090 | + (rd1 << 16) | (rd0 << 12) | (rs << 8) | rm); + else if (rd0 != rs && rd1 != rs) + tcg_out32(s, (cond << 28) | 0x800090 | + (rd1 << 16) | (rd0 << 12) | (rm << 8) | rs); + else { + tcg_out_dat_reg(s, cond, ARITH_MOV, + TCG_REG_R8, 0, rm, SHIFT_IMM_LSL(0)); + tcg_out32(s, (cond << 28) | 0x800098 | + (rd1 << 16) | (rd0 << 12) | (rs << 8)); + } +} + +static inline void tcg_out_smull32(TCGContext *s, + int cond, int rd0, int rd1, int rs, int rm) +{ + if (rd0 != rm && rd1 != rm) + tcg_out32(s, (cond << 28) | 0xc00090 | + (rd1 << 16) | (rd0 << 12) | (rs << 8) | rm); + else if (rd0 != rs && rd1 != rs) + tcg_out32(s, (cond << 28) | 0xc00090 | + (rd1 << 16) | (rd0 << 12) | (rm << 8) | rs); + else { + tcg_out_dat_reg(s, cond, ARITH_MOV, + TCG_REG_R8, 0, rm, SHIFT_IMM_LSL(0)); + tcg_out32(s, (cond << 28) | 0xc00098 | + (rd1 << 16) | (rd0 << 12) | (rs << 8)); + } +} + +static inline void tcg_out_ld32_12(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x05900000 | + (rn << 16) | (rd << 12) | (im & 0xfff)); + else + tcg_out32(s, (cond << 28) | 0x05100000 | + (rn << 16) | (rd << 12) | ((-im) & 0xfff)); +} + +static inline void tcg_out_st32_12(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x05800000 | + (rn << 16) | (rd << 12) | (im & 0xfff)); + else + tcg_out32(s, (cond << 28) | 0x05000000 | + (rn << 16) | (rd << 12) | ((-im) & 0xfff)); +} + +static inline void tcg_out_ld32_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x07900000 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_st32_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x07800000 | + (rn << 16) | (rd << 12) | rm); +} + +/* Register pre-increment with base writeback. */ +static inline void tcg_out_ld32_rwb(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x07b00000 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_st32_rwb(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x07a00000 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_ld16u_8(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x01d000b0 | + (rn << 16) | (rd << 12) | + ((im & 0xf0) << 4) | (im & 0xf)); + else + tcg_out32(s, (cond << 28) | 0x015000b0 | + (rn << 16) | (rd << 12) | + (((-im) & 0xf0) << 4) | ((-im) & 0xf)); +} + +static inline void tcg_out_st16u_8(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x01c000b0 | + (rn << 16) | (rd << 12) | + ((im & 0xf0) << 4) | (im & 0xf)); + else + tcg_out32(s, (cond << 28) | 0x014000b0 | + (rn << 16) | (rd << 12) | + (((-im) & 0xf0) << 4) | ((-im) & 0xf)); +} + +static inline void tcg_out_ld16u_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x019000b0 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_st16u_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x018000b0 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_ld16s_8(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x01d000f0 | + (rn << 16) | (rd << 12) | + ((im & 0xf0) << 4) | (im & 0xf)); + else + tcg_out32(s, (cond << 28) | 0x015000f0 | + (rn << 16) | (rd << 12) | + (((-im) & 0xf0) << 4) | ((-im) & 0xf)); +} + +static inline void tcg_out_st16s_8(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x01c000f0 | + (rn << 16) | (rd << 12) | + ((im & 0xf0) << 4) | (im & 0xf)); + else + tcg_out32(s, (cond << 28) | 0x014000f0 | + (rn << 16) | (rd << 12) | + (((-im) & 0xf0) << 4) | ((-im) & 0xf)); +} + +static inline void tcg_out_ld16s_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x019000f0 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_st16s_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x018000f0 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_ld8_12(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x05d00000 | + (rn << 16) | (rd << 12) | (im & 0xfff)); + else + tcg_out32(s, (cond << 28) | 0x05500000 | + (rn << 16) | (rd << 12) | ((-im) & 0xfff)); +} + +static inline void tcg_out_st8_12(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x05c00000 | + (rn << 16) | (rd << 12) | (im & 0xfff)); + else + tcg_out32(s, (cond << 28) | 0x05400000 | + (rn << 16) | (rd << 12) | ((-im) & 0xfff)); +} + +static inline void tcg_out_ld8_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x07d00000 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_st8_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x07c00000 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_ld8s_8(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x01d000d0 | + (rn << 16) | (rd << 12) | + ((im & 0xf0) << 4) | (im & 0xf)); + else + tcg_out32(s, (cond << 28) | 0x015000d0 | + (rn << 16) | (rd << 12) | + (((-im) & 0xf0) << 4) | ((-im) & 0xf)); +} + +static inline void tcg_out_st8s_8(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x01c000d0 | + (rn << 16) | (rd << 12) | + ((im & 0xf0) << 4) | (im & 0xf)); + else + tcg_out32(s, (cond << 28) | 0x014000d0 | + (rn << 16) | (rd << 12) | + (((-im) & 0xf0) << 4) | ((-im) & 0xf)); +} + +static inline void tcg_out_ld8s_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x019000d0 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_st8s_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x018000d0 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_ld32u(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xfff || offset < -0xfff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_ld32_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_ld32_12(s, cond, rd, rn, offset); +} + +static inline void tcg_out_st32(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xfff || offset < -0xfff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_st32_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_st32_12(s, cond, rd, rn, offset); +} + +static inline void tcg_out_ld16u(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xff || offset < -0xff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_ld16u_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_ld16u_8(s, cond, rd, rn, offset); +} + +static inline void tcg_out_ld16s(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xff || offset < -0xff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_ld16s_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_ld16s_8(s, cond, rd, rn, offset); +} + +static inline void tcg_out_st16u(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xff || offset < -0xff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_st16u_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_st16u_8(s, cond, rd, rn, offset); +} + +static inline void tcg_out_ld8u(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xfff || offset < -0xfff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_ld8_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_ld8_12(s, cond, rd, rn, offset); +} + +static inline void tcg_out_ld8s(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xff || offset < -0xff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_ld8s_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_ld8s_8(s, cond, rd, rn, offset); +} + +static inline void tcg_out_st8u(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xfff || offset < -0xfff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_st8_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_st8_12(s, cond, rd, rn, offset); +} + +static inline void tcg_out_goto(TCGContext *s, int cond, uint32_t addr) +{ + int32_t val; + + val = addr - (tcg_target_long) s->code_ptr; + if (val - 8 < 0x01fffffd && val - 8 > -0x01fffffd) + tcg_out_b(s, cond, val); + else { +#if 1 + tcg_abort(); +#else + if (cond == COND_AL) { + tcg_out_ld32_12(s, COND_AL, 15, 15, -4); + tcg_out32(s, addr); /* XXX: This is l->u.value, can we use it? */ + } else { + tcg_out_movi32(s, cond, TCG_REG_R8, val - 8); + tcg_out_dat_reg(s, cond, ARITH_ADD, + 15, 15, TCG_REG_R8, SHIFT_IMM_LSL(0)); + } +#endif + } +} + +static inline void tcg_out_call(TCGContext *s, int cond, uint32_t addr) +{ + int32_t val; + +#ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, TCG_REG_R8, 0, 14, SHIFT_IMM_LSL(0)); +#endif + + val = addr - (tcg_target_long) s->code_ptr; + if (val < 0x01fffffd && val > -0x01fffffd) + tcg_out_bl(s, cond, val); + else { +#if 1 + tcg_abort(); +#else + if (cond == COND_AL) { + tcg_out_dat_imm(s, cond, ARITH_ADD, 14, 15, 4); + tcg_out_ld32_12(s, COND_AL, 15, 15, -4); + tcg_out32(s, addr); /* XXX: This is l->u.value, can we use it? */ + } else { + tcg_out_movi32(s, cond, TCG_REG_R9, addr); + tcg_out_dat_imm(s, cond, ARITH_MOV, 14, 0, 15); + tcg_out_bx(s, cond, TCG_REG_R9); + } +#endif + } + +#ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, TCG_REG_R8, SHIFT_IMM_LSL(0)); +#endif +} + +static inline void tcg_out_callr(TCGContext *s, int cond, int arg) +{ +#ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, TCG_REG_R8, 0, 14, SHIFT_IMM_LSL(0)); +#endif + /* TODO: on ARMv5 and ARMv6 replace with tcg_out_blx(s, cond, arg); */ + tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, 15, SHIFT_IMM_LSL(0)); + tcg_out_bx(s, cond, arg); +#ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, TCG_REG_R8, SHIFT_IMM_LSL(0)); +#endif +} + +static inline void tcg_out_goto_label(TCGContext *s, int cond, int label_index) +{ + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) + tcg_out_goto(s, cond, l->u.value); + else if (cond == COND_AL) { + tcg_out_ld32_12(s, COND_AL, 15, 15, -4); + tcg_out_reloc(s, s->code_ptr, R_ARM_ABS32, label_index, 31337); + s->code_ptr += 4; + } else { + /* Probably this should be preferred even for COND_AL... */ + tcg_out_reloc(s, s->code_ptr, R_ARM_PC24, label_index, 31337); + tcg_out_b_noaddr(s, cond); + } +} + +static void tcg_out_div_helper(TCGContext *s, int cond, const TCGArg *args, + void *helper_div, void *helper_rem, int shift) +{ + int div_reg = args[0]; + int rem_reg = args[1]; + + /* stmdb sp!, { r0 - r3, ip, lr } */ + /* (Note that we need an even number of registers as per EABI) */ + tcg_out32(s, (cond << 28) | 0x092d500f); + + tcg_out_dat_reg(s, cond, ARITH_MOV, 0, 0, args[2], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, 1, 0, args[3], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, 2, 0, args[4], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, 3, 0, 2, shift); + + tcg_out_call(s, cond, (uint32_t) helper_div); + tcg_out_dat_reg(s, cond, ARITH_MOV, 8, 0, 0, SHIFT_IMM_LSL(0)); + + /* ldmia sp, { r0 - r3, fp, lr } */ + tcg_out32(s, (cond << 28) | 0x089d500f); + + tcg_out_dat_reg(s, cond, ARITH_MOV, 0, 0, args[2], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, 1, 0, args[3], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, 2, 0, args[4], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, 3, 0, 2, shift); + + tcg_out_call(s, cond, (uint32_t) helper_rem); + + tcg_out_dat_reg(s, cond, ARITH_MOV, rem_reg, 0, 0, SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, div_reg, 0, 8, SHIFT_IMM_LSL(0)); + + /* ldr r0, [sp], #4 */ + if (rem_reg != 0 && div_reg != 0) + tcg_out32(s, (cond << 28) | 0x04bd0004); + /* ldr r1, [sp], #4 */ + if (rem_reg != 1 && div_reg != 1) + tcg_out32(s, (cond << 28) | 0x04bd1004); + /* ldr r2, [sp], #4 */ + if (rem_reg != 2 && div_reg != 2) + tcg_out32(s, (cond << 28) | 0x04bd2004); + /* ldr r3, [sp], #4 */ + if (rem_reg != 3 && div_reg != 3) + tcg_out32(s, (cond << 28) | 0x04bd3004); + /* ldr ip, [sp], #4 */ + if (rem_reg != 12 && div_reg != 12) + tcg_out32(s, (cond << 28) | 0x04bdc004); + /* ldr lr, [sp], #4 */ + if (rem_reg != 14 && div_reg != 14) + tcg_out32(s, (cond << 28) | 0x04bde004); +} + +#ifdef CONFIG_SOFTMMU + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +#define TLB_SHIFT (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS) + +static inline void tcg_out_qemu_ld(TCGContext *s, int cond, + const TCGArg *args, int opc) +{ + int addr_reg, data_reg, data_reg2; +#ifdef CONFIG_SOFTMMU + int mem_index, s_bits; +# if TARGET_LONG_BITS == 64 + int addr_reg2; +# endif + uint32_t *label_ptr; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; /* surpress warning */ + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif +#ifdef CONFIG_SOFTMMU + mem_index = *args; + s_bits = opc & 3; + + /* Should generate something like the following: + * shr r8, addr_reg, #TARGET_PAGE_BITS + * and r0, r8, #(CPU_TLB_SIZE - 1) @ Assumption: CPU_TLB_BITS <= 8 + * add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS + */ +# if CPU_TLB_BITS > 8 +# error +# endif + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + 8, 0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS)); + tcg_out_dat_imm(s, COND_AL, ARITH_AND, + 0, 8, CPU_TLB_SIZE - 1); + tcg_out_dat_reg(s, COND_AL, ARITH_ADD, + 0, TCG_AREG0, 0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS)); + /* In the + * ldr r1 [r0, #(offsetof(CPUState, tlb_table[mem_index][0].addr_read))] + * below, the offset is likely to exceed 12 bits if mem_index != 0 and + * not exceed otherwise, so use an + * add r0, r0, #(mem_index * sizeof *CPUState.tlb_table) + * before. + */ + if (mem_index) + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 0, 0, + (mem_index << (TLB_SHIFT & 1)) | + ((16 - (TLB_SHIFT >> 1)) << 8)); + tcg_out_ld32_12(s, COND_AL, 1, 0, + offsetof(CPUState, tlb_table[0][0].addr_read)); + tcg_out_dat_reg(s, COND_AL, ARITH_CMP, + 0, 1, 8, SHIFT_IMM_LSL(TARGET_PAGE_BITS)); + /* Check alignment. */ + if (s_bits) + tcg_out_dat_imm(s, COND_EQ, ARITH_TST, + 0, addr_reg, (1 << s_bits) - 1); +# if TARGET_LONG_BITS == 64 + /* XXX: possibly we could use a block data load or writeback in + * the first access. */ + tcg_out_ld32_12(s, COND_EQ, 1, 0, + offsetof(CPUState, tlb_table[0][0].addr_read) + 4); + tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, + 0, 1, addr_reg2, SHIFT_IMM_LSL(0)); +# endif + tcg_out_ld32_12(s, COND_EQ, 1, 0, + offsetof(CPUState, tlb_table[0][0].addend)); + + switch (opc) { + case 0: + tcg_out_ld8_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 0 | 4: + tcg_out_ld8s_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 1: + tcg_out_ld16u_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 1 | 4: + tcg_out_ld16s_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 2: + default: + tcg_out_ld32_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 3: + tcg_out_ld32_rwb(s, COND_EQ, data_reg, 1, addr_reg); + tcg_out_ld32_12(s, COND_EQ, data_reg2, 1, 4); + break; + } + + label_ptr = (void *) s->code_ptr; + tcg_out_b(s, COND_EQ, 8); + +# ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, 8, 0, 14, SHIFT_IMM_LSL(0)); +# endif + + /* TODO: move this code to where the constants pool will be */ + if (addr_reg) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 0, 0, addr_reg, SHIFT_IMM_LSL(0)); +# if TARGET_LONG_BITS == 32 + tcg_out_dat_imm(s, cond, ARITH_MOV, 1, 0, mem_index); +# else + if (addr_reg2 != 1) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 1, 0, addr_reg2, SHIFT_IMM_LSL(0)); + tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index); +# endif + tcg_out_bl(s, cond, (tcg_target_long) qemu_ld_helpers[s_bits] - + (tcg_target_long) s->code_ptr); + + switch (opc) { + case 0 | 4: + tcg_out_dat_reg(s, cond, ARITH_MOV, + 0, 0, 0, SHIFT_IMM_LSL(24)); + tcg_out_dat_reg(s, cond, ARITH_MOV, + data_reg, 0, 0, SHIFT_IMM_ASR(24)); + break; + case 1 | 4: + tcg_out_dat_reg(s, cond, ARITH_MOV, + 0, 0, 0, SHIFT_IMM_LSL(16)); + tcg_out_dat_reg(s, cond, ARITH_MOV, + data_reg, 0, 0, SHIFT_IMM_ASR(16)); + break; + case 0: + case 1: + case 2: + default: + if (data_reg) + tcg_out_dat_reg(s, cond, ARITH_MOV, + data_reg, 0, 0, SHIFT_IMM_LSL(0)); + break; + case 3: + if (data_reg != 0) + tcg_out_dat_reg(s, cond, ARITH_MOV, + data_reg, 0, 0, SHIFT_IMM_LSL(0)); + if (data_reg2 != 1) + tcg_out_dat_reg(s, cond, ARITH_MOV, + data_reg2, 0, 1, SHIFT_IMM_LSL(0)); + break; + } + +# ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, 8, SHIFT_IMM_LSL(0)); +# endif + + *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2; +#else + switch (opc) { + case 0: + tcg_out_ld8_12(s, COND_AL, data_reg, addr_reg, 0); + break; + case 0 | 4: + tcg_out_ld8s_8(s, COND_AL, data_reg, addr_reg, 0); + break; + case 1: + tcg_out_ld16u_8(s, COND_AL, data_reg, addr_reg, 0); + break; + case 1 | 4: + tcg_out_ld16s_8(s, COND_AL, data_reg, addr_reg, 0); + break; + case 2: + default: + tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0); + break; + case 3: + /* TODO: use block load - + * check that data_reg2 > data_reg or the other way */ + tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0); + tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, 4); + break; + } +#endif +} + +static inline void tcg_out_qemu_st(TCGContext *s, int cond, + const TCGArg *args, int opc) +{ + int addr_reg, data_reg, data_reg2; +#ifdef CONFIG_SOFTMMU + int mem_index, s_bits; +# if TARGET_LONG_BITS == 64 + int addr_reg2; +# endif + uint32_t *label_ptr; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; /* surpress warning */ + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif +#ifdef CONFIG_SOFTMMU + mem_index = *args; + s_bits = opc & 3; + + /* Should generate something like the following: + * shr r8, addr_reg, #TARGET_PAGE_BITS + * and r0, r8, #(CPU_TLB_SIZE - 1) @ Assumption: CPU_TLB_BITS <= 8 + * add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS + */ + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + 8, 0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS)); + tcg_out_dat_imm(s, COND_AL, ARITH_AND, + 0, 8, CPU_TLB_SIZE - 1); + tcg_out_dat_reg(s, COND_AL, ARITH_ADD, + 0, TCG_AREG0, 0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS)); + /* In the + * ldr r1 [r0, #(offsetof(CPUState, tlb_table[mem_index][0].addr_write))] + * below, the offset is likely to exceed 12 bits if mem_index != 0 and + * not exceed otherwise, so use an + * add r0, r0, #(mem_index * sizeof *CPUState.tlb_table) + * before. + */ + if (mem_index) + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 0, 0, + (mem_index << (TLB_SHIFT & 1)) | + ((16 - (TLB_SHIFT >> 1)) << 8)); + tcg_out_ld32_12(s, COND_AL, 1, 0, + offsetof(CPUState, tlb_table[0][0].addr_write)); + tcg_out_dat_reg(s, COND_AL, ARITH_CMP, + 0, 1, 8, SHIFT_IMM_LSL(TARGET_PAGE_BITS)); + /* Check alignment. */ + if (s_bits) + tcg_out_dat_imm(s, COND_EQ, ARITH_TST, + 0, addr_reg, (1 << s_bits) - 1); +# if TARGET_LONG_BITS == 64 + /* XXX: possibly we could use a block data load or writeback in + * the first access. */ + tcg_out_ld32_12(s, COND_EQ, 1, 0, + offsetof(CPUState, tlb_table[0][0].addr_write) + + 4); + tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, + 0, 1, addr_reg2, SHIFT_IMM_LSL(0)); +# endif + tcg_out_ld32_12(s, COND_EQ, 1, 0, + offsetof(CPUState, tlb_table[0][0].addend)); + + switch (opc) { + case 0: + tcg_out_st8_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 0 | 4: + tcg_out_st8s_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 1: + tcg_out_st16u_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 1 | 4: + tcg_out_st16s_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 2: + default: + tcg_out_st32_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 3: + tcg_out_st32_rwb(s, COND_EQ, data_reg, 1, addr_reg); + tcg_out_st32_12(s, COND_EQ, data_reg2, 1, 4); + break; + } + + label_ptr = (void *) s->code_ptr; + tcg_out_b(s, COND_EQ, 8); + + /* TODO: move this code to where the constants pool will be */ + if (addr_reg) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 0, 0, addr_reg, SHIFT_IMM_LSL(0)); +# if TARGET_LONG_BITS == 32 + switch (opc) { + case 0: + tcg_out_dat_imm(s, cond, ARITH_AND, 1, data_reg, 0xff); + tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index); + break; + case 1: + tcg_out_dat_reg(s, cond, ARITH_MOV, + 1, 0, data_reg, SHIFT_IMM_LSL(16)); + tcg_out_dat_reg(s, cond, ARITH_MOV, + 1, 0, 1, SHIFT_IMM_LSR(16)); + tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index); + break; + case 2: + if (data_reg != 1) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 1, 0, data_reg, SHIFT_IMM_LSL(0)); + tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index); + break; + case 3: + if (data_reg != 1) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 1, 0, data_reg, SHIFT_IMM_LSL(0)); + if (data_reg2 != 2) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 2, 0, data_reg2, SHIFT_IMM_LSL(0)); + tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index); + break; + } +# else + if (addr_reg2 != 1) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 1, 0, addr_reg2, SHIFT_IMM_LSL(0)); + switch (opc) { + case 0: + tcg_out_dat_imm(s, cond, ARITH_AND, 2, data_reg, 0xff); + tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index); + break; + case 1: + tcg_out_dat_reg(s, cond, ARITH_MOV, + 2, 0, data_reg, SHIFT_IMM_LSL(16)); + tcg_out_dat_reg(s, cond, ARITH_MOV, + 2, 0, 2, SHIFT_IMM_LSR(16)); + tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index); + break; + case 2: + if (data_reg != 2) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 2, 0, data_reg, SHIFT_IMM_LSL(0)); + tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index); + break; + case 3: + tcg_out_dat_imm(s, cond, ARITH_MOV, 8, 0, mem_index); + tcg_out32(s, (cond << 28) | 0x052d8010); /* str r8, [sp, #-0x10]! */ + if (data_reg != 2) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 2, 0, data_reg, SHIFT_IMM_LSL(0)); + if (data_reg2 != 3) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 3, 0, data_reg2, SHIFT_IMM_LSL(0)); + break; + } +# endif + +# ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, 8, 0, 14, SHIFT_IMM_LSL(0)); +# endif + + tcg_out_bl(s, cond, (tcg_target_long) qemu_st_helpers[s_bits] - + (tcg_target_long) s->code_ptr); +# if TARGET_LONG_BITS == 64 + if (opc == 3) + tcg_out_dat_imm(s, cond, ARITH_ADD, 13, 13, 0x10); +# endif + +# ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, 8, SHIFT_IMM_LSL(0)); +# endif + + *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2; +#else + switch (opc) { + case 0: + tcg_out_st8_12(s, COND_AL, data_reg, addr_reg, 0); + break; + case 0 | 4: + tcg_out_st8s_8(s, COND_AL, data_reg, addr_reg, 0); + break; + case 1: + tcg_out_st16u_8(s, COND_AL, data_reg, addr_reg, 0); + break; + case 1 | 4: + tcg_out_st16s_8(s, COND_AL, data_reg, addr_reg, 0); + break; + case 2: + default: + tcg_out_st32_12(s, COND_AL, data_reg, addr_reg, 0); + break; + case 3: + /* TODO: use block store - + * check that data_reg2 > data_reg or the other way */ + tcg_out_st32_12(s, COND_AL, data_reg, addr_reg, 0); + tcg_out_st32_12(s, COND_AL, data_reg2, addr_reg, 4); + break; + } +#endif +} + +static uint8_t *tb_ret_addr; + +static inline void tcg_out_op(TCGContext *s, int opc, + const TCGArg *args, const int *const_args) +{ + int c; + + switch (opc) { + case INDEX_op_exit_tb: +#ifdef SAVE_LR + if (args[0] >> 8) + tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, 15, 0); + else + tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R0, 0, args[0]); + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, 15, 0, 14, SHIFT_IMM_LSL(0)); + if (args[0] >> 8) + tcg_out32(s, args[0]); +#else + if (args[0] >> 8) + tcg_out_ld32_12(s, COND_AL, 0, 15, 0); + else + tcg_out_dat_imm(s, COND_AL, ARITH_MOV, 0, 0, args[0]); + tcg_out_goto(s, COND_AL, (tcg_target_ulong) tb_ret_addr); + if (args[0] >> 8) + tcg_out32(s, args[0]); +#endif + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* Direct jump method */ +#if 1 + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + tcg_out_b(s, COND_AL, 8); +#else + tcg_out_ld32_12(s, COND_AL, 15, 15, -4); + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + tcg_out32(s, 0); +#endif + } else { + /* Indirect jump method */ +#if 1 + c = (int) (s->tb_next + args[0]) - ((int) s->code_ptr + 8); + if (c > 0xfff || c < -0xfff) { + tcg_out_movi32(s, COND_AL, TCG_REG_R0, + (tcg_target_long) (s->tb_next + args[0])); + tcg_out_ld32_12(s, COND_AL, 15, TCG_REG_R0, 0); + } else + tcg_out_ld32_12(s, COND_AL, 15, 15, c); +#else + tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, 15, 0); + tcg_out_ld32_12(s, COND_AL, 15, TCG_REG_R0, 0); + tcg_out32(s, (tcg_target_long) (s->tb_next + args[0])); +#endif + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_call: + if (const_args[0]) + tcg_out_call(s, COND_AL, args[0]); + else + tcg_out_callr(s, COND_AL, args[0]); + break; + case INDEX_op_jmp: + if (const_args[0]) + tcg_out_goto(s, COND_AL, args[0]); + else + tcg_out_bx(s, COND_AL, args[0]); + break; + case INDEX_op_br: + tcg_out_goto_label(s, COND_AL, args[0]); + break; + + case INDEX_op_ld8u_i32: + tcg_out_ld8u(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_ld8s_i32: + tcg_out_ld8s(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_ld16u_i32: + tcg_out_ld16u(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_ld16s_i32: + tcg_out_ld16s(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_ld_i32: + tcg_out_ld32u(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_st8_i32: + tcg_out_st8u(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_st16_i32: + tcg_out_st16u(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_st_i32: + tcg_out_st32(s, COND_AL, args[0], args[1], args[2]); + break; + + case INDEX_op_mov_i32: + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + args[0], 0, args[1], SHIFT_IMM_LSL(0)); + break; + case INDEX_op_movi_i32: + tcg_out_movi32(s, COND_AL, args[0], args[1]); + break; + case INDEX_op_add_i32: + c = ARITH_ADD; + goto gen_arith; + case INDEX_op_sub_i32: + c = ARITH_SUB; + goto gen_arith; + case INDEX_op_and_i32: + c = ARITH_AND; + goto gen_arith; + case INDEX_op_or_i32: + c = ARITH_ORR; + goto gen_arith; + case INDEX_op_xor_i32: + c = ARITH_EOR; + /* Fall through. */ + gen_arith: + tcg_out_dat_reg(s, COND_AL, c, + args[0], args[1], args[2], SHIFT_IMM_LSL(0)); + break; + case INDEX_op_add2_i32: + tcg_out_dat_reg2(s, COND_AL, ARITH_ADD, ARITH_ADC, + args[0], args[1], args[2], args[3], + args[4], args[5], SHIFT_IMM_LSL(0)); + break; + case INDEX_op_sub2_i32: + tcg_out_dat_reg2(s, COND_AL, ARITH_SUB, ARITH_SBC, + args[0], args[1], args[2], args[3], + args[4], args[5], SHIFT_IMM_LSL(0)); + break; + case INDEX_op_neg_i32: + tcg_out_dat_imm(s, COND_AL, ARITH_RSB, args[0], args[1], 0); + break; + case INDEX_op_mul_i32: + tcg_out_mul32(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_mulu2_i32: + tcg_out_umull32(s, COND_AL, args[0], args[1], args[2], args[3]); + break; + case INDEX_op_div2_i32: + tcg_out_div_helper(s, COND_AL, args, + tcg_helper_div_i64, tcg_helper_rem_i64, + SHIFT_IMM_ASR(31)); + break; + case INDEX_op_divu2_i32: + tcg_out_div_helper(s, COND_AL, args, + tcg_helper_divu_i64, tcg_helper_remu_i64, + SHIFT_IMM_LSR(31)); + break; + /* XXX: Perhaps args[2] & 0x1f is wrong */ + case INDEX_op_shl_i32: + c = const_args[2] ? + SHIFT_IMM_LSL(args[2] & 0x1f) : SHIFT_REG_LSL(args[2]); + goto gen_shift32; + case INDEX_op_shr_i32: + c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_LSR(args[2] & 0x1f) : + SHIFT_IMM_LSL(0) : SHIFT_REG_LSR(args[2]); + goto gen_shift32; + case INDEX_op_sar_i32: + c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ASR(args[2] & 0x1f) : + SHIFT_IMM_LSL(0) : SHIFT_REG_ASR(args[2]); + /* Fall through. */ + gen_shift32: + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1], c); + break; + + case INDEX_op_brcond_i32: + tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, + args[0], args[1], SHIFT_IMM_LSL(0)); + tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[2]], args[3]); + break; + case INDEX_op_brcond2_i32: + /* The resulting conditions are: + * TCG_COND_EQ --> a0 == a2 && a1 == a3, + * TCG_COND_NE --> (a0 != a2 && a1 == a3) || a1 != a3, + * TCG_COND_LT(U) --> (a0 < a2 && a1 == a3) || a1 < a3, + * TCG_COND_GE(U) --> (a0 >= a2 && a1 == a3) || (a1 >= a3 && a1 != a3), + * TCG_COND_LE(U) --> (a0 <= a2 && a1 == a3) || (a1 <= a3 && a1 != a3), + * TCG_COND_GT(U) --> (a0 > a2 && a1 == a3) || a1 > a3, + */ + tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, + args[1], args[3], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0, + args[0], args[2], SHIFT_IMM_LSL(0)); + tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[4]], args[5]); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, COND_AL, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, COND_AL, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, COND_AL, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, COND_AL, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, COND_AL, args, 2); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, COND_AL, args, 3); + break; + + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, COND_AL, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, COND_AL, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, COND_AL, args, 2); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, COND_AL, args, 3); + break; + + case INDEX_op_ext8s_i32: + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + args[0], 0, args[1], SHIFT_IMM_LSL(24)); + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + args[0], 0, args[0], SHIFT_IMM_ASR(24)); + break; + case INDEX_op_ext16s_i32: + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + args[0], 0, args[1], SHIFT_IMM_LSL(16)); + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + args[0], 0, args[0], SHIFT_IMM_ASR(16)); + break; + + default: + tcg_abort(); + } +} + +static const TCGTargetOpDef arm_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, + { INDEX_op_jmp, { "ri" } }, + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + + /* TODO: "r", "r", "ri" */ + { INDEX_op_add_i32, { "r", "r", "r" } }, + { INDEX_op_sub_i32, { "r", "r", "r" } }, + { INDEX_op_mul_i32, { "r", "r", "r" } }, + { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } }, + { INDEX_op_div2_i32, { "r", "r", "r", "1", "2" } }, + { INDEX_op_divu2_i32, { "r", "r", "r", "1", "2" } }, + { INDEX_op_and_i32, { "r", "r", "r" } }, + { INDEX_op_or_i32, { "r", "r", "r" } }, + { INDEX_op_xor_i32, { "r", "r", "r" } }, + { INDEX_op_neg_i32, { "r", "r" } }, + + { INDEX_op_shl_i32, { "r", "r", "ri" } }, + { INDEX_op_shr_i32, { "r", "r", "ri" } }, + { INDEX_op_sar_i32, { "r", "r", "ri" } }, + + { INDEX_op_brcond_i32, { "r", "r" } }, + + /* TODO: "r", "r", "r", "r", "ri", "ri" */ + { INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } }, + { INDEX_op_sub2_i32, { "r", "r", "r", "r", "r", "r" } }, + { INDEX_op_brcond2_i32, { "r", "r", "r", "r" } }, + + { INDEX_op_qemu_ld8u, { "r", "x", "X" } }, + { INDEX_op_qemu_ld8s, { "r", "x", "X" } }, + { INDEX_op_qemu_ld16u, { "r", "x", "X" } }, + { INDEX_op_qemu_ld16s, { "r", "x", "X" } }, + { INDEX_op_qemu_ld32u, { "r", "x", "X" } }, + { INDEX_op_qemu_ld64, { "d", "r", "x", "X" } }, + + { INDEX_op_qemu_st8, { "x", "x", "X" } }, + { INDEX_op_qemu_st16, { "x", "x", "X" } }, + { INDEX_op_qemu_st32, { "x", "x", "X" } }, + { INDEX_op_qemu_st64, { "x", "D", "x", "X" } }, + + { INDEX_op_ext8s_i32, { "r", "r" } }, + { INDEX_op_ext16s_i32, { "r", "r" } }, + + { -1 }, +}; + +void tcg_target_init(TCGContext *s) +{ + /* fail safe */ + if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) + tcg_abort(); + + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, + ((2 << TCG_REG_R14) - 1) & ~(1 << TCG_REG_R8)); + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + ((2 << TCG_REG_R3) - 1) | + (1 << TCG_REG_R12) | (1 << TCG_REG_R14)); + + tcg_regset_clear(s->reserved_regs); +#ifdef SAVE_LR + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R14); +#endif + tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R8); + + tcg_add_target_add_op_defs(arm_op_defs); +} + +static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + tcg_out_ld32u(s, COND_AL, arg, arg1, arg2); +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + tcg_out_st32(s, COND_AL, arg, arg1, arg2); +} + +void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + if (val > 0) + if (val < 0x100) + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, reg, reg, val); + else + tcg_abort(); + else if (val < 0) { + if (val > -0x100) + tcg_out_dat_imm(s, COND_AL, ARITH_SUB, reg, reg, -val); + else + tcg_abort(); + } +} + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ret, 0, arg, SHIFT_IMM_LSL(0)); +} + +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + tcg_out_movi32(s, COND_AL, ret, arg); +} + +void tcg_target_qemu_prologue(TCGContext *s) +{ + /* stmdb sp!, { r9 - r11, lr } */ + tcg_out32(s, (COND_AL << 28) | 0x092d4e00); + + tcg_out_bx(s, COND_AL, TCG_REG_R0); + tb_ret_addr = s->code_ptr; + + /* ldmia sp!, { r9 - r11, pc } */ + tcg_out32(s, (COND_AL << 28) | 0x08bd8e00); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/arm/tcg-target.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/arm/tcg-target.h --- qemu-0.9.1/tcg/arm/tcg-target.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/arm/tcg-target.h 2008-05-23 13:47:22.000000000 +0100 @@ -0,0 +1,76 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * Copyright (c) 2008 Andrzej Zaborowski + * + * 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. + */ +#define TCG_TARGET_ARM 1 + +#define TCG_TARGET_REG_BITS 32 +#undef TCG_TARGET_WORDS_BIGENDIAN +#undef TCG_TARGET_HAS_div_i32 +#undef TCG_TARGET_HAS_div_i64 +#undef TCG_TARGET_HAS_bswap_i32 +#define TCG_TARGET_HAS_ext8s_i32 +#define TCG_TARGET_HAS_ext16s_i32 +#define TCG_TARGET_HAS_neg_i32 +#undef TCG_TARGET_HAS_neg_i64 +#undef TCG_TARGET_STACK_GROWSUP + +enum { + TCG_REG_R0 = 0, + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_TARGET_NB_REGS +}; + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_R13 +#define TCG_TARGET_STACK_ALIGN 8 +#define TCG_TARGET_CALL_STACK_OFFSET 0 + +enum { + /* Note: must be synced with dyngen-exec.h */ + TCG_AREG0 = TCG_REG_R7, + TCG_AREG1 = TCG_REG_R4, + TCG_AREG2 = TCG_REG_R5, + TCG_AREG3 = TCG_REG_R6, +}; + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + register unsigned long _beg __asm ("a1") = start; + register unsigned long _end __asm ("a2") = stop; + register unsigned long _flg __asm ("a3") = 0; + __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/hppa/tcg-target.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/hppa/tcg-target.c --- qemu-0.9.1/tcg/hppa/tcg-target.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/hppa/tcg-target.c 2008-10-05 10:59:14.000000000 +0100 @@ -0,0 +1,975 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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. + */ + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "%r0", + "%r1", + "%rp", + "%r3", + "%r4", + "%r5", + "%r6", + "%r7", + "%r8", + "%r9", + "%r10", + "%r11", + "%r12", + "%r13", + "%r14", + "%r15", + "%r16", + "%r17", + "%r18", + "%r19", + "%r20", + "%r21", + "%r22", + "%r23", + "%r24", + "%r25", + "%r26", + "%dp", + "%ret0", + "%ret1", + "%sp", + "%r31", +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + + TCG_REG_R17, + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, +}; + +static const int tcg_target_call_iarg_regs[4] = { + TCG_REG_R26, + TCG_REG_R25, + TCG_REG_R24, + TCG_REG_R23, +}; + +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_RET0, + TCG_REG_RET1, +}; + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + switch (type) { + case R_PARISC_PCREL17F: + hppa_patch17f((uint32_t *)code_ptr, value, addend); + break; + default: + tcg_abort(); + } +} + +/* maximum number of register used for input function arguments */ +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + return 4; +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch (ct_str[0]) { + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + break; + case 'L': /* qemu_ld/st constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R26); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R25); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R24); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R23); + break; + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + + ct = arg_ct->ct; + + /* TODO */ + + return 0; +} + +#define INSN_OP(x) ((x) << 26) +#define INSN_EXT3BR(x) ((x) << 13) +#define INSN_EXT3SH(x) ((x) << 10) +#define INSN_EXT4(x) ((x) << 6) +#define INSN_EXT5(x) (x) +#define INSN_EXT6(x) ((x) << 6) +#define INSN_EXT7(x) ((x) << 6) +#define INSN_EXT8A(x) ((x) << 6) +#define INSN_EXT8B(x) ((x) << 5) +#define INSN_T(x) (x) +#define INSN_R1(x) ((x) << 16) +#define INSN_R2(x) ((x) << 21) +#define INSN_DEP_LEN(x) (32 - (x)) +#define INSN_SHDEP_CP(x) ((31 - (x)) << 5) +#define INSN_SHDEP_P(x) ((x) << 5) +#define INSN_COND(x) ((x) << 13) + +#define COND_NEVER 0 +#define COND_EQUAL 1 +#define COND_LT 2 +#define COND_LTEQ 3 +#define COND_LTU 4 +#define COND_LTUEQ 5 +#define COND_SV 6 +#define COND_OD 7 + + +/* Logical ADD */ +#define ARITH_ADD (INSN_OP(0x02) | INSN_EXT6(0x28)) +#define ARITH_AND (INSN_OP(0x02) | INSN_EXT6(0x08)) +#define ARITH_OR (INSN_OP(0x02) | INSN_EXT6(0x09)) +#define ARITH_XOR (INSN_OP(0x02) | INSN_EXT6(0x0a)) +#define ARITH_SUB (INSN_OP(0x02) | INSN_EXT6(0x10)) + +#define SHD (INSN_OP(0x34) | INSN_EXT3SH(2)) +#define VSHD (INSN_OP(0x34) | INSN_EXT3SH(0)) +#define DEP (INSN_OP(0x35) | INSN_EXT3SH(3)) +#define ZDEP (INSN_OP(0x35) | INSN_EXT3SH(2)) +#define ZVDEP (INSN_OP(0x35) | INSN_EXT3SH(0)) +#define EXTRU (INSN_OP(0x34) | INSN_EXT3SH(6)) +#define EXTRS (INSN_OP(0x34) | INSN_EXT3SH(7)) +#define VEXTRS (INSN_OP(0x34) | INSN_EXT3SH(5)) + +#define SUBI (INSN_OP(0x25)) +#define MTCTL (INSN_OP(0x00) | INSN_EXT8B(0xc2)) + +#define BL (INSN_OP(0x3a) | INSN_EXT3BR(0)) +#define BLE_SR4 (INSN_OP(0x39) | (1 << 13)) +#define BV (INSN_OP(0x3a) | INSN_EXT3BR(6)) +#define BV_N (INSN_OP(0x3a) | INSN_EXT3BR(6) | 2) +#define LDIL (INSN_OP(0x08)) +#define LDO (INSN_OP(0x0d)) + +#define LDB (INSN_OP(0x10)) +#define LDH (INSN_OP(0x11)) +#define LDW (INSN_OP(0x12)) +#define LDWM (INSN_OP(0x13)) + +#define STB (INSN_OP(0x18)) +#define STH (INSN_OP(0x19)) +#define STW (INSN_OP(0x1a)) +#define STWM (INSN_OP(0x1b)) + +#define COMBT (INSN_OP(0x20)) +#define COMBF (INSN_OP(0x22)) + +static int lowsignext(uint32_t val, int start, int length) +{ + return (((val << 1) & ~(~0 << length)) | + ((val >> (length - 1)) & 1)) << start; +} + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + /* PA1.1 defines COPY as OR r,0,t */ + tcg_out32(s, ARITH_OR | INSN_T(ret) | INSN_R1(arg) | INSN_R2(TCG_REG_R0)); + + /* PA2.0 defines COPY as LDO 0(r),t + * but hppa-dis.c is unaware of this definition */ + /* tcg_out32(s, LDO | INSN_R1(ret) | INSN_R2(arg) | reassemble_14(0)); */ +} + +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + if (arg == (arg & 0x1fff)) { + tcg_out32(s, LDO | INSN_R1(ret) | INSN_R2(TCG_REG_R0) | + reassemble_14(arg)); + } else { + tcg_out32(s, LDIL | INSN_R2(ret) | + reassemble_21(lrsel((uint32_t)arg, 0))); + if (arg & 0x7ff) + tcg_out32(s, LDO | INSN_R1(ret) | INSN_R2(ret) | + reassemble_14(rrsel((uint32_t)arg, 0))); + } +} + +static inline void tcg_out_ld_raw(TCGContext *s, int ret, + tcg_target_long arg) +{ + tcg_out32(s, LDIL | INSN_R2(ret) | + reassemble_21(lrsel((uint32_t)arg, 0))); + tcg_out32(s, LDW | INSN_R1(ret) | INSN_R2(ret) | + reassemble_14(rrsel((uint32_t)arg, 0))); +} + +static inline void tcg_out_ld_ptr(TCGContext *s, int ret, + tcg_target_long arg) +{ + tcg_out_ld_raw(s, ret, arg); +} + +static inline void tcg_out_ldst(TCGContext *s, int ret, int addr, int offset, + int op) +{ + if (offset == (offset & 0xfff)) + tcg_out32(s, op | INSN_R1(ret) | INSN_R2(addr) | + reassemble_14(offset)); + else { + fprintf(stderr, "unimplemented %s with offset %d\n", __func__, offset); + tcg_abort(); + } +} + +static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret, + int arg1, tcg_target_long arg2) +{ + fprintf(stderr, "unimplemented %s\n", __func__); + tcg_abort(); +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int ret, + int arg1, tcg_target_long arg2) +{ + fprintf(stderr, "unimplemented %s\n", __func__); + tcg_abort(); +} + +static inline void tcg_out_arith(TCGContext *s, int t, int r1, int r2, int op) +{ + tcg_out32(s, op | INSN_T(t) | INSN_R1(r1) | INSN_R2(r2)); +} + +static inline void tcg_out_arithi(TCGContext *s, int t, int r1, + tcg_target_long val, int op) +{ + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R20, val); + tcg_out_arith(s, t, r1, TCG_REG_R20, op); +} + +static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + tcg_out_arithi(s, reg, reg, val, ARITH_ADD); +} + +static inline void tcg_out_nop(TCGContext *s) +{ + tcg_out32(s, ARITH_OR | INSN_T(TCG_REG_R0) | INSN_R1(TCG_REG_R0) | + INSN_R2(TCG_REG_R0)); +} + +static inline void tcg_out_ext8s(TCGContext *s, int ret, int arg) { + tcg_out32(s, EXTRS | INSN_R1(ret) | INSN_R2(arg) | + INSN_SHDEP_P(31) | INSN_DEP_LEN(8)); +} + +static inline void tcg_out_ext16s(TCGContext *s, int ret, int arg) { + tcg_out32(s, EXTRS | INSN_R1(ret) | INSN_R2(arg) | + INSN_SHDEP_P(31) | INSN_DEP_LEN(16)); +} + +static inline void tcg_out_bswap16(TCGContext *s, int ret, int arg) { + if(ret != arg) + tcg_out_mov(s, ret, arg); + tcg_out32(s, DEP | INSN_R2(ret) | INSN_R1(ret) | + INSN_SHDEP_CP(15) | INSN_DEP_LEN(8)); + tcg_out32(s, SHD | INSN_T(ret) | INSN_R1(TCG_REG_R0) | + INSN_R2(ret) | INSN_SHDEP_CP(8)); +} + +static inline void tcg_out_bswap32(TCGContext *s, int ret, int arg, int temp) { + tcg_out32(s, SHD | INSN_T(temp) | INSN_R1(arg) | + INSN_R2(arg) | INSN_SHDEP_CP(16)); + tcg_out32(s, DEP | INSN_R2(temp) | INSN_R1(temp) | + INSN_SHDEP_CP(15) | INSN_DEP_LEN(8)); + tcg_out32(s, SHD | INSN_T(ret) | INSN_R1(arg) | + INSN_R2(temp) | INSN_SHDEP_CP(8)); +} + +static inline void tcg_out_call(TCGContext *s, void *func) +{ + uint32_t val = (uint32_t)__canonicalize_funcptr_for_compare(func); + tcg_out32(s, LDIL | INSN_R2(TCG_REG_R20) | + reassemble_21(lrsel(val, 0))); + tcg_out32(s, BLE_SR4 | INSN_R2(TCG_REG_R20) | + reassemble_17(rrsel(val, 0) >> 2)); + tcg_out_mov(s, TCG_REG_RP, TCG_REG_R31); +} + +#if defined(CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) +{ + int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap; +#if defined(CONFIG_SOFTMMU) + uint32_t *label1_ptr, *label2_ptr; +#endif +#if TARGET_LONG_BITS == 64 +#if defined(CONFIG_SOFTMMU) + uint32_t *label3_ptr; +#endif + int addr_reg2; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; /* surpress warning */ + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif + mem_index = *args; + s_bits = opc & 3; + + r0 = TCG_REG_R26; + r1 = TCG_REG_R25; + +#if defined(CONFIG_SOFTMMU) + tcg_out_mov(s, r1, addr_reg); + + tcg_out_mov(s, r0, addr_reg); + + tcg_out32(s, SHD | INSN_T(r1) | INSN_R1(TCG_REG_R0) | INSN_R2(r1) | + INSN_SHDEP_CP(TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)); + + tcg_out_arithi(s, r0, r0, TARGET_PAGE_MASK | ((1 << s_bits) - 1), + ARITH_AND); + + tcg_out_arithi(s, r1, r1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, + ARITH_AND); + + tcg_out_arith(s, r1, r1, TCG_AREG0, ARITH_ADD); + tcg_out_arithi(s, r1, r1, + offsetof(CPUState, tlb_table[mem_index][0].addr_read), + ARITH_ADD); + + tcg_out_ldst(s, TCG_REG_R20, r1, 0, LDW); + +#if TARGET_LONG_BITS == 32 + /* if equal, jump to label1 */ + label1_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(r0) | + INSN_COND(COND_EQUAL)); + tcg_out_mov(s, r0, addr_reg); /* delay slot */ +#else + /* if not equal, jump to label3 */ + label3_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, COMBF | INSN_R1(TCG_REG_R20) | INSN_R2(r0) | + INSN_COND(COND_EQUAL)); + tcg_out_mov(s, r0, addr_reg); /* delay slot */ + + tcg_out_ldst(s, TCG_REG_R20, r1, 4, LDW); + + /* if equal, jump to label1 */ + label1_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(addr_reg2) | + INSN_COND(COND_EQUAL)); + tcg_out_nop(s); /* delay slot */ + + /* label3: */ + *label3_ptr |= reassemble_12((uint32_t *)s->code_ptr - label3_ptr - 2); +#endif + +#if TARGET_LONG_BITS == 32 + tcg_out_mov(s, TCG_REG_R26, addr_reg); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R25, mem_index); +#else + tcg_out_mov(s, TCG_REG_R26, addr_reg); + tcg_out_mov(s, TCG_REG_R25, addr_reg2); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R24, mem_index); +#endif + + tcg_out_call(s, qemu_ld_helpers[s_bits]); + + switch(opc) { + case 0 | 4: + tcg_out_ext8s(s, data_reg, TCG_REG_RET0); + break; + case 1 | 4: + tcg_out_ext16s(s, data_reg, TCG_REG_RET0); + break; + case 0: + case 1: + case 2: + default: + tcg_out_mov(s, data_reg, TCG_REG_RET0); + break; + case 3: + tcg_abort(); + tcg_out_mov(s, data_reg, TCG_REG_RET0); + tcg_out_mov(s, data_reg2, TCG_REG_RET1); + break; + } + + /* jump to label2 */ + label2_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, BL | INSN_R2(TCG_REG_R0) | 2); + + /* label1: */ + *label1_ptr |= reassemble_12((uint32_t *)s->code_ptr - label1_ptr - 2); + + tcg_out_arithi(s, TCG_REG_R20, r1, + offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_read), + ARITH_ADD); + tcg_out_ldst(s, TCG_REG_R20, TCG_REG_R20, 0, LDW); + tcg_out_arith(s, r0, r0, TCG_REG_R20, ARITH_ADD); +#else + r0 = addr_reg; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + switch (opc) { + case 0: + tcg_out_ldst(s, data_reg, r0, 0, LDB); + break; + case 0 | 4: + tcg_out_ldst(s, data_reg, r0, 0, LDB); + tcg_out_ext8s(s, data_reg, data_reg); + break; + case 1: + tcg_out_ldst(s, data_reg, r0, 0, LDH); + if (bswap) + tcg_out_bswap16(s, data_reg, data_reg); + break; + case 1 | 4: + tcg_out_ldst(s, data_reg, r0, 0, LDH); + if (bswap) + tcg_out_bswap16(s, data_reg, data_reg); + tcg_out_ext16s(s, data_reg, data_reg); + break; + case 2: + tcg_out_ldst(s, data_reg, r0, 0, LDW); + if (bswap) + tcg_out_bswap32(s, data_reg, data_reg, TCG_REG_R20); + break; + case 3: + tcg_abort(); + if (!bswap) { + tcg_out_ldst(s, data_reg, r0, 0, LDW); + tcg_out_ldst(s, data_reg2, r0, 4, LDW); + } else { + tcg_out_ldst(s, data_reg, r0, 4, LDW); + tcg_out_bswap32(s, data_reg, data_reg, TCG_REG_R20); + tcg_out_ldst(s, data_reg2, r0, 0, LDW); + tcg_out_bswap32(s, data_reg2, data_reg2, TCG_REG_R20); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr |= reassemble_17((uint32_t *)s->code_ptr - label2_ptr - 2); +#endif +} + +static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) +{ + int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap; +#if defined(CONFIG_SOFTMMU) + uint32_t *label1_ptr, *label2_ptr; +#endif +#if TARGET_LONG_BITS == 64 +#if defined(CONFIG_SOFTMMU) + uint32_t *label3_ptr; +#endif + int addr_reg2; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; /* surpress warning */ + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif + mem_index = *args; + + s_bits = opc; + + r0 = TCG_REG_R26; + r1 = TCG_REG_R25; + +#if defined(CONFIG_SOFTMMU) + tcg_out_mov(s, r1, addr_reg); + + tcg_out_mov(s, r0, addr_reg); + + tcg_out32(s, SHD | INSN_T(r1) | INSN_R1(TCG_REG_R0) | INSN_R2(r1) | + INSN_SHDEP_CP(TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)); + + tcg_out_arithi(s, r0, r0, TARGET_PAGE_MASK | ((1 << s_bits) - 1), + ARITH_AND); + + tcg_out_arithi(s, r1, r1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, + ARITH_AND); + + tcg_out_arith(s, r1, r1, TCG_AREG0, ARITH_ADD); + tcg_out_arithi(s, r1, r1, + offsetof(CPUState, tlb_table[mem_index][0].addr_write), + ARITH_ADD); + + tcg_out_ldst(s, TCG_REG_R20, r1, 0, LDW); + +#if TARGET_LONG_BITS == 32 + /* if equal, jump to label1 */ + label1_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(r0) | + INSN_COND(COND_EQUAL)); + tcg_out_mov(s, r0, addr_reg); /* delay slot */ +#else + /* if not equal, jump to label3 */ + label3_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, COMBF | INSN_R1(TCG_REG_R20) | INSN_R2(r0) | + INSN_COND(COND_EQUAL)); + tcg_out_mov(s, r0, addr_reg); /* delay slot */ + + tcg_out_ldst(s, TCG_REG_R20, r1, 4, LDW); + + /* if equal, jump to label1 */ + label1_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(addr_reg2) | + INSN_COND(COND_EQUAL)); + tcg_out_nop(s); /* delay slot */ + + /* label3: */ + *label3_ptr |= reassemble_12((uint32_t *)s->code_ptr - label3_ptr - 2); +#endif + + tcg_out_mov(s, TCG_REG_R26, addr_reg); +#if TARGET_LONG_BITS == 64 + tcg_out_mov(s, TCG_REG_R25, addr_reg2); + if (opc == 3) { + tcg_abort(); + tcg_out_mov(s, TCG_REG_R24, data_reg); + tcg_out_mov(s, TCG_REG_R23, data_reg2); + /* TODO: push mem_index */ + tcg_abort(); + } else { + switch(opc) { + case 0: + tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R24) | INSN_R2(data_reg) | + INSN_SHDEP_P(31) | INSN_DEP_LEN(8)); + break; + case 1: + tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R24) | INSN_R2(data_reg) | + INSN_SHDEP_P(31) | INSN_DEP_LEN(16)); + break; + case 2: + tcg_out_mov(s, TCG_REG_R24, data_reg); + break; + } + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R23, mem_index); + } +#else + if (opc == 3) { + tcg_abort(); + tcg_out_mov(s, TCG_REG_R25, data_reg); + tcg_out_mov(s, TCG_REG_R24, data_reg2); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R23, mem_index); + } else { + switch(opc) { + case 0: + tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R25) | INSN_R2(data_reg) | + INSN_SHDEP_P(31) | INSN_DEP_LEN(8)); + break; + case 1: + tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R25) | INSN_R2(data_reg) | + INSN_SHDEP_P(31) | INSN_DEP_LEN(16)); + break; + case 2: + tcg_out_mov(s, TCG_REG_R25, data_reg); + break; + } + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R24, mem_index); + } +#endif + tcg_out_call(s, qemu_st_helpers[s_bits]); + + /* jump to label2 */ + label2_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, BL | INSN_R2(TCG_REG_R0) | 2); + + /* label1: */ + *label1_ptr |= reassemble_12((uint32_t *)s->code_ptr - label1_ptr - 2); + + tcg_out_arithi(s, TCG_REG_R20, r1, + offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_write), + ARITH_ADD); + tcg_out_ldst(s, TCG_REG_R20, TCG_REG_R20, 0, LDW); + tcg_out_arith(s, r0, r0, TCG_REG_R20, ARITH_ADD); +#else + r0 = addr_reg; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + switch (opc) { + case 0: + tcg_out_ldst(s, data_reg, r0, 0, STB); + break; + case 1: + if (bswap) { + tcg_out_bswap16(s, TCG_REG_R20, data_reg); + data_reg = TCG_REG_R20; + } + tcg_out_ldst(s, data_reg, r0, 0, STH); + break; + case 2: + if (bswap) { + tcg_out_bswap32(s, TCG_REG_R20, data_reg, TCG_REG_R20); + data_reg = TCG_REG_R20; + } + tcg_out_ldst(s, data_reg, r0, 0, STW); + break; + case 3: + tcg_abort(); + if (!bswap) { + tcg_out_ldst(s, data_reg, r0, 0, STW); + tcg_out_ldst(s, data_reg2, r0, 4, STW); + } else { + tcg_out_bswap32(s, TCG_REG_R20, data_reg, TCG_REG_R20); + tcg_out_ldst(s, TCG_REG_R20, r0, 4, STW); + tcg_out_bswap32(s, TCG_REG_R20, data_reg2, TCG_REG_R20); + tcg_out_ldst(s, TCG_REG_R20, r0, 0, STW); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr |= reassemble_17((uint32_t *)s->code_ptr - label2_ptr - 2); +#endif +} + +static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, + const int *const_args) +{ + int c; + + switch (opc) { + case INDEX_op_exit_tb: + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RET0, args[0]); + tcg_out32(s, BV_N | INSN_R2(TCG_REG_R18)); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + fprintf(stderr, "goto_tb direct\n"); + tcg_abort(); + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R20, args[0]); + tcg_out32(s, BV_N | INSN_R2(TCG_REG_R20)); + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + } else { + /* indirect jump method */ + tcg_out_ld_ptr(s, TCG_REG_R20, + (tcg_target_long)(s->tb_next + args[0])); + tcg_out32(s, BV_N | INSN_R2(TCG_REG_R20)); + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_call: + tcg_out32(s, BLE_SR4 | INSN_R2(args[0])); + tcg_out_mov(s, TCG_REG_RP, TCG_REG_R31); + break; + case INDEX_op_jmp: + fprintf(stderr, "unimplemented jmp\n"); + tcg_abort(); + break; + case INDEX_op_br: + fprintf(stderr, "unimplemented br\n"); + tcg_abort(); + break; + case INDEX_op_movi_i32: + tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]); + break; + + case INDEX_op_ld8u_i32: + tcg_out_ldst(s, args[0], args[1], args[2], LDB); + break; + case INDEX_op_ld8s_i32: + tcg_out_ldst(s, args[0], args[1], args[2], LDB); + tcg_out_ext8s(s, args[0], args[0]); + break; + case INDEX_op_ld16u_i32: + tcg_out_ldst(s, args[0], args[1], args[2], LDH); + break; + case INDEX_op_ld16s_i32: + tcg_out_ldst(s, args[0], args[1], args[2], LDH); + tcg_out_ext16s(s, args[0], args[0]); + break; + case INDEX_op_ld_i32: + tcg_out_ldst(s, args[0], args[1], args[2], LDW); + break; + + case INDEX_op_st8_i32: + tcg_out_ldst(s, args[0], args[1], args[2], STB); + break; + case INDEX_op_st16_i32: + tcg_out_ldst(s, args[0], args[1], args[2], STH); + break; + case INDEX_op_st_i32: + tcg_out_ldst(s, args[0], args[1], args[2], STW); + break; + + case INDEX_op_sub_i32: + c = ARITH_SUB; + goto gen_arith; + case INDEX_op_and_i32: + c = ARITH_AND; + goto gen_arith; + case INDEX_op_or_i32: + c = ARITH_OR; + goto gen_arith; + case INDEX_op_xor_i32: + c = ARITH_XOR; + goto gen_arith; + case INDEX_op_add_i32: + c = ARITH_ADD; + goto gen_arith; + + case INDEX_op_shl_i32: + tcg_out32(s, SUBI | INSN_R1(TCG_REG_R20) | INSN_R2(args[2]) | + lowsignext(0x1f, 0, 11)); + tcg_out32(s, MTCTL | INSN_R2(11) | INSN_R1(TCG_REG_R20)); + tcg_out32(s, ZVDEP | INSN_R2(args[0]) | INSN_R1(args[1]) | + INSN_DEP_LEN(32)); + break; + case INDEX_op_shr_i32: + tcg_out32(s, MTCTL | INSN_R2(11) | INSN_R1(args[2])); + tcg_out32(s, VSHD | INSN_T(args[0]) | INSN_R1(TCG_REG_R0) | + INSN_R2(args[1])); + break; + case INDEX_op_sar_i32: + tcg_out32(s, SUBI | INSN_R1(TCG_REG_R20) | INSN_R2(args[2]) | + lowsignext(0x1f, 0, 11)); + tcg_out32(s, MTCTL | INSN_R2(11) | INSN_R1(TCG_REG_R20)); + tcg_out32(s, VEXTRS | INSN_R1(args[0]) | INSN_R2(args[1]) | + INSN_DEP_LEN(32)); + break; + + case INDEX_op_mul_i32: + fprintf(stderr, "unimplemented mul\n"); + tcg_abort(); + break; + case INDEX_op_mulu2_i32: + fprintf(stderr, "unimplemented mulu2\n"); + tcg_abort(); + break; + case INDEX_op_div2_i32: + fprintf(stderr, "unimplemented div2\n"); + tcg_abort(); + break; + case INDEX_op_divu2_i32: + fprintf(stderr, "unimplemented divu2\n"); + tcg_abort(); + break; + + case INDEX_op_brcond_i32: + fprintf(stderr, "unimplemented brcond\n"); + tcg_abort(); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, args, 2); + break; + + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; + + default: + fprintf(stderr, "unknown opcode 0x%x\n", opc); + tcg_abort(); + } + return; + +gen_arith: + tcg_out_arith(s, args[0], args[1], args[2], c); +} + +static const TCGTargetOpDef hppa_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + + { INDEX_op_call, { "r" } }, + { INDEX_op_jmp, { "r" } }, + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "r", "r" } }, + { INDEX_op_sub_i32, { "r", "r", "r" } }, + { INDEX_op_and_i32, { "r", "r", "r" } }, + { INDEX_op_or_i32, { "r", "r", "r" } }, + { INDEX_op_xor_i32, { "r", "r", "r" } }, + + { INDEX_op_shl_i32, { "r", "r", "r" } }, + { INDEX_op_shr_i32, { "r", "r", "r" } }, + { INDEX_op_sar_i32, { "r", "r", "r" } }, + + { INDEX_op_brcond_i32, { "r", "r" } }, + +#if TARGET_LONG_BITS == 32 + { INDEX_op_qemu_ld8u, { "r", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L" } }, + { INDEX_op_qemu_ld64, { "r", "r", "L" } }, + + { INDEX_op_qemu_st8, { "L", "L" } }, + { INDEX_op_qemu_st16, { "L", "L" } }, + { INDEX_op_qemu_st32, { "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L", "L" } }, +#else + { INDEX_op_qemu_ld8u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld32s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld64, { "r", "r", "L", "L" } }, + + { INDEX_op_qemu_st8, { "L", "L", "L" } }, + { INDEX_op_qemu_st16, { "L", "L", "L" } }, + { INDEX_op_qemu_st32, { "L", "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L", "L", "L" } }, +#endif + { -1 }, +}; + +void tcg_target_init(TCGContext *s) +{ + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff); + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_R20) | + (1 << TCG_REG_R21) | + (1 << TCG_REG_R22) | + (1 << TCG_REG_R23) | + (1 << TCG_REG_R24) | + (1 << TCG_REG_R25) | + (1 << TCG_REG_R26)); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0); /* hardwired to zero */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1); /* addil target */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_RP); /* link register */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R3); /* frame pointer */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R18); /* return pointer */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R19); /* clobbered w/o pic */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R20); /* reserved */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_DP); /* data pointer */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); /* stack pointer */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R31); /* ble link reg */ + + tcg_add_target_add_op_defs(hppa_op_defs); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/hppa/tcg-target.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/hppa/tcg-target.h --- qemu-0.9.1/tcg/hppa/tcg-target.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/hppa/tcg-target.h 2008-04-12 21:14:54.000000000 +0100 @@ -0,0 +1,204 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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. + */ + +#define TCG_TARGET_HPPA 1 + +#if defined(_PA_RISC1_1) +#define TCG_TARGET_REG_BITS 32 +#else +#error unsupported +#endif + +#define TCG_TARGET_WORDS_BIGENDIAN + +#define TCG_TARGET_NB_REGS 32 + +enum { + TCG_REG_R0 = 0, + TCG_REG_R1, + TCG_REG_RP, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + TCG_REG_DP, + TCG_REG_RET0, + TCG_REG_RET1, + TCG_REG_SP, + TCG_REG_R31, +}; + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_SP +#define TCG_TARGET_STACK_ALIGN 16 +#define TCG_TARGET_STACK_GROWSUP + +/* optional instructions */ +//#define TCG_TARGET_HAS_ext8s_i32 +//#define TCG_TARGET_HAS_ext16s_i32 +//#define TCG_TARGET_HAS_bswap16_i32 +//#define TCG_TARGET_HAS_bswap_i32 + +/* Note: must be synced with dyngen-exec.h */ +#define TCG_AREG0 TCG_REG_R17 +#define TCG_AREG1 TCG_REG_R14 +#define TCG_AREG2 TCG_REG_R15 +#define TCG_AREG3 TCG_REG_R16 + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + start &= ~31; + while (start <= stop) + { + asm volatile ("fdc 0(%0)\n" + "sync\n" + "fic 0(%%sr4, %0)\n" + "sync\n" + : : "r"(start) : "memory"); + start += 32; + } +} + +/* supplied by libgcc */ +extern void *__canonicalize_funcptr_for_compare(void *); + +/* Field selection types defined by hppa */ +#define rnd(x) (((x)+0x1000)&~0x1fff) +/* lsel: select left 21 bits */ +#define lsel(v,a) (((v)+(a))>>11) +/* rsel: select right 11 bits */ +#define rsel(v,a) (((v)+(a))&0x7ff) +/* lrsel with rounding of addend to nearest 8k */ +#define lrsel(v,a) (((v)+rnd(a))>>11) +/* rrsel with rounding of addend to nearest 8k */ +#define rrsel(v,a) ((((v)+rnd(a))&0x7ff)+((a)-rnd(a))) + +#define mask(x,sz) ((x) & ~((1<<(sz))-1)) + +static inline int reassemble_12(int as12) +{ + return (((as12 & 0x800) >> 11) | + ((as12 & 0x400) >> 8) | + ((as12 & 0x3ff) << 3)); +} + +static inline int reassemble_14(int as14) +{ + return (((as14 & 0x1fff) << 1) | + ((as14 & 0x2000) >> 13)); +} + +static inline int reassemble_17(int as17) +{ + return (((as17 & 0x10000) >> 16) | + ((as17 & 0x0f800) << 5) | + ((as17 & 0x00400) >> 8) | + ((as17 & 0x003ff) << 3)); +} + +static inline int reassemble_21(int as21) +{ + return (((as21 & 0x100000) >> 20) | + ((as21 & 0x0ffe00) >> 8) | + ((as21 & 0x000180) << 7) | + ((as21 & 0x00007c) << 14) | + ((as21 & 0x000003) << 12)); +} + +static inline void hppa_patch21l(uint32_t *insn, int val, int addend) +{ + val = lrsel(val, addend); + *insn = mask(*insn, 21) | reassemble_21(val); +} + +static inline void hppa_patch14r(uint32_t *insn, int val, int addend) +{ + val = rrsel(val, addend); + *insn = mask(*insn, 14) | reassemble_14(val); +} + +static inline void hppa_patch17r(uint32_t *insn, int val, int addend) +{ + val = rrsel(val, addend); + *insn = (*insn & ~0x1f1ffd) | reassemble_17(val); +} + + +static inline void hppa_patch21l_dprel(uint32_t *insn, int val, int addend) +{ + register unsigned int dp asm("r27"); + hppa_patch21l(insn, val - dp, addend); +} + +static inline void hppa_patch14r_dprel(uint32_t *insn, int val, int addend) +{ + register unsigned int dp asm("r27"); + hppa_patch14r(insn, val - dp, addend); +} + +static inline void hppa_patch17f(uint32_t *insn, int val, int addend) +{ + int dot = (int)insn & ~0x3; + int v = ((val + addend) - dot - 8) / 4; + if (v > (1 << 16) || v < -(1 << 16)) { + printf("cannot fit branch to offset %d [%08x->%08x]\n", v, dot, val); + abort(); + } + *insn = (*insn & ~0x1f1ffd) | reassemble_17(v); +} + +static inline void hppa_load_imm21l(uint32_t *insn, int val, int addend) +{ + /* Transform addil L'sym(%dp) to ldil L'val, %r1 */ + *insn = 0x20200000 | reassemble_21(lrsel(val, 0)); +} + +static inline void hppa_load_imm14r(uint32_t *insn, int val, int addend) +{ + /* Transform ldw R'sym(%r1), %rN to ldo R'sym(%r1), %rN */ + hppa_patch14r(insn, val, addend); + /* HACK */ + if (addend == 0) + *insn = (*insn & ~0xfc000000) | (0x0d << 26); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/i386/tcg-target.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/i386/tcg-target.c --- qemu-0.9.1/tcg/i386/tcg-target.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/i386/tcg-target.c 2008-10-05 10:59:14.000000000 +0100 @@ -0,0 +1,1188 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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. + */ + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "%eax", + "%ecx", + "%edx", + "%ebx", + "%esp", + "%ebp", + "%esi", + "%edi", +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_EAX, + TCG_REG_EDX, + TCG_REG_ECX, + TCG_REG_EBX, + TCG_REG_ESI, + TCG_REG_EDI, + TCG_REG_EBP, +}; + +static const int tcg_target_call_iarg_regs[3] = { TCG_REG_EAX, TCG_REG_EDX, TCG_REG_ECX }; +static const int tcg_target_call_oarg_regs[2] = { TCG_REG_EAX, TCG_REG_EDX }; + +static uint8_t *tb_ret_addr; + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + value += addend; + switch(type) { + case R_386_32: + *(uint32_t *)code_ptr = value; + break; + case R_386_PC32: + *(uint32_t *)code_ptr = value - (long)code_ptr; + break; + default: + tcg_abort(); + } +} + +/* maximum number of register used for input function arguments */ +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + flags &= TCG_CALL_TYPE_MASK; + switch(flags) { + case TCG_CALL_TYPE_STD: + return 0; + case TCG_CALL_TYPE_REGPARM_1: + case TCG_CALL_TYPE_REGPARM_2: + case TCG_CALL_TYPE_REGPARM: + return flags - TCG_CALL_TYPE_REGPARM_1 + 1; + default: + tcg_abort(); + } +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch(ct_str[0]) { + case 'a': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_EAX); + break; + case 'b': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_EBX); + break; + case 'c': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_ECX); + break; + case 'd': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_EDX); + break; + case 'S': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_ESI); + break; + case 'D': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_EDI); + break; + case 'q': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xf); + break; + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xff); + break; + + /* qemu_ld/st address constraint */ + case 'L': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_EAX); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_EDX); + break; + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + else + return 0; +} + +#define ARITH_ADD 0 +#define ARITH_OR 1 +#define ARITH_ADC 2 +#define ARITH_SBB 3 +#define ARITH_AND 4 +#define ARITH_SUB 5 +#define ARITH_XOR 6 +#define ARITH_CMP 7 + +#define SHIFT_SHL 4 +#define SHIFT_SHR 5 +#define SHIFT_SAR 7 + +#define JCC_JMP (-1) +#define JCC_JO 0x0 +#define JCC_JNO 0x1 +#define JCC_JB 0x2 +#define JCC_JAE 0x3 +#define JCC_JE 0x4 +#define JCC_JNE 0x5 +#define JCC_JBE 0x6 +#define JCC_JA 0x7 +#define JCC_JS 0x8 +#define JCC_JNS 0x9 +#define JCC_JP 0xa +#define JCC_JNP 0xb +#define JCC_JL 0xc +#define JCC_JGE 0xd +#define JCC_JLE 0xe +#define JCC_JG 0xf + +#define P_EXT 0x100 /* 0x0f opcode prefix */ + +static const uint8_t tcg_cond_to_jcc[10] = { + [TCG_COND_EQ] = JCC_JE, + [TCG_COND_NE] = JCC_JNE, + [TCG_COND_LT] = JCC_JL, + [TCG_COND_GE] = JCC_JGE, + [TCG_COND_LE] = JCC_JLE, + [TCG_COND_GT] = JCC_JG, + [TCG_COND_LTU] = JCC_JB, + [TCG_COND_GEU] = JCC_JAE, + [TCG_COND_LEU] = JCC_JBE, + [TCG_COND_GTU] = JCC_JA, +}; + +static inline void tcg_out_opc(TCGContext *s, int opc) +{ + if (opc & P_EXT) + tcg_out8(s, 0x0f); + tcg_out8(s, opc); +} + +static inline void tcg_out_modrm(TCGContext *s, int opc, int r, int rm) +{ + tcg_out_opc(s, opc); + tcg_out8(s, 0xc0 | (r << 3) | rm); +} + +/* rm == -1 means no register index */ +static inline void tcg_out_modrm_offset(TCGContext *s, int opc, int r, int rm, + int32_t offset) +{ + tcg_out_opc(s, opc); + if (rm == -1) { + tcg_out8(s, 0x05 | (r << 3)); + tcg_out32(s, offset); + } else if (offset == 0 && rm != TCG_REG_EBP) { + if (rm == TCG_REG_ESP) { + tcg_out8(s, 0x04 | (r << 3)); + tcg_out8(s, 0x24); + } else { + tcg_out8(s, 0x00 | (r << 3) | rm); + } + } else if ((int8_t)offset == offset) { + if (rm == TCG_REG_ESP) { + tcg_out8(s, 0x44 | (r << 3)); + tcg_out8(s, 0x24); + } else { + tcg_out8(s, 0x40 | (r << 3) | rm); + } + tcg_out8(s, offset); + } else { + if (rm == TCG_REG_ESP) { + tcg_out8(s, 0x84 | (r << 3)); + tcg_out8(s, 0x24); + } else { + tcg_out8(s, 0x80 | (r << 3) | rm); + } + tcg_out32(s, offset); + } +} + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + if (arg != ret) + tcg_out_modrm(s, 0x8b, ret, arg); +} + +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int ret, int32_t arg) +{ + if (arg == 0) { + /* xor r0,r0 */ + tcg_out_modrm(s, 0x01 | (ARITH_XOR << 3), ret, ret); + } else { + tcg_out8(s, 0xb8 + ret); + tcg_out32(s, arg); + } +} + +static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret, + int arg1, tcg_target_long arg2) +{ + /* movl */ + tcg_out_modrm_offset(s, 0x8b, ret, arg1, arg2); +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + /* movl */ + tcg_out_modrm_offset(s, 0x89, arg, arg1, arg2); +} + +static inline void tgen_arithi(TCGContext *s, int c, int r0, int32_t val) +{ + if (val == (int8_t)val) { + tcg_out_modrm(s, 0x83, c, r0); + tcg_out8(s, val); + } else { + tcg_out_modrm(s, 0x81, c, r0); + tcg_out32(s, val); + } +} + +void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + if (val != 0) + tgen_arithi(s, ARITH_ADD, reg, val); +} + +static void tcg_out_jxx(TCGContext *s, int opc, int label_index) +{ + int32_t val, val1; + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) { + val = l->u.value - (tcg_target_long)s->code_ptr; + val1 = val - 2; + if ((int8_t)val1 == val1) { + if (opc == -1) + tcg_out8(s, 0xeb); + else + tcg_out8(s, 0x70 + opc); + tcg_out8(s, val1); + } else { + if (opc == -1) { + tcg_out8(s, 0xe9); + tcg_out32(s, val - 5); + } else { + tcg_out8(s, 0x0f); + tcg_out8(s, 0x80 + opc); + tcg_out32(s, val - 6); + } + } + } else { + if (opc == -1) { + tcg_out8(s, 0xe9); + } else { + tcg_out8(s, 0x0f); + tcg_out8(s, 0x80 + opc); + } + tcg_out_reloc(s, s->code_ptr, R_386_PC32, label_index, -4); + s->code_ptr += 4; + } +} + +static void tcg_out_brcond(TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index) +{ + if (const_arg2) { + if (arg2 == 0) { + /* test r, r */ + tcg_out_modrm(s, 0x85, arg1, arg1); + } else { + tgen_arithi(s, ARITH_CMP, arg1, arg2); + } + } else { + tcg_out_modrm(s, 0x01 | (ARITH_CMP << 3), arg2, arg1); + } + tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index); +} + +/* XXX: we implement it at the target level to avoid having to + handle cross basic blocks temporaries */ +static void tcg_out_brcond2(TCGContext *s, + const TCGArg *args, const int *const_args) +{ + int label_next; + label_next = gen_new_label(); + switch(args[4]) { + case TCG_COND_EQ: + tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], label_next); + tcg_out_brcond(s, TCG_COND_EQ, args[1], args[3], const_args[3], args[5]); + break; + case TCG_COND_NE: + tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], args[5]); + tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], args[5]); + break; + case TCG_COND_LT: + tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_LE: + tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_GT: + tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_GE: + tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_LTU: + tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_LEU: + tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_GTU: + tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_GEU: + tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], args[5]); + break; + default: + tcg_abort(); + } + tcg_out_label(s, label_next, (tcg_target_long)s->code_ptr); +} + +#if defined(CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +/* XXX: qemu_ld and qemu_st could be modified to clobber only EDX and + EAX. It will be useful once fixed registers globals are less + common. */ +static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap; +#if defined(CONFIG_SOFTMMU) + uint8_t *label1_ptr, *label2_ptr; +#endif +#if TARGET_LONG_BITS == 64 +#if defined(CONFIG_SOFTMMU) + uint8_t *label3_ptr; +#endif + int addr_reg2; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif + mem_index = *args; + s_bits = opc & 3; + + r0 = TCG_REG_EAX; + r1 = TCG_REG_EDX; + +#if defined(CONFIG_SOFTMMU) + tcg_out_mov(s, r1, addr_reg); + + tcg_out_mov(s, r0, addr_reg); + + tcg_out_modrm(s, 0xc1, 5, r1); /* shr $x, r1 */ + tcg_out8(s, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + + tcg_out_modrm(s, 0x81, 4, r0); /* andl $x, r0 */ + tcg_out32(s, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + + tcg_out_modrm(s, 0x81, 4, r1); /* andl $x, r1 */ + tcg_out32(s, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + + tcg_out_opc(s, 0x8d); /* lea offset(r1, %ebp), r1 */ + tcg_out8(s, 0x80 | (r1 << 3) | 0x04); + tcg_out8(s, (5 << 3) | r1); + tcg_out32(s, offsetof(CPUState, tlb_table[mem_index][0].addr_read)); + + /* cmp 0(r1), r0 */ + tcg_out_modrm_offset(s, 0x3b, r0, r1, 0); + + tcg_out_mov(s, r0, addr_reg); + +#if TARGET_LONG_BITS == 32 + /* je label1 */ + tcg_out8(s, 0x70 + JCC_JE); + label1_ptr = s->code_ptr; + s->code_ptr++; +#else + /* jne label3 */ + tcg_out8(s, 0x70 + JCC_JNE); + label3_ptr = s->code_ptr; + s->code_ptr++; + + /* cmp 4(r1), addr_reg2 */ + tcg_out_modrm_offset(s, 0x3b, addr_reg2, r1, 4); + + /* je label1 */ + tcg_out8(s, 0x70 + JCC_JE); + label1_ptr = s->code_ptr; + s->code_ptr++; + + /* label3: */ + *label3_ptr = s->code_ptr - label3_ptr - 1; +#endif + + /* XXX: move that code at the end of the TB */ +#if TARGET_LONG_BITS == 32 + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_EDX, mem_index); +#else + tcg_out_mov(s, TCG_REG_EDX, addr_reg2); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_ECX, mem_index); +#endif + tcg_out8(s, 0xe8); + tcg_out32(s, (tcg_target_long)qemu_ld_helpers[s_bits] - + (tcg_target_long)s->code_ptr - 4); + + switch(opc) { + case 0 | 4: + /* movsbl */ + tcg_out_modrm(s, 0xbe | P_EXT, data_reg, TCG_REG_EAX); + break; + case 1 | 4: + /* movswl */ + tcg_out_modrm(s, 0xbf | P_EXT, data_reg, TCG_REG_EAX); + break; + case 0: + case 1: + case 2: + default: + tcg_out_mov(s, data_reg, TCG_REG_EAX); + break; + case 3: + if (data_reg == TCG_REG_EDX) { + tcg_out_opc(s, 0x90 + TCG_REG_EDX); /* xchg %edx, %eax */ + tcg_out_mov(s, data_reg2, TCG_REG_EAX); + } else { + tcg_out_mov(s, data_reg, TCG_REG_EAX); + tcg_out_mov(s, data_reg2, TCG_REG_EDX); + } + break; + } + + /* jmp label2 */ + tcg_out8(s, 0xeb); + label2_ptr = s->code_ptr; + s->code_ptr++; + + /* label1: */ + *label1_ptr = s->code_ptr - label1_ptr - 1; + + /* add x(r1), r0 */ + tcg_out_modrm_offset(s, 0x03, r0, r1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_read)); +#else + r0 = addr_reg; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 1; +#else + bswap = 0; +#endif + switch(opc) { + case 0: + /* movzbl */ + tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, 0); + break; + case 0 | 4: + /* movsbl */ + tcg_out_modrm_offset(s, 0xbe | P_EXT, data_reg, r0, 0); + break; + case 1: + /* movzwl */ + tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0); + if (bswap) { + /* rolw $8, data_reg */ + tcg_out8(s, 0x66); + tcg_out_modrm(s, 0xc1, 0, data_reg); + tcg_out8(s, 8); + } + break; + case 1 | 4: + /* movswl */ + tcg_out_modrm_offset(s, 0xbf | P_EXT, data_reg, r0, 0); + if (bswap) { + /* rolw $8, data_reg */ + tcg_out8(s, 0x66); + tcg_out_modrm(s, 0xc1, 0, data_reg); + tcg_out8(s, 8); + + /* movswl data_reg, data_reg */ + tcg_out_modrm(s, 0xbf | P_EXT, data_reg, data_reg); + } + break; + case 2: + /* movl (r0), data_reg */ + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0); + if (bswap) { + /* bswap */ + tcg_out_opc(s, (0xc8 + data_reg) | P_EXT); + } + break; + case 3: + /* XXX: could be nicer */ + if (r0 == data_reg) { + r1 = TCG_REG_EDX; + if (r1 == data_reg) + r1 = TCG_REG_EAX; + tcg_out_mov(s, r1, r0); + r0 = r1; + } + if (!bswap) { + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, 4); + } else { + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 4); + tcg_out_opc(s, (0xc8 + data_reg) | P_EXT); + + tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, 0); + /* bswap */ + tcg_out_opc(s, (0xc8 + data_reg2) | P_EXT); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = s->code_ptr - label2_ptr - 1; +#endif +} + + +static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap; +#if defined(CONFIG_SOFTMMU) + uint8_t *label1_ptr, *label2_ptr; +#endif +#if TARGET_LONG_BITS == 64 +#if defined(CONFIG_SOFTMMU) + uint8_t *label3_ptr; +#endif + int addr_reg2; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif + mem_index = *args; + + s_bits = opc; + + r0 = TCG_REG_EAX; + r1 = TCG_REG_EDX; + +#if defined(CONFIG_SOFTMMU) + tcg_out_mov(s, r1, addr_reg); + + tcg_out_mov(s, r0, addr_reg); + + tcg_out_modrm(s, 0xc1, 5, r1); /* shr $x, r1 */ + tcg_out8(s, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + + tcg_out_modrm(s, 0x81, 4, r0); /* andl $x, r0 */ + tcg_out32(s, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + + tcg_out_modrm(s, 0x81, 4, r1); /* andl $x, r1 */ + tcg_out32(s, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + + tcg_out_opc(s, 0x8d); /* lea offset(r1, %ebp), r1 */ + tcg_out8(s, 0x80 | (r1 << 3) | 0x04); + tcg_out8(s, (5 << 3) | r1); + tcg_out32(s, offsetof(CPUState, tlb_table[mem_index][0].addr_write)); + + /* cmp 0(r1), r0 */ + tcg_out_modrm_offset(s, 0x3b, r0, r1, 0); + + tcg_out_mov(s, r0, addr_reg); + +#if TARGET_LONG_BITS == 32 + /* je label1 */ + tcg_out8(s, 0x70 + JCC_JE); + label1_ptr = s->code_ptr; + s->code_ptr++; +#else + /* jne label3 */ + tcg_out8(s, 0x70 + JCC_JNE); + label3_ptr = s->code_ptr; + s->code_ptr++; + + /* cmp 4(r1), addr_reg2 */ + tcg_out_modrm_offset(s, 0x3b, addr_reg2, r1, 4); + + /* je label1 */ + tcg_out8(s, 0x70 + JCC_JE); + label1_ptr = s->code_ptr; + s->code_ptr++; + + /* label3: */ + *label3_ptr = s->code_ptr - label3_ptr - 1; +#endif + + /* XXX: move that code at the end of the TB */ +#if TARGET_LONG_BITS == 32 + if (opc == 3) { + tcg_out_mov(s, TCG_REG_EDX, data_reg); + tcg_out_mov(s, TCG_REG_ECX, data_reg2); + tcg_out8(s, 0x6a); /* push Ib */ + tcg_out8(s, mem_index); + tcg_out8(s, 0xe8); + tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] - + (tcg_target_long)s->code_ptr - 4); + tcg_out_addi(s, TCG_REG_ESP, 4); + } else { + switch(opc) { + case 0: + /* movzbl */ + tcg_out_modrm(s, 0xb6 | P_EXT, TCG_REG_EDX, data_reg); + break; + case 1: + /* movzwl */ + tcg_out_modrm(s, 0xb7 | P_EXT, TCG_REG_EDX, data_reg); + break; + case 2: + tcg_out_mov(s, TCG_REG_EDX, data_reg); + break; + } + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_ECX, mem_index); + tcg_out8(s, 0xe8); + tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] - + (tcg_target_long)s->code_ptr - 4); + } +#else + if (opc == 3) { + tcg_out_mov(s, TCG_REG_EDX, addr_reg2); + tcg_out8(s, 0x6a); /* push Ib */ + tcg_out8(s, mem_index); + tcg_out_opc(s, 0x50 + data_reg2); /* push */ + tcg_out_opc(s, 0x50 + data_reg); /* push */ + tcg_out8(s, 0xe8); + tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] - + (tcg_target_long)s->code_ptr - 4); + tcg_out_addi(s, TCG_REG_ESP, 12); + } else { + tcg_out_mov(s, TCG_REG_EDX, addr_reg2); + switch(opc) { + case 0: + /* movzbl */ + tcg_out_modrm(s, 0xb6 | P_EXT, TCG_REG_ECX, data_reg); + break; + case 1: + /* movzwl */ + tcg_out_modrm(s, 0xb7 | P_EXT, TCG_REG_ECX, data_reg); + break; + case 2: + tcg_out_mov(s, TCG_REG_ECX, data_reg); + break; + } + tcg_out8(s, 0x6a); /* push Ib */ + tcg_out8(s, mem_index); + tcg_out8(s, 0xe8); + tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] - + (tcg_target_long)s->code_ptr - 4); + tcg_out_addi(s, TCG_REG_ESP, 4); + } +#endif + + /* jmp label2 */ + tcg_out8(s, 0xeb); + label2_ptr = s->code_ptr; + s->code_ptr++; + + /* label1: */ + *label1_ptr = s->code_ptr - label1_ptr - 1; + + /* add x(r1), r0 */ + tcg_out_modrm_offset(s, 0x03, r0, r1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_write)); +#else + r0 = addr_reg; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 1; +#else + bswap = 0; +#endif + switch(opc) { + case 0: + /* movb */ + tcg_out_modrm_offset(s, 0x88, data_reg, r0, 0); + break; + case 1: + if (bswap) { + tcg_out_mov(s, r1, data_reg); + tcg_out8(s, 0x66); /* rolw $8, %ecx */ + tcg_out_modrm(s, 0xc1, 0, r1); + tcg_out8(s, 8); + data_reg = r1; + } + /* movw */ + tcg_out8(s, 0x66); + tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0); + break; + case 2: + if (bswap) { + tcg_out_mov(s, r1, data_reg); + /* bswap data_reg */ + tcg_out_opc(s, (0xc8 + r1) | P_EXT); + data_reg = r1; + } + /* movl */ + tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0); + break; + case 3: + if (bswap) { + tcg_out_mov(s, r1, data_reg2); + /* bswap data_reg */ + tcg_out_opc(s, (0xc8 + r1) | P_EXT); + tcg_out_modrm_offset(s, 0x89, r1, r0, 0); + tcg_out_mov(s, r1, data_reg); + /* bswap data_reg */ + tcg_out_opc(s, (0xc8 + r1) | P_EXT); + tcg_out_modrm_offset(s, 0x89, r1, r0, 4); + } else { + tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0x89, data_reg2, r0, 4); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = s->code_ptr - label2_ptr - 1; +#endif +} + +static inline void tcg_out_op(TCGContext *s, int opc, + const TCGArg *args, const int *const_args) +{ + int c; + + switch(opc) { + case INDEX_op_exit_tb: + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_EAX, args[0]); + tcg_out8(s, 0xe9); /* jmp tb_ret_addr */ + tcg_out32(s, tb_ret_addr - s->code_ptr - 4); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + tcg_out8(s, 0xe9); /* jmp im */ + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + tcg_out32(s, 0); + } else { + /* indirect jump method */ + /* jmp Ev */ + tcg_out_modrm_offset(s, 0xff, 4, -1, + (tcg_target_long)(s->tb_next + args[0])); + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_call: + if (const_args[0]) { + tcg_out8(s, 0xe8); + tcg_out32(s, args[0] - (tcg_target_long)s->code_ptr - 4); + } else { + tcg_out_modrm(s, 0xff, 2, args[0]); + } + break; + case INDEX_op_jmp: + if (const_args[0]) { + tcg_out8(s, 0xe9); + tcg_out32(s, args[0] - (tcg_target_long)s->code_ptr - 4); + } else { + tcg_out_modrm(s, 0xff, 4, args[0]); + } + break; + case INDEX_op_br: + tcg_out_jxx(s, JCC_JMP, args[0]); + break; + case INDEX_op_movi_i32: + tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); + break; + case INDEX_op_ld8u_i32: + /* movzbl */ + tcg_out_modrm_offset(s, 0xb6 | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld8s_i32: + /* movsbl */ + tcg_out_modrm_offset(s, 0xbe | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld16u_i32: + /* movzwl */ + tcg_out_modrm_offset(s, 0xb7 | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld16s_i32: + /* movswl */ + tcg_out_modrm_offset(s, 0xbf | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld_i32: + /* movl */ + tcg_out_modrm_offset(s, 0x8b, args[0], args[1], args[2]); + break; + case INDEX_op_st8_i32: + /* movb */ + tcg_out_modrm_offset(s, 0x88, args[0], args[1], args[2]); + break; + case INDEX_op_st16_i32: + /* movw */ + tcg_out8(s, 0x66); + tcg_out_modrm_offset(s, 0x89, args[0], args[1], args[2]); + break; + case INDEX_op_st_i32: + /* movl */ + tcg_out_modrm_offset(s, 0x89, args[0], args[1], args[2]); + break; + case INDEX_op_sub_i32: + c = ARITH_SUB; + goto gen_arith; + case INDEX_op_and_i32: + c = ARITH_AND; + goto gen_arith; + case INDEX_op_or_i32: + c = ARITH_OR; + goto gen_arith; + case INDEX_op_xor_i32: + c = ARITH_XOR; + goto gen_arith; + case INDEX_op_add_i32: + c = ARITH_ADD; + gen_arith: + if (const_args[2]) { + tgen_arithi(s, c, args[0], args[2]); + } else { + tcg_out_modrm(s, 0x01 | (c << 3), args[2], args[0]); + } + break; + case INDEX_op_mul_i32: + if (const_args[2]) { + int32_t val; + val = args[2]; + if (val == (int8_t)val) { + tcg_out_modrm(s, 0x6b, args[0], args[0]); + tcg_out8(s, val); + } else { + tcg_out_modrm(s, 0x69, args[0], args[0]); + tcg_out32(s, val); + } + } else { + tcg_out_modrm(s, 0xaf | P_EXT, args[0], args[2]); + } + break; + case INDEX_op_mulu2_i32: + tcg_out_modrm(s, 0xf7, 4, args[3]); + break; + case INDEX_op_div2_i32: + tcg_out_modrm(s, 0xf7, 7, args[4]); + break; + case INDEX_op_divu2_i32: + tcg_out_modrm(s, 0xf7, 6, args[4]); + break; + case INDEX_op_shl_i32: + c = SHIFT_SHL; + gen_shift32: + if (const_args[2]) { + if (args[2] == 1) { + tcg_out_modrm(s, 0xd1, c, args[0]); + } else { + tcg_out_modrm(s, 0xc1, c, args[0]); + tcg_out8(s, args[2]); + } + } else { + tcg_out_modrm(s, 0xd3, c, args[0]); + } + break; + case INDEX_op_shr_i32: + c = SHIFT_SHR; + goto gen_shift32; + case INDEX_op_sar_i32: + c = SHIFT_SAR; + goto gen_shift32; + + case INDEX_op_add2_i32: + if (const_args[4]) + tgen_arithi(s, ARITH_ADD, args[0], args[4]); + else + tcg_out_modrm(s, 0x01 | (ARITH_ADD << 3), args[4], args[0]); + if (const_args[5]) + tgen_arithi(s, ARITH_ADC, args[1], args[5]); + else + tcg_out_modrm(s, 0x01 | (ARITH_ADC << 3), args[5], args[1]); + break; + case INDEX_op_sub2_i32: + if (const_args[4]) + tgen_arithi(s, ARITH_SUB, args[0], args[4]); + else + tcg_out_modrm(s, 0x01 | (ARITH_SUB << 3), args[4], args[0]); + if (const_args[5]) + tgen_arithi(s, ARITH_SBB, args[1], args[5]); + else + tcg_out_modrm(s, 0x01 | (ARITH_SBB << 3), args[5], args[1]); + break; + case INDEX_op_brcond_i32: + tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], args[3]); + break; + case INDEX_op_brcond2_i32: + tcg_out_brcond2(s, args, const_args); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, args, 2); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, args, 3); + break; + + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, args, 3); + break; + + default: + tcg_abort(); + } +} + +static const TCGTargetOpDef x86_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, + { INDEX_op_jmp, { "ri" } }, + { INDEX_op_br, { } }, + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "q", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "0", "ri" } }, + { INDEX_op_sub_i32, { "r", "0", "ri" } }, + { INDEX_op_mul_i32, { "r", "0", "ri" } }, + { INDEX_op_mulu2_i32, { "a", "d", "a", "r" } }, + { INDEX_op_div2_i32, { "a", "d", "0", "1", "r" } }, + { INDEX_op_divu2_i32, { "a", "d", "0", "1", "r" } }, + { INDEX_op_and_i32, { "r", "0", "ri" } }, + { INDEX_op_or_i32, { "r", "0", "ri" } }, + { INDEX_op_xor_i32, { "r", "0", "ri" } }, + + { INDEX_op_shl_i32, { "r", "0", "ci" } }, + { INDEX_op_shr_i32, { "r", "0", "ci" } }, + { INDEX_op_sar_i32, { "r", "0", "ci" } }, + + { INDEX_op_brcond_i32, { "r", "ri" } }, + + { INDEX_op_add2_i32, { "r", "r", "0", "1", "ri", "ri" } }, + { INDEX_op_sub2_i32, { "r", "r", "0", "1", "ri", "ri" } }, + { INDEX_op_brcond2_i32, { "r", "r", "ri", "ri" } }, + +#if TARGET_LONG_BITS == 32 + { INDEX_op_qemu_ld8u, { "r", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L" } }, + { INDEX_op_qemu_ld64, { "r", "r", "L" } }, + + { INDEX_op_qemu_st8, { "cb", "L" } }, + { INDEX_op_qemu_st16, { "L", "L" } }, + { INDEX_op_qemu_st32, { "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L", "L" } }, +#else + { INDEX_op_qemu_ld8u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld64, { "r", "r", "L", "L" } }, + + { INDEX_op_qemu_st8, { "cb", "L", "L" } }, + { INDEX_op_qemu_st16, { "L", "L", "L" } }, + { INDEX_op_qemu_st32, { "L", "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L", "L", "L" } }, +#endif + { -1 }, +}; + +static int tcg_target_callee_save_regs[] = { + /* TCG_REG_EBP, */ /* currently used for the global env, so no + need to save */ + TCG_REG_EBX, + TCG_REG_ESI, + TCG_REG_EDI, +}; + +static inline void tcg_out_push(TCGContext *s, int reg) +{ + tcg_out_opc(s, 0x50 + reg); +} + +static inline void tcg_out_pop(TCGContext *s, int reg) +{ + tcg_out_opc(s, 0x58 + reg); +} + +/* Generate global QEMU prologue and epilogue code */ +void tcg_target_qemu_prologue(TCGContext *s) +{ + int i, frame_size, push_size, stack_addend; + + /* TB prologue */ + /* save all callee saved registers */ + for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { + tcg_out_push(s, tcg_target_callee_save_regs[i]); + } + /* reserve some stack space */ + push_size = 4 + ARRAY_SIZE(tcg_target_callee_save_regs) * 4; + frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE; + frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & + ~(TCG_TARGET_STACK_ALIGN - 1); + stack_addend = frame_size - push_size; + tcg_out_addi(s, TCG_REG_ESP, -stack_addend); + + tcg_out_modrm(s, 0xff, 4, TCG_REG_EAX); /* jmp *%eax */ + + /* TB epilogue */ + tb_ret_addr = s->code_ptr; + tcg_out_addi(s, TCG_REG_ESP, stack_addend); + for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) { + tcg_out_pop(s, tcg_target_callee_save_regs[i]); + } + tcg_out8(s, 0xc3); /* ret */ +} + +void tcg_target_init(TCGContext *s) +{ + /* fail safe */ + if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) + tcg_abort(); + + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xff); + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_EAX) | + (1 << TCG_REG_EDX) | + (1 << TCG_REG_ECX)); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_ESP); + + tcg_add_target_add_op_defs(x86_op_defs); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/i386/tcg-target.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/i386/tcg-target.h --- qemu-0.9.1/tcg/i386/tcg-target.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/i386/tcg-target.h 2008-05-22 15:59:57.000000000 +0100 @@ -0,0 +1,55 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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. + */ +#define TCG_TARGET_I386 1 + +#define TCG_TARGET_REG_BITS 32 +//#define TCG_TARGET_WORDS_BIGENDIAN + +#define TCG_TARGET_NB_REGS 8 + +enum { + TCG_REG_EAX = 0, + TCG_REG_ECX, + TCG_REG_EDX, + TCG_REG_EBX, + TCG_REG_ESP, + TCG_REG_EBP, + TCG_REG_ESI, + TCG_REG_EDI, +}; + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_ESP +#define TCG_TARGET_STACK_ALIGN 16 +#define TCG_TARGET_CALL_STACK_OFFSET 0 + +/* Note: must be synced with dyngen-exec.h */ +#define TCG_AREG0 TCG_REG_EBP +#define TCG_AREG1 TCG_REG_EBX +#define TCG_AREG2 TCG_REG_ESI +#define TCG_AREG3 TCG_REG_EDI + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/LICENSE /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/LICENSE --- qemu-0.9.1/tcg/LICENSE 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/LICENSE 2008-02-01 10:05:41.000000000 +0000 @@ -0,0 +1,3 @@ +All the files in this directory and subdirectories are released under +a BSD like license (see header in each file). No other license is +accepted. diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/ppc/tcg-target.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/ppc/tcg-target.c --- qemu-0.9.1/tcg/ppc/tcg-target.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/ppc/tcg-target.c 2008-10-05 10:59:14.000000000 +0100 @@ -0,0 +1,1487 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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. + */ + +static uint8_t *tb_ret_addr; + +#ifdef __APPLE__ +#define LINKAGE_AREA_SIZE 24 +#define BACK_CHAIN_OFFSET 8 +#else +#define LINKAGE_AREA_SIZE 8 +#define BACK_CHAIN_OFFSET 4 +#endif + +#define FAST_PATH +#if TARGET_PHYS_ADDR_BITS <= 32 +#define ADDEND_OFFSET 0 +#else +#define ADDEND_OFFSET 4 +#endif + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "r0", + "r1", + "rp", + "r3", + "r4", + "r5", + "r6", + "r7", + "r8", + "r9", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", + "r16", + "r17", + "r18", + "r19", + "r20", + "r21", + "r22", + "r23", + "r24", + "r25", + "r26", + "r27", + "r28", + "r29", + "r30", + "r31" +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R28, + TCG_REG_R29, + TCG_REG_R30, + TCG_REG_R31, +#ifdef __APPLE__ + TCG_REG_R2, +#endif + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, +#ifndef __APPLE__ + TCG_REG_R11, +#endif + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R0, + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + TCG_REG_R27 +}; + +static const int tcg_target_call_iarg_regs[] = { + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10 +}; + +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_R3, + TCG_REG_R4 +}; + +static const int tcg_target_callee_save_regs[] = { +#ifdef __APPLE__ + TCG_REG_R11, + TCG_REG_R13, +#endif + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R28, + TCG_REG_R29, + TCG_REG_R30, + TCG_REG_R31 +}; + +static uint32_t reloc_pc24_val (void *pc, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) pc; + if ((disp << 6) >> 6 != disp) + tcg_abort (); + + return disp & 0x3fffffc; +} + +static void reloc_pc24 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3fffffc) + | reloc_pc24_val (pc, target); +} + +static uint16_t reloc_pc14_val (void *pc, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) pc; + if (disp != (int16_t) disp) + tcg_abort (); + + return disp & 0xfffc; +} + +static void reloc_pc14 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0xfffc) + | reloc_pc14_val (pc, target); +} + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + value += addend; + switch (type) { + case R_PPC_REL14: + reloc_pc14 (code_ptr, value); + break; + case R_PPC_REL24: + reloc_pc24 (code_ptr, value); + break; + default: + tcg_abort(); + } +} + +/* maximum number of register used for input function arguments */ +static int tcg_target_get_call_iarg_regs_count(int flags) +{ + return sizeof (tcg_target_call_iarg_regs) / sizeof (tcg_target_call_iarg_regs[0]); +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch (ct_str[0]) { + case 'A': case 'B': case 'C': case 'D': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, 3 + ct_str[0] - 'A'); + break; + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + break; +#ifdef CONFIG_SOFTMMU + case 'L': /* qemu_ld constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4); + break; + case 'K': /* qemu_st[8..32] constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5); +#if TARGET_LONG_BITS == 64 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6); +#endif + break; + case 'M': /* qemu_st64 constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R7); + break; +#else + case 'L': + case 'K': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + break; + case 'M': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); + break; +#endif + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + return 0; +} + +#define OPCD(opc) ((opc)<<26) +#define XO31(opc) (OPCD(31)|((opc)<<1)) +#define XO19(opc) (OPCD(19)|((opc)<<1)) + +#define B OPCD(18) +#define BC OPCD(16) +#define LBZ OPCD(34) +#define LHZ OPCD(40) +#define LHA OPCD(42) +#define LWZ OPCD(32) +#define STB OPCD(38) +#define STH OPCD(44) +#define STW OPCD(36) + +#define ADDI OPCD(14) +#define ADDIS OPCD(15) +#define ORI OPCD(24) +#define ORIS OPCD(25) +#define XORI OPCD(26) +#define XORIS OPCD(27) +#define ANDI OPCD(28) +#define ANDIS OPCD(29) +#define MULLI OPCD( 7) +#define CMPLI OPCD(10) +#define CMPI OPCD(11) + +#define LWZU OPCD(33) +#define STWU OPCD(37) + +#define RLWINM OPCD(21) + +#define BCLR XO19( 16) +#define BCCTR XO19(528) +#define CRAND XO19(257) +#define CRANDC XO19(129) +#define CRNAND XO19(225) +#define CROR XO19(449) + +#define EXTSB XO31(954) +#define EXTSH XO31(922) +#define ADD XO31(266) +#define ADDE XO31(138) +#define ADDC XO31( 10) +#define AND XO31( 28) +#define SUBF XO31( 40) +#define SUBFC XO31( 8) +#define SUBFE XO31(136) +#define OR XO31(444) +#define XOR XO31(316) +#define MULLW XO31(235) +#define MULHWU XO31( 11) +#define DIVW XO31(491) +#define DIVWU XO31(459) +#define CMP XO31( 0) +#define CMPL XO31( 32) +#define LHBRX XO31(790) +#define LWBRX XO31(534) +#define STHBRX XO31(918) +#define STWBRX XO31(662) +#define MFSPR XO31(339) +#define MTSPR XO31(467) +#define SRAWI XO31(824) +#define NEG XO31(104) + +#define LBZX XO31( 87) +#define LHZX XO31(276) +#define LHAX XO31(343) +#define LWZX XO31( 23) +#define STBX XO31(215) +#define STHX XO31(407) +#define STWX XO31(151) + +#define SPR(a,b) ((((a)<<5)|(b))<<11) +#define LR SPR(8, 0) +#define CTR SPR(9, 0) + +#define SLW XO31( 24) +#define SRW XO31(536) +#define SRAW XO31(792) + +#define LMW OPCD(46) +#define STMW OPCD(47) + +#define TW XO31(4) +#define TRAP (TW | TO (31)) + +#define RT(r) ((r)<<21) +#define RS(r) ((r)<<21) +#define RA(r) ((r)<<16) +#define RB(r) ((r)<<11) +#define TO(t) ((t)<<21) +#define SH(s) ((s)<<11) +#define MB(b) ((b)<<6) +#define ME(e) ((e)<<1) +#define BO(o) ((o)<<21) + +#define LK 1 + +#define TAB(t,a,b) (RT(t) | RA(a) | RB(b)) +#define SAB(s,a,b) (RS(s) | RA(a) | RB(b)) + +#define BF(n) ((n)<<23) +#define BI(n, c) (((c)+((n)*4))<<16) +#define BT(n, c) (((c)+((n)*4))<<21) +#define BA(n, c) (((c)+((n)*4))<<16) +#define BB(n, c) (((c)+((n)*4))<<11) + +#define BO_COND_TRUE BO (12) +#define BO_COND_FALSE BO (4) +#define BO_ALWAYS BO (20) + +enum { + CR_LT, + CR_GT, + CR_EQ, + CR_SO +}; + +static const uint32_t tcg_to_bc[10] = { + [TCG_COND_EQ] = BC | BI (7, CR_EQ) | BO_COND_TRUE, + [TCG_COND_NE] = BC | BI (7, CR_EQ) | BO_COND_FALSE, + [TCG_COND_LT] = BC | BI (7, CR_LT) | BO_COND_TRUE, + [TCG_COND_GE] = BC | BI (7, CR_LT) | BO_COND_FALSE, + [TCG_COND_LE] = BC | BI (7, CR_GT) | BO_COND_FALSE, + [TCG_COND_GT] = BC | BI (7, CR_GT) | BO_COND_TRUE, + [TCG_COND_LTU] = BC | BI (7, CR_LT) | BO_COND_TRUE, + [TCG_COND_GEU] = BC | BI (7, CR_LT) | BO_COND_FALSE, + [TCG_COND_LEU] = BC | BI (7, CR_GT) | BO_COND_FALSE, + [TCG_COND_GTU] = BC | BI (7, CR_GT) | BO_COND_TRUE, +}; + +static void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + tcg_out32 (s, OR | SAB (arg, ret, arg)); +} + +static void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + if (arg == (int16_t) arg) + tcg_out32 (s, ADDI | RT (ret) | RA (0) | (arg & 0xffff)); + else { + tcg_out32 (s, ADDIS | RT (ret) | RA (0) | ((arg >> 16) & 0xffff)); + if (arg & 0xffff) + tcg_out32 (s, ORI | RS (ret) | RA (ret) | (arg & 0xffff)); + } +} + +static void tcg_out_ldst (TCGContext *s, int ret, int addr, + int offset, int op1, int op2) +{ + if (offset == (int16_t) offset) + tcg_out32 (s, op1 | RT (ret) | RA (addr) | (offset & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, offset); + tcg_out32 (s, op2 | RT (ret) | RA (addr) | RB (0)); + } +} + +static void tcg_out_b (TCGContext *s, int mask, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) s->code_ptr; + if ((disp << 6) >> 6 == disp) + tcg_out32 (s, B | (disp & 0x3fffffc) | mask); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, (tcg_target_long) target); + tcg_out32 (s, MTSPR | RS (0) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS | mask); + } +} + +#if defined(CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc) +{ + int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap; +#ifdef CONFIG_SOFTMMU + int r2; + void *label1_ptr, *label2_ptr; +#endif +#if TARGET_LONG_BITS == 64 + int addr_reg2; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif + mem_index = *args; + s_bits = opc & 3; + +#ifdef CONFIG_SOFTMMU + r0 = 3; + r1 = 4; + r2 = 0; + + tcg_out32 (s, (RLWINM + | RA (r0) + | RS (addr_reg) + | SH (32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)) + | MB (32 - (CPU_TLB_BITS + CPU_TLB_ENTRY_BITS)) + | ME (31 - CPU_TLB_ENTRY_BITS) + ) + ); + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (TCG_AREG0)); + tcg_out32 (s, (LWZU + | RT (r1) + | RA (r0) + | offsetof (CPUState, tlb_table[mem_index][0].addr_read) + ) + ); + tcg_out32 (s, (RLWINM + | RA (r2) + | RS (addr_reg) + | SH (0) + | MB ((32 - s_bits) & 31) + | ME (31 - TARGET_PAGE_BITS) + ) + ); + + tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1)); +#if TARGET_LONG_BITS == 64 + tcg_out32 (s, LWZ | RT (r1) | RA (r0) | 4); + tcg_out32 (s, CMP | BF (6) | RA (addr_reg2) | RB (r1)); + tcg_out32 (s, CRAND | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ)); +#endif + + label1_ptr = s->code_ptr; +#ifdef FAST_PATH + tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE); +#endif + + /* slow path */ +#if TARGET_LONG_BITS == 32 + tcg_out_mov (s, 3, addr_reg); + tcg_out_movi (s, TCG_TYPE_I32, 4, mem_index); +#else + tcg_out_mov (s, 3, addr_reg2); + tcg_out_mov (s, 4, addr_reg); + tcg_out_movi (s, TCG_TYPE_I32, 5, mem_index); +#endif + + tcg_out_b (s, LK, (tcg_target_long) qemu_ld_helpers[s_bits]); + switch (opc) { + case 0|4: + tcg_out32 (s, EXTSB | RA (data_reg) | RS (3)); + break; + case 1|4: + tcg_out32 (s, EXTSH | RA (data_reg) | RS (3)); + break; + case 0: + case 1: + case 2: + if (data_reg != 3) + tcg_out_mov (s, data_reg, 3); + break; + case 3: + if (data_reg == 3) { + if (data_reg2 == 4) { + tcg_out_mov (s, 0, 4); + tcg_out_mov (s, 4, 3); + tcg_out_mov (s, 3, 0); + } + else { + tcg_out_mov (s, data_reg2, 3); + tcg_out_mov (s, 3, 4); + } + } + else { + if (data_reg != 4) tcg_out_mov (s, data_reg, 4); + if (data_reg2 != 3) tcg_out_mov (s, data_reg2, 3); + } + break; + } + label2_ptr = s->code_ptr; + tcg_out32 (s, B); + + /* label1: fast path */ +#ifdef FAST_PATH + reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr); +#endif + + /* r0 now contains &env->tlb_table[mem_index][index].addr_read */ + tcg_out32 (s, (LWZ + | RT (r0) + | RA (r0) + | (ADDEND_OFFSET + offsetof (CPUTLBEntry, addend) + - offsetof (CPUTLBEntry, addr_read)) + )); + /* r0 = env->tlb_table[mem_index][index].addend */ + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg)); + /* r0 = env->tlb_table[mem_index][index].addend + addr */ + +#else /* !CONFIG_SOFTMMU */ + r0 = addr_reg; + r1 = 3; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + switch (opc) { + default: + case 0: + tcg_out32 (s, LBZ | RT (data_reg) | RA (r0)); + break; + case 0|4: + tcg_out32 (s, LBZ | RT (data_reg) | RA (r0)); + tcg_out32 (s, EXTSB | RA (data_reg) | RS (data_reg)); + break; + case 1: + if (bswap) tcg_out32 (s, LHBRX | RT (data_reg) | RB (r0)); + else tcg_out32 (s, LHZ | RT (data_reg) | RA (r0)); + break; + case 1|4: + if (bswap) { + tcg_out32 (s, LHBRX | RT (data_reg) | RB (r0)); + tcg_out32 (s, EXTSH | RA (data_reg) | RS (data_reg)); + } + else tcg_out32 (s, LHA | RT (data_reg) | RA (r0)); + break; + case 2: + if (bswap) tcg_out32 (s, LWBRX | RT (data_reg) | RB (r0)); + else tcg_out32 (s, LWZ | RT (data_reg)| RA (r0)); + break; + case 3: + if (bswap) { + tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4); + tcg_out32 (s, LWBRX | RT (data_reg) | RB (r0)); + tcg_out32 (s, LWBRX | RT (data_reg2) | RB (r1)); + } + else { + if (r0 == data_reg2) { + tcg_out32 (s, LWZ | RT (0) | RA (r0)); + tcg_out32 (s, LWZ | RT (data_reg) | RA (r0) | 4); + tcg_out_mov (s, data_reg2, 0); + } + else { + tcg_out32 (s, LWZ | RT (data_reg2) | RA (r0)); + tcg_out32 (s, LWZ | RT (data_reg) | RA (r0) | 4); + } + } + break; + } + +#ifdef CONFIG_SOFTMMU + reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr); +#endif +} + +static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc) +{ + int addr_reg, r0, r1, data_reg, data_reg2, mem_index, bswap; +#ifdef CONFIG_SOFTMMU + int r2, ir; + void *label1_ptr, *label2_ptr; +#endif +#if TARGET_LONG_BITS == 64 + int addr_reg2; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif + mem_index = *args; + +#ifdef CONFIG_SOFTMMU + r0 = 3; + r1 = 4; + r2 = 0; + + tcg_out32 (s, (RLWINM + | RA (r0) + | RS (addr_reg) + | SH (32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)) + | MB (32 - (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS)) + | ME (31 - CPU_TLB_ENTRY_BITS) + ) + ); + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (TCG_AREG0)); + tcg_out32 (s, (LWZU + | RT (r1) + | RA (r0) + | offsetof (CPUState, tlb_table[mem_index][0].addr_write) + ) + ); + tcg_out32 (s, (RLWINM + | RA (r2) + | RS (addr_reg) + | SH (0) + | MB ((32 - opc) & 31) + | ME (31 - TARGET_PAGE_BITS) + ) + ); + + tcg_out32 (s, CMP | (7 << 23) | RA (r2) | RB (r1)); +#if TARGET_LONG_BITS == 64 + tcg_out32 (s, LWZ | RT (r1) | RA (r0) | 4); + tcg_out32 (s, CMP | BF (6) | RA (addr_reg2) | RB (r1)); + tcg_out32 (s, CRAND | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ)); +#endif + + label1_ptr = s->code_ptr; +#ifdef FAST_PATH + tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE); +#endif + + /* slow path */ +#if TARGET_LONG_BITS == 32 + tcg_out_mov (s, 3, addr_reg); + ir = 4; +#else + tcg_out_mov (s, 3, addr_reg2); + tcg_out_mov (s, 4, addr_reg); +#ifdef TCG_TARGET_CALL_ALIGN_ARGS + ir = 5; +#else + ir = 4; +#endif +#endif + + switch (opc) { + case 0: + tcg_out32 (s, (RLWINM + | RA (ir) + | RS (data_reg) + | SH (0) + | MB (24) + | ME (31))); + break; + case 1: + tcg_out32 (s, (RLWINM + | RA (ir) + | RS (data_reg) + | SH (0) + | MB (16) + | ME (31))); + break; + case 2: + tcg_out_mov (s, ir, data_reg); + break; + case 3: +#ifdef TCG_TARGET_CALL_ALIGN_ARGS + ir = 5; +#endif + tcg_out_mov (s, ir++, data_reg2); + tcg_out_mov (s, ir, data_reg); + break; + } + ir++; + + tcg_out_movi (s, TCG_TYPE_I32, ir, mem_index); + tcg_out_b (s, LK, (tcg_target_long) qemu_st_helpers[opc]); + label2_ptr = s->code_ptr; + tcg_out32 (s, B); + + /* label1: fast path */ +#ifdef FAST_PATH + reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr); +#endif + + tcg_out32 (s, (LWZ + | RT (r0) + | RA (r0) + | (ADDEND_OFFSET + offsetof (CPUTLBEntry, addend) + - offsetof (CPUTLBEntry, addr_write)) + )); + /* r0 = env->tlb_table[mem_index][index].addend */ + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg)); + /* r0 = env->tlb_table[mem_index][index].addend + addr */ + +#else /* !CONFIG_SOFTMMU */ + r1 = 3; + r0 = addr_reg; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + switch (opc) { + case 0: + tcg_out32 (s, STB | RS (data_reg) | RA (r0)); + break; + case 1: + if (bswap) tcg_out32 (s, STHBRX | RS (data_reg) | RA (0) | RB (r0)); + else tcg_out32 (s, STH | RS (data_reg) | RA (r0)); + break; + case 2: + if (bswap) tcg_out32 (s, STWBRX | RS (data_reg) | RA (0) | RB (r0)); + else tcg_out32 (s, STW | RS (data_reg) | RA (r0)); + break; + case 3: + if (bswap) { + tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4); + tcg_out32 (s, STWBRX | RS (data_reg) | RA (0) | RB (r0)); + tcg_out32 (s, STWBRX | RS (data_reg2) | RA (0) | RB (r1)); + } + else { + tcg_out32 (s, STW | RS (data_reg2) | RA (r0)); + tcg_out32 (s, STW | RS (data_reg) | RA (r0) | 4); + } + break; + } + +#ifdef CONFIG_SOFTMMU + reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr); +#endif +} + +void tcg_target_qemu_prologue (TCGContext *s) +{ + int i, frame_size; + + frame_size = 0 + + LINKAGE_AREA_SIZE + + TCG_STATIC_CALL_ARGS_SIZE + + ARRAY_SIZE (tcg_target_callee_save_regs) * 4 + ; + frame_size = (frame_size + 15) & ~15; + + tcg_out32 (s, MFSPR | RT (0) | LR); + tcg_out32 (s, STWU | RS (1) | RA (1) | (-frame_size & 0xffff)); + for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i) + tcg_out32 (s, (STW + | RS (tcg_target_callee_save_regs[i]) + | RA (1) + | (i * 4 + LINKAGE_AREA_SIZE + TCG_STATIC_CALL_ARGS_SIZE) + ) + ); + tcg_out32 (s, STW | RS (0) | RA (1) | (frame_size + BACK_CHAIN_OFFSET)); + + tcg_out32 (s, MTSPR | RS (3) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS); + tb_ret_addr = s->code_ptr; + + for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i) + tcg_out32 (s, (LWZ + | RT (tcg_target_callee_save_regs[i]) + | RA (1) + | (i * 4 + LINKAGE_AREA_SIZE + TCG_STATIC_CALL_ARGS_SIZE) + ) + ); + tcg_out32 (s, LWZ | RT (0) | RA (1) | (frame_size + BACK_CHAIN_OFFSET)); + tcg_out32 (s, MTSPR | RS (0) | LR); + tcg_out32 (s, ADDI | RT (1) | RA (1) | frame_size); + tcg_out32 (s, BCLR | BO_ALWAYS); +} + +static void tcg_out_ld (TCGContext *s, TCGType type, int ret, int arg1, + tcg_target_long arg2) +{ + tcg_out_ldst (s, ret, arg1, arg2, LWZ, LWZX); +} + +static void tcg_out_st (TCGContext *s, TCGType type, int arg, int arg1, + tcg_target_long arg2) +{ + tcg_out_ldst (s, arg, arg1, arg2, STW, STWX); +} + +static void ppc_addi (TCGContext *s, int rt, int ra, tcg_target_long si) +{ + if (!si && rt == ra) + return; + + if (si == (int16_t) si) + tcg_out32 (s, ADDI | RT (rt) | RA (ra) | (si & 0xffff)); + else { + uint16_t h = ((si >> 16) & 0xffff) + ((uint16_t) si >> 15); + tcg_out32 (s, ADDIS | RT (rt) | RA (ra) | h); + tcg_out32 (s, ADDI | RT (rt) | RA (rt) | (si & 0xffff)); + } +} + +static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + ppc_addi (s, reg, reg, val); +} + +static void tcg_out_cmp (TCGContext *s, int cond, TCGArg arg1, TCGArg arg2, + int const_arg2, int cr) +{ + int imm; + uint32_t op; + + switch (cond) { + case TCG_COND_EQ: + case TCG_COND_NE: + if (const_arg2) { + if ((int16_t) arg2 == arg2) { + op = CMPI; + imm = 1; + break; + } + else if ((uint16_t) arg2 == arg2) { + op = CMPLI; + imm = 1; + break; + } + } + op = CMPL; + imm = 0; + break; + + case TCG_COND_LT: + case TCG_COND_GE: + case TCG_COND_LE: + case TCG_COND_GT: + if (const_arg2) { + if ((int16_t) arg2 == arg2) { + op = CMPI; + imm = 1; + break; + } + } + op = CMP; + imm = 0; + break; + + case TCG_COND_LTU: + case TCG_COND_GEU: + case TCG_COND_LEU: + case TCG_COND_GTU: + if (const_arg2) { + if ((uint16_t) arg2 == arg2) { + op = CMPLI; + imm = 1; + break; + } + } + op = CMPL; + imm = 0; + break; + + default: + tcg_abort (); + } + op |= BF (cr); + + if (imm) + tcg_out32 (s, op | RA (arg1) | (arg2 & 0xffff)); + else { + if (const_arg2) { + tcg_out_movi (s, TCG_TYPE_I32, 0, arg2); + tcg_out32 (s, op | RA (arg1) | RB (0)); + } + else + tcg_out32 (s, op | RA (arg1) | RB (arg2)); + } + +} + +static void tcg_out_bc (TCGContext *s, int bc, int label_index) +{ + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) + tcg_out32 (s, bc | reloc_pc14_val (s->code_ptr, l->u.value)); + else { + uint16_t val = *(uint16_t *) &s->code_ptr[2]; + + /* Thanks to Andrzej Zaborowski */ + tcg_out32 (s, bc | (val & 0xfffc)); + tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL14, label_index, 0); + } +} + +static void tcg_out_brcond (TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index) +{ + tcg_out_cmp (s, cond, arg1, arg2, const_arg2, 7); + tcg_out_bc (s, tcg_to_bc[cond], label_index); +} + +/* XXX: we implement it at the target level to avoid having to + handle cross basic blocks temporaries */ +static void tcg_out_brcond2 (TCGContext *s, const TCGArg *args, + const int *const_args) +{ + int cond = args[4], label_index = args[5], op; + struct { int bit1; int bit2; int cond2; } bits[] = { + [TCG_COND_LT ] = { CR_LT, CR_LT, TCG_COND_LT }, + [TCG_COND_LE ] = { CR_LT, CR_GT, TCG_COND_LT }, + [TCG_COND_GT ] = { CR_GT, CR_GT, TCG_COND_GT }, + [TCG_COND_GE ] = { CR_GT, CR_LT, TCG_COND_GT }, + [TCG_COND_LTU] = { CR_LT, CR_LT, TCG_COND_LTU }, + [TCG_COND_LEU] = { CR_LT, CR_GT, TCG_COND_LTU }, + [TCG_COND_GTU] = { CR_GT, CR_GT, TCG_COND_GTU }, + [TCG_COND_GEU] = { CR_GT, CR_LT, TCG_COND_GTU }, + }, *b = &bits[cond]; + + switch (cond) { + case TCG_COND_EQ: + case TCG_COND_NE: + op = (cond == TCG_COND_EQ) ? CRAND : CRNAND; + tcg_out_cmp (s, cond, args[0], args[2], const_args[2], 6); + tcg_out_cmp (s, cond, args[1], args[3], const_args[3], 7); + tcg_out32 (s, op | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ)); + break; + case TCG_COND_LT: + case TCG_COND_LE: + case TCG_COND_GT: + case TCG_COND_GE: + case TCG_COND_LTU: + case TCG_COND_LEU: + case TCG_COND_GTU: + case TCG_COND_GEU: + op = (b->bit1 != b->bit2) ? CRANDC : CRAND; + tcg_out_cmp (s, b->cond2, args[1], args[3], const_args[3], 5); + tcg_out_cmp (s, TCG_COND_EQ, args[1], args[3], const_args[3], 6); + tcg_out_cmp (s, cond, args[0], args[2], const_args[2], 7); + tcg_out32 (s, op | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, b->bit2)); + tcg_out32 (s, CROR | BT (7, CR_EQ) | BA (5, b->bit1) | BB (7, CR_EQ)); + break; + default: + tcg_abort(); + } + + tcg_out_bc (s, (BC | BI (7, CR_EQ) | BO_COND_TRUE), label_index); +} + +void ppc_tb_set_jmp_target (unsigned long jmp_addr, unsigned long addr) +{ + uint32_t *ptr; + long disp = addr - jmp_addr; + unsigned long patch_size; + + ptr = (uint32_t *)jmp_addr; + + if ((disp << 6) >> 6 != disp) { + ptr[0] = 0x3c000000 | (addr >> 16); /* lis 0,addr@ha */ + ptr[1] = 0x60000000 | (addr & 0xffff); /* la 0,addr@l(0) */ + ptr[2] = 0x7c0903a6; /* mtctr 0 */ + ptr[3] = 0x4e800420; /* brctr */ + patch_size = 16; + } else { + /* patch the branch destination */ + if (disp != 16) { + *ptr = 0x48000000 | (disp & 0x03fffffc); /* b disp */ + patch_size = 4; + } else { + ptr[0] = 0x60000000; /* nop */ + ptr[1] = 0x60000000; + ptr[2] = 0x60000000; + ptr[3] = 0x60000000; + patch_size = 16; + } + } + /* flush icache */ + flush_icache_range(jmp_addr, jmp_addr + patch_size); +} + +static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, + const int *const_args) +{ + switch (opc) { + case INDEX_op_exit_tb: + tcg_out_movi (s, TCG_TYPE_I32, TCG_REG_R3, args[0]); + tcg_out_b (s, 0, (tcg_target_long) tb_ret_addr); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + s->code_ptr += 16; + } + else { + tcg_abort (); + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_br: + { + TCGLabel *l = &s->labels[args[0]]; + + if (l->has_value) { + tcg_out_b (s, 0, l->u.value); + } + else { + uint32_t val = *(uint32_t *) s->code_ptr; + + /* Thanks to Andrzej Zaborowski */ + tcg_out32 (s, B | (val & 0x3fffffc)); + tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL24, args[0], 0); + } + } + break; + case INDEX_op_call: + if (const_args[0]) { + tcg_out_b (s, LK, args[0]); + } + else { + tcg_out32 (s, MTSPR | RS (args[0]) | LR); + tcg_out32 (s, BCLR | BO_ALWAYS | LK); + } + break; + case INDEX_op_jmp: + if (const_args[0]) { + tcg_out_b (s, 0, args[0]); + } + else { + tcg_out32 (s, MTSPR | RS (args[0]) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS); + } + break; + case INDEX_op_movi_i32: + tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); + break; + case INDEX_op_ld8u_i32: + tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX); + break; + case INDEX_op_ld8s_i32: + tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX); + tcg_out32 (s, EXTSB | RS (args[0]) | RA (args[0])); + break; + case INDEX_op_ld16u_i32: + tcg_out_ldst (s, args[0], args[1], args[2], LHZ, LHZX); + break; + case INDEX_op_ld16s_i32: + tcg_out_ldst (s, args[0], args[1], args[2], LHA, LHAX); + break; + case INDEX_op_ld_i32: + tcg_out_ldst (s, args[0], args[1], args[2], LWZ, LWZX); + break; + case INDEX_op_st8_i32: + tcg_out_ldst (s, args[0], args[1], args[2], STB, STBX); + break; + case INDEX_op_st16_i32: + tcg_out_ldst (s, args[0], args[1], args[2], STH, STHX); + break; + case INDEX_op_st_i32: + tcg_out_ldst (s, args[0], args[1], args[2], STW, STWX); + break; + + case INDEX_op_add_i32: + if (const_args[2]) + ppc_addi (s, args[0], args[1], args[2]); + else + tcg_out32 (s, ADD | TAB (args[0], args[1], args[2])); + break; + case INDEX_op_sub_i32: + if (const_args[2]) + ppc_addi (s, args[0], args[1], -args[2]); + else + tcg_out32 (s, SUBF | TAB (args[0], args[2], args[1])); + break; + + case INDEX_op_and_i32: + if (const_args[2]) { + if ((args[2] & 0xffff) == args[2]) + tcg_out32 (s, ANDI | RS (args[1]) | RA (args[0]) | args[2]); + else if ((args[2] & 0xffff0000) == args[2]) + tcg_out32 (s, ANDIS | RS (args[1]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]); + tcg_out32 (s, AND | SAB (args[1], args[0], 0)); + } + } + else + tcg_out32 (s, AND | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_or_i32: + if (const_args[2]) { + if (args[2] & 0xffff) { + tcg_out32 (s, ORI | RS (args[1]) | RA (args[0]) + | (args[2] & 0xffff)); + if (args[2] >> 16) + tcg_out32 (s, ORIS | RS (args[0]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + } + else { + tcg_out32 (s, ORIS | RS (args[1]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + } + } + else + tcg_out32 (s, OR | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_xor_i32: + if (const_args[2]) { + if ((args[2] & 0xffff) == args[2]) + tcg_out32 (s, XORI | RS (args[1]) | RA (args[0]) + | (args[2] & 0xffff)); + else if ((args[2] & 0xffff0000) == args[2]) + tcg_out32 (s, XORIS | RS (args[1]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]); + tcg_out32 (s, XOR | SAB (args[1], args[0], 0)); + } + } + else + tcg_out32 (s, XOR | SAB (args[1], args[0], args[2])); + break; + + case INDEX_op_mul_i32: + if (const_args[2]) { + if (args[2] == (int16_t) args[2]) + tcg_out32 (s, MULLI | RT (args[0]) | RA (args[1]) + | (args[2] & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]); + tcg_out32 (s, MULLW | TAB (args[0], args[1], 0)); + } + } + else + tcg_out32 (s, MULLW | TAB (args[0], args[1], args[2])); + break; + + case INDEX_op_div_i32: + tcg_out32 (s, DIVW | TAB (args[0], args[1], args[2])); + break; + + case INDEX_op_divu_i32: + tcg_out32 (s, DIVWU | TAB (args[0], args[1], args[2])); + break; + + case INDEX_op_rem_i32: + tcg_out32 (s, DIVW | TAB (0, args[1], args[2])); + tcg_out32 (s, MULLW | TAB (0, 0, args[2])); + tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); + break; + + case INDEX_op_remu_i32: + tcg_out32 (s, DIVWU | TAB (0, args[1], args[2])); + tcg_out32 (s, MULLW | TAB (0, 0, args[2])); + tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); + break; + + case INDEX_op_mulu2_i32: + if (args[0] == args[2] || args[0] == args[3]) { + tcg_out32 (s, MULLW | TAB (0, args[2], args[3])); + tcg_out32 (s, MULHWU | TAB (args[1], args[2], args[3])); + tcg_out_mov (s, args[0], 0); + } + else { + tcg_out32 (s, MULLW | TAB (args[0], args[2], args[3])); + tcg_out32 (s, MULHWU | TAB (args[1], args[2], args[3])); + } + break; + + case INDEX_op_shl_i32: + if (const_args[2]) { + tcg_out32 (s, (RLWINM + | RA (args[0]) + | RS (args[1]) + | SH (args[2]) + | MB (0) + | ME (31 - args[2]) + ) + ); + } + else + tcg_out32 (s, SLW | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_shr_i32: + if (const_args[2]) { + tcg_out32 (s, (RLWINM + | RA (args[0]) + | RS (args[1]) + | SH (32 - args[2]) + | MB (args[2]) + | ME (31) + ) + ); + } + else + tcg_out32 (s, SRW | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_sar_i32: + if (const_args[2]) + tcg_out32 (s, SRAWI | RS (args[1]) | RA (args[0]) | SH (args[2])); + else + tcg_out32 (s, SRAW | SAB (args[1], args[0], args[2])); + break; + + case INDEX_op_add2_i32: + if (args[0] == args[3] || args[0] == args[5]) { + tcg_out32 (s, ADDC | TAB (0, args[2], args[4])); + tcg_out32 (s, ADDE | TAB (args[1], args[3], args[5])); + tcg_out_mov (s, args[0], 0); + } + else { + tcg_out32 (s, ADDC | TAB (args[0], args[2], args[4])); + tcg_out32 (s, ADDE | TAB (args[1], args[3], args[5])); + } + break; + case INDEX_op_sub2_i32: + if (args[0] == args[3] || args[0] == args[5]) { + tcg_out32 (s, SUBFC | TAB (0, args[4], args[2])); + tcg_out32 (s, SUBFE | TAB (args[1], args[5], args[3])); + tcg_out_mov (s, args[0], 0); + } + else { + tcg_out32 (s, SUBFC | TAB (args[0], args[4], args[2])); + tcg_out32 (s, SUBFE | TAB (args[1], args[5], args[3])); + } + break; + + case INDEX_op_brcond_i32: + /* + args[0] = r0 + args[1] = r1 + args[2] = cond + args[3] = r1 is const + args[4] = label_index + */ + tcg_out_brcond (s, args[2], args[0], args[1], const_args[1], args[3]); + break; + case INDEX_op_brcond2_i32: + tcg_out_brcond2(s, args, const_args); + break; + + case INDEX_op_neg_i32: + tcg_out32 (s, NEG | RT (args[0]) | RA (args[1])); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, args, 2); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, args, 3); + break; + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, args, 3); + break; + + case INDEX_op_ext8s_i32: + tcg_out32 (s, EXTSB | RS (args[1]) | RA (args[0])); + break; + case INDEX_op_ext16s_i32: + tcg_out32 (s, EXTSH | RS (args[1]) | RA (args[0])); + break; + + default: + tcg_dump_ops (s, stderr); + tcg_abort (); + } +} + +static const TCGTargetOpDef ppc_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, + { INDEX_op_jmp, { "ri" } }, + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "r", "ri" } }, + { INDEX_op_mul_i32, { "r", "r", "ri" } }, + { INDEX_op_div_i32, { "r", "r", "r" } }, + { INDEX_op_divu_i32, { "r", "r", "r" } }, + { INDEX_op_rem_i32, { "r", "r", "r" } }, + { INDEX_op_remu_i32, { "r", "r", "r" } }, + { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } }, + { INDEX_op_sub_i32, { "r", "r", "ri" } }, + { INDEX_op_and_i32, { "r", "r", "ri" } }, + { INDEX_op_or_i32, { "r", "r", "ri" } }, + { INDEX_op_xor_i32, { "r", "r", "ri" } }, + + { INDEX_op_shl_i32, { "r", "r", "ri" } }, + { INDEX_op_shr_i32, { "r", "r", "ri" } }, + { INDEX_op_sar_i32, { "r", "r", "ri" } }, + + { INDEX_op_brcond_i32, { "r", "ri" } }, + + { INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } }, + { INDEX_op_sub2_i32, { "r", "r", "r", "r", "r", "r" } }, + { INDEX_op_brcond2_i32, { "r", "r", "r", "r" } }, + + { INDEX_op_neg_i32, { "r", "r" } }, + +#if TARGET_LONG_BITS == 32 + { INDEX_op_qemu_ld8u, { "r", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L" } }, + { INDEX_op_qemu_ld32s, { "r", "L" } }, + { INDEX_op_qemu_ld64, { "r", "r", "L" } }, + + { INDEX_op_qemu_st8, { "K", "K" } }, + { INDEX_op_qemu_st16, { "K", "K" } }, + { INDEX_op_qemu_st32, { "K", "K" } }, + { INDEX_op_qemu_st64, { "M", "M", "M" } }, +#else + { INDEX_op_qemu_ld8u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld32s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld64, { "r", "L", "L", "L" } }, + + { INDEX_op_qemu_st8, { "K", "K", "K" } }, + { INDEX_op_qemu_st16, { "K", "K", "K" } }, + { INDEX_op_qemu_st32, { "K", "K", "K" } }, + { INDEX_op_qemu_st64, { "M", "M", "M", "M" } }, +#endif + + { INDEX_op_ext8s_i32, { "r", "r" } }, + { INDEX_op_ext16s_i32, { "r", "r" } }, + + { -1 }, +}; + +void tcg_target_init(TCGContext *s) +{ + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff); + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_R0) | +#ifdef __APPLE__ + (1 << TCG_REG_R2) | +#endif + (1 << TCG_REG_R3) | + (1 << TCG_REG_R4) | + (1 << TCG_REG_R5) | + (1 << TCG_REG_R6) | + (1 << TCG_REG_R7) | + (1 << TCG_REG_R8) | + (1 << TCG_REG_R9) | + (1 << TCG_REG_R10) | + (1 << TCG_REG_R11) | + (1 << TCG_REG_R12) + ); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1); +#ifndef __APPLE__ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R2); +#endif + + tcg_add_target_add_op_defs(ppc_op_defs); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/ppc/tcg-target.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/ppc/tcg-target.h --- qemu-0.9.1/tcg/ppc/tcg-target.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/ppc/tcg-target.h 2008-08-03 20:04:11.000000000 +0100 @@ -0,0 +1,105 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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. + */ +#define TCG_TARGET_PPC 1 + +#define TCG_TARGET_REG_BITS 32 +#define TCG_TARGET_WORDS_BIGENDIAN +#define TCG_TARGET_NB_REGS 32 + +enum { + TCG_REG_R0 = 0, + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + TCG_REG_R27, + TCG_REG_R28, + TCG_REG_R29, + TCG_REG_R30, + TCG_REG_R31 +}; + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_R1 +#define TCG_TARGET_STACK_ALIGN 16 +#ifdef __APPLE__ +#define TCG_TARGET_CALL_STACK_OFFSET 24 +#else +#define TCG_TARGET_CALL_ALIGN_ARGS 1 +#define TCG_TARGET_CALL_STACK_OFFSET 8 +#endif + +/* optional instructions */ +#define TCG_TARGET_HAS_neg_i32 +#define TCG_TARGET_HAS_div_i32 +#define TCG_TARGET_HAS_ext8s_i32 +#define TCG_TARGET_HAS_ext16s_i32 + +#define TCG_AREG0 TCG_REG_R27 +#define TCG_AREG1 TCG_REG_R24 +#define TCG_AREG2 TCG_REG_R25 +#define TCG_AREG3 TCG_REG_R26 + +/* taken directly from tcg-dyngen.c */ +#define MIN_CACHE_LINE_SIZE 8 /* conservative value */ + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + unsigned long p; + + start &= ~(MIN_CACHE_LINE_SIZE - 1); + stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1); + + for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { + asm volatile ("dcbst 0,%0" : : "r"(p) : "memory"); + } + asm volatile ("sync" : : : "memory"); + for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { + asm volatile ("icbi 0,%0" : : "r"(p) : "memory"); + } + asm volatile ("sync" : : : "memory"); + asm volatile ("isync" : : : "memory"); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/ppc64/tcg-target.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/ppc64/tcg-target.c --- qemu-0.9.1/tcg/ppc64/tcg-target.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/ppc64/tcg-target.c 2008-11-11 03:04:57.000000000 +0000 @@ -0,0 +1,1504 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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. + */ + +#define TCG_CT_CONST_U32 0x100 + +static uint8_t *tb_ret_addr; + +#define FAST_PATH + +#if TARGET_PHYS_ADDR_BITS == 32 +#define LD_ADDEND LWZ +#else +#define LD_ADDEND LD +#endif + +#if TARGET_LONG_BITS == 32 +#define LD_ADDR LWZU +#define CMP_L 0 +#else +#define LD_ADDR LDU +#define CMP_L (1<<21) +#endif + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "r0", + "r1", + "rp", + "r3", + "r4", + "r5", + "r6", + "r7", + "r8", + "r9", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", + "r16", + "r17", + "r18", + "r19", + "r20", + "r21", + "r22", + "r23", + "r24", + "r25", + "r26", + "r27", + "r28", + "r29", + "r30", + "r31" +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R28, + TCG_REG_R29, + TCG_REG_R30, + TCG_REG_R31, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R0, + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + TCG_REG_R27 +}; + +static const int tcg_target_call_iarg_regs[] = { + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10 +}; + +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_R3 +}; + +static const int tcg_target_callee_save_regs[] = { + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R28, + TCG_REG_R29, + TCG_REG_R30, + TCG_REG_R31 +}; + +static uint32_t reloc_pc24_val (void *pc, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) pc; + if ((disp << 38) >> 38 != disp) + tcg_abort (); + + return disp & 0x3fffffc; +} + +static void reloc_pc24 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3fffffc) + | reloc_pc24_val (pc, target); +} + +static uint16_t reloc_pc14_val (void *pc, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) pc; + if (disp != (int16_t) disp) + tcg_abort (); + + return disp & 0xfffc; +} + +static void reloc_pc14 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0xfffc) + | reloc_pc14_val (pc, target); +} + +static void patch_reloc (uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + value += addend; + switch (type) { + case R_PPC_REL14: + reloc_pc14 (code_ptr, value); + break; + case R_PPC_REL24: + reloc_pc24 (code_ptr, value); + break; + default: + tcg_abort (); + } +} + +/* maximum number of register used for input function arguments */ +static int tcg_target_get_call_iarg_regs_count (int flags) +{ + return sizeof (tcg_target_call_iarg_regs) / sizeof (tcg_target_call_iarg_regs[0]); +} + +/* parse target specific constraints */ +static int target_parse_constraint (TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch (ct_str[0]) { + case 'A': case 'B': case 'C': case 'D': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg (ct->u.regs, 3 + ct_str[0] - 'A'); + break; + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32 (ct->u.regs, 0, 0xffffffff); + break; + case 'L': /* qemu_ld constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32 (ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3); +#ifdef CONFIG_SOFTMMU + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R4); +#endif + break; + case 'S': /* qemu_st constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32 (ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3); +#ifdef CONFIG_SOFTMMU + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R4); + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R5); +#endif + break; + case 'Z': + ct->ct |= TCG_CT_CONST_U32; + break; + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static int tcg_target_const_match (tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + else if ((ct & TCG_CT_CONST_U32) && (val == (uint32_t) val)) + return 1; + return 0; +} + +#define OPCD(opc) ((opc)<<26) +#define XO19(opc) (OPCD(19)|((opc)<<1)) +#define XO30(opc) (OPCD(30)|((opc)<<2)) +#define XO31(opc) (OPCD(31)|((opc)<<1)) +#define XO58(opc) (OPCD(58)|(opc)) +#define XO62(opc) (OPCD(62)|(opc)) + +#define B OPCD( 18) +#define BC OPCD( 16) +#define LBZ OPCD( 34) +#define LHZ OPCD( 40) +#define LHA OPCD( 42) +#define LWZ OPCD( 32) +#define STB OPCD( 38) +#define STH OPCD( 44) +#define STW OPCD( 36) + +#define STD XO62( 0) +#define STDU XO62( 1) +#define STDX XO31(149) + +#define LD XO58( 0) +#define LDX XO31( 21) +#define LDU XO58( 1) +#define LWA XO58( 2) +#define LWAX XO31(341) + +#define ADDI OPCD( 14) +#define ADDIS OPCD( 15) +#define ORI OPCD( 24) +#define ORIS OPCD( 25) +#define XORI OPCD( 26) +#define XORIS OPCD( 27) +#define ANDI OPCD( 28) +#define ANDIS OPCD( 29) +#define MULLI OPCD( 7) +#define CMPLI OPCD( 10) +#define CMPI OPCD( 11) + +#define LWZU OPCD( 33) +#define STWU OPCD( 37) + +#define RLWINM OPCD( 21) + +#define RLDICL XO30( 0) +#define RLDICR XO30( 1) +#define RLDIMI XO30( 3) + +#define BCLR XO19( 16) +#define BCCTR XO19(528) +#define CRAND XO19(257) +#define CRANDC XO19(129) +#define CRNAND XO19(225) +#define CROR XO19(449) + +#define EXTSB XO31(954) +#define EXTSH XO31(922) +#define EXTSW XO31(986) +#define ADD XO31(266) +#define ADDE XO31(138) +#define ADDC XO31( 10) +#define AND XO31( 28) +#define SUBF XO31( 40) +#define SUBFC XO31( 8) +#define SUBFE XO31(136) +#define OR XO31(444) +#define XOR XO31(316) +#define MULLW XO31(235) +#define MULHWU XO31( 11) +#define DIVW XO31(491) +#define DIVWU XO31(459) +#define CMP XO31( 0) +#define CMPL XO31( 32) +#define LHBRX XO31(790) +#define LWBRX XO31(534) +#define STHBRX XO31(918) +#define STWBRX XO31(662) +#define MFSPR XO31(339) +#define MTSPR XO31(467) +#define SRAWI XO31(824) +#define NEG XO31(104) + +#define MULLD XO31(233) +#define MULHD XO31( 73) +#define MULHDU XO31( 9) +#define DIVD XO31(489) +#define DIVDU XO31(457) + +#define LBZX XO31( 87) +#define LHZX XO31(276) +#define LHAX XO31(343) +#define LWZX XO31( 23) +#define STBX XO31(215) +#define STHX XO31(407) +#define STWX XO31(151) + +#define SPR(a,b) ((((a)<<5)|(b))<<11) +#define LR SPR(8, 0) +#define CTR SPR(9, 0) + +#define SLW XO31( 24) +#define SRW XO31(536) +#define SRAW XO31(792) + +#define SLD XO31( 27) +#define SRD XO31(539) +#define SRAD XO31(794) +#define SRADI XO31(413<<1) + +#define LMW OPCD( 46) +#define STMW OPCD( 47) + +#define TW XO31( 4) +#define TRAP (TW | TO (31)) + +#define RT(r) ((r)<<21) +#define RS(r) ((r)<<21) +#define RA(r) ((r)<<16) +#define RB(r) ((r)<<11) +#define TO(t) ((t)<<21) +#define SH(s) ((s)<<11) +#define MB(b) ((b)<<6) +#define ME(e) ((e)<<1) +#define BO(o) ((o)<<21) +#define MB64(b) ((b)<<5) + +#define LK 1 + +#define TAB(t,a,b) (RT(t) | RA(a) | RB(b)) +#define SAB(s,a,b) (RS(s) | RA(a) | RB(b)) + +#define BF(n) ((n)<<23) +#define BI(n, c) (((c)+((n)*4))<<16) +#define BT(n, c) (((c)+((n)*4))<<21) +#define BA(n, c) (((c)+((n)*4))<<16) +#define BB(n, c) (((c)+((n)*4))<<11) + +#define BO_COND_TRUE BO (12) +#define BO_COND_FALSE BO ( 4) +#define BO_ALWAYS BO (20) + +enum { + CR_LT, + CR_GT, + CR_EQ, + CR_SO +}; + +static const uint32_t tcg_to_bc[10] = { + [TCG_COND_EQ] = BC | BI (7, CR_EQ) | BO_COND_TRUE, + [TCG_COND_NE] = BC | BI (7, CR_EQ) | BO_COND_FALSE, + [TCG_COND_LT] = BC | BI (7, CR_LT) | BO_COND_TRUE, + [TCG_COND_GE] = BC | BI (7, CR_LT) | BO_COND_FALSE, + [TCG_COND_LE] = BC | BI (7, CR_GT) | BO_COND_FALSE, + [TCG_COND_GT] = BC | BI (7, CR_GT) | BO_COND_TRUE, + [TCG_COND_LTU] = BC | BI (7, CR_LT) | BO_COND_TRUE, + [TCG_COND_GEU] = BC | BI (7, CR_LT) | BO_COND_FALSE, + [TCG_COND_LEU] = BC | BI (7, CR_GT) | BO_COND_FALSE, + [TCG_COND_GTU] = BC | BI (7, CR_GT) | BO_COND_TRUE, +}; + +static void tcg_out_mov (TCGContext *s, int ret, int arg) +{ + tcg_out32 (s, OR | SAB (arg, ret, arg)); +} + +static void tcg_out_rld (TCGContext *s, int op, int ra, int rs, int sh, int mb) +{ + sh = SH (sh & 0x1f) | (((sh >> 5) & 1) << 1); + mb = MB64 ((mb >> 5) | ((mb << 1) & 0x3f)); + tcg_out32 (s, op | RA (ra) | RS (rs) | sh | mb); +} + +static void tcg_out_movi32 (TCGContext *s, int ret, int32_t arg) +{ + if (arg == (int16_t) arg) + tcg_out32 (s, ADDI | RT (ret) | RA (0) | (arg & 0xffff)); + else { + tcg_out32 (s, ADDIS | RT (ret) | RA (0) | ((arg >> 16) & 0xffff)); + if (arg & 0xffff) + tcg_out32 (s, ORI | RS (ret) | RA (ret) | (arg & 0xffff)); + } +} + +static void tcg_out_movi (TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + int32_t arg32 = arg; + + if (type == TCG_TYPE_I32 || arg == arg32) { + tcg_out_movi32 (s, ret, arg32); + } + else { + if ((uint64_t) arg >> 32) { + uint16_t h16 = arg >> 16; + uint16_t l16 = arg; + + tcg_out_movi32 (s, ret, arg >> 32); + tcg_out_rld (s, RLDICR, ret, ret, 32, 31); + if (h16) tcg_out32 (s, ORIS | RS (ret) | RA (ret) | h16); + if (l16) tcg_out32 (s, ORI | RS (ret) | RA (ret) | l16); + } + else { + tcg_out_movi32 (s, ret, arg32); + if (arg32 < 0) + tcg_out_rld (s, RLDICL, ret, ret, 0, 32); + } + } +} + +static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg) +{ + int reg; + + if (const_arg) { + reg = 2; + tcg_out_movi (s, TCG_TYPE_I64, reg, arg); + } + else reg = arg; + + tcg_out32 (s, LD | RT (0) | RA (reg)); + tcg_out32 (s, MTSPR | RA (0) | CTR); + tcg_out32 (s, LD | RT (11) | RA (reg) | 16); + tcg_out32 (s, LD | RT (2) | RA (reg) | 8); + tcg_out32 (s, BCCTR | BO_ALWAYS | LK); +} + +static void tcg_out_ldst (TCGContext *s, int ret, int addr, + int offset, int op1, int op2) +{ + if (offset == (int16_t) offset) + tcg_out32 (s, op1 | RT (ret) | RA (addr) | (offset & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I64, 0, offset); + tcg_out32 (s, op2 | RT (ret) | RA (addr) | RB (0)); + } +} + +static void tcg_out_ldsta (TCGContext *s, int ret, int addr, + int offset, int op1, int op2) +{ + if (offset == (int16_t) (offset & ~3)) + tcg_out32 (s, op1 | RT (ret) | RA (addr) | (offset & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I64, 0, offset); + tcg_out32 (s, op2 | RT (ret) | RA (addr) | RB (0)); + } +} + +static void tcg_out_b (TCGContext *s, int mask, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) s->code_ptr; + if ((disp << 38) >> 38 == disp) + tcg_out32 (s, B | (disp & 0x3fffffc) | mask); + else { + tcg_out_movi (s, TCG_TYPE_I64, 0, (tcg_target_long) target); + tcg_out32 (s, MTSPR | RS (0) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS | mask); + } +} + +#if defined (CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; + +static void tcg_out_tlb_read (TCGContext *s, int r0, int r1, int r2, + int addr_reg, int s_bits, int offset) +{ +#if TARGET_LONG_BITS == 32 + tcg_out_rld (s, RLDICL, addr_reg, addr_reg, 0, 32); + + tcg_out32 (s, (RLWINM + | RA (r0) + | RS (addr_reg) + | SH (32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)) + | MB (32 - (CPU_TLB_BITS + CPU_TLB_ENTRY_BITS)) + | ME (31 - CPU_TLB_ENTRY_BITS) + ) + ); + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (TCG_AREG0)); + tcg_out32 (s, (LWZU | RT (r1) | RA (r0) | offset)); + tcg_out32 (s, (RLWINM + | RA (r2) + | RS (addr_reg) + | SH (0) + | MB ((32 - s_bits) & 31) + | ME (31 - TARGET_PAGE_BITS) + ) + ); +#else + tcg_out_rld (s, RLDICL, r0, addr_reg, + 64 - TARGET_PAGE_BITS, + 64 - CPU_TLB_BITS); + tcg_out_rld (s, RLDICR, r0, r0, + CPU_TLB_ENTRY_BITS, + 63 - CPU_TLB_ENTRY_BITS); + + tcg_out32 (s, ADD | TAB (r0, r0, TCG_AREG0)); + tcg_out32 (s, LD_ADDR | RT (r1) | RA (r0) | offset); + + if (!s_bits) { + tcg_out_rld (s, RLDICR, r2, addr_reg, 0, 63 - TARGET_PAGE_BITS); + } + else { + tcg_out_rld (s, RLDICL, r2, addr_reg, + 64 - TARGET_PAGE_BITS, + TARGET_PAGE_BITS - s_bits); + tcg_out_rld (s, RLDICL, r2, r2, TARGET_PAGE_BITS, 0); + } +#endif +} +#endif + +static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc) +{ + int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap; +#ifdef CONFIG_SOFTMMU + int r2; + void *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + s_bits = opc & 3; + +#ifdef CONFIG_SOFTMMU + r0 = 3; + r1 = 4; + r2 = 0; + + tcg_out_tlb_read (s, r0, r1, r2, addr_reg, s_bits, + offsetof (CPUState, tlb_table[mem_index][0].addr_read)); + + tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1) | CMP_L); + + label1_ptr = s->code_ptr; +#ifdef FAST_PATH + tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE); +#endif + + /* slow path */ + tcg_out_mov (s, 3, addr_reg); + tcg_out_movi (s, TCG_TYPE_I64, 4, mem_index); + + tcg_out_call (s, (tcg_target_long) qemu_ld_helpers[s_bits], 1); + + switch (opc) { + case 0|4: + tcg_out32 (s, EXTSB | RA (data_reg) | RS (3)); + break; + case 1|4: + tcg_out32 (s, EXTSH | RA (data_reg) | RS (3)); + break; + case 2|4: + tcg_out32 (s, EXTSW | RA (data_reg) | RS (3)); + break; + case 0: + case 1: + case 2: + case 3: + if (data_reg != 3) + tcg_out_mov (s, data_reg, 3); + break; + } + label2_ptr = s->code_ptr; + tcg_out32 (s, B); + + /* label1: fast path */ +#ifdef FAST_PATH + reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr); +#endif + + /* r0 now contains &env->tlb_table[mem_index][index].addr_read */ + tcg_out32 (s, (LD_ADDEND + | RT (r0) + | RA (r0) + | (offsetof (CPUTLBEntry, addend) + - offsetof (CPUTLBEntry, addr_read)) + )); + /* r0 = env->tlb_table[mem_index][index].addend */ + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg)); + /* r0 = env->tlb_table[mem_index][index].addend + addr */ + +#else /* !CONFIG_SOFTMMU */ +#if TARGET_LONG_BITS == 32 + tcg_out_rld (s, RLDICL, addr_reg, addr_reg, 0, 32); +#endif + r0 = addr_reg; + r1 = 3; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + switch (opc) { + default: + case 0: + tcg_out32 (s, LBZ | RT (data_reg) | RA (r0)); + break; + case 0|4: + tcg_out32 (s, LBZ | RT (data_reg) | RA (r0)); + tcg_out32 (s, EXTSB | RA (data_reg) | RS (data_reg)); + break; + case 1: + if (bswap) tcg_out32 (s, LHBRX | RT (data_reg) | RB (r0)); + else tcg_out32 (s, LHZ | RT (data_reg) | RA (r0)); + break; + case 1|4: + if (bswap) { + tcg_out32 (s, LHBRX | RT (data_reg) | RB (r0)); + tcg_out32 (s, EXTSH | RA (data_reg) | RS (data_reg)); + } + else tcg_out32 (s, LHA | RT (data_reg) | RA (r0)); + break; + case 2: + if (bswap) tcg_out32 (s, LWBRX | RT (data_reg) | RB (r0)); + else tcg_out32 (s, LWZ | RT (data_reg)| RA (r0)); + break; + case 2|4: + if (bswap) { + tcg_out32 (s, LWBRX | RT (data_reg) | RB (r0)); + tcg_out32 (s, EXTSW | RA (data_reg) | RS (data_reg)); + } + else tcg_out32 (s, LWA | RT (data_reg)| RA (r0)); + break; + case 3: + if (bswap) { + tcg_out_movi32 (s, 0, 4); + tcg_out32 (s, LWBRX | RT (data_reg) | RB (r0)); + tcg_out32 (s, LWBRX | RT ( r1) | RA (r0)); + tcg_out_rld (s, RLDIMI, data_reg, r1, 32, 0); + } + else tcg_out32 (s, LD | RT (data_reg) | RA (r0)); + break; + } + +#ifdef CONFIG_SOFTMMU + reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr); +#endif +} + +static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc) +{ + int addr_reg, r0, r1, data_reg, mem_index, bswap; +#ifdef CONFIG_SOFTMMU + int r2; + void *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + +#ifdef CONFIG_SOFTMMU + r0 = 3; + r1 = 4; + r2 = 0; + + tcg_out_tlb_read (s, r0, r1, r2, addr_reg, opc, + offsetof (CPUState, tlb_table[mem_index][0].addr_write)); + + tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1) | CMP_L); + + label1_ptr = s->code_ptr; +#ifdef FAST_PATH + tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE); +#endif + + /* slow path */ + tcg_out_mov (s, 3, addr_reg); + tcg_out_rld (s, RLDICL, 4, data_reg, 0, 64 - (1 << (3 + opc))); + tcg_out_movi (s, TCG_TYPE_I64, 5, mem_index); + + tcg_out_call (s, (tcg_target_long) qemu_st_helpers[opc], 1); + + label2_ptr = s->code_ptr; + tcg_out32 (s, B); + + /* label1: fast path */ +#ifdef FAST_PATH + reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr); +#endif + + tcg_out32 (s, (LD_ADDEND + | RT (r0) + | RA (r0) + | (offsetof (CPUTLBEntry, addend) + - offsetof (CPUTLBEntry, addr_write)) + )); + /* r0 = env->tlb_table[mem_index][index].addend */ + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg)); + /* r0 = env->tlb_table[mem_index][index].addend + addr */ + +#else /* !CONFIG_SOFTMMU */ +#if TARGET_LONG_BITS == 32 + tcg_out_rld (s, RLDICL, addr_reg, addr_reg, 0, 32); +#endif + r1 = 3; + r0 = addr_reg; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + switch (opc) { + case 0: + tcg_out32 (s, STB | RS (data_reg) | RA (r0)); + break; + case 1: + if (bswap) tcg_out32 (s, STHBRX | RS (data_reg) | RA (0) | RB (r0)); + else tcg_out32 (s, STH | RS (data_reg) | RA (r0)); + break; + case 2: + if (bswap) tcg_out32 (s, STWBRX | RS (data_reg) | RA (0) | RB (r0)); + else tcg_out32 (s, STW | RS (data_reg) | RA (r0)); + break; + case 3: + if (bswap) { + tcg_out32 (s, STWBRX | RS (data_reg) | RA (0) | RB (r0)); + tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4); + tcg_out_rld (s, RLDICL, 0, data_reg, 32, 0); + tcg_out32 (s, STWBRX | RS (0) | RA (0) | RB (r1)); + } + else tcg_out32 (s, STD | RS (data_reg) | RA (r0)); + break; + } + +#ifdef CONFIG_SOFTMMU + reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr); +#endif +} + +void tcg_target_qemu_prologue (TCGContext *s) +{ + int i, frame_size; + uint64_t addr; + + frame_size = 0 + + 8 /* back chain */ + + 8 /* CR */ + + 8 /* LR */ + + 8 /* compiler doubleword */ + + 8 /* link editor doubleword */ + + 8 /* TOC save area */ + + TCG_STATIC_CALL_ARGS_SIZE + + ARRAY_SIZE (tcg_target_callee_save_regs) * 8 + ; + frame_size = (frame_size + 15) & ~15; + + /* First emit adhoc function descriptor */ + addr = (uint64_t) s->code_ptr + 24; + tcg_out32 (s, addr >> 32); tcg_out32 (s, addr); /* entry point */ + s->code_ptr += 16; /* skip TOC and environment pointer */ + + /* Prologue */ + tcg_out32 (s, MFSPR | RT (0) | LR); + tcg_out32 (s, STDU | RS (1) | RA (1) | (-frame_size & 0xffff)); + for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i) + tcg_out32 (s, (STD + | RS (tcg_target_callee_save_regs[i]) + | RA (1) + | (i * 8 + 48 + TCG_STATIC_CALL_ARGS_SIZE) + ) + ); + tcg_out32 (s, STD | RS (0) | RA (1) | (frame_size + 16)); + + tcg_out32 (s, MTSPR | RS (3) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS); + + /* Epilogue */ + tb_ret_addr = s->code_ptr; + + for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i) + tcg_out32 (s, (LD + | RT (tcg_target_callee_save_regs[i]) + | RA (1) + | (i * 8 + 48 + TCG_STATIC_CALL_ARGS_SIZE) + ) + ); + tcg_out32 (s, LD | RT (0) | RA (1) | (frame_size + 16)); + tcg_out32 (s, MTSPR | RS (0) | LR); + tcg_out32 (s, ADDI | RT (1) | RA (1) | frame_size); + tcg_out32 (s, BCLR | BO_ALWAYS); +} + +static void tcg_out_ld (TCGContext *s, TCGType type, int ret, int arg1, + tcg_target_long arg2) +{ + if (type == TCG_TYPE_I32) + tcg_out_ldst (s, ret, arg1, arg2, LWZ, LWZX); + else + tcg_out_ldsta (s, ret, arg1, arg2, LD, LDX); +} + +static void tcg_out_st (TCGContext *s, TCGType type, int arg, int arg1, + tcg_target_long arg2) +{ + if (type == TCG_TYPE_I32) + tcg_out_ldst (s, arg, arg1, arg2, STW, STWX); + else + tcg_out_ldsta (s, arg, arg1, arg2, STD, STDX); +} + +static void ppc_addi32 (TCGContext *s, int rt, int ra, tcg_target_long si) +{ + if (!si && rt == ra) + return; + + if (si == (int16_t) si) + tcg_out32 (s, ADDI | RT (rt) | RA (ra) | (si & 0xffff)); + else { + uint16_t h = ((si >> 16) & 0xffff) + ((uint16_t) si >> 15); + tcg_out32 (s, ADDIS | RT (rt) | RA (ra) | h); + tcg_out32 (s, ADDI | RT (rt) | RA (rt) | (si & 0xffff)); + } +} + +static void ppc_addi64 (TCGContext *s, int rt, int ra, tcg_target_long si) +{ + /* XXX: suboptimal */ + if (si == (int16_t) si + || (((uint64_t) si >> 31) == 0) && (si & 0x8000) == 0) + ppc_addi32 (s, rt, ra, si); + else { + tcg_out_movi (s, TCG_TYPE_I64, 0, si); + tcg_out32 (s, ADD | RT (rt) | RA (ra)); + } +} + +static void tcg_out_addi (TCGContext *s, int reg, tcg_target_long val) +{ + ppc_addi64 (s, reg, reg, val); +} + +static void tcg_out_cmp (TCGContext *s, int cond, TCGArg arg1, TCGArg arg2, + int const_arg2, int cr, int arch64) +{ + int imm; + uint32_t op; + + switch (cond) { + case TCG_COND_EQ: + case TCG_COND_NE: + if (const_arg2) { + if ((int16_t) arg2 == arg2) { + op = CMPI; + imm = 1; + break; + } + else if ((uint16_t) arg2 == arg2) { + op = CMPLI; + imm = 1; + break; + } + } + op = CMPL; + imm = 0; + break; + + case TCG_COND_LT: + case TCG_COND_GE: + case TCG_COND_LE: + case TCG_COND_GT: + if (const_arg2) { + if ((int16_t) arg2 == arg2) { + op = CMPI; + imm = 1; + break; + } + } + op = CMP; + imm = 0; + break; + + case TCG_COND_LTU: + case TCG_COND_GEU: + case TCG_COND_LEU: + case TCG_COND_GTU: + if (const_arg2) { + if ((uint16_t) arg2 == arg2) { + op = CMPLI; + imm = 1; + break; + } + } + op = CMPL; + imm = 0; + break; + + default: + tcg_abort (); + } + op |= BF (cr) | (arch64 << 21); + + if (imm) + tcg_out32 (s, op | RA (arg1) | (arg2 & 0xffff)); + else { + if (const_arg2) { + tcg_out_movi (s, TCG_TYPE_I64, 0, arg2); + tcg_out32 (s, op | RA (arg1) | RB (0)); + } + else + tcg_out32 (s, op | RA (arg1) | RB (arg2)); + } + +} + +static void tcg_out_bc (TCGContext *s, int bc, int label_index) +{ + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) + tcg_out32 (s, bc | reloc_pc14_val (s->code_ptr, l->u.value)); + else { + uint16_t val = *(uint16_t *) &s->code_ptr[2]; + + /* Thanks to Andrzej Zaborowski */ + tcg_out32 (s, bc | (val & 0xfffc)); + tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL14, label_index, 0); + } +} + +static void tcg_out_brcond (TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index, int arch64) +{ + tcg_out_cmp (s, cond, arg1, arg2, const_arg2, 7, arch64); + tcg_out_bc (s, tcg_to_bc[cond], label_index); +} + +void ppc_tb_set_jmp_target (unsigned long jmp_addr, unsigned long addr) +{ + TCGContext s; + unsigned long patch_size; + + s.code_ptr = (uint8_t *) jmp_addr; + tcg_out_b (&s, 0, addr); + patch_size = s.code_ptr - (uint8_t *) jmp_addr; + flush_icache_range (jmp_addr, jmp_addr + patch_size); +} + +static void tcg_out_op (TCGContext *s, int opc, const TCGArg *args, + const int *const_args) +{ + int c; + + switch (opc) { + case INDEX_op_exit_tb: + tcg_out_movi (s, TCG_TYPE_I64, TCG_REG_R3, args[0]); + tcg_out_b (s, 0, (tcg_target_long) tb_ret_addr); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + s->code_ptr += 28; + } + else { + tcg_abort (); + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_br: + { + TCGLabel *l = &s->labels[args[0]]; + + if (l->has_value) { + tcg_out_b (s, 0, l->u.value); + } + else { + uint32_t val = *(uint32_t *) s->code_ptr; + + /* Thanks to Andrzej Zaborowski */ + tcg_out32 (s, B | (val & 0x3fffffc)); + tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL24, args[0], 0); + } + } + break; + case INDEX_op_call: + tcg_out_call (s, args[0], const_args[0]); + break; + case INDEX_op_jmp: + if (const_args[0]) { + tcg_out_b (s, 0, args[0]); + } + else { + tcg_out32 (s, MTSPR | RS (args[0]) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS); + } + break; + case INDEX_op_movi_i32: + tcg_out_movi (s, TCG_TYPE_I32, args[0], args[1]); + break; + case INDEX_op_movi_i64: + tcg_out_movi (s, TCG_TYPE_I64, args[0], args[1]); + break; + case INDEX_op_ld8u_i32: + case INDEX_op_ld8u_i64: + tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX); + break; + case INDEX_op_ld8s_i32: + case INDEX_op_ld8s_i64: + tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX); + tcg_out32 (s, EXTSB | RS (args[0]) | RA (args[0])); + break; + case INDEX_op_ld16u_i32: + case INDEX_op_ld16u_i64: + tcg_out_ldst (s, args[0], args[1], args[2], LHZ, LHZX); + break; + case INDEX_op_ld16s_i32: + case INDEX_op_ld16s_i64: + tcg_out_ldst (s, args[0], args[1], args[2], LHA, LHAX); + break; + case INDEX_op_ld_i32: + case INDEX_op_ld32u_i64: + tcg_out_ldst (s, args[0], args[1], args[2], LWZ, LWZX); + break; + case INDEX_op_ld32s_i64: + tcg_out_ldsta (s, args[0], args[1], args[2], LWA, LWAX); + break; + case INDEX_op_ld_i64: + tcg_out_ldsta (s, args[0], args[1], args[2], LD, LDX); + break; + case INDEX_op_st8_i32: + case INDEX_op_st8_i64: + tcg_out_ldst (s, args[0], args[1], args[2], STB, STBX); + break; + case INDEX_op_st16_i32: + case INDEX_op_st16_i64: + tcg_out_ldst (s, args[0], args[1], args[2], STH, STHX); + break; + case INDEX_op_st_i32: + case INDEX_op_st32_i64: + tcg_out_ldst (s, args[0], args[1], args[2], STW, STWX); + break; + case INDEX_op_st_i64: + tcg_out_ldsta (s, args[0], args[1], args[2], STD, STDX); + break; + + case INDEX_op_add_i32: + if (const_args[2]) + ppc_addi32 (s, args[0], args[1], args[2]); + else + tcg_out32 (s, ADD | TAB (args[0], args[1], args[2])); + break; + case INDEX_op_sub_i32: + if (const_args[2]) + ppc_addi32 (s, args[0], args[1], -args[2]); + else + tcg_out32 (s, SUBF | TAB (args[0], args[2], args[1])); + break; + + case INDEX_op_and_i64: + case INDEX_op_and_i32: + if (const_args[2]) { + if ((args[2] & 0xffff) == args[2]) + tcg_out32 (s, ANDI | RS (args[1]) | RA (args[0]) | args[2]); + else if ((args[2] & 0xffff0000) == args[2]) + tcg_out32 (s, ANDIS | RS (args[1]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + else { + tcg_out_movi (s, (opc == INDEX_op_and_i32 + ? TCG_TYPE_I32 + : TCG_TYPE_I64), + 0, args[2]); + tcg_out32 (s, AND | SAB (args[1], args[0], 0)); + } + } + else + tcg_out32 (s, AND | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_or_i64: + case INDEX_op_or_i32: + if (const_args[2]) { + if (args[2] & 0xffff) { + tcg_out32 (s, ORI | RS (args[1]) | RA (args[0]) + | (args[2] & 0xffff)); + if (args[2] >> 16) + tcg_out32 (s, ORIS | RS (args[0]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + } + else { + tcg_out32 (s, ORIS | RS (args[1]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + } + } + else + tcg_out32 (s, OR | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_xor_i64: + case INDEX_op_xor_i32: + if (const_args[2]) { + if ((args[2] & 0xffff) == args[2]) + tcg_out32 (s, XORI | RS (args[1]) | RA (args[0]) + | (args[2] & 0xffff)); + else if ((args[2] & 0xffff0000) == args[2]) + tcg_out32 (s, XORIS | RS (args[1]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + else { + tcg_out_movi (s, (opc == INDEX_op_and_i32 + ? TCG_TYPE_I32 + : TCG_TYPE_I64), + 0, args[2]); + tcg_out32 (s, XOR | SAB (args[1], args[0], 0)); + } + } + else + tcg_out32 (s, XOR | SAB (args[1], args[0], args[2])); + break; + + case INDEX_op_mul_i32: + if (const_args[2]) { + if (args[2] == (int16_t) args[2]) + tcg_out32 (s, MULLI | RT (args[0]) | RA (args[1]) + | (args[2] & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]); + tcg_out32 (s, MULLW | TAB (args[0], args[1], 0)); + } + } + else + tcg_out32 (s, MULLW | TAB (args[0], args[1], args[2])); + break; + + case INDEX_op_div_i32: + tcg_out32 (s, DIVW | TAB (args[0], args[1], args[2])); + break; + + case INDEX_op_divu_i32: + tcg_out32 (s, DIVWU | TAB (args[0], args[1], args[2])); + break; + + case INDEX_op_rem_i32: + tcg_out32 (s, DIVW | TAB (0, args[1], args[2])); + tcg_out32 (s, MULLW | TAB (0, 0, args[2])); + tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); + break; + + case INDEX_op_remu_i32: + tcg_out32 (s, DIVWU | TAB (0, args[1], args[2])); + tcg_out32 (s, MULLW | TAB (0, 0, args[2])); + tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); + break; + + case INDEX_op_shl_i32: + if (const_args[2]) { + tcg_out32 (s, (RLWINM + | RA (args[0]) + | RS (args[1]) + | SH (args[2]) + | MB (0) + | ME (31 - args[2]) + ) + ); + } + else + tcg_out32 (s, SLW | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_shr_i32: + if (const_args[2]) { + tcg_out32 (s, (RLWINM + | RA (args[0]) + | RS (args[1]) + | SH (32 - args[2]) + | MB (args[2]) + | ME (31) + ) + ); + } + else + tcg_out32 (s, SRW | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_sar_i32: + if (const_args[2]) + tcg_out32 (s, SRAWI | RS (args[1]) | RA (args[0]) | SH (args[2])); + else + tcg_out32 (s, SRAW | SAB (args[1], args[0], args[2])); + break; + + case INDEX_op_brcond_i32: + tcg_out_brcond (s, args[2], args[0], args[1], const_args[1], args[3], 0); + break; + + case INDEX_op_brcond_i64: + tcg_out_brcond (s, args[2], args[0], args[1], const_args[1], args[3], 1); + break; + + case INDEX_op_neg_i32: + case INDEX_op_neg_i64: + tcg_out32 (s, NEG | RT (args[0]) | RA (args[1])); + break; + + case INDEX_op_add_i64: + if (const_args[2]) + ppc_addi64 (s, args[0], args[1], args[2]); + else + tcg_out32 (s, ADD | TAB (args[0], args[1], args[2])); + break; + case INDEX_op_sub_i64: + if (const_args[2]) + ppc_addi64 (s, args[0], args[1], -args[2]); + else + tcg_out32 (s, SUBF | TAB (args[0], args[2], args[1])); + break; + + case INDEX_op_shl_i64: + if (const_args[2]) + tcg_out_rld (s, RLDICR, args[0], args[1], args[2], 63 - args[2]); + else + tcg_out32 (s, SLD | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_shr_i64: + if (const_args[2]) + tcg_out_rld (s, RLDICL, args[0], args[1], 64 - args[2], args[2]); + else + tcg_out32 (s, SRD | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_sar_i64: + if (const_args[2]) { + int sh = SH (args[2] & 0x1f) | (((args[2] >> 5) & 1) << 1); + tcg_out32 (s, SRADI | RA (args[0]) | RS (args[1]) | sh); + } + else + tcg_out32 (s, SRAD | SAB (args[1], args[0], args[2])); + break; + + case INDEX_op_mul_i64: + tcg_out32 (s, MULLD | TAB (args[0], args[1], args[2])); + break; + case INDEX_op_div_i64: + tcg_out32 (s, DIVD | TAB (args[0], args[1], args[2])); + break; + case INDEX_op_divu_i64: + tcg_out32 (s, DIVDU | TAB (args[0], args[1], args[2])); + break; + case INDEX_op_rem_i64: + tcg_out32 (s, DIVD | TAB (0, args[1], args[2])); + tcg_out32 (s, MULLD | TAB (0, 0, args[2])); + tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); + break; + case INDEX_op_remu_i64: + tcg_out32 (s, DIVDU | TAB (0, args[1], args[2])); + tcg_out32 (s, MULLD | TAB (0, 0, args[2])); + tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld (s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld (s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld (s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld (s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld (s, args, 2); + break; + case INDEX_op_qemu_ld32s: + tcg_out_qemu_ld (s, args, 2 | 4); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld (s, args, 3); + break; + case INDEX_op_qemu_st8: + tcg_out_qemu_st (s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st (s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st (s, args, 2); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st (s, args, 3); + break; + + case INDEX_op_ext8s_i32: + case INDEX_op_ext8s_i64: + c = EXTSB; + goto gen_ext; + case INDEX_op_ext16s_i32: + case INDEX_op_ext16s_i64: + c = EXTSH; + goto gen_ext; + case INDEX_op_ext32s_i64: + c = EXTSW; + goto gen_ext; + gen_ext: + tcg_out32 (s, c | RS (args[1]) | RA (args[0])); + break; + + default: + tcg_dump_ops (s, stderr); + tcg_abort (); + } +} + +static const TCGTargetOpDef ppc_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, + { INDEX_op_jmp, { "ri" } }, + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_mov_i64, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_movi_i64, { "r" } }, + + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_ld_i64, { "r", "r" } }, + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st8_i64, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st16_i64, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + { INDEX_op_st_i64, { "r", "r" } }, + { INDEX_op_st32_i64, { "r", "r" } }, + + { INDEX_op_ld8u_i64, { "r", "r" } }, + { INDEX_op_ld8s_i64, { "r", "r" } }, + { INDEX_op_ld16u_i64, { "r", "r" } }, + { INDEX_op_ld16s_i64, { "r", "r" } }, + { INDEX_op_ld32u_i64, { "r", "r" } }, + { INDEX_op_ld32s_i64, { "r", "r" } }, + { INDEX_op_ld_i64, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "r", "ri" } }, + { INDEX_op_mul_i32, { "r", "r", "ri" } }, + { INDEX_op_div_i32, { "r", "r", "r" } }, + { INDEX_op_divu_i32, { "r", "r", "r" } }, + { INDEX_op_rem_i32, { "r", "r", "r" } }, + { INDEX_op_remu_i32, { "r", "r", "r" } }, + { INDEX_op_sub_i32, { "r", "r", "ri" } }, + { INDEX_op_and_i32, { "r", "r", "ri" } }, + { INDEX_op_or_i32, { "r", "r", "ri" } }, + { INDEX_op_xor_i32, { "r", "r", "ri" } }, + + { INDEX_op_shl_i32, { "r", "r", "ri" } }, + { INDEX_op_shr_i32, { "r", "r", "ri" } }, + { INDEX_op_sar_i32, { "r", "r", "ri" } }, + + { INDEX_op_brcond_i32, { "r", "ri" } }, + { INDEX_op_brcond_i64, { "r", "ri" } }, + + { INDEX_op_neg_i32, { "r", "r" } }, + + { INDEX_op_add_i64, { "r", "r", "ri" } }, + { INDEX_op_sub_i64, { "r", "r", "ri" } }, + { INDEX_op_and_i64, { "r", "r", "rZ" } }, + { INDEX_op_or_i64, { "r", "r", "rZ" } }, + { INDEX_op_xor_i64, { "r", "r", "rZ" } }, + + { INDEX_op_shl_i64, { "r", "r", "ri" } }, + { INDEX_op_shr_i64, { "r", "r", "ri" } }, + { INDEX_op_sar_i64, { "r", "r", "ri" } }, + + { INDEX_op_mul_i64, { "r", "r", "r" } }, + { INDEX_op_div_i64, { "r", "r", "r" } }, + { INDEX_op_divu_i64, { "r", "r", "r" } }, + { INDEX_op_rem_i64, { "r", "r", "r" } }, + { INDEX_op_remu_i64, { "r", "r", "r" } }, + + { INDEX_op_neg_i64, { "r", "r" } }, + + { INDEX_op_qemu_ld8u, { "r", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L" } }, + { INDEX_op_qemu_ld32s, { "r", "L" } }, + { INDEX_op_qemu_ld64, { "r", "L" } }, + + { INDEX_op_qemu_st8, { "S", "S" } }, + { INDEX_op_qemu_st16, { "S", "S" } }, + { INDEX_op_qemu_st32, { "S", "S" } }, + { INDEX_op_qemu_st64, { "S", "S", "S" } }, + + { INDEX_op_ext8s_i32, { "r", "r" } }, + { INDEX_op_ext16s_i32, { "r", "r" } }, + { INDEX_op_ext8s_i64, { "r", "r" } }, + { INDEX_op_ext16s_i64, { "r", "r" } }, + { INDEX_op_ext32s_i64, { "r", "r" } }, + + { -1 }, +}; + +void tcg_target_init (TCGContext *s) +{ + tcg_regset_set32 (tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff); + tcg_regset_set32 (tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff); + tcg_regset_set32 (tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_R0) | + (1 << TCG_REG_R3) | + (1 << TCG_REG_R4) | + (1 << TCG_REG_R5) | + (1 << TCG_REG_R6) | + (1 << TCG_REG_R7) | + (1 << TCG_REG_R8) | + (1 << TCG_REG_R9) | + (1 << TCG_REG_R10) | + (1 << TCG_REG_R11) | + (1 << TCG_REG_R12) + ); + + tcg_regset_clear (s->reserved_regs); + tcg_regset_set_reg (s->reserved_regs, TCG_REG_R0); + tcg_regset_set_reg (s->reserved_regs, TCG_REG_R1); + tcg_regset_set_reg (s->reserved_regs, TCG_REG_R2); + tcg_regset_set_reg (s->reserved_regs, TCG_REG_R13); + + tcg_add_target_add_op_defs (ppc_op_defs); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/ppc64/tcg-target.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/ppc64/tcg-target.h --- qemu-0.9.1/tcg/ppc64/tcg-target.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/ppc64/tcg-target.h 2008-07-24 23:56:21.000000000 +0100 @@ -0,0 +1,105 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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. + */ +#define TCG_TARGET_PPC64 1 + +#define TCG_TARGET_REG_BITS 64 +#define TCG_TARGET_WORDS_BIGENDIAN +#define TCG_TARGET_NB_REGS 32 + +enum { + TCG_REG_R0 = 0, + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + TCG_REG_R27, + TCG_REG_R28, + TCG_REG_R29, + TCG_REG_R30, + TCG_REG_R31 +}; + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_R1 +#define TCG_TARGET_STACK_ALIGN 16 +#define TCG_TARGET_CALL_STACK_OFFSET 48 + +/* optional instructions */ +#define TCG_TARGET_HAS_neg_i32 +#define TCG_TARGET_HAS_div_i32 +#define TCG_TARGET_HAS_neg_i64 +#define TCG_TARGET_HAS_div_i64 +#define TCG_TARGET_HAS_ext8s_i32 +#define TCG_TARGET_HAS_ext16s_i32 +#define TCG_TARGET_HAS_ext8s_i64 +#define TCG_TARGET_HAS_ext16s_i64 +#define TCG_TARGET_HAS_ext32s_i64 + +#define TCG_AREG0 TCG_REG_R27 +#define TCG_AREG1 TCG_REG_R24 +#define TCG_AREG2 TCG_REG_R25 +#define TCG_AREG3 TCG_REG_R26 + +/* taken directly from tcg-dyngen.c */ +#define MIN_CACHE_LINE_SIZE 8 /* conservative value */ + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + unsigned long p; + + start &= ~(MIN_CACHE_LINE_SIZE - 1); + stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1); + + for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { + asm volatile ("dcbst 0,%0" : : "r"(p) : "memory"); + } + asm volatile ("sync" : : : "memory"); + for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { + asm volatile ("icbi 0,%0" : : "r"(p) : "memory"); + } + asm volatile ("sync" : : : "memory"); + asm volatile ("isync" : : : "memory"); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/README /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/README --- qemu-0.9.1/tcg/README 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/README 2008-11-04 13:17:17.000000000 +0000 @@ -0,0 +1,466 @@ +Tiny Code Generator - Fabrice Bellard. + +1) Introduction + +TCG (Tiny Code Generator) began as a generic backend for a C +compiler. It was simplified to be used in QEMU. It also has its roots +in the QOP code generator written by Paul Brook. + +2) Definitions + +The TCG "target" is the architecture for which we generate the +code. It is of course not the same as the "target" of QEMU which is +the emulated architecture. As TCG started as a generic C backend used +for cross compiling, it is assumed that the TCG target is different +from the host, although it is never the case for QEMU. + +A TCG "function" corresponds to a QEMU Translated Block (TB). + +A TCG "temporary" is a variable only live in a basic +block. Temporaries are allocated explicitly in each function. + +A TCG "local temporary" is a variable only live in a function. Local +temporaries are allocated explicitly in each function. + +A TCG "global" is a variable which is live in all the functions +(equivalent of a C global variable). They are defined before the +functions defined. A TCG global can be a memory location (e.g. a QEMU +CPU register), a fixed host register (e.g. the QEMU CPU state pointer) +or a memory location which is stored in a register outside QEMU TBs +(not implemented yet). + +A TCG "basic block" corresponds to a list of instructions terminated +by a branch instruction. + +3) Intermediate representation + +3.1) Introduction + +TCG instructions operate on variables which are temporaries, local +temporaries or globals. TCG instructions and variables are strongly +typed. Two types are supported: 32 bit integers and 64 bit +integers. Pointers are defined as an alias to 32 bit or 64 bit +integers depending on the TCG target word size. + +Each instruction has a fixed number of output variable operands, input +variable operands and always constant operands. + +The notable exception is the call instruction which has a variable +number of outputs and inputs. + +In the textual form, output operands usually come first, followed by +input operands, followed by constant operands. The output type is +included in the instruction name. Constants are prefixed with a '$'. + +add_i32 t0, t1, t2 (t0 <- t1 + t2) + +3.2) Assumptions + +* Basic blocks + +- Basic blocks end after branches (e.g. brcond_i32 instruction), + goto_tb and exit_tb instructions. +- Basic blocks end before legacy dyngen operations. +- Basic blocks start after the end of a previous basic block, at a + set_label instruction or after a legacy dyngen operation. + +After the end of a basic block, the content of temporaries is +destroyed, but local temporaries and globals are preserved. + +* Floating point types are not supported yet + +* Pointers: depending on the TCG target, pointer size is 32 bit or 64 + bit. The type TCG_TYPE_PTR is an alias to TCG_TYPE_I32 or + TCG_TYPE_I64. + +* Helpers: + +Using the tcg_gen_helper_x_y it is possible to call any function +taking i32, i64 or pointer types. Before calling an helper, all +globals are stored at their canonical location and it is assumed that +the function can modify them. In the future, function modifiers will +be allowed to tell that the helper does not read or write some globals. + +On some TCG targets (e.g. x86), several calling conventions are +supported. + +* Branches: + +Use the instruction 'br' to jump to a label. Use 'jmp' to jump to an +explicit address. Conditional branches can only jump to labels. + +3.3) Code Optimizations + +When generating instructions, you can count on at least the following +optimizations: + +- Single instructions are simplified, e.g. + + and_i32 t0, t0, $0xffffffff + + is suppressed. + +- A liveness analysis is done at the basic block level. The + information is used to suppress moves from a dead variable to + another one. It is also used to remove instructions which compute + dead results. The later is especially useful for condition code + optimization in QEMU. + + In the following example: + + add_i32 t0, t1, t2 + add_i32 t0, t0, $1 + mov_i32 t0, $1 + + only the last instruction is kept. + +3.4) Instruction Reference + +********* Function call + +* call ptr + +call function 'ptr' (pointer type) + + optional 32 bit or 64 bit return value + optional 32 bit or 64 bit parameters + +********* Jumps/Labels + +* jmp t0 + +Absolute jump to address t0 (pointer type). + +* set_label $label + +Define label 'label' at the current program point. + +* br $label + +Jump to label. + +* brcond_i32/i64 cond, t0, t1, label + +Conditional jump if t0 cond t1 is true. cond can be: + TCG_COND_EQ + TCG_COND_NE + TCG_COND_LT /* signed */ + TCG_COND_GE /* signed */ + TCG_COND_LE /* signed */ + TCG_COND_GT /* signed */ + TCG_COND_LTU /* unsigned */ + TCG_COND_GEU /* unsigned */ + TCG_COND_LEU /* unsigned */ + TCG_COND_GTU /* unsigned */ + +********* Arithmetic + +* add_i32/i64 t0, t1, t2 + +t0=t1+t2 + +* sub_i32/i64 t0, t1, t2 + +t0=t1-t2 + +* neg_i32/i64 t0, t1 + +t0=-t1 (two's complement) + +* mul_i32/i64 t0, t1, t2 + +t0=t1*t2 + +* div_i32/i64 t0, t1, t2 + +t0=t1/t2 (signed). Undefined behavior if division by zero or overflow. + +* divu_i32/i64 t0, t1, t2 + +t0=t1/t2 (unsigned). Undefined behavior if division by zero. + +* rem_i32/i64 t0, t1, t2 + +t0=t1%t2 (signed). Undefined behavior if division by zero or overflow. + +* remu_i32/i64 t0, t1, t2 + +t0=t1%t2 (unsigned). Undefined behavior if division by zero. + +********* Logical + +* and_i32/i64 t0, t1, t2 + +t0=t1&t2 + +* or_i32/i64 t0, t1, t2 + +t0=t1|t2 + +* xor_i32/i64 t0, t1, t2 + +t0=t1^t2 + +* not_i32/i64 t0, t1 + +t0=~t1 + +* andc_i32/i64 t0, t1, t2 + +t0=t1&~t2 + +* eqv_i32/i64 t0, t1, t2 + +t0=~(t1^t2) + +* nand_i32/i64 t0, t1, t2 + +t0=~(t1&t2) + +* nor_i32/i64 t0, t1, t2 + +t0=~(t1|t2) + +* orc_i32/i64 t0, t1, t2 + +t0=t1|~t2 + +********* Shifts/Rotates + +* shl_i32/i64 t0, t1, t2 + +t0=t1 << t2. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64) + +* shr_i32/i64 t0, t1, t2 + +t0=t1 >> t2 (unsigned). Undefined behavior if t2 < 0 or t2 >= 32 (resp 64) + +* sar_i32/i64 t0, t1, t2 + +t0=t1 >> t2 (signed). Undefined behavior if t2 < 0 or t2 >= 32 (resp 64) + +* rotl_i32/i64 t0, t1, t2 + +Rotation of t2 bits to the left. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64) + +* rotr_i32/i64 t0, t1, t2 + +Rotation of t2 bits to the right. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64) + +********* Misc + +* mov_i32/i64 t0, t1 + +t0 = t1 + +Move t1 to t0 (both operands must have the same type). + +* ext8s_i32/i64 t0, t1 +ext8u_i32/i64 t0, t1 +ext16s_i32/i64 t0, t1 +ext16u_i32/i64 t0, t1 +ext32s_i64 t0, t1 +ext32u_i64 t0, t1 + +8, 16 or 32 bit sign/zero extension (both operands must have the same type) + +* bswap16_i32 t0, t1 + +16 bit byte swap on a 32 bit value. The two high order bytes must be set +to zero. + +* bswap_i32 t0, t1 + +32 bit byte swap + +* bswap_i64 t0, t1 + +64 bit byte swap + +* discard_i32/i64 t0 + +Indicate that the value of t0 won't be used later. It is useful to +force dead code elimination. + +********* Type conversions + +* ext_i32_i64 t0, t1 +Convert t1 (32 bit) to t0 (64 bit) and does sign extension + +* extu_i32_i64 t0, t1 +Convert t1 (32 bit) to t0 (64 bit) and does zero extension + +* trunc_i64_i32 t0, t1 +Truncate t1 (64 bit) to t0 (32 bit) + +* concat_i32_i64 t0, t1, t2 +Construct t0 (64-bit) taking the low half from t1 (32 bit) and the high half +from t2 (32 bit). + +* concat32_i64 t0, t1, t2 +Construct t0 (64-bit) taking the low half from t1 (64 bit) and the high half +from t2 (64 bit). + +********* Load/Store + +* ld_i32/i64 t0, t1, offset +ld8s_i32/i64 t0, t1, offset +ld8u_i32/i64 t0, t1, offset +ld16s_i32/i64 t0, t1, offset +ld16u_i32/i64 t0, t1, offset +ld32s_i64 t0, t1, offset +ld32u_i64 t0, t1, offset + +t0 = read(t1 + offset) +Load 8, 16, 32 or 64 bits with or without sign extension from host memory. +offset must be a constant. + +* st_i32/i64 t0, t1, offset +st8_i32/i64 t0, t1, offset +st16_i32/i64 t0, t1, offset +st32_i64 t0, t1, offset + +write(t0, t1 + offset) +Write 8, 16, 32 or 64 bits to host memory. + +********* QEMU specific operations + +* tb_exit t0 + +Exit the current TB and return the value t0 (word type). + +* goto_tb index + +Exit the current TB and jump to the TB index 'index' (constant) if the +current TB was linked to this TB. Otherwise execute the next +instructions. + +* qemu_ld_i32/i64 t0, t1, flags +qemu_ld8u_i32/i64 t0, t1, flags +qemu_ld8s_i32/i64 t0, t1, flags +qemu_ld16u_i32/i64 t0, t1, flags +qemu_ld16s_i32/i64 t0, t1, flags +qemu_ld32u_i64 t0, t1, flags +qemu_ld32s_i64 t0, t1, flags + +Load data at the QEMU CPU address t1 into t0. t1 has the QEMU CPU +address type. 'flags' contains the QEMU memory index (selects user or +kernel access) for example. + +* qemu_st_i32/i64 t0, t1, flags +qemu_st8_i32/i64 t0, t1, flags +qemu_st16_i32/i64 t0, t1, flags +qemu_st32_i64 t0, t1, flags + +Store the data t0 at the QEMU CPU Address t1. t1 has the QEMU CPU +address type. 'flags' contains the QEMU memory index (selects user or +kernel access) for example. + +Note 1: Some shortcuts are defined when the last operand is known to be +a constant (e.g. addi for add, movi for mov). + +Note 2: When using TCG, the opcodes must never be generated directly +as some of them may not be available as "real" opcodes. Always use the +function tcg_gen_xxx(args). + +4) Backend + +tcg-target.h contains the target specific definitions. tcg-target.c +contains the target specific code. + +4.1) Assumptions + +The target word size (TCG_TARGET_REG_BITS) is expected to be 32 bit or +64 bit. It is expected that the pointer has the same size as the word. + +On a 32 bit target, all 64 bit operations are converted to 32 bits. A +few specific operations must be implemented to allow it (see add2_i32, +sub2_i32, brcond2_i32). + +Floating point operations are not supported in this version. A +previous incarnation of the code generator had full support of them, +but it is better to concentrate on integer operations first. + +On a 64 bit target, no assumption is made in TCG about the storage of +the 32 bit values in 64 bit registers. + +4.2) Constraints + +GCC like constraints are used to define the constraints of every +instruction. Memory constraints are not supported in this +version. Aliases are specified in the input operands as for GCC. + +The same register may be used for both an input and an output, even when +they are not explicitly aliased. If an op expands to multiple target +instructions then care must be taken to avoid clobbering input values. +GCC style "early clobber" outputs are not currently supported. + +A target can define specific register or constant constraints. If an +operation uses a constant input constraint which does not allow all +constants, it must also accept registers in order to have a fallback. + +The movi_i32 and movi_i64 operations must accept any constants. + +The mov_i32 and mov_i64 operations must accept any registers of the +same type. + +The ld/st instructions must accept signed 32 bit constant offsets. It +can be implemented by reserving a specific register to compute the +address if the offset is too big. + +The ld/st instructions must accept any destination (ld) or source (st) +register. + +4.3) Function call assumptions + +- The only supported types for parameters and return value are: 32 and + 64 bit integers and pointer. +- The stack grows downwards. +- The first N parameters are passed in registers. +- The next parameters are passed on the stack by storing them as words. +- Some registers are clobbered during the call. +- The function can return 0 or 1 value in registers. On a 32 bit + target, functions must be able to return 2 values in registers for + 64 bit return type. + +5) Migration from dyngen to TCG + +TCG is backward compatible with QEMU "dyngen" operations. It means +that TCG instructions can be freely mixed with dyngen operations. It +is expected that QEMU targets will be progressively fully converted to +TCG. Once a target is fully converted to TCG, it will be possible +to apply more optimizations because more registers will be free for +the generated code. + +The exception model is the same as the dyngen one. + +6) Recommended coding rules for best performance + +- Use globals to represent the parts of the QEMU CPU state which are + often modified, e.g. the integer registers and the condition + codes. TCG will be able to use host registers to store them. + +- Avoid globals stored in fixed registers. They must be used only to + store the pointer to the CPU state and possibly to store a pointer + to a register window. The other uses are to ensure backward + compatibility with dyngen during the porting a new target to TCG. + +- Use temporaries. Use local temporaries only when really needed, + e.g. when you need to use a value after a jump. Local temporaries + introduce a performance hit in the current TCG implementation: their + content is saved to memory at end of each basic block. + +- Free temporaries and local temporaries when they are no longer used + (tcg_temp_free). Since tcg_const_x() also creates a temporary, you + should free it after it is used. Freeing temporaries does not yield + a better generated code, but it reduces the memory usage of TCG and + the speed of the translation. + +- Don't hesitate to use helpers for complicated or seldom used target + intructions. There is little performance advantage in using TCG to + implement target instructions taking more than about twenty TCG + instructions. + +- Use the 'discard' instruction if you know that TCG won't be able to + prove that a given global is "dead" at a given program point. The + x86 target uses it to improve the condition codes optimisation. diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/sparc/tcg-target.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/sparc/tcg-target.c --- qemu-0.9.1/tcg/sparc/tcg-target.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/sparc/tcg-target.c 2008-10-05 10:59:14.000000000 +0100 @@ -0,0 +1,1208 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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. + */ + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "%g0", + "%g1", + "%g2", + "%g3", + "%g4", + "%g5", + "%g6", + "%g7", + "%o0", + "%o1", + "%o2", + "%o3", + "%o4", + "%o5", + "%o6", + "%o7", + "%l0", + "%l1", + "%l2", + "%l3", + "%l4", + "%l5", + "%l6", + "%l7", + "%i0", + "%i1", + "%i2", + "%i3", + "%i4", + "%i5", + "%i6", + "%i7", +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_L0, + TCG_REG_L1, + TCG_REG_L2, + TCG_REG_L3, + TCG_REG_L4, + TCG_REG_L5, + TCG_REG_L6, + TCG_REG_L7, + TCG_REG_I0, + TCG_REG_I1, + TCG_REG_I2, + TCG_REG_I3, + TCG_REG_I4, +}; + +static const int tcg_target_call_iarg_regs[6] = { + TCG_REG_O0, + TCG_REG_O1, + TCG_REG_O2, + TCG_REG_O3, + TCG_REG_O4, + TCG_REG_O5, +}; + +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_O0, + TCG_REG_O1, +}; + +static inline int check_fit_tl(tcg_target_long val, unsigned int bits) +{ + return (val << ((sizeof(tcg_target_long) * 8 - bits)) + >> (sizeof(tcg_target_long) * 8 - bits)) == val; +} + +static inline int check_fit_i32(uint32_t val, unsigned int bits) +{ + return ((val << (32 - bits)) >> (32 - bits)) == val; +} + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + value += addend; + switch (type) { + case R_SPARC_32: + if (value != (uint32_t)value) + tcg_abort(); + *(uint32_t *)code_ptr = value; + break; + case R_SPARC_WDISP22: + value -= (long)code_ptr; + value >>= 2; + if (!check_fit_tl(value, 22)) + tcg_abort(); + *(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x3fffff) | value; + break; + default: + tcg_abort(); + } +} + +/* maximum number of register used for input function arguments */ +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + return 6; +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch (ct_str[0]) { + case 'r': + case 'L': /* qemu_ld/st constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + // Helper args + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O1); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O2); + break; + case 'I': + ct->ct |= TCG_CT_CONST_S11; + break; + case 'J': + ct->ct |= TCG_CT_CONST_S13; + break; + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + else if ((ct & TCG_CT_CONST_S11) && check_fit_tl(val, 11)) + return 1; + else if ((ct & TCG_CT_CONST_S13) && check_fit_tl(val, 13)) + return 1; + else + return 0; +} + +#define INSN_OP(x) ((x) << 30) +#define INSN_OP2(x) ((x) << 22) +#define INSN_OP3(x) ((x) << 19) +#define INSN_OPF(x) ((x) << 5) +#define INSN_RD(x) ((x) << 25) +#define INSN_RS1(x) ((x) << 14) +#define INSN_RS2(x) (x) +#define INSN_ASI(x) ((x) << 5) + +#define INSN_IMM13(x) ((1 << 13) | ((x) & 0x1fff)) +#define INSN_OFF22(x) (((x) >> 2) & 0x3fffff) + +#define INSN_COND(x, a) (((x) << 25) | ((a) << 29)) +#define COND_N 0x0 +#define COND_E 0x1 +#define COND_LE 0x2 +#define COND_L 0x3 +#define COND_LEU 0x4 +#define COND_CS 0x5 +#define COND_NEG 0x6 +#define COND_VS 0x7 +#define COND_A 0x8 +#define COND_NE 0x9 +#define COND_G 0xa +#define COND_GE 0xb +#define COND_GU 0xc +#define COND_CC 0xd +#define COND_POS 0xe +#define COND_VC 0xf +#define BA (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2)) + +#define ARITH_ADD (INSN_OP(2) | INSN_OP3(0x00)) +#define ARITH_AND (INSN_OP(2) | INSN_OP3(0x01)) +#define ARITH_OR (INSN_OP(2) | INSN_OP3(0x02)) +#define ARITH_ORCC (INSN_OP(2) | INSN_OP3(0x12)) +#define ARITH_XOR (INSN_OP(2) | INSN_OP3(0x03)) +#define ARITH_SUB (INSN_OP(2) | INSN_OP3(0x04)) +#define ARITH_SUBCC (INSN_OP(2) | INSN_OP3(0x14)) +#define ARITH_ADDX (INSN_OP(2) | INSN_OP3(0x10)) +#define ARITH_SUBX (INSN_OP(2) | INSN_OP3(0x0c)) +#define ARITH_UMUL (INSN_OP(2) | INSN_OP3(0x0a)) +#define ARITH_UDIV (INSN_OP(2) | INSN_OP3(0x0e)) +#define ARITH_SDIV (INSN_OP(2) | INSN_OP3(0x0f)) +#define ARITH_MULX (INSN_OP(2) | INSN_OP3(0x09)) +#define ARITH_UDIVX (INSN_OP(2) | INSN_OP3(0x0d)) +#define ARITH_SDIVX (INSN_OP(2) | INSN_OP3(0x2d)) + +#define SHIFT_SLL (INSN_OP(2) | INSN_OP3(0x25)) +#define SHIFT_SRL (INSN_OP(2) | INSN_OP3(0x26)) +#define SHIFT_SRA (INSN_OP(2) | INSN_OP3(0x27)) + +#define SHIFT_SLLX (INSN_OP(2) | INSN_OP3(0x25) | (1 << 12)) +#define SHIFT_SRLX (INSN_OP(2) | INSN_OP3(0x26) | (1 << 12)) +#define SHIFT_SRAX (INSN_OP(2) | INSN_OP3(0x27) | (1 << 12)) + +#define WRY (INSN_OP(2) | INSN_OP3(0x30)) +#define JMPL (INSN_OP(2) | INSN_OP3(0x38)) +#define SAVE (INSN_OP(2) | INSN_OP3(0x3c)) +#define RESTORE (INSN_OP(2) | INSN_OP3(0x3d)) +#define SETHI (INSN_OP(0) | INSN_OP2(0x4)) +#define CALL INSN_OP(1) +#define LDUB (INSN_OP(3) | INSN_OP3(0x01)) +#define LDSB (INSN_OP(3) | INSN_OP3(0x09)) +#define LDUH (INSN_OP(3) | INSN_OP3(0x02)) +#define LDSH (INSN_OP(3) | INSN_OP3(0x0a)) +#define LDUW (INSN_OP(3) | INSN_OP3(0x00)) +#define LDSW (INSN_OP(3) | INSN_OP3(0x08)) +#define LDX (INSN_OP(3) | INSN_OP3(0x0b)) +#define STB (INSN_OP(3) | INSN_OP3(0x05)) +#define STH (INSN_OP(3) | INSN_OP3(0x06)) +#define STW (INSN_OP(3) | INSN_OP3(0x04)) +#define STX (INSN_OP(3) | INSN_OP3(0x0e)) +#define LDUBA (INSN_OP(3) | INSN_OP3(0x11)) +#define LDSBA (INSN_OP(3) | INSN_OP3(0x19)) +#define LDUHA (INSN_OP(3) | INSN_OP3(0x12)) +#define LDSHA (INSN_OP(3) | INSN_OP3(0x1a)) +#define LDUWA (INSN_OP(3) | INSN_OP3(0x10)) +#define LDSWA (INSN_OP(3) | INSN_OP3(0x18)) +#define LDXA (INSN_OP(3) | INSN_OP3(0x1b)) +#define STBA (INSN_OP(3) | INSN_OP3(0x15)) +#define STHA (INSN_OP(3) | INSN_OP3(0x16)) +#define STWA (INSN_OP(3) | INSN_OP3(0x14)) +#define STXA (INSN_OP(3) | INSN_OP3(0x1e)) + +#ifndef ASI_PRIMARY_LITTLE +#define ASI_PRIMARY_LITTLE 0x88 +#endif + +static inline void tcg_out_arith(TCGContext *s, int rd, int rs1, int rs2, + int op) +{ + tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) | + INSN_RS2(rs2)); +} + +static inline void tcg_out_arithi(TCGContext *s, int rd, int rs1, + uint32_t offset, int op) +{ + tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) | + INSN_IMM13(offset)); +} + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + tcg_out_arith(s, ret, arg, TCG_REG_G0, ARITH_OR); +} + +static inline void tcg_out_sethi(TCGContext *s, int ret, uint32_t arg) +{ + tcg_out32(s, SETHI | INSN_RD(ret) | ((arg & 0xfffffc00) >> 10)); +} + +static inline void tcg_out_movi_imm13(TCGContext *s, int ret, uint32_t arg) +{ + tcg_out_arithi(s, ret, TCG_REG_G0, arg, ARITH_OR); +} + +static inline void tcg_out_movi_imm32(TCGContext *s, int ret, uint32_t arg) +{ + if (check_fit_tl(arg, 12)) + tcg_out_movi_imm13(s, ret, arg); + else { + tcg_out_sethi(s, ret, arg); + if (arg & 0x3ff) + tcg_out_arithi(s, ret, ret, arg & 0x3ff, ARITH_OR); + } +} + +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ +#if defined(__sparc_v9__) && !defined(__sparc_v8plus__) + if (!check_fit_tl(arg, 32) && (arg & ~0xffffffffULL) != 0) { + tcg_out_movi_imm32(s, TCG_REG_I4, arg >> 32); + tcg_out_arithi(s, TCG_REG_I4, TCG_REG_I4, 32, SHIFT_SLLX); + tcg_out_movi_imm32(s, ret, arg); + tcg_out_arith(s, ret, ret, TCG_REG_I4, ARITH_OR); + } else if (check_fit_tl(arg, 12)) + tcg_out_movi_imm13(s, ret, arg); + else { + tcg_out_sethi(s, ret, arg); + if (arg & 0x3ff) + tcg_out_arithi(s, ret, ret, arg & 0x3ff, ARITH_OR); + } +#else + tcg_out_movi_imm32(s, ret, arg); +#endif +} + +static inline void tcg_out_ld_raw(TCGContext *s, int ret, + tcg_target_long arg) +{ + tcg_out_sethi(s, ret, arg); + tcg_out32(s, LDUW | INSN_RD(ret) | INSN_RS1(ret) | + INSN_IMM13(arg & 0x3ff)); +} + +static inline void tcg_out_ld_ptr(TCGContext *s, int ret, + tcg_target_long arg) +{ + if (!check_fit_tl(arg, 10)) + tcg_out_movi(s, TCG_TYPE_PTR, ret, arg & ~0x3ffULL); +#if defined(__sparc_v9__) && !defined(__sparc_v8plus__) + tcg_out32(s, LDX | INSN_RD(ret) | INSN_RS1(ret) | + INSN_IMM13(arg & 0x3ff)); +#else + tcg_out32(s, LDUW | INSN_RD(ret) | INSN_RS1(ret) | + INSN_IMM13(arg & 0x3ff)); +#endif +} + +static inline void tcg_out_ldst(TCGContext *s, int ret, int addr, int offset, int op) +{ + if (check_fit_tl(offset, 13)) + tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(addr) | + INSN_IMM13(offset)); + else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, offset); + tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(TCG_REG_I5) | + INSN_RS2(addr)); + } +} + +static inline void tcg_out_ldst_asi(TCGContext *s, int ret, int addr, + int offset, int op, int asi) +{ + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, offset); + tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(TCG_REG_I5) | + INSN_ASI(asi) | INSN_RS2(addr)); +} + +static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret, + int arg1, tcg_target_long arg2) +{ + if (type == TCG_TYPE_I32) + tcg_out_ldst(s, ret, arg1, arg2, LDUW); + else + tcg_out_ldst(s, ret, arg1, arg2, LDX); +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + if (type == TCG_TYPE_I32) + tcg_out_ldst(s, arg, arg1, arg2, STW); + else + tcg_out_ldst(s, arg, arg1, arg2, STX); +} + +static inline void tcg_out_sety(TCGContext *s, tcg_target_long val) +{ + if (val == 0 || val == -1) + tcg_out32(s, WRY | INSN_IMM13(val)); + else + fprintf(stderr, "unimplemented sety %ld\n", (long)val); +} + +static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + if (val != 0) { + if (check_fit_tl(val, 13)) + tcg_out_arithi(s, reg, reg, val, ARITH_ADD); + else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, val); + tcg_out_arith(s, reg, reg, TCG_REG_I5, ARITH_ADD); + } + } +} + +static inline void tcg_out_andi(TCGContext *s, int reg, tcg_target_long val) +{ + if (val != 0) { + if (check_fit_tl(val, 13)) + tcg_out_arithi(s, reg, reg, val, ARITH_AND); + else { + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, val); + tcg_out_arith(s, reg, reg, TCG_REG_I5, ARITH_AND); + } + } +} + +static inline void tcg_out_nop(TCGContext *s) +{ + tcg_out_sethi(s, TCG_REG_G0, 0); +} + +static void tcg_out_branch(TCGContext *s, int opc, int label_index) +{ + int32_t val; + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) { + val = l->u.value - (tcg_target_long)s->code_ptr; + tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2) + | INSN_OFF22(l->u.value - (unsigned long)s->code_ptr))); + } else { + tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP22, label_index, 0); + tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2) | 0)); + } +} + +static const uint8_t tcg_cond_to_bcond[10] = { + [TCG_COND_EQ] = COND_E, + [TCG_COND_NE] = COND_NE, + [TCG_COND_LT] = COND_L, + [TCG_COND_GE] = COND_GE, + [TCG_COND_LE] = COND_LE, + [TCG_COND_GT] = COND_G, + [TCG_COND_LTU] = COND_CS, + [TCG_COND_GEU] = COND_CC, + [TCG_COND_LEU] = COND_LEU, + [TCG_COND_GTU] = COND_GU, +}; + +static void tcg_out_brcond(TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index) +{ + if (const_arg2 && arg2 == 0) + /* orcc %g0, r, %g0 */ + tcg_out_arith(s, TCG_REG_G0, TCG_REG_G0, arg1, ARITH_ORCC); + else + /* subcc r1, r2, %g0 */ + tcg_out_arith(s, TCG_REG_G0, arg1, arg2, ARITH_SUBCC); + tcg_out_branch(s, tcg_cond_to_bcond[cond], label_index); + tcg_out_nop(s); +} + +/* Generate global QEMU prologue and epilogue code */ +void tcg_target_qemu_prologue(TCGContext *s) +{ + tcg_out32(s, SAVE | INSN_RD(TCG_REG_O6) | INSN_RS1(TCG_REG_O6) | + INSN_IMM13(-TCG_TARGET_STACK_MINFRAME)); + tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I0) | + INSN_RS2(TCG_REG_G0)); + tcg_out_nop(s); +} + +#if defined(CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static const void * const qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static const void * const qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +#if TARGET_LONG_BITS == 32 +#define TARGET_LD_OP LDUW +#else +#define TARGET_LD_OP LDX +#endif + +#if TARGET_PHYS_ADDR_BITS == 32 +#define TARGET_ADDEND_LD_OP LDUW +#else +#define TARGET_ADDEND_LD_OP LDX +#endif + +#ifdef __arch64__ +#define HOST_LD_OP LDX +#define HOST_ST_OP STX +#define HOST_SLL_OP SHIFT_SLLX +#define HOST_SRA_OP SHIFT_SRAX +#else +#define HOST_LD_OP LDUW +#define HOST_ST_OP STW +#define HOST_SLL_OP SHIFT_SLL +#define HOST_SRA_OP SHIFT_SRA +#endif + +static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, arg0, arg1, arg2, mem_index, s_bits; +#if defined(CONFIG_SOFTMMU) + uint32_t *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + s_bits = opc & 3; + + arg0 = TCG_REG_O0; + arg1 = TCG_REG_O1; + arg2 = TCG_REG_O2; + +#if defined(CONFIG_SOFTMMU) + /* srl addr_reg, x, arg1 */ + tcg_out_arithi(s, arg1, addr_reg, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS, + SHIFT_SRL); + /* and addr_reg, x, arg0 */ + tcg_out_arithi(s, arg0, addr_reg, TARGET_PAGE_MASK | ((1 << s_bits) - 1), + ARITH_AND); + + /* and arg1, x, arg1 */ + tcg_out_andi(s, arg1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + + /* add arg1, x, arg1 */ + tcg_out_addi(s, arg1, offsetof(CPUState, + tlb_table[mem_index][0].addr_read)); + + /* add env, arg1, arg1 */ + tcg_out_arith(s, arg1, TCG_AREG0, arg1, ARITH_ADD); + + /* ld [arg1], arg2 */ + tcg_out32(s, TARGET_LD_OP | INSN_RD(arg2) | INSN_RS1(arg1) | + INSN_RS2(TCG_REG_G0)); + + /* subcc arg0, arg2, %g0 */ + tcg_out_arith(s, TCG_REG_G0, arg0, arg2, ARITH_SUBCC); + + /* will become: + be label1 */ + label1_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, 0); + + /* mov (delay slot) */ + tcg_out_mov(s, arg0, addr_reg); + + /* mov */ + tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index); + + /* XXX: move that code at the end of the TB */ + /* qemu_ld_helper[s_bits](arg0, arg1) */ + tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_ld_helpers[s_bits] + - (tcg_target_ulong)s->code_ptr) >> 2) + & 0x3fffffff)); + /* Store AREG0 in stack to avoid ugly glibc bugs that mangle + global registers */ + // delay slot + tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_ST_OP); + tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_LD_OP); + + /* data_reg = sign_extend(arg0) */ + switch(opc) { + case 0 | 4: + /* sll arg0, 24/56, data_reg */ + tcg_out_arithi(s, data_reg, arg0, (int)sizeof(tcg_target_long) * 8 - 8, + HOST_SLL_OP); + /* sra data_reg, 24/56, data_reg */ + tcg_out_arithi(s, data_reg, data_reg, + (int)sizeof(tcg_target_long) * 8 - 8, HOST_SRA_OP); + break; + case 1 | 4: + /* sll arg0, 16/48, data_reg */ + tcg_out_arithi(s, data_reg, arg0, + (int)sizeof(tcg_target_long) * 8 - 16, HOST_SLL_OP); + /* sra data_reg, 16/48, data_reg */ + tcg_out_arithi(s, data_reg, data_reg, + (int)sizeof(tcg_target_long) * 8 - 16, HOST_SRA_OP); + break; + case 2 | 4: + /* sll arg0, 32, data_reg */ + tcg_out_arithi(s, data_reg, arg0, 32, HOST_SLL_OP); + /* sra data_reg, 32, data_reg */ + tcg_out_arithi(s, data_reg, data_reg, 32, HOST_SRA_OP); + break; + case 0: + case 1: + case 2: + case 3: + default: + /* mov */ + tcg_out_mov(s, data_reg, arg0); + break; + } + + /* will become: + ba label2 */ + label2_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, 0); + + /* nop (delay slot */ + tcg_out_nop(s); + + /* label1: */ + *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x2) | + INSN_OFF22((unsigned long)s->code_ptr - + (unsigned long)label1_ptr)); + + /* ld [arg1 + x], arg1 */ + tcg_out_ldst(s, arg1, arg1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_read), TARGET_ADDEND_LD_OP); + +#if TARGET_LONG_BITS == 32 + /* and addr_reg, x, arg0 */ + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, 0xffffffff); + tcg_out_arith(s, arg0, addr_reg, TCG_REG_I5, ARITH_AND); + /* add arg0, arg1, arg0 */ + tcg_out_arith(s, arg0, arg0, arg1, ARITH_ADD); +#else + /* add addr_reg, arg1, arg0 */ + tcg_out_arith(s, arg0, addr_reg, arg1, ARITH_ADD); +#endif + +#else + arg0 = addr_reg; +#endif + + switch(opc) { + case 0: + /* ldub [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDUB); + break; + case 0 | 4: + /* ldsb [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDSB); + break; + case 1: +#ifdef TARGET_WORDS_BIGENDIAN + /* lduh [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDUH); +#else + /* lduha [arg0] ASI_PRIMARY_LITTLE, data_reg */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, LDUHA, ASI_PRIMARY_LITTLE); +#endif + break; + case 1 | 4: +#ifdef TARGET_WORDS_BIGENDIAN + /* ldsh [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDSH); +#else + /* ldsha [arg0] ASI_PRIMARY_LITTLE, data_reg */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, LDSHA, ASI_PRIMARY_LITTLE); +#endif + break; + case 2: +#ifdef TARGET_WORDS_BIGENDIAN + /* lduw [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDUW); +#else + /* lduwa [arg0] ASI_PRIMARY_LITTLE, data_reg */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, LDUWA, ASI_PRIMARY_LITTLE); +#endif + break; + case 2 | 4: +#ifdef TARGET_WORDS_BIGENDIAN + /* ldsw [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDSW); +#else + /* ldswa [arg0] ASI_PRIMARY_LITTLE, data_reg */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, LDSWA, ASI_PRIMARY_LITTLE); +#endif + break; + case 3: +#ifdef TARGET_WORDS_BIGENDIAN + /* ldx [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDX); +#else + /* ldxa [arg0] ASI_PRIMARY_LITTLE, data_reg */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, LDXA, ASI_PRIMARY_LITTLE); +#endif + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2) | + INSN_OFF22((unsigned long)s->code_ptr - + (unsigned long)label2_ptr)); +#endif +} + +static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, arg0, arg1, arg2, mem_index, s_bits; +#if defined(CONFIG_SOFTMMU) + uint32_t *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + + s_bits = opc; + + arg0 = TCG_REG_O0; + arg1 = TCG_REG_O1; + arg2 = TCG_REG_O2; + +#if defined(CONFIG_SOFTMMU) + /* srl addr_reg, x, arg1 */ + tcg_out_arithi(s, arg1, addr_reg, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS, + SHIFT_SRL); + + /* and addr_reg, x, arg0 */ + tcg_out_arithi(s, arg0, addr_reg, TARGET_PAGE_MASK | ((1 << s_bits) - 1), + ARITH_AND); + + /* and arg1, x, arg1 */ + tcg_out_andi(s, arg1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + + /* add arg1, x, arg1 */ + tcg_out_addi(s, arg1, offsetof(CPUState, + tlb_table[mem_index][0].addr_write)); + + /* add env, arg1, arg1 */ + tcg_out_arith(s, arg1, TCG_AREG0, arg1, ARITH_ADD); + + /* ld [arg1], arg2 */ + tcg_out32(s, TARGET_LD_OP | INSN_RD(arg2) | INSN_RS1(arg1) | + INSN_RS2(TCG_REG_G0)); + + /* subcc arg0, arg2, %g0 */ + tcg_out_arith(s, TCG_REG_G0, arg0, arg2, ARITH_SUBCC); + + /* will become: + be label1 */ + label1_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, 0); + + /* mov (delay slot) */ + tcg_out_mov(s, arg0, addr_reg); + + /* mov */ + tcg_out_mov(s, arg1, data_reg); + + /* mov */ + tcg_out_movi(s, TCG_TYPE_I32, arg2, mem_index); + + /* XXX: move that code at the end of the TB */ + /* qemu_st_helper[s_bits](arg0, arg1, arg2) */ + tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_st_helpers[s_bits] + - (tcg_target_ulong)s->code_ptr) >> 2) + & 0x3fffffff)); + /* Store AREG0 in stack to avoid ugly glibc bugs that mangle + global registers */ + // delay slot + tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_ST_OP); + tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_LD_OP); + + /* will become: + ba label2 */ + label2_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, 0); + + /* nop (delay slot) */ + tcg_out_nop(s); + + /* label1: */ + *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x2) | + INSN_OFF22((unsigned long)s->code_ptr - + (unsigned long)label1_ptr)); + + /* ld [arg1 + x], arg1 */ + tcg_out_ldst(s, arg1, arg1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_write), TARGET_ADDEND_LD_OP); + +#if TARGET_LONG_BITS == 32 + /* and addr_reg, x, arg0 */ + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, 0xffffffff); + tcg_out_arith(s, arg0, addr_reg, TCG_REG_I5, ARITH_AND); + /* add arg0, arg1, arg0 */ + tcg_out_arith(s, arg0, arg0, arg1, ARITH_ADD); +#else + /* add addr_reg, arg1, arg0 */ + tcg_out_arith(s, arg0, addr_reg, arg1, ARITH_ADD); +#endif + +#else + arg0 = addr_reg; +#endif + + switch(opc) { + case 0: + /* stb data_reg, [arg0] */ + tcg_out_ldst(s, data_reg, arg0, 0, STB); + break; + case 1: +#ifdef TARGET_WORDS_BIGENDIAN + /* sth data_reg, [arg0] */ + tcg_out_ldst(s, data_reg, arg0, 0, STH); +#else + /* stha data_reg, [arg0] ASI_PRIMARY_LITTLE */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, STHA, ASI_PRIMARY_LITTLE); +#endif + break; + case 2: +#ifdef TARGET_WORDS_BIGENDIAN + /* stw data_reg, [arg0] */ + tcg_out_ldst(s, data_reg, arg0, 0, STW); +#else + /* stwa data_reg, [arg0] ASI_PRIMARY_LITTLE */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, STWA, ASI_PRIMARY_LITTLE); +#endif + break; + case 3: +#ifdef TARGET_WORDS_BIGENDIAN + /* stx data_reg, [arg0] */ + tcg_out_ldst(s, data_reg, arg0, 0, STX); +#else + /* stxa data_reg, [arg0] ASI_PRIMARY_LITTLE */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, STXA, ASI_PRIMARY_LITTLE); +#endif + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2) | + INSN_OFF22((unsigned long)s->code_ptr - + (unsigned long)label2_ptr)); +#endif +} + +static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, + const int *const_args) +{ + int c; + + switch (opc) { + case INDEX_op_exit_tb: + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I0, args[0]); + tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I7) | + INSN_IMM13(8)); + tcg_out32(s, RESTORE | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_G0) | + INSN_RS2(TCG_REG_G0)); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + tcg_out_sethi(s, TCG_REG_I5, args[0] & 0xffffe000); + tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I5) | + INSN_IMM13((args[0] & 0x1fff))); + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + } else { + /* indirect jump method */ + tcg_out_ld_ptr(s, TCG_REG_I5, (tcg_target_long)(s->tb_next + args[0])); + tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I5) | + INSN_RS2(TCG_REG_G0)); + } + tcg_out_nop(s); + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_call: + if (const_args[0]) + tcg_out32(s, CALL | ((((tcg_target_ulong)args[0] + - (tcg_target_ulong)s->code_ptr) >> 2) + & 0x3fffffff)); + else { + tcg_out_ld_ptr(s, TCG_REG_I5, + (tcg_target_long)(s->tb_next + args[0])); + tcg_out32(s, JMPL | INSN_RD(TCG_REG_O7) | INSN_RS1(TCG_REG_I5) | + INSN_RS2(TCG_REG_G0)); + } + /* Store AREG0 in stack to avoid ugly glibc bugs that mangle + global registers */ + // delay slot + tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_ST_OP); + tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_LD_OP); + break; + case INDEX_op_jmp: + case INDEX_op_br: + tcg_out_branch(s, COND_A, args[0]); + tcg_out_nop(s); + break; + case INDEX_op_movi_i32: + tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]); + break; + +#if defined(__sparc_v9__) && !defined(__sparc_v8plus__) +#define OP_32_64(x) \ + glue(glue(case INDEX_op_, x), _i32:) \ + glue(glue(case INDEX_op_, x), _i64:) +#else +#define OP_32_64(x) \ + glue(glue(case INDEX_op_, x), _i32:) +#endif + OP_32_64(ld8u); + tcg_out_ldst(s, args[0], args[1], args[2], LDUB); + break; + OP_32_64(ld8s); + tcg_out_ldst(s, args[0], args[1], args[2], LDSB); + break; + OP_32_64(ld16u); + tcg_out_ldst(s, args[0], args[1], args[2], LDUH); + break; + OP_32_64(ld16s); + tcg_out_ldst(s, args[0], args[1], args[2], LDSH); + break; + case INDEX_op_ld_i32: +#if defined(__sparc_v9__) && !defined(__sparc_v8plus__) + case INDEX_op_ld32u_i64: +#endif + tcg_out_ldst(s, args[0], args[1], args[2], LDUW); + break; + OP_32_64(st8); + tcg_out_ldst(s, args[0], args[1], args[2], STB); + break; + OP_32_64(st16); + tcg_out_ldst(s, args[0], args[1], args[2], STH); + break; + case INDEX_op_st_i32: +#if defined(__sparc_v9__) && !defined(__sparc_v8plus__) + case INDEX_op_st32_i64: +#endif + tcg_out_ldst(s, args[0], args[1], args[2], STW); + break; + OP_32_64(add); + c = ARITH_ADD; + goto gen_arith32; + OP_32_64(sub); + c = ARITH_SUB; + goto gen_arith32; + OP_32_64(and); + c = ARITH_AND; + goto gen_arith32; + OP_32_64(or); + c = ARITH_OR; + goto gen_arith32; + OP_32_64(xor); + c = ARITH_XOR; + goto gen_arith32; + case INDEX_op_shl_i32: + c = SHIFT_SLL; + goto gen_arith32; + case INDEX_op_shr_i32: + c = SHIFT_SRL; + goto gen_arith32; + case INDEX_op_sar_i32: + c = SHIFT_SRA; + goto gen_arith32; + case INDEX_op_mul_i32: + c = ARITH_UMUL; + goto gen_arith32; + case INDEX_op_div2_i32: +#if defined(__sparc_v9__) || defined(__sparc_v8plus__) + c = ARITH_SDIVX; + goto gen_arith32; +#else + tcg_out_sety(s, 0); + c = ARITH_SDIV; + goto gen_arith32; +#endif + case INDEX_op_divu2_i32: +#if defined(__sparc_v9__) || defined(__sparc_v8plus__) + c = ARITH_UDIVX; + goto gen_arith32; +#else + tcg_out_sety(s, 0); + c = ARITH_UDIV; + goto gen_arith32; +#endif + + case INDEX_op_brcond_i32: + tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], + args[3]); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, args, 2); + break; + case INDEX_op_qemu_ld32s: + tcg_out_qemu_ld(s, args, 2 | 4); + break; + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; + +#if defined(__sparc_v9__) && !defined(__sparc_v8plus__) + case INDEX_op_movi_i64: + tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]); + break; + case INDEX_op_ld32s_i64: + tcg_out_ldst(s, args[0], args[1], args[2], LDSW); + break; + case INDEX_op_ld_i64: + tcg_out_ldst(s, args[0], args[1], args[2], LDX); + break; + case INDEX_op_st_i64: + tcg_out_ldst(s, args[0], args[1], args[2], STX); + break; + case INDEX_op_shl_i64: + c = SHIFT_SLLX; + goto gen_arith32; + case INDEX_op_shr_i64: + c = SHIFT_SRLX; + goto gen_arith32; + case INDEX_op_sar_i64: + c = SHIFT_SRAX; + goto gen_arith32; + case INDEX_op_mul_i64: + c = ARITH_MULX; + goto gen_arith32; + case INDEX_op_div2_i64: + c = ARITH_SDIVX; + goto gen_arith32; + case INDEX_op_divu2_i64: + c = ARITH_UDIVX; + goto gen_arith32; + + case INDEX_op_brcond_i64: + tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], + args[3]); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, args, 3); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, args, 3); + break; + +#endif + gen_arith32: + if (const_args[2]) { + tcg_out_arithi(s, args[0], args[1], args[2], c); + } else { + tcg_out_arith(s, args[0], args[1], args[2], c); + } + break; + + default: + fprintf(stderr, "unknown opcode 0x%x\n", opc); + tcg_abort(); + } +} + +static const TCGTargetOpDef sparc_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, + { INDEX_op_jmp, { "ri" } }, + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "r", "rJ" } }, + { INDEX_op_mul_i32, { "r", "r", "rJ" } }, + { INDEX_op_div2_i32, { "r", "r", "0", "1", "r" } }, + { INDEX_op_divu2_i32, { "r", "r", "0", "1", "r" } }, + { INDEX_op_sub_i32, { "r", "r", "rJ" } }, + { INDEX_op_and_i32, { "r", "r", "rJ" } }, + { INDEX_op_or_i32, { "r", "r", "rJ" } }, + { INDEX_op_xor_i32, { "r", "r", "rJ" } }, + + { INDEX_op_shl_i32, { "r", "r", "rJ" } }, + { INDEX_op_shr_i32, { "r", "r", "rJ" } }, + { INDEX_op_sar_i32, { "r", "r", "rJ" } }, + + { INDEX_op_brcond_i32, { "r", "ri" } }, + + { INDEX_op_qemu_ld8u, { "r", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L" } }, + { INDEX_op_qemu_ld32s, { "r", "L" } }, + + { INDEX_op_qemu_st8, { "L", "L" } }, + { INDEX_op_qemu_st16, { "L", "L" } }, + { INDEX_op_qemu_st32, { "L", "L" } }, + +#if defined(__sparc_v9__) && !defined(__sparc_v8plus__) + { INDEX_op_mov_i64, { "r", "r" } }, + { INDEX_op_movi_i64, { "r" } }, + { INDEX_op_ld8u_i64, { "r", "r" } }, + { INDEX_op_ld8s_i64, { "r", "r" } }, + { INDEX_op_ld16u_i64, { "r", "r" } }, + { INDEX_op_ld16s_i64, { "r", "r" } }, + { INDEX_op_ld32u_i64, { "r", "r" } }, + { INDEX_op_ld32s_i64, { "r", "r" } }, + { INDEX_op_ld_i64, { "r", "r" } }, + { INDEX_op_st8_i64, { "r", "r" } }, + { INDEX_op_st16_i64, { "r", "r" } }, + { INDEX_op_st32_i64, { "r", "r" } }, + { INDEX_op_st_i64, { "r", "r" } }, + { INDEX_op_qemu_ld64, { "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L" } }, + + { INDEX_op_add_i64, { "r", "r", "rJ" } }, + { INDEX_op_mul_i64, { "r", "r", "rJ" } }, + { INDEX_op_div2_i64, { "r", "r", "0", "1", "r" } }, + { INDEX_op_divu2_i64, { "r", "r", "0", "1", "r" } }, + { INDEX_op_sub_i64, { "r", "r", "rJ" } }, + { INDEX_op_and_i64, { "r", "r", "rJ" } }, + { INDEX_op_or_i64, { "r", "r", "rJ" } }, + { INDEX_op_xor_i64, { "r", "r", "rJ" } }, + + { INDEX_op_shl_i64, { "r", "r", "rJ" } }, + { INDEX_op_shr_i64, { "r", "r", "rJ" } }, + { INDEX_op_sar_i64, { "r", "r", "rJ" } }, + + { INDEX_op_brcond_i64, { "r", "ri" } }, +#endif + { -1 }, +}; + +void tcg_target_init(TCGContext *s) +{ + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff); +#if defined(__sparc_v9__) && !defined(__sparc_v8plus__) + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff); +#endif + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_G1) | + (1 << TCG_REG_G2) | + (1 << TCG_REG_G3) | + (1 << TCG_REG_G4) | + (1 << TCG_REG_G5) | + (1 << TCG_REG_G6) | + (1 << TCG_REG_G7) | + (1 << TCG_REG_O0) | + (1 << TCG_REG_O1) | + (1 << TCG_REG_O2) | + (1 << TCG_REG_O3) | + (1 << TCG_REG_O4) | + (1 << TCG_REG_O5) | + (1 << TCG_REG_O7)); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_G0); +#if defined(__sparc_v9__) && !defined(__sparc_v8plus__) + tcg_regset_set_reg(s->reserved_regs, TCG_REG_I4); // for internal use +#endif + tcg_regset_set_reg(s->reserved_regs, TCG_REG_I5); // for internal use + tcg_regset_set_reg(s->reserved_regs, TCG_REG_I6); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_I7); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_O6); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_O7); + tcg_add_target_add_op_defs(sparc_op_defs); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/sparc/tcg-target.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/sparc/tcg-target.h --- qemu-0.9.1/tcg/sparc/tcg-target.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/sparc/tcg-target.h 2008-09-13 21:05:32.000000000 +0100 @@ -0,0 +1,122 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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. + */ +#define TCG_TARGET_SPARC 1 + +#if defined(__sparc_v9__) && !defined(__sparc_v8plus__) +#define TCG_TARGET_REG_BITS 64 +#else +#define TCG_TARGET_REG_BITS 32 +#endif + +#define TCG_TARGET_WORDS_BIGENDIAN + +#define TCG_TARGET_NB_REGS 32 + +enum { + TCG_REG_G0 = 0, + TCG_REG_G1, + TCG_REG_G2, + TCG_REG_G3, + TCG_REG_G4, + TCG_REG_G5, + TCG_REG_G6, + TCG_REG_G7, + TCG_REG_O0, + TCG_REG_O1, + TCG_REG_O2, + TCG_REG_O3, + TCG_REG_O4, + TCG_REG_O5, + TCG_REG_O6, + TCG_REG_O7, + TCG_REG_L0, + TCG_REG_L1, + TCG_REG_L2, + TCG_REG_L3, + TCG_REG_L4, + TCG_REG_L5, + TCG_REG_L6, + TCG_REG_L7, + TCG_REG_I0, + TCG_REG_I1, + TCG_REG_I2, + TCG_REG_I3, + TCG_REG_I4, + TCG_REG_I5, + TCG_REG_I6, + TCG_REG_I7, +}; + +#define TCG_CT_CONST_S11 0x100 +#define TCG_CT_CONST_S13 0x200 + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_I6 +#ifdef __arch64__ +// Reserve space for AREG0 +#define TCG_TARGET_STACK_MINFRAME (176 + 2 * (int)sizeof(long)) +#define TCG_TARGET_CALL_STACK_OFFSET (2047 + TCG_TARGET_STACK_MINFRAME) +#define TCG_TARGET_STACK_ALIGN 16 +#else +// AREG0 + one word for alignment +#define TCG_TARGET_STACK_MINFRAME (92 + (2 + 1) * (int)sizeof(long)) +#define TCG_TARGET_CALL_STACK_OFFSET TCG_TARGET_STACK_MINFRAME +#define TCG_TARGET_STACK_ALIGN 8 +#endif + +/* optional instructions */ +//#define TCG_TARGET_HAS_bswap_i32 +//#define TCG_TARGET_HAS_bswap_i64 +//#define TCG_TARGET_HAS_neg_i32 +//#define TCG_TARGET_HAS_neg_i64 + + +/* Note: must be synced with dyngen-exec.h and Makefile.target */ +#ifdef HOST_SOLARIS +#define TCG_AREG0 TCG_REG_G2 +#define TCG_AREG1 TCG_REG_G3 +#define TCG_AREG2 TCG_REG_G4 +#define TCG_AREG3 TCG_REG_G5 +#define TCG_AREG4 TCG_REG_G6 +#elif defined(__sparc_v9__) +#define TCG_AREG0 TCG_REG_G5 +#define TCG_AREG1 TCG_REG_G6 +#define TCG_AREG2 TCG_REG_G7 +#else +#define TCG_AREG0 TCG_REG_G6 +#define TCG_AREG1 TCG_REG_G1 +#define TCG_AREG2 TCG_REG_G2 +#define TCG_AREG3 TCG_REG_G3 +#endif + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + unsigned long p; + + p = start & ~(8UL - 1UL); + stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL); + + for (; p < stop; p += 8) + __asm__ __volatile__("flush\t%0" : : "r" (p)); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/tcg.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/tcg.c --- qemu-0.9.1/tcg/tcg.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/tcg.c 2008-10-26 13:43:07.000000000 +0000 @@ -0,0 +1,2097 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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. + */ + +/* define it to suppress various consistency checks (faster) */ +#define NDEBUG + +/* define it to use liveness analysis (better code) */ +#define USE_LIVENESS_ANALYSIS + +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +#include +#endif + +#include "config.h" +#include "qemu-common.h" + +/* Note: the long term plan is to reduce the dependancies on the QEMU + CPU definitions. Currently they are used for qemu_ld/st + instructions */ +#define NO_CPU_IO_DEFS +#include "cpu.h" +#include "exec-all.h" + +#include "tcg-op.h" +#include "elf.h" + + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend); + +TCGOpDef tcg_op_defs[] = { +#define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size }, +#define DEF2(s, iargs, oargs, cargs, flags) { #s, iargs, oargs, cargs, iargs + oargs + cargs, flags, 0 }, +#include "tcg-opc.h" +#undef DEF +#undef DEF2 +}; + +static TCGRegSet tcg_target_available_regs[2]; +static TCGRegSet tcg_target_call_clobber_regs; + +/* XXX: move that inside the context */ +uint16_t *gen_opc_ptr; +TCGArg *gen_opparam_ptr; + +static inline void tcg_out8(TCGContext *s, uint8_t v) +{ + *s->code_ptr++ = v; +} + +static inline void tcg_out16(TCGContext *s, uint16_t v) +{ + *(uint16_t *)s->code_ptr = v; + s->code_ptr += 2; +} + +static inline void tcg_out32(TCGContext *s, uint32_t v) +{ + *(uint32_t *)s->code_ptr = v; + s->code_ptr += 4; +} + +/* label relocation processing */ + +void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, + int label_index, long addend) +{ + TCGLabel *l; + TCGRelocation *r; + + l = &s->labels[label_index]; + if (l->has_value) { + /* FIXME: This may break relocations on RISC targets that + modify instruction fields in place. The caller may not have + written the initial value. */ + patch_reloc(code_ptr, type, l->u.value, addend); + } else { + /* add a new relocation entry */ + r = tcg_malloc(sizeof(TCGRelocation)); + r->type = type; + r->ptr = code_ptr; + r->addend = addend; + r->next = l->u.first_reloc; + l->u.first_reloc = r; + } +} + +static void tcg_out_label(TCGContext *s, int label_index, + tcg_target_long value) +{ + TCGLabel *l; + TCGRelocation *r; + + l = &s->labels[label_index]; + if (l->has_value) + tcg_abort(); + r = l->u.first_reloc; + while (r != NULL) { + patch_reloc(r->ptr, r->type, value, r->addend); + r = r->next; + } + l->has_value = 1; + l->u.value = value; +} + +int gen_new_label(void) +{ + TCGContext *s = &tcg_ctx; + int idx; + TCGLabel *l; + + if (s->nb_labels >= TCG_MAX_LABELS) + tcg_abort(); + idx = s->nb_labels++; + l = &s->labels[idx]; + l->has_value = 0; + l->u.first_reloc = NULL; + return idx; +} + +#include "tcg-target.c" + +/* pool based memory allocation */ +void *tcg_malloc_internal(TCGContext *s, int size) +{ + TCGPool *p; + int pool_size; + + if (size > TCG_POOL_CHUNK_SIZE) { + /* big malloc: insert a new pool (XXX: could optimize) */ + p = qemu_malloc(sizeof(TCGPool) + size); + p->size = size; + if (s->pool_current) + s->pool_current->next = p; + else + s->pool_first = p; + p->next = s->pool_current; + } else { + p = s->pool_current; + if (!p) { + p = s->pool_first; + if (!p) + goto new_pool; + } else { + if (!p->next) { + new_pool: + pool_size = TCG_POOL_CHUNK_SIZE; + p = qemu_malloc(sizeof(TCGPool) + pool_size); + p->size = pool_size; + p->next = NULL; + if (s->pool_current) + s->pool_current->next = p; + else + s->pool_first = p; + } else { + p = p->next; + } + } + } + s->pool_current = p; + s->pool_cur = p->data + size; + s->pool_end = p->data + p->size; + return p->data; +} + +void tcg_pool_reset(TCGContext *s) +{ + s->pool_cur = s->pool_end = NULL; + s->pool_current = NULL; +} + +void tcg_context_init(TCGContext *s) +{ + int op, total_args, n; + TCGOpDef *def; + TCGArgConstraint *args_ct; + int *sorted_args; + + memset(s, 0, sizeof(*s)); + s->temps = s->static_temps; + s->nb_globals = 0; + + /* Count total number of arguments and allocate the corresponding + space */ + total_args = 0; + for(op = 0; op < NB_OPS; op++) { + def = &tcg_op_defs[op]; + n = def->nb_iargs + def->nb_oargs; + total_args += n; + } + + args_ct = qemu_malloc(sizeof(TCGArgConstraint) * total_args); + sorted_args = qemu_malloc(sizeof(int) * total_args); + + for(op = 0; op < NB_OPS; op++) { + def = &tcg_op_defs[op]; + def->args_ct = args_ct; + def->sorted_args = sorted_args; + n = def->nb_iargs + def->nb_oargs; + sorted_args += n; + args_ct += n; + } + + tcg_target_init(s); + + /* init global prologue and epilogue */ + s->code_buf = code_gen_prologue; + s->code_ptr = s->code_buf; + tcg_target_qemu_prologue(s); + flush_icache_range((unsigned long)s->code_buf, + (unsigned long)s->code_ptr); +} + +void tcg_set_frame(TCGContext *s, int reg, + tcg_target_long start, tcg_target_long size) +{ + s->frame_start = start; + s->frame_end = start + size; + s->frame_reg = reg; +} + +void tcg_func_start(TCGContext *s) +{ + int i; + tcg_pool_reset(s); + s->nb_temps = s->nb_globals; + for(i = 0; i < (TCG_TYPE_COUNT * 2); i++) + s->first_free_temp[i] = -1; + s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS); + s->nb_labels = 0; + s->current_frame_offset = s->frame_start; + + gen_opc_ptr = gen_opc_buf; + gen_opparam_ptr = gen_opparam_buf; +} + +static inline void tcg_temp_alloc(TCGContext *s, int n) +{ + if (n > TCG_MAX_TEMPS) + tcg_abort(); +} + +TCGv tcg_global_reg_new(TCGType type, int reg, const char *name) +{ + TCGContext *s = &tcg_ctx; + TCGTemp *ts; + int idx; + +#if TCG_TARGET_REG_BITS == 32 + if (type != TCG_TYPE_I32) + tcg_abort(); +#endif + if (tcg_regset_test_reg(s->reserved_regs, reg)) + tcg_abort(); + idx = s->nb_globals; + tcg_temp_alloc(s, s->nb_globals + 1); + ts = &s->temps[s->nb_globals]; + ts->base_type = type; + ts->type = type; + ts->fixed_reg = 1; + ts->reg = reg; + ts->name = name; + s->nb_globals++; + tcg_regset_set_reg(s->reserved_regs, reg); + return MAKE_TCGV(idx); +} + +#if TCG_TARGET_REG_BITS == 32 +/* temporary hack to avoid register shortage for tcg_qemu_st64() */ +TCGv tcg_global_reg2_new_hack(TCGType type, int reg1, int reg2, + const char *name) +{ + TCGContext *s = &tcg_ctx; + TCGTemp *ts; + int idx; + char buf[64]; + + if (type != TCG_TYPE_I64) + tcg_abort(); + idx = s->nb_globals; + tcg_temp_alloc(s, s->nb_globals + 2); + ts = &s->temps[s->nb_globals]; + ts->base_type = type; + ts->type = TCG_TYPE_I32; + ts->fixed_reg = 1; + ts->reg = reg1; + pstrcpy(buf, sizeof(buf), name); + pstrcat(buf, sizeof(buf), "_0"); + ts->name = strdup(buf); + + ts++; + ts->base_type = type; + ts->type = TCG_TYPE_I32; + ts->fixed_reg = 1; + ts->reg = reg2; + pstrcpy(buf, sizeof(buf), name); + pstrcat(buf, sizeof(buf), "_1"); + ts->name = strdup(buf); + + s->nb_globals += 2; + return MAKE_TCGV(idx); +} +#endif + +TCGv tcg_global_mem_new(TCGType type, int reg, tcg_target_long offset, + const char *name) +{ + TCGContext *s = &tcg_ctx; + TCGTemp *ts; + int idx; + + idx = s->nb_globals; +#if TCG_TARGET_REG_BITS == 32 + if (type == TCG_TYPE_I64) { + char buf[64]; + tcg_temp_alloc(s, s->nb_globals + 2); + ts = &s->temps[s->nb_globals]; + ts->base_type = type; + ts->type = TCG_TYPE_I32; + ts->fixed_reg = 0; + ts->mem_allocated = 1; + ts->mem_reg = reg; +#ifdef TCG_TARGET_WORDS_BIGENDIAN + ts->mem_offset = offset + 4; +#else + ts->mem_offset = offset; +#endif + pstrcpy(buf, sizeof(buf), name); + pstrcat(buf, sizeof(buf), "_0"); + ts->name = strdup(buf); + ts++; + + ts->base_type = type; + ts->type = TCG_TYPE_I32; + ts->fixed_reg = 0; + ts->mem_allocated = 1; + ts->mem_reg = reg; +#ifdef TCG_TARGET_WORDS_BIGENDIAN + ts->mem_offset = offset; +#else + ts->mem_offset = offset + 4; +#endif + pstrcpy(buf, sizeof(buf), name); + pstrcat(buf, sizeof(buf), "_1"); + ts->name = strdup(buf); + + s->nb_globals += 2; + } else +#endif + { + tcg_temp_alloc(s, s->nb_globals + 1); + ts = &s->temps[s->nb_globals]; + ts->base_type = type; + ts->type = type; + ts->fixed_reg = 0; + ts->mem_allocated = 1; + ts->mem_reg = reg; + ts->mem_offset = offset; + ts->name = name; + s->nb_globals++; + } + return MAKE_TCGV(idx); +} + +TCGv tcg_temp_new_internal(TCGType type, int temp_local) +{ + TCGContext *s = &tcg_ctx; + TCGTemp *ts; + int idx, k; + + k = type; + if (temp_local) + k += TCG_TYPE_COUNT; + idx = s->first_free_temp[k]; + if (idx != -1) { + /* There is already an available temp with the + right type */ + ts = &s->temps[idx]; + s->first_free_temp[k] = ts->next_free_temp; + ts->temp_allocated = 1; + assert(ts->temp_local == temp_local); + } else { + idx = s->nb_temps; +#if TCG_TARGET_REG_BITS == 32 + if (type == TCG_TYPE_I64) { + tcg_temp_alloc(s, s->nb_temps + 2); + ts = &s->temps[s->nb_temps]; + ts->base_type = type; + ts->type = TCG_TYPE_I32; + ts->temp_allocated = 1; + ts->temp_local = temp_local; + ts->name = NULL; + ts++; + ts->base_type = TCG_TYPE_I32; + ts->type = TCG_TYPE_I32; + ts->temp_allocated = 1; + ts->temp_local = temp_local; + ts->name = NULL; + s->nb_temps += 2; + } else +#endif + { + tcg_temp_alloc(s, s->nb_temps + 1); + ts = &s->temps[s->nb_temps]; + ts->base_type = type; + ts->type = type; + ts->temp_allocated = 1; + ts->temp_local = temp_local; + ts->name = NULL; + s->nb_temps++; + } + } + return MAKE_TCGV(idx); +} + +void tcg_temp_free(TCGv arg) +{ + TCGContext *s = &tcg_ctx; + TCGTemp *ts; + int idx = GET_TCGV(arg); + int k; + + assert(idx >= s->nb_globals && idx < s->nb_temps); + ts = &s->temps[idx]; + assert(ts->temp_allocated != 0); + ts->temp_allocated = 0; + k = ts->base_type; + if (ts->temp_local) + k += TCG_TYPE_COUNT; + ts->next_free_temp = s->first_free_temp[k]; + s->first_free_temp[k] = idx; +} + + +TCGv tcg_const_i32(int32_t val) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_movi_i32(t0, val); + return t0; +} + +TCGv tcg_const_i64(int64_t val) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_movi_i64(t0, val); + return t0; +} + +TCGv tcg_const_local_i32(int32_t val) +{ + TCGv t0; + t0 = tcg_temp_local_new(TCG_TYPE_I32); + tcg_gen_movi_i32(t0, val); + return t0; +} + +TCGv tcg_const_local_i64(int64_t val) +{ + TCGv t0; + t0 = tcg_temp_local_new(TCG_TYPE_I64); + tcg_gen_movi_i64(t0, val); + return t0; +} + +void tcg_register_helper(void *func, const char *name) +{ + TCGContext *s = &tcg_ctx; + int n; + if ((s->nb_helpers + 1) > s->allocated_helpers) { + n = s->allocated_helpers; + if (n == 0) { + n = 4; + } else { + n *= 2; + } + s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo)); + s->allocated_helpers = n; + } + s->helpers[s->nb_helpers].func = (tcg_target_ulong)func; + s->helpers[s->nb_helpers].name = name; + s->nb_helpers++; +} + +static inline TCGType tcg_get_base_type(TCGContext *s, TCGv arg) +{ + return s->temps[GET_TCGV(arg)].base_type; +} + +static void tcg_gen_call_internal(TCGContext *s, TCGv func, + unsigned int flags, + unsigned int nb_rets, const TCGv *rets, + unsigned int nb_params, const TCGv *params) +{ + int i; + *gen_opc_ptr++ = INDEX_op_call; + *gen_opparam_ptr++ = (nb_rets << 16) | (nb_params + 1); + for(i = 0; i < nb_rets; i++) { + *gen_opparam_ptr++ = GET_TCGV(rets[i]); + } + for(i = 0; i < nb_params; i++) { + *gen_opparam_ptr++ = GET_TCGV(params[i]); + } + *gen_opparam_ptr++ = GET_TCGV(func); + + *gen_opparam_ptr++ = flags; + /* total parameters, needed to go backward in the instruction stream */ + *gen_opparam_ptr++ = 1 + nb_rets + nb_params + 3; +} + + +#if TCG_TARGET_REG_BITS < 64 +/* Note: we convert the 64 bit args to 32 bit and do some alignment + and endian swap. Maybe it would be better to do the alignment + and endian swap in tcg_reg_alloc_call(). */ +void tcg_gen_call(TCGContext *s, TCGv func, unsigned int flags, + unsigned int nb_rets, const TCGv *rets, + unsigned int nb_params, const TCGv *args1) +{ + TCGv ret, *args2, rets_2[2], arg; + int j, i, call_type; + + if (nb_rets == 1) { + ret = rets[0]; + if (tcg_get_base_type(s, ret) == TCG_TYPE_I64) { + nb_rets = 2; +#ifdef TCG_TARGET_WORDS_BIGENDIAN + rets_2[0] = TCGV_HIGH(ret); + rets_2[1] = ret; +#else + rets_2[0] = ret; + rets_2[1] = TCGV_HIGH(ret); +#endif + rets = rets_2; + } + } + args2 = alloca((nb_params * 3) * sizeof(TCGv)); + j = 0; + call_type = (flags & TCG_CALL_TYPE_MASK); + for(i = 0; i < nb_params; i++) { + arg = args1[i]; + if (tcg_get_base_type(s, arg) == TCG_TYPE_I64) { +#ifdef TCG_TARGET_I386 + /* REGPARM case: if the third parameter is 64 bit, it is + allocated on the stack */ + if (j == 2 && call_type == TCG_CALL_TYPE_REGPARM) { + call_type = TCG_CALL_TYPE_REGPARM_2; + flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type; + } + args2[j++] = arg; + args2[j++] = TCGV_HIGH(arg); +#else +#ifdef TCG_TARGET_CALL_ALIGN_ARGS + /* some targets want aligned 64 bit args */ + if (j & 1) { + args2[j++] = TCG_CALL_DUMMY_ARG; + } +#endif +#ifdef TCG_TARGET_WORDS_BIGENDIAN + args2[j++] = TCGV_HIGH(arg); + args2[j++] = arg; +#else + args2[j++] = arg; + args2[j++] = TCGV_HIGH(arg); +#endif +#endif + } else { + args2[j++] = arg; + } + } + tcg_gen_call_internal(s, func, flags, + nb_rets, rets, j, args2); +} +#else +void tcg_gen_call(TCGContext *s, TCGv func, unsigned int flags, + unsigned int nb_rets, const TCGv *rets, + unsigned int nb_params, const TCGv *args1) +{ + tcg_gen_call_internal(s, func, flags, + nb_rets, rets, nb_params, args1); +} +#endif + +#if TCG_TARGET_REG_BITS == 32 +void tcg_gen_shifti_i64(TCGv ret, TCGv arg1, + int c, int right, int arith) +{ + if (c == 0) { + tcg_gen_mov_i32(ret, arg1); + tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); + } else if (c >= 32) { + c -= 32; + if (right) { + if (arith) { + tcg_gen_sari_i32(ret, TCGV_HIGH(arg1), c); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31); + } else { + tcg_gen_shri_i32(ret, TCGV_HIGH(arg1), c); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); + } + } else { + tcg_gen_shli_i32(TCGV_HIGH(ret), arg1, c); + tcg_gen_movi_i32(ret, 0); + } + } else { + TCGv t0, t1; + + t0 = tcg_temp_new(TCG_TYPE_I32); + t1 = tcg_temp_new(TCG_TYPE_I32); + if (right) { + tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c); + if (arith) + tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c); + else + tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c); + tcg_gen_shri_i32(ret, arg1, c); + tcg_gen_or_i32(ret, ret, t0); + tcg_gen_mov_i32(TCGV_HIGH(ret), t1); + } else { + tcg_gen_shri_i32(t0, arg1, 32 - c); + /* Note: ret can be the same as arg1, so we use t1 */ + tcg_gen_shli_i32(t1, arg1, c); + tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c); + tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0); + tcg_gen_mov_i32(ret, t1); + } + tcg_temp_free(t0); + tcg_temp_free(t1); + } +} +#endif + +static void tcg_reg_alloc_start(TCGContext *s) +{ + int i; + TCGTemp *ts; + for(i = 0; i < s->nb_globals; i++) { + ts = &s->temps[i]; + if (ts->fixed_reg) { + ts->val_type = TEMP_VAL_REG; + } else { + ts->val_type = TEMP_VAL_MEM; + } + } + for(i = s->nb_globals; i < s->nb_temps; i++) { + ts = &s->temps[i]; + ts->val_type = TEMP_VAL_DEAD; + ts->mem_allocated = 0; + ts->fixed_reg = 0; + } + for(i = 0; i < TCG_TARGET_NB_REGS; i++) { + s->reg_to_temp[i] = -1; + } +} + +static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size, + int idx) +{ + TCGTemp *ts; + + ts = &s->temps[idx]; + if (idx < s->nb_globals) { + pstrcpy(buf, buf_size, ts->name); + } else { + if (ts->temp_local) + snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); + else + snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); + } + return buf; +} + +char *tcg_get_arg_str(TCGContext *s, char *buf, int buf_size, TCGv arg) +{ + return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV(arg)); +} + +static int helper_cmp(const void *p1, const void *p2) +{ + const TCGHelperInfo *th1 = p1; + const TCGHelperInfo *th2 = p2; + if (th1->func < th2->func) + return -1; + else if (th1->func == th2->func) + return 0; + else + return 1; +} + +/* find helper definition (Note: A hash table would be better) */ +static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val) +{ + int m, m_min, m_max; + TCGHelperInfo *th; + tcg_target_ulong v; + + if (unlikely(!s->helpers_sorted)) { + qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo), + helper_cmp); + s->helpers_sorted = 1; + } + + /* binary search */ + m_min = 0; + m_max = s->nb_helpers - 1; + while (m_min <= m_max) { + m = (m_min + m_max) >> 1; + th = &s->helpers[m]; + v = th->func; + if (v == val) + return th; + else if (val < v) { + m_max = m - 1; + } else { + m_min = m + 1; + } + } + return NULL; +} + +static const char * const cond_name[] = +{ + [TCG_COND_EQ] = "eq", + [TCG_COND_NE] = "ne", + [TCG_COND_LT] = "lt", + [TCG_COND_GE] = "ge", + [TCG_COND_LE] = "le", + [TCG_COND_GT] = "gt", + [TCG_COND_LTU] = "ltu", + [TCG_COND_GEU] = "geu", + [TCG_COND_LEU] = "leu", + [TCG_COND_GTU] = "gtu" +}; + +void tcg_dump_ops(TCGContext *s, FILE *outfile) +{ + const uint16_t *opc_ptr; + const TCGArg *args; + TCGArg arg; + int c, i, k, nb_oargs, nb_iargs, nb_cargs, first_insn; + const TCGOpDef *def; + char buf[128]; + + first_insn = 1; + opc_ptr = gen_opc_buf; + args = gen_opparam_buf; + while (opc_ptr < gen_opc_ptr) { + c = *opc_ptr++; + def = &tcg_op_defs[c]; + if (c == INDEX_op_debug_insn_start) { + uint64_t pc; +#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS + pc = ((uint64_t)args[1] << 32) | args[0]; +#else + pc = args[0]; +#endif + if (!first_insn) + fprintf(outfile, "\n"); + fprintf(outfile, " ---- 0x%" PRIx64, pc); + first_insn = 0; + nb_oargs = def->nb_oargs; + nb_iargs = def->nb_iargs; + nb_cargs = def->nb_cargs; + } else if (c == INDEX_op_call) { + TCGArg arg; + + /* variable number of arguments */ + arg = *args++; + nb_oargs = arg >> 16; + nb_iargs = arg & 0xffff; + nb_cargs = def->nb_cargs; + + fprintf(outfile, " %s ", def->name); + + /* function name */ + fprintf(outfile, "%s", + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1])); + /* flags */ + fprintf(outfile, ",$0x%" TCG_PRIlx, + args[nb_oargs + nb_iargs]); + /* nb out args */ + fprintf(outfile, ",$%d", nb_oargs); + for(i = 0; i < nb_oargs; i++) { + fprintf(outfile, ","); + fprintf(outfile, "%s", + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i])); + } + for(i = 0; i < (nb_iargs - 1); i++) { + fprintf(outfile, ","); + if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) { + fprintf(outfile, ""); + } else { + fprintf(outfile, "%s", + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i])); + } + } + } else if (c == INDEX_op_movi_i32 +#if TCG_TARGET_REG_BITS == 64 + || c == INDEX_op_movi_i64 +#endif + ) { + tcg_target_ulong val; + TCGHelperInfo *th; + + nb_oargs = def->nb_oargs; + nb_iargs = def->nb_iargs; + nb_cargs = def->nb_cargs; + fprintf(outfile, " %s %s,$", def->name, + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0])); + val = args[1]; + th = tcg_find_helper(s, val); + if (th) { + fprintf(outfile, th->name); + } else { + if (c == INDEX_op_movi_i32) + fprintf(outfile, "0x%x", (uint32_t)val); + else + fprintf(outfile, "0x%" PRIx64 , (uint64_t)val); + } + } else { + fprintf(outfile, " %s ", def->name); + if (c == INDEX_op_nopn) { + /* variable number of arguments */ + nb_cargs = *args; + nb_oargs = 0; + nb_iargs = 0; + } else { + nb_oargs = def->nb_oargs; + nb_iargs = def->nb_iargs; + nb_cargs = def->nb_cargs; + } + + k = 0; + for(i = 0; i < nb_oargs; i++) { + if (k != 0) + fprintf(outfile, ","); + fprintf(outfile, "%s", + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); + } + for(i = 0; i < nb_iargs; i++) { + if (k != 0) + fprintf(outfile, ","); + fprintf(outfile, "%s", + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); + } + if (c == INDEX_op_brcond_i32 +#if TCG_TARGET_REG_BITS == 32 + || c == INDEX_op_brcond2_i32 +#elif TCG_TARGET_REG_BITS == 64 + || c == INDEX_op_brcond_i64 +#endif + ) { + if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]]) + fprintf(outfile, ",%s", cond_name[args[k++]]); + else + fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]); + i = 1; + } + else + i = 0; + for(; i < nb_cargs; i++) { + if (k != 0) + fprintf(outfile, ","); + arg = args[k++]; + fprintf(outfile, "$0x%" TCG_PRIlx, arg); + } + } + fprintf(outfile, "\n"); + args += nb_iargs + nb_oargs + nb_cargs; + } +} + +/* we give more priority to constraints with less registers */ +static int get_constraint_priority(const TCGOpDef *def, int k) +{ + const TCGArgConstraint *arg_ct; + + int i, n; + arg_ct = &def->args_ct[k]; + if (arg_ct->ct & TCG_CT_ALIAS) { + /* an alias is equivalent to a single register */ + n = 1; + } else { + if (!(arg_ct->ct & TCG_CT_REG)) + return 0; + n = 0; + for(i = 0; i < TCG_TARGET_NB_REGS; i++) { + if (tcg_regset_test_reg(arg_ct->u.regs, i)) + n++; + } + } + return TCG_TARGET_NB_REGS - n + 1; +} + +/* sort from highest priority to lowest */ +static void sort_constraints(TCGOpDef *def, int start, int n) +{ + int i, j, p1, p2, tmp; + + for(i = 0; i < n; i++) + def->sorted_args[start + i] = start + i; + if (n <= 1) + return; + for(i = 0; i < n - 1; i++) { + for(j = i + 1; j < n; j++) { + p1 = get_constraint_priority(def, def->sorted_args[start + i]); + p2 = get_constraint_priority(def, def->sorted_args[start + j]); + if (p1 < p2) { + tmp = def->sorted_args[start + i]; + def->sorted_args[start + i] = def->sorted_args[start + j]; + def->sorted_args[start + j] = tmp; + } + } + } +} + +void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs) +{ + int op; + TCGOpDef *def; + const char *ct_str; + int i, nb_args; + + for(;;) { + if (tdefs->op < 0) + break; + op = tdefs->op; + assert(op >= 0 && op < NB_OPS); + def = &tcg_op_defs[op]; + nb_args = def->nb_iargs + def->nb_oargs; + for(i = 0; i < nb_args; i++) { + ct_str = tdefs->args_ct_str[i]; + tcg_regset_clear(def->args_ct[i].u.regs); + def->args_ct[i].ct = 0; + if (ct_str[0] >= '0' && ct_str[0] <= '9') { + int oarg; + oarg = ct_str[0] - '0'; + assert(oarg < def->nb_oargs); + assert(def->args_ct[oarg].ct & TCG_CT_REG); + /* TCG_CT_ALIAS is for the output arguments. The input + argument is tagged with TCG_CT_IALIAS. */ + def->args_ct[i] = def->args_ct[oarg]; + def->args_ct[oarg].ct = TCG_CT_ALIAS; + def->args_ct[oarg].alias_index = i; + def->args_ct[i].ct |= TCG_CT_IALIAS; + def->args_ct[i].alias_index = oarg; + } else { + for(;;) { + if (*ct_str == '\0') + break; + switch(*ct_str) { + case 'i': + def->args_ct[i].ct |= TCG_CT_CONST; + ct_str++; + break; + default: + if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) { + fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n", + ct_str, i, def->name); + exit(1); + } + } + } + } + } + + /* sort the constraints (XXX: this is just an heuristic) */ + sort_constraints(def, 0, def->nb_oargs); + sort_constraints(def, def->nb_oargs, def->nb_iargs); + +#if 0 + { + int i; + + printf("%s: sorted=", def->name); + for(i = 0; i < def->nb_oargs + def->nb_iargs; i++) + printf(" %d", def->sorted_args[i]); + printf("\n"); + } +#endif + tdefs++; + } + +} + +#ifdef USE_LIVENESS_ANALYSIS + +/* set a nop for an operation using 'nb_args' */ +static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, + TCGArg *args, int nb_args) +{ + if (nb_args == 0) { + *opc_ptr = INDEX_op_nop; + } else { + *opc_ptr = INDEX_op_nopn; + args[0] = nb_args; + args[nb_args - 1] = nb_args; + } +} + +/* liveness analysis: end of function: globals are live, temps are + dead. */ +/* XXX: at this stage, not used as there would be little gains because + most TBs end with a conditional jump. */ +static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps) +{ + memset(dead_temps, 0, s->nb_globals); + memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals); +} + +/* liveness analysis: end of basic block: globals are live, temps are + dead, local temps are live. */ +static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps) +{ + int i; + TCGTemp *ts; + + memset(dead_temps, 0, s->nb_globals); + ts = &s->temps[s->nb_globals]; + for(i = s->nb_globals; i < s->nb_temps; i++) { + if (ts->temp_local) + dead_temps[i] = 0; + else + dead_temps[i] = 1; + ts++; + } +} + +/* Liveness analysis : update the opc_dead_iargs array to tell if a + given input arguments is dead. Instructions updating dead + temporaries are removed. */ +static void tcg_liveness_analysis(TCGContext *s) +{ + int i, op_index, op, nb_args, nb_iargs, nb_oargs, arg, nb_ops; + TCGArg *args; + const TCGOpDef *def; + uint8_t *dead_temps; + unsigned int dead_iargs; + + gen_opc_ptr++; /* skip end */ + + nb_ops = gen_opc_ptr - gen_opc_buf; + + /* XXX: make it really dynamic */ + s->op_dead_iargs = tcg_malloc(OPC_BUF_SIZE * sizeof(uint16_t)); + + dead_temps = tcg_malloc(s->nb_temps); + memset(dead_temps, 1, s->nb_temps); + + args = gen_opparam_ptr; + op_index = nb_ops - 1; + while (op_index >= 0) { + op = gen_opc_buf[op_index]; + def = &tcg_op_defs[op]; + switch(op) { + case INDEX_op_call: + { + int call_flags; + + nb_args = args[-1]; + args -= nb_args; + nb_iargs = args[0] & 0xffff; + nb_oargs = args[0] >> 16; + args++; + call_flags = args[nb_oargs + nb_iargs]; + + /* pure functions can be removed if their result is not + used */ + if (call_flags & TCG_CALL_PURE) { + for(i = 0; i < nb_oargs; i++) { + arg = args[i]; + if (!dead_temps[arg]) + goto do_not_remove_call; + } + tcg_set_nop(s, gen_opc_buf + op_index, + args - 1, nb_args); + } else { + do_not_remove_call: + + /* output args are dead */ + for(i = 0; i < nb_oargs; i++) { + arg = args[i]; + dead_temps[arg] = 1; + } + + /* globals are live (they may be used by the call) */ + memset(dead_temps, 0, s->nb_globals); + + /* input args are live */ + dead_iargs = 0; + for(i = 0; i < nb_iargs; i++) { + arg = args[i + nb_oargs]; + if (arg != TCG_CALL_DUMMY_ARG) { + if (dead_temps[arg]) { + dead_iargs |= (1 << i); + } + dead_temps[arg] = 0; + } + } + s->op_dead_iargs[op_index] = dead_iargs; + } + args--; + } + break; + case INDEX_op_set_label: + args--; + /* mark end of basic block */ + tcg_la_bb_end(s, dead_temps); + break; + case INDEX_op_debug_insn_start: + args -= def->nb_args; + break; + case INDEX_op_nopn: + nb_args = args[-1]; + args -= nb_args; + break; + case INDEX_op_discard: + args--; + /* mark the temporary as dead */ + dead_temps[args[0]] = 1; + break; + case INDEX_op_end: + break; + /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ + default: + if (op > INDEX_op_end) { + args -= def->nb_args; + nb_iargs = def->nb_iargs; + nb_oargs = def->nb_oargs; + + /* Test if the operation can be removed because all + its outputs are dead. We assume that nb_oargs == 0 + implies side effects */ + if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { + for(i = 0; i < nb_oargs; i++) { + arg = args[i]; + if (!dead_temps[arg]) + goto do_not_remove; + } + tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args); +#ifdef CONFIG_PROFILER + s->del_op_count++; +#endif + } else { + do_not_remove: + + /* output args are dead */ + for(i = 0; i < nb_oargs; i++) { + arg = args[i]; + dead_temps[arg] = 1; + } + + /* if end of basic block, update */ + if (def->flags & TCG_OPF_BB_END) { + tcg_la_bb_end(s, dead_temps); + } else if (def->flags & TCG_OPF_CALL_CLOBBER) { + /* globals are live */ + memset(dead_temps, 0, s->nb_globals); + } + + /* input args are live */ + dead_iargs = 0; + for(i = 0; i < nb_iargs; i++) { + arg = args[i + nb_oargs]; + if (dead_temps[arg]) { + dead_iargs |= (1 << i); + } + dead_temps[arg] = 0; + } + s->op_dead_iargs[op_index] = dead_iargs; + } + } else { + /* legacy dyngen operations */ + args -= def->nb_args; + /* mark end of basic block */ + tcg_la_bb_end(s, dead_temps); + } + break; + } + op_index--; + } + + if (args != gen_opparam_buf) + tcg_abort(); +} +#else +/* dummy liveness analysis */ +void tcg_liveness_analysis(TCGContext *s) +{ + int nb_ops; + nb_ops = gen_opc_ptr - gen_opc_buf; + + s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t)); + memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t)); +} +#endif + +#ifndef NDEBUG +static void dump_regs(TCGContext *s) +{ + TCGTemp *ts; + int i; + char buf[64]; + + for(i = 0; i < s->nb_temps; i++) { + ts = &s->temps[i]; + printf(" %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i)); + switch(ts->val_type) { + case TEMP_VAL_REG: + printf("%s", tcg_target_reg_names[ts->reg]); + break; + case TEMP_VAL_MEM: + printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]); + break; + case TEMP_VAL_CONST: + printf("$0x%" TCG_PRIlx, ts->val); + break; + case TEMP_VAL_DEAD: + printf("D"); + break; + default: + printf("???"); + break; + } + printf("\n"); + } + + for(i = 0; i < TCG_TARGET_NB_REGS; i++) { + if (s->reg_to_temp[i] >= 0) { + printf("%s: %s\n", + tcg_target_reg_names[i], + tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i])); + } + } +} + +static void check_regs(TCGContext *s) +{ + int reg, k; + TCGTemp *ts; + char buf[64]; + + for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { + k = s->reg_to_temp[reg]; + if (k >= 0) { + ts = &s->temps[k]; + if (ts->val_type != TEMP_VAL_REG || + ts->reg != reg) { + printf("Inconsistency for register %s:\n", + tcg_target_reg_names[reg]); + goto fail; + } + } + } + for(k = 0; k < s->nb_temps; k++) { + ts = &s->temps[k]; + if (ts->val_type == TEMP_VAL_REG && + !ts->fixed_reg && + s->reg_to_temp[ts->reg] != k) { + printf("Inconsistency for temp %s:\n", + tcg_get_arg_str_idx(s, buf, sizeof(buf), k)); + fail: + printf("reg state:\n"); + dump_regs(s); + tcg_abort(); + } + } +} +#endif + +static void temp_allocate_frame(TCGContext *s, int temp) +{ + TCGTemp *ts; + ts = &s->temps[temp]; + s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1); + if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end) + tcg_abort(); + ts->mem_offset = s->current_frame_offset; + ts->mem_reg = s->frame_reg; + ts->mem_allocated = 1; + s->current_frame_offset += sizeof(tcg_target_long); +} + +/* free register 'reg' by spilling the corresponding temporary if necessary */ +static void tcg_reg_free(TCGContext *s, int reg) +{ + TCGTemp *ts; + int temp; + + temp = s->reg_to_temp[reg]; + if (temp != -1) { + ts = &s->temps[temp]; + assert(ts->val_type == TEMP_VAL_REG); + if (!ts->mem_coherent) { + if (!ts->mem_allocated) + temp_allocate_frame(s, temp); + tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + } + ts->val_type = TEMP_VAL_MEM; + s->reg_to_temp[reg] = -1; + } +} + +/* Allocate a register belonging to reg1 & ~reg2 */ +static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2) +{ + int i, reg; + TCGRegSet reg_ct; + + tcg_regset_andnot(reg_ct, reg1, reg2); + + /* first try free registers */ + for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) { + reg = tcg_target_reg_alloc_order[i]; + if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1) + return reg; + } + + /* XXX: do better spill choice */ + for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) { + reg = tcg_target_reg_alloc_order[i]; + if (tcg_regset_test_reg(reg_ct, reg)) { + tcg_reg_free(s, reg); + return reg; + } + } + + tcg_abort(); +} + +/* save a temporary to memory. 'allocated_regs' is used in case a + temporary registers needs to be allocated to store a constant. */ +static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs) +{ + TCGTemp *ts; + int reg; + + ts = &s->temps[temp]; + if (!ts->fixed_reg) { + switch(ts->val_type) { + case TEMP_VAL_REG: + tcg_reg_free(s, ts->reg); + break; + case TEMP_VAL_DEAD: + ts->val_type = TEMP_VAL_MEM; + break; + case TEMP_VAL_CONST: + reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], + allocated_regs); + if (!ts->mem_allocated) + temp_allocate_frame(s, temp); + tcg_out_movi(s, ts->type, reg, ts->val); + tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + ts->val_type = TEMP_VAL_MEM; + break; + case TEMP_VAL_MEM: + break; + default: + tcg_abort(); + } + } +} + +/* save globals to their cannonical location and assume they can be + modified be the following code. 'allocated_regs' is used in case a + temporary registers needs to be allocated to store a constant. */ +static void save_globals(TCGContext *s, TCGRegSet allocated_regs) +{ + int i; + + for(i = 0; i < s->nb_globals; i++) { + temp_save(s, i, allocated_regs); + } +} + +/* at the end of a basic block, we assume all temporaries are dead and + all globals are stored at their canonical location. */ +static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) +{ + TCGTemp *ts; + int i; + + for(i = s->nb_globals; i < s->nb_temps; i++) { + ts = &s->temps[i]; + if (ts->temp_local) { + temp_save(s, i, allocated_regs); + } else { + if (ts->val_type == TEMP_VAL_REG) { + s->reg_to_temp[ts->reg] = -1; + } + ts->val_type = TEMP_VAL_DEAD; + } + } + + save_globals(s, allocated_regs); +} + +#define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1) + +static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args) +{ + TCGTemp *ots; + tcg_target_ulong val; + + ots = &s->temps[args[0]]; + val = args[1]; + + if (ots->fixed_reg) { + /* for fixed registers, we do not do any constant + propagation */ + tcg_out_movi(s, ots->type, ots->reg, val); + } else { + /* The movi is not explicitly generated here */ + if (ots->val_type == TEMP_VAL_REG) + s->reg_to_temp[ots->reg] = -1; + ots->val_type = TEMP_VAL_CONST; + ots->val = val; + } +} + +static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, + const TCGArg *args, + unsigned int dead_iargs) +{ + TCGTemp *ts, *ots; + int reg; + const TCGArgConstraint *arg_ct; + + ots = &s->temps[args[0]]; + ts = &s->temps[args[1]]; + arg_ct = &def->args_ct[0]; + + /* XXX: always mark arg dead if IS_DEAD_IARG(0) */ + if (ts->val_type == TEMP_VAL_REG) { + if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) { + /* the mov can be suppressed */ + if (ots->val_type == TEMP_VAL_REG) + s->reg_to_temp[ots->reg] = -1; + reg = ts->reg; + s->reg_to_temp[reg] = -1; + ts->val_type = TEMP_VAL_DEAD; + } else { + if (ots->val_type == TEMP_VAL_REG) { + reg = ots->reg; + } else { + reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs); + } + if (ts->reg != reg) { + tcg_out_mov(s, reg, ts->reg); + } + } + } else if (ts->val_type == TEMP_VAL_MEM) { + if (ots->val_type == TEMP_VAL_REG) { + reg = ots->reg; + } else { + reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs); + } + tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + } else if (ts->val_type == TEMP_VAL_CONST) { + if (ots->fixed_reg) { + reg = ots->reg; + tcg_out_movi(s, ots->type, reg, ts->val); + } else { + /* propagate constant */ + if (ots->val_type == TEMP_VAL_REG) + s->reg_to_temp[ots->reg] = -1; + ots->val_type = TEMP_VAL_CONST; + ots->val = ts->val; + return; + } + } else { + tcg_abort(); + } + s->reg_to_temp[reg] = args[0]; + ots->reg = reg; + ots->val_type = TEMP_VAL_REG; + ots->mem_coherent = 0; +} + +static void tcg_reg_alloc_op(TCGContext *s, + const TCGOpDef *def, int opc, + const TCGArg *args, + unsigned int dead_iargs) +{ + TCGRegSet allocated_regs; + int i, k, nb_iargs, nb_oargs, reg; + TCGArg arg; + const TCGArgConstraint *arg_ct; + TCGTemp *ts; + TCGArg new_args[TCG_MAX_OP_ARGS]; + int const_args[TCG_MAX_OP_ARGS]; + + nb_oargs = def->nb_oargs; + nb_iargs = def->nb_iargs; + + /* copy constants */ + memcpy(new_args + nb_oargs + nb_iargs, + args + nb_oargs + nb_iargs, + sizeof(TCGArg) * def->nb_cargs); + + /* satisfy input constraints */ + tcg_regset_set(allocated_regs, s->reserved_regs); + for(k = 0; k < nb_iargs; k++) { + i = def->sorted_args[nb_oargs + k]; + arg = args[i]; + arg_ct = &def->args_ct[i]; + ts = &s->temps[arg]; + if (ts->val_type == TEMP_VAL_MEM) { + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + ts->val_type = TEMP_VAL_REG; + ts->reg = reg; + ts->mem_coherent = 1; + s->reg_to_temp[reg] = arg; + } else if (ts->val_type == TEMP_VAL_CONST) { + if (tcg_target_const_match(ts->val, arg_ct)) { + /* constant is OK for instruction */ + const_args[i] = 1; + new_args[i] = ts->val; + goto iarg_end; + } else { + /* need to move to a register */ + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + tcg_out_movi(s, ts->type, reg, ts->val); + ts->val_type = TEMP_VAL_REG; + ts->reg = reg; + ts->mem_coherent = 0; + s->reg_to_temp[reg] = arg; + } + } + assert(ts->val_type == TEMP_VAL_REG); + if (arg_ct->ct & TCG_CT_IALIAS) { + if (ts->fixed_reg) { + /* if fixed register, we must allocate a new register + if the alias is not the same register */ + if (arg != args[arg_ct->alias_index]) + goto allocate_in_reg; + } else { + /* if the input is aliased to an output and if it is + not dead after the instruction, we must allocate + a new register and move it */ + if (!IS_DEAD_IARG(i - nb_oargs)) + goto allocate_in_reg; + } + } + reg = ts->reg; + if (tcg_regset_test_reg(arg_ct->u.regs, reg)) { + /* nothing to do : the constraint is satisfied */ + } else { + allocate_in_reg: + /* allocate a new register matching the constraint + and move the temporary register into it */ + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + tcg_out_mov(s, reg, ts->reg); + } + new_args[i] = reg; + const_args[i] = 0; + tcg_regset_set_reg(allocated_regs, reg); + iarg_end: ; + } + + if (def->flags & TCG_OPF_BB_END) { + tcg_reg_alloc_bb_end(s, allocated_regs); + } else { + /* mark dead temporaries and free the associated registers */ + for(i = 0; i < nb_iargs; i++) { + arg = args[nb_oargs + i]; + if (IS_DEAD_IARG(i)) { + ts = &s->temps[arg]; + if (!ts->fixed_reg) { + if (ts->val_type == TEMP_VAL_REG) + s->reg_to_temp[ts->reg] = -1; + ts->val_type = TEMP_VAL_DEAD; + } + } + } + + if (def->flags & TCG_OPF_CALL_CLOBBER) { + /* XXX: permit generic clobber register list ? */ + for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { + if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) { + tcg_reg_free(s, reg); + } + } + /* XXX: for load/store we could do that only for the slow path + (i.e. when a memory callback is called) */ + + /* store globals and free associated registers (we assume the insn + can modify any global. */ + save_globals(s, allocated_regs); + } + + /* satisfy the output constraints */ + tcg_regset_set(allocated_regs, s->reserved_regs); + for(k = 0; k < nb_oargs; k++) { + i = def->sorted_args[k]; + arg = args[i]; + arg_ct = &def->args_ct[i]; + ts = &s->temps[arg]; + if (arg_ct->ct & TCG_CT_ALIAS) { + reg = new_args[arg_ct->alias_index]; + } else { + /* if fixed register, we try to use it */ + reg = ts->reg; + if (ts->fixed_reg && + tcg_regset_test_reg(arg_ct->u.regs, reg)) { + goto oarg_end; + } + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + } + tcg_regset_set_reg(allocated_regs, reg); + /* if a fixed register is used, then a move will be done afterwards */ + if (!ts->fixed_reg) { + if (ts->val_type == TEMP_VAL_REG) + s->reg_to_temp[ts->reg] = -1; + ts->val_type = TEMP_VAL_REG; + ts->reg = reg; + /* temp value is modified, so the value kept in memory is + potentially not the same */ + ts->mem_coherent = 0; + s->reg_to_temp[reg] = arg; + } + oarg_end: + new_args[i] = reg; + } + } + + /* emit instruction */ + tcg_out_op(s, opc, new_args, const_args); + + /* move the outputs in the correct register if needed */ + for(i = 0; i < nb_oargs; i++) { + ts = &s->temps[args[i]]; + reg = new_args[i]; + if (ts->fixed_reg && ts->reg != reg) { + tcg_out_mov(s, ts->reg, reg); + } + } +} + +#ifdef TCG_TARGET_STACK_GROWSUP +#define STACK_DIR(x) (-(x)) +#else +#define STACK_DIR(x) (x) +#endif + +static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, + int opc, const TCGArg *args, + unsigned int dead_iargs) +{ + int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params; + TCGArg arg, func_arg; + TCGTemp *ts; + tcg_target_long stack_offset, call_stack_size, func_addr; + int const_func_arg, allocate_args; + TCGRegSet allocated_regs; + const TCGArgConstraint *arg_ct; + + arg = *args++; + + nb_oargs = arg >> 16; + nb_iargs = arg & 0xffff; + nb_params = nb_iargs - 1; + + flags = args[nb_oargs + nb_iargs]; + + nb_regs = tcg_target_get_call_iarg_regs_count(flags); + if (nb_regs > nb_params) + nb_regs = nb_params; + + /* assign stack slots first */ + /* XXX: preallocate call stack */ + call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long); + call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & + ~(TCG_TARGET_STACK_ALIGN - 1); + allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); + if (allocate_args) { + tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size)); + } + + stack_offset = TCG_TARGET_CALL_STACK_OFFSET; + for(i = nb_regs; i < nb_params; i++) { + arg = args[nb_oargs + i]; +#ifdef TCG_TARGET_STACK_GROWSUP + stack_offset -= sizeof(tcg_target_long); +#endif + if (arg != TCG_CALL_DUMMY_ARG) { + ts = &s->temps[arg]; + if (ts->val_type == TEMP_VAL_REG) { + tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); + } else if (ts->val_type == TEMP_VAL_MEM) { + reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], + s->reserved_regs); + /* XXX: not correct if reading values from the stack */ + tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset); + } else if (ts->val_type == TEMP_VAL_CONST) { + reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], + s->reserved_regs); + /* XXX: sign extend may be needed on some targets */ + tcg_out_movi(s, ts->type, reg, ts->val); + tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset); + } else { + tcg_abort(); + } + } +#ifndef TCG_TARGET_STACK_GROWSUP + stack_offset += sizeof(tcg_target_long); +#endif + } + + /* assign input registers */ + tcg_regset_set(allocated_regs, s->reserved_regs); + for(i = 0; i < nb_regs; i++) { + arg = args[nb_oargs + i]; + if (arg != TCG_CALL_DUMMY_ARG) { + ts = &s->temps[arg]; + reg = tcg_target_call_iarg_regs[i]; + tcg_reg_free(s, reg); + if (ts->val_type == TEMP_VAL_REG) { + if (ts->reg != reg) { + tcg_out_mov(s, reg, ts->reg); + } + } else if (ts->val_type == TEMP_VAL_MEM) { + tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + } else if (ts->val_type == TEMP_VAL_CONST) { + /* XXX: sign extend ? */ + tcg_out_movi(s, ts->type, reg, ts->val); + } else { + tcg_abort(); + } + tcg_regset_set_reg(allocated_regs, reg); + } + } + + /* assign function address */ + func_arg = args[nb_oargs + nb_iargs - 1]; + arg_ct = &def->args_ct[0]; + ts = &s->temps[func_arg]; + func_addr = ts->val; + const_func_arg = 0; + if (ts->val_type == TEMP_VAL_MEM) { + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + func_arg = reg; + tcg_regset_set_reg(allocated_regs, reg); + } else if (ts->val_type == TEMP_VAL_REG) { + reg = ts->reg; + if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) { + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + tcg_out_mov(s, reg, ts->reg); + } + func_arg = reg; + tcg_regset_set_reg(allocated_regs, reg); + } else if (ts->val_type == TEMP_VAL_CONST) { + if (tcg_target_const_match(func_addr, arg_ct)) { + const_func_arg = 1; + func_arg = func_addr; + } else { + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + tcg_out_movi(s, ts->type, reg, func_addr); + func_arg = reg; + tcg_regset_set_reg(allocated_regs, reg); + } + } else { + tcg_abort(); + } + + + /* mark dead temporaries and free the associated registers */ + for(i = 0; i < nb_iargs; i++) { + arg = args[nb_oargs + i]; + if (IS_DEAD_IARG(i)) { + ts = &s->temps[arg]; + if (!ts->fixed_reg) { + if (ts->val_type == TEMP_VAL_REG) + s->reg_to_temp[ts->reg] = -1; + ts->val_type = TEMP_VAL_DEAD; + } + } + } + + /* clobber call registers */ + for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { + if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) { + tcg_reg_free(s, reg); + } + } + + /* store globals and free associated registers (we assume the call + can modify any global. */ + save_globals(s, allocated_regs); + + tcg_out_op(s, opc, &func_arg, &const_func_arg); + + if (allocate_args) { + tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size)); + } + + /* assign output registers and emit moves if needed */ + for(i = 0; i < nb_oargs; i++) { + arg = args[i]; + ts = &s->temps[arg]; + reg = tcg_target_call_oarg_regs[i]; + assert(s->reg_to_temp[reg] == -1); + if (ts->fixed_reg) { + if (ts->reg != reg) { + tcg_out_mov(s, ts->reg, reg); + } + } else { + if (ts->val_type == TEMP_VAL_REG) + s->reg_to_temp[ts->reg] = -1; + ts->val_type = TEMP_VAL_REG; + ts->reg = reg; + ts->mem_coherent = 0; + s->reg_to_temp[reg] = arg; + } + } + + return nb_iargs + nb_oargs + def->nb_cargs + 1; +} + +#ifdef CONFIG_PROFILER + +static int64_t dyngen_table_op_count[NB_OPS]; + +void dump_op_count(void) +{ + int i; + FILE *f; + f = fopen("/tmp/op1.log", "w"); + for(i = 0; i < INDEX_op_end; i++) { + fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, dyngen_table_op_count[i]); + } + fclose(f); + f = fopen("/tmp/op2.log", "w"); + for(i = INDEX_op_end; i < NB_OPS; i++) { + fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, dyngen_table_op_count[i]); + } + fclose(f); +} +#endif + + +static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, + long search_pc) +{ + int opc, op_index; + const TCGOpDef *def; + unsigned int dead_iargs; + const TCGArg *args; + +#ifdef DEBUG_DISAS + if (unlikely(loglevel & CPU_LOG_TB_OP)) { + fprintf(logfile, "OP:\n"); + tcg_dump_ops(s, logfile); + fprintf(logfile, "\n"); + } +#endif + +#ifdef CONFIG_PROFILER + s->la_time -= profile_getclock(); +#endif + tcg_liveness_analysis(s); +#ifdef CONFIG_PROFILER + s->la_time += profile_getclock(); +#endif + +#ifdef DEBUG_DISAS + if (unlikely(loglevel & CPU_LOG_TB_OP_OPT)) { + fprintf(logfile, "OP after la:\n"); + tcg_dump_ops(s, logfile); + fprintf(logfile, "\n"); + } +#endif + + tcg_reg_alloc_start(s); + + s->code_buf = gen_code_buf; + s->code_ptr = gen_code_buf; + + args = gen_opparam_buf; + op_index = 0; + + for(;;) { + opc = gen_opc_buf[op_index]; +#ifdef CONFIG_PROFILER + dyngen_table_op_count[opc]++; +#endif + def = &tcg_op_defs[opc]; +#if 0 + printf("%s: %d %d %d\n", def->name, + def->nb_oargs, def->nb_iargs, def->nb_cargs); + // dump_regs(s); +#endif + switch(opc) { + case INDEX_op_mov_i32: +#if TCG_TARGET_REG_BITS == 64 + case INDEX_op_mov_i64: +#endif + dead_iargs = s->op_dead_iargs[op_index]; + tcg_reg_alloc_mov(s, def, args, dead_iargs); + break; + case INDEX_op_movi_i32: +#if TCG_TARGET_REG_BITS == 64 + case INDEX_op_movi_i64: +#endif + tcg_reg_alloc_movi(s, args); + break; + case INDEX_op_debug_insn_start: + /* debug instruction */ + break; + case INDEX_op_nop: + case INDEX_op_nop1: + case INDEX_op_nop2: + case INDEX_op_nop3: + break; + case INDEX_op_nopn: + args += args[0]; + goto next; + case INDEX_op_discard: + { + TCGTemp *ts; + ts = &s->temps[args[0]]; + /* mark the temporary as dead */ + if (!ts->fixed_reg) { + if (ts->val_type == TEMP_VAL_REG) + s->reg_to_temp[ts->reg] = -1; + ts->val_type = TEMP_VAL_DEAD; + } + } + break; + case INDEX_op_set_label: + tcg_reg_alloc_bb_end(s, s->reserved_regs); + tcg_out_label(s, args[0], (long)s->code_ptr); + break; + case INDEX_op_call: + dead_iargs = s->op_dead_iargs[op_index]; + args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs); + goto next; + case INDEX_op_end: + goto the_end; + +#ifdef CONFIG_DYNGEN_OP + case 0 ... INDEX_op_end - 1: + /* legacy dyngen ops */ +#ifdef CONFIG_PROFILER + s->old_op_count++; +#endif + tcg_reg_alloc_bb_end(s, s->reserved_regs); + if (search_pc >= 0) { + s->code_ptr += def->copy_size; + args += def->nb_args; + } else { + args = dyngen_op(s, opc, args); + } + goto next; +#endif + default: + /* Note: in order to speed up the code, it would be much + faster to have specialized register allocator functions for + some common argument patterns */ + dead_iargs = s->op_dead_iargs[op_index]; + tcg_reg_alloc_op(s, def, opc, args, dead_iargs); + break; + } + args += def->nb_args; + next: + if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) { + return op_index; + } + op_index++; +#ifndef NDEBUG + check_regs(s); +#endif + } + the_end: + return -1; +} + +int dyngen_code(TCGContext *s, uint8_t *gen_code_buf) +{ +#ifdef CONFIG_PROFILER + { + int n; + n = (gen_opc_ptr - gen_opc_buf); + s->op_count += n; + if (n > s->op_count_max) + s->op_count_max = n; + + s->temp_count += s->nb_temps; + if (s->nb_temps > s->temp_count_max) + s->temp_count_max = s->nb_temps; + } +#endif + + tcg_gen_code_common(s, gen_code_buf, -1); + + /* flush instruction cache */ + flush_icache_range((unsigned long)gen_code_buf, + (unsigned long)s->code_ptr); + return s->code_ptr - gen_code_buf; +} + +/* Return the index of the micro operation such as the pc after is < + offset bytes from the start of the TB. The contents of gen_code_buf must + not be changed, though writing the same values is ok. + Return -1 if not found. */ +int dyngen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset) +{ + return tcg_gen_code_common(s, gen_code_buf, offset); +} + +#ifdef CONFIG_PROFILER +void tcg_dump_info(FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + TCGContext *s = &tcg_ctx; + int64_t tot; + + tot = s->interm_time + s->code_time; + cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n", + tot, tot / 2.4e9); + cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n", + s->tb_count, + s->tb_count1 - s->tb_count, + s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0); + cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n", + s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max); + cpu_fprintf(f, "old ops/total ops %0.1f%%\n", + s->op_count ? (double)s->old_op_count / s->op_count * 100.0 : 0); + cpu_fprintf(f, "deleted ops/TB %0.2f\n", + s->tb_count ? + (double)s->del_op_count / s->tb_count : 0); + cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n", + s->tb_count ? + (double)s->temp_count / s->tb_count : 0, + s->temp_count_max); + + cpu_fprintf(f, "cycles/op %0.1f\n", + s->op_count ? (double)tot / s->op_count : 0); + cpu_fprintf(f, "cycles/in byte %0.1f\n", + s->code_in_len ? (double)tot / s->code_in_len : 0); + cpu_fprintf(f, "cycles/out byte %0.1f\n", + s->code_out_len ? (double)tot / s->code_out_len : 0); + if (tot == 0) + tot = 1; + cpu_fprintf(f, " gen_interm time %0.1f%%\n", + (double)s->interm_time / tot * 100.0); + cpu_fprintf(f, " gen_code time %0.1f%%\n", + (double)s->code_time / tot * 100.0); + cpu_fprintf(f, "liveness/code time %0.1f%%\n", + (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0); + cpu_fprintf(f, "cpu_restore count %" PRId64 "\n", + s->restore_count); + cpu_fprintf(f, " avg cycles %0.1f\n", + s->restore_count ? (double)s->restore_time / s->restore_count : 0); + { + extern void dump_op_count(void); + dump_op_count(); + } +} +#else +void tcg_dump_info(FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + cpu_fprintf(f, "[TCG profiler not compiled]\n"); +} +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/tcg-dyngen.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/tcg-dyngen.c --- qemu-0.9.1/tcg/tcg-dyngen.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/tcg-dyngen.c 2008-05-20 01:01:55.000000000 +0100 @@ -0,0 +1,431 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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 +#include +#include +#include +#include +#include + +#include "config.h" +#include "osdep.h" + +#include "tcg.h" + +int __op_param1, __op_param2, __op_param3; +#if defined(__sparc__) || defined(__arm__) + void __op_gen_label1(){} + void __op_gen_label2(){} + void __op_gen_label3(){} +#else + int __op_gen_label1, __op_gen_label2, __op_gen_label3; +#endif +int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; + +#if 0 +#if defined(__s390__) +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +} +#elif defined(__ia64__) +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + while (start < stop) { + asm volatile ("fc %0" :: "r"(start)); + start += 32; + } + asm volatile (";;sync.i;;srlz.i;;"); +} +#elif defined(__powerpc__) + +#define MIN_CACHE_LINE_SIZE 8 /* conservative value */ + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + unsigned long p; + + start &= ~(MIN_CACHE_LINE_SIZE - 1); + stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1); + + for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { + asm volatile ("dcbst 0,%0" : : "r"(p) : "memory"); + } + asm volatile ("sync" : : : "memory"); + for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { + asm volatile ("icbi 0,%0" : : "r"(p) : "memory"); + } + asm volatile ("sync" : : : "memory"); + asm volatile ("isync" : : : "memory"); +} +#elif defined(__alpha__) +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + asm ("imb"); +} +#elif defined(__sparc__) +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + unsigned long p; + + p = start & ~(8UL - 1UL); + stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL); + + for (; p < stop; p += 8) + __asm__ __volatile__("flush\t%0" : : "r" (p)); +} +#elif defined(__arm__) +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + register unsigned long _beg __asm ("a1") = start; + register unsigned long _end __asm ("a2") = stop; + register unsigned long _flg __asm ("a3") = 0; + __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); +} +#elif defined(__mc68000) + +# include +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + cacheflush(start,FLUSH_SCOPE_LINE,FLUSH_CACHE_BOTH,stop-start+16); +} +#elif defined(__mips__) + +#include +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + _flush_cache ((void *)start, stop - start, BCACHE); +} +#else +#error unsupported CPU +#endif + +#ifdef __alpha__ + +register int gp asm("$29"); + +static inline void immediate_ldah(void *p, int val) { + uint32_t *dest = p; + long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff; + + *dest &= ~0xffff; + *dest |= high; + *dest |= 31 << 16; +} +static inline void immediate_lda(void *dest, int val) { + *(uint16_t *) dest = val; +} +void fix_bsr(void *p, int offset) { + uint32_t *dest = p; + *dest &= ~((1 << 21) - 1); + *dest |= (offset >> 2) & ((1 << 21) - 1); +} + +#endif /* __alpha__ */ + +#ifdef __ia64 + +/* Patch instruction with "val" where "mask" has 1 bits. */ +static inline void ia64_patch (uint64_t insn_addr, uint64_t mask, uint64_t val) +{ + uint64_t m0, m1, v0, v1, b0, b1, *b = (uint64_t *) (insn_addr & -16); +# define insn_mask ((1UL << 41) - 1) + unsigned long shift; + + b0 = b[0]; b1 = b[1]; + shift = 5 + 41 * (insn_addr % 16); /* 5 template, 3 x 41-bit insns */ + if (shift >= 64) { + m1 = mask << (shift - 64); + v1 = val << (shift - 64); + } else { + m0 = mask << shift; m1 = mask >> (64 - shift); + v0 = val << shift; v1 = val >> (64 - shift); + b[0] = (b0 & ~m0) | (v0 & m0); + } + b[1] = (b1 & ~m1) | (v1 & m1); +} + +static inline void ia64_patch_imm60 (uint64_t insn_addr, uint64_t val) +{ + ia64_patch(insn_addr, + 0x011ffffe000UL, + ( ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */ + | ((val & 0x00000000000fffffUL) << 13) /* bit 0 -> 13 */)); + ia64_patch(insn_addr - 1, 0x1fffffffffcUL, val >> 18); +} + +static inline void ia64_imm64 (void *insn, uint64_t val) +{ + /* Ignore the slot number of the relocation; GCC and Intel + toolchains differed for some time on whether IMM64 relocs are + against slot 1 (Intel) or slot 2 (GCC). */ + uint64_t insn_addr = (uint64_t) insn & ~3UL; + + ia64_patch(insn_addr + 2, + 0x01fffefe000UL, + ( ((val & 0x8000000000000000UL) >> 27) /* bit 63 -> 36 */ + | ((val & 0x0000000000200000UL) << 0) /* bit 21 -> 21 */ + | ((val & 0x00000000001f0000UL) << 6) /* bit 16 -> 22 */ + | ((val & 0x000000000000ff80UL) << 20) /* bit 7 -> 27 */ + | ((val & 0x000000000000007fUL) << 13) /* bit 0 -> 13 */) + ); + ia64_patch(insn_addr + 1, 0x1ffffffffffUL, val >> 22); +} + +static inline void ia64_imm60b (void *insn, uint64_t val) +{ + /* Ignore the slot number of the relocation; GCC and Intel + toolchains differed for some time on whether IMM64 relocs are + against slot 1 (Intel) or slot 2 (GCC). */ + uint64_t insn_addr = (uint64_t) insn & ~3UL; + + if (val + ((uint64_t) 1 << 59) >= (1UL << 60)) + fprintf(stderr, "%s: value %ld out of IMM60 range\n", + __FUNCTION__, (int64_t) val); + ia64_patch_imm60(insn_addr + 2, val); +} + +static inline void ia64_imm22 (void *insn, uint64_t val) +{ + if (val + (1 << 21) >= (1 << 22)) + fprintf(stderr, "%s: value %li out of IMM22 range\n", + __FUNCTION__, (int64_t)val); + ia64_patch((uint64_t) insn, 0x01fffcfe000UL, + ( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */ + | ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */ + | ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */ + | ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */)); +} + +/* Like ia64_imm22(), but also clear bits 20-21. For addl, this has + the effect of turning "addl rX=imm22,rY" into "addl + rX=imm22,r0". */ +static inline void ia64_imm22_r0 (void *insn, uint64_t val) +{ + if (val + (1 << 21) >= (1 << 22)) + fprintf(stderr, "%s: value %li out of IMM22 range\n", + __FUNCTION__, (int64_t)val); + ia64_patch((uint64_t) insn, 0x01fffcfe000UL | (0x3UL << 20), + ( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */ + | ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */ + | ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */ + | ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */)); +} + +static inline void ia64_imm21b (void *insn, uint64_t val) +{ + if (val + (1 << 20) >= (1 << 21)) + fprintf(stderr, "%s: value %li out of IMM21b range\n", + __FUNCTION__, (int64_t)val); + ia64_patch((uint64_t) insn, 0x11ffffe000UL, + ( ((val & 0x100000UL) << 16) /* bit 20 -> 36 */ + | ((val & 0x0fffffUL) << 13) /* bit 0 -> 13 */)); +} + +static inline void ia64_nop_b (void *insn) +{ + ia64_patch((uint64_t) insn, (1UL << 41) - 1, 2UL << 37); +} + +static inline void ia64_ldxmov(void *insn, uint64_t val) +{ + if (val + (1 << 21) < (1 << 22)) + ia64_patch((uint64_t) insn, 0x1fff80fe000UL, 8UL << 37); +} + +static inline int ia64_patch_ltoff(void *insn, uint64_t val, + int relaxable) +{ + if (relaxable && (val + (1 << 21) < (1 << 22))) { + ia64_imm22_r0(insn, val); + return 0; + } + return 1; +} + +struct ia64_fixup { + struct ia64_fixup *next; + void *addr; /* address that needs to be patched */ + long value; +}; + +#define IA64_PLT(insn, plt_index) \ +do { \ + struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \ + fixup->next = plt_fixes; \ + plt_fixes = fixup; \ + fixup->addr = (insn); \ + fixup->value = (plt_index); \ + plt_offset[(plt_index)] = 1; \ +} while (0) + +#define IA64_LTOFF(insn, val, relaxable) \ +do { \ + if (ia64_patch_ltoff(insn, val, relaxable)) { \ + struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \ + fixup->next = ltoff_fixes; \ + ltoff_fixes = fixup; \ + fixup->addr = (insn); \ + fixup->value = (val); \ + } \ +} while (0) + +static inline void ia64_apply_fixes (uint8_t **gen_code_pp, + struct ia64_fixup *ltoff_fixes, + uint64_t gp, + struct ia64_fixup *plt_fixes, + int num_plts, + unsigned long *plt_target, + unsigned int *plt_offset) +{ + static const uint8_t plt_bundle[] = { + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; movl r1=GP */ + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60, + + 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; brl IP */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0 + }; + uint8_t *gen_code_ptr = *gen_code_pp, *plt_start, *got_start; + uint64_t *vp; + struct ia64_fixup *fixup; + unsigned int offset = 0; + struct fdesc { + long ip; + long gp; + } *fdesc; + int i; + + if (plt_fixes) { + plt_start = gen_code_ptr; + + for (i = 0; i < num_plts; ++i) { + if (plt_offset[i]) { + plt_offset[i] = offset; + offset += sizeof(plt_bundle); + + fdesc = (struct fdesc *) plt_target[i]; + memcpy(gen_code_ptr, plt_bundle, sizeof(plt_bundle)); + ia64_imm64 (gen_code_ptr + 0x02, fdesc->gp); + ia64_imm60b(gen_code_ptr + 0x12, + (fdesc->ip - (long) (gen_code_ptr + 0x10)) >> 4); + gen_code_ptr += sizeof(plt_bundle); + } + } + + for (fixup = plt_fixes; fixup; fixup = fixup->next) + ia64_imm21b(fixup->addr, + ((long) plt_start + plt_offset[fixup->value] + - ((long) fixup->addr & ~0xf)) >> 4); + } + + got_start = gen_code_ptr; + + /* First, create the GOT: */ + for (fixup = ltoff_fixes; fixup; fixup = fixup->next) { + /* first check if we already have this value in the GOT: */ + for (vp = (uint64_t *) got_start; vp < (uint64_t *) gen_code_ptr; ++vp) + if (*vp == fixup->value) + break; + if (vp == (uint64_t *) gen_code_ptr) { + /* Nope, we need to put the value in the GOT: */ + *vp = fixup->value; + gen_code_ptr += 8; + } + ia64_imm22(fixup->addr, (long) vp - gp); + } + /* Keep code ptr aligned. */ + if ((long) gen_code_ptr & 15) + gen_code_ptr += 8; + *gen_code_pp = gen_code_ptr; +} +#endif +#endif + +#ifdef CONFIG_DYNGEN_OP + +#if defined __hppa__ +struct hppa_branch_stub { + uint32_t *location; + long target; + struct hppa_branch_stub *next; +}; + +#define HPPA_RECORD_BRANCH(LIST, LOC, TARGET) \ +do { \ + struct hppa_branch_stub *stub = alloca(sizeof(struct hppa_branch_stub)); \ + stub->location = LOC; \ + stub->target = TARGET; \ + stub->next = LIST; \ + LIST = stub; \ +} while (0) + +static inline void hppa_process_stubs(struct hppa_branch_stub *stub, + uint8_t **gen_code_pp) +{ + uint32_t *s = (uint32_t *)*gen_code_pp; + uint32_t *p = s + 1; + + if (!stub) return; + + for (; stub != NULL; stub = stub->next) { + unsigned long l = (unsigned long)p; + /* stub: + * ldil L'target, %r1 + * be,n R'target(%sr4,%r1) + */ + *p++ = 0x20200000 | reassemble_21(lrsel(stub->target, 0)); + *p++ = 0xe0202002 | (reassemble_17(rrsel(stub->target, 0) >> 2)); + hppa_patch17f(stub->location, l, 0); + } + /* b,l,n stub,%r0 */ + *s = 0xe8000002 | reassemble_17((p - s) - 2); + *gen_code_pp = (uint8_t *)p; +} +#endif /* __hppa__ */ + +const TCGArg *dyngen_op(TCGContext *s, int opc, const TCGArg *opparam_ptr) +{ + uint8_t *gen_code_ptr; + +#ifdef __hppa__ + struct hppa_branch_stub *hppa_stubs = NULL; +#endif + + gen_code_ptr = s->code_ptr; + switch(opc) { + +/* op.h is dynamically generated by dyngen.c from op.c */ +#include "op.h" + + default: + tcg_abort(); + } + +#ifdef __hppa__ + hppa_process_stubs(hppa_stubs, &gen_code_ptr); +#endif + + s->code_ptr = gen_code_ptr; + return opparam_ptr; +} +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/tcg.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/tcg.h --- qemu-0.9.1/tcg/tcg.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/tcg.h 2008-10-21 12:30:45.000000000 +0100 @@ -0,0 +1,423 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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 "tcg-target.h" + +#if TCG_TARGET_REG_BITS == 32 +typedef int32_t tcg_target_long; +typedef uint32_t tcg_target_ulong; +#define TCG_PRIlx PRIx32 +#define TCG_PRIld PRId32 +#elif TCG_TARGET_REG_BITS == 64 +typedef int64_t tcg_target_long; +typedef uint64_t tcg_target_ulong; +#define TCG_PRIlx PRIx64 +#define TCG_PRIld PRId64 +#else +#error unsupported +#endif + +#if TCG_TARGET_NB_REGS <= 32 +typedef uint32_t TCGRegSet; +#elif TCG_TARGET_NB_REGS <= 64 +typedef uint64_t TCGRegSet; +#else +#error unsupported +#endif + +enum { +#define DEF(s, n, copy_size) INDEX_op_ ## s, +#include "tcg-opc.h" +#undef DEF + NB_OPS, +}; + +#define tcg_regset_clear(d) (d) = 0 +#define tcg_regset_set(d, s) (d) = (s) +#define tcg_regset_set32(d, reg, val32) (d) |= (val32) << (reg) +#define tcg_regset_set_reg(d, r) (d) |= 1 << (r) +#define tcg_regset_reset_reg(d, r) (d) &= ~(1 << (r)) +#define tcg_regset_test_reg(d, r) (((d) >> (r)) & 1) +#define tcg_regset_or(d, a, b) (d) = (a) | (b) +#define tcg_regset_and(d, a, b) (d) = (a) & (b) +#define tcg_regset_andnot(d, a, b) (d) = (a) & ~(b) +#define tcg_regset_not(d, a) (d) = ~(a) + +typedef struct TCGRelocation { + struct TCGRelocation *next; + int type; + uint8_t *ptr; + tcg_target_long addend; +} TCGRelocation; + +typedef struct TCGLabel { + int has_value; + union { + tcg_target_ulong value; + TCGRelocation *first_reloc; + } u; +} TCGLabel; + +typedef struct TCGPool { + struct TCGPool *next; + int size; + uint8_t data[0] __attribute__ ((aligned)); +} TCGPool; + +#define TCG_POOL_CHUNK_SIZE 32768 + +#define TCG_MAX_LABELS 512 + +#define TCG_MAX_TEMPS 512 + +/* when the size of the arguments of a called function is smaller than + this value, they are statically allocated in the TB stack frame */ +#define TCG_STATIC_CALL_ARGS_SIZE 128 + +typedef int TCGType; + +#define TCG_TYPE_I32 0 +#define TCG_TYPE_I64 1 +#define TCG_TYPE_COUNT 2 /* number of different types */ + +#if TCG_TARGET_REG_BITS == 32 +#define TCG_TYPE_PTR TCG_TYPE_I32 +#else +#define TCG_TYPE_PTR TCG_TYPE_I64 +#endif + +typedef tcg_target_ulong TCGArg; + +/* Define a type and accessor macros for varables. Using a struct is + nice because it gives some level of type safely. Ideally the compiler + be able to see through all this. However in practice this is not true, + expecially on targets with braindamaged ABIs (e.g. i386). + We use plain int by default to avoid this runtime overhead. + Users of tcg_gen_* don't need to know about any of this, and should + treat TCGv as an opaque type. */ + +//#define DEBUG_TCGV 1 + +#ifdef DEBUG_TCGV + +typedef struct +{ + int n; +} TCGv; + +#define MAKE_TCGV(i) __extension__ \ + ({ TCGv make_tcgv_tmp = {i}; make_tcgv_tmp;}) +#define GET_TCGV(t) ((t).n) +#if TCG_TARGET_REG_BITS == 32 +#define TCGV_HIGH(t) MAKE_TCGV(GET_TCGV(t) + 1) +#endif + +#else /* !DEBUG_TCGV */ + +typedef int TCGv; +#define MAKE_TCGV(x) (x) +#define GET_TCGV(t) (t) +#if TCG_TARGET_REG_BITS == 32 +#define TCGV_HIGH(t) ((t) + 1) +#endif + +#endif /* DEBUG_TCGV */ + +/* Dummy definition to avoid compiler warnings. */ +#define TCGV_UNUSED(x) x = MAKE_TCGV(-1) + +/* call flags */ +#define TCG_CALL_TYPE_MASK 0x000f +#define TCG_CALL_TYPE_STD 0x0000 /* standard C call */ +#define TCG_CALL_TYPE_REGPARM_1 0x0001 /* i386 style regparm call (1 reg) */ +#define TCG_CALL_TYPE_REGPARM_2 0x0002 /* i386 style regparm call (2 regs) */ +#define TCG_CALL_TYPE_REGPARM 0x0003 /* i386 style regparm call (3 regs) */ +/* A pure function only reads its arguments and globals variables and + cannot raise exceptions. Hence a call to a pure function can be + safely suppressed if the return value is not used. */ +#define TCG_CALL_PURE 0x0010 + +/* used to align parameters */ +#define TCG_CALL_DUMMY_TCGV MAKE_TCGV(-1) +#define TCG_CALL_DUMMY_ARG ((TCGArg)(-1)) + +typedef enum { + TCG_COND_EQ, + TCG_COND_NE, + TCG_COND_LT, + TCG_COND_GE, + TCG_COND_LE, + TCG_COND_GT, + /* unsigned */ + TCG_COND_LTU, + TCG_COND_GEU, + TCG_COND_LEU, + TCG_COND_GTU, +} TCGCond; + +#define TEMP_VAL_DEAD 0 +#define TEMP_VAL_REG 1 +#define TEMP_VAL_MEM 2 +#define TEMP_VAL_CONST 3 + +/* XXX: optimize memory layout */ +typedef struct TCGTemp { + TCGType base_type; + TCGType type; + int val_type; + int reg; + tcg_target_long val; + int mem_reg; + tcg_target_long mem_offset; + unsigned int fixed_reg:1; + unsigned int mem_coherent:1; + unsigned int mem_allocated:1; + unsigned int temp_local:1; /* If true, the temp is saved accross + basic blocks. Otherwise, it is not + preserved accross basic blocks. */ + unsigned int temp_allocated:1; /* never used for code gen */ + /* index of next free temp of same base type, -1 if end */ + int next_free_temp; + const char *name; +} TCGTemp; + +typedef struct TCGHelperInfo { + tcg_target_ulong func; + const char *name; +} TCGHelperInfo; + +typedef struct TCGContext TCGContext; + +struct TCGContext { + uint8_t *pool_cur, *pool_end; + TCGPool *pool_first, *pool_current; + TCGLabel *labels; + int nb_labels; + TCGTemp *temps; /* globals first, temps after */ + int nb_globals; + int nb_temps; + /* index of free temps, -1 if none */ + int first_free_temp[TCG_TYPE_COUNT * 2]; + + /* goto_tb support */ + uint8_t *code_buf; + unsigned long *tb_next; + uint16_t *tb_next_offset; + uint16_t *tb_jmp_offset; /* != NULL if USE_DIRECT_JUMP */ + + /* liveness analysis */ + uint16_t *op_dead_iargs; /* for each operation, each bit tells if the + corresponding input argument is dead */ + + /* tells in which temporary a given register is. It does not take + into account fixed registers */ + int reg_to_temp[TCG_TARGET_NB_REGS]; + TCGRegSet reserved_regs; + tcg_target_long current_frame_offset; + tcg_target_long frame_start; + tcg_target_long frame_end; + int frame_reg; + + uint8_t *code_ptr; + TCGTemp static_temps[TCG_MAX_TEMPS]; + + TCGHelperInfo *helpers; + int nb_helpers; + int allocated_helpers; + int helpers_sorted; + +#ifdef CONFIG_PROFILER + /* profiling info */ + int64_t tb_count1; + int64_t tb_count; + int64_t op_count; /* total insn count */ + int op_count_max; /* max insn per TB */ + int64_t temp_count; + int temp_count_max; + int64_t old_op_count; + int64_t del_op_count; + int64_t code_in_len; + int64_t code_out_len; + int64_t interm_time; + int64_t code_time; + int64_t la_time; + int64_t restore_count; + int64_t restore_time; +#endif +}; + +extern TCGContext tcg_ctx; +extern uint16_t *gen_opc_ptr; +extern TCGArg *gen_opparam_ptr; +extern uint16_t gen_opc_buf[]; +extern TCGArg gen_opparam_buf[]; + +/* pool based memory allocation */ + +void *tcg_malloc_internal(TCGContext *s, int size); +void tcg_pool_reset(TCGContext *s); +void tcg_pool_delete(TCGContext *s); + +static inline void *tcg_malloc(int size) +{ + TCGContext *s = &tcg_ctx; + uint8_t *ptr, *ptr_end; + size = (size + sizeof(long) - 1) & ~(sizeof(long) - 1); + ptr = s->pool_cur; + ptr_end = ptr + size; + if (unlikely(ptr_end > s->pool_end)) { + return tcg_malloc_internal(&tcg_ctx, size); + } else { + s->pool_cur = ptr_end; + return ptr; + } +} + +void tcg_context_init(TCGContext *s); +void tcg_func_start(TCGContext *s); + +int dyngen_code(TCGContext *s, uint8_t *gen_code_buf); +int dyngen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset); + +void tcg_set_frame(TCGContext *s, int reg, + tcg_target_long start, tcg_target_long size); +TCGv tcg_global_reg_new(TCGType type, int reg, const char *name); +TCGv tcg_global_reg2_new_hack(TCGType type, int reg1, int reg2, + const char *name); +TCGv tcg_global_mem_new(TCGType type, int reg, tcg_target_long offset, + const char *name); +TCGv tcg_temp_new_internal(TCGType type, int temp_local); +static inline TCGv tcg_temp_new(TCGType type) +{ + return tcg_temp_new_internal(type, 0); +} +static inline TCGv tcg_temp_local_new(TCGType type) +{ + return tcg_temp_new_internal(type, 1); +} +void tcg_temp_free(TCGv arg); +char *tcg_get_arg_str(TCGContext *s, char *buf, int buf_size, TCGv arg); +void tcg_dump_info(FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); + +#define TCG_CT_ALIAS 0x80 +#define TCG_CT_IALIAS 0x40 +#define TCG_CT_REG 0x01 +#define TCG_CT_CONST 0x02 /* any constant of register size */ + +typedef struct TCGArgConstraint { + uint16_t ct; + uint8_t alias_index; + union { + TCGRegSet regs; + } u; +} TCGArgConstraint; + +#define TCG_MAX_OP_ARGS 16 + +#define TCG_OPF_BB_END 0x01 /* instruction defines the end of a basic + block */ +#define TCG_OPF_CALL_CLOBBER 0x02 /* instruction clobbers call registers + and potentially update globals. */ +#define TCG_OPF_SIDE_EFFECTS 0x04 /* instruction has side effects : it + cannot be removed if its output + are not used */ + +typedef struct TCGOpDef { + const char *name; + uint8_t nb_oargs, nb_iargs, nb_cargs, nb_args; + uint8_t flags; + uint16_t copy_size; + TCGArgConstraint *args_ct; + int *sorted_args; +} TCGOpDef; + +typedef struct TCGTargetOpDef { + int op; + const char *args_ct_str[TCG_MAX_OP_ARGS]; +} TCGTargetOpDef; + +extern TCGOpDef tcg_op_defs[]; + +void tcg_target_init(TCGContext *s); +void tcg_target_qemu_prologue(TCGContext *s); + +#define tcg_abort() \ +do {\ + fprintf(stderr, "%s:%d: tcg fatal error\n", __FILE__, __LINE__);\ + abort();\ +} while (0) + +void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs); + +void tcg_gen_call(TCGContext *s, TCGv func, unsigned int flags, + unsigned int nb_rets, const TCGv *rets, + unsigned int nb_params, const TCGv *args1); +void tcg_gen_shifti_i64(TCGv ret, TCGv arg1, + int c, int right, int arith); + +/* only used for debugging purposes */ +void tcg_register_helper(void *func, const char *name); +#define TCG_HELPER(func) tcg_register_helper(func, #func) +const char *tcg_helper_get_name(TCGContext *s, void *func); +void tcg_dump_ops(TCGContext *s, FILE *outfile); + +void dump_ops(const uint16_t *opc_buf, const TCGArg *opparam_buf); +TCGv tcg_const_i32(int32_t val); +TCGv tcg_const_i64(int64_t val); +TCGv tcg_const_local_i32(int32_t val); +TCGv tcg_const_local_i64(int64_t val); + +#if TCG_TARGET_REG_BITS == 32 +#define tcg_const_ptr tcg_const_i32 +#define tcg_add_ptr tcg_add_i32 +#define tcg_sub_ptr tcg_sub_i32 +#else +#define tcg_const_ptr tcg_const_i64 +#define tcg_add_ptr tcg_add_i64 +#define tcg_sub_ptr tcg_sub_i64 +#endif + +void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, + int label_index, long addend); +const TCGArg *tcg_gen_code_op(TCGContext *s, int opc, const TCGArg *args1, + unsigned int dead_iargs); + +const TCGArg *dyngen_op(TCGContext *s, int opc, const TCGArg *opparam_ptr); + +/* tcg-runtime.c */ +int64_t tcg_helper_shl_i64(int64_t arg1, int64_t arg2); +int64_t tcg_helper_shr_i64(int64_t arg1, int64_t arg2); +int64_t tcg_helper_sar_i64(int64_t arg1, int64_t arg2); +int64_t tcg_helper_div_i64(int64_t arg1, int64_t arg2); +int64_t tcg_helper_rem_i64(int64_t arg1, int64_t arg2); +uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2); +uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2); + +extern uint8_t code_gen_prologue[]; +#if defined(__powerpc__) && !defined(__powerpc64__) +#define tcg_qemu_tb_exec(tb_ptr) \ + ((long REGPARM __attribute__ ((longcall)) (*)(void *))code_gen_prologue)(tb_ptr) +#else +#define tcg_qemu_tb_exec(tb_ptr) ((long REGPARM (*)(void *))code_gen_prologue)(tb_ptr) +#endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/tcg-opc.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/tcg-opc.h --- qemu-0.9.1/tcg/tcg-opc.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/tcg-opc.h 2008-05-25 19:21:31.000000000 +0100 @@ -0,0 +1,238 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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. + */ +#ifdef CONFIG_DYNGEN_OP +#include "dyngen-opc.h" +#endif + +#ifndef DEF2 +#define DEF2(name, oargs, iargs, cargs, flags) DEF(name, oargs + iargs + cargs, 0) +#endif + +/* predefined ops */ +DEF2(end, 0, 0, 0, 0) /* must be kept first */ +DEF2(nop, 0, 0, 0, 0) +DEF2(nop1, 0, 0, 1, 0) +DEF2(nop2, 0, 0, 2, 0) +DEF2(nop3, 0, 0, 3, 0) +DEF2(nopn, 0, 0, 1, 0) /* variable number of parameters */ + +DEF2(discard, 1, 0, 0, 0) + +DEF2(set_label, 0, 0, 1, 0) +DEF2(call, 0, 1, 2, TCG_OPF_SIDE_EFFECTS) /* variable number of parameters */ +DEF2(jmp, 0, 1, 0, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +DEF2(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) + +DEF2(mov_i32, 1, 1, 0, 0) +DEF2(movi_i32, 1, 0, 1, 0) +/* load/store */ +DEF2(ld8u_i32, 1, 1, 1, 0) +DEF2(ld8s_i32, 1, 1, 1, 0) +DEF2(ld16u_i32, 1, 1, 1, 0) +DEF2(ld16s_i32, 1, 1, 1, 0) +DEF2(ld_i32, 1, 1, 1, 0) +DEF2(st8_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st16_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +/* arith */ +DEF2(add_i32, 1, 2, 0, 0) +DEF2(sub_i32, 1, 2, 0, 0) +DEF2(mul_i32, 1, 2, 0, 0) +#ifdef TCG_TARGET_HAS_div_i32 +DEF2(div_i32, 1, 2, 0, 0) +DEF2(divu_i32, 1, 2, 0, 0) +DEF2(rem_i32, 1, 2, 0, 0) +DEF2(remu_i32, 1, 2, 0, 0) +#else +DEF2(div2_i32, 2, 3, 0, 0) +DEF2(divu2_i32, 2, 3, 0, 0) +#endif +DEF2(and_i32, 1, 2, 0, 0) +DEF2(or_i32, 1, 2, 0, 0) +DEF2(xor_i32, 1, 2, 0, 0) +/* shifts */ +DEF2(shl_i32, 1, 2, 0, 0) +DEF2(shr_i32, 1, 2, 0, 0) +DEF2(sar_i32, 1, 2, 0, 0) + +DEF2(brcond_i32, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +#if TCG_TARGET_REG_BITS == 32 +DEF2(add2_i32, 2, 4, 0, 0) +DEF2(sub2_i32, 2, 4, 0, 0) +DEF2(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +DEF2(mulu2_i32, 2, 2, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext8s_i32 +DEF2(ext8s_i32, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext16s_i32 +DEF2(ext16s_i32, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_bswap_i32 +DEF2(bswap_i32, 1, 1, 0, 0) +#endif + +#if TCG_TARGET_REG_BITS == 64 +DEF2(mov_i64, 1, 1, 0, 0) +DEF2(movi_i64, 1, 0, 1, 0) +/* load/store */ +DEF2(ld8u_i64, 1, 1, 1, 0) +DEF2(ld8s_i64, 1, 1, 1, 0) +DEF2(ld16u_i64, 1, 1, 1, 0) +DEF2(ld16s_i64, 1, 1, 1, 0) +DEF2(ld32u_i64, 1, 1, 1, 0) +DEF2(ld32s_i64, 1, 1, 1, 0) +DEF2(ld_i64, 1, 1, 1, 0) +DEF2(st8_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st16_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st32_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +/* arith */ +DEF2(add_i64, 1, 2, 0, 0) +DEF2(sub_i64, 1, 2, 0, 0) +DEF2(mul_i64, 1, 2, 0, 0) +#ifdef TCG_TARGET_HAS_div_i64 +DEF2(div_i64, 1, 2, 0, 0) +DEF2(divu_i64, 1, 2, 0, 0) +DEF2(rem_i64, 1, 2, 0, 0) +DEF2(remu_i64, 1, 2, 0, 0) +#else +DEF2(div2_i64, 2, 3, 0, 0) +DEF2(divu2_i64, 2, 3, 0, 0) +#endif +DEF2(and_i64, 1, 2, 0, 0) +DEF2(or_i64, 1, 2, 0, 0) +DEF2(xor_i64, 1, 2, 0, 0) +/* shifts */ +DEF2(shl_i64, 1, 2, 0, 0) +DEF2(shr_i64, 1, 2, 0, 0) +DEF2(sar_i64, 1, 2, 0, 0) + +DEF2(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +#ifdef TCG_TARGET_HAS_ext8s_i64 +DEF2(ext8s_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext16s_i64 +DEF2(ext16s_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext32s_i64 +DEF2(ext32s_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_bswap_i64 +DEF2(bswap_i64, 1, 1, 0, 0) +#endif +#endif +#ifdef TCG_TARGET_HAS_neg_i32 +DEF2(neg_i32, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_neg_i64 +DEF2(neg_i64, 1, 1, 0, 0) +#endif + +/* QEMU specific */ +#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS +DEF2(debug_insn_start, 0, 0, 2, 0) +#else +DEF2(debug_insn_start, 0, 0, 1, 0) +#endif +DEF2(exit_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +DEF2(goto_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +/* Note: even if TARGET_LONG_BITS is not defined, the INDEX_op + constants must be defined */ +#if TCG_TARGET_REG_BITS == 32 +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld8u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld8s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld16u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld16s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld32u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld32s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld64, 2, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld64, 2, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif + +#if TARGET_LONG_BITS == 32 +DEF2(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_st8, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_st16, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_st32, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_st64, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_st64, 0, 4, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif + +#else /* TCG_TARGET_REG_BITS == 32 */ + +DEF2(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld64, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) + +DEF2(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_st64, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) + +#endif /* TCG_TARGET_REG_BITS != 32 */ + +#undef DEF2 diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/tcg-op.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/tcg-op.h --- qemu-0.9.1/tcg/tcg-op.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/tcg-op.h 2008-11-03 13:30:50.000000000 +0000 @@ -0,0 +1,1970 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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 "tcg.h" + +#ifdef CONFIG_DYNGEN_OP +/* legacy dyngen operations */ +#include "gen-op.h" +#endif + +int gen_new_label(void); + +static inline void tcg_gen_op1(int opc, TCGv arg1) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV(arg1); +} + +static inline void tcg_gen_op1i(int opc, TCGArg arg1) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = arg1; +} + +static inline void tcg_gen_op2(int opc, TCGv arg1, TCGv arg2) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV(arg1); + *gen_opparam_ptr++ = GET_TCGV(arg2); +} + +static inline void tcg_gen_op2i(int opc, TCGv arg1, TCGArg arg2) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV(arg1); + *gen_opparam_ptr++ = arg2; +} + +static inline void tcg_gen_op2ii(int opc, TCGArg arg1, TCGArg arg2) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = arg1; + *gen_opparam_ptr++ = arg2; +} + +static inline void tcg_gen_op3(int opc, TCGv arg1, TCGv arg2, TCGv arg3) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV(arg1); + *gen_opparam_ptr++ = GET_TCGV(arg2); + *gen_opparam_ptr++ = GET_TCGV(arg3); +} + +static inline void tcg_gen_op3i(int opc, TCGv arg1, TCGv arg2, TCGArg arg3) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV(arg1); + *gen_opparam_ptr++ = GET_TCGV(arg2); + *gen_opparam_ptr++ = arg3; +} + +static inline void tcg_gen_op4(int opc, TCGv arg1, TCGv arg2, TCGv arg3, + TCGv arg4) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV(arg1); + *gen_opparam_ptr++ = GET_TCGV(arg2); + *gen_opparam_ptr++ = GET_TCGV(arg3); + *gen_opparam_ptr++ = GET_TCGV(arg4); +} + +static inline void tcg_gen_op4i(int opc, TCGv arg1, TCGv arg2, TCGv arg3, + TCGArg arg4) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV(arg1); + *gen_opparam_ptr++ = GET_TCGV(arg2); + *gen_opparam_ptr++ = GET_TCGV(arg3); + *gen_opparam_ptr++ = arg4; +} + +static inline void tcg_gen_op4ii(int opc, TCGv arg1, TCGv arg2, TCGArg arg3, + TCGArg arg4) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV(arg1); + *gen_opparam_ptr++ = GET_TCGV(arg2); + *gen_opparam_ptr++ = arg3; + *gen_opparam_ptr++ = arg4; +} + +static inline void tcg_gen_op5(int opc, TCGv arg1, TCGv arg2, + TCGv arg3, TCGv arg4, + TCGv arg5) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV(arg1); + *gen_opparam_ptr++ = GET_TCGV(arg2); + *gen_opparam_ptr++ = GET_TCGV(arg3); + *gen_opparam_ptr++ = GET_TCGV(arg4); + *gen_opparam_ptr++ = GET_TCGV(arg5); +} + +static inline void tcg_gen_op5i(int opc, TCGv arg1, TCGv arg2, + TCGv arg3, TCGv arg4, + TCGArg arg5) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV(arg1); + *gen_opparam_ptr++ = GET_TCGV(arg2); + *gen_opparam_ptr++ = GET_TCGV(arg3); + *gen_opparam_ptr++ = GET_TCGV(arg4); + *gen_opparam_ptr++ = arg5; +} + +static inline void tcg_gen_op6(int opc, TCGv arg1, TCGv arg2, + TCGv arg3, TCGv arg4, + TCGv arg5, TCGv arg6) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV(arg1); + *gen_opparam_ptr++ = GET_TCGV(arg2); + *gen_opparam_ptr++ = GET_TCGV(arg3); + *gen_opparam_ptr++ = GET_TCGV(arg4); + *gen_opparam_ptr++ = GET_TCGV(arg5); + *gen_opparam_ptr++ = GET_TCGV(arg6); +} + +static inline void tcg_gen_op6ii(int opc, TCGv arg1, TCGv arg2, + TCGv arg3, TCGv arg4, + TCGArg arg5, TCGArg arg6) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV(arg1); + *gen_opparam_ptr++ = GET_TCGV(arg2); + *gen_opparam_ptr++ = GET_TCGV(arg3); + *gen_opparam_ptr++ = GET_TCGV(arg4); + *gen_opparam_ptr++ = arg5; + *gen_opparam_ptr++ = arg6; +} + +static inline void gen_set_label(int n) +{ + tcg_gen_op1i(INDEX_op_set_label, n); +} + +static inline void tcg_gen_br(int label) +{ + tcg_gen_op1i(INDEX_op_br, label); +} + +static inline void tcg_gen_mov_i32(TCGv ret, TCGv arg) +{ + if (GET_TCGV(ret) != GET_TCGV(arg)) + tcg_gen_op2(INDEX_op_mov_i32, ret, arg); +} + +static inline void tcg_gen_movi_i32(TCGv ret, int32_t arg) +{ + tcg_gen_op2i(INDEX_op_movi_i32, ret, arg); +} + +/* helper calls */ +#define TCG_HELPER_CALL_FLAGS 0 + +static inline void tcg_gen_helper_0_0(void *func) +{ + TCGv t0; + t0 = tcg_const_ptr((tcg_target_long)func); + tcg_gen_call(&tcg_ctx, + t0, TCG_HELPER_CALL_FLAGS, + 0, NULL, 0, NULL); + tcg_temp_free(t0); +} + +static inline void tcg_gen_helper_0_1(void *func, TCGv arg) +{ + TCGv t0; + t0 = tcg_const_ptr((tcg_target_long)func); + tcg_gen_call(&tcg_ctx, + t0, TCG_HELPER_CALL_FLAGS, + 0, NULL, 1, &arg); + tcg_temp_free(t0); +} + +static inline void tcg_gen_helper_0_2(void *func, TCGv arg1, TCGv arg2) +{ + TCGv args[2]; + TCGv t0; + args[0] = arg1; + args[1] = arg2; + t0 = tcg_const_ptr((tcg_target_long)func); + tcg_gen_call(&tcg_ctx, + t0, TCG_HELPER_CALL_FLAGS, + 0, NULL, 2, args); + tcg_temp_free(t0); +} + +static inline void tcg_gen_helper_0_3(void *func, + TCGv arg1, TCGv arg2, TCGv arg3) +{ + TCGv args[3]; + TCGv t0; + args[0] = arg1; + args[1] = arg2; + args[2] = arg3; + t0 = tcg_const_ptr((tcg_target_long)func); + tcg_gen_call(&tcg_ctx, + t0, TCG_HELPER_CALL_FLAGS, + 0, NULL, 3, args); + tcg_temp_free(t0); +} + +static inline void tcg_gen_helper_0_4(void *func, TCGv arg1, TCGv arg2, + TCGv arg3, TCGv arg4) +{ + TCGv args[4]; + TCGv t0; + args[0] = arg1; + args[1] = arg2; + args[2] = arg3; + args[3] = arg4; + t0 = tcg_const_ptr((tcg_target_long)func); + tcg_gen_call(&tcg_ctx, + t0, TCG_HELPER_CALL_FLAGS, + 0, NULL, 4, args); + tcg_temp_free(t0); +} + +static inline void tcg_gen_helper_1_0(void *func, TCGv ret) +{ + TCGv t0; + t0 = tcg_const_ptr((tcg_target_long)func); + tcg_gen_call(&tcg_ctx, + t0, TCG_HELPER_CALL_FLAGS, + 1, &ret, 0, NULL); + tcg_temp_free(t0); +} + +static inline void tcg_gen_helper_1_1(void *func, TCGv ret, TCGv arg1) +{ + TCGv t0; + t0 = tcg_const_ptr((tcg_target_long)func); + tcg_gen_call(&tcg_ctx, + t0, TCG_HELPER_CALL_FLAGS, + 1, &ret, 1, &arg1); + tcg_temp_free(t0); +} + +static inline void tcg_gen_helper_1_2(void *func, TCGv ret, + TCGv arg1, TCGv arg2) +{ + TCGv args[2]; + TCGv t0; + args[0] = arg1; + args[1] = arg2; + t0 = tcg_const_ptr((tcg_target_long)func); + tcg_gen_call(&tcg_ctx, + t0, TCG_HELPER_CALL_FLAGS, + 1, &ret, 2, args); + tcg_temp_free(t0); +} + +static inline void tcg_gen_helper_1_3(void *func, TCGv ret, + TCGv arg1, TCGv arg2, TCGv arg3) +{ + TCGv args[3]; + TCGv t0; + args[0] = arg1; + args[1] = arg2; + args[2] = arg3; + t0 = tcg_const_ptr((tcg_target_long)func); + tcg_gen_call(&tcg_ctx, + t0, TCG_HELPER_CALL_FLAGS, + 1, &ret, 3, args); + tcg_temp_free(t0); +} + +static inline void tcg_gen_helper_1_4(void *func, TCGv ret, + TCGv arg1, TCGv arg2, TCGv arg3, + TCGv arg4) +{ + TCGv args[4]; + TCGv t0; + args[0] = arg1; + args[1] = arg2; + args[2] = arg3; + args[3] = arg4; + t0 = tcg_const_ptr((tcg_target_long)func); + tcg_gen_call(&tcg_ctx, + t0, TCG_HELPER_CALL_FLAGS, + 1, &ret, 4, args); + tcg_temp_free(t0); +} + +/* 32 bit ops */ + +static inline void tcg_gen_ld8u_i32(TCGv ret, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_ld8u_i32, ret, arg2, offset); +} + +static inline void tcg_gen_ld8s_i32(TCGv ret, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_ld8s_i32, ret, arg2, offset); +} + +static inline void tcg_gen_ld16u_i32(TCGv ret, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_ld16u_i32, ret, arg2, offset); +} + +static inline void tcg_gen_ld16s_i32(TCGv ret, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_ld16s_i32, ret, arg2, offset); +} + +static inline void tcg_gen_ld_i32(TCGv ret, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_ld_i32, ret, arg2, offset); +} + +static inline void tcg_gen_st8_i32(TCGv arg1, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_st8_i32, arg1, arg2, offset); +} + +static inline void tcg_gen_st16_i32(TCGv arg1, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_st16_i32, arg1, arg2, offset); +} + +static inline void tcg_gen_st_i32(TCGv arg1, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_st_i32, arg1, arg2, offset); +} + +static inline void tcg_gen_add_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_add_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_addi_i32(TCGv ret, TCGv arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv t0 = tcg_const_i32(arg2); + tcg_gen_add_i32(ret, arg1, t0); + tcg_temp_free(t0); + } +} + +static inline void tcg_gen_sub_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_sub_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_subfi_i32(TCGv ret, int32_t arg1, TCGv arg2) +{ + TCGv t0 = tcg_const_i32(arg1); + tcg_gen_sub_i32(ret, t0, arg2); + tcg_temp_free(t0); +} + +static inline void tcg_gen_subi_i32(TCGv ret, TCGv arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv t0 = tcg_const_i32(arg2); + tcg_gen_sub_i32(ret, arg1, t0); + tcg_temp_free(t0); + } +} + +static inline void tcg_gen_and_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_and_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_andi_i32(TCGv ret, TCGv arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_movi_i32(ret, 0); + } else if (arg2 == 0xffffffff) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv t0 = tcg_const_i32(arg2); + tcg_gen_and_i32(ret, arg1, t0); + tcg_temp_free(t0); + } +} + +static inline void tcg_gen_or_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_or_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_ori_i32(TCGv ret, TCGv arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0xffffffff) { + tcg_gen_movi_i32(ret, 0xffffffff); + } else if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv t0 = tcg_const_i32(arg2); + tcg_gen_or_i32(ret, arg1, t0); + tcg_temp_free(t0); + } +} + +static inline void tcg_gen_xor_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_xor_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_xori_i32(TCGv ret, TCGv arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv t0 = tcg_const_i32(arg2); + tcg_gen_xor_i32(ret, arg1, t0); + tcg_temp_free(t0); + } +} + +static inline void tcg_gen_shl_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_shl_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_shli_i32(TCGv ret, TCGv arg1, int32_t arg2) +{ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv t0 = tcg_const_i32(arg2); + tcg_gen_shl_i32(ret, arg1, t0); + tcg_temp_free(t0); + } +} + +static inline void tcg_gen_shr_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_shr_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_shri_i32(TCGv ret, TCGv arg1, int32_t arg2) +{ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv t0 = tcg_const_i32(arg2); + tcg_gen_shr_i32(ret, arg1, t0); + tcg_temp_free(t0); + } +} + +static inline void tcg_gen_sar_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_sar_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_sari_i32(TCGv ret, TCGv arg1, int32_t arg2) +{ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv t0 = tcg_const_i32(arg2); + tcg_gen_sar_i32(ret, arg1, t0); + tcg_temp_free(t0); + } +} + +static inline void tcg_gen_brcond_i32(int cond, TCGv arg1, TCGv arg2, + int label_index) +{ + tcg_gen_op4ii(INDEX_op_brcond_i32, arg1, arg2, cond, label_index); +} + +static inline void tcg_gen_brcondi_i32(int cond, TCGv arg1, int32_t arg2, + int label_index) +{ + TCGv t0 = tcg_const_i32(arg2); + tcg_gen_brcond_i32(cond, arg1, t0, label_index); + tcg_temp_free(t0); +} + +static inline void tcg_gen_mul_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_mul_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_muli_i32(TCGv ret, TCGv arg1, int32_t arg2) +{ + TCGv t0 = tcg_const_i32(arg2); + tcg_gen_mul_i32(ret, arg1, t0); + tcg_temp_free(t0); +} + +#ifdef TCG_TARGET_HAS_div_i32 +static inline void tcg_gen_div_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_div_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_rem_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_rem_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_divu_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_divu_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_remu_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_remu_i32, ret, arg1, arg2); +} +#else +static inline void tcg_gen_div_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_sari_i32(t0, arg1, 31); + tcg_gen_op5(INDEX_op_div2_i32, ret, t0, arg1, t0, arg2); + tcg_temp_free(t0); +} + +static inline void tcg_gen_rem_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_sari_i32(t0, arg1, 31); + tcg_gen_op5(INDEX_op_div2_i32, t0, ret, arg1, t0, arg2); + tcg_temp_free(t0); +} + +static inline void tcg_gen_divu_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_movi_i32(t0, 0); + tcg_gen_op5(INDEX_op_divu2_i32, ret, t0, arg1, t0, arg2); + tcg_temp_free(t0); +} + +static inline void tcg_gen_remu_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_movi_i32(t0, 0); + tcg_gen_op5(INDEX_op_divu2_i32, t0, ret, arg1, t0, arg2); + tcg_temp_free(t0); +} +#endif + +#if TCG_TARGET_REG_BITS == 32 + +static inline void tcg_gen_mov_i64(TCGv ret, TCGv arg) +{ + if (GET_TCGV(ret) != GET_TCGV(arg)) { + tcg_gen_mov_i32(ret, arg); + tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg)); + } +} + +static inline void tcg_gen_movi_i64(TCGv ret, int64_t arg) +{ + tcg_gen_movi_i32(ret, arg); + tcg_gen_movi_i32(TCGV_HIGH(ret), arg >> 32); +} + +static inline void tcg_gen_ld8u_i64(TCGv ret, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_ld8u_i32(ret, arg2, offset); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_ld8s_i64(TCGv ret, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_ld8s_i32(ret, arg2, offset); + tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31); +} + +static inline void tcg_gen_ld16u_i64(TCGv ret, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_ld16u_i32(ret, arg2, offset); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_ld16s_i64(TCGv ret, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_ld16s_i32(ret, arg2, offset); + tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31); +} + +static inline void tcg_gen_ld32u_i64(TCGv ret, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_ld_i32(ret, arg2, offset); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_ld32s_i64(TCGv ret, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_ld_i32(ret, arg2, offset); + tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31); +} + +static inline void tcg_gen_ld_i64(TCGv ret, TCGv arg2, tcg_target_long offset) +{ + /* since arg2 and ret have different types, they cannot be the + same temporary */ +#ifdef TCG_TARGET_WORDS_BIGENDIAN + tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset); + tcg_gen_ld_i32(ret, arg2, offset + 4); +#else + tcg_gen_ld_i32(ret, arg2, offset); + tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset + 4); +#endif +} + +static inline void tcg_gen_st8_i64(TCGv arg1, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_st8_i32(arg1, arg2, offset); +} + +static inline void tcg_gen_st16_i64(TCGv arg1, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_st16_i32(arg1, arg2, offset); +} + +static inline void tcg_gen_st32_i64(TCGv arg1, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_st_i32(arg1, arg2, offset); +} + +static inline void tcg_gen_st_i64(TCGv arg1, TCGv arg2, tcg_target_long offset) +{ +#ifdef TCG_TARGET_WORDS_BIGENDIAN + tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset); + tcg_gen_st_i32(arg1, arg2, offset + 4); +#else + tcg_gen_st_i32(arg1, arg2, offset); + tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset + 4); +#endif +} + +static inline void tcg_gen_add_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op6(INDEX_op_add2_i32, ret, TCGV_HIGH(ret), + arg1, TCGV_HIGH(arg1), arg2, TCGV_HIGH(arg2)); +} + +static inline void tcg_gen_sub_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op6(INDEX_op_sub2_i32, ret, TCGV_HIGH(ret), + arg1, TCGV_HIGH(arg1), arg2, TCGV_HIGH(arg2)); +} + +static inline void tcg_gen_and_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_and_i32(ret, arg1, arg2); + tcg_gen_and_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); +} + +static inline void tcg_gen_andi_i64(TCGv ret, TCGv arg1, int64_t arg2) +{ + tcg_gen_andi_i32(ret, arg1, arg2); + tcg_gen_andi_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32); +} + +static inline void tcg_gen_or_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_or_i32(ret, arg1, arg2); + tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); +} + +static inline void tcg_gen_ori_i64(TCGv ret, TCGv arg1, int64_t arg2) +{ + tcg_gen_ori_i32(ret, arg1, arg2); + tcg_gen_ori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32); +} + +static inline void tcg_gen_xor_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_xor_i32(ret, arg1, arg2); + tcg_gen_xor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); +} + +static inline void tcg_gen_xori_i64(TCGv ret, TCGv arg1, int64_t arg2) +{ + tcg_gen_xori_i32(ret, arg1, arg2); + tcg_gen_xori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32); +} + +/* XXX: use generic code when basic block handling is OK or CPU + specific code (x86) */ +static inline void tcg_gen_shl_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_helper_1_2(tcg_helper_shl_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_shli_i64(TCGv ret, TCGv arg1, int64_t arg2) +{ + tcg_gen_shifti_i64(ret, arg1, arg2, 0, 0); +} + +static inline void tcg_gen_shr_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_helper_1_2(tcg_helper_shr_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_shri_i64(TCGv ret, TCGv arg1, int64_t arg2) +{ + tcg_gen_shifti_i64(ret, arg1, arg2, 1, 0); +} + +static inline void tcg_gen_sar_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_helper_1_2(tcg_helper_sar_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_sari_i64(TCGv ret, TCGv arg1, int64_t arg2) +{ + tcg_gen_shifti_i64(ret, arg1, arg2, 1, 1); +} + +static inline void tcg_gen_brcond_i64(int cond, TCGv arg1, TCGv arg2, + int label_index) +{ + tcg_gen_op6ii(INDEX_op_brcond2_i32, + arg1, TCGV_HIGH(arg1), arg2, TCGV_HIGH(arg2), + cond, label_index); +} + +static inline void tcg_gen_mul_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0, t1; + + t0 = tcg_temp_new(TCG_TYPE_I64); + t1 = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_op4(INDEX_op_mulu2_i32, t0, TCGV_HIGH(t0), arg1, arg2); + + tcg_gen_mul_i32(t1, arg1, TCGV_HIGH(arg2)); + tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1); + tcg_gen_mul_i32(t1, TCGV_HIGH(arg1), arg2); + tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1); + + tcg_gen_mov_i64(ret, t0); + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static inline void tcg_gen_div_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_helper_1_2(tcg_helper_div_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_rem_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_helper_1_2(tcg_helper_rem_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_divu_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_helper_1_2(tcg_helper_divu_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_remu_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_helper_1_2(tcg_helper_remu_i64, ret, arg1, arg2); +} + +#else + +static inline void tcg_gen_mov_i64(TCGv ret, TCGv arg) +{ + if (GET_TCGV(ret) != GET_TCGV(arg)) + tcg_gen_op2(INDEX_op_mov_i64, ret, arg); +} + +static inline void tcg_gen_movi_i64(TCGv ret, int64_t arg) +{ + tcg_gen_op2i(INDEX_op_movi_i64, ret, arg); +} + +static inline void tcg_gen_ld8u_i64(TCGv ret, TCGv arg2, + tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_ld8u_i64, ret, arg2, offset); +} + +static inline void tcg_gen_ld8s_i64(TCGv ret, TCGv arg2, + tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_ld8s_i64, ret, arg2, offset); +} + +static inline void tcg_gen_ld16u_i64(TCGv ret, TCGv arg2, + tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_ld16u_i64, ret, arg2, offset); +} + +static inline void tcg_gen_ld16s_i64(TCGv ret, TCGv arg2, + tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_ld16s_i64, ret, arg2, offset); +} + +static inline void tcg_gen_ld32u_i64(TCGv ret, TCGv arg2, + tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_ld32u_i64, ret, arg2, offset); +} + +static inline void tcg_gen_ld32s_i64(TCGv ret, TCGv arg2, + tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_ld32s_i64, ret, arg2, offset); +} + +static inline void tcg_gen_ld_i64(TCGv ret, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_ld_i64, ret, arg2, offset); +} + +static inline void tcg_gen_st8_i64(TCGv arg1, TCGv arg2, + tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_st8_i64, arg1, arg2, offset); +} + +static inline void tcg_gen_st16_i64(TCGv arg1, TCGv arg2, + tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_st16_i64, arg1, arg2, offset); +} + +static inline void tcg_gen_st32_i64(TCGv arg1, TCGv arg2, + tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_st32_i64, arg1, arg2, offset); +} + +static inline void tcg_gen_st_i64(TCGv arg1, TCGv arg2, tcg_target_long offset) +{ + tcg_gen_op3i(INDEX_op_st_i64, arg1, arg2, offset); +} + +static inline void tcg_gen_add_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_add_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_sub_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_sub_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_and_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_and_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_andi_i64(TCGv ret, TCGv arg1, int64_t arg2) +{ + TCGv t0 = tcg_const_i64(arg2); + tcg_gen_and_i64(ret, arg1, t0); + tcg_temp_free(t0); +} + +static inline void tcg_gen_or_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_or_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_ori_i64(TCGv ret, TCGv arg1, int64_t arg2) +{ + TCGv t0 = tcg_const_i64(arg2); + tcg_gen_or_i64(ret, arg1, t0); + tcg_temp_free(t0); +} + +static inline void tcg_gen_xor_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_xor_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_xori_i64(TCGv ret, TCGv arg1, int64_t arg2) +{ + TCGv t0 = tcg_const_i64(arg2); + tcg_gen_xor_i64(ret, arg1, t0); + tcg_temp_free(t0); +} + +static inline void tcg_gen_shl_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_shl_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_shli_i64(TCGv ret, TCGv arg1, int64_t arg2) +{ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + TCGv t0 = tcg_const_i64(arg2); + tcg_gen_shl_i64(ret, arg1, t0); + tcg_temp_free(t0); + } +} + +static inline void tcg_gen_shr_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_shr_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_shri_i64(TCGv ret, TCGv arg1, int64_t arg2) +{ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + TCGv t0 = tcg_const_i64(arg2); + tcg_gen_shr_i64(ret, arg1, t0); + tcg_temp_free(t0); + } +} + +static inline void tcg_gen_sar_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_sar_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_sari_i64(TCGv ret, TCGv arg1, int64_t arg2) +{ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + TCGv t0 = tcg_const_i64(arg2); + tcg_gen_sar_i64(ret, arg1, t0); + tcg_temp_free(t0); + } +} + +static inline void tcg_gen_brcond_i64(int cond, TCGv arg1, TCGv arg2, + int label_index) +{ + tcg_gen_op4ii(INDEX_op_brcond_i64, arg1, arg2, cond, label_index); +} + +static inline void tcg_gen_mul_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_mul_i64, ret, arg1, arg2); +} + +#ifdef TCG_TARGET_HAS_div_i64 +static inline void tcg_gen_div_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_div_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_rem_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_rem_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_divu_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_divu_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_remu_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_op3(INDEX_op_remu_i64, ret, arg1, arg2); +} +#else +static inline void tcg_gen_div_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_sari_i64(t0, arg1, 63); + tcg_gen_op5(INDEX_op_div2_i64, ret, t0, arg1, t0, arg2); + tcg_temp_free(t0); +} + +static inline void tcg_gen_rem_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_sari_i64(t0, arg1, 63); + tcg_gen_op5(INDEX_op_div2_i64, t0, ret, arg1, t0, arg2); + tcg_temp_free(t0); +} + +static inline void tcg_gen_divu_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_movi_i64(t0, 0); + tcg_gen_op5(INDEX_op_divu2_i64, ret, t0, arg1, t0, arg2); + tcg_temp_free(t0); +} + +static inline void tcg_gen_remu_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_movi_i64(t0, 0); + tcg_gen_op5(INDEX_op_divu2_i64, t0, ret, arg1, t0, arg2); + tcg_temp_free(t0); +} +#endif + +#endif + +static inline void tcg_gen_addi_i64(TCGv ret, TCGv arg1, int64_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + TCGv t0 = tcg_const_i64(arg2); + tcg_gen_add_i64(ret, arg1, t0); + tcg_temp_free(t0); + } +} + +static inline void tcg_gen_subfi_i64(TCGv ret, int64_t arg1, TCGv arg2) +{ + TCGv t0 = tcg_const_i64(arg1); + tcg_gen_sub_i64(ret, t0, arg2); + tcg_temp_free(t0); +} + +static inline void tcg_gen_subi_i64(TCGv ret, TCGv arg1, int64_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + TCGv t0 = tcg_const_i64(arg2); + tcg_gen_sub_i64(ret, arg1, t0); + tcg_temp_free(t0); + } +} +static inline void tcg_gen_brcondi_i64(int cond, TCGv arg1, int64_t arg2, + int label_index) +{ + TCGv t0 = tcg_const_i64(arg2); + tcg_gen_brcond_i64(cond, arg1, t0, label_index); + tcg_temp_free(t0); +} + +static inline void tcg_gen_muli_i64(TCGv ret, TCGv arg1, int64_t arg2) +{ + TCGv t0 = tcg_const_i64(arg2); + tcg_gen_mul_i64(ret, arg1, t0); + tcg_temp_free(t0); +} + + +/***************************************/ +/* optional operations */ + +static inline void tcg_gen_ext8s_i32(TCGv ret, TCGv arg) +{ +#ifdef TCG_TARGET_HAS_ext8s_i32 + tcg_gen_op2(INDEX_op_ext8s_i32, ret, arg); +#else + tcg_gen_shli_i32(ret, arg, 24); + tcg_gen_sari_i32(ret, ret, 24); +#endif +} + +static inline void tcg_gen_ext16s_i32(TCGv ret, TCGv arg) +{ +#ifdef TCG_TARGET_HAS_ext16s_i32 + tcg_gen_op2(INDEX_op_ext16s_i32, ret, arg); +#else + tcg_gen_shli_i32(ret, arg, 16); + tcg_gen_sari_i32(ret, ret, 16); +#endif +} + +/* These are currently just for convenience. + We assume a target will recognise these automatically . */ +static inline void tcg_gen_ext8u_i32(TCGv ret, TCGv arg) +{ + tcg_gen_andi_i32(ret, arg, 0xffu); +} + +static inline void tcg_gen_ext16u_i32(TCGv ret, TCGv arg) +{ + tcg_gen_andi_i32(ret, arg, 0xffffu); +} + +/* Note: we assume the two high bytes are set to zero */ +static inline void tcg_gen_bswap16_i32(TCGv ret, TCGv arg) +{ +#ifdef TCG_TARGET_HAS_bswap16_i32 + tcg_gen_op2(INDEX_op_bswap16_i32, ret, arg); +#else + TCGv t0, t1; + t0 = tcg_temp_new(TCG_TYPE_I32); + t1 = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_shri_i32(t0, arg, 8); + tcg_gen_andi_i32(t1, arg, 0x000000ff); + tcg_gen_shli_i32(t1, t1, 8); + tcg_gen_or_i32(ret, t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); +#endif +} + +static inline void tcg_gen_bswap_i32(TCGv ret, TCGv arg) +{ +#ifdef TCG_TARGET_HAS_bswap_i32 + tcg_gen_op2(INDEX_op_bswap_i32, ret, arg); +#else + TCGv t0, t1; + t0 = tcg_temp_new(TCG_TYPE_I32); + t1 = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_shli_i32(t0, arg, 24); + + tcg_gen_andi_i32(t1, arg, 0x0000ff00); + tcg_gen_shli_i32(t1, t1, 8); + tcg_gen_or_i32(t0, t0, t1); + + tcg_gen_shri_i32(t1, arg, 8); + tcg_gen_andi_i32(t1, t1, 0x0000ff00); + tcg_gen_or_i32(t0, t0, t1); + + tcg_gen_shri_i32(t1, arg, 24); + tcg_gen_or_i32(ret, t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); +#endif +} + +#if TCG_TARGET_REG_BITS == 32 +static inline void tcg_gen_ext8s_i64(TCGv ret, TCGv arg) +{ + tcg_gen_ext8s_i32(ret, arg); + tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31); +} + +static inline void tcg_gen_ext16s_i64(TCGv ret, TCGv arg) +{ + tcg_gen_ext16s_i32(ret, arg); + tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31); +} + +static inline void tcg_gen_ext32s_i64(TCGv ret, TCGv arg) +{ + tcg_gen_mov_i32(ret, arg); + tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31); +} + +static inline void tcg_gen_ext8u_i64(TCGv ret, TCGv arg) +{ + tcg_gen_ext8u_i32(ret, arg); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_ext16u_i64(TCGv ret, TCGv arg) +{ + tcg_gen_ext16u_i32(ret, arg); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_ext32u_i64(TCGv ret, TCGv arg) +{ + tcg_gen_mov_i32(ret, arg); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_trunc_i64_i32(TCGv ret, TCGv arg) +{ + tcg_gen_mov_i32(ret, arg); +} + +static inline void tcg_gen_extu_i32_i64(TCGv ret, TCGv arg) +{ + tcg_gen_mov_i32(ret, arg); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_ext_i32_i64(TCGv ret, TCGv arg) +{ + tcg_gen_mov_i32(ret, arg); + tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31); +} + +static inline void tcg_gen_bswap_i64(TCGv ret, TCGv arg) +{ + TCGv t0, t1; + t0 = tcg_temp_new(TCG_TYPE_I32); + t1 = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_bswap_i32(t0, arg); + tcg_gen_bswap_i32(t1, TCGV_HIGH(arg)); + tcg_gen_mov_i32(ret, t1); + tcg_gen_mov_i32(TCGV_HIGH(ret), t0); + tcg_temp_free(t0); + tcg_temp_free(t1); +} +#else + +static inline void tcg_gen_ext8s_i64(TCGv ret, TCGv arg) +{ +#ifdef TCG_TARGET_HAS_ext8s_i64 + tcg_gen_op2(INDEX_op_ext8s_i64, ret, arg); +#else + tcg_gen_shli_i64(ret, arg, 56); + tcg_gen_sari_i64(ret, ret, 56); +#endif +} + +static inline void tcg_gen_ext16s_i64(TCGv ret, TCGv arg) +{ +#ifdef TCG_TARGET_HAS_ext16s_i64 + tcg_gen_op2(INDEX_op_ext16s_i64, ret, arg); +#else + tcg_gen_shli_i64(ret, arg, 48); + tcg_gen_sari_i64(ret, ret, 48); +#endif +} + +static inline void tcg_gen_ext32s_i64(TCGv ret, TCGv arg) +{ +#ifdef TCG_TARGET_HAS_ext32s_i64 + tcg_gen_op2(INDEX_op_ext32s_i64, ret, arg); +#else + tcg_gen_shli_i64(ret, arg, 32); + tcg_gen_sari_i64(ret, ret, 32); +#endif +} + +static inline void tcg_gen_ext8u_i64(TCGv ret, TCGv arg) +{ + tcg_gen_andi_i64(ret, arg, 0xffu); +} + +static inline void tcg_gen_ext16u_i64(TCGv ret, TCGv arg) +{ + tcg_gen_andi_i64(ret, arg, 0xffffu); +} + +static inline void tcg_gen_ext32u_i64(TCGv ret, TCGv arg) +{ + tcg_gen_andi_i64(ret, arg, 0xffffffffu); +} + +/* Note: we assume the target supports move between 32 and 64 bit + registers. This will probably break MIPS64 targets. */ +static inline void tcg_gen_trunc_i64_i32(TCGv ret, TCGv arg) +{ + tcg_gen_mov_i32(ret, arg); +} + +/* Note: we assume the target supports move between 32 and 64 bit + registers */ +static inline void tcg_gen_extu_i32_i64(TCGv ret, TCGv arg) +{ + tcg_gen_andi_i64(ret, arg, 0xffffffffu); +} + +/* Note: we assume the target supports move between 32 and 64 bit + registers */ +static inline void tcg_gen_ext_i32_i64(TCGv ret, TCGv arg) +{ + tcg_gen_ext32s_i64(ret, arg); +} + +static inline void tcg_gen_bswap_i64(TCGv ret, TCGv arg) +{ +#ifdef TCG_TARGET_HAS_bswap_i64 + tcg_gen_op2(INDEX_op_bswap_i64, ret, arg); +#else + TCGv t0, t1; + t0 = tcg_temp_new(TCG_TYPE_I32); + t1 = tcg_temp_new(TCG_TYPE_I32); + + tcg_gen_shli_i64(t0, arg, 56); + + tcg_gen_andi_i64(t1, arg, 0x0000ff00); + tcg_gen_shli_i64(t1, t1, 40); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_andi_i64(t1, arg, 0x00ff0000); + tcg_gen_shli_i64(t1, t1, 24); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_andi_i64(t1, arg, 0xff000000); + tcg_gen_shli_i64(t1, t1, 8); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_shri_i64(t1, arg, 8); + tcg_gen_andi_i64(t1, t1, 0xff000000); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_shri_i64(t1, arg, 24); + tcg_gen_andi_i64(t1, t1, 0x00ff0000); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_shri_i64(t1, arg, 40); + tcg_gen_andi_i64(t1, t1, 0x0000ff00); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_shri_i64(t1, arg, 56); + tcg_gen_or_i64(ret, t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); +#endif +} + +#endif + +static inline void tcg_gen_neg_i32(TCGv ret, TCGv arg) +{ +#ifdef TCG_TARGET_HAS_neg_i32 + tcg_gen_op2(INDEX_op_neg_i32, ret, arg); +#else + TCGv t0 = tcg_const_i32(0); + tcg_gen_sub_i32(ret, t0, arg); + tcg_temp_free(t0); +#endif +} + +static inline void tcg_gen_neg_i64(TCGv ret, TCGv arg) +{ +#ifdef TCG_TARGET_HAS_neg_i64 + tcg_gen_op2(INDEX_op_neg_i64, ret, arg); +#else + TCGv t0 = tcg_const_i64(0); + tcg_gen_sub_i64(ret, t0, arg); + tcg_temp_free(t0); +#endif +} + +static inline void tcg_gen_not_i32(TCGv ret, TCGv arg) +{ + tcg_gen_xori_i32(ret, arg, -1); +} + +static inline void tcg_gen_not_i64(TCGv ret, TCGv arg) +{ + tcg_gen_xori_i64(ret, arg, -1); +} + +static inline void tcg_gen_discard_i32(TCGv arg) +{ + tcg_gen_op1(INDEX_op_discard, arg); +} + +#if TCG_TARGET_REG_BITS == 32 +static inline void tcg_gen_discard_i64(TCGv arg) +{ + tcg_gen_discard_i32(arg); + tcg_gen_discard_i32(TCGV_HIGH(arg)); +} +#else +static inline void tcg_gen_discard_i64(TCGv arg) +{ + tcg_gen_op1(INDEX_op_discard, arg); +} +#endif + +static inline void tcg_gen_concat_i32_i64(TCGv dest, TCGv low, TCGv high) +{ +#if TCG_TARGET_REG_BITS == 32 + tcg_gen_mov_i32(dest, low); + tcg_gen_mov_i32(TCGV_HIGH(dest), high); +#else + TCGv tmp = tcg_temp_new (TCG_TYPE_I64); + /* This extension is only needed for type correctness. + We may be able to do better given target specific information. */ + tcg_gen_extu_i32_i64(tmp, high); + tcg_gen_shli_i64(tmp, tmp, 32); + tcg_gen_extu_i32_i64(dest, low); + tcg_gen_or_i64(dest, dest, tmp); + tcg_temp_free(tmp); +#endif +} + +static inline void tcg_gen_concat32_i64(TCGv dest, TCGv low, TCGv high) +{ +#if TCG_TARGET_REG_BITS == 32 + tcg_gen_concat_i32_i64(dest, low, high); +#else + TCGv tmp = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_ext32u_i64(dest, low); + tcg_gen_shli_i64(tmp, high, 32); + tcg_gen_or_i64(dest, dest, tmp); + tcg_temp_free(tmp); +#endif +} + +static inline void tcg_gen_andc_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_not_i32(t0, arg2); + tcg_gen_and_i32(ret, arg1, t0); + tcg_temp_free(t0); +} + +static inline void tcg_gen_andc_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_not_i64(t0, arg2); + tcg_gen_and_i64(ret, arg1, t0); + tcg_temp_free(t0); +} + +static inline void tcg_gen_eqv_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_xor_i32(t0, arg1, arg2); + tcg_gen_not_i32(ret, t0); + tcg_temp_free(t0); +} + +static inline void tcg_gen_eqv_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_xor_i64(t0, arg1, arg2); + tcg_gen_not_i64(ret, t0); + tcg_temp_free(t0); +} + +static inline void tcg_gen_nand_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_and_i32(t0, arg1, arg2); + tcg_gen_not_i32(ret, t0); + tcg_temp_free(t0); +} + +static inline void tcg_gen_nand_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_and_i64(t0, arg1, arg2); + tcg_gen_not_i64(ret, t0); + tcg_temp_free(t0); +} + +static inline void tcg_gen_nor_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_or_i32(t0, arg1, arg2); + tcg_gen_not_i32(ret, t0); + tcg_temp_free(t0); +} + +static inline void tcg_gen_nor_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_or_i64(t0, arg1, arg2); + tcg_gen_not_i64(ret, t0); + tcg_temp_free(t0); +} + +static inline void tcg_gen_orc_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_not_i32(t0, arg2); + tcg_gen_or_i32(ret, arg1, t0); + tcg_temp_free(t0); +} + +static inline void tcg_gen_orc_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0; + t0 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_not_i64(t0, arg2); + tcg_gen_or_i64(ret, arg1, t0); + tcg_temp_free(t0); +} + +static inline void tcg_gen_rotl_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0, t1; + + t0 = tcg_temp_new(TCG_TYPE_I32); + t1 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_shl_i32(t0, arg1, arg2); + tcg_gen_subfi_i32(t1, 32, arg2); + tcg_gen_shr_i32(t1, arg1, t1); + tcg_gen_or_i32(ret, t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static inline void tcg_gen_rotl_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0, t1; + + t0 = tcg_temp_new(TCG_TYPE_I64); + t1 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_shl_i64(t0, arg1, arg2); + tcg_gen_subfi_i64(t1, 64, arg2); + tcg_gen_shr_i64(t1, arg1, t1); + tcg_gen_or_i64(ret, t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static inline void tcg_gen_rotli_i32(TCGv ret, TCGv arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv t0, t1; + t0 = tcg_temp_new(TCG_TYPE_I32); + t1 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_shli_i32(t0, arg1, arg2); + tcg_gen_shri_i32(t1, arg1, 32 - arg2); + tcg_gen_or_i32(ret, t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); + } +} + +static inline void tcg_gen_rotli_i64(TCGv ret, TCGv arg1, int64_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + TCGv t0, t1; + t0 = tcg_temp_new(TCG_TYPE_I64); + t1 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_shli_i64(t0, arg1, arg2); + tcg_gen_shri_i64(t1, arg1, 64 - arg2); + tcg_gen_or_i64(ret, t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); + } +} + +static inline void tcg_gen_rotr_i32(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0, t1; + + t0 = tcg_temp_new(TCG_TYPE_I32); + t1 = tcg_temp_new(TCG_TYPE_I32); + tcg_gen_shr_i32(t0, arg1, arg2); + tcg_gen_subfi_i32(t1, 32, arg2); + tcg_gen_shl_i32(t1, arg1, t1); + tcg_gen_or_i32(ret, t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static inline void tcg_gen_rotr_i64(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t0, t1; + + t0 = tcg_temp_new(TCG_TYPE_I64); + t1 = tcg_temp_new(TCG_TYPE_I64); + tcg_gen_shl_i64(t0, arg1, arg2); + tcg_gen_subfi_i64(t1, 64, arg2); + tcg_gen_shl_i64(t1, arg1, t1); + tcg_gen_or_i64(ret, t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static inline void tcg_gen_rotri_i32(TCGv ret, TCGv arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + tcg_gen_rotli_i32(ret, arg1, 32 - arg2); + } +} + +static inline void tcg_gen_rotri_i64(TCGv ret, TCGv arg1, int64_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + tcg_gen_rotli_i64(ret, arg1, 64 - arg2); + } +} + +/***************************************/ +/* QEMU specific operations. Their type depend on the QEMU CPU + type. */ +#ifndef TARGET_LONG_BITS +#error must include QEMU headers +#endif + +/* debug info: write the PC of the corresponding QEMU CPU instruction */ +static inline void tcg_gen_debug_insn_start(uint64_t pc) +{ + /* XXX: must really use a 32 bit size for TCGArg in all cases */ +#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS + tcg_gen_op2ii(INDEX_op_debug_insn_start, + (uint32_t)(pc), (uint32_t)(pc >> 32)); +#else + tcg_gen_op1i(INDEX_op_debug_insn_start, pc); +#endif +} + +static inline void tcg_gen_exit_tb(tcg_target_long val) +{ + tcg_gen_op1i(INDEX_op_exit_tb, val); +} + +static inline void tcg_gen_goto_tb(int idx) +{ + tcg_gen_op1i(INDEX_op_goto_tb, idx); +} + +#if TCG_TARGET_REG_BITS == 32 +static inline void tcg_gen_qemu_ld8u(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i(INDEX_op_qemu_ld8u, ret, addr, mem_index); +#else + tcg_gen_op4i(INDEX_op_qemu_ld8u, ret, addr, TCGV_HIGH(addr), mem_index); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +#endif +} + +static inline void tcg_gen_qemu_ld8s(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i(INDEX_op_qemu_ld8s, ret, addr, mem_index); +#else + tcg_gen_op4i(INDEX_op_qemu_ld8s, ret, addr, TCGV_HIGH(addr), mem_index); + tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31); +#endif +} + +static inline void tcg_gen_qemu_ld16u(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i(INDEX_op_qemu_ld16u, ret, addr, mem_index); +#else + tcg_gen_op4i(INDEX_op_qemu_ld16u, ret, addr, TCGV_HIGH(addr), mem_index); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +#endif +} + +static inline void tcg_gen_qemu_ld16s(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i(INDEX_op_qemu_ld16s, ret, addr, mem_index); +#else + tcg_gen_op4i(INDEX_op_qemu_ld16s, ret, addr, TCGV_HIGH(addr), mem_index); + tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31); +#endif +} + +static inline void tcg_gen_qemu_ld32u(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i(INDEX_op_qemu_ld32u, ret, addr, mem_index); +#else + tcg_gen_op4i(INDEX_op_qemu_ld32u, ret, addr, TCGV_HIGH(addr), mem_index); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +#endif +} + +static inline void tcg_gen_qemu_ld32s(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i(INDEX_op_qemu_ld32u, ret, addr, mem_index); +#else + tcg_gen_op4i(INDEX_op_qemu_ld32u, ret, addr, TCGV_HIGH(addr), mem_index); + tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31); +#endif +} + +static inline void tcg_gen_qemu_ld64(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op4i(INDEX_op_qemu_ld64, ret, TCGV_HIGH(ret), addr, mem_index); +#else + tcg_gen_op5i(INDEX_op_qemu_ld64, ret, TCGV_HIGH(ret), + addr, TCGV_HIGH(addr), mem_index); +#endif +} + +static inline void tcg_gen_qemu_st8(TCGv arg, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i(INDEX_op_qemu_st8, arg, addr, mem_index); +#else + tcg_gen_op4i(INDEX_op_qemu_st8, arg, addr, TCGV_HIGH(addr), mem_index); +#endif +} + +static inline void tcg_gen_qemu_st16(TCGv arg, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i(INDEX_op_qemu_st16, arg, addr, mem_index); +#else + tcg_gen_op4i(INDEX_op_qemu_st16, arg, addr, TCGV_HIGH(addr), mem_index); +#endif +} + +static inline void tcg_gen_qemu_st32(TCGv arg, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i(INDEX_op_qemu_st32, arg, addr, mem_index); +#else + tcg_gen_op4i(INDEX_op_qemu_st32, arg, addr, TCGV_HIGH(addr), mem_index); +#endif +} + +static inline void tcg_gen_qemu_st64(TCGv arg, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op4i(INDEX_op_qemu_st64, arg, TCGV_HIGH(arg), addr, mem_index); +#else + tcg_gen_op5i(INDEX_op_qemu_st64, arg, TCGV_HIGH(arg), + addr, TCGV_HIGH(addr), mem_index); +#endif +} + +#define tcg_gen_ld_ptr tcg_gen_ld_i32 +#define tcg_gen_discard_ptr tcg_gen_discard_i32 + +#else /* TCG_TARGET_REG_BITS == 32 */ + +static inline void tcg_gen_qemu_ld8u(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_op3i(INDEX_op_qemu_ld8u, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_ld8s(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_op3i(INDEX_op_qemu_ld8s, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_ld16u(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_op3i(INDEX_op_qemu_ld16u, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_ld16s(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_op3i(INDEX_op_qemu_ld16s, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_ld32u(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_op3i(INDEX_op_qemu_ld32u, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_ld32s(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_op3i(INDEX_op_qemu_ld32s, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_ld64(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_op3i(INDEX_op_qemu_ld64, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_st8(TCGv arg, TCGv addr, int mem_index) +{ + tcg_gen_op3i(INDEX_op_qemu_st8, arg, addr, mem_index); +} + +static inline void tcg_gen_qemu_st16(TCGv arg, TCGv addr, int mem_index) +{ + tcg_gen_op3i(INDEX_op_qemu_st16, arg, addr, mem_index); +} + +static inline void tcg_gen_qemu_st32(TCGv arg, TCGv addr, int mem_index) +{ + tcg_gen_op3i(INDEX_op_qemu_st32, arg, addr, mem_index); +} + +static inline void tcg_gen_qemu_st64(TCGv arg, TCGv addr, int mem_index) +{ + tcg_gen_op3i(INDEX_op_qemu_st64, arg, addr, mem_index); +} + +#define tcg_gen_ld_ptr tcg_gen_ld_i64 +#define tcg_gen_discard_ptr tcg_gen_discard_i64 + +#endif /* TCG_TARGET_REG_BITS != 32 */ + +#if TARGET_LONG_BITS == 64 +#define TCG_TYPE_TL TCG_TYPE_I64 +#define tcg_gen_movi_tl tcg_gen_movi_i64 +#define tcg_gen_mov_tl tcg_gen_mov_i64 +#define tcg_gen_ld8u_tl tcg_gen_ld8u_i64 +#define tcg_gen_ld8s_tl tcg_gen_ld8s_i64 +#define tcg_gen_ld16u_tl tcg_gen_ld16u_i64 +#define tcg_gen_ld16s_tl tcg_gen_ld16s_i64 +#define tcg_gen_ld32u_tl tcg_gen_ld32u_i64 +#define tcg_gen_ld32s_tl tcg_gen_ld32s_i64 +#define tcg_gen_ld_tl tcg_gen_ld_i64 +#define tcg_gen_st8_tl tcg_gen_st8_i64 +#define tcg_gen_st16_tl tcg_gen_st16_i64 +#define tcg_gen_st32_tl tcg_gen_st32_i64 +#define tcg_gen_st_tl tcg_gen_st_i64 +#define tcg_gen_add_tl tcg_gen_add_i64 +#define tcg_gen_addi_tl tcg_gen_addi_i64 +#define tcg_gen_sub_tl tcg_gen_sub_i64 +#define tcg_gen_neg_tl tcg_gen_neg_i64 +#define tcg_gen_subfi_tl tcg_gen_subfi_i64 +#define tcg_gen_subi_tl tcg_gen_subi_i64 +#define tcg_gen_and_tl tcg_gen_and_i64 +#define tcg_gen_andi_tl tcg_gen_andi_i64 +#define tcg_gen_or_tl tcg_gen_or_i64 +#define tcg_gen_ori_tl tcg_gen_ori_i64 +#define tcg_gen_xor_tl tcg_gen_xor_i64 +#define tcg_gen_xori_tl tcg_gen_xori_i64 +#define tcg_gen_not_tl tcg_gen_not_i64 +#define tcg_gen_shl_tl tcg_gen_shl_i64 +#define tcg_gen_shli_tl tcg_gen_shli_i64 +#define tcg_gen_shr_tl tcg_gen_shr_i64 +#define tcg_gen_shri_tl tcg_gen_shri_i64 +#define tcg_gen_sar_tl tcg_gen_sar_i64 +#define tcg_gen_sari_tl tcg_gen_sari_i64 +#define tcg_gen_brcond_tl tcg_gen_brcond_i64 +#define tcg_gen_brcondi_tl tcg_gen_brcondi_i64 +#define tcg_gen_mul_tl tcg_gen_mul_i64 +#define tcg_gen_muli_tl tcg_gen_muli_i64 +#define tcg_gen_discard_tl tcg_gen_discard_i64 +#define tcg_gen_trunc_tl_i32 tcg_gen_trunc_i64_i32 +#define tcg_gen_trunc_i64_tl tcg_gen_mov_i64 +#define tcg_gen_extu_i32_tl tcg_gen_extu_i32_i64 +#define tcg_gen_ext_i32_tl tcg_gen_ext_i32_i64 +#define tcg_gen_extu_tl_i64 tcg_gen_mov_i64 +#define tcg_gen_ext_tl_i64 tcg_gen_mov_i64 +#define tcg_gen_ext8u_tl tcg_gen_ext8u_i64 +#define tcg_gen_ext8s_tl tcg_gen_ext8s_i64 +#define tcg_gen_ext16u_tl tcg_gen_ext16u_i64 +#define tcg_gen_ext16s_tl tcg_gen_ext16s_i64 +#define tcg_gen_ext32u_tl tcg_gen_ext32u_i64 +#define tcg_gen_ext32s_tl tcg_gen_ext32s_i64 +#define tcg_gen_concat_tl_i64 tcg_gen_concat32_i64 +#define tcg_gen_andc_tl tcg_gen_andc_i64 +#define tcg_gen_eqv_tl tcg_gen_eqv_i64 +#define tcg_gen_nand_tl tcg_gen_nand_i64 +#define tcg_gen_nor_tl tcg_gen_nor_i64 +#define tcg_gen_orc_tl tcg_gen_orc_i64 +#define tcg_gen_rotl_tl tcg_gen_rotl_i64 +#define tcg_gen_rotli_tl tcg_gen_rotli_i64 +#define tcg_gen_rotr_tl tcg_gen_rotr_i64 +#define tcg_gen_rotri_tl tcg_gen_rotri_i64 +#define tcg_const_tl tcg_const_i64 +#define tcg_const_local_tl tcg_const_local_i64 +#else +#define TCG_TYPE_TL TCG_TYPE_I32 +#define tcg_gen_movi_tl tcg_gen_movi_i32 +#define tcg_gen_mov_tl tcg_gen_mov_i32 +#define tcg_gen_ld8u_tl tcg_gen_ld8u_i32 +#define tcg_gen_ld8s_tl tcg_gen_ld8s_i32 +#define tcg_gen_ld16u_tl tcg_gen_ld16u_i32 +#define tcg_gen_ld16s_tl tcg_gen_ld16s_i32 +#define tcg_gen_ld32u_tl tcg_gen_ld_i32 +#define tcg_gen_ld32s_tl tcg_gen_ld_i32 +#define tcg_gen_ld_tl tcg_gen_ld_i32 +#define tcg_gen_st8_tl tcg_gen_st8_i32 +#define tcg_gen_st16_tl tcg_gen_st16_i32 +#define tcg_gen_st32_tl tcg_gen_st_i32 +#define tcg_gen_st_tl tcg_gen_st_i32 +#define tcg_gen_add_tl tcg_gen_add_i32 +#define tcg_gen_addi_tl tcg_gen_addi_i32 +#define tcg_gen_sub_tl tcg_gen_sub_i32 +#define tcg_gen_neg_tl tcg_gen_neg_i32 +#define tcg_gen_subfi_tl tcg_gen_subfi_i32 +#define tcg_gen_subi_tl tcg_gen_subi_i32 +#define tcg_gen_and_tl tcg_gen_and_i32 +#define tcg_gen_andi_tl tcg_gen_andi_i32 +#define tcg_gen_or_tl tcg_gen_or_i32 +#define tcg_gen_ori_tl tcg_gen_ori_i32 +#define tcg_gen_xor_tl tcg_gen_xor_i32 +#define tcg_gen_xori_tl tcg_gen_xori_i32 +#define tcg_gen_not_tl tcg_gen_not_i32 +#define tcg_gen_shl_tl tcg_gen_shl_i32 +#define tcg_gen_shli_tl tcg_gen_shli_i32 +#define tcg_gen_shr_tl tcg_gen_shr_i32 +#define tcg_gen_shri_tl tcg_gen_shri_i32 +#define tcg_gen_sar_tl tcg_gen_sar_i32 +#define tcg_gen_sari_tl tcg_gen_sari_i32 +#define tcg_gen_brcond_tl tcg_gen_brcond_i32 +#define tcg_gen_brcondi_tl tcg_gen_brcondi_i32 +#define tcg_gen_mul_tl tcg_gen_mul_i32 +#define tcg_gen_muli_tl tcg_gen_muli_i32 +#define tcg_gen_discard_tl tcg_gen_discard_i32 +#define tcg_gen_trunc_tl_i32 tcg_gen_mov_i32 +#define tcg_gen_trunc_i64_tl tcg_gen_trunc_i64_i32 +#define tcg_gen_extu_i32_tl tcg_gen_mov_i32 +#define tcg_gen_ext_i32_tl tcg_gen_mov_i32 +#define tcg_gen_extu_tl_i64 tcg_gen_extu_i32_i64 +#define tcg_gen_ext_tl_i64 tcg_gen_ext_i32_i64 +#define tcg_gen_ext8u_tl tcg_gen_ext8u_i32 +#define tcg_gen_ext8s_tl tcg_gen_ext8s_i32 +#define tcg_gen_ext16u_tl tcg_gen_ext16u_i32 +#define tcg_gen_ext16s_tl tcg_gen_ext16s_i32 +#define tcg_gen_ext32u_tl tcg_gen_mov_i32 +#define tcg_gen_ext32s_tl tcg_gen_mov_i32 +#define tcg_gen_concat_tl_i64 tcg_gen_concat_i32_i64 +#define tcg_gen_andc_tl tcg_gen_andc_i32 +#define tcg_gen_eqv_tl tcg_gen_eqv_i32 +#define tcg_gen_nand_tl tcg_gen_nand_i32 +#define tcg_gen_nor_tl tcg_gen_nor_i32 +#define tcg_gen_orc_tl tcg_gen_orc_i32 +#define tcg_gen_rotl_tl tcg_gen_rotl_i32 +#define tcg_gen_rotli_tl tcg_gen_rotli_i32 +#define tcg_gen_rotr_tl tcg_gen_rotr_i32 +#define tcg_gen_rotri_tl tcg_gen_rotri_i32 +#define tcg_const_tl tcg_const_i32 +#define tcg_const_local_tl tcg_const_local_i32 +#endif + +#if TCG_TARGET_REG_BITS == 32 +#define tcg_gen_add_ptr tcg_gen_add_i32 +#define tcg_gen_addi_ptr tcg_gen_addi_i32 +#define tcg_gen_ext_i32_ptr tcg_gen_mov_i32 +#else /* TCG_TARGET_REG_BITS == 32 */ +#define tcg_gen_add_ptr tcg_gen_add_i64 +#define tcg_gen_addi_ptr tcg_gen_addi_i64 +#define tcg_gen_ext_i32_ptr tcg_gen_ext_i32_i64 +#endif /* TCG_TARGET_REG_BITS != 32 */ + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/tcg-runtime.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/tcg-runtime.c --- qemu-0.9.1/tcg/tcg-runtime.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/tcg-runtime.c 2008-05-06 15:40:28.000000000 +0100 @@ -0,0 +1,68 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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 +#include +#include +#include +#include + +#include "config.h" +#include "osdep.h" +#include "tcg.h" + +int64_t tcg_helper_shl_i64(int64_t arg1, int64_t arg2) +{ + return arg1 << arg2; +} + +int64_t tcg_helper_shr_i64(int64_t arg1, int64_t arg2) +{ + return (uint64_t)arg1 >> arg2; +} + +int64_t tcg_helper_sar_i64(int64_t arg1, int64_t arg2) +{ + return arg1 >> arg2; +} + +int64_t tcg_helper_div_i64(int64_t arg1, int64_t arg2) +{ + return arg1 / arg2; +} + +int64_t tcg_helper_rem_i64(int64_t arg1, int64_t arg2) +{ + return arg1 % arg2; +} + +uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2) +{ + return arg1 / arg2; +} + +uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2) +{ + return arg1 % arg2; +} + diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/TODO /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/TODO --- qemu-0.9.1/tcg/TODO 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/TODO 2008-05-25 19:24:40.000000000 +0100 @@ -0,0 +1,15 @@ +- Add new instructions such as: andnot, ror, rol, setcond, clz, ctz, + popcnt. + +- See if it is worth exporting mul2, mulu2, div2, divu2. + +- Support of globals saved in fixed registers between TBs. + +Ideas: + +- Move the slow part of the qemu_ld/st ops after the end of the TB. + +- Change exception syntax to get closer to QOP system (exception + parameters given with a specific instruction). + +- Add float and vector support. diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/x86_64/tcg-target.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/x86_64/tcg-target.c --- qemu-0.9.1/tcg/x86_64/tcg-target.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/x86_64/tcg-target.c 2008-10-05 10:59:14.000000000 +0100 @@ -0,0 +1,1310 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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. + */ + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "%rax", + "%rcx", + "%rdx", + "%rbx", + "%rsp", + "%rbp", + "%rsi", + "%rdi", + "%r8", + "%r9", + "%r10", + "%r11", + "%r12", + "%r13", + "%r14", + "%r15", +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_RDI, + TCG_REG_RSI, + TCG_REG_RDX, + TCG_REG_RCX, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_RAX, + TCG_REG_R10, + TCG_REG_R11, + + TCG_REG_RBP, + TCG_REG_RBX, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_REG_R15, +}; + +static const int tcg_target_call_iarg_regs[6] = { + TCG_REG_RDI, + TCG_REG_RSI, + TCG_REG_RDX, + TCG_REG_RCX, + TCG_REG_R8, + TCG_REG_R9, +}; + +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_RAX, + TCG_REG_RDX +}; + +static uint8_t *tb_ret_addr; + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + value += addend; + switch(type) { + case R_X86_64_32: + if (value != (uint32_t)value) + tcg_abort(); + *(uint32_t *)code_ptr = value; + break; + case R_X86_64_32S: + if (value != (int32_t)value) + tcg_abort(); + *(uint32_t *)code_ptr = value; + break; + case R_386_PC32: + value -= (long)code_ptr; + if (value != (int32_t)value) + tcg_abort(); + *(uint32_t *)code_ptr = value; + break; + default: + tcg_abort(); + } +} + +/* maximum number of register used for input function arguments */ +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + return 6; +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch(ct_str[0]) { + case 'a': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_RAX); + break; + case 'b': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_RBX); + break; + case 'c': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_RCX); + break; + case 'd': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_RDX); + break; + case 'S': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_RSI); + break; + case 'D': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_RDI); + break; + case 'q': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xf); + break; + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffff); + break; + case 'L': /* qemu_ld/st constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_RSI); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_RDI); + break; + case 'e': + ct->ct |= TCG_CT_CONST_S32; + break; + case 'Z': + ct->ct |= TCG_CT_CONST_U32; + break; + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + else if ((ct & TCG_CT_CONST_S32) && val == (int32_t)val) + return 1; + else if ((ct & TCG_CT_CONST_U32) && val == (uint32_t)val) + return 1; + else + return 0; +} + +#define ARITH_ADD 0 +#define ARITH_OR 1 +#define ARITH_ADC 2 +#define ARITH_SBB 3 +#define ARITH_AND 4 +#define ARITH_SUB 5 +#define ARITH_XOR 6 +#define ARITH_CMP 7 + +#define SHIFT_SHL 4 +#define SHIFT_SHR 5 +#define SHIFT_SAR 7 + +#define JCC_JMP (-1) +#define JCC_JO 0x0 +#define JCC_JNO 0x1 +#define JCC_JB 0x2 +#define JCC_JAE 0x3 +#define JCC_JE 0x4 +#define JCC_JNE 0x5 +#define JCC_JBE 0x6 +#define JCC_JA 0x7 +#define JCC_JS 0x8 +#define JCC_JNS 0x9 +#define JCC_JP 0xa +#define JCC_JNP 0xb +#define JCC_JL 0xc +#define JCC_JGE 0xd +#define JCC_JLE 0xe +#define JCC_JG 0xf + +#define P_EXT 0x100 /* 0x0f opcode prefix */ +#define P_REXW 0x200 /* set rex.w = 1 */ +#define P_REXB 0x400 /* force rex use for byte registers */ + +static const uint8_t tcg_cond_to_jcc[10] = { + [TCG_COND_EQ] = JCC_JE, + [TCG_COND_NE] = JCC_JNE, + [TCG_COND_LT] = JCC_JL, + [TCG_COND_GE] = JCC_JGE, + [TCG_COND_LE] = JCC_JLE, + [TCG_COND_GT] = JCC_JG, + [TCG_COND_LTU] = JCC_JB, + [TCG_COND_GEU] = JCC_JAE, + [TCG_COND_LEU] = JCC_JBE, + [TCG_COND_GTU] = JCC_JA, +}; + +static inline void tcg_out_opc(TCGContext *s, int opc, int r, int rm, int x) +{ + int rex; + rex = ((opc >> 6) & 0x8) | ((r >> 1) & 0x4) | + ((x >> 2) & 2) | ((rm >> 3) & 1); + if (rex || (opc & P_REXB)) { + tcg_out8(s, rex | 0x40); + } + if (opc & P_EXT) + tcg_out8(s, 0x0f); + tcg_out8(s, opc); +} + +static inline void tcg_out_modrm(TCGContext *s, int opc, int r, int rm) +{ + tcg_out_opc(s, opc, r, rm, 0); + tcg_out8(s, 0xc0 | ((r & 7) << 3) | (rm & 7)); +} + +/* rm < 0 means no register index plus (-rm - 1 immediate bytes) */ +static inline void tcg_out_modrm_offset(TCGContext *s, int opc, int r, int rm, + tcg_target_long offset) +{ + if (rm < 0) { + tcg_target_long val; + tcg_out_opc(s, opc, r, 0, 0); + val = offset - ((tcg_target_long)s->code_ptr + 5 + (-rm - 1)); + if (val == (int32_t)val) { + /* eip relative */ + tcg_out8(s, 0x05 | ((r & 7) << 3)); + tcg_out32(s, val); + } else if (offset == (int32_t)offset) { + tcg_out8(s, 0x04 | ((r & 7) << 3)); + tcg_out8(s, 0x25); /* sib */ + tcg_out32(s, offset); + } else { + tcg_abort(); + } + } else if (offset == 0 && (rm & 7) != TCG_REG_RBP) { + tcg_out_opc(s, opc, r, rm, 0); + if ((rm & 7) == TCG_REG_RSP) { + tcg_out8(s, 0x04 | ((r & 7) << 3)); + tcg_out8(s, 0x24); + } else { + tcg_out8(s, 0x00 | ((r & 7) << 3) | (rm & 7)); + } + } else if ((int8_t)offset == offset) { + tcg_out_opc(s, opc, r, rm, 0); + if ((rm & 7) == TCG_REG_RSP) { + tcg_out8(s, 0x44 | ((r & 7) << 3)); + tcg_out8(s, 0x24); + } else { + tcg_out8(s, 0x40 | ((r & 7) << 3) | (rm & 7)); + } + tcg_out8(s, offset); + } else { + tcg_out_opc(s, opc, r, rm, 0); + if ((rm & 7) == TCG_REG_RSP) { + tcg_out8(s, 0x84 | ((r & 7) << 3)); + tcg_out8(s, 0x24); + } else { + tcg_out8(s, 0x80 | ((r & 7) << 3) | (rm & 7)); + } + tcg_out32(s, offset); + } +} + +#if defined(CONFIG_SOFTMMU) +/* XXX: incomplete. index must be different from ESP */ +static void tcg_out_modrm_offset2(TCGContext *s, int opc, int r, int rm, + int index, int shift, + tcg_target_long offset) +{ + int mod; + if (rm == -1) + tcg_abort(); + if (offset == 0 && (rm & 7) != TCG_REG_RBP) { + mod = 0; + } else if (offset == (int8_t)offset) { + mod = 0x40; + } else if (offset == (int32_t)offset) { + mod = 0x80; + } else { + tcg_abort(); + } + if (index == -1) { + tcg_out_opc(s, opc, r, rm, 0); + if ((rm & 7) == TCG_REG_RSP) { + tcg_out8(s, mod | ((r & 7) << 3) | 0x04); + tcg_out8(s, 0x04 | (rm & 7)); + } else { + tcg_out8(s, mod | ((r & 7) << 3) | (rm & 7)); + } + } else { + tcg_out_opc(s, opc, r, rm, index); + tcg_out8(s, mod | ((r & 7) << 3) | 0x04); + tcg_out8(s, (shift << 6) | ((index & 7) << 3) | (rm & 7)); + } + if (mod == 0x40) { + tcg_out8(s, offset); + } else if (mod == 0x80) { + tcg_out32(s, offset); + } +} +#endif + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + tcg_out_modrm(s, 0x8b | P_REXW, ret, arg); +} + +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + if (arg == 0) { + tcg_out_modrm(s, 0x01 | (ARITH_XOR << 3), ret, ret); /* xor r0,r0 */ + } else if (arg == (uint32_t)arg || type == TCG_TYPE_I32) { + tcg_out_opc(s, 0xb8 + (ret & 7), 0, ret, 0); + tcg_out32(s, arg); + } else if (arg == (int32_t)arg) { + tcg_out_modrm(s, 0xc7 | P_REXW, 0, ret); + tcg_out32(s, arg); + } else { + tcg_out_opc(s, (0xb8 + (ret & 7)) | P_REXW, 0, ret, 0); + tcg_out32(s, arg); + tcg_out32(s, arg >> 32); + } +} + +static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret, + int arg1, tcg_target_long arg2) +{ + if (type == TCG_TYPE_I32) + tcg_out_modrm_offset(s, 0x8b, ret, arg1, arg2); /* movl */ + else + tcg_out_modrm_offset(s, 0x8b | P_REXW, ret, arg1, arg2); /* movq */ +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + if (type == TCG_TYPE_I32) + tcg_out_modrm_offset(s, 0x89, arg, arg1, arg2); /* movl */ + else + tcg_out_modrm_offset(s, 0x89 | P_REXW, arg, arg1, arg2); /* movq */ +} + +static inline void tgen_arithi32(TCGContext *s, int c, int r0, int32_t val) +{ + if (val == (int8_t)val) { + tcg_out_modrm(s, 0x83, c, r0); + tcg_out8(s, val); + } else if (c == ARITH_AND && val == 0xffu) { + /* movzbl */ + tcg_out_modrm(s, 0xb6 | P_EXT | P_REXB, r0, r0); + } else if (c == ARITH_AND && val == 0xffffu) { + /* movzwl */ + tcg_out_modrm(s, 0xb7 | P_EXT, r0, r0); + } else { + tcg_out_modrm(s, 0x81, c, r0); + tcg_out32(s, val); + } +} + +static inline void tgen_arithi64(TCGContext *s, int c, int r0, int64_t val) +{ + if (val == (int8_t)val) { + tcg_out_modrm(s, 0x83 | P_REXW, c, r0); + tcg_out8(s, val); + } else if (c == ARITH_AND && val == 0xffu) { + /* movzbl */ + tcg_out_modrm(s, 0xb6 | P_EXT | P_REXW, r0, r0); + } else if (c == ARITH_AND && val == 0xffffu) { + /* movzwl */ + tcg_out_modrm(s, 0xb7 | P_EXT | P_REXW, r0, r0); + } else if (c == ARITH_AND && val == 0xffffffffu) { + /* 32-bit mov zero extends */ + tcg_out_modrm(s, 0x8b, r0, r0); + } else if (val == (int32_t)val) { + tcg_out_modrm(s, 0x81 | P_REXW, c, r0); + tcg_out32(s, val); + } else if (c == ARITH_AND && val == (uint32_t)val) { + tcg_out_modrm(s, 0x81, c, r0); + tcg_out32(s, val); + } else { + tcg_abort(); + } +} + +static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + if (val != 0) + tgen_arithi64(s, ARITH_ADD, reg, val); +} + +static void tcg_out_jxx(TCGContext *s, int opc, int label_index) +{ + int32_t val, val1; + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) { + val = l->u.value - (tcg_target_long)s->code_ptr; + val1 = val - 2; + if ((int8_t)val1 == val1) { + if (opc == -1) + tcg_out8(s, 0xeb); + else + tcg_out8(s, 0x70 + opc); + tcg_out8(s, val1); + } else { + if (opc == -1) { + tcg_out8(s, 0xe9); + tcg_out32(s, val - 5); + } else { + tcg_out8(s, 0x0f); + tcg_out8(s, 0x80 + opc); + tcg_out32(s, val - 6); + } + } + } else { + if (opc == -1) { + tcg_out8(s, 0xe9); + } else { + tcg_out8(s, 0x0f); + tcg_out8(s, 0x80 + opc); + } + tcg_out_reloc(s, s->code_ptr, R_386_PC32, label_index, -4); + s->code_ptr += 4; + } +} + +static void tcg_out_brcond(TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index, int rexw) +{ + if (const_arg2) { + if (arg2 == 0) { + /* test r, r */ + tcg_out_modrm(s, 0x85 | rexw, arg1, arg1); + } else { + if (rexw) + tgen_arithi64(s, ARITH_CMP, arg1, arg2); + else + tgen_arithi32(s, ARITH_CMP, arg1, arg2); + } + } else { + tcg_out_modrm(s, 0x01 | (ARITH_CMP << 3) | rexw, arg2, arg1); + } + tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index); +} + +#if defined(CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw; +#if defined(CONFIG_SOFTMMU) + uint8_t *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + s_bits = opc & 3; + + r0 = TCG_REG_RDI; + r1 = TCG_REG_RSI; + +#if TARGET_LONG_BITS == 32 + rexw = 0; +#else + rexw = P_REXW; +#endif +#if defined(CONFIG_SOFTMMU) + /* mov */ + tcg_out_modrm(s, 0x8b | rexw, r1, addr_reg); + + /* mov */ + tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg); + + tcg_out_modrm(s, 0xc1 | rexw, 5, r1); /* shr $x, r1 */ + tcg_out8(s, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + + tcg_out_modrm(s, 0x81 | rexw, 4, r0); /* andl $x, r0 */ + tcg_out32(s, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + + tcg_out_modrm(s, 0x81, 4, r1); /* andl $x, r1 */ + tcg_out32(s, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + + /* lea offset(r1, env), r1 */ + tcg_out_modrm_offset2(s, 0x8d | P_REXW, r1, r1, TCG_AREG0, 0, + offsetof(CPUState, tlb_table[mem_index][0].addr_read)); + + /* cmp 0(r1), r0 */ + tcg_out_modrm_offset(s, 0x3b | rexw, r0, r1, 0); + + /* mov */ + tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg); + + /* je label1 */ + tcg_out8(s, 0x70 + JCC_JE); + label1_ptr = s->code_ptr; + s->code_ptr++; + + /* XXX: move that code at the end of the TB */ + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RSI, mem_index); + tcg_out8(s, 0xe8); + tcg_out32(s, (tcg_target_long)qemu_ld_helpers[s_bits] - + (tcg_target_long)s->code_ptr - 4); + + switch(opc) { + case 0 | 4: + /* movsbq */ + tcg_out_modrm(s, 0xbe | P_EXT | P_REXW, data_reg, TCG_REG_RAX); + break; + case 1 | 4: + /* movswq */ + tcg_out_modrm(s, 0xbf | P_EXT | P_REXW, data_reg, TCG_REG_RAX); + break; + case 2 | 4: + /* movslq */ + tcg_out_modrm(s, 0x63 | P_REXW, data_reg, TCG_REG_RAX); + break; + case 0: + case 1: + case 2: + default: + /* movl */ + tcg_out_modrm(s, 0x8b, data_reg, TCG_REG_RAX); + break; + case 3: + tcg_out_mov(s, data_reg, TCG_REG_RAX); + break; + } + + /* jmp label2 */ + tcg_out8(s, 0xeb); + label2_ptr = s->code_ptr; + s->code_ptr++; + + /* label1: */ + *label1_ptr = s->code_ptr - label1_ptr - 1; + + /* add x(r1), r0 */ + tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_read)); +#else + r0 = addr_reg; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 1; +#else + bswap = 0; +#endif + switch(opc) { + case 0: + /* movzbl */ + tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, 0); + break; + case 0 | 4: + /* movsbX */ + tcg_out_modrm_offset(s, 0xbe | P_EXT | rexw, data_reg, r0, 0); + break; + case 1: + /* movzwl */ + tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0); + if (bswap) { + /* rolw $8, data_reg */ + tcg_out8(s, 0x66); + tcg_out_modrm(s, 0xc1, 0, data_reg); + tcg_out8(s, 8); + } + break; + case 1 | 4: + if (bswap) { + /* movzwl */ + tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0); + /* rolw $8, data_reg */ + tcg_out8(s, 0x66); + tcg_out_modrm(s, 0xc1, 0, data_reg); + tcg_out8(s, 8); + + /* movswX data_reg, data_reg */ + tcg_out_modrm(s, 0xbf | P_EXT | rexw, data_reg, data_reg); + } else { + /* movswX */ + tcg_out_modrm_offset(s, 0xbf | P_EXT | rexw, data_reg, r0, 0); + } + break; + case 2: + /* movl (r0), data_reg */ + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0); + if (bswap) { + /* bswap */ + tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0); + } + break; + case 2 | 4: + if (bswap) { + /* movl (r0), data_reg */ + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0); + /* bswap */ + tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0); + /* movslq */ + tcg_out_modrm(s, 0x63 | P_REXW, data_reg, data_reg); + } else { + /* movslq */ + tcg_out_modrm_offset(s, 0x63 | P_REXW, data_reg, r0, 0); + } + break; + case 3: + /* movq (r0), data_reg */ + tcg_out_modrm_offset(s, 0x8b | P_REXW, data_reg, r0, 0); + if (bswap) { + /* bswap */ + tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT | P_REXW, 0, data_reg, 0); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = s->code_ptr - label2_ptr - 1; +#endif +} + +static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw; +#if defined(CONFIG_SOFTMMU) + uint8_t *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + + s_bits = opc; + + r0 = TCG_REG_RDI; + r1 = TCG_REG_RSI; + +#if TARGET_LONG_BITS == 32 + rexw = 0; +#else + rexw = P_REXW; +#endif +#if defined(CONFIG_SOFTMMU) + /* mov */ + tcg_out_modrm(s, 0x8b | rexw, r1, addr_reg); + + /* mov */ + tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg); + + tcg_out_modrm(s, 0xc1 | rexw, 5, r1); /* shr $x, r1 */ + tcg_out8(s, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + + tcg_out_modrm(s, 0x81 | rexw, 4, r0); /* andl $x, r0 */ + tcg_out32(s, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + + tcg_out_modrm(s, 0x81, 4, r1); /* andl $x, r1 */ + tcg_out32(s, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + + /* lea offset(r1, env), r1 */ + tcg_out_modrm_offset2(s, 0x8d | P_REXW, r1, r1, TCG_AREG0, 0, + offsetof(CPUState, tlb_table[mem_index][0].addr_write)); + + /* cmp 0(r1), r0 */ + tcg_out_modrm_offset(s, 0x3b | rexw, r0, r1, 0); + + /* mov */ + tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg); + + /* je label1 */ + tcg_out8(s, 0x70 + JCC_JE); + label1_ptr = s->code_ptr; + s->code_ptr++; + + /* XXX: move that code at the end of the TB */ + switch(opc) { + case 0: + /* movzbl */ + tcg_out_modrm(s, 0xb6 | P_EXT | P_REXB, TCG_REG_RSI, data_reg); + break; + case 1: + /* movzwl */ + tcg_out_modrm(s, 0xb7 | P_EXT, TCG_REG_RSI, data_reg); + break; + case 2: + /* movl */ + tcg_out_modrm(s, 0x8b, TCG_REG_RSI, data_reg); + break; + default: + case 3: + tcg_out_mov(s, TCG_REG_RSI, data_reg); + break; + } + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RDX, mem_index); + tcg_out8(s, 0xe8); + tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] - + (tcg_target_long)s->code_ptr - 4); + + /* jmp label2 */ + tcg_out8(s, 0xeb); + label2_ptr = s->code_ptr; + s->code_ptr++; + + /* label1: */ + *label1_ptr = s->code_ptr - label1_ptr - 1; + + /* add x(r1), r0 */ + tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_write)); +#else + r0 = addr_reg; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 1; +#else + bswap = 0; +#endif + switch(opc) { + case 0: + /* movb */ + tcg_out_modrm_offset(s, 0x88 | P_REXB, data_reg, r0, 0); + break; + case 1: + if (bswap) { + tcg_out_modrm(s, 0x8b, r1, data_reg); /* movl */ + tcg_out8(s, 0x66); /* rolw $8, %ecx */ + tcg_out_modrm(s, 0xc1, 0, r1); + tcg_out8(s, 8); + data_reg = r1; + } + /* movw */ + tcg_out8(s, 0x66); + tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0); + break; + case 2: + if (bswap) { + tcg_out_modrm(s, 0x8b, r1, data_reg); /* movl */ + /* bswap data_reg */ + tcg_out_opc(s, (0xc8 + r1) | P_EXT, 0, r1, 0); + data_reg = r1; + } + /* movl */ + tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0); + break; + case 3: + if (bswap) { + tcg_out_mov(s, r1, data_reg); + /* bswap data_reg */ + tcg_out_opc(s, (0xc8 + r1) | P_EXT | P_REXW, 0, r1, 0); + data_reg = r1; + } + /* movq */ + tcg_out_modrm_offset(s, 0x89 | P_REXW, data_reg, r0, 0); + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = s->code_ptr - label2_ptr - 1; +#endif +} + +static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, + const int *const_args) +{ + int c; + + switch(opc) { + case INDEX_op_exit_tb: + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RAX, args[0]); + tcg_out8(s, 0xe9); /* jmp tb_ret_addr */ + tcg_out32(s, tb_ret_addr - s->code_ptr - 4); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + tcg_out8(s, 0xe9); /* jmp im */ + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + tcg_out32(s, 0); + } else { + /* indirect jump method */ + /* jmp Ev */ + tcg_out_modrm_offset(s, 0xff, 4, -1, + (tcg_target_long)(s->tb_next + + args[0])); + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_call: + if (const_args[0]) { + tcg_out8(s, 0xe8); + tcg_out32(s, args[0] - (tcg_target_long)s->code_ptr - 4); + } else { + tcg_out_modrm(s, 0xff, 2, args[0]); + } + break; + case INDEX_op_jmp: + if (const_args[0]) { + tcg_out8(s, 0xe9); + tcg_out32(s, args[0] - (tcg_target_long)s->code_ptr - 4); + } else { + tcg_out_modrm(s, 0xff, 4, args[0]); + } + break; + case INDEX_op_br: + tcg_out_jxx(s, JCC_JMP, args[0]); + break; + case INDEX_op_movi_i32: + tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]); + break; + case INDEX_op_movi_i64: + tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]); + break; + case INDEX_op_ld8u_i32: + case INDEX_op_ld8u_i64: + /* movzbl */ + tcg_out_modrm_offset(s, 0xb6 | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld8s_i32: + /* movsbl */ + tcg_out_modrm_offset(s, 0xbe | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld8s_i64: + /* movsbq */ + tcg_out_modrm_offset(s, 0xbe | P_EXT | P_REXW, args[0], args[1], args[2]); + break; + case INDEX_op_ld16u_i32: + case INDEX_op_ld16u_i64: + /* movzwl */ + tcg_out_modrm_offset(s, 0xb7 | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld16s_i32: + /* movswl */ + tcg_out_modrm_offset(s, 0xbf | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld16s_i64: + /* movswq */ + tcg_out_modrm_offset(s, 0xbf | P_EXT | P_REXW, args[0], args[1], args[2]); + break; + case INDEX_op_ld_i32: + case INDEX_op_ld32u_i64: + /* movl */ + tcg_out_modrm_offset(s, 0x8b, args[0], args[1], args[2]); + break; + case INDEX_op_ld32s_i64: + /* movslq */ + tcg_out_modrm_offset(s, 0x63 | P_REXW, args[0], args[1], args[2]); + break; + case INDEX_op_ld_i64: + /* movq */ + tcg_out_modrm_offset(s, 0x8b | P_REXW, args[0], args[1], args[2]); + break; + + case INDEX_op_st8_i32: + case INDEX_op_st8_i64: + /* movb */ + tcg_out_modrm_offset(s, 0x88 | P_REXB, args[0], args[1], args[2]); + break; + case INDEX_op_st16_i32: + case INDEX_op_st16_i64: + /* movw */ + tcg_out8(s, 0x66); + tcg_out_modrm_offset(s, 0x89, args[0], args[1], args[2]); + break; + case INDEX_op_st_i32: + case INDEX_op_st32_i64: + /* movl */ + tcg_out_modrm_offset(s, 0x89, args[0], args[1], args[2]); + break; + case INDEX_op_st_i64: + /* movq */ + tcg_out_modrm_offset(s, 0x89 | P_REXW, args[0], args[1], args[2]); + break; + + case INDEX_op_sub_i32: + c = ARITH_SUB; + goto gen_arith32; + case INDEX_op_and_i32: + c = ARITH_AND; + goto gen_arith32; + case INDEX_op_or_i32: + c = ARITH_OR; + goto gen_arith32; + case INDEX_op_xor_i32: + c = ARITH_XOR; + goto gen_arith32; + case INDEX_op_add_i32: + c = ARITH_ADD; + gen_arith32: + if (const_args[2]) { + tgen_arithi32(s, c, args[0], args[2]); + } else { + tcg_out_modrm(s, 0x01 | (c << 3), args[2], args[0]); + } + break; + + case INDEX_op_sub_i64: + c = ARITH_SUB; + goto gen_arith64; + case INDEX_op_and_i64: + c = ARITH_AND; + goto gen_arith64; + case INDEX_op_or_i64: + c = ARITH_OR; + goto gen_arith64; + case INDEX_op_xor_i64: + c = ARITH_XOR; + goto gen_arith64; + case INDEX_op_add_i64: + c = ARITH_ADD; + gen_arith64: + if (const_args[2]) { + tgen_arithi64(s, c, args[0], args[2]); + } else { + tcg_out_modrm(s, 0x01 | (c << 3) | P_REXW, args[2], args[0]); + } + break; + + case INDEX_op_mul_i32: + if (const_args[2]) { + int32_t val; + val = args[2]; + if (val == (int8_t)val) { + tcg_out_modrm(s, 0x6b, args[0], args[0]); + tcg_out8(s, val); + } else { + tcg_out_modrm(s, 0x69, args[0], args[0]); + tcg_out32(s, val); + } + } else { + tcg_out_modrm(s, 0xaf | P_EXT, args[0], args[2]); + } + break; + case INDEX_op_mul_i64: + if (const_args[2]) { + int32_t val; + val = args[2]; + if (val == (int8_t)val) { + tcg_out_modrm(s, 0x6b | P_REXW, args[0], args[0]); + tcg_out8(s, val); + } else { + tcg_out_modrm(s, 0x69 | P_REXW, args[0], args[0]); + tcg_out32(s, val); + } + } else { + tcg_out_modrm(s, 0xaf | P_EXT | P_REXW, args[0], args[2]); + } + break; + case INDEX_op_div2_i32: + tcg_out_modrm(s, 0xf7, 7, args[4]); + break; + case INDEX_op_divu2_i32: + tcg_out_modrm(s, 0xf7, 6, args[4]); + break; + case INDEX_op_div2_i64: + tcg_out_modrm(s, 0xf7 | P_REXW, 7, args[4]); + break; + case INDEX_op_divu2_i64: + tcg_out_modrm(s, 0xf7 | P_REXW, 6, args[4]); + break; + + case INDEX_op_shl_i32: + c = SHIFT_SHL; + gen_shift32: + if (const_args[2]) { + if (args[2] == 1) { + tcg_out_modrm(s, 0xd1, c, args[0]); + } else { + tcg_out_modrm(s, 0xc1, c, args[0]); + tcg_out8(s, args[2]); + } + } else { + tcg_out_modrm(s, 0xd3, c, args[0]); + } + break; + case INDEX_op_shr_i32: + c = SHIFT_SHR; + goto gen_shift32; + case INDEX_op_sar_i32: + c = SHIFT_SAR; + goto gen_shift32; + + case INDEX_op_shl_i64: + c = SHIFT_SHL; + gen_shift64: + if (const_args[2]) { + if (args[2] == 1) { + tcg_out_modrm(s, 0xd1 | P_REXW, c, args[0]); + } else { + tcg_out_modrm(s, 0xc1 | P_REXW, c, args[0]); + tcg_out8(s, args[2]); + } + } else { + tcg_out_modrm(s, 0xd3 | P_REXW, c, args[0]); + } + break; + case INDEX_op_shr_i64: + c = SHIFT_SHR; + goto gen_shift64; + case INDEX_op_sar_i64: + c = SHIFT_SAR; + goto gen_shift64; + + case INDEX_op_brcond_i32: + tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], + args[3], 0); + break; + case INDEX_op_brcond_i64: + tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], + args[3], P_REXW); + break; + + case INDEX_op_bswap_i32: + tcg_out_opc(s, (0xc8 + (args[0] & 7)) | P_EXT, 0, args[0], 0); + break; + case INDEX_op_bswap_i64: + tcg_out_opc(s, (0xc8 + (args[0] & 7)) | P_EXT | P_REXW, 0, args[0], 0); + break; + + case INDEX_op_neg_i32: + tcg_out_modrm(s, 0xf7, 3, args[0]); + break; + case INDEX_op_neg_i64: + tcg_out_modrm(s, 0xf7 | P_REXW, 3, args[0]); + break; + + case INDEX_op_ext8s_i32: + tcg_out_modrm(s, 0xbe | P_EXT | P_REXB, args[0], args[1]); + break; + case INDEX_op_ext16s_i32: + tcg_out_modrm(s, 0xbf | P_EXT, args[0], args[1]); + break; + case INDEX_op_ext8s_i64: + tcg_out_modrm(s, 0xbe | P_EXT | P_REXW, args[0], args[1]); + break; + case INDEX_op_ext16s_i64: + tcg_out_modrm(s, 0xbf | P_EXT | P_REXW, args[0], args[1]); + break; + case INDEX_op_ext32s_i64: + tcg_out_modrm(s, 0x63 | P_REXW, args[0], args[1]); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, args, 2); + break; + case INDEX_op_qemu_ld32s: + tcg_out_qemu_ld(s, args, 2 | 4); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, args, 3); + break; + + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, args, 3); + break; + + default: + tcg_abort(); + } +} + +static int tcg_target_callee_save_regs[] = { + TCG_REG_RBP, + TCG_REG_RBX, + TCG_REG_R12, + TCG_REG_R13, + /* TCG_REG_R14, */ /* currently used for the global env, so no + need to save */ + TCG_REG_R15, +}; + +static inline void tcg_out_push(TCGContext *s, int reg) +{ + tcg_out_opc(s, (0x50 + (reg & 7)), 0, reg, 0); +} + +static inline void tcg_out_pop(TCGContext *s, int reg) +{ + tcg_out_opc(s, (0x58 + (reg & 7)), 0, reg, 0); +} + +/* Generate global QEMU prologue and epilogue code */ +void tcg_target_qemu_prologue(TCGContext *s) +{ + int i, frame_size, push_size, stack_addend; + + /* TB prologue */ + /* save all callee saved registers */ + for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { + tcg_out_push(s, tcg_target_callee_save_regs[i]); + + } + /* reserve some stack space */ + push_size = 8 + ARRAY_SIZE(tcg_target_callee_save_regs) * 8; + frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE; + frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & + ~(TCG_TARGET_STACK_ALIGN - 1); + stack_addend = frame_size - push_size; + tcg_out_addi(s, TCG_REG_RSP, -stack_addend); + + tcg_out_modrm(s, 0xff, 4, TCG_REG_RDI); /* jmp *%rdi */ + + /* TB epilogue */ + tb_ret_addr = s->code_ptr; + tcg_out_addi(s, TCG_REG_RSP, stack_addend); + for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) { + tcg_out_pop(s, tcg_target_callee_save_regs[i]); + } + tcg_out8(s, 0xc3); /* ret */ +} + +static const TCGTargetOpDef x86_64_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, /* XXX: might need a specific constant constraint */ + { INDEX_op_jmp, { "ri" } }, /* XXX: might need a specific constant constraint */ + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "0", "ri" } }, + { INDEX_op_mul_i32, { "r", "0", "ri" } }, + { INDEX_op_div2_i32, { "a", "d", "0", "1", "r" } }, + { INDEX_op_divu2_i32, { "a", "d", "0", "1", "r" } }, + { INDEX_op_sub_i32, { "r", "0", "ri" } }, + { INDEX_op_and_i32, { "r", "0", "ri" } }, + { INDEX_op_or_i32, { "r", "0", "ri" } }, + { INDEX_op_xor_i32, { "r", "0", "ri" } }, + + { INDEX_op_shl_i32, { "r", "0", "ci" } }, + { INDEX_op_shr_i32, { "r", "0", "ci" } }, + { INDEX_op_sar_i32, { "r", "0", "ci" } }, + + { INDEX_op_brcond_i32, { "r", "ri" } }, + + { INDEX_op_mov_i64, { "r", "r" } }, + { INDEX_op_movi_i64, { "r" } }, + { INDEX_op_ld8u_i64, { "r", "r" } }, + { INDEX_op_ld8s_i64, { "r", "r" } }, + { INDEX_op_ld16u_i64, { "r", "r" } }, + { INDEX_op_ld16s_i64, { "r", "r" } }, + { INDEX_op_ld32u_i64, { "r", "r" } }, + { INDEX_op_ld32s_i64, { "r", "r" } }, + { INDEX_op_ld_i64, { "r", "r" } }, + { INDEX_op_st8_i64, { "r", "r" } }, + { INDEX_op_st16_i64, { "r", "r" } }, + { INDEX_op_st32_i64, { "r", "r" } }, + { INDEX_op_st_i64, { "r", "r" } }, + + { INDEX_op_add_i64, { "r", "0", "re" } }, + { INDEX_op_mul_i64, { "r", "0", "re" } }, + { INDEX_op_div2_i64, { "a", "d", "0", "1", "r" } }, + { INDEX_op_divu2_i64, { "a", "d", "0", "1", "r" } }, + { INDEX_op_sub_i64, { "r", "0", "re" } }, + { INDEX_op_and_i64, { "r", "0", "reZ" } }, + { INDEX_op_or_i64, { "r", "0", "re" } }, + { INDEX_op_xor_i64, { "r", "0", "re" } }, + + { INDEX_op_shl_i64, { "r", "0", "ci" } }, + { INDEX_op_shr_i64, { "r", "0", "ci" } }, + { INDEX_op_sar_i64, { "r", "0", "ci" } }, + + { INDEX_op_brcond_i64, { "r", "re" } }, + + { INDEX_op_bswap_i32, { "r", "0" } }, + { INDEX_op_bswap_i64, { "r", "0" } }, + + { INDEX_op_neg_i32, { "r", "0" } }, + { INDEX_op_neg_i64, { "r", "0" } }, + + { INDEX_op_ext8s_i32, { "r", "r"} }, + { INDEX_op_ext16s_i32, { "r", "r"} }, + { INDEX_op_ext8s_i64, { "r", "r"} }, + { INDEX_op_ext16s_i64, { "r", "r"} }, + { INDEX_op_ext32s_i64, { "r", "r"} }, + + { INDEX_op_qemu_ld8u, { "r", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L" } }, + { INDEX_op_qemu_ld32s, { "r", "L" } }, + { INDEX_op_qemu_ld64, { "r", "L" } }, + + { INDEX_op_qemu_st8, { "L", "L" } }, + { INDEX_op_qemu_st16, { "L", "L" } }, + { INDEX_op_qemu_st32, { "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L", "L" } }, + + { -1 }, +}; + +void tcg_target_init(TCGContext *s) +{ + /* fail safe */ + if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) + tcg_abort(); + + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff); + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffff); + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_RDI) | + (1 << TCG_REG_RSI) | + (1 << TCG_REG_RDX) | + (1 << TCG_REG_RCX) | + (1 << TCG_REG_R8) | + (1 << TCG_REG_R9) | + (1 << TCG_REG_RAX) | + (1 << TCG_REG_R10) | + (1 << TCG_REG_R11)); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_RSP); + + tcg_add_target_add_op_defs(x86_64_op_defs); +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tcg/x86_64/tcg-target.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tcg/x86_64/tcg-target.h --- qemu-0.9.1/tcg/x86_64/tcg-target.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tcg/x86_64/tcg-target.h 2008-09-07 18:45:15.000000000 +0100 @@ -0,0 +1,77 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * 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. + */ +#define TCG_TARGET_X86_64 1 + +#define TCG_TARGET_REG_BITS 64 +//#define TCG_TARGET_WORDS_BIGENDIAN + +#define TCG_TARGET_NB_REGS 16 + +enum { + TCG_REG_RAX = 0, + TCG_REG_RCX, + TCG_REG_RDX, + TCG_REG_RBX, + TCG_REG_RSP, + TCG_REG_RBP, + TCG_REG_RSI, + TCG_REG_RDI, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_REG_R15, +}; + +#define TCG_CT_CONST_S32 0x100 +#define TCG_CT_CONST_U32 0x200 + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_RSP +#define TCG_TARGET_STACK_ALIGN 16 +#define TCG_TARGET_CALL_STACK_OFFSET 0 + +/* optional instructions */ +#define TCG_TARGET_HAS_bswap_i32 +#define TCG_TARGET_HAS_bswap_i64 +#define TCG_TARGET_HAS_neg_i32 +#define TCG_TARGET_HAS_neg_i64 +#define TCG_TARGET_HAS_ext8s_i32 +#define TCG_TARGET_HAS_ext16s_i32 +#define TCG_TARGET_HAS_ext8s_i64 +#define TCG_TARGET_HAS_ext16s_i64 +#define TCG_TARGET_HAS_ext32s_i64 + +/* Note: must be synced with dyngen-exec.h */ +#define TCG_AREG0 TCG_REG_R14 +#define TCG_AREG1 TCG_REG_R15 +#define TCG_AREG2 TCG_REG_R12 +#define TCG_AREG3 TCG_REG_R13 + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/alpha/crt.s /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/alpha/crt.s --- qemu-0.9.1/tests/alpha/crt.s 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tests/alpha/crt.s 2008-09-17 23:04:37.000000000 +0100 @@ -0,0 +1,26 @@ + .text + + .globl _start + .ent _start,0 +_start: + .frame $15,0,$15 + br $29,1f +1: ldgp $29, 0($29) + .prologue 0 + ldq $27,main($29) !literal!1 + jsr $26,($27) + or $0,$0,$16 + .end _start + + .globl _exit +_exit: + lda $0,1 + callsys + + call_pal 0 + + .globl write +write: + lda $0,4 + callsys + ret diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/alpha/hello-alpha.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/alpha/hello-alpha.c --- qemu-0.9.1/tests/alpha/hello-alpha.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tests/alpha/hello-alpha.c 2008-09-14 18:18:29.000000000 +0100 @@ -0,0 +1,5 @@ +int main (void) +{ + write (1, "hello\n", 6); + return 0; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/alpha/Makefile /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/alpha/Makefile --- qemu-0.9.1/tests/alpha/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tests/alpha/Makefile 2008-09-17 23:04:37.000000000 +0100 @@ -0,0 +1,32 @@ +CROSS=alpha-linux-gnu- +CC=$(CROSS)gcc +AS=$(CROSS)as + +SIM=../../alpha-linux-user/qemu-alpha + +CFLAGS=-O +LINK=$(CC) -o $@ crt.o $< -nostdlib + +TESTS=test-cond test-cmov + +all: hello-alpha $(TESTS) + +hello-alpha: hello-alpha.o crt.o + $(LINK) + +test-cond: test-cond.o crt.o + $(LINK) + +test-cmov.o: test-cond.c + $(CC) -c $(CFLAGS) -DTEST_CMOV -o $@ $< + +test-cmov: test-cmov.o crt.o + $(LINK) + +check: $(TESTS) + for f in $(TESTS); do $(SIM) $$f || exit 1; done + +clean: + $(RM) *.o *~ hello-alpha $(TESTS) + +.PHONY: clean all check diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/alpha/test-cond.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/alpha/test-cond.c --- qemu-0.9.1/tests/alpha/test-cond.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tests/alpha/test-cond.c 2008-09-14 18:18:29.000000000 +0100 @@ -0,0 +1,87 @@ + +#ifdef TEST_CMOV + +#define TEST_COND(N) \ +int test_##N (long a) \ +{ \ + int res = 1; \ + \ + asm ("cmov"#N" %1,$31,%0" \ + : "+r" (res) : "r" (a)); \ + return !res; \ +} + +#else + +#define TEST_COND(N) \ +int test_##N (long a) \ +{ \ + int res = 1; \ + \ + asm ("b"#N" %1,1f\n\t" \ + "addq $31,$31,%0\n\t" \ + "1: unop\n" \ + : "+r" (res) : "r" (a)); \ + return res; \ +} + +#endif + +TEST_COND(eq) +TEST_COND(ne) +TEST_COND(ge) +TEST_COND(gt) +TEST_COND(lbc) +TEST_COND(lbs) +TEST_COND(le) +TEST_COND(lt) + +static struct { + int (*func)(long); + long v; + int r; +} vectors[] = + { + {test_eq, 0, 1}, + {test_eq, 1, 0}, + + {test_ne, 0, 0}, + {test_ne, 1, 1}, + + {test_ge, 0, 1}, + {test_ge, 1, 1}, + {test_ge, -1, 0}, + + {test_gt, 0, 0}, + {test_gt, 1, 1}, + {test_gt, -1, 0}, + + {test_lbc, 0, 1}, + {test_lbc, 1, 0}, + {test_lbc, -1, 0}, + + {test_lbs, 0, 0}, + {test_lbs, 1, 1}, + {test_lbs, -1, 1}, + + {test_le, 0, 1}, + {test_le, 1, 0}, + {test_le, -1, 1}, + + {test_lt, 0, 0}, + {test_lt, 1, 0}, + {test_lt, -1, 1}, + }; + +int main (void) +{ + int i; + + for (i = 0; i < sizeof (vectors)/sizeof(vectors[0]); i++) + if ((*vectors[i].func)(vectors[i].v) != vectors[i].r) { + write(1, "Failed\n", 7); + return 1; + } + write(1, "OK\n", 3); + return 0; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/cris/check_btst.s /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/cris/check_btst.s --- qemu-0.9.1/tests/cris/check_btst.s 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/tests/cris/check_btst.s 2008-05-02 22:13:21.000000000 +0100 @@ -84,4 +84,13 @@ move.d 0x1111,r3 checkr3 1111 + ; check that X gets cleared and that only the NZ flags are touched. + move.d 0xff, $r0 + move $r0, $ccs + btst r3,r3 + move $ccs, $r0 + and.d 0xff, $r0 + cmp.d 0xe3, $r0 + test_cc 0 1 0 0 + quit diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/cris/check_clearfv32.s /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/cris/check_clearfv32.s --- qemu-0.9.1/tests/cris/check_clearfv32.s 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/tests/cris/check_clearfv32.s 2008-05-02 22:13:21.000000000 +0100 @@ -8,10 +8,12 @@ setf puixnzvc clearf x ; Actually, x would be cleared by almost-all other insns. move ccs,r3 + and.d 0xff, $r3 checkr3 ef setf puixnzvc moveq 0, $r3 ; moveq should only clear the xflag. move ccs,r3 + and.d 0xff, $r3 checkr3 ef quit diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/cris/check_ftag.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/cris/check_ftag.c --- qemu-0.9.1/tests/cris/check_ftag.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tests/cris/check_ftag.c 2008-02-25 10:00:07.000000000 +0000 @@ -0,0 +1,33 @@ +#include +#include +#include +#include "sys.h" +#include "crisutils.h" + +extern inline void cris_ftag_i(unsigned int x) { + register unsigned int v asm("$r10") = x; + asm ("ftagi\t[%0]\n" : : "r" (v) ); +} +extern inline void cris_ftag_d(unsigned int x) { + register unsigned int v asm("$r10") = x; + asm ("ftagd\t[%0]\n" : : "r" (v) ); +} +extern inline void cris_fidx_i(unsigned int x) { + register unsigned int v asm("$r10") = x; + asm ("fidxi\t[%0]\n" : : "r" (v) ); +} +extern inline void cris_fidx_d(unsigned int x) { + register unsigned int v asm("$r10") = x; + asm ("fidxd\t[%0]\n" : : "r" (v) ); +} + + +int main(void) +{ + cris_ftag_i(0); + cris_ftag_d(0); + cris_fidx_i(0); + cris_fidx_d(0); + pass(); + return 0; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/cris/check_movei.s /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/cris/check_movei.s --- qemu-0.9.1/tests/cris/check_movei.s 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/tests/cris/check_movei.s 2008-06-06 12:00:58.000000000 +0100 @@ -7,8 +7,11 @@ .include "testutils.inc" start + move.d 0, $r3 ; A write that works. Check that flags are set correspondingly. move.d d,r4 + ;; store to bring it into the tlb with the right prot bits + move.d r3,[r4] moveq -2,r5 setf c clearf p diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/cris/check_moverm.s /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/cris/check_moverm.s --- qemu-0.9.1/tests/cris/check_moverm.s 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/tests/cris/check_moverm.s 2008-05-02 22:08:33.000000000 +0100 @@ -40,6 +40,6 @@ test_cc 0 1 1 0 subq 1,r2 move.d [r2],r3 - checkr3 102318ff + checkr3 102318fe quit diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/cris/check_sigalrm.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/cris/check_sigalrm.c --- qemu-0.9.1/tests/cris/check_sigalrm.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tests/cris/check_sigalrm.c 2008-02-28 11:23:20.000000000 +0000 @@ -0,0 +1,26 @@ +#include +#include +#include +#include + +#define MAGIC (0xdeadbeef) + +int s = 0; +void sighandler(int sig) +{ + s = MAGIC; +} + +int main(int argc, char **argv) +{ + int p; + + p = getpid(); + signal(SIGALRM, sighandler); + kill(p, SIGALRM); + if (s != MAGIC) + return EXIT_FAILURE; + + printf ("passed\n"); + return EXIT_SUCCESS; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/cris/check_swap.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/cris/check_swap.c --- qemu-0.9.1/tests/cris/check_swap.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/tests/cris/check_swap.c 2008-06-06 12:00:04.000000000 +0100 @@ -72,4 +72,5 @@ { check_swap(); pass(); + return 0; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/cris/check_xarith.s /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/cris/check_xarith.s --- qemu-0.9.1/tests/cris/check_xarith.s 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/tests/cris/check_xarith.s 2008-06-06 12:05:18.000000000 +0100 @@ -42,5 +42,31 @@ nop fail 1: + + ;; test for broken X sequence, run it several times. + moveq 8, $r0 +1: + moveq 0, $r3 + move.d $r0, $r1 + andq 1, $r1 + lslq 4, $r1 + moveq 1, $r2 + or.d $r1, $r2 + ba 2f + move $r2, $ccs +2: + addq 0, $r3 + move.d $r0, $r4 + move.d $r1, $r5 + move.d $r2, $r6 + move.d $r3, $r7 + lsrq 4, $r1 + move.d $r1, $r8 + xor $r1, $r3 + checkr3 0 + subq 1, $r0 + bne 1b + nop + pass quit diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/cris/crisutils.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/cris/crisutils.h --- qemu-0.9.1/tests/cris/crisutils.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/tests/cris/crisutils.h 2008-06-06 12:00:04.000000000 +0100 @@ -4,7 +4,7 @@ do { tst_cc_loc = "test_cc failed at " CURRENT_LOCATION; } while(0) /* We need a real symbol to signal error. */ -static void _err(void) { +void _err(void) { if (!tst_cc_loc) tst_cc_loc = "tst_cc_failed\n"; _fail(tst_cc_loc); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/cris/Makefile /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/cris/Makefile --- qemu-0.9.1/tests/cris/Makefile 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/tests/cris/Makefile 2008-06-06 12:07:50.000000000 +0100 @@ -55,6 +55,7 @@ TESTCASES += check_cmp-2.tst TESTCASES += check_clrjmp1.tst TESTCASES += check_dstep.tst +TESTCASES += check_ftag.tst TESTCASES += check_int64.tst # check_jsr is broken. #TESTCASES += check_jsr.tst @@ -113,6 +114,7 @@ TESTCASES += check_mmap1.ctst TESTCASES += check_mmap2.ctst TESTCASES += check_mmap3.ctst +TESTCASES += check_sigalrm.ctst TESTCASES += check_time1.ctst TESTCASES += check_time2.ctst @@ -138,9 +140,9 @@ check: $(CRT) $(SYS) $(TESTCASES) @echo -e "\nQEMU simulator." - @for case in $(TESTCASES); do \ + for case in $(TESTCASES); do \ echo -n "$$case "; \ - $(SIM) $$case; \ + $(SIM) ./$$case; \ done check-g: $(CRT) $(SYS) $(TESTCASES) @echo -e "\nGDB simulator." diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/cris/sys.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/cris/sys.c --- qemu-0.9.1/tests/cris/sys.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/tests/cris/sys.c 2008-06-06 12:07:50.000000000 +0100 @@ -16,7 +16,7 @@ } void _fail(char *reason) { - char s[] = "failed: "; + char s[] = "\nfailed: "; int len = mystrlen(reason); write (1, s, sizeof (s) - 1); write (1, reason, len); @@ -41,8 +41,11 @@ ssize_t write (int fd, const void *buf, size_t count) { int r; - asm volatile ("moveq 4, $r9\n" /* NR_write. */ - "break 13\n" : : : "memory"); - asm volatile ("move.d $r10, %0\n" : "=r" (r)); + asm ("move.d %0, $r10\n" + "move.d %1, $r11\n" + "move.d %2, $r12\n" + "moveq 4, $r9\n" /* NR_write. */ + "break 13\n" : : "r" (fd), "r" (buf), "r" (count) : "memory"); + asm ("move.d $r10, %0\n" : "=r" (r)); return r; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/cris/testutils.inc /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/cris/testutils.inc --- qemu-0.9.1/tests/cris/testutils.inc 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/tests/cris/testutils.inc 2008-06-06 12:07:50.000000000 +0100 @@ -23,7 +23,7 @@ .macro fail .data 99: - .asciz " checkr3 failed" + .asciz " checkr3 failed\n" .text move.d 99b, $r10 jsr _fail @@ -36,7 +36,7 @@ nop .data 99: - .asciz "checkr3 failed" + .asciz "checkr3 failed\n" .text move.d 99b, $r10 jsr _fail @@ -79,7 +79,7 @@ 9: .data 99: - .asciz "test_move_cc failed" + .asciz "test_move_cc failed\n" .text move.d 99b, $r10 jsr _fail @@ -108,7 +108,7 @@ 9: .data 99: - .asciz "test_move_cc failed" + .asciz "test_move_cc failed\n" .text move.d 99b, $r10 jsr _fail diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/.cvsignore /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/.cvsignore --- qemu-0.9.1/tests/.cvsignore 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/tests/.cvsignore 1970-01-01 01:00:00.000000000 +0100 @@ -1,23 +0,0 @@ - gmon.out - testsig - hello-i386 - hello-arm - sha1.test.c - sha1.c - test-i386 - sha1 - testclone - .gdb_history - testthread - test-i386.s - test-i386.ref - sha1-i386 - runcom - debug.com - test-i386.out - speed.txt - test-i386.ref.P3 - pi_10.com - test-i386.ref.P4 - ldso.c - test_path diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/Makefile /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/Makefile --- qemu-0.9.1/tests/Makefile 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/tests/Makefile 2008-09-22 02:39:29.000000000 +0100 @@ -1,17 +1,19 @@ -include ../config-host.mak +VPATH=$(SRC_PATH)/tests CFLAGS=-Wall -O2 -g -fno-strict-aliasing #CFLAGS+=-msse2 LDFLAGS= ifeq ($(ARCH),i386) -TESTS=linux-test testthread sha1-i386 test-i386 runcom +TESTS=linux-test testthread sha1-i386 test-i386 endif ifeq ($(ARCH),x86_64) TESTS=test-x86_64 endif TESTS+=sha1# test_path #TESTS+=test_path +#TESTS+=runcom QEMU=../i386-linux-user/qemu-i386 @@ -31,12 +33,12 @@ # i386/x86_64 emulation test (test various opcodes) */ test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S \ test-i386.h test-i386-shift.h test-i386-muldiv.h - $(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ \ - test-i386.c test-i386-code16.S test-i386-vm86.S -lm + $(CC) -m32 $(CFLAGS) $(LDFLAGS) -static -o $@ \ + $( test-i386.out @if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi -ifeq ($(ARCH),i386) - $(QEMU) -no-code-copy test-i386 > test-i386.out - @if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK (no code copy)"; fi -endif + +.PHONY: test-mmap +test-mmap: test-mmap.c + $(CC) $(CFLAGS) -Wall -static -O2 $(LDFLAGS) -o $@ $< + -./test-mmap + -$(QEMU) ./test-mmap + -$(QEMU) -p 8192 ./test-mmap 8192 + -$(QEMU) -p 16384 ./test-mmap 16384 + -$(QEMU) -p 32768 ./test-mmap 32768 # generic Linux and CPU test linux-test: linux-test.c diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/qruncom.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/qruncom.c --- qemu-0.9.1/tests/qruncom.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/tests/qruncom.c 2008-05-12 13:00:46.000000000 +0100 @@ -199,9 +199,6 @@ env = cpu_init("qemu32"); - /* disable code copy to simplify debugging */ - code_copy_enabled = 0; - /* set user mode state (XXX: should be done automatically by cpu_init ?) */ env->user_mode_only = 1; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/test-i386.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/test-i386.c --- qemu-0.9.1/tests/test-i386.c 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/tests/test-i386.c 2008-09-21 03:34:50.000000000 +0100 @@ -30,19 +30,19 @@ #include #if !defined(__x86_64__) -#define TEST_VM86 +//#define TEST_VM86 #define TEST_SEGS #endif //#define LINUX_VM86_IOPL_FIX //#define TEST_P4_FLAGS -#if defined(__x86_64__) +#ifdef __SSE__ #define TEST_SSE #define TEST_CMOV 1 #define TEST_FCOMI 1 #else -//#define TEST_SSE -#define TEST_CMOV 0 -#define TEST_FCOMI 0 +#undef TEST_SSE +#define TEST_CMOV 1 +#define TEST_FCOMI 1 #endif #if defined(__x86_64__) @@ -457,6 +457,51 @@ TEST_JCC("ns", 0, 0); } +#define TEST_LOOP(insn) \ +{\ + for(i = 0; i < sizeof(ecx_vals) / sizeof(long); i++) {\ + ecx = ecx_vals[i];\ + for(zf = 0; zf < 2; zf++) {\ + asm("test %2, %2\n\t"\ + "movl $1, %0\n\t"\ + insn " 1f\n\t" \ + "movl $0, %0\n\t"\ + "1:\n\t"\ + : "=a" (res)\ + : "c" (ecx), "b" (!zf)); \ + printf("%-10s ECX=" FMTLX " ZF=%ld r=%d\n", insn, ecx, zf, res); \ + }\ + }\ +} + +void test_loop(void) +{ + long ecx, zf; + const long ecx_vals[] = { + 0, + 1, + 0x10000, + 0x10001, +#if defined(__x86_64__) + 0x100000000L, + 0x100000001L, +#endif + }; + int i, res; + +#if !defined(__x86_64__) + TEST_LOOP("jcxz"); + TEST_LOOP("loopw"); + TEST_LOOP("loopzw"); + TEST_LOOP("loopnzw"); +#endif + + TEST_LOOP("jecxz"); + TEST_LOOP("loopl"); + TEST_LOOP("loopzl"); + TEST_LOOP("loopnzl"); +} + #undef CC_MASK #ifdef TEST_P4_FLAGS #define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A) @@ -673,8 +718,8 @@ asm("xor %1, %1\n"\ "mov $0x12345678, %0\n"\ #op " %" size "2, %" size "0 ; setz %b1" \ - : "=r" (res), "=q" (resz)\ - : "g" (val));\ + : "=&r" (res), "=&q" (resz)\ + : "r" (val));\ printf("%-10s A=" FMTLX " R=" FMTLX " %ld\n", #op, val, res, resz);\ } @@ -1065,7 +1110,7 @@ op1 = i2l(0xfbca7654);\ asm(#op " %" size "0, %" size "1" \ : "=q" (op0), opconst (op1) \ - : "0" (op0), "1" (op1));\ + : "0" (op0));\ printf("%-10s A=" FMTLX " B=" FMTLX "\n",\ #op, op0, op1);\ } @@ -1078,7 +1123,7 @@ op2 = i2l(eax);\ asm(#op " %" size "0, %" size "1" \ : "=q" (op0), opconst (op1) \ - : "0" (op0), "1" (op1), "a" (op2));\ + : "0" (op0), "a" (op2));\ printf("%-10s EAX=" FMTLX " A=" FMTLX " C=" FMTLX "\n",\ #op, op2, op0, op1);\ } @@ -1086,25 +1131,25 @@ void test_xchg(void) { #if defined(__x86_64__) - TEST_XCHG(xchgq, "", "=q"); + TEST_XCHG(xchgq, "", "+q"); #endif - TEST_XCHG(xchgl, "k", "=q"); - TEST_XCHG(xchgw, "w", "=q"); - TEST_XCHG(xchgb, "b", "=q"); + TEST_XCHG(xchgl, "k", "+q"); + TEST_XCHG(xchgw, "w", "+q"); + TEST_XCHG(xchgb, "b", "+q"); #if defined(__x86_64__) TEST_XCHG(xchgq, "", "=m"); #endif - TEST_XCHG(xchgl, "k", "=m"); - TEST_XCHG(xchgw, "w", "=m"); - TEST_XCHG(xchgb, "b", "=m"); + TEST_XCHG(xchgl, "k", "+m"); + TEST_XCHG(xchgw, "w", "+m"); + TEST_XCHG(xchgb, "b", "+m"); #if defined(__x86_64__) - TEST_XCHG(xaddq, "", "=q"); + TEST_XCHG(xaddq, "", "+q"); #endif - TEST_XCHG(xaddl, "k", "=q"); - TEST_XCHG(xaddw, "w", "=q"); - TEST_XCHG(xaddb, "b", "=q"); + TEST_XCHG(xaddl, "k", "+q"); + TEST_XCHG(xaddw, "w", "+q"); + TEST_XCHG(xaddb, "b", "+q"); { int res; @@ -1114,58 +1159,61 @@ } #if defined(__x86_64__) - TEST_XCHG(xaddq, "", "=m"); + TEST_XCHG(xaddq, "", "+m"); #endif - TEST_XCHG(xaddl, "k", "=m"); - TEST_XCHG(xaddw, "w", "=m"); - TEST_XCHG(xaddb, "b", "=m"); + TEST_XCHG(xaddl, "k", "+m"); + TEST_XCHG(xaddw, "w", "+m"); + TEST_XCHG(xaddb, "b", "+m"); #if defined(__x86_64__) - TEST_CMPXCHG(cmpxchgq, "", "=q", 0xfbca7654); + TEST_CMPXCHG(cmpxchgq, "", "+q", 0xfbca7654); #endif - TEST_CMPXCHG(cmpxchgl, "k", "=q", 0xfbca7654); - TEST_CMPXCHG(cmpxchgw, "w", "=q", 0xfbca7654); - TEST_CMPXCHG(cmpxchgb, "b", "=q", 0xfbca7654); + TEST_CMPXCHG(cmpxchgl, "k", "+q", 0xfbca7654); + TEST_CMPXCHG(cmpxchgw, "w", "+q", 0xfbca7654); + TEST_CMPXCHG(cmpxchgb, "b", "+q", 0xfbca7654); #if defined(__x86_64__) - TEST_CMPXCHG(cmpxchgq, "", "=q", 0xfffefdfc); + TEST_CMPXCHG(cmpxchgq, "", "+q", 0xfffefdfc); #endif - TEST_CMPXCHG(cmpxchgl, "k", "=q", 0xfffefdfc); - TEST_CMPXCHG(cmpxchgw, "w", "=q", 0xfffefdfc); - TEST_CMPXCHG(cmpxchgb, "b", "=q", 0xfffefdfc); + TEST_CMPXCHG(cmpxchgl, "k", "+q", 0xfffefdfc); + TEST_CMPXCHG(cmpxchgw, "w", "+q", 0xfffefdfc); + TEST_CMPXCHG(cmpxchgb, "b", "+q", 0xfffefdfc); #if defined(__x86_64__) - TEST_CMPXCHG(cmpxchgq, "", "=m", 0xfbca7654); + TEST_CMPXCHG(cmpxchgq, "", "+m", 0xfbca7654); #endif - TEST_CMPXCHG(cmpxchgl, "k", "=m", 0xfbca7654); - TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfbca7654); - TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfbca7654); + TEST_CMPXCHG(cmpxchgl, "k", "+m", 0xfbca7654); + TEST_CMPXCHG(cmpxchgw, "w", "+m", 0xfbca7654); + TEST_CMPXCHG(cmpxchgb, "b", "+m", 0xfbca7654); #if defined(__x86_64__) - TEST_CMPXCHG(cmpxchgq, "", "=m", 0xfffefdfc); + TEST_CMPXCHG(cmpxchgq, "", "+m", 0xfffefdfc); #endif - TEST_CMPXCHG(cmpxchgl, "k", "=m", 0xfffefdfc); - TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfffefdfc); - TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfffefdfc); + TEST_CMPXCHG(cmpxchgl, "k", "+m", 0xfffefdfc); + TEST_CMPXCHG(cmpxchgw, "w", "+m", 0xfffefdfc); + TEST_CMPXCHG(cmpxchgb, "b", "+m", 0xfffefdfc); { uint64_t op0, op1, op2; + long eax, edx; long i, eflags; for(i = 0; i < 2; i++) { op0 = 0x123456789abcdLL; + eax = i2l(op0 & 0xffffffff); + edx = i2l(op0 >> 32); if (i == 0) op1 = 0xfbca765423456LL; else op1 = op0; op2 = 0x6532432432434LL; - asm("cmpxchg8b %1\n" + asm("cmpxchg8b %2\n" "pushf\n" - "pop %2\n" - : "=A" (op0), "=m" (op1), "=g" (eflags) - : "0" (op0), "m" (op1), "b" ((int)op2), "c" ((int)(op2 >> 32))); - printf("cmpxchg8b: op0=" FMT64X " op1=" FMT64X " CC=%02lx\n", - op0, op1, eflags & CC_Z); + "pop %3\n" + : "=a" (eax), "=d" (edx), "=m" (op1), "=g" (eflags) + : "0" (eax), "1" (edx), "m" (op1), "b" ((int)op2), "c" ((int)(op2 >> 32))); + printf("cmpxchg8b: eax=" FMTLX " edx=" FMTLX " op1=" FMT64X " CC=%02lx\n", + eax, edx, op1, eflags & CC_Z); } } } @@ -1196,16 +1244,32 @@ #define TEST_LR(op, size, seg, mask)\ {\ int res, res2;\ + uint16_t mseg = seg;\ res = 0x12345678;\ asm (op " %" size "2, %" size "0\n" \ "movl $0, %1\n"\ "jnz 1f\n"\ "movl $1, %1\n"\ "1:\n"\ - : "=r" (res), "=r" (res2) : "m" (seg), "0" (res));\ + : "=r" (res), "=r" (res2) : "m" (mseg), "0" (res));\ printf(op ": Z=%d %08x\n", res2, res & ~(mask));\ } +#define TEST_ARPL(op, size, op1, op2)\ +{\ + long a, b, c; \ + a = (op1); \ + b = (op2); \ + asm volatile(op " %" size "3, %" size "0\n"\ + "movl $0,%1\n"\ + "jnz 1f\n"\ + "movl $1,%1\n"\ + "1:\n"\ + : "=r" (a), "=r" (c) : "0" (a), "r" (b)); \ + printf(op size " A=" FMTLX " B=" FMTLX " R=" FMTLX " z=%ld\n",\ + (long)(op1), (long)(op2), a, c);\ +} + /* NOTE: we use Linux modify_ldt syscall */ void test_segs(void) { @@ -1297,6 +1361,10 @@ TEST_LR("larl", "", 0xfff8, 0); TEST_LR("lslw", "w", 0xfff8, 0); TEST_LR("lsll", "", 0xfff8, 0); + + TEST_ARPL("arpl", "w", 0x12345678 | 3, 0x762123c | 1); + TEST_ARPL("arpl", "w", 0x12345678 | 1, 0x762123c | 3); + TEST_ARPL("arpl", "w", 0x12345678 | 1, 0x762123c | 1); } /* 16 bit code test */ @@ -1369,9 +1437,13 @@ printf("xlat: EAX=" FMTLX "\n", res); #if defined(__x86_64__) +#if 0 { + /* XXX: see if Intel Core2 and AMD64 behavior really + differ. Here we implemented the Intel way which is not + compatible yet with QEMU. */ static struct __attribute__((packed)) { - uint32_t offset; + uint64_t offset; uint16_t seg; } desc; long cs_sel; @@ -1384,27 +1456,27 @@ : "r" (cs_sel) : "memory", "cc"); printf("func_lret=" FMTLX "\n", res); - /* NOTE: we assume that &func_lret < 4GB */ desc.offset = (long)&func_lret; desc.seg = cs_sel; asm volatile ("xor %%rax, %%rax\n" - "rex64 lcall %1\n" + "rex64 lcall *(%%rcx)\n" : "=a" (res) - : "m" (desc) + : "c" (&desc) : "memory", "cc"); printf("func_lret2=" FMTLX "\n", res); asm volatile ("push %2\n" "mov $ 1f, %%rax\n" "push %%rax\n" - "ljmp %1\n" + "rex64 ljmp *(%%rcx)\n" "1:\n" : "=a" (res) - : "m" (desc), "b" (cs_sel) + : "c" (&desc), "b" (cs_sel) : "memory", "cc"); printf("func_lret3=" FMTLX "\n", res); } +#endif #else asm volatile ("push %%cs ; call %1" : "=a" (res) @@ -1927,7 +1999,8 @@ 0xc3, /* ret */ }; -asm("smc_code2:\n" +asm(".section \".data\"\n" + "smc_code2:\n" "movl 4(%esp), %eax\n" "movl %eax, smc_patch_addr2 + 1\n" "nop\n" @@ -1940,14 +2013,15 @@ "nop\n" "smc_patch_addr2:\n" "movl $1, %eax\n" - "ret\n"); + "ret\n" + ".previous\n" + ); typedef int FuncType(void); extern int smc_code2(int); void test_self_modifying_code(void) { int i; - printf("self modifying code:\n"); printf("func1 = 0x%x\n", ((FuncType *)code)()); for(i = 2; i <= 4; i++) { @@ -2029,7 +2103,7 @@ #ifdef TEST_SSE typedef int __m64 __attribute__ ((__mode__ (__V2SI__))); -typedef int __m128 __attribute__ ((__mode__(__V4SF__))); +typedef float __m128 __attribute__ ((__mode__(__V4SF__))); typedef union { double d[2]; @@ -2207,7 +2281,8 @@ #define CVT_OP_XMM2MMX(op)\ {\ asm volatile (#op " %1, %0" : "=y" (r.q[0]) : "x" (a.dq) \ - : "%xmm0");\ + : "%xmm0"); \ + asm volatile("emms\n"); \ printf("%-9s: a=" FMT64X "" FMT64X " r=" FMT64X "\n",\ #op,\ a.q[1], a.q[0],\ @@ -2217,6 +2292,7 @@ #define CVT_OP_MMX2XMM(op)\ {\ asm volatile (#op " %1, %0" : "=x" (r.dq) : "y" (a.q[0]));\ + asm volatile("emms\n"); \ printf("%-9s: a=" FMT64X " r=" FMT64X "" FMT64X "\n",\ #op,\ a.q[0],\ @@ -2619,6 +2695,21 @@ #if defined(__x86_64__) TEST_CONV_RAX_RDX(cqo); #endif + + { + unsigned long a, r; + a = i2l(0x12345678); + asm volatile("bswapl %k0" : "=r" (r) : "0" (a)); + printf("%-10s: A=" FMTLX " R=" FMTLX "\n", "bswapl", a, r); + } +#if defined(__x86_64__) + { + unsigned long a, r; + a = i2l(0x12345678); + asm volatile("bswapq %0" : "=r" (r) : "0" (a)); + printf("%-10s: A=" FMTLX " R=" FMTLX "\n", "bswapq", a, r); + } +#endif } extern void *__start_initcall; @@ -2638,6 +2729,7 @@ test_bsx(); test_mul(); test_jcc(); + test_loop(); test_floats(); #if !defined(__x86_64__) test_bcd(); @@ -2653,8 +2745,8 @@ #ifdef TEST_VM86 test_vm86(); #endif - test_exceptions(); #if !defined(__x86_64__) + test_exceptions(); test_self_modifying_code(); test_single_step(); #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/test-i386-code16.S /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/test-i386-code16.S --- qemu-0.9.1/tests/test-i386-code16.S 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/tests/test-i386-code16.S 2008-01-31 15:19:39.000000000 +0000 @@ -44,9 +44,9 @@ ljmp $CS_SEG, $(myjmp1 - code16_start) myjmp1_next: - cs lcall myfunc2_addr - code16_start + cs lcall *myfunc2_addr - code16_start - cs ljmp myjmp2_addr - code16_start + cs ljmp *myjmp2_addr - code16_start myjmp2_next: data32 lret diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/test-i386-shift.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/test-i386-shift.h --- qemu-0.9.1/tests/test-i386-shift.h 2008-01-06 19:38:45.000000000 +0000 +++ qemu-0.9.1+svn20081112/tests/test-i386-shift.h 2008-05-28 13:34:49.000000000 +0100 @@ -145,8 +145,7 @@ #endif exec_opl(s2, s0, s1, 0); #ifdef OP_SHIFTD - if (s1 <= 15) - exec_opw(s2, s0, s1, 0); + exec_opw(s2, s0, s1, 0); #else exec_opw(s2, s0, s1, 0); #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/test-i386-ssse3.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/test-i386-ssse3.c --- qemu-0.9.1/tests/test-i386-ssse3.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tests/test-i386-ssse3.c 2008-10-04 04:27:44.000000000 +0100 @@ -0,0 +1,57 @@ +/* See if various MMX/SSE SSSE3 instructions give expected results */ +#include +#include +#include + +int main(int argc, char *argv[]) { + char hello[16]; + const char ehlo[8] = "EHLO "; + uint64_t mask = 0x8080800302020001; + + uint64_t a = 0x0000000000090007; + uint64_t b = 0x0000000000000000; + uint32_t c; + uint16_t d; + + const char e[16] = "LLOaaaaaaaaaaaaa"; + const char f[16] = "aaaaaaaaaaaaaaHE"; + + /* pshufb mm1/xmm1, mm2/xmm2 */ + asm volatile ("movq (%0), %%mm0" : : "r" (ehlo) : "mm0", "mm1"); + asm volatile ("movq %0, %%mm1" : : "m" (mask)); + asm volatile ("pshufb %mm1, %mm0"); + asm volatile ("movq %%mm0, %0" : "=m" (hello)); + printf("%s\n", hello); + + /* pshufb mm1/xmm1, m64/m128 */ + asm volatile ("movq (%0), %%mm0" : : "r" (ehlo) : "mm0"); + asm volatile ("pshufb %0, %%mm0" : : "m" (mask)); + asm volatile ("movq %%mm0, %0" : "=m" (hello)); + printf("%s\n", hello); + + /* psubsw mm1/xmm1, m64/m128 */ + asm volatile ("movq %0, %%mm0" : : "r" (a) : "mm0"); + asm volatile ("phsubsw %0, %%mm0" : : "m" (b)); + asm volatile ("movq %%mm0, %0" : "=m" (a)); + printf("%i - %i = %i\n", 9, 7, -(int16_t) a); + + /* palignr mm1/xmm1, m64/m128, imm8 */ + asm volatile ("movdqa (%0), %%xmm0" : : "r" (e) : "xmm0"); + asm volatile ("palignr $14, (%0), %%xmm0" : : "r" (f)); + asm volatile ("movdqa %%xmm0, (%0)" : : "r" (hello)); + printf("%5.5s\n", hello); + +#if 1 /* SSE4 */ + /* popcnt r64, r/m64 */ + asm volatile ("movq $0x8421000010009c63, %%rax" : : : "rax"); + asm volatile ("popcnt %%ax, %%dx" : : : "dx"); + asm volatile ("popcnt %%eax, %%ecx" : : : "ecx"); + asm volatile ("popcnt %rax, %rax"); + asm volatile ("movq %%rax, %0" : "=m" (a)); + asm volatile ("movl %%ecx, %0" : "=m" (c)); + asm volatile ("movw %%dx, %0" : "=m" (d)); + printf("%i = %i\n%i = %i = %i\n", 13, (int) a, 9, c, d + 1); +#endif + + return 0; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/tests/test-mmap.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/tests/test-mmap.c --- qemu-0.9.1/tests/test-mmap.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1+svn20081112/tests/test-mmap.c 2008-05-03 16:55:42.000000000 +0100 @@ -0,0 +1,477 @@ +/* + * Small test program to verify simulated mmap behaviour. + * + * When running qemu-linux-user with the -p flag, you may need to tell + * this test program about the pagesize because getpagesize() will not reflect + * the -p choice. Simply pass one argument beeing the pagesize. + * + * Copyright (c) 2007 AXIS Communications AB + * Written by Edgar E. Iglesias. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include + +#define D(x) + +#define fail_unless(x) \ +do \ +{ \ + if (!(x)) { \ + fprintf (stderr, "FAILED at %s:%d\n", __FILE__, __LINE__); \ + exit (EXIT_FAILURE); \ + } \ +} while (0); + +unsigned char *dummybuf; +static unsigned int pagesize; +static unsigned int pagemask; +int test_fd; +size_t test_fsize; + +void check_aligned_anonymous_unfixed_mmaps(void) +{ + void *p1; + void *p2; + void *p3; + void *p4; + void *p5; + uintptr_t p; + int i; + + fprintf (stderr, "%s", __func__); + for (i = 0; i < 0x1fff; i++) + { + size_t len; + + len = pagesize + (pagesize * i & 7); + p1 = mmap(NULL, len, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + p2 = mmap(NULL, len, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + p3 = mmap(NULL, len, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + p4 = mmap(NULL, len, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + p5 = mmap(NULL, len, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + /* Make sure we get pages aligned with the pagesize. The + target expects this. */ + fail_unless (p1 != MAP_FAILED); + fail_unless (p2 != MAP_FAILED); + fail_unless (p3 != MAP_FAILED); + fail_unless (p4 != MAP_FAILED); + fail_unless (p5 != MAP_FAILED); + p = (uintptr_t) p1; + D(printf ("p=%x\n", p)); + fail_unless ((p & pagemask) == 0); + p = (uintptr_t) p2; + fail_unless ((p & pagemask) == 0); + p = (uintptr_t) p3; + fail_unless ((p & pagemask) == 0); + p = (uintptr_t) p4; + fail_unless ((p & pagemask) == 0); + p = (uintptr_t) p5; + fail_unless ((p & pagemask) == 0); + + /* Make sure we can read from the entire area. */ + memcpy (dummybuf, p1, pagesize); + memcpy (dummybuf, p2, pagesize); + memcpy (dummybuf, p3, pagesize); + memcpy (dummybuf, p4, pagesize); + memcpy (dummybuf, p5, pagesize); + + munmap (p1, len); + munmap (p2, len); + munmap (p3, len); + munmap (p4, len); + munmap (p5, len); + } + fprintf (stderr, " passed\n"); +} + +void check_large_anonymous_unfixed_mmap(void) +{ + void *p1; + uintptr_t p; + size_t len; + + fprintf (stderr, "%s", __func__); + + len = 0x02000000; + p1 = mmap(NULL, len, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + /* Make sure we get pages aligned with the pagesize. The + target expects this. */ + fail_unless (p1 != MAP_FAILED); + p = (uintptr_t) p1; + fail_unless ((p & pagemask) == 0); + + /* Make sure we can read from the entire area. */ + memcpy (dummybuf, p1, pagesize); + munmap (p1, len); + fprintf (stderr, " passed\n"); +} + +void check_aligned_anonymous_unfixed_colliding_mmaps(void) +{ + char *p1; + char *p2; + char *p3; + uintptr_t p; + int i; + + fprintf (stderr, "%s", __func__); + for (i = 0; i < 0x2fff; i++) + { + int nlen; + p1 = mmap(NULL, pagesize, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + fail_unless (p1 != MAP_FAILED); + p = (uintptr_t) p1; + fail_unless ((p & pagemask) == 0); + memcpy (dummybuf, p1, pagesize); + + p2 = mmap(NULL, pagesize, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + fail_unless (p2 != MAP_FAILED); + p = (uintptr_t) p2; + fail_unless ((p & pagemask) == 0); + memcpy (dummybuf, p2, pagesize); + + + munmap (p1, pagesize); + nlen = pagesize * 8; + p3 = mmap(NULL, nlen, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + /* Check if the mmaped areas collide. */ + if (p3 < p2 + && (p3 + nlen) > p2) + fail_unless (0); + + memcpy (dummybuf, p3, pagesize); + + /* Make sure we get pages aligned with the pagesize. The + target expects this. */ + fail_unless (p3 != MAP_FAILED); + p = (uintptr_t) p3; + fail_unless ((p & pagemask) == 0); + munmap (p2, pagesize); + munmap (p3, nlen); + } + fprintf (stderr, " passed\n"); +} + +void check_aligned_anonymous_fixed_mmaps(void) +{ + char *addr; + void *p1; + uintptr_t p; + int i; + + /* Find a suitable address to start with. */ + addr = mmap(NULL, pagesize * 40, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + fprintf (stderr, "%s addr=%p", __func__, addr); + fail_unless (addr != MAP_FAILED); + + for (i = 0; i < 40; i++) + { + /* Create submaps within our unfixed map. */ + p1 = mmap(addr, pagesize, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, + -1, 0); + /* Make sure we get pages aligned with the pagesize. + The target expects this. */ + p = (uintptr_t) p1; + fail_unless (p1 == addr); + fail_unless ((p & pagemask) == 0); + memcpy (dummybuf, p1, pagesize); + munmap (p1, pagesize); + addr += pagesize; + } + fprintf (stderr, " passed\n"); +} + +void check_aligned_anonymous_fixed_mmaps_collide_with_host(void) +{ + char *addr; + void *p1; + uintptr_t p; + int i; + + /* Find a suitable address to start with. Right were the x86 hosts + stack is. */ + addr = ((void *)0x80000000); + fprintf (stderr, "%s addr=%p", __func__, addr); + fprintf (stderr, "FIXME: QEMU fails to track pages used by the host."); + + for (i = 0; i < 20; i++) + { + /* Create submaps within our unfixed map. */ + p1 = mmap(addr, pagesize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, + -1, 0); + /* Make sure we get pages aligned with the pagesize. + The target expects this. */ + p = (uintptr_t) p1; + fail_unless (p1 == addr); + fail_unless ((p & pagemask) == 0); + memcpy (p1, dummybuf, pagesize); + munmap (p1, pagesize); + addr += pagesize; + } + fprintf (stderr, " passed\n"); +} + +void check_file_unfixed_mmaps(void) +{ + unsigned int *p1, *p2, *p3; + uintptr_t p; + int i; + + fprintf (stderr, "%s", __func__); + for (i = 0; i < 0x10; i++) + { + size_t len; + + len = pagesize; + p1 = mmap(NULL, len, PROT_READ, + MAP_PRIVATE, + test_fd, 0); + p2 = mmap(NULL, len, PROT_READ, + MAP_PRIVATE, + test_fd, pagesize); + p3 = mmap(NULL, len, PROT_READ, + MAP_PRIVATE, + test_fd, pagesize * 2); + + fail_unless (p1 != MAP_FAILED); + fail_unless (p2 != MAP_FAILED); + fail_unless (p3 != MAP_FAILED); + + /* Make sure we get pages aligned with the pagesize. The + target expects this. */ + p = (uintptr_t) p1; + fail_unless ((p & pagemask) == 0); + p = (uintptr_t) p2; + fail_unless ((p & pagemask) == 0); + p = (uintptr_t) p3; + fail_unless ((p & pagemask) == 0); + + /* Verify that the file maps was made correctly. */ + D(printf ("p1=%d p2=%d p3=%d\n", *p1, *p2, *p3)); + fail_unless (*p1 == 0); + fail_unless (*p2 == (pagesize / sizeof *p2)); + fail_unless (*p3 == ((pagesize * 2) / sizeof *p3)); + + memcpy (dummybuf, p1, pagesize); + memcpy (dummybuf, p2, pagesize); + memcpy (dummybuf, p3, pagesize); + munmap (p1, len); + munmap (p2, len); + munmap (p3, len); + } + fprintf (stderr, " passed\n"); +} + +void check_file_unfixed_eof_mmaps(void) +{ + char *cp; + unsigned int *p1; + uintptr_t p; + int i; + + fprintf (stderr, "%s", __func__); + for (i = 0; i < 0x10; i++) + { + p1 = mmap(NULL, pagesize, PROT_READ, + MAP_PRIVATE, + test_fd, + (test_fsize - sizeof *p1) & ~pagemask); + + fail_unless (p1 != MAP_FAILED); + + /* Make sure we get pages aligned with the pagesize. The + target expects this. */ + p = (uintptr_t) p1; + fail_unless ((p & pagemask) == 0); + /* Verify that the file maps was made correctly. */ + fail_unless (p1[(test_fsize & pagemask) / sizeof *p1 - 1] + == ((test_fsize - sizeof *p1) / sizeof *p1)); + + /* Verify that the end of page is accessable and zeroed. */ + cp = (void *) p1; + fail_unless (cp[pagesize - 4] == 0); + munmap (p1, pagesize); + } + fprintf (stderr, " passed\n"); +} + +void check_file_fixed_eof_mmaps(void) +{ + char *addr; + char *cp; + unsigned int *p1; + uintptr_t p; + int i; + + /* Find a suitable address to start with. */ + addr = mmap(NULL, pagesize * 44, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + + fprintf (stderr, "%s addr=%p", __func__, (void *)addr); + fail_unless (addr != MAP_FAILED); + + for (i = 0; i < 0x10; i++) + { + /* Create submaps within our unfixed map. */ + p1 = mmap(addr, pagesize, PROT_READ, + MAP_PRIVATE | MAP_FIXED, + test_fd, + (test_fsize - sizeof *p1) & ~pagemask); + + fail_unless (p1 != MAP_FAILED); + + /* Make sure we get pages aligned with the pagesize. The + target expects this. */ + p = (uintptr_t) p1; + fail_unless ((p & pagemask) == 0); + + /* Verify that the file maps was made correctly. */ + fail_unless (p1[(test_fsize & pagemask) / sizeof *p1 - 1] + == ((test_fsize - sizeof *p1) / sizeof *p1)); + + /* Verify that the end of page is accessable and zeroed. */ + cp = (void *)p1; + fail_unless (cp[pagesize - 4] == 0); + munmap (p1, pagesize); + addr += pagesize; + } + fprintf (stderr, " passed\n"); +} + +void check_file_fixed_mmaps(void) +{ + unsigned char *addr; + unsigned int *p1, *p2, *p3, *p4; + int i; + + /* Find a suitable address to start with. */ + addr = mmap(NULL, pagesize * 40 * 4, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + fprintf (stderr, "%s addr=%p", __func__, (void *)addr); + fail_unless (addr != MAP_FAILED); + + for (i = 0; i < 40; i++) + { + p1 = mmap(addr, pagesize, PROT_READ, + MAP_PRIVATE | MAP_FIXED, + test_fd, 0); + p2 = mmap(addr + pagesize, pagesize, PROT_READ, + MAP_PRIVATE | MAP_FIXED, + test_fd, pagesize); + p3 = mmap(addr + pagesize * 2, pagesize, PROT_READ, + MAP_PRIVATE | MAP_FIXED, + test_fd, pagesize * 2); + p4 = mmap(addr + pagesize * 3, pagesize, PROT_READ, + MAP_PRIVATE | MAP_FIXED, + test_fd, pagesize * 3); + + /* Make sure we get pages aligned with the pagesize. + The target expects this. */ + fail_unless (p1 == (void *)addr); + fail_unless (p2 == (void *)addr + pagesize); + fail_unless (p3 == (void *)addr + pagesize * 2); + fail_unless (p4 == (void *)addr + pagesize * 3); + + /* Verify that the file maps was made correctly. */ + fail_unless (*p1 == 0); + fail_unless (*p2 == (pagesize / sizeof *p2)); + fail_unless (*p3 == ((pagesize * 2) / sizeof *p3)); + fail_unless (*p4 == ((pagesize * 3) / sizeof *p4)); + + memcpy (dummybuf, p1, pagesize); + memcpy (dummybuf, p2, pagesize); + memcpy (dummybuf, p3, pagesize); + memcpy (dummybuf, p4, pagesize); + + munmap (p1, pagesize); + munmap (p2, pagesize); + munmap (p3, pagesize); + munmap (p4, pagesize); + addr += pagesize * 4; + } + fprintf (stderr, " passed\n"); +} + +int main(int argc, char **argv) +{ + char tempname[] = "/tmp/.cmmapXXXXXX"; + unsigned int i; + + /* Trust the first argument, otherwise probe the system for our + pagesize. */ + if (argc > 1) + pagesize = strtoul(argv[1], NULL, 0); + else + pagesize = sysconf(_SC_PAGESIZE); + + /* Assume pagesize is a power of two. */ + pagemask = pagesize - 1; + dummybuf = malloc (pagesize); + printf ("pagesize=%u pagemask=%x\n", pagesize, pagemask); + + test_fd = mkstemp(tempname); + unlink(tempname); + + /* Fill the file with int's counting from zero and up. */ + for (i = 0; i < (pagesize * 4) / sizeof i; i++) + write (test_fd, &i, sizeof i); + /* Append a few extra writes to make the file end at non + page boundary. */ + write (test_fd, &i, sizeof i); i++; + write (test_fd, &i, sizeof i); i++; + write (test_fd, &i, sizeof i); i++; + + test_fsize = lseek(test_fd, 0, SEEK_CUR); + + /* Run the tests. */ + check_aligned_anonymous_unfixed_mmaps(); + check_aligned_anonymous_unfixed_colliding_mmaps(); + check_aligned_anonymous_fixed_mmaps(); + check_file_unfixed_mmaps(); + check_file_fixed_mmaps(); + check_file_fixed_eof_mmaps(); + check_file_unfixed_eof_mmaps(); + + /* Fails at the moment. */ + /* check_aligned_anonymous_fixed_mmaps_collide_with_host(); */ + + return EXIT_SUCCESS; +} diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/texi2pod.pl /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/texi2pod.pl --- qemu-0.9.1/texi2pod.pl 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/texi2pod.pl 2008-02-04 14:47:49.000000000 +0000 @@ -1,23 +1,23 @@ #! /usr/bin/perl -w -# Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. +# Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation, Inc. -# This file is part of GNU CC. +# This file is part of GCC. -# GNU CC is free software; you can redistribute it and/or modify +# GCC is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. -# GNU CC is distributed in the hope that it will be useful, +# GCC 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 General Public License for more details. # You should have received a copy of the GNU General Public License -# along with GNU CC; see the file COPYING. If not, write to -# the Free Software Foundation, 59 Temple Place - Suite 330, -# Boston MA 02111-1307, USA. +# along with GCC; see the file COPYING. If not, write to +# the Free Software Foundation, 51 Franklin Street, Fifth Floor, +# Boston MA 02110-1301, USA. # This does trivial (and I mean _trivial_) conversion of Texinfo # markup to Perl POD format. It's intended to be used to extract @@ -36,6 +36,7 @@ $fnno = 1; $inf = ""; $ibase = ""; +@ipath = (); while ($_ = shift) { if (/^-D(.*)$/) { @@ -51,6 +52,13 @@ die "flags may only contain letters, digits, hyphens, dashes and underscores\n" unless $flag =~ /^[a-zA-Z0-9_-]+$/; $defs{$flag} = $value; + } elsif (/^-I(.*)$/) { + if ($1 ne "") { + $flag = $1; + } else { + $flag = shift; + } + push (@ipath, $flag); } elsif (/^-/) { usage(); } else { @@ -138,7 +146,7 @@ # Ignore @end foo, where foo is not an operation which may # cause us to skip, if we are presently skipping. my $ended = $1; - next if $skipping && $ended !~ /^(?:ifset|ifclear|ignore|menu|iftex)$/; + next if $skipping && $ended !~ /^(?:ifset|ifclear|ignore|menu|iftex|copying)$/; die "\@end $ended without \@$ended at line $.\n" unless defined $endw; die "\@$endw ended by \@end $ended at line $.\n" unless $ended eq $endw; @@ -154,6 +162,8 @@ } elsif ($ended =~ /^(?:itemize|enumerate|[fv]?table)$/) { $_ = "\n=back\n"; $ic = pop @icstack; + } elsif ($ended eq "multitable") { + $_ = "\n=back\n"; } else { die "unknown command \@end $ended at line $.\n"; } @@ -178,7 +188,7 @@ next; }; - /^\@(ignore|menu|iftex)\b/ and do { + /^\@(ignore|menu|iftex|copying)\b/ and do { push @endwstack, $endw; push @skstack, $skipping; $endw = $1; @@ -227,11 +237,16 @@ /^\@include\s+(.+)$/ and do { push @instack, $inf; $inf = gensym(); + $file = postprocess($1); - # Try cwd and $ibase. - open($inf, "<" . $1) - or open($inf, "<" . $ibase . "/" . $1) - or die "cannot open $1 or $ibase/$1: $!\n"; + # Try cwd and $ibase, then explicit -I paths. + $done = 0; + foreach $path ("", $ibase, @ipath) { + $mypath = $file; + $mypath = $path . "/" . $mypath if ($path ne ""); + open($inf, "<" . $mypath) and ($done = 1, last); + } + die "cannot find $file" if !$done; next; }; @@ -239,12 +254,18 @@ and $_ = "\n=head2 $1\n"; /^\@subsection\s+(.+)$/ and $_ = "\n=head3 $1\n"; + /^\@subsubsection\s+(.+)$/ + and $_ = "\n=head4 $1\n"; # Block command handlers: - /^\@itemize\s+(\@[a-z]+|\*|-)/ and do { + /^\@itemize(?:\s+(\@[a-z]+|\*|-))?/ and do { push @endwstack, $endw; push @icstack, $ic; - $ic = $1; + if (defined $1) { + $ic = $1; + } else { + $ic = '*'; + } $_ = "\n=over 4\n"; $endw = "itemize"; }; @@ -261,6 +282,12 @@ $endw = "enumerate"; }; + /^\@multitable\s.*/ and do { + push @endwstack, $endw; + $endw = "multitable"; + $_ = "\n=over 4\n"; + }; + /^\@([fv]?table)\s+(\@[a-z]+)/ and do { push @endwstack, $endw; push @icstack, $ic; @@ -280,10 +307,19 @@ $_ = ""; # need a paragraph break }; + /^\@item\s+(.*\S)\s*$/ and $endw eq "multitable" and do { + @columns = (); + for $column (split (/\s*\@tab\s*/, $1)) { + # @strong{...} is used a @headitem work-alike + $column =~ s/^\@strong{(.*)}$/$1/; + push @columns, $column; + } + $_ = "\n=item ".join (" : ", @columns)."\n"; + }; + /^\@itemx?\s*(.+)?$/ and do { if (defined $1) { # Entity escapes prevent munging by the <> processing below. -# print "$ic\n"; $_ = "\n=item $ic\<$1\>\n"; } else { $_ = "\n=item $ic\n"; @@ -346,6 +382,13 @@ s/\@w\{([^\}]*)\}/S<$1>/g; s/\@(?:dmn|math)\{([^\}]*)\}/$1/g; + # keep references of the form @ref{...}, print them bold + s/\@(?:ref)\{([^\}]*)\}/B<$1>/g; + + # Change double single quotes to double quotes. + s/''/"/g; + s/``/"/g; + # Cross references are thrown away, as are @noindent and @refill. # (@noindent is impossible in .pod, and @refill is unnecessary.) # @* is also impossible in .pod; we discard it and any newline that @@ -359,6 +402,9 @@ s/\@gol//g; s/\@\*\s*\n?//g; + # Anchors are thrown away + s/\@anchor\{(?:[^\}]*)\}//g; + # @uref can take one, two, or three arguments, with different # semantics each time. @url and @email are just like @uref with # one argument, for our purposes. @@ -366,14 +412,18 @@ s/\@uref\{([^\},]*),([^\},]*)\}/$2 (C<$1>)/g; s/\@uref\{([^\},]*),([^\},]*),([^\},]*)\}/$3/g; - # Turn B blah> into B I B to - # match Texinfo semantics of @emph inside @samp. Also handle @r - # inside bold. + # Un-escape <> at this point. s/<//g; - 1 while s/B<((?:[^<>]|I<[^<>]*>)*)R<([^>]*)>/B<$1>${2}B]*)I<([^>]+)>/B<$1>I<$2>B]*)B<([^>]+)>/I<$1>B<$2>I, I<>, R<>. Theoretically we could have + # indefinitely deep nesting; in practice, one level suffices. + 1 while s/([BIR])<([^<>]*)([BIR])<([^<>]*)>/$1<$2>$3<$4>$1 with bare ...; eliminate empty markup, B<>; + # shift white space at the ends of [BI]<...> expressions outside + # the expression. + s/R<([^<>]*)>/$1/g; s/[BI]<>//g; s/([BI])<(\s+)([^>]+)>/$2$1<$3>/g; s/([BI])<([^>]+?)(\s+)>/$1<$2>$3/g; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/thunk.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/thunk.c --- qemu-0.9.1/thunk.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/thunk.c 2008-10-05 11:51:10.000000000 +0100 @@ -113,7 +113,8 @@ } } -void thunk_register_struct_direct(int id, const char *name, StructEntry *se1) +void thunk_register_struct_direct(int id, const char *name, + const StructEntry *se1) { StructEntry *se; se = struct_entries + id; @@ -248,9 +249,9 @@ * between X86 and Alpha formats... */ unsigned int target_to_host_bitmask(unsigned int x86_mask, - bitmask_transtbl * trans_tbl) + const bitmask_transtbl * trans_tbl) { - bitmask_transtbl * btp; + const bitmask_transtbl *btp; unsigned int alpha_mask = 0; for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) { @@ -262,9 +263,9 @@ } unsigned int host_to_target_bitmask(unsigned int alpha_mask, - bitmask_transtbl * trans_tbl) + const bitmask_transtbl * trans_tbl) { - bitmask_transtbl * btp; + const bitmask_transtbl *btp; unsigned int x86_mask = 0; for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) { diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/thunk.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/thunk.h --- qemu-0.9.1/thunk.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/thunk.h 2008-10-05 11:51:10.000000000 +0100 @@ -68,7 +68,8 @@ } bitmask_transtbl; void thunk_register_struct(int id, const char *name, const argtype *types); -void thunk_register_struct_direct(int id, const char *name, StructEntry *se1); +void thunk_register_struct_direct(int id, const char *name, + const StructEntry *se1); const argtype *thunk_convert(void *dst, const void *src, const argtype *type_ptr, int to_host); #ifndef NO_THUNK_TYPE_SIZE @@ -154,8 +155,8 @@ #endif /* NO_THUNK_TYPE_SIZE */ unsigned int target_to_host_bitmask(unsigned int x86_mask, - bitmask_transtbl * trans_tbl); + const bitmask_transtbl * trans_tbl); unsigned int host_to_target_bitmask(unsigned int alpha_mask, - bitmask_transtbl * trans_tbl); + const bitmask_transtbl * trans_tbl); #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/TODO /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/TODO --- qemu-0.9.1/TODO 2008-01-06 19:38:41.000000000 +0000 +++ qemu-0.9.1+svn20081112/TODO 2008-05-13 19:26:52.000000000 +0100 @@ -1,30 +1,20 @@ -short term: ----------- +General: +------- - cycle counter for all archs - cpu_interrupt() win32/SMP fix -- support variable tsc freq -- USB host async -- IDE async -- debug option in 'configure' script + disable -fomit-frame-pointer - Precise VGA timings for old games/demos (malc patch) - merge PIC spurious interrupt patch - warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?) - config file (at least for windows/Mac OS X) - update doc: PCI infos. - basic VGA optimizations -- better code fetch (different exception handling + CS.limit support) +- better code fetch - do not resize vga if invalid size. -- avoid looping if only exceptions - TLB code protection support for PPC -- see openMosix Doc - disable SMC handling for ARM/SPARC/PPC (not finished) - see undefined flags for BTx insn -- user/kernel PUSHL/POPL in helper.c - keyboard output buffer filling timing emulation -- return UD exception if LOCK prefix incorrectly used -- test ldt limit < 7 ? - tests for each target CPU -- fix CCOP optimisation - fix all remaining thread lock issues (must put TBs in a specific invalid state, find a solution for tb_flush()). @@ -35,21 +25,14 @@ linux-user specific: ------------------- -- add IPC syscalls -- handle rare page fault cases (in particular if page fault in helpers or - in syscall emulation code). +- remove threading support as it cannot work at this point +- improve IPC syscalls - more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit issues, fix 16 bit uid issues) -- use page_unprotect_range in every suitable syscall to handle all - cases of self modifying code. -- fix thread stack freeing (use kernel 2.5.x CLONE_CHILD_CLEARTID) - use kernel traps for unaligned accesses on ARM ? lower priority: -------------- - int15 ah=86: use better timing -- suppress shift_mem ops -- fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret) -- optimize FPU operations (evaluate x87 stack pointer statically) - use -msoft-float on ARM diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/translate-all.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/translate-all.c --- qemu-0.9.1/translate-all.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/translate-all.c 2008-07-18 19:01:29.000000000 +0100 @@ -29,24 +29,16 @@ #include "cpu.h" #include "exec-all.h" #include "disas.h" +#include "tcg.h" -extern int dyngen_code(uint8_t *gen_code_buf, - uint16_t *label_offsets, uint16_t *jmp_offsets, - const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels); - -enum { -#define DEF(s, n, copy_size) INDEX_op_ ## s, -#include "opc.h" -#undef DEF - NB_OPS, -}; +/* code generation context */ +TCGContext tcg_ctx; uint16_t gen_opc_buf[OPC_BUF_SIZE]; -uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; -long gen_labels[OPC_BUF_SIZE]; -int nb_gen_labels; +TCGArg gen_opparam_buf[OPPARAM_BUF_SIZE]; target_ulong gen_opc_pc[OPC_BUF_SIZE]; +uint16_t gen_opc_icount[OPC_BUF_SIZE]; uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; #if defined(TARGET_I386) uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; @@ -57,88 +49,15 @@ uint32_t gen_opc_hflags[OPC_BUF_SIZE]; #endif -int code_copy_enabled = 1; - -#ifdef DEBUG_DISAS -static const char *op_str[] = { -#define DEF(s, n, copy_size) #s, -#include "opc.h" -#undef DEF -}; - -static uint8_t op_nb_args[] = { -#define DEF(s, n, copy_size) n, -#include "opc.h" -#undef DEF -}; - -static const unsigned short opc_copy_size[] = { -#define DEF(s, n, copy_size) copy_size, -#include "opc.h" -#undef DEF -}; - -void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) -{ - const uint16_t *opc_ptr; - const uint32_t *opparam_ptr; - int c, n, i; - - opc_ptr = opc_buf; - opparam_ptr = opparam_buf; - for(;;) { - c = *opc_ptr++; - n = op_nb_args[c]; - fprintf(logfile, "0x%04x: %s", - (int)(opc_ptr - opc_buf - 1), op_str[c]); - for(i = 0; i < n; i++) { - fprintf(logfile, " 0x%x", opparam_ptr[i]); - } - fprintf(logfile, "\n"); - if (c == INDEX_op_end) - break; - opparam_ptr += n; - } -} - -#endif - -/* compute label info */ -static void dyngen_labels(long *gen_labels, int nb_gen_labels, - uint8_t *gen_code_buf, const uint16_t *opc_buf) -{ - uint8_t *gen_code_ptr; - int c, i; - unsigned long gen_code_addr[OPC_BUF_SIZE]; - - if (nb_gen_labels == 0) - return; - /* compute the address of each op code */ - - gen_code_ptr = gen_code_buf; - i = 0; - for(;;) { - c = opc_buf[i]; - gen_code_addr[i] =(unsigned long)gen_code_ptr; - if (c == INDEX_op_end) - break; - gen_code_ptr += opc_copy_size[c]; - i++; - } - - /* compute the address of each label */ - for(i = 0; i < nb_gen_labels; i++) { - gen_labels[i] = gen_code_addr[gen_labels[i]]; - } -} - +/* XXX: suppress that */ unsigned long code_gen_max_block_size(void) { static unsigned long max; if (max == 0) { + max = TCG_MAX_OP_SIZE; #define DEF(s, n, copy_size) max = copy_size > max? copy_size : max; -#include "opc.h" +#include "tcg-opc.h" #undef DEF max *= OPC_MAX_SIZE; } @@ -146,6 +65,13 @@ return max; } +void cpu_gen_init(void) +{ + tcg_context_init(&tcg_ctx); + tcg_set_frame(&tcg_ctx, TCG_AREG0, offsetof(CPUState, temp_buf), + CPU_TEMP_BUF_NLONGS * sizeof(long)); +} + /* return non zero if the very first instruction is invalid so that the virtual CPU can trigger an exception. @@ -154,31 +80,52 @@ */ int cpu_gen_code(CPUState *env, TranslationBlock *tb, int *gen_code_size_ptr) { + TCGContext *s = &tcg_ctx; uint8_t *gen_code_buf; int gen_code_size; +#ifdef CONFIG_PROFILER + int64_t ti; +#endif + +#ifdef CONFIG_PROFILER + s->tb_count1++; /* includes aborted translations because of + exceptions */ + ti = profile_getclock(); +#endif + tcg_func_start(s); + + gen_intermediate_code(env, tb); - if (gen_intermediate_code(env, tb) < 0) - return -1; - /* generate machine code */ + gen_code_buf = tb->tc_ptr; tb->tb_next_offset[0] = 0xffff; tb->tb_next_offset[1] = 0xffff; - gen_code_buf = tb->tc_ptr; + s->tb_next_offset = tb->tb_next_offset; #ifdef USE_DIRECT_JUMP + s->tb_jmp_offset = tb->tb_jmp_offset; + s->tb_next = NULL; /* the following two entries are optional (only used for string ops) */ + /* XXX: not used ? */ tb->tb_jmp_offset[2] = 0xffff; tb->tb_jmp_offset[3] = 0xffff; -#endif - dyngen_labels(gen_labels, nb_gen_labels, gen_code_buf, gen_opc_buf); - - gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset, -#ifdef USE_DIRECT_JUMP - tb->tb_jmp_offset, #else - NULL, + s->tb_jmp_offset = NULL; + s->tb_next = tb->tb_next; #endif - gen_opc_buf, gen_opparam_buf, gen_labels); + +#ifdef CONFIG_PROFILER + s->tb_count++; + s->interm_time += profile_getclock() - ti; + s->code_time -= profile_getclock(); +#endif + gen_code_size = dyngen_code(s, gen_code_buf); *gen_code_size_ptr = gen_code_size; +#ifdef CONFIG_PROFILER + s->code_time += profile_getclock(); + s->code_in_len += tb->size; + s->code_out_len += gen_code_size; +#endif + #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_OUT_ASM) { fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr); @@ -196,124 +143,53 @@ CPUState *env, unsigned long searched_pc, void *puc) { - int j, c; + TCGContext *s = &tcg_ctx; + int j; unsigned long tc_ptr; - uint16_t *opc_ptr; +#ifdef CONFIG_PROFILER + int64_t ti; +#endif - if (gen_intermediate_code_pc(env, tb) < 0) - return -1; +#ifdef CONFIG_PROFILER + ti = profile_getclock(); +#endif + tcg_func_start(s); + + gen_intermediate_code_pc(env, tb); + + if (use_icount) { + /* Reset the cycle counter to the start of the block. */ + env->icount_decr.u16.low += tb->icount; + /* Clear the IO flag. */ + env->can_do_io = 0; + } /* find opc index corresponding to search_pc */ tc_ptr = (unsigned long)tb->tc_ptr; if (searched_pc < tc_ptr) return -1; - j = 0; - opc_ptr = gen_opc_buf; - for(;;) { - c = *opc_ptr; - if (c == INDEX_op_end) - return -1; - tc_ptr += opc_copy_size[c]; - if (searched_pc < tc_ptr) - break; - opc_ptr++; - } - j = opc_ptr - gen_opc_buf; + + s->tb_next_offset = tb->tb_next_offset; +#ifdef USE_DIRECT_JUMP + s->tb_jmp_offset = tb->tb_jmp_offset; + s->tb_next = NULL; +#else + s->tb_jmp_offset = NULL; + s->tb_next = tb->tb_next; +#endif + j = dyngen_code_search_pc(s, (uint8_t *)tc_ptr, searched_pc - tc_ptr); + if (j < 0) + return -1; /* now find start of instruction before */ while (gen_opc_instr_start[j] == 0) j--; -#if defined(TARGET_I386) - { - int cc_op; -#ifdef DEBUG_DISAS - if (loglevel & CPU_LOG_TB_OP) { - int i; - fprintf(logfile, "RESTORE:\n"); - for(i=0;i<=j; i++) { - if (gen_opc_instr_start[i]) { - fprintf(logfile, "0x%04x: " TARGET_FMT_lx "\n", i, gen_opc_pc[i]); - } - } - fprintf(logfile, "spc=0x%08lx j=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n", - searched_pc, j, gen_opc_pc[j] - tb->cs_base, - (uint32_t)tb->cs_base); - } -#endif - env->eip = gen_opc_pc[j] - tb->cs_base; - cc_op = gen_opc_cc_op[j]; - if (cc_op != CC_OP_DYNAMIC) - env->cc_op = cc_op; - } -#elif defined(TARGET_ARM) - env->regs[15] = gen_opc_pc[j]; -#elif defined(TARGET_SPARC) - { - target_ulong npc; - env->pc = gen_opc_pc[j]; - npc = gen_opc_npc[j]; - if (npc == 1) { - /* dynamic NPC: already stored */ - } else if (npc == 2) { - target_ulong t2 = (target_ulong)(unsigned long)puc; - /* jump PC: use T2 and the jump targets of the translation */ - if (t2) - env->npc = gen_opc_jump_pc[0]; - else - env->npc = gen_opc_jump_pc[1]; - } else { - env->npc = npc; - } - } -#elif defined(TARGET_PPC) - { - int type; - /* for PPC, we need to look at the micro operation to get the - access type */ - env->nip = gen_opc_pc[j]; - switch(c) { -#if defined(CONFIG_USER_ONLY) -#define CASE3(op)\ - case INDEX_op_ ## op ## _raw -#else -#define CASE3(op)\ - case INDEX_op_ ## op ## _user:\ - case INDEX_op_ ## op ## _kernel:\ - case INDEX_op_ ## op ## _hypv -#endif - - CASE3(stfd): - CASE3(stfs): - CASE3(lfd): - CASE3(lfs): - type = ACCESS_FLOAT; - break; - CASE3(lwarx): - type = ACCESS_RES; - break; - CASE3(stwcx): - type = ACCESS_RES; - break; - CASE3(eciwx): - CASE3(ecowx): - type = ACCESS_EXT; - break; - default: - type = ACCESS_INT; - break; - } - env->access_type = type; - } -#elif defined(TARGET_M68K) - env->pc = gen_opc_pc[j]; -#elif defined(TARGET_MIPS) - env->PC[env->current_tc] = gen_opc_pc[j]; - env->hflags &= ~MIPS_HFLAG_BMASK; - env->hflags |= gen_opc_hflags[j]; -#elif defined(TARGET_ALPHA) - env->pc = gen_opc_pc[j]; -#elif defined(TARGET_SH4) - env->pc = gen_opc_pc[j]; - env->flags = gen_opc_hflags[j]; + env->icount_decr.u16.low -= gen_opc_icount[j]; + + gen_pc_load(env, tb, searched_pc, j, puc); + +#ifdef CONFIG_PROFILER + s->restore_time += profile_getclock() - ti; + s->restore_count++; #endif return 0; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/translate-op.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/translate-op.c --- qemu-0.9.1/translate-op.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/translate-op.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,41 +0,0 @@ -/* - * Host code generation - * - * Copyright (c) 2003 Fabrice Bellard - * - * 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 -#include -#include -#include -#include - -#include "config.h" -#include "osdep.h" - -enum { -#define DEF(s, n, copy_size) INDEX_op_ ## s, -#include "opc.h" -#undef DEF - NB_OPS, -}; - -#include "dyngen.h" -extern int dyngen_code(uint8_t *gen_code_buf, - uint16_t *label_offsets, uint16_t *jmp_offsets, - const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels); -#include "op.h" - diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/usb-linux.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/usb-linux.c --- qemu-0.9.1/usb-linux.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/usb-linux.c 2008-10-28 18:22:59.000000000 +0000 @@ -3,6 +3,14 @@ * * Copyright (c) 2005 Fabrice Bellard * + * Copyright (c) 2008 Max Krasnyansky + * Support for host device auto connect & disconnect + * Major rewrite to support fully async operation + * + * Copyright 2008 TJ + * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition + * to the legacy /proc/bus/usb USB device discovery and handling + * * 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 @@ -21,16 +29,19 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #include "qemu-common.h" -#include "hw/usb.h" +#include "qemu-timer.h" #include "console.h" #if defined(__linux__) #include #include +#include + #include #include -#include +#include "hw/usb.h" /* We redefine it to avoid version problems */ struct usb_ctrltransfer { @@ -43,102 +54,258 @@ void *data; }; +struct usb_ctrlrequest { + uint8_t bRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +}; + typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id, int vendor_id, int product_id, const char *product_name, int speed); static int usb_host_find_device(int *pbus_num, int *paddr, char *product_name, int product_name_size, const char *devname); - //#define DEBUG -//#define DEBUG_ISOCH -//#define USE_ASYNCIO -#define USBDEVFS_PATH "/proc/bus/usb" +#ifdef DEBUG +#define dprintf printf +#else +#define dprintf(...) +#endif + +#define USBDBG_DEVOPENED "husb: opened %s/devices\n" + +#define USBPROCBUS_PATH "/proc/bus/usb" #define PRODUCT_NAME_SZ 32 -#define SIG_ISOCOMPLETE (SIGRTMIN+7) #define MAX_ENDPOINTS 16 +#define USBDEVBUS_PATH "/dev/bus/usb" +#define USBSYSBUS_PATH "/sys/bus/usb" -struct sigaction sigact; +static char *usb_host_device_path; + +#define USB_FS_NONE 0 +#define USB_FS_PROC 1 +#define USB_FS_DEV 2 +#define USB_FS_SYS 3 + +static int usb_fs_type; /* endpoint association data */ struct endp_data { uint8_t type; + uint8_t halted; +}; + +enum { + CTRL_STATE_IDLE = 0, + CTRL_STATE_SETUP, + CTRL_STATE_DATA, + CTRL_STATE_ACK +}; + +/* + * Control transfer state. + * Note that 'buffer' _must_ follow 'req' field because + * we need contigious buffer when we submit control URB. + */ +struct ctrl_struct { + uint16_t len; + uint16_t offset; + uint8_t state; + struct usb_ctrlrequest req; + uint8_t buffer[1024]; }; -/* FIXME: move USBPacket to PendingURB */ typedef struct USBHostDevice { USBDevice dev; - int fd; - int pipe_fds[2]; - USBPacket *packet; + int fd; + + uint8_t descr[1024]; + int descr_len; + int configuration; + int ninterfaces; + int closing; + + struct ctrl_struct ctrl; struct endp_data endp_table[MAX_ENDPOINTS]; - int configuration; - uint8_t descr[1024]; - int descr_len; - int urbs_ready; + + /* Host side address */ + int bus_num; + int addr; + + struct USBHostDevice *next; } USBHostDevice; -typedef struct PendingURB { - struct usbdevfs_urb *urb; - int status; - struct PendingURB *next; -} PendingURB; - -static PendingURB *pending_urbs = NULL; - -static int add_pending_urb(struct usbdevfs_urb *urb) -{ - PendingURB *purb = qemu_mallocz(sizeof(PendingURB)); - if (purb) { - purb->urb = urb; - purb->status = 0; - purb->next = pending_urbs; - pending_urbs = purb; - return 1; +static int is_isoc(USBHostDevice *s, int ep) +{ + return s->endp_table[ep - 1].type == USBDEVFS_URB_TYPE_ISO; +} + +static int is_halted(USBHostDevice *s, int ep) +{ + return s->endp_table[ep - 1].halted; +} + +static void clear_halt(USBHostDevice *s, int ep) +{ + s->endp_table[ep - 1].halted = 0; +} + +static void set_halt(USBHostDevice *s, int ep) +{ + s->endp_table[ep - 1].halted = 1; +} + +static USBHostDevice *hostdev_list; + +static void hostdev_link(USBHostDevice *dev) +{ + dev->next = hostdev_list; + hostdev_list = dev; +} + +static void hostdev_unlink(USBHostDevice *dev) +{ + USBHostDevice *pdev = hostdev_list; + USBHostDevice **prev = &hostdev_list; + + while (pdev) { + if (pdev == dev) { + *prev = dev->next; + return; + } + + prev = &pdev->next; + pdev = pdev->next; } - return 0; } -static int del_pending_urb(struct usbdevfs_urb *urb) +static USBHostDevice *hostdev_find(int bus_num, int addr) +{ + USBHostDevice *s = hostdev_list; + while (s) { + if (s->bus_num == bus_num && s->addr == addr) + return s; + s = s->next; + } + return NULL; +} + +/* + * Async URB state. + * We always allocate one isoc descriptor even for bulk transfers + * to simplify allocation and casts. + */ +typedef struct AsyncURB +{ + struct usbdevfs_urb urb; + struct usbdevfs_iso_packet_desc isocpd; + + USBPacket *packet; + USBHostDevice *hdev; +} AsyncURB; + +static AsyncURB *async_alloc(void) { - PendingURB *purb = pending_urbs; - PendingURB *prev = NULL; + return (AsyncURB *) qemu_mallocz(sizeof(AsyncURB)); +} + +static void async_free(AsyncURB *aurb) +{ + qemu_free(aurb); +} - while (purb && purb->urb != urb) { - prev = purb; - purb = purb->next; +static void async_complete_ctrl(USBHostDevice *s, USBPacket *p) +{ + switch(s->ctrl.state) { + case CTRL_STATE_SETUP: + if (p->len < s->ctrl.len) + s->ctrl.len = p->len; + s->ctrl.state = CTRL_STATE_DATA; + p->len = 8; + break; + + case CTRL_STATE_ACK: + s->ctrl.state = CTRL_STATE_IDLE; + p->len = 0; + break; + + default: + break; } +} - if (purb && purb->urb == urb) { - if (prev) { - prev->next = purb->next; - } else { - pending_urbs = purb->next; +static void async_complete(void *opaque) +{ + USBHostDevice *s = opaque; + AsyncURB *aurb; + + while (1) { + USBPacket *p; + + int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb); + if (r < 0) { + if (errno == EAGAIN) + return; + + if (errno == ENODEV && !s->closing) { + printf("husb: device %d.%d disconnected\n", s->bus_num, s->addr); + usb_device_del_addr(0, s->dev.addr); + return; + } + + dprintf("husb: async. reap urb failed errno %d\n", errno); + return; } - qemu_free(purb); - return 1; + + p = aurb->packet; + + dprintf("husb: async completed. aurb %p status %d alen %d\n", + aurb, aurb->urb.status, aurb->urb.actual_length); + + if (p) { + switch (aurb->urb.status) { + case 0: + p->len = aurb->urb.actual_length; + if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) + async_complete_ctrl(s, p); + break; + + case -EPIPE: + set_halt(s, p->devep); + /* fall through */ + default: + p->len = USB_RET_NAK; + break; + } + + usb_packet_complete(p); + } + + async_free(aurb); } - return 0; } -#ifdef USE_ASYNCIO -static PendingURB *get_pending_urb(struct usbdevfs_urb *urb) +static void async_cancel(USBPacket *unused, void *opaque) { - PendingURB *purb = pending_urbs; + AsyncURB *aurb = opaque; + USBHostDevice *s = aurb->hdev; - while (purb && purb->urb != urb) { - purb = purb->next; - } + dprintf("husb: async cancel. aurb %p\n", aurb); - if (purb && purb->urb == urb) { - return purb; + /* Mark it as dead (see async_complete above) */ + aurb->packet = NULL; + + int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb); + if (r < 0) { + dprintf("husb: async. discard urb failed errno %d\n", errno); } - return NULL; } -#endif -static int usb_host_update_interfaces(USBHostDevice *dev, int configuration) +static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration) { int dev_descr_len, config_descr_len; int interface, nb_interfaces, nb_configurations; @@ -147,6 +314,8 @@ if (configuration == 0) /* address state - ignore */ return 1; + dprintf("husb: claiming interfaces. config %d\n", configuration); + i = 0; dev_descr_len = dev->descr[0]; if (dev_descr_len > dev->descr_len) @@ -155,24 +324,27 @@ i += dev_descr_len; while (i < dev->descr_len) { -#ifdef DEBUG - printf("i is %d, descr_len is %d, dl %d, dt %d\n", i, dev->descr_len, + dprintf("husb: i is %d, descr_len is %d, dl %d, dt %d\n", i, dev->descr_len, dev->descr[i], dev->descr[i+1]); -#endif + if (dev->descr[i+1] != USB_DT_CONFIG) { i += dev->descr[i]; continue; } config_descr_len = dev->descr[i]; - if (configuration == dev->descr[i + 5]) + printf("husb: config #%d need %d\n", dev->descr[i + 5], configuration); + + if (configuration < 0 || configuration == dev->descr[i + 5]) { + configuration = dev->descr[i + 5]; break; + } i += config_descr_len; } if (i >= dev->descr_len) { - printf("usb_host: error - device has no matching configuration\n"); + fprintf(stderr, "husb: update iface failed. no matching configuration\n"); goto fail; } nb_interfaces = dev->descr[i + 4]; @@ -198,293 +370,417 @@ ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface); if (ret < 0) { if (errno == EBUSY) { - fprintf(stderr, - "usb_host: warning - device already grabbed\n"); + printf("husb: update iface. device already grabbed\n"); } else { - perror("USBDEVFS_CLAIMINTERFACE"); + perror("husb: failed to claim interface"); } fail: return 0; } } -#ifdef DEBUG - printf("usb_host: %d interfaces claimed for configuration %d\n", + printf("husb: %d interfaces claimed for configuration %d\n", nb_interfaces, configuration); -#endif + + dev->ninterfaces = nb_interfaces; + dev->configuration = configuration; + return 1; +} + +static int usb_host_release_interfaces(USBHostDevice *s) +{ + int ret, i; + + dprintf("husb: releasing interfaces\n"); + + for (i = 0; i < s->ninterfaces; i++) { + ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i); + if (ret < 0) { + perror("husb: failed to release interface"); + return 0; + } + } return 1; } static void usb_host_handle_reset(USBDevice *dev) { -#if 0 - USBHostDevice *s = (USBHostDevice *)dev; - /* USBDEVFS_RESET, but not the first time as it has already be - done by the host OS */ + USBHostDevice *s = (USBHostDevice *) dev; + + dprintf("husb: reset device %u.%u\n", s->bus_num, s->addr); + ioctl(s->fd, USBDEVFS_RESET); -#endif + + usb_host_claim_interfaces(s, s->configuration); } static void usb_host_handle_destroy(USBDevice *dev) { USBHostDevice *s = (USBHostDevice *)dev; + s->closing = 1; + + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + + hostdev_unlink(s); + + async_complete(s); + if (s->fd >= 0) close(s->fd); + qemu_free(s); } static int usb_linux_update_endp_table(USBHostDevice *s); -static int usb_host_handle_control(USBDevice *dev, - int request, - int value, - int index, - int length, - uint8_t *data) +static int usb_host_handle_data(USBHostDevice *s, USBPacket *p) { - USBHostDevice *s = (USBHostDevice *)dev; - struct usb_ctrltransfer ct; - struct usbdevfs_setinterface si; - int intf_update_required = 0; + struct usbdevfs_urb *urb; + AsyncURB *aurb; int ret; - if (request == (DeviceOutRequest | USB_REQ_SET_ADDRESS)) { - /* specific SET_ADDRESS support */ - dev->addr = value; - return 0; - } else if (request == ((USB_RECIP_INTERFACE << 8) | - USB_REQ_SET_INTERFACE)) { - /* set alternate setting for the interface */ - si.interface = index; - si.altsetting = value; - ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si); - usb_linux_update_endp_table(s); - } else if (request == (DeviceOutRequest | USB_REQ_SET_CONFIGURATION)) { -#ifdef DEBUG - printf("usb_host_handle_control: SET_CONFIGURATION request - " - "config %d\n", value & 0xff); -#endif - if (s->configuration != (value & 0xff)) { - s->configuration = (value & 0xff); - intf_update_required = 1; + aurb = async_alloc(); + if (!aurb) { + dprintf("husb: async malloc failed\n"); + return USB_RET_NAK; + } + aurb->hdev = s; + aurb->packet = p; + + urb = &aurb->urb; + + if (p->pid == USB_TOKEN_IN) + urb->endpoint = p->devep | 0x80; + else + urb->endpoint = p->devep; + + if (is_halted(s, p->devep)) { + ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &urb->endpoint); + if (ret < 0) { + dprintf("husb: failed to clear halt. ep 0x%x errno %d\n", + urb->endpoint, errno); + return USB_RET_NAK; } - goto do_request; + clear_halt(s, p->devep); + } + + urb->buffer = p->data; + urb->buffer_length = p->len; + + if (is_isoc(s, p->devep)) { + /* Setup ISOC transfer */ + urb->type = USBDEVFS_URB_TYPE_ISO; + urb->flags = USBDEVFS_URB_ISO_ASAP; + urb->number_of_packets = 1; + urb->iso_frame_desc[0].length = p->len; } else { - do_request: - ct.bRequestType = request >> 8; - ct.bRequest = request; - ct.wValue = value; - ct.wIndex = index; - ct.wLength = length; - ct.timeout = 50; - ct.data = data; - ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct); + /* Setup bulk transfer */ + urb->type = USBDEVFS_URB_TYPE_BULK; } + urb->usercontext = s; + + ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb); + + dprintf("husb: data submit. ep 0x%x len %u aurb %p\n", urb->endpoint, p->len, aurb); + if (ret < 0) { + dprintf("husb: submit failed. errno %d\n", errno); + async_free(aurb); + switch(errno) { case ETIMEDOUT: return USB_RET_NAK; + case EPIPE: default: return USB_RET_STALL; } - } else { - if (intf_update_required) { -#ifdef DEBUG - printf("usb_host_handle_control: updating interfaces\n"); -#endif - usb_host_update_interfaces(s, value & 0xff); - } - return ret; } + + usb_defer_packet(p, async_cancel, aurb); + return USB_RET_ASYNC; } -static int usb_host_handle_isoch(USBDevice *dev, USBPacket *p); +static int ctrl_error(void) +{ + if (errno == ETIMEDOUT) + return USB_RET_NAK; + else + return USB_RET_STALL; +} -static int usb_host_handle_data(USBDevice *dev, USBPacket *p) +static int usb_host_set_address(USBHostDevice *s, int addr) { - USBHostDevice *s = (USBHostDevice *)dev; - struct usbdevfs_bulktransfer bt; + dprintf("husb: ctrl set addr %u\n", addr); + s->dev.addr = addr; + return 0; +} + +static int usb_host_set_config(USBHostDevice *s, int config) +{ + usb_host_release_interfaces(s); + + int ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config); + + dprintf("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno); + + if (ret < 0) + return ctrl_error(); + + usb_host_claim_interfaces(s, config); + return 0; +} + +static int usb_host_set_interface(USBHostDevice *s, int iface, int alt) +{ + struct usbdevfs_setinterface si; int ret; - uint8_t devep = p->devep; - if (s->endp_table[p->devep - 1].type == USBDEVFS_URB_TYPE_ISO) { - return usb_host_handle_isoch(dev, p); + si.interface = iface; + si.altsetting = alt; + ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si); + + dprintf("husb: ctrl set iface %d altset %d ret %d errno %d\n", + iface, alt, ret, errno); + + if (ret < 0) + return ctrl_error(); + + usb_linux_update_endp_table(s); + return 0; +} + +static int usb_host_handle_control(USBHostDevice *s, USBPacket *p) +{ + struct usbdevfs_urb *urb; + AsyncURB *aurb; + int ret, value, index; + + /* + * Process certain standard device requests. + * These are infrequent and are processed synchronously. + */ + value = le16_to_cpu(s->ctrl.req.wValue); + index = le16_to_cpu(s->ctrl.req.wIndex); + + dprintf("husb: ctrl type 0x%x req 0x%x val 0x%x index %u len %u\n", + s->ctrl.req.bRequestType, s->ctrl.req.bRequest, value, index, + s->ctrl.len); + + if (s->ctrl.req.bRequestType == 0) { + switch (s->ctrl.req.bRequest) { + case USB_REQ_SET_ADDRESS: + return usb_host_set_address(s, value); + + case USB_REQ_SET_CONFIGURATION: + return usb_host_set_config(s, value & 0xff); + } } - /* XXX: optimize and handle all data types by looking at the - config descriptor */ - if (p->pid == USB_TOKEN_IN) - devep |= 0x80; - bt.ep = devep; - bt.len = p->len; - bt.timeout = 50; - bt.data = p->data; - ret = ioctl(s->fd, USBDEVFS_BULK, &bt); + if (s->ctrl.req.bRequestType == 1 && + s->ctrl.req.bRequest == USB_REQ_SET_INTERFACE) + return usb_host_set_interface(s, index, value); + + /* The rest are asynchronous */ + + aurb = async_alloc(); + if (!aurb) { + dprintf("husb: async malloc failed\n"); + return USB_RET_NAK; + } + aurb->hdev = s; + aurb->packet = p; + + /* + * Setup ctrl transfer. + * + * s->ctrl is layed out such that data buffer immediately follows + * 'req' struct which is exactly what usbdevfs expects. + */ + urb = &aurb->urb; + + urb->type = USBDEVFS_URB_TYPE_CONTROL; + urb->endpoint = p->devep; + + urb->buffer = &s->ctrl.req; + urb->buffer_length = 8 + s->ctrl.len; + + urb->usercontext = s; + + ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb); + + dprintf("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb); + if (ret < 0) { + dprintf("husb: submit failed. errno %d\n", errno); + async_free(aurb); + switch(errno) { case ETIMEDOUT: return USB_RET_NAK; case EPIPE: default: -#ifdef DEBUG - printf("handle_data: errno=%d\n", errno); -#endif return USB_RET_STALL; } - } else { - return ret; } + + usb_defer_packet(p, async_cancel, aurb); + return USB_RET_ASYNC; } -#ifdef USE_ASYNCIO -static void urb_completion_pipe_read(void *opaque) +static int do_token_setup(USBDevice *dev, USBPacket *p) { - USBHostDevice *s = opaque; - USBPacket *p = s->packet; - PendingURB *pending_urb = NULL; - struct usbdevfs_urb *purb = NULL; - int len, ret; + USBHostDevice *s = (USBHostDevice *) dev; + int ret = 0; - len = read(s->pipe_fds[0], &pending_urb, sizeof(pending_urb)); - if (len != sizeof(pending_urb)) { - printf("urb_completion: error reading pending_urb, len=%d\n", len); - return; + if (p->len != 8) + return USB_RET_STALL; + + memcpy(&s->ctrl.req, p->data, 8); + s->ctrl.len = le16_to_cpu(s->ctrl.req.wLength); + s->ctrl.offset = 0; + s->ctrl.state = CTRL_STATE_SETUP; + + if (s->ctrl.req.bRequestType & USB_DIR_IN) { + ret = usb_host_handle_control(s, p); + if (ret < 0) + return ret; + + if (ret < s->ctrl.len) + s->ctrl.len = ret; + s->ctrl.state = CTRL_STATE_DATA; + } else { + if (s->ctrl.len == 0) + s->ctrl.state = CTRL_STATE_ACK; + else + s->ctrl.state = CTRL_STATE_DATA; } - /* FIXME: handle pending_urb->status */ - del_pending_urb(pending_urb->urb); + return ret; +} - if (!p) { - s->urbs_ready++; - return; - } +static int do_token_in(USBDevice *dev, USBPacket *p) +{ + USBHostDevice *s = (USBHostDevice *) dev; + int ret = 0; - ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb); - if (ret < 0) { - printf("urb_completion: REAPURBNDELAY ioctl=%d errno=%d\n", - ret, errno); - return; - } + if (p->devep != 0) + return usb_host_handle_data(s, p); -#ifdef DEBUG_ISOCH - if (purb == pending_urb->urb) { - printf("urb_completion: urb mismatch reaped=%p pending=%p\n", - purb, urb); - } -#endif + switch(s->ctrl.state) { + case CTRL_STATE_ACK: + if (!(s->ctrl.req.bRequestType & USB_DIR_IN)) { + ret = usb_host_handle_control(s, p); + if (ret == USB_RET_ASYNC) + return USB_RET_ASYNC; - p->len = purb->actual_length; - usb_packet_complete(p); - qemu_free(purb); - s->packet = NULL; -} + s->ctrl.state = CTRL_STATE_IDLE; + return ret > 0 ? 0 : ret; + } -static void isoch_done(int signum, siginfo_t *info, void *context) -{ - struct usbdevfs_urb *urb = (struct usbdevfs_urb *)info->si_addr; - USBHostDevice *s = (USBHostDevice *)urb->usercontext; - PendingURB *purb; + return 0; - if (info->si_code != SI_ASYNCIO || - info->si_signo != SIG_ISOCOMPLETE) { - return; - } + case CTRL_STATE_DATA: + if (s->ctrl.req.bRequestType & USB_DIR_IN) { + int len = s->ctrl.len - s->ctrl.offset; + if (len > p->len) + len = p->len; + memcpy(p->data, s->ctrl.buffer + s->ctrl.offset, len); + s->ctrl.offset += len; + if (s->ctrl.offset >= s->ctrl.len) + s->ctrl.state = CTRL_STATE_ACK; + return len; + } - purb = get_pending_urb(urb); - if (purb) { - purb->status = info->si_errno; - write(s->pipe_fds[1], &purb, sizeof(purb)); + s->ctrl.state = CTRL_STATE_IDLE; + return USB_RET_STALL; + + default: + return USB_RET_STALL; } } -#endif -static int usb_host_handle_isoch(USBDevice *dev, USBPacket *p) +static int do_token_out(USBDevice *dev, USBPacket *p) { - USBHostDevice *s = (USBHostDevice *)dev; - struct usbdevfs_urb *urb, *purb = NULL; - int ret; - uint8_t devep = p->devep; + USBHostDevice *s = (USBHostDevice *) dev; - if (p->pid == USB_TOKEN_IN) - devep |= 0x80; + if (p->devep != 0) + return usb_host_handle_data(s, p); - urb = qemu_mallocz(sizeof(struct usbdevfs_urb) + - sizeof(struct usbdevfs_iso_packet_desc)); - if (!urb) { - printf("usb_host_handle_isoch: malloc failed\n"); + switch(s->ctrl.state) { + case CTRL_STATE_ACK: + if (s->ctrl.req.bRequestType & USB_DIR_IN) { + s->ctrl.state = CTRL_STATE_IDLE; + /* transfer OK */ + } else { + /* ignore additional output */ + } return 0; - } - urb->type = USBDEVFS_URB_TYPE_ISO; - urb->endpoint = devep; - urb->status = 0; - urb->flags = USBDEVFS_URB_ISO_ASAP; - urb->buffer = p->data; - urb->buffer_length = p->len; - urb->actual_length = 0; - urb->start_frame = 0; - urb->error_count = 0; -#ifdef USE_ASYNCIO - urb->signr = SIG_ISOCOMPLETE; -#else - urb->signr = 0; -#endif - urb->usercontext = s; - urb->number_of_packets = 1; - urb->iso_frame_desc[0].length = p->len; - urb->iso_frame_desc[0].actual_length = 0; - urb->iso_frame_desc[0].status = 0; - ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb); - if (ret == 0) { - if (!add_pending_urb(urb)) { - printf("usb_host_handle_isoch: add_pending_urb failed %p\n", urb); - } - } else { - printf("usb_host_handle_isoch: SUBMITURB ioctl=%d errno=%d\n", - ret, errno); - qemu_free(urb); - switch(errno) { - case ETIMEDOUT: - return USB_RET_NAK; - case EPIPE: - default: - return USB_RET_STALL; + case CTRL_STATE_DATA: + if (!(s->ctrl.req.bRequestType & USB_DIR_IN)) { + int len = s->ctrl.len - s->ctrl.offset; + if (len > p->len) + len = p->len; + memcpy(s->ctrl.buffer + s->ctrl.offset, p->data, len); + s->ctrl.offset += len; + if (s->ctrl.offset >= s->ctrl.len) + s->ctrl.state = CTRL_STATE_ACK; + return len; } + + s->ctrl.state = CTRL_STATE_IDLE; + return USB_RET_STALL; + + default: + return USB_RET_STALL; } -#ifdef USE_ASYNCIO - /* FIXME: handle urbs_ready together with sync io - * workaround for injecting the signaled urbs into current frame */ - if (s->urbs_ready > 0) { - ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb); - if (ret == 0) { - ret = purb->actual_length; - qemu_free(purb); - s->urbs_ready--; - } - return ret; +} + +/* + * Packet handler. + * Called by the HC (host controller). + * + * Returns length of the transaction or one of the USB_RET_XXX codes. + */ +static int usb_host_handle_packet(USBDevice *s, USBPacket *p) +{ + switch(p->pid) { + case USB_MSG_ATTACH: + s->state = USB_STATE_ATTACHED; + return 0; + + case USB_MSG_DETACH: + s->state = USB_STATE_NOTATTACHED; + return 0; + + case USB_MSG_RESET: + s->remote_wakeup = 0; + s->addr = 0; + s->state = USB_STATE_DEFAULT; + s->handle_reset(s); + return 0; } - s->packet = p; - return USB_RET_ASYNC; -#else - ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb); - if (ret == 0) { - if (del_pending_urb(purb)) { - ret = purb->actual_length; - qemu_free(purb); - } else { - printf("usb_host_handle_isoch: del_pending_urb failed %p\n", purb); - } - } else { -#ifdef DEBUG_ISOCH - printf("usb_host_handle_isoch: REAPURBNDELAY ioctl=%d errno=%d\n", - ret, errno); -#endif + + /* Rest of the PIDs must match our address */ + if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr) + return USB_RET_NODEV; + + switch (p->pid) { + case USB_TOKEN_SETUP: + return do_token_setup(s, p); + + case USB_TOKEN_IN: + return do_token_in(s, p); + + case USB_TOKEN_OUT: + return do_token_out(s, p); + + default: + return USB_RET_STALL; } - return ret; -#endif } /* returns 1 on problem encountered or 0 for success */ @@ -521,7 +817,7 @@ if (descriptors[i + 1] != USB_DT_CONFIG || descriptors[i + 5] != configuration) { - printf("invalid descriptor data - configuration\n"); + dprintf("invalid descriptor data - configuration\n"); return 1; } i += descriptors[i]; @@ -583,10 +879,11 @@ type = USBDEVFS_URB_TYPE_INTERRUPT; break; default: - printf("usb_host: malformed endpoint type\n"); + dprintf("usb_host: malformed endpoint type\n"); type = USBDEVFS_URB_TYPE_BULK; } s->endp_table[(devep & 0xf) - 1].type = type; + s->endp_table[(devep & 0xf) - 1].halted = 0; i += descriptors[i]; } @@ -594,40 +891,39 @@ return 0; } -/* XXX: exclude high speed devices or implement EHCI */ -USBDevice *usb_host_device_open(const char *devname) +static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *prod_name) { int fd = -1, ret; USBHostDevice *dev = NULL; struct usbdevfs_connectinfo ci; char buf[1024]; - int bus_num, addr; - char product_name[PRODUCT_NAME_SZ]; dev = qemu_mallocz(sizeof(USBHostDevice)); if (!dev) goto fail; -#ifdef DEBUG_ISOCH - printf("usb_host_device_open %s\n", devname); -#endif - if (usb_host_find_device(&bus_num, &addr, - product_name, sizeof(product_name), - devname) < 0) - return NULL; + dev->bus_num = bus_num; + dev->addr = addr; + + printf("husb: open device %d.%d\n", bus_num, addr); - snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", + if (!usb_host_device_path) { + perror("husb: USB Host Device Path not set"); + goto fail; + } + snprintf(buf, sizeof(buf), "%s/%03d/%03d", usb_host_device_path, bus_num, addr); fd = open(buf, O_RDWR | O_NONBLOCK); if (fd < 0) { perror(buf); - return NULL; + goto fail; } + dprintf("husb: opened %s\n", buf); /* read the device description */ dev->descr_len = read(fd, dev->descr, sizeof(dev->descr)); if (dev->descr_len <= 0) { - perror("usb_host_device_open: reading device data failed"); + perror("husb: reading device data failed"); goto fail; } @@ -642,10 +938,14 @@ #endif dev->fd = fd; - dev->configuration = 1; - /* XXX - do something about initial configuration */ - if (!usb_host_update_interfaces(dev, 1)) + /* + * Initial configuration is -1 which makes us claim first + * available config. We used to start with 1, which does not + * always work. I've seen devices where first config starts + * with 2. + */ + if (!usb_host_claim_interfaces(dev, -1)) goto fail; ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci); @@ -654,9 +954,7 @@ goto fail; } -#ifdef DEBUG - printf("host USB device %d.%d grabbed\n", bus_num, addr); -#endif + printf("husb: grabbed usb device %d.%d\n", bus_num, addr); ret = usb_linux_update_endp_table(dev); if (ret) @@ -666,49 +964,80 @@ dev->dev.speed = USB_SPEED_LOW; else dev->dev.speed = USB_SPEED_HIGH; - dev->dev.handle_packet = usb_generic_handle_packet; - dev->dev.handle_reset = usb_host_handle_reset; - dev->dev.handle_control = usb_host_handle_control; - dev->dev.handle_data = usb_host_handle_data; + dev->dev.handle_packet = usb_host_handle_packet; + dev->dev.handle_reset = usb_host_handle_reset; dev->dev.handle_destroy = usb_host_handle_destroy; - if (product_name[0] == '\0') + if (!prod_name || prod_name[0] == '\0') snprintf(dev->dev.devname, sizeof(dev->dev.devname), - "host:%s", devname); + "host:%d.%d", bus_num, addr); else pstrcpy(dev->dev.devname, sizeof(dev->dev.devname), - product_name); + prod_name); -#ifdef USE_ASYNCIO - /* set up the signal handlers */ - sigemptyset(&sigact.sa_mask); - sigact.sa_sigaction = isoch_done; - sigact.sa_flags = SA_SIGINFO; - sigact.sa_restorer = 0; - ret = sigaction(SIG_ISOCOMPLETE, &sigact, NULL); - if (ret < 0) { - perror("usb_host_device_open: sigaction failed"); - goto fail; - } + /* USB devio uses 'write' flag to check for async completions */ + qemu_set_fd_handler(dev->fd, NULL, async_complete, dev); + + hostdev_link(dev); + + return (USBDevice *) dev; - if (pipe(dev->pipe_fds) < 0) { - perror("usb_host_device_open: pipe creation failed"); - goto fail; - } - fcntl(dev->pipe_fds[0], F_SETFL, O_NONBLOCK | O_ASYNC); - fcntl(dev->pipe_fds[1], F_SETFL, O_NONBLOCK); - qemu_set_fd_handler(dev->pipe_fds[0], urb_completion_pipe_read, NULL, dev); -#endif - dev->urbs_ready = 0; - return (USBDevice *)dev; fail: if (dev) qemu_free(dev); + close(fd); return NULL; } +static int usb_host_auto_add(const char *spec); +static int usb_host_auto_del(const char *spec); + +USBDevice *usb_host_device_open(const char *devname) +{ + int bus_num, addr; + char product_name[PRODUCT_NAME_SZ]; + + if (strstr(devname, "auto:")) { + usb_host_auto_add(devname); + return NULL; + } + + if (usb_host_find_device(&bus_num, &addr, product_name, sizeof(product_name), + devname) < 0) + return NULL; + + if (hostdev_find(bus_num, addr)) { + term_printf("husb: host usb device %d.%d is already open\n", bus_num, addr); + return NULL; + } + + return usb_host_device_open_addr(bus_num, addr, product_name); +} + +int usb_host_device_close(const char *devname) +{ + char product_name[PRODUCT_NAME_SZ]; + int bus_num, addr; + USBHostDevice *s; + + if (strstr(devname, "auto:")) + return usb_host_auto_del(devname); + + if (usb_host_find_device(&bus_num, &addr, product_name, sizeof(product_name), + devname) < 0) + return -1; + + s = hostdev_find(bus_num, addr); + if (s) { + usb_device_del_addr(0, s->dev.addr); + return 0; + } + + return -1; +} + static int get_tag_value(char *buf, int buf_size, const char *str, const char *tag, const char *stopchars) @@ -731,23 +1060,33 @@ return q - buf; } -static int usb_host_scan(void *opaque, USBScanFunc *func) +/* + * Use /proc/bus/usb/devices or /dev/bus/usb/devices file to determine + * host's USB devices. This is legacy support since many distributions + * are moving to /sys/bus/usb + */ +static int usb_host_scan_dev(void *opaque, USBScanFunc *func) { - FILE *f; + FILE *f = 0; char line[1024]; char buf[1024]; int bus_num, addr, speed, device_count, class_id, product_id, vendor_id; - int ret; char product_name[512]; + int ret = 0; - f = fopen(USBDEVFS_PATH "/devices", "r"); + if (!usb_host_device_path) { + perror("husb: USB Host Device Path not set"); + goto the_end; + } + snprintf(line, sizeof(line), "%s/devices", usb_host_device_path); + f = fopen(line, "r"); if (!f) { - term_printf("Could not open %s\n", USBDEVFS_PATH "/devices"); - return 0; + perror("husb: cannot open devices file"); + goto the_end; } + device_count = 0; bus_num = addr = speed = class_id = product_id = vendor_id = 0; - ret = 0; for(;;) { if (fgets(line, sizeof(line), f) == NULL) break; @@ -804,10 +1143,381 @@ product_id, product_name, speed); } the_end: - fclose(f); + if (f) + fclose(f); return ret; } +/* + * Read sys file-system device file + * + * @line address of buffer to put file contents in + * @line_size size of line + * @device_file path to device file (printf format string) + * @device_name device being opened (inserted into device_file) + * + * @return 0 failed, 1 succeeded ('line' contains data) + */ +static int usb_host_read_file(char *line, size_t line_size, const char *device_file, const char *device_name) +{ + FILE *f; + int ret = 0; + char filename[PATH_MAX]; + + snprintf(filename, PATH_MAX, device_file, device_name); + f = fopen(filename, "r"); + if (f) { + fgets(line, line_size, f); + fclose(f); + ret = 1; + } else { + term_printf("husb: could not open %s\n", filename); + } + + return ret; +} + +/* + * Use /sys/bus/usb/devices/ directory to determine host's USB + * devices. + * + * This code is based on Robert Schiele's original patches posted to + * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950 + */ +static int usb_host_scan_sys(void *opaque, USBScanFunc *func) +{ + DIR *dir = 0; + char line[1024]; + int bus_num, addr, speed, class_id, product_id, vendor_id; + int ret = 0; + char product_name[512]; + struct dirent *de; + + dir = opendir(USBSYSBUS_PATH "/devices"); + if (!dir) { + perror("husb: cannot open devices directory"); + goto the_end; + } + + while ((de = readdir(dir))) { + if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) { + char *tmpstr = de->d_name; + if (!strncmp(de->d_name, "usb", 3)) + tmpstr += 3; + bus_num = atoi(tmpstr); + + if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/devnum", de->d_name)) + goto the_end; + if (sscanf(line, "%d", &addr) != 1) + goto the_end; + + if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/bDeviceClass", de->d_name)) + goto the_end; + if (sscanf(line, "%x", &class_id) != 1) + goto the_end; + + if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/idVendor", de->d_name)) + goto the_end; + if (sscanf(line, "%x", &vendor_id) != 1) + goto the_end; + + if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/idProduct", de->d_name)) + goto the_end; + if (sscanf(line, "%x", &product_id) != 1) + goto the_end; + + if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/product", de->d_name)) { + *product_name = 0; + } else { + if (strlen(line) > 0) + line[strlen(line) - 1] = '\0'; + pstrcpy(product_name, sizeof(product_name), line); + } + + if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/speed", de->d_name)) + goto the_end; + if (!strcmp(line, "480\n")) + speed = USB_SPEED_HIGH; + else if (!strcmp(line, "1.5\n")) + speed = USB_SPEED_LOW; + else + speed = USB_SPEED_FULL; + + ret = func(opaque, bus_num, addr, class_id, vendor_id, + product_id, product_name, speed); + if (ret) + goto the_end; + } + } + the_end: + if (dir) + closedir(dir); + return ret; +} + +/* + * Determine how to access the host's USB devices and call the + * specific support function. + */ +static int usb_host_scan(void *opaque, USBScanFunc *func) +{ + FILE *f = 0; + DIR *dir = 0; + int ret = 0; + const char *fs_type[] = {"unknown", "proc", "dev", "sys"}; + char devpath[PATH_MAX]; + + /* only check the host once */ + if (!usb_fs_type) { + f = fopen(USBPROCBUS_PATH "/devices", "r"); + if (f) { + /* devices found in /proc/bus/usb/ */ + strcpy(devpath, USBPROCBUS_PATH); + usb_fs_type = USB_FS_PROC; + fclose(f); + dprintf(USBDBG_DEVOPENED, USBPROCBUS_PATH); + goto found_devices; + } + /* try additional methods if an access method hasn't been found yet */ + f = fopen(USBDEVBUS_PATH "/devices", "r"); + if (f) { + /* devices found in /dev/bus/usb/ */ + strcpy(devpath, USBDEVBUS_PATH); + usb_fs_type = USB_FS_DEV; + fclose(f); + dprintf(USBDBG_DEVOPENED, USBDEVBUS_PATH); + goto found_devices; + } + dir = opendir(USBSYSBUS_PATH "/devices"); + if (dir) { + /* devices found in /dev/bus/usb/ (yes - not a mistake!) */ + strcpy(devpath, USBDEVBUS_PATH); + usb_fs_type = USB_FS_SYS; + closedir(dir); + dprintf(USBDBG_DEVOPENED, USBSYSBUS_PATH); + goto found_devices; + } + found_devices: + if (!usb_fs_type) { + term_printf("husb: unable to access USB devices\n"); + return -ENOENT; + } + + /* the module setting (used later for opening devices) */ + usb_host_device_path = qemu_mallocz(strlen(devpath)+1); + if (usb_host_device_path) { + strcpy(usb_host_device_path, devpath); + term_printf("husb: using %s file-system with %s\n", fs_type[usb_fs_type], usb_host_device_path); + } else { + /* out of memory? */ + perror("husb: unable to allocate memory for device path"); + return -ENOMEM; + } + } + + switch (usb_fs_type) { + case USB_FS_PROC: + case USB_FS_DEV: + ret = usb_host_scan_dev(opaque, func); + break; + case USB_FS_SYS: + ret = usb_host_scan_sys(opaque, func); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +struct USBAutoFilter { + struct USBAutoFilter *next; + int bus_num; + int addr; + int vendor_id; + int product_id; +}; + +static QEMUTimer *usb_auto_timer; +static struct USBAutoFilter *usb_auto_filter; + +static int usb_host_auto_scan(void *opaque, int bus_num, int addr, + int class_id, int vendor_id, int product_id, + const char *product_name, int speed) +{ + struct USBAutoFilter *f; + struct USBDevice *dev; + + /* Ignore hubs */ + if (class_id == 9) + return 0; + + for (f = usb_auto_filter; f; f = f->next) { + if (f->bus_num >= 0 && f->bus_num != bus_num) + continue; + + if (f->addr >= 0 && f->addr != addr) + continue; + + if (f->vendor_id >= 0 && f->vendor_id != vendor_id) + continue; + + if (f->product_id >= 0 && f->product_id != product_id) + continue; + + /* We got a match */ + + /* Allredy attached ? */ + if (hostdev_find(bus_num, addr)) + return 0; + + dprintf("husb: auto open: bus_num %d addr %d\n", bus_num, addr); + + dev = usb_host_device_open_addr(bus_num, addr, product_name); + if (dev) + usb_device_add_dev(dev); + } + + return 0; +} + +static void usb_host_auto_timer(void *unused) +{ + usb_host_scan(NULL, usb_host_auto_scan); + qemu_mod_timer(usb_auto_timer, qemu_get_clock(rt_clock) + 2000); +} + +/* + * Autoconnect filter + * Format: + * auto:bus:dev[:vid:pid] + * auto:bus.dev[:vid:pid] + * + * bus - bus number (dec, * means any) + * dev - device number (dec, * means any) + * vid - vendor id (hex, * means any) + * pid - product id (hex, * means any) + * + * See 'lsusb' output. + */ +static int parse_filter(const char *spec, struct USBAutoFilter *f) +{ + enum { BUS, DEV, VID, PID, DONE }; + const char *p = spec; + int i; + + f->bus_num = -1; + f->addr = -1; + f->vendor_id = -1; + f->product_id = -1; + + for (i = BUS; i < DONE; i++) { + p = strpbrk(p, ":."); + if (!p) break; + p++; + + if (*p == '*') + continue; + + switch(i) { + case BUS: f->bus_num = strtol(p, NULL, 10); break; + case DEV: f->addr = strtol(p, NULL, 10); break; + case VID: f->vendor_id = strtol(p, NULL, 16); break; + case PID: f->product_id = strtol(p, NULL, 16); break; + } + } + + if (i < DEV) { + fprintf(stderr, "husb: invalid auto filter spec %s\n", spec); + return -1; + } + + return 0; +} + +static int match_filter(const struct USBAutoFilter *f1, + const struct USBAutoFilter *f2) +{ + return f1->bus_num == f2->bus_num && + f1->addr == f2->addr && + f1->vendor_id == f2->vendor_id && + f1->product_id == f2->product_id; +} + +static int usb_host_auto_add(const char *spec) +{ + struct USBAutoFilter filter, *f; + + if (parse_filter(spec, &filter) < 0) + return -1; + + f = qemu_mallocz(sizeof(*f)); + if (!f) { + fprintf(stderr, "husb: failed to allocate auto filter\n"); + return -1; + } + + *f = filter; + + if (!usb_auto_filter) { + /* + * First entry. Init and start the monitor. + * Right now we're using timer to check for new devices. + * If this turns out to be too expensive we can move that into a + * separate thread. + */ + usb_auto_timer = qemu_new_timer(rt_clock, usb_host_auto_timer, NULL); + if (!usb_auto_timer) { + fprintf(stderr, "husb: failed to allocate auto scan timer\n"); + qemu_free(f); + return -1; + } + + /* Check for new devices every two seconds */ + qemu_mod_timer(usb_auto_timer, qemu_get_clock(rt_clock) + 2000); + } + + dprintf("husb: added auto filter: bus_num %d addr %d vid %d pid %d\n", + f->bus_num, f->addr, f->vendor_id, f->product_id); + + f->next = usb_auto_filter; + usb_auto_filter = f; + + return 0; +} + +static int usb_host_auto_del(const char *spec) +{ + struct USBAutoFilter *pf = usb_auto_filter; + struct USBAutoFilter **prev = &usb_auto_filter; + struct USBAutoFilter filter; + + if (parse_filter(spec, &filter) < 0) + return -1; + + while (pf) { + if (match_filter(pf, &filter)) { + dprintf("husb: removed auto filter: bus_num %d addr %d vid %d pid %d\n", + pf->bus_num, pf->addr, pf->vendor_id, pf->product_id); + + *prev = pf->next; + + if (!usb_auto_filter) { + /* No more filters. Stop scanning. */ + qemu_del_timer(usb_auto_timer); + qemu_free_timer(usb_auto_timer); + } + + return 0; + } + + prev = &pf->next; + pf = pf->next; + } + + return -1; +} + typedef struct FindDeviceState { int vendor_id; int product_id; @@ -857,6 +1567,7 @@ pstrcpy(product_name, product_name_size, fs.product_name); return 0; } + p = strchr(devname, ':'); if (p) { fs.vendor_id = strtoul(devname, NULL, 16); @@ -953,13 +1664,44 @@ return 0; } +static void dec2str(int val, char *str, size_t size) +{ + if (val == -1) + snprintf(str, size, "*"); + else + snprintf(str, size, "%d", val); +} + +static void hex2str(int val, char *str, size_t size) +{ + if (val == -1) + snprintf(str, size, "*"); + else + snprintf(str, size, "%x", val); +} + void usb_host_info(void) { + struct USBAutoFilter *f; + usb_host_scan(NULL, usb_host_info_device); + + if (usb_auto_filter) + term_printf(" Auto filters:\n"); + for (f = usb_auto_filter; f; f = f->next) { + char bus[10], addr[10], vid[10], pid[10]; + dec2str(f->bus_num, bus, sizeof(bus)); + dec2str(f->addr, addr, sizeof(addr)); + hex2str(f->vendor_id, vid, sizeof(vid)); + hex2str(f->product_id, pid, sizeof(pid)); + term_printf(" Device %s.%s ID %s:%s\n", bus, addr, vid, pid); + } } #else +#include "hw/usb.h" + void usb_host_info(void) { term_printf("USB host devices not supported\n"); @@ -971,4 +1713,9 @@ return NULL; } +int usb_host_device_close(const char *devname) +{ + return 0; +} + #endif diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/vgafont.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/vgafont.h --- qemu-0.9.1/vgafont.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/vgafont.h 2008-09-06 17:31:30.000000000 +0100 @@ -1,4 +1,4 @@ -static uint8_t vgafont16[256 * 16] = { +static const uint8_t vgafont16[256 * 16] = { /* 0 0x00 '^@' */ 0x00, /* 00000000 */ diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/vl.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/vl.c --- qemu-0.9.1/vl.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/vl.c 2008-11-11 21:33:36.000000000 +0000 @@ -26,9 +26,10 @@ #include "hw/usb.h" #include "hw/pcmcia.h" #include "hw/pc.h" -#include "hw/fdc.h" #include "hw/audiodev.h" #include "hw/isa.h" +#include "hw/baum.h" +#include "hw/bt.h" #include "net.h" #include "console.h" #include "sysemu.h" @@ -37,6 +38,8 @@ #include "qemu-char.h" #include "block.h" #include "audio/audio.h" +#include "migration.h" +#include "kvm.h" #include #include @@ -50,26 +53,33 @@ #include #include #include -#include #include #include +#include #include #include +#include +#if defined(__NetBSD__) +#include +#endif +#ifdef __linux__ +#include +#endif +#include #include #include #include -#include #ifdef _BSD #include -#ifndef __APPLE__ +#ifdef __FreeBSD__ #include +#else +#include #endif #elif defined (__GLIBC__) && defined (__FreeBSD_kernel__) #include #else -#ifndef __sun__ -#include -#include +#ifdef __linux__ #include #include #include @@ -81,7 +91,8 @@ #include #include -#else +#endif +#ifdef __sun__ #include #include #include @@ -97,15 +108,22 @@ #include #endif #endif -#else -#include -int inet_aton(const char *cp, struct in_addr *ia); #endif +#include "qemu_socket.h" + #if defined(CONFIG_SLIRP) #include "libslirp.h" #endif +#if defined(__OpenBSD__) +#include +#endif + +#if defined(CONFIG_VDE) +#include +#endif + #ifdef _WIN32 #include #include @@ -114,8 +132,6 @@ #define memalign(align, size) malloc(size) #endif -#include "qemu_socket.h" - #ifdef CONFIG_SDL #ifdef __APPLE__ #include @@ -141,46 +157,46 @@ //#define DEBUG_UNUSED_IOPORT //#define DEBUG_IOPORT - -#define PHYS_RAM_MAX_SIZE (2047 * 1024 * 1024) +//#define DEBUG_NET +//#define DEBUG_SLIRP #ifdef TARGET_PPC #define DEFAULT_RAM_SIZE 144 #else #define DEFAULT_RAM_SIZE 128 #endif -/* in ms */ -#define GUI_REFRESH_INTERVAL 30 /* Max number of USB devices that can be specified on the commandline. */ #define MAX_USB_CMDLINE 8 +/* Max number of bluetooth switches on the commandline. */ +#define MAX_BT_CMDLINE 10 + /* XXX: use a two level table to limit memory usage */ #define MAX_IOPORTS 65536 const char *bios_dir = CONFIG_QEMU_SHAREDIR; const char *bios_name = NULL; -void *ioport_opaque[MAX_IOPORTS]; -IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; -IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; +static void *ioport_opaque[MAX_IOPORTS]; +static IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; +static IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; /* Note: drives_table[MAX_DRIVES] is a dummy block driver if none available to store the VM snapshots */ DriveInfo drives_table[MAX_DRIVES+1]; int nb_drives; -/* point to the block driver where the snapshots are managed */ -BlockDriverState *bs_snapshots; -int vga_ram_size; -static DisplayState display_state; +static int vga_ram_size; +enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB; +DisplayState display_state; int nographic; +static int curses; const char* keyboard_layout = NULL; int64_t ticks_per_sec; -int ram_size; -int pit_min_timer_count = 0; +ram_addr_t ram_size; int nb_nics; NICInfo nd_table[MAX_NICS]; int vm_running; -int rtc_utc = 1; -int rtc_start_date = -1; /* -1 means now */ +static int rtc_utc = 1; +static int rtc_date_offset = -1; /* -1 means no change */ int cirrus_vga_enabled = 1; int vmsvga_enabled = 0; #ifdef TARGET_SPARC @@ -192,8 +208,8 @@ int graphic_height = 600; int graphic_depth = 15; #endif -int full_screen = 0; -int no_frame = 0; +static int full_screen = 0; +static int no_frame = 0; int no_quit = 0; CharDriverState *serial_hds[MAX_SERIAL_PORTS]; CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; @@ -201,26 +217,18 @@ int win2k_install_hack = 0; #endif int usb_enabled = 0; -static VLANState *first_vlan; int smp_cpus = 1; const char *vnc_display; -#if defined(TARGET_SPARC) -#define MAX_CPUS 16 -#elif defined(TARGET_I386) -#define MAX_CPUS 255 -#else -#define MAX_CPUS 1 -#endif int acpi_enabled = 1; int fd_bootchk = 1; int no_reboot = 0; +int no_shutdown = 0; int cursor_hide = 1; int graphic_rotate = 0; int daemonize = 0; const char *option_rom[MAX_OPTION_ROMS]; int nb_option_roms; int semihosting_enabled = 0; -int autostart = 1; #ifdef TARGET_ARM int old_param = 0; #endif @@ -230,14 +238,25 @@ unsigned int nb_prom_envs = 0; const char *prom_envs[MAX_PROM_ENVS]; #endif -int nb_drives_opt; -char drives_opt[MAX_DRIVES][1024]; +static int nb_drives_opt; +static struct drive_opt { + const char *file; + char opt[1024]; +} drives_opt[MAX_DRIVES]; static CPUState *cur_cpu; static CPUState *next_cpu; static int event_pending = 1; +/* Conversion factor from emulated instructions to virtual clock ticks. */ +static int icount_time_shift; +/* Arbitrarily pick 1MIPS as the minimum allowable speed. */ +#define MAX_ICOUNT_SHIFT 10 +/* Compensate for varying guest execution speed. */ +static int64_t qemu_icount_bias; +static QEMUTimer *icount_rt_timer; +static QEMUTimer *icount_vm_timer; -#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR) +uint8_t qemu_uuid[16]; /***********************************************************/ /* x86 ISA bus support */ @@ -245,6 +264,35 @@ target_phys_addr_t isa_mem_base = 0; PicState2 *isa_pic; +static IOPortReadFunc default_ioport_readb, default_ioport_readw, default_ioport_readl; +static IOPortWriteFunc default_ioport_writeb, default_ioport_writew, default_ioport_writel; + +static uint32_t ioport_read(int index, uint32_t address) +{ + static IOPortReadFunc *default_func[3] = { + default_ioport_readb, + default_ioport_readw, + default_ioport_readl + }; + IOPortReadFunc *func = ioport_read_table[index][address]; + if (!func) + func = default_func[index]; + return func(ioport_opaque[address], address); +} + +static void ioport_write(int index, uint32_t address, uint32_t data) +{ + static IOPortWriteFunc *default_func[3] = { + default_ioport_writeb, + default_ioport_writew, + default_ioport_writel + }; + IOPortWriteFunc *func = ioport_write_table[index][address]; + if (!func) + func = default_func[index]; + func(ioport_opaque[address], address, data); +} + static uint32_t default_ioport_readb(void *opaque, uint32_t address) { #ifdef DEBUG_UNUSED_IOPORT @@ -264,17 +312,17 @@ static uint32_t default_ioport_readw(void *opaque, uint32_t address) { uint32_t data; - data = ioport_read_table[0][address](ioport_opaque[address], address); + data = ioport_read(0, address); address = (address + 1) & (MAX_IOPORTS - 1); - data |= ioport_read_table[0][address](ioport_opaque[address], address) << 8; + data |= ioport_read(0, address) << 8; return data; } static void default_ioport_writew(void *opaque, uint32_t address, uint32_t data) { - ioport_write_table[0][address](ioport_opaque[address], address, data & 0xff); + ioport_write(0, address, data & 0xff); address = (address + 1) & (MAX_IOPORTS - 1); - ioport_write_table[0][address](ioport_opaque[address], address, (data >> 8) & 0xff); + ioport_write(0, address, (data >> 8) & 0xff); } static uint32_t default_ioport_readl(void *opaque, uint32_t address) @@ -292,20 +340,6 @@ #endif } -static void init_ioports(void) -{ - int i; - - for(i = 0; i < MAX_IOPORTS; i++) { - ioport_read_table[0][i] = default_ioport_readb; - ioport_write_table[0][i] = default_ioport_writeb; - ioport_read_table[1][i] = default_ioport_readw; - ioport_write_table[1][i] = default_ioport_writew; - ioport_read_table[2][i] = default_ioport_readl; - ioport_write_table[2][i] = default_ioport_writel; - } -} - /* size is the word size in byte */ int register_ioport_read(int start, int length, int size, IOPortReadFunc *func, void *opaque) @@ -379,7 +413,7 @@ if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "outb: %04x %02x\n", addr, val); #endif - ioport_write_table[0][addr](ioport_opaque[addr], addr, val); + ioport_write(0, addr, val); #ifdef USE_KQEMU if (env) env->last_io_time = cpu_get_time_fast(); @@ -392,7 +426,7 @@ if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "outw: %04x %04x\n", addr, val); #endif - ioport_write_table[1][addr](ioport_opaque[addr], addr, val); + ioport_write(1, addr, val); #ifdef USE_KQEMU if (env) env->last_io_time = cpu_get_time_fast(); @@ -405,7 +439,7 @@ if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "outl: %04x %08x\n", addr, val); #endif - ioport_write_table[2][addr](ioport_opaque[addr], addr, val); + ioport_write(2, addr, val); #ifdef USE_KQEMU if (env) env->last_io_time = cpu_get_time_fast(); @@ -415,7 +449,7 @@ int cpu_inb(CPUState *env, int addr) { int val; - val = ioport_read_table[0][addr](ioport_opaque[addr], addr); + val = ioport_read(0, addr); #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "inb : %04x %02x\n", addr, val); @@ -430,7 +464,7 @@ int cpu_inw(CPUState *env, int addr) { int val; - val = ioport_read_table[1][addr](ioport_opaque[addr], addr); + val = ioport_read(1, addr); #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "inw : %04x %04x\n", addr, val); @@ -445,7 +479,7 @@ int cpu_inl(CPUState *env, int addr) { int val; - val = ioport_read_table[2][addr](ioport_opaque[addr], addr); + val = ioport_read(2, addr); #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "inl : %04x %08x\n", addr, val); @@ -584,7 +618,7 @@ if (qemu_put_mouse_event_current->qemu_put_mouse_event_absolute) width = 0x7fff; else - width = graphic_width; + width = graphic_width - 1; mouse_event(mouse_event_opaque, width - dy, dx, dz, buttons_state); } else @@ -703,7 +737,7 @@ static void init_get_clock(void) { use_rt_clock = 0; -#if defined(__linux__) +#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) { struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { @@ -715,7 +749,7 @@ static int64_t get_clock(void) { -#if defined(__linux__) +#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) if (use_rt_clock) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); @@ -730,9 +764,22 @@ return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000); } } - #endif +/* Return the virtual CPU time, based on the instruction counter. */ +static int64_t cpu_get_icount(void) +{ + int64_t icount; + CPUState *env = cpu_single_env;; + icount = qemu_icount; + if (env) { + if (!can_do_io(env)) + fprintf(stderr, "Bad clock read\n"); + icount -= (env->icount_decr.u16.low + env->icount_extra); + } + return qemu_icount_bias + (icount << icount_time_shift); +} + /***********************************************************/ /* guest cycle counter */ @@ -744,6 +791,9 @@ /* return the host CPU cycle counter and handle stop/restart */ int64_t cpu_get_ticks(void) { + if (use_icount) { + return cpu_get_icount(); + } if (!cpu_ticks_enabled) { return cpu_ticks_offset; } else { @@ -841,6 +891,9 @@ #define MIN_TIMER_REARM_US 250 static struct qemu_alarm_timer *alarm_timer; +#ifndef _WIN32 +static int alarm_timer_rfd, alarm_timer_wfd; +#endif #ifdef _WIN32 @@ -875,6 +928,71 @@ #endif /* _WIN32 */ +/* Correlation between real and virtual time is always going to be + fairly approximate, so ignore small variation. + When the guest is idle real and virtual time will be aligned in + the IO wait loop. */ +#define ICOUNT_WOBBLE (QEMU_TIMER_BASE / 10) + +static void icount_adjust(void) +{ + int64_t cur_time; + int64_t cur_icount; + int64_t delta; + static int64_t last_delta; + /* If the VM is not running, then do nothing. */ + if (!vm_running) + return; + + cur_time = cpu_get_clock(); + cur_icount = qemu_get_clock(vm_clock); + delta = cur_icount - cur_time; + /* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */ + if (delta > 0 + && last_delta + ICOUNT_WOBBLE < delta * 2 + && icount_time_shift > 0) { + /* The guest is getting too far ahead. Slow time down. */ + icount_time_shift--; + } + if (delta < 0 + && last_delta - ICOUNT_WOBBLE > delta * 2 + && icount_time_shift < MAX_ICOUNT_SHIFT) { + /* The guest is getting too far behind. Speed time up. */ + icount_time_shift++; + } + last_delta = delta; + qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift); +} + +static void icount_adjust_rt(void * opaque) +{ + qemu_mod_timer(icount_rt_timer, + qemu_get_clock(rt_clock) + 1000); + icount_adjust(); +} + +static void icount_adjust_vm(void * opaque) +{ + qemu_mod_timer(icount_vm_timer, + qemu_get_clock(vm_clock) + QEMU_TIMER_BASE / 10); + icount_adjust(); +} + +static void init_icount_adjust(void) +{ + /* Have both realtime and virtual time triggers for speed adjustment. + The realtime trigger catches emulated time passing too slowly, + the virtual time trigger catches emulated time passing too fast. + Realtime triggers occur even when idle, so use them less frequently + than VM triggers. */ + icount_rt_timer = qemu_new_timer(rt_clock, icount_adjust_rt, NULL); + qemu_mod_timer(icount_rt_timer, + qemu_get_clock(rt_clock) + 1000); + icount_vm_timer = qemu_new_timer(vm_clock, icount_adjust_vm, NULL); + qemu_mod_timer(icount_vm_timer, + qemu_get_clock(vm_clock) + QEMU_TIMER_BASE / 10); +} + static struct qemu_alarm_timer alarm_timers[] = { #ifndef _WIN32 #ifdef __linux__ @@ -895,7 +1013,7 @@ {NULL, } }; -static void show_available_alarms() +static void show_available_alarms(void) { int i; @@ -911,8 +1029,9 @@ int count = (sizeof(alarm_timers) / sizeof(*alarm_timers)) - 1; char *arg; char *name; + struct qemu_alarm_timer tmp; - if (!strcmp(opt, "help")) { + if (!strcmp(opt, "?")) { show_available_alarms(); exit(0); } @@ -922,8 +1041,6 @@ /* Reorder the array */ name = strtok(arg, ","); while (name) { - struct qemu_alarm_timer tmp; - for (i = 0; i < count && alarm_timers[i].name; i++) { if (!strcmp(alarm_timers[i].name, name)) break; @@ -951,13 +1068,13 @@ free(arg); if (cur) { - /* Disable remaining timers */ + /* Disable remaining timers */ for (i = cur; i < count; i++) alarm_timers[i].name = NULL; + } else { + show_available_alarms(); + exit(1); } - - /* debug */ - show_available_alarms(); } QEMUClock *rt_clock; @@ -1036,9 +1153,15 @@ *pt = ts; /* Rearm if necessary */ - if ((alarm_timer->flags & ALARM_FLAG_EXPIRED) == 0 && - pt == &active_timers[ts->clock->type]) - qemu_rearm_alarm_timer(alarm_timer); + if (pt == &active_timers[ts->clock->type]) { + if ((alarm_timer->flags & ALARM_FLAG_EXPIRED) == 0) { + qemu_rearm_alarm_timer(alarm_timer); + } + /* Interrupt execution to force deadline recalculation. */ + if (use_icount && cpu_single_env) { + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); + } + } } int qemu_timer_pending(QEMUTimer *ts) @@ -1082,7 +1205,11 @@ return get_clock() / 1000000; default: case QEMU_TIMER_VIRTUAL: - return cpu_get_clock(); + if (use_icount) { + return cpu_get_icount(); + } else { + return cpu_get_clock(); + } } } @@ -1181,16 +1308,20 @@ } #endif if (alarm_has_dynticks(alarm_timer) || - qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], - qemu_get_clock(vm_clock)) || + (!use_icount && + qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], + qemu_get_clock(vm_clock))) || qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock))) { + CPUState *env = next_cpu; + #ifdef _WIN32 struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv; SetEvent(data->host_alarm); +#else + static const char byte = 0; + write(alarm_timer_wfd, &byte, sizeof(byte)); #endif - CPUState *env = next_cpu; - alarm_timer->flags |= ALARM_FLAG_EXPIRED; if (env) { @@ -1206,32 +1337,66 @@ } } -static uint64_t qemu_next_deadline(void) +static int64_t qemu_next_deadline(void) { - int64_t nearest_delta_us = INT64_MAX; - int64_t vmdelta_us; - - if (active_timers[QEMU_TIMER_REALTIME]) - nearest_delta_us = (active_timers[QEMU_TIMER_REALTIME]->expire_time - - qemu_get_clock(rt_clock))*1000; + int64_t delta; if (active_timers[QEMU_TIMER_VIRTUAL]) { - /* round up */ - vmdelta_us = (active_timers[QEMU_TIMER_VIRTUAL]->expire_time - - qemu_get_clock(vm_clock)+999)/1000; - if (vmdelta_us < nearest_delta_us) - nearest_delta_us = vmdelta_us; + delta = active_timers[QEMU_TIMER_VIRTUAL]->expire_time - + qemu_get_clock(vm_clock); + } else { + /* To avoid problems with overflow limit this to 2^32. */ + delta = INT32_MAX; + } + + if (delta < 0) + delta = 0; + + return delta; +} + +#if defined(__linux__) || defined(_WIN32) +static uint64_t qemu_next_deadline_dyntick(void) +{ + int64_t delta; + int64_t rtdelta; + + if (use_icount) + delta = INT32_MAX; + else + delta = (qemu_next_deadline() + 999) / 1000; + + if (active_timers[QEMU_TIMER_REALTIME]) { + rtdelta = (active_timers[QEMU_TIMER_REALTIME]->expire_time - + qemu_get_clock(rt_clock))*1000; + if (rtdelta < delta) + delta = rtdelta; } - /* Avoid arming the timer to negative, zero, or too low values */ - if (nearest_delta_us <= MIN_TIMER_REARM_US) - nearest_delta_us = MIN_TIMER_REARM_US; + if (delta < MIN_TIMER_REARM_US) + delta = MIN_TIMER_REARM_US; - return nearest_delta_us; + return delta; } +#endif #ifndef _WIN32 +/* Sets a specific flag */ +static int fcntl_setfl(int fd, int flag) +{ + int flags; + + flags = fcntl(fd, F_GETFL); + if (flags == -1) + return -errno; + + if (fcntl(fd, F_SETFL, flags | flag) == -1) + return -errno; + + return 0; +} + #if defined(__linux__) #define RTC_FREQ 1024 @@ -1246,7 +1411,7 @@ act.sa_handler = host_alarm_handler; sigaction(SIGIO, &act, NULL); - fcntl(fd, F_SETFL, O_ASYNC); + fcntl_setfl(fd, O_ASYNC); fcntl(fd, F_SETOWN, getpid()); } @@ -1302,11 +1467,14 @@ static int rtc_start_timer(struct qemu_alarm_timer *t) { int rtc_fd; + unsigned long current_rtc_freq = 0; TFR(rtc_fd = open("/dev/rtc", O_RDONLY)); if (rtc_fd < 0) return -1; - if (ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) { + ioctl(rtc_fd, RTC_IRQP_READ, ¤t_rtc_freq); + if (current_rtc_freq != RTC_FREQ && + ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) { fprintf(stderr, "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n" "error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n" "type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n"); @@ -1380,7 +1548,7 @@ !active_timers[QEMU_TIMER_VIRTUAL]) return; - nearest_delta_us = qemu_next_deadline(); + nearest_delta_us = qemu_next_deadline_dyntick(); /* check whether a timer is already running */ if (timer_gettime(host_timer, &timeout)) { @@ -1441,6 +1609,34 @@ #endif /* !defined(_WIN32) */ +static void try_to_rearm_timer(void *opaque) +{ + struct qemu_alarm_timer *t = opaque; +#ifndef _WIN32 + ssize_t len; + + /* Drain the notify pipe */ + do { + char buffer[512]; + len = read(alarm_timer_rfd, buffer, sizeof(buffer)); + } while ((len == -1 && errno == EINTR) || len > 0); +#endif + + /* vm time timers */ + if (vm_running && likely(!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER))) + qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], + qemu_get_clock(vm_clock)); + + /* real time timers */ + qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], + qemu_get_clock(rt_clock)); + + if (t->flags & ALARM_FLAG_EXPIRED) { + alarm_timer->flags &= ~ALARM_FLAG_EXPIRED; + qemu_rearm_alarm_timer(alarm_timer); + } +} + #ifdef _WIN32 static int win32_start_timer(struct qemu_alarm_timer *t) @@ -1483,7 +1679,7 @@ return -1; } - qemu_add_wait_object(data->host_alarm, NULL, NULL); + qemu_add_wait_object(data->host_alarm, try_to_rearm_timer, t); return 0; } @@ -1507,7 +1703,7 @@ !active_timers[QEMU_TIMER_VIRTUAL]) return; - nearest_delta_us = qemu_next_deadline(); + nearest_delta_us = qemu_next_deadline_dyntick(); nearest_delta_us /= 1000; timeKillEvent(data->timerId); @@ -1529,11 +1725,30 @@ #endif /* _WIN32 */ -static void init_timer_alarm(void) +static int init_timer_alarm(void) { - struct qemu_alarm_timer *t; + struct qemu_alarm_timer *t = NULL; int i, err = -1; +#ifndef _WIN32 + int fds[2]; + + err = pipe(fds); + if (err == -1) + return -errno; + + err = fcntl_setfl(fds[0], O_NONBLOCK); + if (err < 0) + goto fail; + + err = fcntl_setfl(fds[1], O_NONBLOCK); + if (err < 0) + goto fail; + + alarm_timer_rfd = fds[0]; + alarm_timer_wfd = fds[1]; +#endif + for (i = 0; alarm_timers[i].name; i++) { t = &alarm_timers[i]; @@ -1543,12 +1758,25 @@ } if (err) { - fprintf(stderr, "Unable to find any suitable alarm timer.\n"); - fprintf(stderr, "Terminating\n"); - exit(1); + err = -ENOENT; + goto fail; } +#ifndef _WIN32 + qemu_set_fd_handler2(alarm_timer_rfd, NULL, + try_to_rearm_timer, NULL, t); +#endif + alarm_timer = t; + + return 0; + +fail: +#ifndef _WIN32 + close(fds[0]); + close(fds[1]); +#endif + return err; } static void quit_timers(void) @@ -1558,5202 +1786,1120 @@ } /***********************************************************/ -/* character device */ - -static void qemu_chr_event(CharDriverState *s, int event) -{ - if (!s->chr_event) - return; - s->chr_event(s->handler_opaque, event); -} - -static void qemu_chr_reset_bh(void *opaque) +/* host time/date access */ +void qemu_get_timedate(struct tm *tm, int offset) { - CharDriverState *s = opaque; - qemu_chr_event(s, CHR_EVENT_RESET); - qemu_bh_delete(s->bh); - s->bh = NULL; -} + time_t ti; + struct tm *ret; -void qemu_chr_reset(CharDriverState *s) -{ - if (s->bh == NULL) { - s->bh = qemu_bh_new(qemu_chr_reset_bh, s); - qemu_bh_schedule(s->bh); + time(&ti); + ti += offset; + if (rtc_date_offset == -1) { + if (rtc_utc) + ret = gmtime(&ti); + else + ret = localtime(&ti); + } else { + ti -= rtc_date_offset; + ret = gmtime(&ti); } -} - -int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len) -{ - return s->chr_write(s, buf, len); -} -int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg) -{ - if (!s->chr_ioctl) - return -ENOTSUP; - return s->chr_ioctl(s, cmd, arg); + memcpy(tm, ret, sizeof(struct tm)); } -int qemu_chr_can_read(CharDriverState *s) +int qemu_timedate_diff(struct tm *tm) { - if (!s->chr_can_read) - return 0; - return s->chr_can_read(s->handler_opaque); -} + time_t seconds; -void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len) -{ - s->chr_read(s->handler_opaque, buf, len); -} + if (rtc_date_offset == -1) + if (rtc_utc) + seconds = mktimegm(tm); + else + seconds = mktime(tm); + else + seconds = mktimegm(tm) + rtc_date_offset; -void qemu_chr_accept_input(CharDriverState *s) -{ - if (s->chr_accept_input) - s->chr_accept_input(s); + return seconds - time(NULL); } -void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) +#ifdef _WIN32 +static void socket_cleanup(void) { - char buf[4096]; - va_list ap; - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - qemu_chr_write(s, (uint8_t *)buf, strlen(buf)); - va_end(ap); + WSACleanup(); } -void qemu_chr_send_event(CharDriverState *s, int event) +static int socket_init(void) { - if (s->chr_send_event) - s->chr_send_event(s, event); -} + WSADATA Data; + int ret, err; -void qemu_chr_add_handlers(CharDriverState *s, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, - IOEventHandler *fd_event, - void *opaque) -{ - s->chr_can_read = fd_can_read; - s->chr_read = fd_read; - s->chr_event = fd_event; - s->handler_opaque = opaque; - if (s->chr_update_read_handler) - s->chr_update_read_handler(s); + ret = WSAStartup(MAKEWORD(2,2), &Data); + if (ret != 0) { + err = WSAGetLastError(); + fprintf(stderr, "WSAStartup: %d\n", err); + return -1; + } + atexit(socket_cleanup); + return 0; } +#endif -static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +const char *get_opt_name(char *buf, int buf_size, const char *p) { - return len; -} + char *q; -static CharDriverState *qemu_chr_open_null(void) -{ - CharDriverState *chr; + q = buf; + while (*p != '\0' && *p != '=') { + if (q && (q - buf) < buf_size - 1) + *q++ = *p; + p++; + } + if (q) + *q = '\0'; - chr = qemu_mallocz(sizeof(CharDriverState)); - if (!chr) - return NULL; - chr->chr_write = null_chr_write; - return chr; + return p; } -/* MUX driver for serial I/O splitting */ -static int term_timestamps; -static int64_t term_timestamps_start; -#define MAX_MUX 4 -#define MUX_BUFFER_SIZE 32 /* Must be a power of 2. */ -#define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1) -typedef struct { - IOCanRWHandler *chr_can_read[MAX_MUX]; - IOReadHandler *chr_read[MAX_MUX]; - IOEventHandler *chr_event[MAX_MUX]; - void *ext_opaque[MAX_MUX]; - CharDriverState *drv; - unsigned char buffer[MUX_BUFFER_SIZE]; - int prod; - int cons; - int mux_cnt; - int term_got_escape; - int max_size; -} MuxDriver; - - -static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +const char *get_opt_value(char *buf, int buf_size, const char *p) { - MuxDriver *d = chr->opaque; - int ret; - if (!term_timestamps) { - ret = d->drv->chr_write(d->drv, buf, len); - } else { - int i; + char *q; - ret = 0; - for(i = 0; i < len; i++) { - ret += d->drv->chr_write(d->drv, buf+i, 1); - if (buf[i] == '\n') { - char buf1[64]; - int64_t ti; - int secs; - - ti = get_clock(); - if (term_timestamps_start == -1) - term_timestamps_start = ti; - ti -= term_timestamps_start; - secs = ti / 1000000000; - snprintf(buf1, sizeof(buf1), - "[%02d:%02d:%02d.%03d] ", - secs / 3600, - (secs / 60) % 60, - secs % 60, - (int)((ti / 1000000) % 1000)); - d->drv->chr_write(d->drv, (uint8_t *)buf1, strlen(buf1)); - } + q = buf; + while (*p != '\0') { + if (*p == ',') { + if (*(p + 1) != ',') + break; + p++; } + if (q && (q - buf) < buf_size - 1) + *q++ = *p; + p++; } - return ret; -} + if (q) + *q = '\0'; -static char *mux_help[] = { - "% h print this help\n\r", - "% x exit emulator\n\r", - "% s save disk data back to file (if -snapshot)\n\r", - "% t toggle console timestamps\n\r" - "% b send break (magic sysrq)\n\r", - "% c switch between console and monitor\n\r", - "% % sends %\n\r", - NULL -}; + return p; +} -static int term_escape_char = 0x01; /* ctrl-a is used for escape */ -static void mux_print_help(CharDriverState *chr) +int get_param_value(char *buf, int buf_size, + const char *tag, const char *str) { - int i, j; - char ebuf[15] = "Escape-Char"; - char cbuf[50] = "\n\r"; - - if (term_escape_char > 0 && term_escape_char < 26) { - sprintf(cbuf,"\n\r"); - sprintf(ebuf,"C-%c", term_escape_char - 1 + 'a'); - } else { - sprintf(cbuf,"\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r", - term_escape_char); - } - chr->chr_write(chr, (uint8_t *)cbuf, strlen(cbuf)); - for (i = 0; mux_help[i] != NULL; i++) { - for (j=0; mux_help[i][j] != '\0'; j++) { - if (mux_help[i][j] == '%') - chr->chr_write(chr, (uint8_t *)ebuf, strlen(ebuf)); - else - chr->chr_write(chr, (uint8_t *)&mux_help[i][j], 1); + const char *p; + char option[128]; + + p = str; + for(;;) { + p = get_opt_name(option, sizeof(option), p); + if (*p != '=') + break; + p++; + if (!strcmp(tag, option)) { + (void)get_opt_value(buf, buf_size, p); + return strlen(buf); + } else { + p = get_opt_value(NULL, 0, p); } + if (*p != ',') + break; + p++; } + return 0; } -static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) +int check_params(char *buf, int buf_size, + const char * const *params, const char *str) { - if (d->term_got_escape) { - d->term_got_escape = 0; - if (ch == term_escape_char) - goto send_char; - switch(ch) { - case '?': - case 'h': - mux_print_help(chr); - break; - case 'x': - { - char *term = "QEMU: Terminated\n\r"; - chr->chr_write(chr,(uint8_t *)term,strlen(term)); - exit(0); - break; - } - case 's': - { - int i; - for (i = 0; i < nb_drives; i++) { - bdrv_commit(drives_table[i].bdrv); - } - } - break; - case 'b': - qemu_chr_event(chr, CHR_EVENT_BREAK); - break; - case 'c': - /* Switch to the next registered device */ - chr->focus++; - if (chr->focus >= d->mux_cnt) - chr->focus = 0; + const char *p; + int i; + + p = str; + for(;;) { + p = get_opt_name(buf, buf_size, p); + if (*p != '=') + return -1; + p++; + for(i = 0; params[i] != NULL; i++) + if (!strcmp(params[i], buf)) + break; + if (params[i] == NULL) + return -1; + p = get_opt_value(NULL, 0, p); + if (*p != ',') break; - case 't': - term_timestamps = !term_timestamps; - term_timestamps_start = -1; - break; - } - } else if (ch == term_escape_char) { - d->term_got_escape = 1; - } else { - send_char: - return 1; + p++; } return 0; } -static void mux_chr_accept_input(CharDriverState *chr) -{ - int m = chr->focus; - MuxDriver *d = chr->opaque; +/***********************************************************/ +/* Bluetooth support */ +static int nb_hcis; +static int cur_hci; +static struct HCIInfo *hci_table[MAX_NICS]; + +static struct bt_vlan_s { + struct bt_scatternet_s net; + int id; + struct bt_vlan_s *next; +} *first_bt_vlan; - while (d->prod != d->cons && - d->chr_can_read[m] && - d->chr_can_read[m](d->ext_opaque[m])) { - d->chr_read[m](d->ext_opaque[m], - &d->buffer[d->cons++ & MUX_BUFFER_MASK], 1); +/* find or alloc a new bluetooth "VLAN" */ +static struct bt_scatternet_s *qemu_find_bt_vlan(int id) +{ + struct bt_vlan_s **pvlan, *vlan; + for (vlan = first_bt_vlan; vlan != NULL; vlan = vlan->next) { + if (vlan->id == id) + return &vlan->net; } + vlan = qemu_mallocz(sizeof(struct bt_vlan_s)); + vlan->id = id; + pvlan = &first_bt_vlan; + while (*pvlan != NULL) + pvlan = &(*pvlan)->next; + *pvlan = vlan; + return &vlan->net; } -static int mux_chr_can_read(void *opaque) +static void null_hci_send(struct HCIInfo *hci, const uint8_t *data, int len) { - CharDriverState *chr = opaque; - MuxDriver *d = chr->opaque; +} - if ((d->prod - d->cons) < MUX_BUFFER_SIZE) - return 1; - if (d->chr_can_read[chr->focus]) - return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]); - return 0; -} - -static void mux_chr_read(void *opaque, const uint8_t *buf, int size) +static int null_hci_addr_set(struct HCIInfo *hci, const uint8_t *bd_addr) { - CharDriverState *chr = opaque; - MuxDriver *d = chr->opaque; - int m = chr->focus; - int i; - - mux_chr_accept_input (opaque); - - for(i = 0; i < size; i++) - if (mux_proc_byte(chr, d, buf[i])) { - if (d->prod == d->cons && - d->chr_can_read[m] && - d->chr_can_read[m](d->ext_opaque[m])) - d->chr_read[m](d->ext_opaque[m], &buf[i], 1); - else - d->buffer[d->prod++ & MUX_BUFFER_MASK] = buf[i]; - } + return -ENOTSUP; } -static void mux_chr_event(void *opaque, int event) -{ - CharDriverState *chr = opaque; - MuxDriver *d = chr->opaque; - int i; - - /* Send the event to all registered listeners */ - for (i = 0; i < d->mux_cnt; i++) - if (d->chr_event[i]) - d->chr_event[i](d->ext_opaque[i], event); -} +static struct HCIInfo null_hci = { + .cmd_send = null_hci_send, + .sco_send = null_hci_send, + .acl_send = null_hci_send, + .bdaddr_set = null_hci_addr_set, +}; -static void mux_chr_update_read_handler(CharDriverState *chr) +struct HCIInfo *qemu_next_hci(void) { - MuxDriver *d = chr->opaque; + if (cur_hci == nb_hcis) + return &null_hci; - if (d->mux_cnt >= MAX_MUX) { - fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n"); - return; - } - d->ext_opaque[d->mux_cnt] = chr->handler_opaque; - d->chr_can_read[d->mux_cnt] = chr->chr_can_read; - d->chr_read[d->mux_cnt] = chr->chr_read; - d->chr_event[d->mux_cnt] = chr->chr_event; - /* Fix up the real driver with mux routines */ - if (d->mux_cnt == 0) { - qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read, - mux_chr_event, chr); - } - chr->focus = d->mux_cnt; - d->mux_cnt++; + return hci_table[cur_hci++]; } -static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) -{ - CharDriverState *chr; - MuxDriver *d; - - chr = qemu_mallocz(sizeof(CharDriverState)); - if (!chr) - return NULL; - d = qemu_mallocz(sizeof(MuxDriver)); - if (!d) { - free(chr); - return NULL; +static struct HCIInfo *hci_init(const char *str) +{ + char *endp; + struct bt_scatternet_s *vlan = 0; + + if (!strcmp(str, "null")) + /* null */ + return &null_hci; + else if (!strncmp(str, "host", 4) && (str[4] == '\0' || str[4] == ':')) + /* host[:hciN] */ + return bt_host_hci(str[4] ? str + 5 : "hci0"); + else if (!strncmp(str, "hci", 3)) { + /* hci[,vlan=n] */ + if (str[3]) { + if (!strncmp(str + 3, ",vlan=", 6)) { + vlan = qemu_find_bt_vlan(strtol(str + 9, &endp, 0)); + if (*endp) + vlan = 0; + } + } else + vlan = qemu_find_bt_vlan(0); + if (vlan) + return bt_new_hci(vlan); } - chr->opaque = d; - d->drv = drv; - chr->focus = -1; - chr->chr_write = mux_chr_write; - chr->chr_update_read_handler = mux_chr_update_read_handler; - chr->chr_accept_input = mux_chr_accept_input; - return chr; -} - - -#ifdef _WIN32 - -static void socket_cleanup(void) -{ - WSACleanup(); -} - -static int socket_init(void) -{ - WSADATA Data; - int ret, err; + fprintf(stderr, "qemu: Unknown bluetooth HCI `%s'.\n", str); - ret = WSAStartup(MAKEWORD(2,2), &Data); - if (ret != 0) { - err = WSAGetLastError(); - fprintf(stderr, "WSAStartup: %d\n", err); - return -1; - } - atexit(socket_cleanup); return 0; } -static int send_all(int fd, const uint8_t *buf, int len1) +static int bt_hci_parse(const char *str) { - int ret, len; + struct HCIInfo *hci; + bdaddr_t bdaddr; - len = len1; - while (len > 0) { - ret = send(fd, buf, len, 0); - if (ret < 0) { - int errno; - errno = WSAGetLastError(); - if (errno != WSAEWOULDBLOCK) { - return -1; - } - } else if (ret == 0) { - break; - } else { - buf += ret; - len -= ret; - } + if (nb_hcis >= MAX_NICS) { + fprintf(stderr, "qemu: Too many bluetooth HCIs (max %i).\n", MAX_NICS); + return -1; } - return len1 - len; -} - -void socket_set_nonblock(int fd) -{ - unsigned long opt = 1; - ioctlsocket(fd, FIONBIO, &opt); -} - -#else -static int unix_write(int fd, const uint8_t *buf, int len1) -{ - int ret, len; + hci = hci_init(str); + if (!hci) + return -1; - len = len1; - while (len > 0) { - ret = write(fd, buf, len); - if (ret < 0) { - if (errno != EINTR && errno != EAGAIN) - return -1; - } else if (ret == 0) { - break; - } else { - buf += ret; - len -= ret; - } - } - return len1 - len; -} + bdaddr.b[0] = 0x52; + bdaddr.b[1] = 0x54; + bdaddr.b[2] = 0x00; + bdaddr.b[3] = 0x12; + bdaddr.b[4] = 0x34; + bdaddr.b[5] = 0x56 + nb_hcis; + hci->bdaddr_set(hci, bdaddr.b); -static inline int send_all(int fd, const uint8_t *buf, int len1) -{ - return unix_write(fd, buf, len1); -} + hci_table[nb_hcis++] = hci; -void socket_set_nonblock(int fd) -{ - fcntl(fd, F_SETFL, O_NONBLOCK); + return 0; } -#endif /* !_WIN32 */ - -#ifndef _WIN32 - -typedef struct { - int fd_in, fd_out; - int max_size; -} FDCharDriver; - -#define STDIO_MAX_CLIENTS 1 -static int stdio_nb_clients = 0; -static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +static void bt_vhci_add(int vlan_id) { - FDCharDriver *s = chr->opaque; - return unix_write(s->fd_out, buf, len); -} + struct bt_scatternet_s *vlan = qemu_find_bt_vlan(vlan_id); -static int fd_chr_read_poll(void *opaque) -{ - CharDriverState *chr = opaque; - FDCharDriver *s = chr->opaque; + if (!vlan->slave) + fprintf(stderr, "qemu: warning: adding a VHCI to " + "an empty scatternet %i\n", vlan_id); - s->max_size = qemu_chr_can_read(chr); - return s->max_size; + bt_vhci_init(bt_new_hci(vlan)); } -static void fd_chr_read(void *opaque) +static struct bt_device_s *bt_device_add(const char *opt) { - CharDriverState *chr = opaque; - FDCharDriver *s = chr->opaque; - int size, len; - uint8_t buf[1024]; - - len = sizeof(buf); - if (len > s->max_size) - len = s->max_size; - if (len == 0) - return; - size = read(s->fd_in, buf, len); - if (size == 0) { - /* FD has been closed. Remove it from the active list. */ - qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL); - return; - } - if (size > 0) { - qemu_chr_read(chr, buf, size); - } -} + struct bt_scatternet_s *vlan; + int vlan_id = 0; + char *endp = strstr(opt, ",vlan="); + int len = (endp ? endp - opt : strlen(opt)) + 1; + char devname[10]; -static void fd_chr_update_read_handler(CharDriverState *chr) -{ - FDCharDriver *s = chr->opaque; + pstrcpy(devname, MIN(sizeof(devname), len), opt); - if (s->fd_in >= 0) { - if (nographic && s->fd_in == 0) { - } else { - qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll, - fd_chr_read, NULL, chr); + if (endp) { + vlan_id = strtol(endp + 6, &endp, 0); + if (*endp) { + fprintf(stderr, "qemu: unrecognised bluetooth vlan Id\n"); + return 0; } } -} -/* open a character device to a unix fd */ -static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) -{ - CharDriverState *chr; - FDCharDriver *s; + vlan = qemu_find_bt_vlan(vlan_id); - chr = qemu_mallocz(sizeof(CharDriverState)); - if (!chr) - return NULL; - s = qemu_mallocz(sizeof(FDCharDriver)); - if (!s) { - free(chr); - return NULL; - } - s->fd_in = fd_in; - s->fd_out = fd_out; - chr->opaque = s; - chr->chr_write = fd_chr_write; - chr->chr_update_read_handler = fd_chr_update_read_handler; + if (!vlan->slave) + fprintf(stderr, "qemu: warning: adding a slave device to " + "an empty scatternet %i\n", vlan_id); - qemu_chr_reset(chr); + if (!strcmp(devname, "keyboard")) + return bt_keyboard_init(vlan); - return chr; + fprintf(stderr, "qemu: unsupported bluetooth device `%s'\n", devname); + return 0; } -static CharDriverState *qemu_chr_open_file_out(const char *file_out) +static int bt_parse(const char *opt) { - int fd_out; - - TFR(fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666)); - if (fd_out < 0) - return NULL; - return qemu_chr_open_fd(-1, fd_out); -} + const char *endp, *p; + int vlan; -static CharDriverState *qemu_chr_open_pipe(const char *filename) -{ - int fd_in, fd_out; - char filename_in[256], filename_out[256]; + if (strstart(opt, "hci", &endp)) { + if (!*endp || *endp == ',') { + if (*endp) + if (!strstart(endp, ",vlan=", 0)) + opt = endp + 1; - snprintf(filename_in, 256, "%s.in", filename); - snprintf(filename_out, 256, "%s.out", filename); - TFR(fd_in = open(filename_in, O_RDWR | O_BINARY)); - TFR(fd_out = open(filename_out, O_RDWR | O_BINARY)); - if (fd_in < 0 || fd_out < 0) { - if (fd_in >= 0) - close(fd_in); - if (fd_out >= 0) - close(fd_out); - TFR(fd_in = fd_out = open(filename, O_RDWR | O_BINARY)); - if (fd_in < 0) - return NULL; - } - return qemu_chr_open_fd(fd_in, fd_out); -} + return bt_hci_parse(opt); + } + } else if (strstart(opt, "vhci", &endp)) { + if (!*endp || *endp == ',') { + if (*endp) { + if (strstart(endp, ",vlan=", &p)) { + vlan = strtol(p, (char **) &endp, 0); + if (*endp) { + fprintf(stderr, "qemu: bad scatternet '%s'\n", p); + return 1; + } + } else { + fprintf(stderr, "qemu: bad parameter '%s'\n", endp + 1); + return 1; + } + } else + vlan = 0; + bt_vhci_add(vlan); + return 0; + } + } else if (strstart(opt, "device:", &endp)) + return !bt_device_add(endp); -/* for STDIO, we handle the case where several clients use it - (nographic mode) */ + fprintf(stderr, "qemu: bad bluetooth parameter '%s'\n", opt); + return 1; +} -#define TERM_FIFO_MAX_SIZE 1 +/***********************************************************/ +/* QEMU Block devices */ -static uint8_t term_fifo[TERM_FIFO_MAX_SIZE]; -static int term_fifo_size; +#define HD_ALIAS "index=%d,media=disk" +#ifdef TARGET_PPC +#define CDROM_ALIAS "index=1,media=cdrom" +#else +#define CDROM_ALIAS "index=2,media=cdrom" +#endif +#define FD_ALIAS "index=%d,if=floppy" +#define PFLASH_ALIAS "if=pflash" +#define MTD_ALIAS "if=mtd" +#define SD_ALIAS "index=0,if=sd" -static int stdio_read_poll(void *opaque) +static int drive_add(const char *file, const char *fmt, ...) { - CharDriverState *chr = opaque; - - /* try to flush the queue if needed */ - if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) { - qemu_chr_read(chr, term_fifo, 1); - term_fifo_size = 0; - } - /* see if we can absorb more chars */ - if (term_fifo_size == 0) - return 1; - else - return 0; -} + va_list ap; -static void stdio_read(void *opaque) -{ - int size; - uint8_t buf[1]; - CharDriverState *chr = opaque; - - size = read(0, buf, 1); - if (size == 0) { - /* stdin has been closed. Remove it from the active list. */ - qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL); - return; - } - if (size > 0) { - if (qemu_chr_can_read(chr) > 0) { - qemu_chr_read(chr, buf, 1); - } else if (term_fifo_size == 0) { - term_fifo[term_fifo_size++] = buf[0]; - } + if (nb_drives_opt >= MAX_DRIVES) { + fprintf(stderr, "qemu: too many drives\n"); + exit(1); } -} -/* init terminal so that we can grab keys */ -static struct termios oldtty; -static int old_fd0_flags; + drives_opt[nb_drives_opt].file = file; + va_start(ap, fmt); + vsnprintf(drives_opt[nb_drives_opt].opt, + sizeof(drives_opt[0].opt), fmt, ap); + va_end(ap); -static void term_exit(void) -{ - tcsetattr (0, TCSANOW, &oldtty); - fcntl(0, F_SETFL, old_fd0_flags); + return nb_drives_opt++; } -static void term_init(void) +int drive_get_index(BlockInterfaceType type, int bus, int unit) { - struct termios tty; - - tcgetattr (0, &tty); - oldtty = tty; - old_fd0_flags = fcntl(0, F_GETFL); - - tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP - |INLCR|IGNCR|ICRNL|IXON); - tty.c_oflag |= OPOST; - tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); - /* if graphical mode, we allow Ctrl-C handling */ - if (nographic) - tty.c_lflag &= ~ISIG; - tty.c_cflag &= ~(CSIZE|PARENB); - tty.c_cflag |= CS8; - tty.c_cc[VMIN] = 1; - tty.c_cc[VTIME] = 0; + int index; - tcsetattr (0, TCSANOW, &tty); + /* seek interface, bus and unit */ - atexit(term_exit); + for (index = 0; index < nb_drives; index++) + if (drives_table[index].type == type && + drives_table[index].bus == bus && + drives_table[index].unit == unit) + return index; - fcntl(0, F_SETFL, O_NONBLOCK); + return -1; } -static CharDriverState *qemu_chr_open_stdio(void) +int drive_get_max_bus(BlockInterfaceType type) { - CharDriverState *chr; - - if (stdio_nb_clients >= STDIO_MAX_CLIENTS) - return NULL; - chr = qemu_chr_open_fd(0, 1); - qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr); - stdio_nb_clients++; - term_init(); + int max_bus; + int index; - return chr; + max_bus = -1; + for (index = 0; index < nb_drives; index++) { + if(drives_table[index].type == type && + drives_table[index].bus > max_bus) + max_bus = drives_table[index].bus; + } + return max_bus; } -#if defined(__linux__) || defined(__sun__) -static CharDriverState *qemu_chr_open_pty(void) +static void bdrv_format_print(void *opaque, const char *name) { - struct termios tty; - char slave_name[1024]; - int master_fd, slave_fd; - -#if defined(__linux__) - /* Not satisfying */ - if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) { - return NULL; - } -#endif - - /* Disabling local echo and line-buffered output */ - tcgetattr (master_fd, &tty); - tty.c_lflag &= ~(ECHO|ICANON|ISIG); - tty.c_cc[VMIN] = 1; - tty.c_cc[VTIME] = 0; - tcsetattr (master_fd, TCSAFLUSH, &tty); - - fprintf(stderr, "char device redirected to %s\n", slave_name); - return qemu_chr_open_fd(master_fd, master_fd); + fprintf(stderr, " %s", name); } -static void tty_serial_init(int fd, int speed, - int parity, int data_bits, int stop_bits) +static int drive_init(struct drive_opt *arg, int snapshot, + QEMUMachine *machine) { - struct termios tty; - speed_t spd; - -#if 0 - printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n", - speed, parity, data_bits, stop_bits); -#endif - tcgetattr (fd, &tty); - - switch(speed) { - case 50: - spd = B50; - break; - case 75: - spd = B75; - break; - case 300: - spd = B300; - break; - case 600: - spd = B600; - break; - case 1200: - spd = B1200; - break; - case 2400: - spd = B2400; - break; - case 4800: - spd = B4800; - break; - case 9600: - spd = B9600; - break; - case 19200: - spd = B19200; - break; - case 38400: - spd = B38400; - break; - case 57600: - spd = B57600; - break; - default: - case 115200: - spd = B115200; - break; - } - - cfsetispeed(&tty, spd); - cfsetospeed(&tty, spd); + char buf[128]; + char file[1024]; + char devname[128]; + const char *mediastr = ""; + BlockInterfaceType type; + enum { MEDIA_DISK, MEDIA_CDROM } media; + int bus_id, unit_id; + int cyls, heads, secs, translation; + BlockDriverState *bdrv; + BlockDriver *drv = NULL; + int max_devs; + int index; + int cache; + int bdrv_flags; + char *str = arg->opt; + static const char * const params[] = { "bus", "unit", "if", "index", + "cyls", "heads", "secs", "trans", + "media", "snapshot", "file", + "cache", "format", NULL }; - tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP - |INLCR|IGNCR|ICRNL|IXON); - tty.c_oflag |= OPOST; - tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG); - tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS|CSTOPB); - switch(data_bits) { - default: - case 8: - tty.c_cflag |= CS8; - break; - case 7: - tty.c_cflag |= CS7; - break; - case 6: - tty.c_cflag |= CS6; - break; - case 5: - tty.c_cflag |= CS5; - break; - } - switch(parity) { - default: - case 'N': - break; - case 'E': - tty.c_cflag |= PARENB; - break; - case 'O': - tty.c_cflag |= PARENB | PARODD; - break; + if (check_params(buf, sizeof(buf), params, str) < 0) { + fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n", + buf, str); + return -1; } - if (stop_bits == 2) - tty.c_cflag |= CSTOPB; - tcsetattr (fd, TCSANOW, &tty); -} - -static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg) -{ - FDCharDriver *s = chr->opaque; + file[0] = 0; + cyls = heads = secs = 0; + bus_id = 0; + unit_id = -1; + translation = BIOS_ATA_TRANSLATION_AUTO; + index = -1; + cache = 1; - switch(cmd) { - case CHR_IOCTL_SERIAL_SET_PARAMS: - { - QEMUSerialSetParams *ssp = arg; - tty_serial_init(s->fd_in, ssp->speed, ssp->parity, - ssp->data_bits, ssp->stop_bits); - } - break; - case CHR_IOCTL_SERIAL_SET_BREAK: - { - int enable = *(int *)arg; - if (enable) - tcsendbreak(s->fd_in, 1); - } - break; - default: - return -ENOTSUP; + if (machine->use_scsi) { + type = IF_SCSI; + max_devs = MAX_SCSI_DEVS; + pstrcpy(devname, sizeof(devname), "scsi"); + } else { + type = IF_IDE; + max_devs = MAX_IDE_DEVS; + pstrcpy(devname, sizeof(devname), "ide"); } - return 0; -} + media = MEDIA_DISK; -static CharDriverState *qemu_chr_open_tty(const char *filename) -{ - CharDriverState *chr; - int fd; + /* extract parameters */ - TFR(fd = open(filename, O_RDWR | O_NONBLOCK)); - fcntl(fd, F_SETFL, O_NONBLOCK); - tty_serial_init(fd, 115200, 'N', 8, 1); - chr = qemu_chr_open_fd(fd, fd); - if (!chr) { - close(fd); - return NULL; + if (get_param_value(buf, sizeof(buf), "bus", str)) { + bus_id = strtol(buf, NULL, 0); + if (bus_id < 0) { + fprintf(stderr, "qemu: '%s' invalid bus id\n", str); + return -1; + } } - chr->chr_ioctl = tty_serial_ioctl; - qemu_chr_reset(chr); - return chr; -} -#else /* ! __linux__ && ! __sun__ */ -static CharDriverState *qemu_chr_open_pty(void) -{ - return NULL; -} -#endif /* __linux__ || __sun__ */ - -#if defined(__linux__) -typedef struct { - int fd; - int mode; -} ParallelCharDriver; -static int pp_hw_mode(ParallelCharDriver *s, uint16_t mode) -{ - if (s->mode != mode) { - int m = mode; - if (ioctl(s->fd, PPSETMODE, &m) < 0) - return 0; - s->mode = mode; + if (get_param_value(buf, sizeof(buf), "unit", str)) { + unit_id = strtol(buf, NULL, 0); + if (unit_id < 0) { + fprintf(stderr, "qemu: '%s' invalid unit id\n", str); + return -1; + } } - return 1; -} -static int pp_ioctl(CharDriverState *chr, int cmd, void *arg) -{ - ParallelCharDriver *drv = chr->opaque; - int fd = drv->fd; - uint8_t b; - - switch(cmd) { - case CHR_IOCTL_PP_READ_DATA: - if (ioctl(fd, PPRDATA, &b) < 0) - return -ENOTSUP; - *(uint8_t *)arg = b; - break; - case CHR_IOCTL_PP_WRITE_DATA: - b = *(uint8_t *)arg; - if (ioctl(fd, PPWDATA, &b) < 0) - return -ENOTSUP; - break; - case CHR_IOCTL_PP_READ_CONTROL: - if (ioctl(fd, PPRCONTROL, &b) < 0) - return -ENOTSUP; - /* Linux gives only the lowest bits, and no way to know data - direction! For better compatibility set the fixed upper - bits. */ - *(uint8_t *)arg = b | 0xc0; - break; - case CHR_IOCTL_PP_WRITE_CONTROL: - b = *(uint8_t *)arg; - if (ioctl(fd, PPWCONTROL, &b) < 0) - return -ENOTSUP; - break; - case CHR_IOCTL_PP_READ_STATUS: - if (ioctl(fd, PPRSTATUS, &b) < 0) - return -ENOTSUP; - *(uint8_t *)arg = b; - break; - case CHR_IOCTL_PP_EPP_READ_ADDR: - if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) { - struct ParallelIOArg *parg = arg; - int n = read(fd, parg->buffer, parg->count); - if (n != parg->count) { - return -EIO; - } - } - break; - case CHR_IOCTL_PP_EPP_READ: - if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) { - struct ParallelIOArg *parg = arg; - int n = read(fd, parg->buffer, parg->count); - if (n != parg->count) { - return -EIO; - } - } - break; - case CHR_IOCTL_PP_EPP_WRITE_ADDR: - if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) { - struct ParallelIOArg *parg = arg; - int n = write(fd, parg->buffer, parg->count); - if (n != parg->count) { - return -EIO; - } - } - break; - case CHR_IOCTL_PP_EPP_WRITE: - if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) { - struct ParallelIOArg *parg = arg; - int n = write(fd, parg->buffer, parg->count); - if (n != parg->count) { - return -EIO; - } + if (get_param_value(buf, sizeof(buf), "if", str)) { + pstrcpy(devname, sizeof(devname), buf); + if (!strcmp(buf, "ide")) { + type = IF_IDE; + max_devs = MAX_IDE_DEVS; + } else if (!strcmp(buf, "scsi")) { + type = IF_SCSI; + max_devs = MAX_SCSI_DEVS; + } else if (!strcmp(buf, "floppy")) { + type = IF_FLOPPY; + max_devs = 0; + } else if (!strcmp(buf, "pflash")) { + type = IF_PFLASH; + max_devs = 0; + } else if (!strcmp(buf, "mtd")) { + type = IF_MTD; + max_devs = 0; + } else if (!strcmp(buf, "sd")) { + type = IF_SD; + max_devs = 0; + } else { + fprintf(stderr, "qemu: '%s' unsupported bus type '%s'\n", str, buf); + return -1; } - break; - default: - return -ENOTSUP; - } - return 0; -} - -static void pp_close(CharDriverState *chr) -{ - ParallelCharDriver *drv = chr->opaque; - int fd = drv->fd; - - pp_hw_mode(drv, IEEE1284_MODE_COMPAT); - ioctl(fd, PPRELEASE); - close(fd); - qemu_free(drv); -} - -static CharDriverState *qemu_chr_open_pp(const char *filename) -{ - CharDriverState *chr; - ParallelCharDriver *drv; - int fd; - - TFR(fd = open(filename, O_RDWR)); - if (fd < 0) - return NULL; - - if (ioctl(fd, PPCLAIM) < 0) { - close(fd); - return NULL; } - drv = qemu_mallocz(sizeof(ParallelCharDriver)); - if (!drv) { - close(fd); - return NULL; - } - drv->fd = fd; - drv->mode = IEEE1284_MODE_COMPAT; - - chr = qemu_mallocz(sizeof(CharDriverState)); - if (!chr) { - qemu_free(drv); - close(fd); - return NULL; + if (get_param_value(buf, sizeof(buf), "index", str)) { + index = strtol(buf, NULL, 0); + if (index < 0) { + fprintf(stderr, "qemu: '%s' invalid index\n", str); + return -1; + } } - chr->chr_write = null_chr_write; - chr->chr_ioctl = pp_ioctl; - chr->chr_close = pp_close; - chr->opaque = drv; - - qemu_chr_reset(chr); - - return chr; -} -#endif /* __linux__ */ -#else /* _WIN32 */ - -typedef struct { - int max_size; - HANDLE hcom, hrecv, hsend; - OVERLAPPED orecv, osend; - BOOL fpipe; - DWORD len; -} WinCharState; - -#define NSENDBUF 2048 -#define NRECVBUF 2048 -#define MAXCONNECT 1 -#define NTIMEOUT 5000 - -static int win_chr_poll(void *opaque); -static int win_chr_pipe_poll(void *opaque); - -static void win_chr_close(CharDriverState *chr) -{ - WinCharState *s = chr->opaque; - - if (s->hsend) { - CloseHandle(s->hsend); - s->hsend = NULL; - } - if (s->hrecv) { - CloseHandle(s->hrecv); - s->hrecv = NULL; - } - if (s->hcom) { - CloseHandle(s->hcom); - s->hcom = NULL; + if (get_param_value(buf, sizeof(buf), "cyls", str)) { + cyls = strtol(buf, NULL, 0); } - if (s->fpipe) - qemu_del_polling_cb(win_chr_pipe_poll, chr); - else - qemu_del_polling_cb(win_chr_poll, chr); -} - -static int win_chr_init(CharDriverState *chr, const char *filename) -{ - WinCharState *s = chr->opaque; - COMMCONFIG comcfg; - COMMTIMEOUTS cto = { 0, 0, 0, 0, 0}; - COMSTAT comstat; - DWORD size; - DWORD err; - s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!s->hsend) { - fprintf(stderr, "Failed CreateEvent\n"); - goto fail; - } - s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!s->hrecv) { - fprintf(stderr, "Failed CreateEvent\n"); - goto fail; + if (get_param_value(buf, sizeof(buf), "heads", str)) { + heads = strtol(buf, NULL, 0); } - s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, - OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); - if (s->hcom == INVALID_HANDLE_VALUE) { - fprintf(stderr, "Failed CreateFile (%lu)\n", GetLastError()); - s->hcom = NULL; - goto fail; + if (get_param_value(buf, sizeof(buf), "secs", str)) { + secs = strtol(buf, NULL, 0); } - if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) { - fprintf(stderr, "Failed SetupComm\n"); - goto fail; + if (cyls || heads || secs) { + if (cyls < 1 || cyls > 16383) { + fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", str); + return -1; + } + if (heads < 1 || heads > 16) { + fprintf(stderr, "qemu: '%s' invalid physical heads number\n", str); + return -1; + } + if (secs < 1 || secs > 63) { + fprintf(stderr, "qemu: '%s' invalid physical secs number\n", str); + return -1; + } } - ZeroMemory(&comcfg, sizeof(COMMCONFIG)); - size = sizeof(COMMCONFIG); - GetDefaultCommConfig(filename, &comcfg, &size); - comcfg.dcb.DCBlength = sizeof(DCB); - CommConfigDialog(filename, NULL, &comcfg); - - if (!SetCommState(s->hcom, &comcfg.dcb)) { - fprintf(stderr, "Failed SetCommState\n"); - goto fail; + if (get_param_value(buf, sizeof(buf), "trans", str)) { + if (!cyls) { + fprintf(stderr, + "qemu: '%s' trans must be used with cyls,heads and secs\n", + str); + return -1; + } + if (!strcmp(buf, "none")) + translation = BIOS_ATA_TRANSLATION_NONE; + else if (!strcmp(buf, "lba")) + translation = BIOS_ATA_TRANSLATION_LBA; + else if (!strcmp(buf, "auto")) + translation = BIOS_ATA_TRANSLATION_AUTO; + else { + fprintf(stderr, "qemu: '%s' invalid translation type\n", str); + return -1; + } } - if (!SetCommMask(s->hcom, EV_ERR)) { - fprintf(stderr, "Failed SetCommMask\n"); - goto fail; + if (get_param_value(buf, sizeof(buf), "media", str)) { + if (!strcmp(buf, "disk")) { + media = MEDIA_DISK; + } else if (!strcmp(buf, "cdrom")) { + if (cyls || secs || heads) { + fprintf(stderr, + "qemu: '%s' invalid physical CHS format\n", str); + return -1; + } + media = MEDIA_CDROM; + } else { + fprintf(stderr, "qemu: '%s' invalid media\n", str); + return -1; + } } - cto.ReadIntervalTimeout = MAXDWORD; - if (!SetCommTimeouts(s->hcom, &cto)) { - fprintf(stderr, "Failed SetCommTimeouts\n"); - goto fail; + if (get_param_value(buf, sizeof(buf), "snapshot", str)) { + if (!strcmp(buf, "on")) + snapshot = 1; + else if (!strcmp(buf, "off")) + snapshot = 0; + else { + fprintf(stderr, "qemu: '%s' invalid snapshot option\n", str); + return -1; + } } - if (!ClearCommError(s->hcom, &err, &comstat)) { - fprintf(stderr, "Failed ClearCommError\n"); - goto fail; + if (get_param_value(buf, sizeof(buf), "cache", str)) { + if (!strcmp(buf, "off") || !strcmp(buf, "none")) + cache = 0; + else if (!strcmp(buf, "writethrough")) + cache = 1; + else if (!strcmp(buf, "writeback")) + cache = 2; + else { + fprintf(stderr, "qemu: invalid cache option\n"); + return -1; + } } - qemu_add_polling_cb(win_chr_poll, chr); - return 0; - - fail: - win_chr_close(chr); - return -1; -} - -static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1) -{ - WinCharState *s = chr->opaque; - DWORD len, ret, size, err; - len = len1; - ZeroMemory(&s->osend, sizeof(s->osend)); - s->osend.hEvent = s->hsend; - while (len > 0) { - if (s->hsend) - ret = WriteFile(s->hcom, buf, len, &size, &s->osend); - else - ret = WriteFile(s->hcom, buf, len, &size, NULL); - if (!ret) { - err = GetLastError(); - if (err == ERROR_IO_PENDING) { - ret = GetOverlappedResult(s->hcom, &s->osend, &size, TRUE); - if (ret) { - buf += size; - len -= size; - } else { - break; - } - } else { - break; - } - } else { - buf += size; - len -= size; + if (get_param_value(buf, sizeof(buf), "format", str)) { + if (strcmp(buf, "?") == 0) { + fprintf(stderr, "qemu: Supported formats:"); + bdrv_iterate_format(bdrv_format_print, NULL); + fprintf(stderr, "\n"); + return -1; + } + drv = bdrv_find_format(buf); + if (!drv) { + fprintf(stderr, "qemu: '%s' invalid format\n", buf); + return -1; } } - return len1 - len; -} - -static int win_chr_read_poll(CharDriverState *chr) -{ - WinCharState *s = chr->opaque; - s->max_size = qemu_chr_can_read(chr); - return s->max_size; -} + if (arg->file == NULL) + get_param_value(file, sizeof(file), "file", str); + else + pstrcpy(file, sizeof(file), arg->file); -static void win_chr_readfile(CharDriverState *chr) -{ - WinCharState *s = chr->opaque; - int ret, err; - uint8_t buf[1024]; - DWORD size; + /* compute bus and unit according index */ - ZeroMemory(&s->orecv, sizeof(s->orecv)); - s->orecv.hEvent = s->hrecv; - ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv); - if (!ret) { - err = GetLastError(); - if (err == ERROR_IO_PENDING) { - ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE); + if (index != -1) { + if (bus_id != 0 || unit_id != -1) { + fprintf(stderr, + "qemu: '%s' index cannot be used with bus and unit\n", str); + return -1; + } + if (max_devs == 0) + { + unit_id = index; + bus_id = 0; + } else { + unit_id = index % max_devs; + bus_id = index / max_devs; } } - if (size > 0) { - qemu_chr_read(chr, buf, size); - } -} - -static void win_chr_read(CharDriverState *chr) -{ - WinCharState *s = chr->opaque; - - if (s->len > s->max_size) - s->len = s->max_size; - if (s->len == 0) - return; - - win_chr_readfile(chr); -} + /* if user doesn't specify a unit_id, + * try to find the first free + */ -static int win_chr_poll(void *opaque) -{ - CharDriverState *chr = opaque; - WinCharState *s = chr->opaque; - COMSTAT status; - DWORD comerr; - - ClearCommError(s->hcom, &comerr, &status); - if (status.cbInQue > 0) { - s->len = status.cbInQue; - win_chr_read_poll(chr); - win_chr_read(chr); - return 1; + if (unit_id == -1) { + unit_id = 0; + while (drive_get_index(type, bus_id, unit_id) != -1) { + unit_id++; + if (max_devs && unit_id >= max_devs) { + unit_id -= max_devs; + bus_id++; + } + } } - return 0; -} - -static CharDriverState *qemu_chr_open_win(const char *filename) -{ - CharDriverState *chr; - WinCharState *s; - chr = qemu_mallocz(sizeof(CharDriverState)); - if (!chr) - return NULL; - s = qemu_mallocz(sizeof(WinCharState)); - if (!s) { - free(chr); - return NULL; - } - chr->opaque = s; - chr->chr_write = win_chr_write; - chr->chr_close = win_chr_close; - - if (win_chr_init(chr, filename) < 0) { - free(s); - free(chr); - return NULL; - } - qemu_chr_reset(chr); - return chr; -} + /* check unit id */ -static int win_chr_pipe_poll(void *opaque) -{ - CharDriverState *chr = opaque; - WinCharState *s = chr->opaque; - DWORD size; - - PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL); - if (size > 0) { - s->len = size; - win_chr_read_poll(chr); - win_chr_read(chr); - return 1; + if (max_devs && unit_id >= max_devs) { + fprintf(stderr, "qemu: '%s' unit %d too big (max is %d)\n", + str, unit_id, max_devs - 1); + return -1; } - return 0; -} - -static int win_chr_pipe_init(CharDriverState *chr, const char *filename) -{ - WinCharState *s = chr->opaque; - OVERLAPPED ov; - int ret; - DWORD size; - char openname[256]; - s->fpipe = TRUE; + /* + * ignore multiple definitions + */ - s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!s->hsend) { - fprintf(stderr, "Failed CreateEvent\n"); - goto fail; - } - s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!s->hrecv) { - fprintf(stderr, "Failed CreateEvent\n"); - goto fail; - } + if (drive_get_index(type, bus_id, unit_id) != -1) + return 0; - snprintf(openname, sizeof(openname), "\\\\.\\pipe\\%s", filename); - s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, - PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | - PIPE_WAIT, - MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL); - if (s->hcom == INVALID_HANDLE_VALUE) { - fprintf(stderr, "Failed CreateNamedPipe (%lu)\n", GetLastError()); - s->hcom = NULL; - goto fail; - } + /* init */ - ZeroMemory(&ov, sizeof(ov)); - ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - ret = ConnectNamedPipe(s->hcom, &ov); - if (ret) { - fprintf(stderr, "Failed ConnectNamedPipe\n"); - goto fail; - } + if (type == IF_IDE || type == IF_SCSI) + mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd"; + if (max_devs) + snprintf(buf, sizeof(buf), "%s%i%s%i", + devname, bus_id, mediastr, unit_id); + else + snprintf(buf, sizeof(buf), "%s%s%i", + devname, mediastr, unit_id); + bdrv = bdrv_new(buf); + drives_table[nb_drives].bdrv = bdrv; + drives_table[nb_drives].type = type; + drives_table[nb_drives].bus = bus_id; + drives_table[nb_drives].unit = unit_id; + nb_drives++; - ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE); - if (!ret) { - fprintf(stderr, "Failed GetOverlappedResult\n"); - if (ov.hEvent) { - CloseHandle(ov.hEvent); - ov.hEvent = NULL; - } - goto fail; - } - - if (ov.hEvent) { - CloseHandle(ov.hEvent); - ov.hEvent = NULL; - } - qemu_add_polling_cb(win_chr_pipe_poll, chr); - return 0; - - fail: - win_chr_close(chr); - return -1; -} - - -static CharDriverState *qemu_chr_open_win_pipe(const char *filename) -{ - CharDriverState *chr; - WinCharState *s; - - chr = qemu_mallocz(sizeof(CharDriverState)); - if (!chr) - return NULL; - s = qemu_mallocz(sizeof(WinCharState)); - if (!s) { - free(chr); - return NULL; - } - chr->opaque = s; - chr->chr_write = win_chr_write; - chr->chr_close = win_chr_close; - - if (win_chr_pipe_init(chr, filename) < 0) { - free(s); - free(chr); - return NULL; - } - qemu_chr_reset(chr); - return chr; -} - -static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) -{ - CharDriverState *chr; - WinCharState *s; - - chr = qemu_mallocz(sizeof(CharDriverState)); - if (!chr) - return NULL; - s = qemu_mallocz(sizeof(WinCharState)); - if (!s) { - free(chr); - return NULL; - } - s->hcom = fd_out; - chr->opaque = s; - chr->chr_write = win_chr_write; - qemu_chr_reset(chr); - return chr; -} - -static CharDriverState *qemu_chr_open_win_con(const char *filename) -{ - return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE)); -} - -static CharDriverState *qemu_chr_open_win_file_out(const char *file_out) -{ - HANDLE fd_out; - - fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (fd_out == INVALID_HANDLE_VALUE) - return NULL; - - return qemu_chr_open_win_file(fd_out); -} -#endif /* !_WIN32 */ - -/***********************************************************/ -/* UDP Net console */ - -typedef struct { - int fd; - struct sockaddr_in daddr; - uint8_t buf[1024]; - int bufcnt; - int bufptr; - int max_size; -} NetCharDriver; - -static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) -{ - NetCharDriver *s = chr->opaque; - - return sendto(s->fd, buf, len, 0, - (struct sockaddr *)&s->daddr, sizeof(struct sockaddr_in)); -} - -static int udp_chr_read_poll(void *opaque) -{ - CharDriverState *chr = opaque; - NetCharDriver *s = chr->opaque; - - s->max_size = qemu_chr_can_read(chr); - - /* If there were any stray characters in the queue process them - * first - */ - while (s->max_size > 0 && s->bufptr < s->bufcnt) { - qemu_chr_read(chr, &s->buf[s->bufptr], 1); - s->bufptr++; - s->max_size = qemu_chr_can_read(chr); - } - return s->max_size; -} - -static void udp_chr_read(void *opaque) -{ - CharDriverState *chr = opaque; - NetCharDriver *s = chr->opaque; - - if (s->max_size == 0) - return; - s->bufcnt = recv(s->fd, s->buf, sizeof(s->buf), 0); - s->bufptr = s->bufcnt; - if (s->bufcnt <= 0) - return; - - s->bufptr = 0; - while (s->max_size > 0 && s->bufptr < s->bufcnt) { - qemu_chr_read(chr, &s->buf[s->bufptr], 1); - s->bufptr++; - s->max_size = qemu_chr_can_read(chr); - } -} - -static void udp_chr_update_read_handler(CharDriverState *chr) -{ - NetCharDriver *s = chr->opaque; - - if (s->fd >= 0) { - qemu_set_fd_handler2(s->fd, udp_chr_read_poll, - udp_chr_read, NULL, chr); - } -} - -int parse_host_port(struct sockaddr_in *saddr, const char *str); -#ifndef _WIN32 -static int parse_unix_path(struct sockaddr_un *uaddr, const char *str); -#endif -int parse_host_src_port(struct sockaddr_in *haddr, - struct sockaddr_in *saddr, - const char *str); - -static CharDriverState *qemu_chr_open_udp(const char *def) -{ - CharDriverState *chr = NULL; - NetCharDriver *s = NULL; - int fd = -1; - struct sockaddr_in saddr; - - chr = qemu_mallocz(sizeof(CharDriverState)); - if (!chr) - goto return_err; - s = qemu_mallocz(sizeof(NetCharDriver)); - if (!s) - goto return_err; - - fd = socket(PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - perror("socket(PF_INET, SOCK_DGRAM)"); - goto return_err; - } - - if (parse_host_src_port(&s->daddr, &saddr, def) < 0) { - printf("Could not parse: %s\n", def); - goto return_err; - } - - if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) - { - perror("bind"); - goto return_err; - } - - s->fd = fd; - s->bufcnt = 0; - s->bufptr = 0; - chr->opaque = s; - chr->chr_write = udp_chr_write; - chr->chr_update_read_handler = udp_chr_update_read_handler; - return chr; - -return_err: - if (chr) - free(chr); - if (s) - free(s); - if (fd >= 0) - closesocket(fd); - return NULL; -} - -/***********************************************************/ -/* TCP Net console */ - -typedef struct { - int fd, listen_fd; - int connected; - int max_size; - int do_telnetopt; - int do_nodelay; - int is_unix; -} TCPCharDriver; - -static void tcp_chr_accept(void *opaque); - -static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) -{ - TCPCharDriver *s = chr->opaque; - if (s->connected) { - return send_all(s->fd, buf, len); - } else { - /* XXX: indicate an error ? */ - return len; - } -} - -static int tcp_chr_read_poll(void *opaque) -{ - CharDriverState *chr = opaque; - TCPCharDriver *s = chr->opaque; - if (!s->connected) - return 0; - s->max_size = qemu_chr_can_read(chr); - return s->max_size; -} - -#define IAC 255 -#define IAC_BREAK 243 -static void tcp_chr_process_IAC_bytes(CharDriverState *chr, - TCPCharDriver *s, - uint8_t *buf, int *size) -{ - /* Handle any telnet client's basic IAC options to satisfy char by - * char mode with no echo. All IAC options will be removed from - * the buf and the do_telnetopt variable will be used to track the - * state of the width of the IAC information. - * - * IAC commands come in sets of 3 bytes with the exception of the - * "IAC BREAK" command and the double IAC. - */ - - int i; - int j = 0; - - for (i = 0; i < *size; i++) { - if (s->do_telnetopt > 1) { - if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) { - /* Double IAC means send an IAC */ - if (j != i) - buf[j] = buf[i]; - j++; - s->do_telnetopt = 1; - } else { - if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) { - /* Handle IAC break commands by sending a serial break */ - qemu_chr_event(chr, CHR_EVENT_BREAK); - s->do_telnetopt++; - } - s->do_telnetopt++; - } - if (s->do_telnetopt >= 4) { - s->do_telnetopt = 1; - } - } else { - if ((unsigned char)buf[i] == IAC) { - s->do_telnetopt = 2; - } else { - if (j != i) - buf[j] = buf[i]; - j++; - } - } - } - *size = j; -} - -static void tcp_chr_read(void *opaque) -{ - CharDriverState *chr = opaque; - TCPCharDriver *s = chr->opaque; - uint8_t buf[1024]; - int len, size; - - if (!s->connected || s->max_size <= 0) - return; - len = sizeof(buf); - if (len > s->max_size) - len = s->max_size; - size = recv(s->fd, buf, len, 0); - if (size == 0) { - /* connection closed */ - s->connected = 0; - if (s->listen_fd >= 0) { - qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); - } - qemu_set_fd_handler(s->fd, NULL, NULL, NULL); - closesocket(s->fd); - s->fd = -1; - } else if (size > 0) { - if (s->do_telnetopt) - tcp_chr_process_IAC_bytes(chr, s, buf, &size); - if (size > 0) - qemu_chr_read(chr, buf, size); - } -} - -static void tcp_chr_connect(void *opaque) -{ - CharDriverState *chr = opaque; - TCPCharDriver *s = chr->opaque; - - s->connected = 1; - qemu_set_fd_handler2(s->fd, tcp_chr_read_poll, - tcp_chr_read, NULL, chr); - qemu_chr_reset(chr); -} - -#define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c; -static void tcp_chr_telnet_init(int fd) -{ - char buf[3]; - /* Send the telnet negotion to put telnet in binary, no echo, single char mode */ - IACSET(buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */ - send(fd, (char *)buf, 3, 0); - IACSET(buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */ - send(fd, (char *)buf, 3, 0); - IACSET(buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */ - send(fd, (char *)buf, 3, 0); - IACSET(buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */ - send(fd, (char *)buf, 3, 0); -} - -static void socket_set_nodelay(int fd) -{ - int val = 1; - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); -} - -static void tcp_chr_accept(void *opaque) -{ - CharDriverState *chr = opaque; - TCPCharDriver *s = chr->opaque; - struct sockaddr_in saddr; -#ifndef _WIN32 - struct sockaddr_un uaddr; -#endif - struct sockaddr *addr; - socklen_t len; - int fd; - - for(;;) { -#ifndef _WIN32 - if (s->is_unix) { - len = sizeof(uaddr); - addr = (struct sockaddr *)&uaddr; - } else -#endif - { - len = sizeof(saddr); - addr = (struct sockaddr *)&saddr; - } - fd = accept(s->listen_fd, addr, &len); - if (fd < 0 && errno != EINTR) { - return; - } else if (fd >= 0) { - if (s->do_telnetopt) - tcp_chr_telnet_init(fd); - break; - } - } - socket_set_nonblock(fd); - if (s->do_nodelay) - socket_set_nodelay(fd); - s->fd = fd; - qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); - tcp_chr_connect(chr); -} - -static void tcp_chr_close(CharDriverState *chr) -{ - TCPCharDriver *s = chr->opaque; - if (s->fd >= 0) - closesocket(s->fd); - if (s->listen_fd >= 0) - closesocket(s->listen_fd); - qemu_free(s); -} - -static CharDriverState *qemu_chr_open_tcp(const char *host_str, - int is_telnet, - int is_unix) -{ - CharDriverState *chr = NULL; - TCPCharDriver *s = NULL; - int fd = -1, ret, err, val; - int is_listen = 0; - int is_waitconnect = 1; - int do_nodelay = 0; - const char *ptr; - struct sockaddr_in saddr; -#ifndef _WIN32 - struct sockaddr_un uaddr; -#endif - struct sockaddr *addr; - socklen_t addrlen; - -#ifndef _WIN32 - if (is_unix) { - addr = (struct sockaddr *)&uaddr; - addrlen = sizeof(uaddr); - if (parse_unix_path(&uaddr, host_str) < 0) - goto fail; - } else -#endif - { - addr = (struct sockaddr *)&saddr; - addrlen = sizeof(saddr); - if (parse_host_port(&saddr, host_str) < 0) - goto fail; - } - - ptr = host_str; - while((ptr = strchr(ptr,','))) { - ptr++; - if (!strncmp(ptr,"server",6)) { - is_listen = 1; - } else if (!strncmp(ptr,"nowait",6)) { - is_waitconnect = 0; - } else if (!strncmp(ptr,"nodelay",6)) { - do_nodelay = 1; - } else { - printf("Unknown option: %s\n", ptr); - goto fail; - } - } - if (!is_listen) - is_waitconnect = 0; - - chr = qemu_mallocz(sizeof(CharDriverState)); - if (!chr) - goto fail; - s = qemu_mallocz(sizeof(TCPCharDriver)); - if (!s) - goto fail; - -#ifndef _WIN32 - if (is_unix) - fd = socket(PF_UNIX, SOCK_STREAM, 0); - else -#endif - fd = socket(PF_INET, SOCK_STREAM, 0); - - if (fd < 0) - goto fail; - - if (!is_waitconnect) - socket_set_nonblock(fd); - - s->connected = 0; - s->fd = -1; - s->listen_fd = -1; - s->is_unix = is_unix; - s->do_nodelay = do_nodelay && !is_unix; - - chr->opaque = s; - chr->chr_write = tcp_chr_write; - chr->chr_close = tcp_chr_close; - - if (is_listen) { - /* allow fast reuse */ -#ifndef _WIN32 - if (is_unix) { - char path[109]; - strncpy(path, uaddr.sun_path, 108); - path[108] = 0; - unlink(path); - } else -#endif - { - val = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); - } - - ret = bind(fd, addr, addrlen); - if (ret < 0) - goto fail; - - ret = listen(fd, 0); - if (ret < 0) - goto fail; - - s->listen_fd = fd; - qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); - if (is_telnet) - s->do_telnetopt = 1; - } else { - for(;;) { - ret = connect(fd, addr, addrlen); - if (ret < 0) { - err = socket_error(); - if (err == EINTR || err == EWOULDBLOCK) { - } else if (err == EINPROGRESS) { - break; -#ifdef _WIN32 - } else if (err == WSAEALREADY) { - break; -#endif - } else { - goto fail; - } - } else { - s->connected = 1; - break; - } - } - s->fd = fd; - socket_set_nodelay(fd); - if (s->connected) - tcp_chr_connect(chr); - else - qemu_set_fd_handler(s->fd, NULL, tcp_chr_connect, chr); - } - - if (is_listen && is_waitconnect) { - printf("QEMU waiting for connection on: %s\n", host_str); - tcp_chr_accept(chr); - socket_set_nonblock(s->listen_fd); - } - - return chr; - fail: - if (fd >= 0) - closesocket(fd); - qemu_free(s); - qemu_free(chr); - return NULL; -} - -CharDriverState *qemu_chr_open(const char *filename) -{ - const char *p; - - if (!strcmp(filename, "vc")) { - return text_console_init(&display_state, 0); - } else if (strstart(filename, "vc:", &p)) { - return text_console_init(&display_state, p); - } else if (!strcmp(filename, "null")) { - return qemu_chr_open_null(); - } else - if (strstart(filename, "tcp:", &p)) { - return qemu_chr_open_tcp(p, 0, 0); - } else - if (strstart(filename, "telnet:", &p)) { - return qemu_chr_open_tcp(p, 1, 0); - } else - if (strstart(filename, "udp:", &p)) { - return qemu_chr_open_udp(p); - } else - if (strstart(filename, "mon:", &p)) { - CharDriverState *drv = qemu_chr_open(p); - if (drv) { - drv = qemu_chr_open_mux(drv); - monitor_init(drv, !nographic); - return drv; - } - printf("Unable to open driver: %s\n", p); - return 0; - } else -#ifndef _WIN32 - if (strstart(filename, "unix:", &p)) { - return qemu_chr_open_tcp(p, 0, 1); - } else if (strstart(filename, "file:", &p)) { - return qemu_chr_open_file_out(p); - } else if (strstart(filename, "pipe:", &p)) { - return qemu_chr_open_pipe(p); - } else if (!strcmp(filename, "pty")) { - return qemu_chr_open_pty(); - } else if (!strcmp(filename, "stdio")) { - return qemu_chr_open_stdio(); - } else -#if defined(__linux__) - if (strstart(filename, "/dev/parport", NULL)) { - return qemu_chr_open_pp(filename); - } else -#endif -#if defined(__linux__) || defined(__sun__) - if (strstart(filename, "/dev/", NULL)) { - return qemu_chr_open_tty(filename); - } else -#endif -#else /* !_WIN32 */ - if (strstart(filename, "COM", NULL)) { - return qemu_chr_open_win(filename); - } else - if (strstart(filename, "pipe:", &p)) { - return qemu_chr_open_win_pipe(p); - } else - if (strstart(filename, "con:", NULL)) { - return qemu_chr_open_win_con(filename); - } else - if (strstart(filename, "file:", &p)) { - return qemu_chr_open_win_file_out(p); - } -#endif - { - return NULL; - } -} - -void qemu_chr_close(CharDriverState *chr) -{ - if (chr->chr_close) - chr->chr_close(chr); -} - -/***********************************************************/ -/* network device redirectors */ - -__attribute__ (( unused )) -static void hex_dump(FILE *f, const uint8_t *buf, int size) -{ - int len, i, j, c; - - for(i=0;i 16) - len = 16; - fprintf(f, "%08x ", i); - for(j=0;j<16;j++) { - if (j < len) - fprintf(f, " %02x", buf[i+j]); - else - fprintf(f, " "); - } - fprintf(f, " "); - for(j=0;j '~') - c = '.'; - fprintf(f, "%c", c); - } - fprintf(f, "\n"); - } -} - -static int parse_macaddr(uint8_t *macaddr, const char *p) -{ - int i; - char *last_char; - long int offset; - - errno = 0; - offset = strtol(p, &last_char, 0); - if (0 == errno && '\0' == *last_char && - offset >= 0 && offset <= 0xFFFFFF) { - macaddr[3] = (offset & 0xFF0000) >> 16; - macaddr[4] = (offset & 0xFF00) >> 8; - macaddr[5] = offset & 0xFF; - return 0; - } else { - for(i = 0; i < 6; i++) { - macaddr[i] = strtol(p, (char **)&p, 16); - if (i == 5) { - if (*p != '\0') - return -1; - } else { - if (*p != ':' && *p != '-') - return -1; - p++; - } - } - return 0; - } - - return -1; -} - -static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) -{ - const char *p, *p1; - int len; - p = *pp; - p1 = strchr(p, sep); - if (!p1) - return -1; - len = p1 - p; - p1++; - if (buf_size > 0) { - if (len > buf_size - 1) - len = buf_size - 1; - memcpy(buf, p, len); - buf[len] = '\0'; - } - *pp = p1; - return 0; -} - -int parse_host_src_port(struct sockaddr_in *haddr, - struct sockaddr_in *saddr, - const char *input_str) -{ - char *str = strdup(input_str); - char *host_str = str; - char *src_str; - char *ptr; - - /* - * Chop off any extra arguments at the end of the string which - * would start with a comma, then fill in the src port information - * if it was provided else use the "any address" and "any port". - */ - if ((ptr = strchr(str,','))) - *ptr = '\0'; - - if ((src_str = strchr(input_str,'@'))) { - *src_str = '\0'; - src_str++; - } - - if (parse_host_port(haddr, host_str) < 0) - goto fail; - - if (!src_str || *src_str == '\0') - src_str = ":0"; - - if (parse_host_port(saddr, src_str) < 0) - goto fail; - - free(str); - return(0); - -fail: - free(str); - return -1; -} - -int parse_host_port(struct sockaddr_in *saddr, const char *str) -{ - char buf[512]; - struct hostent *he; - const char *p, *r; - int port; - - p = str; - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) - return -1; - saddr->sin_family = AF_INET; - if (buf[0] == '\0') { - saddr->sin_addr.s_addr = 0; - } else { - if (isdigit(buf[0])) { - if (!inet_aton(buf, &saddr->sin_addr)) - return -1; - } else { - if ((he = gethostbyname(buf)) == NULL) - return - 1; - saddr->sin_addr = *(struct in_addr *)he->h_addr; - } - } - port = strtol(p, (char **)&r, 0); - if (r == p) - return -1; - saddr->sin_port = htons(port); - return 0; -} - -#ifndef _WIN32 -static int parse_unix_path(struct sockaddr_un *uaddr, const char *str) -{ - const char *p; - int len; - - len = MIN(108, strlen(str)); - p = strchr(str, ','); - if (p) - len = MIN(len, p - str); - - memset(uaddr, 0, sizeof(*uaddr)); - - uaddr->sun_family = AF_UNIX; - memcpy(uaddr->sun_path, str, len); - - return 0; -} -#endif - -/* find or alloc a new VLAN */ -VLANState *qemu_find_vlan(int id) -{ - VLANState **pvlan, *vlan; - for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { - if (vlan->id == id) - return vlan; - } - vlan = qemu_mallocz(sizeof(VLANState)); - if (!vlan) - return NULL; - vlan->id = id; - vlan->next = NULL; - pvlan = &first_vlan; - while (*pvlan != NULL) - pvlan = &(*pvlan)->next; - *pvlan = vlan; - return vlan; -} - -VLANClientState *qemu_new_vlan_client(VLANState *vlan, - IOReadHandler *fd_read, - IOCanRWHandler *fd_can_read, - void *opaque) -{ - VLANClientState *vc, **pvc; - vc = qemu_mallocz(sizeof(VLANClientState)); - if (!vc) - return NULL; - vc->fd_read = fd_read; - vc->fd_can_read = fd_can_read; - vc->opaque = opaque; - vc->vlan = vlan; - - vc->next = NULL; - pvc = &vlan->first_client; - while (*pvc != NULL) - pvc = &(*pvc)->next; - *pvc = vc; - return vc; -} - -int qemu_can_send_packet(VLANClientState *vc1) -{ - VLANState *vlan = vc1->vlan; - VLANClientState *vc; - - for(vc = vlan->first_client; vc != NULL; vc = vc->next) { - if (vc != vc1) { - if (vc->fd_can_read && vc->fd_can_read(vc->opaque)) - return 1; - } - } - return 0; -} - -void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size) -{ - VLANState *vlan = vc1->vlan; - VLANClientState *vc; - -#if 0 - printf("vlan %d send:\n", vlan->id); - hex_dump(stdout, buf, size); -#endif - for(vc = vlan->first_client; vc != NULL; vc = vc->next) { - if (vc != vc1) { - vc->fd_read(vc->opaque, buf, size); - } - } -} - -#if defined(CONFIG_SLIRP) - -/* slirp network adapter */ - -static int slirp_inited; -static VLANClientState *slirp_vc; - -int slirp_can_output(void) -{ - return !slirp_vc || qemu_can_send_packet(slirp_vc); -} - -void slirp_output(const uint8_t *pkt, int pkt_len) -{ -#if 0 - printf("slirp output:\n"); - hex_dump(stdout, pkt, pkt_len); -#endif - if (!slirp_vc) - return; - qemu_send_packet(slirp_vc, pkt, pkt_len); -} - -static void slirp_receive(void *opaque, const uint8_t *buf, int size) -{ -#if 0 - printf("slirp input:\n"); - hex_dump(stdout, buf, size); -#endif - slirp_input(buf, size); -} - -static int net_slirp_init(VLANState *vlan) -{ - if (!slirp_inited) { - slirp_inited = 1; - slirp_init(); - } - slirp_vc = qemu_new_vlan_client(vlan, - slirp_receive, NULL, NULL); - snprintf(slirp_vc->info_str, sizeof(slirp_vc->info_str), "user redirector"); - return 0; -} - -static void net_slirp_redir(const char *redir_str) -{ - int is_udp; - char buf[256], *r; - const char *p; - struct in_addr guest_addr; - int host_port, guest_port; - - if (!slirp_inited) { - slirp_inited = 1; - slirp_init(); - } - - p = redir_str; - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) - goto fail; - if (!strcmp(buf, "tcp")) { - is_udp = 0; - } else if (!strcmp(buf, "udp")) { - is_udp = 1; - } else { - goto fail; - } - - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) - goto fail; - host_port = strtol(buf, &r, 0); - if (r == buf) - goto fail; - - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) - goto fail; - if (buf[0] == '\0') { - pstrcpy(buf, sizeof(buf), "10.0.2.15"); - } - if (!inet_aton(buf, &guest_addr)) - goto fail; - - guest_port = strtol(p, &r, 0); - if (r == p) - goto fail; - - if (slirp_redir(is_udp, host_port, guest_addr, guest_port) < 0) { - fprintf(stderr, "qemu: could not set up redirection\n"); - exit(1); - } - return; - fail: - fprintf(stderr, "qemu: syntax: -redir [tcp|udp]:host-port:[guest-host]:guest-port\n"); - exit(1); -} - -#ifndef _WIN32 - -char smb_dir[1024]; - -static void smb_exit(void) -{ - DIR *d; - struct dirent *de; - char filename[1024]; - - /* erase all the files in the directory */ - d = opendir(smb_dir); - for(;;) { - de = readdir(d); - if (!de) - break; - if (strcmp(de->d_name, ".") != 0 && - strcmp(de->d_name, "..") != 0) { - snprintf(filename, sizeof(filename), "%s/%s", - smb_dir, de->d_name); - unlink(filename); - } - } - closedir(d); - rmdir(smb_dir); -} - -/* automatic user mode samba server configuration */ -static void net_slirp_smb(const char *exported_dir) -{ - char smb_conf[1024]; - char smb_cmdline[1024]; - FILE *f; - - if (!slirp_inited) { - slirp_inited = 1; - slirp_init(); - } - - /* XXX: better tmp dir construction */ - snprintf(smb_dir, sizeof(smb_dir), "/tmp/qemu-smb.%d", getpid()); - if (mkdir(smb_dir, 0700) < 0) { - fprintf(stderr, "qemu: could not create samba server dir '%s'\n", smb_dir); - exit(1); - } - snprintf(smb_conf, sizeof(smb_conf), "%s/%s", smb_dir, "smb.conf"); - - f = fopen(smb_conf, "w"); - if (!f) { - fprintf(stderr, "qemu: could not create samba server configuration file '%s'\n", smb_conf); - exit(1); - } - fprintf(f, - "[global]\n" - "private dir=%s\n" - "smb ports=0\n" - "socket address=127.0.0.1\n" - "pid directory=%s\n" - "lock directory=%s\n" - "log file=%s/log.smbd\n" - "smb passwd file=%s/smbpasswd\n" - "security = share\n" - "[qemu]\n" - "path=%s\n" - "read only=no\n" - "guest ok=yes\n", - smb_dir, - smb_dir, - smb_dir, - smb_dir, - smb_dir, - exported_dir - ); - fclose(f); - atexit(smb_exit); - - snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s", - SMBD_COMMAND, smb_conf); - - slirp_add_exec(0, smb_cmdline, 4, 139); -} - -#endif /* !defined(_WIN32) */ -void do_info_slirp(void) -{ - slirp_stats(); -} - -#endif /* CONFIG_SLIRP */ - -#if !defined(_WIN32) - -typedef struct TAPState { - VLANClientState *vc; - int fd; - char down_script[1024]; -} TAPState; - -static void tap_receive(void *opaque, const uint8_t *buf, int size) -{ - TAPState *s = opaque; - int ret; - for(;;) { - ret = write(s->fd, buf, size); - if (ret < 0 && (errno == EINTR || errno == EAGAIN)) { - } else { - break; - } - } -} - -static void tap_send(void *opaque) -{ - TAPState *s = opaque; - uint8_t buf[4096]; - int size; - -#ifdef __sun__ - struct strbuf sbuf; - int f = 0; - sbuf.maxlen = sizeof(buf); - sbuf.buf = buf; - size = getmsg(s->fd, NULL, &sbuf, &f) >=0 ? sbuf.len : -1; -#else - size = read(s->fd, buf, sizeof(buf)); -#endif - if (size > 0) { - qemu_send_packet(s->vc, buf, size); - } -} - -/* fd support */ - -static TAPState *net_tap_fd_init(VLANState *vlan, int fd) -{ - TAPState *s; - - s = qemu_mallocz(sizeof(TAPState)); - if (!s) - return NULL; - s->fd = fd; - s->vc = qemu_new_vlan_client(vlan, tap_receive, NULL, s); - qemu_set_fd_handler(s->fd, tap_send, NULL, s); - snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: fd=%d", fd); - return s; -} - -#if defined (_BSD) || defined (__FreeBSD_kernel__) -static int tap_open(char *ifname, int ifname_size) -{ - int fd; - char *dev; - struct stat s; - - TFR(fd = open("/dev/tap", O_RDWR)); - if (fd < 0) { - fprintf(stderr, "warning: could not open /dev/tap: no virtual network emulation\n"); - return -1; - } - - fstat(fd, &s); - dev = devname(s.st_rdev, S_IFCHR); - pstrcpy(ifname, ifname_size, dev); - - fcntl(fd, F_SETFL, O_NONBLOCK); - return fd; -} -#elif defined(__sun__) -#define TUNNEWPPA (('T'<<16) | 0x0001) -/* - * Allocate TAP device, returns opened fd. - * Stores dev name in the first arg(must be large enough). - */ -int tap_alloc(char *dev) -{ - int tap_fd, if_fd, ppa = -1; - static int ip_fd = 0; - char *ptr; - - static int arp_fd = 0; - int ip_muxid, arp_muxid; - struct strioctl strioc_if, strioc_ppa; - int link_type = I_PLINK;; - struct lifreq ifr; - char actual_name[32] = ""; - - memset(&ifr, 0x0, sizeof(ifr)); - - if( *dev ){ - ptr = dev; - while( *ptr && !isdigit((int)*ptr) ) ptr++; - ppa = atoi(ptr); - } - - /* Check if IP device was opened */ - if( ip_fd ) - close(ip_fd); - - TFR(ip_fd = open("/dev/udp", O_RDWR, 0)); - if (ip_fd < 0) { - syslog(LOG_ERR, "Can't open /dev/ip (actually /dev/udp)"); - return -1; - } - - TFR(tap_fd = open("/dev/tap", O_RDWR, 0)); - if (tap_fd < 0) { - syslog(LOG_ERR, "Can't open /dev/tap"); - return -1; - } - - /* Assign a new PPA and get its unit number. */ - strioc_ppa.ic_cmd = TUNNEWPPA; - strioc_ppa.ic_timout = 0; - strioc_ppa.ic_len = sizeof(ppa); - strioc_ppa.ic_dp = (char *)&ppa; - if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0) - syslog (LOG_ERR, "Can't assign new interface"); - - TFR(if_fd = open("/dev/tap", O_RDWR, 0)); - if (if_fd < 0) { - syslog(LOG_ERR, "Can't open /dev/tap (2)"); - return -1; - } - if(ioctl(if_fd, I_PUSH, "ip") < 0){ - syslog(LOG_ERR, "Can't push IP module"); - return -1; - } - - if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) - syslog(LOG_ERR, "Can't get flags\n"); - - snprintf (actual_name, 32, "tap%d", ppa); - strncpy (ifr.lifr_name, actual_name, sizeof (ifr.lifr_name)); - - ifr.lifr_ppa = ppa; - /* Assign ppa according to the unit number returned by tun device */ - - if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0) - syslog (LOG_ERR, "Can't set PPA %d", ppa); - if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0) - syslog (LOG_ERR, "Can't get flags\n"); - /* Push arp module to if_fd */ - if (ioctl (if_fd, I_PUSH, "arp") < 0) - syslog (LOG_ERR, "Can't push ARP module (2)"); - - /* Push arp module to ip_fd */ - if (ioctl (ip_fd, I_POP, NULL) < 0) - syslog (LOG_ERR, "I_POP failed\n"); - if (ioctl (ip_fd, I_PUSH, "arp") < 0) - syslog (LOG_ERR, "Can't push ARP module (3)\n"); - /* Open arp_fd */ - TFR(arp_fd = open ("/dev/tap", O_RDWR, 0)); - if (arp_fd < 0) - syslog (LOG_ERR, "Can't open %s\n", "/dev/tap"); - - /* Set ifname to arp */ - strioc_if.ic_cmd = SIOCSLIFNAME; - strioc_if.ic_timout = 0; - strioc_if.ic_len = sizeof(ifr); - strioc_if.ic_dp = (char *)𝔦 - if (ioctl(arp_fd, I_STR, &strioc_if) < 0){ - syslog (LOG_ERR, "Can't set ifname to arp\n"); - } - - if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){ - syslog(LOG_ERR, "Can't link TAP device to IP"); - return -1; - } - - if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0) - syslog (LOG_ERR, "Can't link TAP device to ARP"); - - close (if_fd); - - memset(&ifr, 0x0, sizeof(ifr)); - strncpy (ifr.lifr_name, actual_name, sizeof (ifr.lifr_name)); - ifr.lifr_ip_muxid = ip_muxid; - ifr.lifr_arp_muxid = arp_muxid; - - if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0) - { - ioctl (ip_fd, I_PUNLINK , arp_muxid); - ioctl (ip_fd, I_PUNLINK, ip_muxid); - syslog (LOG_ERR, "Can't set multiplexor id"); - } - - sprintf(dev, "tap%d", ppa); - return tap_fd; -} - -static int tap_open(char *ifname, int ifname_size) -{ - char dev[10]=""; - int fd; - if( (fd = tap_alloc(dev)) < 0 ){ - fprintf(stderr, "Cannot allocate TAP device\n"); - return -1; - } - pstrcpy(ifname, ifname_size, dev); - fcntl(fd, F_SETFL, O_NONBLOCK); - return fd; -} -#else -static int tap_open(char *ifname, int ifname_size) -{ - struct ifreq ifr; - int fd, ret; - - TFR(fd = open("/dev/net/tun", O_RDWR)); - if (fd < 0) { - fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n"); - return -1; - } - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - if (ifname[0] != '\0') - pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname); - else - pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d"); - ret = ioctl(fd, TUNSETIFF, (void *) &ifr); - if (ret != 0) { - fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n"); - close(fd); - return -1; - } - pstrcpy(ifname, ifname_size, ifr.ifr_name); - fcntl(fd, F_SETFL, O_NONBLOCK); - return fd; -} -#endif - -static int launch_script(const char *setup_script, const char *ifname, int fd) -{ - int pid, status; - char *args[3]; - char **parg; - - /* try to launch network script */ - pid = fork(); - if (pid >= 0) { - if (pid == 0) { - int open_max = sysconf (_SC_OPEN_MAX), i; - for (i = 0; i < open_max; i++) - if (i != STDIN_FILENO && - i != STDOUT_FILENO && - i != STDERR_FILENO && - i != fd) - close(i); - - parg = args; - *parg++ = (char *)setup_script; - *parg++ = (char *)ifname; - *parg++ = NULL; - execv(setup_script, args); - _exit(1); - } - while (waitpid(pid, &status, 0) != pid); - if (!WIFEXITED(status) || - WEXITSTATUS(status) != 0) { - fprintf(stderr, "%s: could not launch network script\n", - setup_script); - return -1; - } - } - return 0; -} - -static int net_tap_init(VLANState *vlan, const char *ifname1, - const char *setup_script, const char *down_script) -{ - TAPState *s; - int fd; - char ifname[128]; - - if (ifname1 != NULL) - pstrcpy(ifname, sizeof(ifname), ifname1); - else - ifname[0] = '\0'; - TFR(fd = tap_open(ifname, sizeof(ifname))); - if (fd < 0) - return -1; - - if (!setup_script || !strcmp(setup_script, "no")) - setup_script = ""; - if (setup_script[0] != '\0') { - if (launch_script(setup_script, ifname, fd)) - return -1; - } - s = net_tap_fd_init(vlan, fd); - if (!s) - return -1; - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "tap: ifname=%s setup_script=%s", ifname, setup_script); - if (down_script && strcmp(down_script, "no")) - snprintf(s->down_script, sizeof(s->down_script), "%s", down_script); - return 0; -} - -#endif /* !_WIN32 */ - -/* network connection */ -typedef struct NetSocketState { - VLANClientState *vc; - int fd; - int state; /* 0 = getting length, 1 = getting data */ - int index; - int packet_len; - uint8_t buf[4096]; - struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */ -} NetSocketState; - -typedef struct NetSocketListenState { - VLANState *vlan; - int fd; -} NetSocketListenState; - -/* XXX: we consider we can send the whole packet without blocking */ -static void net_socket_receive(void *opaque, const uint8_t *buf, int size) -{ - NetSocketState *s = opaque; - uint32_t len; - len = htonl(size); - - send_all(s->fd, (const uint8_t *)&len, sizeof(len)); - send_all(s->fd, buf, size); -} - -static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size) -{ - NetSocketState *s = opaque; - sendto(s->fd, buf, size, 0, - (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst)); -} - -static void net_socket_send(void *opaque) -{ - NetSocketState *s = opaque; - int l, size, err; - uint8_t buf1[4096]; - const uint8_t *buf; - - size = recv(s->fd, buf1, sizeof(buf1), 0); - if (size < 0) { - err = socket_error(); - if (err != EWOULDBLOCK) - goto eoc; - } else if (size == 0) { - /* end of connection */ - eoc: - qemu_set_fd_handler(s->fd, NULL, NULL, NULL); - closesocket(s->fd); - return; - } - buf = buf1; - while (size > 0) { - /* reassemble a packet from the network */ - switch(s->state) { - case 0: - l = 4 - s->index; - if (l > size) - l = size; - memcpy(s->buf + s->index, buf, l); - buf += l; - size -= l; - s->index += l; - if (s->index == 4) { - /* got length */ - s->packet_len = ntohl(*(uint32_t *)s->buf); - s->index = 0; - s->state = 1; - } - break; - case 1: - l = s->packet_len - s->index; - if (l > size) - l = size; - memcpy(s->buf + s->index, buf, l); - s->index += l; - buf += l; - size -= l; - if (s->index >= s->packet_len) { - qemu_send_packet(s->vc, s->buf, s->packet_len); - s->index = 0; - s->state = 0; - } - break; - } - } -} - -static void net_socket_send_dgram(void *opaque) -{ - NetSocketState *s = opaque; - int size; - - size = recv(s->fd, s->buf, sizeof(s->buf), 0); - if (size < 0) - return; - if (size == 0) { - /* end of connection */ - qemu_set_fd_handler(s->fd, NULL, NULL, NULL); - return; - } - qemu_send_packet(s->vc, s->buf, size); -} - -static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) -{ - struct ip_mreq imr; - int fd; - int val, ret; - if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) { - fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n", - inet_ntoa(mcastaddr->sin_addr), - (int)ntohl(mcastaddr->sin_addr.s_addr)); - return -1; - - } - fd = socket(PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - perror("socket(PF_INET, SOCK_DGRAM)"); - return -1; - } - - val = 1; - ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, - (const char *)&val, sizeof(val)); - if (ret < 0) { - perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); - goto fail; - } - - ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr)); - if (ret < 0) { - perror("bind"); - goto fail; - } - - /* Add host to multicast group */ - imr.imr_multiaddr = mcastaddr->sin_addr; - imr.imr_interface.s_addr = htonl(INADDR_ANY); - - ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (const char *)&imr, sizeof(struct ip_mreq)); - if (ret < 0) { - perror("setsockopt(IP_ADD_MEMBERSHIP)"); - goto fail; - } - - /* Force mcast msgs to loopback (eg. several QEMUs in same host */ - val = 1; - ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, - (const char *)&val, sizeof(val)); - if (ret < 0) { - perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)"); - goto fail; - } - - socket_set_nonblock(fd); - return fd; -fail: - if (fd >= 0) - closesocket(fd); - return -1; -} - -static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd, - int is_connected) -{ - struct sockaddr_in saddr; - int newfd; - socklen_t saddr_len; - NetSocketState *s; - - /* fd passed: multicast: "learn" dgram_dst address from bound address and save it - * Because this may be "shared" socket from a "master" process, datagrams would be recv() - * by ONLY ONE process: we must "clone" this dgram socket --jjo - */ - - if (is_connected) { - if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) { - /* must be bound */ - if (saddr.sin_addr.s_addr==0) { - fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n", - fd); - return NULL; - } - /* clone dgram socket */ - newfd = net_socket_mcast_create(&saddr); - if (newfd < 0) { - /* error already reported by net_socket_mcast_create() */ - close(fd); - return NULL; - } - /* clone newfd to fd, close newfd */ - dup2(newfd, fd); - close(newfd); - - } else { - fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n", - fd, strerror(errno)); - return NULL; - } - } - - s = qemu_mallocz(sizeof(NetSocketState)); - if (!s) - return NULL; - s->fd = fd; - - s->vc = qemu_new_vlan_client(vlan, net_socket_receive_dgram, NULL, s); - qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s); - - /* mcast: save bound address as dst */ - if (is_connected) s->dgram_dst=saddr; - - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "socket: fd=%d (%s mcast=%s:%d)", - fd, is_connected? "cloned" : "", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); - return s; -} - -static void net_socket_connect(void *opaque) -{ - NetSocketState *s = opaque; - qemu_set_fd_handler(s->fd, net_socket_send, NULL, s); -} - -static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd, - int is_connected) -{ - NetSocketState *s; - s = qemu_mallocz(sizeof(NetSocketState)); - if (!s) - return NULL; - s->fd = fd; - s->vc = qemu_new_vlan_client(vlan, - net_socket_receive, NULL, s); - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "socket: fd=%d", fd); - if (is_connected) { - net_socket_connect(s); - } else { - qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s); - } - return s; -} - -static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd, - int is_connected) -{ - int so_type=-1, optlen=sizeof(so_type); - - if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, - (socklen_t *)&optlen)< 0) { - fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd); - return NULL; - } - switch(so_type) { - case SOCK_DGRAM: - return net_socket_fd_init_dgram(vlan, fd, is_connected); - case SOCK_STREAM: - return net_socket_fd_init_stream(vlan, fd, is_connected); - default: - /* who knows ... this could be a eg. a pty, do warn and continue as stream */ - fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd); - return net_socket_fd_init_stream(vlan, fd, is_connected); - } - return NULL; -} - -static void net_socket_accept(void *opaque) -{ - NetSocketListenState *s = opaque; - NetSocketState *s1; - struct sockaddr_in saddr; - socklen_t len; - int fd; - - for(;;) { - len = sizeof(saddr); - fd = accept(s->fd, (struct sockaddr *)&saddr, &len); - if (fd < 0 && errno != EINTR) { - return; - } else if (fd >= 0) { - break; - } - } - s1 = net_socket_fd_init(s->vlan, fd, 1); - if (!s1) { - closesocket(fd); - } else { - snprintf(s1->vc->info_str, sizeof(s1->vc->info_str), - "socket: connection from %s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); - } -} - -static int net_socket_listen_init(VLANState *vlan, const char *host_str) -{ - NetSocketListenState *s; - int fd, val, ret; - struct sockaddr_in saddr; - - if (parse_host_port(&saddr, host_str) < 0) - return -1; - - s = qemu_mallocz(sizeof(NetSocketListenState)); - if (!s) - return -1; - - fd = socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - perror("socket"); - return -1; - } - socket_set_nonblock(fd); - - /* allow fast reuse */ - val = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); - - ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); - if (ret < 0) { - perror("bind"); - return -1; - } - ret = listen(fd, 0); - if (ret < 0) { - perror("listen"); - return -1; - } - s->vlan = vlan; - s->fd = fd; - qemu_set_fd_handler(fd, net_socket_accept, NULL, s); - return 0; -} - -static int net_socket_connect_init(VLANState *vlan, const char *host_str) -{ - NetSocketState *s; - int fd, connected, ret, err; - struct sockaddr_in saddr; - - if (parse_host_port(&saddr, host_str) < 0) - return -1; - - fd = socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - perror("socket"); - return -1; - } - socket_set_nonblock(fd); - - connected = 0; - for(;;) { - ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); - if (ret < 0) { - err = socket_error(); - if (err == EINTR || err == EWOULDBLOCK) { - } else if (err == EINPROGRESS) { - break; -#ifdef _WIN32 - } else if (err == WSAEALREADY) { - break; -#endif - } else { - perror("connect"); - closesocket(fd); - return -1; - } - } else { - connected = 1; - break; - } - } - s = net_socket_fd_init(vlan, fd, connected); - if (!s) - return -1; - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "socket: connect to %s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); - return 0; -} - -static int net_socket_mcast_init(VLANState *vlan, const char *host_str) -{ - NetSocketState *s; - int fd; - struct sockaddr_in saddr; - - if (parse_host_port(&saddr, host_str) < 0) - return -1; - - - fd = net_socket_mcast_create(&saddr); - if (fd < 0) - return -1; - - s = net_socket_fd_init(vlan, fd, 0); - if (!s) - return -1; - - s->dgram_dst = saddr; - - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "socket: mcast=%s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); - return 0; - -} - -static const char *get_word(char *buf, int buf_size, const char *p) -{ - char *q; - int substring; - - substring = 0; - q = buf; - while (*p != '\0') { - if (*p == '\\') { - p++; - if (*p == '\0') - break; - } else if (*p == '\"') { - substring = !substring; - p++; - continue; - } else if (!substring && (*p == ',' || *p == '=')) - break; - if (q && (q - buf) < buf_size - 1) - *q++ = *p; - p++; - } - if (q) - *q = '\0'; - - return p; -} - -static int get_param_value(char *buf, int buf_size, - const char *tag, const char *str) -{ - const char *p; - char option[128]; - - p = str; - for(;;) { - p = get_word(option, sizeof(option), p); - if (*p != '=') - break; - p++; - if (!strcmp(tag, option)) { - (void)get_word(buf, buf_size, p); - return strlen(buf); - } else { - p = get_word(NULL, 0, p); - } - if (*p != ',') - break; - p++; - } - return 0; -} - -static int check_params(char *buf, int buf_size, - char **params, const char *str) -{ - const char *p; - int i; - - p = str; - for(;;) { - p = get_word(buf, buf_size, p); - if (*p != '=') - return -1; - p++; - for(i = 0; params[i] != NULL; i++) - if (!strcmp(params[i], buf)) - break; - if (params[i] == NULL) - return -1; - p = get_word(NULL, 0, p); - if (*p != ',') - break; - p++; - } - return 0; -} - - -static int net_client_init(const char *str) -{ - const char *p; - char *q; - char device[64]; - char buf[1024]; - int vlan_id, ret; - VLANState *vlan; - - p = str; - q = device; - while (*p != '\0' && *p != ',') { - if ((q - device) < sizeof(device) - 1) - *q++ = *p; - p++; - } - *q = '\0'; - if (*p == ',') - p++; - vlan_id = 0; - if (get_param_value(buf, sizeof(buf), "vlan", p)) { - vlan_id = strtol(buf, NULL, 0); - } - vlan = qemu_find_vlan(vlan_id); - if (!vlan) { - fprintf(stderr, "Could not create vlan %d\n", vlan_id); - return -1; - } - if (!strcmp(device, "nic")) { - NICInfo *nd; - uint8_t *macaddr; - - if (nb_nics >= MAX_NICS) { - fprintf(stderr, "Too Many NICs\n"); - return -1; - } - nd = &nd_table[nb_nics]; - macaddr = nd->macaddr; - macaddr[0] = 0x52; - macaddr[1] = 0x54; - macaddr[2] = 0x00; - macaddr[3] = 0x12; - macaddr[4] = 0x34; - macaddr[5] = 0x56 + nb_nics; - - if (get_param_value(buf, sizeof(buf), "macaddr", p)) { - if (parse_macaddr(macaddr, buf) < 0) { - fprintf(stderr, "invalid syntax for ethernet address\n"); - return -1; - } - } - if (get_param_value(buf, sizeof(buf), "model", p)) { - nd->model = strdup(buf); - } - nd->vlan = vlan; - nb_nics++; - vlan->nb_guest_devs++; - ret = 0; - } else - if (!strcmp(device, "none")) { - /* does nothing. It is needed to signal that no network cards - are wanted */ - ret = 0; - } else -#ifdef CONFIG_SLIRP - if (!strcmp(device, "user")) { - if (get_param_value(buf, sizeof(buf), "hostname", p)) { - pstrcpy(slirp_hostname, sizeof(slirp_hostname), buf); - } - vlan->nb_host_devs++; - ret = net_slirp_init(vlan); - } else -#endif -#ifdef _WIN32 - if (!strcmp(device, "tap")) { - char ifname[64]; - if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) { - fprintf(stderr, "tap: no interface name\n"); - return -1; - } - vlan->nb_host_devs++; - ret = tap_win32_init(vlan, ifname); - } else -#else - if (!strcmp(device, "tap")) { - char ifname[64]; - char setup_script[1024], down_script[1024]; - int fd; - vlan->nb_host_devs++; - if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { - fd = strtol(buf, NULL, 0); - ret = -1; - if (net_tap_fd_init(vlan, fd)) - ret = 0; - } else { - if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) { - ifname[0] = '\0'; - } - if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) { - pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT); - } - if (get_param_value(down_script, sizeof(down_script), "downscript", p) == 0) { - pstrcpy(down_script, sizeof(down_script), DEFAULT_NETWORK_DOWN_SCRIPT); - } - ret = net_tap_init(vlan, ifname, setup_script, down_script); - } - } else -#endif - if (!strcmp(device, "socket")) { - if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { - int fd; - fd = strtol(buf, NULL, 0); - ret = -1; - if (net_socket_fd_init(vlan, fd, 1)) - ret = 0; - } else if (get_param_value(buf, sizeof(buf), "listen", p) > 0) { - ret = net_socket_listen_init(vlan, buf); - } else if (get_param_value(buf, sizeof(buf), "connect", p) > 0) { - ret = net_socket_connect_init(vlan, buf); - } else if (get_param_value(buf, sizeof(buf), "mcast", p) > 0) { - ret = net_socket_mcast_init(vlan, buf); - } else { - fprintf(stderr, "Unknown socket options: %s\n", p); - return -1; - } - vlan->nb_host_devs++; - } else - { - fprintf(stderr, "Unknown network device: %s\n", device); - return -1; - } - if (ret < 0) { - fprintf(stderr, "Could not initialize device '%s'\n", device); - } - - return ret; -} - -void do_info_network(void) -{ - VLANState *vlan; - VLANClientState *vc; - - for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { - term_printf("VLAN %d devices:\n", vlan->id); - for(vc = vlan->first_client; vc != NULL; vc = vc->next) - term_printf(" %s\n", vc->info_str); - } -} - -#define HD_ALIAS "file=\"%s\",index=%d,media=disk" -#ifdef TARGET_PPC -#define CDROM_ALIAS "index=1,media=cdrom" -#else -#define CDROM_ALIAS "index=2,media=cdrom" -#endif -#define FD_ALIAS "index=%d,if=floppy" -#define PFLASH_ALIAS "file=\"%s\",if=pflash" -#define MTD_ALIAS "file=\"%s\",if=mtd" -#define SD_ALIAS "index=0,if=sd" - -static int drive_add(const char *fmt, ...) -{ - va_list ap; - - if (nb_drives_opt >= MAX_DRIVES) { - fprintf(stderr, "qemu: too many drives\n"); - exit(1); - } - - va_start(ap, fmt); - vsnprintf(drives_opt[nb_drives_opt], sizeof(drives_opt[0]), fmt, ap); - va_end(ap); - - return nb_drives_opt++; -} - -int drive_get_index(BlockInterfaceType type, int bus, int unit) -{ - int index; - - /* seek interface, bus and unit */ - - for (index = 0; index < nb_drives; index++) - if (drives_table[index].type == type && - drives_table[index].bus == bus && - drives_table[index].unit == unit) - return index; - - return -1; -} - -int drive_get_max_bus(BlockInterfaceType type) -{ - int max_bus; - int index; - - max_bus = -1; - for (index = 0; index < nb_drives; index++) { - if(drives_table[index].type == type && - drives_table[index].bus > max_bus) - max_bus = drives_table[index].bus; - } - return max_bus; -} - -static int drive_init(const char *str, int snapshot, QEMUMachine *machine) -{ - char buf[128]; - char file[1024]; - char devname[128]; - const char *mediastr = ""; - BlockInterfaceType type; - enum { MEDIA_DISK, MEDIA_CDROM } media; - int bus_id, unit_id; - int cyls, heads, secs, translation; - BlockDriverState *bdrv; - int max_devs; - int index; - int cache; - int bdrv_flags; - char *params[] = { "bus", "unit", "if", "index", "cyls", "heads", - "secs", "trans", "media", "snapshot", "file", - "cache", NULL }; - - if (check_params(buf, sizeof(buf), params, str) < 0) { - fprintf(stderr, "qemu: unknowm parameter '%s' in '%s'\n", - buf, str); - return -1; - } - - file[0] = 0; - cyls = heads = secs = 0; - bus_id = 0; - unit_id = -1; - translation = BIOS_ATA_TRANSLATION_AUTO; - index = -1; - cache = 1; - - if (!strcmp(machine->name, "realview") || - !strcmp(machine->name, "SS-5") || - !strcmp(machine->name, "SS-10") || - !strcmp(machine->name, "SS-600MP") || - !strcmp(machine->name, "versatilepb") || - !strcmp(machine->name, "versatileab")) { - type = IF_SCSI; - max_devs = MAX_SCSI_DEVS; - strcpy(devname, "scsi"); - } else { - type = IF_IDE; - max_devs = MAX_IDE_DEVS; - strcpy(devname, "ide"); - } - media = MEDIA_DISK; - - /* extract parameters */ - - if (get_param_value(buf, sizeof(buf), "bus", str)) { - bus_id = strtol(buf, NULL, 0); - if (bus_id < 0) { - fprintf(stderr, "qemu: '%s' invalid bus id\n", str); - return -1; - } - } - - if (get_param_value(buf, sizeof(buf), "unit", str)) { - unit_id = strtol(buf, NULL, 0); - if (unit_id < 0) { - fprintf(stderr, "qemu: '%s' invalid unit id\n", str); - return -1; - } - } - - if (get_param_value(buf, sizeof(buf), "if", str)) { - strncpy(devname, buf, sizeof(devname)); - if (!strcmp(buf, "ide")) { - type = IF_IDE; - max_devs = MAX_IDE_DEVS; - } else if (!strcmp(buf, "scsi")) { - type = IF_SCSI; - max_devs = MAX_SCSI_DEVS; - } else if (!strcmp(buf, "floppy")) { - type = IF_FLOPPY; - max_devs = 0; - } else if (!strcmp(buf, "pflash")) { - type = IF_PFLASH; - max_devs = 0; - } else if (!strcmp(buf, "mtd")) { - type = IF_MTD; - max_devs = 0; - } else if (!strcmp(buf, "sd")) { - type = IF_SD; - max_devs = 0; - } else { - fprintf(stderr, "qemu: '%s' unsupported bus type '%s'\n", str, buf); - return -1; - } - } - - if (get_param_value(buf, sizeof(buf), "index", str)) { - index = strtol(buf, NULL, 0); - if (index < 0) { - fprintf(stderr, "qemu: '%s' invalid index\n", str); - return -1; - } - } - - if (get_param_value(buf, sizeof(buf), "cyls", str)) { - cyls = strtol(buf, NULL, 0); - } - - if (get_param_value(buf, sizeof(buf), "heads", str)) { - heads = strtol(buf, NULL, 0); - } - - if (get_param_value(buf, sizeof(buf), "secs", str)) { - secs = strtol(buf, NULL, 0); - } - - if (cyls || heads || secs) { - if (cyls < 1 || cyls > 16383) { - fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", str); - return -1; - } - if (heads < 1 || heads > 16) { - fprintf(stderr, "qemu: '%s' invalid physical heads number\n", str); - return -1; - } - if (secs < 1 || secs > 63) { - fprintf(stderr, "qemu: '%s' invalid physical secs number\n", str); - return -1; - } - } - - if (get_param_value(buf, sizeof(buf), "trans", str)) { - if (!cyls) { - fprintf(stderr, - "qemu: '%s' trans must be used with cyls,heads and secs\n", - str); - return -1; - } - if (!strcmp(buf, "none")) - translation = BIOS_ATA_TRANSLATION_NONE; - else if (!strcmp(buf, "lba")) - translation = BIOS_ATA_TRANSLATION_LBA; - else if (!strcmp(buf, "auto")) - translation = BIOS_ATA_TRANSLATION_AUTO; - else { - fprintf(stderr, "qemu: '%s' invalid translation type\n", str); - return -1; - } - } - - if (get_param_value(buf, sizeof(buf), "media", str)) { - if (!strcmp(buf, "disk")) { - media = MEDIA_DISK; - } else if (!strcmp(buf, "cdrom")) { - if (cyls || secs || heads) { - fprintf(stderr, - "qemu: '%s' invalid physical CHS format\n", str); - return -1; - } - media = MEDIA_CDROM; - } else { - fprintf(stderr, "qemu: '%s' invalid media\n", str); - return -1; - } - } - - if (get_param_value(buf, sizeof(buf), "snapshot", str)) { - if (!strcmp(buf, "on")) - snapshot = 1; - else if (!strcmp(buf, "off")) - snapshot = 0; - else { - fprintf(stderr, "qemu: '%s' invalid snapshot option\n", str); - return -1; - } - } - - if (get_param_value(buf, sizeof(buf), "cache", str)) { - if (!strcmp(buf, "off")) - cache = 0; - else if (!strcmp(buf, "on")) - cache = 1; - else { - fprintf(stderr, "qemu: invalid cache option\n"); - return -1; - } - } - - get_param_value(file, sizeof(file), "file", str); - - /* compute bus and unit according index */ - - if (index != -1) { - if (bus_id != 0 || unit_id != -1) { - fprintf(stderr, - "qemu: '%s' index cannot be used with bus and unit\n", str); - return -1; - } - if (max_devs == 0) - { - unit_id = index; - bus_id = 0; - } else { - unit_id = index % max_devs; - bus_id = index / max_devs; - } - } - - /* if user doesn't specify a unit_id, - * try to find the first free - */ - - if (unit_id == -1) { - unit_id = 0; - while (drive_get_index(type, bus_id, unit_id) != -1) { - unit_id++; - if (max_devs && unit_id >= max_devs) { - unit_id -= max_devs; - bus_id++; - } - } - } - - /* check unit id */ - - if (max_devs && unit_id >= max_devs) { - fprintf(stderr, "qemu: '%s' unit %d too big (max is %d)\n", - str, unit_id, max_devs - 1); - return -1; - } - - /* - * ignore multiple definitions - */ - - if (drive_get_index(type, bus_id, unit_id) != -1) - return 0; - - /* init */ - - if (type == IF_IDE || type == IF_SCSI) - mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd"; - if (max_devs) - snprintf(buf, sizeof(buf), "%s%i%s%i", - devname, bus_id, mediastr, unit_id); - else - snprintf(buf, sizeof(buf), "%s%s%i", - devname, mediastr, unit_id); - bdrv = bdrv_new(buf); - drives_table[nb_drives].bdrv = bdrv; - drives_table[nb_drives].type = type; - drives_table[nb_drives].bus = bus_id; - drives_table[nb_drives].unit = unit_id; - nb_drives++; - - switch(type) { - case IF_IDE: - case IF_SCSI: - switch(media) { - case MEDIA_DISK: - if (cyls != 0) { - bdrv_set_geometry_hint(bdrv, cyls, heads, secs); - bdrv_set_translation_hint(bdrv, translation); - } - break; - case MEDIA_CDROM: - bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM); - break; - } - break; - case IF_SD: - /* FIXME: This isn't really a floppy, but it's a reasonable - approximation. */ - case IF_FLOPPY: - bdrv_set_type_hint(bdrv, BDRV_TYPE_FLOPPY); - break; - case IF_PFLASH: - case IF_MTD: - break; - } - if (!file[0]) - return 0; - bdrv_flags = 0; - if (snapshot) - bdrv_flags |= BDRV_O_SNAPSHOT; - if (!cache) - bdrv_flags |= BDRV_O_DIRECT; - if (bdrv_open(bdrv, file, bdrv_flags) < 0 || qemu_key_check(bdrv, file)) { - fprintf(stderr, "qemu: could not open disk image %s\n", - file); - return -1; - } - return 0; -} - -/***********************************************************/ -/* USB devices */ - -static USBPort *used_usb_ports; -static USBPort *free_usb_ports; - -/* ??? Maybe change this to register a hub to keep track of the topology. */ -void qemu_register_usb_port(USBPort *port, void *opaque, int index, - usb_attachfn attach) -{ - port->opaque = opaque; - port->index = index; - port->attach = attach; - port->next = free_usb_ports; - free_usb_ports = port; -} - -static int usb_device_add(const char *devname) -{ - const char *p; - USBDevice *dev; - USBPort *port; - - if (!free_usb_ports) - return -1; - - if (strstart(devname, "host:", &p)) { - dev = usb_host_device_open(p); - } else if (!strcmp(devname, "mouse")) { - dev = usb_mouse_init(); - } else if (!strcmp(devname, "tablet")) { - dev = usb_tablet_init(); - } else if (!strcmp(devname, "keyboard")) { - dev = usb_keyboard_init(); - } else if (strstart(devname, "disk:", &p)) { - dev = usb_msd_init(p); - } else if (!strcmp(devname, "wacom-tablet")) { - dev = usb_wacom_init(); - } else { - return -1; - } - if (!dev) - return -1; - - /* Find a USB port to add the device to. */ - port = free_usb_ports; - if (!port->next) { - USBDevice *hub; - - /* Create a new hub and chain it on. */ - free_usb_ports = NULL; - port->next = used_usb_ports; - used_usb_ports = port; - - hub = usb_hub_init(VM_USB_HUB_SIZE); - usb_attach(port, hub); - port = free_usb_ports; - } - - free_usb_ports = port->next; - port->next = used_usb_ports; - used_usb_ports = port; - usb_attach(port, dev); - return 0; -} - -static int usb_device_del(const char *devname) -{ - USBPort *port; - USBPort **lastp; - USBDevice *dev; - int bus_num, addr; - const char *p; - - if (!used_usb_ports) - return -1; - - p = strchr(devname, '.'); - if (!p) - return -1; - bus_num = strtoul(devname, NULL, 0); - addr = strtoul(p + 1, NULL, 0); - if (bus_num != 0) - return -1; - - lastp = &used_usb_ports; - port = used_usb_ports; - while (port && port->dev->addr != addr) { - lastp = &port->next; - port = port->next; - } - - if (!port) - return -1; - - dev = port->dev; - *lastp = port->next; - usb_attach(port, NULL); - dev->handle_destroy(dev); - port->next = free_usb_ports; - free_usb_ports = port; - return 0; -} - -void do_usb_add(const char *devname) -{ - int ret; - ret = usb_device_add(devname); - if (ret < 0) - term_printf("Could not add USB device '%s'\n", devname); -} - -void do_usb_del(const char *devname) -{ - int ret; - ret = usb_device_del(devname); - if (ret < 0) - term_printf("Could not remove USB device '%s'\n", devname); -} - -void usb_info(void) -{ - USBDevice *dev; - USBPort *port; - const char *speed_str; - - if (!usb_enabled) { - term_printf("USB support not enabled\n"); - return; - } - - for (port = used_usb_ports; port; port = port->next) { - dev = port->dev; - if (!dev) - continue; - switch(dev->speed) { - case USB_SPEED_LOW: - speed_str = "1.5"; - break; - case USB_SPEED_FULL: - speed_str = "12"; - break; - case USB_SPEED_HIGH: - speed_str = "480"; - break; - default: - speed_str = "?"; - break; - } - term_printf(" Device %d.%d, Speed %s Mb/s, Product %s\n", - 0, dev->addr, speed_str, dev->devname); - } -} - -/***********************************************************/ -/* PCMCIA/Cardbus */ - -static struct pcmcia_socket_entry_s { - struct pcmcia_socket_s *socket; - struct pcmcia_socket_entry_s *next; -} *pcmcia_sockets = 0; - -void pcmcia_socket_register(struct pcmcia_socket_s *socket) -{ - struct pcmcia_socket_entry_s *entry; - - entry = qemu_malloc(sizeof(struct pcmcia_socket_entry_s)); - entry->socket = socket; - entry->next = pcmcia_sockets; - pcmcia_sockets = entry; -} - -void pcmcia_socket_unregister(struct pcmcia_socket_s *socket) -{ - struct pcmcia_socket_entry_s *entry, **ptr; - - ptr = &pcmcia_sockets; - for (entry = *ptr; entry; ptr = &entry->next, entry = *ptr) - if (entry->socket == socket) { - *ptr = entry->next; - qemu_free(entry); - } -} - -void pcmcia_info(void) -{ - struct pcmcia_socket_entry_s *iter; - if (!pcmcia_sockets) - term_printf("No PCMCIA sockets\n"); - - for (iter = pcmcia_sockets; iter; iter = iter->next) - term_printf("%s: %s\n", iter->socket->slot_string, - iter->socket->attached ? iter->socket->card_string : - "Empty"); -} - -/***********************************************************/ -/* dumb display */ - -static void dumb_update(DisplayState *ds, int x, int y, int w, int h) -{ -} - -static void dumb_resize(DisplayState *ds, int w, int h) -{ -} - -static void dumb_refresh(DisplayState *ds) -{ -#if defined(CONFIG_SDL) - vga_hw_update(); -#endif -} - -static void dumb_display_init(DisplayState *ds) -{ - ds->data = NULL; - ds->linesize = 0; - ds->depth = 0; - ds->dpy_update = dumb_update; - ds->dpy_resize = dumb_resize; - ds->dpy_refresh = dumb_refresh; -} - -/***********************************************************/ -/* I/O handling */ - -#define MAX_IO_HANDLERS 64 - -typedef struct IOHandlerRecord { - int fd; - IOCanRWHandler *fd_read_poll; - IOHandler *fd_read; - IOHandler *fd_write; - int deleted; - void *opaque; - /* temporary data */ - struct pollfd *ufd; - struct IOHandlerRecord *next; -} IOHandlerRecord; - -static IOHandlerRecord *first_io_handler; - -/* XXX: fd_read_poll should be suppressed, but an API change is - necessary in the character devices to suppress fd_can_read(). */ -int qemu_set_fd_handler2(int fd, - IOCanRWHandler *fd_read_poll, - IOHandler *fd_read, - IOHandler *fd_write, - void *opaque) -{ - IOHandlerRecord **pioh, *ioh; - - if (!fd_read && !fd_write) { - pioh = &first_io_handler; - for(;;) { - ioh = *pioh; - if (ioh == NULL) - break; - if (ioh->fd == fd) { - ioh->deleted = 1; - break; + switch(type) { + case IF_IDE: + case IF_SCSI: + switch(media) { + case MEDIA_DISK: + if (cyls != 0) { + bdrv_set_geometry_hint(bdrv, cyls, heads, secs); + bdrv_set_translation_hint(bdrv, translation); } - pioh = &ioh->next; - } - } else { - for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { - if (ioh->fd == fd) - goto found; - } - ioh = qemu_mallocz(sizeof(IOHandlerRecord)); - if (!ioh) - return -1; - ioh->next = first_io_handler; - first_io_handler = ioh; - found: - ioh->fd = fd; - ioh->fd_read_poll = fd_read_poll; - ioh->fd_read = fd_read; - ioh->fd_write = fd_write; - ioh->opaque = opaque; - ioh->deleted = 0; + break; + case MEDIA_CDROM: + bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM); + break; + } + break; + case IF_SD: + /* FIXME: This isn't really a floppy, but it's a reasonable + approximation. */ + case IF_FLOPPY: + bdrv_set_type_hint(bdrv, BDRV_TYPE_FLOPPY); + break; + case IF_PFLASH: + case IF_MTD: + break; } - return 0; -} - -int qemu_set_fd_handler(int fd, - IOHandler *fd_read, - IOHandler *fd_write, - void *opaque) -{ - return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque); -} - -/***********************************************************/ -/* Polling handling */ - -typedef struct PollingEntry { - PollingFunc *func; - void *opaque; - struct PollingEntry *next; -} PollingEntry; - -static PollingEntry *first_polling_entry; - -int qemu_add_polling_cb(PollingFunc *func, void *opaque) -{ - PollingEntry **ppe, *pe; - pe = qemu_mallocz(sizeof(PollingEntry)); - if (!pe) - return -1; - pe->func = func; - pe->opaque = opaque; - for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next); - *ppe = pe; - return 0; -} - -void qemu_del_polling_cb(PollingFunc *func, void *opaque) -{ - PollingEntry **ppe, *pe; - for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) { - pe = *ppe; - if (pe->func == func && pe->opaque == opaque) { - *ppe = pe->next; - qemu_free(pe); - break; - } + if (!file[0]) + return 0; + bdrv_flags = 0; + if (snapshot) { + bdrv_flags |= BDRV_O_SNAPSHOT; + cache = 2; /* always use write-back with snapshot */ } -} - -#ifdef _WIN32 -/***********************************************************/ -/* Wait objects support */ -typedef struct WaitObjects { - int num; - HANDLE events[MAXIMUM_WAIT_OBJECTS + 1]; - WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1]; - void *opaque[MAXIMUM_WAIT_OBJECTS + 1]; -} WaitObjects; - -static WaitObjects wait_objects = {0}; - -int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) -{ - WaitObjects *w = &wait_objects; - - if (w->num >= MAXIMUM_WAIT_OBJECTS) + if (cache == 0) /* no caching */ + bdrv_flags |= BDRV_O_NOCACHE; + else if (cache == 2) /* write-back */ + bdrv_flags |= BDRV_O_CACHE_WB; + if (bdrv_open2(bdrv, file, bdrv_flags, drv) < 0 || qemu_key_check(bdrv, file)) { + fprintf(stderr, "qemu: could not open disk image %s\n", + file); return -1; - w->events[w->num] = handle; - w->func[w->num] = func; - w->opaque[w->num] = opaque; - w->num++; - return 0; -} - -void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) -{ - int i, found; - WaitObjects *w = &wait_objects; - - found = 0; - for (i = 0; i < w->num; i++) { - if (w->events[i] == handle) - found = 1; - if (found) { - w->events[i] = w->events[i + 1]; - w->func[i] = w->func[i + 1]; - w->opaque[i] = w->opaque[i + 1]; - } } - if (found) - w->num--; + return 0; } -#endif /***********************************************************/ -/* savevm/loadvm support */ - -#define IO_BUF_SIZE 32768 - -struct QEMUFile { - FILE *outfile; - BlockDriverState *bs; - int is_file; - int is_writable; - int64_t base_offset; - int64_t buf_offset; /* start of buffer when writing, end of buffer - when reading */ - int buf_index; - int buf_size; /* 0 when writing */ - uint8_t buf[IO_BUF_SIZE]; -}; - -QEMUFile *qemu_fopen(const char *filename, const char *mode) -{ - QEMUFile *f; - - f = qemu_mallocz(sizeof(QEMUFile)); - if (!f) - return NULL; - if (!strcmp(mode, "wb")) { - f->is_writable = 1; - } else if (!strcmp(mode, "rb")) { - f->is_writable = 0; - } else { - goto fail; - } - f->outfile = fopen(filename, mode); - if (!f->outfile) - goto fail; - f->is_file = 1; - return f; - fail: - if (f->outfile) - fclose(f->outfile); - qemu_free(f); - return NULL; -} - -static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable) -{ - QEMUFile *f; +/* USB devices */ - f = qemu_mallocz(sizeof(QEMUFile)); - if (!f) - return NULL; - f->is_file = 0; - f->bs = bs; - f->is_writable = is_writable; - f->base_offset = offset; - return f; -} +static USBPort *used_usb_ports; +static USBPort *free_usb_ports; -void qemu_fflush(QEMUFile *f) +/* ??? Maybe change this to register a hub to keep track of the topology. */ +void qemu_register_usb_port(USBPort *port, void *opaque, int index, + usb_attachfn attach) { - if (!f->is_writable) - return; - if (f->buf_index > 0) { - if (f->is_file) { - fseek(f->outfile, f->buf_offset, SEEK_SET); - fwrite(f->buf, 1, f->buf_index, f->outfile); - } else { - bdrv_pwrite(f->bs, f->base_offset + f->buf_offset, - f->buf, f->buf_index); - } - f->buf_offset += f->buf_index; - f->buf_index = 0; - } + port->opaque = opaque; + port->index = index; + port->attach = attach; + port->next = free_usb_ports; + free_usb_ports = port; } -static void qemu_fill_buffer(QEMUFile *f) +int usb_device_add_dev(USBDevice *dev) { - int len; + USBPort *port; - if (f->is_writable) - return; - if (f->is_file) { - fseek(f->outfile, f->buf_offset, SEEK_SET); - len = fread(f->buf, 1, IO_BUF_SIZE, f->outfile); - if (len < 0) - len = 0; - } else { - len = bdrv_pread(f->bs, f->base_offset + f->buf_offset, - f->buf, IO_BUF_SIZE); - if (len < 0) - len = 0; - } - f->buf_index = 0; - f->buf_size = len; - f->buf_offset += len; -} + /* Find a USB port to add the device to. */ + port = free_usb_ports; + if (!port->next) { + USBDevice *hub; -void qemu_fclose(QEMUFile *f) -{ - if (f->is_writable) - qemu_fflush(f); - if (f->is_file) { - fclose(f->outfile); - } - qemu_free(f); -} + /* Create a new hub and chain it on. */ + free_usb_ports = NULL; + port->next = used_usb_ports; + used_usb_ports = port; -void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) -{ - int l; - while (size > 0) { - l = IO_BUF_SIZE - f->buf_index; - if (l > size) - l = size; - memcpy(f->buf + f->buf_index, buf, l); - f->buf_index += l; - buf += l; - size -= l; - if (f->buf_index >= IO_BUF_SIZE) - qemu_fflush(f); + hub = usb_hub_init(VM_USB_HUB_SIZE); + usb_attach(port, hub); + port = free_usb_ports; } -} -void qemu_put_byte(QEMUFile *f, int v) -{ - f->buf[f->buf_index++] = v; - if (f->buf_index >= IO_BUF_SIZE) - qemu_fflush(f); + free_usb_ports = port->next; + port->next = used_usb_ports; + used_usb_ports = port; + usb_attach(port, dev); + return 0; } -int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1) +static int usb_device_add(const char *devname) { - int size, l; - - size = size1; - while (size > 0) { - l = f->buf_size - f->buf_index; - if (l == 0) { - qemu_fill_buffer(f); - l = f->buf_size - f->buf_index; - if (l == 0) - break; - } - if (l > size) - l = size; - memcpy(buf, f->buf + f->buf_index, l); - f->buf_index += l; - buf += l; - size -= l; - } - return size1 - size; -} + const char *p; + USBDevice *dev; -int qemu_get_byte(QEMUFile *f) -{ - if (f->buf_index >= f->buf_size) { - qemu_fill_buffer(f); - if (f->buf_index >= f->buf_size) - return 0; - } - return f->buf[f->buf_index++]; -} + if (!free_usb_ports) + return -1; -int64_t qemu_ftell(QEMUFile *f) -{ - return f->buf_offset - f->buf_size + f->buf_index; -} + if (strstart(devname, "host:", &p)) { + dev = usb_host_device_open(p); + } else if (!strcmp(devname, "mouse")) { + dev = usb_mouse_init(); + } else if (!strcmp(devname, "tablet")) { + dev = usb_tablet_init(); + } else if (!strcmp(devname, "keyboard")) { + dev = usb_keyboard_init(); + } else if (strstart(devname, "disk:", &p)) { + dev = usb_msd_init(p); + } else if (!strcmp(devname, "wacom-tablet")) { + dev = usb_wacom_init(); + } else if (strstart(devname, "serial:", &p)) { + dev = usb_serial_init(p); +#ifdef CONFIG_BRLAPI + } else if (!strcmp(devname, "braille")) { + dev = usb_baum_init(); +#endif + } else if (strstart(devname, "net:", &p)) { + int nic = nb_nics; -int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence) -{ - if (whence == SEEK_SET) { - /* nothing to do */ - } else if (whence == SEEK_CUR) { - pos += qemu_ftell(f); + if (net_client_init("nic", p) < 0) + return -1; + nd_table[nic].model = "usb"; + dev = usb_net_init(&nd_table[nic]); + } else if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) { + dev = usb_bt_init(devname[2] ? hci_init(p) : + bt_new_hci(qemu_find_bt_vlan(0))); } else { - /* SEEK_END not supported */ return -1; } - if (f->is_writable) { - qemu_fflush(f); - f->buf_offset = pos; - } else { - f->buf_offset = pos; - f->buf_index = 0; - f->buf_size = 0; - } - return pos; -} - -void qemu_put_be16(QEMUFile *f, unsigned int v) -{ - qemu_put_byte(f, v >> 8); - qemu_put_byte(f, v); -} - -void qemu_put_be32(QEMUFile *f, unsigned int v) -{ - qemu_put_byte(f, v >> 24); - qemu_put_byte(f, v >> 16); - qemu_put_byte(f, v >> 8); - qemu_put_byte(f, v); -} - -void qemu_put_be64(QEMUFile *f, uint64_t v) -{ - qemu_put_be32(f, v >> 32); - qemu_put_be32(f, v); -} - -unsigned int qemu_get_be16(QEMUFile *f) -{ - unsigned int v; - v = qemu_get_byte(f) << 8; - v |= qemu_get_byte(f); - return v; -} + if (!dev) + return -1; -unsigned int qemu_get_be32(QEMUFile *f) -{ - unsigned int v; - v = qemu_get_byte(f) << 24; - v |= qemu_get_byte(f) << 16; - v |= qemu_get_byte(f) << 8; - v |= qemu_get_byte(f); - return v; + return usb_device_add_dev(dev); } -uint64_t qemu_get_be64(QEMUFile *f) +int usb_device_del_addr(int bus_num, int addr) { - uint64_t v; - v = (uint64_t)qemu_get_be32(f) << 32; - v |= qemu_get_be32(f); - return v; -} + USBPort *port; + USBPort **lastp; + USBDevice *dev; -typedef struct SaveStateEntry { - char idstr[256]; - int instance_id; - int version_id; - SaveStateHandler *save_state; - LoadStateHandler *load_state; - void *opaque; - struct SaveStateEntry *next; -} SaveStateEntry; + if (!used_usb_ports) + return -1; -static SaveStateEntry *first_se; + if (bus_num != 0) + return -1; -int register_savevm(const char *idstr, - int instance_id, - int version_id, - SaveStateHandler *save_state, - LoadStateHandler *load_state, - void *opaque) -{ - SaveStateEntry *se, **pse; + lastp = &used_usb_ports; + port = used_usb_ports; + while (port && port->dev->addr != addr) { + lastp = &port->next; + port = port->next; + } - se = qemu_malloc(sizeof(SaveStateEntry)); - if (!se) + if (!port) return -1; - pstrcpy(se->idstr, sizeof(se->idstr), idstr); - se->instance_id = instance_id; - se->version_id = version_id; - se->save_state = save_state; - se->load_state = load_state; - se->opaque = opaque; - se->next = NULL; - - /* add at the end of list */ - pse = &first_se; - while (*pse != NULL) - pse = &(*pse)->next; - *pse = se; + + dev = port->dev; + *lastp = port->next; + usb_attach(port, NULL); + dev->handle_destroy(dev); + port->next = free_usb_ports; + free_usb_ports = port; return 0; } -#define QEMU_VM_FILE_MAGIC 0x5145564d -#define QEMU_VM_FILE_VERSION 0x00000002 - -static int qemu_savevm_state(QEMUFile *f) +static int usb_device_del(const char *devname) { - SaveStateEntry *se; - int len, ret; - int64_t cur_pos, len_pos, total_len_pos; - - qemu_put_be32(f, QEMU_VM_FILE_MAGIC); - qemu_put_be32(f, QEMU_VM_FILE_VERSION); - total_len_pos = qemu_ftell(f); - qemu_put_be64(f, 0); /* total size */ - - for(se = first_se; se != NULL; se = se->next) { - /* ID string */ - len = strlen(se->idstr); - qemu_put_byte(f, len); - qemu_put_buffer(f, (uint8_t *)se->idstr, len); - - qemu_put_be32(f, se->instance_id); - qemu_put_be32(f, se->version_id); - - /* record size: filled later */ - len_pos = qemu_ftell(f); - qemu_put_be32(f, 0); - se->save_state(f, se->opaque); - - /* fill record size */ - cur_pos = qemu_ftell(f); - len = cur_pos - len_pos - 4; - qemu_fseek(f, len_pos, SEEK_SET); - qemu_put_be32(f, len); - qemu_fseek(f, cur_pos, SEEK_SET); - } - cur_pos = qemu_ftell(f); - qemu_fseek(f, total_len_pos, SEEK_SET); - qemu_put_be64(f, cur_pos - total_len_pos - 8); - qemu_fseek(f, cur_pos, SEEK_SET); - - ret = 0; - return ret; -} + int bus_num, addr; + const char *p; -static SaveStateEntry *find_se(const char *idstr, int instance_id) -{ - SaveStateEntry *se; + if (strstart(devname, "host:", &p)) + return usb_host_device_close(p); - for(se = first_se; se != NULL; se = se->next) { - if (!strcmp(se->idstr, idstr) && - instance_id == se->instance_id) - return se; - } - return NULL; -} + if (!used_usb_ports) + return -1; -static int qemu_loadvm_state(QEMUFile *f) -{ - SaveStateEntry *se; - int len, ret, instance_id, record_len, version_id; - int64_t total_len, end_pos, cur_pos; - unsigned int v; - char idstr[256]; + p = strchr(devname, '.'); + if (!p) + return -1; + bus_num = strtoul(devname, NULL, 0); + addr = strtoul(p + 1, NULL, 0); - v = qemu_get_be32(f); - if (v != QEMU_VM_FILE_MAGIC) - goto fail; - v = qemu_get_be32(f); - if (v != QEMU_VM_FILE_VERSION) { - fail: - ret = -1; - goto the_end; - } - total_len = qemu_get_be64(f); - end_pos = total_len + qemu_ftell(f); - for(;;) { - if (qemu_ftell(f) >= end_pos) - break; - len = qemu_get_byte(f); - qemu_get_buffer(f, (uint8_t *)idstr, len); - idstr[len] = '\0'; - instance_id = qemu_get_be32(f); - version_id = qemu_get_be32(f); - record_len = qemu_get_be32(f); -#if 0 - printf("idstr=%s instance=0x%x version=%d len=%d\n", - idstr, instance_id, version_id, record_len); -#endif - cur_pos = qemu_ftell(f); - se = find_se(idstr, instance_id); - if (!se) { - fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n", - instance_id, idstr); - } else { - ret = se->load_state(f, se->opaque, version_id); - if (ret < 0) { - fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n", - instance_id, idstr); - } - } - /* always seek to exact end of record */ - qemu_fseek(f, cur_pos + record_len, SEEK_SET); - } - ret = 0; - the_end: - return ret; + return usb_device_del_addr(bus_num, addr); } -/* device can contain snapshots */ -static int bdrv_can_snapshot(BlockDriverState *bs) +void do_usb_add(const char *devname) { - return (bs && - !bdrv_is_removable(bs) && - !bdrv_is_read_only(bs)); + usb_device_add(devname); } -/* device must be snapshots in order to have a reliable snapshot */ -static int bdrv_has_snapshot(BlockDriverState *bs) +void do_usb_del(const char *devname) { - return (bs && - !bdrv_is_removable(bs) && - !bdrv_is_read_only(bs)); + usb_device_del(devname); } -static BlockDriverState *get_bs_snapshots(void) +void usb_info(void) { - BlockDriverState *bs; - int i; + USBDevice *dev; + USBPort *port; + const char *speed_str; - if (bs_snapshots) - return bs_snapshots; - for(i = 0; i <= nb_drives; i++) { - bs = drives_table[i].bdrv; - if (bdrv_can_snapshot(bs)) - goto ok; + if (!usb_enabled) { + term_printf("USB support not enabled\n"); + return; } - return NULL; - ok: - bs_snapshots = bs; - return bs; -} - -static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, - const char *name) -{ - QEMUSnapshotInfo *sn_tab, *sn; - int nb_sns, i, ret; - - ret = -ENOENT; - nb_sns = bdrv_snapshot_list(bs, &sn_tab); - if (nb_sns < 0) - return ret; - for(i = 0; i < nb_sns; i++) { - sn = &sn_tab[i]; - if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) { - *sn_info = *sn; - ret = 0; + + for (port = used_usb_ports; port; port = port->next) { + dev = port->dev; + if (!dev) + continue; + switch(dev->speed) { + case USB_SPEED_LOW: + speed_str = "1.5"; + break; + case USB_SPEED_FULL: + speed_str = "12"; + break; + case USB_SPEED_HIGH: + speed_str = "480"; + break; + default: + speed_str = "?"; break; } + term_printf(" Device %d.%d, Speed %s Mb/s, Product %s\n", + 0, dev->addr, speed_str, dev->devname); } - qemu_free(sn_tab); - return ret; } -void do_savevm(const char *name) -{ - BlockDriverState *bs, *bs1; - QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1; - int must_delete, ret, i; - BlockDriverInfo bdi1, *bdi = &bdi1; - QEMUFile *f; - int saved_vm_running; -#ifdef _WIN32 - struct _timeb tb; -#else - struct timeval tv; -#endif - - bs = get_bs_snapshots(); - if (!bs) { - term_printf("No block device can accept snapshots\n"); - return; - } - - /* ??? Should this occur after vm_stop? */ - qemu_aio_flush(); - - saved_vm_running = vm_running; - vm_stop(0); +/***********************************************************/ +/* PCMCIA/Cardbus */ - must_delete = 0; - if (name) { - ret = bdrv_snapshot_find(bs, old_sn, name); - if (ret >= 0) { - must_delete = 1; - } - } - memset(sn, 0, sizeof(*sn)); - if (must_delete) { - pstrcpy(sn->name, sizeof(sn->name), old_sn->name); - pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str); - } else { - if (name) - pstrcpy(sn->name, sizeof(sn->name), name); - } +static struct pcmcia_socket_entry_s { + struct pcmcia_socket_s *socket; + struct pcmcia_socket_entry_s *next; +} *pcmcia_sockets = 0; - /* fill auxiliary fields */ -#ifdef _WIN32 - _ftime(&tb); - sn->date_sec = tb.time; - sn->date_nsec = tb.millitm * 1000000; -#else - gettimeofday(&tv, NULL); - sn->date_sec = tv.tv_sec; - sn->date_nsec = tv.tv_usec * 1000; -#endif - sn->vm_clock_nsec = qemu_get_clock(vm_clock); - - if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) { - term_printf("Device %s does not support VM state snapshots\n", - bdrv_get_device_name(bs)); - goto the_end; - } - - /* save the VM state */ - f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 1); - if (!f) { - term_printf("Could not open VM state file\n"); - goto the_end; - } - ret = qemu_savevm_state(f); - sn->vm_state_size = qemu_ftell(f); - qemu_fclose(f); - if (ret < 0) { - term_printf("Error %d while writing VM\n", ret); - goto the_end; - } - - /* create the snapshots */ - - for(i = 0; i < nb_drives; i++) { - bs1 = drives_table[i].bdrv; - if (bdrv_has_snapshot(bs1)) { - if (must_delete) { - ret = bdrv_snapshot_delete(bs1, old_sn->id_str); - if (ret < 0) { - term_printf("Error while deleting snapshot on '%s'\n", - bdrv_get_device_name(bs1)); - } - } - ret = bdrv_snapshot_create(bs1, sn); - if (ret < 0) { - term_printf("Error while creating snapshot on '%s'\n", - bdrv_get_device_name(bs1)); - } - } - } +void pcmcia_socket_register(struct pcmcia_socket_s *socket) +{ + struct pcmcia_socket_entry_s *entry; - the_end: - if (saved_vm_running) - vm_start(); + entry = qemu_malloc(sizeof(struct pcmcia_socket_entry_s)); + entry->socket = socket; + entry->next = pcmcia_sockets; + pcmcia_sockets = entry; } -void do_loadvm(const char *name) +void pcmcia_socket_unregister(struct pcmcia_socket_s *socket) { - BlockDriverState *bs, *bs1; - BlockDriverInfo bdi1, *bdi = &bdi1; - QEMUFile *f; - int i, ret; - int saved_vm_running; - - bs = get_bs_snapshots(); - if (!bs) { - term_printf("No block device supports snapshots\n"); - return; - } - - /* Flush all IO requests so they don't interfere with the new state. */ - qemu_aio_flush(); - - saved_vm_running = vm_running; - vm_stop(0); - - for(i = 0; i <= nb_drives; i++) { - bs1 = drives_table[i].bdrv; - if (bdrv_has_snapshot(bs1)) { - ret = bdrv_snapshot_goto(bs1, name); - if (ret < 0) { - if (bs != bs1) - term_printf("Warning: "); - switch(ret) { - case -ENOTSUP: - term_printf("Snapshots not supported on device '%s'\n", - bdrv_get_device_name(bs1)); - break; - case -ENOENT: - term_printf("Could not find snapshot '%s' on device '%s'\n", - name, bdrv_get_device_name(bs1)); - break; - default: - term_printf("Error %d while activating snapshot on '%s'\n", - ret, bdrv_get_device_name(bs1)); - break; - } - /* fatal on snapshot block device */ - if (bs == bs1) - goto the_end; - } - } - } - - if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) { - term_printf("Device %s does not support VM state snapshots\n", - bdrv_get_device_name(bs)); - return; - } - - /* restore the VM state */ - f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 0); - if (!f) { - term_printf("Could not open VM state file\n"); - goto the_end; - } - ret = qemu_loadvm_state(f); - qemu_fclose(f); - if (ret < 0) { - term_printf("Error %d while loading VM state\n", ret); - } - the_end: - if (saved_vm_running) - vm_start(); -} - -void do_delvm(const char *name) -{ - BlockDriverState *bs, *bs1; - int i, ret; - - bs = get_bs_snapshots(); - if (!bs) { - term_printf("No block device supports snapshots\n"); - return; - } + struct pcmcia_socket_entry_s *entry, **ptr; - for(i = 0; i <= nb_drives; i++) { - bs1 = drives_table[i].bdrv; - if (bdrv_has_snapshot(bs1)) { - ret = bdrv_snapshot_delete(bs1, name); - if (ret < 0) { - if (ret == -ENOTSUP) - term_printf("Snapshots not supported on device '%s'\n", - bdrv_get_device_name(bs1)); - else - term_printf("Error %d while deleting snapshot on '%s'\n", - ret, bdrv_get_device_name(bs1)); - } + ptr = &pcmcia_sockets; + for (entry = *ptr; entry; ptr = &entry->next, entry = *ptr) + if (entry->socket == socket) { + *ptr = entry->next; + qemu_free(entry); } - } } -void do_info_snapshots(void) +void pcmcia_info(void) { - BlockDriverState *bs, *bs1; - QEMUSnapshotInfo *sn_tab, *sn; - int nb_sns, i; - char buf[256]; - - bs = get_bs_snapshots(); - if (!bs) { - term_printf("No available block device supports snapshots\n"); - return; - } - term_printf("Snapshot devices:"); - for(i = 0; i <= nb_drives; i++) { - bs1 = drives_table[i].bdrv; - if (bdrv_has_snapshot(bs1)) { - if (bs == bs1) - term_printf(" %s", bdrv_get_device_name(bs1)); - } - } - term_printf("\n"); - - nb_sns = bdrv_snapshot_list(bs, &sn_tab); - if (nb_sns < 0) { - term_printf("bdrv_snapshot_list: error %d\n", nb_sns); - return; - } - term_printf("Snapshot list (from %s):\n", bdrv_get_device_name(bs)); - term_printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL)); - for(i = 0; i < nb_sns; i++) { - sn = &sn_tab[i]; - term_printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn)); - } - qemu_free(sn_tab); + struct pcmcia_socket_entry_s *iter; + if (!pcmcia_sockets) + term_printf("No PCMCIA sockets\n"); + + for (iter = pcmcia_sockets; iter; iter = iter->next) + term_printf("%s: %s\n", iter->socket->slot_string, + iter->socket->attached ? iter->socket->card_string : + "Empty"); } /***********************************************************/ -/* cpu save/restore */ - -#if defined(TARGET_I386) +/* dumb display */ -static void cpu_put_seg(QEMUFile *f, SegmentCache *dt) +static void dumb_update(DisplayState *ds, int x, int y, int w, int h) { - qemu_put_be32(f, dt->selector); - qemu_put_betl(f, dt->base); - qemu_put_be32(f, dt->limit); - qemu_put_be32(f, dt->flags); } -static void cpu_get_seg(QEMUFile *f, SegmentCache *dt) +static void dumb_resize(DisplayState *ds, int w, int h) { - dt->selector = qemu_get_be32(f); - dt->base = qemu_get_betl(f); - dt->limit = qemu_get_be32(f); - dt->flags = qemu_get_be32(f); } -void cpu_save(QEMUFile *f, void *opaque) +static void dumb_display_init(DisplayState *ds) { - CPUState *env = opaque; - uint16_t fptag, fpus, fpuc, fpregs_format; - uint32_t hflags; - int i; - - for(i = 0; i < CPU_NB_REGS; i++) - qemu_put_betls(f, &env->regs[i]); - qemu_put_betls(f, &env->eip); - qemu_put_betls(f, &env->eflags); - hflags = env->hflags; /* XXX: suppress most of the redundant hflags */ - qemu_put_be32s(f, &hflags); - - /* FPU */ - fpuc = env->fpuc; - fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; - fptag = 0; - for(i = 0; i < 8; i++) { - fptag |= ((!env->fptags[i]) << i); - } - - qemu_put_be16s(f, &fpuc); - qemu_put_be16s(f, &fpus); - qemu_put_be16s(f, &fptag); - -#ifdef USE_X86LDOUBLE - fpregs_format = 0; -#else - fpregs_format = 1; -#endif - qemu_put_be16s(f, &fpregs_format); + ds->data = NULL; + ds->linesize = 0; + ds->depth = 0; + ds->dpy_update = dumb_update; + ds->dpy_resize = dumb_resize; + ds->dpy_refresh = NULL; + ds->gui_timer_interval = 0; + ds->idle = 1; +} - for(i = 0; i < 8; i++) { -#ifdef USE_X86LDOUBLE - { - uint64_t mant; - uint16_t exp; - /* we save the real CPU data (in case of MMX usage only 'mant' - contains the MMX register */ - cpu_get_fp80(&mant, &exp, env->fpregs[i].d); - qemu_put_be64(f, mant); - qemu_put_be16(f, exp); - } -#else - /* if we use doubles for float emulation, we save the doubles to - avoid losing information in case of MMX usage. It can give - problems if the image is restored on a CPU where long - doubles are used instead. */ - qemu_put_be64(f, env->fpregs[i].mmx.MMX_Q(0)); -#endif - } +/***********************************************************/ +/* I/O handling */ - for(i = 0; i < 6; i++) - cpu_put_seg(f, &env->segs[i]); - cpu_put_seg(f, &env->ldt); - cpu_put_seg(f, &env->tr); - cpu_put_seg(f, &env->gdt); - cpu_put_seg(f, &env->idt); - - qemu_put_be32s(f, &env->sysenter_cs); - qemu_put_be32s(f, &env->sysenter_esp); - qemu_put_be32s(f, &env->sysenter_eip); - - qemu_put_betls(f, &env->cr[0]); - qemu_put_betls(f, &env->cr[2]); - qemu_put_betls(f, &env->cr[3]); - qemu_put_betls(f, &env->cr[4]); - - for(i = 0; i < 8; i++) - qemu_put_betls(f, &env->dr[i]); - - /* MMU */ - qemu_put_be32s(f, &env->a20_mask); - - /* XMM */ - qemu_put_be32s(f, &env->mxcsr); - for(i = 0; i < CPU_NB_REGS; i++) { - qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(0)); - qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(1)); - } - -#ifdef TARGET_X86_64 - qemu_put_be64s(f, &env->efer); - qemu_put_be64s(f, &env->star); - qemu_put_be64s(f, &env->lstar); - qemu_put_be64s(f, &env->cstar); - qemu_put_be64s(f, &env->fmask); - qemu_put_be64s(f, &env->kernelgsbase); -#endif - qemu_put_be32s(f, &env->smbase); -} - -#ifdef USE_X86LDOUBLE -/* XXX: add that in a FPU generic layer */ -union x86_longdouble { - uint64_t mant; - uint16_t exp; -}; +#define MAX_IO_HANDLERS 64 -#define MANTD1(fp) (fp & ((1LL << 52) - 1)) -#define EXPBIAS1 1023 -#define EXPD1(fp) ((fp >> 52) & 0x7FF) -#define SIGND1(fp) ((fp >> 32) & 0x80000000) +typedef struct IOHandlerRecord { + int fd; + IOCanRWHandler *fd_read_poll; + IOHandler *fd_read; + IOHandler *fd_write; + int deleted; + void *opaque; + /* temporary data */ + struct pollfd *ufd; + struct IOHandlerRecord *next; +} IOHandlerRecord; -static void fp64_to_fp80(union x86_longdouble *p, uint64_t temp) -{ - int e; - /* mantissa */ - p->mant = (MANTD1(temp) << 11) | (1LL << 63); - /* exponent + sign */ - e = EXPD1(temp) - EXPBIAS1 + 16383; - e |= SIGND1(temp) >> 16; - p->exp = e; -} -#endif +static IOHandlerRecord *first_io_handler; -int cpu_load(QEMUFile *f, void *opaque, int version_id) +/* XXX: fd_read_poll should be suppressed, but an API change is + necessary in the character devices to suppress fd_can_read(). */ +int qemu_set_fd_handler2(int fd, + IOCanRWHandler *fd_read_poll, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque) { - CPUState *env = opaque; - int i, guess_mmx; - uint32_t hflags; - uint16_t fpus, fpuc, fptag, fpregs_format; + IOHandlerRecord **pioh, *ioh; - if (version_id != 3 && version_id != 4) - return -EINVAL; - for(i = 0; i < CPU_NB_REGS; i++) - qemu_get_betls(f, &env->regs[i]); - qemu_get_betls(f, &env->eip); - qemu_get_betls(f, &env->eflags); - qemu_get_be32s(f, &hflags); - - qemu_get_be16s(f, &fpuc); - qemu_get_be16s(f, &fpus); - qemu_get_be16s(f, &fptag); - qemu_get_be16s(f, &fpregs_format); - - /* NOTE: we cannot always restore the FPU state if the image come - from a host with a different 'USE_X86LDOUBLE' define. We guess - if we are in an MMX state to restore correctly in that case. */ - guess_mmx = ((fptag == 0xff) && (fpus & 0x3800) == 0); - for(i = 0; i < 8; i++) { - uint64_t mant; - uint16_t exp; - - switch(fpregs_format) { - case 0: - mant = qemu_get_be64(f); - exp = qemu_get_be16(f); -#ifdef USE_X86LDOUBLE - env->fpregs[i].d = cpu_set_fp80(mant, exp); -#else - /* difficult case */ - if (guess_mmx) - env->fpregs[i].mmx.MMX_Q(0) = mant; - else - env->fpregs[i].d = cpu_set_fp80(mant, exp); -#endif - break; - case 1: - mant = qemu_get_be64(f); -#ifdef USE_X86LDOUBLE - { - union x86_longdouble *p; - /* difficult case */ - p = (void *)&env->fpregs[i]; - if (guess_mmx) { - p->mant = mant; - p->exp = 0xffff; - } else { - fp64_to_fp80(p, mant); - } - } -#else - env->fpregs[i].mmx.MMX_Q(0) = mant; -#endif - break; - default: - return -EINVAL; + if (!fd_read && !fd_write) { + pioh = &first_io_handler; + for(;;) { + ioh = *pioh; + if (ioh == NULL) + break; + if (ioh->fd == fd) { + ioh->deleted = 1; + break; + } + pioh = &ioh->next; + } + } else { + for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { + if (ioh->fd == fd) + goto found; } + ioh = qemu_mallocz(sizeof(IOHandlerRecord)); + if (!ioh) + return -1; + ioh->next = first_io_handler; + first_io_handler = ioh; + found: + ioh->fd = fd; + ioh->fd_read_poll = fd_read_poll; + ioh->fd_read = fd_read; + ioh->fd_write = fd_write; + ioh->opaque = opaque; + ioh->deleted = 0; } - - env->fpuc = fpuc; - /* XXX: restore FPU round state */ - env->fpstt = (fpus >> 11) & 7; - env->fpus = fpus & ~0x3800; - fptag ^= 0xff; - for(i = 0; i < 8; i++) { - env->fptags[i] = (fptag >> i) & 1; - } - - for(i = 0; i < 6; i++) - cpu_get_seg(f, &env->segs[i]); - cpu_get_seg(f, &env->ldt); - cpu_get_seg(f, &env->tr); - cpu_get_seg(f, &env->gdt); - cpu_get_seg(f, &env->idt); - - qemu_get_be32s(f, &env->sysenter_cs); - qemu_get_be32s(f, &env->sysenter_esp); - qemu_get_be32s(f, &env->sysenter_eip); - - qemu_get_betls(f, &env->cr[0]); - qemu_get_betls(f, &env->cr[2]); - qemu_get_betls(f, &env->cr[3]); - qemu_get_betls(f, &env->cr[4]); - - for(i = 0; i < 8; i++) - qemu_get_betls(f, &env->dr[i]); - - /* MMU */ - qemu_get_be32s(f, &env->a20_mask); - - qemu_get_be32s(f, &env->mxcsr); - for(i = 0; i < CPU_NB_REGS; i++) { - qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(0)); - qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(1)); - } - -#ifdef TARGET_X86_64 - qemu_get_be64s(f, &env->efer); - qemu_get_be64s(f, &env->star); - qemu_get_be64s(f, &env->lstar); - qemu_get_be64s(f, &env->cstar); - qemu_get_be64s(f, &env->fmask); - qemu_get_be64s(f, &env->kernelgsbase); -#endif - if (version_id >= 4) - qemu_get_be32s(f, &env->smbase); - - /* XXX: compute hflags from scratch, except for CPL and IIF */ - env->hflags = hflags; - tlb_flush(env, 1); - return 0; -} - -#elif defined(TARGET_PPC) -void cpu_save(QEMUFile *f, void *opaque) -{ -} - -int cpu_load(QEMUFile *f, void *opaque, int version_id) -{ return 0; } -#elif defined(TARGET_MIPS) -void cpu_save(QEMUFile *f, void *opaque) +int qemu_set_fd_handler(int fd, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque) { + return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque); } -int cpu_load(QEMUFile *f, void *opaque, int version_id) -{ - return 0; -} +#ifdef _WIN32 +/***********************************************************/ +/* Polling handling */ -#elif defined(TARGET_SPARC) -void cpu_save(QEMUFile *f, void *opaque) -{ - CPUState *env = opaque; - int i; - uint32_t tmp; +typedef struct PollingEntry { + PollingFunc *func; + void *opaque; + struct PollingEntry *next; +} PollingEntry; - for(i = 0; i < 8; i++) - qemu_put_betls(f, &env->gregs[i]); - for(i = 0; i < NWINDOWS * 16; i++) - qemu_put_betls(f, &env->regbase[i]); - - /* FPU */ - for(i = 0; i < TARGET_FPREGS; i++) { - union { - float32 f; - uint32_t i; - } u; - u.f = env->fpr[i]; - qemu_put_be32(f, u.i); - } - - qemu_put_betls(f, &env->pc); - qemu_put_betls(f, &env->npc); - qemu_put_betls(f, &env->y); - tmp = GET_PSR(env); - qemu_put_be32(f, tmp); - qemu_put_betls(f, &env->fsr); - qemu_put_betls(f, &env->tbr); -#ifndef TARGET_SPARC64 - qemu_put_be32s(f, &env->wim); - /* MMU */ - for(i = 0; i < 16; i++) - qemu_put_be32s(f, &env->mmuregs[i]); -#endif -} +static PollingEntry *first_polling_entry; -int cpu_load(QEMUFile *f, void *opaque, int version_id) +int qemu_add_polling_cb(PollingFunc *func, void *opaque) { - CPUState *env = opaque; - int i; - uint32_t tmp; - - for(i = 0; i < 8; i++) - qemu_get_betls(f, &env->gregs[i]); - for(i = 0; i < NWINDOWS * 16; i++) - qemu_get_betls(f, &env->regbase[i]); - - /* FPU */ - for(i = 0; i < TARGET_FPREGS; i++) { - union { - float32 f; - uint32_t i; - } u; - u.i = qemu_get_be32(f); - env->fpr[i] = u.f; - } - - qemu_get_betls(f, &env->pc); - qemu_get_betls(f, &env->npc); - qemu_get_betls(f, &env->y); - tmp = qemu_get_be32(f); - env->cwp = 0; /* needed to ensure that the wrapping registers are - correctly updated */ - PUT_PSR(env, tmp); - qemu_get_betls(f, &env->fsr); - qemu_get_betls(f, &env->tbr); -#ifndef TARGET_SPARC64 - qemu_get_be32s(f, &env->wim); - /* MMU */ - for(i = 0; i < 16; i++) - qemu_get_be32s(f, &env->mmuregs[i]); -#endif - tlb_flush(env, 1); + PollingEntry **ppe, *pe; + pe = qemu_mallocz(sizeof(PollingEntry)); + if (!pe) + return -1; + pe->func = func; + pe->opaque = opaque; + for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next); + *ppe = pe; return 0; } -#elif defined(TARGET_ARM) - -void cpu_save(QEMUFile *f, void *opaque) +void qemu_del_polling_cb(PollingFunc *func, void *opaque) { - int i; - CPUARMState *env = (CPUARMState *)opaque; - - for (i = 0; i < 16; i++) { - qemu_put_be32(f, env->regs[i]); - } - qemu_put_be32(f, cpsr_read(env)); - qemu_put_be32(f, env->spsr); - for (i = 0; i < 6; i++) { - qemu_put_be32(f, env->banked_spsr[i]); - qemu_put_be32(f, env->banked_r13[i]); - qemu_put_be32(f, env->banked_r14[i]); - } - for (i = 0; i < 5; i++) { - qemu_put_be32(f, env->usr_regs[i]); - qemu_put_be32(f, env->fiq_regs[i]); - } - qemu_put_be32(f, env->cp15.c0_cpuid); - qemu_put_be32(f, env->cp15.c0_cachetype); - qemu_put_be32(f, env->cp15.c1_sys); - qemu_put_be32(f, env->cp15.c1_coproc); - qemu_put_be32(f, env->cp15.c1_xscaleauxcr); - qemu_put_be32(f, env->cp15.c2_base0); - qemu_put_be32(f, env->cp15.c2_base1); - qemu_put_be32(f, env->cp15.c2_mask); - qemu_put_be32(f, env->cp15.c2_data); - qemu_put_be32(f, env->cp15.c2_insn); - qemu_put_be32(f, env->cp15.c3); - qemu_put_be32(f, env->cp15.c5_insn); - qemu_put_be32(f, env->cp15.c5_data); - for (i = 0; i < 8; i++) { - qemu_put_be32(f, env->cp15.c6_region[i]); - } - qemu_put_be32(f, env->cp15.c6_insn); - qemu_put_be32(f, env->cp15.c6_data); - qemu_put_be32(f, env->cp15.c9_insn); - qemu_put_be32(f, env->cp15.c9_data); - qemu_put_be32(f, env->cp15.c13_fcse); - qemu_put_be32(f, env->cp15.c13_context); - qemu_put_be32(f, env->cp15.c13_tls1); - qemu_put_be32(f, env->cp15.c13_tls2); - qemu_put_be32(f, env->cp15.c13_tls3); - qemu_put_be32(f, env->cp15.c15_cpar); - - qemu_put_be32(f, env->features); - - if (arm_feature(env, ARM_FEATURE_VFP)) { - for (i = 0; i < 16; i++) { - CPU_DoubleU u; - u.d = env->vfp.regs[i]; - qemu_put_be32(f, u.l.upper); - qemu_put_be32(f, u.l.lower); - } - for (i = 0; i < 16; i++) { - qemu_put_be32(f, env->vfp.xregs[i]); - } - - /* TODO: Should use proper FPSCR access functions. */ - qemu_put_be32(f, env->vfp.vec_len); - qemu_put_be32(f, env->vfp.vec_stride); - - if (arm_feature(env, ARM_FEATURE_VFP3)) { - for (i = 16; i < 32; i++) { - CPU_DoubleU u; - u.d = env->vfp.regs[i]; - qemu_put_be32(f, u.l.upper); - qemu_put_be32(f, u.l.lower); - } + PollingEntry **ppe, *pe; + for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) { + pe = *ppe; + if (pe->func == func && pe->opaque == opaque) { + *ppe = pe->next; + qemu_free(pe); + break; } } +} - if (arm_feature(env, ARM_FEATURE_IWMMXT)) { - for (i = 0; i < 16; i++) { - qemu_put_be64(f, env->iwmmxt.regs[i]); - } - for (i = 0; i < 16; i++) { - qemu_put_be32(f, env->iwmmxt.cregs[i]); - } - } +/***********************************************************/ +/* Wait objects support */ +typedef struct WaitObjects { + int num; + HANDLE events[MAXIMUM_WAIT_OBJECTS + 1]; + WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1]; + void *opaque[MAXIMUM_WAIT_OBJECTS + 1]; +} WaitObjects; - if (arm_feature(env, ARM_FEATURE_M)) { - qemu_put_be32(f, env->v7m.other_sp); - qemu_put_be32(f, env->v7m.vecbase); - qemu_put_be32(f, env->v7m.basepri); - qemu_put_be32(f, env->v7m.control); - qemu_put_be32(f, env->v7m.current_sp); - qemu_put_be32(f, env->v7m.exception); - } -} +static WaitObjects wait_objects = {0}; -int cpu_load(QEMUFile *f, void *opaque, int version_id) +int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) { - CPUARMState *env = (CPUARMState *)opaque; - int i; + WaitObjects *w = &wait_objects; - if (version_id != ARM_CPU_SAVE_VERSION) - return -EINVAL; + if (w->num >= MAXIMUM_WAIT_OBJECTS) + return -1; + w->events[w->num] = handle; + w->func[w->num] = func; + w->opaque[w->num] = opaque; + w->num++; + return 0; +} - for (i = 0; i < 16; i++) { - env->regs[i] = qemu_get_be32(f); - } - cpsr_write(env, qemu_get_be32(f), 0xffffffff); - env->spsr = qemu_get_be32(f); - for (i = 0; i < 6; i++) { - env->banked_spsr[i] = qemu_get_be32(f); - env->banked_r13[i] = qemu_get_be32(f); - env->banked_r14[i] = qemu_get_be32(f); - } - for (i = 0; i < 5; i++) { - env->usr_regs[i] = qemu_get_be32(f); - env->fiq_regs[i] = qemu_get_be32(f); - } - env->cp15.c0_cpuid = qemu_get_be32(f); - env->cp15.c0_cachetype = qemu_get_be32(f); - env->cp15.c1_sys = qemu_get_be32(f); - env->cp15.c1_coproc = qemu_get_be32(f); - env->cp15.c1_xscaleauxcr = qemu_get_be32(f); - env->cp15.c2_base0 = qemu_get_be32(f); - env->cp15.c2_base1 = qemu_get_be32(f); - env->cp15.c2_mask = qemu_get_be32(f); - env->cp15.c2_data = qemu_get_be32(f); - env->cp15.c2_insn = qemu_get_be32(f); - env->cp15.c3 = qemu_get_be32(f); - env->cp15.c5_insn = qemu_get_be32(f); - env->cp15.c5_data = qemu_get_be32(f); - for (i = 0; i < 8; i++) { - env->cp15.c6_region[i] = qemu_get_be32(f); - } - env->cp15.c6_insn = qemu_get_be32(f); - env->cp15.c6_data = qemu_get_be32(f); - env->cp15.c9_insn = qemu_get_be32(f); - env->cp15.c9_data = qemu_get_be32(f); - env->cp15.c13_fcse = qemu_get_be32(f); - env->cp15.c13_context = qemu_get_be32(f); - env->cp15.c13_tls1 = qemu_get_be32(f); - env->cp15.c13_tls2 = qemu_get_be32(f); - env->cp15.c13_tls3 = qemu_get_be32(f); - env->cp15.c15_cpar = qemu_get_be32(f); - - env->features = qemu_get_be32(f); - - if (arm_feature(env, ARM_FEATURE_VFP)) { - for (i = 0; i < 16; i++) { - CPU_DoubleU u; - u.l.upper = qemu_get_be32(f); - u.l.lower = qemu_get_be32(f); - env->vfp.regs[i] = u.d; - } - for (i = 0; i < 16; i++) { - env->vfp.xregs[i] = qemu_get_be32(f); - } - - /* TODO: Should use proper FPSCR access functions. */ - env->vfp.vec_len = qemu_get_be32(f); - env->vfp.vec_stride = qemu_get_be32(f); - - if (arm_feature(env, ARM_FEATURE_VFP3)) { - for (i = 0; i < 16; i++) { - CPU_DoubleU u; - u.l.upper = qemu_get_be32(f); - u.l.lower = qemu_get_be32(f); - env->vfp.regs[i] = u.d; - } - } - } +void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) +{ + int i, found; + WaitObjects *w = &wait_objects; - if (arm_feature(env, ARM_FEATURE_IWMMXT)) { - for (i = 0; i < 16; i++) { - env->iwmmxt.regs[i] = qemu_get_be64(f); - } - for (i = 0; i < 16; i++) { - env->iwmmxt.cregs[i] = qemu_get_be32(f); + found = 0; + for (i = 0; i < w->num; i++) { + if (w->events[i] == handle) + found = 1; + if (found) { + w->events[i] = w->events[i + 1]; + w->func[i] = w->func[i + 1]; + w->opaque[i] = w->opaque[i + 1]; } } - - if (arm_feature(env, ARM_FEATURE_M)) { - env->v7m.other_sp = qemu_get_be32(f); - env->v7m.vecbase = qemu_get_be32(f); - env->v7m.basepri = qemu_get_be32(f); - env->v7m.control = qemu_get_be32(f); - env->v7m.current_sp = qemu_get_be32(f); - env->v7m.exception = qemu_get_be32(f); - } - - return 0; + if (found) + w->num--; } - -#else - -//#warning No CPU save/restore functions - #endif /***********************************************************/ @@ -6776,12 +2922,17 @@ default: return -EINVAL; } + + if (qemu_file_has_error(f)) + return -EIO; + return 0; } static int ram_load_v1(QEMUFile *f, void *opaque) { - int i, ret; + int ret; + ram_addr_t i; if (qemu_get_be32(f) != phys_ram_size) return -EINVAL; @@ -6797,77 +2948,6 @@ #define IOBUF_SIZE 4096 #define RAM_CBLOCK_MAGIC 0xfabe -typedef struct RamCompressState { - z_stream zstream; - QEMUFile *f; - uint8_t buf[IOBUF_SIZE]; -} RamCompressState; - -static int ram_compress_open(RamCompressState *s, QEMUFile *f) -{ - int ret; - memset(s, 0, sizeof(*s)); - s->f = f; - ret = deflateInit2(&s->zstream, 1, - Z_DEFLATED, 15, - 9, Z_DEFAULT_STRATEGY); - if (ret != Z_OK) - return -1; - s->zstream.avail_out = IOBUF_SIZE; - s->zstream.next_out = s->buf; - return 0; -} - -static void ram_put_cblock(RamCompressState *s, const uint8_t *buf, int len) -{ - qemu_put_be16(s->f, RAM_CBLOCK_MAGIC); - qemu_put_be16(s->f, len); - qemu_put_buffer(s->f, buf, len); -} - -static int ram_compress_buf(RamCompressState *s, const uint8_t *buf, int len) -{ - int ret; - - s->zstream.avail_in = len; - s->zstream.next_in = (uint8_t *)buf; - while (s->zstream.avail_in > 0) { - ret = deflate(&s->zstream, Z_NO_FLUSH); - if (ret != Z_OK) - return -1; - if (s->zstream.avail_out == 0) { - ram_put_cblock(s, s->buf, IOBUF_SIZE); - s->zstream.avail_out = IOBUF_SIZE; - s->zstream.next_out = s->buf; - } - } - return 0; -} - -static void ram_compress_close(RamCompressState *s) -{ - int len, ret; - - /* compress last bytes */ - for(;;) { - ret = deflate(&s->zstream, Z_FINISH); - if (ret == Z_OK || ret == Z_STREAM_END) { - len = IOBUF_SIZE - s->zstream.avail_out; - if (len > 0) { - ram_put_cblock(s, s->buf, len); - } - s->zstream.avail_out = IOBUF_SIZE; - s->zstream.next_out = s->buf; - if (ret == Z_STREAM_END) - break; - } else { - goto fail; - } - } -fail: - deflateEnd(&s->zstream); -} - typedef struct RamDecompressState { z_stream zstream; QEMUFile *f; @@ -6915,61 +2995,121 @@ inflateEnd(&s->zstream); } -static void ram_save(QEMUFile *f, void *opaque) +#define RAM_SAVE_FLAG_FULL 0x01 +#define RAM_SAVE_FLAG_COMPRESS 0x02 +#define RAM_SAVE_FLAG_MEM_SIZE 0x04 +#define RAM_SAVE_FLAG_PAGE 0x08 +#define RAM_SAVE_FLAG_EOS 0x10 + +static int is_dup_page(uint8_t *page, uint8_t ch) { + uint32_t val = ch << 24 | ch << 16 | ch << 8 | ch; + uint32_t *array = (uint32_t *)page; int i; - RamCompressState s1, *s = &s1; - uint8_t buf[10]; - qemu_put_be32(f, phys_ram_size); - if (ram_compress_open(s, f) < 0) - return; - for(i = 0; i < phys_ram_size; i+= BDRV_HASH_BLOCK_SIZE) { -#if 0 - if (tight_savevm_enabled) { - int64_t sector_num; - int j; - - /* find if the memory block is available on a virtual - block device */ - sector_num = -1; - for(j = 0; j < nb_drives; j++) { - sector_num = bdrv_hash_find(drives_table[j].bdrv, - phys_ram_base + i, - BDRV_HASH_BLOCK_SIZE); - if (sector_num >= 0) - break; + for (i = 0; i < (TARGET_PAGE_SIZE / 4); i++) { + if (array[i] != val) + return 0; + } + + return 1; +} + +static int ram_save_block(QEMUFile *f) +{ + static ram_addr_t current_addr = 0; + ram_addr_t saved_addr = current_addr; + ram_addr_t addr = 0; + int found = 0; + + while (addr < phys_ram_size) { + if (cpu_physical_memory_get_dirty(current_addr, MIGRATION_DIRTY_FLAG)) { + uint8_t ch; + + cpu_physical_memory_reset_dirty(current_addr, + current_addr + TARGET_PAGE_SIZE, + MIGRATION_DIRTY_FLAG); + + ch = *(phys_ram_base + current_addr); + + if (is_dup_page(phys_ram_base + current_addr, ch)) { + qemu_put_be64(f, current_addr | RAM_SAVE_FLAG_COMPRESS); + qemu_put_byte(f, ch); + } else { + qemu_put_be64(f, current_addr | RAM_SAVE_FLAG_PAGE); + qemu_put_buffer(f, phys_ram_base + current_addr, TARGET_PAGE_SIZE); } - if (j == nb_drives) - goto normal_compress; - buf[0] = 1; - buf[1] = j; - cpu_to_be64wu((uint64_t *)(buf + 2), sector_num); - ram_compress_buf(s, buf, 10); - } else -#endif - { - // normal_compress: - buf[0] = 0; - ram_compress_buf(s, buf, 1); - ram_compress_buf(s, phys_ram_base + i, BDRV_HASH_BLOCK_SIZE); + + found = 1; + break; } + addr += TARGET_PAGE_SIZE; + current_addr = (saved_addr + addr) % phys_ram_size; } - ram_compress_close(s); + + return found; } -static int ram_load(QEMUFile *f, void *opaque, int version_id) +static ram_addr_t ram_save_threshold = 10; + +static ram_addr_t ram_save_remaining(void) +{ + ram_addr_t addr; + ram_addr_t count = 0; + + for (addr = 0; addr < phys_ram_size; addr += TARGET_PAGE_SIZE) { + if (cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) + count++; + } + + return count; +} + +static int ram_save_live(QEMUFile *f, int stage, void *opaque) +{ + ram_addr_t addr; + + if (stage == 1) { + /* Make sure all dirty bits are set */ + for (addr = 0; addr < phys_ram_size; addr += TARGET_PAGE_SIZE) { + if (!cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) + cpu_physical_memory_set_dirty(addr); + } + + /* Enable dirty memory tracking */ + cpu_physical_memory_set_dirty_tracking(1); + + qemu_put_be64(f, phys_ram_size | RAM_SAVE_FLAG_MEM_SIZE); + } + + while (!qemu_file_rate_limit(f)) { + int ret; + + ret = ram_save_block(f); + if (ret == 0) /* no more blocks */ + break; + } + + /* try transferring iterative blocks of memory */ + + if (stage == 3) { + cpu_physical_memory_set_dirty_tracking(0); + + /* flush all remaining blocks regardless of rate limiting */ + while (ram_save_block(f) != 0); + } + + qemu_put_be64(f, RAM_SAVE_FLAG_EOS); + + return (stage == 2) && (ram_save_remaining() < ram_save_threshold); +} + +static int ram_load_dead(QEMUFile *f, void *opaque) { RamDecompressState s1, *s = &s1; uint8_t buf[10]; - int i; + ram_addr_t i; - if (version_id == 1) - return ram_load_v1(f, opaque); - if (version_id != 2) - return -EINVAL; - if (qemu_get_be32(f) != phys_ram_size) - return -EINVAL; if (ram_decompress_open(s, f) < 0) return -EINVAL; for(i = 0; i < phys_ram_size; i+= BDRV_HASH_BLOCK_SIZE) { @@ -6979,39 +3119,74 @@ } if (buf[0] == 0) { if (ram_decompress_buf(s, phys_ram_base + i, BDRV_HASH_BLOCK_SIZE) < 0) { - fprintf(stderr, "Error while reading ram block address=0x%08x", i); - goto error; - } - } else -#if 0 - if (buf[0] == 1) { - int bs_index; - int64_t sector_num; - - ram_decompress_buf(s, buf + 1, 9); - bs_index = buf[1]; - sector_num = be64_to_cpupu((const uint64_t *)(buf + 2)); - if (bs_index >= nb_drives) { - fprintf(stderr, "Invalid block device index %d\n", bs_index); - goto error; - } - if (bdrv_read(drives_table[bs_index].bdrv, sector_num, - phys_ram_base + i, - BDRV_HASH_BLOCK_SIZE / 512) < 0) { - fprintf(stderr, "Error while reading sector %d:%" PRId64 "\n", - bs_index, sector_num); + fprintf(stderr, "Error while reading ram block address=0x%08" PRIx64, (uint64_t)i); goto error; } - } else -#endif - { + } else { error: printf("Error block header\n"); return -EINVAL; } } - ram_decompress_close(s); - return 0; + ram_decompress_close(s); + + return 0; +} + +static int ram_load(QEMUFile *f, void *opaque, int version_id) +{ + ram_addr_t addr; + int flags; + + if (version_id == 1) + return ram_load_v1(f, opaque); + + if (version_id == 2) { + if (qemu_get_be32(f) != phys_ram_size) + return -EINVAL; + return ram_load_dead(f, opaque); + } + + if (version_id != 3) + return -EINVAL; + + do { + addr = qemu_get_be64(f); + + flags = addr & ~TARGET_PAGE_MASK; + addr &= TARGET_PAGE_MASK; + + if (flags & RAM_SAVE_FLAG_MEM_SIZE) { + if (addr != phys_ram_size) + return -EINVAL; + } + + if (flags & RAM_SAVE_FLAG_FULL) { + if (ram_load_dead(f, opaque) < 0) + return -EINVAL; + } + + if (flags & RAM_SAVE_FLAG_COMPRESS) { + uint8_t ch = qemu_get_byte(f); + memset(phys_ram_base + addr, ch, TARGET_PAGE_SIZE); + } else if (flags & RAM_SAVE_FLAG_PAGE) + qemu_get_buffer(f, phys_ram_base + addr, TARGET_PAGE_SIZE); + } while (!(flags & RAM_SAVE_FLAG_EOS)); + + return 0; +} + +void qemu_service_io(void) +{ + CPUState *env = cpu_single_env; + if (env) { + cpu_interrupt(env, CPU_INTERRUPT_EXIT); +#ifdef USE_KQEMU + if (env->kqemu_enabled) { + kqemu_cpu_interrupt(env); + } +#endif + } } /***********************************************************/ @@ -7021,6 +3196,8 @@ QEMUBHFunc *cb; void *opaque; int scheduled; + int idle; + int deleted; QEMUBH *next; }; @@ -7034,37 +3211,56 @@ return NULL; bh->cb = cb; bh->opaque = opaque; + bh->next = first_bh; + first_bh = bh; return bh; } int qemu_bh_poll(void) { - QEMUBH *bh, **pbh; + QEMUBH *bh, **bhp; int ret; ret = 0; - for(;;) { - pbh = &first_bh; - bh = *pbh; - if (!bh) - break; - ret = 1; - *pbh = bh->next; - bh->scheduled = 0; - bh->cb(bh->opaque); + for (bh = first_bh; bh; bh = bh->next) { + if (!bh->deleted && bh->scheduled) { + bh->scheduled = 0; + if (!bh->idle) + ret = 1; + bh->idle = 0; + bh->cb(bh->opaque); + } + } + + /* remove deleted bhs */ + bhp = &first_bh; + while (*bhp) { + bh = *bhp; + if (bh->deleted) { + *bhp = bh->next; + qemu_free(bh); + } else + bhp = &bh->next; } + return ret; } +void qemu_bh_schedule_idle(QEMUBH *bh) +{ + if (bh->scheduled) + return; + bh->scheduled = 1; + bh->idle = 1; +} + void qemu_bh_schedule(QEMUBH *bh) { CPUState *env = cpu_single_env; if (bh->scheduled) return; bh->scheduled = 1; - bh->next = first_bh; - first_bh = bh; - + bh->idle = 0; /* stop the currently executing CPU to execute the BH ASAP */ if (env) { cpu_interrupt(env, CPU_INTERRUPT_EXIT); @@ -7073,26 +3269,39 @@ void qemu_bh_cancel(QEMUBH *bh) { - QEMUBH **pbh; - if (bh->scheduled) { - pbh = &first_bh; - while (*pbh != bh) - pbh = &(*pbh)->next; - *pbh = bh->next; - bh->scheduled = 0; - } + bh->scheduled = 0; } void qemu_bh_delete(QEMUBH *bh) { - qemu_bh_cancel(bh); - qemu_free(bh); + bh->scheduled = 0; + bh->deleted = 1; +} + +static void qemu_bh_update_timeout(int *timeout) +{ + QEMUBH *bh; + + for (bh = first_bh; bh; bh = bh->next) { + if (!bh->deleted && bh->scheduled) { + if (bh->idle) { + /* idle bottom halves will be polled at least + * every 10ms */ + *timeout = MIN(10, *timeout); + } else { + /* non-idle bottom halves will be executed + * immediately */ + *timeout = 0; + break; + } + } + } } /***********************************************************/ /* machine registration */ -QEMUMachine *first_machine = NULL; +static QEMUMachine *first_machine = NULL; int qemu_register_machine(QEMUMachine *m) { @@ -7123,7 +3332,11 @@ { DisplayState *ds = opaque; ds->dpy_refresh(ds); - qemu_mod_timer(ds->gui_timer, GUI_REFRESH_INTERVAL + qemu_get_clock(rt_clock)); + qemu_mod_timer(ds->gui_timer, + (ds->gui_timer_interval ? + ds->gui_timer_interval : + GUI_REFRESH_INTERVAL) + + qemu_get_clock(rt_clock)); } struct vm_change_state_entry { @@ -7217,6 +3430,27 @@ static int shutdown_requested; static int powerdown_requested; +int qemu_shutdown_requested(void) +{ + int r = shutdown_requested; + shutdown_requested = 0; + return r; +} + +int qemu_reset_requested(void) +{ + int r = reset_requested; + reset_requested = 0; + return r; +} + +int qemu_powerdown_requested(void) +{ + int r = powerdown_requested; + powerdown_requested = 0; + return r; +} + void qemu_register_reset(QEMUResetHandler *func, void *opaque) { QEMUResetEntry **pre, *re; @@ -7231,7 +3465,7 @@ *pre = re; } -static void qemu_system_reset(void) +void qemu_system_reset(void) { QEMUResetEntry *re; @@ -7266,15 +3500,10 @@ cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); } -void main_loop_wait(int timeout) -{ - IOHandlerRecord *ioh; - fd_set rfds, wfds, xfds; - int ret, nfds; #ifdef _WIN32 - int ret2, i; -#endif - struct timeval tv; +void host_main_loop_wait(int *timeout) +{ + int ret, ret2, i; PollingEntry *pe; @@ -7283,12 +3512,11 @@ for(pe = first_polling_entry; pe != NULL; pe = pe->next) { ret |= pe->func(pe->opaque); } -#ifdef _WIN32 if (ret == 0) { int err; WaitObjects *w = &wait_objects; - ret = WaitForMultipleObjects(w->num, w->events, FALSE, timeout); + ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout); if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) { if (w->func[ret - WAIT_OBJECT_0]) w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]); @@ -7313,7 +3541,26 @@ fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err); } } + + *timeout = 0; +} +#else +void host_main_loop_wait(int *timeout) +{ +} #endif + +void main_loop_wait(int timeout) +{ + IOHandlerRecord *ioh; + fd_set rfds, wfds, xfds; + int ret, nfds; + struct timeval tv; + + qemu_bh_update_timeout(&timeout); + + host_main_loop_wait(&timeout); + /* poll any events */ /* XXX: separate device handlers from system ones */ nfds = -1; @@ -7337,14 +3584,11 @@ } } - tv.tv_sec = 0; -#ifdef _WIN32 - tv.tv_usec = 0; -#else - tv.tv_usec = timeout * 1000; -#endif + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + #if defined(CONFIG_SLIRP) - if (slirp_inited) { + if (slirp_is_inited()) { slirp_select_fill(&nfds, &rfds, &wfds, &xfds); } #endif @@ -7373,7 +3617,7 @@ } } #if defined(CONFIG_SLIRP) - if (slirp_inited) { + if (slirp_is_inited()) { if (ret < 0) { FD_ZERO(&rfds); FD_ZERO(&wfds); @@ -7382,23 +3626,6 @@ slirp_select_poll(&rfds, &wfds, &xfds); } #endif - qemu_aio_poll(); - - if (vm_running) { - qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], - qemu_get_clock(vm_clock)); - /* run dma transfers, if any */ - DMA_run(); - } - - /* real time timers */ - qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], - qemu_get_clock(rt_clock)); - - if (alarm_timer->flags & ALARM_FLAG_EXPIRED) { - alarm_timer->flags &= ~(ALARM_FLAG_EXPIRED); - qemu_rearm_alarm_timer(alarm_timer); - } /* Check bottom-halves last in case any of the earlier events triggered them. */ @@ -7425,12 +3652,35 @@ #ifdef CONFIG_PROFILER ti = profile_getclock(); #endif + if (use_icount) { + int64_t count; + int decr; + qemu_icount -= (env->icount_decr.u16.low + env->icount_extra); + env->icount_decr.u16.low = 0; + env->icount_extra = 0; + count = qemu_next_deadline(); + count = (count + (1 << icount_time_shift) - 1) + >> icount_time_shift; + qemu_icount += count; + decr = (count > 0xffff) ? 0xffff : count; + count -= decr; + env->icount_decr.u16.low = decr; + env->icount_extra = count; + } ret = cpu_exec(env); #ifdef CONFIG_PROFILER qemu_time += profile_getclock() - ti; #endif + if (use_icount) { + /* Fold pending instructions back into the + instruction counter, and clear the interrupt flag. */ + qemu_icount -= (env->icount_decr.u16.low + + env->icount_extra); + env->icount_decr.u32 = 0; + env->icount_extra = 0; + } next_cpu = env->next_cpu ?: first_cpu; - if (event_pending) { + if (event_pending && likely(ret != EXCP_DEBUG)) { ret = EXCP_INTERRUPT; event_pending = 0; break; @@ -7450,7 +3700,12 @@ if (shutdown_requested) { ret = EXCP_INTERRUPT; - break; + if (no_shutdown) { + vm_stop(0); + no_shutdown = 0; + } + else + break; } if (reset_requested) { reset_requested = 0; @@ -7462,17 +3717,57 @@ qemu_system_powerdown(); ret = EXCP_INTERRUPT; } - if (ret == EXCP_DEBUG) { + if (unlikely(ret == EXCP_DEBUG)) { vm_stop(EXCP_DEBUG); } /* If all cpus are halted then wait until the next IRQ */ /* XXX: use timeout computed from timers */ - if (ret == EXCP_HALTED) - timeout = 10; - else + if (ret == EXCP_HALTED) { + if (use_icount) { + int64_t add; + int64_t delta; + /* Advance virtual time to the next event. */ + if (use_icount == 1) { + /* When not using an adaptive execution frequency + we tend to get badly out of sync with real time, + so just delay for a reasonable amount of time. */ + delta = 0; + } else { + delta = cpu_get_icount() - cpu_get_clock(); + } + if (delta > 0) { + /* If virtual time is ahead of real time then just + wait for IO. */ + timeout = (delta / 1000000) + 1; + } else { + /* Wait for either IO to occur or the next + timer event. */ + add = qemu_next_deadline(); + /* We advance the timer before checking for IO. + Limit the amount we advance so that early IO + activity won't get the guest too far ahead. */ + if (add > 10000000) + add = 10000000; + delta += add; + add = (add + (1 << icount_time_shift) - 1) + >> icount_time_shift; + qemu_icount += add; + timeout = delta / 1000000; + if (timeout < 0) + timeout = 0; + } + } else { + timeout = 5000; + } + } else { timeout = 0; + } } else { - timeout = 10; + if (shutdown_requested) { + ret = EXCP_INTERRUPT; + break; + } + timeout = 5000; } #ifdef CONFIG_PROFILER ti = profile_getclock(); @@ -7500,9 +3795,9 @@ "-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n" "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" - "-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][index=i]\n" - " [,cyls=c,heads=h,secs=s[,trans=t]][snapshot=on|off]" - " [,cache=on|off]\n" + "-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n" + " [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n" + " [,cache=writethrough|writeback|none][,format=f]\n" " use 'file' as a drive image\n" "-mtdblock file use 'file' as on-board Flash memory image\n" "-sd file use 'file' as SecureDigital card image\n" @@ -7531,6 +3826,8 @@ " use -soundhw ? to get the list of supported cards\n" " use -soundhw all to enable all of them\n" #endif + "-vga [std|cirrus|vmware]\n" + " select video card type\n" "-localtime set the real time clock to local time [default=utc]\n" "-full-screen start in full screen\n" #ifdef TARGET_I386 @@ -7542,6 +3839,7 @@ "-g WxH[xDEPTH] Set the initial graphical resolution and depth\n" #endif "-name string set the name of the guest\n" + "-uuid %%08x-%%04x-%%04x-%%04x-%%012x specify machine UUID\n" "\n" "Network options:\n" "-net nic[,vlan=n][,macaddr=addr][,model=type]\n" @@ -7566,9 +3864,26 @@ " connect the vlan 'n' to another VLAN using a socket connection\n" "-net socket[,vlan=n][,fd=h][,mcast=maddr:port]\n" " connect the vlan 'n' to multicast maddr and port\n" +#ifdef CONFIG_VDE + "-net vde[,vlan=n][,sock=socketpath][,port=n][,group=groupname][,mode=octalmode]\n" + " connect the vlan 'n' to port 'n' of a vde switch running\n" + " on host and listening for incoming connections on 'socketpath'.\n" + " Use group 'groupname' and mode 'octalmode' to change default\n" + " ownership and permissions for communication port.\n" +#endif "-net none use it alone to have zero network devices; if no -net option\n" " is provided, the default is '-net nic -net user'\n" "\n" + "-bt hci,null Dumb bluetooth HCI - doesn't respond to commands\n" + "-bt hci,host[:id]\n" + " Use host's HCI with the given name\n" + "-bt hci[,vlan=n]\n" + " Emulate a standard HCI in virtual scatternet 'n'\n" + "-bt vhci[,vlan=n]\n" + " Add host computer to virtual scatternet 'n' using VHCI\n" + "-bt device:dev[,vlan=n]\n" + " Emulate a bluetooth device 'dev' in scatternet 'n'\n" + "\n" #ifdef CONFIG_SLIRP "-tftp dir allow tftp access to files in dir [-net user]\n" "-bootp file advertise file in BOOTP replies\n" @@ -7600,13 +3915,18 @@ "-kernel-kqemu enable KQEMU full virtualization (default is user mode only)\n" "-no-kqemu disable KQEMU kernel module usage\n" #endif +#ifdef CONFIG_KVM + "-enable-kvm enable KVM full virtualization support\n" +#endif #ifdef TARGET_I386 - "-std-vga simulate a standard VGA card with VESA Bochs Extensions\n" - " (default is CL-GD5446 PCI VGA)\n" "-no-acpi disable ACPI\n" #endif +#ifdef CONFIG_CURSES + "-curses use a curses/ncurses interface instead of SDL\n" +#endif "-no-reboot exit instead of rebooting\n" - "-loadvm file start right away with a saved state (loadvm in monitor)\n" + "-no-shutdown stop before shutdown\n" + "-loadvm [tag|id] start right away with a saved state (loadvm in monitor)\n" "-vnc display start a VNC server on display\n" #ifndef _WIN32 "-daemonize daemonize QEMU after initializing\n" @@ -7616,7 +3936,10 @@ "-prom-env variable=value set OpenBIOS nvram variables\n" #endif "-clock force the use of the given methods for timer alarm.\n" - " To see what timers are available use -clock help\n" + " To see what timers are available use -clock ?\n" + "-startdate select initial date of the clock\n" + "-icount [N|auto]\n" + " Enable virtual instruction counter with 2^N clock ticks per instruction\n" "\n" "During emulation, the following keys are useful:\n" "ctrl-alt-f toggle full screen\n" @@ -7672,6 +3995,7 @@ QEMU_OPTION_bootp, QEMU_OPTION_smb, QEMU_OPTION_redir, + QEMU_OPTION_bt, QEMU_OPTION_kernel, QEMU_OPTION_append, @@ -7684,13 +4008,10 @@ QEMU_OPTION_hdachs, QEMU_OPTION_L, QEMU_OPTION_bios, - QEMU_OPTION_no_code_copy, QEMU_OPTION_k, QEMU_OPTION_localtime, - QEMU_OPTION_cirrusvga, - QEMU_OPTION_vmsvga, QEMU_OPTION_g, - QEMU_OPTION_std_vga, + QEMU_OPTION_vga, QEMU_OPTION_echr, QEMU_OPTION_monitor, QEMU_OPTION_serial, @@ -7703,13 +4024,16 @@ QEMU_OPTION_pidfile, QEMU_OPTION_no_kqemu, QEMU_OPTION_kernel_kqemu, + QEMU_OPTION_enable_kvm, QEMU_OPTION_win2k_hack, QEMU_OPTION_usb, QEMU_OPTION_usbdevice, QEMU_OPTION_smp, QEMU_OPTION_vnc, QEMU_OPTION_no_acpi, + QEMU_OPTION_curses, QEMU_OPTION_no_reboot, + QEMU_OPTION_no_shutdown, QEMU_OPTION_show_cursor, QEMU_OPTION_daemonize, QEMU_OPTION_option_rom, @@ -7719,6 +4043,10 @@ QEMU_OPTION_old_param, QEMU_OPTION_clock, QEMU_OPTION_startdate, + QEMU_OPTION_tb_size, + QEMU_OPTION_icount, + QEMU_OPTION_uuid, + QEMU_OPTION_incoming, }; typedef struct QEMUOption { @@ -7727,7 +4055,7 @@ int index; } QEMUOption; -const QEMUOption qemu_options[] = { +static const QEMUOption qemu_options[] = { { "h", 0, QEMU_OPTION_h }, { "help", 0, QEMU_OPTION_h }, @@ -7767,6 +4095,7 @@ #endif { "redir", HAS_ARG, QEMU_OPTION_redir }, #endif + { "bt", HAS_ARG, QEMU_OPTION_bt }, { "kernel", HAS_ARG, QEMU_OPTION_kernel }, { "append", HAS_ARG, QEMU_OPTION_append }, @@ -7779,16 +4108,18 @@ { "hdachs", HAS_ARG, QEMU_OPTION_hdachs }, { "L", HAS_ARG, QEMU_OPTION_L }, { "bios", HAS_ARG, QEMU_OPTION_bios }, - { "no-code-copy", 0, QEMU_OPTION_no_code_copy }, #ifdef USE_KQEMU { "no-kqemu", 0, QEMU_OPTION_no_kqemu }, { "kernel-kqemu", 0, QEMU_OPTION_kernel_kqemu }, #endif +#ifdef CONFIG_KVM + { "enable-kvm", 0, QEMU_OPTION_enable_kvm }, +#endif #if defined(TARGET_PPC) || defined(TARGET_SPARC) { "g", 1, QEMU_OPTION_g }, #endif { "localtime", 0, QEMU_OPTION_localtime }, - { "std-vga", 0, QEMU_OPTION_std_vga }, + { "vga", HAS_ARG, QEMU_OPTION_vga }, { "echr", HAS_ARG, QEMU_OPTION_echr }, { "monitor", HAS_ARG, QEMU_OPTION_monitor }, { "serial", HAS_ARG, QEMU_OPTION_serial }, @@ -7805,13 +4136,16 @@ { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, { "smp", HAS_ARG, QEMU_OPTION_smp }, { "vnc", HAS_ARG, QEMU_OPTION_vnc }, +#ifdef CONFIG_CURSES + { "curses", 0, QEMU_OPTION_curses }, +#endif + { "uuid", HAS_ARG, QEMU_OPTION_uuid }, /* temporary options */ { "usb", 0, QEMU_OPTION_usb }, - { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, - { "vmwarevga", 0, QEMU_OPTION_vmsvga }, { "no-acpi", 0, QEMU_OPTION_no_acpi }, { "no-reboot", 0, QEMU_OPTION_no_reboot }, + { "no-shutdown", 0, QEMU_OPTION_no_shutdown }, { "show-cursor", 0, QEMU_OPTION_show_cursor }, { "daemonize", 0, QEMU_OPTION_daemonize }, { "option-rom", HAS_ARG, QEMU_OPTION_option_rom }, @@ -7827,6 +4161,9 @@ #endif { "clock", HAS_ARG, QEMU_OPTION_clock }, { "startdate", HAS_ARG, QEMU_OPTION_startdate }, + { "tb-size", HAS_ARG, QEMU_OPTION_tb_size }, + { "icount", HAS_ARG, QEMU_OPTION_icount }, + { "incoming", HAS_ARG, QEMU_OPTION_incoming }, { NULL }, }; @@ -7869,70 +4206,10 @@ } } -/* XXX: currently we cannot use simultaneously different CPUs */ -static void register_machines(void) -{ -#if defined(TARGET_I386) - qemu_register_machine(&pc_machine); - qemu_register_machine(&isapc_machine); -#elif defined(TARGET_PPC) - qemu_register_machine(&heathrow_machine); - qemu_register_machine(&core99_machine); - qemu_register_machine(&prep_machine); - qemu_register_machine(&ref405ep_machine); - qemu_register_machine(&taihu_machine); -#elif defined(TARGET_MIPS) - qemu_register_machine(&mips_machine); - qemu_register_machine(&mips_malta_machine); - qemu_register_machine(&mips_pica61_machine); - qemu_register_machine(&mips_mipssim_machine); -#elif defined(TARGET_SPARC) -#ifdef TARGET_SPARC64 - qemu_register_machine(&sun4u_machine); -#else - qemu_register_machine(&ss5_machine); - qemu_register_machine(&ss10_machine); - qemu_register_machine(&ss600mp_machine); - qemu_register_machine(&ss20_machine); - qemu_register_machine(&ss2_machine); - qemu_register_machine(&ss1000_machine); - qemu_register_machine(&ss2000_machine); -#endif -#elif defined(TARGET_ARM) - qemu_register_machine(&integratorcp_machine); - qemu_register_machine(&versatilepb_machine); - qemu_register_machine(&versatileab_machine); - qemu_register_machine(&realview_machine); - qemu_register_machine(&akitapda_machine); - qemu_register_machine(&spitzpda_machine); - qemu_register_machine(&borzoipda_machine); - qemu_register_machine(&terrierpda_machine); - qemu_register_machine(&palmte_machine); - qemu_register_machine(&lm3s811evb_machine); - qemu_register_machine(&lm3s6965evb_machine); - qemu_register_machine(&connex_machine); - qemu_register_machine(&verdex_machine); - qemu_register_machine(&mainstone2_machine); -#elif defined(TARGET_SH4) - qemu_register_machine(&shix_machine); - qemu_register_machine(&r2d_machine); -#elif defined(TARGET_ALPHA) - /* XXX: TODO */ -#elif defined(TARGET_M68K) - qemu_register_machine(&mcf5208evb_machine); - qemu_register_machine(&an5206_machine); - qemu_register_machine(&dummy_m68k_machine); -#elif defined(TARGET_CRIS) - qemu_register_machine(&bareetraxfs_machine); -#else -#error unsupported CPU -#endif -} - #ifdef HAS_AUDIO struct soundhw soundhw[] = { #ifdef HAS_AUDIO_CHOICE -#ifdef TARGET_I386 +#if defined(TARGET_I386) || defined(TARGET_MIPS) { "pcspk", "PC speaker", @@ -7949,6 +4226,16 @@ { .init_isa = SB16_init } }, +#ifdef CONFIG_CS4231A + { + "cs4231a", + "CS4231A", + 0, + 1, + { .init_isa = cs4231a_init } + }, +#endif + #ifdef CONFIG_ADLIB { "adlib", @@ -7973,6 +4260,16 @@ }, #endif +#ifdef CONFIG_AC97 + { + "ac97", + "Intel 82801AA AC97 Audio", + 0, + 0, + { .init_pci = ac97_init } + }, +#endif + { "es1370", "ENSONIQ AudioPCI ES1370", @@ -8044,6 +4341,39 @@ } #endif +static void select_vgahw (const char *p) +{ + const char *opts; + + if (strstart(p, "std", &opts)) { + cirrus_vga_enabled = 0; + vmsvga_enabled = 0; + } else if (strstart(p, "cirrus", &opts)) { + cirrus_vga_enabled = 1; + vmsvga_enabled = 0; + } else if (strstart(p, "vmware", &opts)) { + cirrus_vga_enabled = 0; + vmsvga_enabled = 1; + } else { + invalid_vga: + fprintf(stderr, "Unknown vga type: %s\n", p); + exit(1); + } + while (*opts) { + const char *nextopt; + + if (strstart(opts, ",retrace=", &nextopt)) { + opts = nextopt; + if (strstart(opts, "dumb", &nextopt)) + vga_retrace_method = VGA_RETRACE_DUMB; + else if (strstart(opts, "precise", &nextopt)) + vga_retrace_method = VGA_RETRACE_PRECISE; + else goto invalid_vga; + } else goto invalid_vga; + opts = nextopt; + } +} + #ifdef _WIN32 static BOOL WINAPI qemu_ctrl_handler(DWORD type) { @@ -8052,8 +4382,45 @@ } #endif +static int qemu_uuid_parse(const char *str, uint8_t *uuid) +{ + int ret; + + if(strlen(str) != 36) + return -1; + + ret = sscanf(str, UUID_FMT, &uuid[0], &uuid[1], &uuid[2], &uuid[3], + &uuid[4], &uuid[5], &uuid[6], &uuid[7], &uuid[8], &uuid[9], + &uuid[10], &uuid[11], &uuid[12], &uuid[13], &uuid[14], &uuid[15]); + + if(ret != 16) + return -1; + + return 0; +} + #define MAX_NET_CLIENTS 32 +#ifndef _WIN32 + +static void termsig_handler(int signal) +{ + qemu_system_shutdown_request(); +} + +static void termsig_setup(void) +{ + struct sigaction act; + + memset(&act, 0, sizeof(act)); + act.sa_handler = termsig_handler; + sigaction(SIGINT, &act, NULL); + sigaction(SIGHUP, &act, NULL); + sigaction(SIGTERM, &act, NULL); +} + +#endif + int main(int argc, char **argv) { #ifdef CONFIG_GDBSTUB @@ -8068,25 +4435,29 @@ const char *boot_devices = ""; DisplayState *ds = &display_state; int cyls, heads, secs, translation; - char net_clients[MAX_NET_CLIENTS][256]; + const char *net_clients[MAX_NET_CLIENTS]; int nb_net_clients; + const char *bt_opts[MAX_BT_CMDLINE]; + int nb_bt_opts; int hda_index; int optind; const char *r, *optarg; CharDriverState *monitor_hd; - char monitor_device[128]; - char serial_devices[MAX_SERIAL_PORTS][128]; + const char *monitor_device; + const char *serial_devices[MAX_SERIAL_PORTS]; int serial_device_index; - char parallel_devices[MAX_PARALLEL_PORTS][128]; + const char *parallel_devices[MAX_PARALLEL_PORTS]; int parallel_device_index; const char *loadvm = NULL; QEMUMachine *machine; const char *cpu_model; - char usb_devices[MAX_USB_CMDLINE][128]; + const char *usb_devices[MAX_USB_CMDLINE]; int usb_devices_index; int fds[2]; + int tb_size; const char *pid_file = NULL; - VLANState *vlan; + int autostart; + const char *incoming = NULL; LIST_INIT (&vm_change_state_head); #ifndef _WIN32 @@ -8123,7 +4494,7 @@ machine = first_machine; cpu_model = NULL; initrd_filename = NULL; - ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; + ram_size = 0; vga_ram_size = VGA_RAM_SIZE; #ifdef CONFIG_GDBSTUB use_gdbstub = 0; @@ -8131,31 +4502,35 @@ #endif snapshot = 0; nographic = 0; + curses = 0; kernel_filename = NULL; kernel_cmdline = ""; cyls = heads = secs = 0; translation = BIOS_ATA_TRANSLATION_AUTO; - pstrcpy(monitor_device, sizeof(monitor_device), "vc"); + monitor_device = "vc"; - pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "vc"); + serial_devices[0] = "vc:80Cx24C"; for(i = 1; i < MAX_SERIAL_PORTS; i++) - serial_devices[i][0] = '\0'; + serial_devices[i] = NULL; serial_device_index = 0; - pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "vc"); + parallel_devices[0] = "vc:640x480"; for(i = 1; i < MAX_PARALLEL_PORTS; i++) - parallel_devices[i][0] = '\0'; + parallel_devices[i] = NULL; parallel_device_index = 0; usb_devices_index = 0; nb_net_clients = 0; + nb_bt_opts = 0; nb_drives = 0; nb_drives_opt = 0; hda_index = -1; nb_nics = 0; - /* default mac address of the first network interface */ + + tb_size = 0; + autostart= 1; optind = 1; for(;;) { @@ -8163,7 +4538,7 @@ break; r = argv[optind]; if (r[0] != '-') { - hda_index = drive_add(HD_ALIAS, argv[optind++], 0); + hda_index = drive_add(argv[optind++], HD_ALIAS, 0); } else { const QEMUOption *popt; @@ -8224,11 +4599,11 @@ break; case QEMU_OPTION_hda: if (cyls == 0) - hda_index = drive_add(HD_ALIAS, optarg, 0); + hda_index = drive_add(optarg, HD_ALIAS, 0); else - hda_index = drive_add(HD_ALIAS + hda_index = drive_add(optarg, HD_ALIAS ",cyls=%d,heads=%d,secs=%d%s", - optarg, 0, cyls, heads, secs, + 0, cyls, heads, secs, translation == BIOS_ATA_TRANSLATION_LBA ? ",trans=lba" : translation == BIOS_ATA_TRANSLATION_NONE ? @@ -8237,19 +4612,19 @@ case QEMU_OPTION_hdb: case QEMU_OPTION_hdc: case QEMU_OPTION_hdd: - drive_add(HD_ALIAS, optarg, popt->index - QEMU_OPTION_hda); + drive_add(optarg, HD_ALIAS, popt->index - QEMU_OPTION_hda); break; case QEMU_OPTION_drive: - drive_add("%s", optarg); + drive_add(NULL, "%s", optarg); break; case QEMU_OPTION_mtdblock: - drive_add(MTD_ALIAS, optarg); + drive_add(optarg, MTD_ALIAS); break; case QEMU_OPTION_sd: - drive_add("file=\"%s\"," SD_ALIAS, optarg); + drive_add(optarg, SD_ALIAS); break; case QEMU_OPTION_pflash: - drive_add(PFLASH_ALIAS, optarg); + drive_add(optarg, PFLASH_ALIAS); break; case QEMU_OPTION_snapshot: snapshot = 1; @@ -8289,12 +4664,10 @@ exit(1); } if (hda_index != -1) - snprintf(drives_opt[hda_index] + - strlen(drives_opt[hda_index]), - sizeof(drives_opt[0]) - - strlen(drives_opt[hda_index]), - ",cyls=%d,heads=%d,secs=%d%s", - cyls, heads, secs, + snprintf(drives_opt[hda_index].opt, + sizeof(drives_opt[hda_index].opt), + HD_ALIAS ",cyls=%d,heads=%d,secs=%d%s", + 0, cyls, heads, secs, translation == BIOS_ATA_TRANSLATION_LBA ? ",trans=lba" : translation == BIOS_ATA_TRANSLATION_NONE ? @@ -8302,11 +4675,13 @@ } break; case QEMU_OPTION_nographic: - pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio"); - pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "null"); - pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); nographic = 1; break; +#ifdef CONFIG_CURSES + case QEMU_OPTION_curses: + curses = 1; + break; +#endif case QEMU_OPTION_portrait: graphic_rotate = 1; break; @@ -8317,7 +4692,7 @@ kernel_cmdline = optarg; break; case QEMU_OPTION_cdrom: - drive_add("file=\"%s\"," CDROM_ALIAS, optarg); + drive_add(optarg, CDROM_ALIAS); break; case QEMU_OPTION_boot: boot_devices = optarg; @@ -8352,25 +4727,19 @@ break; case QEMU_OPTION_fda: case QEMU_OPTION_fdb: - drive_add("file=\"%s\"," FD_ALIAS, optarg, - popt->index - QEMU_OPTION_fda); + drive_add(optarg, FD_ALIAS, popt->index - QEMU_OPTION_fda); break; #ifdef TARGET_I386 case QEMU_OPTION_no_fd_bootchk: fd_bootchk = 0; break; #endif - case QEMU_OPTION_no_code_copy: - code_copy_enabled = 0; - break; case QEMU_OPTION_net: if (nb_net_clients >= MAX_NET_CLIENTS) { fprintf(stderr, "qemu: too many network clients\n"); exit(1); } - pstrcpy(net_clients[nb_net_clients], - sizeof(net_clients[0]), - optarg); + net_clients[nb_net_clients] = optarg; nb_net_clients++; break; #ifdef CONFIG_SLIRP @@ -8389,6 +4758,13 @@ net_slirp_redir(optarg); break; #endif + case QEMU_OPTION_bt: + if (nb_bt_opts >= MAX_BT_CMDLINE) { + fprintf(stderr, "qemu: too many bluetooth options\n"); + exit(1); + } + bt_opts[nb_bt_opts++] = optarg; + break; #ifdef HAS_AUDIO case QEMU_OPTION_audio_help: AUD_help (); @@ -8401,20 +4777,43 @@ case QEMU_OPTION_h: help(0); break; - case QEMU_OPTION_m: - ram_size = atoi(optarg) * 1024 * 1024; - if (ram_size <= 0) - help(1); - if (ram_size > PHYS_RAM_MAX_SIZE) { - fprintf(stderr, "qemu: at most %d MB RAM can be simulated\n", - PHYS_RAM_MAX_SIZE / (1024 * 1024)); + case QEMU_OPTION_m: { + uint64_t value; + char *ptr; + + value = strtoul(optarg, &ptr, 10); + switch (*ptr) { + case 0: case 'M': case 'm': + value <<= 20; + break; + case 'G': case 'g': + value <<= 30; + break; + default: + fprintf(stderr, "qemu: invalid ram size: %s\n", optarg); + exit(1); + } + + /* On 32-bit hosts, QEMU is limited by virtual address space */ + if (value > (2047 << 20) +#ifndef USE_KQEMU + && HOST_LONG_BITS == 32 +#endif + ) { + fprintf(stderr, "qemu: at most 2047 MB RAM can be simulated\n"); + exit(1); + } + if (value != (uint64_t)(ram_addr_t)value) { + fprintf(stderr, "qemu: ram size too large\n"); exit(1); } + ram_size = value; break; + } case QEMU_OPTION_d: { int mask; - CPULogItem *item; + const CPULogItem *item; mask = cpu_str_to_log_mask(optarg); if (!mask) { @@ -8450,17 +4849,8 @@ case QEMU_OPTION_localtime: rtc_utc = 0; break; - case QEMU_OPTION_cirrusvga: - cirrus_vga_enabled = 1; - vmsvga_enabled = 0; - break; - case QEMU_OPTION_vmsvga: - cirrus_vga_enabled = 0; - vmsvga_enabled = 1; - break; - case QEMU_OPTION_std_vga: - cirrus_vga_enabled = 0; - vmsvga_enabled = 0; + case QEMU_OPTION_vga: + select_vgahw (optarg); break; case QEMU_OPTION_g: { @@ -8505,15 +4895,14 @@ break; } case QEMU_OPTION_monitor: - pstrcpy(monitor_device, sizeof(monitor_device), optarg); + monitor_device = optarg; break; case QEMU_OPTION_serial: if (serial_device_index >= MAX_SERIAL_PORTS) { fprintf(stderr, "qemu: too many serial ports\n"); exit(1); } - pstrcpy(serial_devices[serial_device_index], - sizeof(serial_devices[0]), optarg); + serial_devices[serial_device_index] = optarg; serial_device_index++; break; case QEMU_OPTION_parallel: @@ -8521,8 +4910,7 @@ fprintf(stderr, "qemu: too many parallel ports\n"); exit(1); } - pstrcpy(parallel_devices[parallel_device_index], - sizeof(parallel_devices[0]), optarg); + parallel_devices[parallel_device_index] = optarg; parallel_device_index++; break; case QEMU_OPTION_loadvm: @@ -8558,6 +4946,14 @@ kqemu_allowed = 2; break; #endif +#ifdef CONFIG_KVM + case QEMU_OPTION_enable_kvm: + kvm_allowed = 1; +#ifdef USE_KQEMU + kqemu_allowed = 0; +#endif + break; +#endif case QEMU_OPTION_usb: usb_enabled = 1; break; @@ -8567,14 +4963,12 @@ fprintf(stderr, "Too many USB devices\n"); exit(1); } - pstrcpy(usb_devices[usb_devices_index], - sizeof(usb_devices[usb_devices_index]), - optarg); + usb_devices[usb_devices_index] = optarg; usb_devices_index++; break; case QEMU_OPTION_smp: smp_cpus = atoi(optarg); - if (smp_cpus < 1 || smp_cpus > MAX_CPUS) { + if (smp_cpus < 1) { fprintf(stderr, "Invalid number of CPUs\n"); exit(1); } @@ -8588,9 +4982,19 @@ case QEMU_OPTION_no_reboot: no_reboot = 1; break; + case QEMU_OPTION_no_shutdown: + no_shutdown = 1; + break; case QEMU_OPTION_show_cursor: cursor_hide = 0; break; + case QEMU_OPTION_uuid: + if(qemu_uuid_parse(optarg, qemu_uuid) < 0) { + fprintf(stderr, "Fail to parse UUID string." + " Wrong format.\n"); + exit(1); + } + break; case QEMU_OPTION_daemonize: daemonize = 1; break; @@ -8621,6 +5025,7 @@ #ifdef TARGET_ARM case QEMU_OPTION_old_param: old_param = 1; + break; #endif case QEMU_OPTION_clock: configure_alarms(optarg); @@ -8628,8 +5033,9 @@ case QEMU_OPTION_startdate: { struct tm tm; + time_t rtc_start_date; if (!strcmp(optarg, "now")) { - rtc_start_date = -1; + rtc_date_offset = -1; } else { if (sscanf(optarg, "%d-%d-%dT%d:%d:%d", &tm.tm_year, @@ -8658,19 +5064,56 @@ "'now' or '2006-06-17T16:01:21' or '2006-06-17'\n"); exit(1); } + rtc_date_offset = time(NULL) - rtc_start_date; } } break; + case QEMU_OPTION_tb_size: + tb_size = strtol(optarg, NULL, 0); + if (tb_size < 0) + tb_size = 0; + break; + case QEMU_OPTION_icount: + use_icount = 1; + if (strcmp(optarg, "auto") == 0) { + icount_time_shift = -1; + } else { + icount_time_shift = strtol(optarg, NULL, 0); + } + break; + case QEMU_OPTION_incoming: + incoming = optarg; + break; } } } -#ifndef _WIN32 - if (daemonize && !nographic && vnc_display == NULL) { - fprintf(stderr, "Can only daemonize if using -nographic or -vnc\n"); - daemonize = 0; +#if defined(CONFIG_KVM) && defined(USE_KQEMU) + if (kvm_allowed && kqemu_allowed) { + fprintf(stderr, + "You can not enable both KVM and kqemu at the same time\n"); + exit(1); + } +#endif + + machine->max_cpus = machine->max_cpus ?: 1; /* Default to UP */ + if (smp_cpus > machine->max_cpus) { + fprintf(stderr, "Number of SMP cpus requested (%d), exceeds max cpus " + "supported by machine `%s' (%d)\n", smp_cpus, machine->name, + machine->max_cpus); + exit(1); + } + + if (nographic) { + if (serial_device_index == 0) + serial_devices[0] = "stdio"; + if (parallel_device_index == 0) + parallel_devices[0] = "null"; + if (strncmp(monitor_device, "vc", 2) == 0) + monitor_device = "stdio"; } +#ifndef _WIN32 if (daemonize) { pid_t pid; @@ -8708,7 +5151,6 @@ exit(1); umask(027); - chdir("/"); signal(SIGTSTP, SIG_IGN); signal(SIGTTOU, SIG_IGN); @@ -8732,11 +5174,20 @@ linux_boot = (kernel_filename != NULL); net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF; - /* XXX: this should not be: some embedded targets just have flash */ if (!linux_boot && net_boot == 0 && - nb_drives_opt == 0) + !machine->nodisk_ok && nb_drives_opt == 0) help(1); + if (!linux_boot && *kernel_cmdline != '\0') { + fprintf(stderr, "-append only allowed with -kernel option\n"); + exit(1); + } + + if (!linux_boot && initrd_filename != NULL) { + fprintf(stderr, "-initrd only allowed with -kernel option\n"); + exit(1); + } + /* boot to floppy or the default cd if no hard disk defined yet */ if (!boot_devices[0]) { boot_devices = "cad"; @@ -8744,8 +5195,17 @@ setvbuf(stdout, NULL, _IOLBF, 0); init_timers(); - init_timer_alarm(); - qemu_aio_init(); + if (init_timer_alarm() < 0) { + fprintf(stderr, "could not initialize alarm timer\n"); + exit(1); + } + if (use_icount && icount_time_shift < 0) { + use_icount = 2; + /* 125MIPS seems a reasonable initial guess at the guest speed. + It will be corrected fairly quickly anyway. */ + icount_time_shift = 3; + init_icount_adjust(); + } #ifdef _WIN32 socket_init(); @@ -8754,29 +5214,17 @@ /* init network clients */ if (nb_net_clients == 0) { /* if no clients, we use a default config */ - pstrcpy(net_clients[0], sizeof(net_clients[0]), - "nic"); - pstrcpy(net_clients[1], sizeof(net_clients[0]), - "user"); - nb_net_clients = 2; + net_clients[nb_net_clients++] = "nic"; +#ifdef CONFIG_SLIRP + net_clients[nb_net_clients++] = "user"; +#endif } for(i = 0;i < nb_net_clients; i++) { - if (net_client_init(net_clients[i]) < 0) - exit(1); - } - for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { - if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0) - continue; - if (vlan->nb_guest_devs == 0) { - fprintf(stderr, "Invalid vlan (%d) with no nics\n", vlan->id); + if (net_client_parse(net_clients[i]) < 0) exit(1); - } - if (vlan->nb_host_devs == 0) - fprintf(stderr, - "Warning: vlan %d is not connected to host network\n", - vlan->id); } + net_client_check(); #ifdef TARGET_I386 /* XXX: this should be moved in the PC machine instantiation code */ @@ -8807,8 +5255,31 @@ } #endif + /* init the bluetooth world */ + for (i = 0; i < nb_bt_opts; i++) + if (bt_parse(bt_opts[i])) + exit(1); + /* init the memory */ - phys_ram_size = ram_size + vga_ram_size + MAX_BIOS_SIZE; + phys_ram_size = machine->ram_require & ~RAMSIZE_FIXED; + + if (machine->ram_require & RAMSIZE_FIXED) { + if (ram_size > 0) { + if (ram_size < phys_ram_size) { + fprintf(stderr, "Machine `%s' requires %llu bytes of memory\n", + machine->name, (unsigned long long) phys_ram_size); + exit(-1); + } + + phys_ram_size = ram_size; + } else + ram_size = phys_ram_size; + } else { + if (ram_size == 0) + ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; + + phys_ram_size += ram_size; + } phys_ram_base = qemu_vmalloc(phys_ram_size); if (!phys_ram_base) { @@ -8816,44 +5287,55 @@ exit(1); } + /* init the dynamic translator */ + cpu_exec_init_all(tb_size * 1024 * 1024); + bdrv_init(); /* we always create the cdrom drive, even if no disk is there */ if (nb_drives_opt < MAX_DRIVES) - drive_add(CDROM_ALIAS); + drive_add(NULL, CDROM_ALIAS); /* we always create at least one floppy */ if (nb_drives_opt < MAX_DRIVES) - drive_add(FD_ALIAS, 0); + drive_add(NULL, FD_ALIAS, 0); /* we always create one sd slot, even if no card is in it */ if (nb_drives_opt < MAX_DRIVES) - drive_add(SD_ALIAS); + drive_add(NULL, SD_ALIAS); /* open the virtual block devices */ for(i = 0; i < nb_drives_opt; i++) - if (drive_init(drives_opt[i], snapshot, machine) == -1) + if (drive_init(&drives_opt[i], snapshot, machine) == -1) exit(1); register_savevm("timer", 0, 2, timer_save, timer_load, NULL); - register_savevm("ram", 0, 2, ram_save, ram_load, NULL); - - init_ioports(); + register_savevm_live("ram", 0, 3, ram_save_live, NULL, ram_load, NULL); /* terminal init */ memset(&display_state, 0, sizeof(display_state)); if (nographic) { + if (curses) { + fprintf(stderr, "fatal: -nographic can't be used with -curses\n"); + exit(1); + } /* nearly nothing to do */ dumb_display_init(ds); } else if (vnc_display != NULL) { vnc_display_init(ds); if (vnc_display_open(ds, vnc_display) < 0) exit(1); - } else { + } else +#if defined(CONFIG_CURSES) + if (curses) { + curses_display_init(ds, full_screen); + } else +#endif + { #if defined(CONFIG_SDL) sdl_display_init(ds, full_screen, no_frame); #elif defined(CONFIG_COCOA) @@ -8863,21 +5345,27 @@ #endif } +#ifndef _WIN32 + /* must be after terminal init, SDL library changes signal handlers */ + termsig_setup(); +#endif + /* Maintain compatibility with multiple stdio monitors */ if (!strcmp(monitor_device,"stdio")) { for (i = 0; i < MAX_SERIAL_PORTS; i++) { - if (!strcmp(serial_devices[i],"mon:stdio")) { - monitor_device[0] = '\0'; + const char *devname = serial_devices[i]; + if (devname && !strcmp(devname,"mon:stdio")) { + monitor_device = NULL; break; - } else if (!strcmp(serial_devices[i],"stdio")) { - monitor_device[0] = '\0'; - pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "mon:stdio"); + } else if (devname && !strcmp(devname,"stdio")) { + monitor_device = NULL; + serial_devices[i] = "mon:stdio"; break; } } } - if (monitor_device[0] != '\0') { - monitor_hd = qemu_chr_open(monitor_device); + if (monitor_device) { + monitor_hd = qemu_chr_open("monitor", monitor_device); if (!monitor_hd) { fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device); exit(1); @@ -8887,8 +5375,10 @@ for(i = 0; i < MAX_SERIAL_PORTS; i++) { const char *devname = serial_devices[i]; - if (devname[0] != '\0' && strcmp(devname, "none")) { - serial_hds[i] = qemu_chr_open(devname); + if (devname && strcmp(devname, "none")) { + char label[32]; + snprintf(label, sizeof(label), "serial%d", i); + serial_hds[i] = qemu_chr_open(label, devname); if (!serial_hds[i]) { fprintf(stderr, "qemu: could not open serial device '%s'\n", devname); @@ -8901,8 +5391,10 @@ for(i = 0; i < MAX_PARALLEL_PORTS; i++) { const char *devname = parallel_devices[i]; - if (devname[0] != '\0' && strcmp(devname, "none")) { - parallel_hds[i] = qemu_chr_open(devname); + if (devname && strcmp(devname, "none")) { + char label[32]; + snprintf(label, sizeof(label), "parallel%d", i); + parallel_hds[i] = qemu_chr_open(label, devname); if (!parallel_hds[i]) { fprintf(stderr, "qemu: could not open parallel device '%s'\n", devname); @@ -8913,6 +5405,16 @@ } } + if (kvm_enabled()) { + int ret; + + ret = kvm_init(smp_cpus); + if (ret < 0) { + fprintf(stderr, "failed to initialize KVM\n"); + exit(1); + } + } + machine->init(ram_size, vga_ram_size, boot_devices, ds, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); @@ -8946,6 +5448,11 @@ if (loadvm) do_loadvm(loadvm); + if (incoming) { + autostart = 0; /* fixme how to deal with -daemonize */ + qemu_start_incoming_migration(incoming); + } + { /* XXX: simplify init */ read_passwords(); @@ -8967,6 +5474,7 @@ if (len != 1) exit(1); + chdir("/"); TFR(fd = open("/dev/null", O_RDWR)); if (fd == -1) exit(1); @@ -8980,23 +5488,7 @@ main_loop(); quit_timers(); + net_cleanup(); -#if !defined(_WIN32) - /* close network clients */ - for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { - VLANClientState *vc; - - for(vc = vlan->first_client; vc != NULL; vc = vc->next) { - if (vc->fd_read == tap_receive) { - char ifname[64]; - TAPState *s = vc->opaque; - - if (sscanf(vc->info_str, "tap: ifname=%63s ", ifname) == 1 && - s->down_script[0]) - launch_script(s->down_script, ifname, s->fd); - } - } - } -#endif return 0; } diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/vnc.c /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/vnc.c --- qemu-0.9.1/vnc.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/vnc.c 2008-11-11 20:51:59.000000000 +0000 @@ -35,14 +35,14 @@ #include "keymaps.c" #include "d3des.h" -#if CONFIG_VNC_TLS +#ifdef CONFIG_VNC_TLS #include #include #endif /* CONFIG_VNC_TLS */ // #define _VNC_DEBUG 1 -#if _VNC_DEBUG +#ifdef _VNC_DEBUG #define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) #if CONFIG_VNC_TLS && _VNC_DEBUG >= 2 @@ -71,8 +71,8 @@ typedef void VncSendHextileTile(VncState *vs, int x, int y, int w, int h, - uint32_t *last_bg, - uint32_t *last_fg, + void *last_bg, + void *last_fg, int *has_bg, int *has_fg); #define VNC_MAX_WIDTH 2048 @@ -93,7 +93,7 @@ VNC_AUTH_VENCRYPT = 19 }; -#if CONFIG_VNC_TLS +#ifdef CONFIG_VNC_TLS enum { VNC_WIREMODE_CLEAR, VNC_WIREMODE_TLS, @@ -109,12 +109,10 @@ VNC_AUTH_VENCRYPT_X509PLAIN = 262, }; -#if CONFIG_VNC_TLS #define X509_CA_CERT_FILE "ca-cert.pem" #define X509_CA_CRL_FILE "ca-crl.pem" #define X509_SERVER_KEY_FILE "server-key.pem" #define X509_SERVER_CERT_FILE "server-cert.pem" -#endif #endif /* CONFIG_VNC_TLS */ @@ -133,6 +131,7 @@ int has_resize; int has_hextile; int has_pointer_type_change; + int has_WMVi; int absolute; int last_x; int last_y; @@ -143,7 +142,7 @@ char *display; char *password; int auth; -#if CONFIG_VNC_TLS +#ifdef CONFIG_VNC_TLS int subauth; int x509verify; @@ -154,7 +153,7 @@ #endif char challenge[VNC_AUTH_CHALLENGE_SIZE]; -#if CONFIG_VNC_TLS +#ifdef CONFIG_VNC_TLS int wiremode; gnutls_session_t tls_session; #endif @@ -166,9 +165,9 @@ VncWritePixels *write_pixels; VncSendHextileTile *send_hextile_tile; int pix_bpp, pix_big_endian; - int red_shift, red_max, red_shift1; - int green_shift, green_max, green_shift1; - int blue_shift, blue_max, blue_shift1; + int client_red_shift, client_red_max, server_red_shift, server_red_max; + int client_green_shift, client_green_max, server_green_shift, server_green_max; + int client_blue_shift, client_blue_max, server_blue_shift, server_blue_max; VncReadEvent *read_handler; size_t read_handler_expect; @@ -210,6 +209,8 @@ static void vnc_update_client(void *opaque); static void vnc_client_read(void *opaque); +static void vnc_colordepth(DisplayState *ds, int depth); + static inline void vnc_set_bit(uint32_t *d, int k) { d[k >> 5] |= 1 << (k & 0x1f); @@ -265,6 +266,11 @@ w += (x % 16); x -= (x % 16); + x = MIN(x, vs->width); + y = MIN(y, vs->height); + w = MIN(x + w, vs->width) - x; + h = MIN(h, vs->height); + for (; y < h; y++) for (i = 0; i < w; i += 16) vnc_set_bit(vs->dirty_row[y], (x + i) / 16); @@ -286,8 +292,8 @@ int size_changed; VncState *vs = ds->opaque; - ds->data = realloc(ds->data, w * h * vs->depth); - vs->old_data = realloc(vs->old_data, w * h * vs->depth); + ds->data = qemu_realloc(ds->data, w * h * vs->depth); + vs->old_data = qemu_realloc(vs->old_data, w * h * vs->depth); if (ds->data == NULL || vs->old_data == NULL) { fprintf(stderr, "vnc: memory allocation failed\n"); @@ -302,15 +308,20 @@ ds->width = w; ds->height = h; ds->linesize = w * vs->depth; - if (vs->csock != -1 && vs->has_resize && size_changed) { - vnc_write_u8(vs, 0); /* msg id */ - vnc_write_u8(vs, 0); - vnc_write_u16(vs, 1); /* number of rects */ - vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, -223); - vnc_flush(vs); - vs->width = ds->width; - vs->height = ds->height; + if (size_changed) { + vs->width = ds->width; + vs->height = ds->height; + if (vs->csock != -1 && vs->has_resize) { + vnc_write_u8(vs, 0); /* msg id */ + vnc_write_u8(vs, 0); + vnc_write_u16(vs, 1); /* number of rects */ + vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, -223); + vnc_flush(vs); + } } + + memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); + memset(vs->old_data, 42, vs->ds->linesize * vs->ds->height); } /* fastest code */ @@ -322,14 +333,17 @@ /* slowest but generic code. */ static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v) { - unsigned int r, g, b; + uint8_t r, g, b; - r = (v >> vs->red_shift1) & vs->red_max; - g = (v >> vs->green_shift1) & vs->green_max; - b = (v >> vs->blue_shift1) & vs->blue_max; - v = (r << vs->red_shift) | - (g << vs->green_shift) | - (b << vs->blue_shift); + r = ((v >> vs->server_red_shift) & vs->server_red_max) * (vs->client_red_max + 1) / + (vs->server_red_max + 1); + g = ((v >> vs->server_green_shift) & vs->server_green_max) * (vs->client_green_max + 1) / + (vs->server_green_max + 1); + b = ((v >> vs->server_blue_shift) & vs->server_blue_max) * (vs->client_blue_max + 1) / + (vs->server_blue_max + 1); + v = (r << vs->client_red_shift) | + (g << vs->client_green_shift) | + (b << vs->client_blue_shift); switch(vs->pix_bpp) { case 1: buf[0] = v; @@ -362,14 +376,34 @@ static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size) { - uint32_t *pixels = pixels1; uint8_t buf[4]; - int n, i; - n = size >> 2; - for(i = 0; i < n; i++) { - vnc_convert_pixel(vs, buf, pixels[i]); - vnc_write(vs, buf, vs->pix_bpp); + if (vs->depth == 4) { + uint32_t *pixels = pixels1; + int n, i; + n = size >> 2; + for(i = 0; i < n; i++) { + vnc_convert_pixel(vs, buf, pixels[i]); + vnc_write(vs, buf, vs->pix_bpp); + } + } else if (vs->depth == 2) { + uint16_t *pixels = pixels1; + int n, i; + n = size >> 1; + for(i = 0; i < n; i++) { + vnc_convert_pixel(vs, buf, pixels[i]); + vnc_write(vs, buf, vs->pix_bpp); + } + } else if (vs->depth == 1) { + uint8_t *pixels = pixels1; + int n, i; + n = size; + for(i = 0; i < n; i++) { + vnc_convert_pixel(vs, buf, pixels[i]); + vnc_write(vs, buf, vs->pix_bpp); + } + } else { + fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n"); } } @@ -406,6 +440,18 @@ #undef BPP #define GENERIC +#define BPP 8 +#include "vnchextile.h" +#undef BPP +#undef GENERIC + +#define GENERIC +#define BPP 16 +#include "vnchextile.h" +#undef BPP +#undef GENERIC + +#define GENERIC #define BPP 32 #include "vnchextile.h" #undef BPP @@ -415,18 +461,23 @@ { int i, j; int has_fg, has_bg; - uint32_t last_fg32, last_bg32; + uint8_t *last_fg, *last_bg; vnc_framebuffer_update(vs, x, y, w, h, 5); + last_fg = (uint8_t *) malloc(vs->depth); + last_bg = (uint8_t *) malloc(vs->depth); has_fg = has_bg = 0; for (j = y; j < (y + h); j += 16) { for (i = x; i < (x + w); i += 16) { vs->send_hextile_tile(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j), - &last_bg32, &last_fg32, &has_bg, &has_fg); + last_bg, last_fg, &has_bg, &has_fg); } } + free(last_fg); + free(last_bg); + } static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h) @@ -506,6 +557,8 @@ int saved_offset; int has_dirty = 0; + vga_hw_update(); + vnc_set_bits(width_mask, (vs->width / 16), VNC_DIRTY_WORDS); /* Walk through the dirty map and eliminate tiles that @@ -580,22 +633,11 @@ vnc_flush(vs); } - qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL); -} -static void vnc_timer_init(VncState *vs) -{ - if (vs->timer == NULL) { - vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs); - qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock)); + if (vs->csock != -1) { + qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL); } -} -static void vnc_dpy_refresh(DisplayState *ds) -{ - VncState *vs = ds->opaque; - vnc_timer_init(vs); - vga_hw_update(); } static int vnc_listen_poll(void *opaque) @@ -610,7 +652,7 @@ { if ((buffer->capacity - buffer->offset) < len) { buffer->capacity += (len + 1024); - buffer->buffer = realloc(buffer->buffer, buffer->capacity); + buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity); if (buffer->buffer == NULL) { fprintf(stderr, "vnc: out of memory\n"); exit(1); @@ -642,17 +684,28 @@ static int vnc_client_io_error(VncState *vs, int ret, int last_errno) { if (ret == 0 || ret == -1) { - if (ret == -1 && (last_errno == EINTR || last_errno == EAGAIN)) - return 0; + if (ret == -1) { + switch (last_errno) { + case EINTR: + case EAGAIN: +#ifdef _WIN32 + case WSAEWOULDBLOCK: +#endif + return 0; + default: + break; + } + } VNC_DEBUG("Closing down client sock %d %d\n", ret, ret < 0 ? last_errno : 0); qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); closesocket(vs->csock); vs->csock = -1; + vs->ds->idle = 1; buffer_reset(&vs->input); buffer_reset(&vs->output); vs->need_update = 0; -#if CONFIG_VNC_TLS +#ifdef CONFIG_VNC_TLS if (vs->tls_session) { gnutls_deinit(vs->tls_session); vs->tls_session = NULL; @@ -674,7 +727,7 @@ long ret; VncState *vs = opaque; -#if CONFIG_VNC_TLS +#ifdef CONFIG_VNC_TLS if (vs->tls_session) { ret = gnutls_write(vs->tls_session, vs->output.buffer, vs->output.offset); if (ret < 0) { @@ -712,7 +765,7 @@ buffer_reserve(&vs->input, 4096); -#if CONFIG_VNC_TLS +#ifdef CONFIG_VNC_TLS if (vs->tls_session) { ret = gnutls_read(vs->tls_session, buffer_end(&vs->input), 4096); if (ret < 0) { @@ -819,7 +872,7 @@ (data[offset + 2] << 8) | data[offset + 3]); } -#if CONFIG_VNC_TLS +#ifdef CONFIG_VNC_TLS static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport, const void *data, size_t len) { @@ -888,8 +941,8 @@ dz = 1; if (vs->absolute) { - kbd_mouse_event(x * 0x7FFF / vs->ds->width, - y * 0x7FFF / vs->ds->height, + kbd_mouse_event(x * 0x7FFF / (vs->ds->width - 1), + y * 0x7FFF / (vs->ds->height - 1), dz, buttons); } else if (vs->has_pointer_type_change) { x -= 0x7FFF; @@ -927,12 +980,8 @@ kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) | 0x80); } -static void do_key_event(VncState *vs, int down, uint32_t sym) +static void do_key_event(VncState *vs, int down, int keycode, int sym) { - int keycode; - - keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF); - /* QEMU console switch */ switch(keycode) { case 0x2a: /* Left Shift */ @@ -954,6 +1003,7 @@ return; } break; + case 0x3a: /* CapsLock */ case 0x45: /* NumLock */ if (!down) vs->modifiers_state[keycode] ^= 1; @@ -1033,9 +1083,23 @@ static void key_event(VncState *vs, int down, uint32_t sym) { + int keycode; + if (sym >= 'A' && sym <= 'Z' && is_graphic_console()) sym = sym - 'A' + 'a'; - do_key_event(vs, down, sym); + + keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF); + do_key_event(vs, down, keycode, sym); +} + +static void ext_key_event(VncState *vs, int down, + uint32_t sym, uint16_t keycode) +{ + /* if the user specifies a keyboard layout, always use it */ + if (keyboard_layout) + key_event(vs, down, sym); + else + do_key_event(vs, down, keycode, sym); } static void framebuffer_update_request(VncState *vs, int incremental, @@ -1065,6 +1129,15 @@ } } +static void send_ext_key_event_ack(VncState *vs) +{ + vnc_write_u8(vs, 0); + vnc_write_u8(vs, 0); + vnc_write_u16(vs, 1); + vnc_framebuffer_update(vs, 0, 0, vs->ds->width, vs->ds->height, -258); + vnc_flush(vs); +} + static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) { int i; @@ -1072,6 +1145,7 @@ vs->has_hextile = 0; vs->has_resize = 0; vs->has_pointer_type_change = 0; + vs->has_WMVi = 0; vs->absolute = -1; vs->ds->dpy_copy = NULL; @@ -1092,6 +1166,12 @@ case -257: vs->has_pointer_type_change = 1; break; + case -258: + send_ext_key_event_ack(vs); + break; + case 0x574D5669: + vs->has_WMVi = 1; + break; default: break; } @@ -1100,17 +1180,6 @@ check_pointer_type_change(vs, kbd_mouse_is_absolute()); } -static int compute_nbits(unsigned int val) -{ - int n; - n = 0; - while (val != 0) { - n++; - val >>= 1; - } - return n; -} - static void set_pixel_format(VncState *vs, int bits_per_pixel, int depth, int big_endian_flag, int true_color_flag, @@ -1130,6 +1199,7 @@ return; } if (bits_per_pixel == 32 && + bits_per_pixel == vs->depth * 8 && host_big_endian_flag == big_endian_flag && red_max == 0xff && green_max == 0xff && blue_max == 0xff && red_shift == 16 && green_shift == 8 && blue_shift == 0) { @@ -1138,6 +1208,7 @@ vs->send_hextile_tile = send_hextile_tile_32; } else if (bits_per_pixel == 16 && + bits_per_pixel == vs->depth * 8 && host_big_endian_flag == big_endian_flag && red_max == 31 && green_max == 63 && blue_max == 31 && red_shift == 11 && green_shift == 5 && blue_shift == 0) { @@ -1146,6 +1217,7 @@ vs->send_hextile_tile = send_hextile_tile_16; } else if (bits_per_pixel == 8 && + bits_per_pixel == vs->depth * 8 && red_max == 7 && green_max == 7 && blue_max == 3 && red_shift == 5 && green_shift == 2 && blue_shift == 0) { vs->depth = 1; @@ -1158,30 +1230,177 @@ bits_per_pixel != 16 && bits_per_pixel != 32) goto fail; - vs->depth = 4; - vs->red_shift = red_shift; - vs->red_max = red_max; - vs->red_shift1 = 24 - compute_nbits(red_max); - vs->green_shift = green_shift; - vs->green_max = green_max; - vs->green_shift1 = 16 - compute_nbits(green_max); - vs->blue_shift = blue_shift; - vs->blue_max = blue_max; - vs->blue_shift1 = 8 - compute_nbits(blue_max); - vs->pix_bpp = bits_per_pixel / 8; + if (vs->depth == 4) { + vs->send_hextile_tile = send_hextile_tile_generic_32; + } else if (vs->depth == 2) { + vs->send_hextile_tile = send_hextile_tile_generic_16; + } else { + vs->send_hextile_tile = send_hextile_tile_generic_8; + } + vs->pix_big_endian = big_endian_flag; vs->write_pixels = vnc_write_pixels_generic; - vs->send_hextile_tile = send_hextile_tile_generic; } - vnc_dpy_resize(vs->ds, vs->ds->width, vs->ds->height); - memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); - memset(vs->old_data, 42, vs->ds->linesize * vs->ds->height); + vs->client_red_shift = red_shift; + vs->client_red_max = red_max; + vs->client_green_shift = green_shift; + vs->client_green_max = green_max; + vs->client_blue_shift = blue_shift; + vs->client_blue_max = blue_max; + vs->pix_bpp = bits_per_pixel / 8; vga_hw_invalidate(); vga_hw_update(); } +static void pixel_format_message (VncState *vs) { + char pad[3] = { 0, 0, 0 }; + + vnc_write_u8(vs, vs->depth * 8); /* bits-per-pixel */ + if (vs->depth == 4) vnc_write_u8(vs, 24); /* depth */ + else vnc_write_u8(vs, vs->depth * 8); /* depth */ + +#ifdef WORDS_BIGENDIAN + vnc_write_u8(vs, 1); /* big-endian-flag */ +#else + vnc_write_u8(vs, 0); /* big-endian-flag */ +#endif + vnc_write_u8(vs, 1); /* true-color-flag */ + if (vs->depth == 4) { + vnc_write_u16(vs, 0xFF); /* red-max */ + vnc_write_u16(vs, 0xFF); /* green-max */ + vnc_write_u16(vs, 0xFF); /* blue-max */ + vnc_write_u8(vs, 16); /* red-shift */ + vnc_write_u8(vs, 8); /* green-shift */ + vnc_write_u8(vs, 0); /* blue-shift */ + vs->send_hextile_tile = send_hextile_tile_32; + } else if (vs->depth == 2) { + vnc_write_u16(vs, 31); /* red-max */ + vnc_write_u16(vs, 63); /* green-max */ + vnc_write_u16(vs, 31); /* blue-max */ + vnc_write_u8(vs, 11); /* red-shift */ + vnc_write_u8(vs, 5); /* green-shift */ + vnc_write_u8(vs, 0); /* blue-shift */ + vs->send_hextile_tile = send_hextile_tile_16; + } else if (vs->depth == 1) { + /* XXX: change QEMU pixel 8 bit pixel format to match the VNC one ? */ + vnc_write_u16(vs, 7); /* red-max */ + vnc_write_u16(vs, 7); /* green-max */ + vnc_write_u16(vs, 3); /* blue-max */ + vnc_write_u8(vs, 5); /* red-shift */ + vnc_write_u8(vs, 2); /* green-shift */ + vnc_write_u8(vs, 0); /* blue-shift */ + vs->send_hextile_tile = send_hextile_tile_8; + } + vs->client_red_max = vs->server_red_max; + vs->client_green_max = vs->server_green_max; + vs->client_blue_max = vs->server_blue_max; + vs->client_red_shift = vs->server_red_shift; + vs->client_green_shift = vs->server_green_shift; + vs->client_blue_shift = vs->server_blue_shift; + vs->pix_bpp = vs->depth * 8; + vs->write_pixels = vnc_write_pixels_copy; + + vnc_write(vs, pad, 3); /* padding */ +} + +static void vnc_colordepth(DisplayState *ds, int depth) +{ + int host_big_endian_flag; + struct VncState *vs = ds->opaque; + + switch (depth) { + case 24: + if (ds->depth == 32) return; + depth = 32; + break; + case 15: + case 8: + case 0: + return; + default: + break; + } + +#ifdef WORDS_BIGENDIAN + host_big_endian_flag = 1; +#else + host_big_endian_flag = 0; +#endif + + switch (depth) { + case 8: + vs->depth = depth / 8; + vs->server_red_max = 7; + vs->server_green_max = 7; + vs->server_blue_max = 3; + vs->server_red_shift = 5; + vs->server_green_shift = 2; + vs->server_blue_shift = 0; + break; + case 16: + vs->depth = depth / 8; + vs->server_red_max = 31; + vs->server_green_max = 63; + vs->server_blue_max = 31; + vs->server_red_shift = 11; + vs->server_green_shift = 5; + vs->server_blue_shift = 0; + break; + case 32: + vs->depth = 4; + vs->server_red_max = 255; + vs->server_green_max = 255; + vs->server_blue_max = 255; + vs->server_red_shift = 16; + vs->server_green_shift = 8; + vs->server_blue_shift = 0; + break; + default: + return; + } + + if (vs->csock != -1 && vs->has_WMVi) { + /* Sending a WMVi message to notify the client*/ + vnc_write_u8(vs, 0); /* msg id */ + vnc_write_u8(vs, 0); + vnc_write_u16(vs, 1); /* number of rects */ + vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, 0x574D5669); + pixel_format_message(vs); + vnc_flush(vs); + } else { + if (vs->pix_bpp == 4 && vs->depth == 4 && + host_big_endian_flag == vs->pix_big_endian && + vs->client_red_max == 0xff && vs->client_green_max == 0xff && vs->client_blue_max == 0xff && + vs->client_red_shift == 16 && vs->client_green_shift == 8 && vs->client_blue_shift == 0) { + vs->write_pixels = vnc_write_pixels_copy; + vs->send_hextile_tile = send_hextile_tile_32; + } else if (vs->pix_bpp == 2 && vs->depth == 2 && + host_big_endian_flag == vs->pix_big_endian && + vs->client_red_max == 31 && vs->client_green_max == 63 && vs->client_blue_max == 31 && + vs->client_red_shift == 11 && vs->client_green_shift == 5 && vs->client_blue_shift == 0) { + vs->write_pixels = vnc_write_pixels_copy; + vs->send_hextile_tile = send_hextile_tile_16; + } else if (vs->pix_bpp == 1 && vs->depth == 1 && + host_big_endian_flag == vs->pix_big_endian && + vs->client_red_max == 7 && vs->client_green_max == 7 && vs->client_blue_max == 3 && + vs->client_red_shift == 5 && vs->client_green_shift == 2 && vs->client_blue_shift == 0) { + vs->write_pixels = vnc_write_pixels_copy; + vs->send_hextile_tile = send_hextile_tile_8; + } else { + if (vs->depth == 4) { + vs->send_hextile_tile = send_hextile_tile_generic_32; + } else if (vs->depth == 2) { + vs->send_hextile_tile = send_hextile_tile_generic_16; + } else { + vs->send_hextile_tile = send_hextile_tile_generic_8; + } + vs->write_pixels = vnc_write_pixels_generic; + } + } +} + static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) { int i; @@ -1245,6 +1464,24 @@ client_cut_text(vs, read_u32(data, 4), data + 8); break; + case 255: + if (len == 1) + return 2; + + switch (read_u8(data, 1)) { + case 0: + if (len == 2) + return 12; + + ext_key_event(vs, read_u16(data, 2), + read_u32(data, 4), read_u32(data, 8)); + break; + default: + printf("Msg: %d\n", read_u16(data, 0)); + vnc_client_error(vs); + break; + } + break; default: printf("Msg: %d\n", data[0]); vnc_client_error(vs); @@ -1257,7 +1494,6 @@ static int protocol_client_init(VncState *vs, uint8_t *data, size_t len) { - char pad[3] = { 0, 0, 0 }; char buf[1024]; int size; @@ -1266,43 +1502,7 @@ vnc_write_u16(vs, vs->ds->width); vnc_write_u16(vs, vs->ds->height); - vnc_write_u8(vs, vs->depth * 8); /* bits-per-pixel */ - vnc_write_u8(vs, vs->depth * 8); /* depth */ -#ifdef WORDS_BIGENDIAN - vnc_write_u8(vs, 1); /* big-endian-flag */ -#else - vnc_write_u8(vs, 0); /* big-endian-flag */ -#endif - vnc_write_u8(vs, 1); /* true-color-flag */ - if (vs->depth == 4) { - vnc_write_u16(vs, 0xFF); /* red-max */ - vnc_write_u16(vs, 0xFF); /* green-max */ - vnc_write_u16(vs, 0xFF); /* blue-max */ - vnc_write_u8(vs, 16); /* red-shift */ - vnc_write_u8(vs, 8); /* green-shift */ - vnc_write_u8(vs, 0); /* blue-shift */ - vs->send_hextile_tile = send_hextile_tile_32; - } else if (vs->depth == 2) { - vnc_write_u16(vs, 31); /* red-max */ - vnc_write_u16(vs, 63); /* green-max */ - vnc_write_u16(vs, 31); /* blue-max */ - vnc_write_u8(vs, 11); /* red-shift */ - vnc_write_u8(vs, 5); /* green-shift */ - vnc_write_u8(vs, 0); /* blue-shift */ - vs->send_hextile_tile = send_hextile_tile_16; - } else if (vs->depth == 1) { - /* XXX: change QEMU pixel 8 bit pixel format to match the VNC one ? */ - vnc_write_u16(vs, 7); /* red-max */ - vnc_write_u16(vs, 7); /* green-max */ - vnc_write_u16(vs, 3); /* blue-max */ - vnc_write_u8(vs, 5); /* red-shift */ - vnc_write_u8(vs, 2); /* green-shift */ - vnc_write_u8(vs, 0); /* blue-shift */ - vs->send_hextile_tile = send_hextile_tile_8; - } - vs->write_pixels = vnc_write_pixels_copy; - - vnc_write(vs, pad, 3); /* padding */ + pixel_format_message(vs); if (qemu_name) size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name); @@ -1390,7 +1590,7 @@ } -#if CONFIG_VNC_TLS +#ifdef CONFIG_VNC_TLS #define DH_BITS 1024 static gnutls_dh_params_t dh_params; @@ -1410,7 +1610,7 @@ if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0) return 0; -#if _VNC_DEBUG == 2 +#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2 gnutls_global_set_log_level(10); gnutls_global_set_log_function(vnc_debug_gnutls_log); #endif @@ -1828,7 +2028,7 @@ VNC_DEBUG("Start VNC auth\n"); return start_auth_vnc(vs); -#if CONFIG_VNC_TLS +#ifdef CONFIG_VNC_TLS case VNC_AUTH_VENCRYPT: VNC_DEBUG("Accept VeNCrypt auth\n");; return start_auth_vencrypt(vs); @@ -1907,30 +2107,38 @@ return 0; } +static void vnc_connect(VncState *vs) +{ + VNC_DEBUG("New client on socket %d\n", vs->csock); + vs->ds->idle = 0; + socket_set_nonblock(vs->csock); + qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); + vnc_write(vs, "RFB 003.008\n", 12); + vnc_flush(vs); + vnc_read_when(vs, protocol_version, 12); + memset(vs->old_data, 0, vs->ds->linesize * vs->ds->height); + memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); + vs->has_resize = 0; + vs->has_hextile = 0; + vs->ds->dpy_copy = NULL; + vnc_update_client(vs); +} + static void vnc_listen_read(void *opaque) { VncState *vs = opaque; struct sockaddr_in addr; socklen_t addrlen = sizeof(addr); + /* Catch-up */ + vga_hw_update(); + vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); if (vs->csock != -1) { - VNC_DEBUG("New client on socket %d\n", vs->csock); - socket_set_nonblock(vs->csock); - qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque); - vnc_write(vs, "RFB 003.008\n", 12); - vnc_flush(vs); - vnc_read_when(vs, protocol_version, 12); - memset(vs->old_data, 0, vs->ds->linesize * vs->ds->height); - memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); - vs->has_resize = 0; - vs->has_hextile = 0; - vs->ds->dpy_copy = NULL; + vnc_connect(vs); } } -extern int parse_host_port(struct sockaddr_in *saddr, const char *str); - void vnc_display_init(DisplayState *ds) { VncState *vs; @@ -1940,36 +2148,38 @@ exit(1); ds->opaque = vs; + ds->idle = 1; vnc_state = vs; vs->display = NULL; vs->password = NULL; vs->lsock = -1; vs->csock = -1; - vs->depth = 4; vs->last_x = -1; vs->last_y = -1; vs->ds = ds; - if (!keyboard_layout) - keyboard_layout = "en-us"; + if (keyboard_layout) + vs->kbd_layout = init_keyboard_layout(keyboard_layout); + else + vs->kbd_layout = init_keyboard_layout("en-us"); - vs->kbd_layout = init_keyboard_layout(keyboard_layout); if (!vs->kbd_layout) exit(1); + vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs); + vs->ds->data = NULL; vs->ds->dpy_update = vnc_dpy_update; vs->ds->dpy_resize = vnc_dpy_resize; - vs->ds->dpy_refresh = vnc_dpy_refresh; - - memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); + vs->ds->dpy_refresh = NULL; + vnc_colordepth(vs->ds, 32); vnc_dpy_resize(vs->ds, 640, 400); } -#if CONFIG_VNC_TLS +#ifdef CONFIG_VNC_TLS static int vnc_set_x509_credential(VncState *vs, const char *certdir, const char *filename, @@ -2046,7 +2256,7 @@ buffer_reset(&vs->input); buffer_reset(&vs->output); vs->need_update = 0; -#if CONFIG_VNC_TLS +#ifdef CONFIG_VNC_TLS if (vs->tls_session) { gnutls_deinit(vs->tls_session); vs->tls_session = NULL; @@ -2055,7 +2265,7 @@ #endif /* CONFIG_VNC_TLS */ } vs->auth = VNC_AUTH_INVALID; -#if CONFIG_VNC_TLS +#ifdef CONFIG_VNC_TLS vs->subauth = VNC_AUTH_INVALID; vs->x509verify = 0; #endif @@ -2079,18 +2289,12 @@ int vnc_display_open(DisplayState *ds, const char *display) { - struct sockaddr *addr; - struct sockaddr_in iaddr; -#ifndef _WIN32 - struct sockaddr_un uaddr; -#endif - int reuse_addr, ret; - socklen_t addrlen; - const char *p; VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; const char *options; int password = 0; -#if CONFIG_VNC_TLS + int reverse = 0; + int to_port = 0; +#ifdef CONFIG_VNC_TLS int tls = 0, x509 = 0; #endif @@ -2106,7 +2310,11 @@ options++; if (strncmp(options, "password", 8) == 0) { password = 1; /* Require password auth */ -#if CONFIG_VNC_TLS + } else if (strncmp(options, "reverse", 7) == 0) { + reverse = 1; + } else if (strncmp(options, "to=", 3) == 0) { + to_port = atoi(options+3) + 5900; +#ifdef CONFIG_VNC_TLS } else if (strncmp(options, "tls", 3) == 0) { tls = 1; /* Require TLS */ } else if (strncmp(options, "x509", 4) == 0) { @@ -2122,7 +2330,8 @@ if (start && (!end || (start < end))) { int len = end ? end-(start+1) : strlen(start+1); char *path = qemu_malloc(len+1); - strncpy(path, start+1, len); + + pstrcpy(path, len, start + 1); path[len] = '\0'; VNC_DEBUG("Trying certificate path '%s'\n", path); if (vnc_set_x509_credential_dir(vs, path) < 0) { @@ -2144,7 +2353,7 @@ } if (password) { -#if CONFIG_VNC_TLS +#ifdef CONFIG_VNC_TLS if (tls) { vs->auth = VNC_AUTH_VENCRYPT; if (x509) { @@ -2158,12 +2367,12 @@ #endif VNC_DEBUG("Initializing VNC server with password auth\n"); vs->auth = VNC_AUTH_VNC; -#if CONFIG_VNC_TLS +#ifdef CONFIG_VNC_TLS vs->subauth = VNC_AUTH_INVALID; } #endif } else { -#if CONFIG_VNC_TLS +#ifdef CONFIG_VNC_TLS if (tls) { vs->auth = VNC_AUTH_VENCRYPT; if (x509) { @@ -2177,81 +2386,45 @@ #endif VNC_DEBUG("Initializing VNC server with no auth\n"); vs->auth = VNC_AUTH_NONE; -#if CONFIG_VNC_TLS +#ifdef CONFIG_VNC_TLS vs->subauth = VNC_AUTH_INVALID; } #endif } -#ifndef _WIN32 - if (strstart(display, "unix:", &p)) { - addr = (struct sockaddr *)&uaddr; - addrlen = sizeof(uaddr); - - vs->lsock = socket(PF_UNIX, SOCK_STREAM, 0); - if (vs->lsock == -1) { - fprintf(stderr, "Could not create socket\n"); - free(vs->display); - vs->display = NULL; - return -1; - } - - uaddr.sun_family = AF_UNIX; - memset(uaddr.sun_path, 0, 108); - snprintf(uaddr.sun_path, 108, "%s", p); - - unlink(uaddr.sun_path); - } else -#endif - { - addr = (struct sockaddr *)&iaddr; - addrlen = sizeof(iaddr); - - if (parse_host_port(&iaddr, display) < 0) { - fprintf(stderr, "Could not parse VNC address\n"); - free(vs->display); - vs->display = NULL; - return -1; - } - - iaddr.sin_port = htons(ntohs(iaddr.sin_port) + 5900); - vs->lsock = socket(PF_INET, SOCK_STREAM, 0); - if (vs->lsock == -1) { - fprintf(stderr, "Could not create socket\n"); - free(vs->display); - vs->display = NULL; - return -1; - } - - reuse_addr = 1; - ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR, - (const char *)&reuse_addr, sizeof(reuse_addr)); - if (ret == -1) { - fprintf(stderr, "setsockopt() failed\n"); - close(vs->lsock); - vs->lsock = -1; - free(vs->display); - vs->display = NULL; - return -1; - } - } - - if (bind(vs->lsock, addr, addrlen) == -1) { - fprintf(stderr, "bind() failed\n"); - close(vs->lsock); - vs->lsock = -1; - free(vs->display); - vs->display = NULL; - return -1; - } + if (reverse) { + /* connect to viewer */ + if (strncmp(display, "unix:", 5) == 0) + vs->lsock = unix_connect(display+5); + else + vs->lsock = inet_connect(display, SOCK_STREAM); + if (-1 == vs->lsock) { + free(vs->display); + vs->display = NULL; + return -1; + } else { + vs->csock = vs->lsock; + vs->lsock = -1; + vnc_connect(vs); + } + return 0; - if (listen(vs->lsock, 1) == -1) { - fprintf(stderr, "listen() failed\n"); - close(vs->lsock); - vs->lsock = -1; - free(vs->display); - vs->display = NULL; - return -1; + } else { + /* listen for connects */ + char *dpy; + dpy = qemu_malloc(256); + if (strncmp(display, "unix:", 5) == 0) { + strcpy(dpy, "unix:"); + vs->lsock = unix_listen(display, dpy+5, 256-5); + } else { + vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900); + } + if (-1 == vs->lsock) { + free(dpy); + } else { + free(vs->display); + vs->display = dpy; + } } return qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs); diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/vnchextile.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/vnchextile.h --- qemu-0.9.1/vnchextile.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/vnchextile.h 2008-09-15 17:03:41.000000000 +0100 @@ -2,29 +2,29 @@ #define CONCAT(a, b) CONCAT_I(a, b) #define pixel_t CONCAT(uint, CONCAT(BPP, _t)) #ifdef GENERIC -#define NAME generic +#define NAME CONCAT(generic_, BPP) #else #define NAME BPP #endif static void CONCAT(send_hextile_tile_, NAME)(VncState *vs, int x, int y, int w, int h, - uint32_t *last_bg32, - uint32_t *last_fg32, + void *last_bg_, + void *last_fg_, int *has_bg, int *has_fg) { uint8_t *row = (vs->ds->data + y * vs->ds->linesize + x * vs->depth); pixel_t *irow = (pixel_t *)row; int j, i; - pixel_t *last_bg = (pixel_t *)last_bg32; - pixel_t *last_fg = (pixel_t *)last_fg32; + pixel_t *last_bg = (pixel_t *)last_bg_; + pixel_t *last_fg = (pixel_t *)last_fg_; pixel_t bg = 0; pixel_t fg = 0; int n_colors = 0; int bg_count = 0; int fg_count = 0; int flags = 0; - uint8_t data[(sizeof(pixel_t) + 2) * 16 * 16]; + uint8_t data[(vs->pix_bpp + 2) * 16 * 16]; int n_data = 0; int n_subtiles = 0; diff -Nru /tmp/5T7tsf7Gxy/qemu-0.9.1/vnc_keysym.h /tmp/cOLAdDEwtF/qemu-0.9.1+svn20081112/vnc_keysym.h --- qemu-0.9.1/vnc_keysym.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1+svn20081112/vnc_keysym.h 2008-10-02 19:26:42.000000000 +0100 @@ -2,7 +2,7 @@ const char* name; int keysym; } name2keysym_t; -static name2keysym_t name2keysym[]={ +static const name2keysym_t name2keysym[]={ /* ascii */ { "space", 0x020}, { "exclam", 0x021}, @@ -289,11 +289,14 @@ /* localized keys */ {"BackApostrophe", 0xff21}, {"Muhenkan", 0xff22}, -{"Katakana", 0xff25}, -{"Zenkaku_Hankaku", 0xff29}, +{"Katakana", 0xff27}, +{"Hankaku", 0xff29}, +{"Zenkaku_Hankaku", 0xff2a}, {"Henkan_Mode_Real", 0xff23}, {"Henkan_Mode_Ultra", 0xff3e}, {"backslash_ja", 0xffa5}, +{"Katakana_Real", 0xff25}, +{"Eisu_toggle", 0xff30}, {0,0}, };