aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2009-06-03 13:21:49 +0300
committerAvi Kivity <avi@redhat.com>2009-06-03 13:25:06 +0300
commit0936eb0a32e9442e6722bd517d4bfa43278cebaf (patch)
tree56d987c9f50c3111e087097304d9ee4e8c511c6c
parentProvide a kvm-free pic implementation (diff)
parentUpdate maintainer list. (diff)
downloadqemu-kvm-0936eb0a32e9442e6722bd517d4bfa43278cebaf.tar.gz
qemu-kvm-0936eb0a32e9442e6722bd517d4bfa43278cebaf.tar.bz2
qemu-kvm-0936eb0a32e9442e6722bd517d4bfa43278cebaf.zip
Merge branch 'master' of git://git.sv.gnu.org/qemu
* 'master' of git://git.sv.gnu.org/qemu: (40 commits) Update maintainer list. Install keymaps from new location vvfat: one more missing BlockDriver C99 initializer conversion Move keymaps into pc-bios kvm: Mark full address range dirty on live migration start Add detection of pthread library name User networking: Show active connections User Networking: Enable removal of redirections Allow monitor interaction when using migrate -exec fully split aio_pool from BlockDriver qcow: add qcow_aio_setup helper raw-posix: fix hdev_create fix raw_pread_aligned return value VNC: Fix memory allocation (wrong structure size). Drop bdrv_create2 qcow2: Update multiple refcounts at once qcow2: Refactor update_refcount qcow/qcow2: Drop synchronous qcow_write() e1000: Ignore reset command Fix output of uninitialized strings ... Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--MAINTAINERS4
-rw-r--r--Makefile2
-rw-r--r--Makefile.hw2
-rw-r--r--Makefile.target23
-rw-r--r--block.c120
-rw-r--r--block/curl.c27
-rw-r--r--block/qcow.c111
-rw-r--r--block/qcow2.c185
-rw-r--r--block/raw-posix.c94
-rw-r--r--block/vvfat.c18
-rw-r--r--block_int.h13
-rwxr-xr-xconfigure44
-rw-r--r--cpu-exec.c68
-rw-r--r--dis-asm.h2
-rw-r--r--disas.c3
-rw-r--r--dma-helpers.c32
-rw-r--r--dma.h2
-rw-r--r--elf.h2
-rw-r--r--gdbstub.c32
-rw-r--r--hw/arm_gic.c2
-rw-r--r--hw/armv7m.c2
-rw-r--r--hw/axis_dev88.c6
-rw-r--r--hw/e1000.c11
-rw-r--r--hw/esp.c2
-rw-r--r--hw/etraxfs.c6
-rw-r--r--hw/etraxfs_pic.c2
-rw-r--r--hw/hw.h1
-rw-r--r--hw/integratorcp.c4
-rw-r--r--hw/microblaze_pic_cpu.c50
-rw-r--r--hw/mpcore.c6
-rw-r--r--hw/musicpal.c4
-rw-r--r--hw/pcnet.c2
-rw-r--r--hw/petalogix_s3adsp1800_mmu.c199
-rw-r--r--hw/pl190.c2
-rw-r--r--hw/qdev.c13
-rw-r--r--hw/qdev.h5
-rw-r--r--hw/realview.c2
-rw-r--r--hw/sun4m.c2
-rw-r--r--hw/syborg.c2
-rw-r--r--hw/syborg_interrupt.c2
-rw-r--r--hw/versatilepb.c6
-rw-r--r--hw/xilinx.h50
-rw-r--r--hw/xilinx_ethlite.c235
-rw-r--r--hw/xilinx_intc.c167
-rw-r--r--hw/xilinx_timer.c224
-rw-r--r--hw/xilinx_uartlite.c218
-rw-r--r--linux-user/elfload.c22
-rw-r--r--linux-user/main.c96
-rw-r--r--linux-user/microblaze/syscall.h45
-rw-r--r--linux-user/microblaze/syscall_nr.h369
-rw-r--r--linux-user/microblaze/target_signal.h29
-rw-r--r--linux-user/microblaze/termbits.h213
-rw-r--r--linux-user/signal.c216
-rw-r--r--linux-user/syscall.c2
-rw-r--r--linux-user/syscall_defs.h73
-rwxr-xr-xmicroblaze-dis.c846
-rw-r--r--migration-exec.c33
-rw-r--r--monitor.c6
-rw-r--r--net.c117
-rw-r--r--net.h2
-rw-r--r--pc-bios/keymaps/ar (renamed from keymaps/ar)0
-rw-r--r--pc-bios/keymaps/common (renamed from keymaps/common)0
-rw-r--r--pc-bios/keymaps/da (renamed from keymaps/da)0
-rw-r--r--pc-bios/keymaps/de (renamed from keymaps/de)0
-rw-r--r--pc-bios/keymaps/de-ch (renamed from keymaps/de-ch)0
-rw-r--r--pc-bios/keymaps/en-gb (renamed from keymaps/en-gb)0
-rw-r--r--pc-bios/keymaps/en-us (renamed from keymaps/en-us)0
-rw-r--r--pc-bios/keymaps/es (renamed from keymaps/es)0
-rw-r--r--pc-bios/keymaps/et (renamed from keymaps/et)0
-rw-r--r--pc-bios/keymaps/fi (renamed from keymaps/fi)0
-rw-r--r--pc-bios/keymaps/fo (renamed from keymaps/fo)0
-rw-r--r--pc-bios/keymaps/fr (renamed from keymaps/fr)0
-rw-r--r--pc-bios/keymaps/fr-be (renamed from keymaps/fr-be)0
-rw-r--r--pc-bios/keymaps/fr-ca (renamed from keymaps/fr-ca)0
-rw-r--r--pc-bios/keymaps/fr-ch (renamed from keymaps/fr-ch)0
-rw-r--r--pc-bios/keymaps/hr (renamed from keymaps/hr)0
-rw-r--r--pc-bios/keymaps/hu (renamed from keymaps/hu)0
-rw-r--r--pc-bios/keymaps/is (renamed from keymaps/is)0
-rw-r--r--pc-bios/keymaps/it (renamed from keymaps/it)0
-rw-r--r--pc-bios/keymaps/ja (renamed from keymaps/ja)0
-rw-r--r--pc-bios/keymaps/lt (renamed from keymaps/lt)0
-rw-r--r--pc-bios/keymaps/lv (renamed from keymaps/lv)0
-rw-r--r--pc-bios/keymaps/mk (renamed from keymaps/mk)0
-rw-r--r--pc-bios/keymaps/modifiers (renamed from keymaps/modifiers)0
-rw-r--r--pc-bios/keymaps/nl (renamed from keymaps/nl)0
-rw-r--r--pc-bios/keymaps/nl-be (renamed from keymaps/nl-be)0
-rw-r--r--pc-bios/keymaps/no (renamed from keymaps/no)0
-rw-r--r--pc-bios/keymaps/pl (renamed from keymaps/pl)0
-rw-r--r--pc-bios/keymaps/pt (renamed from keymaps/pt)0
-rw-r--r--pc-bios/keymaps/pt-br (renamed from keymaps/pt-br)0
-rw-r--r--pc-bios/keymaps/ru (renamed from keymaps/ru)0
-rw-r--r--pc-bios/keymaps/sl (renamed from keymaps/sl)0
-rw-r--r--pc-bios/keymaps/sv (renamed from keymaps/sv)0
-rw-r--r--pc-bios/keymaps/th (renamed from keymaps/th)0
-rw-r--r--pc-bios/keymaps/tr (renamed from keymaps/tr)0
-rw-r--r--qemu-doc.texi4
-rw-r--r--savevm.c12
-rw-r--r--slirp/libslirp.h5
-rw-r--r--slirp/slirp.c47
-rw-r--r--target-microblaze/cpu.h311
-rw-r--r--target-microblaze/exec.h57
-rw-r--r--target-microblaze/helper.c255
-rw-r--r--target-microblaze/helper.h19
-rw-r--r--target-microblaze/machine.c11
-rw-r--r--target-microblaze/microblaze-decode.h52
-rw-r--r--target-microblaze/mmu.c257
-rw-r--r--target-microblaze/mmu.h88
-rw-r--r--target-microblaze/op_helper.c216
-rw-r--r--target-microblaze/translate.c1395
-rw-r--r--targphys.h2
-rw-r--r--vl.c8
-rw-r--r--vnc.c3
112 files changed, 6384 insertions, 436 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index a5bbec247..080e1c0a9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19,6 +19,7 @@ M68K Paul Brook
SH4 ?
CRIS Edgar E. Iglesias
Alpha ?
+MicroBlaze Edgar E. Iglesias
Machines (sorted by CPU):
-------------------------
@@ -58,7 +59,10 @@ SH4
r2d.c Magnus Damm
CRIS
etraxfs.c Edgar E. Iglesias
+ axis_dev88.c Edgar E. Iglesias
Alpha
+MicroBlaze
+ petalogix_s3adsp1800.c Edgar E. Iglesias
Generic Subsystems:
-------------------
diff --git a/Makefile b/Makefile
index 4c46d1a08..294e1e2e6 100644
--- a/Makefile
+++ b/Makefile
@@ -319,7 +319,7 @@ endif
ifndef CONFIG_WIN32
$(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps"
set -e; for x in $(KEYMAPS); do \
- $(INSTALL_DATA) $(SRC_PATH)/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
+ $(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
done
endif
for d in $(TARGET_DIRS); do \
diff --git a/Makefile.hw b/Makefile.hw
index 010e63c8a..6accb3bc7 100644
--- a/Makefile.hw
+++ b/Makefile.hw
@@ -29,6 +29,8 @@ OBJS+= lsi53c895a.o esp.o
OBJS+= dma-helpers.o sysbus.o
all: $(HWLIB)
+# Dummy command so that make thinks it has done something
+ @true
$(HWLIB): $(OBJS)
diff --git a/Makefile.target b/Makefile.target
index 0097aa89d..781144487 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -137,6 +137,8 @@ kvm-all.o: CFLAGS+=$(KVM_CFLAGS)
CFLAGS += $(KVM_CFLAGS)
all: $(PROGS)
+# Dummy command so that make thinks it has done something
+ @true
#########################################################
# cpu emulator library
@@ -233,6 +235,12 @@ endif
ifeq ($(findstring ppc, $(TARGET_BASE_ARCH) $(ARCH)),ppc)
LIBOBJS+=ppc-dis.o
endif
+ifeq ($(findstring microblaze, $(TARGET_BASE_ARCH) $(ARCH)),microblaze)
+LIBOBJS+=microblaze-dis.o
+ifndef CONFIG_USER_ONLY
+LIBOBJS+= mmu.o
+endif
+endif
ifeq ($(findstring mips, $(TARGET_BASE_ARCH) $(ARCH)),mips)
LIBOBJS+=mips-dis.o
endif
@@ -679,6 +687,21 @@ OBJS+= pflash_cfi01.o
OBJS+= vmware_vga.o
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
endif
+ifeq ($(TARGET_BASE_ARCH), microblaze)
+OBJS+= petalogix_s3adsp1800_mmu.o
+
+OBJS+= microblaze_pic_cpu.o
+OBJS+= xilinx_intc.o
+OBJS+= xilinx_timer.o
+OBJS+= xilinx_uartlite.o
+OBJS+= xilinx_ethlite.o
+
+OBJS+= pflash_cfi02.o
+ifdef FDT_LIBS
+OBJS+= device_tree.o
+LIBS+= $(FDT_LIBS)
+endif
+endif
ifeq ($(TARGET_BASE_ARCH), cris)
# Boards
OBJS+= cris_pic_cpu.o etraxfs.o axis_dev88.o
diff --git a/block.c b/block.c
index c80d4b90c..e6b91c60a 100644
--- a/block.c
+++ b/block.c
@@ -48,23 +48,12 @@
#define SECTOR_BITS 9
#define SECTOR_SIZE (1 << SECTOR_BITS)
-typedef struct BlockDriverAIOCBSync {
- BlockDriverAIOCB common;
- QEMUBH *bh;
- int ret;
- /* vector translation state */
- QEMUIOVector *qiov;
- uint8_t *bounce;
- int is_write;
-} BlockDriverAIOCBSync;
-
static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
-static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb);
static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
@@ -138,21 +127,17 @@ void path_combine(char *dest, int dest_size,
}
}
-
void bdrv_register(BlockDriver *bdrv)
{
if (!bdrv->bdrv_aio_readv) {
/* add AIO emulation layer */
bdrv->bdrv_aio_readv = bdrv_aio_readv_em;
bdrv->bdrv_aio_writev = bdrv_aio_writev_em;
- bdrv->bdrv_aio_cancel = bdrv_aio_cancel_em;
- bdrv->aiocb_size = sizeof(BlockDriverAIOCBSync);
} else if (!bdrv->bdrv_read) {
/* add synchronous IO emulation layer */
bdrv->bdrv_read = bdrv_read_em;
bdrv->bdrv_write = bdrv_write_em;
}
- aio_pool_init(&bdrv->aio_pool, bdrv->aiocb_size, bdrv->bdrv_aio_cancel);
bdrv->next = first_drv;
first_drv = bdrv;
}
@@ -184,42 +169,6 @@ BlockDriver *bdrv_find_format(const char *format_name)
return NULL;
}
-int bdrv_create2(BlockDriver *drv,
- const char *filename, int64_t size_in_sectors,
- const char *backing_file, const char *backing_format,
- int flags)
-{
- QEMUOptionParameter *options;
-
- options = parse_option_parameters("", drv->create_options, NULL);
-
- // Process flags
- if (flags & ~(BLOCK_FLAG_ENCRYPT | BLOCK_FLAG_COMPAT6 | BLOCK_FLAG_COMPRESS)) {
- return -ENOTSUP;
- }
-
- if (flags & BLOCK_FLAG_ENCRYPT) {
- set_option_parameter_int(options, BLOCK_OPT_ENCRYPT, 1);
- }
- if (flags & BLOCK_FLAG_COMPAT6) {
- set_option_parameter_int(options, BLOCK_OPT_COMPAT6, 1);
- }
-
- // Add size to options
- set_option_parameter_int(options, BLOCK_OPT_SIZE, size_in_sectors * 512);
-
- // Backing files
- if ((backing_file != NULL && set_option_parameter(options,
- BLOCK_OPT_BACKING_FILE, backing_file))
- || (backing_format != NULL && set_option_parameter(options,
- BLOCK_OPT_BACKING_FMT, backing_format)))
- {
- return -ENOTSUP;
- }
-
- return bdrv_create(drv, filename, options);
-}
-
int bdrv_create(BlockDriver *drv, const char* filename,
QEMUOptionParameter *options)
{
@@ -392,6 +341,8 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
BlockDriverState *bs1;
int64_t total_size;
int is_protocol = 0;
+ BlockDriver *bdrv_qcow2;
+ QEMUOptionParameter *options;
/* if snapshot, we create a temporary backing file and open it
instead of opening 'filename' directly */
@@ -419,14 +370,23 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
else
realpath(filename, backing_filename);
- ret = bdrv_create2(bdrv_find_format("qcow2"), tmp_filename,
- total_size, backing_filename,
- (drv ? drv->format_name : NULL), 0);
+ bdrv_qcow2 = bdrv_find_format("qcow2");
+ options = parse_option_parameters("", bdrv_qcow2->create_options, NULL);
+
+ set_option_parameter_int(options, BLOCK_OPT_SIZE, total_size * 512);
+ set_option_parameter(options, BLOCK_OPT_BACKING_FILE, backing_filename);
+ if (drv) {
+ set_option_parameter(options, BLOCK_OPT_BACKING_FMT,
+ drv->format_name);
+ }
+
+ ret = bdrv_create(bdrv_qcow2, tmp_filename, options);
if (ret < 0) {
return ret;
}
+
filename = tmp_filename;
- drv = bdrv_find_format("qcow2");
+ drv = bdrv_qcow2;
bs->is_temporary = 1;
}
@@ -1394,6 +1354,28 @@ void bdrv_aio_cancel(BlockDriverAIOCB *acb)
/**************************************************************/
/* async block device emulation */
+typedef struct BlockDriverAIOCBSync {
+ BlockDriverAIOCB common;
+ QEMUBH *bh;
+ int ret;
+ /* vector translation state */
+ QEMUIOVector *qiov;
+ uint8_t *bounce;
+ int is_write;
+} BlockDriverAIOCBSync;
+
+static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb)
+{
+ BlockDriverAIOCBSync *acb = (BlockDriverAIOCBSync *)blockacb;
+ qemu_bh_cancel(acb->bh);
+ qemu_aio_release(acb);
+}
+
+static AIOPool bdrv_em_aio_pool = {
+ .aiocb_size = sizeof(BlockDriverAIOCBSync),
+ .cancel = bdrv_aio_cancel_em,
+};
+
static void bdrv_aio_bh_cb(void *opaque)
{
BlockDriverAIOCBSync *acb = opaque;
@@ -1417,7 +1399,7 @@ static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
{
BlockDriverAIOCBSync *acb;
- acb = qemu_aio_get(bs, cb, opaque);
+ acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque);
acb->is_write = is_write;
acb->qiov = qiov;
acb->bounce = qemu_blockalign(bs, qiov->size);
@@ -1451,14 +1433,6 @@ static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
}
-
-static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb)
-{
- BlockDriverAIOCBSync *acb = (BlockDriverAIOCBSync *)blockacb;
- qemu_bh_cancel(acb->bh);
- qemu_aio_release(acb);
-}
-
/**************************************************************/
/* sync block device emulation */
@@ -1520,16 +1494,8 @@ void bdrv_init(void)
module_call_init(MODULE_INIT_BLOCK);
}
-void aio_pool_init(AIOPool *pool, int aiocb_size,
- void (*cancel)(BlockDriverAIOCB *acb))
-{
- pool->aiocb_size = aiocb_size;
- pool->cancel = cancel;
- pool->free_aiocb = NULL;
-}
-
-void *qemu_aio_get_pool(AIOPool *pool, BlockDriverState *bs,
- BlockDriverCompletionFunc *cb, void *opaque)
+void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque)
{
BlockDriverAIOCB *acb;
@@ -1546,12 +1512,6 @@ void *qemu_aio_get_pool(AIOPool *pool, BlockDriverState *bs,
return acb;
}
-void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
- void *opaque)
-{
- return qemu_aio_get_pool(&bs->drv->aio_pool, bs, cb, opaque);
-}
-
void qemu_aio_release(void *p)
{
BlockDriverAIOCB *acb = (BlockDriverAIOCB *)p;
diff --git a/block/curl.c b/block/curl.c
index 5d1487dea..e1a553f7a 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -349,6 +349,16 @@ out_noclean:
return -EINVAL;
}
+static void curl_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+ // Do we have to implement canceling? Seems to work without...
+}
+
+static AIOPool curl_aio_pool = {
+ .aiocb_size = sizeof(CURLAIOCB),
+ .cancel = curl_aio_cancel,
+};
+
static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
@@ -359,7 +369,7 @@ static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
size_t end;
CURLState *state;
- acb = qemu_aio_get(bs, cb, opaque);
+ acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque);
if (!acb)
return NULL;
@@ -406,11 +416,6 @@ static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
return &acb->common;
}
-static void curl_aio_cancel(BlockDriverAIOCB *blockacb)
-{
- // Do we have to implement canceling? Seems to work without...
-}
-
static void curl_close(BlockDriverState *bs)
{
BDRVCURLState *s = bs->opaque;
@@ -450,9 +455,7 @@ static BlockDriver bdrv_http = {
.bdrv_close = curl_close,
.bdrv_getlength = curl_getlength,
- .aiocb_size = sizeof(CURLAIOCB),
.bdrv_aio_readv = curl_aio_readv,
- .bdrv_aio_cancel = curl_aio_cancel,
};
static BlockDriver bdrv_https = {
@@ -464,9 +467,7 @@ static BlockDriver bdrv_https = {
.bdrv_close = curl_close,
.bdrv_getlength = curl_getlength,
- .aiocb_size = sizeof(CURLAIOCB),
.bdrv_aio_readv = curl_aio_readv,
- .bdrv_aio_cancel = curl_aio_cancel,
};
static BlockDriver bdrv_ftp = {
@@ -478,9 +479,7 @@ static BlockDriver bdrv_ftp = {
.bdrv_close = curl_close,
.bdrv_getlength = curl_getlength,
- .aiocb_size = sizeof(CURLAIOCB),
.bdrv_aio_readv = curl_aio_readv,
- .bdrv_aio_cancel = curl_aio_cancel,
};
static BlockDriver bdrv_ftps = {
@@ -492,9 +491,7 @@ static BlockDriver bdrv_ftps = {
.bdrv_close = curl_close,
.bdrv_getlength = curl_getlength,
- .aiocb_size = sizeof(CURLAIOCB),
.bdrv_aio_readv = curl_aio_readv,
- .bdrv_aio_cancel = curl_aio_cancel,
};
static BlockDriver bdrv_tftp = {
@@ -506,9 +503,7 @@ static BlockDriver bdrv_tftp = {
.bdrv_close = curl_close,
.bdrv_getlength = curl_getlength,
- .aiocb_size = sizeof(CURLAIOCB),
.bdrv_aio_readv = curl_aio_readv,
- .bdrv_aio_cancel = curl_aio_cancel,
};
static void curl_block_init(void)
diff --git a/block/qcow.c b/block/qcow.c
index 6ecf2e8e0..329b364b7 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -488,41 +488,6 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
}
#endif
-static int qcow_write(BlockDriverState *bs, int64_t sector_num,
- const uint8_t *buf, int nb_sectors)
-{
- BDRVQcowState *s = bs->opaque;
- int ret, index_in_cluster, n;
- uint64_t cluster_offset;
-
- 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);
- if (!cluster_offset)
- return -1;
- if (s->crypt_method) {
- encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
- &s->aes_encrypt_key);
- ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512,
- s->cluster_data, n * 512);
- } else {
- ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
- }
- if (ret != n * 512)
- return -1;
- nb_sectors -= n;
- sector_num += n;
- buf += n * 512;
- }
- s->cluster_cache_offset = -1; /* disable compressed cache */
- return 0;
-}
-
typedef struct QCowAIOCB {
BlockDriverAIOCB common;
int64_t sector_num;
@@ -538,6 +503,44 @@ typedef struct QCowAIOCB {
BlockDriverAIOCB *hd_aiocb;
} QCowAIOCB;
+static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+ QCowAIOCB *acb = (QCowAIOCB *)blockacb;
+ if (acb->hd_aiocb)
+ bdrv_aio_cancel(acb->hd_aiocb);
+ qemu_aio_release(acb);
+}
+
+static AIOPool qcow_aio_pool = {
+ .aiocb_size = sizeof(QCowAIOCB),
+ .cancel = qcow_aio_cancel,
+};
+
+static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque, int is_write)
+{
+ QCowAIOCB *acb;
+
+ acb = qemu_aio_get(&qcow_aio_pool, bs, cb, opaque);
+ if (!acb)
+ return NULL;
+ acb->hd_aiocb = NULL;
+ acb->sector_num = sector_num;
+ acb->qiov = qiov;
+ if (qiov->niov > 1) {
+ acb->buf = acb->orig_buf = qemu_blockalign(bs, qiov->size);
+ if (is_write)
+ qemu_iovec_to_buffer(qiov, acb->buf);
+ } else {
+ acb->buf = (uint8_t *)qiov->iov->iov_base;
+ }
+ acb->nb_sectors = nb_sectors;
+ acb->n = 0;
+ acb->cluster_offset = 0;
+ return acb;
+}
+
static void qcow_aio_read_cb(void *opaque, int ret)
{
QCowAIOCB *acb = opaque;
@@ -635,19 +638,9 @@ static BlockDriverAIOCB *qcow_aio_readv(BlockDriverState *bs,
{
QCowAIOCB *acb;
- acb = qemu_aio_get(bs, cb, opaque);
+ acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
if (!acb)
return NULL;
- acb->hd_aiocb = NULL;
- acb->sector_num = sector_num;
- acb->qiov = qiov;
- if (qiov->niov > 1)
- acb->buf = acb->orig_buf = qemu_blockalign(bs, qiov->size);
- else
- acb->buf = (uint8_t *)qiov->iov->iov_base;
- acb->nb_sectors = nb_sectors;
- acb->n = 0;
- acb->cluster_offset = 0;
qcow_aio_read_cb(acb, 0);
return &acb->common;
@@ -730,33 +723,15 @@ static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
s->cluster_cache_offset = -1; /* disable compressed cache */
- acb = qemu_aio_get(bs, cb, opaque);
+ acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
if (!acb)
return NULL;
- acb->hd_aiocb = NULL;
- acb->sector_num = sector_num;
- acb->qiov = qiov;
- if (qiov->niov > 1) {
- acb->buf = acb->orig_buf = qemu_blockalign(bs, qiov->size);
- qemu_iovec_to_buffer(qiov, acb->buf);
- } else {
- acb->buf = (uint8_t *)qiov->iov->iov_base;
- }
- acb->nb_sectors = nb_sectors;
- acb->n = 0;
+
qcow_aio_write_cb(acb, 0);
return &acb->common;
}
-static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
-{
- QCowAIOCB *acb = (QCowAIOCB *)blockacb;
- if (acb->hd_aiocb)
- bdrv_aio_cancel(acb->hd_aiocb);
- qemu_aio_release(acb);
-}
-
static void qcow_close(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
@@ -904,7 +879,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
/* could not compress: write normal cluster */
- qcow_write(bs, sector_num, buf, s->cluster_sectors);
+ bdrv_write(bs, sector_num, buf, s->cluster_sectors);
} else {
cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
out_len, 0, 0);
@@ -953,8 +928,6 @@ static BlockDriver bdrv_qcow = {
.bdrv_make_empty = qcow_make_empty,
.bdrv_aio_readv = qcow_aio_readv,
.bdrv_aio_writev = qcow_aio_writev,
- .bdrv_aio_cancel = qcow_aio_cancel,
- .aiocb_size = sizeof(QCowAIOCB),
.bdrv_write_compressed = qcow_write_compressed,
.bdrv_get_info = qcow_get_info,
diff --git a/block/qcow2.c b/block/qcow2.c
index 77f433e81..d1611d14c 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -173,7 +173,7 @@ static int get_refcount(BlockDriverState *bs, int64_t cluster_index);
static int update_cluster_refcount(BlockDriverState *bs,
int64_t cluster_index,
int addend);
-static void update_refcount(BlockDriverState *bs,
+static int update_refcount(BlockDriverState *bs,
int64_t offset, int64_t length,
int addend);
static int64_t alloc_clusters(BlockDriverState *bs, int64_t size);
@@ -1229,46 +1229,6 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
return 0;
}
-static int qcow_write(BlockDriverState *bs, int64_t sector_num,
- const uint8_t *buf, int nb_sectors)
-{
- BDRVQcowState *s = bs->opaque;
- int ret, index_in_cluster, n;
- uint64_t cluster_offset;
- int n_end;
- QCowL2Meta l2meta;
-
- while (nb_sectors > 0) {
- index_in_cluster = sector_num & (s->cluster_sectors - 1);
- 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, &l2meta);
- if (!cluster_offset)
- return -1;
- if (s->crypt_method) {
- encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
- &s->aes_encrypt_key);
- ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512,
- s->cluster_data, n * 512);
- } else {
- ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
- }
- if (ret != n * 512 || alloc_cluster_link_l2(bs, cluster_offset, &l2meta) < 0) {
- free_any_clusters(bs, cluster_offset, l2meta.nb_clusters);
- return -1;
- }
- nb_sectors -= n;
- sector_num += n;
- buf += n * 512;
- }
- s->cluster_cache_offset = -1; /* disable compressed cache */
- return 0;
-}
-
typedef struct QCowAIOCB {
BlockDriverAIOCB common;
int64_t sector_num;
@@ -1286,6 +1246,19 @@ typedef struct QCowAIOCB {
QCowL2Meta l2meta;
} QCowAIOCB;
+static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+ QCowAIOCB *acb = (QCowAIOCB *)blockacb;
+ if (acb->hd_aiocb)
+ bdrv_aio_cancel(acb->hd_aiocb);
+ qemu_aio_release(acb);
+}
+
+static AIOPool qcow_aio_pool = {
+ .aiocb_size = sizeof(QCowAIOCB),
+ .cancel = qcow_aio_cancel,
+};
+
static void qcow_aio_read_cb(void *opaque, int ret);
static void qcow_aio_read_bh(void *opaque)
{
@@ -1415,7 +1388,7 @@ static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
{
QCowAIOCB *acb;
- acb = qemu_aio_get(bs, cb, opaque);
+ acb = qemu_aio_get(&qcow_aio_pool, bs, cb, opaque);
if (!acb)
return NULL;
acb->hd_aiocb = NULL;
@@ -1538,14 +1511,6 @@ static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
return &acb->common;
}
-static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
-{
- QCowAIOCB *acb = (QCowAIOCB *)blockacb;
- if (acb->hd_aiocb)
- bdrv_aio_cancel(acb->hd_aiocb);
- qemu_aio_release(acb);
-}
-
static void qcow_close(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
@@ -1834,7 +1799,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
/* could not compress: write normal cluster */
- qcow_write(bs, sector_num, buf, s->cluster_sectors);
+ bdrv_write(bs, sector_num, buf, s->cluster_sectors);
} else {
cluster_offset = alloc_compressed_cluster_offset(bs, sector_num << 9,
out_len);
@@ -2548,29 +2513,25 @@ static int grow_refcount_table(BlockDriverState *bs, int min_size)
return -EIO;
}
-/* addend must be 1 or -1 */
-/* XXX: cache several refcount block clusters ? */
-static int update_cluster_refcount(BlockDriverState *bs,
- int64_t cluster_index,
- int addend)
+
+static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
{
BDRVQcowState *s = bs->opaque;
int64_t offset, refcount_block_offset;
- int ret, refcount_table_index, block_index, refcount;
+ int ret, refcount_table_index;
uint64_t data64;
+ /* Find L1 index and grow refcount table if needed */
refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
if (refcount_table_index >= s->refcount_table_size) {
- if (addend < 0)
- return -EINVAL;
ret = grow_refcount_table(bs, refcount_table_index + 1);
if (ret < 0)
return ret;
}
+
+ /* Load or allocate the refcount block */
refcount_block_offset = s->refcount_table[refcount_table_index];
if (!refcount_block_offset) {
- if (addend < 0)
- return -EINVAL;
/* create a new refcount block */
/* Note: we cannot update the refcount now to avoid recursion */
offset = alloc_clusters_noref(bs, s->cluster_size);
@@ -2595,43 +2556,105 @@ static int update_cluster_refcount(BlockDriverState *bs,
return -EIO;
}
}
- /* we can update the count and save it */
- block_index = cluster_index &
- ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
- refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
- refcount += addend;
- if (refcount < 0 || refcount > 0xffff)
- return -EINVAL;
- if (refcount == 0 && cluster_index < s->free_cluster_index) {
- s->free_cluster_index = cluster_index;
+
+ return refcount_block_offset;
+}
+
+/* addend must be 1 or -1 */
+static int update_cluster_refcount(BlockDriverState *bs,
+ int64_t cluster_index,
+ int addend)
+{
+ BDRVQcowState *s = bs->opaque;
+ int ret;
+
+ ret = update_refcount(bs, cluster_index << s->cluster_bits, 1, addend);
+ if (ret < 0) {
+ return ret;
}
- s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
- if (bdrv_pwrite(s->hd,
- refcount_block_offset + (block_index << REFCOUNT_SHIFT),
- &s->refcount_block_cache[block_index], 2) != 2)
- return -EIO;
- return refcount;
+
+ return get_refcount(bs, cluster_index);
}
-static void update_refcount(BlockDriverState *bs,
+/* XXX: cache several refcount block clusters ? */
+static int update_refcount(BlockDriverState *bs,
int64_t offset, int64_t length,
int addend)
{
BDRVQcowState *s = bs->opaque;
int64_t start, last, cluster_offset;
+ int64_t refcount_block_offset = 0;
+ int64_t table_index = -1, old_table_index;
+ int first_index = -1, last_index = -1;
#ifdef DEBUG_ALLOC2
printf("update_refcount: offset=%lld size=%lld addend=%d\n",
offset, length, addend);
#endif
if (length <= 0)
- return;
+ return -EINVAL;
start = offset & ~(s->cluster_size - 1);
last = (offset + length - 1) & ~(s->cluster_size - 1);
for(cluster_offset = start; cluster_offset <= last;
- cluster_offset += s->cluster_size) {
- update_cluster_refcount(bs, cluster_offset >> s->cluster_bits, addend);
+ cluster_offset += s->cluster_size)
+ {
+ int block_index, refcount;
+ int64_t cluster_index = cluster_offset >> s->cluster_bits;
+
+ /* Only write refcount block to disk when we are done with it */
+ old_table_index = table_index;
+ table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
+ if ((old_table_index >= 0) && (table_index != old_table_index)) {
+ size_t size = (last_index - first_index + 1) << REFCOUNT_SHIFT;
+ if (bdrv_pwrite(s->hd,
+ refcount_block_offset + (first_index << REFCOUNT_SHIFT),
+ &s->refcount_block_cache[first_index], size) != size)
+ {
+ return -EIO;
+ }
+
+ first_index = -1;
+ last_index = -1;
+ }
+
+ /* Load the refcount block and allocate it if needed */
+ refcount_block_offset = alloc_refcount_block(bs, cluster_index);
+ if (refcount_block_offset < 0) {
+ return refcount_block_offset;
+ }
+
+ /* we can update the count and save it */
+ block_index = cluster_index &
+ ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
+ if (first_index == -1 || block_index < first_index) {
+ first_index = block_index;
+ }
+ if (block_index > last_index) {
+ last_index = block_index;
+ }
+
+ refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
+ refcount += addend;
+ if (refcount < 0 || refcount > 0xffff)
+ return -EINVAL;
+ if (refcount == 0 && cluster_index < s->free_cluster_index) {
+ s->free_cluster_index = cluster_index;
+ }
+ s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
}
+
+ /* Write last changed block to disk */
+ if (refcount_block_offset != 0) {
+ size_t size = (last_index - first_index + 1) << REFCOUNT_SHIFT;
+ if (bdrv_pwrite(s->hd,
+ refcount_block_offset + (first_index << REFCOUNT_SHIFT),
+ &s->refcount_block_cache[first_index], size) != size)
+ {
+ return -EIO;
+ }
+ }
+
+ return 0;
}
/*
@@ -2980,8 +3003,6 @@ static BlockDriver bdrv_qcow2 = {
.bdrv_aio_readv = qcow_aio_readv,
.bdrv_aio_writev = qcow_aio_writev,
- .bdrv_aio_cancel = qcow_aio_cancel,
- .aiocb_size = sizeof(QCowAIOCB),
.bdrv_write_compressed = qcow_write_compressed,
.bdrv_snapshot_create = qcow_snapshot_create,
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 04b709f93..fdbf937dc 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -251,7 +251,7 @@ static int raw_pread_aligned(BlockDriverState *bs, int64_t offset,
label__raw_read__success:
- return ret;
+ return (ret < 0) ? -errno : ret;
}
/*
@@ -597,6 +597,45 @@ static int posix_aio_init(void)
return 0;
}
+static void raw_aio_remove(RawAIOCB *acb)
+{
+ RawAIOCB **pacb;
+
+ /* remove the callback from the queue */
+ pacb = &posix_aio_state->first_aio;
+ for(;;) {
+ if (*pacb == NULL) {
+ fprintf(stderr, "raw_aio_remove: aio request not found!\n");
+ break;
+ } else if (*pacb == acb) {
+ *pacb = acb->next;
+ qemu_aio_release(acb);
+ break;
+ }
+ pacb = &(*pacb)->next;
+ }
+}
+
+static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+ int ret;
+ RawAIOCB *acb = (RawAIOCB *)blockacb;
+
+ ret = qemu_paio_cancel(acb->aiocb.aio_fildes, &acb->aiocb);
+ if (ret == QEMU_PAIO_NOTCANCELED) {
+ /* fail safe: if the aio could not be canceled, we wait for
+ it */
+ while (qemu_paio_error(&acb->aiocb) == EINPROGRESS);
+ }
+
+ raw_aio_remove(acb);
+}
+
+static AIOPool raw_aio_pool = {
+ .aiocb_size = sizeof(RawAIOCB),
+ .cancel = raw_aio_cancel,
+};
+
static RawAIOCB *raw_aio_setup(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
@@ -607,7 +646,7 @@ static RawAIOCB *raw_aio_setup(BlockDriverState *bs, int64_t sector_num,
if (fd_open(bs) < 0)
return NULL;
- acb = qemu_aio_get(bs, cb, opaque);
+ acb = qemu_aio_get(&raw_aio_pool, bs, cb, opaque);
if (!acb)
return NULL;
acb->aiocb.aio_fildes = s->fd;
@@ -631,25 +670,6 @@ static RawAIOCB *raw_aio_setup(BlockDriverState *bs, int64_t sector_num,
return acb;
}
-static void raw_aio_remove(RawAIOCB *acb)
-{
- RawAIOCB **pacb;
-
- /* remove the callback from the queue */
- pacb = &posix_aio_state->first_aio;
- for(;;) {
- if (*pacb == NULL) {
- fprintf(stderr, "raw_aio_remove: aio request not found!\n");
- break;
- } else if (*pacb == acb) {
- *pacb = acb->next;
- qemu_aio_release(acb);
- break;
- }
- pacb = &(*pacb)->next;
- }
-}
-
static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
@@ -681,21 +701,6 @@ static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
}
return &acb->common;
}
-
-static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
-{
- int ret;
- RawAIOCB *acb = (RawAIOCB *)blockacb;
-
- ret = qemu_paio_cancel(acb->aiocb.aio_fildes, &acb->aiocb);
- if (ret == QEMU_PAIO_NOTCANCELED) {
- /* fail safe: if the aio could not be canceled, we wait for
- it */
- while (qemu_paio_error(&acb->aiocb) == EINPROGRESS);
- }
-
- raw_aio_remove(acb);
-}
#else /* CONFIG_AIO */
static int posix_aio_init(void)
{
@@ -869,8 +874,6 @@ static BlockDriver bdrv_raw = {
#ifdef CONFIG_AIO
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
- .bdrv_aio_cancel = raw_aio_cancel,
- .aiocb_size = sizeof(RawAIOCB),
#endif
.bdrv_truncate = raw_truncate,
@@ -1203,7 +1206,7 @@ static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
if (fd_open(bs) < 0)
return NULL;
- acb = qemu_aio_get(bs, cb, opaque);
+ acb = qemu_aio_get(&raw_aio_pool, bs, cb, opaque);
if (!acb)
return NULL;
acb->aiocb.aio_fildes = s->fd;
@@ -1374,7 +1377,6 @@ static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
}
#endif /* !linux && !FreeBSD */
-#if defined(__linux__) || defined(__FreeBSD__)
static int hdev_create(const char *filename, QEMUOptionParameter *options)
{
int fd;
@@ -1396,7 +1398,7 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options)
if (fstat(fd, &stat_buf) < 0)
ret = -EIO;
- else if (!S_ISBLK(stat_buf.st_mode))
+ else if (!S_ISBLK(stat_buf.st_mode) && !S_ISCHR(stat_buf.st_mode))
ret = -EIO;
else if (lseek(fd, 0, SEEK_END) < total_size * 512)
ret = -ENOSPC;
@@ -1405,14 +1407,6 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options)
return ret;
}
-#else /* !(linux || freebsd) */
-
-static int hdev_create(const char *filename, QEMUOptionParameter *options)
-{
- return -ENOTSUP;
-}
-#endif
-
static BlockDriver bdrv_host_device = {
.format_name = "host_device",
.instance_size = sizeof(BDRVRawState),
@@ -1424,8 +1418,6 @@ static BlockDriver bdrv_host_device = {
#ifdef CONFIG_AIO
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
- .bdrv_aio_cancel = raw_aio_cancel,
- .aiocb_size = sizeof(RawAIOCB),
#endif
.bdrv_read = raw_read,
diff --git a/block/vvfat.c b/block/vvfat.c
index 13960e95a..1e37b9f9f 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -2762,14 +2762,15 @@ static void write_target_close(BlockDriverState *bs) {
}
static BlockDriver vvfat_write_target = {
- "vvfat_write_target", 0, NULL, NULL, NULL,
- write_target_commit,
- write_target_close,
- NULL, NULL, NULL
+ .format_name = "vvfat_write_target",
+ .bdrv_write = write_target_commit,
+ .bdrv_close = write_target_close,
};
static int enable_write_target(BDRVVVFATState *s)
{
+ BlockDriver *bdrv_qcow;
+ QEMUOptionParameter *options;
int size = sector2cluster(s, s->sector_count);
s->used_clusters = calloc(size, 1);
@@ -2777,8 +2778,13 @@ static int enable_write_target(BDRVVVFATState *s)
s->qcow_filename = qemu_malloc(1024);
get_tmp_filename(s->qcow_filename, 1024);
- if (bdrv_create2(bdrv_find_format("qcow"),
- s->qcow_filename, s->sector_count, "fat:", NULL, 0) < 0)
+
+ bdrv_qcow = bdrv_find_format("qcow");
+ options = parse_option_parameters("", bdrv_qcow->create_options, NULL);
+ set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512);
+ set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
+
+ if (bdrv_create(bdrv_qcow, s->qcow_filename, options) < 0)
return -1;
s->qcow = bdrv_new("");
if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
diff --git a/block_int.h b/block_int.h
index 0820ed1d5..8d0da7cfd 100644
--- a/block_int.h
+++ b/block_int.h
@@ -67,8 +67,6 @@ struct BlockDriver {
BlockDriverAIOCB *(*bdrv_aio_writev)(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
- void (*bdrv_aio_cancel)(BlockDriverAIOCB *acb);
- int aiocb_size;
const char *protocol_name;
int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
@@ -102,8 +100,6 @@ struct BlockDriver {
unsigned long int req, void *buf,
BlockDriverCompletionFunc *cb, void *opaque);
- AIOPool aio_pool;
-
/* List of options for creating images, terminated by name == NULL */
QEMUOptionParameter *create_options;
@@ -173,13 +169,8 @@ struct BlockDriverAIOCB {
void get_tmp_filename(char *filename, int size);
-void aio_pool_init(AIOPool *pool, int aiocb_size,
- void (*cancel)(BlockDriverAIOCB *acb));
-
-void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
- void *opaque);
-void *qemu_aio_get_pool(AIOPool *pool, BlockDriverState *bs,
- BlockDriverCompletionFunc *cb, void *opaque);
+void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque);
void qemu_aio_release(void *p);
void *qemu_blockalign(BlockDriverState *bs, size_t size);
diff --git a/configure b/configure
index 80ab7d410..68fd70c36 100755
--- a/configure
+++ b/configure
@@ -127,6 +127,9 @@ case "$cpu" in
m68k)
cpu="m68k"
;;
+ microblaze)
+ cpu="microblaze"
+ ;;
mips)
cpu="mips"
;;
@@ -718,6 +721,7 @@ x86_64-softmmu \
arm-softmmu \
cris-softmmu \
m68k-softmmu \
+microblaze-softmmu \
mips-softmmu \
mipsel-softmmu \
mips64-softmmu \
@@ -740,6 +744,7 @@ arm-linux-user \
armeb-linux-user \
cris-linux-user \
m68k-linux-user \
+microblaze-linux-user \
mips-linux-user \
mipsel-linux-user \
ppc-linux-user \
@@ -1244,18 +1249,22 @@ fi
##########################################
# pthread probe
+PTHREADLIBS_LIST="-lpthread -lpthreadGC2"
PTHREADLIBS=""
if test "$pthread" = yes; then
pthread=no
cat > $TMPC << EOF
#include <pthread.h>
-int main(void) { pthread_mutex_t lock; return 0; }
+int main(void) { pthread_create(0,0,0,0); return 0; }
EOF
- if $cc $ARCH_CFLAGS -o $TMPE $PTHREADLIBS $TMPC 2> /dev/null > /dev/null ; then
- pthread=yes
- PTHREADLIBS="-lpthread"
- fi
+ for pthread_lib in $PTHREADLIBS_LIST; do
+ if $cc $ARCH_CFLAGS -o $TMPE $TMPC $pthread_lib 2> /dev/null > /dev/null ; then
+ pthread=yes
+ PTHREADLIBS="$pthread_lib"
+ break
+ fi
+ done
fi
if test "$pthread" = no; then
@@ -1580,6 +1589,10 @@ case "$cpu" in
echo "ARCH=m68k" >> $config_mak
echo "#define HOST_M68K 1" >> $config_h
;;
+ microblaze)
+ echo "ARCH=microblaze" >> $config_mak
+ echo "#define HOST_MICROBLAZE 1" >> $config_h
+ ;;
mips)
echo "ARCH=mips" >> $config_mak
echo "#define HOST_MIPS 1" >> $config_h
@@ -1896,7 +1909,14 @@ if test `expr "$target_list" : ".*softmmu.*"` != 0 ; then
fi
echo "TOOLS=$tools" >> $config_mak
-test -f ${config_h}~ && cmp -s $config_h ${config_h}~ && mv ${config_h}~ $config_h
+if test -f ${config_h}~ ; then
+ if cmp -s $config_h ${config_h}~ ; then
+ mv ${config_h}~ $config_h
+ else
+ rm ${config_h}~
+ fi
+fi
+
config_host_mak=${config_mak}
for target in $target_list; do
@@ -1907,6 +1927,7 @@ target_cpu=`echo $target | cut -d '-' -f 1`
target_bigendian="no"
[ "$target_cpu" = "armeb" ] && target_bigendian=yes
[ "$target_cpu" = "m68k" ] && target_bigendian=yes
+[ "$target_cpu" = "microblaze" ] && target_bigendian=yes
[ "$target_cpu" = "mips" ] && target_bigendian=yes
[ "$target_cpu" = "mipsn32" ] && target_bigendian=yes
[ "$target_cpu" = "mips64" ] && target_bigendian=yes
@@ -2103,7 +2124,15 @@ case "$target_cpu" in
gdb_xml_files="cf-core.xml cf-fp.xml"
target_phys_bits=32
;;
- mips|mipsel)
+ microblaze)
+ echo "TARGET_ARCH=microblaze" >> $config_mak
+ echo "#define TARGET_ARCH \"microblaze\"" >> $config_h
+ echo "#define TARGET_MICROBLAZE 1" >> $config_h
+ bflt="yes"
+ target_nptl="yes"
+ target_phys_bits=32
+ ;;
+ mips|mipsel)
echo "TARGET_ARCH=mips" >> $config_mak
echo "#define TARGET_ARCH \"mips\"" >> $config_h
echo "#define TARGET_MIPS 1" >> $config_h
@@ -2240,6 +2269,7 @@ echo "TARGET_XML_FILES=$list" >> $config_mak
if test "$target_cpu" = "arm" \
-o "$target_cpu" = "armeb" \
-o "$target_cpu" = "m68k" \
+ -o "$target_cpu" = "microblaze" \
-o "$target_cpu" = "mips" \
-o "$target_cpu" = "mipsel" \
-o "$target_cpu" = "mipsn32" \
diff --git a/cpu-exec.c b/cpu-exec.c
index 777fa5fef..71102958a 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -250,6 +250,7 @@ int cpu_exec(CPUState *env1)
#elif defined(TARGET_ALPHA)
#elif defined(TARGET_ARM)
#elif defined(TARGET_PPC)
+#elif defined(TARGET_MICROBLAZE)
#elif defined(TARGET_MIPS)
#elif defined(TARGET_SH4)
#elif defined(TARGET_CRIS)
@@ -305,6 +306,8 @@ int cpu_exec(CPUState *env1)
env->old_exception = -1;
#elif defined(TARGET_PPC)
do_interrupt(env);
+#elif defined(TARGET_MICROBLAZE)
+ do_interrupt(env);
#elif defined(TARGET_MIPS)
do_interrupt(env);
#elif defined(TARGET_SPARC)
@@ -374,7 +377,8 @@ int cpu_exec(CPUState *env1)
cpu_loop_exit();
}
#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
- defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
+ defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
+ defined(TARGET_MICROBLAZE)
if (interrupt_request & CPU_INTERRUPT_HALT) {
env->interrupt_request &= ~CPU_INTERRUPT_HALT;
env->halted = 1;
@@ -443,6 +447,15 @@ int cpu_exec(CPUState *env1)
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
next_tb = 0;
}
+#elif defined(TARGET_MICROBLAZE)
+ if ((interrupt_request & CPU_INTERRUPT_HARD)
+ && (env->sregs[SR_MSR] & MSR_IE)
+ && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
+ && !(env->iflags & (D_FLAG | IMM_FLAG))) {
+ env->exception_index = EXCP_IRQ;
+ do_interrupt(env);
+ next_tb = 0;
+ }
#elif defined(TARGET_MIPS)
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
(env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
@@ -572,6 +585,8 @@ int cpu_exec(CPUState *env1)
env->sr = (env->sr & 0xffe0)
| env->cc_dest | (env->cc_x << 4);
log_cpu_state(env, 0);
+#elif defined(TARGET_MICROBLAZE)
+ log_cpu_state(env, 0);
#elif defined(TARGET_MIPS)
log_cpu_state(env, 0);
#elif defined(TARGET_SH4)
@@ -689,6 +704,7 @@ int cpu_exec(CPUState *env1)
env->cc_op = CC_OP_FLAGS;
env->sr = (env->sr & 0xffe0)
| env->cc_dest | (env->cc_x << 4);
+#elif defined(TARGET_MICROBLAZE)
#elif defined(TARGET_MIPS)
#elif defined(TARGET_SH4)
#elif defined(TARGET_IA64)
@@ -1036,6 +1052,56 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
return 1;
}
+#elif defined (TARGET_MICROBLAZE)
+static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+ int is_write, sigset_t *old_set,
+ void *puc)
+{
+ TranslationBlock *tb;
+ int ret;
+
+ if (cpu_single_env)
+ env = cpu_single_env; /* XXX: find a correct solution for multithread */
+#if defined(DEBUG_SIGNAL)
+ printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
+ pc, address, is_write, *(unsigned long *)old_set);
+#endif
+ /* XXX: locking issue */
+ if (is_write && page_unprotect(h2g(address), pc, puc)) {
+ return 1;
+ }
+
+ /* see if it is an MMU fault */
+ ret = cpu_mb_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
+ if (ret < 0)
+ return 0; /* not an MMU fault */
+ if (ret == 0)
+ return 1; /* the MMU fault was handled without causing real CPU fault */
+
+ /* now we have a real cpu fault */
+ 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, puc);
+ }
+ if (ret == 1) {
+#if 0
+ printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
+ env->PC, 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);
+ cpu_loop_exit();
+ } else {
+ /* activate soft MMU for this block */
+ cpu_resume_from_signal(env, puc);
+ }
+ /* never comes here */
+ return 1;
+}
+
#elif defined (TARGET_SH4)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set,
diff --git a/dis-asm.h b/dis-asm.h
index 303e23f4b..251c49030 100644
--- a/dis-asm.h
+++ b/dis-asm.h
@@ -218,6 +218,7 @@ enum bfd_architecture
#define bfd_mach_cris_v0_v10 255
#define bfd_mach_cris_v32 32
#define bfd_mach_cris_v10_v32 1032
+ bfd_arch_microblaze, /* Xilinx MicroBlaze. */
bfd_arch_last
};
#define bfd_mach_s390_31 31
@@ -400,6 +401,7 @@ extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_ppc 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*));
+extern int print_insn_microblaze PARAMS ((bfd_vma, disassemble_info*));
#if 0
/* Fetch the disassembler for a given BFD, if that support is available. */
diff --git a/disas.c b/disas.c
index 6ed31e3b7..af5a9ea14 100644
--- a/disas.c
+++ b/disas.c
@@ -195,6 +195,9 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
#elif defined(TARGET_CRIS)
disasm_info.mach = bfd_mach_cris_v32;
print_insn = print_insn_crisv32;
+#elif defined(TARGET_MICROBLAZE)
+ disasm_info.mach = bfd_arch_microblaze;
+ print_insn = print_insn_microblaze;
#else
fprintf(out, "0x" TARGET_FMT_lx
": Asm output not supported on this arch\n", code);
diff --git a/dma-helpers.c b/dma-helpers.c
index f9eb2240b..712ed897f 100644
--- a/dma-helpers.c
+++ b/dma-helpers.c
@@ -10,8 +10,6 @@
#include "dma.h"
#include "block_int.h"
-static AIOPool dma_aio_pool;
-
void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint)
{
qsg->sg = qemu_malloc(alloc_hint * sizeof(ScatterGatherEntry));
@@ -132,12 +130,26 @@ static void dma_bdrv_cb(void *opaque, int ret)
}
}
+static void dma_aio_cancel(BlockDriverAIOCB *acb)
+{
+ DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common);
+
+ if (dbs->acb) {
+ bdrv_aio_cancel(dbs->acb);
+ }
+}
+
+static AIOPool dma_aio_pool = {
+ .aiocb_size = sizeof(DMAAIOCB),
+ .cancel = dma_aio_cancel,
+};
+
static BlockDriverAIOCB *dma_bdrv_io(
BlockDriverState *bs, QEMUSGList *sg, uint64_t sector_num,
BlockDriverCompletionFunc *cb, void *opaque,
int is_write)
{
- DMAAIOCB *dbs = qemu_aio_get_pool(&dma_aio_pool, bs, cb, opaque);
+ DMAAIOCB *dbs = qemu_aio_get(&dma_aio_pool, bs, cb, opaque);
dbs->acb = NULL;
dbs->bs = bs;
@@ -170,17 +182,3 @@ BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
{
return dma_bdrv_io(bs, sg, sector, cb, opaque, 1);
}
-
-static void dma_aio_cancel(BlockDriverAIOCB *acb)
-{
- DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common);
-
- if (dbs->acb) {
- bdrv_aio_cancel(dbs->acb);
- }
-}
-
-void dma_helper_init(void)
-{
- aio_pool_init(&dma_aio_pool, sizeof(DMAAIOCB), dma_aio_cancel);
-}
diff --git a/dma.h b/dma.h
index 4fd80b972..f3bb27515 100644
--- a/dma.h
+++ b/dma.h
@@ -38,6 +38,4 @@ BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
QEMUSGList *sg, uint64_t sector,
BlockDriverCompletionFunc *cb, void *opaque);
-void dma_helper_init(void);
-
#endif
diff --git a/elf.h b/elf.h
index 861f1d384..182cad92d 100644
--- a/elf.h
+++ b/elf.h
@@ -119,6 +119,8 @@ typedef int64_t Elf64_Sxword;
*/
#define EM_S390_OLD 0xA390
+#define EM_XILINX_MICROBLAZE 0xBAAB
+
/* This is the info that is needed to parse the dynamic section of the file */
#define DT_NULL 0
#define DT_NEEDED 1
diff --git a/gdbstub.c b/gdbstub.c
index 0a7abab1c..9d99f7540 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1157,6 +1157,36 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
return 4;
}
+#elif defined (TARGET_MICROBLAZE)
+
+#define NUM_CORE_REGS (32 + 5)
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+ if (n < 32) {
+ GET_REG32(env->regs[n]);
+ } else {
+ GET_REG32(env->sregs[n - 32]);
+ }
+ return 0;
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+ uint32_t tmp;
+
+ if (n > NUM_CORE_REGS)
+ return 0;
+
+ tmp = ldl_p(mem_buf);
+
+ if (n < 32) {
+ env->regs[n] = tmp;
+ } else {
+ env->sregs[n - 32] = tmp;
+ }
+ return 4;
+}
#elif defined (TARGET_CRIS)
#define NUM_CORE_REGS 49
@@ -1529,6 +1559,8 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
s->c_cpu->pc = pc;
#elif defined (TARGET_MIPS)
s->c_cpu->active_tc.PC = pc;
+#elif defined (TARGET_MICROBLAZE)
+ s->c_cpu->sregs[SR_PC] = pc;
#elif defined (TARGET_CRIS)
s->c_cpu->pc = pc;
#elif defined (TARGET_ALPHA)
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 5dc944836..817234da9 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -721,7 +721,7 @@ static void gic_init(gic_state *s)
{
int i;
- qdev_init_irq_sink(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32);
+ qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32);
for (i = 0; i < NCPU; i++) {
sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
}
diff --git a/hw/armv7m.c b/hw/armv7m.c
index 6be9940bc..e3d00ffd7 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -186,7 +186,7 @@ qemu_irq *armv7m_init(int flash_size, int sram_size,
cpu_pic = arm_pic_init_cpu(env);
sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]);
for (i = 0; i < 64; i++) {
- pic[i] = qdev_get_irq_sink(nvic, i);
+ pic[i] = qdev_get_gpio_in(nvic, i);
}
image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL);
diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c
index 60b719b2f..fc527cbec 100644
--- a/hw/axis_dev88.c
+++ b/hw/axis_dev88.c
@@ -304,10 +304,10 @@ void axisdev88_init (ram_addr_t ram_size,
sysbus_connect_irq(s, 0, cpu_irq[0]);
sysbus_connect_irq(s, 1, cpu_irq[1]);
for (i = 0; i < 30; i++) {
- irq[i] = qdev_get_irq_sink(dev, i);
+ irq[i] = qdev_get_gpio_in(dev, i);
}
- nmi[0] = qdev_get_irq_sink(dev, 30);
- nmi[1] = qdev_get_irq_sink(dev, 31);
+ nmi[0] = qdev_get_gpio_in(dev, 30);
+ nmi[1] = qdev_get_gpio_in(dev, 31);
etraxfs_dmac = etraxfs_dmac_init(env, 0x30000000, 10);
for (i = 0; i < 10; i++) {
diff --git a/hw/e1000.c b/hw/e1000.c
index c5eb54699..26657922c 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -190,6 +190,13 @@ rxbufsize(uint32_t v)
}
static void
+set_ctrl(E1000State *s, int index, uint32_t val)
+{
+ /* RST is self clearing */
+ s->mac_reg[CTRL] = val & ~E1000_CTRL_RST;
+}
+
+static void
set_rx_control(E1000State *s, int index, uint32_t val)
{
s->mac_reg[RCTL] = val;
@@ -783,12 +790,12 @@ enum { NREADOPS = ARRAY_SIZE(macreg_readops) };
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), putreg(CTRL), putreg(VET),
+ putreg(RDBAL), putreg(LEDCTL), putreg(VET),
[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,
+ [EECD] = set_eecd, [RCTL] = set_rx_control, [CTRL] = set_ctrl,
[RA ... RA+31] = &mac_writereg,
[MTA ... MTA+127] = &mac_writereg,
[VFTA ... VFTA+127] = &mac_writereg,
diff --git a/hw/esp.c b/hw/esp.c
index 6ac8c35d6..ffb222525 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -684,7 +684,7 @@ static void esp_init1(SysBusDevice *dev)
register_savevm("esp", -1, 3, esp_save, esp_load, s);
qemu_register_reset(esp_reset, 0, s);
- qdev_init_irq_sink(&dev->qdev, parent_esp_reset, 1);
+ qdev_init_gpio_in(&dev->qdev, parent_esp_reset, 1);
scsi_bus_new(&dev->qdev, esp_scsi_attach);
}
diff --git a/hw/etraxfs.c b/hw/etraxfs.c
index f82e1cd0f..1e200553e 100644
--- a/hw/etraxfs.c
+++ b/hw/etraxfs.c
@@ -90,10 +90,10 @@ void bareetraxfs_init (ram_addr_t ram_size,
/* FIXME: Is there a proper way to signal vectors to the CPU core? */
qdev_set_prop_ptr(dev, "interrupt_vector", &env->interrupt_vector);
for (i = 0; i < 30; i++) {
- irq[i] = qdev_get_irq_sink(dev, i);
+ irq[i] = qdev_get_gpio_in(dev, i);
}
- nmi[0] = qdev_get_irq_sink(dev, 30);
- nmi[1] = qdev_get_irq_sink(dev, 31);
+ nmi[0] = qdev_get_gpio_in(dev, 30);
+ nmi[1] = qdev_get_gpio_in(dev, 31);
etraxfs_dmac = etraxfs_dmac_init(env, 0x30000000, 10);
for (i = 0; i < 10; i++) {
diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c
index da9d0c3be..585e7850f 100644
--- a/hw/etraxfs_pic.c
+++ b/hw/etraxfs_pic.c
@@ -141,7 +141,7 @@ static void etraxfs_pic_init(SysBusDevice *dev)
int intr_vect_regs;
s->interrupt_vector = qdev_get_prop_ptr(&dev->qdev, "interrupt_vector");
- qdev_init_irq_sink(&dev->qdev, irq_handler, 32);
+ qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
sysbus_init_irq(dev, &s->parent_irq);
sysbus_init_irq(dev, &s->parent_nmi);
diff --git a/hw/hw.h b/hw/hw.h
index a3f5717b3..c83580073 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -51,6 +51,7 @@ 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);
+int qemu_popen_fd(QEMUFile *f);
void qemu_fflush(QEMUFile *f);
int qemu_fclose(QEMUFile *f);
void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size);
diff --git a/hw/integratorcp.c b/hw/integratorcp.c
index 493866c92..b6fbe1523 100644
--- a/hw/integratorcp.c
+++ b/hw/integratorcp.c
@@ -378,7 +378,7 @@ static void icp_pic_init(SysBusDevice *dev)
icp_pic_state *s = FROM_SYSBUS(icp_pic_state, dev);
int iomemtype;
- qdev_init_irq_sink(&dev->qdev, icp_pic_set_irq, 32);
+ qdev_init_gpio_in(&dev->qdev, icp_pic_set_irq, 32);
sysbus_init_irq(dev, &s->parent_irq);
sysbus_init_irq(dev, &s->parent_fiq);
iomemtype = cpu_register_io_memory(0, icp_pic_readfn,
@@ -484,7 +484,7 @@ static void integratorcp_init(ram_addr_t ram_size,
cpu_pic[ARM_PIC_CPU_IRQ],
cpu_pic[ARM_PIC_CPU_FIQ], NULL);
for (i = 0; i < 32; i++) {
- pic[i] = qdev_get_irq_sink(dev, i);
+ pic[i] = qdev_get_gpio_in(dev, i);
}
sysbus_create_simple("integrator_pic", 0xca000000, pic[26]);
sysbus_create_varargs("integrator_pit", 0x13000000,
diff --git a/hw/microblaze_pic_cpu.c b/hw/microblaze_pic_cpu.c
new file mode 100644
index 000000000..7c59382fb
--- /dev/null
+++ b/hw/microblaze_pic_cpu.c
@@ -0,0 +1,50 @@
+/*
+ * QEMU MicroBlaze CPU interrupt wrapper logic.
+ *
+ * Copyright (c) 2009 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 "hw.h"
+#include "pc.h"
+
+#define D(x)
+
+void pic_info(Monitor *mon)
+{}
+void irq_info(Monitor *mon)
+{}
+
+static void microblaze_pic_cpu_handler(void *opaque, int irq, int level)
+{
+ CPUState *env = (CPUState *)opaque;
+ int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD;
+
+ if (level)
+ cpu_interrupt(env, type);
+ else
+ cpu_reset_interrupt(env, type);
+}
+
+qemu_irq *microblaze_pic_init_cpu(CPUState *env);
+qemu_irq *microblaze_pic_init_cpu(CPUState *env)
+{
+ return qemu_allocate_irqs(microblaze_pic_cpu_handler, env, 2);
+}
diff --git a/hw/mpcore.c b/hw/mpcore.c
index 6df9a91ad..a5eddd9cc 100644
--- a/hw/mpcore.c
+++ b/hw/mpcore.c
@@ -320,17 +320,17 @@ static void realview_mpcore_init(SysBusDevice *dev)
priv = sysbus_create_simple("arm11mpcore_priv", MPCORE_PRIV_BASE, NULL);
sysbus_pass_irq(dev, sysbus_from_qdev(priv));
for (i = 0; i < 32; i++) {
- s->cpuic[i] = qdev_get_irq_sink(priv, i);
+ s->cpuic[i] = qdev_get_gpio_in(priv, i);
}
/* ??? IRQ routing is hardcoded to "normal" mode. */
for (n = 0; n < 4; n++) {
gic = sysbus_create_simple("realview_gic", 0x10040000 + n * 0x10000,
s->cpuic[10 + n]);
for (i = 0; i < 64; i++) {
- s->rvic[n][i] = qdev_get_irq_sink(gic, i);
+ s->rvic[n][i] = qdev_get_gpio_in(gic, i);
}
}
- qdev_init_irq_sink(&dev->qdev, mpcore_rirq_set_irq, 64);
+ qdev_init_gpio_in(&dev->qdev, mpcore_rirq_set_irq, 64);
}
static void mpcore_register_devices(void)
diff --git a/hw/musicpal.c b/hw/musicpal.c
index 1e0aff5cb..9389af958 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -1040,7 +1040,7 @@ static void mv88w8618_pic_init(SysBusDevice *dev)
mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state, dev);
int iomemtype;
- qdev_init_irq_sink(&dev->qdev, mv88w8618_pic_set_irq, 32);
+ qdev_init_gpio_in(&dev->qdev, mv88w8618_pic_set_irq, 32);
sysbus_init_irq(dev, &s->parent_irq);
iomemtype = cpu_register_io_memory(0, mv88w8618_pic_readfn,
mv88w8618_pic_writefn, s);
@@ -1534,7 +1534,7 @@ static void musicpal_init(ram_addr_t ram_size,
dev = sysbus_create_simple("mv88w8618_pic", MP_PIC_BASE,
cpu_pic[ARM_PIC_CPU_IRQ]);
for (i = 0; i < 32; i++) {
- pic[i] = qdev_get_irq_sink(dev, i);
+ pic[i] = qdev_get_gpio_in(dev, i);
}
sysbus_create_varargs("mv88w8618_pit", MP_PIT_BASE, pic[MP_TIMER1_IRQ],
pic[MP_TIMER2_IRQ], pic[MP_TIMER3_IRQ],
diff --git a/hw/pcnet.c b/hw/pcnet.c
index 2c22f4a50..c44ba7edf 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -2127,7 +2127,7 @@ static void lance_init(SysBusDevice *dev)
s->dma_opaque = qdev_get_prop_ptr(&dev->qdev, "dma");
- qdev_init_irq_sink(&dev->qdev, parent_lance_reset, 1);
+ qdev_init_gpio_in(&dev->qdev, parent_lance_reset, 1);
sysbus_init_mmio(dev, 4, s->mmio_index);
diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c
new file mode 100644
index 000000000..80097df81
--- /dev/null
+++ b/hw/petalogix_s3adsp1800_mmu.c
@@ -0,0 +1,199 @@
+/*
+ * Model of Petalogix linux reference design targeting Xilinx Spartan 3ADSP-1800
+ * boards.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * 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 "sysbus.h"
+#include "hw.h"
+#include "net.h"
+#include "flash.h"
+#include "sysemu.h"
+#include "devices.h"
+#include "boards.h"
+#include "device_tree.h"
+#include "xilinx.h"
+
+#define LMB_BRAM_SIZE (128 * 1024)
+#define FLASH_SIZE (16 * 1024 * 1024)
+
+static uint32_t bootstrap_pc;
+
+static void main_cpu_reset(void *opaque)
+{
+ CPUState *env = opaque;
+ cpu_reset(env);
+ env->sregs[SR_PC] = bootstrap_pc;
+}
+
+#define BINARY_DEVICE_TREE_FILE "petalogix-s3adsp1800.dtb"
+static int petalogix_load_device_tree(target_phys_addr_t addr,
+ uint32_t ramsize,
+ target_phys_addr_t initrd_base,
+ target_phys_addr_t initrd_size,
+ const char *kernel_cmdline)
+{
+#ifdef HAVE_FDT
+ void *fdt;
+ char *path = NULL;
+ int pathlen;
+ int r;
+#endif
+ int fdt_size;
+
+#ifdef HAVE_FDT
+ /* Try the local "mb.dtb" override. */
+ fdt = load_device_tree("mb.dtb", &fdt_size);
+ if (!fdt) {
+ pathlen = snprintf(NULL, 0, "%s/%s",
+ bios_dir, BINARY_DEVICE_TREE_FILE) + 1;
+ path = qemu_malloc(pathlen);
+ snprintf(path, pathlen, "%s/%s", bios_dir, BINARY_DEVICE_TREE_FILE);
+ fdt = load_device_tree(BINARY_DEVICE_TREE_FILE, &fdt_size);
+ free(path);
+ if (!fdt)
+ return 0;
+ }
+
+ r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
+ if (r < 0)
+ fprintf(stderr, "couldn't set /chosen/bootargs\n");
+ cpu_physical_memory_write (addr, (void *)fdt, fdt_size);
+#else
+ /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob
+ to the kernel. */
+ fdt_size = load_image_targphys("mb.dtb", addr, 0x10000);
+ if (fdt_size < 0) {
+ fdt_size = load_image_targphys(BINARY_DEVICE_TREE_FILE, addr, 0x10000);
+ }
+
+ if (kernel_cmdline) {
+ fprintf(stderr,
+ "Warning: missing libfdt, cannot pass cmdline to kernel!\n");
+ }
+#endif
+ return fdt_size;
+}
+
+static void
+petalogix_s3adsp1800_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ DeviceState *dev;
+ CPUState *env;
+ int kernel_size;
+ int i;
+ target_phys_addr_t ddr_base = 0x90000000;
+ ram_addr_t phys_lmb_bram;
+ ram_addr_t phys_ram;
+ ram_addr_t phys_flash;
+ qemu_irq irq[32], *cpu_irq;
+
+ /* init CPUs */
+ if (cpu_model == NULL) {
+ cpu_model = "microblaze";
+ }
+ env = cpu_init(cpu_model);
+
+ env->pvr.regs[10] = 0x0c000000; /* spartan 3a dsp family. */
+ qemu_register_reset(main_cpu_reset, 0, env);
+
+ /* Attach emulated BRAM through the LMB. */
+ phys_lmb_bram = qemu_ram_alloc(LMB_BRAM_SIZE);
+ cpu_register_physical_memory(0x00000000, LMB_BRAM_SIZE,
+ phys_lmb_bram | IO_MEM_RAM);
+
+ phys_ram = qemu_ram_alloc(ram_size);
+ cpu_register_physical_memory(ddr_base, ram_size, phys_ram | IO_MEM_RAM);
+
+ phys_flash = qemu_ram_alloc(FLASH_SIZE);
+ i = drive_get_index(IF_PFLASH, 0, 0);
+ pflash_cfi02_register(0xa0000000, phys_flash,
+ i != -1 ? drives_table[i].bdrv : NULL, (64 * 1024),
+ FLASH_SIZE >> 16,
+ 1, 1, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x555, 0x2aa);
+
+ cpu_irq = microblaze_pic_init_cpu(env);
+ dev = xilinx_intc_create(0x81800000, cpu_irq[0], 2);
+ for (i = 0; i < 32; i++) {
+ irq[i] = qdev_get_gpio_in(dev, i);
+ }
+
+ sysbus_create_simple("xilinx,uartlite", 0x84000000, irq[3]);
+ /* 2 timers at irq 2 @ 62 Mhz. */
+ xilinx_timer_create(0x83c00000, irq[0], 2, 62 * 1000000);
+ xilinx_ethlite_create(&nd_table[0], 0x81000000, irq[1], 0, 0);
+
+ if (kernel_filename) {
+ uint64_t entry, low, high;
+ int kcmdline_len;
+ uint32_t base32;
+
+ /* Boots a kernel elf binary. */
+ kernel_size = load_elf(kernel_filename, 0,
+ &entry, &low, &high);
+ base32 = entry;
+ if (base32 == 0xc0000000) {
+ kernel_size = load_elf(kernel_filename, -0x30000000LL,
+ &entry, NULL, NULL);
+ }
+ /* Always boot into physical ram. */
+ bootstrap_pc = ddr_base + (entry & 0x0fffffff);
+ if (kernel_size < 0) {
+ /* If we failed loading ELF's try a raw image. */
+ kernel_size = load_image_targphys(kernel_filename, ddr_base,
+ ram_size);
+ bootstrap_pc = ddr_base;
+ }
+
+ env->regs[5] = ddr_base + kernel_size;
+ if (kernel_cmdline && (kcmdline_len = strlen(kernel_cmdline))) {
+ pstrcpy_targphys(env->regs[5], 256, kernel_cmdline);
+ }
+ env->regs[6] = 0;
+ /* Provide a device-tree. */
+ env->regs[7] = ddr_base + kernel_size + 256;
+ petalogix_load_device_tree(env->regs[7], ram_size,
+ env->regs[6], 0,
+ kernel_cmdline);
+ }
+
+ env->sregs[SR_PC] = bootstrap_pc;
+}
+
+static QEMUMachine petalogix_s3adsp1800_machine = {
+ .name = "petalogix-s3adsp1800",
+ .desc = "Petalogix linux refdesign for xilinx Spartan 3ADSP1800",
+ .init = petalogix_s3adsp1800_init,
+ .is_default = 1
+};
+
+static void petalogix_s3adsp1800_machine_init(void)
+{
+ qemu_register_machine(&petalogix_s3adsp1800_machine);
+}
+
+machine_init(petalogix_s3adsp1800_machine_init);
diff --git a/hw/pl190.c b/hw/pl190.c
index b8c2018d3..10857683d 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -235,7 +235,7 @@ static void pl190_init(SysBusDevice *dev)
iomemtype = cpu_register_io_memory(0, pl190_readfn,
pl190_writefn, s);
sysbus_init_mmio(dev, 0x1000, iomemtype);
- qdev_init_irq_sink(&dev->qdev, pl190_set_irq, 32);
+ qdev_init_gpio_in(&dev->qdev, pl190_set_irq, 32);
sysbus_init_irq(dev, &s->irq);
sysbus_init_irq(dev, &s->fiq);
pl190_reset(s);
diff --git a/hw/qdev.c b/hw/qdev.c
index b9278e9a5..d945ff953 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -156,19 +156,6 @@ void qdev_set_netdev(DeviceState *dev, NICInfo *nd)
}
-qemu_irq qdev_get_irq_sink(DeviceState *dev, int n)
-{
- assert(n >= 0 && n < dev->num_irq_sink);
- return dev->irq_sink[n];
-}
-
-/* Register device IRQ sinks. */
-void qdev_init_irq_sink(DeviceState *dev, qemu_irq_handler handler, int nirq)
-{
- dev->num_irq_sink = nirq;
- dev->irq_sink = qemu_allocate_irqs(handler, dev, nirq);
-}
-
/* Get a character (serial) device interface. */
CharDriverState *qdev_init_chardev(DeviceState *dev)
{
diff --git a/hw/qdev.h b/hw/qdev.h
index 0931bc19d..143a1f873 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -17,8 +17,6 @@ struct DeviceState {
DeviceType *type;
BusState *parent_bus;
DeviceProperty *props;
- int num_irq_sink;
- qemu_irq *irq_sink;
int num_gpio_out;
qemu_irq *gpio_out;
int num_gpio_in;
@@ -55,7 +53,6 @@ void qdev_set_prop_int(DeviceState *dev, const char *name, uint64_t value);
void qdev_set_prop_ptr(DeviceState *dev, const char *name, void *value);
void qdev_set_netdev(DeviceState *dev, NICInfo *nd);
-qemu_irq qdev_get_irq_sink(DeviceState *dev, int n);
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
@@ -77,7 +74,7 @@ struct DeviceInfo {
void qdev_register(const char *name, int size, DeviceInfo *info);
/* Register device properties. */
-void qdev_init_irq_sink(DeviceState *dev, qemu_irq_handler handler, int nirq);
+/* GPIO inputs also double as IRQ sinks. */
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
diff --git a/hw/realview.c b/hw/realview.c
index 535f90762..62d8bf503 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -84,7 +84,7 @@ static void realview_init(ram_addr_t ram_size,
cpu_irq[3], NULL);
}
for (n = 0; n < 64; n++) {
- pic[n] = qdev_get_irq_sink(dev, n);
+ pic[n] = qdev_get_gpio_in(dev, n);
}
sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]);
diff --git a/hw/sun4m.c b/hw/sun4m.c
index af9f8719a..4ba9e89ed 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -379,7 +379,7 @@ static void lance_init(NICInfo *nd, target_phys_addr_t leaddr,
s = sysbus_from_qdev(dev);
sysbus_mmio_map(s, 0, leaddr);
sysbus_connect_irq(s, 0, irq);
- *reset = qdev_get_irq_sink(dev, 0);
+ *reset = qdev_get_gpio_in(dev, 0);
}
static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
diff --git a/hw/syborg.c b/hw/syborg.c
index ae0ca6702..5ca9977b2 100644
--- a/hw/syborg.c
+++ b/hw/syborg.c
@@ -58,7 +58,7 @@ static void syborg_init(ram_addr_t ram_size,
dev = sysbus_create_simple("syborg,interrupt", 0xC0000000,
cpu_pic[ARM_PIC_CPU_IRQ]);
for (i = 0; i < 64; i++) {
- pic[i] = qdev_get_irq_sink(dev, i);
+ pic[i] = qdev_get_gpio_in(dev, i);
}
sysbus_create_simple("syborg,rtc", 0xC0001000, NULL);
diff --git a/hw/syborg_interrupt.c b/hw/syborg_interrupt.c
index e3fbbf7bf..29e0d1a74 100644
--- a/hw/syborg_interrupt.c
+++ b/hw/syborg_interrupt.c
@@ -209,7 +209,7 @@ static void syborg_int_init(SysBusDevice *dev)
sysbus_init_irq(dev, &s->parent_irq);
s->num_irqs = qdev_get_prop_int(&dev->qdev, "num-interrupts", 64);
- qdev_init_irq_sink(&dev->qdev, syborg_int_set_irq, s->num_irqs);
+ qdev_init_gpio_in(&dev->qdev, syborg_int_set_irq, s->num_irqs);
iomemtype = cpu_register_io_memory(0, syborg_int_readfn,
syborg_int_writefn, s);
sysbus_init_mmio(dev, 0x1000, iomemtype);
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index eed97d6db..03cf4d8f3 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -135,7 +135,7 @@ static void vpb_sic_init(SysBusDevice *dev)
int iomemtype;
int i;
- qdev_init_irq_sink(&dev->qdev, vpb_sic_set_irq, 32);
+ qdev_init_gpio_in(&dev->qdev, vpb_sic_set_irq, 32);
for (i = 0; i < 32; i++) {
sysbus_init_irq(dev, &s->parent[i]);
}
@@ -188,12 +188,12 @@ static void versatile_init(ram_addr_t ram_size,
dev = sysbus_create_varargs("pl190", 0x10140000,
cpu_pic[0], cpu_pic[1], NULL);
for (n = 0; n < 32; n++) {
- pic[n] = qdev_get_irq_sink(dev, n);
+ pic[n] = qdev_get_gpio_in(dev, n);
}
dev = sysbus_create_simple("versatilepb_sic", 0x10003000, NULL);
for (n = 0; n < 32; n++) {
sysbus_connect_irq(sysbus_from_qdev(dev), n, pic[n]);
- sic[n] = qdev_get_irq_sink(dev, n);
+ sic[n] = qdev_get_gpio_in(dev, n);
}
sysbus_create_simple("pl050_keyboard", 0x10006000, sic[3]);
diff --git a/hw/xilinx.h b/hw/xilinx.h
new file mode 100644
index 000000000..9707a0e0b
--- /dev/null
+++ b/hw/xilinx.h
@@ -0,0 +1,50 @@
+
+/* OPB Interrupt Controller. */
+qemu_irq *microblaze_pic_init_cpu(CPUState *env);
+
+static inline DeviceState *
+xilinx_intc_create(target_phys_addr_t base, qemu_irq irq, int kind_of_intr)
+{
+ DeviceState *dev;
+
+ dev = qdev_create(NULL, "xilinx,intc");
+ qdev_set_prop_int(dev, "kind-of-intr", kind_of_intr);
+ qdev_init(dev);
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+ return dev;
+}
+
+/* OPB Timer/Counter. */
+static inline DeviceState *
+xilinx_timer_create(target_phys_addr_t base, qemu_irq irq, int nr, int freq)
+{
+ DeviceState *dev;
+
+ dev = qdev_create(NULL, "xilinx,timer");
+ qdev_set_prop_int(dev, "nr-timers", nr);
+ qdev_set_prop_int(dev, "frequency", freq);
+ qdev_init(dev);
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+ return dev;
+}
+
+/* XPS Ethernet Lite MAC. */
+static inline DeviceState *
+xilinx_ethlite_create(NICInfo *nd, target_phys_addr_t base, qemu_irq irq,
+ int txpingpong, int rxpingpong)
+{
+ DeviceState *dev;
+
+ qemu_check_nic_model(nd, "xilinx-ethlite");
+
+ dev = qdev_create(NULL, "xilinx,ethlite");
+ qdev_set_netdev(dev, nd);
+ qdev_set_prop_int(dev, "txpingpong", txpingpong);
+ qdev_set_prop_int(dev, "rxpingpong", rxpingpong);
+ qdev_init(dev);
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+ return dev;
+}
diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c
new file mode 100644
index 000000000..780e9c05a
--- /dev/null
+++ b/hw/xilinx_ethlite.c
@@ -0,0 +1,235 @@
+/*
+ * QEMU model of the Xilinx Ethernet Lite MAC.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * 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 "sysbus.h"
+#include "hw.h"
+#include "net.h"
+
+#define D(x)
+#define R_TX_BUF0 0
+#define R_TX_LEN0 (0x07f4 / 4)
+#define R_TX_GIE0 (0x07f8 / 4)
+#define R_TX_CTRL0 (0x07fc / 4)
+#define R_TX_BUF1 (0x0800 / 4)
+#define R_TX_LEN1 (0x0ff4 / 4)
+#define R_TX_CTRL1 (0x0ffc / 4)
+
+#define R_RX_BUF0 (0x1000 / 4)
+#define R_RX_CTRL0 (0x17fc / 4)
+#define R_RX_BUF1 (0x1800 / 4)
+#define R_RX_CTRL1 (0x1ffc / 4)
+#define R_MAX (0x2000 / 4)
+
+#define GIE_GIE 0x80000000
+
+#define CTRL_I 0x8
+#define CTRL_P 0x2
+#define CTRL_S 0x1
+
+struct xlx_ethlite
+{
+ SysBusDevice busdev;
+ qemu_irq irq;
+ VLANClientState *vc;
+
+ unsigned int c_tx_pingpong;
+ unsigned int c_rx_pingpong;
+ unsigned int txbuf;
+ unsigned int rxbuf;
+
+ uint8_t macaddr[6];
+ uint32_t regs[R_MAX];
+};
+
+static inline void eth_pulse_irq(struct xlx_ethlite *s)
+{
+ /* Only the first gie reg is active. */
+ if (s->regs[R_TX_GIE0] & GIE_GIE) {
+ qemu_irq_pulse(s->irq);
+ }
+}
+
+static uint32_t eth_readl (void *opaque, target_phys_addr_t addr)
+{
+ struct xlx_ethlite *s = opaque;
+ uint32_t r = 0;
+
+ addr >>= 2;
+
+ switch (addr)
+ {
+ case R_TX_GIE0:
+ case R_TX_LEN0:
+ case R_TX_LEN1:
+ case R_TX_CTRL1:
+ case R_TX_CTRL0:
+ case R_RX_CTRL1:
+ case R_RX_CTRL0:
+ r = s->regs[addr];
+ D(qemu_log("%s %x=%x\n", __func__, addr * 4, r));
+ break;
+
+ /* Rx packet data is endian fixed at the way into the rx rams. This
+ * speeds things up because the ethlite MAC does not have a len
+ * register. That means the CPU will issue MMIO reads for the entire
+ * 2k rx buffer even for small packets.
+ */
+ default:
+ r = s->regs[addr];
+ break;
+ }
+ return r;
+}
+
+static void
+eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ struct xlx_ethlite *s = opaque;
+ unsigned int base = 0;
+
+ addr >>= 2;
+ switch (addr)
+ {
+ case R_TX_CTRL0:
+ case R_TX_CTRL1:
+ if (addr == R_TX_CTRL1)
+ base = 0x800 / 4;
+
+ D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
+ if ((value & (CTRL_P | CTRL_S)) == CTRL_S) {
+ qemu_send_packet(s->vc,
+ (void *) &s->regs[base],
+ s->regs[base + R_TX_LEN0]);
+ D(qemu_log("eth_tx %d\n", s->regs[base + R_TX_LEN0]));
+ if (s->regs[base + R_TX_CTRL0] & CTRL_I)
+ eth_pulse_irq(s);
+ } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) {
+ memcpy(&s->macaddr[0], &s->regs[base], 6);
+ if (s->regs[base + R_TX_CTRL0] & CTRL_I)
+ eth_pulse_irq(s);
+ }
+
+ /* We are fast and get ready pretty much immediately so
+ we actually never flip the S nor P bits to one. */
+ s->regs[addr] = value & ~(CTRL_P | CTRL_S);
+ break;
+
+ /* Keep these native. */
+ case R_TX_LEN0:
+ case R_TX_LEN1:
+ case R_TX_GIE0:
+ case R_RX_CTRL0:
+ case R_RX_CTRL1:
+ D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
+ s->regs[addr] = value;
+ break;
+
+ /* Packet data, make sure it stays BE. */
+ default:
+ s->regs[addr] = cpu_to_be32(value);
+ break;
+ }
+}
+
+static CPUReadMemoryFunc *eth_read[] = {
+ NULL, NULL, &eth_readl,
+};
+
+static CPUWriteMemoryFunc *eth_write[] = {
+ NULL, NULL, &eth_writel,
+};
+
+static int eth_can_rx(void *opaque)
+{
+ struct xlx_ethlite *s = opaque;
+ int r;
+ r = !(s->regs[R_RX_CTRL0] & CTRL_S);
+ qemu_log("%s %d\n", __func__, r);
+ return r;
+}
+
+static void eth_rx(void *opaque, const uint8_t *buf, int size)
+{
+ struct xlx_ethlite *s = opaque;
+ unsigned int rxbase = s->rxbuf * (0x800 / 4);
+ int i;
+
+ /* DA filter. */
+ if (!(buf[0] & 0x80) && memcmp(&s->macaddr[0], buf, 6))
+ return;
+
+ if (s->regs[rxbase + R_RX_CTRL0] & CTRL_S) {
+ D(qemu_log("ethlite lost packet %x\n", s->regs[R_RX_CTRL0]));
+ return;
+ }
+
+ D(qemu_log("%s %d rxbase=%x\n", __func__, size, rxbase));
+ memcpy(&s->regs[rxbase + R_RX_BUF0], buf, size);
+
+ /* Bring it into host endianess. */
+ for (i = 0; i < ((size + 3) / 4); i++) {
+ uint32_t d = s->regs[rxbase + R_RX_BUF0 + i];
+ s->regs[rxbase + R_RX_BUF0 + i] = be32_to_cpu(d);
+ }
+
+ s->regs[rxbase + R_RX_CTRL0] |= CTRL_S;
+ if (s->regs[rxbase + R_RX_CTRL0] & CTRL_I)
+ eth_pulse_irq(s);
+
+ /* If c_rx_pingpong was set flip buffers. */
+ s->rxbuf ^= s->c_rx_pingpong;
+ return;
+}
+
+static void eth_cleanup(VLANClientState *vc)
+{
+ struct xlx_ethlite *s = vc->opaque;
+ qemu_free(s);
+}
+
+static void xilinx_ethlite_init(SysBusDevice *dev)
+{
+ struct xlx_ethlite *s = FROM_SYSBUS(typeof (*s), dev);
+ int regs;
+
+ sysbus_init_irq(dev, &s->irq);
+ s->c_tx_pingpong = qdev_get_prop_int(&dev->qdev, "txpingpong", 1);
+ s->c_rx_pingpong = qdev_get_prop_int(&dev->qdev, "rxpingpong", 1);
+ s->rxbuf = 0;
+
+ regs = cpu_register_io_memory(0, eth_read, eth_write, s);
+ sysbus_init_mmio(dev, R_MAX * 4, regs);
+
+ qdev_get_macaddr(&dev->qdev, s->macaddr);
+ s->vc = qdev_get_vlan_client(&dev->qdev,
+ eth_rx, eth_can_rx, eth_cleanup, s);
+}
+
+static void xilinx_ethlite_register(void)
+{
+ sysbus_register_dev("xilinx,ethlite", sizeof (struct xlx_ethlite),
+ xilinx_ethlite_init);
+}
+
+device_init(xilinx_ethlite_register)
diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c
new file mode 100644
index 000000000..0b17fae28
--- /dev/null
+++ b/hw/xilinx_intc.c
@@ -0,0 +1,167 @@
+/*
+ * QEMU Xilinx OPB Interrupt Controller.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * 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 "sysbus.h"
+#include "hw.h"
+
+#define D(x)
+
+#define R_ISR 0
+#define R_IPR 1
+#define R_IER 2
+#define R_IAR 3
+#define R_SIE 4
+#define R_CIE 5
+#define R_IVR 6
+#define R_MER 7
+#define R_MAX 8
+
+struct xlx_pic
+{
+ SysBusDevice busdev;
+ qemu_irq parent_irq;
+
+ /* Configuration reg chosen at synthesis-time. QEMU populates
+ the bits at board-setup. */
+ uint32_t c_kind_of_intr;
+
+ /* Runtime control registers. */
+ uint32_t regs[R_MAX];
+};
+
+static void update_irq(struct xlx_pic *p)
+{
+ uint32_t i;
+ /* Update the pending register. */
+ p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER];
+
+ /* Update the vector register. */
+ for (i = 0; i < 32; i++) {
+ if (p->regs[R_IPR] & (1 << i))
+ break;
+ }
+ if (i == 32)
+ i = ~0;
+
+ p->regs[R_IVR] = i;
+ if ((p->regs[R_MER] & 1) && p->regs[R_IPR]) {
+ qemu_irq_raise(p->parent_irq);
+ } else {
+ qemu_irq_lower(p->parent_irq);
+ }
+}
+
+static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
+{
+ struct xlx_pic *p = opaque;
+ uint32_t r = 0;
+
+ addr >>= 2;
+ switch (addr)
+ {
+ default:
+ if (addr < ARRAY_SIZE(p->regs))
+ r = p->regs[addr];
+ break;
+
+ }
+ D(printf("%s %x=%x\n", __func__, addr * 4, r));
+ return r;
+}
+
+static void
+pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ struct xlx_pic *p = opaque;
+
+ addr >>= 2;
+ D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
+ switch (addr)
+ {
+ case R_IAR:
+ p->regs[R_ISR] &= ~value; /* ACK. */
+ break;
+ case R_SIE:
+ p->regs[R_IER] |= value; /* Atomic set ie. */
+ break;
+ case R_CIE:
+ p->regs[R_IER] &= ~value; /* Atomic clear ie. */
+ break;
+ default:
+ if (addr < ARRAY_SIZE(p->regs))
+ p->regs[addr] = value;
+ break;
+ }
+ update_irq(p);
+}
+
+static CPUReadMemoryFunc *pic_read[] = {
+ NULL, NULL,
+ &pic_readl,
+};
+
+static CPUWriteMemoryFunc *pic_write[] = {
+ NULL, NULL,
+ &pic_writel,
+};
+
+static void irq_handler(void *opaque, int irq, int level)
+{
+ struct xlx_pic *p = opaque;
+
+ if (!(p->regs[R_MER] & 2)) {
+ qemu_irq_lower(p->parent_irq);
+ return;
+ }
+
+ /* Update source flops. Don't clear unless level triggered.
+ Edge triggered interrupts only go away when explicitely acked to
+ the interrupt controller. */
+ if (!(p->c_kind_of_intr & (1 << irq)) || level) {
+ p->regs[R_ISR] &= ~(1 << irq);
+ p->regs[R_ISR] |= (level << irq);
+ }
+ update_irq(p);
+}
+
+static void xilinx_intc_init(SysBusDevice *dev)
+{
+ struct xlx_pic *p = FROM_SYSBUS(typeof (*p), dev);
+ int pic_regs;
+
+ p->c_kind_of_intr = qdev_get_prop_int(&dev->qdev, "kind-of-intr", 0);
+ qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
+ sysbus_init_irq(dev, &p->parent_irq);
+
+ pic_regs = cpu_register_io_memory(0, pic_read, pic_write, p);
+ sysbus_init_mmio(dev, R_MAX * 4, pic_regs);
+}
+
+static void xilinx_intc_register(void)
+{
+ sysbus_register_dev("xilinx,intc", sizeof (struct xlx_pic),
+ xilinx_intc_init);
+}
+
+device_init(xilinx_intc_register)
diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c
new file mode 100644
index 000000000..d0e8f1862
--- /dev/null
+++ b/hw/xilinx_timer.c
@@ -0,0 +1,224 @@
+/*
+ * QEMU model of the Xilinx timer block.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * 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 "sysbus.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+
+#define D(x)
+
+#define R_TCSR 0
+#define R_TLR 1
+#define R_TCR 2
+#define R_MAX 4
+
+#define TCSR_MDT (1<<0)
+#define TCSR_UDT (1<<1)
+#define TCSR_GENT (1<<2)
+#define TCSR_CAPT (1<<3)
+#define TCSR_ARHT (1<<4)
+#define TCSR_LOAD (1<<5)
+#define TCSR_ENIT (1<<6)
+#define TCSR_ENT (1<<7)
+#define TCSR_TINT (1<<8)
+#define TCSR_PWMA (1<<9)
+#define TCSR_ENALL (1<<10)
+
+struct xlx_timer
+{
+ QEMUBH *bh;
+ ptimer_state *ptimer;
+ void *parent;
+ int nr; /* for debug. */
+
+ unsigned long timer_div;
+
+ uint32_t regs[R_MAX];
+};
+
+struct timerblock
+{
+ SysBusDevice busdev;
+ qemu_irq irq;
+ unsigned int nr_timers;
+ struct xlx_timer *timers;
+};
+
+static inline unsigned int timer_from_addr(target_phys_addr_t addr)
+{
+ /* Timers get a 4x32bit control reg area each. */
+ return addr >> 2;
+}
+
+static void timer_update_irq(struct timerblock *t)
+{
+ unsigned int i, irq = 0;
+ uint32_t csr;
+
+ for (i = 0; i < t->nr_timers; i++) {
+ csr = t->timers[i].regs[R_TCSR];
+ irq |= (csr & TCSR_TINT) && (csr & TCSR_ENIT);
+ }
+
+ /* All timers within the same slave share a single IRQ line. */
+ qemu_set_irq(t->irq, !!irq);
+}
+
+static uint32_t timer_readl (void *opaque, target_phys_addr_t addr)
+{
+ struct timerblock *t = opaque;
+ struct xlx_timer *xt;
+ uint32_t r = 0;
+ unsigned int timer;
+
+ addr >>= 2;
+ timer = timer_from_addr(addr);
+ xt = &t->timers[timer];
+ /* Further decoding to address a specific timers reg. */
+ addr &= 0x3;
+ switch (addr)
+ {
+ case R_TCR:
+ r = ptimer_get_count(xt->ptimer);
+ if (!(xt->regs[R_TCSR] & TCSR_UDT))
+ r = ~r;
+ D(qemu_log("xlx_timer t=%d read counter=%x udt=%d\n",
+ timer, r, xt->regs[R_TCSR] & TCSR_UDT));
+ break;
+ default:
+ if (addr < ARRAY_SIZE(xt->regs))
+ r = xt->regs[addr];
+ break;
+
+ }
+ D(printf("%s timer=%d %x=%x\n", __func__, timer, addr * 4, r));
+ return r;
+}
+
+static void timer_enable(struct xlx_timer *xt)
+{
+ uint64_t count;
+
+ D(printf("%s timer=%d down=%d\n", __func__,
+ xt->nr, xt->regs[R_TCSR] & TCSR_UDT));
+
+ ptimer_stop(xt->ptimer);
+
+ if (xt->regs[R_TCSR] & TCSR_UDT)
+ count = xt->regs[R_TLR];
+ else
+ count = ~0 - xt->regs[R_TLR];
+ ptimer_set_count(xt->ptimer, count);
+ ptimer_run(xt->ptimer, 1);
+}
+
+static void
+timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ struct timerblock *t = opaque;
+ struct xlx_timer *xt;
+ unsigned int timer;
+
+ addr >>= 2;
+ timer = timer_from_addr(addr);
+ xt = &t->timers[timer];
+ D(printf("%s addr=%x val=%x (timer=%d off=%d)\n",
+ __func__, addr * 4, value, timer, addr & 3));
+ /* Further decoding to address a specific timers reg. */
+ addr &= 3;
+ switch (addr)
+ {
+ case R_TCSR:
+ if (value & TCSR_TINT)
+ value &= ~TCSR_TINT;
+
+ xt->regs[addr] = value;
+ if (value & TCSR_ENT)
+ timer_enable(xt);
+ break;
+
+ default:
+ if (addr < ARRAY_SIZE(xt->regs))
+ xt->regs[addr] = value;
+ break;
+ }
+ timer_update_irq(t);
+}
+
+static CPUReadMemoryFunc *timer_read[] = {
+ NULL, NULL,
+ &timer_readl,
+};
+
+static CPUWriteMemoryFunc *timer_write[] = {
+ NULL, NULL,
+ &timer_writel,
+};
+
+static void timer_hit(void *opaque)
+{
+ struct xlx_timer *xt = opaque;
+ struct timerblock *t = xt->parent;
+ D(printf("%s %d\n", __func__, timer));
+ xt->regs[R_TCSR] |= TCSR_TINT;
+
+ if (xt->regs[R_TCSR] & TCSR_ARHT)
+ timer_enable(xt);
+ timer_update_irq(t);
+}
+
+static void xilinx_timer_init(SysBusDevice *dev)
+{
+ struct timerblock *t = FROM_SYSBUS(typeof (*t), dev);
+ unsigned int i;
+ int timer_regs, freq_hz;
+
+ /* All timers share a single irq line. */
+ sysbus_init_irq(dev, &t->irq);
+
+ /* Init all the ptimers. */
+ freq_hz = qdev_get_prop_int(&dev->qdev, "frequency", 2);
+ t->nr_timers = qdev_get_prop_int(&dev->qdev, "nr-timers", 2);
+ t->timers = qemu_mallocz(sizeof t->timers[0] * t->nr_timers);
+ for (i = 0; i < t->nr_timers; i++) {
+ struct xlx_timer *xt = &t->timers[i];
+
+ xt->parent = t;
+ xt->nr = i;
+ xt->bh = qemu_bh_new(timer_hit, xt);
+ xt->ptimer = ptimer_init(xt->bh);
+ ptimer_set_freq(xt->ptimer, freq_hz);
+ }
+
+ timer_regs = cpu_register_io_memory(0, timer_read, timer_write, t);
+ sysbus_init_mmio(dev, R_MAX * 4 * t->nr_timers, timer_regs);
+}
+
+static void xilinx_timer_register(void)
+{
+ sysbus_register_dev("xilinx,timer", sizeof (struct timerblock),
+ xilinx_timer_init);
+}
+
+device_init(xilinx_timer_register)
diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c
new file mode 100644
index 000000000..5cfb36c48
--- /dev/null
+++ b/hw/xilinx_uartlite.c
@@ -0,0 +1,218 @@
+/*
+ * QEMU model of Xilinx uartlite.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * 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 "sysbus.h"
+#include "qemu-char.h"
+
+#define DUART(x)
+
+#define R_RX 0
+#define R_TX 1
+#define R_STATUS 2
+#define R_CTRL 3
+#define R_MAX 4
+
+#define STATUS_RXVALID 0x01
+#define STATUS_RXFULL 0x02
+#define STATUS_TXEMPTY 0x04
+#define STATUS_TXFULL 0x08
+#define STATUS_IE 0x10
+#define STATUS_OVERRUN 0x20
+#define STATUS_FRAME 0x40
+#define STATUS_PARITY 0x80
+
+#define CONTROL_RST_TX 0x01
+#define CONTROL_RST_RX 0x02
+#define CONTROL_IE 0x10
+
+struct xlx_uartlite
+{
+ SysBusDevice busdev;
+ CharDriverState *chr;
+ qemu_irq irq;
+
+ uint8_t rx_fifo[8];
+ unsigned int rx_fifo_pos;
+ unsigned int rx_fifo_len;
+
+ uint32_t regs[R_MAX];
+};
+
+static void uart_update_irq(struct xlx_uartlite *s)
+{
+ unsigned int irq;
+
+ if (s->rx_fifo_len)
+ s->regs[R_STATUS] |= STATUS_IE;
+
+ irq = (s->regs[R_STATUS] & STATUS_IE) && (s->regs[R_CTRL] & CONTROL_IE);
+ qemu_set_irq(s->irq, irq);
+}
+
+static void uart_update_status(struct xlx_uartlite *s)
+{
+ uint32_t r;
+
+ r = s->regs[R_STATUS];
+ r &= ~7;
+ r |= 1 << 2; /* Tx fifo is always empty. We are fast :) */
+ r |= (s->rx_fifo_len == sizeof (s->rx_fifo)) << 1;
+ r |= (!!s->rx_fifo_len);
+ s->regs[R_STATUS] = r;
+}
+
+static uint32_t uart_readl (void *opaque, target_phys_addr_t addr)
+{
+ struct xlx_uartlite *s = opaque;
+ uint32_t r = 0;
+ addr >>= 2;
+ switch (addr)
+ {
+ case R_RX:
+ r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 7];
+ if (s->rx_fifo_len)
+ s->rx_fifo_len--;
+ uart_update_status(s);
+ uart_update_irq(s);
+ break;
+
+ default:
+ if (addr < ARRAY_SIZE(s->regs))
+ r = s->regs[addr];
+ DUART(qemu_log("%s addr=%x v=%x\n", __func__, addr, r));
+ break;
+ }
+ return r;
+}
+
+static void
+uart_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ struct xlx_uartlite *s = opaque;
+ unsigned char ch = value;
+
+ addr >>= 2;
+ switch (addr)
+ {
+ case R_STATUS:
+ hw_error("write to UART STATUS?\n");
+ break;
+
+ case R_CTRL:
+ if (value & CONTROL_RST_RX) {
+ s->rx_fifo_pos = 0;
+ s->rx_fifo_len = 0;
+ }
+ s->regs[addr] = value;
+ break;
+
+ case R_TX:
+ if (s->chr)
+ qemu_chr_write(s->chr, &ch, 1);
+
+ s->regs[addr] = value;
+
+ /* hax. */
+ s->regs[R_STATUS] |= STATUS_IE;
+ break;
+
+ default:
+ DUART(printf("%s addr=%x v=%x\n", __func__, addr, value));
+ if (addr < ARRAY_SIZE(s->regs))
+ s->regs[addr] = value;
+ break;
+ }
+ uart_update_status(s);
+ uart_update_irq(s);
+}
+
+static CPUReadMemoryFunc *uart_read[] = {
+ &uart_readl,
+ &uart_readl,
+ &uart_readl,
+};
+
+static CPUWriteMemoryFunc *uart_write[] = {
+ &uart_writel,
+ &uart_writel,
+ &uart_writel,
+};
+
+static void uart_rx(void *opaque, const uint8_t *buf, int size)
+{
+ struct xlx_uartlite *s = opaque;
+
+ /* Got a byte. */
+ if (s->rx_fifo_len >= 8) {
+ printf("WARNING: UART dropped char.\n");
+ return;
+ }
+ s->rx_fifo[s->rx_fifo_pos] = *buf;
+ s->rx_fifo_pos++;
+ s->rx_fifo_pos &= 0x7;
+ s->rx_fifo_len++;
+
+ uart_update_status(s);
+ uart_update_irq(s);
+}
+
+static int uart_can_rx(void *opaque)
+{
+ struct xlx_uartlite *s = opaque;
+ int r;
+
+ r = s->rx_fifo_len < sizeof(s->rx_fifo);
+ if (!r)
+ printf("cannot receive!\n");
+ return r;
+}
+
+static void uart_event(void *opaque, int event)
+{
+
+}
+
+static void xilinx_uartlite_init(SysBusDevice *dev)
+{
+ struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev);
+ int uart_regs;
+
+ sysbus_init_irq(dev, &s->irq);
+
+ uart_update_status(s);
+ uart_regs = cpu_register_io_memory(0, uart_read, uart_write, s);
+ sysbus_init_mmio(dev, R_MAX * 4, uart_regs);
+
+ s->chr = qdev_init_chardev(&dev->qdev);
+ if (s->chr)
+ qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+}
+
+static void xilinx_uart_register(void)
+{
+ sysbus_register_dev("xilinx,uartlite", sizeof (struct xlx_uartlite),
+ xilinx_uartlite_init);
+}
+
+device_init(xilinx_uart_register)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 508cb379b..190ad143e 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -453,6 +453,28 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
#endif /* TARGET_MIPS */
+#ifdef TARGET_MICROBLAZE
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_XILINX_MICROBLAZE )
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2MSB
+#define ELF_ARCH EM_MIPS
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+ regs->pc = infop->entry;
+ regs->r1 = infop->start_stack;
+
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE 4096
+
+#endif /* TARGET_MICROBLAZE */
+
#ifdef TARGET_SH4
#define ELF_START_MMAP 0x80000000
diff --git a/linux-user/main.c b/linux-user/main.c
index 17cdfa6d9..4832d3f86 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2036,6 +2036,66 @@ void cpu_loop (CPUState *env)
}
#endif
+#ifdef TARGET_MICROBLAZE
+void cpu_loop (CPUState *env)
+{
+ int trapnr, ret;
+ target_siginfo_t info;
+
+ while (1) {
+ trapnr = cpu_mb_exec (env);
+ switch (trapnr) {
+ case 0xaa:
+ {
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ /* XXX: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, &info);
+ }
+ break;
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case EXCP_BREAK:
+ /* Return address is 4 bytes after the call. */
+ env->regs[14] += 4;
+ ret = do_syscall(env,
+ env->regs[12],
+ env->regs[5],
+ env->regs[6],
+ env->regs[7],
+ env->regs[8],
+ env->regs[9],
+ env->regs[10]);
+ env->regs[3] = ret;
+ env->sregs[SR_PC] = env->regs[14];
+ break;
+ case EXCP_DEBUG:
+ {
+ int sig;
+
+ sig = gdb_handlesig (env, TARGET_SIGTRAP);
+ if (sig)
+ {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, &info);
+ }
+ }
+ break;
+ default:
+ printf ("Unhandled trap: 0x%x\n", trapnr);
+ cpu_dump_state(env, stderr, fprintf, 0);
+ exit (1);
+ }
+ process_pending_signals (env);
+ }
+}
+#endif
+
#ifdef TARGET_M68K
void cpu_loop(CPUM68KState *env)
@@ -2698,6 +2758,42 @@ int main(int argc, char **argv, char **envp)
env->sr = regs->sr;
ts->sim_syscalls = 1;
}
+#elif defined(TARGET_MICROBLAZE)
+ {
+ env->regs[0] = regs->r0;
+ env->regs[1] = regs->r1;
+ env->regs[2] = regs->r2;
+ env->regs[3] = regs->r3;
+ env->regs[4] = regs->r4;
+ env->regs[5] = regs->r5;
+ env->regs[6] = regs->r6;
+ env->regs[7] = regs->r7;
+ env->regs[8] = regs->r8;
+ env->regs[9] = regs->r9;
+ env->regs[10] = regs->r10;
+ env->regs[11] = regs->r11;
+ env->regs[12] = regs->r12;
+ env->regs[13] = regs->r13;
+ env->regs[14] = regs->r14;
+ env->regs[15] = regs->r15;
+ env->regs[16] = regs->r16;
+ env->regs[17] = regs->r17;
+ env->regs[18] = regs->r18;
+ env->regs[19] = regs->r19;
+ env->regs[20] = regs->r20;
+ env->regs[21] = regs->r21;
+ env->regs[22] = regs->r22;
+ env->regs[23] = regs->r23;
+ env->regs[24] = regs->r24;
+ env->regs[25] = regs->r25;
+ env->regs[26] = regs->r26;
+ env->regs[27] = regs->r27;
+ env->regs[28] = regs->r28;
+ env->regs[29] = regs->r29;
+ env->regs[30] = regs->r30;
+ env->regs[31] = regs->r31;
+ env->sregs[SR_PC] = regs->pc;
+ }
#elif defined(TARGET_MIPS)
{
int i;
diff --git a/linux-user/microblaze/syscall.h b/linux-user/microblaze/syscall.h
new file mode 100644
index 000000000..db1f98ae6
--- /dev/null
+++ b/linux-user/microblaze/syscall.h
@@ -0,0 +1,45 @@
+#define UNAME_MACHINE "microblaze"
+
+/* We use microblaze_reg_t to keep things similar to the kernel sources. */
+typedef uint32_t microblaze_reg_t;
+
+struct target_pt_regs {
+ microblaze_reg_t r0;
+ microblaze_reg_t r1;
+ microblaze_reg_t r2;
+ microblaze_reg_t r3;
+ microblaze_reg_t r4;
+ microblaze_reg_t r5;
+ microblaze_reg_t r6;
+ microblaze_reg_t r7;
+ microblaze_reg_t r8;
+ microblaze_reg_t r9;
+ microblaze_reg_t r10;
+ microblaze_reg_t r11;
+ microblaze_reg_t r12;
+ microblaze_reg_t r13;
+ microblaze_reg_t r14;
+ microblaze_reg_t r15;
+ microblaze_reg_t r16;
+ microblaze_reg_t r17;
+ microblaze_reg_t r18;
+ microblaze_reg_t r19;
+ microblaze_reg_t r20;
+ microblaze_reg_t r21;
+ microblaze_reg_t r22;
+ microblaze_reg_t r23;
+ microblaze_reg_t r24;
+ microblaze_reg_t r25;
+ microblaze_reg_t r26;
+ microblaze_reg_t r27;
+ microblaze_reg_t r28;
+ microblaze_reg_t r29;
+ microblaze_reg_t r30;
+ microblaze_reg_t r31;
+ microblaze_reg_t pc;
+ microblaze_reg_t msr;
+ microblaze_reg_t ear;
+ microblaze_reg_t esr;
+ microblaze_reg_t fsr;
+ uint32_t kernel_mode;
+};
diff --git a/linux-user/microblaze/syscall_nr.h b/linux-user/microblaze/syscall_nr.h
new file mode 100644
index 000000000..3e641cdb4
--- /dev/null
+++ b/linux-user/microblaze/syscall_nr.h
@@ -0,0 +1,369 @@
+#define TARGET_NR_restart_syscall 0 /* ok */
+#define TARGET_NR_exit 1 /* ok */
+#define TARGET_NR_fork 2 /* not for no MMU - weird */
+#define TARGET_NR_read 3 /* ok */
+#define TARGET_NR_write 4 /* ok */
+#define TARGET_NR_open 5 /* openat */
+#define TARGET_NR_close 6 /* ok */
+#define TARGET_NR_waitpid 7 /* waitid */
+#define TARGET_NR_creat 8 /* openat */
+#define TARGET_NR_link 9 /* linkat */
+#define TARGET_NR_unlink 10 /* unlinkat */
+#define TARGET_NR_execve 11 /* ok */
+#define TARGET_NR_chdir 12 /* ok */
+#define TARGET_NR_time 13 /* obsolete -> sys_gettimeofday */
+#define TARGET_NR_mknod 14 /* mknodat */
+#define TARGET_NR_chmod 15 /* fchmodat */
+#define TARGET_NR_lchown 16 /* ok */
+#define TARGET_NR_break 17 /* don't know */
+#define TARGET_NR_oldstat 18 /* remove */
+#define TARGET_NR_lseek 19 /* ok */
+#define TARGET_NR_getpid 20 /* ok */
+#define TARGET_NR_mount 21 /* ok */
+#define TARGET_NR_umount 22 /* ok */ /* use only umount2 */
+#define TARGET_NR_setuid 23 /* ok */
+#define TARGET_NR_getuid 24 /* ok */
+#define TARGET_NR_stime 25 /* obsolete -> sys_settimeofday */
+#define TARGET_NR_ptrace 26 /* ok */
+#define TARGET_NR_alarm 27 /* obsolete -> sys_setitimer */
+#define TARGET_NR_oldfstat 28 /* remove */
+#define TARGET_NR_pause 29 /* obsolete -> sys_rt_sigtimedwait */
+#define TARGET_NR_utime 30 /* obsolete -> sys_utimesat */
+#define TARGET_NR_stty 31 /* remove */
+#define TARGET_NR_gtty 32 /* remove */
+#define TARGET_NR_access 33 /* faccessat */
+#define TARGET_NR_nice 34 /* can be implemented by sys_setpriority */
+#define TARGET_NR_ftime 35 /* remove */
+#define TARGET_NR_sync 36 /* ok */
+#define TARGET_NR_kill 37 /* ok */
+#define TARGET_NR_rename 38 /* renameat */
+#define TARGET_NR_mkdir 39 /* mkdirat */
+#define TARGET_NR_rmdir 40 /* unlinkat */
+#define TARGET_NR_dup 41 /* ok */
+#define TARGET_NR_pipe 42 /* ok */
+#define TARGET_NR_times 43 /* ok */
+#define TARGET_NR_prof 44 /* remove */
+#define TARGET_NR_brk 45 /* ok -mmu, nommu specific */
+#define TARGET_NR_setgid 46 /* ok */
+#define TARGET_NR_getgid 47 /* ok */
+#define TARGET_NR_signal 48 /* obsolete -> sys_rt_sigaction */
+#define TARGET_NR_geteuid 49 /* ok */
+#define TARGET_NR_getegid 50 /* ok */
+#define TARGET_NR_acct 51 /* add it and then I can disable it */
+#define TARGET_NR_umount2 52 /* remove */
+#define TARGET_NR_lock 53 /* remove */
+#define TARGET_NR_ioctl 54 /* ok */
+#define TARGET_NR_fcntl 55 /* ok -> 64bit version*/
+#define TARGET_NR_mpx 56 /* remove */
+#define TARGET_NR_setpgid 57 /* ok */
+#define TARGET_NR_ulimit 58 /* remove */
+#define TARGET_NR_oldolduname 59 /* remove */
+#define TARGET_NR_umask 60 /* ok */
+#define TARGET_NR_chroot 61 /* ok */
+#define TARGET_NR_ustat 62 /* obsolete -> statfs64 */
+#define TARGET_NR_dup2 63 /* ok */
+#define TARGET_NR_getppid 64 /* ok */
+#define TARGET_NR_getpgrp 65 /* obsolete -> sys_getpgid */
+#define TARGET_NR_setsid 66 /* ok */
+#define TARGET_NR_sigaction 67 /* obsolete -> rt_sigaction */
+#define TARGET_NR_sgetmask 68 /* obsolete -> sys_rt_sigprocmask */
+#define TARGET_NR_ssetmask 69 /* obsolete ->sys_rt_sigprocmask */
+#define TARGET_NR_setreuid 70 /* ok */
+#define TARGET_NR_setregid 71 /* ok */
+#define TARGET_NR_sigsuspend 72 /* obsolete -> rt_sigsuspend */
+#define TARGET_NR_sigpending 73 /* obsolete -> sys_rt_sigpending */
+#define TARGET_NR_sethostname 74 /* ok */
+#define TARGET_NR_setrlimit 75 /* ok */
+#define TARGET_NR_getrlimit 76 /* ok Back compatible 2Gig limited rlimit */
+#define TARGET_NR_getrusage 77 /* ok */
+#define TARGET_NR_gettimeofday 78 /* ok */
+#define TARGET_NR_settimeofday 79 /* ok */
+#define TARGET_NR_getgroups 80 /* ok */
+#define TARGET_NR_setgroups 81 /* ok */
+#define TARGET_NR_select 82 /* obsolete -> sys_pselect7 */
+#define TARGET_NR_symlink 83 /* symlinkat */
+#define TARGET_NR_oldlstat 84 /* remove */
+#define TARGET_NR_readlink 85 /* obsolete -> sys_readlinkat */
+#define TARGET_NR_uselib 86 /* remove */
+#define TARGET_NR_swapon 87 /* ok */
+#define TARGET_NR_reboot 88 /* ok */
+#define TARGET_NR_readdir 89 /* remove ? */
+#define TARGET_NR_mmap 90 /* obsolete -> sys_mmap2 */
+#define TARGET_NR_munmap 91 /* ok - mmu and nommu */
+#define TARGET_NR_truncate 92 /* ok or truncate64 */
+#define TARGET_NR_ftruncate 93 /* ok or ftruncate64 */
+#define TARGET_NR_fchmod 94 /* ok */
+#define TARGET_NR_fchown 95 /* ok */
+#define TARGET_NR_getpriority 96 /* ok */
+#define TARGET_NR_setpriority 97 /* ok */
+#define TARGET_NR_profil 98 /* remove */
+#define TARGET_NR_statfs 99 /* ok or statfs64 */
+#define TARGET_NR_fstatfs 100 /* ok or fstatfs64 */
+#define TARGET_NR_ioperm 101 /* remove */
+#define TARGET_NR_socketcall 102 /* remove */
+#define TARGET_NR_syslog 103 /* ok */
+#define TARGET_NR_setitimer 104 /* ok */
+#define TARGET_NR_getitimer 105 /* ok */
+#define TARGET_NR_stat 106 /* remove */
+#define TARGET_NR_lstat 107 /* remove */
+#define TARGET_NR_fstat 108 /* remove */
+#define TARGET_NR_olduname 109 /* remove */
+#define TARGET_NR_iopl 110 /* remove */
+#define TARGET_NR_vhangup 111 /* ok */
+#define TARGET_NR_idle 112 /* remove */
+#define TARGET_NR_vm86old 113 /* remove */
+#define TARGET_NR_wait4 114 /* obsolete -> waitid */
+#define TARGET_NR_swapoff 115 /* ok */
+#define TARGET_NR_sysinfo 116 /* ok */
+#define TARGET_NR_ipc 117 /* remove - direct call */
+#define TARGET_NR_fsync 118 /* ok */
+#define TARGET_NR_sigreturn 119 /* obsolete -> sys_rt_sigreturn */
+#define TARGET_NR_clone 120 /* ok */
+#define TARGET_NR_setdomainname 121 /* ok */
+#define TARGET_NR_uname 122 /* remove */
+#define TARGET_NR_modify_ldt 123 /* remove */
+#define TARGET_NR_adjtimex 124 /* ok */
+#define TARGET_NR_mprotect 125 /* remove */
+#define TARGET_NR_sigprocmask 126 /* obsolete -> sys_rt_sigprocmask */
+#define TARGET_NR_create_module 127 /* remove */
+#define TARGET_NR_init_module 128 /* ok */
+#define TARGET_NR_delete_module 129 /* ok */
+#define TARGET_NR_get_kernel_syms 130 /* remove */
+#define TARGET_NR_quotactl 131 /* ok */
+#define TARGET_NR_getpgid 132 /* ok */
+#define TARGET_NR_fchdir 133 /* ok */
+#define TARGET_NR_bdflush 134 /* remove */
+#define TARGET_NR_sysfs 135 /* needed for busybox */
+#define TARGET_NR_personality 136 /* ok */
+#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
+#define TARGET_NR_setfsuid 138 /* ok */
+#define TARGET_NR_setfsgid 139 /* ok */
+#define TARGET_NR__llseek 140 /* remove only lseek */
+#define TARGET_NR_getdents 141 /* ok or getdents64 */
+#define TARGET_NR__newselect 142 /* remove */
+#define TARGET_NR_flock 143 /* ok */
+#define TARGET_NR_msync 144 /* remove */
+#define TARGET_NR_readv 145 /* ok */
+#define TARGET_NR_writev 146 /* ok */
+#define TARGET_NR_getsid 147 /* ok */
+#define TARGET_NR_fdatasync 148 /* ok */
+#define TARGET_NR__sysctl 149 /* remove */
+#define TARGET_NR_mlock 150 /* ok - nommu or mmu */
+#define TARGET_NR_munlock 151 /* ok - nommu or mmu */
+#define TARGET_NR_mlockall 152 /* ok - nommu or mmu */
+#define TARGET_NR_munlockall 153 /* ok - nommu or mmu */
+#define TARGET_NR_sched_setparam 154 /* ok */
+#define TARGET_NR_sched_getparam 155 /* ok */
+#define TARGET_NR_sched_setscheduler 156 /* ok */
+#define TARGET_NR_sched_getscheduler 157 /* ok */
+#define TARGET_NR_sched_yield 158 /* ok */
+#define TARGET_NR_sched_get_priority_max 159 /* ok */
+#define TARGET_NR_sched_get_priority_min 160 /* ok */
+#define TARGET_NR_sched_rr_get_interval 161 /* ok */
+#define TARGET_NR_nanosleep 162 /* ok */
+#define TARGET_NR_mremap 163 /* ok - nommu or mmu */
+#define TARGET_NR_setresuid 164 /* ok */
+#define TARGET_NR_getresuid 165 /* ok */
+#define TARGET_NR_vm86 166 /* remove */
+#define TARGET_NR_query_module 167 /* ok */
+#define TARGET_NR_poll 168 /* obsolete -> sys_ppoll */
+#define TARGET_NR_nfsservctl 169 /* ok */
+#define TARGET_NR_setresgid 170 /* ok */
+#define TARGET_NR_getresgid 171 /* ok */
+#define TARGET_NR_prctl 172 /* ok */
+#define TARGET_NR_rt_sigreturn 173 /* ok */
+#define TARGET_NR_rt_sigaction 174 /* ok */
+#define TARGET_NR_rt_sigprocmask 175 /* ok */
+#define TARGET_NR_rt_sigpending 176 /* ok */
+#define TARGET_NR_rt_sigtimedwait 177 /* ok */
+#define TARGET_NR_rt_sigqueueinfo 178 /* ok */
+#define TARGET_NR_rt_sigsuspend 179 /* ok */
+#define TARGET_NR_pread64 180 /* ok */
+#define TARGET_NR_pwrite64 181 /* ok */
+#define TARGET_NR_chown 182 /* obsolete -> fchownat */
+#define TARGET_NR_getcwd 183 /* ok */
+#define TARGET_NR_capget 184 /* ok */
+#define TARGET_NR_capset 185 /* ok */
+#define TARGET_NR_sigaltstack 186 /* remove */
+#define TARGET_NR_sendfile 187 /* ok -> exist 64bit version*/
+#define TARGET_NR_getpmsg 188 /* remove - some people actually want streams */
+#define TARGET_NR_putpmsg 189 /* remove - some people actually want streams */
+#define TARGET_NR_vfork 190 /* for noMMU - group with clone -> maybe remove */
+#define TARGET_NR_ugetrlimit 191 /* remove - SuS compliant getrlimit */
+#define TARGET_NR_mmap2 192 /* ok */
+#define TARGET_NR_truncate64 193 /* ok */
+#define TARGET_NR_ftruncate64 194 /* ok */
+#define TARGET_NR_stat64 195 /* remove _ARCH_WANT_STAT64 */
+#define TARGET_NR_lstat64 196 /* remove _ARCH_WANT_STAT64 */
+#define TARGET_NR_fstat64 197 /* remove _ARCH_WANT_STAT64 */
+#define TARGET_NR_lchown32 198 /* ok - without 32 */
+#define TARGET_NR_getuid32 199 /* ok - without 32 */
+#define TARGET_NR_getgid32 200 /* ok - without 32 */
+#define TARGET_NR_geteuid32 201 /* ok - without 32 */
+#define TARGET_NR_getegid32 202 /* ok - without 32 */
+#define TARGET_NR_setreuid32 203 /* ok - without 32 */
+#define TARGET_NR_setregid32 204 /* ok - without 32 */
+#define TARGET_NR_getgroups32 205 /* ok - without 32 */
+#define TARGET_NR_setgroups32 206 /* ok - without 32 */
+#define TARGET_NR_fchown32 207 /* ok - without 32 */
+#define TARGET_NR_setresuid32 208 /* ok - without 32 */
+#define TARGET_NR_getresuid32 209 /* ok - without 32 */
+#define TARGET_NR_setresgid32 210 /* ok - without 32 */
+#define TARGET_NR_getresgid32 211 /* ok - without 32 */
+#define TARGET_NR_chown32 212 /* ok - without 32 -obsolete -> fchownat */
+#define TARGET_NR_setuid32 213 /* ok - without 32 */
+#define TARGET_NR_setgid32 214 /* ok - without 32 */
+#define TARGET_NR_setfsuid32 215 /* ok - without 32 */
+#define TARGET_NR_setfsgid32 216 /* ok - without 32 */
+#define TARGET_NR_pivot_root 217 /* ok */
+#define TARGET_NR_mincore 218 /* ok */
+#define TARGET_NR_madvise 219 /* ok */
+//#define TARGET_NR_madvise1 219 /* remove delete when C lib stub is removed */
+#define TARGET_NR_getdents64 220 /* ok */
+#define TARGET_NR_fcntl64 221 /* ok */
+/* 223 is unused */
+#define TARGET_NR_gettid 224 /* ok */
+#define TARGET_NR_readahead 225 /* ok */
+#define TARGET_NR_setxattr 226 /* ok */
+#define TARGET_NR_lsetxattr 227 /* ok */
+#define TARGET_NR_fsetxattr 228 /* ok */
+#define TARGET_NR_getxattr 229 /* ok */
+#define TARGET_NR_lgetxattr 230 /* ok */
+#define TARGET_NR_fgetxattr 231 /* ok */
+#define TARGET_NR_listxattr 232 /* ok */
+#define TARGET_NR_llistxattr 233 /* ok */
+#define TARGET_NR_flistxattr 234 /* ok */
+#define TARGET_NR_removexattr 235 /* ok */
+#define TARGET_NR_lremovexattr 236 /* ok */
+#define TARGET_NR_fremovexattr 237 /* ok */
+#define TARGET_NR_tkill 238 /* ok */
+#define TARGET_NR_sendfile64 239 /* ok */
+#define TARGET_NR_futex 240 /* ok */
+#define TARGET_NR_sched_setaffinity 241 /* ok */
+#define TARGET_NR_sched_getaffinity 242 /* ok */
+#define TARGET_NR_set_thread_area 243 /* remove */
+#define TARGET_NR_get_thread_area 244 /* remove */
+#define TARGET_NR_io_setup 245 /* ok */
+#define TARGET_NR_io_destroy 246 /* ok */
+#define TARGET_NR_io_getevents 247 /* ok */
+#define TARGET_NR_io_submit 248 /* ok */
+#define TARGET_NR_io_cancel 249 /* ok */
+#define TARGET_NR_fadvise64 250 /* remove -> sys_fadvise64_64 */
+/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */
+#define TARGET_NR_exit_group 252 /* ok */
+#define TARGET_NR_lookup_dcookie 253 /* ok */
+#define TARGET_NR_epoll_create 254 /* ok */
+#define TARGET_NR_epoll_ctl 255 /* ok */
+#define TARGET_NR_epoll_wait 256 /* obsolete -> sys_epoll_pwait */
+#define TARGET_NR_remap_file_pages 257 /* only for mmu */
+#define TARGET_NR_set_tid_address 258 /* ok */
+#define TARGET_NR_timer_create 259 /* ok */
+#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1) /* 260 */ /* ok */
+#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2) /* 261 */ /* ok */
+#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3) /* 262 */ /* ok */
+#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4) /* 263 */ /* ok */
+#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5) /* 264 */ /* ok */
+#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6) /* 265 */ /* ok */
+#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7) /* 266 */ /* ok */
+#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8) /* 267 */ /* ok */
+#define TARGET_NR_statfs64 268 /* ok */
+#define TARGET_NR_fstatfs64 269 /* ok */
+#define TARGET_NR_tgkill 270 /* ok */
+#define TARGET_NR_utimes 271 /* obsolete -> sys_futimesat */
+#define TARGET_NR_fadvise64_64 272 /* ok */
+#define TARGET_NR_vserver 273 /* ok */
+#define TARGET_NR_mbind 274 /* only for mmu */
+#define TARGET_NR_get_mempolicy 275 /* only for mmu */
+#define TARGET_NR_set_mempolicy 276 /* only for mmu */
+#define TARGET_NR_mq_open 277 /* ok */
+#define TARGET_NR_mq_unlink (TARGET_NR_mq_open+1) /* 278 */ /* ok */
+#define TARGET_NR_mq_timedsend (TARGET_NR_mq_open+2) /* 279 */ /* ok */
+#define TARGET_NR_mq_timedreceive (TARGET_NR_mq_open+3) /* 280 */ /* ok */
+#define TARGET_NR_mq_notify (TARGET_NR_mq_open+4) /* 281 */ /* ok */
+#define TARGET_NR_mq_getsetattr (TARGET_NR_mq_open+5) /* 282 */ /* ok */
+#define TARGET_NR_kexec_load 283 /* ok */
+#define TARGET_NR_waitid 284 /* ok */
+/* #define TARGET_NR_sys_setaltroot 285 */
+#define TARGET_NR_add_key 286 /* ok */
+#define TARGET_NR_request_key 287 /* ok */
+#define TARGET_NR_keyctl 288 /* ok */
+#define TARGET_NR_ioprio_set 289 /* ok */
+#define TARGET_NR_ioprio_get 290 /* ok */
+#define TARGET_NR_inotify_init 291 /* ok */
+#define TARGET_NR_inotify_add_watch 292 /* ok */
+#define TARGET_NR_inotify_rm_watch 293 /* ok */
+#define TARGET_NR_migrate_pages 294 /* mmu */
+#define TARGET_NR_openat 295 /* ok */
+#define TARGET_NR_mkdirat 296 /* ok */
+#define TARGET_NR_mknodat 297 /* ok */
+#define TARGET_NR_fchownat 298 /* ok */
+#define TARGET_NR_futimesat 299 /* obsolete -> sys_utimesat */
+#define TARGET_NR_fstatat64 300 /* stat64 */
+#define TARGET_NR_unlinkat 301 /* ok */
+#define TARGET_NR_renameat 302 /* ok */
+#define TARGET_NR_linkat 303 /* ok */
+#define TARGET_NR_symlinkat 304 /* ok */
+#define TARGET_NR_readlinkat 305 /* ok */
+#define TARGET_NR_fchmodat 306 /* ok */
+#define TARGET_NR_faccessat 307 /* ok */
+#define TARGET_NR_pselect6 308 /* obsolete -> sys_pselect7 */
+#define TARGET_NR_ppoll 309 /* ok */
+#define TARGET_NR_unshare 310 /* ok */
+#define TARGET_NR_set_robust_list 311 /* ok */
+#define TARGET_NR_get_robust_list 312 /* ok */
+#define TARGET_NR_splice 313 /* ok */
+#define TARGET_NR_sync_file_range 314 /* ok */
+#define TARGET_NR_tee 315 /* ok */
+#define TARGET_NR_vmsplice 316 /* ok */
+#define TARGET_NR_move_pages 317 /* mmu */
+#define TARGET_NR_getcpu 318 /* ok */
+#define TARGET_NR_epoll_pwait 319 /* ok */
+#define TARGET_NR_utimensat 320 /* ok */
+#define TARGET_NR_signalfd 321 /* ok */
+#define TARGET_NR_timerfd_create 322 /* ok */
+#define TARGET_NR_eventfd 323 /* ok */
+#define TARGET_NR_fallocate 324 /* ok */
+#define TARGET_NR_semtimedop 325 /* ok - semaphore group */
+#define TARGET_NR_timerfd_settime 326 /* ok */
+#define TARGET_NR_timerfd_gettime 327 /* ok */
+/* sysv ipc syscalls */
+#define TARGET_NR_semctl 328 /* ok */
+#define TARGET_NR_semget 329 /* ok */
+#define TARGET_NR_semop 330 /* ok */
+#define TARGET_NR_msgctl 331 /* ok */
+#define TARGET_NR_msgget 332 /* ok */
+#define TARGET_NR_msgrcv 333 /* ok */
+#define TARGET_NR_msgsnd 334 /* ok */
+#define TARGET_NR_shmat 335 /* ok */
+#define TARGET_NR_shmctl 336 /* ok */
+#define TARGET_NR_shmdt 337 /* ok */
+#define TARGET_NR_shmget 338 /* ok */
+
+
+#define TARGET_NR_signalfd4 339 /* new */
+#define TARGET_NR_eventfd2 340 /* new */
+#define TARGET_NR_epoll_create1 341 /* new */
+#define TARGET_NR_dup3 342 /* new */
+#define TARGET_NR_pipe2 343 /* new */
+#define TARGET_NR_inotify_init1 344 /* new */
+#define TARGET_NR_socket 345 /* new */
+#define TARGET_NR_socketpair 346 /* new */
+#define TARGET_NR_bind 347 /* new */
+#define TARGET_NR_listen 348 /* new */
+#define TARGET_NR_accept 349 /* new */
+#define TARGET_NR_connect 350 /* new */
+#define TARGET_NR_getsockname 351 /* new */
+#define TARGET_NR_getpeername 352 /* new */
+#define TARGET_NR_sendto 353 /* new */
+#define TARGET_NR_send 354 /* new */
+#define TARGET_NR_recvfrom 355 /* new */
+#define TARGET_NR_recv 356 /* new */
+#define TARGET_NR_setsockopt 357 /* new */
+#define TARGET_NR_getsockopt 358 /* new */
+#define TARGET_NR_shutdown 359 /* new */
+#define TARGET_NR_sendmsg 360 /* new */
+#define TARGET_NR_recvmsg 361 /* new */
+#define TARGET_NR_accept04 362 /* new */
+
+#define TARGET_NR_syscalls 363
+
diff --git a/linux-user/microblaze/target_signal.h b/linux-user/microblaze/target_signal.h
new file mode 100644
index 000000000..3d1f7a723
--- /dev/null
+++ b/linux-user/microblaze/target_signal.h
@@ -0,0 +1,29 @@
+#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_ulong ss_size;
+ abi_long ss_flags;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK 1
+#define TARGET_SS_DISABLE 2
+
+#define TARGET_MINSIGSTKSZ 2048
+#define TARGET_SIGSTKSZ 8192
+
+static inline abi_ulong get_sp_from_cpustate(CPUMBState *state)
+{
+ return state->regs[14];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/microblaze/termbits.h b/linux-user/microblaze/termbits.h
new file mode 100644
index 000000000..fc82ca084
--- /dev/null
+++ b/linux-user/microblaze/termbits.h
@@ -0,0 +1,213 @@
+/* from asm/termbits.h */
+
+#define TARGET_NCCS 19
+
+struct target_termios {
+ unsigned int c_iflag; /* input mode flags */
+ unsigned int c_oflag; /* output mode flags */
+ unsigned int c_cflag; /* control mode flags */
+ unsigned int c_lflag; /* local mode flags */
+ unsigned char c_line; /* line discipline */
+ unsigned char c_cc[TARGET_NCCS]; /* control characters */
+};
+
+/* c_iflag bits */
+#define TARGET_IGNBRK 0000001
+#define TARGET_BRKINT 0000002
+#define TARGET_IGNPAR 0000004
+#define TARGET_PARMRK 0000010
+#define TARGET_INPCK 0000020
+#define TARGET_ISTRIP 0000040
+#define TARGET_INLCR 0000100
+#define TARGET_IGNCR 0000200
+#define TARGET_ICRNL 0000400
+#define TARGET_IUCLC 0001000
+#define TARGET_IXON 0002000
+#define TARGET_IXANY 0004000
+#define TARGET_IXOFF 0010000
+#define TARGET_IMAXBEL 0020000
+
+/* c_oflag bits */
+#define TARGET_OPOST 0000001
+#define TARGET_OLCUC 0000002
+#define TARGET_ONLCR 0000004
+#define TARGET_OCRNL 0000010
+#define TARGET_ONOCR 0000020
+#define TARGET_ONLRET 0000040
+#define TARGET_OFILL 0000100
+#define TARGET_OFDEL 0000200
+#define TARGET_NLDLY 0000400
+#define TARGET_NL0 0000000
+#define TARGET_NL1 0000400
+#define TARGET_CRDLY 0003000
+#define TARGET_CR0 0000000
+#define TARGET_CR1 0001000
+#define TARGET_CR2 0002000
+#define TARGET_CR3 0003000
+#define TARGET_TABDLY 0014000
+#define TARGET_TAB0 0000000
+#define TARGET_TAB1 0004000
+#define TARGET_TAB2 0010000
+#define TARGET_TAB3 0014000
+#define TARGET_XTABS 0014000
+#define TARGET_BSDLY 0020000
+#define TARGET_BS0 0000000
+#define TARGET_BS1 0020000
+#define TARGET_VTDLY 0040000
+#define TARGET_VT0 0000000
+#define TARGET_VT1 0040000
+#define TARGET_FFDLY 0100000
+#define TARGET_FF0 0000000
+#define TARGET_FF1 0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD 0010017
+#define TARGET_B0 0000000 /* hang up */
+#define TARGET_B50 0000001
+#define TARGET_B75 0000002
+#define TARGET_B110 0000003
+#define TARGET_B134 0000004
+#define TARGET_B150 0000005
+#define TARGET_B200 0000006
+#define TARGET_B300 0000007
+#define TARGET_B600 0000010
+#define TARGET_B1200 0000011
+#define TARGET_B1800 0000012
+#define TARGET_B2400 0000013
+#define TARGET_B4800 0000014
+#define TARGET_B9600 0000015
+#define TARGET_B19200 0000016
+#define TARGET_B38400 0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE 0000060
+#define TARGET_CS5 0000000
+#define TARGET_CS6 0000020
+#define TARGET_CS7 0000040
+#define TARGET_CS8 0000060
+#define TARGET_CSTOPB 0000100
+#define TARGET_CREAD 0000200
+#define TARGET_PARENB 0000400
+#define TARGET_PARODD 0001000
+#define TARGET_HUPCL 0002000
+#define TARGET_CLOCAL 0004000
+#define TARGET_CBAUDEX 0010000
+#define TARGET_B57600 0010001
+#define TARGET_B115200 0010002
+#define TARGET_B230400 0010003
+#define TARGET_B460800 0010004
+#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
+#define TARGET_CRTSCTS 020000000000 /* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG 0000001
+#define TARGET_ICANON 0000002
+#define TARGET_XCASE 0000004
+#define TARGET_ECHO 0000010
+#define TARGET_ECHOE 0000020
+#define TARGET_ECHOK 0000040
+#define TARGET_ECHONL 0000100
+#define TARGET_NOFLSH 0000200
+#define TARGET_TOSTOP 0000400
+#define TARGET_ECHOCTL 0001000
+#define TARGET_ECHOPRT 0002000
+#define TARGET_ECHOKE 0004000
+#define TARGET_FLUSHO 0010000
+#define TARGET_PENDIN 0040000
+#define TARGET_IEXTEN 0100000
+
+/* c_cc character offsets */
+#define TARGET_VINTR 0
+#define TARGET_VQUIT 1
+#define TARGET_VERASE 2
+#define TARGET_VKILL 3
+#define TARGET_VEOF 4
+#define TARGET_VTIME 5
+#define TARGET_VMIN 6
+#define TARGET_VSWTC 7
+#define TARGET_VSTART 8
+#define TARGET_VSTOP 9
+#define TARGET_VSUSP 10
+#define TARGET_VEOL 11
+#define TARGET_VREPRINT 12
+#define TARGET_VDISCARD 13
+#define TARGET_VWERASE 14
+#define TARGET_VLNEXT 15
+#define TARGET_VEOL2 16
+
+/* ioctls */
+
+#define TARGET_TCGETS 0x5401
+#define TARGET_TCSETS 0x5402
+#define TARGET_TCSETSW 0x5403
+#define TARGET_TCSETSF 0x5404
+#define TARGET_TCGETA 0x5405
+#define TARGET_TCSETA 0x5406
+#define TARGET_TCSETAW 0x5407
+#define TARGET_TCSETAF 0x5408
+#define TARGET_TCSBRK 0x5409
+#define TARGET_TCXONC 0x540A
+#define TARGET_TCFLSH 0x540B
+
+#define TARGET_TIOCEXCL 0x540C
+#define TARGET_TIOCNXCL 0x540D
+#define TARGET_TIOCSCTTY 0x540E
+#define TARGET_TIOCGPGRP 0x540F
+#define TARGET_TIOCSPGRP 0x5410
+#define TARGET_TIOCOUTQ 0x5411
+#define TARGET_TIOCSTI 0x5412
+#define TARGET_TIOCGWINSZ 0x5413
+#define TARGET_TIOCSWINSZ 0x5414
+#define TARGET_TIOCMGET 0x5415
+#define TARGET_TIOCMBIS 0x5416
+#define TARGET_TIOCMBIC 0x5417
+#define TARGET_TIOCMSET 0x5418
+#define TARGET_TIOCGSOFTCAR 0x5419
+#define TARGET_TIOCSSOFTCAR 0x541A
+#define TARGET_FIONREAD 0x541B
+#define TARGET_TIOCINQ TARGET_FIONREAD
+#define TARGET_TIOCLINUX 0x541C
+#define TARGET_TIOCCONS 0x541D
+#define TARGET_TIOCGSERIAL 0x541E
+#define TARGET_TIOCSSERIAL 0x541F
+#define TARGET_TIOCPKT 0x5420
+#define TARGET_FIONBIO 0x5421
+#define TARGET_TIOCNOTTY 0x5422
+#define TARGET_TIOCSETD 0x5423
+#define TARGET_TIOCGETD 0x5424
+#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
+#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 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_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
+#define TARGET_FIOCLEX 0x5451
+#define TARGET_FIOASYNC 0x5452
+#define TARGET_TIOCSERCONFIG 0x5453
+#define TARGET_TIOCSERGWILD 0x5454
+#define TARGET_TIOCSERSWILD 0x5455
+#define TARGET_TIOCGLCKTRMIOS 0x5456
+#define TARGET_TIOCSLCKTRMIOS 0x5457
+#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
+
+/* Used for packet mode */
+#define TARGET_TIOCPKT_DATA 0
+#define TARGET_TIOCPKT_FLUSHREAD 1
+#define TARGET_TIOCPKT_FLUSHWRITE 2
+#define TARGET_TIOCPKT_STOP 4
+#define TARGET_TIOCPKT_START 8
+#define TARGET_TIOCPKT_NOSTOP 16
+#define TARGET_TIOCPKT_DOSTOP 32
+
+#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 9c9c7eb63..371927e2a 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -3011,6 +3011,222 @@ badframe:
force_sig(TARGET_SIGSEGV);
return 0;
}
+#elif defined(TARGET_MICROBLAZE)
+
+struct target_sigcontext {
+ struct target_pt_regs regs; /* needs to be first */
+ uint32_t oldmask;
+};
+
+/* Signal frames. */
+struct target_signal_frame {
+ struct target_sigcontext sc;
+ uint32_t extramask[TARGET_NSIG_WORDS - 1];
+ uint32_t tramp[2];
+};
+
+struct rt_signal_frame {
+ struct siginfo info;
+ struct ucontext uc;
+ uint32_t tramp[2];
+};
+
+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->regs.r14);
+ __put_user(env->regs[15], &sc->regs.r15);
+ __put_user(env->regs[16], &sc->regs.r16);
+ __put_user(env->regs[17], &sc->regs.r17);
+ __put_user(env->regs[18], &sc->regs.r18);
+ __put_user(env->regs[19], &sc->regs.r19);
+ __put_user(env->regs[20], &sc->regs.r20);
+ __put_user(env->regs[21], &sc->regs.r21);
+ __put_user(env->regs[22], &sc->regs.r22);
+ __put_user(env->regs[23], &sc->regs.r23);
+ __put_user(env->regs[24], &sc->regs.r24);
+ __put_user(env->regs[25], &sc->regs.r25);
+ __put_user(env->regs[26], &sc->regs.r26);
+ __put_user(env->regs[27], &sc->regs.r27);
+ __put_user(env->regs[28], &sc->regs.r28);
+ __put_user(env->regs[29], &sc->regs.r29);
+ __put_user(env->regs[30], &sc->regs.r30);
+ __put_user(env->regs[31], &sc->regs.r31);
+ __put_user(env->sregs[SR_PC], &sc->regs.pc);
+}
+
+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->regs.r14);
+ __get_user(env->regs[15], &sc->regs.r15);
+ __get_user(env->regs[16], &sc->regs.r16);
+ __get_user(env->regs[17], &sc->regs.r17);
+ __get_user(env->regs[18], &sc->regs.r18);
+ __get_user(env->regs[19], &sc->regs.r19);
+ __get_user(env->regs[20], &sc->regs.r20);
+ __get_user(env->regs[21], &sc->regs.r21);
+ __get_user(env->regs[22], &sc->regs.r22);
+ __get_user(env->regs[23], &sc->regs.r23);
+ __get_user(env->regs[24], &sc->regs.r24);
+ __get_user(env->regs[25], &sc->regs.r25);
+ __get_user(env->regs[26], &sc->regs.r26);
+ __get_user(env->regs[27], &sc->regs.r27);
+ __get_user(env->regs[28], &sc->regs.r28);
+ __get_user(env->regs[29], &sc->regs.r29);
+ __get_user(env->regs[30], &sc->regs.r30);
+ __get_user(env->regs[31], &sc->regs.r31);
+ __get_user(env->sregs[SR_PC], &sc->regs.pc);
+}
+
+static abi_ulong get_sigframe(struct target_sigaction *ka,
+ CPUState *env, int frame_size)
+{
+ abi_ulong sp = env->regs[1];
+
+ if ((ka->sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
+ sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+
+ return ((sp - frame_size) & -8UL);
+}
+
+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(ka, env, sizeof *frame);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+ goto badframe;
+
+ /* 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);
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ /* minus 8 is offset to cater for "rtsd r15,8" offset */
+ if (ka->sa_flags & TARGET_SA_RESTORER) {
+ env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
+ } else {
+ uint32_t t;
+ /* Note, these encodings are _big endian_! */
+ /* addi r12, r0, __NR_sigreturn */
+ t = 0x31800000UL | TARGET_NR_sigreturn;
+ err |= __put_user(t, frame->tramp + 0);
+ /* brki r14, 0x8 */
+ t = 0xb9cc0008UL;
+ err |= __put_user(t, frame->tramp + 1);
+
+ /* Return from sighandler will jump to the tramp.
+ Negative 8 offset because return is rtsd r15, 8 */
+ env->regs[15] = ((unsigned long)frame->tramp) - 8;
+ }
+
+ if (err)
+ goto badframe;
+
+ /* Set up registers for signal handler */
+ env->regs[1] = (unsigned long) frame;
+ /* Signal handler args: */
+ env->regs[5] = sig; /* Arg 0: signum */
+ env->regs[6] = (unsigned long) &frame->sc; /* arg 1: sigcontext */
+
+ /* Offset of 4 to handle microblaze rtid r14, 0 */
+ env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
+
+ 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, "Microblaze 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);
+ /* We got here through a sigreturn syscall, our path back is via an
+ rtb insn so setup r14 for that. */
+ env->regs[14] = env->sregs[SR_PC];
+
+ 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, "Microblaze do_rt_sigreturn: not implemented\n");
+ return -TARGET_ENOSYS;
+}
+
#elif defined(TARGET_CRIS)
struct target_sigcontext {
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index b58220d9a..a0915a455 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -4854,7 +4854,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif
#ifdef TARGET_NR_mmap
case TARGET_NR_mmap:
-#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_CRIS)
+#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE)
{
abi_ulong *v;
abi_ulong v1, v2, v3, v4, v5, v6;
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 7f0b0dff1..e2ba0bbc1 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -59,7 +59,8 @@
#define TARGET_IOC_READ 2U
#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
- defined(TARGET_SPARC) || defined(TARGET_MIPS)
+ defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) || \
+ defined(TARGET_MIPS)
#define TARGET_IOC_SIZEBITS 13
#define TARGET_IOC_DIRBITS 3
@@ -286,7 +287,7 @@ struct target_sigaction;
int do_sigaction(int sig, const struct target_sigaction *act,
struct target_sigaction *oact);
-#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) || defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) || defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE)
#if defined(TARGET_SPARC)
#define TARGET_SA_NOCLDSTOP 8u
@@ -1170,6 +1171,54 @@ struct __attribute__((__packed__)) target_stat64 {
unsigned int __unused5;
};
+#elif defined(TARGET_MICROBLAZE)
+
+struct target_stat {
+ abi_ulong st_dev;
+ abi_ulong st_ino;
+ unsigned int st_mode;
+ unsigned short st_nlink;
+ unsigned int st_uid;
+ unsigned int st_gid;
+ abi_ulong st_rdev;
+ abi_ulong st_size;
+ abi_ulong st_blksize;
+ abi_ulong st_blocks;
+ abi_ulong target_st_atime;
+ abi_ulong target_st_atime_nsec;
+ abi_ulong target_st_mtime;
+ abi_ulong target_st_mtime_nsec;
+ abi_ulong target_st_ctime;
+ abi_ulong target_st_ctime_nsec;
+ abi_ulong __unused4;
+ abi_ulong __unused5;
+};
+
+/* FIXME: Microblaze no-mmu user-space has a difference stat64 layout... */
+struct __attribute__((__packed__)) target_stat64 {
+ uint64_t st_dev;
+ uint64_t st_ino;
+ uint32_t st_mode;
+ uint32_t st_nlink;
+ uint32_t st_uid;
+ uint32_t st_gid;
+ uint64_t st_rdev;
+ uint32_t __pad2;
+
+ int64_t st_size;
+ int32_t st_blksize;
+ int64_t st_blocks; /* Number 512-byte blocks allocated. */
+
+ int target_st_atime;
+ unsigned int target_st_atime_nsec;
+ int target_st_mtime;
+ unsigned int target_st_mtime_nsec;
+ int target_st_ctime;
+ unsigned int target_st_ctime_nsec;
+ uint32_t __unused4;
+ uint32_t __unused5;
+};
+
#elif defined(TARGET_M68K)
struct target_stat {
@@ -1719,6 +1768,24 @@ struct target_statfs64 {
#define TARGET_O_NOFOLLOW 0100000 /* don't follow links */
#define TARGET_O_LARGEFILE 0200000
#define TARGET_O_DIRECT 0400000 /* direct disk access hint */
+#elif defined (TARGET_MICROBLAZE)
+#define TARGET_O_ACCMODE 0003
+#define TARGET_O_RDONLY 00
+#define TARGET_O_WRONLY 01
+#define TARGET_O_RDWR 02
+#define TARGET_O_CREAT 0100 /* not fcntl */
+#define TARGET_O_EXCL 0200 /* not fcntl */
+#define TARGET_O_NOCTTY 0400 /* not fcntl */
+#define TARGET_O_TRUNC 01000 /* not fcntl */
+#define TARGET_O_APPEND 02000
+#define TARGET_O_NONBLOCK 04000
+#define TARGET_O_NDELAY TARGET_O_NONBLOCK
+#define TARGET_O_SYNC 010000
+#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */
+#define TARGET_O_DIRECTORY 040000 /* must be a directory */
+#define TARGET_O_NOFOLLOW 0100000 /* don't follow links */
+#define TARGET_O_LARGEFILE 0200000
+#define TARGET_O_DIRECT 0400000 /* direct disk access hint */
#elif defined (TARGET_SPARC)
#define TARGET_O_RDONLY 0x0000
#define TARGET_O_WRONLY 0x0001
@@ -1806,7 +1873,7 @@ struct target_flock {
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)
+#if defined(TARGET_PPC) || defined(TARGET_X86_64) || defined(TARGET_MIPS) || defined(TARGET_SPARC) || defined(TARGET_HPPA) || defined (TARGET_MICROBLAZE)
int __pad;
#endif
unsigned long long l_start;
diff --git a/microblaze-dis.c b/microblaze-dis.c
new file mode 100755
index 000000000..0caacc0bc
--- /dev/null
+++ b/microblaze-dis.c
@@ -0,0 +1,846 @@
+/* Disassemble Xilinx microblaze instructions.
+ Copyright (C) 1993, 1999, 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/*
+ * Copyright (c) 2001 Xilinx, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Xilinx, Inc. The name of the Company may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Xilinx, Inc.
+ */
+
+
+#include <stdio.h>
+#define STATIC_TABLE
+#define DEFINE_TABLE
+
+#ifndef MICROBLAZE_OPC
+#define MICROBLAZE_OPC
+/* Assembler instructions for Xilinx's microblaze processor
+ Copyright (C) 1999, 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/*
+ * Copyright (c) 2001 Xilinx, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Xilinx, Inc. The name of the Company may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Xilinx, Inc.
+ */
+
+
+#ifndef MICROBLAZE_OPCM
+#define MICROBLAZE_OPCM
+
+/*
+ * Copyright (c) 2001 Xilinx, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Xilinx, Inc. The name of the Company may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Xilinx, Inc.
+ * $Header:
+ */
+
+enum microblaze_instr {
+ add, rsub, addc, rsubc, addk, rsubk, addkc, rsubkc, cmp, cmpu,
+ addi, rsubi, addic, rsubic, addik, rsubik, addikc, rsubikc, mul,
+ idiv, idivu, bsll, bsra, bsrl, get, put, nget, nput, cget, cput,
+ ncget, ncput, muli, bslli, bsrai, bsrli, mului, or, and, xor,
+ andn, pcmpbf, pcmpbc, pcmpeq, pcmpne, sra, src, srl, sext8, sext16, wic, wdc, mts, mfs, br, brd,
+ brld, bra, brad, brald, microblaze_brk, beq, beqd, bne, bned, blt,
+ bltd, ble, bled, bgt, bgtd, bge, bged, ori, andi, xori, andni,
+ imm, rtsd, rtid, rtbd, rted, bri, brid, brlid, brai, braid, bralid,
+ brki, beqi, beqid, bnei, bneid, blti, bltid, blei, bleid, bgti,
+ bgtid, bgei, bgeid, lbu, lhu, lw, sb, sh, sw, lbui, lhui, lwi,
+ sbi, shi, swi, msrset, msrclr, tuqula, fadd, frsub, fmul, fdiv,
+ fcmp_lt, fcmp_eq, fcmp_le, fcmp_gt, fcmp_ne, fcmp_ge, fcmp_un, invalid_inst } ;
+
+enum microblaze_instr_type {
+ arithmetic_inst, logical_inst, mult_inst, div_inst, branch_inst,
+ return_inst, immediate_inst, special_inst, memory_load_inst,
+ memory_store_inst, barrel_shift_inst, anyware_inst };
+
+#define INST_WORD_SIZE 4
+
+/* gen purpose regs go from 0 to 31 */
+/* mask is reg num - max_reg_num, ie reg_num - 32 in this case */
+
+#define REG_PC_MASK 0x8000
+#define REG_MSR_MASK 0x8001
+#define REG_EAR_MASK 0x8003
+#define REG_ESR_MASK 0x8005
+#define REG_FSR_MASK 0x8007
+
+#define MIN_REGNUM 0
+#define MAX_REGNUM 31
+
+#define REG_PC 32 /* PC */
+#define REG_MSR 33 /* machine status reg */
+#define REG_EAR 35 /* Exception reg */
+#define REG_ESR 37 /* Exception reg */
+#define REG_FSR 39 /* FPU Status reg */
+
+/* alternate names for gen purpose regs */
+#define REG_SP 1 /* stack pointer */
+#define REG_ROSDP 2 /* read-only small data pointer */
+#define REG_RWSDP 13 /* read-write small data pointer */
+
+/* Assembler Register - Used in Delay Slot Optimization */
+#define REG_AS 18
+#define REG_ZERO 0
+
+#define RD_LOW 21 /* low bit for RD */
+#define RA_LOW 16 /* low bit for RA */
+#define RB_LOW 11 /* low bit for RB */
+#define IMM_LOW 0 /* low bit for immediate */
+
+#define RD_MASK 0x03E00000
+#define RA_MASK 0x001F0000
+#define RB_MASK 0x0000F800
+#define IMM_MASK 0x0000FFFF
+
+// imm mask for barrel shifts
+#define IMM5_MASK 0x0000001F
+
+
+// imm mask for get, put instructions
+#define IMM12_MASK 0x00000FFF
+
+// imm mask for msrset, msrclr instructions
+#define IMM14_MASK 0x00003FFF
+
+#endif /* MICROBLAZE-OPCM */
+
+#define INST_TYPE_RD_R1_R2 0
+#define INST_TYPE_RD_R1_IMM 1
+#define INST_TYPE_RD_R1_UNSIGNED_IMM 2
+#define INST_TYPE_RD_R1 3
+#define INST_TYPE_RD_R2 4
+#define INST_TYPE_RD_IMM 5
+#define INST_TYPE_R2 6
+#define INST_TYPE_R1_R2 7
+#define INST_TYPE_R1_IMM 8
+#define INST_TYPE_IMM 9
+#define INST_TYPE_SPECIAL_R1 10
+#define INST_TYPE_RD_SPECIAL 11
+#define INST_TYPE_R1 12
+ // new instn type for barrel shift imms
+#define INST_TYPE_RD_R1_IMM5 13
+#define INST_TYPE_RD_IMM12 14
+#define INST_TYPE_R1_IMM12 15
+
+ // new insn type for insn cache
+#define INST_TYPE_RD_R1_SPECIAL 16
+
+// new insn type for msrclr, msrset insns.
+#define INST_TYPE_RD_IMM14 17
+
+// new insn type for tuqula rd - addik rd, r0, 42
+#define INST_TYPE_RD 18
+
+#define INST_TYPE_NONE 25
+
+
+
+#define INST_PC_OFFSET 1 /* instructions where the label address is resolved as a PC offset (for branch label)*/
+#define INST_NO_OFFSET 0 /* instructions where the label address is resolved as an absolute value (for data mem or abs address)*/
+
+#define IMMVAL_MASK_NON_SPECIAL 0x0000
+#define IMMVAL_MASK_MTS 0x4000
+#define IMMVAL_MASK_MFS 0x0000
+
+#define OPCODE_MASK_H 0xFC000000 /* High 6 bits only */
+#define OPCODE_MASK_H1 0xFFE00000 /* High 11 bits */
+#define OPCODE_MASK_H2 0xFC1F0000 /* High 6 and bits 20-16 */
+#define OPCODE_MASK_H12 0xFFFF0000 /* High 16 */
+#define OPCODE_MASK_H4 0xFC0007FF /* High 6 and low 11 bits */
+#define OPCODE_MASK_H13S 0xFFE0FFF0 /* High 11 and 15:1 bits and last nibble of last byte for spr */
+#define OPCODE_MASK_H23S 0xFC1FFFF0 /* High 6, 20-16 and 15:1 bits and last nibble of last byte for spr */
+#define OPCODE_MASK_H34 0xFC00FFFF /* High 6 and low 16 bits */
+#define OPCODE_MASK_H14 0xFFE007FF /* High 11 and low 11 bits */
+#define OPCODE_MASK_H24 0xFC1F07FF /* High 6, bits 20-16 and low 11 bits */
+#define OPCODE_MASK_H124 0xFFFF07FF /* High 16, and low 11 bits */
+#define OPCODE_MASK_H1234 0xFFFFFFFF /* All 32 bits */
+#define OPCODE_MASK_H3 0xFC000600 /* High 6 bits and bits 21, 22 */
+#define OPCODE_MASK_H32 0xFC00F000 /* High 6 bits and bit 16, 17, 18 and 19*/
+#define OPCODE_MASK_H34B 0xFC0000FF /* High 6 bits and low 8 bits */
+
+// New Mask for msrset, msrclr insns.
+#define OPCODE_MASK_H23N 0xFC1FC000 /* High 6 and bits 12 - 18 */
+
+#define DELAY_SLOT 1
+#define NO_DELAY_SLOT 0
+
+#define MAX_OPCODES 149
+
+struct op_code_struct {
+ const char *name;
+ short inst_type; /* registers and immediate values involved */
+ short inst_offset_type; /* immediate vals offset from PC? (= 1 for branches) */
+ short delay_slots; /* info about delay slots needed after this instr. */
+ short immval_mask;
+ unsigned long bit_sequence; /* all the fixed bits for the op are set and all the variable bits (reg names, imm vals) are set to 0 */
+ unsigned long opcode_mask; /* which bits define the opcode */
+ enum microblaze_instr instr;
+ enum microblaze_instr_type instr_type;
+ /* more info about output format here */
+} opcodes[MAX_OPCODES] =
+
+{
+ {"add", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x00000000, OPCODE_MASK_H4, add, arithmetic_inst },
+ {"rsub", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x04000000, OPCODE_MASK_H4, rsub, arithmetic_inst },
+ {"addc", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x08000000, OPCODE_MASK_H4, addc, arithmetic_inst },
+ {"rsubc", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x0C000000, OPCODE_MASK_H4, rsubc, arithmetic_inst },
+ {"addk", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x10000000, OPCODE_MASK_H4, addk, arithmetic_inst },
+ {"rsubk", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000000, OPCODE_MASK_H4, rsubk, arithmetic_inst },
+ {"cmp", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000001, OPCODE_MASK_H4, cmp, arithmetic_inst },
+ {"cmpu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000003, OPCODE_MASK_H4, cmpu, arithmetic_inst },
+ {"addkc", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x18000000, OPCODE_MASK_H4, addkc, arithmetic_inst },
+ {"rsubkc",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x1C000000, OPCODE_MASK_H4, rsubkc, arithmetic_inst },
+ {"addi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x20000000, OPCODE_MASK_H, addi, arithmetic_inst },
+ {"rsubi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x24000000, OPCODE_MASK_H, rsubi, arithmetic_inst },
+ {"addic", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x28000000, OPCODE_MASK_H, addic, arithmetic_inst },
+ {"rsubic",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x2C000000, OPCODE_MASK_H, rsubic, arithmetic_inst },
+ {"addik", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x30000000, OPCODE_MASK_H, addik, arithmetic_inst },
+ {"rsubik",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x34000000, OPCODE_MASK_H, rsubik, arithmetic_inst },
+ {"addikc",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x38000000, OPCODE_MASK_H, addikc, arithmetic_inst },
+ {"rsubikc",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x3C000000, OPCODE_MASK_H, rsubikc, arithmetic_inst },
+ {"mul", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x40000000, OPCODE_MASK_H4, mul, mult_inst },
+ {"idiv", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x48000000, OPCODE_MASK_H4, idiv, div_inst },
+ {"idivu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x48000002, OPCODE_MASK_H4, idivu, div_inst },
+ {"bsll", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000400, OPCODE_MASK_H3, bsll, barrel_shift_inst },
+ {"bsra", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000200, OPCODE_MASK_H3, bsra, barrel_shift_inst },
+ {"bsrl", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000000, OPCODE_MASK_H3, bsrl, barrel_shift_inst },
+ {"get", INST_TYPE_RD_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C000000, OPCODE_MASK_H32, get, anyware_inst },
+ {"put", INST_TYPE_R1_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C008000, OPCODE_MASK_H32, put, anyware_inst },
+ {"nget", INST_TYPE_RD_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C004000, OPCODE_MASK_H32, nget, anyware_inst },
+ {"nput", INST_TYPE_R1_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00C000, OPCODE_MASK_H32, nput, anyware_inst },
+ {"cget", INST_TYPE_RD_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C002000, OPCODE_MASK_H32, cget, anyware_inst },
+ {"cput", INST_TYPE_R1_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00A000, OPCODE_MASK_H32, cput, anyware_inst },
+ {"ncget", INST_TYPE_RD_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C006000, OPCODE_MASK_H32, ncget, anyware_inst },
+ {"ncput", INST_TYPE_R1_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00E000, OPCODE_MASK_H32, ncput, anyware_inst },
+ {"muli", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x60000000, OPCODE_MASK_H, muli, mult_inst },
+ {"bslli", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000400, OPCODE_MASK_H3, bslli, barrel_shift_inst },
+ {"bsrai", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000200, OPCODE_MASK_H3, bsrai, barrel_shift_inst },
+ {"bsrli", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000000, OPCODE_MASK_H3, bsrli, barrel_shift_inst },
+ {"or", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000000, OPCODE_MASK_H4, or, logical_inst },
+ {"and", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x84000000, OPCODE_MASK_H4, and, logical_inst },
+ {"xor", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x88000000, OPCODE_MASK_H4, xor, logical_inst },
+ {"andn", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x8C000000, OPCODE_MASK_H4, andn, logical_inst },
+ {"pcmpbf",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000400, OPCODE_MASK_H4, pcmpbf, logical_inst },
+ {"pcmpbc",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x84000400, OPCODE_MASK_H4, pcmpbc, logical_inst },
+ {"pcmpeq",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x88000400, OPCODE_MASK_H4, pcmpeq, logical_inst },
+ {"pcmpne",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x8C000400, OPCODE_MASK_H4, pcmpne, logical_inst },
+ {"sra", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000001, OPCODE_MASK_H34, sra, logical_inst },
+ {"src", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000021, OPCODE_MASK_H34, src, logical_inst },
+ {"srl", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000041, OPCODE_MASK_H34, srl, logical_inst },
+ {"sext8", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000060, OPCODE_MASK_H34, sext8, logical_inst },
+ {"sext16",INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000061, OPCODE_MASK_H34, sext16, logical_inst },
+ {"wic", INST_TYPE_RD_R1_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000068, OPCODE_MASK_H34B, wic, special_inst },
+ {"wdc", INST_TYPE_RD_R1_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000064, OPCODE_MASK_H34B, wdc, special_inst },
+ {"mts", INST_TYPE_SPECIAL_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_MTS, 0x9400C000, OPCODE_MASK_H13S, mts, special_inst },
+ {"mfs", INST_TYPE_RD_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_MFS, 0x94008000, OPCODE_MASK_H23S, mfs, special_inst },
+ {"br", INST_TYPE_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98000000, OPCODE_MASK_H124, br, branch_inst },
+ {"brd", INST_TYPE_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98100000, OPCODE_MASK_H124, brd, branch_inst },
+ {"brld", INST_TYPE_RD_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98140000, OPCODE_MASK_H24, brld, branch_inst },
+ {"bra", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98080000, OPCODE_MASK_H124, bra, branch_inst },
+ {"brad", INST_TYPE_R2, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98180000, OPCODE_MASK_H124, brad, branch_inst },
+ {"brald", INST_TYPE_RD_R2, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x981C0000, OPCODE_MASK_H24, brald, branch_inst },
+ {"brk", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x980C0000, OPCODE_MASK_H24, microblaze_brk, branch_inst },
+ {"beq", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C000000, OPCODE_MASK_H14, beq, branch_inst },
+ {"beqd", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E000000, OPCODE_MASK_H14, beqd, branch_inst },
+ {"bne", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C200000, OPCODE_MASK_H14, bne, branch_inst },
+ {"bned", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E200000, OPCODE_MASK_H14, bned, branch_inst },
+ {"blt", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C400000, OPCODE_MASK_H14, blt, branch_inst },
+ {"bltd", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E400000, OPCODE_MASK_H14, bltd, branch_inst },
+ {"ble", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C600000, OPCODE_MASK_H14, ble, branch_inst },
+ {"bled", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E600000, OPCODE_MASK_H14, bled, branch_inst },
+ {"bgt", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C800000, OPCODE_MASK_H14, bgt, branch_inst },
+ {"bgtd", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E800000, OPCODE_MASK_H14, bgtd, branch_inst },
+ {"bge", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9CA00000, OPCODE_MASK_H14, bge, branch_inst },
+ {"bged", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9EA00000, OPCODE_MASK_H14, bged, branch_inst },
+ {"ori", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA0000000, OPCODE_MASK_H, ori, logical_inst },
+ {"andi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA4000000, OPCODE_MASK_H, andi, logical_inst },
+ {"xori", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA8000000, OPCODE_MASK_H, xori, logical_inst },
+ {"andni", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xAC000000, OPCODE_MASK_H, andni, logical_inst },
+ {"imm", INST_TYPE_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB0000000, OPCODE_MASK_H12, imm, immediate_inst },
+ {"rtsd", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6000000, OPCODE_MASK_H1, rtsd, return_inst },
+ {"rtid", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6200000, OPCODE_MASK_H1, rtid, return_inst },
+ {"rtbd", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6400000, OPCODE_MASK_H1, rtbd, return_inst },
+ {"rted", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6800000, OPCODE_MASK_H1, rted, return_inst },
+ {"bri", INST_TYPE_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8000000, OPCODE_MASK_H12, bri, branch_inst },
+ {"brid", INST_TYPE_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8100000, OPCODE_MASK_H12, brid, branch_inst },
+ {"brlid", INST_TYPE_RD_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8140000, OPCODE_MASK_H2, brlid, branch_inst },
+ {"brai", INST_TYPE_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8080000, OPCODE_MASK_H12, brai, branch_inst },
+ {"braid", INST_TYPE_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8180000, OPCODE_MASK_H12, braid, branch_inst },
+ {"bralid",INST_TYPE_RD_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB81C0000, OPCODE_MASK_H2, bralid, branch_inst },
+ {"brki", INST_TYPE_RD_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB80C0000, OPCODE_MASK_H2, brki, branch_inst },
+ {"beqi", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC000000, OPCODE_MASK_H1, beqi, branch_inst },
+ {"beqid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE000000, OPCODE_MASK_H1, beqid, branch_inst },
+ {"bnei", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC200000, OPCODE_MASK_H1, bnei, branch_inst },
+ {"bneid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE200000, OPCODE_MASK_H1, bneid, branch_inst },
+ {"blti", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC400000, OPCODE_MASK_H1, blti, branch_inst },
+ {"bltid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE400000, OPCODE_MASK_H1, bltid, branch_inst },
+ {"blei", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC600000, OPCODE_MASK_H1, blei, branch_inst },
+ {"bleid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE600000, OPCODE_MASK_H1, bleid, branch_inst },
+ {"bgti", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC800000, OPCODE_MASK_H1, bgti, branch_inst },
+ {"bgtid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE800000, OPCODE_MASK_H1, bgtid, branch_inst },
+ {"bgei", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBCA00000, OPCODE_MASK_H1, bgei, branch_inst },
+ {"bgeid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBEA00000, OPCODE_MASK_H1, bgeid, branch_inst },
+ {"lbu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC0000000, OPCODE_MASK_H4, lbu, memory_load_inst },
+ {"lhu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC4000000, OPCODE_MASK_H4, lhu, memory_load_inst },
+ {"lw", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC8000000, OPCODE_MASK_H4, lw, memory_load_inst },
+ {"sb", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD0000000, OPCODE_MASK_H4, sb, memory_store_inst },
+ {"sh", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD4000000, OPCODE_MASK_H4, sh, memory_store_inst },
+ {"sw", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD8000000, OPCODE_MASK_H4, sw, memory_store_inst },
+ {"lbui", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE0000000, OPCODE_MASK_H, lbui, memory_load_inst },
+ {"lhui", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE4000000, OPCODE_MASK_H, lhui, memory_load_inst },
+ {"lwi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE8000000, OPCODE_MASK_H, lwi, memory_load_inst },
+ {"sbi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF0000000, OPCODE_MASK_H, sbi, memory_store_inst },
+ {"shi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF4000000, OPCODE_MASK_H, shi, memory_store_inst },
+ {"swi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF8000000, OPCODE_MASK_H, swi, memory_store_inst },
+ {"nop", INST_TYPE_NONE, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000000, OPCODE_MASK_H1234, invalid_inst, logical_inst }, /* translates to or r0, r0, r0 */
+ {"la", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x30000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* la translates to addik */
+ {"tuqula",INST_TYPE_RD, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x3000002A, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* tuqula rd translates to addik rd, r0, 42 */
+ {"not", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA800FFFF, OPCODE_MASK_H34, invalid_inst, logical_inst }, /* not translates to xori rd,ra,-1 */
+ {"neg", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x04000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* neg translates to rsub rd, ra, r0 */
+ {"rtb", INST_TYPE_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6000004, OPCODE_MASK_H1, invalid_inst, return_inst }, /* rtb translates to rts rd, 4 */
+ {"sub", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x04000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* sub translates to rsub rd, rb, ra */
+ {"lmi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE8000000, OPCODE_MASK_H, invalid_inst, memory_load_inst },
+ {"smi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF8000000, OPCODE_MASK_H, invalid_inst, memory_store_inst },
+ {"msrset",INST_TYPE_RD_IMM14, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x94100000, OPCODE_MASK_H23N, msrset, special_inst },
+ {"msrclr",INST_TYPE_RD_IMM14, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x94110000, OPCODE_MASK_H23N, msrclr, special_inst },
+ {"fadd", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000000, OPCODE_MASK_H4, fadd, arithmetic_inst },
+ {"frsub", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000080, OPCODE_MASK_H4, frsub, arithmetic_inst },
+ {"fmul", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000100, OPCODE_MASK_H4, fmul, arithmetic_inst },
+ {"fdiv", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000180, OPCODE_MASK_H4, fdiv, arithmetic_inst },
+ {"fcmp.lt", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000210, OPCODE_MASK_H4, fcmp_lt, arithmetic_inst },
+ {"fcmp.eq", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000220, OPCODE_MASK_H4, fcmp_eq, arithmetic_inst },
+ {"fcmp.le", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000230, OPCODE_MASK_H4, fcmp_le, arithmetic_inst },
+ {"fcmp.gt", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000240, OPCODE_MASK_H4, fcmp_gt, arithmetic_inst },
+ {"fcmp.ne", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000250, OPCODE_MASK_H4, fcmp_ne, arithmetic_inst },
+ {"fcmp.ge", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000260, OPCODE_MASK_H4, fcmp_ge, arithmetic_inst },
+ {"fcmp.un", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000200, OPCODE_MASK_H4, fcmp_un, arithmetic_inst },
+ {""}
+};
+
+/* prefix for register names */
+char register_prefix[] = "r";
+char special_register_prefix[] = "spr";
+char fsl_register_prefix[] = "rfsl";
+
+
+/* #defines for valid immediate range */
+#define MIN_IMM 0x80000000
+#define MAX_IMM 0x7fffffff
+
+#define MIN_IMM12 0x000
+#define MAX_IMM12 0x7ff
+
+#define MIN_IMM14 0x0000
+#define MAX_IMM14 0x1fff
+
+#endif /* MICROBLAZE_OPC */
+
+#include "dis-asm.h"
+#include <strings.h>
+
+#define get_field_rd(instr) get_field(instr, RD_MASK, RD_LOW)
+#define get_field_r1(instr) get_field(instr, RA_MASK, RA_LOW)
+#define get_field_r2(instr) get_field(instr, RB_MASK, RB_LOW)
+#define get_int_field_imm(instr) ((instr & IMM_MASK) >> IMM_LOW)
+#define get_int_field_r1(instr) ((instr & RA_MASK) >> RA_LOW)
+
+static char *
+get_field (long instr, long mask, unsigned short low)
+{
+ char tmpstr[25];
+ sprintf(tmpstr, "%s%d", register_prefix, (int)((instr & mask) >> low));
+ return(strdup(tmpstr));
+}
+
+static char *
+get_field_imm (long instr)
+{
+ char tmpstr[25];
+ sprintf(tmpstr, "%d", (short)((instr & IMM_MASK) >> IMM_LOW));
+ return(strdup(tmpstr));
+}
+
+static char *
+get_field_imm5 (long instr)
+{
+ char tmpstr[25];
+ sprintf(tmpstr, "%d", (short)((instr & IMM5_MASK) >> IMM_LOW));
+ return(strdup(tmpstr));
+}
+
+static char *
+get_field_imm12 (long instr)
+{
+ char tmpstr[25];
+ sprintf(tmpstr, "%s%d", fsl_register_prefix, (short)((instr & IMM12_MASK) >> IMM_LOW));
+ return(strdup(tmpstr));
+}
+
+static char *
+get_field_imm14 (long instr)
+{
+ char tmpstr[25];
+ sprintf(tmpstr, "%d", (short)((instr & IMM14_MASK) >> IMM_LOW));
+ return(strdup(tmpstr));
+}
+
+#if 0
+static char *
+get_field_unsigned_imm (long instr)
+{
+ char tmpstr[25];
+ sprintf(tmpstr, "%d", (int)((instr & IMM_MASK) >> IMM_LOW));
+ return(strdup(tmpstr));
+}
+#endif
+
+/*
+ char *
+ get_field_special (instr)
+ long instr;
+ {
+ char tmpstr[25];
+
+ sprintf(tmpstr, "%s%s", register_prefix, (((instr & IMM_MASK) >> IMM_LOW) & REG_MSR_MASK) == 0 ? "pc" : "msr");
+
+ return(strdup(tmpstr));
+ }
+*/
+
+static char *
+get_field_special (long instr, struct op_code_struct * op)
+{
+ char tmpstr[25];
+ char spr[5];
+
+ switch ( (((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) ) {
+ case REG_MSR_MASK :
+ strcpy(spr, "msr");
+ break;
+ case REG_PC_MASK :
+ strcpy(spr, "pc");
+ break;
+ case REG_EAR_MASK :
+ strcpy(spr, "ear");
+ break;
+ case REG_ESR_MASK :
+ strcpy(spr, "esr");
+ break;
+ case REG_FSR_MASK :
+ strcpy(spr, "fsr");
+ break;
+ default :
+ strcpy(spr, "pc");
+ break;
+ }
+
+ sprintf(tmpstr, "%s%s", register_prefix, spr);
+ return(strdup(tmpstr));
+}
+
+static unsigned long
+read_insn_microblaze(bfd_vma memaddr, struct disassemble_info *info,
+ struct op_code_struct ** opr)
+{
+ unsigned char ibytes[4];
+ int status;
+ struct op_code_struct * op;
+ unsigned long inst;
+
+ status = info->read_memory_func (memaddr, ibytes, 4, info);
+
+ if (status != 0)
+ {
+ info->memory_error_func (status, memaddr, info);
+ return 0;
+ }
+
+ if (info->endian == BFD_ENDIAN_BIG)
+ inst = (ibytes[0] << 24) | (ibytes[1] << 16) | (ibytes[2] << 8) | ibytes[3];
+ else if (info->endian == BFD_ENDIAN_LITTLE)
+ inst = (ibytes[3] << 24) | (ibytes[2] << 16) | (ibytes[1] << 8) | ibytes[0];
+ else
+ abort ();
+
+ /* Just a linear search of the table. */
+ for (op = opcodes; op->name != 0; op ++)
+ if (op->bit_sequence == (inst & op->opcode_mask))
+ break;
+
+ *opr = op;
+ return inst;
+}
+
+
+int
+print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info)
+{
+ fprintf_ftype fprintf = info->fprintf_func;
+ void * stream = info->stream;
+ unsigned long inst, prev_inst;
+ struct op_code_struct * op, *pop;
+ int immval = 0;
+ boolean immfound = false;
+ static bfd_vma prev_insn_addr = -1; /*init the prev insn addr */
+ static int prev_insn_vma = -1; /*init the prev insn vma */
+ int curr_insn_vma = info->buffer_vma;
+
+ info->bytes_per_chunk = 4;
+
+ inst = read_insn_microblaze (memaddr, info, &op);
+ if (inst == 0)
+ return -1;
+
+ if (prev_insn_vma == curr_insn_vma) {
+ if (memaddr-(info->bytes_per_chunk) == prev_insn_addr) {
+ prev_inst = read_insn_microblaze (prev_insn_addr, info, &pop);
+ if (prev_inst == 0)
+ return -1;
+ if (pop->instr == imm) {
+ immval = (get_int_field_imm(prev_inst) << 16) & 0xffff0000;
+ immfound = true;
+ }
+ else {
+ immval = 0;
+ immfound = false;
+ }
+ }
+ }
+ /* make curr insn as prev insn */
+ prev_insn_addr = memaddr;
+ prev_insn_vma = curr_insn_vma;
+
+ if (op->name == 0)
+ fprintf (stream, ".short 0x%04x", inst);
+ else
+ {
+ fprintf (stream, "%s", op->name);
+
+ switch (op->inst_type)
+ {
+ case INST_TYPE_RD_R1_R2:
+ fprintf(stream, "\t%s, %s, %s", get_field_rd(inst), get_field_r1(inst), get_field_r2(inst));
+ break;
+ case INST_TYPE_RD_R1_IMM:
+ fprintf(stream, "\t%s, %s, %s", get_field_rd(inst), get_field_r1(inst), get_field_imm(inst));
+ if (info->print_address_func && get_int_field_r1(inst) == 0 && info->symbol_at_address_func) {
+ if (immfound)
+ immval |= (get_int_field_imm(inst) & 0x0000ffff);
+ else {
+ immval = get_int_field_imm(inst);
+ if (immval & 0x8000)
+ immval |= 0xFFFF0000;
+ }
+ if (immval > 0 && info->symbol_at_address_func(immval, info)) {
+ fprintf (stream, "\t// ");
+ info->print_address_func (immval, info);
+ }
+ }
+ break;
+ case INST_TYPE_RD_R1_IMM5:
+ fprintf(stream, "\t%s, %s, %s", get_field_rd(inst), get_field_r1(inst), get_field_imm5(inst));
+ break;
+ case INST_TYPE_RD_IMM12:
+ fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_imm12(inst));
+ break;
+ case INST_TYPE_R1_IMM12:
+ fprintf(stream, "\t%s, %s", get_field_r1(inst), get_field_imm12(inst));
+ break;
+ case INST_TYPE_RD_SPECIAL:
+ fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_special(inst, op));
+ break;
+ case INST_TYPE_SPECIAL_R1:
+ fprintf(stream, "\t%s, %s", get_field_special(inst, op), get_field_r1(inst));
+ break;
+ case INST_TYPE_RD_R1:
+ fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_r1(inst));
+ break;
+ case INST_TYPE_R1_R2:
+ fprintf(stream, "\t%s, %s", get_field_r1(inst), get_field_r2(inst));
+ break;
+ case INST_TYPE_R1_IMM:
+ fprintf(stream, "\t%s, %s", get_field_r1(inst), get_field_imm(inst));
+ /* The non-pc relative instructions are returns, which shouldn't
+ have a label printed */
+ if (info->print_address_func && op->inst_offset_type == INST_PC_OFFSET && info->symbol_at_address_func) {
+ if (immfound)
+ immval |= (get_int_field_imm(inst) & 0x0000ffff);
+ else {
+ immval = get_int_field_imm(inst);
+ if (immval & 0x8000)
+ immval |= 0xFFFF0000;
+ }
+ immval += memaddr;
+ if (immval > 0 && info->symbol_at_address_func(immval, info)) {
+ fprintf (stream, "\t// ");
+ info->print_address_func (immval, info);
+ } else {
+ fprintf (stream, "\t\t// ");
+ fprintf (stream, "%x", immval);
+ }
+ }
+ break;
+ case INST_TYPE_RD_IMM:
+ fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_imm(inst));
+ if (info->print_address_func && info->symbol_at_address_func) {
+ if (immfound)
+ immval |= (get_int_field_imm(inst) & 0x0000ffff);
+ else {
+ immval = get_int_field_imm(inst);
+ if (immval & 0x8000)
+ immval |= 0xFFFF0000;
+ }
+ if (op->inst_offset_type == INST_PC_OFFSET)
+ immval += (int) memaddr;
+ if (info->symbol_at_address_func(immval, info)) {
+ fprintf (stream, "\t// ");
+ info->print_address_func (immval, info);
+ }
+ }
+ break;
+ case INST_TYPE_IMM:
+ fprintf(stream, "\t%s", get_field_imm(inst));
+ if (info->print_address_func && info->symbol_at_address_func && op->instr != imm) {
+ if (immfound)
+ immval |= (get_int_field_imm(inst) & 0x0000ffff);
+ else {
+ immval = get_int_field_imm(inst);
+ if (immval & 0x8000)
+ immval |= 0xFFFF0000;
+ }
+ if (op->inst_offset_type == INST_PC_OFFSET)
+ immval += (int) memaddr;
+ if (immval > 0 && info->symbol_at_address_func(immval, info)) {
+ fprintf (stream, "\t// ");
+ info->print_address_func (immval, info);
+ } else if (op->inst_offset_type == INST_PC_OFFSET) {
+ fprintf (stream, "\t\t// ");
+ fprintf (stream, "%x", immval);
+ }
+ }
+ break;
+ case INST_TYPE_RD_R2:
+ fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_r2(inst));
+ break;
+ case INST_TYPE_R2:
+ fprintf(stream, "\t%s", get_field_r2(inst));
+ break;
+ case INST_TYPE_R1:
+ fprintf(stream, "\t%s", get_field_r1(inst));
+ break;
+ case INST_TYPE_RD_R1_SPECIAL:
+ fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_r2(inst));
+ break;
+ case INST_TYPE_RD_IMM14:
+ fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_imm14(inst));
+ break;
+ /* For tuqula instruction */
+ case INST_TYPE_RD:
+ fprintf(stream, "\t%s", get_field_rd(inst));
+ break;
+
+ default:
+ /* if the disassembler lags the instruction set */
+ fprintf (stream, "\tundecoded operands, inst is 0x%04x", inst);
+ break;
+ }
+ }
+
+ /* Say how many bytes we consumed? */
+ return 4;
+}
+
+#if 0
+static enum microblaze_instr
+get_insn_microblaze (long inst, boolean *isunsignedimm,
+ enum microblaze_instr_type *insn_type,
+ short *delay_slots )
+{
+ struct op_code_struct * op;
+ *isunsignedimm = false;
+
+ /* Just a linear search of the table. */
+ for (op = opcodes; op->name != 0; op ++)
+ if (op->bit_sequence == (inst & op->opcode_mask))
+ break;
+
+ if (op->name == 0)
+ return invalid_inst;
+ else {
+ *isunsignedimm = (op->inst_type == INST_TYPE_RD_R1_UNSIGNED_IMM);
+ *insn_type = op->instr_type;
+ *delay_slots = op->delay_slots;
+ return op->instr;
+ }
+}
+#endif
+
+#if 0
+static short
+get_delay_slots_microblaze ( long inst )
+{
+ boolean isunsignedimm;
+ enum microblaze_instr_type insn_type;
+ enum microblaze_instr op;
+ short delay_slots;
+
+ op = get_insn_microblaze( inst, &isunsignedimm, &insn_type, &delay_slots);
+ if (op == invalid_inst)
+ return 0;
+ else
+ return delay_slots;
+}
+#endif
+
+#if 0
+static enum microblaze_instr
+microblaze_decode_insn (long insn, int *rd, int *ra, int *rb, int *imm)
+{
+ enum microblaze_instr op;
+ boolean t1;
+ enum microblaze_instr_type t2;
+ short t3;
+
+ op = get_insn_microblaze(insn, &t1, &t2, &t3);
+ *rd = (insn & RD_MASK) >> RD_LOW;
+ *ra = (insn & RA_MASK) >> RA_LOW;
+ *rb = (insn & RB_MASK) >> RB_LOW;
+ t3 = (insn & IMM_MASK) >> IMM_LOW;
+ *imm = (int) t3;
+ return (op);
+}
+#endif
+
+#if 0
+static unsigned long
+microblaze_get_target_address (long inst, boolean immfound, int immval,
+ long pcval, long r1val, long r2val,
+ boolean *targetvalid,
+ boolean *unconditionalbranch)
+{
+ struct op_code_struct * op;
+ long targetaddr = 0;
+
+ *unconditionalbranch = false;
+ /* Just a linear search of the table. */
+ for (op = opcodes; op->name != 0; op ++)
+ if (op->bit_sequence == (inst & op->opcode_mask))
+ break;
+
+ if (op->name == 0) {
+ *targetvalid = false;
+ } else if (op->instr_type == branch_inst) {
+ switch (op->inst_type) {
+ case INST_TYPE_R2:
+ *unconditionalbranch = true;
+ /* fallthru */
+ case INST_TYPE_RD_R2:
+ case INST_TYPE_R1_R2:
+ targetaddr = r2val;
+ *targetvalid = true;
+ if (op->inst_offset_type == INST_PC_OFFSET)
+ targetaddr += pcval;
+ break;
+ case INST_TYPE_IMM:
+ *unconditionalbranch = true;
+ /* fallthru */
+ case INST_TYPE_RD_IMM:
+ case INST_TYPE_R1_IMM:
+ if (immfound) {
+ targetaddr = (immval << 16) & 0xffff0000;
+ targetaddr |= (get_int_field_imm(inst) & 0x0000ffff);
+ } else {
+ targetaddr = get_int_field_imm(inst);
+ if (targetaddr & 0x8000)
+ targetaddr |= 0xFFFF0000;
+ }
+ if (op->inst_offset_type == INST_PC_OFFSET)
+ targetaddr += pcval;
+ *targetvalid = true;
+ break;
+ default:
+ *targetvalid = false;
+ break;
+ }
+ } else if (op->instr_type == return_inst) {
+ if (immfound) {
+ targetaddr = (immval << 16) & 0xffff0000;
+ targetaddr |= (get_int_field_imm(inst) & 0x0000ffff);
+ } else {
+ targetaddr = get_int_field_imm(inst);
+ if (targetaddr & 0x8000)
+ targetaddr |= 0xFFFF0000;
+ }
+ targetaddr += r1val;
+ *targetvalid = true;
+ } else {
+ *targetvalid = false;
+ }
+ return targetaddr;
+}
+#endif
diff --git a/migration-exec.c b/migration-exec.c
index f0869a114..0dd5aff31 100644
--- a/migration-exec.c
+++ b/migration-exec.c
@@ -104,17 +104,11 @@ err_after_alloc:
return NULL;
}
-int exec_start_incoming_migration(const char *command)
+static void exec_accept_incoming_migration(void *opaque)
{
+ QEMUFile *f = opaque;
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) {
@@ -123,11 +117,28 @@ int exec_start_incoming_migration(const char *command)
}
qemu_announce_self();
dprintf("successfully loaded vm state\n");
+ /* we've successfully migrated, close the fd */
+ qemu_set_fd_handler2(qemu_popen_fd(f), NULL, NULL, NULL, NULL);
vm_start();
- qemu_fclose(f);
- return 0;
err:
qemu_fclose(f);
- return -errno;
+}
+
+int exec_start_incoming_migration(const char *command)
+{
+ 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;
+ }
+
+ qemu_set_fd_handler2(qemu_popen_fd(f), NULL,
+ exec_accept_incoming_migration, NULL,
+ (void *)(unsigned long)f);
+
+ return 0;
}
diff --git a/monitor.c b/monitor.c
index 262020302..540e95b34 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1783,8 +1783,10 @@ static const mon_cmd_t mon_cmds[] = {
{ "host_net_remove", "is", net_host_device_remove,
"vlan_id name", "remove host VLAN client" },
#ifdef CONFIG_SLIRP
- { "host_net_redir", "s", net_slirp_redir,
- "[tcp|udp]:host-port:[guest-host]:guest-port", "redirect TCP or UDP connections from host to guest (requires -net user)" },
+ { "host_net_redir", "ss?", net_slirp_redir,
+ "[tcp|udp]:host-port:[guest-host]:guest-port", "redirect TCP or UDP connections from host to guest (requires -net user)\n"
+ "host_net_redir remove [tcp:|udp:]host-port -- remove redirection\n"
+ "host_net_redir list -- show all redirections" },
#endif
{ "balloon", "i", do_balloon,
"target", "request VM to change it's memory allocation (in MB)" },
diff --git a/net.c b/net.c
index 01e31dbbf..fb70b7084 100644
--- a/net.c
+++ b/net.c
@@ -603,7 +603,82 @@ static int net_slirp_init(VLANState *vlan, const char *model, const char *name)
return 0;
}
-void net_slirp_redir(Monitor *mon, const char *redir_str)
+static void net_slirp_redir_print(void *opaque, int is_udp,
+ struct in_addr *laddr, u_int lport,
+ struct in_addr *faddr, u_int fport)
+{
+ Monitor *mon = (Monitor *)opaque;
+ uint32_t h_addr;
+ uint32_t g_addr;
+ char buf[16];
+
+ h_addr = ntohl(faddr->s_addr);
+ g_addr = ntohl(laddr->s_addr);
+
+ monitor_printf(mon, " %s |", is_udp ? "udp" : "tcp" );
+ snprintf(buf, 15, "%d.%d.%d.%d", (h_addr >> 24) & 0xff,
+ (h_addr >> 16) & 0xff,
+ (h_addr >> 8) & 0xff,
+ (h_addr) & 0xff);
+ monitor_printf(mon, " %15s |", buf);
+ monitor_printf(mon, " %5d |", fport);
+
+ snprintf(buf, 15, "%d.%d.%d.%d", (g_addr >> 24) & 0xff,
+ (g_addr >> 16) & 0xff,
+ (g_addr >> 8) & 0xff,
+ (g_addr) & 0xff);
+ monitor_printf(mon, " %15s |", buf);
+ monitor_printf(mon, " %5d\n", lport);
+
+}
+
+static void net_slirp_redir_list(Monitor *mon)
+{
+ if (!mon)
+ return;
+
+ monitor_printf(mon, " Prot | Host Addr | HPort | Guest Addr | GPort\n");
+ monitor_printf(mon, " | | | | \n");
+ slirp_redir_loop(net_slirp_redir_print, mon);
+}
+
+static void net_slirp_redir_rm(Monitor *mon, const char *port_str)
+{
+ int host_port;
+ char buf[256] = "";
+ const char *p = port_str;
+ int is_udp = 0;
+ int n;
+
+ if (!mon)
+ return;
+
+ if (!port_str || !port_str[0])
+ goto fail_syntax;
+
+ get_str_sep(buf, sizeof(buf), &p, ':');
+
+ if (!strcmp(buf, "tcp") || buf[0] == '\0') {
+ is_udp = 0;
+ } else if (!strcmp(buf, "udp")) {
+ is_udp = 1;
+ } else {
+ goto fail_syntax;
+ }
+
+ host_port = atoi(p);
+
+ n = slirp_redir_rm(is_udp, host_port);
+
+ monitor_printf(mon, "removed %d redirections to %s port %d\n", n,
+ is_udp ? "udp" : "tcp", host_port);
+ return;
+
+ fail_syntax:
+ monitor_printf(mon, "invalid format\n");
+}
+
+void net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2)
{
int is_udp;
char buf[256], *r;
@@ -616,6 +691,16 @@ void net_slirp_redir(Monitor *mon, const char *redir_str)
slirp_init(slirp_restrict, slirp_ip);
}
+ if (!strcmp(redir_str, "remove")) {
+ net_slirp_redir_rm(mon, redir_opt2);
+ return;
+ }
+
+ if (!strcmp(redir_str, "list")) {
+ net_slirp_redir_list(mon);
+ return;
+ }
+
p = redir_str;
if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)
goto fail_syntax;
@@ -2027,8 +2112,7 @@ int net_client_init(const char *device, const char *p)
int idx = nic_get_free_idx();
if (check_params(nic_params, p) < 0) {
- fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
- buf, p);
+ fprintf(stderr, "qemu: invalid parameter in '%s'\n", p);
return -1;
}
if (idx == -1 || nb_nics >= MAX_NICS) {
@@ -2078,8 +2162,7 @@ int net_client_init(const char *device, const char *p)
"vlan", "name", "hostname", "restrict", "ip", NULL
};
if (check_params(slirp_params, p) < 0) {
- fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
- buf, p);
+ fprintf(stderr, "qemu: invalid parameter in '%s'\n", p);
return -1;
}
if (get_param_value(buf, sizeof(buf), "hostname", p)) {
@@ -2129,8 +2212,7 @@ int net_client_init(const char *device, const char *p)
char ifname[64];
if (check_params(tap_params, p) < 0) {
- fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
- buf, p);
+ fprintf(stderr, "qemu: invalid parameter in '%s'\n", p);
return -1;
}
if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {
@@ -2150,8 +2232,7 @@ int net_client_init(const char *device, const char *p)
vlan->nb_host_devs++;
if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
if (check_params(fd_params, p) < 0) {
- fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
- buf, p);
+ fprintf(stderr, "qemu: invalid parameter in '%s'\n", p);
return -1;
}
fd = strtol(buf, NULL, 0);
@@ -2163,8 +2244,7 @@ int net_client_init(const char *device, const char *p)
"vlan", "name", "ifname", "script", "downscript", NULL
};
if (check_params(tap_params, p) < 0) {
- fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
- buf, p);
+ fprintf(stderr, "qemu: invalid parameter in '%s'\n", p);
return -1;
}
if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {
@@ -2184,8 +2264,7 @@ int net_client_init(const char *device, const char *p)
if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
int fd;
if (check_params(fd_params, p) < 0) {
- fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
- buf, p);
+ fprintf(stderr, "qemu: invalid parameter in '%s'\n", p);
return -1;
}
fd = strtol(buf, NULL, 0);
@@ -2197,8 +2276,7 @@ int net_client_init(const char *device, const char *p)
"vlan", "name", "listen", NULL
};
if (check_params(listen_params, p) < 0) {
- fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
- buf, p);
+ fprintf(stderr, "qemu: invalid parameter in '%s'\n", p);
return -1;
}
ret = net_socket_listen_init(vlan, device, name, buf);
@@ -2207,8 +2285,7 @@ int net_client_init(const char *device, const char *p)
"vlan", "name", "connect", NULL
};
if (check_params(connect_params, p) < 0) {
- fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
- buf, p);
+ fprintf(stderr, "qemu: invalid parameter in '%s'\n", p);
return -1;
}
ret = net_socket_connect_init(vlan, device, name, buf);
@@ -2217,8 +2294,7 @@ int net_client_init(const char *device, const char *p)
"vlan", "name", "mcast", NULL
};
if (check_params(mcast_params, p) < 0) {
- fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
- buf, p);
+ fprintf(stderr, "qemu: invalid parameter in '%s'\n", p);
return -1;
}
ret = net_socket_mcast_init(vlan, device, name, buf);
@@ -2238,8 +2314,7 @@ int net_client_init(const char *device, const char *p)
int vde_port, vde_mode;
if (check_params(vde_params, p) < 0) {
- fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
- buf, p);
+ fprintf(stderr, "qemu: invalid parameter in '%s'\n", p);
return -1;
}
vlan->nb_host_devs++;
diff --git a/net.h b/net.h
index 3d0b6f2bd..8600e7eed 100644
--- a/net.h
+++ b/net.h
@@ -119,7 +119,7 @@ int net_client_init(const char *device, const char *p);
void net_client_uninit(NICInfo *nd);
int net_client_parse(const char *str);
void net_slirp_smb(const char *exported_dir);
-void net_slirp_redir(Monitor *mon, const char *redir_str);
+void net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2);
void net_cleanup(void);
int slirp_is_inited(void);
void net_client_check(void);
diff --git a/keymaps/ar b/pc-bios/keymaps/ar
index c430c03bb..c430c03bb 100644
--- a/keymaps/ar
+++ b/pc-bios/keymaps/ar
diff --git a/keymaps/common b/pc-bios/keymaps/common
index adc56c77d..adc56c77d 100644
--- a/keymaps/common
+++ b/pc-bios/keymaps/common
diff --git a/keymaps/da b/pc-bios/keymaps/da
index 3884dcf14..3884dcf14 100644
--- a/keymaps/da
+++ b/pc-bios/keymaps/da
diff --git a/keymaps/de b/pc-bios/keymaps/de
index ed929c743..ed929c743 100644
--- a/keymaps/de
+++ b/pc-bios/keymaps/de
diff --git a/keymaps/de-ch b/pc-bios/keymaps/de-ch
index 852f8b8db..852f8b8db 100644
--- a/keymaps/de-ch
+++ b/pc-bios/keymaps/de-ch
diff --git a/keymaps/en-gb b/pc-bios/keymaps/en-gb
index b45f06c7c..b45f06c7c 100644
--- a/keymaps/en-gb
+++ b/pc-bios/keymaps/en-gb
diff --git a/keymaps/en-us b/pc-bios/keymaps/en-us
index f5784bbb3..f5784bbb3 100644
--- a/keymaps/en-us
+++ b/pc-bios/keymaps/en-us
diff --git a/keymaps/es b/pc-bios/keymaps/es
index 0c29eec5a..0c29eec5a 100644
--- a/keymaps/es
+++ b/pc-bios/keymaps/es
diff --git a/keymaps/et b/pc-bios/keymaps/et
index 85541a377..85541a377 100644
--- a/keymaps/et
+++ b/pc-bios/keymaps/et
diff --git a/keymaps/fi b/pc-bios/keymaps/fi
index 2a4e0f045..2a4e0f045 100644
--- a/keymaps/fi
+++ b/pc-bios/keymaps/fi
diff --git a/keymaps/fo b/pc-bios/keymaps/fo
index c00d9d4de..c00d9d4de 100644
--- a/keymaps/fo
+++ b/pc-bios/keymaps/fo
diff --git a/keymaps/fr b/pc-bios/keymaps/fr
index ba5a176c3..ba5a176c3 100644
--- a/keymaps/fr
+++ b/pc-bios/keymaps/fr
diff --git a/keymaps/fr-be b/pc-bios/keymaps/fr-be
index 62f71286e..62f71286e 100644
--- a/keymaps/fr-be
+++ b/pc-bios/keymaps/fr-be
diff --git a/keymaps/fr-ca b/pc-bios/keymaps/fr-ca
index b645208e4..b645208e4 100644
--- a/keymaps/fr-ca
+++ b/pc-bios/keymaps/fr-ca
diff --git a/keymaps/fr-ch b/pc-bios/keymaps/fr-ch
index 4620d2033..4620d2033 100644
--- a/keymaps/fr-ch
+++ b/pc-bios/keymaps/fr-ch
diff --git a/keymaps/hr b/pc-bios/keymaps/hr
index 613aa6925..613aa6925 100644
--- a/keymaps/hr
+++ b/pc-bios/keymaps/hr
diff --git a/keymaps/hu b/pc-bios/keymaps/hu
index 8aba44441..8aba44441 100644
--- a/keymaps/hu
+++ b/pc-bios/keymaps/hu
diff --git a/keymaps/is b/pc-bios/keymaps/is
index 21dc1fd3c..21dc1fd3c 100644
--- a/keymaps/is
+++ b/pc-bios/keymaps/is
diff --git a/keymaps/it b/pc-bios/keymaps/it
index 00ca73a3e..00ca73a3e 100644
--- a/keymaps/it
+++ b/pc-bios/keymaps/it
diff --git a/keymaps/ja b/pc-bios/keymaps/ja
index 9d90a78c8..9d90a78c8 100644
--- a/keymaps/ja
+++ b/pc-bios/keymaps/ja
diff --git a/keymaps/lt b/pc-bios/keymaps/lt
index 3d9d619ea..3d9d619ea 100644
--- a/keymaps/lt
+++ b/pc-bios/keymaps/lt
diff --git a/keymaps/lv b/pc-bios/keymaps/lv
index 1d9172791..1d9172791 100644
--- a/keymaps/lv
+++ b/pc-bios/keymaps/lv
diff --git a/keymaps/mk b/pc-bios/keymaps/mk
index 18c150484..18c150484 100644
--- a/keymaps/mk
+++ b/pc-bios/keymaps/mk
diff --git a/keymaps/modifiers b/pc-bios/keymaps/modifiers
index d73b7a663..d73b7a663 100644
--- a/keymaps/modifiers
+++ b/pc-bios/keymaps/modifiers
diff --git a/keymaps/nl b/pc-bios/keymaps/nl
index b4892f930..b4892f930 100644
--- a/keymaps/nl
+++ b/pc-bios/keymaps/nl
diff --git a/keymaps/nl-be b/pc-bios/keymaps/nl-be
index 34fc881ad..34fc881ad 100644
--- a/keymaps/nl-be
+++ b/pc-bios/keymaps/nl-be
diff --git a/keymaps/no b/pc-bios/keymaps/no
index 40a64790d..40a64790d 100644
--- a/keymaps/no
+++ b/pc-bios/keymaps/no
diff --git a/keymaps/pl b/pc-bios/keymaps/pl
index 09c600d35..09c600d35 100644
--- a/keymaps/pl
+++ b/pc-bios/keymaps/pl
diff --git a/keymaps/pt b/pc-bios/keymaps/pt
index c6941f651..c6941f651 100644
--- a/keymaps/pt
+++ b/pc-bios/keymaps/pt
diff --git a/keymaps/pt-br b/pc-bios/keymaps/pt-br
index 54bafc5dc..54bafc5dc 100644
--- a/keymaps/pt-br
+++ b/pc-bios/keymaps/pt-br
diff --git a/keymaps/ru b/pc-bios/keymaps/ru
index b3e7d24de..b3e7d24de 100644
--- a/keymaps/ru
+++ b/pc-bios/keymaps/ru
diff --git a/keymaps/sl b/pc-bios/keymaps/sl
index 56835a92c..56835a92c 100644
--- a/keymaps/sl
+++ b/pc-bios/keymaps/sl
diff --git a/keymaps/sv b/pc-bios/keymaps/sv
index 5d9080eff..5d9080eff 100644
--- a/keymaps/sv
+++ b/pc-bios/keymaps/sv
diff --git a/keymaps/th b/pc-bios/keymaps/th
index b65b6da5d..b65b6da5d 100644
--- a/keymaps/th
+++ b/pc-bios/keymaps/th
diff --git a/keymaps/tr b/pc-bios/keymaps/tr
index 5650e1e93..5650e1e93 100644
--- a/keymaps/tr
+++ b/pc-bios/keymaps/tr
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 2b6461a3e..837c2a4e5 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -92,9 +92,11 @@ For system emulation, the following hardware targets are supported:
@item Gumstix "Connex" and "Verdex" motherboards (PXA255/270).
@item Siemens SX1 smartphone (OMAP310 processor)
@item Syborg SVP base model (ARM Cortex-A8).
+@item AXIS-Devboard88 (CRISv32 ETRAX-FS).
+@item Petalogix Spartan 3aDSP1800 MMU ref design (MicroBlaze).
@end itemize
-For user emulation, x86, PowerPC, ARM, 32-bit MIPS, Sparc32/64 and ColdFire(m68k) CPUs are supported.
+For user emulation, x86, PowerPC, ARM, 32-bit MIPS, Sparc32/64, ColdFire(m68k), CRISv32 and MicroBlaze CPUs are supported.
@node Installation
@chapter Installation
diff --git a/savevm.c b/savevm.c
index 68ffd03e6..248aea3ed 100644
--- a/savevm.c
+++ b/savevm.c
@@ -244,7 +244,6 @@ QEMUFile *qemu_popen(FILE *popen_file, const char *mode)
} else {
s->file = qemu_fopen_ops(s, popen_put_buffer, NULL, popen_close, NULL, NULL);
}
- fprintf(stderr, "qemu_popen: returning result of qemu_fopen_ops\n");
return s->file;
}
@@ -260,6 +259,17 @@ QEMUFile *qemu_popen_cmd(const char *command, const char *mode)
return qemu_popen(popen_file, mode);
}
+int qemu_popen_fd(QEMUFile *f)
+{
+ QEMUFilePopen *p;
+ int fd;
+
+ p = (QEMUFilePopen *)f->opaque;
+ fd = fileno(p->popen_file);
+
+ return fd;
+}
+
QEMUFile *qemu_fopen_socket(int fd)
{
QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket));
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index a1cd70e97..b2313b43c 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -18,6 +18,11 @@ void slirp_input(const uint8_t *pkt, int pkt_len);
int slirp_can_output(void);
void slirp_output(const uint8_t *pkt, int pkt_len);
+void slirp_redir_loop(void (*func)(void *opaque, int is_udp,
+ struct in_addr *laddr, u_int lport,
+ struct in_addr *faddr, u_int fport),
+ void *opaque);
+int slirp_redir_rm(int is_udp, int host_port);
int slirp_redir(int is_udp, int host_port,
struct in_addr guest_addr, int guest_port);
int slirp_add_exec(int do_pty, const void *args, int addr_low_byte,
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 04d3dede2..9cab73124 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -734,6 +734,53 @@ void if_encap(const uint8_t *ip_data, int ip_data_len)
}
}
+static void _slirp_redir_loop(void (*func)(void *opaque, int is_udp,
+ struct in_addr *laddr, u_int lport,
+ struct in_addr *faddr, u_int fport),
+ void *opaque, int is_udp)
+{
+ struct socket *head = (is_udp ? &udb : &tcb);
+ struct socket *so;
+
+ for (so = head->so_next; so != head; so = so->so_next) {
+ func(opaque, is_udp,
+ &so->so_laddr, ntohs(so->so_lport),
+ &so->so_faddr, ntohs(so->so_fport));
+ }
+}
+
+void slirp_redir_loop(void (*func)(void *opaque, int is_udp,
+ struct in_addr *laddr, u_int lport,
+ struct in_addr *faddr, u_int fport),
+ void *opaque)
+{
+ _slirp_redir_loop(func, opaque, 0);
+ _slirp_redir_loop(func, opaque, 1);
+}
+
+/* Unlistens a redirection
+ *
+ * Return value: number of redirs removed */
+int slirp_redir_rm(int is_udp, int host_port)
+{
+ struct socket *so;
+ struct socket *head = (is_udp ? &udb : &tcb);
+ int fport = htons(host_port);
+ int n = 0;
+
+ loop_again:
+ for (so = head->so_next; so != head; so = so->so_next) {
+ if (so->so_fport == fport) {
+ close(so->s);
+ sofree(so);
+ n++;
+ goto loop_again;
+ }
+ }
+
+ return n;
+}
+
int slirp_redir(int is_udp, int host_port,
struct in_addr guest_addr, int guest_port)
{
diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h
new file mode 100644
index 000000000..97f708c5a
--- /dev/null
+++ b/target-microblaze/cpu.h
@@ -0,0 +1,311 @@
+/*
+ * MicroBlaze virtual CPU header
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+#ifndef CPU_MICROBLAZE_H
+#define CPU_MICROBLAZE_H
+
+#define TARGET_LONG_BITS 32
+
+#define CPUState struct CPUMBState
+
+#include "cpu-defs.h"
+struct CPUMBState;
+#if !defined(CONFIG_USER_ONLY)
+#include "mmu.h"
+#endif
+
+#define TARGET_HAS_ICE 1
+
+#define ELF_MACHINE EM_XILINX_MICROBLAZE
+
+#define EXCP_NMI 1
+#define EXCP_MMU 2
+#define EXCP_IRQ 3
+#define EXCP_BREAK 4
+#define EXCP_HW_BREAK 5
+
+/* Register aliases. R0 - R15 */
+#define R_SP 1
+#define SR_PC 0
+#define SR_MSR 1
+#define SR_EAR 3
+#define SR_ESR 5
+#define SR_FSR 7
+#define SR_BTR 0xb
+#define SR_EDR 0xd
+
+/* MSR flags. */
+#define MSR_BE (1<<0) /* 0x001 */
+#define MSR_IE (1<<1) /* 0x002 */
+#define MSR_C (1<<2) /* 0x004 */
+#define MSR_BIP (1<<3) /* 0x008 */
+#define MSR_FSL (1<<4) /* 0x010 */
+#define MSR_ICE (1<<5) /* 0x020 */
+#define MSR_DZ (1<<6) /* 0x040 */
+#define MSR_DCE (1<<7) /* 0x080 */
+#define MSR_EE (1<<8) /* 0x100 */
+#define MSR_EIP (1<<9) /* 0x200 */
+#define MSR_CC (1<<31)
+
+/* Machine State Register (MSR) Fields */
+#define MSR_UM (1<<11) /* User Mode */
+#define MSR_UMS (1<<12) /* User Mode Save */
+#define MSR_VM (1<<13) /* Virtual Mode */
+#define MSR_VMS (1<<14) /* Virtual Mode Save */
+
+#define MSR_KERNEL MSR_EE|MSR_VM
+//#define MSR_USER MSR_KERNEL|MSR_UM|MSR_IE
+#define MSR_KERNEL_VMS MSR_EE|MSR_VMS
+//#define MSR_USER_VMS MSR_KERNEL_VMS|MSR_UMS|MSR_IE
+
+/* Exception State Register (ESR) Fields */
+#define ESR_DIZ (1<<11) /* Zone Protection */
+#define ESR_S (1<<10) /* Store instruction */
+
+
+
+/* Version reg. */
+/* Basic PVR mask */
+#define PVR0_PVR_FULL_MASK 0x80000000
+#define PVR0_USE_BARREL_MASK 0x40000000
+#define PVR0_USE_DIV_MASK 0x20000000
+#define PVR0_USE_HW_MUL_MASK 0x10000000
+#define PVR0_USE_FPU_MASK 0x08000000
+#define PVR0_USE_EXC_MASK 0x04000000
+#define PVR0_USE_ICACHE_MASK 0x02000000
+#define PVR0_USE_DCACHE_MASK 0x01000000
+#define PVR0_USE_MMU 0x00800000 /* new */
+#define PVR0_VERSION_MASK 0x0000FF00
+#define PVR0_USER1_MASK 0x000000FF
+
+/* User 2 PVR mask */
+#define PVR1_USER2_MASK 0xFFFFFFFF
+
+/* Configuration PVR masks */
+#define PVR2_D_OPB_MASK 0x80000000
+#define PVR2_D_LMB_MASK 0x40000000
+#define PVR2_I_OPB_MASK 0x20000000
+#define PVR2_I_LMB_MASK 0x10000000
+#define PVR2_INTERRUPT_IS_EDGE_MASK 0x08000000
+#define PVR2_EDGE_IS_POSITIVE_MASK 0x04000000
+#define PVR2_D_PLB_MASK 0x02000000 /* new */
+#define PVR2_I_PLB_MASK 0x01000000 /* new */
+#define PVR2_INTERCONNECT 0x00800000 /* new */
+#define PVR2_USE_EXTEND_FSL 0x00080000 /* new */
+#define PVR2_USE_FSL_EXC 0x00040000 /* new */
+#define PVR2_USE_MSR_INSTR 0x00020000
+#define PVR2_USE_PCMP_INSTR 0x00010000
+#define PVR2_AREA_OPTIMISED 0x00008000
+#define PVR2_USE_BARREL_MASK 0x00004000
+#define PVR2_USE_DIV_MASK 0x00002000
+#define PVR2_USE_HW_MUL_MASK 0x00001000
+#define PVR2_USE_FPU_MASK 0x00000800
+#define PVR2_USE_MUL64_MASK 0x00000400
+#define PVR2_USE_FPU2_MASK 0x00000200 /* new */
+#define PVR2_USE_IPLBEXC 0x00000100
+#define PVR2_USE_DPLBEXC 0x00000080
+#define PVR2_OPCODE_0x0_ILL_MASK 0x00000040
+#define PVR2_UNALIGNED_EXC_MASK 0x00000020
+#define PVR2_ILL_OPCODE_EXC_MASK 0x00000010
+#define PVR2_IOPB_BUS_EXC_MASK 0x00000008
+#define PVR2_DOPB_BUS_EXC_MASK 0x00000004
+#define PVR2_DIV_ZERO_EXC_MASK 0x00000002
+#define PVR2_FPU_EXC_MASK 0x00000001
+
+/* Debug and exception PVR masks */
+#define PVR3_DEBUG_ENABLED_MASK 0x80000000
+#define PVR3_NUMBER_OF_PC_BRK_MASK 0x1E000000
+#define PVR3_NUMBER_OF_RD_ADDR_BRK_MASK 0x00380000
+#define PVR3_NUMBER_OF_WR_ADDR_BRK_MASK 0x0000E000
+#define PVR3_FSL_LINKS_MASK 0x00000380
+
+/* ICache config PVR masks */
+#define PVR4_USE_ICACHE_MASK 0x80000000
+#define PVR4_ICACHE_ADDR_TAG_BITS_MASK 0x7C000000
+#define PVR4_ICACHE_USE_FSL_MASK 0x02000000
+#define PVR4_ICACHE_ALLOW_WR_MASK 0x01000000
+#define PVR4_ICACHE_LINE_LEN_MASK 0x00E00000
+#define PVR4_ICACHE_BYTE_SIZE_MASK 0x001F0000
+
+/* DCache config PVR masks */
+#define PVR5_USE_DCACHE_MASK 0x80000000
+#define PVR5_DCACHE_ADDR_TAG_BITS_MASK 0x7C000000
+#define PVR5_DCACHE_USE_FSL_MASK 0x02000000
+#define PVR5_DCACHE_ALLOW_WR_MASK 0x01000000
+#define PVR5_DCACHE_LINE_LEN_MASK 0x00E00000
+#define PVR5_DCACHE_BYTE_SIZE_MASK 0x001F0000
+
+/* ICache base address PVR mask */
+#define PVR6_ICACHE_BASEADDR_MASK 0xFFFFFFFF
+
+/* ICache high address PVR mask */
+#define PVR7_ICACHE_HIGHADDR_MASK 0xFFFFFFFF
+
+/* DCache base address PVR mask */
+#define PVR8_DCACHE_BASEADDR_MASK 0xFFFFFFFF
+
+/* DCache high address PVR mask */
+#define PVR9_DCACHE_HIGHADDR_MASK 0xFFFFFFFF
+
+/* Target family PVR mask */
+#define PVR10_TARGET_FAMILY_MASK 0xFF000000
+
+/* MMU descrtiption */
+#define PVR11_USE_MMU 0xC0000000
+#define PVR11_MMU_ITLB_SIZE 0x38000000
+#define PVR11_MMU_DTLB_SIZE 0x07000000
+#define PVR11_MMU_TLB_ACCESS 0x00C00000
+#define PVR11_MMU_ZONES 0x003C0000
+/* MSR Reset value PVR mask */
+#define PVR11_MSR_RESET_VALUE_MASK 0x000007FF
+
+
+
+/* CPU flags. */
+
+/* Condition codes. */
+#define CC_GE 5
+#define CC_GT 4
+#define CC_LE 3
+#define CC_LT 2
+#define CC_NE 1
+#define CC_EQ 0
+
+#define NB_MMU_MODES 3
+typedef struct CPUMBState {
+ uint32_t debug;
+ uint32_t btaken;
+ uint32_t btarget;
+ uint32_t bimm;
+
+ uint32_t imm;
+ uint32_t regs[33];
+ uint32_t sregs[24];
+
+ /* Internal flags. */
+#define IMM_FLAG 4
+#define DRTI_FLAG (1 << 16)
+#define DRTE_FLAG (1 << 17)
+#define DRTB_FLAG (1 << 18)
+#define D_FLAG (1 << 19) /* Bit in ESR. */
+/* TB dependant CPUState. */
+#define IFLAGS_TB_MASK (D_FLAG | IMM_FLAG | DRTI_FLAG | DRTE_FLAG | DRTB_FLAG)
+ uint32_t iflags;
+
+ struct {
+ uint32_t regs[16];
+ } pvr;
+
+#if !defined(CONFIG_USER_ONLY)
+ /* Unified MMU. */
+ struct microblaze_mmu mmu;
+#endif
+
+ CPU_COMMON
+} CPUMBState;
+
+CPUState *cpu_mb_init(const char *cpu_model);
+int cpu_mb_exec(CPUState *s);
+void cpu_mb_close(CPUState *s);
+void do_interrupt(CPUState *env);
+/* you can call this signal handler from your SIGBUS and SIGSEGV
+ signal handlers to inform the virtual CPU of exceptions. non zero
+ is returned if the signal was handled by the virtual CPU. */
+int cpu_mb_signal_handler(int host_signum, void *pinfo,
+ void *puc);
+
+enum {
+ CC_OP_DYNAMIC, /* Use env->cc_op */
+ CC_OP_FLAGS,
+ CC_OP_CMP,
+};
+
+/* FIXME: MB uses variable pages down to 1K but linux only uses 4k. */
+#define TARGET_PAGE_BITS 12
+#define MMAP_SHIFT TARGET_PAGE_BITS
+
+#define cpu_init cpu_mb_init
+#define cpu_exec cpu_mb_exec
+#define cpu_gen_code cpu_mb_gen_code
+#define cpu_signal_handler cpu_mb_signal_handler
+
+#define CPU_SAVE_VERSION 1
+
+/* MMU modes definitions */
+#define MMU_MODE0_SUFFIX _nommu
+#define MMU_MODE1_SUFFIX _kernel
+#define MMU_MODE2_SUFFIX _user
+#define MMU_NOMMU_IDX 0
+#define MMU_KERNEL_IDX 1
+#define MMU_USER_IDX 2
+/* See NB_MMU_MODES further up the file. */
+
+static inline int cpu_mmu_index (CPUState *env)
+{
+ /* Are we in nommu mode?. */
+ if (!(env->sregs[SR_MSR] & MSR_VM))
+ return MMU_NOMMU_IDX;
+
+ if (env->sregs[SR_MSR] & MSR_UM)
+ return MMU_USER_IDX;
+ return MMU_KERNEL_IDX;
+}
+
+int cpu_mb_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+ int mmu_idx, int is_softmmu);
+
+#if defined(CONFIG_USER_ONLY)
+static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
+{
+ if (newsp)
+ env->regs[R_SP] = newsp;
+ env->regs[3] = 0;
+}
+#endif
+
+static inline void cpu_set_tls(CPUState *env, target_ulong newtls)
+{
+}
+
+static inline int cpu_interrupts_enabled(CPUState *env)
+{
+ return env->sregs[SR_MSR] & MSR_IE;
+}
+
+#include "cpu-all.h"
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+ env->sregs[SR_PC] = tb->pc;
+}
+
+static inline target_ulong cpu_get_pc(CPUState *env)
+{
+ return env->sregs[SR_PC];
+}
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+ target_ulong *cs_base, int *flags)
+{
+ *pc = env->sregs[SR_PC];
+ *cs_base = 0;
+ *flags = env->iflags & IFLAGS_TB_MASK;
+}
+#endif
diff --git a/target-microblaze/exec.h b/target-microblaze/exec.h
new file mode 100644
index 000000000..55045bb92
--- /dev/null
+++ b/target-microblaze/exec.h
@@ -0,0 +1,57 @@
+/*
+ * Microblaze execution defines
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+#include "dyngen-exec.h"
+
+register struct CPUMBState *env asm(AREG0);
+
+#include "cpu.h"
+#include "exec-all.h"
+
+static inline void env_to_regs(void)
+{
+}
+
+static inline void regs_to_env(void)
+{
+}
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif
+
+void cpu_mb_flush_flags(CPUMBState *env, int cc_op);
+
+static inline int cpu_has_work(CPUState *env)
+{
+ return (env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI));
+}
+
+static inline int cpu_halted(CPUState *env) {
+ if (!env->halted)
+ return 0;
+
+ /* IRQ, NMI and GURU execeptions wakes us up. */
+ if (env->interrupt_request
+ & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI)) {
+ env->halted = 0;
+ return 0;
+ }
+ return EXCP_HALTED;
+}
diff --git a/target-microblaze/helper.c b/target-microblaze/helper.c
new file mode 100644
index 000000000..00936594d
--- /dev/null
+++ b/target-microblaze/helper.c
@@ -0,0 +1,255 @@
+/*
+ * MicroBlaze helper routines.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "config.h"
+#include "cpu.h"
+#include "exec-all.h"
+#include "host-utils.h"
+
+#define D(x)
+#define DMMU(x)
+
+#if defined(CONFIG_USER_ONLY)
+
+void do_interrupt (CPUState *env)
+{
+ env->exception_index = -1;
+ env->regs[14] = env->sregs[SR_PC];
+}
+
+int cpu_mb_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
+ int mmu_idx, int is_softmmu)
+{
+ env->exception_index = 0xaa;
+ 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;
+}
+
+#else /* !CONFIG_USER_ONLY */
+
+int cpu_mb_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+ int mmu_idx, int is_softmmu)
+{
+ unsigned int hit;
+ unsigned int mmu_available;
+ int r = 1;
+ int prot;
+
+ mmu_available = 0;
+ if (env->pvr.regs[0] & PVR0_USE_MMU) {
+ mmu_available = 1;
+ if ((env->pvr.regs[0] & PVR0_PVR_FULL_MASK)
+ && (env->pvr.regs[11] & PVR11_USE_MMU) != PVR11_USE_MMU) {
+ mmu_available = 0;
+ }
+ }
+
+ /* Translate if the MMU is available and enabled. */
+ if (mmu_available && (env->sregs[SR_MSR] & MSR_VM)) {
+ target_ulong vaddr, paddr;
+ struct microblaze_mmu_lookup lu;
+
+ hit = mmu_translate(&env->mmu, &lu, address, rw, mmu_idx);
+ if (hit) {
+ vaddr = address & TARGET_PAGE_MASK;
+ paddr = lu.paddr + vaddr - lu.vaddr;
+
+ DMMU(qemu_log("MMU map mmu=%d v=%x p=%x prot=%x\n",
+ mmu_idx, vaddr, paddr, lu.prot));
+ r = tlb_set_page(env, vaddr,
+ paddr, lu.prot, mmu_idx, is_softmmu);
+ } else {
+ env->sregs[SR_EAR] = address;
+ DMMU(qemu_log("mmu=%d miss addr=%x\n", mmu_idx, vaddr));
+
+ switch (lu.err) {
+ case ERR_PROT:
+ env->sregs[SR_ESR] = rw == 2 ? 17 : 16;
+ env->sregs[SR_ESR] |= (rw == 1) << 10;
+ break;
+ case ERR_MISS:
+ env->sregs[SR_ESR] = rw == 2 ? 19 : 18;
+ env->sregs[SR_ESR] |= (rw == 1) << 10;
+ break;
+ default:
+ abort();
+ break;
+ }
+
+ if (env->exception_index == EXCP_MMU) {
+ cpu_abort(env, "recursive faults\n");
+ }
+
+ /* TLB miss. */
+ env->exception_index = EXCP_MMU;
+ }
+ } else {
+ /* MMU disabled or not available. */
+ address &= TARGET_PAGE_MASK;
+ prot = PAGE_BITS;
+ r = tlb_set_page(env, address, address, prot, mmu_idx, is_softmmu);
+ }
+ return r;
+}
+
+void do_interrupt(CPUState *env)
+{
+ uint32_t t;
+
+ /* IMM flag cannot propagate accross a branch and into the dslot. */
+ assert(!((env->iflags & D_FLAG) && (env->iflags & IMM_FLAG)));
+ assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG)));
+/* assert(env->sregs[SR_MSR] & (MSR_EE)); Only for HW exceptions. */
+ switch (env->exception_index) {
+ case EXCP_MMU:
+ env->regs[17] = env->sregs[SR_PC];
+
+ /* Exception breaks branch + dslot sequence? */
+ if (env->iflags & D_FLAG) {
+ D(qemu_log("D_FLAG set at exception bimm=%d\n", env->bimm));
+ env->sregs[SR_ESR] |= 1 << 12 ;
+ env->sregs[SR_BTR] = env->btarget;
+
+ /* Reexecute the branch. */
+ env->regs[17] -= 4;
+ /* was the branch immprefixed?. */
+ if (env->bimm) {
+ qemu_log_mask(CPU_LOG_INT,
+ "bimm exception at pc=%x iflags=%x\n",
+ env->sregs[SR_PC], env->iflags);
+ env->regs[17] -= 4;
+ log_cpu_state_mask(CPU_LOG_INT, env, 0);
+ }
+ } else if (env->iflags & IMM_FLAG) {
+ D(qemu_log("IMM_FLAG set at exception\n"));
+ env->regs[17] -= 4;
+ }
+
+ /* Disable the MMU. */
+ t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
+ env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
+ env->sregs[SR_MSR] |= t;
+ /* Exception in progress. */
+ env->sregs[SR_MSR] |= MSR_EIP;
+
+ qemu_log_mask(CPU_LOG_INT,
+ "exception at pc=%x ear=%x iflags=%x\n",
+ env->sregs[SR_PC], env->sregs[SR_EAR], env->iflags);
+ log_cpu_state_mask(CPU_LOG_INT, env, 0);
+ env->iflags &= ~(IMM_FLAG | D_FLAG);
+ env->sregs[SR_PC] = 0x20;
+ break;
+
+ case EXCP_IRQ:
+ assert(!(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP)));
+ assert(env->sregs[SR_MSR] & MSR_IE);
+ assert(!(env->iflags & D_FLAG));
+
+ t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
+
+#if 0
+#include "disas.h"
+
+/* Useful instrumentation when debugging interrupt issues in either
+ the models or in sw. */
+ {
+ const char *sym;
+
+ sym = lookup_symbol(env->sregs[SR_PC]);
+ if (sym
+ && (!strcmp("netif_rx", sym)
+ || !strcmp("process_backlog", sym))) {
+
+ qemu_log(
+ "interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n",
+ env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags,
+ sym);
+
+ log_cpu_state(env, 0);
+ }
+ }
+#endif
+ qemu_log_mask(CPU_LOG_INT,
+ "interrupt at pc=%x msr=%x %x iflags=%x\n",
+ env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags);
+
+ env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM \
+ | MSR_UM | MSR_IE);
+ env->sregs[SR_MSR] |= t;
+
+ env->regs[14] = env->sregs[SR_PC];
+ env->sregs[SR_PC] = 0x10;
+ //log_cpu_state_mask(CPU_LOG_INT, env, 0);
+ break;
+
+ case EXCP_BREAK:
+ case EXCP_HW_BREAK:
+ assert(!(env->iflags & IMM_FLAG));
+ assert(!(env->iflags & D_FLAG));
+ t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
+ qemu_log_mask(CPU_LOG_INT,
+ "break at pc=%x msr=%x %x iflags=%x\n",
+ env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags);
+ log_cpu_state_mask(CPU_LOG_INT, env, 0);
+ env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
+ env->sregs[SR_MSR] |= t;
+ env->sregs[SR_MSR] |= MSR_BIP;
+ if (env->exception_index == EXCP_HW_BREAK) {
+ env->regs[16] = env->sregs[SR_PC];
+ env->sregs[SR_MSR] |= MSR_BIP;
+ env->sregs[SR_PC] = 0x18;
+ } else
+ env->sregs[SR_PC] = env->btarget;
+ break;
+ default:
+ cpu_abort(env, "unhandled exception type=%d\n",
+ env->exception_index);
+ break;
+ }
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
+{
+ target_ulong vaddr, paddr = 0;
+ struct microblaze_mmu_lookup lu;
+ unsigned int hit;
+
+ if (env->sregs[SR_MSR] & MSR_VM) {
+ hit = mmu_translate(&env->mmu, &lu, addr, 0, 0);
+ if (hit) {
+ vaddr = addr & TARGET_PAGE_MASK;
+ paddr = lu.paddr + vaddr - lu.vaddr;
+ } else
+ paddr = 0; /* ???. */
+ } else
+ paddr = addr & TARGET_PAGE_MASK;
+
+ return paddr;
+}
+#endif
diff --git a/target-microblaze/helper.h b/target-microblaze/helper.h
new file mode 100644
index 000000000..8c5361ecd
--- /dev/null
+++ b/target-microblaze/helper.h
@@ -0,0 +1,19 @@
+#include "def-helper.h"
+
+DEF_HELPER_1(raise_exception, void, i32)
+DEF_HELPER_0(debug, void)
+DEF_HELPER_4(addkc, i32, i32, i32, i32, i32)
+DEF_HELPER_4(subkc, i32, i32, i32, i32, i32)
+DEF_HELPER_2(cmp, i32, i32, i32)
+DEF_HELPER_2(cmpu, i32, i32, i32)
+
+DEF_HELPER_2(divs, i32, i32, i32)
+DEF_HELPER_2(divu, i32, i32, i32)
+
+DEF_HELPER_FLAGS_2(pcmpbf, TCG_CALL_PURE | TCG_CALL_CONST, i32, i32, i32)
+#if !defined(CONFIG_USER_ONLY)
+DEF_HELPER_1(mmu_read, i32, i32)
+DEF_HELPER_2(mmu_write, void, i32, i32)
+#endif
+
+#include "def-helper.h"
diff --git a/target-microblaze/machine.c b/target-microblaze/machine.c
new file mode 100644
index 000000000..1be1c351b
--- /dev/null
+++ b/target-microblaze/machine.c
@@ -0,0 +1,11 @@
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+ return 0;
+}
diff --git a/target-microblaze/microblaze-decode.h b/target-microblaze/microblaze-decode.h
new file mode 100644
index 000000000..27b01288c
--- /dev/null
+++ b/target-microblaze/microblaze-decode.h
@@ -0,0 +1,52 @@
+/*
+ * MicroBlaze insn decoding macros.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+
+/* Convenient binary macros. */
+#define HEX__(n) 0x##n##LU
+#define B8__(x) ((x&0x0000000FLU)?1:0) \
+ + ((x&0x000000F0LU)?2:0) \
+ + ((x&0x00000F00LU)?4:0) \
+ + ((x&0x0000F000LU)?8:0) \
+ + ((x&0x000F0000LU)?16:0) \
+ + ((x&0x00F00000LU)?32:0) \
+ + ((x&0x0F000000LU)?64:0) \
+ + ((x&0xF0000000LU)?128:0)
+#define B8(d) ((unsigned char)B8__(HEX__(d)))
+
+/* Decode logic, mask and value. */
+#define DEC_ADD {B8(00000000), B8(00110001)}
+#define DEC_SUB {B8(00000001), B8(00110001)}
+#define DEC_AND {B8(00100001), B8(00110101)}
+#define DEC_XOR {B8(00100010), B8(00110111)}
+#define DEC_OR {B8(00100000), B8(00110111)}
+#define DEC_BIT {B8(00100100), B8(00111111)}
+#define DEC_MSR {B8(00100101), B8(00111111)}
+
+#define DEC_BARREL {B8(00010001), B8(00110111)}
+#define DEC_MUL {B8(00010000), B8(00110111)}
+#define DEC_DIV {B8(00010010), B8(00110111)}
+
+#define DEC_LD {B8(00110000), B8(00110100)}
+#define DEC_ST {B8(00110100), B8(00110100)}
+#define DEC_IMM {B8(00101100), B8(00111111)}
+
+#define DEC_BR {B8(00100110), B8(00110111)}
+#define DEC_BCC {B8(00100111), B8(00110111)}
+#define DEC_RTS {B8(00101101), B8(00111111)}
diff --git a/target-microblaze/mmu.c b/target-microblaze/mmu.c
new file mode 100644
index 000000000..d14373ce4
--- /dev/null
+++ b/target-microblaze/mmu.c
@@ -0,0 +1,257 @@
+/*
+ * Microblaze MMU emulation for qemu.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "config.h"
+#include "cpu.h"
+#include "exec-all.h"
+
+#define D(x)
+
+static unsigned int tlb_decode_size(unsigned int f)
+{
+ static const unsigned int sizes[] = {
+ 1 * 1024, 4 * 1024, 16 * 1024, 64 * 1024, 256 * 1024,
+ 1 * 1024 * 1024, 4 * 1024 * 1024, 16 * 1024 * 1024
+ };
+ assert(f < ARRAY_SIZE(sizes));
+ return sizes[f];
+}
+
+static void mmu_flush_idx(CPUState *env, unsigned int idx)
+{
+ struct microblaze_mmu *mmu = &env->mmu;
+ unsigned int tlb_size;
+ uint32_t tlb_tag, end, t;
+
+ t = mmu->rams[RAM_TAG][idx];
+ if (!(t & TLB_VALID))
+ return;
+
+ tlb_tag = t & TLB_EPN_MASK;
+ tlb_size = tlb_decode_size((t & TLB_PAGESZ_MASK) >> 7);
+ end = tlb_tag + tlb_size;
+
+ while (tlb_tag < end) {
+ tlb_flush_page(env, tlb_tag);
+ tlb_tag += TARGET_PAGE_SIZE;
+ }
+}
+
+static void mmu_change_pid(CPUState *env, unsigned int newpid)
+{
+ struct microblaze_mmu *mmu = &env->mmu;
+ unsigned int i;
+ unsigned int tlb_size;
+ uint32_t tlb_tag, mask, t;
+
+ if (newpid & ~0xff)
+ qemu_log("Illegal rpid=%x\n", newpid);
+
+ for (i = 0; i < ARRAY_SIZE(mmu->rams[RAM_TAG]); i++) {
+ /* Lookup and decode. */
+ t = mmu->rams[RAM_TAG][i];
+ if (t & TLB_VALID) {
+ tlb_size = tlb_decode_size((t & TLB_PAGESZ_MASK) >> 7);
+ mask = ~(tlb_size - 1);
+
+ tlb_tag = t & TLB_EPN_MASK;
+ if (mmu->tids[i] && ((mmu->regs[MMU_R_PID] & 0xff) == mmu->tids[i]))
+ mmu_flush_idx(env, i);
+ }
+ }
+}
+
+/* rw - 0 = read, 1 = write, 2 = fetch. */
+unsigned int mmu_translate(struct microblaze_mmu *mmu,
+ struct microblaze_mmu_lookup *lu,
+ target_ulong vaddr, int rw, int mmu_idx)
+{
+ unsigned int i, hit = 0;
+ unsigned int tlb_ex = 0, tlb_wr = 0, tlb_zsel;
+ unsigned int tlb_size;
+ uint32_t tlb_tag, tlb_rpn, mask, t0;
+
+ lu->err = ERR_MISS;
+ for (i = 0; i < ARRAY_SIZE(mmu->rams[RAM_TAG]); i++) {
+ uint32_t t, d;
+
+ /* Lookup and decode. */
+ t = mmu->rams[RAM_TAG][i];
+ D(qemu_log("TLB %d valid=%d\n", i, t & TLB_VALID));
+ if (t & TLB_VALID) {
+ tlb_size = tlb_decode_size((t & TLB_PAGESZ_MASK) >> 7);
+ if (tlb_size < TARGET_PAGE_SIZE) {
+ qemu_log("%d pages not supported\n", tlb_size);
+ abort();
+ }
+
+ mask = ~(tlb_size - 1);
+ tlb_tag = t & TLB_EPN_MASK;
+ if ((vaddr & mask) != (tlb_tag & mask)) {
+ D(qemu_log("TLB %d vaddr=%x != tag=%x\n",
+ i, vaddr & mask, tlb_tag & mask));
+ continue;
+ }
+ if (mmu->tids[i]
+ && ((mmu->regs[MMU_R_PID] & 0xff) != mmu->tids[i])) {
+ D(qemu_log("TLB %d pid=%x != tid=%x\n",
+ i, mmu->regs[MMU_R_PID], mmu->tids[i]));
+ continue;
+ }
+
+ /* Bring in the data part. */
+ d = mmu->rams[RAM_DATA][i];
+ tlb_ex = d & TLB_EX;
+ tlb_wr = d & TLB_WR;
+
+ /* Now lets see if there is a zone that overrides the protbits. */
+ tlb_zsel = (d >> 4) & 0xf;
+ t0 = mmu->regs[MMU_R_ZPR] >> (30 - (tlb_zsel * 2));
+ t0 &= 0x3;
+ switch (t0) {
+ case 0:
+ if (mmu_idx == MMU_USER_IDX)
+ continue;
+ break;
+ case 2:
+ if (mmu_idx != MMU_USER_IDX) {
+ tlb_ex = 1;
+ tlb_wr = 1;
+ }
+ break;
+ case 3:
+ tlb_ex = 1;
+ tlb_wr = 1;
+ break;
+ }
+
+
+ lu->err = ERR_PROT;
+ lu->prot = PAGE_READ;
+ if (tlb_wr)
+ lu->prot |= PAGE_WRITE;
+ else if (rw == 1)
+ goto done;
+ if (tlb_ex)
+ lu->prot |=PAGE_EXEC;
+ else if (rw == 2) {
+ goto done;
+ }
+
+ tlb_rpn = d & TLB_RPN_MASK;
+
+ lu->vaddr = tlb_tag;
+ lu->paddr = tlb_rpn;
+ lu->size = tlb_size;
+ lu->err = ERR_HIT;
+ lu->idx = i;
+ hit = 1;
+ goto done;
+ }
+ }
+done:
+ D(qemu_log("MMU vaddr=%x rw=%d tlb_wr=%d tlb_ex=%d hit=%d\n",
+ vaddr, rw, tlb_wr, tlb_ex, hit));
+ return hit;
+}
+
+/* Writes/reads to the MMU's special regs end up here. */
+uint32_t mmu_read(CPUState *env, uint32_t rn)
+{
+ unsigned int i;
+ uint32_t r;
+
+ switch (rn) {
+ /* Reads to HI/LO trig reads from the mmu rams. */
+ case MMU_R_TLBLO:
+ case MMU_R_TLBHI:
+ i = env->mmu.regs[MMU_R_TLBX] & 0xff;
+ r = env->mmu.rams[rn & 1][i];
+ if (rn == MMU_R_TLBHI)
+ env->mmu.regs[MMU_R_PID] = env->mmu.tids[i];
+ break;
+ default:
+ r = env->mmu.regs[rn];
+ break;
+ }
+ D(qemu_log("%s rn=%d=%x\n", __func__, rn, r));
+ return r;
+}
+
+void mmu_write(CPUState *env, uint32_t rn, uint32_t v)
+{
+ unsigned int i;
+ D(qemu_log("%s rn=%d=%x old=%x\n", __func__, rn, v, env->mmu.regs[rn]));
+
+ switch (rn) {
+ /* Writes to HI/LO trig writes to the mmu rams. */
+ case MMU_R_TLBLO:
+ case MMU_R_TLBHI:
+ i = env->mmu.regs[MMU_R_TLBX] & 0xff;
+ if (rn == MMU_R_TLBHI) {
+ if (i < 3 && !(v & TLB_VALID) && qemu_loglevel_mask(~0))
+ qemu_log("invalidating index %x at pc=%x\n",
+ i, env->sregs[SR_PC]);
+ env->mmu.tids[i] = env->mmu.regs[MMU_R_PID] & 0xff;
+ mmu_flush_idx(env, i);
+ }
+ env->mmu.rams[rn & 1][i] = v;
+
+ D(qemu_log("%s ram[%d][%d]=%x\n", __func__, rn & 1, i, v));
+ break;
+ case MMU_R_ZPR:
+ /* Changes to the zone protection reg flush the QEMU TLB.
+ Fortunately, these are very uncommon. */
+ if (v != env->mmu.regs[rn]) {
+ tlb_flush(env, 1);
+ }
+ env->mmu.regs[rn] = v;
+ break;
+ case MMU_R_PID:
+ if (v != env->mmu.regs[rn]) {
+ mmu_change_pid(env, v);
+ env->mmu.regs[rn] = v;
+ }
+ break;
+ case MMU_R_TLBSX:
+ {
+ struct microblaze_mmu_lookup lu;
+ int hit;
+ hit = mmu_translate(&env->mmu, &lu,
+ v & TLB_EPN_MASK, 0, cpu_mmu_index(env));
+ if (hit) {
+ env->mmu.regs[MMU_R_TLBX] = lu.idx;
+ } else
+ env->mmu.regs[MMU_R_TLBX] |= 0x80000000;
+ break;
+ }
+ default:
+ env->mmu.regs[rn] = v;
+ break;
+ }
+}
+
+void mmu_init(struct microblaze_mmu *mmu)
+{
+ memset(mmu, 0, sizeof *mmu);
+}
diff --git a/target-microblaze/mmu.h b/target-microblaze/mmu.h
new file mode 100644
index 000000000..975933396
--- /dev/null
+++ b/target-microblaze/mmu.h
@@ -0,0 +1,88 @@
+/*
+ * Microblaze MMU emulation for qemu.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+
+#define MMU_R_PID 0
+#define MMU_R_ZPR 1
+#define MMU_R_TLBX 2
+#define MMU_R_TLBLO 3
+#define MMU_R_TLBHI 4
+#define MMU_R_TLBSX 5
+
+#define RAM_DATA 1
+#define RAM_TAG 0
+
+/* Tag portion */
+#define TLB_EPN_MASK 0xFFFFFC00 /* Effective Page Number */
+#define TLB_PAGESZ_MASK 0x00000380
+#define TLB_PAGESZ(x) (((x) & 0x7) << 7)
+#define PAGESZ_1K 0
+#define PAGESZ_4K 1
+#define PAGESZ_16K 2
+#define PAGESZ_64K 3
+#define PAGESZ_256K 4
+#define PAGESZ_1M 5
+#define PAGESZ_4M 6
+#define PAGESZ_16M 7
+#define TLB_VALID 0x00000040 /* Entry is valid */
+
+/* Data portion */
+#define TLB_RPN_MASK 0xFFFFFC00 /* Real Page Number */
+#define TLB_PERM_MASK 0x00000300
+#define TLB_EX 0x00000200 /* Instruction execution allowed */
+#define TLB_WR 0x00000100 /* Writes permitted */
+#define TLB_ZSEL_MASK 0x000000F0
+#define TLB_ZSEL(x) (((x) & 0xF) << 4)
+#define TLB_ATTR_MASK 0x0000000F
+#define TLB_W 0x00000008 /* Caching is write-through */
+#define TLB_I 0x00000004 /* Caching is inhibited */
+#define TLB_M 0x00000002 /* Memory is coherent */
+#define TLB_G 0x00000001 /* Memory is guarded from prefetch */
+
+#define TLB_ENTRIES 64
+
+struct microblaze_mmu
+{
+ /* Data and tag brams. */
+ uint32_t rams[2][TLB_ENTRIES];
+ /* We keep a separate ram for the tids to avoid the 48 bit tag width. */
+ uint8_t tids[TLB_ENTRIES];
+ /* Control flops. */
+ uint32_t regs[8];;
+};
+
+struct microblaze_mmu_lookup
+{
+ uint32_t paddr;
+ uint32_t vaddr;
+ unsigned int size;
+ unsigned int idx;
+ int prot;
+ enum {
+ ERR_PROT, ERR_MISS, ERR_HIT
+ } err;
+};
+
+void mmu_flip_um(CPUState *env, unsigned int um);
+unsigned int mmu_translate(struct microblaze_mmu *mmu,
+ struct microblaze_mmu_lookup *lu,
+ target_ulong vaddr, int rw, int mmu_idx);
+uint32_t mmu_read(CPUState *env, uint32_t rn);
+void mmu_write(CPUState *env, uint32_t rn, uint32_t v);
+void mmu_init(struct microblaze_mmu *mmu);
diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c
new file mode 100644
index 000000000..1a0776d2c
--- /dev/null
+++ b/target-microblaze/op_helper.c
@@ -0,0 +1,216 @@
+/*
+ * Microblaze helper routines.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+
+#include <assert.h>
+#include "exec.h"
+#include "helper.h"
+#include "host-utils.h"
+
+#define D(x)
+
+#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"
+
+/* 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;
+ CPUState *saved_env;
+ unsigned long pc;
+ int ret;
+
+ /* XXX: hack to restore env in all cases, even if not called from
+ generated code */
+ saved_env = env;
+ env = cpu_single_env;
+
+ ret = cpu_mb_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+ if (unlikely(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);
+ }
+ }
+ cpu_loop_exit();
+ }
+ env = saved_env;
+}
+#endif
+
+void helper_raise_exception(uint32_t index)
+{
+ env->exception_index = index;
+ cpu_loop_exit();
+}
+
+void helper_debug(void)
+{
+ int i;
+
+ qemu_log("PC=%8.8x\n", env->sregs[SR_PC]);
+ for (i = 0; i < 32; i++) {
+ qemu_log("r%2.2d=%8.8x ", i, env->regs[i]);
+ if ((i + 1) % 4 == 0)
+ qemu_log("\n");
+ }
+ qemu_log("\n\n");
+}
+
+static inline uint32_t compute_carry(uint32_t a, uint32_t b, uint32_t cin)
+{
+ uint32_t cout = 0;
+
+ if ((b == ~0) && cin)
+ cout = 1;
+ else if ((~0 - a) < (b + cin))
+ cout = 1;
+ return cout;
+}
+
+uint32_t helper_cmp(uint32_t a, uint32_t b)
+{
+ uint32_t t;
+
+ t = b + ~a + 1;
+ if ((b & 0x80000000) ^ (a & 0x80000000))
+ t = (t & 0x7fffffff) | (b & 0x80000000);
+ return t;
+}
+
+uint32_t helper_cmpu(uint32_t a, uint32_t b)
+{
+ uint32_t t;
+
+ t = b + ~a + 1;
+ if ((b & 0x80000000) ^ (a & 0x80000000))
+ t = (t & 0x7fffffff) | (a & 0x80000000);
+ return t;
+}
+
+uint32_t helper_addkc(uint32_t a, uint32_t b, uint32_t k, uint32_t c)
+{
+ uint32_t d, cf = 0, ncf;
+
+ if (c)
+ cf = env->sregs[SR_MSR] >> 31;
+ assert(cf == 0 || cf == 1);
+ d = a + b + cf;
+
+ if (!k) {
+ ncf = compute_carry(a, b, cf);
+ assert(ncf == 0 || ncf == 1);
+ if (ncf)
+ env->sregs[SR_MSR] |= MSR_C | MSR_CC;
+ else
+ env->sregs[SR_MSR] &= ~(MSR_C | MSR_CC);
+ }
+ D(qemu_log("%x = %x + %x cf=%d ncf=%d k=%d c=%d\n",
+ d, a, b, cf, ncf, k, c));
+ return d;
+}
+
+uint32_t helper_subkc(uint32_t a, uint32_t b, uint32_t k, uint32_t c)
+{
+ uint32_t d, cf = 1, ncf;
+
+ if (c)
+ cf = env->sregs[SR_MSR] >> 31;
+ assert(cf == 0 || cf == 1);
+ d = b + ~a + cf;
+
+ if (!k) {
+ ncf = compute_carry(b, ~a, cf);
+ assert(ncf == 0 || ncf == 1);
+ if (ncf)
+ env->sregs[SR_MSR] |= MSR_C | MSR_CC;
+ else
+ env->sregs[SR_MSR] &= ~(MSR_C | MSR_CC);
+ }
+ D(qemu_log("%x = %x + %x cf=%d ncf=%d k=%d c=%d\n",
+ d, a, b, cf, ncf, k, c));
+ return d;
+}
+
+static inline int div_prepare(uint32_t a, uint32_t b)
+{
+ if (b == 0) {
+ env->sregs[SR_MSR] |= MSR_DZ;
+ /* FIXME: Raise the div by zero exception. */
+ return 0;
+ }
+ env->sregs[SR_MSR] &= ~MSR_DZ;
+ return 1;
+}
+
+uint32_t helper_divs(uint32_t a, uint32_t b)
+{
+ if (!div_prepare(a, b))
+ return 0;
+ return (int32_t)a / (int32_t)b;
+}
+
+uint32_t helper_divu(uint32_t a, uint32_t b)
+{
+ if (!div_prepare(a, b))
+ return 0;
+ return a / b;
+}
+
+uint32_t helper_pcmpbf(uint32_t a, uint32_t b)
+{
+ unsigned int i;
+ uint32_t mask = 0xff000000;
+
+ for (i = 0; i < 4; i++) {
+ if ((a & mask) == (b & mask))
+ return i + 1;
+ mask >>= 8;
+ }
+ return 0;
+}
+
+#if !defined(CONFIG_USER_ONLY)
+/* Writes/reads to the MMU's special regs end up here. */
+uint32_t helper_mmu_read(uint32_t rn)
+{
+ return mmu_read(env, rn);
+}
+
+void helper_mmu_write(uint32_t rn, uint32_t v)
+{
+ mmu_write(env, rn, v);
+}
+#endif
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
new file mode 100644
index 000000000..33fff9c2c
--- /dev/null
+++ b/target-microblaze/translate.c
@@ -0,0 +1,1395 @@
+/*
+ * Xilinx MicroBlaze emulation for qemu: main translation routines.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "disas.h"
+#include "tcg-op.h"
+#include "helper.h"
+#include "microblaze-decode.h"
+#include "qemu-common.h"
+
+#define GEN_HELPER 1
+#include "helper.h"
+
+#define SIM_COMPAT 0
+#define DISAS_GNU 1
+#define DISAS_MB 1
+#if DISAS_MB && !SIM_COMPAT
+# define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
+#else
+# define LOG_DIS(...) do { } while (0)
+#endif
+
+#define D(x)
+
+#define EXTRACT_FIELD(src, start, end) \
+ (((src) >> start) & ((1 << (end - start + 1)) - 1))
+
+static TCGv env_debug;
+static TCGv_ptr cpu_env;
+static TCGv cpu_R[32];
+static TCGv cpu_SR[18];
+static TCGv env_imm;
+static TCGv env_btaken;
+static TCGv env_btarget;
+static TCGv env_iflags;
+
+#include "gen-icount.h"
+
+/* This is the state at translation time. */
+typedef struct DisasContext {
+ CPUState *env;
+ target_ulong pc, ppc;
+ target_ulong cache_pc;
+
+ /* Decoder. */
+ int type_b;
+ uint32_t ir;
+ uint8_t opcode;
+ uint8_t rd, ra, rb;
+ uint16_t imm;
+
+ unsigned int cpustate_changed;
+ unsigned int delayed_branch;
+ unsigned int tb_flags, synced_flags; /* tb dependent flags. */
+ unsigned int clear_imm;
+ int is_jmp;
+
+#define JMP_NOJMP 0
+#define JMP_DIRECT 1
+#define JMP_INDIRECT 2
+ unsigned int jmp;
+ uint32_t jmp_pc;
+
+ int abort_at_next_insn;
+ int nr_nops;
+ struct TranslationBlock *tb;
+ int singlestep_enabled;
+} DisasContext;
+
+const static char *regnames[] =
+{
+ "r0", "r1", "r2", "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",
+};
+
+const static char *special_regnames[] =
+{
+ "rpc", "rmsr", "sr2", "sr3", "sr4", "sr5", "sr6", "sr7",
+ "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15",
+ "sr16", "sr17", "sr18"
+};
+
+/* Sign extend at translation time. */
+static inline int sign_extend(unsigned int val, unsigned int width)
+{
+ int sval;
+
+ /* LSL. */
+ val <<= 31 - width;
+ sval = val;
+ /* ASR. */
+ sval >>= 31 - width;
+ return sval;
+}
+
+static inline void t_sync_flags(DisasContext *dc)
+{
+ /* Synch the tb dependant flags between translator and runtime. */
+ if (dc->tb_flags != dc->synced_flags) {
+ tcg_gen_movi_tl(env_iflags, dc->tb_flags);
+ dc->synced_flags = dc->tb_flags;
+ }
+}
+
+static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index)
+{
+ TCGv_i32 tmp = tcg_const_i32(index);
+
+ t_sync_flags(dc);
+ tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
+ gen_helper_raise_exception(tmp);
+ tcg_temp_free_i32(tmp);
+ dc->is_jmp = DISAS_UPDATE;
+}
+
+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)) {
+ tcg_gen_goto_tb(n);
+ tcg_gen_movi_tl(cpu_SR[SR_PC], dest);
+ tcg_gen_exit_tb((long)tb + n);
+ } else {
+ tcg_gen_movi_tl(cpu_SR[SR_PC], dest);
+ tcg_gen_exit_tb(0);
+ }
+}
+
+static inline TCGv *dec_alu_op_b(DisasContext *dc)
+{
+ if (dc->type_b) {
+ if (dc->tb_flags & IMM_FLAG)
+ tcg_gen_ori_tl(env_imm, env_imm, dc->imm);
+ else
+ tcg_gen_movi_tl(env_imm, (int32_t)((int16_t)dc->imm));
+ return &env_imm;
+ } else
+ return &cpu_R[dc->rb];
+}
+
+static void dec_add(DisasContext *dc)
+{
+ unsigned int k, c;
+
+ k = dc->opcode & 4;
+ c = dc->opcode & 2;
+
+ LOG_DIS("add%s%s%s r%d r%d r%d\n",
+ dc->type_b ? "i" : "", k ? "k" : "", c ? "c" : "",
+ dc->rd, dc->ra, dc->rb);
+
+ if (k && !c && dc->rd)
+ tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+ else if (dc->rd)
+ gen_helper_addkc(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)),
+ tcg_const_tl(k), tcg_const_tl(c));
+ else {
+ TCGv d = tcg_temp_new();
+ gen_helper_addkc(d, cpu_R[dc->ra], *(dec_alu_op_b(dc)),
+ tcg_const_tl(k), tcg_const_tl(c));
+ tcg_temp_free(d);
+ }
+}
+
+static void dec_sub(DisasContext *dc)
+{
+ unsigned int u, cmp, k, c;
+
+ u = dc->imm & 2;
+ k = dc->opcode & 4;
+ c = dc->opcode & 2;
+ cmp = (dc->imm & 1) && (!dc->type_b) && k;
+
+ if (cmp) {
+ LOG_DIS("cmp%s r%d, r%d ir=%x\n", u ? "u" : "", dc->rd, dc->ra, dc->ir);
+ if (dc->rd) {
+ if (u)
+ gen_helper_cmpu(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+ else
+ gen_helper_cmp(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+ }
+ } else {
+ LOG_DIS("sub%s%s r%d, r%d r%d\n",
+ k ? "k" : "", c ? "c" : "", dc->rd, dc->ra, dc->rb);
+
+ if (!k || c) {
+ TCGv t;
+ t = tcg_temp_new();
+ if (dc->rd)
+ gen_helper_subkc(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)),
+ tcg_const_tl(k), tcg_const_tl(c));
+ else
+ gen_helper_subkc(t, cpu_R[dc->ra], *(dec_alu_op_b(dc)),
+ tcg_const_tl(k), tcg_const_tl(c));
+ tcg_temp_free(t);
+ }
+ else if (dc->rd)
+ tcg_gen_sub_tl(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]);
+ }
+}
+
+static void dec_pattern(DisasContext *dc)
+{
+ unsigned int mode;
+ int l1;
+
+ mode = dc->opcode & 3;
+ switch (mode) {
+ case 0:
+ /* pcmpbf. */
+ LOG_DIS("pcmpbf r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
+ if (dc->rd)
+ gen_helper_pcmpbf(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+ break;
+ case 2:
+ LOG_DIS("pcmpeq r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
+ if (dc->rd) {
+ TCGv t0 = tcg_temp_local_new();
+ l1 = gen_new_label();
+ tcg_gen_movi_tl(t0, 1);
+ tcg_gen_brcond_tl(TCG_COND_EQ,
+ cpu_R[dc->ra], cpu_R[dc->rb], l1);
+ tcg_gen_movi_tl(t0, 0);
+ gen_set_label(l1);
+ tcg_gen_mov_tl(cpu_R[dc->rd], t0);
+ tcg_temp_free(t0);
+ }
+ break;
+ case 3:
+ LOG_DIS("pcmpne r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
+ l1 = gen_new_label();
+ if (dc->rd) {
+ TCGv t0 = tcg_temp_local_new();
+ tcg_gen_movi_tl(t0, 1);
+ tcg_gen_brcond_tl(TCG_COND_NE,
+ cpu_R[dc->ra], cpu_R[dc->rb], l1);
+ tcg_gen_movi_tl(t0, 0);
+ gen_set_label(l1);
+ tcg_gen_mov_tl(cpu_R[dc->rd], t0);
+ tcg_temp_free(t0);
+ }
+ break;
+ default:
+ cpu_abort(dc->env,
+ "unsupported pattern insn opcode=%x\n", dc->opcode);
+ break;
+ }
+}
+
+static void dec_and(DisasContext *dc)
+{
+ unsigned int not;
+
+ if (!dc->type_b && (dc->imm & (1 << 10))) {
+ dec_pattern(dc);
+ return;
+ }
+
+ not = dc->opcode & (1 << 1);
+ LOG_DIS("and%s\n", not ? "n" : "");
+
+ if (!dc->rd)
+ return;
+
+ if (not) {
+ TCGv t = tcg_temp_new();
+ tcg_gen_not_tl(t, *(dec_alu_op_b(dc)));
+ tcg_gen_and_tl(cpu_R[dc->rd], cpu_R[dc->ra], t);
+ tcg_temp_free(t);
+ } else
+ tcg_gen_and_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+}
+
+static void dec_or(DisasContext *dc)
+{
+ if (!dc->type_b && (dc->imm & (1 << 10))) {
+ dec_pattern(dc);
+ return;
+ }
+
+ LOG_DIS("or r%d r%d r%d imm=%x\n", dc->rd, dc->ra, dc->rb, dc->imm);
+ if (dc->rd)
+ tcg_gen_or_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+}
+
+static void dec_xor(DisasContext *dc)
+{
+ if (!dc->type_b && (dc->imm & (1 << 10))) {
+ dec_pattern(dc);
+ return;
+ }
+
+ LOG_DIS("xor r%d\n", dc->rd);
+ if (dc->rd)
+ tcg_gen_xor_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+}
+
+static void read_carry(DisasContext *dc, TCGv d)
+{
+ tcg_gen_shri_tl(d, cpu_SR[SR_MSR], 31);
+}
+
+static void write_carry(DisasContext *dc, TCGv v)
+{
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_shli_tl(t0, v, 31);
+ tcg_gen_sari_tl(t0, t0, 31);
+ tcg_gen_mov_tl(env_debug, t0);
+ tcg_gen_andi_tl(t0, t0, (MSR_C | MSR_CC));
+ tcg_gen_andi_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR],
+ ~(MSR_C | MSR_CC));
+ tcg_gen_or_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t0);
+ tcg_temp_free(t0);
+}
+
+
+static inline void msr_read(DisasContext *dc, TCGv d)
+{
+ tcg_gen_mov_tl(d, cpu_SR[SR_MSR]);
+}
+
+static inline void msr_write(DisasContext *dc, TCGv v)
+{
+ dc->cpustate_changed = 1;
+ tcg_gen_mov_tl(cpu_SR[SR_MSR], v);
+ /* PVR, we have a processor version register. */
+ tcg_gen_ori_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], (1 << 10));
+}
+
+static void dec_msr(DisasContext *dc)
+{
+ TCGv t0, t1;
+ unsigned int sr, to, rn;
+
+ sr = dc->imm & ((1 << 14) - 1);
+ to = dc->imm & (1 << 14);
+ dc->type_b = 1;
+ if (to)
+ dc->cpustate_changed = 1;
+
+ /* msrclr and msrset. */
+ if (!(dc->imm & (1 << 15))) {
+ unsigned int clr = dc->ir & (1 << 16);
+
+ LOG_DIS("msr%s r%d imm=%x\n", clr ? "clr" : "set",
+ dc->rd, dc->imm);
+ if (dc->rd)
+ msr_read(dc, cpu_R[dc->rd]);
+
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+ msr_read(dc, t0);
+ tcg_gen_mov_tl(t1, *(dec_alu_op_b(dc)));
+
+ if (clr) {
+ tcg_gen_not_tl(t1, t1);
+ tcg_gen_and_tl(t0, t0, t1);
+ } else
+ tcg_gen_or_tl(t0, t0, t1);
+ msr_write(dc, t0);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc + 4);
+ dc->is_jmp = DISAS_UPDATE;
+ return;
+ }
+
+#if !defined(CONFIG_USER_ONLY)
+ /* Catch read/writes to the mmu block. */
+ if ((sr & ~0xff) == 0x1000) {
+ sr &= 7;
+ LOG_DIS("m%ss sr%d r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm);
+ if (to)
+ gen_helper_mmu_write(tcg_const_tl(sr), cpu_R[dc->ra]);
+ else
+ gen_helper_mmu_read(cpu_R[dc->rd], tcg_const_tl(sr));
+ return;
+ }
+#endif
+
+ if (to) {
+ LOG_DIS("m%ss sr%x r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm);
+ switch (sr) {
+ case 0:
+ break;
+ case 1:
+ msr_write(dc, cpu_R[dc->ra]);
+ break;
+ case 0x3:
+ tcg_gen_mov_tl(cpu_SR[SR_EAR], cpu_R[dc->ra]);
+ break;
+ case 0x5:
+ tcg_gen_mov_tl(cpu_SR[SR_ESR], cpu_R[dc->ra]);
+ break;
+ case 0x7:
+ /* Ignored at the moment. */
+ break;
+ default:
+ cpu_abort(dc->env, "unknown mts reg %x\n", sr);
+ break;
+ }
+ } else {
+ LOG_DIS("m%ss r%d sr%x imm=%x\n", to ? "t" : "f", dc->rd, sr, dc->imm);
+
+ switch (sr) {
+ case 0:
+ tcg_gen_movi_tl(cpu_R[dc->rd], dc->pc);
+ break;
+ case 1:
+ msr_read(dc, cpu_R[dc->rd]);
+ break;
+ case 0x3:
+ tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_EAR]);
+ break;
+ case 0x5:
+ tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_ESR]);
+ break;
+ case 0x7:
+ tcg_gen_movi_tl(cpu_R[dc->rd], 0);
+ break;
+ case 0xb:
+ tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_BTR]);
+ break;
+ case 0x2000:
+ case 0x2001:
+ case 0x2002:
+ case 0x2003:
+ case 0x2004:
+ case 0x2005:
+ case 0x2006:
+ case 0x2007:
+ case 0x2008:
+ case 0x2009:
+ case 0x200a:
+ case 0x200b:
+ case 0x200c:
+ rn = sr & 0xf;
+ tcg_gen_ld_tl(cpu_R[dc->rd],
+ cpu_env, offsetof(CPUState, pvr.regs[rn]));
+ break;
+ default:
+ cpu_abort(dc->env, "unknown mfs reg %x\n", sr);
+ break;
+ }
+ }
+}
+
+/* 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_i64 t0, t1;
+
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+
+ tcg_gen_ext_i32_i64(t0, a);
+ tcg_gen_ext_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_i64(t0);
+ tcg_temp_free_i64(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_i64 t0, t1;
+
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_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_i64(t0);
+ tcg_temp_free_i64(t1);
+}
+
+/* Multiplier unit. */
+static void dec_mul(DisasContext *dc)
+{
+ TCGv d[2];
+ unsigned int subcode;
+
+ subcode = dc->imm & 3;
+ d[0] = tcg_temp_new();
+ d[1] = tcg_temp_new();
+
+ if (dc->type_b) {
+ LOG_DIS("muli r%d r%d %x\n", dc->rd, dc->ra, dc->imm);
+ t_gen_mulu(cpu_R[dc->rd], d[1], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+ goto done;
+ }
+
+ switch (subcode) {
+ case 0:
+ LOG_DIS("mul r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
+ t_gen_mulu(cpu_R[dc->rd], d[1], cpu_R[dc->ra], cpu_R[dc->rb]);
+ break;
+ case 1:
+ LOG_DIS("mulh r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
+ t_gen_muls(d[0], cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+ break;
+ case 2:
+ LOG_DIS("mulhsu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
+ t_gen_muls(d[0], cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+ break;
+ case 3:
+ LOG_DIS("mulhu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
+ t_gen_mulu(d[0], cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+ break;
+ default:
+ cpu_abort(dc->env, "unknown MUL insn %x\n", subcode);
+ break;
+ }
+done:
+ tcg_temp_free(d[0]);
+ tcg_temp_free(d[1]);
+}
+
+/* Div unit. */
+static void dec_div(DisasContext *dc)
+{
+ unsigned int u;
+
+ u = dc->imm & 2;
+ LOG_DIS("div\n");
+
+ /* FIXME: support div by zero exceptions. */
+ if (u)
+ gen_helper_divu(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]);
+ else
+ gen_helper_divs(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]);
+ if (!dc->rd)
+ tcg_gen_movi_tl(cpu_R[dc->rd], 0);
+}
+
+static void dec_barrel(DisasContext *dc)
+{
+ TCGv t0;
+ unsigned int s, t;
+
+ s = dc->imm & (1 << 10);
+ t = dc->imm & (1 << 9);
+
+ LOG_DIS("bs%s%s r%d r%d r%d\n",
+ s ? "l" : "r", t ? "a" : "l", dc->rd, dc->ra, dc->rb);
+
+ t0 = tcg_temp_new();
+
+ tcg_gen_mov_tl(t0, *(dec_alu_op_b(dc)));
+ tcg_gen_andi_tl(t0, t0, 31);
+
+ if (s)
+ tcg_gen_shl_tl(cpu_R[dc->rd], cpu_R[dc->ra], t0);
+ else {
+ if (t)
+ tcg_gen_sar_tl(cpu_R[dc->rd], cpu_R[dc->ra], t0);
+ else
+ tcg_gen_shr_tl(cpu_R[dc->rd], cpu_R[dc->ra], t0);
+ }
+}
+
+static void dec_bit(DisasContext *dc)
+{
+ TCGv t0, t1;
+ unsigned int op;
+
+ op = dc->ir & ((1 << 8) - 1);
+ switch (op) {
+ case 0x21:
+ /* src. */
+ t0 = tcg_temp_new();
+
+ LOG_DIS("src r%d r%d\n", dc->rd, dc->ra);
+ tcg_gen_andi_tl(t0, cpu_R[dc->ra], 1);
+ if (dc->rd) {
+ t1 = tcg_temp_new();
+ read_carry(dc, t1);
+ tcg_gen_shli_tl(t1, t1, 31);
+
+ tcg_gen_shri_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1);
+ tcg_gen_or_tl(cpu_R[dc->rd], cpu_R[dc->rd], t1);
+ tcg_temp_free(t1);
+ }
+
+ /* Update carry. */
+ write_carry(dc, t0);
+ tcg_temp_free(t0);
+ break;
+
+ case 0x1:
+ case 0x41:
+ /* srl. */
+ t0 = tcg_temp_new();
+ LOG_DIS("srl r%d r%d\n", dc->rd, dc->ra);
+
+ /* Update carry. */
+ tcg_gen_andi_tl(t0, cpu_R[dc->ra], 1);
+ write_carry(dc, t0);
+ tcg_temp_free(t0);
+ if (dc->rd) {
+ if (op == 0x41)
+ tcg_gen_shri_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1);
+ else
+ tcg_gen_sari_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1);
+ }
+ break;
+ case 0x60:
+ LOG_DIS("ext8s r%d r%d\n", dc->rd, dc->ra);
+ tcg_gen_ext8s_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
+ break;
+ case 0x61:
+ LOG_DIS("ext16s r%d r%d\n", dc->rd, dc->ra);
+ tcg_gen_ext16s_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
+ break;
+ case 0x64:
+ /* wdc. */
+ LOG_DIS("wdc r%d\n", dc->ra);
+ break;
+ case 0x68:
+ /* wic. */
+ LOG_DIS("wic r%d\n", dc->ra);
+ break;
+ default:
+ cpu_abort(dc->env, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n",
+ dc->pc, op, dc->rd, dc->ra, dc->rb);
+ break;
+ }
+}
+
+static inline void sync_jmpstate(DisasContext *dc)
+{
+ if (dc->jmp == JMP_DIRECT) {
+ dc->jmp = JMP_INDIRECT;
+ tcg_gen_movi_tl(env_btaken, 1);
+ tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
+ }
+}
+
+static void dec_imm(DisasContext *dc)
+{
+ LOG_DIS("imm %x\n", dc->imm << 16);
+ tcg_gen_movi_tl(env_imm, (dc->imm << 16));
+ dc->tb_flags |= IMM_FLAG;
+ dc->clear_imm = 0;
+}
+
+static inline void gen_load(DisasContext *dc, TCGv dst, TCGv addr,
+ unsigned int size)
+{
+ int mem_index = cpu_mmu_index(dc->env);
+
+ if (size == 1) {
+ tcg_gen_qemu_ld8u(dst, addr, mem_index);
+ } else if (size == 2) {
+ tcg_gen_qemu_ld16u(dst, addr, mem_index);
+ } else if (size == 4) {
+ tcg_gen_qemu_ld32u(dst, addr, mem_index);
+ } else
+ cpu_abort(dc->env, "Incorrect load size %d\n", size);
+}
+
+static inline TCGv *compute_ldst_addr(DisasContext *dc, TCGv *t)
+{
+ unsigned int extimm = dc->tb_flags & IMM_FLAG;
+
+ /* Treat the fast cases first. */
+ if (!dc->type_b) {
+ *t = tcg_temp_new();
+ tcg_gen_add_tl(*t, cpu_R[dc->ra], cpu_R[dc->rb]);
+ return t;
+ }
+ /* Immediate. */
+ if (!extimm) {
+ if (dc->imm == 0) {
+ return &cpu_R[dc->ra];
+ }
+ *t = tcg_temp_new();
+ tcg_gen_movi_tl(*t, (int32_t)((int16_t)dc->imm));
+ tcg_gen_add_tl(*t, cpu_R[dc->ra], *t);
+ } else {
+ *t = tcg_temp_new();
+ tcg_gen_add_tl(*t, cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+ }
+
+ return t;
+}
+
+static void dec_load(DisasContext *dc)
+{
+ TCGv t, *addr;
+ unsigned int size;
+
+ size = 1 << (dc->opcode & 3);
+
+ LOG_DIS("l %x %d\n", dc->opcode, size);
+ t_sync_flags(dc);
+ addr = compute_ldst_addr(dc, &t);
+
+ /* If we get a fault on a dslot, the jmpstate better be in sync. */
+ sync_jmpstate(dc);
+ if (dc->rd)
+ gen_load(dc, cpu_R[dc->rd], *addr, size);
+ else {
+ gen_load(dc, env_imm, *addr, size);
+ }
+
+ if (addr == &t)
+ tcg_temp_free(t);
+}
+
+static void gen_store(DisasContext *dc, TCGv addr, TCGv val,
+ unsigned int size)
+{
+ int mem_index = cpu_mmu_index(dc->env);
+
+ if (size == 1)
+ tcg_gen_qemu_st8(val, addr, mem_index);
+ else if (size == 2) {
+ tcg_gen_qemu_st16(val, addr, mem_index);
+ } else if (size == 4) {
+ tcg_gen_qemu_st32(val, addr, mem_index);
+ } else
+ cpu_abort(dc->env, "Incorrect store size %d\n", size);
+}
+
+static void dec_store(DisasContext *dc)
+{
+ TCGv t, *addr;
+ unsigned int size;
+
+ size = 1 << (dc->opcode & 3);
+
+ LOG_DIS("s%d%s\n", size, dc->type_b ? "i" : "");
+ t_sync_flags(dc);
+ /* If we get a fault on a dslot, the jmpstate better be in sync. */
+ sync_jmpstate(dc);
+ addr = compute_ldst_addr(dc, &t);
+ gen_store(dc, *addr, cpu_R[dc->rd], size);
+ if (addr == &t)
+ tcg_temp_free(t);
+}
+
+static inline void eval_cc(DisasContext *dc, unsigned int cc,
+ TCGv d, TCGv a, TCGv b)
+{
+ int l1;
+
+ switch (cc) {
+ case CC_EQ:
+ l1 = gen_new_label();
+ tcg_gen_movi_tl(env_btaken, 1);
+ tcg_gen_brcond_tl(TCG_COND_EQ, a, b, l1);
+ tcg_gen_movi_tl(env_btaken, 0);
+ gen_set_label(l1);
+ break;
+ case CC_NE:
+ l1 = gen_new_label();
+ tcg_gen_movi_tl(env_btaken, 1);
+ tcg_gen_brcond_tl(TCG_COND_NE, a, b, l1);
+ tcg_gen_movi_tl(env_btaken, 0);
+ gen_set_label(l1);
+ break;
+ case CC_LT:
+ l1 = gen_new_label();
+ tcg_gen_movi_tl(env_btaken, 1);
+ tcg_gen_brcond_tl(TCG_COND_LT, a, b, l1);
+ tcg_gen_movi_tl(env_btaken, 0);
+ gen_set_label(l1);
+ break;
+ case CC_LE:
+ l1 = gen_new_label();
+ tcg_gen_movi_tl(env_btaken, 1);
+ tcg_gen_brcond_tl(TCG_COND_LE, a, b, l1);
+ tcg_gen_movi_tl(env_btaken, 0);
+ gen_set_label(l1);
+ break;
+ case CC_GE:
+ l1 = gen_new_label();
+ tcg_gen_movi_tl(env_btaken, 1);
+ tcg_gen_brcond_tl(TCG_COND_GE, a, b, l1);
+ tcg_gen_movi_tl(env_btaken, 0);
+ gen_set_label(l1);
+ break;
+ case CC_GT:
+ l1 = gen_new_label();
+ tcg_gen_movi_tl(env_btaken, 1);
+ tcg_gen_brcond_tl(TCG_COND_GT, a, b, l1);
+ tcg_gen_movi_tl(env_btaken, 0);
+ gen_set_label(l1);
+ break;
+ default:
+ cpu_abort(dc->env, "Unknown condition code %x.\n", cc);
+ break;
+ }
+}
+
+static void eval_cond_jmp(DisasContext *dc, TCGv pc_true, TCGv pc_false)
+{
+ int l1;
+
+ l1 = gen_new_label();
+ /* Conditional jmp. */
+ tcg_gen_mov_tl(cpu_SR[SR_PC], pc_false);
+ tcg_gen_brcondi_tl(TCG_COND_EQ, env_btaken, 0, l1);
+ tcg_gen_mov_tl(cpu_SR[SR_PC], pc_true);
+ gen_set_label(l1);
+}
+
+static void dec_bcc(DisasContext *dc)
+{
+ unsigned int cc;
+ unsigned int dslot;
+
+ cc = EXTRACT_FIELD(dc->ir, 21, 23);
+ dslot = dc->ir & (1 << 25);
+ LOG_DIS("bcc%s r%d %x\n", dslot ? "d" : "", dc->ra, dc->imm);
+
+ dc->delayed_branch = 1;
+ if (dslot) {
+ dc->delayed_branch = 2;
+ dc->tb_flags |= D_FLAG;
+ tcg_gen_st_tl(tcg_const_tl(dc->type_b && (dc->tb_flags & IMM_FLAG)),
+ cpu_env, offsetof(CPUState, bimm));
+ }
+
+ tcg_gen_movi_tl(env_btarget, dc->pc);
+ tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc)));
+ eval_cc(dc, cc, env_btaken, cpu_R[dc->ra], tcg_const_tl(0));
+ dc->jmp = JMP_INDIRECT;
+}
+
+static void dec_br(DisasContext *dc)
+{
+ unsigned int dslot, link, abs;
+
+ dslot = dc->ir & (1 << 20);
+ abs = dc->ir & (1 << 19);
+ link = dc->ir & (1 << 18);
+ LOG_DIS("br%s%s%s%s imm=%x\n",
+ abs ? "a" : "", link ? "l" : "",
+ dc->type_b ? "i" : "", dslot ? "d" : "",
+ dc->imm);
+
+ dc->delayed_branch = 1;
+ if (dslot) {
+ dc->delayed_branch = 2;
+ dc->tb_flags |= D_FLAG;
+ tcg_gen_st_tl(tcg_const_tl(dc->type_b && (dc->tb_flags & IMM_FLAG)),
+ cpu_env, offsetof(CPUState, bimm));
+ }
+ if (link && dc->rd)
+ tcg_gen_movi_tl(cpu_R[dc->rd], dc->pc);
+
+ dc->jmp = JMP_INDIRECT;
+ if (abs) {
+ tcg_gen_movi_tl(env_btaken, 1);
+ tcg_gen_mov_tl(env_btarget, *(dec_alu_op_b(dc)));
+ if (link && !(dc->tb_flags & IMM_FLAG)
+ && (dc->imm == 8 || dc->imm == 0x18))
+ t_gen_raise_exception(dc, EXCP_BREAK);
+ if (dc->imm == 0)
+ t_gen_raise_exception(dc, EXCP_DEBUG);
+ } else {
+ if (dc->tb_flags & IMM_FLAG) {
+ tcg_gen_movi_tl(env_btaken, 1);
+ tcg_gen_movi_tl(env_btarget, dc->pc);
+ tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc)));
+ } else {
+ dc->jmp = JMP_DIRECT;
+ dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm);
+ }
+ }
+}
+
+static inline void do_rti(DisasContext *dc)
+{
+ TCGv t0, t1;
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+ tcg_gen_shri_tl(t0, cpu_SR[SR_MSR], 1);
+ tcg_gen_ori_tl(t1, cpu_SR[SR_MSR], MSR_IE);
+ tcg_gen_andi_tl(t0, t0, (MSR_VM | MSR_UM));
+
+ tcg_gen_andi_tl(t1, t1, ~(MSR_VM | MSR_UM));
+ tcg_gen_or_tl(t1, t1, t0);
+ msr_write(dc, t1);
+ tcg_temp_free(t1);
+ tcg_temp_free(t0);
+ dc->tb_flags &= ~DRTI_FLAG;
+}
+
+static inline void do_rtb(DisasContext *dc)
+{
+ TCGv t0, t1;
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+ tcg_gen_andi_tl(t1, cpu_SR[SR_MSR], ~MSR_BIP);
+ tcg_gen_shri_tl(t0, t1, 1);
+ tcg_gen_andi_tl(t0, t0, (MSR_VM | MSR_UM));
+
+ tcg_gen_andi_tl(t1, t1, ~(MSR_VM | MSR_UM));
+ tcg_gen_or_tl(t1, t1, t0);
+ msr_write(dc, t1);
+ tcg_temp_free(t1);
+ tcg_temp_free(t0);
+ dc->tb_flags &= ~DRTB_FLAG;
+}
+
+static inline void do_rte(DisasContext *dc)
+{
+ TCGv t0, t1;
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+
+ tcg_gen_ori_tl(t1, cpu_SR[SR_MSR], MSR_EE);
+ tcg_gen_andi_tl(t1, t1, ~MSR_EIP);
+ tcg_gen_shri_tl(t0, t1, 1);
+ tcg_gen_andi_tl(t0, t0, (MSR_VM | MSR_UM));
+
+ tcg_gen_andi_tl(t1, t1, ~(MSR_VM | MSR_UM));
+ tcg_gen_or_tl(t1, t1, t0);
+ msr_write(dc, t1);
+ tcg_temp_free(t1);
+ tcg_temp_free(t0);
+ dc->tb_flags &= ~DRTE_FLAG;
+}
+
+static void dec_rts(DisasContext *dc)
+{
+ unsigned int b_bit, i_bit, e_bit;
+
+ i_bit = dc->ir & (1 << 21);
+ b_bit = dc->ir & (1 << 22);
+ e_bit = dc->ir & (1 << 23);
+
+ dc->delayed_branch = 2;
+ dc->tb_flags |= D_FLAG;
+ tcg_gen_st_tl(tcg_const_tl(dc->type_b && (dc->tb_flags & IMM_FLAG)),
+ cpu_env, offsetof(CPUState, bimm));
+
+ if (i_bit) {
+ LOG_DIS("rtid ir=%x\n", dc->ir);
+ dc->tb_flags |= DRTI_FLAG;
+ } else if (b_bit) {
+ LOG_DIS("rtbd ir=%x\n", dc->ir);
+ dc->tb_flags |= DRTB_FLAG;
+ } else if (e_bit) {
+ LOG_DIS("rted ir=%x\n", dc->ir);
+ dc->tb_flags |= DRTE_FLAG;
+ } else
+ LOG_DIS("rts ir=%x\n", dc->ir);
+
+ tcg_gen_movi_tl(env_btaken, 1);
+ tcg_gen_add_tl(env_btarget, cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+}
+
+static void dec_null(DisasContext *dc)
+{
+ qemu_log ("unknown insn pc=%x opc=%x\n", dc->pc, dc->opcode);
+ dc->abort_at_next_insn = 1;
+}
+
+static struct decoder_info {
+ struct {
+ uint32_t bits;
+ uint32_t mask;
+ };
+ void (*dec)(DisasContext *dc);
+} decinfo[] = {
+ {DEC_ADD, dec_add},
+ {DEC_SUB, dec_sub},
+ {DEC_AND, dec_and},
+ {DEC_XOR, dec_xor},
+ {DEC_OR, dec_or},
+ {DEC_BIT, dec_bit},
+ {DEC_BARREL, dec_barrel},
+ {DEC_LD, dec_load},
+ {DEC_ST, dec_store},
+ {DEC_IMM, dec_imm},
+ {DEC_BR, dec_br},
+ {DEC_BCC, dec_bcc},
+ {DEC_RTS, dec_rts},
+ {DEC_MUL, dec_mul},
+ {DEC_DIV, dec_div},
+ {DEC_MSR, dec_msr},
+ {{0, 0}, dec_null}
+};
+
+static inline void decode(DisasContext *dc)
+{
+ uint32_t ir;
+ int i;
+
+ if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
+ tcg_gen_debug_insn_start(dc->pc);
+
+ dc->ir = ir = ldl_code(dc->pc);
+ LOG_DIS("%8.8x\t", dc->ir);
+
+ if (dc->ir)
+ dc->nr_nops = 0;
+ else {
+ LOG_DIS("nr_nops=%d\t", dc->nr_nops);
+ dc->nr_nops++;
+ if (dc->nr_nops > 4)
+ cpu_abort(dc->env, "fetching nop sequence\n");
+ }
+ /* bit 2 seems to indicate insn type. */
+ dc->type_b = ir & (1 << 29);
+
+ dc->opcode = EXTRACT_FIELD(ir, 26, 31);
+ dc->rd = EXTRACT_FIELD(ir, 21, 25);
+ dc->ra = EXTRACT_FIELD(ir, 16, 20);
+ dc->rb = EXTRACT_FIELD(ir, 11, 15);
+ dc->imm = EXTRACT_FIELD(ir, 0, 15);
+
+ /* Large switch for all insns. */
+ for (i = 0; i < ARRAY_SIZE(decinfo); i++) {
+ if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) {
+ decinfo[i].dec(dc);
+ break;
+ }
+ }
+}
+
+
+static void check_breakpoint(CPUState *env, DisasContext *dc)
+{
+ CPUBreakpoint *bp;
+
+ if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
+ TAILQ_FOREACH(bp, &env->breakpoints, entry) {
+ if (bp->pc == dc->pc) {
+ t_gen_raise_exception(dc, EXCP_DEBUG);
+ dc->is_jmp = DISAS_UPDATE;
+ }
+ }
+ }
+}
+
+/* generate intermediate code for basic block 'tb'. */
+static void
+gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
+ int search_pc)
+{
+ uint16_t *gen_opc_end;
+ uint32_t pc_start;
+ int j, lj;
+ struct DisasContext ctx;
+ struct DisasContext *dc = &ctx;
+ uint32_t next_page_start, org_flags;
+ target_ulong npc;
+ int num_insns;
+ int max_insns;
+
+ qemu_log_try_set_file(stderr);
+
+ pc_start = tb->pc;
+ dc->env = env;
+ dc->tb = tb;
+ org_flags = dc->synced_flags = dc->tb_flags = tb->flags;
+
+ gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+
+ dc->is_jmp = DISAS_NEXT;
+ dc->jmp = 0;
+ dc->delayed_branch = !!(dc->tb_flags & D_FLAG);
+ dc->ppc = pc_start;
+ dc->pc = pc_start;
+ dc->cache_pc = -1;
+ dc->singlestep_enabled = env->singlestep_enabled;
+ dc->cpustate_changed = 0;
+ dc->abort_at_next_insn = 0;
+ dc->nr_nops = 0;
+
+ if (pc_start & 3)
+ cpu_abort(env, "Microblaze: unaligned PC=%x\n", pc_start);
+
+ if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+#if !SIM_COMPAT
+ qemu_log("--------------\n");
+ log_cpu_state(env, 0);
+#endif
+ }
+
+ 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
+ {
+#if SIM_COMPAT
+ if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+ tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
+ gen_helper_debug();
+ }
+#endif
+ check_breakpoint(env, dc);
+
+ if (search_pc) {
+ j = gen_opc_ptr - gen_opc_buf;
+ if (lj < j) {
+ lj++;
+ while (lj < j)
+ gen_opc_instr_start[lj++] = 0;
+ }
+ gen_opc_pc[lj] = dc->pc;
+ gen_opc_instr_start[lj] = 1;
+ gen_opc_icount[lj] = num_insns;
+ }
+
+ /* Pretty disas. */
+ LOG_DIS("%8.8x:\t", dc->pc);
+
+ if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+ gen_io_start();
+
+ dc->clear_imm = 1;
+ decode(dc);
+ if (dc->clear_imm)
+ dc->tb_flags &= ~IMM_FLAG;
+ dc->ppc = dc->pc;
+ dc->pc += 4;
+ num_insns++;
+
+ if (dc->delayed_branch) {
+ dc->delayed_branch--;
+ if (!dc->delayed_branch) {
+ if (dc->tb_flags & DRTI_FLAG)
+ do_rti(dc);
+ if (dc->tb_flags & DRTB_FLAG)
+ do_rtb(dc);
+ if (dc->tb_flags & DRTE_FLAG)
+ do_rte(dc);
+ /* Clear the delay slot flag. */
+ dc->tb_flags &= ~D_FLAG;
+ /* If it is a direct jump, try direct chaining. */
+ if (dc->jmp != JMP_DIRECT) {
+ eval_cond_jmp(dc, env_btarget, tcg_const_tl(dc->pc));
+ dc->is_jmp = DISAS_JUMP;
+ }
+ break;
+ }
+ }
+ if (env->singlestep_enabled)
+ break;
+ } while (!dc->is_jmp && !dc->cpustate_changed
+ && gen_opc_ptr < gen_opc_end
+ && !singlestep
+ && (dc->pc < next_page_start)
+ && num_insns < max_insns);
+
+ npc = dc->pc;
+ if (dc->jmp == JMP_DIRECT) {
+ if (dc->tb_flags & D_FLAG) {
+ dc->is_jmp = DISAS_UPDATE;
+ tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
+ sync_jmpstate(dc);
+ } else
+ 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 || org_flags != dc->tb_flags)) {
+ dc->is_jmp = DISAS_UPDATE;
+ tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
+ }
+ t_sync_flags(dc);
+
+ if (unlikely(env->singlestep_enabled)) {
+ t_gen_raise_exception(dc, EXCP_DEBUG);
+ if (dc->is_jmp == DISAS_NEXT)
+ tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
+ } else {
+ switch(dc->is_jmp) {
+ case DISAS_NEXT:
+ 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 */
+ 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;
+ if (search_pc) {
+ j = gen_opc_ptr - gen_opc_buf;
+ lj++;
+ while (lj <= j)
+ gen_opc_instr_start[lj++] = 0;
+ } else {
+ tb->size = dc->pc - pc_start;
+ tb->icount = num_insns;
+ }
+
+#ifdef DEBUG_DISAS
+#if !SIM_COMPAT
+ if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+ qemu_log("\n");
+#if DISAS_GNU
+ log_target_disas(pc_start, dc->pc - pc_start, 0);
+#endif
+ qemu_log("\nisize=%d osize=%zd\n",
+ dc->pc - pc_start, gen_opc_ptr - gen_opc_buf);
+ }
+#endif
+#endif
+ assert(!dc->abort_at_next_insn);
+}
+
+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)
+{
+ gen_intermediate_code_internal(env, tb, 1);
+}
+
+void cpu_dump_state (CPUState *env, FILE *f,
+ int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+ int flags)
+{
+ int i;
+
+ if (!env || !f)
+ return;
+
+ cpu_fprintf(f, "IN: PC=%x %s\n",
+ env->sregs[SR_PC], lookup_symbol(env->sregs[SR_PC]));
+ cpu_fprintf(f, "rmsr=%x resr=%x debug[%x] imm=%x iflags=%x\n",
+ env->sregs[SR_MSR], env->sregs[SR_ESR],
+ env->debug, env->imm, env->iflags);
+ cpu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s)\n",
+ env->btaken, env->btarget,
+ (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel",
+ (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel");
+ for (i = 0; i < 32; i++) {
+ cpu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]);
+ if ((i + 1) % 4 == 0)
+ cpu_fprintf(f, "\n");
+ }
+ cpu_fprintf(f, "\n\n");
+}
+
+CPUState *cpu_mb_init (const char *cpu_model)
+{
+ CPUState *env;
+ static int tcg_initialized = 0;
+ int i;
+
+ env = qemu_mallocz(sizeof(CPUState));
+
+ cpu_exec_init(env);
+ cpu_reset(env);
+
+ env->pvr.regs[0] = PVR0_PVR_FULL_MASK \
+ | PVR0_USE_BARREL_MASK \
+ | PVR0_USE_DIV_MASK \
+ | PVR0_USE_HW_MUL_MASK \
+ | PVR0_USE_EXC_MASK \
+ | PVR0_USE_ICACHE_MASK \
+ | PVR0_USE_DCACHE_MASK \
+ | PVR0_USE_MMU \
+ | (0xb << 8);
+ env->pvr.regs[2] = PVR2_D_OPB_MASK \
+ | PVR2_D_LMB_MASK \
+ | PVR2_I_OPB_MASK \
+ | PVR2_I_LMB_MASK \
+ | PVR2_USE_MSR_INSTR \
+ | PVR2_USE_PCMP_INSTR \
+ | PVR2_USE_BARREL_MASK \
+ | PVR2_USE_DIV_MASK \
+ | PVR2_USE_HW_MUL_MASK \
+ | PVR2_USE_MUL64_MASK \
+ | 0;
+ env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family. */
+ env->pvr.regs[11] = PVR11_USE_MMU;
+
+ if (tcg_initialized)
+ return env;
+
+ tcg_initialized = 1;
+
+ cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+
+ env_debug = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUState, debug),
+ "debug0");
+ env_iflags = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUState, iflags),
+ "iflags");
+ env_imm = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUState, imm),
+ "imm");
+ env_btarget = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUState, btarget),
+ "btarget");
+ env_btaken = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUState, btaken),
+ "btaken");
+ for (i = 0; i < ARRAY_SIZE(cpu_R); i++) {
+ cpu_R[i] = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUState, regs[i]),
+ regnames[i]);
+ }
+ for (i = 0; i < ARRAY_SIZE(cpu_SR); i++) {
+ cpu_SR[i] = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUState, sregs[i]),
+ special_regnames[i]);
+ }
+#define GEN_HELPER 2
+#include "helper.h"
+
+ return env;
+}
+
+void cpu_reset (CPUState *env)
+{
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
+
+ memset(env, 0, offsetof(CPUMBState, breakpoints));
+ tlb_flush(env, 1);
+
+ env->sregs[SR_MSR] = 0;
+#if defined(CONFIG_USER_ONLY)
+ /* start in user mode with interrupts enabled. */
+ env->pvr.regs[10] = 0x0c000000; /* Spartan 3a dsp. */
+#else
+ mmu_init(&env->mmu);
+#endif
+}
+
+void gen_pc_load(CPUState *env, struct TranslationBlock *tb,
+ unsigned long searched_pc, int pc_pos, void *puc)
+{
+ env->sregs[SR_PC] = gen_opc_pc[pc_pos];
+}
diff --git a/targphys.h b/targphys.h
index 81a9c3733..99ab23c7a 100644
--- a/targphys.h
+++ b/targphys.h
@@ -12,9 +12,11 @@
#if TARGET_PHYS_ADDR_BITS == 32
typedef uint32_t target_phys_addr_t;
+#define TARGET_PHYS_ADDR_MAX UINT32_MAX
#define TARGET_FMT_plx "%08x"
#elif TARGET_PHYS_ADDR_BITS == 64
typedef uint64_t target_phys_addr_t;
+#define TARGET_PHYS_ADDR_MAX UINT64_MAX
#define TARGET_FMT_plx "%016" PRIx64
#endif
#endif
diff --git a/vl.c b/vl.c
index 8aea7d699..2fda17b71 100644
--- a/vl.c
+++ b/vl.c
@@ -2257,8 +2257,7 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque)
"boot", NULL };
if (check_params(params, str) < 0) {
- fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n",
- buf, str);
+ fprintf(stderr, "qemu: unknown parameter in '%s'\n", str);
return -1;
}
@@ -3287,7 +3286,7 @@ static int ram_save_live(QEMUFile *f, int stage, void *opaque)
{
ram_addr_t addr;
- if (cpu_physical_sync_dirty_bitmap(0, last_ram_offset) != 0) {
+ if (cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX) != 0) {
qemu_file_set_error(f);
return 0;
}
@@ -5232,7 +5231,7 @@ int main(int argc, char **argv, char **envp)
break;
#endif
case QEMU_OPTION_redir:
- net_slirp_redir(NULL, optarg);
+ net_slirp_redir(NULL, optarg, NULL);
break;
#endif
case QEMU_OPTION_bt:
@@ -5902,7 +5901,6 @@ int main(int argc, char **argv, char **envp)
cpu_exec_init_all(tb_size * 1024 * 1024);
bdrv_init();
- dma_helper_init();
/* we always create the cdrom drive, even if no disk is there */
diff --git a/vnc.c b/vnc.c
index 3f5d622ab..41defc2b4 100644
--- a/vnc.c
+++ b/vnc.c
@@ -2033,9 +2033,8 @@ static void vnc_listen_read(void *opaque)
void vnc_display_init(DisplayState *ds)
{
- VncDisplay *vs;
+ VncDisplay *vs = qemu_mallocz(sizeof(*vs));
- vs = qemu_mallocz(sizeof(VncState));
dcl = qemu_mallocz(sizeof(DisplayChangeListener));
ds->opaque = vs;