mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-27 05:20:50 +00:00
Miscellaneous patches for 2021-05-12
-----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAmCcALcSHGFybWJydUBy ZWRoYXQuY29tAAoJEDhwtADrkYZTjKYQAK75Rv2R3AGYDte6NmqKshoaE6p7imy2 iWE+CCdtxuhlqr2KLqZnGPvCYYz5ekqgvFLiDVe+DG3fLJm8VGHVdyJpdFZKZlEQ 4g74BpTVfuF4ZaSCBBKAAcC5qsWieAhqM5tZmrmI1vpxq0OsRDGKx13ntRu0oIaz 1TCqDv2k7bwA1+PL/qT9CdFgXlVlshIRXB4ahiynBByUBCItFRqn2dlaBRcSSTam 7fqncqsoWw/0ttTx8EaU4tJKW4mOJMVlbhDDWykTrBs4OV31iKB13+2Qec2qdo19 owfNlGO4sqgrkokepR+T3P6iT9ENAX1F9dS8wijGutCAvrxBxF+Av67o2V+ctjxS JkYBmDsjJWNV1gqjlt0MoeMQxgGnRN/21RZhog2uu7cVzNwv25Pn3CUOjvmsLrWm 2DKb7EgPXlR55qGz7B6I77/NkUIQO7pqb9qCPx6VRDoqLe5IF5nzBR9jvlbKyIlk vay6a/uiiUT0EJufHD+VhjTzBK9nfMP6dT/jB4wUb00OL2c0Y9Ns03mWnoINs2CG emHhC0ZLhUHV3qPWXQV3JOcWGILxaDqCBYEkwZ4l6Cpv15CW6wYqLtqI6w4aClVd hR1mTeoIt+73nixBnI8iIYTHt9W8ChN/QyY0rMBM/jkg077MtvF0uXoFfYOAVWXl 0tDiM3FDnN41 =OYV9 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/armbru/tags/pull-misc-2021-05-12' into staging Miscellaneous patches for 2021-05-12 # gpg: Signature made Wed 12 May 2021 17:22:15 BST # gpg: using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653 # gpg: issuer "armbru@redhat.com" # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full] # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" [full] # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * remotes/armbru/tags/pull-misc-2021-05-12: Drop the deprecated unicore32 target Drop the deprecated lm32 target block: Drop the sheepdog block driver Remove the deprecated moxie target monitor/qmp: fix race on CHR_EVENT_CLOSED without OOB Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
2d3fc4e2b0
@ -89,7 +89,7 @@ build-system-alpine:
|
||||
variables:
|
||||
IMAGE: alpine
|
||||
TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu
|
||||
moxie-softmmu microblazeel-softmmu mips64el-softmmu
|
||||
microblazeel-softmmu mips64el-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
CONFIGURE_ARGS: --enable-docs --enable-trace-backends=log,simple,syslog
|
||||
artifacts:
|
||||
@ -125,7 +125,7 @@ build-system-ubuntu:
|
||||
IMAGE: ubuntu2004
|
||||
CONFIGURE_ARGS: --enable-docs --enable-fdt=system --enable-slirp=system
|
||||
TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu
|
||||
moxie-softmmu microblazeel-softmmu mips64el-softmmu
|
||||
microblazeel-softmmu mips64el-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
@ -342,7 +342,6 @@ build-disabled:
|
||||
--disable-replication
|
||||
--disable-sdl
|
||||
--disable-seccomp
|
||||
--disable-sheepdog
|
||||
--disable-slirp
|
||||
--disable-smartcard
|
||||
--disable-snappy
|
||||
@ -625,7 +624,7 @@ build-deprecated:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --disable-tools
|
||||
MAKE_CHECK_ARGS: build-tcg
|
||||
TARGETS: ppc64abi32-linux-user lm32-softmmu unicore32-softmmu
|
||||
TARGETS: ppc64abi32-linux-user
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
@ -684,7 +683,7 @@ build-tci:
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
script:
|
||||
- TARGETS="aarch64 alpha arm hppa m68k microblaze moxie ppc64 s390x x86_64"
|
||||
- TARGETS="aarch64 alpha arm hppa m68k microblaze ppc64 s390x x86_64"
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-tcg-interpreter
|
||||
|
54
MAINTAINERS
54
MAINTAINERS
@ -207,19 +207,6 @@ F: disas/hppa.c
|
||||
F: hw/net/*i82596*
|
||||
F: include/hw/net/lasi_82596.h
|
||||
|
||||
LM32 TCG CPUs
|
||||
R: Michael Walle <michael@walle.cc>
|
||||
S: Orphan
|
||||
F: target/lm32/
|
||||
F: disas/lm32.c
|
||||
F: hw/lm32/
|
||||
F: hw/*/lm32_*
|
||||
F: hw/*/milkymist-*
|
||||
F: include/hw/display/milkymist_tmu2.h
|
||||
F: include/hw/char/lm32_juart.h
|
||||
F: include/hw/lm32/
|
||||
F: tests/tcg/lm32/
|
||||
|
||||
M68K TCG CPUs
|
||||
M: Laurent Vivier <laurent@vivier.eu>
|
||||
S: Maintained
|
||||
@ -258,14 +245,6 @@ MIPS TCG CPUs (nanoMIPS ISA)
|
||||
S: Orphan
|
||||
F: disas/nanomips.*
|
||||
|
||||
Moxie TCG CPUs
|
||||
M: Anthony Green <green@moxielogic.com>
|
||||
S: Maintained
|
||||
F: target/moxie/
|
||||
F: disas/moxie.c
|
||||
F: hw/moxie/
|
||||
F: default-configs/*/moxie-softmmu.mak
|
||||
|
||||
NiosII TCG CPUs
|
||||
M: Chris Wulff <crwulff@gmail.com>
|
||||
M: Marek Vasut <marex@denx.de>
|
||||
@ -338,13 +317,6 @@ F: hw/sparc64/
|
||||
F: include/hw/sparc/sparc64.h
|
||||
F: disas/sparc.c
|
||||
|
||||
UniCore32 TCG CPUs
|
||||
M: Guan Xuetao <gxt@mprc.pku.edu.cn>
|
||||
S: Maintained
|
||||
F: target/unicore32/
|
||||
F: hw/unicore32/
|
||||
F: include/hw/unicore32/
|
||||
|
||||
X86 TCG CPUs
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
M: Richard Henderson <richard.henderson@linaro.org>
|
||||
@ -1088,18 +1060,6 @@ F: default-configs/*/hppa-softmmu.mak
|
||||
F: hw/hppa/
|
||||
F: pc-bios/hppa-firmware.img
|
||||
|
||||
LM32 Machines
|
||||
-------------
|
||||
EVR32 and uclinux BSP
|
||||
R: Michael Walle <michael@walle.cc>
|
||||
S: Orphan
|
||||
F: hw/lm32/lm32_boards.c
|
||||
|
||||
milkymist
|
||||
R: Michael Walle <michael@walle.cc>
|
||||
S: Orphan
|
||||
F: hw/lm32/milkymist.c
|
||||
|
||||
M68K Machines
|
||||
-------------
|
||||
an5206
|
||||
@ -1549,14 +1509,6 @@ F: hw/s390x/s390-pci*
|
||||
F: include/hw/s390x/s390-pci*
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
UniCore32 Machines
|
||||
------------------
|
||||
PKUnity-3 SoC initramfs-with-busybox
|
||||
M: Guan Xuetao <gxt@mprc.pku.edu.cn>
|
||||
S: Maintained
|
||||
F: hw/*/puv3*
|
||||
F: hw/unicore32/
|
||||
|
||||
X86 Machines
|
||||
------------
|
||||
PC
|
||||
@ -3088,12 +3040,6 @@ L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/rbd.c
|
||||
|
||||
Sheepdog
|
||||
M: Liu Yuan <namei.unix@gmail.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: block/sheepdog.c
|
||||
|
||||
VHDX
|
||||
M: Jeff Cody <codyprime@gmail.com>
|
||||
L: qemu-block@nongnu.org
|
||||
|
@ -64,7 +64,6 @@ block_ss.add(when: 'CONFIG_POSIX', if_true: [files('file-posix.c'), coref, iokit
|
||||
block_ss.add(when: libiscsi, if_true: files('iscsi-opts.c'))
|
||||
block_ss.add(when: 'CONFIG_LINUX', if_true: files('nvme.c'))
|
||||
block_ss.add(when: 'CONFIG_REPLICATION', if_true: files('replication.c'))
|
||||
block_ss.add(when: 'CONFIG_SHEEPDOG', if_true: files('sheepdog.c'))
|
||||
block_ss.add(when: ['CONFIG_LINUX_AIO', libaio], if_true: files('linux-aio.c'))
|
||||
block_ss.add(when: ['CONFIG_LINUX_IO_URING', linux_io_uring], if_true: files('io_uring.c'))
|
||||
|
||||
|
3356
block/sheepdog.c
3356
block/sheepdog.c
File diff suppressed because it is too large
Load Diff
@ -207,19 +207,5 @@ file_FindEjectableOpticalMedia(const char *media) "Matching using %s"
|
||||
file_setup_cdrom(const char *partition) "Using %s as optical disc"
|
||||
file_hdev_is_sg(int type, int version) "SG device found: type=%d, version=%d"
|
||||
|
||||
# sheepdog.c
|
||||
sheepdog_reconnect_to_sdog(void) "Wait for connection to be established"
|
||||
sheepdog_aio_read_response(void) "disable cache since the server doesn't support it"
|
||||
sheepdog_open(uint32_t vid) "0x%" PRIx32 " snapshot inode was open"
|
||||
sheepdog_close(const char *name) "%s"
|
||||
sheepdog_create_branch_snapshot(uint32_t vdi) "0x%" PRIx32 " is snapshot"
|
||||
sheepdog_create_branch_created(uint32_t vdi) "0x%" PRIx32 " is created"
|
||||
sheepdog_create_branch_new(uint32_t vdi) "0x%" PRIx32 " was newly created"
|
||||
sheepdog_co_rw_vector_update(uint32_t vdi, uint64_t oid, uint64_t data, long idx) "update ino (%" PRIu32 ") %" PRIu64 " %" PRIu64 " %ld"
|
||||
sheepdog_co_rw_vector_new(uint64_t oid) "new oid 0x%" PRIx64
|
||||
sheepdog_snapshot_create_info(const char *sn_name, const char *id, const char *name, int64_t size, int is_snapshot) "sn_info: name %s id_str %s s: name %s vm_state_size %" PRId64 " " "is_snapshot %d"
|
||||
sheepdog_snapshot_create(const char *sn_name, const char *id) "%s %s"
|
||||
sheepdog_snapshot_create_inode(const char *name, uint32_t snap, uint32_t vdi) "s->inode: name %s snap_id 0x%" PRIx32 " vdi 0x%" PRIx32
|
||||
|
||||
# ssh.c
|
||||
sftp_error(const char *op, const char *ssh_err, int ssh_err_code, int sftp_err_code) "%s failed: %s (libssh error code: %d, sftp error code: %d)"
|
||||
|
17
configure
vendored
17
configure
vendored
@ -447,7 +447,6 @@ vdi=${default_feature:-yes}
|
||||
vvfat=${default_feature:-yes}
|
||||
qed=${default_feature:-yes}
|
||||
parallels=${default_feature:-yes}
|
||||
sheepdog="no"
|
||||
libxml2="$default_feature"
|
||||
debug_mutex="no"
|
||||
libpmem="$default_feature"
|
||||
@ -1478,10 +1477,6 @@ for opt do
|
||||
;;
|
||||
--enable-parallels) parallels="yes"
|
||||
;;
|
||||
--disable-sheepdog) sheepdog="no"
|
||||
;;
|
||||
--enable-sheepdog) sheepdog="yes"
|
||||
;;
|
||||
--disable-vhost-user) vhost_user="no"
|
||||
;;
|
||||
--enable-vhost-user) vhost_user="yes"
|
||||
@ -1668,7 +1663,7 @@ if [ "$ARCH" = "unknown" ]; then
|
||||
fi
|
||||
|
||||
default_target_list=""
|
||||
deprecated_targets_list=ppc64abi32-linux-user,lm32-softmmu,unicore32-softmmu
|
||||
deprecated_targets_list=ppc64abi32-linux-user
|
||||
deprecated_features=""
|
||||
mak_wilds=""
|
||||
|
||||
@ -1916,7 +1911,6 @@ disabled with --disable-FEATURE, default is enabled if available
|
||||
vvfat vvfat image format support
|
||||
qed qed image format support
|
||||
parallels parallels image format support
|
||||
sheepdog sheepdog block driver support (deprecated)
|
||||
crypto-afalg Linux AF_ALG crypto backend driver
|
||||
capstone capstone disassembler support
|
||||
debug-mutex mutex debugging support
|
||||
@ -3623,7 +3617,7 @@ case "$fdt" in
|
||||
esac
|
||||
|
||||
##########################################
|
||||
# opengl probe (for sdl2, gtk, milkymist-tmu2)
|
||||
# opengl probe (for sdl2, gtk)
|
||||
|
||||
gbm="no"
|
||||
if $pkg_config gbm; then
|
||||
@ -6108,10 +6102,6 @@ fi
|
||||
if test "$parallels" = "yes" ; then
|
||||
echo "CONFIG_PARALLELS=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$sheepdog" = "yes" ; then
|
||||
add_to deprecated_features "sheepdog"
|
||||
echo "CONFIG_SHEEPDOG=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$have_mlockall" = "yes" ; then
|
||||
echo "HAVE_MLOCKALL=y" >> $config_host_mak
|
||||
fi
|
||||
@ -6286,14 +6276,13 @@ fi
|
||||
# UNLINK is used to remove symlinks from older development versions
|
||||
# that might get into the way when doing "git update" without doing
|
||||
# a "make distclean" in between.
|
||||
DIRS="tests tests/tcg tests/tcg/lm32 tests/qapi-schema tests/qtest/libqos"
|
||||
DIRS="tests tests/tcg tests/qapi-schema tests/qtest/libqos"
|
||||
DIRS="$DIRS tests/qtest tests/qemu-iotests tests/vm tests/fp tests/qgraph"
|
||||
DIRS="$DIRS docs docs/interop fsdev scsi"
|
||||
DIRS="$DIRS pc-bios/optionrom pc-bios/s390-ccw"
|
||||
DIRS="$DIRS roms/seabios"
|
||||
DIRS="$DIRS contrib/plugins/"
|
||||
LINKS="Makefile"
|
||||
LINKS="$LINKS tests/tcg/lm32/Makefile"
|
||||
LINKS="$LINKS tests/tcg/Makefile.target"
|
||||
LINKS="$LINKS pc-bios/optionrom/Makefile"
|
||||
LINKS="$LINKS pc-bios/s390-ccw/Makefile"
|
||||
|
@ -1,12 +0,0 @@
|
||||
# Default configuration for lm32-softmmu
|
||||
|
||||
# Uncomment the following lines to disable these optional devices:
|
||||
#
|
||||
#CONFIG_MILKYMIST_TMU2=n # disabling it actually causes compile-time failures
|
||||
|
||||
CONFIG_SEMIHOSTING=y
|
||||
|
||||
# Boards:
|
||||
#
|
||||
CONFIG_LM32_EVR=y
|
||||
CONFIG_MILKYMIST=y
|
@ -1,5 +0,0 @@
|
||||
# Default configuration for moxie-softmmu
|
||||
|
||||
# Boards:
|
||||
#
|
||||
CONFIG_MOXIESIM=y
|
@ -1,6 +0,0 @@
|
||||
# Default configuration for unicore32-softmmu
|
||||
|
||||
# Boards:
|
||||
#
|
||||
CONFIG_PUV3=y
|
||||
CONFIG_SEMIHOSTING=y
|
@ -1,2 +0,0 @@
|
||||
TARGET_ARCH=lm32
|
||||
TARGET_WORDS_BIGENDIAN=y
|
@ -1,2 +0,0 @@
|
||||
TARGET_ARCH=moxie
|
||||
TARGET_WORDS_BIGENDIAN=y
|
@ -1 +0,0 @@
|
||||
TARGET_ARCH=unicore32
|
361
disas/lm32.c
361
disas/lm32.c
@ -1,361 +0,0 @@
|
||||
/*
|
||||
* Simple LatticeMico32 disassembler.
|
||||
*
|
||||
* Copyright (c) 2012 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "disas/dis-asm.h"
|
||||
|
||||
typedef enum {
|
||||
LM32_OP_SRUI = 0, LM32_OP_NORI, LM32_OP_MULI, LM32_OP_SH, LM32_OP_LB,
|
||||
LM32_OP_SRI, LM32_OP_XORI, LM32_OP_LH, LM32_OP_ANDI, LM32_OP_XNORI,
|
||||
LM32_OP_LW, LM32_OP_LHU, LM32_OP_SB, LM32_OP_ADDI, LM32_OP_ORI,
|
||||
LM32_OP_SLI, LM32_OP_LBU, LM32_OP_BE, LM32_OP_BG, LM32_OP_BGE,
|
||||
LM32_OP_BGEU, LM32_OP_BGU, LM32_OP_SW, LM32_OP_BNE, LM32_OP_ANDHI,
|
||||
LM32_OP_CMPEI, LM32_OP_CMPGI, LM32_OP_CMPGEI, LM32_OP_CMPGEUI,
|
||||
LM32_OP_CMPGUI, LM32_OP_ORHI, LM32_OP_CMPNEI, LM32_OP_SRU, LM32_OP_NOR,
|
||||
LM32_OP_MUL, LM32_OP_DIVU, LM32_OP_RCSR, LM32_OP_SR, LM32_OP_XOR,
|
||||
LM32_OP_ILL0, LM32_OP_AND, LM32_OP_XNOR, LM32_OP_ILL1, LM32_OP_SCALL,
|
||||
LM32_OP_SEXTB, LM32_OP_ADD, LM32_OP_OR, LM32_OP_SL, LM32_OP_B,
|
||||
LM32_OP_MODU, LM32_OP_SUB, LM32_OP_ILL2, LM32_OP_WCSR, LM32_OP_ILL3,
|
||||
LM32_OP_CALL, LM32_OP_SEXTH, LM32_OP_BI, LM32_OP_CMPE, LM32_OP_CMPG,
|
||||
LM32_OP_CMPGE, LM32_OP_CMPGEU, LM32_OP_CMPGU, LM32_OP_CALLI, LM32_OP_CMPNE,
|
||||
} Lm32Opcode;
|
||||
|
||||
typedef enum {
|
||||
FMT_INVALID = 0, FMT_RRI5, FMT_RRI16, FMT_IMM26, FMT_LOAD, FMT_STORE,
|
||||
FMT_RRR, FMT_R, FMT_RNR, FMT_CRN, FMT_CNR, FMT_BREAK,
|
||||
} Lm32OpcodeFmt;
|
||||
|
||||
typedef enum {
|
||||
LM32_CSR_IE = 0, LM32_CSR_IM, LM32_CSR_IP, LM32_CSR_ICC, LM32_CSR_DCC,
|
||||
LM32_CSR_CC, LM32_CSR_CFG, LM32_CSR_EBA, LM32_CSR_DC, LM32_CSR_DEBA,
|
||||
LM32_CSR_CFG2, LM32_CSR_JTX = 0xe, LM32_CSR_JRX, LM32_CSR_BP0,
|
||||
LM32_CSR_BP1, LM32_CSR_BP2, LM32_CSR_BP3, LM32_CSR_WP0 = 0x18,
|
||||
LM32_CSR_WP1, LM32_CSR_WP2, LM32_CSR_WP3,
|
||||
} Lm32CsrNum;
|
||||
|
||||
typedef struct {
|
||||
int csr;
|
||||
const char *name;
|
||||
} Lm32CsrInfo;
|
||||
|
||||
static const Lm32CsrInfo lm32_csr_info[] = {
|
||||
{LM32_CSR_IE, "ie", },
|
||||
{LM32_CSR_IM, "im", },
|
||||
{LM32_CSR_IP, "ip", },
|
||||
{LM32_CSR_ICC, "icc", },
|
||||
{LM32_CSR_DCC, "dcc", },
|
||||
{LM32_CSR_CC, "cc", },
|
||||
{LM32_CSR_CFG, "cfg", },
|
||||
{LM32_CSR_EBA, "eba", },
|
||||
{LM32_CSR_DC, "dc", },
|
||||
{LM32_CSR_DEBA, "deba", },
|
||||
{LM32_CSR_CFG2, "cfg2", },
|
||||
{LM32_CSR_JTX, "jtx", },
|
||||
{LM32_CSR_JRX, "jrx", },
|
||||
{LM32_CSR_BP0, "bp0", },
|
||||
{LM32_CSR_BP1, "bp1", },
|
||||
{LM32_CSR_BP2, "bp2", },
|
||||
{LM32_CSR_BP3, "bp3", },
|
||||
{LM32_CSR_WP0, "wp0", },
|
||||
{LM32_CSR_WP1, "wp1", },
|
||||
{LM32_CSR_WP2, "wp2", },
|
||||
{LM32_CSR_WP3, "wp3", },
|
||||
};
|
||||
|
||||
static const Lm32CsrInfo *find_csr_info(int csr)
|
||||
{
|
||||
const Lm32CsrInfo *info;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(lm32_csr_info); i++) {
|
||||
info = &lm32_csr_info[i];
|
||||
if (csr == info->csr) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int reg;
|
||||
const char *name;
|
||||
} Lm32RegInfo;
|
||||
|
||||
typedef enum {
|
||||
LM32_REG_R0 = 0, LM32_REG_R1, LM32_REG_R2, LM32_REG_R3, LM32_REG_R4,
|
||||
LM32_REG_R5, LM32_REG_R6, LM32_REG_R7, LM32_REG_R8, LM32_REG_R9,
|
||||
LM32_REG_R10, LM32_REG_R11, LM32_REG_R12, LM32_REG_R13, LM32_REG_R14,
|
||||
LM32_REG_R15, LM32_REG_R16, LM32_REG_R17, LM32_REG_R18, LM32_REG_R19,
|
||||
LM32_REG_R20, LM32_REG_R21, LM32_REG_R22, LM32_REG_R23, LM32_REG_R24,
|
||||
LM32_REG_R25, LM32_REG_GP, LM32_REG_FP, LM32_REG_SP, LM32_REG_RA,
|
||||
LM32_REG_EA, LM32_REG_BA,
|
||||
} Lm32RegNum;
|
||||
|
||||
static const Lm32RegInfo lm32_reg_info[] = {
|
||||
{LM32_REG_R0, "r0", },
|
||||
{LM32_REG_R1, "r1", },
|
||||
{LM32_REG_R2, "r2", },
|
||||
{LM32_REG_R3, "r3", },
|
||||
{LM32_REG_R4, "r4", },
|
||||
{LM32_REG_R5, "r5", },
|
||||
{LM32_REG_R6, "r6", },
|
||||
{LM32_REG_R7, "r7", },
|
||||
{LM32_REG_R8, "r8", },
|
||||
{LM32_REG_R9, "r9", },
|
||||
{LM32_REG_R10, "r10", },
|
||||
{LM32_REG_R11, "r11", },
|
||||
{LM32_REG_R12, "r12", },
|
||||
{LM32_REG_R13, "r13", },
|
||||
{LM32_REG_R14, "r14", },
|
||||
{LM32_REG_R15, "r15", },
|
||||
{LM32_REG_R16, "r16", },
|
||||
{LM32_REG_R17, "r17", },
|
||||
{LM32_REG_R18, "r18", },
|
||||
{LM32_REG_R19, "r19", },
|
||||
{LM32_REG_R20, "r20", },
|
||||
{LM32_REG_R21, "r21", },
|
||||
{LM32_REG_R22, "r22", },
|
||||
{LM32_REG_R23, "r23", },
|
||||
{LM32_REG_R24, "r24", },
|
||||
{LM32_REG_R25, "r25", },
|
||||
{LM32_REG_GP, "gp", },
|
||||
{LM32_REG_FP, "fp", },
|
||||
{LM32_REG_SP, "sp", },
|
||||
{LM32_REG_RA, "ra", },
|
||||
{LM32_REG_EA, "ea", },
|
||||
{LM32_REG_BA, "ba", },
|
||||
};
|
||||
|
||||
static const Lm32RegInfo *find_reg_info(int reg)
|
||||
{
|
||||
assert(ARRAY_SIZE(lm32_reg_info) == 32);
|
||||
return &lm32_reg_info[reg & 0x1f];
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
uint32_t code;
|
||||
uint32_t mask;
|
||||
} op;
|
||||
const char *name;
|
||||
const char *args_fmt;
|
||||
} Lm32OpcodeInfo;
|
||||
|
||||
static const Lm32OpcodeInfo lm32_opcode_info[] = {
|
||||
/* pseudo instructions */
|
||||
{{0x34000000, 0xffffffff}, "nop", NULL},
|
||||
{{0xac000002, 0xffffffff}, "break", NULL},
|
||||
{{0xac000003, 0xffffffff}, "scall", NULL},
|
||||
{{0xc3e00000, 0xffffffff}, "bret", NULL},
|
||||
{{0xc3c00000, 0xffffffff}, "eret", NULL},
|
||||
{{0xc3a00000, 0xffffffff}, "ret", NULL},
|
||||
{{0xa4000000, 0xfc1f07ff}, "not", "%2, %0"},
|
||||
{{0xb8000000, 0xfc1f07ff}, "mv", "%2, %0"},
|
||||
{{0x71e00000, 0xffe00000}, "mvhi", "%1, %u"},
|
||||
{{0x34000000, 0xffe00000}, "mvi", "%1, %s"},
|
||||
|
||||
#define _O(op) {op << 26, 0x3f << 26}
|
||||
/* regular opcodes */
|
||||
{_O(LM32_OP_ADD), "add", "%2, %0, %1" },
|
||||
{_O(LM32_OP_ADDI), "addi", "%1, %0, %s" },
|
||||
{_O(LM32_OP_AND), "and", "%2, %0, %1" },
|
||||
{_O(LM32_OP_ANDHI), "andhi", "%1, %0, %u" },
|
||||
{_O(LM32_OP_ANDI), "andi", "%1, %0, %u" },
|
||||
{_O(LM32_OP_B), "b", "%0", },
|
||||
{_O(LM32_OP_BE), "be", "%1, %0, %r" },
|
||||
{_O(LM32_OP_BG), "bg", "%1, %0, %r" },
|
||||
{_O(LM32_OP_BGE), "bge", "%1, %0, %r" },
|
||||
{_O(LM32_OP_BGEU), "bgeu", "%1, %0, %r" },
|
||||
{_O(LM32_OP_BGU), "bgu", "%1, %0, %r" },
|
||||
{_O(LM32_OP_BI), "bi", "%R", },
|
||||
{_O(LM32_OP_BNE), "bne", "%1, %0, %r" },
|
||||
{_O(LM32_OP_CALL), "call", "%0", },
|
||||
{_O(LM32_OP_CALLI), "calli", "%R", },
|
||||
{_O(LM32_OP_CMPE), "cmpe", "%2, %0, %1" },
|
||||
{_O(LM32_OP_CMPEI), "cmpei", "%1, %0, %s" },
|
||||
{_O(LM32_OP_CMPG), "cmpg", "%2, %0, %1" },
|
||||
{_O(LM32_OP_CMPGE), "cmpge", "%2, %0, %1" },
|
||||
{_O(LM32_OP_CMPGEI), "cmpgei", "%1, %0, %s" },
|
||||
{_O(LM32_OP_CMPGEU), "cmpgeu", "%2, %0, %1" },
|
||||
{_O(LM32_OP_CMPGEUI), "cmpgeui", "%1, %0, %s" },
|
||||
{_O(LM32_OP_CMPGI), "cmpgi", "%1, %0, %s" },
|
||||
{_O(LM32_OP_CMPGU), "cmpgu", "%2, %0, %1" },
|
||||
{_O(LM32_OP_CMPGUI), "cmpgui", "%1, %0, %s" },
|
||||
{_O(LM32_OP_CMPNE), "cmpne", "%2, %0, %1" },
|
||||
{_O(LM32_OP_CMPNEI), "cmpnei", "%1, %0, %s" },
|
||||
{_O(LM32_OP_DIVU), "divu", "%2, %0, %1" },
|
||||
{_O(LM32_OP_LB), "lb", "%1, (%0+%s)" },
|
||||
{_O(LM32_OP_LBU), "lbu", "%1, (%0+%s)" },
|
||||
{_O(LM32_OP_LH), "lh", "%1, (%0+%s)" },
|
||||
{_O(LM32_OP_LHU), "lhu", "%1, (%0+%s)" },
|
||||
{_O(LM32_OP_LW), "lw", "%1, (%0+%s)" },
|
||||
{_O(LM32_OP_MODU), "modu", "%2, %0, %1" },
|
||||
{_O(LM32_OP_MULI), "muli", "%1, %0, %s" },
|
||||
{_O(LM32_OP_MUL), "mul", "%2, %0, %1" },
|
||||
{_O(LM32_OP_NORI), "nori", "%1, %0, %u" },
|
||||
{_O(LM32_OP_NOR), "nor", "%2, %0, %1" },
|
||||
{_O(LM32_OP_ORHI), "orhi", "%1, %0, %u" },
|
||||
{_O(LM32_OP_ORI), "ori", "%1, %0, %u" },
|
||||
{_O(LM32_OP_OR), "or", "%2, %0, %1" },
|
||||
{_O(LM32_OP_RCSR), "rcsr", "%2, %c", },
|
||||
{_O(LM32_OP_SB), "sb", "(%0+%s), %1" },
|
||||
{_O(LM32_OP_SEXTB), "sextb", "%2, %0", },
|
||||
{_O(LM32_OP_SEXTH), "sexth", "%2, %0", },
|
||||
{_O(LM32_OP_SH), "sh", "(%0+%s), %1" },
|
||||
{_O(LM32_OP_SLI), "sli", "%1, %0, %h" },
|
||||
{_O(LM32_OP_SL), "sl", "%2, %0, %1" },
|
||||
{_O(LM32_OP_SRI), "sri", "%1, %0, %h" },
|
||||
{_O(LM32_OP_SR), "sr", "%2, %0, %1" },
|
||||
{_O(LM32_OP_SRUI), "srui", "%1, %0, %d" },
|
||||
{_O(LM32_OP_SRU), "sru", "%2, %0, %s" },
|
||||
{_O(LM32_OP_SUB), "sub", "%2, %0, %s" },
|
||||
{_O(LM32_OP_SW), "sw", "(%0+%s), %1" },
|
||||
{_O(LM32_OP_WCSR), "wcsr", "%c, %1", },
|
||||
{_O(LM32_OP_XNORI), "xnori", "%1, %0, %u" },
|
||||
{_O(LM32_OP_XNOR), "xnor", "%2, %0, %1" },
|
||||
{_O(LM32_OP_XORI), "xori", "%1, %0, %u" },
|
||||
{_O(LM32_OP_XOR), "xor", "%2, %0, %1" },
|
||||
#undef _O
|
||||
};
|
||||
|
||||
static const Lm32OpcodeInfo *find_opcode_info(uint32_t opcode)
|
||||
{
|
||||
const Lm32OpcodeInfo *info;
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(lm32_opcode_info); i++) {
|
||||
info = &lm32_opcode_info[i];
|
||||
if ((opcode & info->op.mask) == info->op.code) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int print_insn_lm32(bfd_vma memaddr, struct disassemble_info *info)
|
||||
{
|
||||
fprintf_function fprintf_fn = info->fprintf_func;
|
||||
void *stream = info->stream;
|
||||
int rc;
|
||||
uint8_t insn[4];
|
||||
const Lm32OpcodeInfo *opc_info;
|
||||
uint32_t op;
|
||||
const char *args_fmt;
|
||||
|
||||
rc = info->read_memory_func(memaddr, insn, 4, info);
|
||||
if (rc != 0) {
|
||||
info->memory_error_func(rc, memaddr, info);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fprintf_fn(stream, "%02x %02x %02x %02x ",
|
||||
insn[0], insn[1], insn[2], insn[3]);
|
||||
|
||||
op = bfd_getb32(insn);
|
||||
opc_info = find_opcode_info(op);
|
||||
if (opc_info) {
|
||||
fprintf_fn(stream, "%-8s ", opc_info->name);
|
||||
args_fmt = opc_info->args_fmt;
|
||||
while (args_fmt && *args_fmt) {
|
||||
if (*args_fmt == '%') {
|
||||
switch (*(++args_fmt)) {
|
||||
case '0': {
|
||||
uint8_t r0;
|
||||
const char *r0_name;
|
||||
r0 = (op >> 21) & 0x1f;
|
||||
r0_name = find_reg_info(r0)->name;
|
||||
fprintf_fn(stream, "%s", r0_name);
|
||||
break;
|
||||
}
|
||||
case '1': {
|
||||
uint8_t r1;
|
||||
const char *r1_name;
|
||||
r1 = (op >> 16) & 0x1f;
|
||||
r1_name = find_reg_info(r1)->name;
|
||||
fprintf_fn(stream, "%s", r1_name);
|
||||
break;
|
||||
}
|
||||
case '2': {
|
||||
uint8_t r2;
|
||||
const char *r2_name;
|
||||
r2 = (op >> 11) & 0x1f;
|
||||
r2_name = find_reg_info(r2)->name;
|
||||
fprintf_fn(stream, "%s", r2_name);
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
uint8_t csr;
|
||||
const Lm32CsrInfo *info;
|
||||
csr = (op >> 21) & 0x1f;
|
||||
info = find_csr_info(csr);
|
||||
if (info) {
|
||||
fprintf_fn(stream, "%s", info->name);
|
||||
} else {
|
||||
fprintf_fn(stream, "0x%x", csr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
uint16_t u16;
|
||||
u16 = op & 0xffff;
|
||||
fprintf_fn(stream, "0x%x", u16);
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
int16_t s16;
|
||||
s16 = (int16_t)(op & 0xffff);
|
||||
fprintf_fn(stream, "%d", s16);
|
||||
break;
|
||||
}
|
||||
case 'r': {
|
||||
uint32_t rela;
|
||||
rela = memaddr + (((int16_t)(op & 0xffff)) << 2);
|
||||
fprintf_fn(stream, "%x", rela);
|
||||
break;
|
||||
}
|
||||
case 'R': {
|
||||
uint32_t rela;
|
||||
int32_t imm26;
|
||||
imm26 = (int32_t)((op & 0x3ffffff) << 6) >> 4;
|
||||
rela = memaddr + imm26;
|
||||
fprintf_fn(stream, "%x", rela);
|
||||
break;
|
||||
}
|
||||
case 'h': {
|
||||
uint8_t u5;
|
||||
u5 = (op & 0x1f);
|
||||
fprintf_fn(stream, "%d", u5);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
fprintf_fn(stream, "%c", *args_fmt);
|
||||
}
|
||||
args_fmt++;
|
||||
}
|
||||
} else {
|
||||
fprintf_fn(stream, ".word 0x%x", op);
|
||||
}
|
||||
|
||||
return 4;
|
||||
}
|
@ -9,11 +9,9 @@ common_ss.add(when: 'CONFIG_CRIS_DIS', if_true: files('cris.c'))
|
||||
common_ss.add(when: 'CONFIG_HEXAGON_DIS', if_true: files('hexagon.c'))
|
||||
common_ss.add(when: 'CONFIG_HPPA_DIS', if_true: files('hppa.c'))
|
||||
common_ss.add(when: 'CONFIG_I386_DIS', if_true: files('i386.c'))
|
||||
common_ss.add(when: 'CONFIG_LM32_DIS', if_true: files('lm32.c'))
|
||||
common_ss.add(when: 'CONFIG_M68K_DIS', if_true: files('m68k.c'))
|
||||
common_ss.add(when: 'CONFIG_MICROBLAZE_DIS', if_true: files('microblaze.c'))
|
||||
common_ss.add(when: 'CONFIG_MIPS_DIS', if_true: files('mips.c'))
|
||||
common_ss.add(when: 'CONFIG_MOXIE_DIS', if_true: files('moxie.c'))
|
||||
common_ss.add(when: 'CONFIG_NANOMIPS_DIS', if_true: files('nanomips.cpp'))
|
||||
common_ss.add(when: 'CONFIG_NIOS2_DIS', if_true: files('nios2.c'))
|
||||
common_ss.add(when: 'CONFIG_PPC_DIS', if_true: files('ppc.c'))
|
||||
|
360
disas/moxie.c
360
disas/moxie.c
@ -1,360 +0,0 @@
|
||||
/* Disassemble moxie instructions.
|
||||
Copyright (c) 2009 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#define STATIC_TABLE
|
||||
#define DEFINE_TABLE
|
||||
|
||||
#include "disas/dis-asm.h"
|
||||
|
||||
static void *stream;
|
||||
|
||||
/* Form 1 instructions come in different flavors:
|
||||
|
||||
Some have no arguments (MOXIE_F1_NARG)
|
||||
Some only use the A operand (MOXIE_F1_A)
|
||||
Some use A and B registers (MOXIE_F1_AB)
|
||||
Some use A and consume a 4 byte immediate value (MOXIE_F1_A4)
|
||||
Some use just a 4 byte immediate value (MOXIE_F1_4)
|
||||
Some use just a 4 byte memory address (MOXIE_F1_M)
|
||||
Some use B and an indirect A (MOXIE_F1_AiB)
|
||||
Some use A and an indirect B (MOXIE_F1_ABi)
|
||||
Some consume a 4 byte immediate value and use X (MOXIE_F1_4A)
|
||||
Some use B and an indirect A plus 4 bytes (MOXIE_F1_AiB4)
|
||||
Some use A and an indirect B plus 4 bytes (MOXIE_F1_ABi4)
|
||||
|
||||
Form 2 instructions also come in different flavors:
|
||||
|
||||
Some have no arguments (MOXIE_F2_NARG)
|
||||
Some use the A register and an 8-bit value (MOXIE_F2_A8V)
|
||||
|
||||
Form 3 instructions also come in different flavors:
|
||||
|
||||
Some have no arguments (MOXIE_F3_NARG)
|
||||
Some have a 10-bit PC relative operand (MOXIE_F3_PCREL). */
|
||||
|
||||
#define MOXIE_F1_NARG 0x100
|
||||
#define MOXIE_F1_A 0x101
|
||||
#define MOXIE_F1_AB 0x102
|
||||
/* #define MOXIE_F1_ABC 0x103 */
|
||||
#define MOXIE_F1_A4 0x104
|
||||
#define MOXIE_F1_4 0x105
|
||||
#define MOXIE_F1_AiB 0x106
|
||||
#define MOXIE_F1_ABi 0x107
|
||||
#define MOXIE_F1_4A 0x108
|
||||
#define MOXIE_F1_AiB4 0x109
|
||||
#define MOXIE_F1_ABi4 0x10a
|
||||
#define MOXIE_F1_M 0x10b
|
||||
|
||||
#define MOXIE_F2_NARG 0x200
|
||||
#define MOXIE_F2_A8V 0x201
|
||||
|
||||
#define MOXIE_F3_NARG 0x300
|
||||
#define MOXIE_F3_PCREL 0x301
|
||||
|
||||
typedef struct moxie_opc_info_t {
|
||||
short opcode;
|
||||
unsigned itype;
|
||||
const char * name;
|
||||
} moxie_opc_info_t;
|
||||
|
||||
extern const moxie_opc_info_t moxie_form1_opc_info[64];
|
||||
extern const moxie_opc_info_t moxie_form2_opc_info[4];
|
||||
extern const moxie_opc_info_t moxie_form3_opc_info[16];
|
||||
|
||||
/* The moxie processor's 16-bit instructions come in two forms:
|
||||
|
||||
FORM 1 instructions start with a 0 bit...
|
||||
|
||||
0oooooooaaaabbbb
|
||||
0 F
|
||||
|
||||
ooooooo - form 1 opcode number
|
||||
aaaa - operand A
|
||||
bbbb - operand B
|
||||
|
||||
FORM 2 instructions start with bits "10"...
|
||||
|
||||
10ooaaaavvvvvvvv
|
||||
0 F
|
||||
|
||||
oo - form 2 opcode number
|
||||
aaaa - operand A
|
||||
vvvvvvvv - 8-bit immediate value
|
||||
|
||||
FORM 3 instructions start with a bits "11"...
|
||||
|
||||
11oooovvvvvvvvvv
|
||||
0 F
|
||||
|
||||
oooo - form 3 opcode number
|
||||
vvvvvvvvvv - 10-bit immediate value. */
|
||||
|
||||
const moxie_opc_info_t moxie_form1_opc_info[64] =
|
||||
{
|
||||
{ 0x00, MOXIE_F1_NARG, "nop" },
|
||||
{ 0x01, MOXIE_F1_A4, "ldi.l" },
|
||||
{ 0x02, MOXIE_F1_AB, "mov" },
|
||||
{ 0x03, MOXIE_F1_M, "jsra" },
|
||||
{ 0x04, MOXIE_F1_NARG, "ret" },
|
||||
{ 0x05, MOXIE_F1_AB, "add.l" },
|
||||
{ 0x06, MOXIE_F1_AB, "push" },
|
||||
{ 0x07, MOXIE_F1_AB, "pop" },
|
||||
{ 0x08, MOXIE_F1_A4, "lda.l" },
|
||||
{ 0x09, MOXIE_F1_4A, "sta.l" },
|
||||
{ 0x0a, MOXIE_F1_ABi, "ld.l" },
|
||||
{ 0x0b, MOXIE_F1_AiB, "st.l" },
|
||||
{ 0x0c, MOXIE_F1_ABi4, "ldo.l" },
|
||||
{ 0x0d, MOXIE_F1_AiB4, "sto.l" },
|
||||
{ 0x0e, MOXIE_F1_AB, "cmp" },
|
||||
{ 0x0f, MOXIE_F1_NARG, "bad" },
|
||||
{ 0x10, MOXIE_F1_NARG, "bad" },
|
||||
{ 0x11, MOXIE_F1_NARG, "bad" },
|
||||
{ 0x12, MOXIE_F1_NARG, "bad" },
|
||||
{ 0x13, MOXIE_F1_NARG, "bad" },
|
||||
{ 0x14, MOXIE_F1_NARG, "bad" },
|
||||
{ 0x15, MOXIE_F1_NARG, "bad" },
|
||||
{ 0x16, MOXIE_F1_NARG, "bad" },
|
||||
{ 0x17, MOXIE_F1_NARG, "bad" },
|
||||
{ 0x18, MOXIE_F1_NARG, "bad" },
|
||||
{ 0x19, MOXIE_F1_A, "jsr" },
|
||||
{ 0x1a, MOXIE_F1_M, "jmpa" },
|
||||
{ 0x1b, MOXIE_F1_A4, "ldi.b" },
|
||||
{ 0x1c, MOXIE_F1_ABi, "ld.b" },
|
||||
{ 0x1d, MOXIE_F1_A4, "lda.b" },
|
||||
{ 0x1e, MOXIE_F1_AiB, "st.b" },
|
||||
{ 0x1f, MOXIE_F1_4A, "sta.b" },
|
||||
{ 0x20, MOXIE_F1_A4, "ldi.s" },
|
||||
{ 0x21, MOXIE_F1_ABi, "ld.s" },
|
||||
{ 0x22, MOXIE_F1_A4, "lda.s" },
|
||||
{ 0x23, MOXIE_F1_AiB, "st.s" },
|
||||
{ 0x24, MOXIE_F1_4A, "sta.s" },
|
||||
{ 0x25, MOXIE_F1_A, "jmp" },
|
||||
{ 0x26, MOXIE_F1_AB, "and" },
|
||||
{ 0x27, MOXIE_F1_AB, "lshr" },
|
||||
{ 0x28, MOXIE_F1_AB, "ashl" },
|
||||
{ 0x29, MOXIE_F1_AB, "sub.l" },
|
||||
{ 0x2a, MOXIE_F1_AB, "neg" },
|
||||
{ 0x2b, MOXIE_F1_AB, "or" },
|
||||
{ 0x2c, MOXIE_F1_AB, "not" },
|
||||
{ 0x2d, MOXIE_F1_AB, "ashr" },
|
||||
{ 0x2e, MOXIE_F1_AB, "xor" },
|
||||
{ 0x2f, MOXIE_F1_AB, "mul.l" },
|
||||
{ 0x30, MOXIE_F1_4, "swi" },
|
||||
{ 0x31, MOXIE_F1_AB, "div.l" },
|
||||
{ 0x32, MOXIE_F1_AB, "udiv.l" },
|
||||
{ 0x33, MOXIE_F1_AB, "mod.l" },
|
||||
{ 0x34, MOXIE_F1_AB, "umod.l" },
|
||||
{ 0x35, MOXIE_F1_NARG, "brk" },
|
||||
{ 0x36, MOXIE_F1_ABi4, "ldo.b" },
|
||||
{ 0x37, MOXIE_F1_AiB4, "sto.b" },
|
||||
{ 0x38, MOXIE_F1_ABi4, "ldo.s" },
|
||||
{ 0x39, MOXIE_F1_AiB4, "sto.s" },
|
||||
{ 0x3a, MOXIE_F1_NARG, "bad" },
|
||||
{ 0x3b, MOXIE_F1_NARG, "bad" },
|
||||
{ 0x3c, MOXIE_F1_NARG, "bad" },
|
||||
{ 0x3d, MOXIE_F1_NARG, "bad" },
|
||||
{ 0x3e, MOXIE_F1_NARG, "bad" },
|
||||
{ 0x3f, MOXIE_F1_NARG, "bad" }
|
||||
};
|
||||
|
||||
const moxie_opc_info_t moxie_form2_opc_info[4] =
|
||||
{
|
||||
{ 0x00, MOXIE_F2_A8V, "inc" },
|
||||
{ 0x01, MOXIE_F2_A8V, "dec" },
|
||||
{ 0x02, MOXIE_F2_A8V, "gsr" },
|
||||
{ 0x03, MOXIE_F2_A8V, "ssr" }
|
||||
};
|
||||
|
||||
const moxie_opc_info_t moxie_form3_opc_info[16] =
|
||||
{
|
||||
{ 0x00, MOXIE_F3_PCREL,"beq" },
|
||||
{ 0x01, MOXIE_F3_PCREL,"bne" },
|
||||
{ 0x02, MOXIE_F3_PCREL,"blt" },
|
||||
{ 0x03, MOXIE_F3_PCREL,"bgt" },
|
||||
{ 0x04, MOXIE_F3_PCREL,"bltu" },
|
||||
{ 0x05, MOXIE_F3_PCREL,"bgtu" },
|
||||
{ 0x06, MOXIE_F3_PCREL,"bge" },
|
||||
{ 0x07, MOXIE_F3_PCREL,"ble" },
|
||||
{ 0x08, MOXIE_F3_PCREL,"bgeu" },
|
||||
{ 0x09, MOXIE_F3_PCREL,"bleu" },
|
||||
{ 0x0a, MOXIE_F3_NARG, "bad" },
|
||||
{ 0x0b, MOXIE_F3_NARG, "bad" },
|
||||
{ 0x0c, MOXIE_F3_NARG, "bad" },
|
||||
{ 0x0d, MOXIE_F3_NARG, "bad" },
|
||||
{ 0x0e, MOXIE_F3_NARG, "bad" },
|
||||
{ 0x0f, MOXIE_F3_NARG, "bad" }
|
||||
};
|
||||
|
||||
/* Macros to extract operands from the instruction word. */
|
||||
#define OP_A(i) ((i >> 4) & 0xf)
|
||||
#define OP_B(i) (i & 0xf)
|
||||
#define INST2OFFSET(o) ((((signed short)((o & ((1<<10)-1))<<6))>>6)<<1)
|
||||
|
||||
static const char * reg_names[16] =
|
||||
{ "$fp", "$sp", "$r0", "$r1", "$r2", "$r3", "$r4", "$r5",
|
||||
"$r6", "$r7", "$r8", "$r9", "$r10", "$r11", "$r12", "$r13" };
|
||||
|
||||
int
|
||||
print_insn_moxie(bfd_vma addr, struct disassemble_info * info)
|
||||
{
|
||||
int length = 2;
|
||||
int status;
|
||||
stream = info->stream;
|
||||
const moxie_opc_info_t * opcode;
|
||||
bfd_byte buffer[4];
|
||||
unsigned short iword;
|
||||
fprintf_function fpr = info->fprintf_func;
|
||||
|
||||
if ((status = info->read_memory_func(addr, buffer, 2, info)))
|
||||
goto fail;
|
||||
iword = (bfd_getb16(buffer) >> 16);
|
||||
|
||||
/* Form 1 instructions have the high bit set to 0. */
|
||||
if ((iword & (1<<15)) == 0) {
|
||||
/* Extract the Form 1 opcode. */
|
||||
opcode = &moxie_form1_opc_info[iword >> 8];
|
||||
switch (opcode->itype) {
|
||||
case MOXIE_F1_NARG:
|
||||
fpr(stream, "%s", opcode->name);
|
||||
break;
|
||||
case MOXIE_F1_A:
|
||||
fpr(stream, "%s\t%s", opcode->name,
|
||||
reg_names[OP_A(iword)]);
|
||||
break;
|
||||
case MOXIE_F1_AB:
|
||||
fpr(stream, "%s\t%s, %s", opcode->name,
|
||||
reg_names[OP_A(iword)],
|
||||
reg_names[OP_B(iword)]);
|
||||
break;
|
||||
case MOXIE_F1_A4:
|
||||
{
|
||||
unsigned imm;
|
||||
if ((status = info->read_memory_func(addr + 2, buffer, 4, info)))
|
||||
goto fail;
|
||||
imm = bfd_getb32(buffer);
|
||||
fpr(stream, "%s\t%s, 0x%x", opcode->name,
|
||||
reg_names[OP_A(iword)], imm);
|
||||
length = 6;
|
||||
}
|
||||
break;
|
||||
case MOXIE_F1_4:
|
||||
{
|
||||
unsigned imm;
|
||||
if ((status = info->read_memory_func(addr + 2, buffer, 4, info)))
|
||||
goto fail;
|
||||
imm = bfd_getb32(buffer);
|
||||
fpr(stream, "%s\t0x%x", opcode->name, imm);
|
||||
length = 6;
|
||||
}
|
||||
break;
|
||||
case MOXIE_F1_M:
|
||||
{
|
||||
unsigned imm;
|
||||
if ((status = info->read_memory_func(addr + 2, buffer, 4, info)))
|
||||
goto fail;
|
||||
imm = bfd_getb32(buffer);
|
||||
fpr(stream, "%s\t", opcode->name);
|
||||
info->print_address_func((bfd_vma) imm, info);
|
||||
length = 6;
|
||||
}
|
||||
break;
|
||||
case MOXIE_F1_AiB:
|
||||
fpr (stream, "%s\t(%s), %s", opcode->name,
|
||||
reg_names[OP_A(iword)], reg_names[OP_B(iword)]);
|
||||
break;
|
||||
case MOXIE_F1_ABi:
|
||||
fpr(stream, "%s\t%s, (%s)", opcode->name,
|
||||
reg_names[OP_A(iword)], reg_names[OP_B(iword)]);
|
||||
break;
|
||||
case MOXIE_F1_4A:
|
||||
{
|
||||
unsigned imm;
|
||||
if ((status = info->read_memory_func(addr + 2, buffer, 4, info)))
|
||||
goto fail;
|
||||
imm = bfd_getb32(buffer);
|
||||
fpr(stream, "%s\t0x%x, %s",
|
||||
opcode->name, imm, reg_names[OP_A(iword)]);
|
||||
length = 6;
|
||||
}
|
||||
break;
|
||||
case MOXIE_F1_AiB4:
|
||||
{
|
||||
unsigned imm;
|
||||
if ((status = info->read_memory_func(addr+2, buffer, 4, info)))
|
||||
goto fail;
|
||||
imm = bfd_getb32(buffer);
|
||||
fpr(stream, "%s\t0x%x(%s), %s", opcode->name,
|
||||
imm,
|
||||
reg_names[OP_A(iword)],
|
||||
reg_names[OP_B(iword)]);
|
||||
length = 6;
|
||||
}
|
||||
break;
|
||||
case MOXIE_F1_ABi4:
|
||||
{
|
||||
unsigned imm;
|
||||
if ((status = info->read_memory_func(addr+2, buffer, 4, info)))
|
||||
goto fail;
|
||||
imm = bfd_getb32(buffer);
|
||||
fpr(stream, "%s\t%s, 0x%x(%s)",
|
||||
opcode->name,
|
||||
reg_names[OP_A(iword)],
|
||||
imm,
|
||||
reg_names[OP_B(iword)]);
|
||||
length = 6;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
else if ((iword & (1<<14)) == 0) {
|
||||
/* Extract the Form 2 opcode. */
|
||||
opcode = &moxie_form2_opc_info[(iword >> 12) & 3];
|
||||
switch (opcode->itype) {
|
||||
case MOXIE_F2_A8V:
|
||||
fpr(stream, "%s\t%s, 0x%x",
|
||||
opcode->name,
|
||||
reg_names[(iword >> 8) & 0xf],
|
||||
iword & ((1 << 8) - 1));
|
||||
break;
|
||||
case MOXIE_F2_NARG:
|
||||
fpr(stream, "%s", opcode->name);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
/* Extract the Form 3 opcode. */
|
||||
opcode = &moxie_form3_opc_info[(iword >> 10) & 15];
|
||||
switch (opcode->itype) {
|
||||
case MOXIE_F3_PCREL:
|
||||
fpr(stream, "%s\t", opcode->name);
|
||||
info->print_address_func((bfd_vma) (addr + INST2OFFSET(iword) + 2),
|
||||
info);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
|
||||
fail:
|
||||
info->memory_error_func(status, addr, info);
|
||||
return -1;
|
||||
}
|
@ -198,30 +198,6 @@ from Linux upstream kernel, declare it deprecated.
|
||||
System emulator CPUS
|
||||
--------------------
|
||||
|
||||
``moxie`` CPU (since 5.2.0)
|
||||
'''''''''''''''''''''''''''
|
||||
|
||||
The ``moxie`` guest CPU support is deprecated and will be removed in
|
||||
a future version of QEMU. It's unclear whether anybody is still using
|
||||
CPU emulation in QEMU, and there are no test images available to make
|
||||
sure that the code is still working.
|
||||
|
||||
``lm32`` CPUs (since 5.2.0)
|
||||
'''''''''''''''''''''''''''
|
||||
|
||||
The ``lm32`` guest CPU support is deprecated and will be removed in
|
||||
a future version of QEMU. The only public user of this architecture
|
||||
was the milkymist project, which has been dead for years; there was
|
||||
never an upstream Linux port.
|
||||
|
||||
``unicore32`` CPUs (since 5.2.0)
|
||||
''''''''''''''''''''''''''''''''
|
||||
|
||||
The ``unicore32`` guest CPU support is deprecated and will be removed in
|
||||
a future version of QEMU. Support for this CPU was removed from the
|
||||
upstream Linux kernel, and there is no available upstream toolchain
|
||||
to build binaries for it.
|
||||
|
||||
``Icelake-Client`` CPU Model (since 5.2.0)
|
||||
''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
@ -293,15 +269,6 @@ The above, converted to the current supported format::
|
||||
|
||||
json:{"file.driver":"rbd", "file.pool":"rbd", "file.image":"name"}
|
||||
|
||||
``sheepdog`` driver (since 5.2.0)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The ``sheepdog`` block device driver is deprecated. The corresponding upstream
|
||||
server project is no longer actively maintained. Users are recommended to switch
|
||||
to an alternative distributed block device driver such as RBD. The
|
||||
``qemu-img convert`` command can be used to liberate existing data by moving
|
||||
it out of sheepdog volumes into an alternative storage backend.
|
||||
|
||||
linux-user mode CPUs
|
||||
--------------------
|
||||
|
||||
|
@ -85,24 +85,6 @@ These are specified using a special URL syntax.
|
||||
Currently authentication must be done using ssh-agent. Other
|
||||
authentication methods may be supported in future.
|
||||
|
||||
``Sheepdog``
|
||||
Sheepdog is a distributed storage system for QEMU. QEMU supports
|
||||
using either local sheepdog devices or remote networked devices.
|
||||
|
||||
Syntax for specifying a sheepdog device
|
||||
|
||||
::
|
||||
|
||||
sheepdog[+tcp|+unix]://[host:port]/vdiname[?socket=path][#snapid|#tag]
|
||||
|
||||
Example
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
|qemu_system| --drive file=sheepdog://192.0.2.1:30000/MyVirtualMachine
|
||||
|
||||
See also https://sheepdog.github.io/sheepdog/.
|
||||
|
||||
``GlusterFS``
|
||||
GlusterFS is a user space distributed file system. QEMU supports the
|
||||
use of GlusterFS volumes for hosting VM disk images using TCP, Unix
|
||||
|
@ -547,75 +547,6 @@ also available. Here are some example of the older syntax:
|
||||
|qemu_system| linux2.img -hdb nbd:unix:/tmp/my_socket
|
||||
|qemu_system| -cdrom nbd:localhost:10809:exportname=debian-500-ppc-netinst
|
||||
|
||||
|
||||
|
||||
Sheepdog disk images
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sheepdog is a distributed storage system for QEMU. It provides highly
|
||||
available block level storage volumes that can be attached to
|
||||
QEMU-based virtual machines.
|
||||
|
||||
You can create a Sheepdog disk image with the command:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
qemu-img create sheepdog:///IMAGE SIZE
|
||||
|
||||
where *IMAGE* is the Sheepdog image name and *SIZE* is its
|
||||
size.
|
||||
|
||||
To import the existing *FILENAME* to Sheepdog, you can use a
|
||||
convert command.
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
qemu-img convert FILENAME sheepdog:///IMAGE
|
||||
|
||||
You can boot from the Sheepdog disk image with the command:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
|qemu_system| sheepdog:///IMAGE
|
||||
|
||||
You can also create a snapshot of the Sheepdog image like qcow2.
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
qemu-img snapshot -c TAG sheepdog:///IMAGE
|
||||
|
||||
where *TAG* is a tag name of the newly created snapshot.
|
||||
|
||||
To boot from the Sheepdog snapshot, specify the tag name of the
|
||||
snapshot.
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
|qemu_system| sheepdog:///IMAGE#TAG
|
||||
|
||||
You can create a cloned image from the existing snapshot.
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
qemu-img create -b sheepdog:///BASE#TAG sheepdog:///IMAGE
|
||||
|
||||
where *BASE* is an image name of the source snapshot and *TAG*
|
||||
is its tag name.
|
||||
|
||||
You can use an unix socket instead of an inet socket:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
|qemu_system| sheepdog+unix:///IMAGE?socket=PATH
|
||||
|
||||
If the Sheepdog daemon doesn't run on the local host, you need to
|
||||
specify one of the Sheepdog servers to connect to.
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
qemu-img create sheepdog://HOSTNAME:PORT/IMAGE SIZE
|
||||
|qemu_system| sheepdog://HOSTNAME:PORT/IMAGE
|
||||
|
||||
iSCSI LUNs
|
||||
~~~~~~~~~~
|
||||
|
||||
|
@ -291,6 +291,27 @@ via the CPU ``mmu`` option when using the ``rv32`` or ``rv64`` CPUs.
|
||||
The ``max-cpu-compat`` property of the ``pseries`` machine type should be used
|
||||
instead.
|
||||
|
||||
``moxie`` CPU (removed in 6.1)
|
||||
''''''''''''''''''''''''''''''
|
||||
|
||||
Nobody was using this CPU emulation in QEMU, and there were no test images
|
||||
available to make sure that the code is still working, so it has been removed
|
||||
without replacement.
|
||||
|
||||
``lm32`` CPUs (removed in 6.1.0)
|
||||
''''''''''''''''''''''''''''''''
|
||||
|
||||
The only public user of this architecture was the milkymist project,
|
||||
which has been dead for years; there was never an upstream Linux
|
||||
port. Removed without replacement.
|
||||
|
||||
``unicore32`` CPUs (since 6.1.0)
|
||||
''''''''''''''''''''''''''''''''
|
||||
|
||||
Support for this CPU was removed from the upstream Linux kernel, and
|
||||
there is no available upstream toolchain to build binaries for it.
|
||||
Removed without replacement.
|
||||
|
||||
System emulator machines
|
||||
------------------------
|
||||
|
||||
@ -467,3 +488,10 @@ VXHS backend (removed in 5.1)
|
||||
'''''''''''''''''''''''''''''
|
||||
|
||||
The VXHS code did not compile since v2.12.0. It was removed in 5.1.
|
||||
|
||||
``sheepdog`` driver (removed in 6.0)
|
||||
''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The corresponding upstream server project is no longer maintained.
|
||||
Users are recommended to switch to an alternative distributed block
|
||||
device driver such as RBD.
|
||||
|
@ -103,7 +103,7 @@ static inline bool snan_bit_is_one(float_status *status)
|
||||
{
|
||||
#if defined(TARGET_MIPS)
|
||||
return status->snan_bit_is_one;
|
||||
#elif defined(TARGET_HPPA) || defined(TARGET_UNICORE32) || defined(TARGET_SH4)
|
||||
#elif defined(TARGET_HPPA) || defined(TARGET_SH4)
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
@ -149,11 +149,10 @@ static FloatParts parts_default_nan(float_status *status)
|
||||
sign = 1;
|
||||
frac = ~0ULL;
|
||||
#else
|
||||
/* This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V,
|
||||
* S390, SH4, TriCore, and Xtensa. I cannot find documentation
|
||||
* for Unicore32; the choice from the original commit is unchanged.
|
||||
* Our other supported targets, CRIS, LM32, Moxie, Nios2, and Tile,
|
||||
* do not have floating-point.
|
||||
/*
|
||||
* This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V,
|
||||
* S390, SH4, TriCore, and Xtensa. Our other supported targets,
|
||||
* CRIS, Nios2, and Tile, do not have floating-point.
|
||||
*/
|
||||
if (snan_bit_is_one(status)) {
|
||||
/* set all bits other than msb */
|
||||
|
@ -47,11 +47,9 @@ source avr/Kconfig
|
||||
source cris/Kconfig
|
||||
source hppa/Kconfig
|
||||
source i386/Kconfig
|
||||
source lm32/Kconfig
|
||||
source m68k/Kconfig
|
||||
source microblaze/Kconfig
|
||||
source mips/Kconfig
|
||||
source moxie/Kconfig
|
||||
source nios2/Kconfig
|
||||
source openrisc/Kconfig
|
||||
source ppc/Kconfig
|
||||
@ -62,7 +60,6 @@ source sh4/Kconfig
|
||||
source sparc/Kconfig
|
||||
source sparc64/Kconfig
|
||||
source tricore/Kconfig
|
||||
source unicore32/Kconfig
|
||||
source xtensa/Kconfig
|
||||
|
||||
# Symbols used by multiple targets
|
||||
|
@ -7,7 +7,6 @@ softmmu_ss.add(when: 'CONFIG_ES1370', if_true: files('es1370.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_GUS', if_true: files('gus.c', 'gusemu_hal.c', 'gusemu_mixer.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_HDA', if_true: files('intel-hda.c', 'hda-codec.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_MARVELL_88W8618', if_true: files('marvell_88w8618.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-ac97.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PCSPK', if_true: files('pcspk.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PL041', if_true: files('pl041.c', 'lm4549.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_SB16', if_true: files('sb16.c'))
|
||||
|
@ -1,360 +0,0 @@
|
||||
/*
|
||||
* QEMU model of the Milkymist System Controller.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Specification available at:
|
||||
* http://milkymist.walle.cc/socdoc/ac97.pdf
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
#include "audio/audio.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
enum {
|
||||
R_AC97_CTRL = 0,
|
||||
R_AC97_ADDR,
|
||||
R_AC97_DATAOUT,
|
||||
R_AC97_DATAIN,
|
||||
R_D_CTRL,
|
||||
R_D_ADDR,
|
||||
R_D_REMAINING,
|
||||
R_RESERVED,
|
||||
R_U_CTRL,
|
||||
R_U_ADDR,
|
||||
R_U_REMAINING,
|
||||
R_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
AC97_CTRL_RQEN = (1<<0),
|
||||
AC97_CTRL_WRITE = (1<<1),
|
||||
};
|
||||
|
||||
enum {
|
||||
CTRL_EN = (1<<0),
|
||||
};
|
||||
|
||||
#define TYPE_MILKYMIST_AC97 "milkymist-ac97"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(MilkymistAC97State, MILKYMIST_AC97)
|
||||
|
||||
struct MilkymistAC97State {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion regs_region;
|
||||
|
||||
QEMUSoundCard card;
|
||||
SWVoiceIn *voice_in;
|
||||
SWVoiceOut *voice_out;
|
||||
|
||||
uint32_t regs[R_MAX];
|
||||
|
||||
qemu_irq crrequest_irq;
|
||||
qemu_irq crreply_irq;
|
||||
qemu_irq dmar_irq;
|
||||
qemu_irq dmaw_irq;
|
||||
};
|
||||
|
||||
static void update_voices(MilkymistAC97State *s)
|
||||
{
|
||||
if (s->regs[R_D_CTRL] & CTRL_EN) {
|
||||
AUD_set_active_out(s->voice_out, 1);
|
||||
} else {
|
||||
AUD_set_active_out(s->voice_out, 0);
|
||||
}
|
||||
|
||||
if (s->regs[R_U_CTRL] & CTRL_EN) {
|
||||
AUD_set_active_in(s->voice_in, 1);
|
||||
} else {
|
||||
AUD_set_active_in(s->voice_in, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t ac97_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistAC97State *s = opaque;
|
||||
uint32_t r = 0;
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_AC97_CTRL:
|
||||
case R_AC97_ADDR:
|
||||
case R_AC97_DATAOUT:
|
||||
case R_AC97_DATAIN:
|
||||
case R_D_CTRL:
|
||||
case R_D_ADDR:
|
||||
case R_D_REMAINING:
|
||||
case R_U_CTRL:
|
||||
case R_U_ADDR:
|
||||
case R_U_REMAINING:
|
||||
r = s->regs[addr];
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("milkymist_ac97: read access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_milkymist_ac97_memory_read(addr << 2, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void ac97_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistAC97State *s = opaque;
|
||||
|
||||
trace_milkymist_ac97_memory_write(addr, value);
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_AC97_CTRL:
|
||||
/* always raise an IRQ according to the direction */
|
||||
if (value & AC97_CTRL_RQEN) {
|
||||
if (value & AC97_CTRL_WRITE) {
|
||||
trace_milkymist_ac97_pulse_irq_crrequest();
|
||||
qemu_irq_pulse(s->crrequest_irq);
|
||||
} else {
|
||||
trace_milkymist_ac97_pulse_irq_crreply();
|
||||
qemu_irq_pulse(s->crreply_irq);
|
||||
}
|
||||
}
|
||||
|
||||
/* RQEN is self clearing */
|
||||
s->regs[addr] = value & ~AC97_CTRL_RQEN;
|
||||
break;
|
||||
case R_D_CTRL:
|
||||
case R_U_CTRL:
|
||||
s->regs[addr] = value;
|
||||
update_voices(s);
|
||||
break;
|
||||
case R_AC97_ADDR:
|
||||
case R_AC97_DATAOUT:
|
||||
case R_AC97_DATAIN:
|
||||
case R_D_ADDR:
|
||||
case R_D_REMAINING:
|
||||
case R_U_ADDR:
|
||||
case R_U_REMAINING:
|
||||
s->regs[addr] = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("milkymist_ac97: write access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static const MemoryRegionOps ac97_mmio_ops = {
|
||||
.read = ac97_read,
|
||||
.write = ac97_write,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void ac97_in_cb(void *opaque, int avail_b)
|
||||
{
|
||||
MilkymistAC97State *s = opaque;
|
||||
uint8_t buf[4096];
|
||||
uint32_t remaining = s->regs[R_U_REMAINING];
|
||||
int temp = MIN(remaining, avail_b);
|
||||
uint32_t addr = s->regs[R_U_ADDR];
|
||||
int transferred = 0;
|
||||
|
||||
trace_milkymist_ac97_in_cb(avail_b, remaining);
|
||||
|
||||
/* prevent from raising an IRQ */
|
||||
if (temp == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (temp) {
|
||||
int acquired, to_copy;
|
||||
|
||||
to_copy = MIN(temp, sizeof(buf));
|
||||
acquired = AUD_read(s->voice_in, buf, to_copy);
|
||||
if (!acquired) {
|
||||
break;
|
||||
}
|
||||
|
||||
cpu_physical_memory_write(addr, buf, acquired);
|
||||
|
||||
temp -= acquired;
|
||||
addr += acquired;
|
||||
transferred += acquired;
|
||||
}
|
||||
|
||||
trace_milkymist_ac97_in_cb_transferred(transferred);
|
||||
|
||||
s->regs[R_U_ADDR] = addr;
|
||||
s->regs[R_U_REMAINING] -= transferred;
|
||||
|
||||
if ((s->regs[R_U_CTRL] & CTRL_EN) && (s->regs[R_U_REMAINING] == 0)) {
|
||||
trace_milkymist_ac97_pulse_irq_dmaw();
|
||||
qemu_irq_pulse(s->dmaw_irq);
|
||||
}
|
||||
}
|
||||
|
||||
static void ac97_out_cb(void *opaque, int free_b)
|
||||
{
|
||||
MilkymistAC97State *s = opaque;
|
||||
uint8_t buf[4096];
|
||||
uint32_t remaining = s->regs[R_D_REMAINING];
|
||||
int temp = MIN(remaining, free_b);
|
||||
uint32_t addr = s->regs[R_D_ADDR];
|
||||
int transferred = 0;
|
||||
|
||||
trace_milkymist_ac97_out_cb(free_b, remaining);
|
||||
|
||||
/* prevent from raising an IRQ */
|
||||
if (temp == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (temp) {
|
||||
int copied, to_copy;
|
||||
|
||||
to_copy = MIN(temp, sizeof(buf));
|
||||
cpu_physical_memory_read(addr, buf, to_copy);
|
||||
copied = AUD_write(s->voice_out, buf, to_copy);
|
||||
if (!copied) {
|
||||
break;
|
||||
}
|
||||
temp -= copied;
|
||||
addr += copied;
|
||||
transferred += copied;
|
||||
}
|
||||
|
||||
trace_milkymist_ac97_out_cb_transferred(transferred);
|
||||
|
||||
s->regs[R_D_ADDR] = addr;
|
||||
s->regs[R_D_REMAINING] -= transferred;
|
||||
|
||||
if ((s->regs[R_D_CTRL] & CTRL_EN) && (s->regs[R_D_REMAINING] == 0)) {
|
||||
trace_milkymist_ac97_pulse_irq_dmar();
|
||||
qemu_irq_pulse(s->dmar_irq);
|
||||
}
|
||||
}
|
||||
|
||||
static void milkymist_ac97_reset(DeviceState *d)
|
||||
{
|
||||
MilkymistAC97State *s = MILKYMIST_AC97(d);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < R_MAX; i++) {
|
||||
s->regs[i] = 0;
|
||||
}
|
||||
|
||||
AUD_set_active_in(s->voice_in, 0);
|
||||
AUD_set_active_out(s->voice_out, 0);
|
||||
}
|
||||
|
||||
static int ac97_post_load(void *opaque, int version_id)
|
||||
{
|
||||
MilkymistAC97State *s = opaque;
|
||||
|
||||
update_voices(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void milkymist_ac97_init(Object *obj)
|
||||
{
|
||||
MilkymistAC97State *s = MILKYMIST_AC97(obj);
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
|
||||
sysbus_init_irq(dev, &s->crrequest_irq);
|
||||
sysbus_init_irq(dev, &s->crreply_irq);
|
||||
sysbus_init_irq(dev, &s->dmar_irq);
|
||||
sysbus_init_irq(dev, &s->dmaw_irq);
|
||||
|
||||
memory_region_init_io(&s->regs_region, obj, &ac97_mmio_ops, s,
|
||||
"milkymist-ac97", R_MAX * 4);
|
||||
sysbus_init_mmio(dev, &s->regs_region);
|
||||
}
|
||||
|
||||
static void milkymist_ac97_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MilkymistAC97State *s = MILKYMIST_AC97(dev);
|
||||
struct audsettings as;
|
||||
|
||||
AUD_register_card("Milkymist AC'97", &s->card);
|
||||
|
||||
as.freq = 48000;
|
||||
as.nchannels = 2;
|
||||
as.fmt = AUDIO_FORMAT_S16;
|
||||
as.endianness = 1;
|
||||
|
||||
s->voice_in = AUD_open_in(&s->card, s->voice_in,
|
||||
"mm_ac97.in", s, ac97_in_cb, &as);
|
||||
s->voice_out = AUD_open_out(&s->card, s->voice_out,
|
||||
"mm_ac97.out", s, ac97_out_cb, &as);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_milkymist_ac97 = {
|
||||
.name = "milkymist-ac97",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.post_load = ac97_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property milkymist_ac97_properties[] = {
|
||||
DEFINE_AUDIO_PROPERTIES(MilkymistAC97State, card),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void milkymist_ac97_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = milkymist_ac97_realize;
|
||||
dc->reset = milkymist_ac97_reset;
|
||||
dc->vmsd = &vmstate_milkymist_ac97;
|
||||
device_class_set_props(dc, milkymist_ac97_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo milkymist_ac97_info = {
|
||||
.name = TYPE_MILKYMIST_AC97,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MilkymistAC97State),
|
||||
.instance_init = milkymist_ac97_init,
|
||||
.class_init = milkymist_ac97_class_init,
|
||||
};
|
||||
|
||||
static void milkymist_ac97_register_types(void)
|
||||
{
|
||||
type_register_static(&milkymist_ac97_info);
|
||||
}
|
||||
|
||||
type_init(milkymist_ac97_register_types)
|
@ -6,18 +6,6 @@ cs4231_mem_readl_reg(uint32_t reg, uint32_t ret) "read reg %d: 0x%08x"
|
||||
cs4231_mem_writel_reg(uint32_t reg, uint32_t old, uint32_t val) "write reg %d: 0x%08x -> 0x%08x"
|
||||
cs4231_mem_writel_dreg(uint32_t reg, uint32_t old, uint32_t val) "write dreg %d: 0x%02x -> 0x%02x"
|
||||
|
||||
# milkymist-ac97.c
|
||||
milkymist_ac97_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
milkymist_ac97_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
milkymist_ac97_pulse_irq_crrequest(void) "Pulse IRQ CR request"
|
||||
milkymist_ac97_pulse_irq_crreply(void) "Pulse IRQ CR reply"
|
||||
milkymist_ac97_pulse_irq_dmaw(void) "Pulse IRQ DMA write"
|
||||
milkymist_ac97_pulse_irq_dmar(void) "Pulse IRQ DMA read"
|
||||
milkymist_ac97_in_cb(int avail, uint32_t remaining) "avail %d remaining %u"
|
||||
milkymist_ac97_in_cb_transferred(int transferred) "transferred %d"
|
||||
milkymist_ac97_out_cb(int free, uint32_t remaining) "free %d remaining %u"
|
||||
milkymist_ac97_out_cb_transferred(int transferred) "transferred %d"
|
||||
|
||||
# hda-codec.c
|
||||
hda_audio_running(const char *stream, int nr, bool running) "st %s, nr %d, run %d"
|
||||
hda_audio_format(const char *stream, int chan, const char *fmt, int freq) "st %s, %d x %s @ %d Hz"
|
||||
|
@ -1,166 +0,0 @@
|
||||
/*
|
||||
* LatticeMico32 JTAG UART model.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qemu/module.h"
|
||||
#include "trace.h"
|
||||
#include "chardev/char-fe.h"
|
||||
|
||||
#include "hw/char/lm32_juart.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/qdev-properties-system.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
enum {
|
||||
LM32_JUART_MIN_SAVE_VERSION = 0,
|
||||
LM32_JUART_CURRENT_SAVE_VERSION = 0,
|
||||
LM32_JUART_MAX_SAVE_VERSION = 0,
|
||||
};
|
||||
|
||||
enum {
|
||||
JTX_FULL = (1<<8),
|
||||
};
|
||||
|
||||
enum {
|
||||
JRX_FULL = (1<<8),
|
||||
};
|
||||
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(LM32JuartState, LM32_JUART)
|
||||
|
||||
struct LM32JuartState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
CharBackend chr;
|
||||
|
||||
uint32_t jtx;
|
||||
uint32_t jrx;
|
||||
};
|
||||
|
||||
uint32_t lm32_juart_get_jtx(DeviceState *d)
|
||||
{
|
||||
LM32JuartState *s = LM32_JUART(d);
|
||||
|
||||
trace_lm32_juart_get_jtx(s->jtx);
|
||||
return s->jtx;
|
||||
}
|
||||
|
||||
uint32_t lm32_juart_get_jrx(DeviceState *d)
|
||||
{
|
||||
LM32JuartState *s = LM32_JUART(d);
|
||||
|
||||
trace_lm32_juart_get_jrx(s->jrx);
|
||||
return s->jrx;
|
||||
}
|
||||
|
||||
void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx)
|
||||
{
|
||||
LM32JuartState *s = LM32_JUART(d);
|
||||
unsigned char ch = jtx & 0xff;
|
||||
|
||||
trace_lm32_juart_set_jtx(s->jtx);
|
||||
|
||||
s->jtx = jtx;
|
||||
/* XXX this blocks entire thread. Rewrite to use
|
||||
* qemu_chr_fe_write and background I/O callbacks */
|
||||
qemu_chr_fe_write_all(&s->chr, &ch, 1);
|
||||
}
|
||||
|
||||
void lm32_juart_set_jrx(DeviceState *d, uint32_t jtx)
|
||||
{
|
||||
LM32JuartState *s = LM32_JUART(d);
|
||||
|
||||
trace_lm32_juart_set_jrx(s->jrx);
|
||||
s->jrx &= ~JRX_FULL;
|
||||
}
|
||||
|
||||
static void juart_rx(void *opaque, const uint8_t *buf, int size)
|
||||
{
|
||||
LM32JuartState *s = opaque;
|
||||
|
||||
s->jrx = *buf | JRX_FULL;
|
||||
}
|
||||
|
||||
static int juart_can_rx(void *opaque)
|
||||
{
|
||||
LM32JuartState *s = opaque;
|
||||
|
||||
return !(s->jrx & JRX_FULL);
|
||||
}
|
||||
|
||||
static void juart_event(void *opaque, QEMUChrEvent event)
|
||||
{
|
||||
}
|
||||
|
||||
static void juart_reset(DeviceState *d)
|
||||
{
|
||||
LM32JuartState *s = LM32_JUART(d);
|
||||
|
||||
s->jtx = 0;
|
||||
s->jrx = 0;
|
||||
}
|
||||
|
||||
static void lm32_juart_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
LM32JuartState *s = LM32_JUART(dev);
|
||||
|
||||
qemu_chr_fe_set_handlers(&s->chr, juart_can_rx, juart_rx,
|
||||
juart_event, NULL, s, NULL, true);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_lm32_juart = {
|
||||
.name = "lm32-juart",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(jtx, LM32JuartState),
|
||||
VMSTATE_UINT32(jrx, LM32JuartState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property lm32_juart_properties[] = {
|
||||
DEFINE_PROP_CHR("chardev", LM32JuartState, chr),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void lm32_juart_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->reset = juart_reset;
|
||||
dc->vmsd = &vmstate_lm32_juart;
|
||||
device_class_set_props(dc, lm32_juart_properties);
|
||||
dc->realize = lm32_juart_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo lm32_juart_info = {
|
||||
.name = TYPE_LM32_JUART,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(LM32JuartState),
|
||||
.class_init = lm32_juart_class_init,
|
||||
};
|
||||
|
||||
static void lm32_juart_register_types(void)
|
||||
{
|
||||
type_register_static(&lm32_juart_info);
|
||||
}
|
||||
|
||||
type_init(lm32_juart_register_types)
|
@ -1,314 +0,0 @@
|
||||
/*
|
||||
* QEMU model of the LatticeMico32 UART block.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Specification available at:
|
||||
* http://www.latticesemi.com/documents/mico32uart.pdf
|
||||
*/
|
||||
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/qdev-properties-system.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
enum {
|
||||
R_RXTX = 0,
|
||||
R_IER,
|
||||
R_IIR,
|
||||
R_LCR,
|
||||
R_MCR,
|
||||
R_LSR,
|
||||
R_MSR,
|
||||
R_DIV,
|
||||
R_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
IER_RBRI = (1<<0),
|
||||
IER_THRI = (1<<1),
|
||||
IER_RLSI = (1<<2),
|
||||
IER_MSI = (1<<3),
|
||||
};
|
||||
|
||||
enum {
|
||||
IIR_STAT = (1<<0),
|
||||
IIR_ID0 = (1<<1),
|
||||
IIR_ID1 = (1<<2),
|
||||
};
|
||||
|
||||
enum {
|
||||
LCR_WLS0 = (1<<0),
|
||||
LCR_WLS1 = (1<<1),
|
||||
LCR_STB = (1<<2),
|
||||
LCR_PEN = (1<<3),
|
||||
LCR_EPS = (1<<4),
|
||||
LCR_SP = (1<<5),
|
||||
LCR_SB = (1<<6),
|
||||
};
|
||||
|
||||
enum {
|
||||
MCR_DTR = (1<<0),
|
||||
MCR_RTS = (1<<1),
|
||||
};
|
||||
|
||||
enum {
|
||||
LSR_DR = (1<<0),
|
||||
LSR_OE = (1<<1),
|
||||
LSR_PE = (1<<2),
|
||||
LSR_FE = (1<<3),
|
||||
LSR_BI = (1<<4),
|
||||
LSR_THRE = (1<<5),
|
||||
LSR_TEMT = (1<<6),
|
||||
};
|
||||
|
||||
enum {
|
||||
MSR_DCTS = (1<<0),
|
||||
MSR_DDSR = (1<<1),
|
||||
MSR_TERI = (1<<2),
|
||||
MSR_DDCD = (1<<3),
|
||||
MSR_CTS = (1<<4),
|
||||
MSR_DSR = (1<<5),
|
||||
MSR_RI = (1<<6),
|
||||
MSR_DCD = (1<<7),
|
||||
};
|
||||
|
||||
#define TYPE_LM32_UART "lm32-uart"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(LM32UartState, LM32_UART)
|
||||
|
||||
struct LM32UartState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
CharBackend chr;
|
||||
qemu_irq irq;
|
||||
|
||||
uint32_t regs[R_MAX];
|
||||
};
|
||||
|
||||
static void uart_update_irq(LM32UartState *s)
|
||||
{
|
||||
unsigned int irq;
|
||||
|
||||
if ((s->regs[R_LSR] & (LSR_OE | LSR_PE | LSR_FE | LSR_BI))
|
||||
&& (s->regs[R_IER] & IER_RLSI)) {
|
||||
irq = 1;
|
||||
s->regs[R_IIR] = IIR_ID1 | IIR_ID0;
|
||||
} else if ((s->regs[R_LSR] & LSR_DR) && (s->regs[R_IER] & IER_RBRI)) {
|
||||
irq = 1;
|
||||
s->regs[R_IIR] = IIR_ID1;
|
||||
} else if ((s->regs[R_LSR] & LSR_THRE) && (s->regs[R_IER] & IER_THRI)) {
|
||||
irq = 1;
|
||||
s->regs[R_IIR] = IIR_ID0;
|
||||
} else if ((s->regs[R_MSR] & 0x0f) && (s->regs[R_IER] & IER_MSI)) {
|
||||
irq = 1;
|
||||
s->regs[R_IIR] = 0;
|
||||
} else {
|
||||
irq = 0;
|
||||
s->regs[R_IIR] = IIR_STAT;
|
||||
}
|
||||
|
||||
trace_lm32_uart_irq_state(irq);
|
||||
qemu_set_irq(s->irq, irq);
|
||||
}
|
||||
|
||||
static uint64_t uart_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
LM32UartState *s = opaque;
|
||||
uint32_t r = 0;
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_RXTX:
|
||||
r = s->regs[R_RXTX];
|
||||
s->regs[R_LSR] &= ~LSR_DR;
|
||||
uart_update_irq(s);
|
||||
qemu_chr_fe_accept_input(&s->chr);
|
||||
break;
|
||||
case R_IIR:
|
||||
case R_LSR:
|
||||
case R_MSR:
|
||||
r = s->regs[addr];
|
||||
break;
|
||||
case R_IER:
|
||||
case R_LCR:
|
||||
case R_MCR:
|
||||
case R_DIV:
|
||||
error_report("lm32_uart: read access to write only register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
default:
|
||||
error_report("lm32_uart: read access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_lm32_uart_memory_read(addr << 2, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void uart_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
LM32UartState *s = opaque;
|
||||
unsigned char ch = value;
|
||||
|
||||
trace_lm32_uart_memory_write(addr, value);
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_RXTX:
|
||||
/* XXX this blocks entire thread. Rewrite to use
|
||||
* qemu_chr_fe_write and background I/O callbacks */
|
||||
qemu_chr_fe_write_all(&s->chr, &ch, 1);
|
||||
break;
|
||||
case R_IER:
|
||||
case R_LCR:
|
||||
case R_MCR:
|
||||
case R_DIV:
|
||||
s->regs[addr] = value;
|
||||
break;
|
||||
case R_IIR:
|
||||
case R_LSR:
|
||||
case R_MSR:
|
||||
error_report("lm32_uart: write access to read only register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
default:
|
||||
error_report("lm32_uart: write access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
uart_update_irq(s);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps uart_ops = {
|
||||
.read = uart_read,
|
||||
.write = uart_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void uart_rx(void *opaque, const uint8_t *buf, int size)
|
||||
{
|
||||
LM32UartState *s = opaque;
|
||||
|
||||
if (s->regs[R_LSR] & LSR_DR) {
|
||||
s->regs[R_LSR] |= LSR_OE;
|
||||
}
|
||||
|
||||
s->regs[R_LSR] |= LSR_DR;
|
||||
s->regs[R_RXTX] = *buf;
|
||||
|
||||
uart_update_irq(s);
|
||||
}
|
||||
|
||||
static int uart_can_rx(void *opaque)
|
||||
{
|
||||
LM32UartState *s = opaque;
|
||||
|
||||
return !(s->regs[R_LSR] & LSR_DR);
|
||||
}
|
||||
|
||||
static void uart_event(void *opaque, QEMUChrEvent event)
|
||||
{
|
||||
}
|
||||
|
||||
static void uart_reset(DeviceState *d)
|
||||
{
|
||||
LM32UartState *s = LM32_UART(d);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < R_MAX; i++) {
|
||||
s->regs[i] = 0;
|
||||
}
|
||||
|
||||
/* defaults */
|
||||
s->regs[R_LSR] = LSR_THRE | LSR_TEMT;
|
||||
}
|
||||
|
||||
static void lm32_uart_init(Object *obj)
|
||||
{
|
||||
LM32UartState *s = LM32_UART(obj);
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
|
||||
sysbus_init_irq(dev, &s->irq);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &uart_ops, s,
|
||||
"uart", R_MAX * 4);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
}
|
||||
|
||||
static void lm32_uart_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
LM32UartState *s = LM32_UART(dev);
|
||||
|
||||
qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
|
||||
uart_event, NULL, s, NULL, true);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_lm32_uart = {
|
||||
.name = "lm32-uart",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, LM32UartState, R_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property lm32_uart_properties[] = {
|
||||
DEFINE_PROP_CHR("chardev", LM32UartState, chr),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void lm32_uart_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->reset = uart_reset;
|
||||
dc->vmsd = &vmstate_lm32_uart;
|
||||
device_class_set_props(dc, lm32_uart_properties);
|
||||
dc->realize = lm32_uart_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo lm32_uart_info = {
|
||||
.name = TYPE_LM32_UART,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(LM32UartState),
|
||||
.instance_init = lm32_uart_init,
|
||||
.class_init = lm32_uart_class_init,
|
||||
};
|
||||
|
||||
static void lm32_uart_register_types(void)
|
||||
{
|
||||
type_register_static(&lm32_uart_info);
|
||||
}
|
||||
|
||||
type_init(lm32_uart_register_types)
|
@ -8,9 +8,6 @@ softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_serial.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_IPACK', if_true: files('ipoctal232.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_ISA_BUS', if_true: files('parallel-isa.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_ISA_DEBUG', if_true: files('debugcon.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_LM32_DEVICES', if_true: files('lm32_juart.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_LM32_DEVICES', if_true: files('lm32_uart.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-uart.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_uart.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PARALLEL', if_true: files('parallel.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PL011', if_true: files('pl011.c'))
|
||||
|
@ -1,258 +0,0 @@
|
||||
/*
|
||||
* QEMU model of the Milkymist UART block.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Specification available at:
|
||||
* http://milkymist.walle.cc/socdoc/uart.pdf
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/qdev-properties-system.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
enum {
|
||||
R_RXTX = 0,
|
||||
R_DIV,
|
||||
R_STAT,
|
||||
R_CTRL,
|
||||
R_DBG,
|
||||
R_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
STAT_THRE = (1<<0),
|
||||
STAT_RX_EVT = (1<<1),
|
||||
STAT_TX_EVT = (1<<2),
|
||||
};
|
||||
|
||||
enum {
|
||||
CTRL_RX_IRQ_EN = (1<<0),
|
||||
CTRL_TX_IRQ_EN = (1<<1),
|
||||
CTRL_THRU_EN = (1<<2),
|
||||
};
|
||||
|
||||
enum {
|
||||
DBG_BREAK_EN = (1<<0),
|
||||
};
|
||||
|
||||
#define TYPE_MILKYMIST_UART "milkymist-uart"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(MilkymistUartState, MILKYMIST_UART)
|
||||
|
||||
struct MilkymistUartState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion regs_region;
|
||||
CharBackend chr;
|
||||
qemu_irq irq;
|
||||
|
||||
uint32_t regs[R_MAX];
|
||||
};
|
||||
|
||||
static void uart_update_irq(MilkymistUartState *s)
|
||||
{
|
||||
int rx_event = s->regs[R_STAT] & STAT_RX_EVT;
|
||||
int tx_event = s->regs[R_STAT] & STAT_TX_EVT;
|
||||
int rx_irq_en = s->regs[R_CTRL] & CTRL_RX_IRQ_EN;
|
||||
int tx_irq_en = s->regs[R_CTRL] & CTRL_TX_IRQ_EN;
|
||||
|
||||
if ((rx_irq_en && rx_event) || (tx_irq_en && tx_event)) {
|
||||
trace_milkymist_uart_raise_irq();
|
||||
qemu_irq_raise(s->irq);
|
||||
} else {
|
||||
trace_milkymist_uart_lower_irq();
|
||||
qemu_irq_lower(s->irq);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t uart_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistUartState *s = opaque;
|
||||
uint32_t r = 0;
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_RXTX:
|
||||
r = s->regs[addr];
|
||||
break;
|
||||
case R_DIV:
|
||||
case R_STAT:
|
||||
case R_CTRL:
|
||||
case R_DBG:
|
||||
r = s->regs[addr];
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("milkymist_uart: read access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_milkymist_uart_memory_read(addr << 2, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void uart_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistUartState *s = opaque;
|
||||
unsigned char ch = value;
|
||||
|
||||
trace_milkymist_uart_memory_write(addr, value);
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_RXTX:
|
||||
qemu_chr_fe_write_all(&s->chr, &ch, 1);
|
||||
s->regs[R_STAT] |= STAT_TX_EVT;
|
||||
break;
|
||||
case R_DIV:
|
||||
case R_CTRL:
|
||||
case R_DBG:
|
||||
s->regs[addr] = value;
|
||||
break;
|
||||
|
||||
case R_STAT:
|
||||
/* write one to clear bits */
|
||||
s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT));
|
||||
qemu_chr_fe_accept_input(&s->chr);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("milkymist_uart: write access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
|
||||
uart_update_irq(s);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps uart_mmio_ops = {
|
||||
.read = uart_read,
|
||||
.write = uart_write,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void uart_rx(void *opaque, const uint8_t *buf, int size)
|
||||
{
|
||||
MilkymistUartState *s = opaque;
|
||||
|
||||
assert(!(s->regs[R_STAT] & STAT_RX_EVT));
|
||||
|
||||
s->regs[R_STAT] |= STAT_RX_EVT;
|
||||
s->regs[R_RXTX] = *buf;
|
||||
|
||||
uart_update_irq(s);
|
||||
}
|
||||
|
||||
static int uart_can_rx(void *opaque)
|
||||
{
|
||||
MilkymistUartState *s = opaque;
|
||||
|
||||
return !(s->regs[R_STAT] & STAT_RX_EVT);
|
||||
}
|
||||
|
||||
static void uart_event(void *opaque, QEMUChrEvent event)
|
||||
{
|
||||
}
|
||||
|
||||
static void milkymist_uart_reset(DeviceState *d)
|
||||
{
|
||||
MilkymistUartState *s = MILKYMIST_UART(d);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < R_MAX; i++) {
|
||||
s->regs[i] = 0;
|
||||
}
|
||||
|
||||
/* THRE is always set */
|
||||
s->regs[R_STAT] = STAT_THRE;
|
||||
}
|
||||
|
||||
static void milkymist_uart_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MilkymistUartState *s = MILKYMIST_UART(dev);
|
||||
|
||||
qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
|
||||
uart_event, NULL, s, NULL, true);
|
||||
}
|
||||
|
||||
static void milkymist_uart_init(Object *obj)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
MilkymistUartState *s = MILKYMIST_UART(obj);
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
||||
memory_region_init_io(&s->regs_region, OBJECT(s), &uart_mmio_ops, s,
|
||||
"milkymist-uart", R_MAX * 4);
|
||||
sysbus_init_mmio(sbd, &s->regs_region);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_milkymist_uart = {
|
||||
.name = "milkymist-uart",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property milkymist_uart_properties[] = {
|
||||
DEFINE_PROP_CHR("chardev", MilkymistUartState, chr),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void milkymist_uart_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = milkymist_uart_realize;
|
||||
dc->reset = milkymist_uart_reset;
|
||||
dc->vmsd = &vmstate_milkymist_uart;
|
||||
device_class_set_props(dc, milkymist_uart_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo milkymist_uart_info = {
|
||||
.name = TYPE_MILKYMIST_UART,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MilkymistUartState),
|
||||
.instance_init = milkymist_uart_init,
|
||||
.class_init = milkymist_uart_class_init,
|
||||
};
|
||||
|
||||
static void milkymist_uart_register_types(void)
|
||||
{
|
||||
type_register_static(&milkymist_uart_info);
|
||||
}
|
||||
|
||||
type_init(milkymist_uart_register_types)
|
@ -35,23 +35,6 @@ grlib_apbuart_event(int event) "event:%d"
|
||||
grlib_apbuart_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x"
|
||||
grlib_apbuart_readl_unknown(uint64_t addr) "addr 0x%"PRIx64
|
||||
|
||||
# lm32_juart.c
|
||||
lm32_juart_get_jtx(uint32_t value) "jtx 0x%08x"
|
||||
lm32_juart_set_jtx(uint32_t value) "jtx 0x%08x"
|
||||
lm32_juart_get_jrx(uint32_t value) "jrx 0x%08x"
|
||||
lm32_juart_set_jrx(uint32_t value) "jrx 0x%08x"
|
||||
|
||||
# lm32_uart.c
|
||||
lm32_uart_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
lm32_uart_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
lm32_uart_irq_state(int level) "irq state %d"
|
||||
|
||||
# milkymist-uart.c
|
||||
milkymist_uart_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
milkymist_uart_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
milkymist_uart_raise_irq(void) "Raise IRQ"
|
||||
milkymist_uart_lower_irq(void) "Lower IRQ"
|
||||
|
||||
# escc.c
|
||||
escc_put_queue(char channel, int b) "channel %c put: 0x%02x"
|
||||
escc_get_queue(char channel, int val) "channel %c get 0x%02x"
|
||||
|
@ -72,10 +72,6 @@ config BLIZZARD
|
||||
config FRAMEBUFFER
|
||||
bool
|
||||
|
||||
config MILKYMIST_TMU2
|
||||
bool
|
||||
depends on OPENGL && X11
|
||||
|
||||
config SM501
|
||||
bool
|
||||
select I2C
|
||||
|
@ -48,7 +48,6 @@ endif
|
||||
softmmu_ss.add(when: 'CONFIG_DPCD', if_true: files('dpcd.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx_dp.c'))
|
||||
|
||||
softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-vgafb.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_ARTIST', if_true: files('artist.c'))
|
||||
|
||||
softmmu_ss.add(when: [pixman, 'CONFIG_ATI_VGA'], if_true: files('ati.c', 'ati_2d.c', 'ati_dbg.c'))
|
||||
@ -94,7 +93,6 @@ if config_all_devices.has_key('CONFIG_VIRTIO_VGA')
|
||||
hw_display_modules += {'virtio-vga-gl': virtio_vga_gl_ss}
|
||||
endif
|
||||
|
||||
specific_ss.add(when: [x11, opengl, 'CONFIG_MILKYMIST_TMU2'], if_true: files('milkymist-tmu2.c'))
|
||||
specific_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_lcdc.c'))
|
||||
|
||||
modules += { 'hw-display': hw_display_modules }
|
||||
|
@ -1,551 +0,0 @@
|
||||
/*
|
||||
* QEMU model of the Milkymist texture mapping unit.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
* Copyright (c) 2010 Sebastien Bourdeauducq
|
||||
* <sebastien.bourdeauducq@lekernel.net>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Specification available at:
|
||||
* http://milkymist.walle.cc/socdoc/tmu2.pdf
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/display/milkymist_tmu2.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <epoxy/gl.h>
|
||||
#include <epoxy/glx.h>
|
||||
#include "qom/object.h"
|
||||
|
||||
enum {
|
||||
R_CTL = 0,
|
||||
R_HMESHLAST,
|
||||
R_VMESHLAST,
|
||||
R_BRIGHTNESS,
|
||||
R_CHROMAKEY,
|
||||
R_VERTICESADDR,
|
||||
R_TEXFBUF,
|
||||
R_TEXHRES,
|
||||
R_TEXVRES,
|
||||
R_TEXHMASK,
|
||||
R_TEXVMASK,
|
||||
R_DSTFBUF,
|
||||
R_DSTHRES,
|
||||
R_DSTVRES,
|
||||
R_DSTHOFFSET,
|
||||
R_DSTVOFFSET,
|
||||
R_DSTSQUAREW,
|
||||
R_DSTSQUAREH,
|
||||
R_ALPHA,
|
||||
R_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
CTL_START_BUSY = (1<<0),
|
||||
CTL_CHROMAKEY = (1<<1),
|
||||
};
|
||||
|
||||
enum {
|
||||
MAX_BRIGHTNESS = 63,
|
||||
MAX_ALPHA = 63,
|
||||
};
|
||||
|
||||
enum {
|
||||
MESH_MAXSIZE = 128,
|
||||
};
|
||||
|
||||
struct vertex {
|
||||
int x;
|
||||
int y;
|
||||
} QEMU_PACKED;
|
||||
|
||||
#define TYPE_MILKYMIST_TMU2 "milkymist-tmu2"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(MilkymistTMU2State, MILKYMIST_TMU2)
|
||||
|
||||
struct MilkymistTMU2State {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion regs_region;
|
||||
Chardev *chr;
|
||||
qemu_irq irq;
|
||||
|
||||
uint32_t regs[R_MAX];
|
||||
|
||||
Display *dpy;
|
||||
GLXFBConfig glx_fb_config;
|
||||
GLXContext glx_context;
|
||||
};
|
||||
|
||||
static const int glx_fbconfig_attr[] = {
|
||||
GLX_GREEN_SIZE, 5,
|
||||
GLX_GREEN_SIZE, 6,
|
||||
GLX_BLUE_SIZE, 5,
|
||||
None
|
||||
};
|
||||
|
||||
static int tmu2_glx_init(MilkymistTMU2State *s)
|
||||
{
|
||||
GLXFBConfig *configs;
|
||||
int nelements;
|
||||
|
||||
s->dpy = XOpenDisplay(NULL); /* FIXME: call XCloseDisplay() */
|
||||
if (s->dpy == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
configs = glXChooseFBConfig(s->dpy, 0, glx_fbconfig_attr, &nelements);
|
||||
if (configs == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
s->glx_fb_config = *configs;
|
||||
XFree(configs);
|
||||
|
||||
/* FIXME: call glXDestroyContext() */
|
||||
s->glx_context = glXCreateNewContext(s->dpy, s->glx_fb_config,
|
||||
GLX_RGBA_TYPE, NULL, 1);
|
||||
if (s->glx_context == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tmu2_gl_map(struct vertex *mesh, int texhres, int texvres,
|
||||
int hmeshlast, int vmeshlast, int ho, int vo, int sw, int sh)
|
||||
{
|
||||
int x, y;
|
||||
int x0, y0, x1, y1;
|
||||
int u0, v0, u1, v1, u2, v2, u3, v3;
|
||||
double xscale = 1.0 / ((double)(64 * texhres));
|
||||
double yscale = 1.0 / ((double)(64 * texvres));
|
||||
|
||||
glLoadIdentity();
|
||||
glTranslatef(ho, vo, 0);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
for (y = 0; y < vmeshlast; y++) {
|
||||
y0 = y * sh;
|
||||
y1 = y0 + sh;
|
||||
for (x = 0; x < hmeshlast; x++) {
|
||||
x0 = x * sw;
|
||||
x1 = x0 + sw;
|
||||
|
||||
u0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].x);
|
||||
v0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].y);
|
||||
u1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].x);
|
||||
v1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].y);
|
||||
u2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].x);
|
||||
v2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].y);
|
||||
u3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].x);
|
||||
v3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].y);
|
||||
|
||||
glTexCoord2d(((double)u0) * xscale, ((double)v0) * yscale);
|
||||
glVertex3i(x0, y0, 0);
|
||||
glTexCoord2d(((double)u1) * xscale, ((double)v1) * yscale);
|
||||
glVertex3i(x1, y0, 0);
|
||||
glTexCoord2d(((double)u2) * xscale, ((double)v2) * yscale);
|
||||
glVertex3i(x1, y1, 0);
|
||||
glTexCoord2d(((double)u3) * xscale, ((double)v3) * yscale);
|
||||
glVertex3i(x0, y1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
static void tmu2_start(MilkymistTMU2State *s)
|
||||
{
|
||||
int pbuffer_attrib[6] = {
|
||||
GLX_PBUFFER_WIDTH,
|
||||
0,
|
||||
GLX_PBUFFER_HEIGHT,
|
||||
0,
|
||||
GLX_PRESERVED_CONTENTS,
|
||||
True
|
||||
};
|
||||
|
||||
GLXPbuffer pbuffer;
|
||||
GLuint texture;
|
||||
void *fb;
|
||||
hwaddr fb_len;
|
||||
void *mesh;
|
||||
hwaddr mesh_len;
|
||||
float m;
|
||||
|
||||
trace_milkymist_tmu2_start();
|
||||
|
||||
/* Create and set up a suitable OpenGL context */
|
||||
pbuffer_attrib[1] = s->regs[R_DSTHRES];
|
||||
pbuffer_attrib[3] = s->regs[R_DSTVRES];
|
||||
pbuffer = glXCreatePbuffer(s->dpy, s->glx_fb_config, pbuffer_attrib);
|
||||
glXMakeContextCurrent(s->dpy, pbuffer, pbuffer, s->glx_context);
|
||||
|
||||
/* Fixup endianness. TODO: would it work on BE hosts? */
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
|
||||
glPixelStorei(GL_PACK_SWAP_BYTES, 1);
|
||||
|
||||
/* Row alignment */
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 2);
|
||||
|
||||
/* Read the QEMU source framebuffer into an OpenGL texture */
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
fb_len = 2ULL * s->regs[R_TEXHRES] * s->regs[R_TEXVRES];
|
||||
fb = cpu_physical_memory_map(s->regs[R_TEXFBUF], &fb_len, false);
|
||||
if (fb == NULL) {
|
||||
glDeleteTextures(1, &texture);
|
||||
glXMakeContextCurrent(s->dpy, None, None, NULL);
|
||||
glXDestroyPbuffer(s->dpy, pbuffer);
|
||||
return;
|
||||
}
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, 3, s->regs[R_TEXHRES], s->regs[R_TEXVRES],
|
||||
0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb);
|
||||
cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
|
||||
|
||||
/* Set up texturing options */
|
||||
/* WARNING:
|
||||
* Many cases of TMU2 masking are not supported by OpenGL.
|
||||
* We only implement the most common ones:
|
||||
* - full bilinear filtering vs. nearest texel
|
||||
* - texture clamping vs. texture wrapping
|
||||
*/
|
||||
if ((s->regs[R_TEXHMASK] & 0x3f) > 0x20) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
if ((s->regs[R_TEXHMASK] >> 6) & s->regs[R_TEXHRES]) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
}
|
||||
if ((s->regs[R_TEXVMASK] >> 6) & s->regs[R_TEXVRES]) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
}
|
||||
|
||||
/* Translucency and decay */
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
m = (float)(s->regs[R_BRIGHTNESS] + 1) / 64.0f;
|
||||
glColor4f(m, m, m, (float)(s->regs[R_ALPHA] + 1) / 64.0f);
|
||||
|
||||
/* Read the QEMU dest. framebuffer into the OpenGL framebuffer */
|
||||
fb_len = 2ULL * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
|
||||
fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, false);
|
||||
if (fb == NULL) {
|
||||
glDeleteTextures(1, &texture);
|
||||
glXMakeContextCurrent(s->dpy, None, None, NULL);
|
||||
glXDestroyPbuffer(s->dpy, pbuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
glDrawPixels(s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
|
||||
GL_UNSIGNED_SHORT_5_6_5, fb);
|
||||
cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
|
||||
glViewport(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES]);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0.0, s->regs[R_DSTHRES], 0.0, s->regs[R_DSTVRES], -1.0, 1.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
/* Map the texture */
|
||||
mesh_len = MESH_MAXSIZE*MESH_MAXSIZE*sizeof(struct vertex);
|
||||
mesh = cpu_physical_memory_map(s->regs[R_VERTICESADDR], &mesh_len, false);
|
||||
if (mesh == NULL) {
|
||||
glDeleteTextures(1, &texture);
|
||||
glXMakeContextCurrent(s->dpy, None, None, NULL);
|
||||
glXDestroyPbuffer(s->dpy, pbuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
tmu2_gl_map((struct vertex *)mesh,
|
||||
s->regs[R_TEXHRES], s->regs[R_TEXVRES],
|
||||
s->regs[R_HMESHLAST], s->regs[R_VMESHLAST],
|
||||
s->regs[R_DSTHOFFSET], s->regs[R_DSTVOFFSET],
|
||||
s->regs[R_DSTSQUAREW], s->regs[R_DSTSQUAREH]);
|
||||
cpu_physical_memory_unmap(mesh, mesh_len, 0, mesh_len);
|
||||
|
||||
/* Write back the OpenGL framebuffer to the QEMU framebuffer */
|
||||
fb_len = 2ULL * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
|
||||
fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, true);
|
||||
if (fb == NULL) {
|
||||
glDeleteTextures(1, &texture);
|
||||
glXMakeContextCurrent(s->dpy, None, None, NULL);
|
||||
glXDestroyPbuffer(s->dpy, pbuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
glReadPixels(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
|
||||
GL_UNSIGNED_SHORT_5_6_5, fb);
|
||||
cpu_physical_memory_unmap(fb, fb_len, 1, fb_len);
|
||||
|
||||
/* Free OpenGL allocs */
|
||||
glDeleteTextures(1, &texture);
|
||||
glXMakeContextCurrent(s->dpy, None, None, NULL);
|
||||
glXDestroyPbuffer(s->dpy, pbuffer);
|
||||
|
||||
s->regs[R_CTL] &= ~CTL_START_BUSY;
|
||||
|
||||
trace_milkymist_tmu2_pulse_irq();
|
||||
qemu_irq_pulse(s->irq);
|
||||
}
|
||||
|
||||
static uint64_t tmu2_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistTMU2State *s = opaque;
|
||||
uint32_t r = 0;
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_CTL:
|
||||
case R_HMESHLAST:
|
||||
case R_VMESHLAST:
|
||||
case R_BRIGHTNESS:
|
||||
case R_CHROMAKEY:
|
||||
case R_VERTICESADDR:
|
||||
case R_TEXFBUF:
|
||||
case R_TEXHRES:
|
||||
case R_TEXVRES:
|
||||
case R_TEXHMASK:
|
||||
case R_TEXVMASK:
|
||||
case R_DSTFBUF:
|
||||
case R_DSTHRES:
|
||||
case R_DSTVRES:
|
||||
case R_DSTHOFFSET:
|
||||
case R_DSTVOFFSET:
|
||||
case R_DSTSQUAREW:
|
||||
case R_DSTSQUAREH:
|
||||
case R_ALPHA:
|
||||
r = s->regs[addr];
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("milkymist_tmu2: read access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_milkymist_tmu2_memory_read(addr << 2, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void tmu2_check_registers(MilkymistTMU2State *s)
|
||||
{
|
||||
if (s->regs[R_BRIGHTNESS] > MAX_BRIGHTNESS) {
|
||||
error_report("milkymist_tmu2: max brightness is %d", MAX_BRIGHTNESS);
|
||||
}
|
||||
|
||||
if (s->regs[R_ALPHA] > MAX_ALPHA) {
|
||||
error_report("milkymist_tmu2: max alpha is %d", MAX_ALPHA);
|
||||
}
|
||||
|
||||
if (s->regs[R_VERTICESADDR] & 0x07) {
|
||||
error_report("milkymist_tmu2: vertex mesh address has to be 64-bit "
|
||||
"aligned");
|
||||
}
|
||||
|
||||
if (s->regs[R_TEXFBUF] & 0x01) {
|
||||
error_report("milkymist_tmu2: texture buffer address has to be "
|
||||
"16-bit aligned");
|
||||
}
|
||||
}
|
||||
|
||||
static void tmu2_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistTMU2State *s = opaque;
|
||||
|
||||
trace_milkymist_tmu2_memory_write(addr, value);
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_CTL:
|
||||
s->regs[addr] = value;
|
||||
if (value & CTL_START_BUSY) {
|
||||
tmu2_start(s);
|
||||
}
|
||||
break;
|
||||
case R_BRIGHTNESS:
|
||||
case R_HMESHLAST:
|
||||
case R_VMESHLAST:
|
||||
case R_CHROMAKEY:
|
||||
case R_VERTICESADDR:
|
||||
case R_TEXFBUF:
|
||||
case R_TEXHRES:
|
||||
case R_TEXVRES:
|
||||
case R_TEXHMASK:
|
||||
case R_TEXVMASK:
|
||||
case R_DSTFBUF:
|
||||
case R_DSTHRES:
|
||||
case R_DSTVRES:
|
||||
case R_DSTHOFFSET:
|
||||
case R_DSTVOFFSET:
|
||||
case R_DSTSQUAREW:
|
||||
case R_DSTSQUAREH:
|
||||
case R_ALPHA:
|
||||
s->regs[addr] = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("milkymist_tmu2: write access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
|
||||
tmu2_check_registers(s);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps tmu2_mmio_ops = {
|
||||
.read = tmu2_read,
|
||||
.write = tmu2_write,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void milkymist_tmu2_reset(DeviceState *d)
|
||||
{
|
||||
MilkymistTMU2State *s = MILKYMIST_TMU2(d);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < R_MAX; i++) {
|
||||
s->regs[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void milkymist_tmu2_init(Object *obj)
|
||||
{
|
||||
MilkymistTMU2State *s = MILKYMIST_TMU2(obj);
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
|
||||
sysbus_init_irq(dev, &s->irq);
|
||||
|
||||
memory_region_init_io(&s->regs_region, obj, &tmu2_mmio_ops, s,
|
||||
"milkymist-tmu2", R_MAX * 4);
|
||||
sysbus_init_mmio(dev, &s->regs_region);
|
||||
}
|
||||
|
||||
static void milkymist_tmu2_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MilkymistTMU2State *s = MILKYMIST_TMU2(dev);
|
||||
|
||||
if (tmu2_glx_init(s)) {
|
||||
error_setg(errp, "tmu2_glx_init failed");
|
||||
}
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_milkymist_tmu2 = {
|
||||
.name = "milkymist-tmu2",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, MilkymistTMU2State, R_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void milkymist_tmu2_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = milkymist_tmu2_realize;
|
||||
dc->reset = milkymist_tmu2_reset;
|
||||
dc->vmsd = &vmstate_milkymist_tmu2;
|
||||
}
|
||||
|
||||
static const TypeInfo milkymist_tmu2_info = {
|
||||
.name = TYPE_MILKYMIST_TMU2,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MilkymistTMU2State),
|
||||
.instance_init = milkymist_tmu2_init,
|
||||
.class_init = milkymist_tmu2_class_init,
|
||||
};
|
||||
|
||||
static void milkymist_tmu2_register_types(void)
|
||||
{
|
||||
type_register_static(&milkymist_tmu2_info);
|
||||
}
|
||||
|
||||
type_init(milkymist_tmu2_register_types)
|
||||
|
||||
DeviceState *milkymist_tmu2_create(hwaddr base, qemu_irq irq)
|
||||
{
|
||||
DeviceState *dev;
|
||||
Display *d;
|
||||
GLXFBConfig *configs;
|
||||
int nelements;
|
||||
int ver_major, ver_minor;
|
||||
|
||||
/* check that GLX will work */
|
||||
d = XOpenDisplay(NULL);
|
||||
if (d == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!glXQueryVersion(d, &ver_major, &ver_minor)) {
|
||||
/*
|
||||
* Yeah, sometimes getting the GLX version can fail.
|
||||
* Isn't X beautiful?
|
||||
*/
|
||||
XCloseDisplay(d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((ver_major < 1) || ((ver_major == 1) && (ver_minor < 3))) {
|
||||
printf("Your GLX version is %d.%d,"
|
||||
"but TMU emulation needs at least 1.3. TMU disabled.\n",
|
||||
ver_major, ver_minor);
|
||||
XCloseDisplay(d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
configs = glXChooseFBConfig(d, 0, glx_fbconfig_attr, &nelements);
|
||||
if (configs == NULL) {
|
||||
XCloseDisplay(d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
XFree(configs);
|
||||
XCloseDisplay(d);
|
||||
|
||||
dev = qdev_new(TYPE_MILKYMIST_TMU2);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
|
||||
|
||||
return dev;
|
||||
}
|
@ -1,360 +0,0 @@
|
||||
|
||||
/*
|
||||
* QEMU model of the Milkymist VGA framebuffer.
|
||||
*
|
||||
* Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Specification available at:
|
||||
* http://milkymist.walle.cc/socdoc/vgafb.pdf
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "trace.h"
|
||||
#include "ui/console.h"
|
||||
#include "framebuffer.h"
|
||||
#include "ui/pixel_ops.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define BITS 8
|
||||
#include "migration/vmstate.h"
|
||||
#include "milkymist-vgafb_template.h"
|
||||
#define BITS 15
|
||||
#include "milkymist-vgafb_template.h"
|
||||
#define BITS 16
|
||||
#include "milkymist-vgafb_template.h"
|
||||
#define BITS 24
|
||||
#include "milkymist-vgafb_template.h"
|
||||
#define BITS 32
|
||||
#include "milkymist-vgafb_template.h"
|
||||
|
||||
enum {
|
||||
R_CTRL = 0,
|
||||
R_HRES,
|
||||
R_HSYNC_START,
|
||||
R_HSYNC_END,
|
||||
R_HSCAN,
|
||||
R_VRES,
|
||||
R_VSYNC_START,
|
||||
R_VSYNC_END,
|
||||
R_VSCAN,
|
||||
R_BASEADDRESS,
|
||||
R_BASEADDRESS_ACT,
|
||||
R_BURST_COUNT,
|
||||
R_DDC,
|
||||
R_SOURCE_CLOCK,
|
||||
R_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
CTRL_RESET = (1<<0),
|
||||
};
|
||||
|
||||
#define TYPE_MILKYMIST_VGAFB "milkymist-vgafb"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(MilkymistVgafbState, MILKYMIST_VGAFB)
|
||||
|
||||
struct MilkymistVgafbState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion regs_region;
|
||||
MemoryRegionSection fbsection;
|
||||
QemuConsole *con;
|
||||
|
||||
int invalidate;
|
||||
uint32_t fb_offset;
|
||||
uint32_t fb_mask;
|
||||
|
||||
uint32_t regs[R_MAX];
|
||||
};
|
||||
|
||||
static int vgafb_enabled(MilkymistVgafbState *s)
|
||||
{
|
||||
return !(s->regs[R_CTRL] & CTRL_RESET);
|
||||
}
|
||||
|
||||
static void vgafb_update_display(void *opaque)
|
||||
{
|
||||
MilkymistVgafbState *s = opaque;
|
||||
SysBusDevice *sbd;
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
int src_width;
|
||||
int first = 0;
|
||||
int last = 0;
|
||||
drawfn fn;
|
||||
|
||||
if (!vgafb_enabled(s)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sbd = SYS_BUS_DEVICE(s);
|
||||
int dest_width = s->regs[R_HRES];
|
||||
|
||||
switch (surface_bits_per_pixel(surface)) {
|
||||
case 0:
|
||||
return;
|
||||
case 8:
|
||||
fn = draw_line_8;
|
||||
break;
|
||||
case 15:
|
||||
fn = draw_line_15;
|
||||
dest_width *= 2;
|
||||
break;
|
||||
case 16:
|
||||
fn = draw_line_16;
|
||||
dest_width *= 2;
|
||||
break;
|
||||
case 24:
|
||||
fn = draw_line_24;
|
||||
dest_width *= 3;
|
||||
break;
|
||||
case 32:
|
||||
fn = draw_line_32;
|
||||
dest_width *= 4;
|
||||
break;
|
||||
default:
|
||||
hw_error("milkymist_vgafb: bad color depth\n");
|
||||
break;
|
||||
}
|
||||
|
||||
src_width = s->regs[R_HRES] * 2;
|
||||
if (s->invalidate) {
|
||||
framebuffer_update_memory_section(&s->fbsection,
|
||||
sysbus_address_space(sbd),
|
||||
s->regs[R_BASEADDRESS] + s->fb_offset,
|
||||
s->regs[R_VRES], src_width);
|
||||
}
|
||||
|
||||
framebuffer_update_display(surface, &s->fbsection,
|
||||
s->regs[R_HRES],
|
||||
s->regs[R_VRES],
|
||||
src_width,
|
||||
dest_width,
|
||||
0,
|
||||
s->invalidate,
|
||||
fn,
|
||||
NULL,
|
||||
&first, &last);
|
||||
|
||||
if (first >= 0) {
|
||||
dpy_gfx_update(s->con, 0, first, s->regs[R_HRES], last - first + 1);
|
||||
}
|
||||
s->invalidate = 0;
|
||||
}
|
||||
|
||||
static void vgafb_invalidate_display(void *opaque)
|
||||
{
|
||||
MilkymistVgafbState *s = opaque;
|
||||
s->invalidate = 1;
|
||||
}
|
||||
|
||||
static void vgafb_resize(MilkymistVgafbState *s)
|
||||
{
|
||||
if (!vgafb_enabled(s)) {
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_console_resize(s->con, s->regs[R_HRES], s->regs[R_VRES]);
|
||||
s->invalidate = 1;
|
||||
}
|
||||
|
||||
static uint64_t vgafb_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistVgafbState *s = opaque;
|
||||
uint32_t r = 0;
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_CTRL:
|
||||
case R_HRES:
|
||||
case R_HSYNC_START:
|
||||
case R_HSYNC_END:
|
||||
case R_HSCAN:
|
||||
case R_VRES:
|
||||
case R_VSYNC_START:
|
||||
case R_VSYNC_END:
|
||||
case R_VSCAN:
|
||||
case R_BASEADDRESS:
|
||||
case R_BURST_COUNT:
|
||||
case R_DDC:
|
||||
case R_SOURCE_CLOCK:
|
||||
r = s->regs[addr];
|
||||
break;
|
||||
case R_BASEADDRESS_ACT:
|
||||
r = s->regs[R_BASEADDRESS];
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("milkymist_vgafb: read access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_milkymist_vgafb_memory_read(addr << 2, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void vgafb_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistVgafbState *s = opaque;
|
||||
|
||||
trace_milkymist_vgafb_memory_write(addr, value);
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_CTRL:
|
||||
s->regs[addr] = value;
|
||||
vgafb_resize(s);
|
||||
break;
|
||||
case R_HSYNC_START:
|
||||
case R_HSYNC_END:
|
||||
case R_HSCAN:
|
||||
case R_VSYNC_START:
|
||||
case R_VSYNC_END:
|
||||
case R_VSCAN:
|
||||
case R_BURST_COUNT:
|
||||
case R_DDC:
|
||||
case R_SOURCE_CLOCK:
|
||||
s->regs[addr] = value;
|
||||
break;
|
||||
case R_BASEADDRESS:
|
||||
if (value & 0x1f) {
|
||||
error_report("milkymist_vgafb: framebuffer base address have to "
|
||||
"be 32 byte aligned");
|
||||
break;
|
||||
}
|
||||
s->regs[addr] = value & s->fb_mask;
|
||||
s->invalidate = 1;
|
||||
break;
|
||||
case R_HRES:
|
||||
case R_VRES:
|
||||
s->regs[addr] = value;
|
||||
vgafb_resize(s);
|
||||
break;
|
||||
case R_BASEADDRESS_ACT:
|
||||
error_report("milkymist_vgafb: write to read-only register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("milkymist_vgafb: write access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps vgafb_mmio_ops = {
|
||||
.read = vgafb_read,
|
||||
.write = vgafb_write,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void milkymist_vgafb_reset(DeviceState *d)
|
||||
{
|
||||
MilkymistVgafbState *s = MILKYMIST_VGAFB(d);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < R_MAX; i++) {
|
||||
s->regs[i] = 0;
|
||||
}
|
||||
|
||||
/* defaults */
|
||||
s->regs[R_CTRL] = CTRL_RESET;
|
||||
s->regs[R_HRES] = 640;
|
||||
s->regs[R_VRES] = 480;
|
||||
s->regs[R_BASEADDRESS] = 0;
|
||||
}
|
||||
|
||||
static const GraphicHwOps vgafb_ops = {
|
||||
.invalidate = vgafb_invalidate_display,
|
||||
.gfx_update = vgafb_update_display,
|
||||
};
|
||||
|
||||
static void milkymist_vgafb_init(Object *obj)
|
||||
{
|
||||
MilkymistVgafbState *s = MILKYMIST_VGAFB(obj);
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->regs_region, OBJECT(s), &vgafb_mmio_ops, s,
|
||||
"milkymist-vgafb", R_MAX * 4);
|
||||
sysbus_init_mmio(dev, &s->regs_region);
|
||||
}
|
||||
|
||||
static void milkymist_vgafb_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MilkymistVgafbState *s = MILKYMIST_VGAFB(dev);
|
||||
|
||||
s->con = graphic_console_init(dev, 0, &vgafb_ops, s);
|
||||
}
|
||||
|
||||
static int vgafb_post_load(void *opaque, int version_id)
|
||||
{
|
||||
vgafb_invalidate_display(opaque);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_milkymist_vgafb = {
|
||||
.name = "milkymist-vgafb",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.post_load = vgafb_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, MilkymistVgafbState, R_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property milkymist_vgafb_properties[] = {
|
||||
DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0),
|
||||
DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void milkymist_vgafb_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->reset = milkymist_vgafb_reset;
|
||||
dc->vmsd = &vmstate_milkymist_vgafb;
|
||||
device_class_set_props(dc, milkymist_vgafb_properties);
|
||||
dc->realize = milkymist_vgafb_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo milkymist_vgafb_info = {
|
||||
.name = TYPE_MILKYMIST_VGAFB,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MilkymistVgafbState),
|
||||
.instance_init = milkymist_vgafb_init,
|
||||
.class_init = milkymist_vgafb_class_init,
|
||||
};
|
||||
|
||||
static void milkymist_vgafb_register_types(void)
|
||||
{
|
||||
type_register_static(&milkymist_vgafb_info);
|
||||
}
|
||||
|
||||
type_init(milkymist_vgafb_register_types)
|
@ -1,74 +0,0 @@
|
||||
/*
|
||||
* QEMU model of the Milkymist VGA framebuffer.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if BITS == 8
|
||||
#define COPY_PIXEL(to, r, g, b) \
|
||||
do { \
|
||||
*to = rgb_to_pixel8(r, g, b); \
|
||||
to += 1; \
|
||||
} while (0)
|
||||
#elif BITS == 15
|
||||
#define COPY_PIXEL(to, r, g, b) \
|
||||
do { \
|
||||
*(uint16_t *)to = rgb_to_pixel15(r, g, b); \
|
||||
to += 2; \
|
||||
} while (0)
|
||||
#elif BITS == 16
|
||||
#define COPY_PIXEL(to, r, g, b) \
|
||||
do { \
|
||||
*(uint16_t *)to = rgb_to_pixel16(r, g, b); \
|
||||
to += 2; \
|
||||
} while (0)
|
||||
#elif BITS == 24
|
||||
#define COPY_PIXEL(to, r, g, b) \
|
||||
do { \
|
||||
uint32_t tmp = rgb_to_pixel24(r, g, b); \
|
||||
*(to++) = tmp & 0xff; \
|
||||
*(to++) = (tmp >> 8) & 0xff; \
|
||||
*(to++) = (tmp >> 16) & 0xff; \
|
||||
} while (0)
|
||||
#elif BITS == 32
|
||||
#define COPY_PIXEL(to, r, g, b) \
|
||||
do { \
|
||||
*(uint32_t *)to = rgb_to_pixel32(r, g, b); \
|
||||
to += 4; \
|
||||
} while (0)
|
||||
#else
|
||||
#error unknown bit depth
|
||||
#endif
|
||||
|
||||
static void glue(draw_line_, BITS)(void *opaque, uint8_t *d, const uint8_t *s,
|
||||
int width, int deststep)
|
||||
{
|
||||
uint16_t rgb565;
|
||||
uint8_t r, g, b;
|
||||
|
||||
while (width--) {
|
||||
rgb565 = lduw_be_p(s);
|
||||
r = ((rgb565 >> 11) & 0x1f) << 3;
|
||||
g = ((rgb565 >> 5) & 0x3f) << 2;
|
||||
b = ((rgb565 >> 0) & 0x1f) << 3;
|
||||
COPY_PIXEL(d, r, g, b);
|
||||
s += 2;
|
||||
}
|
||||
}
|
||||
|
||||
#undef BITS
|
||||
#undef COPY_PIXEL
|
@ -13,16 +13,6 @@ xenfb_input_connected(void *xendev, int abs_pointer_wanted) "%p abs %d"
|
||||
g364fb_read(uint64_t addr, uint32_t val) "read addr=0x%"PRIx64": 0x%x"
|
||||
g364fb_write(uint64_t addr, uint32_t new) "write addr=0x%"PRIx64": 0x%x"
|
||||
|
||||
# milkymist-tmu2.c
|
||||
milkymist_tmu2_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
milkymist_tmu2_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
milkymist_tmu2_start(void) "Start TMU"
|
||||
milkymist_tmu2_pulse_irq(void) "Pulse IRQ"
|
||||
|
||||
# milkymist-vgafb.c
|
||||
milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
milkymist_vgafb_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
|
||||
# vmware_vga.c
|
||||
vmware_value_read(uint32_t index, uint32_t value) "index %d, value 0x%x"
|
||||
vmware_value_write(uint32_t index, uint32_t value) "index %d, value 0x%x"
|
||||
|
@ -1,4 +1,3 @@
|
||||
softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_dma.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_RC4030', if_true: files('rc4030.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PL080', if_true: files('pl080.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PL330', if_true: files('pl330.c'))
|
||||
|
@ -1,119 +0,0 @@
|
||||
/*
|
||||
* DMA device simulation in PKUnity SoC
|
||||
*
|
||||
* Copyright (C) 2010-2012 Guan Xuetao
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation, or any later version.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#undef DEBUG_PUV3
|
||||
#include "hw/unicore32/puv3.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/log.h"
|
||||
|
||||
#define PUV3_DMA_CH_NR (6)
|
||||
#define PUV3_DMA_CH_MASK (0xff)
|
||||
#define PUV3_DMA_CH(offset) ((offset) >> 8)
|
||||
|
||||
#define TYPE_PUV3_DMA "puv3_dma"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(PUV3DMAState, PUV3_DMA)
|
||||
|
||||
struct PUV3DMAState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
uint32_t reg_CFG[PUV3_DMA_CH_NR];
|
||||
};
|
||||
|
||||
static uint64_t puv3_dma_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
PUV3DMAState *s = opaque;
|
||||
uint32_t ret = 0;
|
||||
|
||||
assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR);
|
||||
|
||||
switch (offset & PUV3_DMA_CH_MASK) {
|
||||
case 0x10:
|
||||
ret = s->reg_CFG[PUV3_DMA_CH(offset)];
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad read offset 0x%"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
}
|
||||
DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void puv3_dma_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
PUV3DMAState *s = opaque;
|
||||
|
||||
assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR);
|
||||
|
||||
switch (offset & PUV3_DMA_CH_MASK) {
|
||||
case 0x10:
|
||||
s->reg_CFG[PUV3_DMA_CH(offset)] = value;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad write offset 0x%"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
}
|
||||
DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps puv3_dma_ops = {
|
||||
.read = puv3_dma_read,
|
||||
.write = puv3_dma_write,
|
||||
.impl = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void puv3_dma_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PUV3DMAState *s = PUV3_DMA(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PUV3_DMA_CH_NR; i++) {
|
||||
s->reg_CFG[i] = 0x0;
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &puv3_dma_ops, s, "puv3_dma",
|
||||
PUV3_REGS_OFFSET);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
|
||||
}
|
||||
|
||||
static void puv3_dma_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = puv3_dma_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo puv3_dma_info = {
|
||||
.name = TYPE_PUV3_DMA,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PUV3DMAState),
|
||||
.class_init = puv3_dma_class_init,
|
||||
};
|
||||
|
||||
static void puv3_dma_register_type(void)
|
||||
{
|
||||
type_register_static(&puv3_dma_info);
|
||||
}
|
||||
|
||||
type_init(puv3_dma_register_type)
|
@ -3,7 +3,6 @@ softmmu_ss.add(when: 'CONFIG_GPIO_KEY', if_true: files('gpio_key.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_GPIO_PWR', if_true: files('gpio_pwr.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_MAX7310', if_true: files('max7310.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PL061', if_true: files('pl061.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_gpio.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_ZAURUS', if_true: files('zaurus.c'))
|
||||
|
||||
softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpio.c'))
|
||||
|
@ -1,154 +0,0 @@
|
||||
/*
|
||||
* GPIO device simulation in PKUnity SoC
|
||||
*
|
||||
* Copyright (C) 2010-2012 Guan Xuetao
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation, or any later version.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#undef DEBUG_PUV3
|
||||
#include "hw/unicore32/puv3.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/log.h"
|
||||
|
||||
#define TYPE_PUV3_GPIO "puv3_gpio"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(PUV3GPIOState, PUV3_GPIO)
|
||||
|
||||
struct PUV3GPIOState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
qemu_irq irq[9];
|
||||
|
||||
uint32_t reg_GPLR;
|
||||
uint32_t reg_GPDR;
|
||||
uint32_t reg_GPIR;
|
||||
};
|
||||
|
||||
static uint64_t puv3_gpio_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
PUV3GPIOState *s = opaque;
|
||||
uint32_t ret = 0;
|
||||
|
||||
switch (offset) {
|
||||
case 0x00:
|
||||
ret = s->reg_GPLR;
|
||||
break;
|
||||
case 0x04:
|
||||
ret = s->reg_GPDR;
|
||||
break;
|
||||
case 0x20:
|
||||
ret = s->reg_GPIR;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad read offset 0x%"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
}
|
||||
DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void puv3_gpio_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
PUV3GPIOState *s = opaque;
|
||||
|
||||
DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
|
||||
switch (offset) {
|
||||
case 0x04:
|
||||
s->reg_GPDR = value;
|
||||
break;
|
||||
case 0x08:
|
||||
if (s->reg_GPDR & value) {
|
||||
s->reg_GPLR |= value;
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Write gpio input port\n",
|
||||
__func__);
|
||||
}
|
||||
break;
|
||||
case 0x0c:
|
||||
if (s->reg_GPDR & value) {
|
||||
s->reg_GPLR &= ~value;
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Write gpio input port\n",
|
||||
__func__);
|
||||
}
|
||||
break;
|
||||
case 0x10: /* GRER */
|
||||
case 0x14: /* GFER */
|
||||
case 0x18: /* GEDR */
|
||||
break;
|
||||
case 0x20: /* GPIR */
|
||||
s->reg_GPIR = value;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad write offset 0x%"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps puv3_gpio_ops = {
|
||||
.read = puv3_gpio_read,
|
||||
.write = puv3_gpio_write,
|
||||
.impl = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void puv3_gpio_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PUV3GPIOState *s = PUV3_GPIO(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
s->reg_GPLR = 0;
|
||||
s->reg_GPDR = 0;
|
||||
|
||||
/* FIXME: these irqs not handled yet */
|
||||
sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW0]);
|
||||
sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW1]);
|
||||
sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW2]);
|
||||
sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW3]);
|
||||
sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW4]);
|
||||
sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW5]);
|
||||
sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW6]);
|
||||
sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW7]);
|
||||
sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOHIGH]);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &puv3_gpio_ops, s, "puv3_gpio",
|
||||
PUV3_REGS_OFFSET);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
}
|
||||
|
||||
static void puv3_gpio_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = puv3_gpio_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo puv3_gpio_info = {
|
||||
.name = TYPE_PUV3_GPIO,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PUV3GPIOState),
|
||||
.class_init = puv3_gpio_class_init,
|
||||
};
|
||||
|
||||
static void puv3_gpio_register_type(void)
|
||||
{
|
||||
type_register_static(&puv3_gpio_info);
|
||||
}
|
||||
|
||||
type_init(puv3_gpio_register_type)
|
@ -13,7 +13,6 @@ softmmu_ss.add(when: 'CONFIG_VIRTIO_INPUT', if_true: files('virtio-input-hid.c')
|
||||
softmmu_ss.add(when: 'CONFIG_VIRTIO_INPUT_HOST', if_true: files('virtio-input-host.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_VHOST_USER_INPUT', if_true: files('vhost-user-input.c'))
|
||||
|
||||
softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-softusb.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_keypad.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_TSC210X', if_true: files('tsc210x.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_LASIPS2', if_true: files('lasips2.c'))
|
||||
|
@ -1,319 +0,0 @@
|
||||
/*
|
||||
* QEMU model of the Milkymist SoftUSB block.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Specification available at:
|
||||
* not available yet
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
#include "ui/console.h"
|
||||
#include "hw/input/hid.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
enum {
|
||||
R_CTRL = 0,
|
||||
R_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
CTRL_RESET = (1<<0),
|
||||
};
|
||||
|
||||
#define COMLOC_DEBUG_PRODUCE 0x1000
|
||||
#define COMLOC_DEBUG_BASE 0x1001
|
||||
#define COMLOC_MEVT_PRODUCE 0x1101
|
||||
#define COMLOC_MEVT_BASE 0x1102
|
||||
#define COMLOC_KEVT_PRODUCE 0x1142
|
||||
#define COMLOC_KEVT_BASE 0x1143
|
||||
|
||||
#define TYPE_MILKYMIST_SOFTUSB "milkymist-softusb"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(MilkymistSoftUsbState, MILKYMIST_SOFTUSB)
|
||||
|
||||
struct MilkymistSoftUsbState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
HIDState hid_kbd;
|
||||
HIDState hid_mouse;
|
||||
|
||||
MemoryRegion regs_region;
|
||||
MemoryRegion pmem;
|
||||
MemoryRegion dmem;
|
||||
qemu_irq irq;
|
||||
|
||||
void *pmem_ptr;
|
||||
void *dmem_ptr;
|
||||
|
||||
/* device properties */
|
||||
uint32_t pmem_size;
|
||||
uint32_t dmem_size;
|
||||
|
||||
/* device registers */
|
||||
uint32_t regs[R_MAX];
|
||||
|
||||
/* mouse state */
|
||||
uint8_t mouse_hid_buffer[4];
|
||||
|
||||
/* keyboard state */
|
||||
uint8_t kbd_hid_buffer[8];
|
||||
};
|
||||
|
||||
static uint64_t softusb_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistSoftUsbState *s = opaque;
|
||||
uint32_t r = 0;
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_CTRL:
|
||||
r = s->regs[addr];
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("milkymist_softusb: read access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_milkymist_softusb_memory_read(addr << 2, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
softusb_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistSoftUsbState *s = opaque;
|
||||
|
||||
trace_milkymist_softusb_memory_write(addr, value);
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_CTRL:
|
||||
s->regs[addr] = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("milkymist_softusb: write access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps softusb_mmio_ops = {
|
||||
.read = softusb_read,
|
||||
.write = softusb_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static inline void softusb_read_dmem(MilkymistSoftUsbState *s,
|
||||
uint32_t offset, uint8_t *buf, uint32_t len)
|
||||
{
|
||||
if (offset + len >= s->dmem_size) {
|
||||
error_report("milkymist_softusb: read dmem out of bounds "
|
||||
"at offset 0x%x, len %d", offset, len);
|
||||
memset(buf, 0, len);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(buf, s->dmem_ptr + offset, len);
|
||||
}
|
||||
|
||||
static inline void softusb_write_dmem(MilkymistSoftUsbState *s,
|
||||
uint32_t offset, uint8_t *buf, uint32_t len)
|
||||
{
|
||||
if (offset + len >= s->dmem_size) {
|
||||
error_report("milkymist_softusb: write dmem out of bounds "
|
||||
"at offset 0x%x, len %d", offset, len);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(s->dmem_ptr + offset, buf, len);
|
||||
}
|
||||
|
||||
static void softusb_mouse_changed(MilkymistSoftUsbState *s)
|
||||
{
|
||||
uint8_t m;
|
||||
|
||||
softusb_read_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
|
||||
trace_milkymist_softusb_mevt(m);
|
||||
softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, s->mouse_hid_buffer, 4);
|
||||
m = (m + 1) & 0xf;
|
||||
softusb_write_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
|
||||
|
||||
trace_milkymist_softusb_pulse_irq();
|
||||
qemu_irq_pulse(s->irq);
|
||||
}
|
||||
|
||||
static void softusb_kbd_changed(MilkymistSoftUsbState *s)
|
||||
{
|
||||
uint8_t m;
|
||||
|
||||
softusb_read_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
|
||||
trace_milkymist_softusb_kevt(m);
|
||||
softusb_write_dmem(s, COMLOC_KEVT_BASE + 8 * m, s->kbd_hid_buffer, 8);
|
||||
m = (m + 1) & 0x7;
|
||||
softusb_write_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
|
||||
|
||||
trace_milkymist_softusb_pulse_irq();
|
||||
qemu_irq_pulse(s->irq);
|
||||
}
|
||||
|
||||
static void softusb_kbd_hid_datain(HIDState *hs)
|
||||
{
|
||||
MilkymistSoftUsbState *s = container_of(hs, MilkymistSoftUsbState, hid_kbd);
|
||||
int len;
|
||||
|
||||
/* if device is in reset, do nothing */
|
||||
if (s->regs[R_CTRL] & CTRL_RESET) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (hid_has_events(hs)) {
|
||||
len = hid_keyboard_poll(hs, s->kbd_hid_buffer,
|
||||
sizeof(s->kbd_hid_buffer));
|
||||
|
||||
if (len == 8) {
|
||||
softusb_kbd_changed(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void softusb_mouse_hid_datain(HIDState *hs)
|
||||
{
|
||||
MilkymistSoftUsbState *s =
|
||||
container_of(hs, MilkymistSoftUsbState, hid_mouse);
|
||||
int len;
|
||||
|
||||
/* if device is in reset, do nothing */
|
||||
if (s->regs[R_CTRL] & CTRL_RESET) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (hid_has_events(hs)) {
|
||||
len = hid_pointer_poll(hs, s->mouse_hid_buffer,
|
||||
sizeof(s->mouse_hid_buffer));
|
||||
|
||||
if (len == 4) {
|
||||
softusb_mouse_changed(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void milkymist_softusb_reset(DeviceState *d)
|
||||
{
|
||||
MilkymistSoftUsbState *s = MILKYMIST_SOFTUSB(d);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < R_MAX; i++) {
|
||||
s->regs[i] = 0;
|
||||
}
|
||||
memset(s->kbd_hid_buffer, 0, sizeof(s->kbd_hid_buffer));
|
||||
memset(s->mouse_hid_buffer, 0, sizeof(s->mouse_hid_buffer));
|
||||
|
||||
hid_reset(&s->hid_kbd);
|
||||
hid_reset(&s->hid_mouse);
|
||||
|
||||
/* defaults */
|
||||
s->regs[R_CTRL] = CTRL_RESET;
|
||||
}
|
||||
|
||||
static void milkymist_softusb_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MilkymistSoftUsbState *s = MILKYMIST_SOFTUSB(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
||||
memory_region_init_io(&s->regs_region, OBJECT(s), &softusb_mmio_ops, s,
|
||||
"milkymist-softusb", R_MAX * 4);
|
||||
sysbus_init_mmio(sbd, &s->regs_region);
|
||||
|
||||
/* register pmem and dmem */
|
||||
memory_region_init_ram_nomigrate(&s->pmem, OBJECT(s), "milkymist-softusb.pmem",
|
||||
s->pmem_size, &error_fatal);
|
||||
vmstate_register_ram_global(&s->pmem);
|
||||
s->pmem_ptr = memory_region_get_ram_ptr(&s->pmem);
|
||||
sysbus_init_mmio(sbd, &s->pmem);
|
||||
memory_region_init_ram_nomigrate(&s->dmem, OBJECT(s), "milkymist-softusb.dmem",
|
||||
s->dmem_size, &error_fatal);
|
||||
vmstate_register_ram_global(&s->dmem);
|
||||
s->dmem_ptr = memory_region_get_ram_ptr(&s->dmem);
|
||||
sysbus_init_mmio(sbd, &s->dmem);
|
||||
|
||||
hid_init(&s->hid_kbd, HID_KEYBOARD, softusb_kbd_hid_datain);
|
||||
hid_init(&s->hid_mouse, HID_MOUSE, softusb_mouse_hid_datain);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_milkymist_softusb = {
|
||||
.name = "milkymist-softusb",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX),
|
||||
VMSTATE_HID_KEYBOARD_DEVICE(hid_kbd, MilkymistSoftUsbState),
|
||||
VMSTATE_HID_POINTER_DEVICE(hid_mouse, MilkymistSoftUsbState),
|
||||
VMSTATE_BUFFER(kbd_hid_buffer, MilkymistSoftUsbState),
|
||||
VMSTATE_BUFFER(mouse_hid_buffer, MilkymistSoftUsbState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property milkymist_softusb_properties[] = {
|
||||
DEFINE_PROP_UINT32("pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000),
|
||||
DEFINE_PROP_UINT32("dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void milkymist_softusb_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = milkymist_softusb_realize;
|
||||
dc->reset = milkymist_softusb_reset;
|
||||
dc->vmsd = &vmstate_milkymist_softusb;
|
||||
device_class_set_props(dc, milkymist_softusb_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo milkymist_softusb_info = {
|
||||
.name = TYPE_MILKYMIST_SOFTUSB,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MilkymistSoftUsbState),
|
||||
.class_init = milkymist_softusb_class_init,
|
||||
};
|
||||
|
||||
static void milkymist_softusb_register_types(void)
|
||||
{
|
||||
type_register_static(&milkymist_softusb_info);
|
||||
}
|
||||
|
||||
type_init(milkymist_softusb_register_types)
|
@ -44,13 +44,6 @@ ps2_mouse_reset(void *opaque) "%p"
|
||||
ps2_kbd_init(void *s) "%p"
|
||||
ps2_mouse_init(void *s) "%p"
|
||||
|
||||
# milkymist-softusb.c
|
||||
milkymist_softusb_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
milkymist_softusb_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
milkymist_softusb_mevt(uint8_t m) "m %d"
|
||||
milkymist_softusb_kevt(uint8_t m) "m %d"
|
||||
milkymist_softusb_pulse_irq(void) "Pulse IRQ"
|
||||
|
||||
# hid.c
|
||||
hid_kbd_queue_full(void) "queue full"
|
||||
hid_kbd_queue_empty(void) "queue empty"
|
||||
|
@ -1,195 +0,0 @@
|
||||
/*
|
||||
* LatticeMico32 CPU interrupt controller logic.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "migration/vmstate.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "qemu/module.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "trace.h"
|
||||
#include "hw/lm32/lm32_pic.h"
|
||||
#include "hw/intc/intc.h"
|
||||
#include "hw/irq.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_LM32_PIC "lm32-pic"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(LM32PicState, LM32_PIC)
|
||||
|
||||
struct LM32PicState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
qemu_irq parent_irq;
|
||||
uint32_t im; /* interrupt mask */
|
||||
uint32_t ip; /* interrupt pending */
|
||||
uint32_t irq_state;
|
||||
|
||||
/* statistics */
|
||||
uint64_t stats_irq_count[32];
|
||||
};
|
||||
|
||||
static void update_irq(LM32PicState *s)
|
||||
{
|
||||
s->ip |= s->irq_state;
|
||||
|
||||
if (s->ip & s->im) {
|
||||
trace_lm32_pic_raise_irq();
|
||||
qemu_irq_raise(s->parent_irq);
|
||||
} else {
|
||||
trace_lm32_pic_lower_irq();
|
||||
qemu_irq_lower(s->parent_irq);
|
||||
}
|
||||
}
|
||||
|
||||
static void irq_handler(void *opaque, int irq, int level)
|
||||
{
|
||||
LM32PicState *s = opaque;
|
||||
|
||||
assert(irq < 32);
|
||||
trace_lm32_pic_interrupt(irq, level);
|
||||
|
||||
if (level) {
|
||||
s->irq_state |= (1 << irq);
|
||||
s->stats_irq_count[irq]++;
|
||||
} else {
|
||||
s->irq_state &= ~(1 << irq);
|
||||
}
|
||||
|
||||
update_irq(s);
|
||||
}
|
||||
|
||||
void lm32_pic_set_im(DeviceState *d, uint32_t im)
|
||||
{
|
||||
LM32PicState *s = LM32_PIC(d);
|
||||
|
||||
trace_lm32_pic_set_im(im);
|
||||
s->im = im;
|
||||
|
||||
update_irq(s);
|
||||
}
|
||||
|
||||
void lm32_pic_set_ip(DeviceState *d, uint32_t ip)
|
||||
{
|
||||
LM32PicState *s = LM32_PIC(d);
|
||||
|
||||
trace_lm32_pic_set_ip(ip);
|
||||
|
||||
/* ack interrupt */
|
||||
s->ip &= ~ip;
|
||||
|
||||
update_irq(s);
|
||||
}
|
||||
|
||||
uint32_t lm32_pic_get_im(DeviceState *d)
|
||||
{
|
||||
LM32PicState *s = LM32_PIC(d);
|
||||
|
||||
trace_lm32_pic_get_im(s->im);
|
||||
return s->im;
|
||||
}
|
||||
|
||||
uint32_t lm32_pic_get_ip(DeviceState *d)
|
||||
{
|
||||
LM32PicState *s = LM32_PIC(d);
|
||||
|
||||
trace_lm32_pic_get_ip(s->ip);
|
||||
return s->ip;
|
||||
}
|
||||
|
||||
static void pic_reset(DeviceState *d)
|
||||
{
|
||||
LM32PicState *s = LM32_PIC(d);
|
||||
int i;
|
||||
|
||||
s->im = 0;
|
||||
s->ip = 0;
|
||||
s->irq_state = 0;
|
||||
for (i = 0; i < 32; i++) {
|
||||
s->stats_irq_count[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool lm32_get_statistics(InterruptStatsProvider *obj,
|
||||
uint64_t **irq_counts, unsigned int *nb_irqs)
|
||||
{
|
||||
LM32PicState *s = LM32_PIC(obj);
|
||||
*irq_counts = s->stats_irq_count;
|
||||
*nb_irqs = ARRAY_SIZE(s->stats_irq_count);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void lm32_print_info(InterruptStatsProvider *obj, Monitor *mon)
|
||||
{
|
||||
LM32PicState *s = LM32_PIC(obj);
|
||||
monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n",
|
||||
s->im, s->ip, s->irq_state);
|
||||
}
|
||||
|
||||
static void lm32_pic_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
LM32PicState *s = LM32_PIC(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
qdev_init_gpio_in(dev, irq_handler, 32);
|
||||
sysbus_init_irq(sbd, &s->parent_irq);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_lm32_pic = {
|
||||
.name = "lm32-pic",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(im, LM32PicState),
|
||||
VMSTATE_UINT32(ip, LM32PicState),
|
||||
VMSTATE_UINT32(irq_state, LM32PicState),
|
||||
VMSTATE_UINT64_ARRAY(stats_irq_count, LM32PicState, 32),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void lm32_pic_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
|
||||
|
||||
dc->reset = pic_reset;
|
||||
dc->vmsd = &vmstate_lm32_pic;
|
||||
ic->get_statistics = lm32_get_statistics;
|
||||
ic->print_info = lm32_print_info;
|
||||
}
|
||||
|
||||
static const TypeInfo lm32_pic_info = {
|
||||
.name = TYPE_LM32_PIC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(LM32PicState),
|
||||
.instance_init = lm32_pic_init,
|
||||
.class_init = lm32_pic_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_INTERRUPT_STATS_PROVIDER },
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
||||
static void lm32_pic_register_types(void)
|
||||
{
|
||||
type_register_static(&lm32_pic_info);
|
||||
}
|
||||
|
||||
type_init(lm32_pic_register_types)
|
@ -14,10 +14,8 @@ softmmu_ss.add(when: 'CONFIG_HEATHROW_PIC', if_true: files('heathrow_pic.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_I8259', if_true: files('i8259_common.c', 'i8259.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_avic.c', 'imx_gpcv2.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_IOAPIC', if_true: files('ioapic_common.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_LM32_DEVICES', if_true: files('lm32_pic.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_OPENPIC', if_true: files('openpic.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PL190', if_true: files('pl190.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_intc.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview_gic.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_intctl.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_intc.c'))
|
||||
|
@ -1,147 +0,0 @@
|
||||
/*
|
||||
* INTC device simulation in PKUnity SoC
|
||||
*
|
||||
* Copyright (C) 2010-2012 Guan Xuetao
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation, or any later version.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#undef DEBUG_PUV3
|
||||
#include "hw/unicore32/puv3.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/log.h"
|
||||
|
||||
#define TYPE_PUV3_INTC "puv3_intc"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(PUV3INTCState, PUV3_INTC)
|
||||
|
||||
struct PUV3INTCState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
qemu_irq parent_irq;
|
||||
|
||||
uint32_t reg_ICMR;
|
||||
uint32_t reg_ICPR;
|
||||
};
|
||||
|
||||
/* Update interrupt status after enabled or pending bits have been changed. */
|
||||
static void puv3_intc_update(PUV3INTCState *s)
|
||||
{
|
||||
if (s->reg_ICMR & s->reg_ICPR) {
|
||||
qemu_irq_raise(s->parent_irq);
|
||||
} else {
|
||||
qemu_irq_lower(s->parent_irq);
|
||||
}
|
||||
}
|
||||
|
||||
/* Process a change in an external INTC input. */
|
||||
static void puv3_intc_handler(void *opaque, int irq, int level)
|
||||
{
|
||||
PUV3INTCState *s = opaque;
|
||||
|
||||
DPRINTF("irq 0x%x, level 0x%x\n", irq, level);
|
||||
if (level) {
|
||||
s->reg_ICPR |= (1 << irq);
|
||||
} else {
|
||||
s->reg_ICPR &= ~(1 << irq);
|
||||
}
|
||||
puv3_intc_update(s);
|
||||
}
|
||||
|
||||
static uint64_t puv3_intc_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
PUV3INTCState *s = opaque;
|
||||
uint32_t ret = 0;
|
||||
|
||||
switch (offset) {
|
||||
case 0x04: /* INTC_ICMR */
|
||||
ret = s->reg_ICMR;
|
||||
break;
|
||||
case 0x0c: /* INTC_ICIP */
|
||||
ret = s->reg_ICPR; /* the same value with ICPR */
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad read offset 0x%"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
}
|
||||
DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void puv3_intc_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
PUV3INTCState *s = opaque;
|
||||
|
||||
DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
|
||||
switch (offset) {
|
||||
case 0x00: /* INTC_ICLR */
|
||||
case 0x14: /* INTC_ICCR */
|
||||
break;
|
||||
case 0x04: /* INTC_ICMR */
|
||||
s->reg_ICMR = value;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad write offset 0x%"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
return;
|
||||
}
|
||||
puv3_intc_update(s);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps puv3_intc_ops = {
|
||||
.read = puv3_intc_read,
|
||||
.write = puv3_intc_write,
|
||||
.impl = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void puv3_intc_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PUV3INTCState *s = PUV3_INTC(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
qdev_init_gpio_in(dev, puv3_intc_handler, PUV3_IRQS_NR);
|
||||
sysbus_init_irq(sbd, &s->parent_irq);
|
||||
|
||||
s->reg_ICMR = 0;
|
||||
s->reg_ICPR = 0;
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &puv3_intc_ops, s, "puv3_intc",
|
||||
PUV3_REGS_OFFSET);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
}
|
||||
|
||||
static void puv3_intc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
dc->realize = puv3_intc_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo puv3_intc_info = {
|
||||
.name = TYPE_PUV3_INTC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PUV3INTCState),
|
||||
.class_init = puv3_intc_class_init,
|
||||
};
|
||||
|
||||
static void puv3_intc_register_type(void)
|
||||
{
|
||||
type_register_static(&puv3_intc_info);
|
||||
}
|
||||
|
||||
type_init(puv3_intc_register_type)
|
@ -51,15 +51,6 @@ grlib_irqmp_set_irq(int irq) "Raise CPU IRQ %d"
|
||||
grlib_irqmp_readl_unknown(uint64_t addr) "addr 0x%"PRIx64
|
||||
grlib_irqmp_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x"
|
||||
|
||||
# lm32_pic.c
|
||||
lm32_pic_raise_irq(void) "Raise CPU interrupt"
|
||||
lm32_pic_lower_irq(void) "Lower CPU interrupt"
|
||||
lm32_pic_interrupt(int irq, int level) "Set IRQ%d %d"
|
||||
lm32_pic_set_im(uint32_t im) "im 0x%08x"
|
||||
lm32_pic_set_ip(uint32_t ip) "ip 0x%08x"
|
||||
lm32_pic_get_im(uint32_t im) "im 0x%08x"
|
||||
lm32_pic_get_ip(uint32_t ip) "ip 0x%08x"
|
||||
|
||||
# xics.c
|
||||
xics_icp_check_ipi(int server, uint8_t mfrr) "CPU %d can take IPI mfrr=0x%x"
|
||||
xics_icp_accept(uint32_t old_xirr, uint32_t new_xirr) "icp_accept: XIRR 0x%"PRIx32"->0x%"PRIx32
|
||||
|
@ -1,18 +0,0 @@
|
||||
config LM32_DEVICES
|
||||
bool
|
||||
select PTIMER
|
||||
|
||||
config MILKYMIST
|
||||
bool
|
||||
# FIXME: disabling it results in compile-time errors
|
||||
select MILKYMIST_TMU2 if OPENGL && X11
|
||||
select PFLASH_CFI01
|
||||
select FRAMEBUFFER
|
||||
select SD
|
||||
select USB_OHCI
|
||||
select LM32_DEVICES
|
||||
|
||||
config LM32_EVR
|
||||
bool
|
||||
select LM32_DEVICES
|
||||
select PFLASH_CFI02
|
@ -1,48 +0,0 @@
|
||||
#ifndef HW_LM32_H
|
||||
#define HW_LM32_H
|
||||
|
||||
#include "hw/char/lm32_juart.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
static inline DeviceState *lm32_pic_init(qemu_irq cpu_irq)
|
||||
{
|
||||
DeviceState *dev;
|
||||
SysBusDevice *d;
|
||||
|
||||
dev = qdev_new("lm32-pic");
|
||||
d = SYS_BUS_DEVICE(dev);
|
||||
sysbus_realize_and_unref(d, &error_fatal);
|
||||
sysbus_connect_irq(d, 0, cpu_irq);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static inline DeviceState *lm32_juart_init(Chardev *chr)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = qdev_new(TYPE_LM32_JUART);
|
||||
qdev_prop_set_chr(dev, "chardev", chr);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static inline DeviceState *lm32_uart_create(hwaddr addr,
|
||||
qemu_irq irq,
|
||||
Chardev *chr)
|
||||
{
|
||||
DeviceState *dev;
|
||||
SysBusDevice *s;
|
||||
|
||||
dev = qdev_new("lm32-uart");
|
||||
s = SYS_BUS_DEVICE(dev);
|
||||
qdev_prop_set_chr(dev, "chardev", chr);
|
||||
sysbus_realize_and_unref(s, &error_fatal);
|
||||
sysbus_mmio_map(s, 0, addr);
|
||||
sysbus_connect_irq(s, 0, irq);
|
||||
return dev;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,332 +0,0 @@
|
||||
/*
|
||||
* QEMU models for LatticeMico32 uclinux and evr32 boards.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/loader.h"
|
||||
#include "elf.h"
|
||||
#include "lm32_hwsetup.h"
|
||||
#include "lm32.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
typedef struct {
|
||||
LM32CPU *cpu;
|
||||
hwaddr bootstrap_pc;
|
||||
hwaddr flash_base;
|
||||
hwaddr hwsetup_base;
|
||||
hwaddr initrd_base;
|
||||
size_t initrd_size;
|
||||
hwaddr cmdline_base;
|
||||
} ResetInfo;
|
||||
|
||||
static void cpu_irq_handler(void *opaque, int irq, int level)
|
||||
{
|
||||
LM32CPU *cpu = opaque;
|
||||
CPUState *cs = CPU(cpu);
|
||||
|
||||
if (level) {
|
||||
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
|
||||
} else {
|
||||
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
}
|
||||
|
||||
static void main_cpu_reset(void *opaque)
|
||||
{
|
||||
ResetInfo *reset_info = opaque;
|
||||
CPULM32State *env = &reset_info->cpu->env;
|
||||
|
||||
cpu_reset(CPU(reset_info->cpu));
|
||||
|
||||
/* init defaults */
|
||||
env->pc = (uint32_t)reset_info->bootstrap_pc;
|
||||
env->regs[R_R1] = (uint32_t)reset_info->hwsetup_base;
|
||||
env->regs[R_R2] = (uint32_t)reset_info->cmdline_base;
|
||||
env->regs[R_R3] = (uint32_t)reset_info->initrd_base;
|
||||
env->regs[R_R4] = (uint32_t)(reset_info->initrd_base +
|
||||
reset_info->initrd_size);
|
||||
env->eba = reset_info->flash_base;
|
||||
env->deba = reset_info->flash_base;
|
||||
}
|
||||
|
||||
static void lm32_evr_init(MachineState *machine)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
LM32CPU *cpu;
|
||||
CPULM32State *env;
|
||||
DriveInfo *dinfo;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
qemu_irq irq[32];
|
||||
ResetInfo *reset_info;
|
||||
int i;
|
||||
|
||||
if (machine->ram_size != mc->default_ram_size) {
|
||||
char *sz = size_to_str(mc->default_ram_size);
|
||||
error_report("Invalid RAM size, should be %s", sz);
|
||||
g_free(sz);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* memory map */
|
||||
hwaddr flash_base = 0x04000000;
|
||||
size_t flash_sector_size = 256 * KiB;
|
||||
size_t flash_size = 32 * MiB;
|
||||
hwaddr ram_base = 0x08000000;
|
||||
hwaddr timer0_base = 0x80002000;
|
||||
hwaddr uart0_base = 0x80006000;
|
||||
hwaddr timer1_base = 0x8000a000;
|
||||
int uart0_irq = 0;
|
||||
int timer0_irq = 1;
|
||||
int timer1_irq = 3;
|
||||
|
||||
reset_info = g_malloc0(sizeof(ResetInfo));
|
||||
|
||||
cpu = LM32_CPU(cpu_create(machine->cpu_type));
|
||||
|
||||
env = &cpu->env;
|
||||
reset_info->cpu = cpu;
|
||||
|
||||
reset_info->flash_base = flash_base;
|
||||
|
||||
memory_region_add_subregion(address_space_mem, ram_base, machine->ram);
|
||||
|
||||
dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||
/* Spansion S29NS128P */
|
||||
pflash_cfi02_register(flash_base, "lm32_evr.flash", flash_size,
|
||||
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
|
||||
flash_sector_size,
|
||||
1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
|
||||
|
||||
/* create irq lines */
|
||||
env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, cpu, 0));
|
||||
for (i = 0; i < 32; i++) {
|
||||
irq[i] = qdev_get_gpio_in(env->pic_state, i);
|
||||
}
|
||||
|
||||
lm32_uart_create(uart0_base, irq[uart0_irq], serial_hd(0));
|
||||
sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]);
|
||||
sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]);
|
||||
|
||||
/* make sure juart isn't the first chardev */
|
||||
env->juart_state = lm32_juart_init(serial_hd(1));
|
||||
|
||||
reset_info->bootstrap_pc = flash_base;
|
||||
|
||||
if (kernel_filename) {
|
||||
uint64_t entry;
|
||||
int kernel_size;
|
||||
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
|
||||
&entry, NULL, NULL, NULL,
|
||||
1, EM_LATTICEMICO32, 0, 0);
|
||||
reset_info->bootstrap_pc = entry;
|
||||
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_image_targphys(kernel_filename, ram_base,
|
||||
machine->ram_size);
|
||||
reset_info->bootstrap_pc = ram_base;
|
||||
}
|
||||
|
||||
if (kernel_size < 0) {
|
||||
error_report("could not load kernel '%s'", kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
qemu_register_reset(main_cpu_reset, reset_info);
|
||||
}
|
||||
|
||||
static void lm32_uclinux_init(MachineState *machine)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
LM32CPU *cpu;
|
||||
CPULM32State *env;
|
||||
DriveInfo *dinfo;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
qemu_irq irq[32];
|
||||
HWSetup *hw;
|
||||
ResetInfo *reset_info;
|
||||
int i;
|
||||
|
||||
if (machine->ram_size != mc->default_ram_size) {
|
||||
char *sz = size_to_str(mc->default_ram_size);
|
||||
error_report("Invalid RAM size, should be %s", sz);
|
||||
g_free(sz);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* memory map */
|
||||
hwaddr flash_base = 0x04000000;
|
||||
size_t flash_sector_size = 256 * KiB;
|
||||
size_t flash_size = 32 * MiB;
|
||||
hwaddr ram_base = 0x08000000;
|
||||
hwaddr uart0_base = 0x80000000;
|
||||
hwaddr timer0_base = 0x80002000;
|
||||
hwaddr timer1_base = 0x80010000;
|
||||
hwaddr timer2_base = 0x80012000;
|
||||
int uart0_irq = 0;
|
||||
int timer0_irq = 1;
|
||||
int timer1_irq = 20;
|
||||
int timer2_irq = 21;
|
||||
hwaddr hwsetup_base = 0x0bffe000;
|
||||
hwaddr cmdline_base = 0x0bfff000;
|
||||
hwaddr initrd_base = 0x08400000;
|
||||
size_t initrd_max = 0x01000000;
|
||||
|
||||
reset_info = g_malloc0(sizeof(ResetInfo));
|
||||
|
||||
cpu = LM32_CPU(cpu_create(machine->cpu_type));
|
||||
|
||||
env = &cpu->env;
|
||||
reset_info->cpu = cpu;
|
||||
|
||||
reset_info->flash_base = flash_base;
|
||||
|
||||
memory_region_add_subregion(address_space_mem, ram_base, machine->ram);
|
||||
|
||||
dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||
/* Spansion S29NS128P */
|
||||
pflash_cfi02_register(flash_base, "lm32_uclinux.flash", flash_size,
|
||||
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
|
||||
flash_sector_size,
|
||||
1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
|
||||
|
||||
/* create irq lines */
|
||||
env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, env, 0));
|
||||
for (i = 0; i < 32; i++) {
|
||||
irq[i] = qdev_get_gpio_in(env->pic_state, i);
|
||||
}
|
||||
|
||||
lm32_uart_create(uart0_base, irq[uart0_irq], serial_hd(0));
|
||||
sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]);
|
||||
sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]);
|
||||
sysbus_create_simple("lm32-timer", timer2_base, irq[timer2_irq]);
|
||||
|
||||
/* make sure juart isn't the first chardev */
|
||||
env->juart_state = lm32_juart_init(serial_hd(1));
|
||||
|
||||
reset_info->bootstrap_pc = flash_base;
|
||||
|
||||
if (kernel_filename) {
|
||||
uint64_t entry;
|
||||
int kernel_size;
|
||||
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
|
||||
&entry, NULL, NULL, NULL,
|
||||
1, EM_LATTICEMICO32, 0, 0);
|
||||
reset_info->bootstrap_pc = entry;
|
||||
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_image_targphys(kernel_filename, ram_base,
|
||||
machine->ram_size);
|
||||
reset_info->bootstrap_pc = ram_base;
|
||||
}
|
||||
|
||||
if (kernel_size < 0) {
|
||||
error_report("could not load kernel '%s'", kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* generate a rom with the hardware description */
|
||||
hw = hwsetup_init();
|
||||
hwsetup_add_cpu(hw, "LM32", 75000000);
|
||||
hwsetup_add_flash(hw, "flash", flash_base, flash_size);
|
||||
hwsetup_add_ddr_sdram(hw, "ddr_sdram", ram_base, machine->ram_size);
|
||||
hwsetup_add_timer(hw, "timer0", timer0_base, timer0_irq);
|
||||
hwsetup_add_timer(hw, "timer1_dev_only", timer1_base, timer1_irq);
|
||||
hwsetup_add_timer(hw, "timer2_dev_only", timer2_base, timer2_irq);
|
||||
hwsetup_add_uart(hw, "uart", uart0_base, uart0_irq);
|
||||
hwsetup_add_trailer(hw);
|
||||
hwsetup_create_rom(hw, hwsetup_base);
|
||||
hwsetup_free(hw);
|
||||
|
||||
reset_info->hwsetup_base = hwsetup_base;
|
||||
|
||||
if (kernel_cmdline && strlen(kernel_cmdline)) {
|
||||
pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE,
|
||||
kernel_cmdline);
|
||||
reset_info->cmdline_base = cmdline_base;
|
||||
}
|
||||
|
||||
if (initrd_filename) {
|
||||
size_t initrd_size;
|
||||
initrd_size = load_image_targphys(initrd_filename, initrd_base,
|
||||
initrd_max);
|
||||
reset_info->initrd_base = initrd_base;
|
||||
reset_info->initrd_size = initrd_size;
|
||||
}
|
||||
|
||||
qemu_register_reset(main_cpu_reset, reset_info);
|
||||
}
|
||||
|
||||
static void lm32_evr_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "LatticeMico32 EVR32 eval system";
|
||||
mc->init = lm32_evr_init;
|
||||
mc->is_default = true;
|
||||
mc->default_cpu_type = LM32_CPU_TYPE_NAME("lm32-full");
|
||||
mc->default_ram_size = 64 * MiB;
|
||||
mc->default_ram_id = "lm32_evr.sdram";
|
||||
}
|
||||
|
||||
static const TypeInfo lm32_evr_type = {
|
||||
.name = MACHINE_TYPE_NAME("lm32-evr"),
|
||||
.parent = TYPE_MACHINE,
|
||||
.class_init = lm32_evr_class_init,
|
||||
};
|
||||
|
||||
static void lm32_uclinux_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "lm32 platform for uClinux and u-boot by Theobroma Systems";
|
||||
mc->init = lm32_uclinux_init;
|
||||
mc->default_cpu_type = LM32_CPU_TYPE_NAME("lm32-full");
|
||||
mc->default_ram_size = 64 * MiB;
|
||||
mc->default_ram_id = "lm32_uclinux.sdram";
|
||||
}
|
||||
|
||||
static const TypeInfo lm32_uclinux_type = {
|
||||
.name = MACHINE_TYPE_NAME("lm32-uclinux"),
|
||||
.parent = TYPE_MACHINE,
|
||||
.class_init = lm32_uclinux_class_init,
|
||||
};
|
||||
|
||||
static void lm32_machine_init(void)
|
||||
{
|
||||
type_register_static(&lm32_evr_type);
|
||||
type_register_static(&lm32_uclinux_type);
|
||||
}
|
||||
|
||||
type_init(lm32_machine_init)
|
@ -1,179 +0,0 @@
|
||||
/*
|
||||
* LatticeMico32 hwsetup helper functions.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* These are helper functions for creating the hardware description blob used
|
||||
* in the Theobroma's uClinux port.
|
||||
*/
|
||||
|
||||
#ifndef QEMU_HW_LM32_HWSETUP_H
|
||||
#define QEMU_HW_LM32_HWSETUP_H
|
||||
|
||||
#include "qemu/cutils.h"
|
||||
#include "hw/loader.h"
|
||||
|
||||
typedef struct {
|
||||
void *data;
|
||||
void *ptr;
|
||||
} HWSetup;
|
||||
|
||||
enum hwsetup_tag {
|
||||
HWSETUP_TAG_EOL = 0,
|
||||
HWSETUP_TAG_CPU = 1,
|
||||
HWSETUP_TAG_ASRAM = 2,
|
||||
HWSETUP_TAG_FLASH = 3,
|
||||
HWSETUP_TAG_SDRAM = 4,
|
||||
HWSETUP_TAG_OCM = 5,
|
||||
HWSETUP_TAG_DDR_SDRAM = 6,
|
||||
HWSETUP_TAG_DDR2_SDRAM = 7,
|
||||
HWSETUP_TAG_TIMER = 8,
|
||||
HWSETUP_TAG_UART = 9,
|
||||
HWSETUP_TAG_GPIO = 10,
|
||||
HWSETUP_TAG_TRISPEEDMAC = 11,
|
||||
HWSETUP_TAG_I2CM = 12,
|
||||
HWSETUP_TAG_LEDS = 13,
|
||||
HWSETUP_TAG_7SEG = 14,
|
||||
HWSETUP_TAG_SPI_S = 15,
|
||||
HWSETUP_TAG_SPI_M = 16,
|
||||
};
|
||||
|
||||
static inline HWSetup *hwsetup_init(void)
|
||||
{
|
||||
HWSetup *hw;
|
||||
|
||||
hw = g_malloc(sizeof(HWSetup));
|
||||
hw->data = g_malloc0(TARGET_PAGE_SIZE);
|
||||
hw->ptr = hw->data;
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
static inline void hwsetup_free(HWSetup *hw)
|
||||
{
|
||||
g_free(hw->data);
|
||||
g_free(hw);
|
||||
}
|
||||
|
||||
static inline void hwsetup_create_rom(HWSetup *hw,
|
||||
hwaddr base)
|
||||
{
|
||||
rom_add_blob("hwsetup", hw->data, TARGET_PAGE_SIZE,
|
||||
TARGET_PAGE_SIZE, base, NULL, NULL, NULL, NULL, true);
|
||||
}
|
||||
|
||||
static inline void hwsetup_add_u8(HWSetup *hw, uint8_t u)
|
||||
{
|
||||
stb_p(hw->ptr, u);
|
||||
hw->ptr += 1;
|
||||
}
|
||||
|
||||
static inline void hwsetup_add_u32(HWSetup *hw, uint32_t u)
|
||||
{
|
||||
stl_p(hw->ptr, u);
|
||||
hw->ptr += 4;
|
||||
}
|
||||
|
||||
static inline void hwsetup_add_tag(HWSetup *hw, enum hwsetup_tag t)
|
||||
{
|
||||
stl_p(hw->ptr, t);
|
||||
hw->ptr += 4;
|
||||
}
|
||||
|
||||
static inline void hwsetup_add_str(HWSetup *hw, const char *str)
|
||||
{
|
||||
pstrcpy(hw->ptr, 32, str);
|
||||
hw->ptr += 32;
|
||||
}
|
||||
|
||||
static inline void hwsetup_add_trailer(HWSetup *hw)
|
||||
{
|
||||
hwsetup_add_u32(hw, 8); /* size */
|
||||
hwsetup_add_tag(hw, HWSETUP_TAG_EOL);
|
||||
}
|
||||
|
||||
static inline void hwsetup_add_cpu(HWSetup *hw,
|
||||
const char *name, uint32_t frequency)
|
||||
{
|
||||
hwsetup_add_u32(hw, 44); /* size */
|
||||
hwsetup_add_tag(hw, HWSETUP_TAG_CPU);
|
||||
hwsetup_add_str(hw, name);
|
||||
hwsetup_add_u32(hw, frequency);
|
||||
}
|
||||
|
||||
static inline void hwsetup_add_flash(HWSetup *hw,
|
||||
const char *name, uint32_t base, uint32_t size)
|
||||
{
|
||||
hwsetup_add_u32(hw, 52); /* size */
|
||||
hwsetup_add_tag(hw, HWSETUP_TAG_FLASH);
|
||||
hwsetup_add_str(hw, name);
|
||||
hwsetup_add_u32(hw, base);
|
||||
hwsetup_add_u32(hw, size);
|
||||
hwsetup_add_u8(hw, 8); /* read latency */
|
||||
hwsetup_add_u8(hw, 8); /* write latency */
|
||||
hwsetup_add_u8(hw, 25); /* address width */
|
||||
hwsetup_add_u8(hw, 32); /* data width */
|
||||
}
|
||||
|
||||
static inline void hwsetup_add_ddr_sdram(HWSetup *hw,
|
||||
const char *name, uint32_t base, uint32_t size)
|
||||
{
|
||||
hwsetup_add_u32(hw, 48); /* size */
|
||||
hwsetup_add_tag(hw, HWSETUP_TAG_DDR_SDRAM);
|
||||
hwsetup_add_str(hw, name);
|
||||
hwsetup_add_u32(hw, base);
|
||||
hwsetup_add_u32(hw, size);
|
||||
}
|
||||
|
||||
static inline void hwsetup_add_timer(HWSetup *hw,
|
||||
const char *name, uint32_t base, uint32_t irq)
|
||||
{
|
||||
hwsetup_add_u32(hw, 56); /* size */
|
||||
hwsetup_add_tag(hw, HWSETUP_TAG_TIMER);
|
||||
hwsetup_add_str(hw, name);
|
||||
hwsetup_add_u32(hw, base);
|
||||
hwsetup_add_u8(hw, 1); /* wr_tickcount */
|
||||
hwsetup_add_u8(hw, 1); /* rd_tickcount */
|
||||
hwsetup_add_u8(hw, 1); /* start_stop_control */
|
||||
hwsetup_add_u8(hw, 32); /* counter_width */
|
||||
hwsetup_add_u32(hw, 20); /* reload_ticks */
|
||||
hwsetup_add_u8(hw, irq);
|
||||
hwsetup_add_u8(hw, 0); /* padding */
|
||||
hwsetup_add_u8(hw, 0); /* padding */
|
||||
hwsetup_add_u8(hw, 0); /* padding */
|
||||
}
|
||||
|
||||
static inline void hwsetup_add_uart(HWSetup *hw,
|
||||
const char *name, uint32_t base, uint32_t irq)
|
||||
{
|
||||
hwsetup_add_u32(hw, 56); /* size */
|
||||
hwsetup_add_tag(hw, HWSETUP_TAG_UART);
|
||||
hwsetup_add_str(hw, name);
|
||||
hwsetup_add_u32(hw, base);
|
||||
hwsetup_add_u32(hw, 115200); /* baudrate */
|
||||
hwsetup_add_u8(hw, 8); /* databits */
|
||||
hwsetup_add_u8(hw, 1); /* stopbits */
|
||||
hwsetup_add_u8(hw, 1); /* use_interrupt */
|
||||
hwsetup_add_u8(hw, 1); /* block_on_transmit */
|
||||
hwsetup_add_u8(hw, 1); /* block_on_receive */
|
||||
hwsetup_add_u8(hw, 4); /* rx_buffer_size */
|
||||
hwsetup_add_u8(hw, 4); /* tx_buffer_size */
|
||||
hwsetup_add_u8(hw, irq);
|
||||
}
|
||||
|
||||
#endif /* QEMU_HW_LM32_HWSETUP_H */
|
@ -1,6 +0,0 @@
|
||||
lm32_ss = ss.source_set()
|
||||
# LM32 boards
|
||||
lm32_ss.add(when: 'CONFIG_LM32_EVR', if_true: files('lm32_boards.c'))
|
||||
lm32_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist.c'))
|
||||
|
||||
hw_arch += {'lm32': lm32_ss}
|
@ -1,133 +0,0 @@
|
||||
#ifndef QEMU_HW_MILKYMIST_HW_H
|
||||
#define QEMU_HW_MILKYMIST_HW_H
|
||||
|
||||
#include "hw/qdev-core.h"
|
||||
#include "net/net.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
static inline DeviceState *milkymist_uart_create(hwaddr base,
|
||||
qemu_irq irq,
|
||||
Chardev *chr)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = qdev_new("milkymist-uart");
|
||||
qdev_prop_set_chr(dev, "chardev", chr);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static inline DeviceState *milkymist_hpdmc_create(hwaddr base)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = qdev_new("milkymist-hpdmc");
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static inline DeviceState *milkymist_vgafb_create(hwaddr base,
|
||||
uint32_t fb_offset, uint32_t fb_mask)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = qdev_new("milkymist-vgafb");
|
||||
qdev_prop_set_uint32(dev, "fb_offset", fb_offset);
|
||||
qdev_prop_set_uint32(dev, "fb_mask", fb_mask);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static inline DeviceState *milkymist_sysctl_create(hwaddr base,
|
||||
qemu_irq gpio_irq, qemu_irq timer0_irq, qemu_irq timer1_irq,
|
||||
uint32_t freq_hz, uint32_t system_id, uint32_t capabilities,
|
||||
uint32_t gpio_strappings)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = qdev_new("milkymist-sysctl");
|
||||
qdev_prop_set_uint32(dev, "frequency", freq_hz);
|
||||
qdev_prop_set_uint32(dev, "systemid", system_id);
|
||||
qdev_prop_set_uint32(dev, "capabilities", capabilities);
|
||||
qdev_prop_set_uint32(dev, "gpio_strappings", gpio_strappings);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, gpio_irq);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, timer0_irq);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, timer1_irq);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static inline DeviceState *milkymist_pfpu_create(hwaddr base,
|
||||
qemu_irq irq)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = qdev_new("milkymist-pfpu");
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
|
||||
return dev;
|
||||
}
|
||||
|
||||
static inline DeviceState *milkymist_ac97_create(hwaddr base,
|
||||
qemu_irq crrequest_irq, qemu_irq crreply_irq, qemu_irq dmar_irq,
|
||||
qemu_irq dmaw_irq)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = qdev_new("milkymist-ac97");
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, crrequest_irq);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, crreply_irq);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, dmar_irq);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 3, dmaw_irq);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static inline DeviceState *milkymist_minimac2_create(hwaddr base,
|
||||
hwaddr buffers_base, qemu_irq rx_irq, qemu_irq tx_irq)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
qemu_check_nic_model(&nd_table[0], "minimac2");
|
||||
dev = qdev_new("milkymist-minimac2");
|
||||
qdev_set_nic_properties(dev, &nd_table[0]);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, buffers_base);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, rx_irq);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, tx_irq);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static inline DeviceState *milkymist_softusb_create(hwaddr base,
|
||||
qemu_irq irq, uint32_t pmem_base, uint32_t pmem_size,
|
||||
uint32_t dmem_base, uint32_t dmem_size)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = qdev_new("milkymist-softusb");
|
||||
qdev_prop_set_uint32(dev, "pmem_size", pmem_size);
|
||||
qdev_prop_set_uint32(dev, "dmem_size", dmem_size);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, pmem_base);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, dmem_base);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
#endif /* QEMU_HW_MILKYMIST_HW_H */
|
@ -1,249 +0,0 @@
|
||||
/*
|
||||
* QEMU model for the Milkymist board.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/datadir.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "elf.h"
|
||||
#include "milkymist-hw.h"
|
||||
#include "hw/display/milkymist_tmu2.h"
|
||||
#include "hw/sd/sd.h"
|
||||
#include "lm32.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
||||
#define BIOS_FILENAME "mmone-bios.bin"
|
||||
#define BIOS_OFFSET 0x00860000
|
||||
#define BIOS_SIZE (512 * KiB)
|
||||
#define KERNEL_LOAD_ADDR 0x40000000
|
||||
|
||||
typedef struct {
|
||||
LM32CPU *cpu;
|
||||
hwaddr bootstrap_pc;
|
||||
hwaddr flash_base;
|
||||
hwaddr initrd_base;
|
||||
size_t initrd_size;
|
||||
hwaddr cmdline_base;
|
||||
} ResetInfo;
|
||||
|
||||
static void cpu_irq_handler(void *opaque, int irq, int level)
|
||||
{
|
||||
LM32CPU *cpu = opaque;
|
||||
CPUState *cs = CPU(cpu);
|
||||
|
||||
if (level) {
|
||||
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
|
||||
} else {
|
||||
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
}
|
||||
|
||||
static void main_cpu_reset(void *opaque)
|
||||
{
|
||||
ResetInfo *reset_info = opaque;
|
||||
CPULM32State *env = &reset_info->cpu->env;
|
||||
|
||||
cpu_reset(CPU(reset_info->cpu));
|
||||
|
||||
/* init defaults */
|
||||
env->pc = reset_info->bootstrap_pc;
|
||||
env->regs[R_R1] = reset_info->cmdline_base;
|
||||
env->regs[R_R2] = reset_info->initrd_base;
|
||||
env->regs[R_R3] = reset_info->initrd_base + reset_info->initrd_size;
|
||||
env->eba = reset_info->flash_base;
|
||||
env->deba = reset_info->flash_base;
|
||||
}
|
||||
|
||||
static DeviceState *milkymist_memcard_create(hwaddr base)
|
||||
{
|
||||
DeviceState *dev;
|
||||
DriveInfo *dinfo;
|
||||
|
||||
dev = qdev_new("milkymist-memcard");
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
||||
|
||||
dinfo = drive_get_next(IF_SD);
|
||||
if (dinfo) {
|
||||
DeviceState *card;
|
||||
|
||||
card = qdev_new(TYPE_SD_CARD);
|
||||
qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo),
|
||||
&error_fatal);
|
||||
qdev_realize_and_unref(card, qdev_get_child_bus(dev, "sd-bus"),
|
||||
&error_fatal);
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void
|
||||
milkymist_init(MachineState *machine)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
const char *bios_name = machine->firmware ?: BIOS_FILENAME;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
LM32CPU *cpu;
|
||||
CPULM32State *env;
|
||||
int kernel_size;
|
||||
DriveInfo *dinfo;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
qemu_irq irq[32];
|
||||
int i;
|
||||
char *bios_filename;
|
||||
ResetInfo *reset_info;
|
||||
|
||||
if (machine->ram_size != mc->default_ram_size) {
|
||||
char *sz = size_to_str(mc->default_ram_size);
|
||||
error_report("Invalid RAM size, should be %s", sz);
|
||||
g_free(sz);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* memory map */
|
||||
hwaddr flash_base = 0x00000000;
|
||||
size_t flash_sector_size = 128 * KiB;
|
||||
size_t flash_size = 32 * MiB;
|
||||
hwaddr sdram_base = 0x40000000;
|
||||
|
||||
hwaddr initrd_base = sdram_base + 0x1002000;
|
||||
hwaddr cmdline_base = sdram_base + 0x1000000;
|
||||
size_t initrd_max = machine->ram_size - 0x1002000;
|
||||
|
||||
reset_info = g_malloc0(sizeof(ResetInfo));
|
||||
|
||||
cpu = LM32_CPU(cpu_create(machine->cpu_type));
|
||||
|
||||
env = &cpu->env;
|
||||
reset_info->cpu = cpu;
|
||||
|
||||
cpu_lm32_set_phys_msb_ignore(env, 1);
|
||||
|
||||
memory_region_add_subregion(address_space_mem, sdram_base, machine->ram);
|
||||
|
||||
dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||
/* Numonyx JS28F256J3F105 */
|
||||
pflash_cfi01_register(flash_base, "milkymist.flash", flash_size,
|
||||
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
|
||||
flash_sector_size, 2, 0x00, 0x89, 0x00, 0x1d, 1);
|
||||
|
||||
/* create irq lines */
|
||||
env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, cpu, 0));
|
||||
for (i = 0; i < 32; i++) {
|
||||
irq[i] = qdev_get_gpio_in(env->pic_state, i);
|
||||
}
|
||||
|
||||
/* load bios rom */
|
||||
bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
|
||||
|
||||
if (bios_filename) {
|
||||
if (load_image_targphys(bios_filename, BIOS_OFFSET, BIOS_SIZE) < 0) {
|
||||
error_report("could not load bios '%s'", bios_filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
reset_info->bootstrap_pc = BIOS_OFFSET;
|
||||
|
||||
/* if no kernel is given no valid bios rom is a fatal error */
|
||||
if (!kernel_filename && !dinfo && !bios_filename && !qtest_enabled()) {
|
||||
error_report("could not load Milkymist One bios '%s'", bios_name);
|
||||
exit(1);
|
||||
}
|
||||
g_free(bios_filename);
|
||||
|
||||
milkymist_uart_create(0x60000000, irq[0], serial_hd(0));
|
||||
milkymist_sysctl_create(0x60001000, irq[1], irq[2], irq[3],
|
||||
80000000, 0x10014d31, 0x0000041f, 0x00000001);
|
||||
milkymist_hpdmc_create(0x60002000);
|
||||
milkymist_vgafb_create(0x60003000, 0x40000000, 0x0fffffff);
|
||||
milkymist_memcard_create(0x60004000);
|
||||
milkymist_ac97_create(0x60005000, irq[4], irq[5], irq[6], irq[7]);
|
||||
milkymist_pfpu_create(0x60006000, irq[8]);
|
||||
if (machine->enable_graphics) {
|
||||
milkymist_tmu2_create(0x60007000, irq[9]);
|
||||
}
|
||||
milkymist_minimac2_create(0x60008000, 0x30000000, irq[10], irq[11]);
|
||||
milkymist_softusb_create(0x6000f000, irq[15],
|
||||
0x20000000, 0x1000, 0x20020000, 0x2000);
|
||||
|
||||
/* make sure juart isn't the first chardev */
|
||||
env->juart_state = lm32_juart_init(serial_hd(1));
|
||||
|
||||
if (kernel_filename) {
|
||||
uint64_t entry;
|
||||
|
||||
/* Boots a kernel elf binary. */
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
|
||||
&entry, NULL, NULL, NULL,
|
||||
1, EM_LATTICEMICO32, 0, 0);
|
||||
reset_info->bootstrap_pc = entry;
|
||||
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_image_targphys(kernel_filename, sdram_base,
|
||||
machine->ram_size);
|
||||
reset_info->bootstrap_pc = sdram_base;
|
||||
}
|
||||
|
||||
if (kernel_size < 0) {
|
||||
error_report("could not load kernel '%s'", kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (kernel_cmdline && strlen(kernel_cmdline)) {
|
||||
pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE,
|
||||
kernel_cmdline);
|
||||
reset_info->cmdline_base = (uint32_t)cmdline_base;
|
||||
}
|
||||
|
||||
if (initrd_filename) {
|
||||
size_t initrd_size;
|
||||
initrd_size = load_image_targphys(initrd_filename, initrd_base,
|
||||
initrd_max);
|
||||
reset_info->initrd_base = (uint32_t)initrd_base;
|
||||
reset_info->initrd_size = (uint32_t)initrd_size;
|
||||
}
|
||||
|
||||
qemu_register_reset(main_cpu_reset, reset_info);
|
||||
}
|
||||
|
||||
static void milkymist_machine_init(MachineClass *mc)
|
||||
{
|
||||
mc->desc = "Milkymist One";
|
||||
mc->init = milkymist_init;
|
||||
mc->default_cpu_type = LM32_CPU_TYPE_NAME("lm32-full");
|
||||
mc->default_ram_size = 128 * MiB;
|
||||
mc->default_ram_id = "milkymist.sdram";
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("milkymist", milkymist_machine_init)
|
@ -47,11 +47,9 @@ subdir('avr')
|
||||
subdir('cris')
|
||||
subdir('hppa')
|
||||
subdir('i386')
|
||||
subdir('lm32')
|
||||
subdir('m68k')
|
||||
subdir('microblaze')
|
||||
subdir('mips')
|
||||
subdir('moxie')
|
||||
subdir('nios2')
|
||||
subdir('openrisc')
|
||||
subdir('ppc')
|
||||
@ -63,5 +61,4 @@ subdir('sh4')
|
||||
subdir('sparc')
|
||||
subdir('sparc64')
|
||||
subdir('tricore')
|
||||
subdir('unicore32')
|
||||
subdir('xtensa')
|
||||
|
@ -36,9 +36,6 @@ softmmu_ss.add(when: 'CONFIG_SIFIVE_E_PRCI', if_true: files('sifive_e_prci.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_SIFIVE_U_OTP', if_true: files('sifive_u_otp.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_SIFIVE_U_PRCI', if_true: files('sifive_u_prci.c'))
|
||||
|
||||
# PKUnity SoC devices
|
||||
softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_pm.c'))
|
||||
|
||||
subdir('macio')
|
||||
|
||||
softmmu_ss.add(when: 'CONFIG_IVSHMEM_DEVICE', if_true: files('ivshmem.c'))
|
||||
@ -63,7 +60,6 @@ softmmu_ss.add(when: 'CONFIG_IMX', if_true: files(
|
||||
'imx_ccm.c',
|
||||
'imx_rngc.c',
|
||||
))
|
||||
softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-hpdmc.c', 'milkymist-pfpu.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
|
||||
'npcm7xx_clk.c',
|
||||
|
@ -1,172 +0,0 @@
|
||||
/*
|
||||
* QEMU model of the Milkymist High Performance Dynamic Memory Controller.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Specification available at:
|
||||
* http://milkymist.walle.cc/socdoc/hpdmc.pdf
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
enum {
|
||||
R_SYSTEM = 0,
|
||||
R_BYPASS,
|
||||
R_TIMING,
|
||||
R_IODELAY,
|
||||
R_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
IODELAY_DQSDELAY_RDY = (1<<5),
|
||||
IODELAY_PLL1_LOCKED = (1<<6),
|
||||
IODELAY_PLL2_LOCKED = (1<<7),
|
||||
};
|
||||
|
||||
#define TYPE_MILKYMIST_HPDMC "milkymist-hpdmc"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(MilkymistHpdmcState, MILKYMIST_HPDMC)
|
||||
|
||||
struct MilkymistHpdmcState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion regs_region;
|
||||
|
||||
uint32_t regs[R_MAX];
|
||||
};
|
||||
|
||||
static uint64_t hpdmc_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistHpdmcState *s = opaque;
|
||||
uint32_t r = 0;
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_SYSTEM:
|
||||
case R_BYPASS:
|
||||
case R_TIMING:
|
||||
case R_IODELAY:
|
||||
r = s->regs[addr];
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("milkymist_hpdmc: read access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_milkymist_hpdmc_memory_read(addr << 2, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void hpdmc_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistHpdmcState *s = opaque;
|
||||
|
||||
trace_milkymist_hpdmc_memory_write(addr, value);
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_SYSTEM:
|
||||
case R_BYPASS:
|
||||
case R_TIMING:
|
||||
s->regs[addr] = value;
|
||||
break;
|
||||
case R_IODELAY:
|
||||
/* ignore writes */
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("milkymist_hpdmc: write access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps hpdmc_mmio_ops = {
|
||||
.read = hpdmc_read,
|
||||
.write = hpdmc_write,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void milkymist_hpdmc_reset(DeviceState *d)
|
||||
{
|
||||
MilkymistHpdmcState *s = MILKYMIST_HPDMC(d);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < R_MAX; i++) {
|
||||
s->regs[i] = 0;
|
||||
}
|
||||
|
||||
/* defaults */
|
||||
s->regs[R_IODELAY] = IODELAY_DQSDELAY_RDY | IODELAY_PLL1_LOCKED
|
||||
| IODELAY_PLL2_LOCKED;
|
||||
}
|
||||
|
||||
static void milkymist_hpdmc_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MilkymistHpdmcState *s = MILKYMIST_HPDMC(dev);
|
||||
|
||||
memory_region_init_io(&s->regs_region, OBJECT(dev), &hpdmc_mmio_ops, s,
|
||||
"milkymist-hpdmc", R_MAX * 4);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->regs_region);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_milkymist_hpdmc = {
|
||||
.name = "milkymist-hpdmc",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, MilkymistHpdmcState, R_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void milkymist_hpdmc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = milkymist_hpdmc_realize;
|
||||
dc->reset = milkymist_hpdmc_reset;
|
||||
dc->vmsd = &vmstate_milkymist_hpdmc;
|
||||
}
|
||||
|
||||
static const TypeInfo milkymist_hpdmc_info = {
|
||||
.name = TYPE_MILKYMIST_HPDMC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MilkymistHpdmcState),
|
||||
.class_init = milkymist_hpdmc_class_init,
|
||||
};
|
||||
|
||||
static void milkymist_hpdmc_register_types(void)
|
||||
{
|
||||
type_register_static(&milkymist_hpdmc_info);
|
||||
}
|
||||
|
||||
type_init(milkymist_hpdmc_register_types)
|
@ -1,548 +0,0 @@
|
||||
/*
|
||||
* QEMU model of the Milkymist programmable FPU.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Specification available at:
|
||||
* http://milkymist.walle.cc/socdoc/pfpu.pdf
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include <math.h>
|
||||
#include "qom/object.h"
|
||||
|
||||
/* #define TRACE_EXEC */
|
||||
|
||||
#ifdef TRACE_EXEC
|
||||
# define D_EXEC(x) x
|
||||
#else
|
||||
# define D_EXEC(x)
|
||||
#endif
|
||||
|
||||
enum {
|
||||
R_CTL = 0,
|
||||
R_MESHBASE,
|
||||
R_HMESHLAST,
|
||||
R_VMESHLAST,
|
||||
R_CODEPAGE,
|
||||
R_VERTICES,
|
||||
R_COLLISIONS,
|
||||
R_STRAYWRITES,
|
||||
R_LASTDMA,
|
||||
R_PC,
|
||||
R_DREGBASE,
|
||||
R_CODEBASE,
|
||||
R_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
CTL_START_BUSY = (1<<0),
|
||||
};
|
||||
|
||||
enum {
|
||||
OP_NOP = 0,
|
||||
OP_FADD,
|
||||
OP_FSUB,
|
||||
OP_FMUL,
|
||||
OP_FABS,
|
||||
OP_F2I,
|
||||
OP_I2F,
|
||||
OP_VECTOUT,
|
||||
OP_SIN,
|
||||
OP_COS,
|
||||
OP_ABOVE,
|
||||
OP_EQUAL,
|
||||
OP_COPY,
|
||||
OP_IF,
|
||||
OP_TSIGN,
|
||||
OP_QUAKE,
|
||||
};
|
||||
|
||||
enum {
|
||||
GPR_X = 0,
|
||||
GPR_Y = 1,
|
||||
GPR_FLAGS = 2,
|
||||
};
|
||||
|
||||
enum {
|
||||
LATENCY_FADD = 5,
|
||||
LATENCY_FSUB = 5,
|
||||
LATENCY_FMUL = 7,
|
||||
LATENCY_FABS = 2,
|
||||
LATENCY_F2I = 2,
|
||||
LATENCY_I2F = 3,
|
||||
LATENCY_VECTOUT = 0,
|
||||
LATENCY_SIN = 4,
|
||||
LATENCY_COS = 4,
|
||||
LATENCY_ABOVE = 2,
|
||||
LATENCY_EQUAL = 2,
|
||||
LATENCY_COPY = 2,
|
||||
LATENCY_IF = 2,
|
||||
LATENCY_TSIGN = 2,
|
||||
LATENCY_QUAKE = 2,
|
||||
MAX_LATENCY = 7
|
||||
};
|
||||
|
||||
#define GPR_BEGIN 0x100
|
||||
#define GPR_END 0x17f
|
||||
#define MICROCODE_BEGIN 0x200
|
||||
#define MICROCODE_END 0x3ff
|
||||
#define MICROCODE_WORDS 2048
|
||||
|
||||
#define REINTERPRET_CAST(type, val) (*((type *)&(val)))
|
||||
|
||||
#ifdef TRACE_EXEC
|
||||
static const char *opcode_to_str[] = {
|
||||
"NOP", "FADD", "FSUB", "FMUL", "FABS", "F2I", "I2F", "VECTOUT",
|
||||
"SIN", "COS", "ABOVE", "EQUAL", "COPY", "IF", "TSIGN", "QUAKE",
|
||||
};
|
||||
#endif
|
||||
|
||||
#define TYPE_MILKYMIST_PFPU "milkymist-pfpu"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(MilkymistPFPUState, MILKYMIST_PFPU)
|
||||
|
||||
struct MilkymistPFPUState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion regs_region;
|
||||
Chardev *chr;
|
||||
qemu_irq irq;
|
||||
|
||||
uint32_t regs[R_MAX];
|
||||
uint32_t gp_regs[128];
|
||||
uint32_t microcode[MICROCODE_WORDS];
|
||||
|
||||
int output_queue_pos;
|
||||
uint32_t output_queue[MAX_LATENCY];
|
||||
};
|
||||
|
||||
static inline uint32_t
|
||||
get_dma_address(uint32_t base, uint32_t x, uint32_t y)
|
||||
{
|
||||
return base + 8 * (128 * y + x);
|
||||
}
|
||||
|
||||
static inline void
|
||||
output_queue_insert(MilkymistPFPUState *s, uint32_t val, int pos)
|
||||
{
|
||||
s->output_queue[(s->output_queue_pos + pos) % MAX_LATENCY] = val;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
output_queue_remove(MilkymistPFPUState *s)
|
||||
{
|
||||
return s->output_queue[s->output_queue_pos];
|
||||
}
|
||||
|
||||
static inline void
|
||||
output_queue_advance(MilkymistPFPUState *s)
|
||||
{
|
||||
s->output_queue[s->output_queue_pos] = 0;
|
||||
s->output_queue_pos = (s->output_queue_pos + 1) % MAX_LATENCY;
|
||||
}
|
||||
|
||||
static int pfpu_decode_insn(MilkymistPFPUState *s)
|
||||
{
|
||||
uint32_t pc = s->regs[R_PC];
|
||||
uint32_t insn = s->microcode[pc];
|
||||
uint32_t reg_a = (insn >> 18) & 0x7f;
|
||||
uint32_t reg_b = (insn >> 11) & 0x7f;
|
||||
uint32_t op = (insn >> 7) & 0xf;
|
||||
uint32_t reg_d = insn & 0x7f;
|
||||
uint32_t r = 0;
|
||||
int latency = 0;
|
||||
|
||||
switch (op) {
|
||||
case OP_NOP:
|
||||
break;
|
||||
case OP_FADD:
|
||||
{
|
||||
float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
|
||||
float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
|
||||
float t = a + b;
|
||||
r = REINTERPRET_CAST(uint32_t, t);
|
||||
latency = LATENCY_FADD;
|
||||
D_EXEC(qemu_log("ADD a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
|
||||
} break;
|
||||
case OP_FSUB:
|
||||
{
|
||||
float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
|
||||
float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
|
||||
float t = a - b;
|
||||
r = REINTERPRET_CAST(uint32_t, t);
|
||||
latency = LATENCY_FSUB;
|
||||
D_EXEC(qemu_log("SUB a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
|
||||
} break;
|
||||
case OP_FMUL:
|
||||
{
|
||||
float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
|
||||
float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
|
||||
float t = a * b;
|
||||
r = REINTERPRET_CAST(uint32_t, t);
|
||||
latency = LATENCY_FMUL;
|
||||
D_EXEC(qemu_log("MUL a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
|
||||
} break;
|
||||
case OP_FABS:
|
||||
{
|
||||
float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
|
||||
float t = fabsf(a);
|
||||
r = REINTERPRET_CAST(uint32_t, t);
|
||||
latency = LATENCY_FABS;
|
||||
D_EXEC(qemu_log("ABS a=%f t=%f, r=%08x\n", a, t, r));
|
||||
} break;
|
||||
case OP_F2I:
|
||||
{
|
||||
float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
|
||||
int32_t t = a;
|
||||
r = REINTERPRET_CAST(uint32_t, t);
|
||||
latency = LATENCY_F2I;
|
||||
D_EXEC(qemu_log("F2I a=%f t=%d, r=%08x\n", a, t, r));
|
||||
} break;
|
||||
case OP_I2F:
|
||||
{
|
||||
int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
|
||||
float t = a;
|
||||
r = REINTERPRET_CAST(uint32_t, t);
|
||||
latency = LATENCY_I2F;
|
||||
D_EXEC(qemu_log("I2F a=%08x t=%f, r=%08x\n", a, t, r));
|
||||
} break;
|
||||
case OP_VECTOUT:
|
||||
{
|
||||
uint32_t a = cpu_to_be32(s->gp_regs[reg_a]);
|
||||
uint32_t b = cpu_to_be32(s->gp_regs[reg_b]);
|
||||
hwaddr dma_ptr =
|
||||
get_dma_address(s->regs[R_MESHBASE],
|
||||
s->gp_regs[GPR_X], s->gp_regs[GPR_Y]);
|
||||
cpu_physical_memory_write(dma_ptr, &a, 4);
|
||||
cpu_physical_memory_write(dma_ptr + 4, &b, 4);
|
||||
s->regs[R_LASTDMA] = dma_ptr + 4;
|
||||
D_EXEC(qemu_log("VECTOUT a=%08x b=%08x dma=%08x\n", a, b, dma_ptr));
|
||||
trace_milkymist_pfpu_vectout(a, b, dma_ptr);
|
||||
} break;
|
||||
case OP_SIN:
|
||||
{
|
||||
int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
|
||||
float t = sinf(a * (1.0f / (M_PI * 4096.0f)));
|
||||
r = REINTERPRET_CAST(uint32_t, t);
|
||||
latency = LATENCY_SIN;
|
||||
D_EXEC(qemu_log("SIN a=%d t=%f, r=%08x\n", a, t, r));
|
||||
} break;
|
||||
case OP_COS:
|
||||
{
|
||||
int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
|
||||
float t = cosf(a * (1.0f / (M_PI * 4096.0f)));
|
||||
r = REINTERPRET_CAST(uint32_t, t);
|
||||
latency = LATENCY_COS;
|
||||
D_EXEC(qemu_log("COS a=%d t=%f, r=%08x\n", a, t, r));
|
||||
} break;
|
||||
case OP_ABOVE:
|
||||
{
|
||||
float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
|
||||
float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
|
||||
float t = (a > b) ? 1.0f : 0.0f;
|
||||
r = REINTERPRET_CAST(uint32_t, t);
|
||||
latency = LATENCY_ABOVE;
|
||||
D_EXEC(qemu_log("ABOVE a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
|
||||
} break;
|
||||
case OP_EQUAL:
|
||||
{
|
||||
float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
|
||||
float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
|
||||
float t = (a == b) ? 1.0f : 0.0f;
|
||||
r = REINTERPRET_CAST(uint32_t, t);
|
||||
latency = LATENCY_EQUAL;
|
||||
D_EXEC(qemu_log("EQUAL a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
|
||||
} break;
|
||||
case OP_COPY:
|
||||
{
|
||||
r = s->gp_regs[reg_a];
|
||||
latency = LATENCY_COPY;
|
||||
D_EXEC(qemu_log("COPY"));
|
||||
} break;
|
||||
case OP_IF:
|
||||
{
|
||||
float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
|
||||
float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
|
||||
uint32_t f = s->gp_regs[GPR_FLAGS];
|
||||
float t = (f != 0) ? a : b;
|
||||
r = REINTERPRET_CAST(uint32_t, t);
|
||||
latency = LATENCY_IF;
|
||||
D_EXEC(qemu_log("IF f=%u a=%f b=%f t=%f, r=%08x\n", f, a, b, t, r));
|
||||
} break;
|
||||
case OP_TSIGN:
|
||||
{
|
||||
float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
|
||||
float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
|
||||
float t = (b < 0) ? -a : a;
|
||||
r = REINTERPRET_CAST(uint32_t, t);
|
||||
latency = LATENCY_TSIGN;
|
||||
D_EXEC(qemu_log("TSIGN a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
|
||||
} break;
|
||||
case OP_QUAKE:
|
||||
{
|
||||
uint32_t a = s->gp_regs[reg_a];
|
||||
r = 0x5f3759df - (a >> 1);
|
||||
latency = LATENCY_QUAKE;
|
||||
D_EXEC(qemu_log("QUAKE a=%d r=%08x\n", a, r));
|
||||
} break;
|
||||
|
||||
default:
|
||||
error_report("milkymist_pfpu: unknown opcode %d", op);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!reg_d) {
|
||||
D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d>\n",
|
||||
s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency,
|
||||
s->regs[R_PC] + latency));
|
||||
} else {
|
||||
D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d> -> R%03d\n",
|
||||
s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency,
|
||||
s->regs[R_PC] + latency, reg_d));
|
||||
}
|
||||
|
||||
if (op == OP_VECTOUT) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* store output for this cycle */
|
||||
if (reg_d) {
|
||||
uint32_t val = output_queue_remove(s);
|
||||
D_EXEC(qemu_log("R%03d <- 0x%08x\n", reg_d, val));
|
||||
s->gp_regs[reg_d] = val;
|
||||
}
|
||||
|
||||
output_queue_advance(s);
|
||||
|
||||
/* store op output */
|
||||
if (op != OP_NOP) {
|
||||
output_queue_insert(s, r, latency-1);
|
||||
}
|
||||
|
||||
/* advance PC */
|
||||
s->regs[R_PC]++;
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
static void pfpu_start(MilkymistPFPUState *s)
|
||||
{
|
||||
int x, y;
|
||||
int i;
|
||||
|
||||
for (y = 0; y <= s->regs[R_VMESHLAST]; y++) {
|
||||
for (x = 0; x <= s->regs[R_HMESHLAST]; x++) {
|
||||
D_EXEC(qemu_log("\nprocessing x=%d y=%d\n", x, y));
|
||||
|
||||
/* set current position */
|
||||
s->gp_regs[GPR_X] = x;
|
||||
s->gp_regs[GPR_Y] = y;
|
||||
|
||||
/* run microcode on this position */
|
||||
i = 0;
|
||||
while (pfpu_decode_insn(s)) {
|
||||
/* decode at most MICROCODE_WORDS instructions */
|
||||
if (++i >= MICROCODE_WORDS) {
|
||||
error_report("milkymist_pfpu: too many instructions "
|
||||
"executed in microcode. No VECTOUT?");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* reset pc for next run */
|
||||
s->regs[R_PC] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
s->regs[R_VERTICES] = x * y;
|
||||
|
||||
trace_milkymist_pfpu_pulse_irq();
|
||||
qemu_irq_pulse(s->irq);
|
||||
}
|
||||
|
||||
static inline int get_microcode_address(MilkymistPFPUState *s, uint32_t addr)
|
||||
{
|
||||
return (512 * s->regs[R_CODEPAGE]) + addr - MICROCODE_BEGIN;
|
||||
}
|
||||
|
||||
static uint64_t pfpu_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistPFPUState *s = opaque;
|
||||
uint32_t r = 0;
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_CTL:
|
||||
case R_MESHBASE:
|
||||
case R_HMESHLAST:
|
||||
case R_VMESHLAST:
|
||||
case R_CODEPAGE:
|
||||
case R_VERTICES:
|
||||
case R_COLLISIONS:
|
||||
case R_STRAYWRITES:
|
||||
case R_LASTDMA:
|
||||
case R_PC:
|
||||
case R_DREGBASE:
|
||||
case R_CODEBASE:
|
||||
r = s->regs[addr];
|
||||
break;
|
||||
case GPR_BEGIN ... GPR_END:
|
||||
r = s->gp_regs[addr - GPR_BEGIN];
|
||||
break;
|
||||
case MICROCODE_BEGIN ... MICROCODE_END:
|
||||
r = s->microcode[get_microcode_address(s, addr)];
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("milkymist_pfpu: read access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_milkymist_pfpu_memory_read(addr << 2, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void pfpu_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistPFPUState *s = opaque;
|
||||
|
||||
trace_milkymist_pfpu_memory_write(addr, value);
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_CTL:
|
||||
if (value & CTL_START_BUSY) {
|
||||
pfpu_start(s);
|
||||
}
|
||||
break;
|
||||
case R_MESHBASE:
|
||||
case R_HMESHLAST:
|
||||
case R_VMESHLAST:
|
||||
case R_CODEPAGE:
|
||||
case R_VERTICES:
|
||||
case R_COLLISIONS:
|
||||
case R_STRAYWRITES:
|
||||
case R_LASTDMA:
|
||||
case R_PC:
|
||||
case R_DREGBASE:
|
||||
case R_CODEBASE:
|
||||
s->regs[addr] = value;
|
||||
break;
|
||||
case GPR_BEGIN ... GPR_END:
|
||||
s->gp_regs[addr - GPR_BEGIN] = value;
|
||||
break;
|
||||
case MICROCODE_BEGIN ... MICROCODE_END:
|
||||
s->microcode[get_microcode_address(s, addr)] = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("milkymist_pfpu: write access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps pfpu_mmio_ops = {
|
||||
.read = pfpu_read,
|
||||
.write = pfpu_write,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void milkymist_pfpu_reset(DeviceState *d)
|
||||
{
|
||||
MilkymistPFPUState *s = MILKYMIST_PFPU(d);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < R_MAX; i++) {
|
||||
s->regs[i] = 0;
|
||||
}
|
||||
for (i = 0; i < 128; i++) {
|
||||
s->gp_regs[i] = 0;
|
||||
}
|
||||
for (i = 0; i < MICROCODE_WORDS; i++) {
|
||||
s->microcode[i] = 0;
|
||||
}
|
||||
s->output_queue_pos = 0;
|
||||
for (i = 0; i < MAX_LATENCY; i++) {
|
||||
s->output_queue[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void milkymist_pfpu_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MilkymistPFPUState *s = MILKYMIST_PFPU(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
||||
memory_region_init_io(&s->regs_region, OBJECT(dev), &pfpu_mmio_ops, s,
|
||||
"milkymist-pfpu", MICROCODE_END * 4);
|
||||
sysbus_init_mmio(sbd, &s->regs_region);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_milkymist_pfpu = {
|
||||
.name = "milkymist-pfpu",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, MilkymistPFPUState, R_MAX),
|
||||
VMSTATE_UINT32_ARRAY(gp_regs, MilkymistPFPUState, 128),
|
||||
VMSTATE_UINT32_ARRAY(microcode, MilkymistPFPUState, MICROCODE_WORDS),
|
||||
VMSTATE_INT32(output_queue_pos, MilkymistPFPUState),
|
||||
VMSTATE_UINT32_ARRAY(output_queue, MilkymistPFPUState, MAX_LATENCY),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void milkymist_pfpu_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = milkymist_pfpu_realize;
|
||||
dc->reset = milkymist_pfpu_reset;
|
||||
dc->vmsd = &vmstate_milkymist_pfpu;
|
||||
}
|
||||
|
||||
static const TypeInfo milkymist_pfpu_info = {
|
||||
.name = TYPE_MILKYMIST_PFPU,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MilkymistPFPUState),
|
||||
.class_init = milkymist_pfpu_class_init,
|
||||
};
|
||||
|
||||
static void milkymist_pfpu_register_types(void)
|
||||
{
|
||||
type_register_static(&milkymist_pfpu_info);
|
||||
}
|
||||
|
||||
type_init(milkymist_pfpu_register_types)
|
@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Power Management device simulation in PKUnity SoC
|
||||
*
|
||||
* Copyright (C) 2010-2012 Guan Xuetao
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation, or any later version.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#undef DEBUG_PUV3
|
||||
#include "hw/unicore32/puv3.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/log.h"
|
||||
|
||||
#define TYPE_PUV3_PM "puv3_pm"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(PUV3PMState, PUV3_PM)
|
||||
|
||||
struct PUV3PMState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
|
||||
uint32_t reg_PMCR;
|
||||
uint32_t reg_PCGR;
|
||||
uint32_t reg_PLL_SYS_CFG;
|
||||
uint32_t reg_PLL_DDR_CFG;
|
||||
uint32_t reg_PLL_VGA_CFG;
|
||||
uint32_t reg_DIVCFG;
|
||||
};
|
||||
|
||||
static uint64_t puv3_pm_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
PUV3PMState *s = opaque;
|
||||
uint32_t ret = 0;
|
||||
|
||||
switch (offset) {
|
||||
case 0x14:
|
||||
ret = s->reg_PCGR;
|
||||
break;
|
||||
case 0x18:
|
||||
ret = s->reg_PLL_SYS_CFG;
|
||||
break;
|
||||
case 0x1c:
|
||||
ret = s->reg_PLL_DDR_CFG;
|
||||
break;
|
||||
case 0x20:
|
||||
ret = s->reg_PLL_VGA_CFG;
|
||||
break;
|
||||
case 0x24:
|
||||
ret = s->reg_DIVCFG;
|
||||
break;
|
||||
case 0x28: /* PLL SYS STATUS */
|
||||
ret = 0x00002401;
|
||||
break;
|
||||
case 0x2c: /* PLL DDR STATUS */
|
||||
ret = 0x00100c00;
|
||||
break;
|
||||
case 0x30: /* PLL VGA STATUS */
|
||||
ret = 0x00003801;
|
||||
break;
|
||||
case 0x34: /* DIV STATUS */
|
||||
ret = 0x22f52015;
|
||||
break;
|
||||
case 0x38: /* SW RESET */
|
||||
ret = 0x0;
|
||||
break;
|
||||
case 0x44: /* PLL DFC DONE */
|
||||
ret = 0x7;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad read offset 0x%"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
}
|
||||
DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void puv3_pm_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
PUV3PMState *s = opaque;
|
||||
|
||||
switch (offset) {
|
||||
case 0x0:
|
||||
s->reg_PMCR = value;
|
||||
break;
|
||||
case 0x14:
|
||||
s->reg_PCGR = value;
|
||||
break;
|
||||
case 0x18:
|
||||
s->reg_PLL_SYS_CFG = value;
|
||||
break;
|
||||
case 0x1c:
|
||||
s->reg_PLL_DDR_CFG = value;
|
||||
break;
|
||||
case 0x20:
|
||||
s->reg_PLL_VGA_CFG = value;
|
||||
break;
|
||||
case 0x24:
|
||||
case 0x38:
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad write offset 0x%"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
}
|
||||
DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps puv3_pm_ops = {
|
||||
.read = puv3_pm_read,
|
||||
.write = puv3_pm_write,
|
||||
.impl = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void puv3_pm_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PUV3PMState *s = PUV3_PM(dev);
|
||||
|
||||
s->reg_PCGR = 0x0;
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &puv3_pm_ops, s, "puv3_pm",
|
||||
PUV3_REGS_OFFSET);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
|
||||
}
|
||||
|
||||
static void puv3_pm_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = puv3_pm_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo puv3_pm_info = {
|
||||
.name = TYPE_PUV3_PM,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PUV3PMState),
|
||||
.class_init = puv3_pm_class_init,
|
||||
};
|
||||
|
||||
static void puv3_pm_register_type(void)
|
||||
{
|
||||
type_register_static(&puv3_pm_info);
|
||||
}
|
||||
|
||||
type_init(puv3_pm_register_type)
|
@ -67,16 +67,6 @@ slavio_sysctrl_mem_readl(uint32_t ret) "Read system control 0x%08x"
|
||||
slavio_led_mem_writew(uint32_t val) "Write diagnostic LED 0x%04x"
|
||||
slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED 0x%04x"
|
||||
|
||||
# milkymist-hpdmc.c
|
||||
milkymist_hpdmc_memory_read(uint32_t addr, uint32_t value) "addr=0x%08x value=0x%08x"
|
||||
milkymist_hpdmc_memory_write(uint32_t addr, uint32_t value) "addr=0x%08x value=0x%08x"
|
||||
|
||||
# milkymist-pfpu.c
|
||||
milkymist_pfpu_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
milkymist_pfpu_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
milkymist_pfpu_vectout(uint32_t a, uint32_t b, uint32_t dma_ptr) "a 0x%08x b 0x%08x dma_ptr 0x%08x"
|
||||
milkymist_pfpu_pulse_irq(void) "Pulse IRQ"
|
||||
|
||||
# aspeed_scu.c
|
||||
aspeed_scu_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
|
||||
|
||||
|
@ -1,3 +0,0 @@
|
||||
config MOXIESIM
|
||||
bool
|
||||
select SERIAL
|
@ -1,4 +0,0 @@
|
||||
moxie_ss = ss.source_set()
|
||||
moxie_ss.add(when: 'CONFIG_MOXIESIM', if_true: files('moxiesim.c'))
|
||||
|
||||
hw_arch += {'moxie': moxie_ss}
|
@ -1,155 +0,0 @@
|
||||
/*
|
||||
* QEMU/moxiesim emulation
|
||||
*
|
||||
* Emulates a very simple machine model similar to the one used by the
|
||||
* GDB moxie simulator.
|
||||
*
|
||||
* Copyright (c) 2008, 2009, 2010, 2013 Anthony Green
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "cpu.h"
|
||||
#include "net/net.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "elf.h"
|
||||
|
||||
#define PHYS_MEM_BASE 0x80000000
|
||||
#define FIRMWARE_BASE 0x1000
|
||||
#define FIRMWARE_SIZE (128 * 0x1000)
|
||||
|
||||
typedef struct {
|
||||
uint64_t ram_size;
|
||||
const char *kernel_filename;
|
||||
const char *kernel_cmdline;
|
||||
const char *initrd_filename;
|
||||
} LoaderParams;
|
||||
|
||||
static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params)
|
||||
{
|
||||
uint64_t entry, kernel_high;
|
||||
int64_t initrd_size;
|
||||
long kernel_size;
|
||||
ram_addr_t initrd_offset;
|
||||
|
||||
kernel_size = load_elf(loader_params->kernel_filename, NULL, NULL, NULL,
|
||||
&entry, NULL, &kernel_high, NULL, 1, EM_MOXIE,
|
||||
0, 0);
|
||||
|
||||
if (kernel_size <= 0) {
|
||||
error_report("could not load kernel '%s'",
|
||||
loader_params->kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* load initrd */
|
||||
initrd_size = 0;
|
||||
initrd_offset = 0;
|
||||
if (loader_params->initrd_filename) {
|
||||
initrd_size = get_image_size(loader_params->initrd_filename);
|
||||
if (initrd_size > 0) {
|
||||
initrd_offset = (kernel_high + ~TARGET_PAGE_MASK)
|
||||
& TARGET_PAGE_MASK;
|
||||
if (initrd_offset + initrd_size > loader_params->ram_size) {
|
||||
error_report("memory too small for initial ram disk '%s'",
|
||||
loader_params->initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
initrd_size = load_image_targphys(loader_params->initrd_filename,
|
||||
initrd_offset,
|
||||
loader_params->ram_size);
|
||||
}
|
||||
if (initrd_size == (target_ulong)-1) {
|
||||
error_report("could not load initial ram disk '%s'",
|
||||
loader_params->initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void main_cpu_reset(void *opaque)
|
||||
{
|
||||
MoxieCPU *cpu = opaque;
|
||||
|
||||
cpu_reset(CPU(cpu));
|
||||
}
|
||||
|
||||
static void moxiesim_init(MachineState *machine)
|
||||
{
|
||||
MoxieCPU *cpu = NULL;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
CPUMoxieState *env;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *rom = g_new(MemoryRegion, 1);
|
||||
hwaddr ram_base = 0x200000;
|
||||
LoaderParams loader_params;
|
||||
|
||||
/* Init CPUs. */
|
||||
cpu = MOXIE_CPU(cpu_create(machine->cpu_type));
|
||||
env = &cpu->env;
|
||||
|
||||
qemu_register_reset(main_cpu_reset, cpu);
|
||||
|
||||
/* Allocate RAM. */
|
||||
memory_region_init_ram(ram, NULL, "moxiesim.ram", ram_size, &error_fatal);
|
||||
memory_region_add_subregion(address_space_mem, ram_base, ram);
|
||||
|
||||
memory_region_init_ram(rom, NULL, "moxie.rom", FIRMWARE_SIZE, &error_fatal);
|
||||
memory_region_add_subregion(get_system_memory(), FIRMWARE_BASE, rom);
|
||||
|
||||
if (kernel_filename) {
|
||||
loader_params.ram_size = ram_size;
|
||||
loader_params.kernel_filename = kernel_filename;
|
||||
loader_params.kernel_cmdline = kernel_cmdline;
|
||||
loader_params.initrd_filename = initrd_filename;
|
||||
load_kernel(cpu, &loader_params);
|
||||
}
|
||||
if (machine->firmware) {
|
||||
if (load_image_targphys(machine->firmware, FIRMWARE_BASE, FIRMWARE_SIZE) < 0) {
|
||||
error_report("Failed to load firmware '%s'", machine->firmware);
|
||||
}
|
||||
}
|
||||
|
||||
/* A single 16450 sits at offset 0x3f8. */
|
||||
if (serial_hd(0)) {
|
||||
serial_mm_init(address_space_mem, 0x3f8, 0, env->irq[4],
|
||||
8000000/16, serial_hd(0), DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
}
|
||||
|
||||
static void moxiesim_machine_init(MachineClass *mc)
|
||||
{
|
||||
mc->desc = "Moxie simulator platform";
|
||||
mc->init = moxiesim_init;
|
||||
mc->is_default = true;
|
||||
mc->default_cpu_type = MOXIE_CPU_TYPE_NAME("MoxieLite");
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("moxiesim", moxiesim_machine_init)
|
@ -39,7 +39,6 @@ softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_emc.c'))
|
||||
|
||||
softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_eth.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_fec.c'))
|
||||
specific_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-minimac2.c'))
|
||||
specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_llan.c'))
|
||||
specific_ss.add(when: 'CONFIG_XILINX_ETHLITE', if_true: files('xilinx_ethlite.c'))
|
||||
|
||||
|
@ -1,547 +0,0 @@
|
||||
/*
|
||||
* QEMU model of the Milkymist minimac2 block.
|
||||
*
|
||||
* Copyright (c) 2011 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Specification available at:
|
||||
* not available yet
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qom/object.h"
|
||||
#include "cpu.h" /* FIXME: why does this use TARGET_PAGE_ALIGN? */
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
#include "net/net.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
enum {
|
||||
R_SETUP = 0,
|
||||
R_MDIO,
|
||||
R_STATE0,
|
||||
R_COUNT0,
|
||||
R_STATE1,
|
||||
R_COUNT1,
|
||||
R_TXCOUNT,
|
||||
R_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
SETUP_PHY_RST = (1<<0),
|
||||
};
|
||||
|
||||
enum {
|
||||
MDIO_DO = (1<<0),
|
||||
MDIO_DI = (1<<1),
|
||||
MDIO_OE = (1<<2),
|
||||
MDIO_CLK = (1<<3),
|
||||
};
|
||||
|
||||
enum {
|
||||
STATE_EMPTY = 0,
|
||||
STATE_LOADED = 1,
|
||||
STATE_PENDING = 2,
|
||||
};
|
||||
|
||||
enum {
|
||||
MDIO_OP_WRITE = 1,
|
||||
MDIO_OP_READ = 2,
|
||||
};
|
||||
|
||||
enum mdio_state {
|
||||
MDIO_STATE_IDLE,
|
||||
MDIO_STATE_READING,
|
||||
MDIO_STATE_WRITING,
|
||||
};
|
||||
|
||||
enum {
|
||||
R_PHY_ID1 = 2,
|
||||
R_PHY_ID2 = 3,
|
||||
R_PHY_MAX = 32
|
||||
};
|
||||
|
||||
#define MINIMAC2_MTU 1530
|
||||
#define MINIMAC2_BUFFER_SIZE 2048
|
||||
|
||||
struct MilkymistMinimac2MdioState {
|
||||
int last_clk;
|
||||
int count;
|
||||
uint32_t data;
|
||||
uint16_t data_out;
|
||||
int state;
|
||||
|
||||
uint8_t phy_addr;
|
||||
uint8_t reg_addr;
|
||||
};
|
||||
typedef struct MilkymistMinimac2MdioState MilkymistMinimac2MdioState;
|
||||
|
||||
#define TYPE_MILKYMIST_MINIMAC2 "milkymist-minimac2"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(MilkymistMinimac2State, MILKYMIST_MINIMAC2)
|
||||
|
||||
struct MilkymistMinimac2State {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
NICState *nic;
|
||||
NICConf conf;
|
||||
char *phy_model;
|
||||
MemoryRegion buffers;
|
||||
MemoryRegion regs_region;
|
||||
|
||||
qemu_irq rx_irq;
|
||||
qemu_irq tx_irq;
|
||||
|
||||
uint32_t regs[R_MAX];
|
||||
|
||||
MilkymistMinimac2MdioState mdio;
|
||||
|
||||
uint16_t phy_regs[R_PHY_MAX];
|
||||
|
||||
uint8_t *rx0_buf;
|
||||
uint8_t *rx1_buf;
|
||||
uint8_t *tx_buf;
|
||||
};
|
||||
|
||||
static const uint8_t preamble_sfd[] = {
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5
|
||||
};
|
||||
|
||||
static void minimac2_mdio_write_reg(MilkymistMinimac2State *s,
|
||||
uint8_t phy_addr, uint8_t reg_addr, uint16_t value)
|
||||
{
|
||||
trace_milkymist_minimac2_mdio_write(phy_addr, reg_addr, value);
|
||||
|
||||
/* nop */
|
||||
}
|
||||
|
||||
static uint16_t minimac2_mdio_read_reg(MilkymistMinimac2State *s,
|
||||
uint8_t phy_addr, uint8_t reg_addr)
|
||||
{
|
||||
uint16_t r = s->phy_regs[reg_addr];
|
||||
|
||||
trace_milkymist_minimac2_mdio_read(phy_addr, reg_addr, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void minimac2_update_mdio(MilkymistMinimac2State *s)
|
||||
{
|
||||
MilkymistMinimac2MdioState *m = &s->mdio;
|
||||
|
||||
/* detect rising clk edge */
|
||||
if (m->last_clk == 0 && (s->regs[R_MDIO] & MDIO_CLK)) {
|
||||
/* shift data in */
|
||||
int bit = ((s->regs[R_MDIO] & MDIO_DO)
|
||||
&& (s->regs[R_MDIO] & MDIO_OE)) ? 1 : 0;
|
||||
m->data = (m->data << 1) | bit;
|
||||
|
||||
/* check for sync */
|
||||
if (m->data == 0xffffffff) {
|
||||
m->count = 32;
|
||||
}
|
||||
|
||||
if (m->count == 16) {
|
||||
uint8_t start = (m->data >> 14) & 0x3;
|
||||
uint8_t op = (m->data >> 12) & 0x3;
|
||||
uint8_t ta = (m->data) & 0x3;
|
||||
|
||||
if (start == 1 && op == MDIO_OP_WRITE && ta == 2) {
|
||||
m->state = MDIO_STATE_WRITING;
|
||||
} else if (start == 1 && op == MDIO_OP_READ && (ta & 1) == 0) {
|
||||
m->state = MDIO_STATE_READING;
|
||||
} else {
|
||||
m->state = MDIO_STATE_IDLE;
|
||||
}
|
||||
|
||||
if (m->state != MDIO_STATE_IDLE) {
|
||||
m->phy_addr = (m->data >> 7) & 0x1f;
|
||||
m->reg_addr = (m->data >> 2) & 0x1f;
|
||||
}
|
||||
|
||||
if (m->state == MDIO_STATE_READING) {
|
||||
m->data_out = minimac2_mdio_read_reg(s, m->phy_addr,
|
||||
m->reg_addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (m->count < 16 && m->state == MDIO_STATE_READING) {
|
||||
int bit = (m->data_out & 0x8000) ? 1 : 0;
|
||||
m->data_out <<= 1;
|
||||
|
||||
if (bit) {
|
||||
s->regs[R_MDIO] |= MDIO_DI;
|
||||
} else {
|
||||
s->regs[R_MDIO] &= ~MDIO_DI;
|
||||
}
|
||||
}
|
||||
|
||||
if (m->count == 0 && m->state) {
|
||||
if (m->state == MDIO_STATE_WRITING) {
|
||||
uint16_t data = m->data & 0xffff;
|
||||
minimac2_mdio_write_reg(s, m->phy_addr, m->reg_addr, data);
|
||||
}
|
||||
m->state = MDIO_STATE_IDLE;
|
||||
}
|
||||
m->count--;
|
||||
}
|
||||
|
||||
m->last_clk = (s->regs[R_MDIO] & MDIO_CLK) ? 1 : 0;
|
||||
}
|
||||
|
||||
static size_t assemble_frame(uint8_t *buf, size_t size,
|
||||
const uint8_t *payload, size_t payload_size)
|
||||
{
|
||||
uint32_t crc;
|
||||
|
||||
if (size < payload_size + 12) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "milkymist_minimac2: frame too big "
|
||||
"(%zd bytes)\n", payload_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* prepend preamble and sfd */
|
||||
memcpy(buf, preamble_sfd, 8);
|
||||
|
||||
/* now copy the payload */
|
||||
memcpy(buf + 8, payload, payload_size);
|
||||
|
||||
/* pad frame if needed */
|
||||
if (payload_size < 60) {
|
||||
memset(buf + payload_size + 8, 0, 60 - payload_size);
|
||||
payload_size = 60;
|
||||
}
|
||||
|
||||
/* append fcs */
|
||||
crc = cpu_to_le32(crc32(0, buf + 8, payload_size));
|
||||
memcpy(buf + payload_size + 8, &crc, 4);
|
||||
|
||||
return payload_size + 12;
|
||||
}
|
||||
|
||||
static void minimac2_tx(MilkymistMinimac2State *s)
|
||||
{
|
||||
uint32_t txcount = s->regs[R_TXCOUNT];
|
||||
uint8_t *buf = s->tx_buf;
|
||||
|
||||
if (txcount < 64) {
|
||||
error_report("milkymist_minimac2: ethernet frame too small (%u < %u)",
|
||||
txcount, 64);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (txcount > MINIMAC2_MTU) {
|
||||
error_report("milkymist_minimac2: MTU exceeded (%u > %u)",
|
||||
txcount, MINIMAC2_MTU);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (memcmp(buf, preamble_sfd, 8) != 0) {
|
||||
error_report("milkymist_minimac2: frame doesn't contain the preamble "
|
||||
"and/or the SFD (%02x %02x %02x %02x %02x %02x %02x %02x)",
|
||||
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
|
||||
goto err;
|
||||
}
|
||||
|
||||
trace_milkymist_minimac2_tx_frame(txcount - 12);
|
||||
|
||||
/* send packet, skipping preamble and sfd */
|
||||
qemu_send_packet_raw(qemu_get_queue(s->nic), buf + 8, txcount - 12);
|
||||
|
||||
s->regs[R_TXCOUNT] = 0;
|
||||
|
||||
err:
|
||||
trace_milkymist_minimac2_pulse_irq_tx();
|
||||
qemu_irq_pulse(s->tx_irq);
|
||||
}
|
||||
|
||||
static void update_rx_interrupt(MilkymistMinimac2State *s)
|
||||
{
|
||||
if (s->regs[R_STATE0] == STATE_PENDING
|
||||
|| s->regs[R_STATE1] == STATE_PENDING) {
|
||||
trace_milkymist_minimac2_raise_irq_rx();
|
||||
qemu_irq_raise(s->rx_irq);
|
||||
} else {
|
||||
trace_milkymist_minimac2_lower_irq_rx();
|
||||
qemu_irq_lower(s->rx_irq);
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t minimac2_rx(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
{
|
||||
MilkymistMinimac2State *s = qemu_get_nic_opaque(nc);
|
||||
|
||||
uint32_t r_count;
|
||||
uint32_t r_state;
|
||||
uint8_t *rx_buf;
|
||||
|
||||
size_t frame_size;
|
||||
|
||||
trace_milkymist_minimac2_rx_frame(buf, size);
|
||||
|
||||
/* choose appropriate slot */
|
||||
if (s->regs[R_STATE0] == STATE_LOADED) {
|
||||
r_count = R_COUNT0;
|
||||
r_state = R_STATE0;
|
||||
rx_buf = s->rx0_buf;
|
||||
} else if (s->regs[R_STATE1] == STATE_LOADED) {
|
||||
r_count = R_COUNT1;
|
||||
r_state = R_STATE1;
|
||||
rx_buf = s->rx1_buf;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* assemble frame */
|
||||
frame_size = assemble_frame(rx_buf, MINIMAC2_BUFFER_SIZE, buf, size);
|
||||
|
||||
if (frame_size == 0) {
|
||||
return size;
|
||||
}
|
||||
|
||||
trace_milkymist_minimac2_rx_transfer(rx_buf, frame_size);
|
||||
|
||||
/* update slot */
|
||||
s->regs[r_count] = frame_size;
|
||||
s->regs[r_state] = STATE_PENDING;
|
||||
|
||||
update_rx_interrupt(s);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
minimac2_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
MilkymistMinimac2State *s = opaque;
|
||||
uint32_t r = 0;
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_SETUP:
|
||||
case R_MDIO:
|
||||
case R_STATE0:
|
||||
case R_COUNT0:
|
||||
case R_STATE1:
|
||||
case R_COUNT1:
|
||||
case R_TXCOUNT:
|
||||
r = s->regs[addr];
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"milkymist_minimac2_rd%d: 0x%" HWADDR_PRIx "\n",
|
||||
size, addr << 2);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_milkymist_minimac2_memory_read(addr << 2, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int minimac2_can_rx(MilkymistMinimac2State *s)
|
||||
{
|
||||
if (s->regs[R_STATE0] == STATE_LOADED) {
|
||||
return 1;
|
||||
}
|
||||
if (s->regs[R_STATE1] == STATE_LOADED) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
minimac2_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistMinimac2State *s = opaque;
|
||||
|
||||
trace_milkymist_minimac2_memory_write(addr, value);
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_MDIO:
|
||||
{
|
||||
/* MDIO_DI is read only */
|
||||
int mdio_di = (s->regs[R_MDIO] & MDIO_DI);
|
||||
s->regs[R_MDIO] = value;
|
||||
if (mdio_di) {
|
||||
s->regs[R_MDIO] |= mdio_di;
|
||||
} else {
|
||||
s->regs[R_MDIO] &= ~mdio_di;
|
||||
}
|
||||
|
||||
minimac2_update_mdio(s);
|
||||
} break;
|
||||
case R_TXCOUNT:
|
||||
s->regs[addr] = value;
|
||||
if (value > 0) {
|
||||
minimac2_tx(s);
|
||||
}
|
||||
break;
|
||||
case R_STATE0:
|
||||
case R_STATE1:
|
||||
s->regs[addr] = value;
|
||||
update_rx_interrupt(s);
|
||||
if (minimac2_can_rx(s)) {
|
||||
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
||||
}
|
||||
break;
|
||||
case R_SETUP:
|
||||
case R_COUNT0:
|
||||
case R_COUNT1:
|
||||
s->regs[addr] = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"milkymist_minimac2_wr%d: 0x%" HWADDR_PRIx
|
||||
" = 0x%" PRIx64 "\n",
|
||||
size, addr << 2, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps minimac2_ops = {
|
||||
.read = minimac2_read,
|
||||
.write = minimac2_write,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void milkymist_minimac2_reset(DeviceState *d)
|
||||
{
|
||||
MilkymistMinimac2State *s = MILKYMIST_MINIMAC2(d);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < R_MAX; i++) {
|
||||
s->regs[i] = 0;
|
||||
}
|
||||
for (i = 0; i < R_PHY_MAX; i++) {
|
||||
s->phy_regs[i] = 0;
|
||||
}
|
||||
|
||||
/* defaults */
|
||||
s->phy_regs[R_PHY_ID1] = 0x0022; /* Micrel KSZ8001L */
|
||||
s->phy_regs[R_PHY_ID2] = 0x161a;
|
||||
}
|
||||
|
||||
static NetClientInfo net_milkymist_minimac2_info = {
|
||||
.type = NET_CLIENT_DRIVER_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.receive = minimac2_rx,
|
||||
};
|
||||
|
||||
static void milkymist_minimac2_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
MilkymistMinimac2State *s = MILKYMIST_MINIMAC2(dev);
|
||||
size_t buffers_size = TARGET_PAGE_ALIGN(3 * MINIMAC2_BUFFER_SIZE);
|
||||
|
||||
sysbus_init_irq(sbd, &s->rx_irq);
|
||||
sysbus_init_irq(sbd, &s->tx_irq);
|
||||
|
||||
memory_region_init_io(&s->regs_region, OBJECT(dev), &minimac2_ops, s,
|
||||
"milkymist-minimac2", R_MAX * 4);
|
||||
sysbus_init_mmio(sbd, &s->regs_region);
|
||||
|
||||
/* register buffers memory */
|
||||
memory_region_init_ram_nomigrate(&s->buffers, OBJECT(dev), "milkymist-minimac2.buffers",
|
||||
buffers_size, &error_fatal);
|
||||
vmstate_register_ram_global(&s->buffers);
|
||||
s->rx0_buf = memory_region_get_ram_ptr(&s->buffers);
|
||||
s->rx1_buf = s->rx0_buf + MINIMAC2_BUFFER_SIZE;
|
||||
s->tx_buf = s->rx1_buf + MINIMAC2_BUFFER_SIZE;
|
||||
|
||||
sysbus_init_mmio(sbd, &s->buffers);
|
||||
|
||||
qemu_macaddr_default_if_unset(&s->conf.macaddr);
|
||||
s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf,
|
||||
object_get_typename(OBJECT(dev)), dev->id, s);
|
||||
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_milkymist_minimac2_mdio = {
|
||||
.name = "milkymist-minimac2-mdio",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT32(last_clk, MilkymistMinimac2MdioState),
|
||||
VMSTATE_INT32(count, MilkymistMinimac2MdioState),
|
||||
VMSTATE_UINT32(data, MilkymistMinimac2MdioState),
|
||||
VMSTATE_UINT16(data_out, MilkymistMinimac2MdioState),
|
||||
VMSTATE_INT32(state, MilkymistMinimac2MdioState),
|
||||
VMSTATE_UINT8(phy_addr, MilkymistMinimac2MdioState),
|
||||
VMSTATE_UINT8(reg_addr, MilkymistMinimac2MdioState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_milkymist_minimac2 = {
|
||||
.name = "milkymist-minimac2",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, MilkymistMinimac2State, R_MAX),
|
||||
VMSTATE_UINT16_ARRAY(phy_regs, MilkymistMinimac2State, R_PHY_MAX),
|
||||
VMSTATE_STRUCT(mdio, MilkymistMinimac2State, 0,
|
||||
vmstate_milkymist_minimac2_mdio, MilkymistMinimac2MdioState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property milkymist_minimac2_properties[] = {
|
||||
DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf),
|
||||
DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void milkymist_minimac2_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = milkymist_minimac2_realize;
|
||||
dc->reset = milkymist_minimac2_reset;
|
||||
dc->vmsd = &vmstate_milkymist_minimac2;
|
||||
device_class_set_props(dc, milkymist_minimac2_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo milkymist_minimac2_info = {
|
||||
.name = TYPE_MILKYMIST_MINIMAC2,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MilkymistMinimac2State),
|
||||
.class_init = milkymist_minimac2_class_init,
|
||||
};
|
||||
|
||||
static void milkymist_minimac2_register_types(void)
|
||||
{
|
||||
type_register_static(&milkymist_minimac2_info);
|
||||
}
|
||||
|
||||
type_init(milkymist_minimac2_register_types)
|
@ -19,18 +19,6 @@ mdio_bitbang(bool mdc, bool mdio, int state, uint16_t cnt, unsigned int drive) "
|
||||
lance_mem_readw(uint64_t addr, uint32_t ret) "addr=0x%"PRIx64"val=0x%04x"
|
||||
lance_mem_writew(uint64_t addr, uint32_t val) "addr=0x%"PRIx64"val=0x%04x"
|
||||
|
||||
# milkymist-minimac2.c
|
||||
milkymist_minimac2_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
milkymist_minimac2_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
milkymist_minimac2_mdio_write(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr 0x%02x addr 0x%02x value 0x%04x"
|
||||
milkymist_minimac2_mdio_read(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr 0x%02x addr 0x%02x value 0x%04x"
|
||||
milkymist_minimac2_tx_frame(uint32_t length) "length %u"
|
||||
milkymist_minimac2_rx_frame(const void *buf, uint32_t length) "buf %p length %u"
|
||||
milkymist_minimac2_rx_transfer(const void *buf, uint32_t length) "buf %p length %d"
|
||||
milkymist_minimac2_raise_irq_rx(void) "Raise IRQ RX"
|
||||
milkymist_minimac2_lower_irq_rx(void) "Lower IRQ RX"
|
||||
milkymist_minimac2_pulse_irq_tx(void) "Pulse IRQ TX"
|
||||
|
||||
# mipsnet.c
|
||||
mipsnet_send(uint32_t size) "sending len=%u"
|
||||
mipsnet_receive(uint32_t size) "receiving len=%u"
|
||||
|
@ -4,7 +4,6 @@ softmmu_ss.add(when: 'CONFIG_SDHCI', if_true: files('sdhci.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_SDHCI_PCI', if_true: files('sdhci-pci.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_SSI_SD', if_true: files('ssi-sd.c'))
|
||||
|
||||
softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-memcard.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_mmc.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_mmci.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_sdhost.c'))
|
||||
|
@ -1,335 +0,0 @@
|
||||
/*
|
||||
* QEMU model of the Milkymist SD Card Controller.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Specification available at:
|
||||
* http://milkymist.walle.cc/socdoc/memcard.pdf
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
#include "qapi/error.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/sd/sd.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
enum {
|
||||
ENABLE_CMD_TX = (1<<0),
|
||||
ENABLE_CMD_RX = (1<<1),
|
||||
ENABLE_DAT_TX = (1<<2),
|
||||
ENABLE_DAT_RX = (1<<3),
|
||||
};
|
||||
|
||||
enum {
|
||||
PENDING_CMD_TX = (1<<0),
|
||||
PENDING_CMD_RX = (1<<1),
|
||||
PENDING_DAT_TX = (1<<2),
|
||||
PENDING_DAT_RX = (1<<3),
|
||||
};
|
||||
|
||||
enum {
|
||||
START_CMD_TX = (1<<0),
|
||||
START_DAT_RX = (1<<1),
|
||||
};
|
||||
|
||||
enum {
|
||||
R_CLK2XDIV = 0,
|
||||
R_ENABLE,
|
||||
R_PENDING,
|
||||
R_START,
|
||||
R_CMD,
|
||||
R_DAT,
|
||||
R_MAX
|
||||
};
|
||||
|
||||
#define TYPE_MILKYMIST_MEMCARD "milkymist-memcard"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(MilkymistMemcardState, MILKYMIST_MEMCARD)
|
||||
|
||||
#define TYPE_MILKYMIST_SDBUS "milkymist-sdbus"
|
||||
|
||||
struct MilkymistMemcardState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion regs_region;
|
||||
SDBus sdbus;
|
||||
|
||||
int command_write_ptr;
|
||||
int response_read_ptr;
|
||||
int response_len;
|
||||
int ignore_next_cmd;
|
||||
int enabled;
|
||||
uint8_t command[6];
|
||||
uint8_t response[17];
|
||||
uint32_t regs[R_MAX];
|
||||
};
|
||||
|
||||
static void update_pending_bits(MilkymistMemcardState *s)
|
||||
{
|
||||
/* transmits are instantaneous, thus tx pending bits are never set */
|
||||
s->regs[R_PENDING] = 0;
|
||||
/* if rx is enabled the corresponding pending bits are always set */
|
||||
if (s->regs[R_ENABLE] & ENABLE_CMD_RX) {
|
||||
s->regs[R_PENDING] |= PENDING_CMD_RX;
|
||||
}
|
||||
if (s->regs[R_ENABLE] & ENABLE_DAT_RX) {
|
||||
s->regs[R_PENDING] |= PENDING_DAT_RX;
|
||||
}
|
||||
}
|
||||
|
||||
static void memcard_sd_command(MilkymistMemcardState *s)
|
||||
{
|
||||
SDRequest req;
|
||||
|
||||
req.cmd = s->command[0] & 0x3f;
|
||||
req.arg = ldl_be_p(s->command + 1);
|
||||
req.crc = s->command[5];
|
||||
|
||||
s->response[0] = req.cmd;
|
||||
s->response_len = sdbus_do_command(&s->sdbus, &req, s->response + 1);
|
||||
s->response_read_ptr = 0;
|
||||
|
||||
if (s->response_len == 16) {
|
||||
/* R2 response */
|
||||
s->response[0] = 0x3f;
|
||||
s->response_len += 1;
|
||||
} else if (s->response_len == 4) {
|
||||
/* no crc calculation, insert dummy byte */
|
||||
s->response[5] = 0;
|
||||
s->response_len += 2;
|
||||
}
|
||||
|
||||
if (req.cmd == 0) {
|
||||
/* next write is a dummy byte to clock the initialization of the sd
|
||||
* card */
|
||||
s->ignore_next_cmd = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t memcard_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistMemcardState *s = opaque;
|
||||
uint32_t r = 0;
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_CMD:
|
||||
if (!s->enabled) {
|
||||
r = 0xff;
|
||||
} else {
|
||||
r = s->response[s->response_read_ptr++];
|
||||
if (s->response_read_ptr > s->response_len) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "milkymist_memcard: "
|
||||
"read more cmd bytes than available: clipping\n");
|
||||
s->response_read_ptr = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case R_DAT:
|
||||
if (!s->enabled) {
|
||||
r = 0xffffffff;
|
||||
} else {
|
||||
sdbus_read_data(&s->sdbus, &r, sizeof(r));
|
||||
be32_to_cpus(&r);
|
||||
}
|
||||
break;
|
||||
case R_CLK2XDIV:
|
||||
case R_ENABLE:
|
||||
case R_PENDING:
|
||||
case R_START:
|
||||
r = s->regs[addr];
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "milkymist_memcard: "
|
||||
"read access to unknown register 0x%" HWADDR_PRIx "\n",
|
||||
addr << 2);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_milkymist_memcard_memory_read(addr << 2, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void memcard_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistMemcardState *s = opaque;
|
||||
uint32_t val32;
|
||||
|
||||
trace_milkymist_memcard_memory_write(addr, value);
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_PENDING:
|
||||
/* clear rx pending bits */
|
||||
s->regs[R_PENDING] &= ~(value & (PENDING_CMD_RX | PENDING_DAT_RX));
|
||||
update_pending_bits(s);
|
||||
break;
|
||||
case R_CMD:
|
||||
if (!s->enabled) {
|
||||
break;
|
||||
}
|
||||
if (s->ignore_next_cmd) {
|
||||
s->ignore_next_cmd = 0;
|
||||
break;
|
||||
}
|
||||
s->command[s->command_write_ptr] = value & 0xff;
|
||||
s->command_write_ptr = (s->command_write_ptr + 1) % 6;
|
||||
if (s->command_write_ptr == 0) {
|
||||
memcard_sd_command(s);
|
||||
}
|
||||
break;
|
||||
case R_DAT:
|
||||
if (!s->enabled) {
|
||||
break;
|
||||
}
|
||||
val32 = cpu_to_be32(value);
|
||||
sdbus_write_data(&s->sdbus, &val32, sizeof(val32));
|
||||
break;
|
||||
case R_ENABLE:
|
||||
s->regs[addr] = value;
|
||||
update_pending_bits(s);
|
||||
break;
|
||||
case R_CLK2XDIV:
|
||||
case R_START:
|
||||
s->regs[addr] = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "milkymist_memcard: "
|
||||
"write access to unknown register 0x%" HWADDR_PRIx " "
|
||||
"(value 0x%" PRIx64 ")\n", addr << 2, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps memcard_mmio_ops = {
|
||||
.read = memcard_read,
|
||||
.write = memcard_write,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void milkymist_memcard_reset(DeviceState *d)
|
||||
{
|
||||
MilkymistMemcardState *s = MILKYMIST_MEMCARD(d);
|
||||
int i;
|
||||
|
||||
s->command_write_ptr = 0;
|
||||
s->response_read_ptr = 0;
|
||||
s->response_len = 0;
|
||||
|
||||
for (i = 0; i < R_MAX; i++) {
|
||||
s->regs[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void milkymist_memcard_set_readonly(DeviceState *dev, bool level)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"milkymist_memcard: read-only mode not supported\n");
|
||||
}
|
||||
|
||||
static void milkymist_memcard_set_inserted(DeviceState *dev, bool level)
|
||||
{
|
||||
MilkymistMemcardState *s = MILKYMIST_MEMCARD(dev);
|
||||
|
||||
s->enabled = !!level;
|
||||
}
|
||||
|
||||
static void milkymist_memcard_init(Object *obj)
|
||||
{
|
||||
MilkymistMemcardState *s = MILKYMIST_MEMCARD(obj);
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->regs_region, OBJECT(s), &memcard_mmio_ops, s,
|
||||
"milkymist-memcard", R_MAX * 4);
|
||||
sysbus_init_mmio(dev, &s->regs_region);
|
||||
|
||||
qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS,
|
||||
DEVICE(obj), "sd-bus");
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_milkymist_memcard = {
|
||||
.name = "milkymist-memcard",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT32(command_write_ptr, MilkymistMemcardState),
|
||||
VMSTATE_INT32(response_read_ptr, MilkymistMemcardState),
|
||||
VMSTATE_INT32(response_len, MilkymistMemcardState),
|
||||
VMSTATE_INT32(ignore_next_cmd, MilkymistMemcardState),
|
||||
VMSTATE_INT32(enabled, MilkymistMemcardState),
|
||||
VMSTATE_UINT8_ARRAY(command, MilkymistMemcardState, 6),
|
||||
VMSTATE_UINT8_ARRAY(response, MilkymistMemcardState, 17),
|
||||
VMSTATE_UINT32_ARRAY(regs, MilkymistMemcardState, R_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void milkymist_memcard_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->reset = milkymist_memcard_reset;
|
||||
dc->vmsd = &vmstate_milkymist_memcard;
|
||||
/* Reason: output IRQs should be wired up */
|
||||
dc->user_creatable = false;
|
||||
}
|
||||
|
||||
static const TypeInfo milkymist_memcard_info = {
|
||||
.name = TYPE_MILKYMIST_MEMCARD,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MilkymistMemcardState),
|
||||
.instance_init = milkymist_memcard_init,
|
||||
.class_init = milkymist_memcard_class_init,
|
||||
};
|
||||
|
||||
static void milkymist_sdbus_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
SDBusClass *sbc = SD_BUS_CLASS(klass);
|
||||
|
||||
sbc->set_inserted = milkymist_memcard_set_inserted;
|
||||
sbc->set_readonly = milkymist_memcard_set_readonly;
|
||||
}
|
||||
|
||||
static const TypeInfo milkymist_sdbus_info = {
|
||||
.name = TYPE_MILKYMIST_SDBUS,
|
||||
.parent = TYPE_SD_BUS,
|
||||
.instance_size = sizeof(SDBus),
|
||||
.class_init = milkymist_sdbus_class_init,
|
||||
};
|
||||
|
||||
static void milkymist_memcard_register_types(void)
|
||||
{
|
||||
type_register_static(&milkymist_memcard_info);
|
||||
type_register_static(&milkymist_sdbus_info);
|
||||
}
|
||||
|
||||
type_init(milkymist_memcard_register_types)
|
@ -55,10 +55,6 @@ sdcard_write_data(const char *proto, const char *cmd_desc, uint8_t cmd, uint8_t
|
||||
sdcard_read_data(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t length) "%s %20s/ CMD%02d len %" PRIu32
|
||||
sdcard_set_voltage(uint16_t millivolts) "%u mV"
|
||||
|
||||
# milkymist-memcard.c
|
||||
milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
|
||||
# pxa2xx_mmci.c
|
||||
pxa2xx_mmci_read(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x"
|
||||
pxa2xx_mmci_write(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x"
|
||||
|
@ -1,249 +0,0 @@
|
||||
/*
|
||||
* QEMU model of the LatticeMico32 timer block.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Specification available at:
|
||||
* http://www.latticesemi.com/documents/mico32timer.pdf
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/ptimer.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define DEFAULT_FREQUENCY (50*1000000)
|
||||
|
||||
enum {
|
||||
R_SR = 0,
|
||||
R_CR,
|
||||
R_PERIOD,
|
||||
R_SNAPSHOT,
|
||||
R_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
SR_TO = (1 << 0),
|
||||
SR_RUN = (1 << 1),
|
||||
};
|
||||
|
||||
enum {
|
||||
CR_ITO = (1 << 0),
|
||||
CR_CONT = (1 << 1),
|
||||
CR_START = (1 << 2),
|
||||
CR_STOP = (1 << 3),
|
||||
};
|
||||
|
||||
#define TYPE_LM32_TIMER "lm32-timer"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(LM32TimerState, LM32_TIMER)
|
||||
|
||||
struct LM32TimerState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
|
||||
ptimer_state *ptimer;
|
||||
|
||||
qemu_irq irq;
|
||||
uint32_t freq_hz;
|
||||
|
||||
uint32_t regs[R_MAX];
|
||||
};
|
||||
|
||||
static void timer_update_irq(LM32TimerState *s)
|
||||
{
|
||||
int state = (s->regs[R_SR] & SR_TO) && (s->regs[R_CR] & CR_ITO);
|
||||
|
||||
trace_lm32_timer_irq_state(state);
|
||||
qemu_set_irq(s->irq, state);
|
||||
}
|
||||
|
||||
static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
LM32TimerState *s = opaque;
|
||||
uint32_t r = 0;
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_SR:
|
||||
case R_CR:
|
||||
case R_PERIOD:
|
||||
r = s->regs[addr];
|
||||
break;
|
||||
case R_SNAPSHOT:
|
||||
r = (uint32_t)ptimer_get_count(s->ptimer);
|
||||
break;
|
||||
default:
|
||||
error_report("lm32_timer: read access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_lm32_timer_memory_read(addr << 2, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void timer_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
LM32TimerState *s = opaque;
|
||||
|
||||
trace_lm32_timer_memory_write(addr, value);
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_SR:
|
||||
s->regs[R_SR] &= ~SR_TO;
|
||||
break;
|
||||
case R_CR:
|
||||
ptimer_transaction_begin(s->ptimer);
|
||||
s->regs[R_CR] = value;
|
||||
if (s->regs[R_CR] & CR_START) {
|
||||
ptimer_run(s->ptimer, 1);
|
||||
}
|
||||
if (s->regs[R_CR] & CR_STOP) {
|
||||
ptimer_stop(s->ptimer);
|
||||
}
|
||||
ptimer_transaction_commit(s->ptimer);
|
||||
break;
|
||||
case R_PERIOD:
|
||||
s->regs[R_PERIOD] = value;
|
||||
ptimer_transaction_begin(s->ptimer);
|
||||
ptimer_set_count(s->ptimer, value);
|
||||
ptimer_transaction_commit(s->ptimer);
|
||||
break;
|
||||
case R_SNAPSHOT:
|
||||
error_report("lm32_timer: write access to read only register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
default:
|
||||
error_report("lm32_timer: write access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
timer_update_irq(s);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps timer_ops = {
|
||||
.read = timer_read,
|
||||
.write = timer_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void timer_hit(void *opaque)
|
||||
{
|
||||
LM32TimerState *s = opaque;
|
||||
|
||||
trace_lm32_timer_hit();
|
||||
|
||||
s->regs[R_SR] |= SR_TO;
|
||||
|
||||
if (s->regs[R_CR] & CR_CONT) {
|
||||
ptimer_set_count(s->ptimer, s->regs[R_PERIOD]);
|
||||
ptimer_run(s->ptimer, 1);
|
||||
}
|
||||
timer_update_irq(s);
|
||||
}
|
||||
|
||||
static void timer_reset(DeviceState *d)
|
||||
{
|
||||
LM32TimerState *s = LM32_TIMER(d);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < R_MAX; i++) {
|
||||
s->regs[i] = 0;
|
||||
}
|
||||
ptimer_transaction_begin(s->ptimer);
|
||||
ptimer_stop(s->ptimer);
|
||||
ptimer_transaction_commit(s->ptimer);
|
||||
}
|
||||
|
||||
static void lm32_timer_init(Object *obj)
|
||||
{
|
||||
LM32TimerState *s = LM32_TIMER(obj);
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
|
||||
sysbus_init_irq(dev, &s->irq);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &timer_ops, s,
|
||||
"timer", R_MAX * 4);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
}
|
||||
|
||||
static void lm32_timer_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
LM32TimerState *s = LM32_TIMER(dev);
|
||||
|
||||
s->ptimer = ptimer_init(timer_hit, s, PTIMER_POLICY_DEFAULT);
|
||||
|
||||
ptimer_transaction_begin(s->ptimer);
|
||||
ptimer_set_freq(s->ptimer, s->freq_hz);
|
||||
ptimer_transaction_commit(s->ptimer);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_lm32_timer = {
|
||||
.name = "lm32-timer",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PTIMER(ptimer, LM32TimerState),
|
||||
VMSTATE_UINT32(freq_hz, LM32TimerState),
|
||||
VMSTATE_UINT32_ARRAY(regs, LM32TimerState, R_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property lm32_timer_properties[] = {
|
||||
DEFINE_PROP_UINT32("frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void lm32_timer_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = lm32_timer_realize;
|
||||
dc->reset = timer_reset;
|
||||
dc->vmsd = &vmstate_lm32_timer;
|
||||
device_class_set_props(dc, lm32_timer_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo lm32_timer_info = {
|
||||
.name = TYPE_LM32_TIMER,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(LM32TimerState),
|
||||
.instance_init = lm32_timer_init,
|
||||
.class_init = lm32_timer_class_init,
|
||||
};
|
||||
|
||||
static void lm32_timer_register_types(void)
|
||||
{
|
||||
type_register_static(&lm32_timer_info);
|
||||
}
|
||||
|
||||
type_init(lm32_timer_register_types)
|
@ -19,15 +19,12 @@ softmmu_ss.add(when: 'CONFIG_HPET', if_true: files('hpet.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_I8254', if_true: files('i8254_common.c', 'i8254.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_epit.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpt.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_LM32_DEVICES', if_true: files('lm32_timer.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-sysctl.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_gictimer.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('mss-timer.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_timer.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_timer.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_gptimer.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_synctimer.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_ost.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_timer.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_systmr.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_SH_TIMER', if_true: files('sh_timer.c'))
|
||||
|
@ -1,361 +0,0 @@
|
||||
/*
|
||||
* QEMU model of the Milkymist System Controller.
|
||||
*
|
||||
* Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Specification available at:
|
||||
* http://milkymist.walle.cc/socdoc/sysctl.pdf
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "hw/ptimer.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
enum {
|
||||
CTRL_ENABLE = (1<<0),
|
||||
CTRL_AUTORESTART = (1<<1),
|
||||
};
|
||||
|
||||
enum {
|
||||
ICAP_READY = (1<<0),
|
||||
};
|
||||
|
||||
enum {
|
||||
R_GPIO_IN = 0,
|
||||
R_GPIO_OUT,
|
||||
R_GPIO_INTEN,
|
||||
R_TIMER0_CONTROL = 4,
|
||||
R_TIMER0_COMPARE,
|
||||
R_TIMER0_COUNTER,
|
||||
R_TIMER1_CONTROL = 8,
|
||||
R_TIMER1_COMPARE,
|
||||
R_TIMER1_COUNTER,
|
||||
R_ICAP = 16,
|
||||
R_DBG_SCRATCHPAD = 20,
|
||||
R_DBG_WRITE_LOCK,
|
||||
R_CLK_FREQUENCY = 29,
|
||||
R_CAPABILITIES,
|
||||
R_SYSTEM_ID,
|
||||
R_MAX
|
||||
};
|
||||
|
||||
#define TYPE_MILKYMIST_SYSCTL "milkymist-sysctl"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(MilkymistSysctlState, MILKYMIST_SYSCTL)
|
||||
|
||||
struct MilkymistSysctlState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion regs_region;
|
||||
|
||||
ptimer_state *ptimer0;
|
||||
ptimer_state *ptimer1;
|
||||
|
||||
uint32_t freq_hz;
|
||||
uint32_t capabilities;
|
||||
uint32_t systemid;
|
||||
uint32_t strappings;
|
||||
|
||||
uint32_t regs[R_MAX];
|
||||
|
||||
qemu_irq gpio_irq;
|
||||
qemu_irq timer0_irq;
|
||||
qemu_irq timer1_irq;
|
||||
};
|
||||
|
||||
static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value)
|
||||
{
|
||||
trace_milkymist_sysctl_icap_write(value);
|
||||
switch (value & 0xffff) {
|
||||
case 0x000e:
|
||||
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t sysctl_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistSysctlState *s = opaque;
|
||||
uint32_t r = 0;
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_TIMER0_COUNTER:
|
||||
r = (uint32_t)ptimer_get_count(s->ptimer0);
|
||||
/* milkymist timer counts up */
|
||||
r = s->regs[R_TIMER0_COMPARE] - r;
|
||||
break;
|
||||
case R_TIMER1_COUNTER:
|
||||
r = (uint32_t)ptimer_get_count(s->ptimer1);
|
||||
/* milkymist timer counts up */
|
||||
r = s->regs[R_TIMER1_COMPARE] - r;
|
||||
break;
|
||||
case R_GPIO_IN:
|
||||
case R_GPIO_OUT:
|
||||
case R_GPIO_INTEN:
|
||||
case R_TIMER0_CONTROL:
|
||||
case R_TIMER0_COMPARE:
|
||||
case R_TIMER1_CONTROL:
|
||||
case R_TIMER1_COMPARE:
|
||||
case R_ICAP:
|
||||
case R_DBG_SCRATCHPAD:
|
||||
case R_DBG_WRITE_LOCK:
|
||||
case R_CLK_FREQUENCY:
|
||||
case R_CAPABILITIES:
|
||||
case R_SYSTEM_ID:
|
||||
r = s->regs[addr];
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("milkymist_sysctl: read access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_milkymist_sysctl_memory_read(addr << 2, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void sysctl_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
MilkymistSysctlState *s = opaque;
|
||||
|
||||
trace_milkymist_sysctl_memory_write(addr, value);
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_GPIO_OUT:
|
||||
case R_GPIO_INTEN:
|
||||
case R_TIMER0_COUNTER:
|
||||
case R_TIMER1_COUNTER:
|
||||
case R_DBG_SCRATCHPAD:
|
||||
s->regs[addr] = value;
|
||||
break;
|
||||
case R_TIMER0_COMPARE:
|
||||
ptimer_transaction_begin(s->ptimer0);
|
||||
ptimer_set_limit(s->ptimer0, value, 0);
|
||||
s->regs[addr] = value;
|
||||
ptimer_transaction_commit(s->ptimer0);
|
||||
break;
|
||||
case R_TIMER1_COMPARE:
|
||||
ptimer_transaction_begin(s->ptimer1);
|
||||
ptimer_set_limit(s->ptimer1, value, 0);
|
||||
s->regs[addr] = value;
|
||||
ptimer_transaction_commit(s->ptimer1);
|
||||
break;
|
||||
case R_TIMER0_CONTROL:
|
||||
ptimer_transaction_begin(s->ptimer0);
|
||||
s->regs[addr] = value;
|
||||
if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
|
||||
trace_milkymist_sysctl_start_timer0();
|
||||
ptimer_set_count(s->ptimer0,
|
||||
s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]);
|
||||
ptimer_run(s->ptimer0, 0);
|
||||
} else {
|
||||
trace_milkymist_sysctl_stop_timer0();
|
||||
ptimer_stop(s->ptimer0);
|
||||
}
|
||||
ptimer_transaction_commit(s->ptimer0);
|
||||
break;
|
||||
case R_TIMER1_CONTROL:
|
||||
ptimer_transaction_begin(s->ptimer1);
|
||||
s->regs[addr] = value;
|
||||
if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
|
||||
trace_milkymist_sysctl_start_timer1();
|
||||
ptimer_set_count(s->ptimer1,
|
||||
s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]);
|
||||
ptimer_run(s->ptimer1, 0);
|
||||
} else {
|
||||
trace_milkymist_sysctl_stop_timer1();
|
||||
ptimer_stop(s->ptimer1);
|
||||
}
|
||||
ptimer_transaction_commit(s->ptimer1);
|
||||
break;
|
||||
case R_ICAP:
|
||||
sysctl_icap_write(s, value);
|
||||
break;
|
||||
case R_DBG_WRITE_LOCK:
|
||||
s->regs[addr] = 1;
|
||||
break;
|
||||
case R_SYSTEM_ID:
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
|
||||
break;
|
||||
|
||||
case R_GPIO_IN:
|
||||
case R_CLK_FREQUENCY:
|
||||
case R_CAPABILITIES:
|
||||
error_report("milkymist_sysctl: write to read-only register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("milkymist_sysctl: write access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sysctl_mmio_ops = {
|
||||
.read = sysctl_read,
|
||||
.write = sysctl_write,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void timer0_hit(void *opaque)
|
||||
{
|
||||
MilkymistSysctlState *s = opaque;
|
||||
|
||||
if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) {
|
||||
s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE;
|
||||
trace_milkymist_sysctl_stop_timer0();
|
||||
ptimer_stop(s->ptimer0);
|
||||
}
|
||||
|
||||
trace_milkymist_sysctl_pulse_irq_timer0();
|
||||
qemu_irq_pulse(s->timer0_irq);
|
||||
}
|
||||
|
||||
static void timer1_hit(void *opaque)
|
||||
{
|
||||
MilkymistSysctlState *s = opaque;
|
||||
|
||||
if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) {
|
||||
s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE;
|
||||
trace_milkymist_sysctl_stop_timer1();
|
||||
ptimer_stop(s->ptimer1);
|
||||
}
|
||||
|
||||
trace_milkymist_sysctl_pulse_irq_timer1();
|
||||
qemu_irq_pulse(s->timer1_irq);
|
||||
}
|
||||
|
||||
static void milkymist_sysctl_reset(DeviceState *d)
|
||||
{
|
||||
MilkymistSysctlState *s = MILKYMIST_SYSCTL(d);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < R_MAX; i++) {
|
||||
s->regs[i] = 0;
|
||||
}
|
||||
|
||||
ptimer_transaction_begin(s->ptimer0);
|
||||
ptimer_stop(s->ptimer0);
|
||||
ptimer_transaction_commit(s->ptimer0);
|
||||
ptimer_transaction_begin(s->ptimer1);
|
||||
ptimer_stop(s->ptimer1);
|
||||
ptimer_transaction_commit(s->ptimer1);
|
||||
|
||||
/* defaults */
|
||||
s->regs[R_ICAP] = ICAP_READY;
|
||||
s->regs[R_SYSTEM_ID] = s->systemid;
|
||||
s->regs[R_CLK_FREQUENCY] = s->freq_hz;
|
||||
s->regs[R_CAPABILITIES] = s->capabilities;
|
||||
s->regs[R_GPIO_IN] = s->strappings;
|
||||
}
|
||||
|
||||
static void milkymist_sysctl_init(Object *obj)
|
||||
{
|
||||
MilkymistSysctlState *s = MILKYMIST_SYSCTL(obj);
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
|
||||
sysbus_init_irq(dev, &s->gpio_irq);
|
||||
sysbus_init_irq(dev, &s->timer0_irq);
|
||||
sysbus_init_irq(dev, &s->timer1_irq);
|
||||
|
||||
memory_region_init_io(&s->regs_region, obj, &sysctl_mmio_ops, s,
|
||||
"milkymist-sysctl", R_MAX * 4);
|
||||
sysbus_init_mmio(dev, &s->regs_region);
|
||||
}
|
||||
|
||||
static void milkymist_sysctl_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MilkymistSysctlState *s = MILKYMIST_SYSCTL(dev);
|
||||
|
||||
s->ptimer0 = ptimer_init(timer0_hit, s, PTIMER_POLICY_DEFAULT);
|
||||
s->ptimer1 = ptimer_init(timer1_hit, s, PTIMER_POLICY_DEFAULT);
|
||||
|
||||
ptimer_transaction_begin(s->ptimer0);
|
||||
ptimer_set_freq(s->ptimer0, s->freq_hz);
|
||||
ptimer_transaction_commit(s->ptimer0);
|
||||
ptimer_transaction_begin(s->ptimer1);
|
||||
ptimer_set_freq(s->ptimer1, s->freq_hz);
|
||||
ptimer_transaction_commit(s->ptimer1);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_milkymist_sysctl = {
|
||||
.name = "milkymist-sysctl",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX),
|
||||
VMSTATE_PTIMER(ptimer0, MilkymistSysctlState),
|
||||
VMSTATE_PTIMER(ptimer1, MilkymistSysctlState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property milkymist_sysctl_properties[] = {
|
||||
DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
|
||||
freq_hz, 80000000),
|
||||
DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
|
||||
capabilities, 0x00000000),
|
||||
DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
|
||||
systemid, 0x10014d31),
|
||||
DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
|
||||
strappings, 0x00000001),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void milkymist_sysctl_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = milkymist_sysctl_realize;
|
||||
dc->reset = milkymist_sysctl_reset;
|
||||
dc->vmsd = &vmstate_milkymist_sysctl;
|
||||
device_class_set_props(dc, milkymist_sysctl_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo milkymist_sysctl_info = {
|
||||
.name = TYPE_MILKYMIST_SYSCTL,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MilkymistSysctlState),
|
||||
.instance_init = milkymist_sysctl_init,
|
||||
.class_init = milkymist_sysctl_class_init,
|
||||
};
|
||||
|
||||
static void milkymist_sysctl_register_types(void)
|
||||
{
|
||||
type_register_static(&milkymist_sysctl_info);
|
||||
}
|
||||
|
||||
type_init(milkymist_sysctl_register_types)
|
@ -1,166 +0,0 @@
|
||||
/*
|
||||
* OSTimer device simulation in PKUnity SoC
|
||||
*
|
||||
* Copyright (C) 2010-2012 Guan Xuetao
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation, or any later version.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/ptimer.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#undef DEBUG_PUV3
|
||||
#include "hw/unicore32/puv3.h"
|
||||
|
||||
#define TYPE_PUV3_OST "puv3_ost"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(PUV3OSTState, PUV3_OST)
|
||||
|
||||
/* puv3 ostimer implementation. */
|
||||
struct PUV3OSTState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
qemu_irq irq;
|
||||
ptimer_state *ptimer;
|
||||
|
||||
uint32_t reg_OSMR0;
|
||||
uint32_t reg_OSCR;
|
||||
uint32_t reg_OSSR;
|
||||
uint32_t reg_OIER;
|
||||
};
|
||||
|
||||
static uint64_t puv3_ost_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
PUV3OSTState *s = opaque;
|
||||
uint32_t ret = 0;
|
||||
|
||||
switch (offset) {
|
||||
case 0x10: /* Counter Register */
|
||||
ret = s->reg_OSMR0 - (uint32_t)ptimer_get_count(s->ptimer);
|
||||
break;
|
||||
case 0x14: /* Status Register */
|
||||
ret = s->reg_OSSR;
|
||||
break;
|
||||
case 0x1c: /* Interrupt Enable Register */
|
||||
ret = s->reg_OIER;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad read offset 0x%"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
}
|
||||
DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void puv3_ost_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
PUV3OSTState *s = opaque;
|
||||
|
||||
DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
|
||||
switch (offset) {
|
||||
case 0x00: /* Match Register 0 */
|
||||
ptimer_transaction_begin(s->ptimer);
|
||||
s->reg_OSMR0 = value;
|
||||
if (s->reg_OSMR0 > s->reg_OSCR) {
|
||||
ptimer_set_count(s->ptimer, s->reg_OSMR0 - s->reg_OSCR);
|
||||
} else {
|
||||
ptimer_set_count(s->ptimer, s->reg_OSMR0 +
|
||||
(0xffffffff - s->reg_OSCR));
|
||||
}
|
||||
ptimer_run(s->ptimer, 2);
|
||||
ptimer_transaction_commit(s->ptimer);
|
||||
break;
|
||||
case 0x14: /* Status Register */
|
||||
assert(value == 0);
|
||||
if (s->reg_OSSR) {
|
||||
s->reg_OSSR = value;
|
||||
qemu_irq_lower(s->irq);
|
||||
}
|
||||
break;
|
||||
case 0x1c: /* Interrupt Enable Register */
|
||||
s->reg_OIER = value;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad write offset 0x%"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps puv3_ost_ops = {
|
||||
.read = puv3_ost_read,
|
||||
.write = puv3_ost_write,
|
||||
.impl = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void puv3_ost_tick(void *opaque)
|
||||
{
|
||||
PUV3OSTState *s = opaque;
|
||||
|
||||
DPRINTF("ost hit when ptimer counter from 0x%x to 0x%x!\n",
|
||||
s->reg_OSCR, s->reg_OSMR0);
|
||||
|
||||
s->reg_OSCR = s->reg_OSMR0;
|
||||
if (s->reg_OIER) {
|
||||
s->reg_OSSR = 1;
|
||||
qemu_irq_raise(s->irq);
|
||||
}
|
||||
}
|
||||
|
||||
static void puv3_ost_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PUV3OSTState *s = PUV3_OST(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
s->reg_OIER = 0;
|
||||
s->reg_OSSR = 0;
|
||||
s->reg_OSMR0 = 0;
|
||||
s->reg_OSCR = 0;
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
||||
s->ptimer = ptimer_init(puv3_ost_tick, s, PTIMER_POLICY_DEFAULT);
|
||||
ptimer_transaction_begin(s->ptimer);
|
||||
ptimer_set_freq(s->ptimer, 50 * 1000 * 1000);
|
||||
ptimer_transaction_commit(s->ptimer);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &puv3_ost_ops, s, "puv3_ost",
|
||||
PUV3_REGS_OFFSET);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
}
|
||||
|
||||
static void puv3_ost_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = puv3_ost_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo puv3_ost_info = {
|
||||
.name = TYPE_PUV3_OST,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PUV3OSTState),
|
||||
.class_init = puv3_ost_class_init,
|
||||
};
|
||||
|
||||
static void puv3_ost_register_type(void)
|
||||
{
|
||||
type_register_static(&puv3_ost_info);
|
||||
}
|
||||
|
||||
type_init(puv3_ost_register_type)
|
@ -24,23 +24,6 @@ grlib_gptimer_hit(int id) "timer:%d HIT"
|
||||
grlib_gptimer_readl(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x"
|
||||
grlib_gptimer_writel(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x"
|
||||
|
||||
# lm32_timer.c
|
||||
lm32_timer_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
lm32_timer_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
lm32_timer_hit(void) "timer hit"
|
||||
lm32_timer_irq_state(int level) "irq state %d"
|
||||
|
||||
# milkymist-sysctl.c
|
||||
milkymist_sysctl_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
milkymist_sysctl_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
milkymist_sysctl_icap_write(uint32_t value) "value 0x%08x"
|
||||
milkymist_sysctl_start_timer0(void) "Start timer0"
|
||||
milkymist_sysctl_stop_timer0(void) "Stop timer0"
|
||||
milkymist_sysctl_start_timer1(void) "Start timer1"
|
||||
milkymist_sysctl_stop_timer1(void) "Stop timer1"
|
||||
milkymist_sysctl_pulse_irq_timer0(void) "Pulse IRQ Timer0"
|
||||
milkymist_sysctl_pulse_irq_timer1(void) "Pulse IRQ Timer1"
|
||||
|
||||
# aspeed_timer.c
|
||||
aspeed_timer_ctrl_enable(uint8_t i, bool enable) "Timer %" PRIu8 ": %d"
|
||||
aspeed_timer_ctrl_external_clock(uint8_t i, bool enable) "Timer %" PRIu8 ": %d"
|
||||
|
@ -1,5 +0,0 @@
|
||||
config PUV3
|
||||
bool
|
||||
select ISA_BUS
|
||||
select PCKBD
|
||||
select PTIMER
|
@ -1,5 +0,0 @@
|
||||
unicore32_ss = ss.source_set()
|
||||
# PKUnity-v3 SoC and board information
|
||||
unicore32_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3.c'))
|
||||
|
||||
hw_arch += {'unicore32': unicore32_ss}
|
@ -1,145 +0,0 @@
|
||||
/*
|
||||
* Generic PKUnity SoC machine and board descriptor
|
||||
*
|
||||
* Copyright (C) 2010-2012 Guan Xuetao
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation, or any later version.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "cpu.h"
|
||||
#include "ui/console.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/loader.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "hw/unicore32/puv3.h"
|
||||
#include "hw/input/i8042.h"
|
||||
#include "hw/irq.h"
|
||||
|
||||
#define KERNEL_LOAD_ADDR 0x03000000
|
||||
#define KERNEL_MAX_SIZE 0x00800000 /* Just a guess */
|
||||
|
||||
/* PKUnity System bus (AHB): 0xc0000000 - 0xedffffff (640MB) */
|
||||
#define PUV3_DMA_BASE (0xc0200000) /* AHB-4 */
|
||||
|
||||
/* PKUnity Peripheral bus (APB): 0xee000000 - 0xefffffff (128MB) */
|
||||
#define PUV3_GPIO_BASE (0xee500000) /* APB-5 */
|
||||
#define PUV3_INTC_BASE (0xee600000) /* APB-6 */
|
||||
#define PUV3_OST_BASE (0xee800000) /* APB-8 */
|
||||
#define PUV3_PM_BASE (0xeea00000) /* APB-10 */
|
||||
#define PUV3_PS2_BASE (0xeeb00000) /* APB-11 */
|
||||
|
||||
static void puv3_intc_cpu_handler(void *opaque, int irq, int level)
|
||||
{
|
||||
UniCore32CPU *cpu = opaque;
|
||||
CPUState *cs = CPU(cpu);
|
||||
|
||||
assert(irq == 0);
|
||||
if (level) {
|
||||
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
|
||||
} else {
|
||||
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
}
|
||||
|
||||
static void puv3_soc_init(CPUUniCore32State *env)
|
||||
{
|
||||
qemu_irq cpu_intc, irqs[PUV3_IRQS_NR];
|
||||
DeviceState *dev;
|
||||
MemoryRegion *i8042 = g_new(MemoryRegion, 1);
|
||||
int i;
|
||||
|
||||
/* Initialize interrupt controller */
|
||||
cpu_intc = qemu_allocate_irq(puv3_intc_cpu_handler,
|
||||
env_archcpu(env), 0);
|
||||
dev = sysbus_create_simple("puv3_intc", PUV3_INTC_BASE, cpu_intc);
|
||||
for (i = 0; i < PUV3_IRQS_NR; i++) {
|
||||
irqs[i] = qdev_get_gpio_in(dev, i);
|
||||
}
|
||||
|
||||
/* Initialize minimal necessary devices for kernel booting */
|
||||
sysbus_create_simple("puv3_pm", PUV3_PM_BASE, NULL);
|
||||
sysbus_create_simple("puv3_dma", PUV3_DMA_BASE, NULL);
|
||||
sysbus_create_simple("puv3_ost", PUV3_OST_BASE, irqs[PUV3_IRQS_OST0]);
|
||||
sysbus_create_varargs("puv3_gpio", PUV3_GPIO_BASE,
|
||||
irqs[PUV3_IRQS_GPIOLOW0], irqs[PUV3_IRQS_GPIOLOW1],
|
||||
irqs[PUV3_IRQS_GPIOLOW2], irqs[PUV3_IRQS_GPIOLOW3],
|
||||
irqs[PUV3_IRQS_GPIOLOW4], irqs[PUV3_IRQS_GPIOLOW5],
|
||||
irqs[PUV3_IRQS_GPIOLOW6], irqs[PUV3_IRQS_GPIOLOW7],
|
||||
irqs[PUV3_IRQS_GPIOHIGH], NULL);
|
||||
|
||||
/* Keyboard (i8042), mouse disabled for nographic */
|
||||
i8042_mm_init(irqs[PUV3_IRQS_PS2_KBD], NULL, i8042, PUV3_REGS_OFFSET, 4);
|
||||
memory_region_add_subregion(get_system_memory(), PUV3_PS2_BASE, i8042);
|
||||
}
|
||||
|
||||
static void puv3_board_init(CPUUniCore32State *env, ram_addr_t ram_size)
|
||||
{
|
||||
MemoryRegion *ram_memory = g_new(MemoryRegion, 1);
|
||||
|
||||
/* SDRAM at address zero. */
|
||||
memory_region_init_ram(ram_memory, NULL, "puv3.ram", ram_size,
|
||||
&error_fatal);
|
||||
memory_region_add_subregion(get_system_memory(), 0, ram_memory);
|
||||
}
|
||||
|
||||
static const GraphicHwOps no_ops;
|
||||
|
||||
static void puv3_load_kernel(const char *kernel_filename)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (kernel_filename == NULL && qtest_enabled()) {
|
||||
return;
|
||||
}
|
||||
if (kernel_filename == NULL) {
|
||||
error_report("kernel parameter cannot be empty");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* only zImage format supported */
|
||||
size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR,
|
||||
KERNEL_MAX_SIZE);
|
||||
if (size < 0) {
|
||||
error_report("Load kernel error: '%s'", kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* cheat curses that we have a graphic console, only under ocd console */
|
||||
graphic_console_init(NULL, 0, &no_ops, NULL);
|
||||
}
|
||||
|
||||
static void puv3_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
CPUUniCore32State *env;
|
||||
UniCore32CPU *cpu;
|
||||
|
||||
if (initrd_filename) {
|
||||
error_report("Please use kernel built-in initramdisk");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cpu = UNICORE32_CPU(cpu_create(machine->cpu_type));
|
||||
env = &cpu->env;
|
||||
|
||||
puv3_soc_init(env);
|
||||
puv3_board_init(env, ram_size);
|
||||
puv3_load_kernel(kernel_filename);
|
||||
}
|
||||
|
||||
static void puv3_machine_init(MachineClass *mc)
|
||||
{
|
||||
mc->desc = "PKUnity Version-3 based on UniCore32";
|
||||
mc->init = puv3_init;
|
||||
mc->is_default = true;
|
||||
mc->default_cpu_type = UNICORE32_CPU_TYPE_NAME("UniCore-II");
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("puv3", puv3_machine_init)
|
@ -1221,12 +1221,6 @@
|
||||
#define FTDI_SCIENCESCOPE_LS_LOGBOOK_PID 0xFF1C
|
||||
#define FTDI_SCIENCESCOPE_HS_LOGBOOK_PID 0xFF1D
|
||||
|
||||
/*
|
||||
* Milkymist One JTAG/Serial
|
||||
*/
|
||||
#define QIHARDWARE_VID 0x20B7
|
||||
#define MILKYMISTONE_JTAGSERIAL_PID 0x0713
|
||||
|
||||
/*
|
||||
* CTI GmbH RS485 Converter http://www.cti-lean.com/
|
||||
*/
|
||||
|
@ -904,7 +904,6 @@ static const struct usb_device_id usbredir_ftdi_serial_ids[] = {
|
||||
{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) },
|
||||
{ USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) },
|
||||
{ USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
|
||||
{ USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID) },
|
||||
{ USB_DEVICE(ST_VID, ST_STMCLT1030_PID) },
|
||||
{ USB_DEVICE(FTDI_VID, FTDI_RF_R106) },
|
||||
{ USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID) },
|
||||
|
@ -249,8 +249,6 @@ enum bfd_architecture
|
||||
#define bfd_mach_nios2 0
|
||||
#define bfd_mach_nios2r1 1
|
||||
#define bfd_mach_nios2r2 2
|
||||
bfd_arch_lm32, /* Lattice Mico32 */
|
||||
#define bfd_mach_lm32 1
|
||||
bfd_arch_rx, /* Renesas RX */
|
||||
#define bfd_mach_rx 0x75
|
||||
#define bfd_mach_rx_v2 0x76
|
||||
@ -443,7 +441,6 @@ int print_insn_m32r (bfd_vma, disassemble_info*);
|
||||
int print_insn_m88k (bfd_vma, disassemble_info*);
|
||||
int print_insn_mn10200 (bfd_vma, disassemble_info*);
|
||||
int print_insn_mn10300 (bfd_vma, disassemble_info*);
|
||||
int print_insn_moxie (bfd_vma, disassemble_info*);
|
||||
int print_insn_ns32k (bfd_vma, disassemble_info*);
|
||||
int print_insn_big_powerpc (bfd_vma, disassemble_info*);
|
||||
int print_insn_little_powerpc (bfd_vma, disassemble_info*);
|
||||
@ -458,7 +455,6 @@ int print_insn_crisv32 (bfd_vma, disassemble_info*);
|
||||
int print_insn_crisv10 (bfd_vma, disassemble_info*);
|
||||
int print_insn_microblaze (bfd_vma, disassemble_info*);
|
||||
int print_insn_ia64 (bfd_vma, disassemble_info*);
|
||||
int print_insn_lm32 (bfd_vma, disassemble_info*);
|
||||
int print_insn_big_nios2 (bfd_vma, disassemble_info*);
|
||||
int print_insn_little_nios2 (bfd_vma, disassemble_info*);
|
||||
int print_insn_xtensa (bfd_vma, disassemble_info*);
|
||||
|
@ -174,9 +174,8 @@ typedef struct mips_elf_abiflags_v0 {
|
||||
|
||||
#define EM_OPENRISC 92 /* OpenCores OpenRISC */
|
||||
|
||||
#define EM_UNICORE32 110 /* UniCore32 */
|
||||
|
||||
#define EM_HEXAGON 164 /* Qualcomm Hexagon */
|
||||
|
||||
#define EM_RX 173 /* Renesas RX family */
|
||||
|
||||
#define EM_RISCV 243 /* RISC-V */
|
||||
@ -206,9 +205,6 @@ typedef struct mips_elf_abiflags_v0 {
|
||||
|
||||
#define EM_AARCH64 183
|
||||
|
||||
#define EM_MOXIE 223 /* Moxie processor family */
|
||||
#define EM_MOXIE_OLD 0xFEED
|
||||
|
||||
#define EF_AVR_MACH 0x7F /* Mask for AVR e_flags to get core type */
|
||||
|
||||
/* This is the info that is needed to parse the dynamic section of the file */
|
||||
|
@ -12,7 +12,6 @@
|
||||
#pragma GCC poison TARGET_CRIS
|
||||
#pragma GCC poison TARGET_HEXAGON
|
||||
#pragma GCC poison TARGET_HPPA
|
||||
#pragma GCC poison TARGET_LM32
|
||||
#pragma GCC poison TARGET_M68K
|
||||
#pragma GCC poison TARGET_MICROBLAZE
|
||||
#pragma GCC poison TARGET_MIPS
|
||||
@ -20,7 +19,6 @@
|
||||
#pragma GCC poison TARGET_ABI_MIPSO32
|
||||
#pragma GCC poison TARGET_MIPS64
|
||||
#pragma GCC poison TARGET_ABI_MIPSN64
|
||||
#pragma GCC poison TARGET_MOXIE
|
||||
#pragma GCC poison TARGET_NIOS2
|
||||
#pragma GCC poison TARGET_OPENRISC
|
||||
#pragma GCC poison TARGET_PPC
|
||||
@ -32,7 +30,6 @@
|
||||
#pragma GCC poison TARGET_SPARC
|
||||
#pragma GCC poison TARGET_SPARC64
|
||||
#pragma GCC poison TARGET_TRICORE
|
||||
#pragma GCC poison TARGET_UNICORE32
|
||||
#pragma GCC poison TARGET_XTENSA
|
||||
|
||||
#pragma GCC poison TARGET_ALIGNED_ONLY
|
||||
@ -74,12 +71,10 @@
|
||||
#pragma GCC poison CONFIG_HPPA_DIS
|
||||
#pragma GCC poison CONFIG_I386_DIS
|
||||
#pragma GCC poison CONFIG_HEXAGON_DIS
|
||||
#pragma GCC poison CONFIG_LM32_DIS
|
||||
#pragma GCC poison CONFIG_M68K_DIS
|
||||
#pragma GCC poison CONFIG_MICROBLAZE_DIS
|
||||
#pragma GCC poison CONFIG_MIPS_DIS
|
||||
#pragma GCC poison CONFIG_NANOMIPS_DIS
|
||||
#pragma GCC poison CONFIG_MOXIE_DIS
|
||||
#pragma GCC poison CONFIG_NIOS2_DIS
|
||||
#pragma GCC poison CONFIG_PPC_DIS
|
||||
#pragma GCC poison CONFIG_RISCV_DIS
|
||||
|
@ -1,13 +0,0 @@
|
||||
#ifndef QEMU_HW_CHAR_LM32_JUART_H
|
||||
#define QEMU_HW_CHAR_LM32_JUART_H
|
||||
|
||||
#include "hw/qdev-core.h"
|
||||
|
||||
#define TYPE_LM32_JUART "lm32-juart"
|
||||
|
||||
uint32_t lm32_juart_get_jtx(DeviceState *d);
|
||||
uint32_t lm32_juart_get_jrx(DeviceState *d);
|
||||
void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx);
|
||||
void lm32_juart_set_jrx(DeviceState *d, uint32_t jrx);
|
||||
|
||||
#endif /* QEMU_HW_CHAR_LM32_JUART_H */
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* QEMU model of the Milkymist texture mapping unit.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
* Copyright (c) 2010 Sebastien Bourdeauducq
|
||||
* <sebastien.bourdeauducq@lekernel.net>
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Specification available at:
|
||||
* http://milkymist.walle.cc/socdoc/tmu2.pdf
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HW_DISPLAY_MILKYMIST_TMU2_H
|
||||
#define HW_DISPLAY_MILKYMIST_TMU2_H
|
||||
|
||||
#include "exec/hwaddr.h"
|
||||
#include "hw/qdev-core.h"
|
||||
|
||||
#if defined(CONFIG_X11) && defined(CONFIG_OPENGL)
|
||||
DeviceState *milkymist_tmu2_create(hwaddr base, qemu_irq irq);
|
||||
#else
|
||||
static inline DeviceState *milkymist_tmu2_create(hwaddr base, qemu_irq irq)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HW_DISPLAY_MILKYMIST_TMU2_H */
|
@ -368,14 +368,6 @@ static int glue(load_elf, SZ)(const char *name, int fd,
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EM_MOXIE:
|
||||
if (ehdr.e_machine != EM_MOXIE) {
|
||||
if (ehdr.e_machine != EM_MOXIE_OLD) {
|
||||
ret = ELF_LOAD_WRONG_ARCH;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EM_MIPS:
|
||||
case EM_NANOMIPS:
|
||||
if ((ehdr.e_machine != EM_MIPS) &&
|
||||
|
@ -1,10 +0,0 @@
|
||||
#ifndef QEMU_HW_LM32_PIC_H
|
||||
#define QEMU_HW_LM32_PIC_H
|
||||
|
||||
|
||||
uint32_t lm32_pic_get_ip(DeviceState *d);
|
||||
uint32_t lm32_pic_get_im(DeviceState *d);
|
||||
void lm32_pic_set_ip(DeviceState *d, uint32_t ip);
|
||||
void lm32_pic_set_im(DeviceState *d, uint32_t im);
|
||||
|
||||
#endif /* QEMU_HW_LM32_PIC_H */
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Misc PKUnity SoC declarations
|
||||
*
|
||||
* Copyright (C) 2010-2012 Guan Xuetao
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation, or any later version.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef QEMU_HW_PUV3_H
|
||||
#define QEMU_HW_PUV3_H
|
||||
|
||||
#define PUV3_REGS_OFFSET (0x1000) /* 4K is reasonable */
|
||||
|
||||
/* Hardware interrupts */
|
||||
#define PUV3_IRQS_NR (32)
|
||||
|
||||
#define PUV3_IRQS_GPIOLOW0 (0)
|
||||
#define PUV3_IRQS_GPIOLOW1 (1)
|
||||
#define PUV3_IRQS_GPIOLOW2 (2)
|
||||
#define PUV3_IRQS_GPIOLOW3 (3)
|
||||
#define PUV3_IRQS_GPIOLOW4 (4)
|
||||
#define PUV3_IRQS_GPIOLOW5 (5)
|
||||
#define PUV3_IRQS_GPIOLOW6 (6)
|
||||
#define PUV3_IRQS_GPIOLOW7 (7)
|
||||
#define PUV3_IRQS_GPIOHIGH (8)
|
||||
#define PUV3_IRQS_PS2_KBD (22)
|
||||
#define PUV3_IRQS_PS2_AUX (23)
|
||||
#define PUV3_IRQS_OST0 (26)
|
||||
|
||||
/* All puv3_*.c use DPRINTF for debug. */
|
||||
#ifdef DEBUG_PUV3
|
||||
#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DPRINTF(fmt, ...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#endif /* QEMU_HW_PUV3_H */
|
@ -9,7 +9,6 @@ enum {
|
||||
QEMU_ARCH_CRIS = (1 << 2),
|
||||
QEMU_ARCH_I386 = (1 << 3),
|
||||
QEMU_ARCH_M68K = (1 << 4),
|
||||
QEMU_ARCH_LM32 = (1 << 5),
|
||||
QEMU_ARCH_MICROBLAZE = (1 << 6),
|
||||
QEMU_ARCH_MIPS = (1 << 7),
|
||||
QEMU_ARCH_PPC = (1 << 8),
|
||||
@ -18,8 +17,6 @@ enum {
|
||||
QEMU_ARCH_SPARC = (1 << 11),
|
||||
QEMU_ARCH_XTENSA = (1 << 12),
|
||||
QEMU_ARCH_OPENRISC = (1 << 13),
|
||||
QEMU_ARCH_UNICORE32 = (1 << 14),
|
||||
QEMU_ARCH_MOXIE = (1 << 15),
|
||||
QEMU_ARCH_TRICORE = (1 << 16),
|
||||
QEMU_ARCH_NIOS2 = (1 << 17),
|
||||
QEMU_ARCH_HPPA = (1 << 18),
|
||||
|
@ -847,7 +847,7 @@ if 'CONFIG_VTE' in config_host
|
||||
link_args: config_host['VTE_LIBS'].split())
|
||||
endif
|
||||
x11 = not_found
|
||||
if gtkx11.found() or 'lm32-softmmu' in target_dirs
|
||||
if gtkx11.found()
|
||||
x11 = dependency('x11', method: 'pkg-config', required: gtkx11.found(),
|
||||
kwargs: static_kwargs)
|
||||
endif
|
||||
@ -1210,11 +1210,9 @@ disassemblers = {
|
||||
'i386' : ['CONFIG_I386_DIS'],
|
||||
'x86_64' : ['CONFIG_I386_DIS'],
|
||||
'x32' : ['CONFIG_I386_DIS'],
|
||||
'lm32' : ['CONFIG_LM32_DIS'],
|
||||
'm68k' : ['CONFIG_M68K_DIS'],
|
||||
'microblaze' : ['CONFIG_MICROBLAZE_DIS'],
|
||||
'mips' : ['CONFIG_MIPS_DIS'],
|
||||
'moxie' : ['CONFIG_MOXIE_DIS'],
|
||||
'nios2' : ['CONFIG_NIOS2_DIS'],
|
||||
'or1k' : ['CONFIG_OPENRISC_DIS'],
|
||||
'ppc' : ['CONFIG_PPC_DIS'],
|
||||
@ -2635,7 +2633,6 @@ if have_block
|
||||
summary_info += {'vvfat support': config_host.has_key('CONFIG_VVFAT')}
|
||||
summary_info += {'qed support': config_host.has_key('CONFIG_QED')}
|
||||
summary_info += {'parallels support': config_host.has_key('CONFIG_PARALLELS')}
|
||||
summary_info += {'sheepdog support': config_host.has_key('CONFIG_SHEEPDOG')}
|
||||
summary_info += {'FUSE exports': fuse.found()}
|
||||
endif
|
||||
summary(summary_info, bool_yn: true, section: 'Block layer support')
|
||||
|
@ -257,24 +257,6 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
|
||||
trace_monitor_qmp_in_band_dequeue(req_obj,
|
||||
req_obj->mon->qmp_requests->length);
|
||||
|
||||
if (qatomic_xchg(&qmp_dispatcher_co_busy, true) == true) {
|
||||
/*
|
||||
* Someone rescheduled us (probably because a new requests
|
||||
* came in), but we didn't actually yield. Do that now,
|
||||
* only to be immediately reentered and removed from the
|
||||
* list of scheduled coroutines.
|
||||
*/
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the coroutine from iohandler_ctx to qemu_aio_context for
|
||||
* executing the command handler so that it can make progress if it
|
||||
* involves an AIO_WAIT_WHILE().
|
||||
*/
|
||||
aio_co_schedule(qemu_get_aio_context(), qmp_dispatcher_co);
|
||||
qemu_coroutine_yield();
|
||||
|
||||
/*
|
||||
* @req_obj has a request, we hold req_obj->mon->qmp_queue_lock
|
||||
*/
|
||||
@ -298,8 +280,30 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
|
||||
monitor_resume(&mon->common);
|
||||
}
|
||||
|
||||
/*
|
||||
* Drop the queue mutex now, before yielding, otherwise we might
|
||||
* deadlock if the main thread tries to lock it.
|
||||
*/
|
||||
qemu_mutex_unlock(&mon->qmp_queue_lock);
|
||||
|
||||
if (qatomic_xchg(&qmp_dispatcher_co_busy, true) == true) {
|
||||
/*
|
||||
* Someone rescheduled us (probably because a new requests
|
||||
* came in), but we didn't actually yield. Do that now,
|
||||
* only to be immediately reentered and removed from the
|
||||
* list of scheduled coroutines.
|
||||
*/
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the coroutine from iohandler_ctx to qemu_aio_context for
|
||||
* executing the command handler so that it can make progress if it
|
||||
* involves an AIO_WAIT_WHILE().
|
||||
*/
|
||||
aio_co_schedule(qemu_get_aio_context(), qmp_dispatcher_co);
|
||||
qemu_coroutine_yield();
|
||||
|
||||
/* Process request */
|
||||
if (req_obj->req) {
|
||||
if (trace_event_get_state(TRACE_MONITOR_QMP_CMD_IN_BAND)) {
|
||||
|
@ -2818,7 +2818,6 @@
|
||||
'luks', 'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels',
|
||||
'preallocate', 'qcow', 'qcow2', 'qed', 'quorum', 'raw', 'rbd',
|
||||
{ 'name': 'replication', 'if': 'defined(CONFIG_REPLICATION)' },
|
||||
'sheepdog',
|
||||
'ssh', 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat' ] }
|
||||
|
||||
##
|
||||
@ -3651,26 +3650,6 @@
|
||||
'*key-secret': 'str',
|
||||
'*server': ['InetSocketAddressBase'] } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsSheepdog:
|
||||
#
|
||||
# Driver specific block device options for sheepdog
|
||||
#
|
||||
# @vdi: Virtual disk image name
|
||||
# @server: The Sheepdog server to connect to
|
||||
# @snap-id: Snapshot ID
|
||||
# @tag: Snapshot tag name
|
||||
#
|
||||
# Only one of @snap-id and @tag may be present.
|
||||
#
|
||||
# Since: 2.9
|
||||
##
|
||||
{ 'struct': 'BlockdevOptionsSheepdog',
|
||||
'data': { 'server': 'SocketAddress',
|
||||
'vdi': 'str',
|
||||
'*snap-id': 'uint32',
|
||||
'*tag': 'str' } }
|
||||
|
||||
##
|
||||
# @ReplicationMode:
|
||||
#
|
||||
@ -4037,7 +4016,6 @@
|
||||
'rbd': 'BlockdevOptionsRbd',
|
||||
'replication': { 'type': 'BlockdevOptionsReplication',
|
||||
'if': 'defined(CONFIG_REPLICATION)' },
|
||||
'sheepdog': 'BlockdevOptionsSheepdog',
|
||||
'ssh': 'BlockdevOptionsSsh',
|
||||
'throttle': 'BlockdevOptionsThrottle',
|
||||
'vdi': 'BlockdevOptionsGenericFormat',
|
||||
@ -4496,74 +4474,6 @@
|
||||
'*zeroed-grain': 'bool' } }
|
||||
|
||||
|
||||
##
|
||||
# @SheepdogRedundancyType:
|
||||
#
|
||||
# @full: Create a fully replicated vdi with x copies
|
||||
# @erasure-coded: Create an erasure coded vdi with x data strips and
|
||||
# y parity strips
|
||||
#
|
||||
# Since: 2.12
|
||||
##
|
||||
{ 'enum': 'SheepdogRedundancyType',
|
||||
'data': [ 'full', 'erasure-coded' ] }
|
||||
|
||||
##
|
||||
# @SheepdogRedundancyFull:
|
||||
#
|
||||
# @copies: Number of copies to use (between 1 and 31)
|
||||
#
|
||||
# Since: 2.12
|
||||
##
|
||||
{ 'struct': 'SheepdogRedundancyFull',
|
||||
'data': { 'copies': 'int' }}
|
||||
|
||||
##
|
||||
# @SheepdogRedundancyErasureCoded:
|
||||
#
|
||||
# @data-strips: Number of data strips to use (one of {2,4,8,16})
|
||||
# @parity-strips: Number of parity strips to use (between 1 and 15)
|
||||
#
|
||||
# Since: 2.12
|
||||
##
|
||||
{ 'struct': 'SheepdogRedundancyErasureCoded',
|
||||
'data': { 'data-strips': 'int',
|
||||
'parity-strips': 'int' }}
|
||||
|
||||
##
|
||||
# @SheepdogRedundancy:
|
||||
#
|
||||
# Since: 2.12
|
||||
##
|
||||
{ 'union': 'SheepdogRedundancy',
|
||||
'base': { 'type': 'SheepdogRedundancyType' },
|
||||
'discriminator': 'type',
|
||||
'data': { 'full': 'SheepdogRedundancyFull',
|
||||
'erasure-coded': 'SheepdogRedundancyErasureCoded' } }
|
||||
|
||||
##
|
||||
# @BlockdevCreateOptionsSheepdog:
|
||||
#
|
||||
# Driver specific image creation options for Sheepdog.
|
||||
#
|
||||
# @location: Where to store the new image file
|
||||
# @size: Size of the virtual disk in bytes
|
||||
# @backing-file: File name of a base image
|
||||
# @preallocation: Preallocation mode for the new image (default: off;
|
||||
# allowed values: off, full)
|
||||
# @redundancy: Redundancy of the image
|
||||
# @object-size: Object size of the image
|
||||
#
|
||||
# Since: 2.12
|
||||
##
|
||||
{ 'struct': 'BlockdevCreateOptionsSheepdog',
|
||||
'data': { 'location': 'BlockdevOptionsSheepdog',
|
||||
'size': 'size',
|
||||
'*backing-file': 'str',
|
||||
'*preallocation': 'PreallocMode',
|
||||
'*redundancy': 'SheepdogRedundancy',
|
||||
'*object-size': 'size' } }
|
||||
|
||||
##
|
||||
# @BlockdevCreateOptionsSsh:
|
||||
#
|
||||
@ -4687,7 +4597,6 @@
|
||||
'qcow2': 'BlockdevCreateOptionsQcow2',
|
||||
'qed': 'BlockdevCreateOptionsQed',
|
||||
'rbd': 'BlockdevCreateOptionsRbd',
|
||||
'sheepdog': 'BlockdevCreateOptionsSheepdog',
|
||||
'ssh': 'BlockdevCreateOptionsSsh',
|
||||
'vdi': 'BlockdevCreateOptionsVdi',
|
||||
'vhdx': 'BlockdevCreateOptionsVhdx',
|
||||
@ -5322,7 +5231,7 @@
|
||||
#
|
||||
# Notes: In transaction, if @name is empty, or any snapshot matching @name
|
||||
# exists, the operation will fail. Only some image formats support it,
|
||||
# for example, qcow2, rbd, and sheepdog.
|
||||
# for example, qcow2, and rbd.
|
||||
#
|
||||
# Since: 1.7
|
||||
##
|
||||
|
@ -29,11 +29,11 @@
|
||||
# Since: 3.0
|
||||
##
|
||||
{ 'enum' : 'SysEmuTarget',
|
||||
'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386', 'lm32',
|
||||
'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386',
|
||||
'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64',
|
||||
'mips64el', 'mipsel', 'moxie', 'nios2', 'or1k', 'ppc',
|
||||
'mips64el', 'mipsel', 'nios2', 'or1k', 'ppc',
|
||||
'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4',
|
||||
'sh4eb', 'sparc', 'sparc64', 'tricore', 'unicore32',
|
||||
'sh4eb', 'sparc', 'sparc64', 'tricore',
|
||||
'x86_64', 'xtensa', 'xtensaeb' ] }
|
||||
|
||||
##
|
||||
|
@ -23,7 +23,7 @@
|
||||
##
|
||||
{ 'event': 'RTC_CHANGE',
|
||||
'data': { 'offset': 'int' },
|
||||
'if': 'defined(TARGET_ALPHA) || defined(TARGET_ARM) || defined(TARGET_HPPA) || defined(TARGET_I386) || defined(TARGET_MIPS) || defined(TARGET_MIPS64) || defined(TARGET_MOXIE) || defined(TARGET_PPC) || defined(TARGET_PPC64) || defined(TARGET_S390X) || defined(TARGET_SH4) || defined(TARGET_SPARC)' }
|
||||
'if': 'defined(TARGET_ALPHA) || defined(TARGET_ARM) || defined(TARGET_HPPA) || defined(TARGET_I386) || defined(TARGET_MIPS) || defined(TARGET_MIPS64) || defined(TARGET_PPC) || defined(TARGET_PPC64) || defined(TARGET_S390X) || defined(TARGET_SH4) || defined(TARGET_SPARC)' }
|
||||
|
||||
##
|
||||
# @rtc-reset-reinjection:
|
||||
|
@ -112,10 +112,10 @@
|
||||
#
|
||||
# On failure, the original disks pre-snapshot attempt will be used.
|
||||
#
|
||||
# For internal snapshots, the dictionary contains the device and the snapshot's
|
||||
# name. If an internal snapshot matching name already exists, the request will
|
||||
# be rejected. Only some image formats support it, for example, qcow2, rbd,
|
||||
# and sheepdog.
|
||||
# For internal snapshots, the dictionary contains the device and the
|
||||
# snapshot's name. If an internal snapshot matching name already exists,
|
||||
# the request will be rejected. Only some image formats support it, for
|
||||
# example, qcow2, and rbd,
|
||||
#
|
||||
# On failure, qemu will try delete the newly created internal snapshot in the
|
||||
# transaction. When an I/O error occurs during deletion, the user needs to fix
|
||||
|
@ -4288,7 +4288,7 @@ SRST
|
||||
ERST
|
||||
DEF("semihosting", 0, QEMU_OPTION_semihosting,
|
||||
"-semihosting semihosting mode\n",
|
||||
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 |
|
||||
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA |
|
||||
QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV)
|
||||
SRST
|
||||
``-semihosting``
|
||||
@ -4303,7 +4303,7 @@ ERST
|
||||
DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config,
|
||||
"-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]\n" \
|
||||
" semihosting configuration\n",
|
||||
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 |
|
||||
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA |
|
||||
QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV)
|
||||
SRST
|
||||
``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]``
|
||||
|
@ -56,16 +56,12 @@ int graphic_depth = 32;
|
||||
#define QEMU_ARCH QEMU_ARCH_HPPA
|
||||
#elif defined(TARGET_I386)
|
||||
#define QEMU_ARCH QEMU_ARCH_I386
|
||||
#elif defined(TARGET_LM32)
|
||||
#define QEMU_ARCH QEMU_ARCH_LM32
|
||||
#elif defined(TARGET_M68K)
|
||||
#define QEMU_ARCH QEMU_ARCH_M68K
|
||||
#elif defined(TARGET_MICROBLAZE)
|
||||
#define QEMU_ARCH QEMU_ARCH_MICROBLAZE
|
||||
#elif defined(TARGET_MIPS)
|
||||
#define QEMU_ARCH QEMU_ARCH_MIPS
|
||||
#elif defined(TARGET_MOXIE)
|
||||
#define QEMU_ARCH QEMU_ARCH_MOXIE
|
||||
#elif defined(TARGET_NIOS2)
|
||||
#define QEMU_ARCH QEMU_ARCH_NIOS2
|
||||
#elif defined(TARGET_OPENRISC)
|
||||
@ -84,8 +80,6 @@ int graphic_depth = 32;
|
||||
#define QEMU_ARCH QEMU_ARCH_SPARC
|
||||
#elif defined(TARGET_TRICORE)
|
||||
#define QEMU_ARCH QEMU_ARCH_TRICORE
|
||||
#elif defined(TARGET_UNICORE32)
|
||||
#define QEMU_ARCH QEMU_ARCH_UNICORE32
|
||||
#elif defined(TARGET_XTENSA)
|
||||
#define QEMU_ARCH QEMU_ARCH_XTENSA
|
||||
#elif defined(TARGET_AVR)
|
||||
|
@ -1,45 +0,0 @@
|
||||
LatticeMico32 target
|
||||
--------------------
|
||||
|
||||
General
|
||||
-------
|
||||
All opcodes including the JUART CSRs are supported.
|
||||
|
||||
|
||||
JTAG UART
|
||||
---------
|
||||
JTAG UART is routed to a serial console device. For the current boards it
|
||||
is the second one. Ie to enable it in the qemu virtual console window use
|
||||
the following command line parameters:
|
||||
-serial vc -serial vc
|
||||
This will make serial0 (the lm32_uart) and serial1 (the JTAG UART)
|
||||
available as virtual consoles.
|
||||
|
||||
|
||||
Semihosting
|
||||
-----------
|
||||
Semihosting on this target is supported. Some system calls like read, write
|
||||
and exit are executed on the host if semihosting is enabled. See
|
||||
target/lm32-semi.c for all supported system calls. Emulation aware programs
|
||||
can use this mechanism to shut down the virtual machine and print to the
|
||||
host console. See the tcg tests for an example.
|
||||
|
||||
|
||||
Special instructions
|
||||
--------------------
|
||||
The translation recognizes one special instruction to halt the cpu:
|
||||
and r0, r0, r0
|
||||
On real hardware this instruction is a nop. It is not used by GCC and
|
||||
should (hopefully) not be used within hand-crafted assembly.
|
||||
Insert this instruction in your idle loop to reduce the cpu load on the
|
||||
host.
|
||||
|
||||
|
||||
Ignoring the MSB of the address bus
|
||||
-----------------------------------
|
||||
Some SoC ignores the MSB on the address bus. Thus creating a shadow memory
|
||||
area. As a general rule, 0x00000000-0x7fffffff is cached, whereas
|
||||
0x80000000-0xffffffff is not cached and used to access IO devices. This
|
||||
behaviour can be enabled with:
|
||||
cpu_lm32_set_phys_msb_ignore(env, 1);
|
||||
|
@ -1 +0,0 @@
|
||||
* linux-user emulation
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* LatticeMico32 cpu parameters for qemu.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
* SPDX-License-Identifier: LGPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef LM32_CPU_PARAM_H
|
||||
#define LM32_CPU_PARAM_H 1
|
||||
|
||||
#define TARGET_LONG_BITS 32
|
||||
#define TARGET_PAGE_BITS 12
|
||||
#define TARGET_PHYS_ADDR_SPACE_BITS 32
|
||||
#define TARGET_VIRT_ADDR_SPACE_BITS 32
|
||||
#define NB_MMU_MODES 1
|
||||
|
||||
#endif
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* QEMU LatticeMico32 CPU
|
||||
*
|
||||
* Copyright (c) 2012 SUSE LINUX Products GmbH
|
||||
*
|
||||
* 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.1 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, see
|
||||
* <http://www.gnu.org/licenses/lgpl-2.1.html>
|
||||
*/
|
||||
#ifndef QEMU_LM32_CPU_QOM_H
|
||||
#define QEMU_LM32_CPU_QOM_H
|
||||
|
||||
#include "hw/core/cpu.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_LM32_CPU "lm32-cpu"
|
||||
|
||||
OBJECT_DECLARE_TYPE(LM32CPU, LM32CPUClass,
|
||||
LM32_CPU)
|
||||
|
||||
/**
|
||||
* LM32CPUClass:
|
||||
* @parent_realize: The parent class' realize handler.
|
||||
* @parent_reset: The parent class' reset handler.
|
||||
*
|
||||
* A LatticeMico32 CPU model.
|
||||
*/
|
||||
struct LM32CPUClass {
|
||||
/*< private >*/
|
||||
CPUClass parent_class;
|
||||
/*< public >*/
|
||||
|
||||
DeviceRealize parent_realize;
|
||||
DeviceReset parent_reset;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -1,274 +0,0 @@
|
||||
/*
|
||||
* QEMU LatticeMico32 CPU
|
||||
*
|
||||
* Copyright (c) 2012 SUSE LINUX Products GmbH
|
||||
*
|
||||
* 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.1 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, see
|
||||
* <http://www.gnu.org/licenses/lgpl-2.1.html>
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/qemu-print.h"
|
||||
#include "cpu.h"
|
||||
|
||||
|
||||
static void lm32_cpu_set_pc(CPUState *cs, vaddr value)
|
||||
{
|
||||
LM32CPU *cpu = LM32_CPU(cs);
|
||||
|
||||
cpu->env.pc = value;
|
||||
}
|
||||
|
||||
static void lm32_cpu_list_entry(gpointer data, gpointer user_data)
|
||||
{
|
||||
ObjectClass *oc = data;
|
||||
const char *typename = object_class_get_name(oc);
|
||||
char *name;
|
||||
|
||||
name = g_strndup(typename, strlen(typename) - strlen(LM32_CPU_TYPE_SUFFIX));
|
||||
qemu_printf(" %s\n", name);
|
||||
g_free(name);
|
||||
}
|
||||
|
||||
|
||||
void lm32_cpu_list(void)
|
||||
{
|
||||
GSList *list;
|
||||
|
||||
list = object_class_get_list_sorted(TYPE_LM32_CPU, false);
|
||||
qemu_printf("Available CPUs:\n");
|
||||
g_slist_foreach(list, lm32_cpu_list_entry, NULL);
|
||||
g_slist_free(list);
|
||||
}
|
||||
|
||||
static void lm32_cpu_init_cfg_reg(LM32CPU *cpu)
|
||||
{
|
||||
CPULM32State *env = &cpu->env;
|
||||
uint32_t cfg = 0;
|
||||
|
||||
if (cpu->features & LM32_FEATURE_MULTIPLY) {
|
||||
cfg |= CFG_M;
|
||||
}
|
||||
|
||||
if (cpu->features & LM32_FEATURE_DIVIDE) {
|
||||
cfg |= CFG_D;
|
||||
}
|
||||
|
||||
if (cpu->features & LM32_FEATURE_SHIFT) {
|
||||
cfg |= CFG_S;
|
||||
}
|
||||
|
||||
if (cpu->features & LM32_FEATURE_SIGN_EXTEND) {
|
||||
cfg |= CFG_X;
|
||||
}
|
||||
|
||||
if (cpu->features & LM32_FEATURE_I_CACHE) {
|
||||
cfg |= CFG_IC;
|
||||
}
|
||||
|
||||
if (cpu->features & LM32_FEATURE_D_CACHE) {
|
||||
cfg |= CFG_DC;
|
||||
}
|
||||
|
||||
if (cpu->features & LM32_FEATURE_CYCLE_COUNT) {
|
||||
cfg |= CFG_CC;
|
||||
}
|
||||
|
||||
cfg |= (cpu->num_interrupts << CFG_INT_SHIFT);
|
||||
cfg |= (cpu->num_breakpoints << CFG_BP_SHIFT);
|
||||
cfg |= (cpu->num_watchpoints << CFG_WP_SHIFT);
|
||||
cfg |= (cpu->revision << CFG_REV_SHIFT);
|
||||
|
||||
env->cfg = cfg;
|
||||
}
|
||||
|
||||
static bool lm32_cpu_has_work(CPUState *cs)
|
||||
{
|
||||
return cs->interrupt_request & CPU_INTERRUPT_HARD;
|
||||
}
|
||||
|
||||
static void lm32_cpu_reset(DeviceState *dev)
|
||||
{
|
||||
CPUState *s = CPU(dev);
|
||||
LM32CPU *cpu = LM32_CPU(s);
|
||||
LM32CPUClass *lcc = LM32_CPU_GET_CLASS(cpu);
|
||||
CPULM32State *env = &cpu->env;
|
||||
|
||||
lcc->parent_reset(dev);
|
||||
|
||||
/* reset cpu state */
|
||||
memset(env, 0, offsetof(CPULM32State, end_reset_fields));
|
||||
|
||||
lm32_cpu_init_cfg_reg(cpu);
|
||||
}
|
||||
|
||||
static void lm32_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
|
||||
{
|
||||
info->mach = bfd_mach_lm32;
|
||||
info->print_insn = print_insn_lm32;
|
||||
}
|
||||
|
||||
static void lm32_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||
{
|
||||
CPUState *cs = CPU(dev);
|
||||
LM32CPUClass *lcc = LM32_CPU_GET_CLASS(dev);
|
||||
Error *local_err = NULL;
|
||||
|
||||
cpu_exec_realizefn(cs, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
cpu_reset(cs);
|
||||
|
||||
qemu_init_vcpu(cs);
|
||||
|
||||
lcc->parent_realize(dev, errp);
|
||||
}
|
||||
|
||||
static void lm32_cpu_initfn(Object *obj)
|
||||
{
|
||||
LM32CPU *cpu = LM32_CPU(obj);
|
||||
CPULM32State *env = &cpu->env;
|
||||
|
||||
cpu_set_cpustate_pointers(cpu);
|
||||
|
||||
env->flags = 0;
|
||||
}
|
||||
|
||||
static void lm32_basic_cpu_initfn(Object *obj)
|
||||
{
|
||||
LM32CPU *cpu = LM32_CPU(obj);
|
||||
|
||||
cpu->revision = 3;
|
||||
cpu->num_interrupts = 32;
|
||||
cpu->num_breakpoints = 4;
|
||||
cpu->num_watchpoints = 4;
|
||||
cpu->features = LM32_FEATURE_SHIFT
|
||||
| LM32_FEATURE_SIGN_EXTEND
|
||||
| LM32_FEATURE_CYCLE_COUNT;
|
||||
}
|
||||
|
||||
static void lm32_standard_cpu_initfn(Object *obj)
|
||||
{
|
||||
LM32CPU *cpu = LM32_CPU(obj);
|
||||
|
||||
cpu->revision = 3;
|
||||
cpu->num_interrupts = 32;
|
||||
cpu->num_breakpoints = 4;
|
||||
cpu->num_watchpoints = 4;
|
||||
cpu->features = LM32_FEATURE_MULTIPLY
|
||||
| LM32_FEATURE_DIVIDE
|
||||
| LM32_FEATURE_SHIFT
|
||||
| LM32_FEATURE_SIGN_EXTEND
|
||||
| LM32_FEATURE_I_CACHE
|
||||
| LM32_FEATURE_CYCLE_COUNT;
|
||||
}
|
||||
|
||||
static void lm32_full_cpu_initfn(Object *obj)
|
||||
{
|
||||
LM32CPU *cpu = LM32_CPU(obj);
|
||||
|
||||
cpu->revision = 3;
|
||||
cpu->num_interrupts = 32;
|
||||
cpu->num_breakpoints = 4;
|
||||
cpu->num_watchpoints = 4;
|
||||
cpu->features = LM32_FEATURE_MULTIPLY
|
||||
| LM32_FEATURE_DIVIDE
|
||||
| LM32_FEATURE_SHIFT
|
||||
| LM32_FEATURE_SIGN_EXTEND
|
||||
| LM32_FEATURE_I_CACHE
|
||||
| LM32_FEATURE_D_CACHE
|
||||
| LM32_FEATURE_CYCLE_COUNT;
|
||||
}
|
||||
|
||||
static ObjectClass *lm32_cpu_class_by_name(const char *cpu_model)
|
||||
{
|
||||
ObjectClass *oc;
|
||||
char *typename;
|
||||
|
||||
typename = g_strdup_printf(LM32_CPU_TYPE_NAME("%s"), cpu_model);
|
||||
oc = object_class_by_name(typename);
|
||||
g_free(typename);
|
||||
if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_LM32_CPU) ||
|
||||
object_class_is_abstract(oc))) {
|
||||
oc = NULL;
|
||||
}
|
||||
return oc;
|
||||
}
|
||||
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static struct TCGCPUOps lm32_tcg_ops = {
|
||||
.initialize = lm32_translate_init,
|
||||
.cpu_exec_interrupt = lm32_cpu_exec_interrupt,
|
||||
.tlb_fill = lm32_cpu_tlb_fill,
|
||||
.debug_excp_handler = lm32_debug_excp_handler,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
.do_interrupt = lm32_cpu_do_interrupt,
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
};
|
||||
|
||||
static void lm32_cpu_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
LM32CPUClass *lcc = LM32_CPU_CLASS(oc);
|
||||
CPUClass *cc = CPU_CLASS(oc);
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
device_class_set_parent_realize(dc, lm32_cpu_realizefn,
|
||||
&lcc->parent_realize);
|
||||
device_class_set_parent_reset(dc, lm32_cpu_reset, &lcc->parent_reset);
|
||||
|
||||
cc->class_by_name = lm32_cpu_class_by_name;
|
||||
cc->has_work = lm32_cpu_has_work;
|
||||
cc->dump_state = lm32_cpu_dump_state;
|
||||
cc->set_pc = lm32_cpu_set_pc;
|
||||
cc->gdb_read_register = lm32_cpu_gdb_read_register;
|
||||
cc->gdb_write_register = lm32_cpu_gdb_write_register;
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
cc->get_phys_page_debug = lm32_cpu_get_phys_page_debug;
|
||||
cc->vmsd = &vmstate_lm32_cpu;
|
||||
#endif
|
||||
cc->gdb_num_core_regs = 32 + 7;
|
||||
cc->gdb_stop_before_watchpoint = true;
|
||||
cc->disas_set_info = lm32_cpu_disas_set_info;
|
||||
cc->tcg_ops = &lm32_tcg_ops;
|
||||
}
|
||||
|
||||
#define DEFINE_LM32_CPU_TYPE(cpu_model, initfn) \
|
||||
{ \
|
||||
.parent = TYPE_LM32_CPU, \
|
||||
.name = LM32_CPU_TYPE_NAME(cpu_model), \
|
||||
.instance_init = initfn, \
|
||||
}
|
||||
|
||||
static const TypeInfo lm32_cpus_type_infos[] = {
|
||||
{ /* base class should be registered first */
|
||||
.name = TYPE_LM32_CPU,
|
||||
.parent = TYPE_CPU,
|
||||
.instance_size = sizeof(LM32CPU),
|
||||
.instance_init = lm32_cpu_initfn,
|
||||
.abstract = true,
|
||||
.class_size = sizeof(LM32CPUClass),
|
||||
.class_init = lm32_cpu_class_init,
|
||||
},
|
||||
DEFINE_LM32_CPU_TYPE("lm32-basic", lm32_basic_cpu_initfn),
|
||||
DEFINE_LM32_CPU_TYPE("lm32-standard", lm32_standard_cpu_initfn),
|
||||
DEFINE_LM32_CPU_TYPE("lm32-full", lm32_full_cpu_initfn),
|
||||
};
|
||||
|
||||
DEFINE_TYPES(lm32_cpus_type_infos)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user